#include "options.h"
#include "memory.h"
#include "newcpu.h"
+#include "debug.h"
#include "cpummu030.h"
#define MMU030_OP_DBG_MSG 0
uae_u32 mmu030_data_buffer;
uae_u32 mmu030_disp_store[2];
uae_u32 mmu030_fmovem_store[2];
+int mmu030_cache_inhibit;
struct mmu030_access mmu030_ad[MAX_MMU030_ACCESS];
#if MMU_DPAGECACHE030
/* for debugging messages */
char table_letter[4] = {'A','B','C','D'};
+static const uae_u32 mmu030_size[3] = { MMU030_SSW_SIZE_B, MMU030_SSW_SIZE_W, MMU030_SSW_SIZE_L };
+
uae_u64 srp_030, crp_030;
uae_u32 tt0_030, tt1_030, tc_030;
uae_u16 mmusr_030;
uae_u16 status;
#if MMU_IPAGECACHE030
+ int mmu030_cache_inhibit;
#if MMU_DIRECT_ACCESS
uae_u8 *mmu030_last_physical_address_real;
#else
#if MMU030_OP_DBG_MSG
switch (preg) {
case 0x10:
- write_log(_T("PMOVE: %s TC %08X\n"), rw?"read":"write",
- rw?tc_030:x_get_long(extra));
+ write_log(_T("PMOVE: %s TC %08X\n"), rw ? _T("read"): _T("write"),
+ rw ? tc_030 : x_get_long(extra));
break;
case 0x12:
- write_log(_T("PMOVE: %s SRP %08X%08X\n"), rw?"read":"write",
+ write_log(_T("PMOVE: %s SRP %08X%08X\n"), rw ? _T("read") : _T("write"),
rw?(uae_u32)(srp_030>>32)&0xFFFFFFFF:x_get_long(extra),
rw?(uae_u32)srp_030&0xFFFFFFFF:x_get_long(extra+4));
break;
case 0x13:
- write_log(_T("PMOVE: %s CRP %08X%08X\n"), rw?"read":"write",
+ write_log(_T("PMOVE: %s CRP %08X%08X\n"), rw ? _T("read") : _T("write"),
rw?(uae_u32)(crp_030>>32)&0xFFFFFFFF:x_get_long(extra),
rw?(uae_u32)crp_030&0xFFFFFFFF:x_get_long(extra+4));
break;
case 0x18:
- write_log(_T("PMOVE: %s MMUSR %04X\n"), rw?"read":"write",
+ write_log(_T("PMOVE: %s MMUSR %04X\n"), rw ? _T("read") : _T("write"),
rw?mmusr_030:x_get_word(extra));
break;
case 0x02:
- write_log(_T("PMOVE: %s TT0 %08X\n"), rw?"read":"write",
+ write_log(_T("PMOVE: %s TT0 %08X\n"), rw ? _T("read") : _T("write"),
rw?tt0_030:x_get_long(extra));
break;
case 0x03:
- write_log(_T("PMOVE: %s TT1 %08X\n"), rw?"read":"write",
+ write_log(_T("PMOVE: %s TT1 %08X\n"), rw ? _T("read") : _T("write"),
rw?tt1_030:x_get_long(extra));
break;
default:
static int mmu030_do_match_ttr(uae_u32 tt, TT_info comp, uaecptr addr, uae_u32 fc, bool write)
{
if (tt & TT_ENABLE) { /* transparent translation enabled */
-
+
/* Compare actual function code with function code base using mask */
if ((comp.fc_base&comp.fc_mask)==(fc&comp.fc_mask)) {
-
+
/* Compare actual address with address base using mask */
if ((comp.addr_base&comp.addr_mask)==(addr&comp.addr_mask)) {
-
if (tt&TT_RWM) { /* r/w field disabled */
return TT_OK_MATCH;
} else {
static int mmu030_do_match_lrmw_ttr(uae_u32 tt, TT_info comp, uaecptr addr, uae_u32 fc)
{
if ((tt & TT_ENABLE) && (tt & TT_RWM)) { /* transparent translation enabled */
-
+
/* Compare actual function code with function code base using mask */
if ((comp.fc_base&comp.fc_mask)==(fc&comp.fc_mask)) {
-
+
/* Compare actual address with address base using mask */
if ((comp.addr_base&comp.addr_mask)==(addr&comp.addr_mask)) {
-
return TT_OK_MATCH;
}
}
{
int tt0, tt1;
- bool cache_inhibit = false; /* TODO: pass to memory access function */
-
tt0 = mmu030_do_match_ttr(tt0_030, mmu030.transparent.tt0, addr, fc, write);
if (tt0&TT_OK_MATCH) {
- cache_inhibit = (tt0_030&TT_CI) ? true : false;
- }
+ if (tt0_030&TT_CI)
+ mmu030_cache_inhibit = 1;
+ }
tt1 = mmu030_do_match_ttr(tt1_030, mmu030.transparent.tt1, addr, fc, write);
if (tt1&TT_OK_MATCH) {
- if (!cache_inhibit) {
- cache_inhibit = (tt1_030&TT_CI) ? true : false;
- }
+ if (tt0_030&TT_CI)
+ mmu030_cache_inhibit = 1;
}
return (tt0|tt1);
static void mmu030_do_fake_prefetch(void)
{
+ if (currprefs.cpu_compatible)
+ return;
// fetch next opcode before MMU state switches.
// There are programs that do following:
// - enable MMU
#define ATC030_PHYS_CI 0x04000000
#define ATC030_PHYS_BE 0x08000000
-void mmu030_page_fault(uaecptr addr, bool read, int flags, uae_u32 fc) {
+void mmu030_page_fault(uaecptr addr, bool read, int flags, uae_u32 fc)
+{
+ if (flags < 0) {
+ read = (regs.mmu_ssw & MMU030_SSW_RW) ? 1 : 0;
+ fc = regs.mmu_ssw & 7;
+ flags = regs.mmu_ssw & ~(MMU030_SSW_FC | MMU030_SSW_RC | MMU030_SSW_FB | MMU030_SSW_RB | MMU030_SSW_RW | 7);
+ }
regs.mmu_fault_addr = addr;
- regs.mmu_ssw = (fc & 1) ? MMU030_SSW_DF | (MMU030_SSW_DF << 1) : (MMU030_SSW_FB | MMU030_SSW_RB);
+ if (fc & 1) {
+ regs.mmu_ssw = MMU030_SSW_DF | (MMU030_SSW_DF << 1);
+ } else {
+ if (currprefs.cpu_compatible) {
+ 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 = MMU030_SSW_FB | MMU030_SSW_RB;
+ } else {
+ write_log(_T("mmu030_page_fault without invalid prefetch!\n"));
+ }
+ } else {
+ regs.mmu_ssw = MMU030_SSW_FB | MMU030_SSW_RB;
+ }
+ }
regs.mmu_ssw |= read ? MMU030_SSW_RW : 0;
regs.mmu_ssw |= flags;
regs.mmu_ssw |= fc;
addr, regs.mmu_ssw, read, (flags & MMU030_SSW_SIZE_B) ? 1 : (flags & MMU030_SSW_SIZE_W) ? 2 : 4, fc,
regs.instruction_pc, (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) ? mmu030_data_buffer : mmu030_ad[mmu030_idx].val, mmu030_opcode & 0xffff);
#endif
-
-// extern void activate_debugger(void);
-// activate_debugger ();
THROW(2);
}
l, physical_addr, page_index);
#endif
- if (mmu030.atc[l].physical.bus_error || mmu030.atc[l].physical.write_protect) {
+ if (mmu030.atc[l].physical.bus_error || mmu030.atc[l].physical.write_protect) {
mmu030_page_fault(addr, false, MMU030_SSW_SIZE_B, fc);
return 0;
}
- mmu030_add_data_write_cache(addr, physical_addr, fc);
+ mmu030_cache_inhibit = mmu030.atc[l].physical.cache_inhibit;
+
+ mmu030_add_data_write_cache(addr, physical_addr, fc);
return physical_addr + page_index;
}
physical_addr, page_index);
#endif
- if (mmu030.atc[l].physical.bus_error) {
+ if (mmu030.atc[l].physical.bus_error) {
mmu030_page_fault(addr, true, size, fc);
return 0;
}
+ mmu030_cache_inhibit = mmu030.atc[l].physical.cache_inhibit;
+
mmu030_add_data_read_cache(addr, physical_addr, fc);
return physical_addr + page_index;
}
#if MMU_IPAGECACHE030
+ mmu030.mmu030_cache_inhibit = mmu030.atc[l].physical.cache_inhibit;
#if MMU_DIRECT_ACCESS
mmu030.mmu030_last_physical_address_real = get_real_address(physical_addr);
#else
mmu030.mmu030_last_logical_address = (addr & mmu030.translation.page.imask) | fc;
#endif
+ mmu030_cache_inhibit = mmu030.atc[l].physical.cache_inhibit;
+
return physical_addr + page_index;
}
uae_u32 physical_addr = mmu030.atc[l].physical.addr & addr_mask;
#if MMU030_ATC_DBG_MSG
- write_log(_T("ATC match(%i): page addr = %08X, index = %08X (bput %02X)\n"),
- l, physical_addr, page_index, val);
+ write_log(_T("ATC match(%i): page addr = %08X, index = %08X\n"),
+ l, physical_addr, page_index);
#endif
if (mmu030.atc[l].physical.write_protect || mmu030.atc[l].physical.bus_error) {
* create a new ATC entry and then look up the physical address.
*/
+STATIC_INLINE void cacheablecheck(uaecptr addr)
+{
+ if (!ce_cachable[addr >> 16] && !mmu030_cache_inhibit)
+ mmu030_cache_inhibit = -1; // CIN active
+}
+
void mmu030_put_long(uaecptr addr, uae_u32 val, uae_u32 fc)
{
- if (((fc != 7) || (!tt_enabled || !mmu030_match_ttr_access(addr,fc,true))) && (mmu030.enabled)) {
+ mmu030_cache_inhibit = 0;
+ if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,true)) && mmu030.enabled) {
#if MMU_DPAGECACHE030
uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >> mmu030.translation.page.size3m) | fc;
uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES030 - 1);
}
}
}
+ cacheablecheck(addr);
x_phys_put_long(addr,val);
}
void mmu030_put_word(uaecptr addr, uae_u16 val, uae_u32 fc)
{
- if (((fc != 7) || (!tt_enabled || !mmu030_match_ttr_access(addr,fc,true))) && (mmu030.enabled)) {
+ mmu030_cache_inhibit = 0;
+ if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,true)) && mmu030.enabled) {
#if MMU_DPAGECACHE030
uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >> mmu030.translation.page.size3m) | fc;
uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES030 - 1);
}
}
}
+ cacheablecheck(addr);
x_phys_put_word(addr,val);
}
void mmu030_put_byte(uaecptr addr, uae_u8 val, uae_u32 fc)
{
- if (((fc != 7) || (!tt_enabled || !mmu030_match_ttr_access(addr,fc,true))) && (mmu030.enabled)) {
+ mmu030_cache_inhibit = 0;
+ if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,true)) && mmu030.enabled) {
#if MMU_DPAGECACHE030
uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >> mmu030.translation.page.size3m) | fc;
uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES030 - 1);
}
}
}
+ cacheablecheck(addr);
x_phys_put_byte(addr,val);
}
uae_u32 mmu030_get_long(uaecptr addr, uae_u32 fc)
{
- if (((fc != 7) || (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false))) && (mmu030.enabled)) {
+ mmu030_cache_inhibit = 0;
+ if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false)) && mmu030.enabled) {
#if MMU_DPAGECACHE030
uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >> mmu030.translation.page.size3m) | fc;
uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES030 - 1);
}
}
}
+ cacheablecheck(addr);
return x_phys_get_long(addr);
}
uae_u16 mmu030_get_word(uaecptr addr, uae_u32 fc)
{
- if (((fc != 7) || (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false))) && (mmu030.enabled)) {
+ mmu030_cache_inhibit = 0;
+ if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false)) && mmu030.enabled) {
#if MMU_DPAGECACHE030
uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >> mmu030.translation.page.size3m) | fc;
uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES030 - 1);
}
}
}
+ cacheablecheck(addr);
return x_phys_get_word(addr);
}
uae_u8 mmu030_get_byte(uaecptr addr, uae_u32 fc)
{
- if (((fc != 7) || (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false))) && (mmu030.enabled)) {
+ mmu030_cache_inhibit = 0;
+ if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false)) && mmu030.enabled) {
#if MMU_DPAGECACHE030
uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >> mmu030.translation.page.size3m) | fc;
uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES030 - 1);
}
}
}
+ cacheablecheck(addr);
return x_phys_get_byte(addr);
}
uae_u8 *p = &mmu030.mmu030_last_physical_address_real[addr & mmu030.translation.page.mask];
return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]);
#else
+ mmu030_cache_inhibit = mmu030.mmu030_cache_inhibit;
return x_phys_get_ilong(mmu030.mmu030_last_physical_address + (addr & mmu030.translation.page.mask));
#endif
}
mmu030.mmu030_last_logical_address = 0xffffffff;
#endif
- if (((fc != 7) || (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false))) && (mmu030.enabled)) {
+ mmu030_cache_inhibit = 0;
+ if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false)) && mmu030.enabled) {
int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
if (atc_line_num >= 0) {
addr = mmu030_get_i_atc(addr, atc_line_num, fc, MMU030_SSW_SIZE_L);
uae_u8 *p = &mmu030.mmu030_last_physical_address_real[addr & mmu030.translation.page.mask];
return (p[0] << 8) | p[1];
#else
+ mmu030_cache_inhibit = mmu030.mmu030_cache_inhibit;
return x_phys_get_iword(mmu030.mmu030_last_physical_address + (addr & mmu030.translation.page.mask));
#endif
}
mmu030.mmu030_last_logical_address = 0xffffffff;
#endif
- if (((fc != 7) || (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false))) && (mmu030.enabled)) {
+ mmu030_cache_inhibit = 0;
+ if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false)) && mmu030.enabled) {
int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
if (atc_line_num >= 0) {
addr = mmu030_get_i_atc(addr, atc_line_num, fc, MMU030_SSW_SIZE_W);
/* Not commonly used access function */
void mmu030_put_generic(uaecptr addr, uae_u32 val, uae_u32 fc, int size, int flags)
{
- if (((fc != 7) || (!tt_enabled || !mmu030_match_ttr_access(addr,fc,true))) && (mmu030.enabled)) {
+ mmu030_cache_inhibit = 0;
+ if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,true)) && mmu030.enabled) {
int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
if (atc_line_num>=0) {
addr = mmu030_put_atc_generic(addr, atc_line_num, fc, flags);
}
}
+ cacheablecheck(addr);
if (size == sz_byte)
x_phys_put_byte(addr, val);
else if (size == sz_word)
static uae_u32 mmu030_get_generic_lrmw(uaecptr addr, uae_u32 fc, int size, int flags)
{
- if (((fc != 7) || (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false))) && (mmu030.enabled)) {
+ mmu030_cache_inhibit = 0;
+ if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false)) && mmu030.enabled) {
int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
if (atc_line_num>=0) {
addr = mmu030_get_atc_generic(addr, atc_line_num, fc, flags, true);
}
}
+ cacheablecheck(addr);
if (size == sz_byte)
return x_phys_get_byte(addr);
else if (size == sz_word)
uae_u32 mmu030_get_generic(uaecptr addr, uae_u32 fc, int size, int flags)
{
+ mmu030_cache_inhibit = 0;
+
if (flags & MMU030_SSW_RM) {
return mmu030_get_generic_lrmw(addr, fc, size, flags);
}
- if (((fc != 7) || (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false))) && (mmu030.enabled)) {
+ if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false)) && mmu030.enabled) {
int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
if (atc_line_num>=0) {
addr = mmu030_get_atc_generic(addr, atc_line_num, fc, flags, false);
}
}
+ cacheablecheck(addr);
if (size == sz_byte)
return x_phys_get_byte(addr);
else if (size == sz_word)
return x_phys_get_long(addr);
}
+bool uae_mmu030_check_fc(uaecptr addr, bool write, uae_u32 size)
+{
+ uae_u32 fc = regs.fc030;
+ if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,write)) && mmu030.enabled) {
+ uae_u32 flags = mmu030_size[size];
+ int atc_line_num = mmu030_logical_is_in_atc(addr, fc, write);
+ if (atc_line_num>=0) {
+ addr = mmu030_get_atc_generic(addr, atc_line_num, fc, flags, write);
+ } else {
+ mmu030_table_search(addr, fc, write, 0);
+ atc_line_num = mmu030_logical_is_in_atc(addr, fc, write);
+ addr = mmu030_get_atc_generic(addr, atc_line_num, fc, flags, false);
+ }
+ }
+ cacheablecheck(addr);
+ return mmu030_cache_inhibit == 0;
+}
/* Locked RMW is rarely used */
uae_u32 uae_mmu030_get_lrmw(uaecptr addr, int size)
static uae_u32 get_dcache_byte(uaecptr addr)
{
- return read_dcache030(addr, 0);
+ return read_dcache030(addr, 0, (regs.s ? 4 : 0) | 1);
}
static uae_u32 get_dcache_word(uaecptr addr)
{
- return read_dcache030(addr, 1);
+ return read_dcache030(addr, 1, (regs.s ? 4 : 0) | 1);
}
static uae_u32 get_dcache_long(uaecptr addr)
{
- return read_dcache030(addr, 2);
+ return read_dcache030(addr, 2, (regs.s ? 4 : 0) | 1);
}
static void put_dcache_byte(uaecptr addr, uae_u32 v)
{
- write_dcache030(addr, v, 0);
+ write_dcache030(addr, v, 0, (regs.s ? 4 : 0) | 1);
}
static void put_dcache_word(uaecptr addr, uae_u32 v)
{
- write_dcache030(addr, v, 1);
+ write_dcache030(addr, v, 1, (regs.s ? 4 : 0) | 1);
}
static void put_dcache_long(uaecptr addr, uae_u32 v)
{
- write_dcache030(addr, v, 2);
+ write_dcache030(addr, v, 2, (regs.s ? 4 : 0) | 1);
}
/* MMU Reset */
{
if (currprefs.mmu_model != 68030)
return;
- if (currprefs.cpu_memory_cycle_exact || currprefs.cpu_compatible) {
- x_phys_get_iword = get_word_icache030;
- x_phys_get_ilong = get_long_icache030;
- x_phys_get_byte = get_dcache_byte;
- x_phys_get_word = get_dcache_word;
- x_phys_get_long = get_dcache_long;
- x_phys_put_byte = put_dcache_byte;
- x_phys_put_word = put_dcache_word;
- x_phys_put_long = put_dcache_long;
+ if (currprefs.cpu_memory_cycle_exact) {
+ x_phys_get_iword = mem_access_delay_wordi_read_ce020;
+ x_phys_get_ilong = mem_access_delay_longi_read_ce020;
+ x_phys_get_byte = mem_access_delay_byte_read_ce020;
+ x_phys_get_word = mem_access_delay_word_read_ce020;
+ x_phys_get_long = mem_access_delay_long_read_ce020;
+ x_phys_put_byte = mem_access_delay_byte_write_ce020;
+ x_phys_put_word = mem_access_delay_word_write_ce020;
+ x_phys_put_long = mem_access_delay_long_write_ce020;
} else {
x_phys_get_iword = phys_get_word;
x_phys_get_ilong = phys_get_long;
else
get_word_mmu030(a7 + 32 - 2);
+ // Internal register, misc flags
+ uae_u32 ps = get_long_mmu030c(a7 + 0x28);
// Internal register, our opcode storage area
- mmu030_opcode = get_long_mmu030 (a7 + 0x14);
+ uae_u32 oc = get_long_mmu030c (a7 + 0x14);
+ mmu030_opcode = (ps & 0x80000000) ? -1 : (oc & 0xffff);
// Misc state data
mmu030_state[0] = get_word_mmu030 (a7 + 0x30);
mmu030_state[1] = get_word_mmu030 (a7 + 0x32);
return v;
}
+
+// cache
+
+void m68k_do_rts_mmu030c (void)
+{
+ m68k_setpc (get_long_mmu030c_state (m68k_areg (regs, 7)));
+ m68k_areg (regs, 7) += 4;
+}
+
+void m68k_do_bsr_mmu030c (uaecptr oldpc, uae_s32 offset)
+{
+ put_long_mmu030c_state (m68k_areg (regs, 7) - 4, oldpc);
+ m68k_areg (regs, 7) -= 4;
+ m68k_incpci (offset);
+}
+
+
+uae_u32 REGPARAM2 get_disp_ea_020_mmu030c (uae_u32 base, int idx)
+{
+ uae_u16 dp;
+ int reg;
+ uae_u32 v;
+ int oldidx;
+ int pcadd = 0;
+
+ // we need to do this hack here because in worst case we don't have enough
+ // stack frame space to store two very large 020 addressing mode access state
+ // + whatever the instruction itself does.
+
+ if (mmu030_state[1] & (1 << idx)) {
+ m68k_incpci (((mmu030_state[2] >> (idx * 4)) & 15) * 2);
+ return mmu030_disp_store[idx];
+ }
+
+ oldidx = mmu030_idx;
+ dp = next_iword_mmu030c_state ();
+ pcadd += 1;
+
+ reg = (dp >> 12) & 15;
+ uae_s32 regd = regs.regs[reg];
+ if ((dp & 0x800) == 0)
+ regd = (uae_s32)(uae_s16)regd;
+ regd <<= (dp >> 9) & 3;
+ if (dp & 0x100) {
+ uae_s32 outer = 0;
+ if (dp & 0x80)
+ base = 0;
+ if (dp & 0x40)
+ regd = 0;
+
+ if ((dp & 0x30) == 0x20) {
+ base += (uae_s32)(uae_s16) next_iword_mmu030c_state ();
+ pcadd += 1;
+ }
+ if ((dp & 0x30) == 0x30) {
+ base += next_ilong_mmu030c_state ();
+ pcadd += 2;
+ }
+
+ if ((dp & 0x3) == 0x2) {
+ outer = (uae_s32)(uae_s16) next_iword_mmu030c_state ();
+ pcadd += 1;
+ }
+ if ((dp & 0x3) == 0x3) {
+ outer = next_ilong_mmu030c_state ();
+ pcadd += 2;
+ }
+
+ if ((dp & 0x4) == 0) {
+ base += regd;
+ }
+ if (dp & 0x3) {
+ base = get_long_mmu030c_state (base);
+ }
+ if (dp & 0x4) {
+ base += regd;
+ }
+ v = base + outer;
+ } else {
+ v = base + (uae_s32)((uae_s8)dp) + regd;
+ }
+
+ mmu030_state[1] |= 1 << idx;
+ mmu030_state[2] |= pcadd << (idx * 4);
+ mmu030_disp_store[idx] = v;
+ mmu030_idx = oldidx;
+ mmu030_ad[mmu030_idx].done = false;
+
+ return v;
+}
+
+void m68k_do_rte_mmu030c (uaecptr a7)
+{
+ // Restore access error exception state
+
+ uae_u16 format = get_word_mmu030c (a7 + 6);
+ uae_u16 frame = format >> 12;
+ uae_u16 ssw = get_word_mmu030c (a7 + 10);
+ uae_u16 sr = get_word_mmu030c (a7);
+ uae_u32 pc = get_long_mmu030c (a7 + 2);
+
+ // Fetch last word, real CPU does it to allow OS bus handler to map
+ // the page if frame crosses pages and following page is not resident.
+ if (frame == 0xb)
+ get_word_mmu030c(a7 + 92 - 2);
+ else
+ get_word_mmu030c(a7 + 32 - 2);
+
+ // Internal register, misc flags
+ uae_u32 ps = get_long_mmu030c(a7 + 0x28);
+ // Internal register, our opcode storage area
+ uae_u32 oc = get_long_mmu030c (a7 + 0x14);
+ mmu030_opcode = (ps & 0x80000000) ? -1 : (oc & 0xffff);
+ // Misc state data
+ mmu030_state[0] = get_word_mmu030c (a7 + 0x30);
+ mmu030_state[1] = get_word_mmu030c (a7 + 0x32);
+ mmu030_state[2] = get_word_mmu030c (a7 + 0x34);
+ mmu030_disp_store[0] = get_long_mmu030c (a7 + 0x1c);
+ mmu030_disp_store[1] = get_long_mmu030c (a7 + 0x1c + 4);
+ if (mmu030_state[1] & MMU030_STATEFLAG1_FMOVEM) {
+ mmu030_fmovem_store[0] = get_long_mmu030c (a7 + 0x5c - (7 + 1) * 4);
+ mmu030_fmovem_store[1] = get_long_mmu030c (a7 + 0x5c - (8 + 1) * 4);
+ }
+ // Rerun "mmu030_opcode" using restored state.
+ mmu030_retry = true;
+
+ if (frame == 0xb) {
+ uae_u16 idxsize = get_word_mmu030c(a7 + 0x36);
+ for (int i = 0; i < idxsize + 1; i++) {
+ mmu030_ad[i].done = i < idxsize;
+ mmu030_ad[i].val = get_long_mmu030c(a7 + 0x5c - (i + 1) * 4);
+ }
+ mmu030_ad[idxsize + 1].done = false;
+ // 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 (ssw & MMU030_SSW_RM) {
+ // Read-Modify-Write: whole instruction is considered done
+ write_log (_T("Read-Modify-Write and DF bit cleared! PC=%08x\n"), regs.instruction_pc);
+ mmu030_retry = false;
+ } else if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) {
+ // if movem, skip next move
+ mmu030_data_buffer = get_long_mmu030c(a7 + 0x2c);
+ mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM2;
+ } else {
+ mmu030_ad[idxsize].done = true;
+ if (ssw & MMU030_SSW_RW) {
+ // Read and no DF: use value in data input buffer
+ mmu030_data_buffer = get_long_mmu030c(a7 + 0x2c);
+ mmu030_ad[idxsize].val = mmu030_data_buffer;
+ }
+ }
+ }
+
+ regs.prefetch020_valid[0] = (ps & 1) ? 1 : 0;
+ regs.prefetch020_valid[1] = (ps & 2) ? 1 : 0;
+ regs.prefetch020_valid[2] = (ps & 4) ? 1 : 0;
+ regs.pipeline_r8[0] = (ps >> 8) & 7;
+ regs.pipeline_r8[1] = (ps >> 11) & 7;
+ regs.pipeline_pos = (ps >> 16) & 15;
+ regs.pipeline_stop = ((ps >> 20) & 15) == 15 ? -1 : (ps >> 20) & 15;
+
+ uae_u32 stagesbc = get_long_mmu030c(a7 + 0x0c);
+ regs.prefetch020[2] = stagesbc;
+ regs.prefetch020[1] = stagesbc >> 16;
+ regs.prefetch020[0] = oc >> 16;
+
+ if ((ssw & MMU030_SSW_FB) && !(ssw & MMU030_SSW_RB)) {
+ regs.prefetch020_valid[2] = 1;
+ write_log (_T("Software fixed stage B! opcode = %04x\n"), regs.prefetch020[2]);
+ }
+ if ((ssw & MMU030_SSW_FC) && !(ssw & MMU030_SSW_RC)) {
+ regs.prefetch020_valid[1] = 1;
+ write_log (_T("Software fixed stage C! opcode = %04x\n"), regs.prefetch020[1]);
+ }
+
+ m68k_areg (regs, 7) += 92;
+
+ regs.sr = sr;
+ MakeFromSR_T0();
+ if (pc & 1) {
+ exception3i (0x4E73, pc);
+ return;
+ }
+ m68k_setpci (pc);
+
+ if (!(ssw & (MMU030_SSW_DF << 1))) {
+ if (!regs.prefetch020_valid[0] && regs.prefetch020_valid[2]) {
+ // Prefetch was software fixed, continue pipeline refill
+ fill_prefetch_030_ntx_continue();
+ } else if (regs.prefetch020_valid[0] && regs.prefetch020_valid[1]) {
+ // Finished?
+ fill_prefetch_030_ntx_continue();
+ } else if (mmu030_opcode == -1) {
+ // Previous branch instruction finished successfully but its pipeline refill
+ // step caused the exception, retry the refill, do not retry branch instruction.
+ fill_prefetch_030_ntx();
+ }
+ }
+
+ } else {
+ m68k_areg (regs, 7) += 32;
+ }
+}
extern uae_u32 mmu030_data_buffer;
extern uae_u32 mmu030_disp_store[2];
extern uae_u32 mmu030_fmovem_store[2];
+extern int mmu030_cache_inhibit;
#define MMU030_STATEFLAG1_FMOVEM 0x2000
#define MMU030_STATEFLAG1_MOVEM1 0x4000
};
extern struct mmu030_access mmu030_ad[MAX_MMU030_ACCESS];
-uae_u32 REGPARAM3 get_disp_ea_020_mmu030 (uae_u32 base, int idx) REGPARAM;
void mmu030_page_fault(uaecptr addr, bool read, int flags, uae_u32 fc);
bool mmu_op30_pmove (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra);
return mmu030_get_long_unaligned(addr, fc, 0);
return mmu030_get_long(addr, fc);
}
-static ALWAYS_INLINE uae_u16 uae_mmu030_get_word(uaecptr addr)
+static ALWAYS_INLINE uae_u32 uae_mmu030_get_word(uaecptr addr)
{
uae_u32 fc = (regs.s ? 4 : 0) | 1;
return mmu030_get_word_unaligned(addr, fc, 0);
return mmu030_get_word(addr, fc);
}
-static ALWAYS_INLINE uae_u8 uae_mmu030_get_byte(uaecptr addr)
+static ALWAYS_INLINE uae_u32 uae_mmu030_get_byte(uaecptr addr)
{
uae_u32 fc = (regs.s ? 4 : 0) | 1;
else
mmu030_put_long(addr, val, fc);
}
-static ALWAYS_INLINE void uae_mmu030_put_word(uaecptr addr, uae_u16 val)
+static ALWAYS_INLINE void uae_mmu030_put_word(uaecptr addr, uae_u32 val)
{
uae_u32 fc = (regs.s ? 4 : 0) | 1;
else
mmu030_put_word(addr, val, fc);
}
-static ALWAYS_INLINE void uae_mmu030_put_byte(uaecptr addr, uae_u8 val)
+static ALWAYS_INLINE void uae_mmu030_put_byte(uaecptr addr, uae_u32 val)
{
uae_u32 fc = (regs.s ? 4 : 0) | 1;
mmu030_put_byte(addr, val, fc);
}
+static ALWAYS_INLINE uae_u32 uae_mmu030_get_ilong_fc(uaecptr addr)
+{
+ if (unlikely(is_unaligned(addr, 4)))
+ return mmu030_get_ilong_unaligned(addr, regs.fc030, 0);
+ return mmu030_get_ilong(addr, regs.fc030);
+}
+static ALWAYS_INLINE uae_u16 uae_mmu030_get_iword_fc(uaecptr addr)
+{
+ return mmu030_get_iword(addr, regs.fc030);
+}
+static ALWAYS_INLINE uae_u16 uae_mmu030_get_ibyte_fc(uaecptr addr)
+{
+ return mmu030_get_byte(addr, regs.fc030);
+}
+static ALWAYS_INLINE uae_u32 uae_mmu030_get_long_fc(uaecptr addr)
+{
+ if (unlikely(is_unaligned(addr, 4)))
+ return mmu030_get_long_unaligned(addr, regs.fc030, 0);
+ return mmu030_get_long(addr, regs.fc030);
+}
+static ALWAYS_INLINE uae_u32 uae_mmu030_get_word_fc(uaecptr addr)
+{
+ if (unlikely(is_unaligned(addr, 2)))
+ return mmu030_get_word_unaligned(addr, regs.fc030, 0);
+ return mmu030_get_word(addr, regs.fc030);
+}
+static ALWAYS_INLINE uae_u32 uae_mmu030_get_byte_fc(uaecptr addr)
+{
+ return mmu030_get_byte(addr, regs.fc030);
+}
+static ALWAYS_INLINE void uae_mmu030_put_long_fc(uaecptr addr, uae_u32 val)
+{
+ if (unlikely(is_unaligned(addr, 4)))
+ mmu030_put_long_unaligned(addr, val, regs.fc030, 0);
+ else
+ mmu030_put_long(addr, val, regs.fc030);
+}
+static ALWAYS_INLINE void uae_mmu030_put_word_fc(uaecptr addr, uae_u32 val)
+{
+ if (unlikely(is_unaligned(addr, 2)))
+ mmu030_put_word_unaligned(addr, val, regs.fc030, 0);
+ else
+ mmu030_put_word(addr, val, regs.fc030);
+}
+static ALWAYS_INLINE void uae_mmu030_put_byte_fc(uaecptr addr, uae_u32 val)
+{
+ mmu030_put_byte(addr, val, regs.fc030);
+}
+bool uae_mmu030_check_fc(uaecptr addr, bool write, uae_u32 size);
+
+#define ACCESS_CHECK_PUT \
+ if (!mmu030_ad[mmu030_idx].done) { \
+ mmu030_ad[mmu030_idx].val = v; \
+ } else if (mmu030_ad[mmu030_idx].done) { \
+ mmu030_idx++; \
+ return; \
+ }
+
+#define ACCESS_CHECK_GET \
+ if (mmu030_ad[mmu030_idx].done) { \
+ v = mmu030_ad[mmu030_idx].val; \
+ mmu030_idx++; \
+ return v; \
+ }
+
+#define ACCESS_CHECK_GET_PC(pc) \
+ if (mmu030_ad[mmu030_idx].done) { \
+ v = mmu030_ad[mmu030_idx].val; \
+ mmu030_idx++; \
+ m68k_incpci (pc); \
+ return v; \
+ }
+
+#define ACCESS_EXIT_PUT \
+ mmu030_ad[mmu030_idx].done = true; \
+ mmu030_idx++; \
+ mmu030_ad[mmu030_idx].done = false;
+
+#define ACCESS_EXIT_GET \
+ mmu030_ad[mmu030_idx].val = v; \
+ mmu030_ad[mmu030_idx].done = true; \
+ mmu030_idx++; \
+ mmu030_ad[mmu030_idx].done = false;
+
+// non-cache
+
+
static ALWAYS_INLINE uae_u32 sfc030_get_long(uaecptr addr)
{
uae_u32 fc = regs.sfc;
mmu030_put_byte(addr, val, fc);
}
-#define ACCESS_CHECK_PUT \
- if (!mmu030_ad[mmu030_idx].done) { \
- mmu030_ad[mmu030_idx].val = v; \
- } else if (mmu030_ad[mmu030_idx].done) { \
- mmu030_idx++; \
- return; \
- }
-
-#define ACCESS_CHECK_GET \
- if (mmu030_ad[mmu030_idx].done) { \
- v = mmu030_ad[mmu030_idx].val; \
- mmu030_idx++; \
- return v; \
- }
-
-#define ACCESS_CHECK_GET_PC(pc) \
- if (mmu030_ad[mmu030_idx].done) { \
- v = mmu030_ad[mmu030_idx].val; \
- mmu030_idx++; \
- m68k_incpci (pc); \
- return v; \
- }
-
-#define ACCESS_EXIT_PUT \
- mmu030_ad[mmu030_idx].done = true; \
- mmu030_idx++; \
- mmu030_ad[mmu030_idx].done = false;
-
-#define ACCESS_EXIT_GET \
- mmu030_ad[mmu030_idx].val = v; \
- mmu030_ad[mmu030_idx].done = true; \
- mmu030_idx++; \
- mmu030_ad[mmu030_idx].done = false;
+uae_u32 REGPARAM3 get_disp_ea_020_mmu030 (uae_u32 base, int idx) REGPARAM;
STATIC_INLINE void put_byte_mmu030_state (uaecptr addr, uae_u32 v)
{
{
uae_mmu030_put_byte (addr, v);
}
-
STATIC_INLINE void put_word_mmu030 (uaecptr addr, uae_u32 v)
{
uae_mmu030_put_word (addr, v);
extern void flush_mmu030 (uaecptr, int);
extern void m68k_do_bsr_mmu030 (uaecptr oldpc, uae_s32 offset);
+// cache
+
+static ALWAYS_INLINE uae_u32 sfc030c_get_long(uaecptr addr)
+{
+#if MMUDEBUG > 2
+ write_log(_T("sfc030_get_long: FC = %i\n"),fc);
+#endif
+ return read_dcache030(addr, 2, regs.sfc);
+}
+
+static ALWAYS_INLINE uae_u16 sfc030c_get_word(uaecptr addr)
+{
+#if MMUDEBUG > 2
+ write_log(_T("sfc030_get_word: FC = %i\n"),fc);
+#endif
+ return read_dcache030(addr, 1, regs.sfc);
+}
+
+static ALWAYS_INLINE uae_u8 sfc030c_get_byte(uaecptr addr)
+{
+#if MMUDEBUG > 2
+ write_log(_T("sfc030_get_byte: FC = %i\n"),fc);
+#endif
+ return read_dcache030(addr, 0, regs.sfc);
+}
+
+static ALWAYS_INLINE void dfc030c_put_long(uaecptr addr, uae_u32 val)
+{
+#if MMUDEBUG > 2
+ write_log(_T("dfc030_put_long: %08X = %08X FC = %i\n"), addr, val, fc);
+#endif
+ write_dcache030(addr, val, 2, regs.dfc);
+}
+
+static ALWAYS_INLINE void dfc030c_put_word(uaecptr addr, uae_u16 val)
+{
+#if MMUDEBUG > 2
+ write_log(_T("dfc030_put_word: %08X = %04X FC = %i\n"), addr, val, fc);
+#endif
+ write_dcache030(addr, val, 1, regs.dfc);
+}
+
+static ALWAYS_INLINE void dfc030c_put_byte(uaecptr addr, uae_u8 val)
+{
+#if MMUDEBUG > 2
+ write_log(_T("dfc030_put_byte: %08X = %02X FC = %i\n"), addr, val, fc);
+#endif
+ write_dcache030(addr, val, 0, regs.dfc);
+}
+
+uae_u32 REGPARAM3 get_disp_ea_020_mmu030c (uae_u32 base, int idx) REGPARAM;
+
+STATIC_INLINE void put_byte_mmu030c_state (uaecptr addr, uae_u32 v)
+{
+ ACCESS_CHECK_PUT
+ write_dcache030_mmu(addr, v, 0);
+ ACCESS_EXIT_PUT
+}
+STATIC_INLINE void put_lrmw_byte_mmu030c_state (uaecptr addr, uae_u32 v)
+{
+ ACCESS_CHECK_PUT
+ write_dcache030_lrmw_mmu(addr, v, 0);
+ ACCESS_EXIT_PUT
+}
+STATIC_INLINE void put_word_mmu030c_state (uaecptr addr, uae_u32 v)
+{
+ ACCESS_CHECK_PUT
+ write_dcache030_mmu(addr, v, 1);
+ ACCESS_EXIT_PUT
+}
+STATIC_INLINE void put_lrmw_word_mmu030c_state (uaecptr addr, uae_u32 v)
+{
+ ACCESS_CHECK_PUT
+ write_dcache030_lrmw_mmu(addr, v, 1);
+ ACCESS_EXIT_PUT
+}
+STATIC_INLINE void put_long_mmu030c_state (uaecptr addr, uae_u32 v)
+{
+ ACCESS_CHECK_PUT
+ write_dcache030_mmu(addr, v, 2);
+ ACCESS_EXIT_PUT
+}
+STATIC_INLINE void put_lrmw_long_mmu030c_state (uaecptr addr, uae_u32 v)
+{
+ ACCESS_CHECK_PUT
+ write_dcache030_lrmw_mmu(addr, v, 2);
+ ACCESS_EXIT_PUT
+}
+
+STATIC_INLINE uae_u32 get_byte_mmu030c_state (uaecptr addr)
+{
+ uae_u32 v;
+ ACCESS_CHECK_GET
+ v = read_dcache030_mmu(addr, 0);
+ ACCESS_EXIT_GET
+ return v;
+}
+STATIC_INLINE uae_u32 get_lrmw_byte_mmu030c_state (uaecptr addr)
+{
+ uae_u32 v;
+ ACCESS_CHECK_GET
+ v = read_dcache030_lrmw_mmu(addr, 0);
+ ACCESS_EXIT_GET
+ return v;
+}
+
+STATIC_INLINE uae_u32 get_word_mmu030c_state (uaecptr addr)
+{
+ uae_u32 v;
+ ACCESS_CHECK_GET
+ v = read_dcache030_mmu(addr, 1);
+ ACCESS_EXIT_GET
+ return v;
+}
+STATIC_INLINE uae_u32 get_lrmw_word_mmu030c_state (uaecptr addr)
+{
+ uae_u32 v;
+ ACCESS_CHECK_GET
+ v = read_dcache030_lrmw_mmu(addr, 1);
+ ACCESS_EXIT_GET
+ return v;
+}
+STATIC_INLINE uae_u32 get_long_mmu030c_state (uaecptr addr)
+{
+ uae_u32 v;
+ ACCESS_CHECK_GET
+ v = read_dcache030_mmu(addr, 2);
+ ACCESS_EXIT_GET
+ return v;
+}
+STATIC_INLINE uae_u32 get_lrmw_long_mmu030c_state (uaecptr addr)
+{
+ uae_u32 v;
+ ACCESS_CHECK_GET
+ v = read_dcache030_lrmw_mmu(addr, 2);
+ ACCESS_EXIT_GET
+ return v;
+}
+
+STATIC_INLINE uae_u32 get_ibyte_mmu030c_state (int o)
+{
+ uae_u32 v;
+ uae_u32 addr = m68k_getpci () + o;
+ ACCESS_CHECK_GET
+ v = get_word_icache030(addr);
+ ACCESS_EXIT_GET
+ return v;
+}
+uae_u32 get_word_030_prefetch(int o);
+STATIC_INLINE uae_u32 get_iword_mmu030c_state (int o)
+{
+ uae_u32 v;
+ ACCESS_CHECK_GET;
+ v = get_word_030_prefetch(o);
+ ACCESS_EXIT_GET
+ return v;
+}
+uae_u32 get_long_030_prefetch(int o);
+STATIC_INLINE uae_u32 get_ilong_mmu030c_state (int o)
+{
+ uae_u32 v;
+ ACCESS_CHECK_GET;
+ v = get_word_030_prefetch(o + 0) << 16;
+ v |= get_word_030_prefetch(o + 2);
+ ACCESS_EXIT_GET
+ return v;
+}
+STATIC_INLINE uae_u32 get_iword_mmu030c_opcode_state(int o)
+{
+ return get_iword_mmu030c_state(o);
+}
+
+
+STATIC_INLINE uae_u32 next_iword_mmu030c_state (void)
+{
+ uae_u32 v;
+ ACCESS_CHECK_GET_PC(2);
+ v = get_word_030_prefetch(0);
+ m68k_incpci(2);
+ ACCESS_EXIT_GET
+ return v;
+}
+STATIC_INLINE uae_u32 next_ilong_mmu030c_state (void)
+{
+ uae_u32 v;
+ ACCESS_CHECK_GET_PC(4);
+ v = get_word_030_prefetch(0) << 16;
+ v |= get_word_030_prefetch(2);
+ m68k_incpci (4);
+ ACCESS_EXIT_GET
+ return v;
+}
+
+STATIC_INLINE uae_u32 get_word_mmu030c (uaecptr addr)
+{
+ return read_dcache030_mmu(addr, 1);
+}
+STATIC_INLINE uae_u32 get_long_mmu030c (uaecptr addr)
+{
+ return read_dcache030_mmu(addr, 2);
+}
+STATIC_INLINE void put_word_mmu030c (uaecptr addr, uae_u32 v)
+{
+ write_dcache030_mmu(addr, v, 1);
+}
+STATIC_INLINE void put_long_mmu030c (uaecptr addr, uae_u32 v)
+{
+ write_dcache030_mmu(addr, v, 2);
+}
+
+extern void m68k_do_rts_mmu030c(void);
+extern void m68k_do_rte_mmu030c(uaecptr a7);
+extern void m68k_do_bsr_mmu030c(uaecptr oldpc, uae_s32 offset);
+
#endif /* UAE_CPUMMU030_H */
int m68k_pc_indirect;
bool m68k_interrupt_delay;
static bool m68k_reset_delay;
+
+static bool dcache_complete_inhibit;
+
static int cpu_prefs_changed_flag;
int cpucycleunit;
x_cp_get_disp_ea_020 = x_get_disp_ea_020;
if (currprefs.mmu_model == 68030) {
- x_cp_put_long = put_long_mmu030_state;
- x_cp_put_word = put_word_mmu030_state;
- x_cp_put_byte = put_byte_mmu030_state;
- x_cp_get_long = get_long_mmu030_state;
- x_cp_get_word = get_word_mmu030_state;
- x_cp_get_byte = get_byte_mmu030_state;
- x_cp_next_iword = next_iword_mmu030_state;
- x_cp_next_ilong = next_ilong_mmu030_state;
- x_cp_get_disp_ea_020 = get_disp_ea_020_mmu030;
+ if (currprefs.cpu_compatible) {
+ x_cp_put_long = put_long_mmu030c_state;
+ x_cp_put_word = put_word_mmu030c_state;
+ x_cp_put_byte = put_byte_mmu030c_state;
+ x_cp_get_long = get_long_mmu030c_state;
+ x_cp_get_word = get_word_mmu030c_state;
+ x_cp_get_byte = get_byte_mmu030c_state;
+ x_cp_next_iword = next_iword_mmu030c_state;
+ x_cp_next_ilong = next_ilong_mmu030c_state;
+ x_cp_get_disp_ea_020 = get_disp_ea_020_mmu030c;
+ } else {
+ x_cp_put_long = put_long_mmu030_state;
+ x_cp_put_word = put_word_mmu030_state;
+ x_cp_put_byte = put_byte_mmu030_state;
+ x_cp_get_long = get_long_mmu030_state;
+ x_cp_get_word = get_word_mmu030_state;
+ x_cp_get_byte = get_byte_mmu030_state;
+ x_cp_next_iword = next_iword_mmu030_state;
+ x_cp_next_ilong = next_ilong_mmu030_state;
+ x_cp_get_disp_ea_020 = get_disp_ea_020_mmu030;
+ }
}
}
do_cycles_ce020 (cycles);
}
+static bool dcache030_check_dummy(uaecptr addr, bool write, uae_u32 size)
+{
+ return true;
+}
+
+static uae_u32 (*icache_fetch)(uaecptr);
+static uae_u32 (*dcache030_lget)(uaecptr);
+static uae_u32 (*dcache030_wget)(uaecptr);
+static uae_u32 (*dcache030_bget)(uaecptr);
+static bool (*dcache030_check)(uaecptr, bool, uae_u32);
+static void (*dcache030_lput)(uaecptr, uae_u32);
+static void (*dcache030_wput)(uaecptr, uae_u32);
+static void (*dcache030_bput)(uaecptr, uae_u32);
+
static void set_x_ifetches(void)
{
if (m68k_pc_indirect) {
} else {
- x_prefetch = get_iword_mmu030;
- x_get_ilong = get_ilong_mmu030;
- x_get_iword = get_iword_mmu030;
- x_get_ibyte = get_ibyte_mmu030;
- x_next_iword = next_iword_mmu030;
- x_next_ilong = next_ilong_mmu030;
- x_put_long = put_long_mmu030;
- x_put_word = put_word_mmu030;
- x_put_byte = put_byte_mmu030;
- x_get_long = get_long_mmu030;
- x_get_word = get_word_mmu030;
- x_get_byte = get_byte_mmu030;
+ if (currprefs.cpu_memory_cycle_exact) {
+ x_prefetch = get_iword_mmu030c_state;
+ x_get_ilong = get_ilong_mmu030c_state;
+ x_get_iword = get_iword_mmu030c_state;
+ x_get_ibyte = NULL;
+ x_next_iword = next_iword_mmu030c_state;
+ x_next_ilong = next_ilong_mmu030c_state;
+ x_put_long = put_long_ce030;
+ x_put_word = put_word_ce030;
+ x_put_byte = put_byte_ce030;
+ x_get_long = get_long_ce030;
+ x_get_word = get_word_ce030;
+ x_get_byte = get_byte_ce030;
+ x_do_cycles = do_cycles;
+ x_do_cycles_pre = do_cycles;
+ x_do_cycles_post = do_cycles_post;
+ } else if (currprefs.cpu_compatible) {
+ x_prefetch = get_iword_mmu030c_state;
+ x_get_ilong = get_ilong_mmu030c_state;
+ x_get_iword = get_iword_mmu030c_state;
+ x_get_ibyte = NULL;
+ x_next_iword = next_iword_mmu030c_state;
+ x_next_ilong = next_ilong_mmu030c_state;
+ x_put_long = put_long_ce030;
+ x_put_word = put_word_ce030;
+ x_put_byte = put_byte_ce030;
+ x_get_long = get_long_ce030;
+ x_get_word = get_word_ce030;
+ x_get_byte = get_byte_ce030;
+ x_do_cycles = do_cycles;
+ x_do_cycles_pre = do_cycles;
+ x_do_cycles_post = do_cycles_post;
+ } else {
+ x_prefetch = get_iword_mmu030;
+ x_get_ilong = get_ilong_mmu030;
+ x_get_iword = get_iword_mmu030;
+ x_get_ibyte = get_ibyte_mmu030;
+ x_next_iword = next_iword_mmu030;
+ x_next_ilong = next_ilong_mmu030;
+ x_put_long = put_long_mmu030;
+ x_put_word = put_word_mmu030;
+ x_put_byte = put_byte_mmu030;
+ x_get_long = get_long_mmu030;
+ x_get_word = get_word_mmu030;
+ x_get_byte = get_byte_mmu030;
+ }
+
}
x_do_cycles = do_cycles;
x_do_cycles_pre = do_cycles;
x_get_ibyte = NULL;
x_next_iword = next_iword_030_prefetch;
x_next_ilong = next_ilong_030_prefetch;
- x_put_long = put_long;
- x_put_word = put_word;
- x_put_byte = put_byte;
- x_get_long = get_long;
- x_get_word = get_word;
- x_get_byte = get_byte;
+ x_put_long = put_long_030;
+ x_put_word = put_word_030;
+ x_put_byte = put_byte_030;
+ x_get_long = get_long_030;
+ x_get_word = get_word_030;
+ x_get_byte = get_byte_030;
x_do_cycles = do_cycles;
x_do_cycles_pre = do_cycles;
x_do_cycles_post = do_cycles_post;
mmu_set_funcs();
mmu030_set_funcs();
+ icache_fetch = get_longi;
+ dcache030_lput = put_long;
+ dcache030_wput = put_word;
+ dcache030_bput = put_byte;
+ dcache030_lget = get_long;
+ dcache030_wget = get_word;
+ dcache030_bget = get_byte;
+ dcache030_check = dcache030_check_dummy;
+ if (currprefs.cpu_cycle_exact) {
+ icache_fetch = mem_access_delay_longi_read_ce020;
+ }
+ if (currprefs.cpu_model == 68030) {
+ if (currprefs.mmu_model) {
+ if (currprefs.cpu_compatible) {
+ icache_fetch = uae_mmu030_get_ilong_fc;
+ dcache030_lput = uae_mmu030_put_long_fc;
+ dcache030_wput = uae_mmu030_put_word_fc;
+ dcache030_bput = uae_mmu030_put_byte_fc;
+ dcache030_lget = uae_mmu030_get_long_fc;
+ dcache030_wget = uae_mmu030_get_word_fc;
+ dcache030_bget = uae_mmu030_get_byte_fc;
+ dcache030_check = uae_mmu030_check_fc;
+ } else {
+ icache_fetch = uae_mmu030_get_ilong;
+ dcache030_lput = uae_mmu030_put_long;
+ dcache030_wput = uae_mmu030_put_word;
+ dcache030_bput = uae_mmu030_put_byte;
+ dcache030_lget = uae_mmu030_get_long;
+ dcache030_wget = uae_mmu030_get_word;
+ dcache030_bget = uae_mmu030_get_byte;
+ }
+ } else if (currprefs.cpu_memory_cycle_exact) {
+ icache_fetch = mem_access_delay_longi_read_ce020;
+ dcache030_lput = mem_access_delay_long_write_ce020;
+ dcache030_wput = mem_access_delay_word_write_ce020;
+ dcache030_bput = mem_access_delay_byte_write_ce020;
+ dcache030_lget = mem_access_delay_long_read_ce020;
+ dcache030_wget = mem_access_delay_word_read_ce020;
+ dcache030_bget = mem_access_delay_byte_read_ce020;
+ }
+ }
}
bool can_cpu_tracer (void)
return 4;
}
-// generic+direct, generic+direct+jit, generic+indirect, more compatible, cycle-exact, mmu
-static const struct cputbl *cputbls[6][6] =
+// generic+direct, generic+direct+jit, generic+indirect, more compatible, cycle-exact, mmu, mm+more compatible
+static const struct cputbl *cputbls[6][7] =
{
// 68000
- { op_smalltbl_5_ff, op_smalltbl_45_ff, op_smalltbl_55_ff, op_smalltbl_12_ff, op_smalltbl_14_ff, NULL },
+ { op_smalltbl_5_ff, op_smalltbl_45_ff, op_smalltbl_55_ff, op_smalltbl_12_ff, op_smalltbl_14_ff, NULL, NULL },
// 68010
- { op_smalltbl_4_ff, op_smalltbl_44_ff, op_smalltbl_54_ff, op_smalltbl_11_ff, op_smalltbl_13_ff, NULL },
+ { op_smalltbl_4_ff, op_smalltbl_44_ff, op_smalltbl_54_ff, op_smalltbl_11_ff, op_smalltbl_13_ff, NULL, NULL },
// 68020
- { op_smalltbl_3_ff, op_smalltbl_43_ff, op_smalltbl_53_ff, op_smalltbl_20_ff, op_smalltbl_21_ff, NULL },
+ { op_smalltbl_3_ff, op_smalltbl_43_ff, op_smalltbl_53_ff, op_smalltbl_20_ff, op_smalltbl_21_ff, NULL, NULL },
// 68030
- { op_smalltbl_2_ff, op_smalltbl_42_ff, op_smalltbl_52_ff, op_smalltbl_22_ff, op_smalltbl_23_ff, op_smalltbl_32_ff },
+ { op_smalltbl_2_ff, op_smalltbl_42_ff, op_smalltbl_52_ff, op_smalltbl_22_ff, op_smalltbl_23_ff, op_smalltbl_32_ff, op_smalltbl_34_ff },
// 68040
- { op_smalltbl_1_ff, op_smalltbl_41_ff, op_smalltbl_51_ff, op_smalltbl_25_ff, op_smalltbl_25_ff, op_smalltbl_31_ff },
+ { op_smalltbl_1_ff, op_smalltbl_41_ff, op_smalltbl_51_ff, op_smalltbl_25_ff, op_smalltbl_25_ff, op_smalltbl_31_ff, NULL },
// 68060
- { op_smalltbl_0_ff, op_smalltbl_40_ff, op_smalltbl_50_ff, op_smalltbl_24_ff, op_smalltbl_24_ff, op_smalltbl_33_ff }
+ { op_smalltbl_0_ff, op_smalltbl_40_ff, op_smalltbl_50_ff, op_smalltbl_24_ff, op_smalltbl_24_ff, op_smalltbl_33_ff, NULL }
};
static void build_cpufunctbl (void)
int lvl, mode;
if (!currprefs.cachesize) {
- if (currprefs.mmu_model)
- mode = 5;
- else if (currprefs.cpu_cycle_exact)
+ if (currprefs.mmu_model) {
+ if (currprefs.cpu_compatible)
+ mode = 6;
+ else
+ mode = 5;
+ } else if (currprefs.cpu_cycle_exact) {
mode = 4;
- else if (currprefs.cpu_compatible)
+ } else if (currprefs.cpu_compatible) {
mode = 3;
- else
+ } else {
mode = 0;
+ }
m68k_pc_indirect = mode != 0 ? 1 : 0;
} else {
mode = 1;
fake_crp_030 = crp_030;
}
}
+ currprefs.mmu_ec = changed_prefs.mmu_ec;
currprefs.cpu_compatible = changed_prefs.cpu_compatible;
currprefs.address_space_24 = changed_prefs.address_space_24;
currprefs.cpu_cycle_exact = changed_prefs.cpu_cycle_exact;
|| currprefs.cpu_model != changed_prefs.cpu_model
|| currprefs.fpu_model != changed_prefs.fpu_model
|| currprefs.mmu_model != changed_prefs.mmu_model
+ || currprefs.mmu_ec != changed_prefs.mmu_ec
|| currprefs.int_no_unimplemented != changed_prefs.int_no_unimplemented
|| currprefs.fpu_no_unimplemented != changed_prefs.fpu_no_unimplemented
|| currprefs.cpu_compatible != changed_prefs.cpu_compatible
m68k_areg (regs, 7) -= 4;
x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr);
// 2xinternal
- m68k_areg (regs, 7) -= 2;
- x_put_word (m68k_areg (regs, 7), 0);
- m68k_areg (regs, 7) -= 2;
- x_put_word (m68k_areg (regs, 7), 0);
+ {
+ uae_u32 ps = (regs.prefetch020_valid[0] ? 1 : 0) | (regs.prefetch020_valid[1] ? 2 : 0) | (regs.prefetch020_valid[2] ? 4 : 0);
+ ps |= ((regs.pipeline_r8[0] & 7) << 8);
+ ps |= ((regs.pipeline_r8[1] & 7) << 11);
+ ps |= ((regs.pipeline_pos & 15) << 16);
+ ps |= ((regs.pipeline_stop & 15) << 20);
+ if (mmu030_opcode == -1)
+ ps |= 1 << 31;
+ m68k_areg (regs, 7) -= 4;
+ x_put_long (m68k_areg (regs, 7), ps);
+ }
// stage b address
m68k_areg (regs, 7) -= 4;
x_put_long (m68k_areg (regs, 7), mm030_stageb_address);
// Data output buffer = value that was going to be written
x_put_long (m68k_areg (regs, 7), (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) ? mmu030_data_buffer : mmu030_ad[mmu030_idx].val);
m68k_areg (regs, 7) -= 4;
- x_put_long (m68k_areg (regs, 7), mmu030_opcode); // Internal register (opcode storage)
+ x_put_long (m68k_areg (regs, 7), (mmu030_opcode & 0xffff) | (regs.prefetch020[0] << 16)); // Internal register (opcode storage)
m68k_areg (regs, 7) -= 4;
x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr); // data cycle fault address
m68k_areg (regs, 7) -= 2;
- x_put_word (m68k_areg (regs, 7), 0); // Instr. pipe stage B
+ x_put_word (m68k_areg (regs, 7), regs.prefetch020[2]); // Instr. pipe stage B
m68k_areg (regs, 7) -= 2;
- x_put_word (m68k_areg (regs, 7), 0); // Instr. pipe stage C
+ x_put_word (m68k_areg (regs, 7), regs.prefetch020[1]); // Instr. pipe stage C
m68k_areg (regs, 7) -= 2;
x_put_word (m68k_areg (regs, 7), ssw);
m68k_areg (regs, 7) -= 2;
}
#endif
+ newpc = x_get_long (regs.vbr + 4 * nr);
+
#if 0
- write_log (_T("Exception %d -> %08x\n", nr, newpc));
+ write_log (_T("Exception %d -> %08x\n"), nr, newpc);
#endif
-
- newpc = x_get_long (regs.vbr + 4 * nr);
-
if (regs.m && interrupt) { /* M + Interrupt */
Exception_build_stack_frame (oldpc, currpc, regs.mmu_ssw, nr, 0x0);
MakeSR ();
mmufixup[0].reg = -1;
mmufixup[1].reg = -1;
+ mmu030_cache_inhibit = 0;
+ dcache_complete_inhibit = uae_boot_rom_type > 0;
+ //dcache_complete_inhibit = true;
if (currprefs.mmu_model >= 68040) {
mmu_reset ();
mmu_set_tc (regs.tcr);
}
mmu030_fake_prefetch = -1;
} else if (mmu030_opcode_stageb < 0) {
- regs.opcode = x_prefetch (0);
+ if (currprefs.cpu_compatible)
+ regs.opcode = regs.irc;
+ else
+ regs.opcode = x_prefetch (0);
} else {
regs.opcode = mmu030_opcode_stageb;
mmu030_opcode_stageb = -1;
cnt = 50;
for (;;) {
- regs.opcode = mmu030_opcode;
+ regs.opcode = regs.irc = mmu030_opcode;
mmu030_idx = 0;
count_instr (regs.opcode);
do_cycles (cpu_cycles);
}
} CATCH (prb) {
- regflags.cznv = f.cznv;
- regflags.x = f.x;
-
- m68k_setpci (regs.instruction_pc);
-
- if (mmufixup[0].reg >= 0) {
- m68k_areg (regs, mmufixup[0].reg) = mmufixup[0].value;
+ if (mmu030_opcode == -1 && currprefs.cpu_compatible) {
+ // full prefetch fill access fault
+ // TODO: this should create shorter A-frame
mmufixup[0].reg = -1;
- }
- if (mmufixup[1].reg >= 0) {
- m68k_areg (regs, mmufixup[1].reg) = mmufixup[1].value;
mmufixup[1].reg = -1;
+ } else {
+ regflags.cznv = f.cznv;
+ regflags.x = f.x;
+
+ if (mmufixup[0].reg >= 0) {
+ m68k_areg (regs, mmufixup[0].reg) = mmufixup[0].value;
+ mmufixup[0].reg = -1;
+ }
+ if (mmufixup[1].reg >= 0) {
+ m68k_areg (regs, mmufixup[1].reg) = mmufixup[1].value;
+ mmufixup[1].reg = -1;
+ }
}
+ m68k_setpci (regs.instruction_pc);
+
TRY (prb2) {
Exception (prb);
} CATCH (prb2) {
r->cacheholdingdata020 = cputrace.cacheholdingdata020;
r->cacheholdingaddr020 = cputrace.cacheholdingaddr020;
r->prefetch020addr = cputrace.prefetch020addr;
- memcpy (&r->prefetch020, &cputrace.prefetch020, CPU_PIPELINE_MAX * sizeof (uae_u32));
+ memcpy (&r->prefetch020, &cputrace.prefetch020, CPU_PIPELINE_MAX * sizeof (uae_u16));
memcpy (&caches020, &cputrace.caches020, sizeof caches020);
m68k_setpc (cputrace.pc);
cputrace.cacheholdingdata020 = r->cacheholdingdata020;
cputrace.cacheholdingaddr020 = r->cacheholdingaddr020;
cputrace.prefetch020addr = r->prefetch020addr;
- memcpy (&cputrace.prefetch020, &r->prefetch020, CPU_PIPELINE_MAX * sizeof (uae_u32));
+ memcpy (&cputrace.prefetch020, &r->prefetch020, CPU_PIPELINE_MAX * sizeof (uae_u16));
memcpy (&cputrace.caches020, &caches020, sizeof caches020);
cputrace.memoryoffset = 0;
r->cacheholdingdata020 = cputrace.cacheholdingdata020;
r->cacheholdingaddr020 = cputrace.cacheholdingaddr020;
r->prefetch020addr = cputrace.prefetch020addr;
- memcpy (&r->prefetch020, &cputrace.prefetch020, CPU_PIPELINE_MAX * sizeof (uae_u32));
+ memcpy (&r->prefetch020, &cputrace.prefetch020, CPU_PIPELINE_MAX * sizeof (uae_u16));
memcpy (&caches020, &cputrace.caches020, sizeof caches020);
m68k_setpc (cputrace.pc);
cputrace.cacheholdingdata020 = r->cacheholdingdata020;
cputrace.cacheholdingaddr020 = r->cacheholdingaddr020;
cputrace.prefetch020addr = r->prefetch020addr;
- memcpy (&cputrace.prefetch020, &r->prefetch020, CPU_PIPELINE_MAX * sizeof (uae_u32));
+ memcpy (&cputrace.prefetch020, &r->prefetch020, CPU_PIPELINE_MAX * sizeof (uae_u16));
memcpy (&cputrace.caches020, &caches020, sizeof caches020);
cputrace.memoryoffset = 0;
} else if (lookup->mnemo == i_MOVES) {
TCHAR *p;
pc += 2;
- if (!(extra & 0x1000)) {
+ if (!(extra & 0x0800)) {
pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode);
p = instrname + _tcslen(instrname);
_stprintf(p, _T(",%c%d"), (extra & 0x8000) ? 'A' : 'D', (extra >> 12) & 7);
console_out_f (_T("SRP: %llX CRP: %llX\n"), srp_030, crp_030);
console_out_f (_T("TT0: %08X TT1: %08X TC: %08X\n"), tt0_030, tt1_030, tc_030);
}
- if (currprefs.cpu_compatible && currprefs.cpu_model == 68000) {
- struct instr *dp;
- struct mnemolookup *lookup1, *lookup2;
- dp = table68k + regs.irc;
- for (lookup1 = lookuptab; lookup1->mnemo != dp->mnemo; lookup1++)
- ;
- dp = table68k + regs.ir;
- for (lookup2 = lookuptab; lookup2->mnemo != dp->mnemo; lookup2++)
- ;
- console_out_f (_T("Prefetch %04x (%s) %04x (%s) Chip latch %08X\n"), regs.irc, lookup1->name, regs.ir, lookup2->name, regs.chipset_latch_rw);
+ if (currprefs.cpu_compatible) {
+ if (currprefs.cpu_model == 68000) {
+ struct instr *dp;
+ struct mnemolookup *lookup1, *lookup2;
+ dp = table68k + regs.irc;
+ for (lookup1 = lookuptab; lookup1->mnemo != dp->mnemo; lookup1++)
+ ;
+ dp = table68k + regs.ir;
+ for (lookup2 = lookuptab; lookup2->mnemo != dp->mnemo; lookup2++)
+ ;
+ console_out_f (_T("Prefetch %04x (%s) %04x (%s) Chip latch %08X\n"), regs.irc, lookup1->name, regs.ir, lookup2->name, regs.chipset_latch_rw);
+ } else if (currprefs.cpu_model == 68020 || currprefs.cpu_model == 68030) {
+ console_out_f (_T("Prefetch %08x %08x (%d) %04x (%d) %04x (%d) %04x (%d)\n"),
+ regs.cacheholdingaddr020, regs.cacheholdingdata020, regs.cacheholdingdata_valid,
+ regs.prefetch020[0], regs.prefetch020_valid[0],
+ regs.prefetch020[1], regs.prefetch020_valid[1],
+ regs.prefetch020[2], regs.prefetch020_valid[2]);
+ }
}
if (pc != 0xffffffff) {
for (int j = 0; j < 4; j++) {
int s = i + j;
uaecptr addr;
+ int fc;
struct cache020 *c = &caches020[s];
+ fc = c->tag & 1;
addr = c->tag & ~1;
addr |= s << 2;
- console_out_f (_T("%08X:%08X%c "), addr, c->data, c->valid ? '*' : ' ');
+ console_out_f (_T("%08X%c:%08X%c"), addr, fc ? 'S' : 'U', c->data, c->valid ? '*' : ' ');
}
console_out_f (_T("\n"));
}
} else if (currprefs.cpu_model == 68030) {
- for (int i = 0; i < CACHELINES030; i++) {
- struct cache030 *c = &icaches030[i];
- uaecptr addr;
- addr = c->tag & ~1;
- addr |= i << 4;
- console_out_f (_T("%08X: "), addr);
- for (int j = 0; j < 4; j++) {
- console_out_f (_T("%08X%c "), c->data[j], c->valid[j] ? '*' : ' ');
+ for (int j = 0; j < 2; j++) {
+ console_out_f (_T("%s\n"), j == 0 ? _T("Instruction") : _T("Data"));
+ for (int i = 0; i < CACHELINES030; i++) {
+ struct cache030 *c = j ? &dcaches030[i] : &icaches030[i];
+ int fc;
+ uaecptr addr;
+ if (j == 0) {
+ fc = (c->tag & 1) ? 6 : 2;
+ } else {
+ fc = c->fc;
+ }
+ addr = c->tag & ~1;
+ addr |= i << 4;
+ console_out_f (_T("%08X %d: "), addr, fc);
+ for (int j = 0; j < 4; j++) {
+ console_out_f (_T("%08X%c "), c->data[j], c->valid[j] ? '*' : ' ');
+ }
+ console_out_f (_T("\n"));
}
- console_out_f (_T("\n"));
}
}
}
}
// this one is really simple and easy
-static void fill_icache020 (uae_u32 addr, uae_u32 (*fetch)(uaecptr), bool opcode)
+static void fill_icache020 (uae_u32 addr, bool opcode)
{
int index;
uae_u32 tag;
uae_u32 data;
struct cache020 *c;
+ regs.fc030 = (regs.s ? 4 : 0) | 2;
addr &= ~3;
if (regs.cacheholdingaddr020 == addr)
return;
// cache hit
regs.cacheholdingaddr020 = addr;
regs.cacheholdingdata020 = c->data;
+ regs.cacheholdingdata_valid = true;
return;
}
+
// cache miss
#if 0
// Prefetch apparently can be queued by bus controller
#endif
start_020_cycle_prefetch(opcode);
- data = fetch (addr);
+ data = icache_fetch(addr);
end_020_cycle_prefetch(opcode);
if (!(regs.cacr & 2)) {
}
regs.cacheholdingaddr020 = addr;
regs.cacheholdingdata020 = data;
+ regs.cacheholdingdata_valid = true;
}
#if MORE_ACCURATE_68020_PIPELINE
#if PIPELINE_DEBUG
static uae_u16 pipeline_opcode;
#endif
-static void pipeline_020(uae_u16 w, uaecptr pc)
+static void pipeline_020(uaecptr pc)
{
+ uae_u16 w = regs.prefetch020[1];
+ if (regs.prefetch020_valid[1] == 0) {
+ regs.pipeline_stop = -1;
+ return;
+ }
if (regs.pipeline_pos < 0)
return;
if (regs.pipeline_pos > 0) {
uae_u32 pc = m68k_getpc () + o;
uae_u32 v;
- if (pc & 2) {
- v = regs.prefetch020[0] & 0xffff;
+ v = regs.prefetch020[0];
+ regs.prefetch020[0] = regs.prefetch020[1];
+ regs.prefetch020[1] = regs.prefetch020[2];
#if MORE_ACCURATE_68020_PIPELINE
- pipeline_020(regs.prefetch020[1], pc );
+ pipeline_020(pc);
#endif
- regs.prefetch020[0] = regs.prefetch020[1];
+ if (pc & 2) {
// branch instruction detected in pipeline: stop fetches until branch executed.
if (!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) {
- fill_icache020 (pc + 2 + 4, mem_access_delay_longi_read_ce020, opcode);
- regs.prefetch020[1] = regs.cacheholdingdata020;
+ fill_icache020 (pc + 2 + 4, opcode);
}
- regs.db = regs.prefetch020[0] >> 16;
+ regs.prefetch020[2] = regs.cacheholdingdata020 >> 16;
} else {
- v = regs.prefetch020[0] >> 16;
-#if MORE_ACCURATE_68020_PIPELINE
- pipeline_020(regs.prefetch020[1] >> 16, pc);
-#endif
- regs.db = regs.prefetch020[1] >> 16;
+ regs.prefetch020[2] = (uae_u16)regs.cacheholdingdata020;
}
do_cycles_ce020_internal (2);
+ regs.db = regs.prefetch020[0];
return v;
}
uae_u32 pc = m68k_getpc () + o;
uae_u32 v;
- if (pc & 2) {
- v = regs.prefetch020[0] & 0xffff;
+ v = regs.prefetch020[0];
+ regs.prefetch020[0] = regs.prefetch020[1];
+ regs.prefetch020[1] = regs.prefetch020[2];
#if MORE_ACCURATE_68020_PIPELINE
- pipeline_020(regs.prefetch020[1], pc);
+ pipeline_020(pc);
#endif
- regs.prefetch020[0] = regs.prefetch020[1];
+ if (pc & 2) {
+ // branch instruction detected in pipeline: stop fetches until branch executed.
if (!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) {
- fill_icache020 (pc + 2 + 4, currprefs.cpu_memory_cycle_exact ? mem_access_delay_longi_read_ce020 : get_longi, false);
- regs.prefetch020[1] = regs.cacheholdingdata020;
+ fill_icache020 (pc + 2 + 4, false);
}
- regs.db = regs.prefetch020[0] >> 16;
+ regs.prefetch020[2] = regs.cacheholdingdata020 >> 16;
} else {
- v = regs.prefetch020[0] >> 16;
-#if MORE_ACCURATE_68020_PIPELINE
- pipeline_020(regs.prefetch020[1] >> 16, pc);
-#endif
- regs.db = regs.prefetch020[0];
+ regs.prefetch020[2] = (uae_u16)regs.cacheholdingdata020;
}
+ regs.db = regs.prefetch020[0];
return v;
}
return v;
}
+uae_u32 mem_access_delay_wordi_read_ce020 (uaecptr addr)
+{
+ uae_u32 v;
+ start_020_cycle();
+ switch (ce_banktype[addr >> 16])
+ {
+ case CE_MEMBANK_CHIP16:
+ case CE_MEMBANK_CHIP32:
+ if ((addr & 3) == 3) {
+ v = wait_cpu_cycle_read_ce020 (addr + 0, 0) << 8;
+ v |= wait_cpu_cycle_read_ce020 (addr + 1, 0) << 0;
+ } else {
+ v = wait_cpu_cycle_read_ce020 (addr, 1);
+ }
+ break;
+ case CE_MEMBANK_FAST16:
+ case CE_MEMBANK_FAST32:
+ v = get_wordi (addr);
+ if ((addr & 3) == 3)
+ do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
+ else
+ do_cycles_ce020_mem (1 * CPU020_MEM_CYCLE, v);
+ break;
+ default:
+ v = get_wordi (addr);
+ break;
+ }
+ end_020_cycle();
+ return v;
+}
+
uae_u32 mem_access_delay_word_read_ce020 (uaecptr addr)
{
uae_u32 v;
// 68030 caches aren't so simple as 68020 cache..
-STATIC_INLINE struct cache030 *getcache030 (struct cache030 *cp, uaecptr addr, uae_u32 *tagp, int *lwsp)
+
+STATIC_INLINE struct cache030 *geticache030 (struct cache030 *cp, uaecptr addr, uae_u32 *tagp, int *lwsp)
{
int index, lws;
uae_u32 tag;
return c;
}
-STATIC_INLINE void update_cache030 (struct cache030 *c, uae_u32 val, uae_u32 tag, int lws)
+STATIC_INLINE void update_icache030 (struct cache030 *c, uae_u32 val, uae_u32 tag, int lws)
{
if (c->tag != tag)
c->valid[0] = c->valid[1] = c->valid[2] = c->valid[3] = false;
c->data[lws] = val;
}
+STATIC_INLINE struct cache030 *getdcache030 (struct cache030 *cp, uaecptr addr, uae_u32 *tagp, int *lwsp)
+{
+ int index, lws;
+ uae_u32 tag;
+ struct cache030 *c;
+
+ addr &= ~3;
+ index = (addr >> 4) & (CACHELINES030 - 1);
+ tag = addr & ~((CACHELINES030 << 4) - 1);
+ lws = (addr >> 2) & 3;
+ c = &cp[index];
+ *tagp = tag;
+ *lwsp = lws;
+ return c;
+}
+
+STATIC_INLINE void update_dcache030 (struct cache030 *c, uae_u32 val, uae_u32 tag, uae_u8 fc, int lws)
+{
+ if (c->tag != tag)
+ c->valid[0] = c->valid[1] = c->valid[2] = c->valid[3] = false;
+ c->tag = tag;
+ c->fc = fc;
+ c->valid[lws] = true;
+ c->data[lws] = val;
+}
+
static void fill_icache030 (uae_u32 addr)
{
int lws;
uae_u32 data;
struct cache030 *c;
+ regs.fc030 = (regs.s ? 4 : 0) | 2;
addr &= ~3;
- if (regs.cacheholdingaddr020 == addr)
+ if (regs.cacheholdingaddr020 == addr || regs.cacheholdingdata_valid == 0)
return;
- c = getcache030 (icaches030, addr, &tag, &lws);
+ c = geticache030 (icaches030, addr, &tag, &lws);
if (c->valid[lws] && c->tag == tag) {
// cache hit
regs.cacheholdingaddr020 = addr;
return;
}
- // cache miss
- if (currprefs.cpu_cycle_exact) {
- regs.ce020memcycle_data = false;
- start_020_cycle_prefetch(false);
- data = mem_access_delay_longi_read_ce020 (addr);
- end_020_cycle_prefetch(false);
- } else if (currprefs.cpu_memory_cycle_exact) {
- data = mem_access_delay_longi_read_ce020 (addr);
- } else {
- data = get_longi (addr);
- }
- if ((regs.cacr & 3) == 1) { // not frozen and enabled
- update_cache030 (c, data, tag, lws);
- }
- if ((regs.cacr & 0x11) == 0x11 && lws == 0 && !c->valid[1] && !c->valid[2] && !c->valid[3] && ce_banktype[addr >> 16] == CE_MEMBANK_FAST32) {
- // do burst fetch if cache enabled, not frozen, all slots invalid, no chip ram
- c->data[1] = get_longi (addr + 4);
- c->data[2] = get_longi (addr + 8);
- c->data[3] = get_longi (addr + 12);
- if (currprefs.cpu_cycle_exact)
- do_cycles_ce020_mem (3 * (CPU020_MEM_CYCLE - 1), c->data[3]);
- c->valid[1] = c->valid[2] = c->valid[3] = true;
+ TRY (prb2) {
+ // cache miss
+ if (currprefs.cpu_cycle_exact) {
+ regs.ce020memcycle_data = false;
+ start_020_cycle_prefetch(false);
+ data = icache_fetch(addr);
+ end_020_cycle_prefetch(false);
+ } else {
+ data = icache_fetch(addr);
+ }
+ } CATCH (prb2) {
+ // Bus error/MMU access fault: Delayed exception.
+ regs.cacheholdingdata_valid = 0;
+ regs.cacheholdingaddr020 = 0xffffffff;
+ regs.cacheholdingdata020 = 0xffffffff;
+ return;
+ } ENDTRY
+
+ if (!mmu030_cache_inhibit) {
+ if ((regs.cacr & 0x03) == 0x01) {
+ // instruction cache not frozen and enabled
+ update_icache030 (c, data, tag, lws);
+ }
+ if ((regs.cacr & 0x11) == 0x11 && (c->valid[0] + c->valid[1] + c->valid[2] + c->valid[3] == 1) && ce_banktype[addr >> 16] == CE_MEMBANK_FAST32) {
+ // do burst fetch if cache enabled, not frozen, all slots invalid, no chip ram
+ int i;
+ for (i = 0; i < 4; i++) {
+ if (c->valid[i])
+ break;
+ }
+ uaecptr baddr = addr & ~15;
+ if (currprefs.mmu_model) {
+ if (currprefs.cpu_cycle_exact)
+ do_cycles_ce020(3 * (CPU020_MEM_CYCLE - 1));
+ TRY (prb) {
+ for (int j = 0; j < 3; j++) {
+ i++;
+ i &= 3;
+ c->data[i] = icache_fetch(baddr + i * 4);
+ c->valid[i] = true;
+ }
+ } CATCH (prb) {
+ ; // abort burst fetch if bus error, do not report it.
+ } ENDTRY
+ } else {
+ for (int j = 0; j < 3; j++) {
+ i++;
+ i &= 3;
+ c->data[i] = icache_fetch(baddr + i * 4);
+ c->valid[i] = true;
+ }
+ if (currprefs.cpu_cycle_exact)
+ do_cycles_ce020_mem (3 * (CPU020_MEM_CYCLE - 1), c->data[3]);
+ }
+ }
}
regs.cacheholdingaddr020 = addr;
regs.cacheholdingdata020 = data;
}
+STATIC_INLINE bool candcache030 (uaecptr addr)
+{
+ // mmu mode cacheability is checked in mmu030_get/mmu030_put routines
+ return currprefs.mmu_model || ce_cachable[addr >> 16] != 0;
+}
#if VALIDATE_68030_DATACACHE
static void validate_dcache030(void)
uae_u32 v = get_long(addr);
if (v != c->data[j]) {
write_log(_T("Address %08x data cache mismatch %08x != %08x\n"), addr, v, c->data[j]);
- activate_debugger();
}
}
addr += 4;
}
#endif
-STATIC_INLINE bool cancache030 (uaecptr addr)
-{
- return ce_cachable[addr >> 16] != 0;
-}
-
// and finally the worst part, 68030 data cache..
-static void write_dcache030x(uaecptr addr, uae_u32 val, int size)
-{
- struct cache030 *c1, *c2;
- int lws1, lws2;
- uae_u32 tag1, tag2;
- int aligned = addr & 3;
- int wa = regs.cacr & 0x2000;
- int hit;
-
- if (!(regs.cacr & 0x100)) // data cache disabled?
- return;
- if (!cancache030(addr))
- return;
-
- c1 = getcache030(dcaches030, addr, &tag1, &lws1);
-
- // easy one
- if (size == 2 && aligned == 0 && wa) {
- update_cache030(c1, val, tag1, lws1);
- return;
- }
-
- hit = (c1->tag == tag1 && c1->valid[lws1]);
- if (hit || wa) {
- if (size == 2) {
- if (hit) {
- c1->data[lws1] &= ~(0xffffffff >> (aligned * 8));
- c1->data[lws1] |= val >> (aligned * 8);
- } else
- c1->valid[lws1] = false;
- } else if (size == 1) {
- if (hit) {
- c1->data[lws1] &= ~(0xffff0000 >> (aligned * 8));
- c1->data[lws1] |= (val << 16) >> (aligned * 8);
- } else
+static void write_dcache030x(uaecptr addr, uae_u32 val, uae_u32 size, uae_u32 fc)
+{
+ if (regs.cacr & 0x100) {
+ static const uae_u32 mask[3] = { 0xff000000, 0xffff0000, 0xffffffff };
+ struct cache030 *c1, *c2;
+ int lws1, lws2;
+ uae_u32 tag1, tag2;
+ int aligned = addr & 3;
+ int wa = regs.cacr & 0x2000;
+ int width = 8 << size;
+ int offset = 8 * aligned;
+ int hit;
+
+ c1 = getdcache030(dcaches030, addr, &tag1, &lws1);
+ hit = c1->tag == tag1 && c1->fc == fc && c1->valid[lws1];
+
+ // Write-allocate can create new valid cache entry if
+ // long aligned long write and MMU CI is not active.
+ // All writes ignore external CIIN signal.
+
+ if (width == 32 && offset == 0 && wa) {
+ if (mmu030_cache_inhibit <= 0) {
+ update_dcache030(c1, val, tag1, fc, lws1);
+#if VALIDATE_68030_DATACACHE
+ validate_dcache030();
+#endif
+ } else if (hit) {
+ // Does real 68030 do this if MMU cache inhibited?
c1->valid[lws1] = false;
- } else if (size == 0) {
+ }
+ return;
+ }
+
+ val <<= (32 - width);
+ if (hit || wa) {
if (hit) {
- c1->data[lws1] &= ~(0xff000000 >> (aligned * 8));
- c1->data[lws1] |= (val << 24) >> (aligned * 8);
- } else
+ c1->data[lws1] &= ~(mask[size] >> offset);
+ c1->data[lws1] |= val >> offset;
+ } else {
c1->valid[lws1] = false;
+ }
}
- }
- // do we need to update a 2nd cache entry ?
- if ((size == 0) || (size == 1 && aligned <= 2) || (size == 2 && aligned == 0))
- return;
-
- c2 = getcache030(dcaches030, addr + 4, &tag2, &lws2);
- hit = (c2->tag == tag2 && c2->valid[lws2]);
- if (hit || wa) {
- if (size == 2) {
- if (hit) {
- c2->data[lws2] &= 0xffffffff >> (aligned * 8);
- c2->data[lws2] |= val << ((4 - aligned) * 8);
- } else
- c2->valid[lws2] = false;
- } else if (size == 1) {
- if (hit) {
- c2->data[lws2] &= 0x00ffffff;
- c2->data[lws2] |= val << 24;
- } else
- c2->valid[lws2] = false;
+ // do we need to update a 2nd cache entry ?
+ if (width + offset > 32) {
+ c2 = getdcache030(dcaches030, addr + 4, &tag2, &lws2);
+ hit = c2->tag == tag2 && c2->fc == fc && c2->valid[lws2];
+ if (hit || wa) {
+ if (hit) {
+ c2->data[lws2] &= ~(mask[size] << (width + offset - 32));
+ c2->data[lws2] |= val << (width + offset - 32);
+ } else {
+ c2->valid[lws2] = false;
+ }
+ }
}
+#if VALIDATE_68030_DATACACHE
+ validate_dcache030();
+#endif
}
}
-void write_dcache030(uaecptr addr, uae_u32 v, int size)
+void write_dcache030(uaecptr addr, uae_u32 v, uae_u32 size, uae_u32 fc)
{
- write_dcache030x(addr, v, size);
- if (currprefs.cpu_memory_cycle_exact) {
- if (size == 2)
- mem_access_delay_long_write_ce020(addr, v);
- else if (size == 1)
- mem_access_delay_word_write_ce020(addr, v);
- else
- mem_access_delay_byte_write_ce020(addr, v);
- } else {
- if (size == 2)
- put_long(addr, v);
- else if (size == 1)
- put_word(addr, v);
- else
- put_byte(addr, v);
- }
-#if VALIDATE_68030_DATACACHE
- validate_dcache030();
-#endif
+ regs.fc030 = fc;
+ if (size == 2)
+ dcache030_lput(addr, v);
+ else if (size == 1)
+ dcache030_wput(addr, v);
+ else
+ dcache030_bput(addr, v);
+ write_dcache030x(addr, v, size, fc);
}
-uae_u32 read_dcache030 (uaecptr addr, int size)
+static void dcache030_maybe_burst(uaecptr addr, struct cache030 *c, int lws)
{
- struct cache030 *c1, *c2;
- int lws1, lws2;
- uae_u32 tag1, tag2;
- int aligned = addr & 3;
- uae_u32 v1, v2;
-#if VALIDATE_68030_DATACACHE
- uae_u32 addr2 = addr;
-#endif
-
- if (!(regs.cacr & 0x100) || !cancache030 (addr)) { // data cache disabled?
- if (currprefs.cpu_memory_cycle_exact) {
- if (size == 2)
- return mem_access_delay_long_read_ce020 (addr);
- else if (size == 1)
- return mem_access_delay_word_read_ce020 (addr);
- else
- return mem_access_delay_byte_read_ce020 (addr);
+ if ((c->valid[0] + c->valid[1] + c->valid[2] + c->valid[3] == 1) && ce_banktype[addr >> 16] == CE_MEMBANK_FAST32) {
+ // do burst fetch if cache enabled, not frozen, all slots invalid, no chip ram
+ int i;
+ uaecptr baddr = addr & ~15;
+ for (i = 0; i < 4; i++) {
+ if (c->valid[i])
+ break;
+ }
+ if (currprefs.mmu_model) {
+ TRY (prb) {
+ if (currprefs.cpu_cycle_exact)
+ do_cycles_ce020(3 * (CPU020_MEM_CYCLE - 1));
+ for (int j = 0; j < 3; j++) {
+ i++;
+ i &= 3;
+ c->data[i] = dcache030_lget (baddr + i * 4);
+ c->valid[i] = true;
+ }
+ } CATCH (prb) {
+ ; // abort burst fetch if bus error
+ } ENDTRY
} else {
- if (size == 2)
- return get_long (addr);
- else if (size == 1)
- return get_word (addr);
- else
- return get_byte (addr);
+ for (int j = 0; j < 3; j++) {
+ i++;
+ i &= 3;
+ c->data[i] = dcache030_lget (baddr + i * 4);
+ c->valid[i] = true;
+ }
+ if (currprefs.cpu_cycle_exact)
+ do_cycles_ce020_mem (3 * (CPU020_MEM_CYCLE - 1), c->data[i]);
}
- }
- c1 = getcache030 (dcaches030, addr, &tag1, &lws1);
- addr &= ~3;
- if (!c1->valid[lws1] || c1->tag != tag1) {
- v1 = currprefs.cpu_memory_cycle_exact ? mem_access_delay_long_read_ce020 (addr) : get_long (addr);
- update_cache030 (c1, v1, tag1, lws1);
#if VALIDATE_68030_DATACACHE
validate_dcache030();
#endif
- } else {
- v1 = c1->data[lws1];
- if (uae_boot_rom_type > 0) {
- // this check and fix is needed for UAE filesystem handler because it runs in host side and in
- // separate thread. No way to access via cache without locking that would cause major slowdown
- // and unneeded complexity
- uae_u32 tv = get_long(addr);
- if (tv != v1) {
- write_log(_T("data cache mismatch %d %d %08x %08x != %08x %08x %d PC=%08x\n"),
- size, aligned, addr, tv, v1, tag1, lws1, M68K_GETPC);
- v1 = tv;
- }
- }
}
+}
- // only one long fetch needed?
- if (size == 0) {
- v1 >>= (3 - aligned) * 8;
+#if 0
+static void uae_cache_check(uaecptr addr, uae_u32 *v, struct cache030 *c, int lws, int size)
+{
+ if (uae_boot_rom_type <= 0)
+ return;
+ // this check and fix is needed for UAE filesystem handler because it runs in host side and in
+ // separate thread. No way to access via cache without locking that would cause major slowdown
+ // and unneeded complexity
+ uae_u32 tv = get_long(addr);
+ if (tv != *v) {
+ write_log(_T("data cache mismatch %d %d %08x %08x != %08x %08x %d PC=%08x\n"),
+ size, addr, tv, v, c->tag, lws, M68K_GETPC);
+ *v = tv;
+ }
+}
+#endif
+
+uae_u32 read_dcache030 (uaecptr addr, uae_u32 size, uae_u32 fc)
+{
+ uae_u32 addr_o = addr;
+ regs.fc030 = fc;
+ if ((regs.cacr & 0x100) && !dcache_complete_inhibit) { // data cache enabled?
+ static const uae_u32 mask[3] = { 0x000000ff, 0x0000ffff, 0xffffffff };
+ struct cache030 *c1, *c2;
+ int lws1, lws2;
+ uae_u32 tag1, tag2;
+ int aligned = addr & 3;
+ uae_u32 v1, v2;
+ int width = 8 << size;
+ int offset = 8 * aligned;
+ uae_u32 out;
+
+ c1 = getdcache030 (dcaches030, addr, &tag1, &lws1);
+ addr &= ~3;
+ if (!c1->valid[lws1] || c1->tag != tag1 || c1->fc != fc) {
+ // Cache miss and caching inhibited -> normal read
+ if (mmu030_cache_inhibit || !candcache030(addr))
+ goto end;
+ // MMU validate address, returns zero if valid but uncacheable
+ // throws bus error if invalid
+ if (!dcache030_check(addr_o, false, size))
+ goto end;
+ v1 = dcache030_lget(addr);
+ update_dcache030 (c1, v1, tag1, fc, lws1);
+ if (!mmu030_cache_inhibit && (regs.cacr & 0x1100) == 0x1100)
+ dcache030_maybe_burst(addr, c1, lws1);
#if VALIDATE_68030_DATACACHE
- validate_dcache030_read(addr2, v1, size);
+ validate_dcache030();
#endif
- return v1;
- } else if (size == 1 && aligned <= 2) {
- v1 >>= (2 - aligned) * 8;
-#if VALIDATE_68030_DATACACHE
- validate_dcache030_read(addr2, v1, size);
+ } else {
+ // Cache hit, inhibited caching do not prevent read hits.
+ v1 = c1->data[lws1];
+#if 0
+ uae_cache_check(addr, &v1, c1, lws1, size);
#endif
- return v1;
- } else if (size == 2 && aligned == 0) {
- if ((regs.cacr & 0x1100) == 0x1100 && lws1 == 0 && !c1->valid[1] && !c1->valid[2] && !c1->valid[3] && ce_banktype[addr >> 16] == CE_MEMBANK_FAST32) {
- // do burst fetch if cache enabled, not frozen, all slots invalid, no chip ram
- c1->data[1] = get_long (addr + 4);
- c1->data[2] = get_long (addr + 8);
- c1->data[3] = get_long (addr + 12);
- do_cycles_ce020_mem (3 * (CPU020_MEM_CYCLE - 1), c1->data[3]);
- c1->valid[1] = c1->valid[2] = c1->valid[3] = true;
}
+
+ // only one long fetch needed?
+ if (width + offset <= 32) {
+ out = v1 >> (32 - (offset + width));
+ out &= mask[size];
#if VALIDATE_68030_DATACACHE
- validate_dcache030_read(addr2, v1, size);
- validate_dcache030();
-#endif
- return v1;
- }
- // no, need another one
- addr += 4;
- c2 = getcache030 (dcaches030, addr, &tag2, &lws2);
- if (!c2->valid[lws2] || c2->tag != tag2) {
- v2 = currprefs.cpu_memory_cycle_exact ? mem_access_delay_long_read_ce020 (addr) : get_long (addr);
- update_cache030 (c2, v2, tag2, lws2);
+ validate_dcache030_read(addr_o, out, size);
+#endif
+ return out;
+ }
+
+ // no, need another one
+ addr += 4;
+ c2 = getdcache030 (dcaches030, addr, &tag2, &lws2);
+ if (!c2->valid[lws2] || c2->tag != tag2 || c2->fc != fc) {
+ if (mmu030_cache_inhibit || !candcache030(addr))
+ goto end;
+ if (!dcache030_check(addr, false, 2))
+ goto end;
+ v2 = dcache030_lget(addr);
+ update_dcache030 (c2, v2, tag2, fc, lws2);
+ if (!mmu030_cache_inhibit && (regs.cacr & 0x1100) == 0x1100)
+ dcache030_maybe_burst(addr, c2, lws2);
#if VALIDATE_68030_DATACACHE
- validate_dcache030();
+ validate_dcache030();
#endif
- } else {
- v2 = c2->data[lws2];
- if (uae_boot_rom_type > 0) {
- uae_u32 tv = get_long(addr);
- if (tv != v2) {
- write_log (_T("data cache mismatch %d %d %08x %08x != %08x %08x %d PC=%08x\n"),
- size, aligned, addr, tv, v2, tag2, lws2, M68K_GETPC);
- v2 = tv;
- }
- }
- }
-
- uae_u32 ov;
- if (size == 1 && aligned == 3) {
- ov = (v1 << 8) | (v2 >> 24);
- } else if (size == 2 && aligned == 1) {
- ov = (v1 << 8) | (v2 >> 24);
- } else if (size == 2 && aligned == 2) {
- ov = (v1 << 16) | (v2 >> 16);
- } else if (size == 2 && aligned == 3) {
- ov = (v1 << 24) | (v2 >> 8);
- } else {
- write_log (_T("dcache030 weirdness!?\n"));
- ov = 0;
- }
+ } else {
+ v2 = c2->data[lws2];
+#if 0
+ uae_cache_check(addr, &v2, c2, lws2, size);
+#endif
+ }
+
+ uae_u64 v64 = ((uae_u64)v1 << 32) | v2;
+ out = (uae_u32)(v64 >> (64 - (offset + width)));
+ out &= mask[size];
+
#if VALIDATE_68030_DATACACHE
- validate_dcache030_read(addr2, ov, size);
+ validate_dcache030_read(addr_o, out, size);
#endif
- return ov;
+ return out;
+
+ }
+end:
+ // read from memory, data cache is disabled or inhibited.
+ if (size == 2)
+ return dcache030_lget (addr_o);
+ else if (size == 1)
+ return dcache030_wget (addr_o);
+ else
+ return dcache030_bget (addr_o);
+}
+
+uae_u32 read_dcache030_mmu(uaecptr addr, uae_u32 size)
+{
+ return read_dcache030(addr, size, (regs.s ? 4 : 0) | 1);
+}
+void write_dcache030_mmu(uaecptr addr, uae_u32 val, uae_u32 size)
+{
+ write_dcache030(addr, val, size, (regs.s ? 4 : 0) | 1);
+}
+
+uae_u32 read_dcache030_lrmw_mmu(uaecptr addr, uae_u32 size)
+{
+ mmu030_cache_inhibit = 1;
+ return read_dcache030(addr, size, (regs.s ? 4 : 0) | 1);
+}
+void write_dcache030_lrmw_mmu(uaecptr addr, uae_u32 val, uae_u32 size)
+{
+ mmu030_cache_inhibit = 1;
+ write_dcache030(addr, val, size, (regs.s ? 4 : 0) | 1);
+}
+
+static void do_access_or_bus_error(uaecptr pc, uaecptr pcnow)
+{
+ // TODO: handle external bus errors
+ if (!currprefs.mmu_model)
+ return;
+ if (pc != 0xffffffff)
+ regs.instruction_pc = pc;
+ mmu030_opcode = -1;
+ mmu030_page_fault(pcnow, true, -1, 0);
}
static uae_u32 get_word_ce030_prefetch_2 (int o)
uae_u32 pc = m68k_getpc () + o;
uae_u32 v;
- if (pc & 2) {
- v = regs.prefetch020[0] & 0xffff;
+ v = regs.prefetch020[0];
+ regs.prefetch020[0] = regs.prefetch020[1];
+ regs.prefetch020[1] = regs.prefetch020[2];
#if MORE_ACCURATE_68020_PIPELINE
- pipeline_020(regs.prefetch020[1], pc);
+ pipeline_020(pc);
#endif
- regs.prefetch020[0] = regs.prefetch020[1];
+ if (pc & 2) {
// branch instruction detected in pipeline: stop fetches until branch executed.
if (!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) {
fill_icache030 (pc + 2 + 4);
- regs.prefetch020[1] = regs.cacheholdingdata020;
+ } else {
+ if (regs.cacheholdingdata_valid > 0)
+ regs.cacheholdingdata_valid++;
}
+ regs.prefetch020[2] = regs.cacheholdingdata020 >> 16;
} else {
- v = regs.prefetch020[0] >> 16;
-#if MORE_ACCURATE_68020_PIPELINE
- pipeline_020(regs.prefetch020[1] >> 16, pc);
-#endif
+ pc += 4;
+ // cacheholdingdata020 may be invalid if RTE from bus error
+ if ((!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) && regs.cacheholdingaddr020 != pc) {
+ fill_icache030 (pc);
+ }
+ regs.prefetch020[2] = (uae_u16)regs.cacheholdingdata020;
}
+ regs.db = regs.prefetch020[0];
do_cycles_ce020_internal (2);
return v;
}
return get_word_ce030_prefetch_2(o);
}
-uae_u32 get_word_030_prefetch(int o)
+uae_u32 get_word_030_prefetch (int o)
{
- uae_u32 pc = m68k_getpc() + o;
+ uae_u32 pc = m68k_getpc () + o;
uae_u32 v;
- if (pc & 2) {
- v = regs.prefetch020[0] & 0xffff;
+ v = regs.prefetch020[0];
+ regs.prefetch020[0] = regs.prefetch020[1];
+ regs.prefetch020[1] = regs.prefetch020[2];
+ if (!regs.prefetch020_valid[1]) {
+ do_access_or_bus_error(0xffffffff, pc);
+ }
#if MORE_ACCURATE_68020_PIPELINE
- pipeline_020(regs.prefetch020[1], pc);
+ pipeline_020(pc);
#endif
- regs.prefetch020[0] = regs.prefetch020[1];
+ if (pc & 2) {
// branch instruction detected in pipeline: stop fetches until branch executed.
if (!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) {
- fill_icache030(pc + 2 + 4);
- regs.prefetch020[1] = regs.cacheholdingdata020;
+ fill_icache030 (pc + 2 + 4);
+ } else {
+ if (regs.cacheholdingdata_valid > 0)
+ regs.cacheholdingdata_valid++;
}
+ regs.prefetch020[2] = regs.cacheholdingdata020 >> 16;
} else {
- v = regs.prefetch020[0] >> 16;
-#if MORE_ACCURATE_68020_PIPELINE
- pipeline_020(regs.prefetch020[1] >> 16, pc);
-#endif
+ pc += 4;
+ // cacheholdingdata020 may be invalid if RTE from bus error
+ if ((!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) && regs.cacheholdingaddr020 != pc) {
+ fill_icache030 (pc);
+ }
+ regs.prefetch020[2] = (uae_u16)regs.cacheholdingdata020;
}
+ regs.prefetch020_valid[2] = regs.cacheholdingdata_valid;
+ regs.db = regs.prefetch020[0];
return v;
}
}
}
-void fill_prefetch_030_ntx (void)
+static void reset_pipeline_state(void)
+{
+#if MORE_ACCURATE_68020_PIPELINE
+ regs.pipeline_pos = 0;
+ regs.pipeline_stop = 0;
+ regs.pipeline_r8[0] = regs.pipeline_r8[1] = -1;
+#endif
+}
+
+static int add_prefetch_030(int idx, uae_u16 w, uaecptr pc)
+{
+ regs.prefetch020[0] = regs.prefetch020[1];
+ regs.prefetch020_valid[0] = regs.prefetch020_valid[1];
+ regs.prefetch020[1] = regs.prefetch020[2];
+ regs.prefetch020_valid[1] = regs.prefetch020_valid[2];
+ regs.prefetch020[2] = w;
+ regs.prefetch020_valid[2] = regs.cacheholdingdata_valid;
+
+#if MORE_ACCURATE_68020_PIPELINE
+ if (idx >= 1) {
+ pipeline_020(pc);
+ }
+#endif
+
+ if (!regs.prefetch020_valid[2]) {
+ if (idx == 0 || !regs.pipeline_stop) {
+ // Pipeline refill and first opcode word is invalid?
+ // Generate previously detected bus error/MMU fault
+ do_access_or_bus_error(pc, pc + idx * 2);
+ }
+ }
+ return idx + 1;
+}
+
+void fill_prefetch_030_ntx(void)
{
uaecptr pc = m68k_getpc ();
uaecptr pc2 = pc;
+ int idx = 0;
+
pc &= ~3;
- regs.pipeline_pos = 0;
- regs.pipeline_stop = 0;
+ mmu030_idx = 0;
+ reset_pipeline_state();
+ regs.cacheholdingdata_valid = 1;
+ regs.cacheholdingaddr020 = 0xffffffff;
+ regs.prefetch020_valid[0] = regs.prefetch020_valid[1] = regs.prefetch020_valid[2] = 0;
- fill_icache030 (pc);
+ fill_icache030(pc);
if (currprefs.cpu_cycle_exact)
do_cycles_ce020_internal(2);
- regs.prefetch020[0] = regs.cacheholdingdata020;
+ if (pc2 & 2) {
+ idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc2);
+ } else {
+ idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc2);
+ idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc2);
+ }
- fill_icache030 (pc + 4);
+ fill_icache030(pc + 4);
if (currprefs.cpu_cycle_exact)
do_cycles_ce020_internal(2);
- regs.prefetch020[1] = regs.cacheholdingdata020;
-
-#if MORE_ACCURATE_68020_PIPELINE
if (pc2 & 2) {
- pipeline_020(regs.prefetch020[0], pc);
- pipeline_020(regs.prefetch020[1] >> 16, pc);
+ idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc2);
+ idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc2);
} else {
- pipeline_020(regs.prefetch020[0] >> 16, pc);
- pipeline_020(regs.prefetch020[0], pc);
+ idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc2);
}
+
+ if (currprefs.cpu_cycle_exact)
+ regs.irc = get_word_ce030_prefetch_opcode (0);
+ else
+ regs.irc = get_word_030_prefetch (0);
+}
+
+void fill_prefetch_030_ntx_continue (void)
+{
+ uaecptr pc = m68k_getpc ();
+ uaecptr pc_orig = pc;
+ int idx = 0;
+
+ mmu030_idx = 0;
+ reset_pipeline_state();
+ regs.cacheholdingdata_valid = 1;
+ regs.cacheholdingaddr020 = 0xffffffff;
+
+ for (int i = 2; i >= 0; i--) {
+ if (!regs.prefetch020_valid[i])
+ break;
+#if MORE_ACCURATE_68020_PIPELINE
+ if (idx >= 1) {
+ pipeline_020(pc);
+ }
#endif
+ pc += 2;
+ idx++;
+ }
+
+ if (idx < 3 && !regs.pipeline_stop) {
+ uaecptr pc2 = pc;
+ pc &= ~3;
+
+ fill_icache030(pc);
+ if (currprefs.cpu_cycle_exact)
+ do_cycles_ce020_internal(2);
+ if (pc2 & 2) {
+ idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc_orig);
+ } else {
+ idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc_orig);
+ if (idx < 3)
+ idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc_orig);
+ }
+
+ if (idx < 3) {
+ fill_icache030(pc + 4);
+ if (currprefs.cpu_cycle_exact)
+ do_cycles_ce020_internal(2);
+ if (pc2 & 2) {
+ idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc_orig);
+ if (idx < 3)
+ idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc_orig);
+ } else {
+ idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc_orig);
+ }
+ }
+ }
if (currprefs.cpu_cycle_exact)
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)
{
uaecptr pc = m68k_getpc ();
uaecptr pc2 = pc;
+ int idx = 0;
+
pc &= ~3;
- uae_u32 (*fetch)(uaecptr) = currprefs.cpu_memory_cycle_exact ? mem_access_delay_longi_read_ce020 : get_longi;
- regs.pipeline_pos = 0;
- regs.pipeline_stop = 0;
- regs.pipeline_r8[0] = regs.pipeline_r8[1] = -1;
+ reset_pipeline_state();
- fill_icache020 (pc, fetch, true);
+ fill_icache020 (pc, true);
if (currprefs.cpu_cycle_exact)
do_cycles_ce020_internal(2);
- regs.prefetch020[0] = regs.cacheholdingdata020;
+ if (pc2 & 2) {
+ idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc);
+ } else {
+ idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc);
+ idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc);
+ }
- fill_icache020 (pc + 4, fetch, true);
+ fill_icache020 (pc + 4, true);
if (currprefs.cpu_cycle_exact)
do_cycles_ce020_internal(2);
- regs.prefetch020[1] = regs.cacheholdingdata020;
-
-#if MORE_ACCURATE_68020_PIPELINE
if (pc2 & 2) {
- pipeline_020(regs.prefetch020[0], pc);
- pipeline_020(regs.prefetch020[1] >> 16, pc);
+ idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc);
+ idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc);
} else {
- pipeline_020(regs.prefetch020[0] >> 16, pc);
- pipeline_020(regs.prefetch020[0], pc);
+ idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc);
}
-#endif
if (currprefs.cpu_cycle_exact)
regs.irc = get_word_ce020_prefetch_opcode (0);
void fill_prefetch (void)
{
- regs.pipeline_pos = 0;
+ reset_pipeline_state();
if (currprefs.cachesize)
return;
if (!currprefs.cpu_compatible)