core update - improved IRQ and SA-1

This commit is contained in:
dborth 2011-01-17 13:54:34 +00:00
parent 32f8662987
commit 5d7331ead0
27 changed files with 6118 additions and 6973 deletions

View File

@ -328,14 +328,3 @@ uint8 * S9xGetMemPointerC4 (uint16 Address)
return (NULL);
return (Memory.C4RAM - 0x6000 + (Address & 0xffff));
}
#ifdef ZSNES_C4
START_EXTERN_C
void C4LoaDMem (char *C4RAM)
{
memmove(C4RAM + (READ_WORD(C4RAM + 0x1f45) & 0x1fff), C4GetMemPointer(READ_3WORD(C4RAM + 0x1f40)), READ_WORD(C4RAM + 0x1f43));
}
END_EXTERN_C
#endif

View File

@ -178,10 +178,6 @@
#ifndef _C4_H_
#define _C4_H_
#ifdef ZSNES_C4
START_EXTERN_C
#endif
extern int16 C4WFXVal;
extern int16 C4WFYVal;
extern int16 C4WFZVal;
@ -195,10 +191,6 @@ extern int16 C41FAngleRes;
extern int16 C41FDist;
extern int16 C41FDistVal;
#ifdef ZSNES_C4
extern uint8 *C4Ram;
#endif
void C4TransfWireFrame (void);
void C4TransfWireFrame2 (void);
void C4CalcWireFrame (void);
@ -208,11 +200,6 @@ void C4Op1F (void);
void S9xInitC4 (void);
void S9xSetC4 (uint8, uint16);
uint8 S9xGetC4 (uint16);
#ifdef ZSNES_C4
END_EXTERN_C
#endif
uint8 * S9xGetBasePointerC4 (uint16);
uint8 * S9xGetMemPointerC4 (uint16);

View File

@ -186,12 +186,9 @@ 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);
@ -200,11 +197,8 @@ 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,7 +429,6 @@ static const int ptrspeeds[4] = { 1, 1, 4, 8 };
S(ToggleBG2), \
S(ToggleBG3), \
S(ToggleEmuTurbo), \
S(ToggleHDMA), \
S(ToggleSprites), \
S(ToggleTransparency) \
@ -2458,11 +2457,6 @@ 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,12 +208,16 @@ 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 = -1;
CPU.PrevCycles = CPU.Cycles;
CPU.V_Counter = 0;
CPU.Flags = CPU.Flags & (DEBUG_MODE_FLAG | TRACE_FLAG);
CPU.PCBase = NULL;
CPU.IRQActive = FALSE;
CPU.IRQPending = 0;
CPU.NMILine = FALSE;
CPU.IRQLine = FALSE;
CPU.IRQTransition = FALSE;
CPU.IRQLastState = FALSE;
CPU.IRQExternal = FALSE;
CPU.IRQPending = Timings.IRQPendCount;
CPU.MemSpeed = SLOW_ONE_CYCLE;
CPU.MemSpeedx2 = SLOW_ONE_CYCLE * 2;
CPU.FastROMSpeed = SLOW_ONE_CYCLE;
@ -226,9 +230,6 @@ 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;
@ -261,7 +262,6 @@ static void S9xSoftResetCPU (void)
ICPU.S9xOpcodes = S9xOpcodesE1;
ICPU.S9xOpLengths = S9xOpLengthsM1X1;
ICPU.CPUExecuting = TRUE;
S9xUnpackStatus();
}

File diff suppressed because it is too large Load Diff

View File

@ -179,6 +179,9 @@
#define _CPUEXEC_H_
#include "ppu.h"
#ifdef DEBUGGER
#include "debug.h"
#endif
struct SOpcodes
{
@ -193,7 +196,6 @@ struct SICPU
uint8 _Zero;
uint8 _Negative;
uint8 _Overflow;
bool8 CPUExecuting;
uint32 ShiftedPB;
uint32 ShiftedDB;
uint32 Frame;
@ -217,8 +219,6 @@ void S9xMainLoop (void);
void S9xReset (void);
void S9xSoftReset (void);
void S9xDoHEventProcessing (void);
void S9xClearIRQ (uint32);
void S9xSetIRQ (uint32);
static inline void S9xUnpackStatus (void)
{
@ -270,84 +270,43 @@ static inline void S9xFixCycles (void)
}
}
static inline void S9xReschedule (void)
static inline void S9xCheckInterrupts (void)
{
uint8 next = 0;
int32 hpos = 0;
bool8 thisIRQ = PPU.HTimerEnabled || PPU.VTimerEnabled;
switch (CPU.WhichEvent)
if (CPU.IRQLine && thisIRQ)
CPU.IRQTransition = TRUE;
if (PPU.HTimerEnabled)
{
case HC_HBLANK_START_EVENT:
case HC_IRQ_1_3_EVENT:
next = HC_HDMA_START_EVENT;
hpos = Timings.HDMAStart;
break;
int32 htimepos = PPU.HTimerPosition;
if (CPU.Cycles >= Timings.H_Max)
htimepos += Timings.H_Max;
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 (CPU.PrevCycles >= htimepos || CPU.Cycles < htimepos)
thisIRQ = FALSE;
}
if (((int32) PPU.HTimerPosition > CPU.NextEvent) && ((int32) PPU.HTimerPosition < hpos))
if (PPU.VTimerEnabled)
{
hpos = (int32) PPU.HTimerPosition;
int32 vcounter = CPU.V_Counter;
if (CPU.Cycles >= Timings.H_Max)
vcounter++;
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 (vcounter != PPU.VTimerPosition)
thisIRQ = FALSE;
}
CPU.NextEvent = hpos;
CPU.WhichEvent = next;
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;
}
#endif

