Skip to content

Commit

Permalink
If interrupt level increased during 68040/060 MMU fault handler execu…
Browse files Browse the repository at this point in the history
…tion, interrupt's first instruction was "restarted", if both original and exception's instruction were MOVEM, things went horribly wrong.
  • Loading branch information
tonioni committed Dec 28, 2023
1 parent 35fa11d commit 0be6d4e
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 63 deletions.
3 changes: 3 additions & 0 deletions cpummu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1563,6 +1563,9 @@ void m68k_do_rte_mmu040 (uaecptr a7)
write_log (_T("MMU restarted MOVEM EA=%08X\n"), mmu040_movem_ea);
#endif
}
if (currprefs.mmu_model == 68060 || mmu_restart) {
set_special(SPCFLAG_MMURESTART);
}
}

void m68k_do_rte_mmu060 (uaecptr a7)
Expand Down
18 changes: 0 additions & 18 deletions include/custom.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,24 +85,6 @@ STATIC_INLINE int dmaen(unsigned int dmamask)
return (dmamask & dmacon) && (dmacon & 0x200);
}

#define SPCFLAG_CPUINRESET 2
#define SPCFLAG_COPPER 4
#define SPCFLAG_INT 8
#define SPCFLAG_BRK 16
#define SPCFLAG_UAEINT 32
#define SPCFLAG_TRACE 64
#define SPCFLAG_DOTRACE 128
#define SPCFLAG_DOINT 256 /* arg, JIT fails without this.. */
#define SPCFLAG_BLTNASTY 512
#define SPCFLAG_EXEC 1024
#define SPCFLAG_ACTION_REPLAY 2048
#define SPCFLAG_TRAP 4096 /* enforcer-hack */
#define SPCFLAG_MODE_CHANGE 8192
#ifdef JIT
#define SPCFLAG_END_COMPILE 16384
#endif
#define SPCFLAG_CHECK 32768

extern uae_u16 adkcon;

extern unsigned int joy0dir, joy1dir;
Expand Down
19 changes: 19 additions & 0 deletions include/newcpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,25 @@ extern bool m68k_interrupt_delay;

extern void safe_interrupt_set(int, int, bool);

#define SPCFLAG_CPUINRESET 2
#define SPCFLAG_COPPER 4
#define SPCFLAG_INT 8
#define SPCFLAG_BRK 16
#define SPCFLAG_UAEINT 32
#define SPCFLAG_TRACE 64
#define SPCFLAG_DOTRACE 128
#define SPCFLAG_DOINT 256 /* arg, JIT fails without this.. */
#define SPCFLAG_BLTNASTY 512
#define SPCFLAG_EXEC 1024
#define SPCFLAG_ACTION_REPLAY 2048
#define SPCFLAG_TRAP 4096 /* enforcer-hack */
#define SPCFLAG_MODE_CHANGE 8192
#ifdef JIT
#define SPCFLAG_END_COMPILE 16384
#endif
#define SPCFLAG_CHECK 32768
#define SPCFLAG_MMURESTART 65536

