[Core/CD] improved emulation of Word-RAM access limitations in 2M mode (fixes regression in Mortal Kombat)

This commit is contained in:
ekeeke 2024-01-16 14:00:21 +01:00
parent d4ca576c07
commit 9f25226536
11 changed files with 187 additions and 49 deletions

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 MiB

After

Width:  |  Height:  |  Size: 3.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 MiB

After

Width:  |  Height:  |  Size: 4.0 MiB

View File

@ -2,7 +2,7 @@
* Genesis Plus
* Mega CD / Sega CD hardware
*
* Copyright (C) 2012-2023 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2012-2024 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -82,7 +82,7 @@ static void s68k_lockup_w_8 (unsigned int address, unsigned int data)
#ifdef LOGERROR
error ("[SUB 68k] Lockup write8 %08X = %02X (%08X)\n", address, data, s68k.pc);
#endif
s68k_pulse_wait();
s68k_pulse_wait(address, 1);
}
static void s68k_lockup_w_16 (unsigned int address, unsigned int data)
@ -90,7 +90,7 @@ static void s68k_lockup_w_16 (unsigned int address, unsigned int data)
#ifdef LOGERROR
error ("[SUB 68k] Lockup write16 %08X = %04X (%08X)\n", address, data, s68k.pc);
#endif
s68k_pulse_wait();
s68k_pulse_wait(address, 1);
}
static unsigned int s68k_lockup_r_8 (unsigned int address)
@ -98,7 +98,7 @@ static unsigned int s68k_lockup_r_8 (unsigned int address)
#ifdef LOGERROR
error ("[SUB 68k] Lockup read8 %08X.b (%08X)\n", address, s68k.pc);
#endif
s68k_pulse_wait();
s68k_pulse_wait(address, 0);
return 0xff;
}
@ -107,7 +107,7 @@ static unsigned int s68k_lockup_r_16 (unsigned int address)
#ifdef LOGERROR
error ("[SUB 68k] Lockup read16 %08X.w (%08X)\n", address, s68k.pc);
#endif
s68k_pulse_wait();
s68k_pulse_wait(address, 0);
return 0xffff;
}

View File

@ -2,7 +2,7 @@
* Genesis Plus
* Mega-CD / Sega CD hardware
*
* Copyright (C) 2012-2023 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2012-2024 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -244,6 +244,7 @@ typedef struct
uint dar[16]; /* Data and Address Registers */
uint pc; /* Program Counter */
uint prev_pc; /* Previous Program Counter */
uint prev_ar[8]; /* Previous Address Registers */
uint sp[5]; /* User and Interrupt Stack Pointers */
uint ir; /* Instruction Register */
uint t1_flag; /* Trace 1 */
@ -383,10 +384,8 @@ extern void m68k_clear_halt(void);
extern void s68k_pulse_halt(void);
extern void s68k_clear_halt(void);
/* Put the CPU in waiting state as if DTACK pin is not asserted during bus access */
extern void m68k_pulse_wait(void);
extern void m68k_clear_wait(void);
extern void s68k_pulse_wait(void);
/* Put the CPU in waiting state until DTACK pin is asserted during bus access */
extern void s68k_pulse_wait(unsigned int address, unsigned int write_access);
extern void s68k_clear_wait(void);
/* Peek at the internals of a CPU context. This can either be a context

View File

@ -296,9 +296,6 @@ void m68k_run(unsigned int cycles)
cpu_hook(HOOK_M68K_E, 0, REG_PC, 0);
#endif
/* Save current instruction PC */
m68k.prev_pc = REG_PC;
/* Decode next instruction */
REG_IR = m68ki_read_imm_16();
@ -399,24 +396,6 @@ void m68k_clear_halt(void)
CPU_STOPPED &= ~STOP_LEVEL_HALT;
}
void m68k_pulse_wait(void)
{
/* Hold the DTACK line on the CPU */
CPU_STOPPED |= STOP_LEVEL_WAIT;
/* End CPU execution */
m68k.cycles = m68k.cycle_end - m68k_cycles();
/* Rollback current instruction (memory access will be executed once /DTACK is asserted) */
m68k.pc = m68k.prev_pc;
}
void m68k_clear_wait(void)
{
/* Assert the DTACK line on the CPU */
CPU_STOPPED &= ~STOP_LEVEL_WAIT;
}
/* ======================================================================== */
/* ============================== END OF FILE ============================= */
/* ======================================================================== */

View File

@ -1384,7 +1384,7 @@ INLINE void m68ki_exception_interrupt(uint int_level)
#endif /* M68K_EMULATE_ADDRESS_ERROR */
/* Turn off the stopped state */
CPU_STOPPED &= STOP_LEVEL_HALT;
CPU_STOPPED &= (STOP_LEVEL_HALT | STOP_LEVEL_WAIT);
/* If we are halted, don't do anything */
if(CPU_STOPPED)