View File

@ -280,7 +280,6 @@ static void Op##OP (void) \
S9xSetPCBase(ICPU.ShiftedPB + newPC.W); \
else \
Registers.PCw = newPC.W; \
CPUShutdown(); \
} \
}
@ -515,9 +514,6 @@ 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);
@ -527,9 +523,6 @@ 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);
@ -551,9 +544,6 @@ 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);
@ -563,9 +553,6 @@ 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);

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@ -202,6 +202,7 @@ 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);
}
@ -299,13 +300,10 @@ uint8 S9xGetSuperFX (uint16 address)
uint8 byte;
byte = Memory.FillRAM[address];
#ifdef CPU_SHUTDOWN
if (address == 0x3030)
CPU.WaitAddress = CPU.PBPCAtOpcodeStart;
#endif
if (address == 0x3031)
{
S9xClearIRQ(GSU_IRQ_SOURCE);
CPU.IRQExternal = FALSE;
Memory.FillRAM[0x3031] = byte & 0x7f;
}
@ -320,7 +318,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)
S9xSetIRQ(GSU_IRQ_SOURCE);
CPU.IRQExternal = TRUE;
}
}

View File

@ -178,7 +178,8 @@
#ifndef _FXEMU_H_
#define _FXEMU_H_
#ifndef ZSNES_FX
#define FX_BREAKPOINT (-1)
#define FX_ERROR_ILLEGAL_ADDRESS (-2)
// The FxInfo_s structure, the link between the FxEmulator and the Snes Emulator
struct FxInfo_s
@ -196,41 +197,12 @@ struct FxInfo_s
extern struct FxInfo_s SuperFX;
void S9xInitSuperFX (void);
void S9xResetSuperFX (void);
void S9xSuperFXExec (void);
void S9xSetSuperFX (uint8, uint16);
uint8 S9xGetSuperFX (uint16);
void fx_flushCache (void);
void fx_computeScreenPointers (void);
uint32 fx_run (uint32);
#define FX_BREAKPOINT (-1)
#define FX_ERROR_ILLEGAL_ADDRESS (-2)
#else
#define S9xSetSuperFX S9xSuperFXWriteReg
#define S9xGetSuperFX S9xSuperFXReadReg
START_EXTERN_C
extern uint8 *SFXPlotTable;
void S9xSuperFXWriteReg (uint8, uint32);
uint8 S9xSuperFXReadReg (uint32);
void S9xSuperFXPreSaveState (void);
void S9xSuperFXPostSaveState (void);
void S9xSuperFXPostLoadState (void);
END_EXTERN_C
#endif
#ifdef ZSNES_FX
START_EXTERN_C
#endif
void S9xResetSuperFX (void);
void S9xSuperFXExec (void);
#ifdef ZSNES_FX
END_EXTERN_C
#endif
#endif

View File

