st |= f; \
mmu030_state[1] = st;
-static void mmu030_unaligned_read_continue(uaecptr addr, int fc)
+typedef uae_u32(*unaligned_read_func)(uaecptr addr, uae_u32 fc, int size, int flags);
+
+static void mmu030_unaligned_read_continue(uaecptr addr, int fc, unaligned_read_func func)
{
uae_u32 st = mmu030_state[1];
// odd long access: byte + word + byte
if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) {
mmu030_data_buffer_out &= 0x00ffffff;
- mmu030_data_buffer_out |= mmu030_get_generic(addr, fc, sz_byte, MMU030_SSW_SIZE_L) << 24;
+ mmu030_data_buffer_out |= func(addr, fc, sz_byte, MMU030_SSW_SIZE_L) << 24;
unalign_done(MMU030_STATEFLAG1_SUBACCESS1);
addr++;
}
if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) {
mmu030_data_buffer_out &= 0xff0000ff;
- mmu030_data_buffer_out |= mmu030_get_generic(addr, fc, sz_word, MMU030_SSW_SIZE_W) << 8;
+ mmu030_data_buffer_out |= func(addr, fc, sz_word, MMU030_SSW_SIZE_W) << 8;
unalign_done(MMU030_STATEFLAG1_SUBACCESS2);
addr += 2;
}
if (!(st & MMU030_STATEFLAG1_SUBACCESS3)) {
mmu030_data_buffer_out &= 0xffffff00;
- mmu030_data_buffer_out |= mmu030_get_generic(addr, fc, sz_byte, MMU030_SSW_SIZE_B) << 0;
+ mmu030_data_buffer_out |= func(addr, fc, sz_byte, MMU030_SSW_SIZE_B) << 0;
unalign_done(MMU030_STATEFLAG1_SUBACCESS3);
}
} else {
// even but unaligned long access: word + word
if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) {
mmu030_data_buffer_out &= 0x0000ffff;
- mmu030_data_buffer_out |= mmu030_get_generic(addr, fc, sz_word, MMU030_SSW_SIZE_L) << 16;
+ mmu030_data_buffer_out |= func(addr, fc, sz_word, MMU030_SSW_SIZE_L) << 16;
unalign_done(MMU030_STATEFLAG1_SUBACCESS1);
addr += 2;
}
if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) {
mmu030_data_buffer_out &= 0xffff0000;
- mmu030_data_buffer_out |= mmu030_get_generic(addr, fc, sz_word, MMU030_SSW_SIZE_W) << 0;
+ mmu030_data_buffer_out |= func(addr, fc, sz_word, MMU030_SSW_SIZE_W) << 0;
unalign_done(MMU030_STATEFLAG1_SUBACCESS2);
}
}
// odd word access: byte + byte
if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) {
mmu030_data_buffer_out &= 0x00ff;
- mmu030_data_buffer_out |= mmu030_get_generic(addr, fc, sz_byte, MMU030_SSW_SIZE_W) << 8;
+ mmu030_data_buffer_out |= func(addr, fc, sz_byte, MMU030_SSW_SIZE_W) << 8;
unalign_done(MMU030_STATEFLAG1_SUBACCESS1);
addr++;
}
if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) {
mmu030_data_buffer_out &= 0xff00;
- mmu030_data_buffer_out |= mmu030_get_generic(addr, fc, sz_byte, MMU030_SSW_SIZE_B) << 0;
+ mmu030_data_buffer_out |= func(addr, fc, sz_byte, MMU030_SSW_SIZE_B) << 0;
unalign_done(MMU030_STATEFLAG1_SUBACCESS2);
}
}
#endif
}
-static void mmu030_unaligned_write_continue(uaecptr addr, int fc)
+typedef void (*unaligned_write_func)(uaecptr addr, uae_u32 val, uae_u32 fc, int size, int flags);
+
+static void mmu030_unaligned_write_continue(uaecptr addr, int fc, unaligned_write_func func)
{
uae_u32 st = mmu030_state[1];
// odd long access: byte + word + byte
if (st & MMU030_STATEFLAG1_SUBACCESSX) {
if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) {
- mmu030_put_generic(addr, mmu030_data_buffer_out >> 24, fc, sz_byte, MMU030_SSW_SIZE_L);
+ func(addr, mmu030_data_buffer_out >> 24, fc, sz_byte, MMU030_SSW_SIZE_L);
unalign_done(MMU030_STATEFLAG1_SUBACCESS1);
addr++;
}
if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) {
- mmu030_put_generic(addr, mmu030_data_buffer_out >> 8, fc, sz_word, MMU030_SSW_SIZE_W);
+ func(addr, mmu030_data_buffer_out >> 8, fc, sz_word, MMU030_SSW_SIZE_W);
unalign_done(MMU030_STATEFLAG1_SUBACCESS2);
addr += 2;
}
if (!(st & MMU030_STATEFLAG1_SUBACCESS3)) {
- mmu030_put_generic(addr, mmu030_data_buffer_out >> 0, fc, sz_byte, MMU030_SSW_SIZE_B);
+ func(addr, mmu030_data_buffer_out >> 0, fc, sz_byte, MMU030_SSW_SIZE_B);
unalign_done(MMU030_STATEFLAG1_SUBACCESS3);
}
} else {
// even but unaligned long access: word + word
if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) {
- mmu030_put_generic(addr, mmu030_data_buffer_out >> 16, fc, sz_word, MMU030_SSW_SIZE_L);
+ func(addr, mmu030_data_buffer_out >> 16, fc, sz_word, MMU030_SSW_SIZE_L);
unalign_done(MMU030_STATEFLAG1_SUBACCESS1);
addr += 2;
}
if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) {
- mmu030_put_generic(addr, mmu030_data_buffer_out >> 0, fc, sz_word, MMU030_SSW_SIZE_W);
+ func(addr, mmu030_data_buffer_out >> 0, fc, sz_word, MMU030_SSW_SIZE_W);
unalign_done(MMU030_STATEFLAG1_SUBACCESS2);
}
}
} else {
// odd word access: byte + byte
if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) {
- mmu030_put_generic(addr, mmu030_data_buffer_out >> 8, fc, sz_byte, MMU030_SSW_SIZE_W);
+ func(addr, mmu030_data_buffer_out >> 8, fc, sz_byte, MMU030_SSW_SIZE_W);
unalign_done(MMU030_STATEFLAG1_SUBACCESS1);
addr++;
}
if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) {
- mmu030_put_generic(addr, mmu030_data_buffer_out >> 0, fc, sz_byte, MMU030_SSW_SIZE_B);
+ func(addr, mmu030_data_buffer_out >> 0, fc, sz_byte, MMU030_SSW_SIZE_B);
unalign_done(MMU030_STATEFLAG1_SUBACCESS2);
}
}
mmu030_data_buffer_out = mmu030_ad[idxsize].val;
}
if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0) {
- mmu030_unaligned_read_continue(addr, fc);
+ mmu030_unaligned_read_continue(addr, fc, mmu030_get_generic);
} else {
switch (size)
{
}
} else {
if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0) {
- mmu030_unaligned_write_continue(addr, fc);
+ mmu030_unaligned_write_continue(addr, fc, mmu030_put_generic);
} else {
switch (size)
{
mmu030_data_buffer_out = mmu030_ad[idxsize].val;
}
if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0) {
- mmu030_unaligned_read_continue(addr, fc);
+ mmu030_unaligned_read_continue(addr, fc, read_dcache030_retry);
} else {
switch (size)
{
}
} else {
if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0) {
- mmu030_unaligned_write_continue(addr, fc);
+ mmu030_unaligned_write_continue(addr, fc, write_dcache030_retry);
} else {
switch (size)
{
extern void write_dcache030_bput(uaecptr, uae_u32, uae_u32);
extern void write_dcache030_wput(uaecptr, uae_u32, uae_u32);
extern void write_dcache030_lput(uaecptr, uae_u32, uae_u32);
+extern void write_dcache030_retry(uaecptr addr, uae_u32 v, uae_u32 fc, int size, int flags);
extern uae_u32 read_dcache030_bget(uaecptr, uae_u32);
extern uae_u32 read_dcache030_wget(uaecptr, uae_u32);
extern uae_u32 read_dcache030_lget(uaecptr, uae_u32);
+extern uae_u32 read_dcache030_retry(uaecptr addr, uae_u32 fc, int size, int flags);
extern void write_dcache030_mmu_bput(uaecptr, uae_u32);
extern void write_dcache030_mmu_wput(uaecptr, uae_u32);
write_dcache030x(addr, v, 2, fc);
}
+// 68030 MMU bus fault retry case, direct write, store to cache if enabled
+void write_dcache030_retry(uaecptr addr, uae_u32 v, uae_u32 fc, int size, int flags)
+{
+ regs.fc030 = fc;
+ mmu030_put_generic(addr, v, fc, size, flags);
+ write_dcache030x(addr, v, size, fc);
+}
+
static void dcache030_maybe_burst(uaecptr addr, struct cache030 *c, int lws)
{
if ((c->valid[0] + c->valid[1] + c->valid[2] + c->valid[3] == 1) && ce_banktype[addr >> 16] == CE_MEMBANK_FAST32) {
return out;
}
-uae_u32 read_dcache030 (uaecptr addr, uae_u32 size, uae_u32 fc)
+static bool read_dache030_2(uaecptr addr, uae_u32 size, uae_u32 *valp)
{
+ // data cache enabled?
+ if (!(regs.cacr & 0x100))
+ return false;
+
uae_u32 addr_o = addr;
- regs.fc030 = fc;
- if (regs.cacr & 0x100) { // 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) {
- // MMU validate address, returns zero if valid but uncacheable
- // throws bus error if invalid
- uae_u8 cs = dcache_check(addr_o, false, size);
- if (!(cs & CACHE_ENABLE_DATA))
- goto end;
- v1 = dcache_lget(addr);
- update_dcache030 (c1, v1, tag1, fc, lws1);
- if ((cs & CACHE_ENABLE_DATA_BURST) && (regs.cacr & 0x1100) == 0x1100)
- dcache030_maybe_burst(addr, c1, lws1);
+ uae_u32 fc = regs.fc030;
+ 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) {
+ // MMU validate address, returns zero if valid but uncacheable
+ // throws bus error if invalid
+ uae_u8 cs = dcache_check(addr_o, false, size);
+ if (!(cs & CACHE_ENABLE_DATA))
+ return false;
+ v1 = dcache_lget(addr);
+ update_dcache030(c1, v1, tag1, fc, lws1);
+ if ((cs & CACHE_ENABLE_DATA_BURST) && (regs.cacr & 0x1100) == 0x1100)
+ dcache030_maybe_burst(addr, c1, lws1);
#if VALIDATE_68030_DATACACHE
- validate_dcache030();
+ validate_dcache030();
#endif
- } else {
- // Cache hit, inhibited caching do not prevent read hits.
- v1 = c1->data[lws1];
- }
+ } else {
+ // Cache hit, inhibited caching do not prevent read hits.
+ v1 = c1->data[lws1];
+ }
- // only one long fetch needed?
- if (width + offset <= 32) {
- out = v1 >> (32 - (offset + width));
- out &= mask[size];
+ // only one long fetch needed?
+ if (width + offset <= 32) {
+ out = v1 >> (32 - (offset + width));
+ out &= mask[size];
#if VALIDATE_68030_DATACACHE
- 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) {
- uae_u8 cs = dcache_check(addr, false, 2);
- if (!(cs & CACHE_ENABLE_DATA))
- goto end;
- v2 = dcache_lget(addr);
- update_dcache030 (c2, v2, tag2, fc, lws2);
- if ((cs & CACHE_ENABLE_DATA_BURST) && (regs.cacr & 0x1100) == 0x1100)
- dcache030_maybe_burst(addr, c2, lws2);
+ validate_dcache030_read(addr_o, out, size);
+#endif
+ *valp = out;
+ return true;
+ }
+
+ // no, need another one
+ addr += 4;
+ c2 = getdcache030(dcaches030, addr, &tag2, &lws2);
+ if (!c2->valid[lws2] || c2->tag != tag2 || c2->fc != fc) {
+ uae_u8 cs = dcache_check(addr, false, 2);
+ if (!(cs & CACHE_ENABLE_DATA))
+ return false;
+ v2 = dcache_lget(addr);
+ update_dcache030(c2, v2, tag2, fc, lws2);
+ if ((cs & CACHE_ENABLE_DATA_BURST) && (regs.cacr & 0x1100) == 0x1100)
+ dcache030_maybe_burst(addr, c2, lws2);
#if VALIDATE_68030_DATACACHE
- validate_dcache030();
+ validate_dcache030();
#endif
- } else {
- v2 = c2->data[lws2];
- }
+ } else {
+ v2 = c2->data[lws2];
+ }
- uae_u64 v64 = ((uae_u64)v1 << 32) | v2;
- out = (uae_u32)(v64 >> (64 - (offset + width)));
- out &= mask[size];
+ 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(addr_o, out, size);
+ validate_dcache030_read(addr_o, out, size);
#endif
- return out;
+ *valp = out;
+ return true;
+}
+
+uae_u32 read_dcache030 (uaecptr addr, uae_u32 size, uae_u32 fc)
+{
+ uae_u32 val;
+ regs.fc030 = fc;
+ if (!read_dache030_2(addr, size, &val)) {
+ // read from memory, data cache is disabled or inhibited.
+ if (size == 2)
+ return dcache_lget(addr);
+ else if (size == 1)
+ return dcache_wget(addr);
+ else
+ return dcache_bget(addr);
}
-end:
- // read from memory, data cache is disabled or inhibited.
- if (size == 2)
- return dcache_lget (addr_o);
- else if (size == 1)
- return dcache_wget (addr_o);
- else
- return dcache_bget (addr_o);
+ return val;
}
+
+// 68030 MMU bus fault retry case, either read from cache or use direct reads
+uae_u32 read_dcache030_retry(uaecptr addr, uae_u32 fc, int size, int flags)
+{
+ uae_u32 val;
+ regs.fc030 = fc;
+
+ if (!read_dache030_2(addr, size, &val)) {
+ return mmu030_get_generic(addr, fc, size, flags);
+ }
+ return val;
+}
+
uae_u32 read_dcache030_bget(uaecptr addr, uae_u32 fc)
{
return read_dcache030(addr, 0, fc);