uae_u32 mmu030_fmovem_store[2];
uae_u8 mmu030_cache_state;
struct mmu030_access mmu030_ad[MAX_MMU030_ACCESS + 1];
-bool ismoves030;
+bool ismoves030, islrmw030;
static void mmu030_ptest_atc_search(uaecptr logical_addr, uae_u32 fc, bool write);
static uae_u32 mmu030_table_search(uaecptr addr, uae_u32 fc, bool write, int level);
fc = regs.mmu_ssw & MMU030_SSW_FC_MASK;
flags = regs.mmu_ssw & ~(MMU030_SSW_FC | MMU030_SSW_RC | MMU030_SSW_FB | MMU030_SSW_RB | MMU030_SSW_RW | 7);
}
- ismoves030 = false;
regs.wb3_status = 0;
regs.wb2_status = 0;
regs.mmu_fault_addr = addr;
}
} else {
if (currprefs.cpu_compatible) {
+ regs.wb2_status = mmu030fixupreg(0);
+ mmu030fixupmod(regs.wb2_status, 0, 0);
+ regs.wb3_status = mmu030fixupreg(1);
+ mmu030fixupmod(regs.wb3_status, 0, 1);
if (regs.prefetch020_valid[1] != 1 && regs.prefetch020_valid[2] == 1) {
regs.mmu_ssw = MMU030_SSW_FC | MMU030_SSW_RC;
} else if (regs.prefetch020_valid[2] != 1) {
regs.mmu_ssw |= read ? MMU030_SSW_RW : 0;
regs.mmu_ssw |= flags;
regs.mmu_ssw |= fc;
+ regs.mmu_ssw |= islrmw030 ? MMU030_SSW_RM : 0;
// temporary store in 68040+ variables because stack frame creation may modify them.
regs.wb3_data = mmu030_data_buffer_out;
regs.wb2_address = mmu030_state[1];
write_log(_T("\n"));
#endif
+ ismoves030 = false;
+ islrmw030 = false;
+
#if 0
- if (addr == 0x00016060)
+ if (addr == 0xc1026ea0)
write_log("!");
#endif
#if 0
}
/* Locked RMW is rarely used */
-uae_u32 uae_mmu030_get_lrmw_fcx(uaecptr addr, int size, int fc)
+static uae_u32 uae_mmu030_get_lrmw_fcx(uaecptr addr, int size, int fc)
{
if (size == sz_byte) {
return mmu030_get_generic(addr, fc, size, MMU030_SSW_RM | MMU030_SSW_SIZE_B);
uae_u32 uae_mmu030_get_lrmw(uaecptr addr, int size)
{
uae_u32 fc = (regs.s ? 4 : 0) | 1;
- return uae_mmu030_get_lrmw_fcx(addr, size, fc);
+ islrmw030 = true;
+ uae_u32 v = uae_mmu030_get_lrmw_fcx(addr, size, fc);
+ islrmw030 = false;
+ return v;
}
-void uae_mmu030_put_lrmw_fcx(uaecptr addr, uae_u32 val, int size, int fc)
+static void uae_mmu030_put_lrmw_fcx(uaecptr addr, uae_u32 val, int size, int fc)
{
if (size == sz_byte) {
mmu030_put_generic(addr, val, fc, size, MMU030_SSW_RM | MMU030_SSW_SIZE_B);
void uae_mmu030_put_lrmw(uaecptr addr, uae_u32 val, int size)
{
uae_u32 fc = (regs.s ? 4 : 0) | 1;
+ islrmw030 = true;
uae_mmu030_put_lrmw_fcx(addr, val, size, fc);
+ islrmw030 = false;
}
uae_u32 REGPARAM2 mmu030_get_ilong_unaligned(uaecptr addr, uae_u32 fc, int flags)
mmu030_opcode_stageb = stageb;
write_log(_T("Software fixed stage B! opcode = %04x\n"), stageb);
} else {
- mmu030_ad_v[idxsize].val = stageb;
- idxsize_done = idxsize;
+ mmu030_ad_v[idxsize_done].val = stageb;
+ idxsize_done++;
write_log(_T("Software fixed stage B! opcode = %04X, opword = %04x\n"), mmu030_opcode_v, stageb);
}
}
write_log(_T("68030 MMU MOVEM %04x retry but MMU030_STATEFLAG1_MOVEM2 was already set!?\n"), mmu030_opcode);
}
}
- if (idxsize >= 0 && mmu030_ad[idxsize].done) {
- write_log(_T("68030 MMU ins %04x retry but it was already marked as done!?\n"), mmu030_opcode);
- }
#endif
#if MMU030_DEBUG
mmu030_ad_v[i].val = get_long_mmu030c(a7 + 0x5c - (i + 1) * 4);
}
+ regs.wb2_status = v >> 8;
+ regs.wb3_status = mmu030_state_2 >> 8;
+ mmu030fixupmod(regs.wb2_status, 1, -1);
+ mmu030fixupmod(regs.wb3_status, 1, -1);
+
// did we have data fault but DF bit cleared?
if (ssw & (MMU030_SSW_DF << 1) && !(ssw & MMU030_SSW_DF)) {
// DF not set: mark access as done
if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM2) {
write_log(_T("68030 MMU MOVEM %04x retry but MMU030_STATEFLAG1_MOVEM2 was already set!?\n"), mmu030_opcode);
}
- } else {
- if (idxsize >= 0 && mmu030_ad[idxsize].done) {
- write_log(_T("68030 MMU ins %04x retry but it was already marked as done!?\n"), mmu030_opcode);
- }
}
#endif
if (read) {
}
if (!using_mmu)
return false;
- if (using_mmu == 68040 && (mmufixupstate || mmufixupcnt > 0))
+ if (using_mmu == 68040 && (mmufixupstate || mmufixupcnt > 0)) {
return false;
+ }
+ if (using_mmu == 68030) {
+ switch (g_instr->mnemo)
+ {
+ case i_LINK:
+ case i_RTD:
+ case i_RTR:
+ return false;
+ }
+ }
return true;
}
extern uae_u32 mmu030_disp_store[2];
extern uae_u32 mmu030_fmovem_store[2];
extern uae_u8 mmu030_cache_state, mmu030_cache_state_default;
-extern bool ismoves030;
+extern bool ismoves030, islrmw030;
#define MMU030_STATEFLAG1_FMOVEM 0x2000
#define MMU030_STATEFLAG1_MOVEM1 0x4000
uae_u16 mmu030_get_iword(uaecptr addr, uae_u32 fc);
uae_u32 uae_mmu030_get_lrmw(uaecptr addr, int size);
-uae_u32 uae_mmu030_get_lrmw_fcx(uaecptr addr, int size, int fc);
void uae_mmu030_put_lrmw(uaecptr addr, uae_u32 val, int size);
-void uae_mmu030_put_lrmw_fcx(uaecptr addr, uae_u32 val, int size, int fc);
void mmu030_put_generic(uaecptr addr, uae_u32 val, uae_u32 fc, int size, int flags);
uae_u32 mmu030_get_generic(uaecptr addr, uae_u32 fc, int size, int flags);
}
STATIC_INLINE void put_lrmw_byte_mmu030c_state (uaecptr addr, uae_u32 v)
{
+ islrmw030 = true;
ACCESS_CHECK_PUT
write_dcache030_lrmw_mmu(addr, v, 0);
ACCESS_EXIT_PUT
+ islrmw030 = false;
}
STATIC_INLINE void put_word_mmu030c_state (uaecptr addr, uae_u32 v)
{
}
STATIC_INLINE void put_lrmw_word_mmu030c_state (uaecptr addr, uae_u32 v)
{
+ islrmw030 = true;
ACCESS_CHECK_PUT
write_dcache030_lrmw_mmu(addr, v, 1);
ACCESS_EXIT_PUT
+ islrmw030 = false;
}
STATIC_INLINE void put_long_mmu030c_state (uaecptr addr, uae_u32 v)
{
}
STATIC_INLINE void put_lrmw_long_mmu030c_state (uaecptr addr, uae_u32 v)
{
+ islrmw030 = true;
ACCESS_CHECK_PUT
write_dcache030_lrmw_mmu(addr, v, 2);
ACCESS_EXIT_PUT
+ islrmw030 = false;
}
STATIC_INLINE uae_u32 get_byte_mmu030c_state (uaecptr addr)
STATIC_INLINE uae_u32 get_lrmw_byte_mmu030c_state (uaecptr addr)
{
uae_u32 v;
+ islrmw030 = true;
ACCESS_CHECK_GET
v = read_dcache030_lrmw_mmu(addr, 0);
ACCESS_EXIT_GET
+ islrmw030 = false;
return v;
}
STATIC_INLINE uae_u32 get_lrmw_word_mmu030c_state (uaecptr addr)
{
uae_u32 v;
+ islrmw030 = true;
ACCESS_CHECK_GET
v = read_dcache030_lrmw_mmu(addr, 1);
ACCESS_EXIT_GET
+ islrmw030 = false;
return v;
}
STATIC_INLINE uae_u32 get_long_mmu030c_state (uaecptr addr)
STATIC_INLINE uae_u32 get_lrmw_long_mmu030c_state (uaecptr addr)
{
uae_u32 v;
+ islrmw030 = true;
ACCESS_CHECK_GET
v = read_dcache030_lrmw_mmu(addr, 2);
ACCESS_EXIT_GET
+ islrmw030 = false;
return v;
}
}
static uae_u32 (*icache_fetch)(uaecptr);
+static uae_u16 (*icache_fetch_word)(uaecptr);
static uae_u32 (*dcache_lget)(uaecptr);
static uae_u32 (*dcache_wget)(uaecptr);
static uae_u32 (*dcache_bget)(uaecptr);
dcache_check = dcache_check_nommu;
icache_fetch = get_longi;
+ icache_fetch_word = NULL;
if (currprefs.cpu_cycle_exact) {
icache_fetch = mem_access_delay_longi_read_ce020;
}
if (currprefs.mmu_model) {
if (currprefs.cpu_compatible) {
icache_fetch = uae_mmu030_get_ilong_fc;
+ icache_fetch_word = uae_mmu030_get_iword_fc;
} else {
icache_fetch = uae_mmu030_get_ilong;
+ icache_fetch_word = uae_mmu030_get_iword_fc;
}
dcache_lput = uae_mmu030_put_long_fc;
dcache_wput = uae_mmu030_put_word_fc;
c->data[lws] = val;
}
-static void fill_icache030 (uae_u32 addr)
+static bool maybe_icache030(uae_u32 addr)
+{
+ int lws;
+ uae_u32 tag;
+ uae_u32 data;
+ struct cache030 *c;
+
+ regs.fc030 = (regs.s ? 4 : 0) | 2;
+ addr &= ~3;
+ if (regs.cacheholdingaddr020 == addr || regs.cacheholdingdata_valid == 0)
+ return true;
+ c = geticache030(icaches030, addr, &tag, &lws);
+ if ((regs.cacr & 1) && c->valid[lws] && c->tag == tag) {
+ // cache hit
+ regs.cacheholdingaddr020 = addr;
+ regs.cacheholdingdata020 = c->data[lws];
+ return true;
+ }
+ return false;
+}
+
+static void fill_icache030(uae_u32 addr)
{
int lws;
uae_u32 tag;
regs.prefetch020_valid[1] = regs.prefetch020_valid[2];
regs.prefetch020_valid[2] = false;
if (!regs.prefetch020_valid[1]) {
+ if (regs.pipeline_stop) {
+ regs.db = regs.prefetch020[0];
+ return v;
+ }
do_access_or_bus_error(0xffffffff, pc + 4);
}
#if MORE_ACCURATE_68020_PIPELINE
regs.cacheholdingdata_valid = 1;
regs.cacheholdingaddr020 = 0xffffffff;
- for (int i = 2; i >= 0; i--) {
- if (!regs.prefetch020_valid[i])
- break;
+ if (regs.prefetch020_valid[0] && regs.prefetch020_valid[1] && regs.prefetch020_valid[2]) {
+ for (int i = 2; i >= 0; i--) {
+ regs.prefetch020[i + 1] = regs.prefetch020[i];
+ }
+ for (int i = 1; i <= 3; i++) {
+#if MORE_ACCURATE_68020_PIPELINE
+ pipeline_020(pc);
+#endif
+ regs.prefetch020[i - 1] = regs.prefetch020[i];
+ pc += 2;
+ idx++;
+ }
+ } else if (regs.prefetch020_valid[2] && !regs.prefetch020_valid[1]) {
+ regs.prefetch020_valid[1] = regs.prefetch020_valid[2];
+ regs.prefetch020[1] = regs.prefetch020[2];
+ regs.prefetch020_valid[2] = 0;
+ pc += 2;
+ idx++;
+#if MORE_ACCURATE_68020_PIPELINE
+ pipeline_020(pc);
+#endif
+ if (!regs.pipeline_stop) {
+ if (maybe_icache030(pc)) {
+ regs.prefetch020[2] = regs.cacheholdingdata020 >> (regs.cacheholdingaddr020 == pc ? 16 : 0);
+ } else {
+ regs.prefetch020[2] = icache_fetch_word(pc);
+ }
+ regs.prefetch020_valid[2] = 1;
+ pc += 2;
+ idx++;
#if MORE_ACCURATE_68020_PIPELINE
- if (idx >= 1) {
pipeline_020(pc);
+#endif
}
+
+ } else if (regs.prefetch020_valid[2] && regs.prefetch020_valid[1]) {
+ pc += 2;
+#if MORE_ACCURATE_68020_PIPELINE
+ pipeline_020(pc);
#endif
pc += 2;
+#if MORE_ACCURATE_68020_PIPELINE
+ pipeline_020(pc);
+#endif
+ idx += 2;
+ }
+
+ while (idx < 2) {
+ regs.prefetch020[0] = regs.prefetch020[1];
+ regs.prefetch020[1] = regs.prefetch020[2];
+ regs.prefetch020_valid[0] = regs.prefetch020_valid[1];
+ regs.prefetch020_valid[1] = regs.prefetch020_valid[2];
+ regs.prefetch020_valid[2] = false;
idx++;
}
ipl_fetch();
if (currprefs.cpu_cycle_exact)
- regs.irc = get_word_ce030_prefetch_opcode (0);
+ regs.irc = get_word_ce030_prefetch_opcode(0);
else
- regs.irc = get_word_030_prefetch (0);
+ regs.irc = get_word_030_prefetch(0);
}
void fill_prefetch_020_ntx(void)