STATIC_INLINE void set_special_exter(uae_u32 x)
{
atomic_or(&regs.spcflags, x);
Expand Down
106 changes: 61 additions & 45 deletions newcpu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4614,11 +4614,12 @@ static void debug_cpu_stop(void)
static int do_specialties (int cycles)
{
uaecptr pc = m68k_getpc();
uae_atomic spcflags = regs.spcflags;

if (regs.spcflags & SPCFLAG_MODE_CHANGE)
if (spcflags & SPCFLAG_MODE_CHANGE)
return 1;

if (regs.spcflags & SPCFLAG_CHECK) {
if (spcflags & SPCFLAG_CHECK) {
if (regs.halted) {
if (regs.halted == CPU_HALT_ACCELERATOR_CPU_FALLBACK) {
return 1;
Expand All @@ -4632,8 +4633,10 @@ static int do_specialties (int cycles)
int vsyncstate = -1;
while (vsynccnt > 0 && !quit_program) {
x_do_cycles(8 * CYCLE_UNIT);
if (regs.spcflags & SPCFLAG_COPPER)
spcflags = regs.spcflags;
if (spcflags & SPCFLAG_COPPER) {
do_copper();
}
if (vsync_counter != vsyncstate) {
vsyncstate = vsync_counter;
vsynccnt--;
Expand All @@ -4646,7 +4649,7 @@ static int do_specialties (int cycles)

#ifdef ACTION_REPLAY
#ifdef ACTION_REPLAY_HRTMON
if ((regs.spcflags & SPCFLAG_ACTION_REPLAY) && hrtmon_flag != ACTION_REPLAY_INACTIVE) {
if ((spcflags & SPCFLAG_ACTION_REPLAY) && hrtmon_flag != ACTION_REPLAY_INACTIVE) {
int isinhrt = pc >= hrtmem_start && pc < hrtmem_start + hrtmem_size;
/* exit from HRTMon? */
if (hrtmon_flag == ACTION_REPLAY_ACTIVE && !isinhrt)
Expand All @@ -4658,7 +4661,7 @@ static int do_specialties (int cycles)
hrtmon_enter();
}
#endif
if ((regs.spcflags & SPCFLAG_ACTION_REPLAY) && action_replay_flag != ACTION_REPLAY_INACTIVE) {
if ((spcflags & SPCFLAG_ACTION_REPLAY) && action_replay_flag != ACTION_REPLAY_INACTIVE) {
/*if (action_replay_flag == ACTION_REPLAY_ACTIVE && !is_ar_pc_in_rom ())*/
/* write_log (_T("PC:%p\n"), m68k_getpc ());*/

Expand All @@ -4677,26 +4680,28 @@ static int do_specialties (int cycles)
}
#endif

if (regs.spcflags & SPCFLAG_COPPER)
if (spcflags & SPCFLAG_COPPER) {
do_copper();
}

#ifdef JIT
if (regs.spcflags & SPCFLAG_END_COMPILE) {
if (spcflags & SPCFLAG_END_COMPILE) {
unset_special(SPCFLAG_END_COMPILE);
}
#endif

while ((regs.spcflags & SPCFLAG_CPUINRESET)) {
while (spcflags & SPCFLAG_CPUINRESET) {
x_do_cycles(4 * CYCLE_UNIT);
if (regs.spcflags & SPCFLAG_COPPER) {
spcflags = regs.spcflags;
if (spcflags & SPCFLAG_COPPER) {
do_copper();
}
if (!(regs.spcflags & SPCFLAG_CPUINRESET) || (regs.spcflags & SPCFLAG_BRK) || (regs.spcflags & SPCFLAG_MODE_CHANGE)) {
if (!(spcflags & SPCFLAG_CPUINRESET) || (spcflags & SPCFLAG_BRK) || (spcflags & SPCFLAG_MODE_CHANGE)) {
break;
}
}

while ((regs.spcflags & SPCFLAG_BLTNASTY) && dmaen (DMA_BLITTER) && cycles > 0 && ((currprefs.waiting_blits && currprefs.cpu_model >= 68020) || !currprefs.blitter_cycle_exact)) {
while ((spcflags & SPCFLAG_BLTNASTY) && dmaen (DMA_BLITTER) && cycles > 0 && ((currprefs.waiting_blits && currprefs.cpu_model >= 68020) || !currprefs.blitter_cycle_exact)) {
int c = blitnasty();
if (c < 0) {
break;
Expand All @@ -4708,7 +4713,8 @@ static int do_specialties (int cycles)
c = 4;
}
x_do_cycles(c * CYCLE_UNIT);
if (regs.spcflags & SPCFLAG_COPPER)
spcflags = regs.spcflags;
if (spcflags & SPCFLAG_COPPER)
do_copper();
#ifdef WITH_PPC
if (ppc_state) {
Expand All @@ -4719,43 +4725,51 @@ static int do_specialties (int cycles)
#endif
}

if (regs.spcflags & SPCFLAG_DOTRACE)
Exception(9);
if (spcflags & SPCFLAG_MMURESTART) {
// can't have interrupt when 040/060 CPU reruns faulted instruction
unset_special(SPCFLAG_MMURESTART);
} else {

if (regs.spcflags & SPCFLAG_TRAP) {
unset_special (SPCFLAG_TRAP);
Exception(3);
}
if (spcflags & SPCFLAG_DOTRACE) {
Exception(9);
}

if (regs.spcflags & SPCFLAG_TRACE)
do_trace();
if (spcflags & SPCFLAG_TRAP) {
unset_special (SPCFLAG_TRAP);
Exception(3);
}

if (regs.spcflags & SPCFLAG_UAEINT) {
check_uae_int_request();
unset_special(SPCFLAG_UAEINT);
}
if (spcflags & SPCFLAG_TRACE) {
do_trace();
}

if (m68k_interrupt_delay) {
int ipl = time_for_interrupt();
if (ipl) {
unset_special(SPCFLAG_INT);
do_interrupt(ipl);
if (spcflags & SPCFLAG_UAEINT) {
check_uae_int_request();
unset_special(SPCFLAG_UAEINT);
}
} else {
if (regs.spcflags & SPCFLAG_INT) {
int intr = intlev();
unset_special (SPCFLAG_INT | SPCFLAG_DOINT);
if (intr > 0 && (intr > regs.intmask || intr == 7))
do_interrupt(intr);

if (m68k_interrupt_delay) {
int ipl = time_for_interrupt();
if (ipl) {
unset_special(SPCFLAG_INT);
do_interrupt(ipl);
}
} else {
if (spcflags & SPCFLAG_INT) {
int intr = intlev();
unset_special (SPCFLAG_INT | SPCFLAG_DOINT);
if (intr > 0 && (intr > regs.intmask || intr == 7))
do_interrupt(intr);
}
}
}

if (regs.spcflags & SPCFLAG_DOINT) {
unset_special(SPCFLAG_DOINT);
set_special(SPCFLAG_INT);
if (spcflags & SPCFLAG_DOINT) {
unset_special(SPCFLAG_DOINT);
set_special(SPCFLAG_INT);
}
}

if (regs.spcflags & SPCFLAG_BRK) {
if (spcflags & SPCFLAG_BRK) {
unset_special(SPCFLAG_BRK);
#ifdef DEBUGGER
if (debugging) {
Expand Down Expand Up @@ -5117,7 +5131,9 @@ static bool m68k_cs_initialized;

static int do_specialties_thread(void)
{
if (regs.spcflags & SPCFLAG_MODE_CHANGE)
uae_atomic spcflags = regs.spcflags;

if (spcflags & SPCFLAG_MODE_CHANGE)
return 1;

#ifdef JIT
Expand All @@ -5126,20 +5142,20 @@ static int do_specialties_thread(void)
}
#endif

if (regs.spcflags & SPCFLAG_DOTRACE)
if (spcflags & SPCFLAG_DOTRACE)
Exception(9);

if (regs.spcflags & SPCFLAG_TRAP) {
if (spcflags & SPCFLAG_TRAP) {
unset_special(SPCFLAG_TRAP);
Exception(3);
}

if (regs.spcflags & SPCFLAG_TRACE)
if (spcflags & SPCFLAG_TRACE)
do_trace();

for (;;) {

if (regs.spcflags & (SPCFLAG_BRK | SPCFLAG_MODE_CHANGE)) {
if (spcflags & (SPCFLAG_BRK | SPCFLAG_MODE_CHANGE)) {
return 1;
}

Expand Down

0 comments on commit 0be6d4e

Please sign in to comment.