revert zones' improved IRQ and SA-1 changes committed in r661 - these are detrimental to performance

This commit is contained in:
dborth 2011-03-24 01:07:47 +00:00
parent ce4ee053b6
commit fd8a742cd9
21 changed files with 1414 additions and 683 deletions

View File

@ -186,9 +186,12 @@ static void S9xSetByteFree (uint8, uint32);
static uint8 S9xGetByteFree (uint32 address)
{
uint32 Cycles = CPU.Cycles;
uint32 WaitAddress = CPU.WaitAddress;
uint8 byte;
byte = S9xGetByte(address);
CPU.WaitAddress = WaitAddress;
CPU.Cycles = Cycles;
return (byte);
@ -197,8 +200,11 @@ static uint8 S9xGetByteFree (uint32 address)
static void S9xSetByteFree (uint8 byte, uint32 address)
{
uint32 Cycles = CPU.Cycles;
uint32 WaitAddress = CPU.WaitAddress;
S9xSetByte(byte, address);
CPU.WaitAddress = WaitAddress;
CPU.Cycles = Cycles;
}

View File

@ -429,6 +429,7 @@ static const int ptrspeeds[4] = { 1, 1, 4, 8 };
S(ToggleBG2), \
S(ToggleBG3), \
S(ToggleEmuTurbo), \
S(ToggleHDMA), \
S(ToggleSprites), \
S(ToggleTransparency) \
@ -2457,6 +2458,11 @@ void S9xApplyCommand (s9xcommand_t cmd, int16 data1, int16 data2)
DisplayStateChange("Sprites", !(Settings.BG_Forced & 16));
break;
case ToggleHDMA:
Settings.DisableHDMA = !Settings.DisableHDMA;
DisplayStateChange("HDMA emulation", !Settings.DisableHDMA);
break;
case ToggleTransparency:
Settings.Transparency = !Settings.Transparency;
DisplayStateChange("Transparency effects", Settings.Transparency);

View File

@ -208,16 +208,12 @@ static void S9xResetCPU (void)
static void S9xSoftResetCPU (void)
{
CPU.Cycles = 182; // Or 188. This is the cycle count just after the jump to the Reset Vector.
CPU.PrevCycles = CPU.Cycles;
CPU.PrevCycles = -1;
CPU.V_Counter = 0;
CPU.Flags = CPU.Flags & (DEBUG_MODE_FLAG | TRACE_FLAG);
CPU.PCBase = NULL;
CPU.NMILine = FALSE;
CPU.IRQLine = FALSE;
CPU.IRQTransition = FALSE;
CPU.IRQLastState = FALSE;
CPU.IRQExternal = FALSE;
CPU.IRQPending = Timings.IRQPendCount;
CPU.IRQActive = FALSE;
CPU.IRQPending = 0;
CPU.MemSpeed = SLOW_ONE_CYCLE;
CPU.MemSpeedx2 = SLOW_ONE_CYCLE * 2;
CPU.FastROMSpeed = SLOW_ONE_CYCLE;
@ -230,6 +226,9 @@ static void S9xSoftResetCPU (void)
CPU.WhichEvent = HC_RENDER_EVENT;
CPU.NextEvent = Timings.RenderPos;
CPU.WaitingForInterrupt = FALSE;
CPU.WaitAddress = 0xffffffff;
CPU.WaitCounter = 0;
CPU.PBPCAtOpcodeStart = 0xffffffff;
CPU.AutoSaveTimer = 0;
CPU.SRAMModified = FALSE;
@ -262,6 +261,7 @@ static void S9xSoftResetCPU (void)
ICPU.S9xOpcodes = S9xOpcodesE1;
ICPU.S9xOpLengths = S9xOpLengthsM1X1;
ICPU.CPUExecuting = TRUE;
S9xUnpackStatus();
}

View File

@ -187,91 +187,102 @@
#include "missing.h"
#endif
static inline void S9xReschedule (void);
void S9xMainLoop (void)
{
for (;;)
{
if (CPU.NMILine)
if (CPU.Flags)
{
if (Timings.NMITriggerPos <= CPU.Cycles)
if (CPU.Flags & NMI_FLAG)
{
CPU.NMILine = FALSE;
Timings.NMITriggerPos = 0xffff;
if (CPU.WaitingForInterrupt)
if (Timings.NMITriggerPos <= CPU.Cycles)
{
CPU.WaitingForInterrupt = FALSE;
Registers.PCw++;
CPU.Flags &= ~NMI_FLAG;
Timings.NMITriggerPos = 0xffff;
if (CPU.WaitingForInterrupt)
{
CPU.WaitingForInterrupt = FALSE;
Registers.PCw++;
}
S9xOpcode_NMI();
}
S9xOpcode_NMI();
}
}
if (CPU.IRQTransition || CPU.IRQExternal)
{
if (CPU.IRQPending)
CPU.IRQPending--;
else
#ifdef DEBUGGER
if ((CPU.Flags & BREAK_FLAG) && !(CPU.Flags & SINGLE_STEP_FLAG))
{
if (CPU.WaitingForInterrupt)
for (int Break = 0; Break != 6; Break++)
{
CPU.WaitingForInterrupt = FALSE;
Registers.PCw++;
if (S9xBreakpoint[Break].Enabled &&
S9xBreakpoint[Break].Bank == Registers.PB &&
S9xBreakpoint[Break].Address == Registers.PCw)
{
if (S9xBreakpoint[Break].Enabled == 2)
S9xBreakpoint[Break].Enabled = TRUE;
else
CPU.Flags |= DEBUG_MODE_FLAG;
}
}
CPU.IRQTransition = FALSE;
CPU.IRQPending = Timings.IRQPendCount;
if (!CheckFlag(IRQ))
S9xOpcode_IRQ();
}
}
#endif
#ifdef DEBUGGER
if ((CPU.Flags & BREAK_FLAG) && !(CPU.Flags & SINGLE_STEP_FLAG))
{
for (int Break = 0; Break != 6; Break++)
if (CPU.Flags & IRQ_FLAG)
{
if (S9xBreakpoint[Break].Enabled &&
S9xBreakpoint[Break].Bank == Registers.PB &&
S9xBreakpoint[Break].Address == Registers.PCw)
if (CPU.IRQPending)
// FIXME: In case of IRQ during WRAM refresh
CPU.IRQPending--;
else
{
if (S9xBreakpoint[Break].Enabled == 2)
S9xBreakpoint[Break].Enabled = TRUE;
if (CPU.WaitingForInterrupt)
{
CPU.WaitingForInterrupt = FALSE;
Registers.PCw++;
}
if (CPU.IRQActive && !Settings.DisableIRQ)
{
if (!CheckFlag(IRQ))
// in IRQ handler $4211 is supposed to be read, so IRQ_FLAG should be cleared.
S9xOpcode_IRQ();
}
else
CPU.Flags |= DEBUG_MODE_FLAG;
CPU.Flags &= ~IRQ_FLAG;
}
}
if (CPU.Flags & SCAN_KEYS_FLAG)
break;
#ifdef DEBUGGER
if (CPU.Flags & DEBUG_MODE_FLAG)
break;
if (CPU.Flags & TRACE_FLAG)
S9xTrace();
if (CPU.Flags & SINGLE_STEP_FLAG)
{
CPU.Flags &= ~SINGLE_STEP_FLAG;
CPU.Flags |= DEBUG_MODE_FLAG;
}
#endif
}
if (CPU.Flags & DEBUG_MODE_FLAG)
break;
if (CPU.Flags & TRACE_FLAG)
S9xTrace();
if (CPU.Flags & SINGLE_STEP_FLAG)
{
CPU.Flags &= ~SINGLE_STEP_FLAG;
CPU.Flags |= DEBUG_MODE_FLAG;
}
#ifdef CPU_SHUTDOWN
CPU.PBPCAtOpcodeStart = Registers.PBPC;
#endif
if (CPU.Flags & SCAN_KEYS_FLAG)
break;
register uint8 Op;
register struct SOpcodes *Opcodes;
CPU.PrevCycles = CPU.Cycles;
if (CPU.PCBase)
{
Op = CPU.PCBase[Registers.PCw];
CPU.PrevCycles = CPU.Cycles;
CPU.Cycles += CPU.MemSpeed;
S9xCheckInterrupts();
Opcodes = ICPU.S9xOpcodes;
}
else
@ -293,8 +304,13 @@ void S9xMainLoop (void)
Registers.PCw++;
(*Opcodes[Op].S9xOpcode)();
if (Settings.SA1)
if (SA1.Executing)
S9xSA1MainLoop();
#if (S9X_ACCURACY_LEVEL <= 2)
while (CPU.Cycles >= CPU.NextEvent)
S9xDoHEventProcessing();
#endif
}
S9xPackStatus();
@ -309,54 +325,54 @@ void S9xMainLoop (void)
}
}
static inline void S9xReschedule (void)
void S9xSetIRQ (uint32 source)
{
switch (CPU.WhichEvent)
CPU.IRQActive |= source;
CPU.IRQPending = Timings.IRQPendCount;
CPU.Flags |= IRQ_FLAG;
if (CPU.WaitingForInterrupt)
{
case HC_HBLANK_START_EVENT:
CPU.WhichEvent = HC_HDMA_START_EVENT;
CPU.NextEvent = Timings.HDMAStart;
break;
case HC_HDMA_START_EVENT:
CPU.WhichEvent = HC_HCOUNTER_MAX_EVENT;
CPU.NextEvent = Timings.H_Max;
break;
case HC_HCOUNTER_MAX_EVENT:
CPU.WhichEvent = HC_HDMA_INIT_EVENT;
CPU.NextEvent = Timings.HDMAInit;
break;
case HC_HDMA_INIT_EVENT:
CPU.WhichEvent = HC_RENDER_EVENT;
CPU.NextEvent = Timings.RenderPos;
break;
case HC_RENDER_EVENT:
CPU.WhichEvent = HC_WRAM_REFRESH_EVENT;
CPU.NextEvent = Timings.WRAMRefreshPos;
break;
case HC_WRAM_REFRESH_EVENT:
CPU.WhichEvent = HC_HBLANK_START_EVENT;
CPU.NextEvent = Timings.HBlankStart;
break;
// Force IRQ to trigger immediately after WAI -
// Final Fantasy Mystic Quest crashes without this.
CPU.WaitingForInterrupt = FALSE;
Registers.PCw++;
}
#ifdef DEBUGGER
S9xTraceMessage("--- /IRQ low");
#endif
}
void S9xClearIRQ (uint32 source)
{
CPU.IRQActive &= ~source;
if (!CPU.IRQActive)
CPU.Flags &= ~IRQ_FLAG;
#ifdef DEBUGGER
S9xTraceMessage("--- /IRQ high");
#endif
}
void S9xDoHEventProcessing (void)
{
#ifdef DEBUGGER
static char eventname[7][32] =
static char eventname[13][32] =
{
"",
"HC_HBLANK_START_EVENT",
"HC_IRQ_1_3_EVENT ",
"HC_HDMA_START_EVENT ",
"HC_IRQ_3_5_EVENT ",
"HC_HCOUNTER_MAX_EVENT",
"HC_IRQ_5_7_EVENT ",
"HC_HDMA_INIT_EVENT ",
"HC_IRQ_7_9_EVENT ",
"HC_RENDER_EVENT ",
"HC_WRAM_REFRESH_EVENT"
"HC_IRQ_9_A_EVENT ",
"HC_WRAM_REFRESH_EVENT",
"HC_IRQ_A_1_EVENT "
};
#endif
@ -366,13 +382,19 @@ void S9xDoHEventProcessing (void)
eventname[CPU.WhichEvent], CPU.NextEvent, CPU.Cycles);
#endif
#ifdef CPU_SHUTDOWN
CPU.WaitCounter++;
#endif
switch (CPU.WhichEvent)
{
case HC_HBLANK_START_EVENT:
S9xCheckMissingHTimerPosition(Timings.HBlankStart);
S9xReschedule();
break;
case HC_HDMA_START_EVENT:
S9xCheckMissingHTimerPosition(Timings.HDMAStart);
S9xReschedule();
if (PPU.HDMA && CPU.V_Counter <= PPU.ScreenHeight)
@ -395,7 +417,6 @@ void S9xDoHEventProcessing (void)
S9xAPUEndScanline();
CPU.Cycles -= Timings.H_Max;
CPU.PrevCycles -= Timings.H_Max;
S9xAPUSetReferenceTime(CPU.Cycles);
if ((Timings.NMITriggerPos != 0xffff) && (Timings.NMITriggerPos >= Timings.H_Max))
@ -424,7 +445,7 @@ void S9xDoHEventProcessing (void)
// FIXME: reading $4210 will wait 2 cycles, then perform reading, then wait 4 more cycles.
Memory.FillRAM[0x4210] = Model->_5A22;
CPU.NMILine = FALSE;
CPU.Flags &= ~NMI_FLAG;
Timings.NMITriggerPos = 0xffff;
ICPU.Frame++;
@ -456,6 +477,8 @@ void S9xDoHEventProcessing (void)
else
Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v1;
S9xCheckMissingHTimerPosition(0);
if (CPU.V_Counter == PPU.ScreenHeight + FIRST_VISIBLE_LINE) // VBlank starts from V=225(240).
{
S9xEndScreenRefresh();
@ -490,7 +513,7 @@ void S9xDoHEventProcessing (void)
{
// FIXME: triggered at HC=6, checked just before the final CPU cycle,
// then, when to call S9xOpcode_NMI()?
CPU.NMILine = TRUE;
CPU.Flags |= NMI_FLAG;
Timings.NMITriggerPos = 6 + 6;
}
@ -505,11 +528,13 @@ void S9xDoHEventProcessing (void)
if (CPU.V_Counter == FIRST_VISIBLE_LINE) // V=1
S9xStartScreenRefresh();
CPU.NextEvent = -1;
S9xReschedule();
break;
case HC_HDMA_INIT_EVENT:
S9xCheckMissingHTimerPosition(Timings.HDMAInit);
S9xReschedule();
if (CPU.V_Counter == 0)
@ -526,6 +551,7 @@ void S9xDoHEventProcessing (void)
if (CPU.V_Counter >= FIRST_VISIBLE_LINE && CPU.V_Counter <= PPU.ScreenHeight)
RenderLine((uint8) (CPU.V_Counter - FIRST_VISIBLE_LINE));
S9xCheckMissingHTimerPosition(Timings.RenderPos);
S9xReschedule();
break;
@ -535,13 +561,28 @@ void S9xDoHEventProcessing (void)
S9xTraceFormattedMessage("*** WRAM Refresh HC:%04d", CPU.Cycles);
#endif
CPU.PrevCycles = CPU.Cycles;
S9xCheckMissingHTimerHalt(Timings.WRAMRefreshPos, SNES_WRAM_REFRESH_CYCLES);
CPU.Cycles += SNES_WRAM_REFRESH_CYCLES;
S9xCheckInterrupts();
S9xCheckMissingHTimerPosition(Timings.WRAMRefreshPos);
S9xReschedule();
break;
case HC_IRQ_1_3_EVENT:
case HC_IRQ_3_5_EVENT:
case HC_IRQ_5_7_EVENT:
case HC_IRQ_7_9_EVENT:
case HC_IRQ_9_A_EVENT:
case HC_IRQ_A_1_EVENT:
if (PPU.HTimerEnabled && (!PPU.VTimerEnabled || (CPU.V_Counter == PPU.VTimerPosition)))
S9xSetIRQ(PPU_IRQ_SOURCE);
else
if (PPU.VTimerEnabled && (CPU.V_Counter == PPU.VTimerPosition))
S9xSetIRQ(PPU_IRQ_SOURCE);
S9xReschedule();
break;
}
#ifdef DEBUGGER
@ -550,3 +591,4 @@ void S9xDoHEventProcessing (void)
eventname[CPU.WhichEvent], CPU.NextEvent, CPU.Cycles);
#endif
}

