// if CPU is 68030 and faulted access' addressing mode was -(an) or (an)+
// register content is not restored when exception starts.
-static void mmu030fixupreg(int i)
+static uae_u8 mmu030fixupreg(int i)
{
struct mmufixup *m = &mmufixup[i];
+ uae_u8 v = 0;
if (m->reg < 0)
+ return v;
+ if (!(m->reg & 0x300))
+ return v;
+ v = m->reg & 7;
+ v |= ((m->reg >> 10) & 3) << 3; // size
+ if (m->reg & 0x200) // -(an)?
+ v |= 1 << 5;
+ v |= 1 << 6;
+ return v;
+}
+
+static void mmu030fixupmod(uae_u8 data, int dir, int idx)
+{
+ if (!data)
return;
- int size = 1 << ((m->reg >> 10) & 3);
- if (m->reg & 0x100) {
- m68k_areg(regs, m->reg & 15) += size;
- }
- if (m->reg & 0x200) {
- m68k_areg(regs, m->reg & 15) -= size;
+ int reg = data & 7;
+ int adj = (data & (1 << 5)) ? -1 : 1;
+ if (dir)
+ adj = -adj;
+ adj <<= (data >> 3) & 3;
+ m68k_areg(regs, reg) += adj;
+ if (idx >= 0) {
+ struct mmufixup *m = &mmufixup[idx];
+ m->value += adj;
}
}
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);
}
+ regs.wb3_status = 0;
+ regs.wb2_status = 0;
regs.mmu_fault_addr = addr;
if (fc & 1) {
regs.mmu_ssw = MMU030_SSW_DF | (MMU030_SSW_DF << 1);
+ if (!(mmu030_state[1] & MMU030_STATEFLAG1_LASTWRITE)) {
+ regs.wb2_status = mmu030fixupreg(0);
+ mmu030fixupmod(regs.wb2_status, 0, 0);
+ regs.wb3_status = mmu030fixupreg(1);
+ mmu030fixupmod(regs.wb3_status, 0, 1);
+ }
} else {
if (currprefs.cpu_compatible) {
if (regs.prefetch020_valid[1] != 1 && regs.prefetch020_valid[2] == 1) {
} else {
regs.mmu_ssw = MMU030_SSW_FB | MMU030_SSW_RB;
}
- if (!(mmu030_state[1] & MMU030_STATEFLAG1_LASTWRITE)) {
- mmu030fixupreg(0);
- mmu030fixupreg(1);
- }
}
regs.mmu_ssw |= read ? MMU030_SSW_RW : 0;
regs.mmu_ssw |= flags;
}
uae_u16 v = get_word_mmu030(a7 + 0x36);
- idxsize = v & 0xff;
- idxsize_done = (v >> 8) & 0xff;
+ idxsize = v & 0x0f;
+ idxsize_done = (v >> 4) & 0x0f;
for (int i = 0; i < idxsize_done + 1; i++) {
mmu030_ad_v[i].val = get_long_mmu030(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
}
uae_u16 v = get_word_mmu030c(a7 + 0x36);
- idxsize = v & 0xff;
- idxsize_done = (v >> 8) & 0xff;
+ idxsize = v & 0x0f;
+ idxsize_done = (v >> 4) & 0x0f;
for (int i = 0; i < idxsize_done + 1; i++) {
mmu030_ad_v[i].val = get_long_mmu030c(a7 + 0x5c - (i + 1) * 4);
}
}
// version & internal information (We store index here)
m68k_areg(regs, 7) -= 2;
- x_put_word(m68k_areg(regs, 7), (mmu030_idx & 0xff) | ((mmu030_idx_done & 0xff) << 8));
+ x_put_word(m68k_areg(regs, 7), (mmu030_idx & 0xf) | ((mmu030_idx_done & 0xf) << 4) | (regs.wb2_status << 8));
// 3* internal registers
m68k_areg(regs, 7) -= 2;
- x_put_word(m68k_areg(regs, 7), mmu030_state[2]);
+ x_put_word(m68k_areg(regs, 7), mmu030_state[2] | (regs.wb3_status << 8));
m68k_areg(regs, 7) -= 2;
x_put_word(m68k_areg(regs, 7), regs.wb2_address); // = mmu030_state[1]
m68k_areg(regs, 7) -= 2;