@ -178,8 +178,6 @@
#ifndef _FXINST_H_
#define _FXINST_H_
#ifndef ZSNES_FX
/*
* FxChip(GSU) register space specification
* (Register address space 3000-32ff)
@ -542,5 +540,3 @@ extern void (*fx_OpcodeTable[]) (void);
#define BRANCH_DELAY_RELATIVE
#endif
#endif

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,23 +200,13 @@
#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)
@ -247,10 +237,6 @@ 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);
@ -379,10 +365,6 @@ 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);
@ -510,33 +492,14 @@ 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;
}
@ -593,7 +556,6 @@ inline void S9xSetByte (uint8 Byte, uint32 Address)
case CMemory::MAP_SA1RAM:
*(Memory.SRAM + (Address & 0xffff)) = Byte;
SA1.Executing = !SA1.Waiting;
addCyclesInMemoryAccess;
return;
@ -670,33 +632,14 @@ 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;
}
@ -806,7 +749,6 @@ 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

@ -209,6 +209,8 @@ struct SDSP3 DSP3;
struct SDSP4 DSP4;
struct SSA1 SA1;
struct SSA1Registers SA1Registers;
struct FxRegs_s GSU;
struct FxInfo_s SuperFX;
struct SST010 ST010;
struct SST011 ST011;
struct SST018 ST018;
@ -228,10 +230,6 @@ struct Missing missing;
#endif
struct SCheatData Cheat;
struct Watch watches[16];
#ifndef ZSNES_FX
struct FxRegs_s GSU;
struct FxInfo_s SuperFX;
#endif
CMemory Memory;
char String[513];
@ -244,15 +242,6 @@ SnesModel M1SNES = { 1, 3, 2 };
SnesModel M2SNES = { 2, 4, 3 };
SnesModel *Model = &M1SNES;
#if defined(ZSNES_FX) || defined(ZSNES_C4)
uint8 *ROM = NULL;
uint8 *SRAM = NULL;
uint8 *RegRAM = NULL;
#endif
#ifdef ZSNES_FX
uint8 *SFXPlotTable = NULL;
#endif
#ifdef GFX_MULTI_FORMAT
uint32 RED_LOW_BIT_MASK = RED_LOW_BIT_MASK_RGB565;
uint32 GREEN_LOW_BIT_MASK = GREEN_LOW_BIT_MASK_RGB565;

View File

@ -1144,21 +1144,11 @@ bool8 CMemory::Init (void)
BIOSROM = ROM + 0x300000; // BS
BSRAM = ROM + 0x400000; // BS
#if defined(ZSNES_FX) || defined(ZSNES_C4)
::ROM = ROM;
::SRAM = SRAM;
::RegRAM = FillRAM;
#endif
#ifdef ZSNES_FX
SFXPlotTable = ROM + 0x400000;
#else
SuperFX.pvRegisters = FillRAM + 0x3000;
SuperFX.nRamBanks = 2; // Most only use 1. 1=64KB=512Mb, 2=128KB=1024Mb
SuperFX.pvRam = SRAM;
SuperFX.nRomBanks = (2 * 1024 * 1024) / (32 * 1024);
SuperFX.pvRom = (uint8 *) ROM;
#endif
PostRomInitFunc = NULL;
@ -2280,10 +2270,8 @@ void CMemory::InitROM (void)
Settings.SETA = 0;
Settings.SRTC = FALSE;
Settings.BS = FALSE;
#ifndef ZSNES_FX
SuperFX.nRomBanks = CalculatedSize >> 15;
#endif
SA1.Executing = FALSE;
//// Parse ROM header and read ROM informatoin
@ -2409,9 +2397,7 @@ void CMemory::InitROM (void)
case 0x1520:
case 0x1A20:
Settings.SuperFX = TRUE;
#ifndef ZSNES_FX
S9xInitSuperFX();
#endif
if (ROM[0x7FDA] == 0x33)
SRAMSize = ROM[0x7FBD];
else
@ -3510,7 +3496,6 @@ bool8 CMemory::match_id (const char *str)
void CMemory::ApplyROMFixes (void)
{
Settings.Shutdown = Settings.ShutdownMaster;
Settings.BlockInvalidVRAMAccess = Settings.BlockInvalidVRAMAccessMaster;
//// Warnings
@ -3587,6 +3572,7 @@ 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)
{
@ -3601,14 +3587,6 @@ 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,
@ -3618,12 +3596,6 @@ 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)
@ -3636,242 +3608,6 @@ 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

@ -360,14 +360,6 @@ struct SMulti
extern CMemory Memory;
extern SMulti Multi;
#if defined(ZSNES_FX) || defined(ZSNES_C4)
START_EXTERN_C
extern uint8 *ROM;
extern uint8 *SRAM;
extern uint8 *RegRAM;
END_EXTERN_C
#endif
void S9xAutoSaveSRAM (void);
bool8 LoadZip(const char *, int32 *, int32 *, uint8 *);

View File

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

View File

@ -204,9 +204,6 @@ 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;
@ -245,9 +242,6 @@ 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;
@ -260,72 +254,16 @@ 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)
{
if (PPU.HTimerEnabled)
PPU.HTimerPosition = PPU.IRQHBeamPos * ONE_DOT_CYCLE + Timings.IRQTriggerCycles;
if (Timings.H_Max == Timings.H_Max_Master) // 1364
{
#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;
if (PPU.IRQHBeamPos > 322)
PPU.HTimerPosition += (ONE_DOT_CYCLE / 2);
if (PPU.IRQHBeamPos > 326)
PPU.HTimerPosition += (ONE_DOT_CYCLE / 2);
}
else
PPU.HTimerPosition = 10 + 4 + 6;
PPU.VTimerPosition = PPU.IRQVBeamPos;
@ -338,111 +276,9 @@ 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 settings: H:%d V:%d (%04d, %03d)", PPU.HTimerEnabled, PPU.VTimerEnabled, PPU.HTimerPosition, PPU.VTimerPosition);
S9xTraceFormattedMessage("--- IRQ Timer set HTimer:%d Pos:%04d VTimer:%d Pos:%03d",
PPU.HTimerEnabled, PPU.HTimerPosition, PPU.VTimerEnabled, PPU.VTimerPosition);
#endif
}
@ -787,7 +623,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;
@ -797,15 +633,13 @@ 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;
@ -815,22 +649,14 @@ 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;
@ -1382,7 +1208,6 @@ uint8 S9xGetPPU (uint16 Address)
return (PPU.OpenBus1 = byte);
case 0x2139: // VMDATALREAD
#ifdef CORRECT_VRAM_READS
byte = IPPU.VRAMReadBuffer & 0xff;
if (!PPU.VMA.High)
{
@ -1398,33 +1223,13 @@ 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)
{
@ -1440,26 +1245,6 @@ 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
@ -1697,14 +1482,14 @@ void S9xSetCPU (uint8 Byte, uint16 Address)
else
PPU.HTimerEnabled = FALSE;
S9xUpdateHVTimerPosition();
if (CPU.IRQLine && !PPU.HTimerEnabled && PPU.VTimerEnabled)
CPU.IRQTransition = TRUE;
// 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);
if (!PPU.HTimerEnabled && !PPU.VTimerEnabled)
{
CPU.IRQLine = FALSE;
CPU.IRQTransition = FALSE;
}
// NMI can trigger immediately during VBlank as long as NMI_read ($4210) wasn't cleard.
if ((Byte & 0x80) && !(Memory.FillRAM[0x4200] & 0x80) &&
@ -1712,7 +1497,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.Flags |= NMI_FLAG;
CPU.NMILine = TRUE;
Timings.NMITriggerPos = CPU.Cycles + 6 + 6;
}
@ -1826,8 +1611,6 @@ 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;
@ -1854,17 +1637,7 @@ 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
@ -1980,22 +1753,17 @@ 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.IRQActive & PPU_IRQ_SOURCE) ? 0x80 : 0;
S9xClearIRQ(PPU_IRQ_SOURCE);
byte = CPU.IRQLine ? 0x80 : 0;
CPU.IRQLine = FALSE;
CPU.IRQTransition = FALSE;
return (byte | (OpenBus & 0x7f));
case 0x4212: // HVBJOY
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = CPU.PBPCAtOpcodeStart;
#endif
return (REGISTER_4212() | (OpenBus & 0x3e));
case 0x4213: // RDIO
@ -2189,11 +1957,7 @@ 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,11 +197,6 @@
#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;
@ -218,11 +213,7 @@ 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;
@ -385,9 +376,6 @@ 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);

File diff suppressed because it is too large Load Diff

View File

@ -198,32 +198,33 @@ 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 Executing;
bool8 overflow;
bool8 in_char_dma;
int16 op1;
int16 op2;
bool8 TimerIRQLastState;
uint16 HTimerIRQPos;
uint16 VTimerIRQPos;
int16 HCounter;
int16 VCounter;
int16 PrevHCounter;
int32 MemSpeed;
int32 MemSpeedx2;
int32 arithmetic_op;
int64 sum;
uint16 op1;
uint16 op2;
uint64 sum;
bool8 overflow;
uint8 VirtualBitmapFormat;
uint8 variable_bit_pos;
};
@ -263,13 +264,8 @@ 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

@ -1,303 +1,399 @@
/***********************************************************************************
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
(c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
Jerremy Koot (jkoot@snes9x.com)
(c) Copyright 2002 - 2004 Matthew Kendora
(c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
(c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
(c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
(c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
Kris Bleakley (codeviolation@hotmail.com)
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso,
OV2
BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom,
zones
C4 x86 assembler and some C emulation code
(c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
Nach,
zsKnight (zsknight@zsnes.com)
C4 C++ code
(c) Copyright 2003 - 2006 Brad Jorsch,
Nach
DSP-1 emulator code
(c) Copyright 1998 - 2006 _Demo_,
Andreas Naive (andreasnaive@gmail.com),
Gary Henderson,
Ivar (ivar@snes9x.com),
John Weidman,
Kris Bleakley,
Matthew Kendora,
Nach,
neviksti (neviksti@hotmail.com)
DSP-2 emulator code
(c) Copyright 2003 John Weidman,
Kris Bleakley,
Lord Nightmare (lord_nightmare@users.sourceforge.net),
Matthew Kendora,
neviksti
DSP-3 emulator code
(c) Copyright 2003 - 2006 John Weidman,
Kris Bleakley,
Lancer,
z80 gaiden
DSP-4 emulator code
(c) Copyright 2004 - 2006 Dreamer Nom,
John Weidman,
Kris Bleakley,
Nach,
z80 gaiden
OBC1 emulator code
(c) Copyright 2001 - 2004 zsKnight,
pagefault (pagefault@zsnes.com),
Kris Bleakley
Ported from x86 assembler to C by sanmaiwashi
SPC7110 and RTC C++ emulator code used in 1.39-1.51
(c) Copyright 2002 Matthew Kendora with research by
zsKnight,
John Weidman,
Dark Force
SPC7110 and RTC C++ emulator code used in 1.52+
(c) Copyright 2009 byuu,
neviksti
S-DD1 C emulator code
(c) Copyright 2003 Brad Jorsch with research by
Andreas Naive,
John Weidman
S-RTC C emulator code
(c) Copyright 2001 - 2006 byuu,
John Weidman
ST010 C++ emulator code
(c) Copyright 2003 Feather,
John Weidman,
Kris Bleakley,
Matthew Kendora
Super FX x86 assembler emulator code
(c) Copyright 1998 - 2003 _Demo_,
pagefault,
zsKnight
Super FX C emulator code
(c) Copyright 1997 - 1999 Ivar,
Gary Henderson,
John Weidman
Sound emulator code used in 1.5-1.51
(c) Copyright 1998 - 2003 Brad Martin
(c) Copyright 1998 - 2006 Charles Bilyue'
Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
2xSaI filter
(c) Copyright 1999 - 2001 Derek Liauw Kie Fa
HQ2x, HQ3x, HQ4x filters
(c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
NTSC filter
(c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso
Win32 GUI code
(c) Copyright 2003 - 2006 blip,
funkyass,
Matthew Kendora,
Nach,
nitsuja
(c) Copyright 2009 - 2010 OV2
Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones
Specific ports contains the works of other authors. See headers in
individual files.
Snes9x homepage: http://www.snes9x.com/
Permission to use, copy, modify and/or distribute Snes9x in both binary
and source form, for non-commercial purposes, is hereby granted without
fee, providing that this license information and copyright notice appear
with all copies and any derived work.
This software is provided 'as-is', without any express or implied
warranty. In no event shall the authors be held liable for any damages
arising from the use of this software or it's derivatives.
Snes9x is freeware for PERSONAL USE only. Commercial users should
seek permission of the copyright holders first. Commercial use includes,
but is not limited to, charging money for Snes9x or software derived from
Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
using Snes9x as a promotion for your commercial product.
The copyright holders request that bug fixes and improvements to the code
should be forwarded to them so everyone can benefit from the modifications
in future versions.
Super NES and Super Nintendo Entertainment System are trademarks of
Nintendo Co., Limited and its subsidiary companies.
***********************************************************************************/
#include "snes9x.h"
#include "memmap.h"
#define CPU SA1
#define ICPU SA1
#define Registers SA1Registers
#define OpenBus SA1OpenBus
#define S9xGetByte S9xSA1GetByte
#define S9xGetWord S9xSA1GetWord
#define S9xSetByte S9xSA1SetByte
#define S9xSetWord S9xSA1SetWord
#define S9xSetPCBase S9xSA1SetPCBase
#define S9xOpcodesM1X1 S9xSA1OpcodesM1X1
#define S9xOpcodesM1X0 S9xSA1OpcodesM1X0
#define S9xOpcodesM0X1 S9xSA1OpcodesM0X1
#define S9xOpcodesM0X0 S9xSA1OpcodesM0X0
#define S9xOpcodesE1 S9xSA1OpcodesE1
#define S9xOpcodesSlow S9xSA1OpcodesSlow
#define S9xOpcode_IRQ S9xSA1Opcode_IRQ
#define S9xOpcode_NMI S9xSA1Opcode_NMI
#define S9xUnpackStatus S9xSA1UnpackStatus
#define S9xPackStatus S9xSA1PackStatus
#define S9xFixCycles S9xSA1FixCycles
#define Immediate8 SA1Immediate8
#define Immediate16 SA1Immediate16
#define Relative SA1Relative
#define RelativeLong SA1RelativeLong
#define Absolute SA1Absolute
#define AbsoluteLong SA1AbsoluteLong
#define AbsoluteIndirect SA1AbsoluteIndirect
#define AbsoluteIndirectLong SA1AbsoluteIndirectLong
#define AbsoluteIndexedIndirect SA1AbsoluteIndexedIndirect
#define Direct SA1Direct
#define DirectIndirectIndexed SA1DirectIndirectIndexed
#define DirectIndirectIndexedLong SA1DirectIndirectIndexedLong
#define DirectIndexedIndirect SA1DirectIndexedIndirect
#define DirectIndexedX SA1DirectIndexedX
#define DirectIndexedY SA1DirectIndexedY
#define AbsoluteIndexedX SA1AbsoluteIndexedX
#define AbsoluteIndexedY SA1AbsoluteIndexedY
#define AbsoluteLongIndexedX SA1AbsoluteLongIndexedX
#define DirectIndirect SA1DirectIndirect
#define DirectIndirectLong SA1DirectIndirectLong
#define StackRelative SA1StackRelative
#define StackRelativeIndirectIndexed SA1StackRelativeIndirectIndexed
//#undef CPU_SHUTDOWN
#define SA1_OPCODES
#include "cpuops.cpp"
void S9xSA1MainLoop (void)
{
if (SA1.Flags & NMI_FLAG)
{
if (Memory.FillRAM[0x2200] & 0x10)
{
SA1.Flags &= ~NMI_FLAG;
Memory.FillRAM[0x2301] |= 0x10;
if (SA1.WaitingForInterrupt)
{
SA1.WaitingForInterrupt = FALSE;
SA1Registers.PCw++;
}
S9xSA1Opcode_NMI();
}
}
if (SA1.Flags & IRQ_FLAG)
{
if (SA1.IRQActive)
{
if (SA1.WaitingForInterrupt)
{
SA1.WaitingForInterrupt = FALSE;
SA1Registers.PCw++;
}
if (!SA1CheckFlag(IRQ))
S9xSA1Opcode_IRQ();
}
else
SA1.Flags &= ~IRQ_FLAG;
}
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;
if (SA1.PCBase)
{
SA1OpenBus = Op = SA1.PCBase[Registers.PCw];
Opcodes = SA1.S9xOpcodes;
}
else
{
Op = S9xSA1GetByte(Registers.PBPC);
Opcodes = S9xOpcodesSlow;
}
if ((SA1Registers.PCw & MEMMAP_MASK) + SA1.S9xOpLengths[Op] >= MEMMAP_BLOCK_SIZE)
{
uint32 oldPC = SA1Registers.PBPC;
S9xSA1SetPCBase(SA1Registers.PBPC);
SA1Registers.PBPC = oldPC;
Opcodes = S9xSA1OpcodesSlow;
}
Registers.PCw++;
(*Opcodes[Op].S9xOpcode)();
}
}
/***********************************************************************************
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
(c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
Jerremy Koot (jkoot@snes9x.com)
(c) Copyright 2002 - 2004 Matthew Kendora
(c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
(c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
(c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
(c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
Kris Bleakley (codeviolation@hotmail.com)
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso,
OV2
BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom,
zones
C4 x86 assembler and some C emulation code
(c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
Nach,
zsKnight (zsknight@zsnes.com)
C4 C++ code
(c) Copyright 2003 - 2006 Brad Jorsch,
Nach
DSP-1 emulator code
(c) Copyright 1998 - 2006 _Demo_,
Andreas Naive (andreasnaive@gmail.com),
Gary Henderson,
Ivar (ivar@snes9x.com),
John Weidman,
Kris Bleakley,
Matthew Kendora,
Nach,
neviksti (neviksti@hotmail.com)
DSP-2 emulator code
(c) Copyright 2003 John Weidman,
Kris Bleakley,
Lord Nightmare (lord_nightmare@users.sourceforge.net),
Matthew Kendora,
neviksti
DSP-3 emulator code
(c) Copyright 2003 - 2006 John Weidman,
Kris Bleakley,
Lancer,
z80 gaiden
DSP-4 emulator code
(c) Copyright 2004 - 2006 Dreamer Nom,
John Weidman,
Kris Bleakley,
Nach,
z80 gaiden
OBC1 emulator code
(c) Copyright 2001 - 2004 zsKnight,
pagefault (pagefault@zsnes.com),
Kris Bleakley
Ported from x86 assembler to C by sanmaiwashi
SPC7110 and RTC C++ emulator code used in 1.39-1.51
(c) Copyright 2002 Matthew Kendora with research by
zsKnight,
John Weidman,
Dark Force
SPC7110 and RTC C++ emulator code used in 1.52+
(c) Copyright 2009 byuu,
neviksti
S-DD1 C emulator code
(c) Copyright 2003 Brad Jorsch with research by
Andreas Naive,
John Weidman
S-RTC C emulator code
(c) Copyright 2001 - 2006 byuu,
John Weidman
ST010 C++ emulator code
(c) Copyright 2003 Feather,
John Weidman,
Kris Bleakley,
Matthew Kendora
Super FX x86 assembler emulator code
(c) Copyright 1998 - 2003 _Demo_,
pagefault,
zsKnight
Super FX C emulator code
(c) Copyright 1997 - 1999 Ivar,
Gary Henderson,
John Weidman
Sound emulator code used in 1.5-1.51
(c) Copyright 1998 - 2003 Brad Martin
(c) Copyright 1998 - 2006 Charles Bilyue'
Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
2xSaI filter
(c) Copyright 1999 - 2001 Derek Liauw Kie Fa
HQ2x, HQ3x, HQ4x filters
(c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
NTSC filter
(c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso
Win32 GUI code
(c) Copyright 2003 - 2006 blip,
funkyass,
Matthew Kendora,
Nach,
nitsuja
(c) Copyright 2009 - 2010 OV2
Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones
Specific ports contains the works of other authors. See headers in
individual files.
Snes9x homepage: http://www.snes9x.com/
Permission to use, copy, modify and/or distribute Snes9x in both binary
and source form, for non-commercial purposes, is hereby granted without
fee, providing that this license information and copyright notice appear
with all copies and any derived work.
This software is provided 'as-is', without any express or implied
warranty. In no event shall the authors be held liable for any damages
arising from the use of this software or it's derivatives.
Snes9x is freeware for PERSONAL USE only. Commercial users should
seek permission of the copyright holders first. Commercial use includes,
but is not limited to, charging money for Snes9x or software derived from
Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
using Snes9x as a promotion for your commercial product.
The copyright holders request that bug fixes and improvements to the code
should be forwarded to them so everyone can benefit from the modifications
in future versions.
Super NES and Super Nintendo Entertainment System are trademarks of
Nintendo Co., Limited and its subsidiary companies.
***********************************************************************************/
#include "snes9x.h"
#include "memmap.h"
#define CPU SA1
#define ICPU SA1
#define Registers SA1Registers
#define OpenBus SA1OpenBus
#define S9xGetByte S9xSA1GetByte
#define S9xGetWord S9xSA1GetWord
#define S9xSetByte S9xSA1SetByte
#define S9xSetWord S9xSA1SetWord
#define S9xSetPCBase S9xSA1SetPCBase
#define S9xOpcodesM1X1 S9xSA1OpcodesM1X1
#define S9xOpcodesM1X0 S9xSA1OpcodesM1X0
#define S9xOpcodesM0X1 S9xSA1OpcodesM0X1
#define S9xOpcodesM0X0 S9xSA1OpcodesM0X0
#define S9xOpcodesE1 S9xSA1OpcodesE1
#define S9xOpcodesSlow S9xSA1OpcodesSlow
#define S9xOpcode_IRQ S9xSA1Opcode_IRQ
#define S9xOpcode_NMI S9xSA1Opcode_NMI
#define S9xUnpackStatus S9xSA1UnpackStatus
#define S9xPackStatus S9xSA1PackStatus
#define S9xFixCycles S9xSA1FixCycles
#define Immediate8 SA1Immediate8
#define Immediate16 SA1Immediate16
#define Relative SA1Relative
#define RelativeLong SA1RelativeLong
#define Absolute SA1Absolute
#define AbsoluteLong SA1AbsoluteLong
#define AbsoluteIndirect SA1AbsoluteIndirect
#define AbsoluteIndirectLong SA1AbsoluteIndirectLong
#define AbsoluteIndexedIndirect SA1AbsoluteIndexedIndirect
#define Direct SA1Direct
#define DirectIndirectIndexed SA1DirectIndirectIndexed
#define DirectIndirectIndexedLong SA1DirectIndirectIndexedLong
#define DirectIndexedIndirect SA1DirectIndexedIndirect
#define DirectIndexedX SA1DirectIndexedX
#define DirectIndexedY SA1DirectIndexedY
#define AbsoluteIndexedX SA1AbsoluteIndexedX
#define AbsoluteIndexedY SA1AbsoluteIndexedY
#define AbsoluteLongIndexedX SA1AbsoluteLongIndexedX
#define DirectIndirect SA1DirectIndirect
#define DirectIndirectLong SA1DirectIndirectLong
#define StackRelative SA1StackRelative
#define StackRelativeIndirectIndexed SA1StackRelativeIndirectIndexed
#define SA1_OPCODES
#include "cpuops.cpp"
static void S9xSA1UpdateTimer (void);
void S9xSA1MainLoop (void)
{
if (Memory.FillRAM[0x2200] & 0x60)
{
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)
{
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;
if (SA1.WaitingForInterrupt)
{
SA1.WaitingForInterrupt = FALSE;
SA1Registers.PCw++;
}
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();
}
}
for (int i = 0; i < 3 && !(Memory.FillRAM[0x2200] & 0x60); i++)
{
#ifdef DEBUGGER
if (SA1.Flags & TRACE_FLAG)
S9xSA1Trace();
#endif
register uint8 Op;
register struct SOpcodes *Opcodes;
if (SA1.PCBase)
{
SA1OpenBus = Op = SA1.PCBase[Registers.PCw];
Opcodes = SA1.S9xOpcodes;
}
else
{
Op = S9xSA1GetByte(Registers.PBPC);
Opcodes = S9xOpcodesSlow;
}
if ((SA1Registers.PCw & MEMMAP_MASK) + SA1.S9xOpLengths[Op] >= MEMMAP_BLOCK_SIZE)
{
uint32 oldPC = SA1Registers.PBPC;
S9xSA1SetPCBase(SA1Registers.PBPC);
SA1Registers.PBPC = oldPC;
Opcodes = S9xSA1OpcodesSlow;
}
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 reserved;
uint8 CPU_IRQActive;
} 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),
INT_ENTRY(6, IRQActive),
OBSOLETE_INT_ENTRY(6, 7, CPU_IRQActive),
INT_ENTRY(6, IRQPending),
INT_ENTRY(6, MemSpeed),
INT_ENTRY(6, MemSpeedx2),
@ -366,9 +366,14 @@ static FreezeData SnapCPU[] =
INT_ENTRY(6, WhichEvent),
INT_ENTRY(6, NextEvent),
INT_ENTRY(6, WaitingForInterrupt),
INT_ENTRY(6, WaitAddress),
INT_ENTRY(6, WaitCounter),
INT_ENTRY(6, PBPCAtOpcodeStart)
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)
};
#undef STRUCT
@ -576,11 +581,11 @@ static FreezeData SnapTimings[] =
INT_ENTRY(6, DMACPUSync),
INT_ENTRY(6, NMIDMADelay),
INT_ENTRY(6, IRQPendCount),
INT_ENTRY(6, APUSpeedup)
INT_ENTRY(6, APUSpeedup),
INT_ENTRY(7, IRQTriggerCycles),
INT_ENTRY(7, APUAllowTimeOverflow)
};
#ifndef ZSNES_FX
#undef STRUCT
#define STRUCT struct FxRegs_s
@ -642,24 +647,22 @@ static FreezeData SnapFX[] =
INT_ENTRY(6, vSCBRDirty)
};
#endif
#undef STRUCT
#define STRUCT struct SSA1
static FreezeData SnapSA1[] =
{
INT_ENTRY(6, CPUExecuting),
DELETED_INT_ENTRY(6, 7, CPUExecuting, 1),
INT_ENTRY(6, ShiftedPB),
INT_ENTRY(6, ShiftedDB),
INT_ENTRY(6, Flags),
INT_ENTRY(6, IRQActive),
INT_ENTRY(6, Waiting),
DELETED_INT_ENTRY(6, 7, IRQActive, 1),
DELETED_INT_ENTRY(6, 7, Waiting, 1),
INT_ENTRY(6, WaitingForInterrupt),
INT_ENTRY(6, WaitAddress),
INT_ENTRY(6, WaitCounter),
INT_ENTRY(6, PBPCAtOpcodeStart),
INT_ENTRY(6, Executing),
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, overflow),
INT_ENTRY(6, in_char_dma),
INT_ENTRY(6, op1),
@ -667,7 +670,17 @@ static FreezeData SnapSA1[] =
INT_ENTRY(6, arithmetic_op),
INT_ENTRY(6, sum),
INT_ENTRY(6, VirtualBitmapFormat),
INT_ENTRY(6, variable_bit_pos)
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)
};
#undef STRUCT
@ -1255,15 +1268,10 @@ 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);
#ifdef ZSNES_FX
if (Settings.SuperFX)
S9xSuperFXPreSaveState();
#endif
sprintf(buffer, "%s:%04d\n", SNAPSHOT_MAGIC, SNAPSHOT_VERSION);
WRITE_STREAM(buffer, strlen(buffer), stream);
@ -1298,13 +1306,11 @@ void S9xFreezeToStream (STREAM stream)
FreezeStruct(stream, "TIM", &Timings, SnapTimings, COUNT(SnapTimings));
#ifndef ZSNES_FX
if (Settings.SuperFX)
{
GSU.avRegAddr = (uint8 *) &GSU.avReg;
FreezeStruct(stream, "SFX", &GSU, SnapFX, COUNT(SnapFX));
}
#endif
if (Settings.SA1)
{
@ -1323,11 +1329,7 @@ void S9xFreezeToStream (STREAM stream)
FreezeStruct(stream, "DP4", &DSP4, SnapDSP4, COUNT(SnapDSP4));
if (Settings.C4)
#ifndef ZSNES_C4
FreezeBlock (stream, "CX4", Memory.C4RAM, 8192);
#else
FreezeBlock (stream, "CX4", C4Ram, 8192);
#endif
if (Settings.SETA == ST_010)
FreezeStruct(stream, "ST0", &ST010, SnapST010, COUNT(SnapST010));
@ -1405,11 +1407,6 @@ void S9xFreezeToStream (STREAM stream)
}
}
#ifdef ZSNES_FX
if (Settings.SuperFX)
S9xSuperFXPostSaveState();
#endif
S9xSetSoundMute(FALSE);
delete [] soundsnapshot;
@ -1510,11 +1507,9 @@ int S9xUnfreezeFromStream (STREAM stream)
if (result != SUCCESS)
break;
#ifndef ZSNES_FX
result = UnfreezeStructCopy(stream, "SFX", &local_superfx, SnapFX, COUNT(SnapFX), version);
if (result != SUCCESS && Settings.SuperFX)
break;
#endif
result = UnfreezeStructCopy(stream, "SA1", &local_sa1, SnapSA1, COUNT(SnapSA1), version);
if (result != SUCCESS && Settings.SA1)
@ -1637,13 +1632,11 @@ int S9xUnfreezeFromStream (STREAM stream)
UnfreezeStructFromCopy(&Timings, SnapTimings, COUNT(SnapTimings), local_timing_data, version);
#ifndef ZSNES_FX
if (local_superfx)
{
GSU.avRegAddr = (uint8 *) &GSU.avReg;
UnfreezeStructFromCopy(&GSU, SnapFX, COUNT(SnapFX), local_superfx, version);
}
#endif
if (local_sa1)
UnfreezeStructFromCopy(&SA1, SnapSA1, COUNT(SnapSA1), local_sa1, version);
@ -1661,11 +1654,7 @@ int S9xUnfreezeFromStream (STREAM stream)
UnfreezeStructFromCopy(&DSP4, SnapDSP4, COUNT(SnapDSP4), local_dsp4, version);
if (local_cx4_data)
#ifndef ZSNES_C4
memcpy(Memory.C4RAM, local_cx4_data, 8192);
#else
memcpy(C4Ram, local_cx4_data, 8192);
#endif
if (local_st010)
UnfreezeStructFromCopy(&ST010, SnapST010, COUNT(SnapST010), local_st010, version);
@ -1688,6 +1677,40 @@ 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;
@ -1711,16 +1734,11 @@ int S9xUnfreezeFromStream (STREAM stream)
S9xControlPostLoadState(&ctl_snap);
#ifndef ZSNES_FX
if (local_superfx)
{
GSU.pfPlot = fx_PlotTable[GSU.vMode];
GSU.pfRpix = fx_PlotTable[GSU.vMode + 5];
}
#else
if (Settings.SuperFX)
S9xSuperFXPostLoadState();
#endif
if (local_sa1 && local_sa1_registers)
{
@ -2280,4 +2298,3 @@ bool8 S9xSPCDump (const char *filename)
return (TRUE);
}