View File

@ -357,22 +357,178 @@ void s68k_clear_halt(void)
CPU_STOPPED &= ~STOP_LEVEL_HALT;
}
void s68k_pulse_wait(void)
void s68k_pulse_wait(unsigned int address, unsigned int write_access)
{
/* Hold the DTACK line on the CPU */
CPU_STOPPED |= STOP_LEVEL_WAIT;
/* Check CPU is not already waiting for /DTACK */
if (!(CPU_STOPPED & STOP_LEVEL_WAIT))
{
/* Hold the DTACK line on the CPU */
CPU_STOPPED |= STOP_LEVEL_WAIT;
/* End CPU execution */
s68k.cycles = s68k.cycle_end - s68k_cycles();
/* End CPU execution */
s68k.cycles = s68k.cycle_end - s68k_cycles();
/* Rollback current instruction (memory access will be executed once /DTACK is asserted) */
s68k.pc = s68k.prev_pc;
/* Save CPU address registers */
s68k.prev_ar[0] = s68k.dar[8+0];
s68k.prev_ar[1] = s68k.dar[8+1];
s68k.prev_ar[2] = s68k.dar[8+2];
s68k.prev_ar[3] = s68k.dar[8+3];
s68k.prev_ar[4] = s68k.dar[8+4];
s68k.prev_ar[5] = s68k.dar[8+5];
s68k.prev_ar[6] = s68k.dar[8+6];
s68k.prev_ar[7] = s68k.dar[8+7];
/* Detect address register(s) pre-decrement/post-increment done by MOVE/MOVEA instruction */
if ((s68k.ir >= 0x1000) && (s68k.ir < 0x4000))
{
/* MOVE/MOVEA instructions operand sizes */
static const int mov_instr_sizes[4] = {0, 1, 4, 2};
if ((s68k.ir & 0x38) == 0x18)
{
/* revert source address register post-increment */
s68k.prev_ar[s68k.ir&0x07] -= mov_instr_sizes[(s68k.ir>>12)&0x03];
}
else if ((s68k.ir & 0x38) == 0x20)
{
/* revert source address register pre-decrement */
s68k.prev_ar[s68k.ir&0x07] += mov_instr_sizes[(s68k.ir>>12)&0x03];
}
/* only check destination address register post-increment/pre-decrement in case of halting on write access */
if (write_access)
{
if ((s68k.ir & 0x01c0) == 0x00c0)
{
/* revert destination address register post-increment */
s68k.prev_ar[(s68k.ir>>9)&0x07] -= mov_instr_sizes[(s68k.ir>>12)&0x03];
}
else if ((s68k.ir & 0x01c0) == 0x0100)
{
/* revert destination address register pre-decrement */
s68k.prev_ar[(s68k.ir>>9)&0x07] += mov_instr_sizes[(s68k.ir>>12)&0x03];
}
}
}
else
{
/* Other instructions operand sizes */
static const int def_instr_sizes[4] = {1, 2, 4, 2};
/* Detect address register(s) pre-decrement done by ABCD/SBCD instruction */
if ((s68k.ir & 0xb1f8) == 0x8108)
{
/* revert source address register pre-decrement (byte operands only) */
s68k.prev_ar[s68k.ir&0x07] += 1;
/* only revert destination address register pre-decrement in case of halting on destination address access (byte operands only) */
if (address == s68k.prev_ar[(s68k.ir>>9)&0x07])
{
s68k.prev_ar[(s68k.ir>>9)&0x07] += 1;
}
}
/* Detect address register(s) pre-decrement done by ADDX/SUBX instruction */
else if (((s68k.ir & 0xb1f8) == 0x9108) || ((s68k.ir & 0xb1f8) == 0x9148) || ((s68k.ir & 0xb1f8) == 0x9188))
{
/* revert source address register pre-decrement */
s68k.prev_ar[s68k.ir&0x07] += def_instr_sizes[(s68k.ir>>6)&0x03];
/* only revert destination address register pre-decrement in case of halting on destination address access */
if (address == s68k.prev_ar[(s68k.ir>>9)&0x07])
{
s68k.prev_ar[(s68k.ir>>9)&0x07] += def_instr_sizes[(s68k.ir>>6)&0x03];
}
}
/* Detect address register(s) post-increment done by CMPM instruction */
else if ((s68k.ir & 0xf138) == 0xb108)
{
/* revert source address register post-increment */
s68k.prev_ar[s68k.ir&0x07] -= def_instr_sizes[(s68k.ir>>6)&0x03];
/* only revert destination address register post-increment in case of halting on destination address access */
if (address == s68k.prev_ar[(s68k.ir>>9)&0x07])
{
s68k.prev_ar[(s68k.ir>>9)&0x07] -= def_instr_sizes[(s68k.ir>>6)&0x03];
}
}
/* Detect address register post-increment or pre-increment done by other instruction */
else if (((s68k.ir & 0x38) == 0x18) || ((s68k.ir & 0x38) == 0x20))
{
int size;
/* autodetect MOVEM instruction (no address register modification needed as post-increment/pre-decrement is done after memory access) */
if ((s68k.ir & 0xfb80) == 0x4880)
{
size = 0;
}
/* autodetect instruction with fixed byte operand (and not covered by generic size field value) */
else if (((s68k.ir & 0xf100) == 0x0100) || /* BTST, BCHG, BCLR, BSET (dynamic) */
((s68k.ir & 0xff00) == 0x0800) || /* BTST, BCHG, BCLR, BSET (static) */
((s68k.ir & 0xffc0) == 0x4ac0) || /* TAS */
((s68k.ir & 0xf0c0) == 0x50c0)) /* Scc */
{
size = 1;
}
/* autodetect instruction with fixed word operand (and not covered by generic size field value) */
else if ((s68k.ir & 0xf1c0) == 0x4180) /* CHK */
{
size = 2;
}
/* autodetect instruction with either word or long operand (not covered by generic size field value) */
else if (((s68k.ir & 0xb0c0) == 0x90c0) || /* SUBA, ADDA*/
((s68k.ir & 0xf0c0) == 0xb0c0)) /* CMPA */
{
size = (s68k.ir & 0x100) ? 4 : 2;
}
/* default operand size */
else
{
size = def_instr_sizes[(s68k.ir>>6)&0x03];
}
if (s68k.ir & 0x08)
{
/* revert source address register post-increment */
s68k.prev_ar[s68k.ir&0x07] -= size;
}
else
{
/* revert source address register pre-decrement */
s68k.prev_ar[s68k.ir&0x07] += size;
}
}
}
}
}
void s68k_clear_wait(void)
{
/* Assert the DTACK line on the CPU */
CPU_STOPPED &= ~STOP_LEVEL_WAIT;
/* check CPU is waiting for DTACK */
if (CPU_STOPPED & STOP_LEVEL_WAIT)
{
/* Assert the DTACK line on the CPU */
CPU_STOPPED &= ~STOP_LEVEL_WAIT;
/* Rollback to previously held instruction */
s68k.pc = s68k.prev_pc;
/* Restore CPU address registers */
s68k.dar[8+0] = s68k.prev_ar[0];
s68k.dar[8+1] = s68k.prev_ar[1];
s68k.dar[8+2] = s68k.prev_ar[2];
s68k.dar[8+3] = s68k.prev_ar[3];
s68k.dar[8+4] = s68k.prev_ar[4];
s68k.dar[8+5] = s68k.prev_ar[5];
s68k.dar[8+6] = s68k.prev_ar[6];
s68k.dar[8+7] = s68k.prev_ar[7];
}
}
/* ======================================================================== */