View File

@ -179,9 +179,6 @@
#define _CPUEXEC_H_
#include "ppu.h"
#ifdef DEBUGGER
#include "debug.h"
#endif
struct SOpcodes
{
@ -196,6 +193,7 @@ struct SICPU
uint8 _Zero;
uint8 _Negative;
uint8 _Overflow;
bool8 CPUExecuting;
uint32 ShiftedPB;
uint32 ShiftedDB;
uint32 Frame;
@ -219,6 +217,8 @@ void S9xMainLoop (void);
void S9xReset (void);
void S9xSoftReset (void);
void S9xDoHEventProcessing (void);
void S9xClearIRQ (uint32);
void S9xSetIRQ (uint32);
static inline void S9xUnpackStatus (void)
{
@ -270,43 +270,84 @@ static inline void S9xFixCycles (void)
}
}
static inline void S9xCheckInterrupts (void)
static inline void S9xReschedule (void)
{
bool8 thisIRQ = PPU.HTimerEnabled || PPU.VTimerEnabled;
uint8 next = 0;
int32 hpos = 0;
if (CPU.IRQLine && thisIRQ)
CPU.IRQTransition = TRUE;
if (PPU.HTimerEnabled)
switch (CPU.WhichEvent)
{
int32 htimepos = PPU.HTimerPosition;
if (CPU.Cycles >= Timings.H_Max)
htimepos += Timings.H_Max;
case HC_HBLANK_START_EVENT:
case HC_IRQ_1_3_EVENT:
next = HC_HDMA_START_EVENT;
hpos = Timings.HDMAStart;
break;
if (CPU.PrevCycles >= htimepos || CPU.Cycles < htimepos)
thisIRQ = FALSE;
case HC_HDMA_START_EVENT:
case HC_IRQ_3_5_EVENT:
next = HC_HCOUNTER_MAX_EVENT;
hpos = Timings.H_Max;
break;
case HC_HCOUNTER_MAX_EVENT:
case HC_IRQ_5_7_EVENT:
next = HC_HDMA_INIT_EVENT;
hpos = Timings.HDMAInit;
break;
case HC_HDMA_INIT_EVENT:
case HC_IRQ_7_9_EVENT:
next = HC_RENDER_EVENT;
hpos = Timings.RenderPos;
break;
case HC_RENDER_EVENT:
case HC_IRQ_9_A_EVENT:
next = HC_WRAM_REFRESH_EVENT;
hpos = Timings.WRAMRefreshPos;
break;
case HC_WRAM_REFRESH_EVENT:
case HC_IRQ_A_1_EVENT:
next = HC_HBLANK_START_EVENT;
hpos = Timings.HBlankStart;
break;
}
if (PPU.VTimerEnabled)
if (((int32) PPU.HTimerPosition > CPU.NextEvent) && ((int32) PPU.HTimerPosition < hpos))
{
int32 vcounter = CPU.V_Counter;
if (CPU.Cycles >= Timings.H_Max)
vcounter++;
hpos = (int32) PPU.HTimerPosition;
if (vcounter != PPU.VTimerPosition)
thisIRQ = FALSE;
switch (next)
{
case HC_HDMA_START_EVENT:
next = HC_IRQ_1_3_EVENT;
break;
case HC_HCOUNTER_MAX_EVENT:
next = HC_IRQ_3_5_EVENT;
break;
case HC_HDMA_INIT_EVENT:
next = HC_IRQ_5_7_EVENT;
break;
case HC_RENDER_EVENT:
next = HC_IRQ_7_9_EVENT;
break;
case HC_WRAM_REFRESH_EVENT:
next = HC_IRQ_9_A_EVENT;
break;
case HC_HBLANK_START_EVENT:
next = HC_IRQ_A_1_EVENT;
break;
}
}
if (!CPU.IRQLastState && thisIRQ)
{
#ifdef DEBUGGER
S9xTraceFormattedMessage("--- /IRQ High->Low prev HC:%04d curr HC:%04d HTimer:%d Pos:%04d VTimer:%d Pos:%03d",
CPU.PrevCycles, CPU.Cycles, PPU.HTimerEnabled, PPU.HTimerPosition, PPU.VTimerEnabled, PPU.VTimerPosition);
#endif
CPU.IRQLine = TRUE;
}
CPU.IRQLastState = thisIRQ;
CPU.NextEvent = hpos;
CPU.WhichEvent = next;
}
#endif

View File

