}
addcycles000(8);
out("regs.sr %c= src;\n", curi->mnemo == i_ORSR ? '|' : curi->mnemo == i_ANDSR ? '&' : '^');
- makefromsr_t0();
+ if (cpu_level < 5 && curi->size == sz_word) {
+ makefromsr_t0();
+ } else {
+ makefromsr();
+ }
sync_m68k_pc();
- fill_prefetch_full_ntx(3);
- next_level_000();
+ if (cpu_level < 2 || curi->size == sz_word) {
+ fill_prefetch_full_ntx(3);
+ } else {
+ fill_prefetch_next();
+ }
+ next_cpu_level = cpu_level - 1;
break;
case i_SUB:
{
break;
case i_MV2SR: // MOVE TO SR
genamode(curi, curi->smode, "srcreg", sz_word, "src", 1, 0, 0);
- if (cpu_level == 0)
+ if (cpu_level == 0) {
out("int t1 = regs.t1;\n");
+ }
if (curi->size == sz_byte) {
// MOVE TO CCR
addcycles000(4);
out("MakeSR();\nregs.sr &= 0xFF00;\nregs.sr |= src & 0xFF;\n");
+ makefromsr();
} else {
// MOVE TO SR
check_trace();
addcycles000(4);
out("regs.sr = src;\n");
+ makefromsr_t0();
+ }
+ if (cpu_level >= 2 && curi->size == sz_byte) {
+ fill_prefetch_next();
+ } else {
+ // does full prefetch because S-bit change may change memory mapping under the CPU
+ sync_m68k_pc();
+ fill_prefetch_full_ntx(3);
}
- makefromsr_t0();
- // does full prefetch because S-bit change may change memory mapping under the CPU
- sync_m68k_pc();
- fill_prefetch_full_ntx(3);
next_level_000();
break;
case i_SWAP:
}
} else {
out("uaecptr oldpc = %s;\n", getpc);
- out("uae_u16 newsr; uae_u32 newpc;\n");
+ out("uae_u16 oldsr = regs.sr, newsr;\n");
+ out("uae_u32 newpc;\n");
out("for (;;) {\n");
out("uaecptr a = m68k_areg(regs, 7);\n");
out("uae_u16 sr = %s(a);\n", srcw);
out("else if (frame == 0xb) {\nm68k_areg(regs, 7) += offset + 84; break; }\n");
}
}
+ out("else {\n");
if (cpu_level == 1) {
- out("else {\n");
out("SET_NFLG(((uae_s16)format) < 0); \n");
out("SET_ZFLG(format == 0);\n");
out("SET_VFLG(0);\n");
out("Exception_cpu(14);\n");
write_return_cycles(0);
- out("}\n");
+ } else if (cpu_level == 0) {
+ out("Exception_cpu(14);\n");
+ write_return_cycles(0);
+ } else if (cpu_level == 3) {
+ // 68030: trace bits are cleared
+ out("regs.t1 = regs.t0 = 0;\n");
+ out("Exception_cpu(14);\n");
+ write_return_cycles(0);
} else {
- out("else {\n");
out("Exception_cpu(14);\n");
write_return_cycles(0);
- out("}\n");
}
- out("regs.sr = newsr;\n");
+ out("}\n");
+ out("regs.sr = newsr;\n");
+ out("oldsr = newsr;\n");
makefromsr_t0();
out("}\n");
+ out("MakeFromSR_intmask(regs.sr, newsr);\n");
out("regs.sr = newsr;\n");
addcycles_ce020 (4);
makefromsr_t0();
out("if (newpc & 1) {\n");
- out("exception3_read_prefetch(opcode, newpc);\n");
+ if (cpu_level == 5) {
+ out("regs.sr = oldsr & 0xff00;\n");
+ makefromsr();
+ out("SET_ZFLG(newsr == 0);\n");
+ out("SET_NFLG(newsr & 0x8000);\n");
+ out("exception3_read_prefetch(opcode, newpc);\n");
+ } else if (cpu_level == 4) {
+ makefromsr();
+ out("exception3_read_prefetch_68040bug(opcode, newpc, oldsr);\n");
+ } else {
+ out("exception3_read_prefetch(opcode, newpc);\n");
+ }
write_return_cycles(0);
out("}\n");
setpc ("newpc");
if (cpu_level >= 4) {
out("if (pc & 1) {\n");
out("m68k_areg(regs, 7) -= 6;\n");
- out("exception3_read_prefetch(opcode, pc);\n");
+ if (cpu_level == 5) {
+ out("regs.sr &= 0xFF00; sr &= 0xFF;\n");
+ out("regs.sr |= sr;\n");
+ makefromsr();
+ out("exception3_read_prefetch(opcode, pc);\n");
+ } else {
+ // stacked SR is original SR. Real SR has CCR part zeroed.
+ out("uae_u16 oldsr = regs.sr;\n");
+ out("regs.sr &= 0xFF00; sr &= 0xFF;\n");
+ out("regs.sr |= sr;\n");
+ makefromsr();
+ out("exception3_read_prefetch_68040bug(opcode, pc, oldsr);\n");
+ }
write_return_cycles(0);
out("}\n");
}
}
branch_inst = 1;
tail_ce020_done = true;
- next_level_040_to_030();
+ next_cpu_level = cpu_level - 1;
break;
case i_JSR:
{
out("if (s & 1) {\n");
if (cpu_level < 4)
out("m68k_areg(regs, 7) -= 4;\n");
- out("exception3_read_prefetch(opcode, s);\n");
+ out("exception3_read_prefetch(opcode, oldpc + s);\n");
write_return_cycles(0);
out("}\n");
}
write_return_cycles(0);
out("}\n");
addcycles000(4);
- trace_t0_68040_only();
break;
case i_MOVE2C:
if (cpu_level == 1) {
next_cpu_level = 2 - 1;
genastore_tas("src", curi->smode, "srcreg", curi->size, "src");
fill_prefetch_next();
- trace_t0_68040_only();
}
next_level_000();
break;
static bool last_notinstruction_for_exception_3;
/* set when writing exception stack frame */
static int exception_in_exception;
+/* secondary SR for handling 68040 bug */
+static uae_u16 last_sr_for_exception3;
static void exception3_read_special(uae_u32 opcode, uaecptr addr, int size, int fc);
MakeFromSR_x(0);
}
+void REGPARAM2 MakeFromSR_intmask(uae_u16 oldsr, uae_u16 newsr)
+{
+#if 0
+ int oldlvl = (oldsr >> 8) & 7;
+ int newlvl = (newsr >> 8) & 7;
+ int ilvl = intlev();
+
+ // interrupt mask lowered and allows new interrupt to start?
+ if (newlvl < oldlvl && ilvl > 0 && ilvl > newlvl && ilvl <= oldlvl) {
+ if (currprefs.cpu_model >= 68020) {
+ unset_special(SPCFLAG_INT);
+ }
+ }
+#endif
+}
+
+static bool internalexception(int nr)
+{
+ return nr == 5 || nr == 6 || nr == 7 || (nr >= 32 && nr <= 47);
+}
+
static void exception_check_trace (int nr)
{
unset_special (SPCFLAG_TRACE | SPCFLAG_DOTRACE);
if (regs.t1) {
/* trace stays pending if exception is div by zero, chk,
- * trapv or trap #x
+ * trapv or trap #x. Except if 68040 or 68060.
*/
- if (nr == 5 || nr == 6 || nr == 7 || (nr >= 32 && nr <= 47))
- set_special (SPCFLAG_DOTRACE);
+ if (currprefs.cpu_model < 68040 && internalexception(nr)) {
+ set_special(SPCFLAG_DOTRACE);
+ }
// 68010 and RTE format error: trace is not cleared
- if (nr == 14 && currprefs.cpu_model == 68010)
+ if (nr == 14 && currprefs.cpu_model == 68010) {
set_special(SPCFLAG_DOTRACE);
-
+ }
}
regs.t1 = regs.t0 = 0;
}
*/
-static void exception3f(uae_u32 opcode, uaecptr addr, bool writeaccess, bool instructionaccess, bool notinstruction, uaecptr pc, int size, int fc);
-
static int iack_cycle(int nr)
{
int vector;
regs.irc = regs.read_buffer;
exception3_read_access(regs.opcode, newpc, sz_word, 2);
} else {
+ exception_check_trace(nr);
exception3_notinstruction(regs.ir, newpc);
}
return;
if (currprefs.cpu_model == 68060 && interrupt) {
regs.m = 0;
}
+ if (currprefs.cpu_model == 68040 && nr == 3 && (last_op_for_exception_3 & 0x10000)) {
+ // Weird 68040 bug with RTR and RTE. New SR when exception starts. Stacked SR is different!
+ // Just replace it in stack, it is safe enough because we are in address error exception
+ // any other exception would halt the CPU.
+ x_put_word(m68k_areg(regs, 7), last_sr_for_exception3);
+ }
kludge_me_do:
if ((regs.vbr & 1) && currprefs.cpu_model <= 68010) {
cpu_halt(CPU_HALT_DOUBLE_FAULT);
regs.irc = regs.read_buffer;
exception3_read_access(regs.ir, newpc, sz_word, 2);
} else {
+ exception_check_trace(nr);
exception3_notinstruction(regs.ir, newpc);
}
return;
// Check T0 trace
// RTE format error ignores T0 trace
if (nr != 14) {
+ if (currprefs.cpu_model >= 68040 && internalexception(nr)) {
+ t0 = false;
+ }
if (t0) {
activate_trace();
}
static void do_trace (void)
{
// need to store PC because of branch instructions
- regs.trace_pc = regs.pc;
+ regs.trace_pc = m68k_getpc();
if (regs.t0 && !regs.t1 && currprefs.cpu_model >= 68020) {
// this is obsolete
return;
#endif /* SAVESTATE */
-static void exception3f (uae_u32 opcode, uaecptr addr, bool writeaccess, bool instructionaccess, bool notinstruction, uaecptr pc, int size, int fc)
+static void exception3f(uae_u32 opcode, uaecptr addr, bool writeaccess, bool instructionaccess, bool notinstruction, uaecptr pc, int size, int fc, uae_u16 secondarysr)
{
if (currprefs.cpu_model >= 68040)
addr &= ~1;
else
last_addr_for_exception_3 = pc;
} else if (pc == 0xffffffff) {
- last_addr_for_exception_3 = m68k_getpc ();
+ last_addr_for_exception_3 = m68k_getpc();
} else {
last_addr_for_exception_3 = pc;
}
last_fc_for_exception_3 = fc >= 0 ? fc : (instructionaccess ? 2 : 1);
last_notinstruction_for_exception_3 = notinstruction;
last_size_for_exception_3 = size;
+ last_sr_for_exception3 = secondarysr;
Exception (3);
#if EXCEPTION3_DEBUGGER
activate_debugger();
void exception3_notinstruction(uae_u32 opcode, uaecptr addr)
{
last_di_for_exception_3 = 1;
- exception3f (opcode, addr, true, false, true, 0xffffffff, 1, -1);
+ exception3f (opcode, addr, true, false, true, 0xffffffff, 1, -1, 0);
}
static void exception3_read_special(uae_u32 opcode, uaecptr addr, int size, int fc)
{
- exception3f(opcode, addr, false, 0, false, 0xffffffff, size, fc);
+ exception3f(opcode, addr, false, 0, false, 0xffffffff, size, fc, 0);
}
// 68010 special prefetch handling
x_do_cycles(4 * cpucycleunit);
}
last_di_for_exception_3 = 0;
- exception3f(opcode, addr, false, true, false, m68k_getpc(), sz_word, -1);
+ exception3f(opcode, addr, false, true, false, m68k_getpc(), sz_word, -1, 0);
}
// Some hardware accepts address error aborted reads or writes as normal reads/writes.
if (currprefs.cpu_model == 68000) {
m68k_incpci(2);
}
- exception3f(opcode, addr, false, true, false, m68k_getpc(), sz_word, -1);
+ exception3f(opcode, addr, false, true, false, m68k_getpc(), sz_word, -1, 0);
+}
+void exception3_read_prefetch_68040bug(uae_u32 opcode, uaecptr addr, uae_u16 secondarysr)
+{
+ x_do_cycles(4 * cpucycleunit);
+ last_di_for_exception_3 = 0;
+ exception3f(opcode | 0x10000, addr, false, true, false, m68k_getpc(), sz_word, -1, secondarysr);
}
+
void exception3_read_access(uae_u32 opcode, uaecptr addr, int size, int fc)
{
x_do_cycles(4 * cpucycleunit);
opcode = regs.ir;
}
last_di_for_exception_3 = 1;
- exception3f(opcode, addr, false, ia, ni, 0xffffffff, size & 15, fc);
+ exception3f(opcode, addr, false, ia, ni, 0xffffffff, size & 15, fc, 0);
}
void exception3_write(uae_u32 opcode, uaecptr addr, int size, uae_u32 val, int fc)
{
}
last_di_for_exception_3 = 1;
regs.write_buffer = val;
- exception3f(opcode, addr, true, ia, ni, 0xffffffff, size & 15, fc);
+ exception3f(opcode, addr, true, ia, ni, 0xffffffff, size & 15, fc, 0);
}
void exception2_setup(uae_u32 opcode, uaecptr addr, bool read, int size, uae_u32 fc)