View File

@ -3,7 +3,7 @@
* Main 68k bus handlers
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2023 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2024 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -88,7 +88,8 @@ void m68k_lockup_w_8 (unsigned int address, unsigned int data)
#endif
if (!config.force_dtack)
{
m68k_pulse_wait();
m68k_pulse_halt();
m68k.cycles = m68k.cycle_end;
}
}
@ -99,7 +100,8 @@ void m68k_lockup_w_16 (unsigned int address, unsigned int data)
#endif
if (!config.force_dtack)
{
m68k_pulse_wait();
m68k_pulse_halt();
m68k.cycles = m68k.cycle_end;
}
}
@ -108,11 +110,12 @@ unsigned int m68k_lockup_r_8 (unsigned int address)
#ifdef LOGERROR
error ("Lockup %08X.b (%08X)\n", address, m68k_get_reg(M68K_REG_PC));
#endif
address = m68k.pc | (address & 1);
if (!config.force_dtack)
{
m68k_pulse_wait();
m68k_pulse_halt();
m68k.cycles = m68k.cycle_end;
}
address = m68k.pc | (address & 1);
return READ_BYTE(m68k.memory_map[((address)>>16)&0xff].base, (address) & 0xffff);
}
@ -121,11 +124,12 @@ unsigned int m68k_lockup_r_16 (unsigned int address)
#ifdef LOGERROR
error ("Lockup %08X.w (%08X)\n", address, m68k_get_reg(M68K_REG_PC));
#endif
address = m68k.pc;
if (!config.force_dtack)
{
m68k_pulse_wait();
m68k_pulse_halt();
m68k.cycles = m68k.cycle_end;
}
address = m68k.pc;
return *(uint16 *)(m68k.memory_map[((address)>>16)&0xff].base + ((address) & 0xffff));
}

View File

@ -3,7 +3,7 @@
* Main 68k bus handlers
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2023 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2024 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met: