mirror of
https://github.com/ekeeke/Genesis-Plus-GX.git
synced 2024-11-14 06:45:09 +01:00
[Core/CD] improved emulation of Word-RAM access limitations in 2M mode (fixes regression in Mortal Kombat)
This commit is contained in:
parent
d4ca576c07
commit
9f25226536
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 |
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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 ============================= */
|
||||
/* ======================================================================== */
|
||||
|
@ -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)
|
||||
|
@ -357,7 +357,10 @@ 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)
|
||||
{
|
||||
/* 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;
|
||||
@ -365,14 +368,167 @@ void s68k_pulse_wait(void)
|
||||
/* 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)
|
||||
{
|
||||
/* 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];
|
||||
}
|
||||
}
|
||||
|
||||
/* ======================================================================== */
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user