View File

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

View File

@ -186,8 +186,6 @@
#include "65c816.h"
#include "messages.h"
#define S9X_ACCURACY_LEVEL 3
#ifdef ZLIB
#include <zlib.h>
#define STREAM gzFile
@ -263,8 +261,6 @@
#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)
@ -274,12 +270,16 @@
struct SCPUState
{
uint32 Flags;
int32 Cycles;
int32 PrevCycles;
int32 V_Counter;
uint32 Flags;
uint8 *PCBase;
bool8 IRQActive;
bool8 NMILine;
bool8 IRQLine;
bool8 IRQTransition;
bool8 IRQLastState;
bool8 IRQExternal;
int32 IRQPending;
int32 MemSpeed;
int32 MemSpeedx2;
@ -293,9 +293,6 @@ struct SCPUState
uint8 WhichEvent;
int32 NextEvent;
bool8 WaitingForInterrupt;
uint32 WaitAddress;
uint32 WaitCounter;
uint32 PBPCAtOpcodeStart;
uint32 AutoSaveTimer;
bool8 SRAMModified;
};
@ -303,17 +300,11 @@ struct SCPUState
enum
{
HC_HBLANK_START_EVENT = 1,
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
HC_HDMA_START_EVENT = 2,
HC_HCOUNTER_MAX_EVENT = 3,
HC_HDMA_INIT_EVENT = 4,
HC_RENDER_EVENT = 5,
HC_WRAM_REFRESH_EVENT = 6
};
struct STimings
@ -327,12 +318,13 @@ 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, because Snes9x cannot emulate any events in an opcode.
int32 IRQPendCount; // This value is just a hack.
int32 APUSpeedup;
bool8 APUAllowTimeOverflow;
};
@ -405,12 +397,8 @@ 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;