@ -280,6 +280,7 @@ static void Op##OP (void) \
S9xSetPCBase(ICPU.ShiftedPB + newPC.W); \
else \
Registers.PCw = newPC.W; \
CPUShutdown(); \
} \
}
@ -514,6 +515,9 @@ static inline void CPY (uint8 val)
static inline void DEC16 (uint32 OpAddress, s9xwrap_t w)
{
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
uint16 Work16 = S9xGetWord(OpAddress, w) - 1;
AddCycles(ONE_CYCLE);
S9xSetWord(Work16, OpAddress, w, WRITE_10);
@ -523,6 +527,9 @@ static inline void DEC16 (uint32 OpAddress, s9xwrap_t w)
static inline void DEC8 (uint32 OpAddress)
{
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
uint8 Work8 = S9xGetByte(OpAddress) - 1;
AddCycles(ONE_CYCLE);
S9xSetByte(Work8, OpAddress);
@ -544,6 +551,9 @@ static inline void EOR (uint8 val)
static inline void INC16 (uint32 OpAddress, s9xwrap_t w)
{
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
uint16 Work16 = S9xGetWord(OpAddress, w) + 1;
AddCycles(ONE_CYCLE);
S9xSetWord(Work16, OpAddress, w, WRITE_10);
@ -553,6 +563,9 @@ static inline void INC16 (uint32 OpAddress, s9xwrap_t w)
static inline void INC8 (uint32 OpAddress)
{
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
uint8 Work8 = S9xGetByte(OpAddress) + 1;
AddCycles(ONE_CYCLE);
S9xSetByte(Work8, OpAddress);

View File

@ -188,9 +188,13 @@
#endif
#ifdef SA1_OPCODES
#define AddCycles(n) { SA1.Cycles += (n); }
#define AddCycles(n) { }
#else
#define AddCycles(n) { CPU.PrevCycles = CPU.Cycles; CPU.Cycles += (n); S9xCheckInterrupts(); while (CPU.Cycles >= CPU.NextEvent) S9xDoHEventProcessing(); }
#if (S9X_ACCURACY_LEVEL >= 3)
#define AddCycles(n) { CPU.Cycles += (n); while (CPU.Cycles >= CPU.NextEvent) S9xDoHEventProcessing(); }
#else
#define AddCycles(n) { CPU.Cycles += (n); }
#endif
#endif
#include "cpuaddr.h"
@ -655,6 +659,9 @@ rOPX (CCSlow, AbsoluteSlow, WRAP_NONE, CPY)
static void Op3AM1 (void)
{
AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
Registers.AL--;
SetZN(Registers.AL);
}
@ -662,6 +669,9 @@ static void Op3AM1 (void)
static void Op3AM0 (void)
{
AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
Registers.A.W--;
SetZN(Registers.A.W);
}
@ -669,6 +679,9 @@ static void Op3AM0 (void)
static void Op3ASlow (void)
{
AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
if (CheckMemory())
{
@ -800,6 +813,9 @@ rOPM (53Slow, StackRelativeIndirectIndexedSlow, WRAP_NONE, EOR)
static void Op1AM1 (void)
{
AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
Registers.AL++;
SetZN(Registers.AL);
}
@ -807,6 +823,9 @@ static void Op1AM1 (void)
static void Op1AM0 (void)
{
AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
Registers.A.W++;
SetZN(Registers.A.W);
}
@ -814,6 +833,9 @@ static void Op1AM0 (void)
static void Op1ASlow (void)
{
AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
if (CheckMemory())
{
@ -1528,6 +1550,54 @@ mOPM (0CSlow, AbsoluteSlow, WRAP_BANK, TSB)
/* Branch Instructions ***************************************************** */
#ifdef CPU_SHUTDOWN
#ifndef SA1_OPCODES
inline void CPUShutdown (void)
{
if (Settings.Shutdown && Registers.PBPC == CPU.WaitAddress)
{
// Don't skip cycles with a pending NMI or IRQ - could cause delayed interrupt.
if (CPU.WaitCounter == 0 && !(CPU.Flags & (IRQ_FLAG | NMI_FLAG)))
{
CPU.WaitAddress = 0xffffffff;
if (Settings.SA1)
S9xSA1ExecuteDuringSleep();
CPU.Cycles = CPU.NextEvent;
ICPU.CPUExecuting = FALSE;
S9xAPUExecute();
ICPU.CPUExecuting = TRUE;
}
else
if (CPU.WaitCounter >= 2)
CPU.WaitCounter = 1;
else
CPU.WaitCounter--;
}
}
#else
inline void CPUShutdown (void)
{
if (Settings.Shutdown && Registers.PBPC == CPU.WaitAddress)
{
if (CPU.WaitCounter >= 1)
SA1.Executing = FALSE;
else
CPU.WaitCounter++;
}
}
#endif
#else
#define CPUShutdown()
#endif
// BCC
bOP(90E0, Relative, !CheckCarry(), 0, 0)
bOP(90E1, Relative, !CheckCarry(), 0, 1)
@ -1622,7 +1692,7 @@ static void Op58 (void)
{
ClearIRQ();
AddCycles(ONE_CYCLE);
CHECK_FOR_IRQ();
//CHECK_FOR_IRQ();
}
// SEI
@ -1644,6 +1714,9 @@ static void OpB8 (void)
static void OpCAX1 (void)
{
AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
Registers.XL--;
SetZN(Registers.XL);
}
@ -1651,6 +1724,9 @@ static void OpCAX1 (void)
static void OpCAX0 (void)
{
AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
Registers.X.W--;
SetZN(Registers.X.W);
}
@ -1658,6 +1734,9 @@ static void OpCAX0 (void)
static void OpCASlow (void)
{
AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
if (CheckIndex())
{
@ -1674,6 +1753,9 @@ static void OpCASlow (void)
static void Op88X1 (void)
{
AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
Registers.YL--;
SetZN(Registers.YL);
}
@ -1681,6 +1763,9 @@ static void Op88X1 (void)
static void Op88X0 (void)
{
AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
Registers.Y.W--;
SetZN(Registers.Y.W);
}
@ -1688,6 +1773,9 @@ static void Op88X0 (void)
static void Op88Slow (void)
{
AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
if (CheckIndex())
{
@ -1706,6 +1794,9 @@ static void Op88Slow (void)
static void OpE8X1 (void)
{
AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
Registers.XL++;
SetZN(Registers.XL);
}
@ -1713,6 +1804,9 @@ static void OpE8X1 (void)
static void OpE8X0 (void)
{
AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
Registers.X.W++;
SetZN(Registers.X.W);
}
@ -1720,6 +1814,9 @@ static void OpE8X0 (void)
static void OpE8Slow (void)
{
AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
if (CheckIndex())
{
@ -1736,6 +1833,9 @@ static void OpE8Slow (void)
static void OpC8X1 (void)
{
AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
Registers.YL++;
SetZN(Registers.YL);
}
@ -1743,6 +1843,9 @@ static void OpC8X1 (void)
static void OpC8X0 (void)
{
AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
Registers.Y.W++;
SetZN(Registers.Y.W);
}
@ -1750,6 +1853,9 @@ static void OpC8X0 (void)
static void OpC8Slow (void)
{
AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
if (CheckIndex())
{
@ -2265,7 +2371,7 @@ static void Op28E1 (void)
SetFlags(MemoryFlag | IndexFlag);
S9xUnpackStatus();
S9xFixCycles();
CHECK_FOR_IRQ();
//CHECK_FOR_IRQ();
}
static void Op28E0 (void)
@ -2282,7 +2388,7 @@ static void Op28E0 (void)
}
S9xFixCycles();
CHECK_FOR_IRQ();
//CHECK_FOR_IRQ();
}
static void Op28Slow (void)
@ -2310,7 +2416,7 @@ static void Op28Slow (void)
}
S9xFixCycles();
CHECK_FOR_IRQ();
//CHECK_FOR_IRQ();
}
// PLX
@ -2879,7 +2985,7 @@ void S9xOpcode_NMI (void)
AddCycles(2 * SLOW_ONE_CYCLE);
S9xSA1SetPCBase(Memory.FillRAM[0x2205] | (Memory.FillRAM[0x2206] << 8));
#else
if (Settings.SA1 && (Memory.FillRAM[0x2209] & 0x10))
if (Settings.SA1 && (Memory.FillRAM[0x2209] & 0x20))
{
OpenBus = Memory.FillRAM[0x220d];
AddCycles(2 * SLOW_ONE_CYCLE);
@ -2963,11 +3069,17 @@ static void Op5CSlow (void)
static void Op4C (void)
{
S9xSetPCBase(ICPU.ShiftedPB + ((uint16) Absolute(JUMP)));
#if defined(CPU_SHUTDOWN) && defined(SA1_OPCODES)
CPUShutdown();
#endif
}
static void Op4CSlow (void)
{
S9xSetPCBase(ICPU.ShiftedPB + ((uint16) AbsoluteSlow(JUMP)));
#if defined(CPU_SHUTDOWN) && defined(SA1_OPCODES)
CPUShutdown();
#endif
}
static void Op6C (void)
@ -3313,7 +3425,7 @@ static void OpC2 (void)
}
S9xFixCycles();
CHECK_FOR_IRQ();
//CHECK_FOR_IRQ();
}
static void OpC2Slow (void)
@ -3342,7 +3454,7 @@ static void OpC2Slow (void)
}
S9xFixCycles();
CHECK_FOR_IRQ();
//CHECK_FOR_IRQ();
}
static void OpE2 (void)
@ -3450,7 +3562,7 @@ static void Op40Slow (void)
}
S9xFixCycles();
CHECK_FOR_IRQ();
//CHECK_FOR_IRQ();
}
/* STP/WAI ***************************************************************** */
@ -3458,15 +3570,44 @@ static void Op40Slow (void)
// WAI
static void OpCB (void)
{
// Ok, let's just C-ify the ASM versions separately.
#ifdef SA1_OPCODES
SA1.WaitingForInterrupt = TRUE;
Registers.PCw--;
AddCycles(TWO_CYCLES);
#else
CPU.WaitingForInterrupt = TRUE;
Registers.PCw--;
AddCycles(TWO_CYCLES);
#if 0
// XXX: FIXME
if (Settings.Shutdown)
{
SA1.Cycles = SA1.NextEvent;
SA1.Executing = FALSE;
//S9xAPUExecute(); // FIXME
SA1.Executing = TRUE;
}
#endif
#else // SA1_OPCODES
#if 0
if (CPU.IRQActive)
AddCycles(TWO_CYCLES);
else
#endif
{
CPU.WaitingForInterrupt = TRUE;
Registers.PCw--;
#ifdef CPU_SHUTDOWN
if (Settings.Shutdown)
{
CPU.Cycles = CPU.NextEvent;
ICPU.CPUExecuting = FALSE;
S9xAPUExecute();
ICPU.CPUExecuting = TRUE;
}
else
AddCycles(TWO_CYCLES);
#else
AddCycles(TWO_CYCLES);
#endif
}
#endif // SA1_OPCODES
}
// STP
@ -3509,7 +3650,7 @@ static void Op42 (void)
S9xMessage(S9X_DEBUG, S9X_DEBUG_OUTPUT, buf);
if (trace != NULL)
fclose(trace);
ENSURE_TRACE_OPEN(trace,"WDMtrace.log","ab")
trace = fopen("WDMtrace.log", "ab");
}
break;
@ -3883,3 +4024,4 @@ struct SOpcodes S9xOpcodesSlow[256] =
{ OpFASlow }, { OpFB }, { OpFCSlow }, { OpFDSlow }, { OpFESlow },
{ OpFFSlow }
};

View File

@ -181,9 +181,8 @@
void S9xOpcode_NMI (void);
void S9xOpcode_IRQ (void);
#ifndef SA1_OPCODES
#define CHECK_FOR_IRQ() {} // if (CPU.IRQLine) S9xOpcode_IRQ(); }
#else
#define CHECK_FOR_IRQ() {}
#endif
#define CHECK_FOR_IRQ() \
if (CPU.IRQActive && !CheckFlag(IRQ) && !Settings.DisableIRQ) \
S9xOpcode_IRQ()
#endif

View File

@ -185,7 +185,7 @@
#include "missing.h"
#endif
#define ADD_CYCLES(n) { CPU.PrevCycles = CPU.Cycles; CPU.Cycles += (n); S9xCheckInterrupts(); }
#define ADD_CYCLES(n) CPU.Cycles += (n)
extern uint8 *HDMAMemPointers[8];
extern int HDMA_ModeByteCounts[8];
@ -741,6 +741,9 @@ bool8 S9xDoDMA (uint8 Channel)
break;
case 0x18: // VMDATAL
#ifndef CORRECT_VRAM_READS
IPPU.FirstVRAMRead = TRUE;
#endif
if (!PPU.VMA.FullGraphicCount)
{
do
@ -763,6 +766,9 @@ bool8 S9xDoDMA (uint8 Channel)
break;
case 0x19: // VMDATAH
#ifndef CORRECT_VRAM_READS
IPPU.FirstVRAMRead = TRUE;
#endif
if (!PPU.VMA.FullGraphicCount)
{
do
@ -831,6 +837,9 @@ bool8 S9xDoDMA (uint8 Channel)
if (d->BAddress == 0x18)
{
// VMDATAL
#ifndef CORRECT_VRAM_READS
IPPU.FirstVRAMRead = TRUE;
#endif
if (!PPU.VMA.FullGraphicCount)
{
switch (b)
@ -1273,7 +1282,7 @@ bool8 S9xDoDMA (uint8 Channel)
}
}
if (CPU.NMILine && (Timings.NMITriggerPos != 0xffff))
if ((CPU.Flags & NMI_FLAG) && (Timings.NMITriggerPos != 0xffff))
{
Timings.NMITriggerPos = CPU.Cycles + Timings.NMIDMADelay;
if (Timings.NMITriggerPos >= Timings.H_Max)
@ -1364,7 +1373,10 @@ static inline bool8 HDMAReadLineCount (int d)
void S9xStartHDMA (void)
{
PPU.HDMA = Memory.FillRAM[0x420c];
if (Settings.DisableHDMA)
PPU.HDMA = 0;
else
PPU.HDMA = Memory.FillRAM[0x420c];
#ifdef DEBUGGER
missing.hdma_this_frame = PPU.HDMA;

View File

@ -202,7 +202,6 @@ void S9xResetSuperFX (void)
SuperFX.speedPerLine = (uint32) (0.417 * 10.5e6 * ((1.0 / (float) Memory.ROMFramesPerSecond) / ((float) (Timings.V_Max))));
SuperFX.oneLineDone = FALSE;
SuperFX.vFlags = 0;
CPU.IRQExternal = FALSE;
FxReset(&SuperFX);
}
@ -300,10 +299,13 @@ uint8 S9xGetSuperFX (uint16 address)
uint8 byte;
byte = Memory.FillRAM[address];
#ifdef CPU_SHUTDOWN
if (address == 0x3030)
CPU.WaitAddress = CPU.PBPCAtOpcodeStart;
#endif
if (address == 0x3031)
{
CPU.IRQExternal = FALSE;
S9xClearIRQ(GSU_IRQ_SOURCE);
Memory.FillRAM[0x3031] = byte & 0x7f;
}
@ -318,7 +320,7 @@ void S9xSuperFXExec (void)
uint16 GSUStatus = Memory.FillRAM[0x3000 + GSU_SFR] | (Memory.FillRAM[0x3000 + GSU_SFR + 1] << 8);
if ((GSUStatus & (FLG_G | FLG_IRQ)) == FLG_IRQ)
CPU.IRQExternal = TRUE;
S9xSetIRQ(GSU_IRQ_SOURCE);
}
}

View File

@ -187,12 +187,12 @@
#include "seta.h"
#include "bsx.h"
#if (S9X_ACCURACY_LEVEL >= 2)
#define addCyclesInMemoryAccess \
if (!CPU.InDMAorHDMA) \
{ \
CPU.PrevCycles = CPU.Cycles; \
CPU.Cycles += speed; \
S9xCheckInterrupts(); \
while (CPU.Cycles >= CPU.NextEvent) \
S9xDoHEventProcessing(); \
}
@ -200,13 +200,23 @@
#define addCyclesInMemoryAccess_x2 \
if (!CPU.InDMAorHDMA) \
{ \
CPU.PrevCycles = CPU.Cycles; \
CPU.Cycles += speed << 1; \
S9xCheckInterrupts(); \
while (CPU.Cycles >= CPU.NextEvent) \
S9xDoHEventProcessing(); \
}
#else
#define addCyclesInMemoryAccess \
if (!CPU.InDMAorHDMA) \
CPU.Cycles += speed;
#define addCyclesInMemoryAccess_x2 \
if (!CPU.InDMAorHDMA) \
CPU.Cycles += speed << 1;
#endif
extern uint8 OpenBus;
static inline int32 memory_speed (uint32 address)
@ -237,6 +247,10 @@ inline uint8 S9xGetByte (uint32 Address)
if (GetAddress >= (uint8 *) CMemory::MAP_LAST)
{
#ifdef CPU_SHUTDOWN
if (Memory.BlockIsRAM[block])
CPU.WaitAddress = CPU.PBPCAtOpcodeStart;
#endif
byte = *(GetAddress + (Address & 0xffff));
addCyclesInMemoryAccess;
return (byte);
@ -365,6 +379,10 @@ inline uint16 S9xGetWord (uint32 Address, enum s9xwrap_t w = WRAP_NONE)
if (GetAddress >= (uint8 *) CMemory::MAP_LAST)
{
#ifdef CPU_SHUTDOWN
if (Memory.BlockIsRAM[block])
CPU.WaitAddress = CPU.PBPCAtOpcodeStart;
#endif
word = READ_WORD(GetAddress + (Address & 0xffff));
addCyclesInMemoryAccess_x2;
return (word);
@ -492,14 +510,33 @@ inline uint16 S9xGetWord (uint32 Address, enum s9xwrap_t w = WRAP_NONE)
inline void S9xSetByte (uint8 Byte, uint32 Address)
{
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
int block = (Address & 0xffffff) >> MEMMAP_SHIFT;
uint8 *SetAddress = Memory.WriteMap[block];
int32 speed = memory_speed(Address);
if (SetAddress >= (uint8 *) CMemory::MAP_LAST)
{
#ifdef CPU_SHUTDOWN
SetAddress += (Address & 0xffff);
*SetAddress = Byte;
addCyclesInMemoryAccess;
if (Settings.SA1)
{
if (SetAddress == SA1.WaitByteAddress1 || SetAddress == SA1.WaitByteAddress2)
{
SA1.Executing = SA1.S9xOpcodes != NULL;
SA1.WaitCounter = 0;
}
}
#else
*(SetAddress + (Address & 0xffff)) = Byte;
addCyclesInMemoryAccess;
#endif
return;
}
@ -556,6 +593,7 @@ inline void S9xSetByte (uint8 Byte, uint32 Address)
case CMemory::MAP_SA1RAM:
*(Memory.SRAM + (Address & 0xffff)) = Byte;
SA1.Executing = !SA1.Waiting;
addCyclesInMemoryAccess;
return;
@ -632,14 +670,33 @@ inline void S9xSetWord (uint16 Word, uint32 Address, enum s9xwrap_t w = WRAP_NON
return;
}
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
int block = (Address & 0xffffff) >> MEMMAP_SHIFT;
uint8 *SetAddress = Memory.WriteMap[block];
int32 speed = memory_speed(Address);
if (SetAddress >= (uint8 *) CMemory::MAP_LAST)
{
#ifdef CPU_SHUTDOWN
SetAddress += (Address & 0xffff);
WRITE_WORD(SetAddress, Word);
addCyclesInMemoryAccess_x2;
if (Settings.SA1)
{
if (SetAddress == SA1.WaitByteAddress1 || SetAddress == SA1.WaitByteAddress2)
{
SA1.Executing = SA1.S9xOpcodes != NULL;
SA1.WaitCounter = 0;
}
}
#else
WRITE_WORD(SetAddress + (Address & 0xffff), Word);
addCyclesInMemoryAccess_x2;
#endif
return;
}
@ -749,6 +806,7 @@ inline void S9xSetWord (uint16 Word, uint32 Address, enum s9xwrap_t w = WRAP_NON
case CMemory::MAP_SA1RAM:
WRITE_WORD(Memory.SRAM + (Address & 0xffff), Word);
SA1.Executing = !SA1.Waiting;
addCyclesInMemoryAccess_x2;
return;

View File

@ -2270,9 +2270,11 @@ void CMemory::InitROM (void)
Settings.SETA = 0;
Settings.SRTC = FALSE;
Settings.BS = FALSE;
SuperFX.nRomBanks = CalculatedSize >> 15;
SA1.Executing = FALSE;
//// Parse ROM header and read ROM informatoin
CompanyId = -1;
@ -3496,6 +3498,7 @@ bool8 CMemory::match_id (const char *str)
void CMemory::ApplyROMFixes (void)
{
Settings.Shutdown = Settings.ShutdownMaster;
Settings.BlockInvalidVRAMAccess = Settings.BlockInvalidVRAMAccessMaster;
//// Warnings
@ -3573,7 +3576,6 @@ void CMemory::ApplyROMFixes (void)
Timings.HDMAStart = SNES_HDMA_START_HC + Settings.HDMATimingHack - 100;
Timings.HBlankStart = SNES_HBLANK_START_HC + Timings.HDMAStart - SNES_HDMA_START_HC;
Timings.IRQTriggerCycles = 10;
if (!Settings.DisableGameSpecificHacks)
{
@ -3588,6 +3590,14 @@ void CMemory::ApplyROMFixes (void)
if (!Settings.DisableGameSpecificHacks)
{
// Opcode-based emulators cannot escape from "reading $4211/BPL" infinite loop...
// The true IRQ can be triggered inside an opcode.
if (match_na("TRAVERSE")) // Traverse - Starlight & Prairie
{
Timings.IRQPendCount = 1;
printf("IRQ count hack: %d\n", Timings.IRQPendCount);
}
// An infinite loop reads $4212 and waits V-blank end, whereas VIRQ is set V=0.
// If Snes9x succeeds to escape from the loop before jumping into the IRQ handler, the game goes further.
// If Snes9x jumps into the IRQ handler before escaping from the loop,
@ -3597,6 +3607,12 @@ void CMemory::ApplyROMFixes (void)
Timings.IRQPendCount = 2;
printf("IRQ count hack: %d\n", Timings.IRQPendCount);
}
if (match_na("BATTLE BLAZE"))
{
Timings.IRQPendCount = 1;
printf("IRQ count hack: %d\n", Timings.IRQPendCount);
}
}
if (!Settings.DisableGameSpecificHacks)
@ -3609,6 +3625,242 @@ void CMemory::ApplyROMFixes (void)
}
}
//// CPU speed-ups (CPU_Shutdown())
// Force disabling a speed-up hack
// Games which spool sound samples between the SNES and sound CPU using
// H-DMA as the sample is playing.
if (match_na("EARTHWORM JIM 2") || // Earth Worm Jim 2
match_na("PRIMAL RAGE") || // Primal Rage
match_na("CLAY FIGHTER") || // Clay Fighter
match_na("ClayFighter 2") || // Clay Fighter 2
match_na("WeaponLord") || // Weapon Lord
match_nn("WAR 2410") || // War 2410
match_id("ARF") || // Star Ocean
match_id("A4WJ") || // Mini Yonku Shining Scorpion - Let's & Go!!
match_nn("NHL") ||
match_nc("MADDEN"))
{
if (Settings.Shutdown)
printf("Disabled CPU shutdown hack.\n");
Settings.Shutdown = FALSE;
}
// SA-1
SA1.WaitAddress = 0xffffffff;
SA1.WaitByteAddress1 = NULL;
SA1.WaitByteAddress2 = NULL;
if (Settings.SA1)
{
// Itoi Shigesato no Bass Tsuri No.1 (J)
if (match_id("ZBPJ"))
{
SA1.WaitAddress = 0x0093f1;
SA1.WaitByteAddress1 = FillRAM + 0x304a;
}
// Daisenryaku Expert WWII (J)
if (match_id("AEVJ"))
{
SA1.WaitAddress = 0x0ed18d;
SA1.WaitByteAddress1 = FillRAM + 0x3000;
}
// Derby Jockey 2 (J)
if (match_id("A2DJ"))
{
SA1.WaitAddress = 0x008b62;
}
// Dragon Ball Z - Hyper Dimension (J)
if (match_id("AZIJ"))
{
SA1.WaitAddress = 0x008083;
SA1.WaitByteAddress1 = FillRAM + 0x3020;
}
// SD Gundam G NEXT (J)
if (match_id("ZX3J"))
{
SA1.WaitAddress = 0x0087f2;
SA1.WaitByteAddress1 = FillRAM + 0x30c4;
}
// Shougi no Hanamichi (J)
if (match_id("AARJ"))
{
SA1.WaitAddress = 0xc1f85a;
SA1.WaitByteAddress1 = SRAM + 0x0c64;
SA1.WaitByteAddress2 = SRAM + 0x0c66;
}
// Asahi Shinbun Rensai Katou Hifumi Kudan Shougi Shingiryu (J)
if (match_id("A23J"))
{
SA1.WaitAddress = 0xc25037;
SA1.WaitByteAddress1 = SRAM + 0x0c06;
SA1.WaitByteAddress2 = SRAM + 0x0c08;
}
// Taikyoku Igo - Idaten (J)
if (match_id("AIIJ"))
{
SA1.WaitAddress = 0xc100be;
SA1.WaitByteAddress1 = SRAM + 0x1002;
SA1.WaitByteAddress2 = SRAM + 0x1004;
}
// Takemiya Masaki Kudan no Igo Taishou (J)
if (match_id("AITJ"))
{
SA1.WaitAddress = 0x0080b7;
}
// J. League '96 Dream Stadium (J)
if (match_id("AJ6J"))
{
SA1.WaitAddress = 0xc0f74a;
}
// Jumpin' Derby (J)
if (match_id("AJUJ"))
{
SA1.WaitAddress = 0x00d926;
}
// Kakinoki Shougi (J)
if (match_id("AKAJ"))
{
SA1.WaitAddress = 0x00f070;
}
// Hoshi no Kirby 3 (J), Kirby's Dream Land 3 (U)
if (match_id("AFJJ") || match_id("AFJE"))
{
SA1.WaitAddress = 0x0082d4;
SA1.WaitByteAddress1 = SRAM + 0x72a4;
}
// Hoshi no Kirby - Super Deluxe (J)
if (match_id("AKFJ"))
{
SA1.WaitAddress = 0x008c93;
SA1.WaitByteAddress1 = FillRAM + 0x300a;
SA1.WaitByteAddress2 = FillRAM + 0x300e;
}
// Kirby Super Star (U)
if (match_id("AKFE"))
{
SA1.WaitAddress = 0x008cb8;
SA1.WaitByteAddress1 = FillRAM + 0x300a;
SA1.WaitByteAddress2 = FillRAM + 0x300e;
}
// Super Mario RPG (J), (U)
if (match_id("ARWJ") || match_id("ARWE"))
{
SA1.WaitAddress = 0xc0816f;
SA1.WaitByteAddress1 = FillRAM + 0x3000;
}
// Marvelous (J)
if (match_id("AVRJ"))
{
SA1.WaitAddress = 0x0085f2;
SA1.WaitByteAddress1 = FillRAM + 0x3024;
}
// Harukanaru Augusta 3 - Masters New (J)
if (match_id("AO3J"))
{
SA1.WaitAddress = 0x00dddb;
SA1.WaitByteAddress1 = FillRAM + 0x37b4;
}
// Jikkyou Oshaberi Parodius (J)
if (match_id("AJOJ"))
{
SA1.WaitAddress = 0x8084e5;
}
// Super Bomberman - Panic Bomber W (J)
if (match_id("APBJ"))
{
SA1.WaitAddress = 0x00857a;
}
// Pebble Beach no Hatou New - Tournament Edition (J)
if (match_id("AONJ"))
{
SA1.WaitAddress = 0x00df33;
SA1.WaitByteAddress1 = FillRAM + 0x37b4;
}
// PGA European Tour (U)
if (match_id("AEPE"))
{
SA1.WaitAddress = 0x003700;
SA1.WaitByteAddress1 = FillRAM + 0x3102;
}
// PGA Tour 96 (U)
if (match_id("A3GE"))
{
SA1.WaitAddress = 0x003700;
SA1.WaitByteAddress1 = FillRAM + 0x3102;
}
// Power Rangers Zeo - Battle Racers (U)
if (match_id("A4RE"))
{
SA1.WaitAddress = 0x009899;
SA1.WaitByteAddress1 = FillRAM + 0x3000;
}
// SD F-1 Grand Prix (J)
if (match_id("AGFJ"))
{
SA1.WaitAddress = 0x0181bc;
}
// Saikousoku Shikou Shougi Mahjong (J)
if (match_id("ASYJ"))
{
SA1.WaitAddress = 0x00f2cc;
SA1.WaitByteAddress1 = SRAM + 0x7ffe;
SA1.WaitByteAddress2 = SRAM + 0x7ffc;
}
// Shougi Saikyou II (J)
if (match_id("AX2J"))
{
SA1.WaitAddress = 0x00d675;
}
// Mini Yonku Shining Scorpion - Let's & Go!! (J)
if (match_id("A4WJ"))
{
SA1.WaitAddress = 0xc048be;
}
// Shin Shougi Club (J)
if (match_id("AHJJ"))
{
SA1.WaitAddress = 0xc1002a;
SA1.WaitByteAddress1 = SRAM + 0x0806;
SA1.WaitByteAddress2 = SRAM + 0x0808;
}
// rest games:
// Habu Meijin no Omoshiro Shougi (J)
// Hayashi Kaihou Kudan no Igo Taidou (J)
// Shougi Saikyou (J)
// Super Robot Wars Gaiden (J)
// Super Shougi 3 - Kitaihei (J)
}
//// SRAM initial value
if (!Settings.DisableGameSpecificHacks)

View File

@ -745,8 +745,7 @@ int S9xMovieUnfreeze (uint8 *buf, uint32 size)
}
else
{
uint32 space_processed = (Movie.BytesPerSample * (current_sample + 1));
if (current_frame > Movie.MaxFrame || current_sample > Movie.MaxSample || memcmp(Movie.InputBuffer, ptr, space_processed))
if (current_frame > Movie.MaxFrame || current_sample > Movie.MaxSample || memcmp(Movie.InputBuffer, ptr, space_needed))
return (SNAPSHOT_INCONSISTENT);
change_state(MOVIE_STATE_PLAY);
@ -787,8 +786,8 @@ int S9xMovieOpen (const char *filename, bool8 read_only)
read_movie_extrarominfo(fd, &Movie);
fflush(fd);
fn = fileno(fd);
fn = dup(fileno(fd));
fclose(fd);
store_previous_settings();
restore_movie_settings();
@ -854,6 +853,7 @@ int S9xMovieCreate (const char *filename, uint8 controllers_mask, uint8 opts, co
{
FILE *fd;
STREAM stream;
int fn;
if (controllers_mask == 0)
return (WRONG_FORMAT);
@ -902,9 +902,10 @@ int S9xMovieCreate (const char *filename, uint8 controllers_mask, uint8 opts, co
write_movie_extrarominfo(fd, &Movie);
fn = dup(fileno(fd));
fclose(fd);
stream = OPEN_STREAM(filename, "ab");
stream = REOPEN_STREAM(fn, "ab");
if (!stream)
return (FILE_NOT_FOUND);
@ -1008,10 +1009,9 @@ int S9xMovieGetInfo (const char *filename, struct MovieInfo *info)
strncpy(info->ROMName, local_movie.ROMName, 23);
fclose(fd);
if ((fd = fopen(filename, "r+")) == NULL)
if (access(filename, W_OK))
info->ReadOnly = true;
else
fclose(fd);
return (SUCCESS);
}

View File

@ -204,6 +204,9 @@ static inline void S9xLatchCounters (bool force)
#ifdef DEBUGGER
missing.h_v_latch = 1;
#endif
#if 0 // #ifdef CPU_SHUTDOWN
CPU.WaitAddress = CPU.PCAtOpcodeStart;
#endif
PPU.HVBeamCounterLatched = 1;
PPU.VBeamPosLatched = (uint16) CPU.V_Counter;
@ -242,6 +245,9 @@ static inline void S9xTryGunLatch (bool force)
#ifdef DEBUGGER
missing.h_v_latch = 1;
#endif
#if 0 // #ifdef CPU_SHUTDOWN
CPU.WaitAddress = CPU.PCAtOpcodeStart;
#endif
PPU.HVBeamCounterLatched = 1;
PPU.VBeamPosLatched = (uint16) PPU.GunVLatch;
@ -254,16 +260,72 @@ static inline void S9xTryGunLatch (bool force)
}
}
void S9xCheckMissingHTimerPosition (int32 hc)
{
if (PPU.HTimerPosition == hc)
{
if (PPU.HTimerEnabled && (!PPU.VTimerEnabled || (CPU.V_Counter == PPU.VTimerPosition)))
S9xSetIRQ(PPU_IRQ_SOURCE);
else
if (PPU.VTimerEnabled && (CPU.V_Counter == PPU.VTimerPosition))
S9xSetIRQ(PPU_IRQ_SOURCE);
}
}
void S9xCheckMissingHTimerHalt (int32 hc_from, int32 range)
{
if ((PPU.HTimerPosition >= hc_from) && (PPU.HTimerPosition < (hc_from + range)))
{
if (PPU.HTimerEnabled && (!PPU.VTimerEnabled || (CPU.V_Counter == PPU.VTimerPosition)))
CPU.IRQPending = 1;
else
if (PPU.VTimerEnabled && (CPU.V_Counter == PPU.VTimerPosition))
CPU.IRQPending = 1;
}
}
void S9xCheckMissingHTimerRange (int32 hc_from, int32 range)
{
if ((PPU.HTimerPosition >= hc_from) && (PPU.HTimerPosition < (hc_from + range)))
{
if (PPU.HTimerEnabled && (!PPU.VTimerEnabled || (CPU.V_Counter == PPU.VTimerPosition)))
S9xSetIRQ(PPU_IRQ_SOURCE);
else
if (PPU.VTimerEnabled && (CPU.V_Counter == PPU.VTimerPosition))
S9xSetIRQ(PPU_IRQ_SOURCE);
}
}
void S9xUpdateHVTimerPosition (void)
{
PPU.HTimerPosition = PPU.IRQHBeamPos * ONE_DOT_CYCLE + Timings.IRQTriggerCycles;
if (Timings.H_Max == Timings.H_Max_Master) // 1364
if (PPU.HTimerEnabled)
{
if (PPU.IRQHBeamPos > 322)
PPU.HTimerPosition += (ONE_DOT_CYCLE / 2);
if (PPU.IRQHBeamPos > 326)
PPU.HTimerPosition += (ONE_DOT_CYCLE / 2);
#ifdef DEBUGGER
missing.hirq_pos = PPU.IRQHBeamPos;
#endif
if (PPU.IRQHBeamPos != 0)
{
// IRQ_read
PPU.HTimerPosition = PPU.IRQHBeamPos * ONE_DOT_CYCLE;
if (Timings.H_Max == Timings.H_Max_Master) // 1364
{
if (PPU.IRQHBeamPos > 322)
PPU.HTimerPosition += (ONE_DOT_CYCLE / 2);
if (PPU.IRQHBeamPos > 326)
PPU.HTimerPosition += (ONE_DOT_CYCLE / 2);
}
PPU.HTimerPosition += 14;
// /IRQ
PPU.HTimerPosition += 4;
// after CPU executing
PPU.HTimerPosition += 6;
}
else
PPU.HTimerPosition = 10 + 4 + 6;
}
else
PPU.HTimerPosition = 10 + 4 + 6;
PPU.VTimerPosition = PPU.IRQVBeamPos;
@ -276,9 +338,111 @@ void S9xUpdateHVTimerPosition (void)
PPU.VTimerPosition = 0;
}
if (PPU.HTimerPosition < CPU.Cycles)
{
switch (CPU.WhichEvent)
{
case HC_IRQ_1_3_EVENT:
CPU.WhichEvent = HC_HDMA_START_EVENT;
CPU.NextEvent = Timings.HDMAStart;
break;
case HC_IRQ_3_5_EVENT:
CPU.WhichEvent = HC_HCOUNTER_MAX_EVENT;
CPU.NextEvent = Timings.H_Max;
break;
case HC_IRQ_5_7_EVENT:
CPU.WhichEvent = HC_HDMA_INIT_EVENT;
CPU.NextEvent = Timings.HDMAInit;
break;
case HC_IRQ_7_9_EVENT:
CPU.WhichEvent = HC_RENDER_EVENT;
CPU.NextEvent = Timings.RenderPos;
break;
case HC_IRQ_9_A_EVENT:
CPU.WhichEvent = HC_WRAM_REFRESH_EVENT;
CPU.NextEvent = Timings.WRAMRefreshPos;
break;
case HC_IRQ_A_1_EVENT:
CPU.WhichEvent = HC_HBLANK_START_EVENT;
CPU.NextEvent = Timings.HBlankStart;
break;
}
}
else
if ((PPU.HTimerPosition < CPU.NextEvent) || (!(CPU.WhichEvent & 1) && (PPU.HTimerPosition == CPU.NextEvent)))
{
CPU.NextEvent = PPU.HTimerPosition;
switch (CPU.WhichEvent)
{
case HC_HDMA_START_EVENT:
CPU.WhichEvent = HC_IRQ_1_3_EVENT;
break;
case HC_HCOUNTER_MAX_EVENT:
CPU.WhichEvent = HC_IRQ_3_5_EVENT;
break;
case HC_HDMA_INIT_EVENT:
CPU.WhichEvent = HC_IRQ_5_7_EVENT;
break;
case HC_RENDER_EVENT:
CPU.WhichEvent = HC_IRQ_7_9_EVENT;
break;
case HC_WRAM_REFRESH_EVENT:
CPU.WhichEvent = HC_IRQ_9_A_EVENT;
break;
case HC_HBLANK_START_EVENT:
CPU.WhichEvent = HC_IRQ_A_1_EVENT;
break;
}
}
else
{
switch (CPU.WhichEvent)
{
case HC_IRQ_1_3_EVENT:
CPU.WhichEvent = HC_HDMA_START_EVENT;
CPU.NextEvent = Timings.HDMAStart;
break;
case HC_IRQ_3_5_EVENT:
CPU.WhichEvent = HC_HCOUNTER_MAX_EVENT;
CPU.NextEvent = Timings.H_Max;
break;
case HC_IRQ_5_7_EVENT:
CPU.WhichEvent = HC_HDMA_INIT_EVENT;
CPU.NextEvent = Timings.HDMAInit;
break;
case HC_IRQ_7_9_EVENT:
CPU.WhichEvent = HC_RENDER_EVENT;
CPU.NextEvent = Timings.RenderPos;
break;
case HC_IRQ_9_A_EVENT:
CPU.WhichEvent = HC_WRAM_REFRESH_EVENT;
CPU.NextEvent = Timings.WRAMRefreshPos;
break;
case HC_IRQ_A_1_EVENT:
CPU.WhichEvent = HC_HBLANK_START_EVENT;
CPU.NextEvent = Timings.HBlankStart;
break;
}
}
#ifdef DEBUGGER
S9xTraceFormattedMessage("--- IRQ Timer set HTimer:%d Pos:%04d VTimer:%d Pos:%03d",
PPU.HTimerEnabled, PPU.HTimerPosition, PPU.VTimerEnabled, PPU.VTimerPosition);
S9xTraceFormattedMessage("--- IRQ settings: H:%d V:%d (%04d, %03d)", PPU.HTimerEnabled, PPU.VTimerEnabled, PPU.HTimerPosition, PPU.VTimerPosition);
#endif
}
@ -620,7 +784,7 @@ void S9xSetPPU (uint8 Byte, uint16 Address)
case 0x2116: // VMADDL
PPU.VMA.Address &= 0xff00;
PPU.VMA.Address |= Byte;
#ifdef CORRECT_VRAM_READS
if (PPU.VMA.FullGraphicCount)
{
uint32 addr = PPU.VMA.Address;
@ -630,13 +794,15 @@ void S9xSetPPU (uint8 Byte, uint16 Address)
}
else
IPPU.VRAMReadBuffer = READ_WORD(Memory.VRAM + ((PPU.VMA.Address << 1) & 0xffff));
#else
IPPU.FirstVRAMRead = TRUE;
#endif
break;
case 0x2117: // VMADDH
PPU.VMA.Address &= 0x00ff;
PPU.VMA.Address |= Byte << 8;
#ifdef CORRECT_VRAM_READS
if (PPU.VMA.FullGraphicCount)
{
uint32 addr = PPU.VMA.Address;
@ -646,14 +812,22 @@ void S9xSetPPU (uint8 Byte, uint16 Address)
}
else
IPPU.VRAMReadBuffer = READ_WORD(Memory.VRAM + ((PPU.VMA.Address << 1) & 0xffff));
#else
IPPU.FirstVRAMRead = TRUE;
#endif
break;
case 0x2118: // VMDATAL
#ifndef CORRECT_VRAM_READS
IPPU.FirstVRAMRead = TRUE;
#endif
REGISTER_2118(Byte);
break;
case 0x2119: // VMDATAH
#ifndef CORRECT_VRAM_READS
IPPU.FirstVRAMRead = TRUE;
#endif
REGISTER_2119(Byte);
break;
@ -1204,6 +1378,7 @@ uint8 S9xGetPPU (uint16 Address)
return (PPU.OpenBus1 = byte);
case 0x2139: // VMDATALREAD
#ifdef CORRECT_VRAM_READS
byte = IPPU.VRAMReadBuffer & 0xff;
if (!PPU.VMA.High)
{
@ -1219,13 +1394,33 @@ uint8 S9xGetPPU (uint16 Address)
PPU.VMA.Address += PPU.VMA.Increment;
}
#else
if (IPPU.FirstVRAMRead)
byte = Memory.VRAM[(PPU.VMA.Address << 1) & 0xffff];
else
if (PPU.VMA.FullGraphicCount)
{
uint32 addr = PPU.VMA.Address - 1;
uint32 rem = addr & PPU.VMA.Mask1;
uint32 address = (addr & ~PPU.VMA.Mask1) + (rem >> PPU.VMA.Shift) + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3);
byte = Memory.VRAM[((address << 1) - 2) & 0xffff];
}
else
byte = Memory.VRAM[((PPU.VMA.Address << 1) - 2) & 0xffff];
if (!PPU.VMA.High)
{
PPU.VMA.Address += PPU.VMA.Increment;
IPPU.FirstVRAMRead = FALSE;
}
#endif
#ifdef DEBUGGER
missing.vram_read = 1;
#endif
return (PPU.OpenBus1 = byte);
case 0x213a: // VMDATAHREAD
#ifdef CORRECT_VRAM_READS
byte = (IPPU.VRAMReadBuffer >> 8) & 0xff;
if (PPU.VMA.High)
{
@ -1241,6 +1436,26 @@ uint8 S9xGetPPU (uint16 Address)
PPU.VMA.Address += PPU.VMA.Increment;
}
#else
if (IPPU.FirstVRAMRead)
byte = Memory.VRAM[((PPU.VMA.Address << 1) + 1) & 0xffff];
else
if (PPU.VMA.FullGraphicCount)
{
uint32 addr = PPU.VMA.Address - 1;
uint32 rem = addr & PPU.VMA.Mask1;
uint32 address = (addr & ~PPU.VMA.Mask1) + (rem >> PPU.VMA.Shift) + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3);
byte = Memory.VRAM[((address << 1) - 1) & 0xffff];
}
else
byte = Memory.VRAM[((PPU.VMA.Address << 1) - 1) & 0xffff];
if (PPU.VMA.High)
{
PPU.VMA.Address += PPU.VMA.Increment;
IPPU.FirstVRAMRead = FALSE;
}
#endif
#ifdef DEBUGGER
missing.vram_read = 1;
#endif
@ -1478,14 +1693,14 @@ void S9xSetCPU (uint8 Byte, uint16 Address)
else
PPU.HTimerEnabled = FALSE;
if (CPU.IRQLine && !PPU.HTimerEnabled && PPU.VTimerEnabled)
CPU.IRQTransition = TRUE;
S9xUpdateHVTimerPosition();
if (!PPU.HTimerEnabled && !PPU.VTimerEnabled)
{
CPU.IRQLine = FALSE;
CPU.IRQTransition = FALSE;
}
// The case that IRQ will trigger in an instruction such as STA $4200.
// FIXME: not true but good enough for Snes9x, I think.
S9xCheckMissingHTimerRange(CPU.PrevCycles, CPU.Cycles - CPU.PrevCycles);
if (!(Byte & 0x30))
S9xClearIRQ(PPU_IRQ_SOURCE);
// NMI can trigger immediately during VBlank as long as NMI_read ($4210) wasn't cleard.
if ((Byte & 0x80) && !(Memory.FillRAM[0x4200] & 0x80) &&
@ -1493,7 +1708,7 @@ void S9xSetCPU (uint8 Byte, uint16 Address)
{
// FIXME: triggered at HC+=6, checked just before the final CPU cycle,
// then, when to call S9xOpcode_NMI()?
CPU.NMILine = TRUE;
CPU.Flags |= NMI_FLAG;
Timings.NMITriggerPos = CPU.Cycles + 6 + 6;
}
@ -1607,6 +1822,8 @@ void S9xSetCPU (uint8 Byte, uint16 Address)
case 0x420c: // HDMAEN
if (CPU.InDMAorHDMA)
return;
if (Settings.DisableHDMA)
Byte = 0;
Memory.FillRAM[0x420c] = Byte;
// Yoshi's Island, Genjyu Ryodan, Mortal Kombat, Tales of Phantasia
PPU.HDMA = Byte & ~PPU.HDMAEnded;
@ -1633,7 +1850,17 @@ void S9xSetCPU (uint8 Byte, uint16 Address)
break;
case 0x4210: // RDNMI
#if 0
Memory.FillRAM[0x4210] = Model->_5A22;
#endif
return;
case 0x4211: // TIMEUP
#if 0
S9xClearIRQ(PPU_IRQ_SOURCE);
#endif
return;
case 0x4212: // HVBJOY
case 0x4213: // RDIO
case 0x4214: // RDDIVL
@ -1749,17 +1976,22 @@ uint8 S9xGetCPU (uint16 Address)
switch (Address)
{
case 0x4210: // RDNMI
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = CPU.PBPCAtOpcodeStart;
#endif
byte = Memory.FillRAM[0x4210];
Memory.FillRAM[0x4210] = Model->_5A22;
return ((byte & 0x80) | (OpenBus & 0x70) | Model->_5A22);
case 0x4211: // TIMEUP
byte = CPU.IRQLine ? 0x80 : 0;
CPU.IRQLine = FALSE;
CPU.IRQTransition = FALSE;
byte = (CPU.IRQActive & PPU_IRQ_SOURCE) ? 0x80 : 0;
S9xClearIRQ(PPU_IRQ_SOURCE);
return (byte | (OpenBus & 0x7f));
case 0x4212: // HVBJOY
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = CPU.PBPCAtOpcodeStart;
#endif
return (REGISTER_4212() | (OpenBus & 0x3e));
case 0x4213: // RDIO
@ -1953,7 +2185,11 @@ void S9xSoftResetPPU (void)
ZeroMemory(IPPU.TileCached[TILE_2BIT_ODD], MAX_2BIT_TILES);
ZeroMemory(IPPU.TileCached[TILE_4BIT_EVEN], MAX_4BIT_TILES);
ZeroMemory(IPPU.TileCached[TILE_4BIT_ODD], MAX_4BIT_TILES);
#ifdef CORRECT_VRAM_READS
IPPU.VRAMReadBuffer = 0; // XXX: FIXME: anything better?
#else
IPPU.FirstVRAMRead = FALSE;
#endif
IPPU.Interlace = FALSE;
IPPU.InterlaceOBJ = FALSE;
IPPU.DoubleWidthPixels = FALSE;

View File

@ -197,6 +197,11 @@
#define CLIP_XOR 2
#define CLIP_XNOR 3
#define PPU_IRQ_SOURCE (1 << 1)
#define GSU_IRQ_SOURCE (1 << 2)
#define SA1_IRQ_SOURCE (1 << 7)
#define SA1_DMA_IRQ_SOURCE (1 << 5)
struct ClipData
{
uint8 Count;
@ -213,7 +218,11 @@ struct InternalPPU
bool8 DirectColourMapsNeedRebuild;
uint8 *TileCache[7];
uint8 *TileCached[7];
#ifdef CORRECT_VRAM_READS
uint16 VRAMReadBuffer;
#else
bool8 FirstVRAMRead;
#endif
bool8 Interlace;
bool8 InterlaceOBJ;
bool8 PseudoHires;
@ -376,6 +385,9 @@ uint8 S9xGetPPU (uint16);
void S9xSetCPU (uint8, uint16);
uint8 S9xGetCPU (uint16);
void S9xUpdateHVTimerPosition (void);
void S9xCheckMissingHTimerPosition (int32);
void S9xCheckMissingHTimerRange (int32, int32);
void S9xCheckMissingHTimerHalt (int32, int32);
void S9xFixColourBrightness (void);
void S9xDoAutoJoypad (void);

View File

@ -180,6 +180,7 @@
uint8 SA1OpenBus;
static void S9xSA1Reset (void);
static void S9xSA1SetBWRAMMemMap (uint8);
static void S9xSetSA1MemMap (uint32, uint8);
static void S9xSA1CharConv2 (void);
@ -189,37 +190,31 @@ static void S9xSA1ReadVariableLengthData (bool8, bool8);
void S9xSA1Init (void)
{
SA1.Cycles = 0;
SA1.PrevCycles = 0;
SA1.Flags = 0;
SA1.IRQActive = FALSE;
SA1.WaitingForInterrupt = FALSE;
SA1.Waiting = FALSE;
SA1.Flags = 0;
SA1.Executing = FALSE;
memset(&Memory.FillRAM[0x2200], 0, 0x200);
Memory.FillRAM[0x2200] = 0x20;
Memory.FillRAM[0x2220] = 0x00;
Memory.FillRAM[0x2221] = 0x01;
Memory.FillRAM[0x2222] = 0x02;
Memory.FillRAM[0x2223] = 0x03;
Memory.FillRAM[0x2228] = 0x0f;
SA1.in_char_dma = FALSE;
SA1.TimerIRQLastState = FALSE;
SA1.HTimerIRQPos = 0;
SA1.VTimerIRQPos = 0;
SA1.HCounter = 0;
SA1.VCounter = 0;
SA1.PrevHCounter = 0;
SA1.arithmetic_op = 0;
Memory.FillRAM[0x2228] = 0xff;
SA1.op1 = 0;
SA1.op2 = 0;
SA1.arithmetic_op = 0;
SA1.sum = 0;
SA1.overflow = FALSE;
SA1.VirtualBitmapFormat = 0;
SA1.variable_bit_pos = 0;
SA1.S9xOpcodes = NULL;
}
static void S9xSA1Reset (void)
{
SA1Registers.PBPC = 0;
SA1Registers.PB = 0;
SA1Registers.PCw = 0;
SA1Registers.PCw = Memory.FillRAM[0x2203] | (Memory.FillRAM[0x2204] << 8);
SA1Registers.D.W = 0;
SA1Registers.DB = 0;
SA1Registers.SH = 1;
@ -233,20 +228,17 @@ void S9xSA1Init (void)
SA1SetFlags(MemoryFlag | IndexFlag | IRQ | Emulation);
SA1ClearFlags(Decimal);
SA1.MemSpeed = SLOW_ONE_CYCLE;
SA1.MemSpeedx2 = SLOW_ONE_CYCLE * 2;
SA1.WaitingForInterrupt = FALSE;
SA1.PCBase = NULL;
S9xSA1SetPCBase(SA1Registers.PBPC);
SA1.S9xOpcodes = S9xSA1OpcodesM1X1;
SA1.S9xOpLengths = S9xOpLengthsM1X1;
S9xSA1SetPCBase(SA1Registers.PBPC);
S9xSA1UnpackStatus();
S9xSA1FixCycles();
SA1.Executing = TRUE;
SA1.BWRAM = Memory.SRAM;
CPU.IRQExternal = FALSE;
Memory.FillRAM[0x2225] = 0;
}
static void S9xSA1SetBWRAMMemMap (uint8 val)
@ -288,6 +280,23 @@ void S9xSA1PostLoadState (void)
SA1.VirtualBitmapFormat = (Memory.FillRAM[0x223f] & 0x80) ? 2 : 4;
Memory.BWRAM = Memory.SRAM + (Memory.FillRAM[0x2224] & 7) * 0x2000;
S9xSA1SetBWRAMMemMap(Memory.FillRAM[0x2225]);
SA1.Waiting = (Memory.FillRAM[0x2200] & 0x60) != 0;
SA1.Executing = !SA1.Waiting;
}
void S9xSA1ExecuteDuringSleep (void)
{
#if 0
if (SA1.Executing)
{
while (CPU.Cycles < CPU.NextEvent)
{
S9xSA1MainLoop();
CPU.Cycles += TWO_CYCLES * 2;
}
}
#endif
}
static void S9xSetSA1MemMap (uint32 which1, uint8 map)
@ -317,48 +326,31 @@ uint8 S9xGetSA1 (uint32 address)
{
switch (address)
{
case 0x2300: // S-CPU flag
return ((Memory.FillRAM[0x2209] & 0x5f) | (Memory.FillRAM[0x2300] & 0xa0));
case 0x2300:
return ((uint8) ((Memory.FillRAM[0x2209] & 0x5f) | (CPU.IRQActive & (SA1_IRQ_SOURCE | SA1_DMA_IRQ_SOURCE))));
case 0x2301: // SA-1 flag
return ((Memory.FillRAM[0x2200] & 0x0f) | (Memory.FillRAM[0x2301] & 0xf0));
case 0x2301:
return ((Memory.FillRAM[0x2200] & 0xf) | (Memory.FillRAM[0x2301] & 0xf0));
case 0x2302: // H counter (L)
SA1.HTimerIRQPos = SA1.HCounter / ONE_DOT_CYCLE;
SA1.VTimerIRQPos = SA1.VCounter;
return ((uint8) SA1.HTimerIRQPos);
case 0x2303: // H counter (H)
return ((uint8) (SA1.HTimerIRQPos >> 8));
case 0x2304: // V counter (L)
return ((uint8) SA1.VTimerIRQPos);
case 0x2305: // V counter (H)
return ((uint8) (SA1.VTimerIRQPos >> 8));
case 0x2306: // arithmetic result (LLL)
case 0x2306:
return ((uint8) SA1.sum);
case 0x2307: // arithmetic result (LLH)
case 0x2307:
return ((uint8) (SA1.sum >> 8));
case 0x2308: // arithmetic result (LHL)
case 0x2308:
return ((uint8) (SA1.sum >> 16));
case 0x2309: // arithmetic result (LLH)
case 0x2309:
return ((uint8) (SA1.sum >> 24));
case 0x230a: // arithmetic result (HLL)
case 0x230a:
return ((uint8) (SA1.sum >> 32));
case 0x230b: // arithmetic overflow
return (SA1.overflow ? 0x80 : 0);
case 0x230c: // variable-length data read port (L)
case 0x230c:
return (Memory.FillRAM[0x230c]);
case 0x230d: // variable-length data read port (H)
case 0x230d:
{
uint8 byte = Memory.FillRAM[0x230d];
@ -368,10 +360,8 @@ uint8 S9xGetSA1 (uint32 address)
return (byte);
}
case 0x230e: // version code register
return (0x01);
default:
//printf("R: %04x\n", address);
break;
}
@ -382,279 +372,337 @@ void S9xSetSA1 (uint8 byte, uint32 address)
{
switch (address)
{
case 0x2200: // SA-1 control
#ifdef DEBUGGER
if (byte & 0x60)
printf("SA-1 sleep\n");
#endif
case 0x2200:
SA1.Waiting = (byte & 0x60) != 0;
//SA1.Executing = !SA1.Waiting && SA1.S9xOpcodes;
// SA-1 reset
if (!(byte & 0x80) && (Memory.FillRAM[0x2200] & 0x20))
{
#ifdef DEBUGGER
printf("SA-1 reset\n");
#endif
SA1Registers.PBPC = 0;
SA1Registers.PB = 0;
SA1Registers.PCw = Memory.FillRAM[0x2203] | (Memory.FillRAM[0x2204] << 8);
S9xSA1SetPCBase(SA1Registers.PBPC);
}
if (!(byte & 0x20) && (Memory.FillRAM[0x2200] & 0x20))
S9xSA1Reset();
// SA-1 IRQ control
if (byte & 0x80)
{
Memory.FillRAM[0x2301] |= 0x80;
if (Memory.FillRAM[0x220a] & 0x80)
Memory.FillRAM[0x220b] &= ~0x80;
{
SA1.Flags |= IRQ_FLAG;
SA1.IRQActive |= SNES_IRQ_SOURCE;
SA1.Executing = !SA1.Waiting && SA1.S9xOpcodes;
}
}
// SA-1 NMI control
if (byte & 0x10)
{
Memory.FillRAM[0x2301] |= 0x10;
if (Memory.FillRAM[0x220a] & 0x10)
Memory.FillRAM[0x220b] &= ~0x10;
}
break;
case 0x2201: // S-CPU interrupt enable
// S-CPU IRQ enable
if (((byte ^ Memory.FillRAM[0x2201]) & 0x80) && (Memory.FillRAM[0x2300] & byte & 0x80))
{
Memory.FillRAM[0x2202] &= ~0x80;
CPU.IRQExternal = TRUE;
}
// S-CPU CHDMA IRQ enable
if (((byte ^ Memory.FillRAM[0x2201]) & 0x20) && (Memory.FillRAM[0x2300] & byte & 0x20))
{
Memory.FillRAM[0x2202] &= ~0x20;
CPU.IRQExternal = TRUE;
}
break;
case 0x2202: // S-CPU interrupt clear
// S-CPU IRQ clear
if (byte & 0x80)
Memory.FillRAM[0x2300] &= ~0x80;
// S-CPU CHDMA IRQ clear
if (byte & 0x20)
Memory.FillRAM[0x2300] &= ~0x20;
if (!(Memory.FillRAM[0x2300] & 0xa0))
CPU.IRQExternal = FALSE;
break;
case 0x2203: // SA-1 reset vector (L)
case 0x2204: // SA-1 reset vector (H)
case 0x2205: // SA-1 NMI vector (L)
case 0x2206: // SA-1 NMI vector (H)
case 0x2207: // SA-1 IRQ vector (L)
case 0x2208: // SA-1 IRQ vector (H)
break;
case 0x2209: // S-CPU control
// 0x40: S-CPU IRQ overwrite
// 0x20: S-CPU NMI overwrite
// S-CPU IRQ control
if (byte & 0x80)
{
Memory.FillRAM[0x2300] |= 0x80;
if (Memory.FillRAM[0x2201] & 0x80)
{
Memory.FillRAM[0x2202] &= ~0x80;
CPU.IRQExternal = TRUE;
SA1.Flags |= NMI_FLAG;
SA1.Executing = !SA1.Waiting && SA1.S9xOpcodes;
}
}
break;
case 0x220a: // SA-1 interrupt enable
// SA-1 IRQ enable
if (((byte ^ Memory.FillRAM[0x220a]) & 0x80) && (Memory.FillRAM[0x2301] & byte & 0x80))
Memory.FillRAM[0x220b] &= ~0x80;
case 0x2201:
if (((byte ^ Memory.FillRAM[0x2201]) & 0x80) && (Memory.FillRAM[0x2300] & byte & 0x80))
S9xSetIRQ(SA1_IRQ_SOURCE);
// SA-1 timer IRQ enable
if (((byte ^ Memory.FillRAM[0x220a]) & 0x40) && (Memory.FillRAM[0x2301] & byte & 0x40))
Memory.FillRAM[0x220b] &= ~0x40;
// SA-1 DMA IRQ enable
if (((byte ^ Memory.FillRAM[0x220a]) & 0x20) && (Memory.FillRAM[0x2301] & byte & 0x20))
Memory.FillRAM[0x220b] &= ~0x20;
// SA-1 NMI enable
if (((byte ^ Memory.FillRAM[0x220a]) & 0x10) && (Memory.FillRAM[0x2301] & byte & 0x10))
Memory.FillRAM[0x220b] &= ~0x10;
if (((byte ^ Memory.FillRAM[0x2201]) & 0x20) && (Memory.FillRAM[0x2300] & byte & 0x20))
S9xSetIRQ(SA1_DMA_IRQ_SOURCE);
break;
case 0x220b: // SA-1 interrupt clear
// SA-1 IRQ clear
case 0x2202:
if (byte & 0x80)
Memory.FillRAM[0x2301] &= ~0x80;
{
Memory.FillRAM[0x2300] &= ~0x80;
S9xClearIRQ(SA1_IRQ_SOURCE);
}
// SA-1 timer IRQ clear
if (byte & 0x40)
Memory.FillRAM[0x2301] &= ~0x40;
// SA-1 DMA IRQ clear
if (byte & 0x20)
Memory.FillRAM[0x2301] &= ~0x20;
{
Memory.FillRAM[0x2300] &= ~0x20;
S9xClearIRQ(SA1_DMA_IRQ_SOURCE);
}
break;
case 0x2203:
//printf("SA1 reset vector: %04x\n", byte | (Memory.FillRAM[0x2204] << 8));
break;
case 0x2204:
//printf("SA1 reset vector: %04x\n", (byte << 8) | Memory.FillRAM[0x2203]);
break;
case 0x2205:
//printf("SA1 NMI vector: %04x\n", byte | (Memory.FillRAM[0x2206] << 8));
break;
case 0x2206:
//printf("SA1 NMI vector: %04x\n", (byte << 8) | Memory.FillRAM[0x2205]);
break;
case 0x2207:
//printf("SA1 IRQ vector: %04x\n", byte | (Memory.FillRAM[0x2208] << 8));
break;
case 0x2208:
//printf("SA1 IRQ vector: %04x\n", (byte << 8) | Memory.FillRAM[0x2207]);
break;
case 0x2209:
Memory.FillRAM[0x2209] = byte;
if (byte & 0x80)
Memory.FillRAM[0x2300] |= 0x80;
if (byte & Memory.FillRAM[0x2201] & 0x80)
S9xSetIRQ(SA1_IRQ_SOURCE);
break;
case 0x220a:
if (((byte ^ Memory.FillRAM[0x220a]) & 0x80) && (Memory.FillRAM[0x2301] & byte & 0x80))
{
SA1.Flags |= IRQ_FLAG;
SA1.IRQActive |= SNES_IRQ_SOURCE;
//SA1.Executing = !SA1.Waiting;
}
if (((byte ^ Memory.FillRAM[0x220a]) & 0x40) && (Memory.FillRAM[0x2301] & byte & 0x40))
{
SA1.Flags |= IRQ_FLAG;
SA1.IRQActive |= TIMER_IRQ_SOURCE;
//SA1.Executing = !SA1.Waiting;
}
if (((byte ^ Memory.FillRAM[0x220a]) & 0x20) && (Memory.FillRAM[0x2301] & byte & 0x20))
{
SA1.Flags |= IRQ_FLAG;
SA1.IRQActive |= DMA_IRQ_SOURCE;
//SA1.Executing = !SA1.Waiting;
}
if (((byte ^ Memory.FillRAM[0x220a]) & 0x10) && (Memory.FillRAM[0x2301] & byte & 0x10))
{
SA1.Flags |= NMI_FLAG;
//SA1.Executing = !SA1.Waiting;
}
break;
case 0x220b:
if (byte & 0x80)
{
SA1.IRQActive &= ~SNES_IRQ_SOURCE;
Memory.FillRAM[0x2301] &= ~0x80;
}
if (byte & 0x40)
{
SA1.IRQActive &= ~TIMER_IRQ_SOURCE;
Memory.FillRAM[0x2301] &= ~0x40;
}
if (byte & 0x20)
{
SA1.IRQActive &= ~DMA_IRQ_SOURCE;
Memory.FillRAM[0x2301] &= ~0x20;
}
// SA-1 NMI clear
if (byte & 0x10)
Memory.FillRAM[0x2301] &= ~0x10;
if (!SA1.IRQActive)
SA1.Flags &= ~IRQ_FLAG;
break;
case 0x220c: // S-CPU NMI vector (L)
case 0x220d: // S-CPU NMI vector (H)
case 0x220e: // S-CPU IRQ vector (L)
case 0x220f: // S-CPU IRQ vector (H)
case 0x220c:
//printf("SNES NMI vector: %04x\n", byte | (Memory.FillRAM[0x220d] << 8));
break;
case 0x2210: // SA-1 timer control
// 0x80: mode (linear / HV)
// 0x02: V timer enable
// 0x01: H timer enable
#ifdef DEBUGGER
printf("SA-1 timer control write:%02x\n", byte);
case 0x220d:
//printf("SNES NMI vector: %04x\n", (byte << 8) | Memory.FillRAM[0x220c]);
break;
case 0x220e:
//printf("SNES IRQ vector: %04x\n", byte | (Memory.FillRAM[0x220f] << 8));
break;
case 0x220f:
//printf("SNES IRQ vector: %04x\n", (byte << 8) | Memory.FillRAM[0x220e]);
break;
case 0x2210:
#if 0
printf("Timer %s\n", (byte & 0x80) ? "linear" : "HV");
printf("Timer H-IRQ %s\n", (byte & 1) ? "enabled" : "disabled");
printf("Timer V-IRQ %s\n", (byte & 2) ? "enabled" : "disabled");
#endif
break;
case 0x2211: // SA-1 timer reset
SA1.HCounter = 0;
SA1.VCounter = 0;
case 0x2211:
//printf("Timer reset\n");
break;
case 0x2212: // SA-1 H-timer (L)
SA1.HTimerIRQPos = byte | (Memory.FillRAM[0x2213] << 8);
case 0x2212:
//printf("H-Timer %04x\n", byte | (Memory.FillRAM[0x2213] << 8));
break;
case 0x2213: // SA-1 H-timer (H)
SA1.HTimerIRQPos = (byte << 8) | Memory.FillRAM[0x2212];
case 0x2213:
//printf("H-Timer %04x\n", (byte << 8) | Memory.FillRAM[0x2212]);
break;
case 0x2214: // SA-1 V-timer (L)
SA1.VTimerIRQPos = byte | (Memory.FillRAM[0x2215] << 8);
case 0x2214:
//printf("V-Timer %04x\n", byte | (Memory.FillRAM[0x2215] << 8));
break;
case 0x2215: // SA-1 V-timer (H)
SA1.VTimerIRQPos = (byte << 8) | Memory.FillRAM[0x2214];
case 0x2215:
//printf("V-Timer %04x\n", (byte << 8) | Memory.FillRAM[0x2214]);
break;
case 0x2220: // MMC bank C
case 0x2221: // MMC bank D
case 0x2222: // MMC bank E
case 0x2223: // MMC bank F
case 0x2220:
case 0x2221:
case 0x2222:
case 0x2223:
//printf("MMC: %02x\n", byte);
S9xSetSA1MemMap(address - 0x2220, byte);
break;
case 0x2224: // S-CPU BW-RAM mapping
case 0x2224:
//printf("BWRAM image SNES %02x -> 0x6000\n", byte);
Memory.BWRAM = Memory.SRAM + (byte & 7) * 0x2000;
break;
case 0x2225: // SA-1 BW-RAM mapping
case 0x2225:
//printf("BWRAM image SA1 %02x -> 0x6000 (%02x)\n", byte, Memory.FillRAM[0x2225]);
if (byte != Memory.FillRAM[0x2225])
S9xSA1SetBWRAMMemMap(byte);
break;
case 0x2226: // S-CPU BW-RAM write enable
case 0x2227: // SA-1 BW-RAM write enable
case 0x2228: // BW-RAM write-protected area
case 0x2229: // S-CPU I-RAM write protection
case 0x222a: // SA-1 I-RAM write protection
case 0x2226:
//printf("BW-RAM SNES write %s\n", (byte & 0x80) ? "enabled" : "disabled");
break;
case 0x2230: // DMA control
// 0x80: enable
// 0x40: priority (DMA / SA-1)
// 0x20: character conversion / normal
// 0x10: BW-RAM -> I-RAM / SA-1 -> I-RAM
// 0x04: destinatin (BW-RAM / I-RAM)
// 0x03: source
case 0x2227:
//printf("BW-RAM SA1 write %s\n", (byte & 0x80) ? "enabled" : "disabled");
break;
case 0x2231: // character conversion DMA parameters
// 0x80: CHDEND (complete / incomplete)
// 0x03: color mode
// (byte >> 2) & 7: virtual VRAM width
case 0x2228:
//printf("BW-RAM write protect area %02x\n", byte);
break;
case 0x2229:
//printf("I-RAM SNES write protect area %02x\n", byte);
break;
case 0x222a:
//printf("I-RAM SA1 write protect area %02x\n", byte);
break;
case 0x2230:
#if 0
printf("SA1 DMA %s\n", (byte & 0x80) ? "enabled" : "disabled");
printf("DMA priority %s\n", (byte & 0x40) ? "DMA" : "SA1");
printf("DMA %s\n", (byte & 0x20) ? "char conv" : "normal");
printf("DMA type %s\n", (byte & 0x10) ? "BW-RAM -> I-RAM" : "SA1 -> I-RAM");
printf("DMA distination %s\n", (byte & 4) ? "BW-RAM" : "I-RAM");
printf("DMA source %s\n", DMAsource[byte & 3]);
#endif
break;
case 0x2231:
if (byte & 0x80)
SA1.in_char_dma = FALSE;
#if 0
printf("CHDEND %s\n", (byte & 0x80) ? "complete" : "incomplete");
printf("DMA colour mode %d\n", byte & 3);
printf("virtual VRAM width %d\n", (byte >> 2) & 7);
#endif
break;
case 0x2232: // DMA source start address (LL)
case 0x2233: // DMA source start address (LH)
case 0x2234: // DMA source start address (HL)
case 0x2232:
case 0x2233:
case 0x2234:
Memory.FillRAM[address] = byte;
#if 0
printf("DMA source start %06x\n", Memory.FillRAM[0x2232] | (Memory.FillRAM[0x2233] << 8) | (Memory.FillRAM[0x2234] << 16));
#endif
break;
case 0x2235: // DMA destination start address (LL)
case 0x2235:
Memory.FillRAM[0x2235] = byte;
break;
case 0x2236: // DMA destination start address (LH)
case 0x2236:
Memory.FillRAM[0x2236] = byte;
if ((Memory.FillRAM[0x2230] & 0xa4) == 0x80) // Normal DMA to I-RAM
S9xSA1DMA();
else
if ((Memory.FillRAM[0x2230] & 0xb0) == 0xb0) // CC1
if ((Memory.FillRAM[0x2230] & 0xb0) == 0xb0)
{
SA1.in_char_dma = TRUE;
Memory.FillRAM[0x2300] |= 0x20;
if (Memory.FillRAM[0x2201] & 0x20)
{
Memory.FillRAM[0x2202] &= ~0x20;
CPU.IRQExternal = TRUE;
}
S9xSetIRQ(SA1_DMA_IRQ_SOURCE);
SA1.in_char_dma = TRUE;
}
break;
case 0x2237: // DMA destination start address (HL)
case 0x2237:
Memory.FillRAM[0x2237] = byte;
if ((Memory.FillRAM[0x2230] & 0xa4) == 0x84) // Normal DMA to BW-RAM
S9xSA1DMA();
#if 0
printf("DMA dest address %06x\n", Memory.FillRAM[0x2235] | (Memory.FillRAM[0x2236] << 8) | (Memory.FillRAM[0x2237] << 16));
#endif
break;
case 0x2238: // DMA terminal counter (L)
case 0x2239: // DMA terminal counter (H)
case 0x2238:
case 0x2239:
Memory.FillRAM[address] = byte;
#if 0
printf("DMA length %04x\n", Memory.FillRAM[0x2238] | (Memory.FillRAM[0x2239] << 8));
#endif
break;
case 0x223f: // BW-RAM bitmap format
case 0x223f:
//printf("virtual VRAM depth %d\n", (byte & 0x80) ? 2 : 4);
SA1.VirtualBitmapFormat = (byte & 0x80) ? 2 : 4;
break;
case 0x2240: // bitmap register 0
case 0x2241: // bitmap register 1
case 0x2242: // bitmap register 2
case 0x2243: // bitmap register 3
case 0x2244: // bitmap register 4
case 0x2245: // bitmap register 5
case 0x2246: // bitmap register 6
case 0x2247: // bitmap register 7
case 0x2248: // bitmap register 8
case 0x2249: // bitmap register 9
case 0x224a: // bitmap register A
case 0x224b: // bitmap register B
case 0x224c: // bitmap register C
case 0x224d: // bitmap register D
case 0x224e: // bitmap register E
case 0x2240:
case 0x2241:
case 0x2242:
case 0x2243:
case 0x2244:
case 0x2245:
case 0x2246:
case 0x2247:
case 0x2248:
case 0x2249:
case 0x224a:
case 0x224b:
case 0x224c:
case 0x224d:
case 0x224e:
#if 0
if (!(SA1.Flags & TRACE_FLAG))
{
TraceSA1();
Trace();
}
#endif
Memory.FillRAM[address] = byte;
break;
case 0x224f: // bitmap register F
case 0x224f:
Memory.FillRAM[0x224f] = byte;
if ((Memory.FillRAM[0x2230] & 0xb0) == 0xa0) // CC2
if ((Memory.FillRAM[0x2230] & 0xb0) == 0xa0) // Char conversion 2 DMA enabled
{
memmove(&Memory.ROM[CMemory::MAX_ROM_SIZE - 0x10000] + SA1.in_char_dma * 16, &Memory.FillRAM[0x2240], 16);
SA1.in_char_dma = (SA1.in_char_dma + 1) & 7;
@ -664,67 +712,58 @@ void S9xSetSA1 (uint8 byte, uint32 address)
break;
case 0x2250: // arithmetic control
case 0x2250:
if (byte & 2)
SA1.sum = 0;
SA1.arithmetic_op = byte & 3;
break;
case 0x2251: // multiplicand / dividend (L)
SA1.op1 = (SA1.op1 & 0xff00) | byte;
case 0x2251:
SA1.op1 = (SA1.op1 & 0xff00) | byte;
break;
case 0x2252: // multiplicand / dividend (H)
SA1.op1 = (SA1.op1 & 0x00ff) | (byte << 8);
case 0x2252:
SA1.op1 = (SA1.op1 & 0xff) | (byte << 8);
break;
case 0x2253: // multiplier / divisor (L)
SA1.op2 = (SA1.op2 & 0xff00) | byte;
case 0x2253:
SA1.op2 = (SA1.op2 & 0xff00) | byte;
break;
case 0x2254: // multiplier / divisor (H)
SA1.op2 = (SA1.op2 & 0x00ff) | (byte << 8);
case 0x2254:
SA1.op2 = (SA1.op2 & 0xff) | (byte << 8);
switch (SA1.arithmetic_op)
{
case 0: // signed multiplication
SA1.sum = (int16) SA1.op1 * (int16) SA1.op2;
SA1.op2 = 0;
case 0: // multiply
SA1.sum = SA1.op1 * SA1.op2;
break;
case 1: // unsigned division
case 1: // divide
if (SA1.op2 == 0)
SA1.sum = 0;
SA1.sum = SA1.op1 << 16;
else
{
int16 quotient = (int16) SA1.op1 / (uint16) SA1.op2;
uint16 remainder = (int16) SA1.op1 % (uint16) SA1.op2;
SA1.sum = (remainder << 16) | quotient;
}
SA1.op1 = 0;
SA1.op2 = 0;
SA1.sum = (SA1.op1 / (int) ((uint16) SA1.op2)) | ((SA1.op1 % (int) ((uint16) SA1.op2)) << 16);
break;
case 2: // cumulative sum
default:
SA1.sum += (int16) SA1.op1 * (int16) SA1.op2;
SA1.overflow = (SA1.sum >= (1ULL << 40));
SA1.sum &= (1ULL << 40) - 1;
SA1.op2 = 0;
SA1.sum += SA1.op1 * SA1.op2;
if (SA1.sum & ((int64) 0xffffff << 32))
SA1.overflow = TRUE;
break;
}
break;
case 0x2258: // variable bit-field length / auto inc / start
case 0x2258: // Variable bit-field length/auto inc/start.
Memory.FillRAM[0x2258] = byte;
S9xSA1ReadVariableLengthData(TRUE, FALSE);
return;
case 0x2259: // variable bit-field start address (LL)
case 0x225a: // variable bit-field start address (LH)
case 0x225b: // variable bit-field start address (HL)
case 0x2259: // Variable bit-field start address
case 0x225a:
case 0x225b:
Memory.FillRAM[address] = byte;
// XXX: ???
SA1.variable_bit_pos = 0;
@ -732,6 +771,7 @@ void S9xSetSA1 (uint8 byte, uint32 address)
return;
default:
//printf("W: %02x->%04x\n", byte, address);
break;
}
@ -850,11 +890,14 @@ static void S9xSA1DMA (void)
}
memmove(d, s, len);
// SA-1 DMA IRQ control
Memory.FillRAM[0x2301] |= 0x20;
if (Memory.FillRAM[0x220a] & 0x20)
Memory.FillRAM[0x220b] &= ~0x20;
{
SA1.Flags |= IRQ_FLAG;
SA1.IRQActive |= DMA_IRQ_SOURCE;
//SA1.Executing = !SA1.Waiting;
}
}
static void S9xSA1ReadVariableLengthData (bool8 inc, bool8 no_shift)
@ -1053,10 +1096,6 @@ void S9xSA1SetPCBase (uint32 address)
SA1Registers.PBPC = address & 0xffffff;
SA1.ShiftedPB = address & 0xff0000;
// FIXME
SA1.MemSpeed = memory_speed(address);
SA1.MemSpeedx2 = SA1.MemSpeed << 1;
uint8 *GetAddress = SA1.Map[(address & 0xffffff) >> MEMMAP_SHIFT];
if (GetAddress >= (uint8 *) CMemory::MAP_LAST)
@ -1094,3 +1133,4 @@ void S9xSA1SetPCBase (uint32 address)
return;
}
}

View File

@ -198,33 +198,32 @@ struct SSA1
uint8 _Zero;
uint8 _Negative;
uint8 _Overflow;
bool8 CPUExecuting;
uint32 ShiftedPB;
uint32 ShiftedDB;
uint32 Flags;
int32 Cycles;
int32 PrevCycles;
uint8 *PCBase;
bool8 IRQActive;
bool8 Waiting;
bool8 WaitingForInterrupt;
uint32 WaitAddress;
uint32 WaitCounter;
uint32 PBPCAtOpcodeStart;
uint8 *WaitByteAddress1;
uint8 *WaitByteAddress2;
uint8 *Map[MEMMAP_NUM_BLOCKS];
uint8 *WriteMap[MEMMAP_NUM_BLOCKS];
uint8 *BWRAM;
bool8 in_char_dma;
bool8 TimerIRQLastState;
uint16 HTimerIRQPos;
uint16 VTimerIRQPos;
int16 HCounter;
int16 VCounter;
int16 PrevHCounter;
int32 MemSpeed;
int32 MemSpeedx2;
int32 arithmetic_op;
uint16 op1;
uint16 op2;
uint64 sum;
bool8 Executing;
bool8 overflow;
bool8 in_char_dma;
int16 op1;
int16 op2;
int32 arithmetic_op;
int64 sum;
uint8 VirtualBitmapFormat;
uint8 variable_bit_pos;
};
@ -264,8 +263,13 @@ uint8 S9xGetSA1 (uint32);
void S9xSetSA1 (uint8, uint32);
void S9xSA1Init (void);
void S9xSA1MainLoop (void);
void S9xSA1ExecuteDuringSleep (void);
void S9xSA1PostLoadState (void);
#define SNES_IRQ_SOURCE (1 << 7)
#define TIMER_IRQ_SOURCE (1 << 6)
#define DMA_IRQ_SOURCE (1 << 5)
static inline void S9xSA1UnpackStatus (void)
{
SA1._Zero = (SA1Registers.PL & Zero) == 0;

View File

@ -221,43 +221,20 @@
#define StackRelative SA1StackRelative
#define StackRelativeIndirectIndexed SA1StackRelativeIndirectIndexed
//#undef CPU_SHUTDOWN
#define SA1_OPCODES
#include "cpuops.cpp"
static void S9xSA1UpdateTimer (void);
void S9xSA1MainLoop (void)
{
if (Memory.FillRAM[0x2200] & 0x60)
if (SA1.Flags & NMI_FLAG)
{
SA1.Cycles += 6; // FIXME
S9xSA1UpdateTimer();
return;
}
// SA-1 NMI
if ((Memory.FillRAM[0x2200] & 0x10) && !(Memory.FillRAM[0x220b] & 0x10))
{
Memory.FillRAM[0x2301] |= 0x10;
Memory.FillRAM[0x220b] |= 0x10;
if (SA1.WaitingForInterrupt)
if (Memory.FillRAM[0x2200] & 0x10)
{
SA1.WaitingForInterrupt = FALSE;
SA1Registers.PCw++;
}
S9xSA1Opcode_NMI();
}
else
if (!SA1CheckFlag(IRQ))
{
// SA-1 Timer IRQ
if ((Memory.FillRAM[0x220a] & 0x40) && !(Memory.FillRAM[0x220b] & 0x40))
{
Memory.FillRAM[0x2301] |= 0x40;
SA1.Flags &= ~NMI_FLAG;
Memory.FillRAM[0x2301] |= 0x10;
if (SA1.WaitingForInterrupt)
{
@ -265,45 +242,38 @@ void S9xSA1MainLoop (void)
SA1Registers.PCw++;
}
S9xSA1Opcode_IRQ();
S9xSA1Opcode_NMI();
}
}
if (SA1.Flags & IRQ_FLAG)
{
if (SA1.IRQActive)
{
if (SA1.WaitingForInterrupt)
{
SA1.WaitingForInterrupt = FALSE;
SA1Registers.PCw++;
}
if (!SA1CheckFlag(IRQ))
S9xSA1Opcode_IRQ();
}
else
// SA-1 DMA IRQ
if ((Memory.FillRAM[0x220a] & 0x20) && !(Memory.FillRAM[0x220b] & 0x20))
{
Memory.FillRAM[0x2301] |= 0x20;
if (SA1.WaitingForInterrupt)
{
SA1.WaitingForInterrupt = FALSE;
SA1Registers.PCw++;
}
S9xSA1Opcode_IRQ();
}
else
// SA-1 IRQ
if ((Memory.FillRAM[0x2200] & 0x80) && !(Memory.FillRAM[0x220b] & 0x80))
{
Memory.FillRAM[0x2301] |= 0x80;
if (SA1.WaitingForInterrupt)
{
SA1.WaitingForInterrupt = FALSE;
SA1Registers.PCw++;
}
S9xSA1Opcode_IRQ();
}
SA1.Flags &= ~IRQ_FLAG;
}
for (int i = 0; i < 3 && !(Memory.FillRAM[0x2200] & 0x60); i++)
for (int i = 0; i < 3 && SA1.Executing; i++)
{
#ifdef DEBUGGER
if (SA1.Flags & TRACE_FLAG)
S9xSA1Trace();
#endif
#ifdef CPU_SHUTDOWN
SA1.PBPCAtOpcodeStart = SA1Registers.PBPC;
#endif
register uint8 Op;
register struct SOpcodes *Opcodes;
@ -329,71 +299,5 @@ void S9xSA1MainLoop (void)
Registers.PCw++;
(*Opcodes[Op].S9xOpcode)();
}
S9xSA1UpdateTimer();
}
static void S9xSA1UpdateTimer (void) // FIXME
{
SA1.PrevHCounter = SA1.HCounter;
if (Memory.FillRAM[0x2210] & 0x80)
{
SA1.HCounter += (SA1.Cycles - SA1.PrevCycles);
if (SA1.HCounter >= 0x800)
{
SA1.HCounter -= 0x800;
SA1.PrevHCounter -= 0x800;
if (++SA1.VCounter >= 0x200)
SA1.VCounter = 0;
}
}
else
{
SA1.HCounter += (SA1.Cycles - SA1.PrevCycles);
if (SA1.HCounter >= Timings.H_Max_Master)
{
SA1.HCounter -= Timings.H_Max_Master;
SA1.PrevHCounter -= Timings.H_Max_Master;
if (++SA1.VCounter >= Timings.V_Max_Master)
SA1.VCounter = 0;
}
}
if (SA1.Cycles >= Timings.H_Max_Master)
SA1.Cycles -= Timings.H_Max_Master;
SA1.PrevCycles = SA1.Cycles;
bool8 thisIRQ = Memory.FillRAM[0x2210] & 0x03;
if (Memory.FillRAM[0x2210] & 0x01)
{
if (SA1.PrevHCounter >= SA1.HTimerIRQPos * ONE_DOT_CYCLE || SA1.HCounter < SA1.HTimerIRQPos * ONE_DOT_CYCLE)
thisIRQ = FALSE;
}
if (Memory.FillRAM[0x2210] & 0x02)
{
if (SA1.VCounter != SA1.VTimerIRQPos * ONE_DOT_CYCLE)
thisIRQ = FALSE;
}
// SA-1 Timer IRQ control
if (!SA1.TimerIRQLastState && thisIRQ)
{
Memory.FillRAM[0x2301] |= 0x40;
if (Memory.FillRAM[0x220a] & 0x40)
{
Memory.FillRAM[0x220b] &= ~0x40;
#ifdef DEBUGGER
S9xTraceFormattedMessage("--- SA-1 Timer IRQ triggered prev HC:%04d curr HC:%04d HTimer:%d Pos:%04d VTimer:%d Pos:%03d",
SA1.PrevHCounter, SA1.HCounter,
(Memory.FillRAM[0x2210] & 0x01) ? 1 : 0, SA1.HTimerIRQPos * ONE_DOT_CYCLE,
(Memory.FillRAM[0x2210] & 0x02) ? 1 : 0, SA1.VTimerIRQPos);
#endif
}
}
SA1.TimerIRQLastState = thisIRQ;
}

View File

@ -342,7 +342,7 @@ struct SnapshotScreenshotInfo
static struct Obsolete
{
uint8 CPU_IRQActive;
uint8 reserved;
} Obsolete;
#define STRUCT struct SCPUState
@ -353,7 +353,7 @@ static FreezeData SnapCPU[] =
INT_ENTRY(6, PrevCycles),
INT_ENTRY(6, V_Counter),
INT_ENTRY(6, Flags),
OBSOLETE_INT_ENTRY(6, 7, CPU_IRQActive),
INT_ENTRY(6, IRQActive),
INT_ENTRY(6, IRQPending),
INT_ENTRY(6, MemSpeed),
INT_ENTRY(6, MemSpeedx2),
@ -366,14 +366,9 @@ static FreezeData SnapCPU[] =
INT_ENTRY(6, WhichEvent),
INT_ENTRY(6, NextEvent),
INT_ENTRY(6, WaitingForInterrupt),
DELETED_INT_ENTRY(6, 7, WaitAddress, 4),
DELETED_INT_ENTRY(6, 7, WaitCounter, 4),
DELETED_INT_ENTRY(6, 7, PBPCAtOpcodeStart, 4),
INT_ENTRY(7, NMILine),
INT_ENTRY(7, IRQLine),
INT_ENTRY(7, IRQTransition),
INT_ENTRY(7, IRQLastState),
INT_ENTRY(7, IRQExternal)
INT_ENTRY(6, WaitAddress),
INT_ENTRY(6, WaitCounter),
INT_ENTRY(6, PBPCAtOpcodeStart)
};
#undef STRUCT
@ -581,9 +576,7 @@ static FreezeData SnapTimings[] =
INT_ENTRY(6, DMACPUSync),
INT_ENTRY(6, NMIDMADelay),
INT_ENTRY(6, IRQPendCount),
INT_ENTRY(6, APUSpeedup),
INT_ENTRY(7, IRQTriggerCycles),
INT_ENTRY(7, APUAllowTimeOverflow)
INT_ENTRY(6, APUSpeedup)
};
#undef STRUCT
@ -652,17 +645,17 @@ static FreezeData SnapFX[] =
static FreezeData SnapSA1[] =
{
DELETED_INT_ENTRY(6, 7, CPUExecuting, 1),
INT_ENTRY(6, CPUExecuting),
INT_ENTRY(6, ShiftedPB),
INT_ENTRY(6, ShiftedDB),
INT_ENTRY(6, Flags),
DELETED_INT_ENTRY(6, 7, IRQActive, 1),
DELETED_INT_ENTRY(6, 7, Waiting, 1),
INT_ENTRY(6, IRQActive),
INT_ENTRY(6, Waiting),
INT_ENTRY(6, WaitingForInterrupt),
DELETED_INT_ENTRY(6, 7, WaitAddress, 4),
DELETED_INT_ENTRY(6, 7, WaitCounter, 4),
DELETED_INT_ENTRY(6, 7, PBPCAtOpcodeStart, 4),
DELETED_INT_ENTRY(6, 7, Executing, 1),
INT_ENTRY(6, WaitAddress),
INT_ENTRY(6, WaitCounter),
INT_ENTRY(6, PBPCAtOpcodeStart),
INT_ENTRY(6, Executing),
INT_ENTRY(6, overflow),
INT_ENTRY(6, in_char_dma),
INT_ENTRY(6, op1),
@ -670,17 +663,7 @@ static FreezeData SnapSA1[] =
INT_ENTRY(6, arithmetic_op),
INT_ENTRY(6, sum),
INT_ENTRY(6, VirtualBitmapFormat),
INT_ENTRY(6, variable_bit_pos),
INT_ENTRY(7, Cycles),
INT_ENTRY(7, PrevCycles),
INT_ENTRY(7, TimerIRQLastState),
INT_ENTRY(7, HTimerIRQPos),
INT_ENTRY(7, VTimerIRQPos),
INT_ENTRY(7, HCounter),
INT_ENTRY(7, VCounter),
INT_ENTRY(7, PrevHCounter),
INT_ENTRY(7, MemSpeed),
INT_ENTRY(7, MemSpeedx2)
INT_ENTRY(6, variable_bit_pos)
};
#undef STRUCT
@ -1268,7 +1251,7 @@ bool8 S9xUnfreezeGame (const char *filename)
void S9xFreezeToStream (STREAM stream)
{
char buffer[1024];
uint8 *soundsnapshot = new uint8[SPC_SAVE_STATE_BLOCK_SIZE];
uint8 *soundsnapshot = new uint8[SPC_SAVE_STATE_BLOCK_SIZE];
S9xSetSoundMute(TRUE);
@ -1677,40 +1660,6 @@ int S9xUnfreezeFromStream (STREAM stream)
if (local_bsx_data)
UnfreezeStructFromCopy(&BSX, SnapBSX, COUNT(SnapBSX), local_bsx_data, version);
if (version < SNAPSHOT_VERSION)
{
printf("Converting old snapshot version %d to %d\n...", version, SNAPSHOT_VERSION);
CPU.NMILine = (CPU.Flags & (1 << 7)) ? TRUE : FALSE;
CPU.IRQLine = (CPU.Flags & (1 << 11)) ? TRUE : FALSE;
CPU.IRQTransition = FALSE;
CPU.IRQLastState = FALSE;
CPU.IRQExternal = (Obsolete.CPU_IRQActive & ~(1 << 1)) ? TRUE : FALSE;
switch (CPU.WhichEvent)
{
case 12: case 1: CPU.WhichEvent = 1; break;
case 2: case 3: CPU.WhichEvent = 2; break;
case 4: case 5: CPU.WhichEvent = 3; break;
case 6: case 7: CPU.WhichEvent = 4; break;
case 8: case 9: CPU.WhichEvent = 5; break;
case 10: case 11: CPU.WhichEvent = 6; break;
}
if (local_sa1) // FIXME
{
SA1.Cycles = SA1.PrevCycles = 0;
SA1.TimerIRQLastState = FALSE;
SA1.HTimerIRQPos = Memory.FillRAM[0x2212] | (Memory.FillRAM[0x2213] << 8);
SA1.VTimerIRQPos = Memory.FillRAM[0x2214] | (Memory.FillRAM[0x2215] << 8);
SA1.HCounter = 0;
SA1.VCounter = 0;
SA1.PrevHCounter = 0;
SA1.MemSpeed = SLOW_ONE_CYCLE;
SA1.MemSpeedx2 = SLOW_ONE_CYCLE * 2;
}
}
CPU.Flags |= old_flags & (DEBUG_MODE_FLAG | TRACE_FLAG | SINGLE_STEP_FLAG | FRAME_ADVANCE_FLAG);
ICPU.ShiftedPB = Registers.PB << 16;
ICPU.ShiftedDB = Registers.DB << 16;
@ -2298,3 +2247,4 @@ bool8 S9xSPCDump (const char *filename)
return (TRUE);
}

View File

@ -179,7 +179,7 @@
#define _SNAPSHOT_H_
#define SNAPSHOT_MAGIC "#!s9xsnp"
#define SNAPSHOT_VERSION 7
#define SNAPSHOT_VERSION 6
#define SUCCESS 1
#define WRONG_FORMAT (-1)

View File

@ -186,6 +186,8 @@
#include "65c816.h"
#include "messages.h"
#define S9X_ACCURACY_LEVEL 3
#ifdef ZLIB
#include <zlib.h>
#define STREAM gzFile
@ -261,6 +263,8 @@
#define TRACE_FLAG (1 << 1) // debugger
#define SINGLE_STEP_FLAG (1 << 2) // debugger
#define BREAK_FLAG (1 << 3) // debugger
#define NMI_FLAG (1 << 7) // CPU
#define IRQ_FLAG (1 << 11) // CPU
#define SCAN_KEYS_FLAG (1 << 4) // CPU
#define HALTED_FLAG (1 << 12) // APU
#define FRAME_ADVANCE_FLAG (1 << 9)
@ -270,16 +274,12 @@
struct SCPUState
{
uint32 Flags;
int32 Cycles;
int32 PrevCycles;
int32 V_Counter;
uint32 Flags;
uint8 *PCBase;
bool8 NMILine;
bool8 IRQLine;
bool8 IRQTransition;
bool8 IRQLastState;
bool8 IRQExternal;
bool8 IRQActive;
int32 IRQPending;
int32 MemSpeed;
int32 MemSpeedx2;
@ -293,6 +293,9 @@ struct SCPUState
uint8 WhichEvent;
int32 NextEvent;
bool8 WaitingForInterrupt;
uint32 WaitAddress;
uint32 WaitCounter;
uint32 PBPCAtOpcodeStart;
uint32 AutoSaveTimer;
bool8 SRAMModified;
};
@ -300,11 +303,17 @@ struct SCPUState
enum
{
HC_HBLANK_START_EVENT = 1,
HC_HDMA_START_EVENT = 2,
HC_HCOUNTER_MAX_EVENT = 3,
HC_HDMA_INIT_EVENT = 4,
HC_RENDER_EVENT = 5,
HC_WRAM_REFRESH_EVENT = 6
HC_IRQ_1_3_EVENT = 2,
HC_HDMA_START_EVENT = 3,
HC_IRQ_3_5_EVENT = 4,
HC_HCOUNTER_MAX_EVENT = 5,
HC_IRQ_5_7_EVENT = 6,
HC_HDMA_INIT_EVENT = 7,
HC_IRQ_7_9_EVENT = 8,
HC_RENDER_EVENT = 9,
HC_IRQ_9_A_EVENT = 10,
HC_WRAM_REFRESH_EVENT = 11,
HC_IRQ_A_1_EVENT = 12
};
struct STimings
@ -318,13 +327,12 @@ struct STimings
int32 HDMAInit;
int32 HDMAStart;
int32 NMITriggerPos;
int32 IRQTriggerCycles;
int32 WRAMRefreshPos;
int32 RenderPos;
bool8 InterlaceField;
int32 DMACPUSync; // The cycles to synchronize DMA and CPU. Snes9x cannot emulate correctly.
int32 NMIDMADelay; // The delay of NMI trigger after DMA transfers. Snes9x cannot emulate correctly.
int32 IRQPendCount; // This value is just a hack.
int32 IRQPendCount; // This value is just a hack, because Snes9x cannot emulate any events in an opcode.
int32 APUSpeedup;
bool8 APUAllowTimeOverflow;
};
@ -397,8 +405,12 @@ struct SSettings
char CartBName[PATH_MAX + 1];
bool8 DisableGameSpecificHacks;
bool8 ShutdownMaster;
bool8 Shutdown;
bool8 BlockInvalidVRAMAccessMaster;
bool8 BlockInvalidVRAMAccess;
bool8 DisableIRQ;
bool8 DisableHDMA;
int32 HDMATimingHack;
bool8 ForcedPause;