1 /*****************************************************************************\ 2 Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. 3 This file is licensed under the Snes9x License. 4 For further information, consult the LICENSE file in the root directory. 5 \*****************************************************************************/ 6 7 #include "snes9x.h" 8 #include "memmap.h" 9 10 #define CPU SA1 11 #define ICPU SA1 12 #define Registers SA1Registers 13 #define OpenBus SA1OpenBus 14 #define S9xGetByte S9xSA1GetByte 15 #define S9xGetWord S9xSA1GetWord 16 #define S9xSetByte S9xSA1SetByte 17 #define S9xSetWord S9xSA1SetWord 18 #define S9xSetPCBase S9xSA1SetPCBase 19 #define S9xOpcodesM1X1 S9xSA1OpcodesM1X1 20 #define S9xOpcodesM1X0 S9xSA1OpcodesM1X0 21 #define S9xOpcodesM0X1 S9xSA1OpcodesM0X1 22 #define S9xOpcodesM0X0 S9xSA1OpcodesM0X0 23 #define S9xOpcodesE1 S9xSA1OpcodesE1 24 #define S9xOpcodesSlow S9xSA1OpcodesSlow 25 #define S9xOpcode_IRQ S9xSA1Opcode_IRQ 26 #define S9xOpcode_NMI S9xSA1Opcode_NMI 27 #define S9xUnpackStatus S9xSA1UnpackStatus 28 #define S9xPackStatus S9xSA1PackStatus 29 #define S9xFixCycles S9xSA1FixCycles 30 #define Immediate8 SA1Immediate8 31 #define Immediate16 SA1Immediate16 32 #define Relative SA1Relative 33 #define RelativeLong SA1RelativeLong 34 #define Absolute SA1Absolute 35 #define AbsoluteLong SA1AbsoluteLong 36 #define AbsoluteIndirect SA1AbsoluteIndirect 37 #define AbsoluteIndirectLong SA1AbsoluteIndirectLong 38 #define AbsoluteIndexedIndirect SA1AbsoluteIndexedIndirect 39 #define Direct SA1Direct 40 #define DirectIndirectIndexed SA1DirectIndirectIndexed 41 #define DirectIndirectIndexedLong SA1DirectIndirectIndexedLong 42 #define DirectIndexedIndirect SA1DirectIndexedIndirect 43 #define DirectIndexedX SA1DirectIndexedX 44 #define DirectIndexedY SA1DirectIndexedY 45 #define AbsoluteIndexedX SA1AbsoluteIndexedX 46 #define AbsoluteIndexedY SA1AbsoluteIndexedY 47 #define AbsoluteLongIndexedX SA1AbsoluteLongIndexedX 48 #define DirectIndirect SA1DirectIndirect 49 #define DirectIndirectLong SA1DirectIndirectLong 50 #define StackRelative SA1StackRelative 51 #define StackRelativeIndirectIndexed SA1StackRelativeIndirectIndexed 52 53 #define SA1_OPCODES 54 55 #include "cpuops.cpp" 56 57 static void S9xSA1UpdateTimer (void); 58 59 S9xSA1MainLoop(void)60void S9xSA1MainLoop (void) 61 { 62 if (Memory.FillRAM[0x2200] & 0x60) 63 { 64 SA1.Cycles += 6; // FIXME 65 S9xSA1UpdateTimer(); 66 return; 67 } 68 69 // SA-1 NMI 70 if ((Memory.FillRAM[0x2200] & 0x10) && !(Memory.FillRAM[0x220b] & 0x10)) 71 { 72 Memory.FillRAM[0x2301] |= 0x10; 73 Memory.FillRAM[0x220b] |= 0x10; 74 75 if (SA1.WaitingForInterrupt) 76 { 77 SA1.WaitingForInterrupt = FALSE; 78 SA1Registers.PCw++; 79 } 80 81 S9xSA1Opcode_NMI(); 82 } 83 else 84 if (!SA1CheckFlag(IRQ)) 85 { 86 // SA-1 Timer IRQ 87 if ((Memory.FillRAM[0x220a] & 0x40) && !(Memory.FillRAM[0x220b] & 0x40)) 88 { 89 Memory.FillRAM[0x2301] |= 0x40; 90 91 if (SA1.WaitingForInterrupt) 92 { 93 SA1.WaitingForInterrupt = FALSE; 94 SA1Registers.PCw++; 95 } 96 97 S9xSA1Opcode_IRQ(); 98 } 99 else 100 // SA-1 DMA IRQ 101 if ((Memory.FillRAM[0x220a] & 0x20) && !(Memory.FillRAM[0x220b] & 0x20)) 102 { 103 Memory.FillRAM[0x2301] |= 0x20; 104 105 if (SA1.WaitingForInterrupt) 106 { 107 SA1.WaitingForInterrupt = FALSE; 108 SA1Registers.PCw++; 109 } 110 111 S9xSA1Opcode_IRQ(); 112 } 113 else 114 // SA-1 IRQ 115 if ((Memory.FillRAM[0x2200] & 0x80) && !(Memory.FillRAM[0x220b] & 0x80)) 116 { 117 Memory.FillRAM[0x2301] |= 0x80; 118 119 if (SA1.WaitingForInterrupt) 120 { 121 SA1.WaitingForInterrupt = FALSE; 122 SA1Registers.PCw++; 123 } 124 125 S9xSA1Opcode_IRQ(); 126 } 127 } 128 129 #undef CPU 130 int cycles = CPU.Cycles * 3; 131 #define CPU SA1 132 133 for (; SA1.Cycles < cycles && !(Memory.FillRAM[0x2200] & 0x60);) 134 { 135 #ifdef DEBUGGER 136 if (SA1.Flags & TRACE_FLAG) 137 S9xSA1Trace(); 138 #endif 139 140 uint8 Op; 141 struct SOpcodes *Opcodes; 142 143 if (SA1.PCBase) 144 { 145 SA1OpenBus = Op = SA1.PCBase[Registers.PCw]; 146 Opcodes = SA1.S9xOpcodes; 147 SA1.Cycles += SA1.MemSpeed; 148 } 149 else 150 { 151 Op = S9xSA1GetByte(Registers.PBPC); 152 Opcodes = S9xOpcodesSlow; 153 } 154 155 if ((SA1Registers.PCw & MEMMAP_MASK) + SA1.S9xOpLengths[Op] >= MEMMAP_BLOCK_SIZE) 156 { 157 uint32 oldPC = SA1Registers.PBPC; 158 S9xSA1SetPCBase(SA1Registers.PBPC); 159 SA1Registers.PBPC = oldPC; 160 Opcodes = S9xSA1OpcodesSlow; 161 } 162 163 Registers.PCw++; 164 (*Opcodes[Op].S9xOpcode)(); 165 } 166 167 S9xSA1UpdateTimer(); 168 } 169 S9xSA1UpdateTimer(void)170static void S9xSA1UpdateTimer (void) // FIXME 171 { 172 SA1.PrevHCounter = SA1.HCounter; 173 174 if (Memory.FillRAM[0x2210] & 0x80) 175 { 176 SA1.HCounter += (SA1.Cycles - SA1.PrevCycles); 177 if (SA1.HCounter >= 0x800) 178 { 179 SA1.HCounter -= 0x800; 180 SA1.PrevHCounter -= 0x800; 181 if (++SA1.VCounter >= 0x200) 182 SA1.VCounter = 0; 183 } 184 } 185 else 186 { 187 SA1.HCounter += (SA1.Cycles - SA1.PrevCycles); 188 if (SA1.HCounter >= Timings.H_Max_Master) 189 { 190 SA1.HCounter -= Timings.H_Max_Master; 191 SA1.PrevHCounter -= Timings.H_Max_Master; 192 if (++SA1.VCounter >= Timings.V_Max_Master) 193 SA1.VCounter = 0; 194 } 195 } 196 197 SA1.PrevCycles = SA1.Cycles; 198 199 bool8 thisIRQ = Memory.FillRAM[0x2210] & 0x03; 200 201 if (Memory.FillRAM[0x2210] & 0x01) 202 { 203 if (SA1.PrevHCounter >= SA1.HTimerIRQPos * ONE_DOT_CYCLE || SA1.HCounter < SA1.HTimerIRQPos * ONE_DOT_CYCLE) 204 thisIRQ = FALSE; 205 } 206 207 if (Memory.FillRAM[0x2210] & 0x02) 208 { 209 if (SA1.VCounter != SA1.VTimerIRQPos * ONE_DOT_CYCLE) 210 thisIRQ = FALSE; 211 } 212 213 // SA-1 Timer IRQ control 214 if (!SA1.TimerIRQLastState && thisIRQ) 215 { 216 Memory.FillRAM[0x2301] |= 0x40; 217 if (Memory.FillRAM[0x220a] & 0x40) 218 { 219 Memory.FillRAM[0x220b] &= ~0x40; 220 #ifdef DEBUGGER 221 S9xTraceFormattedMessage("--- SA-1 Timer IRQ triggered prev HC:%04d curr HC:%04d HTimer:%d Pos:%04d VTimer:%d Pos:%03d", 222 SA1.PrevHCounter, SA1.HCounter, 223 (Memory.FillRAM[0x2210] & 0x01) ? 1 : 0, SA1.HTimerIRQPos * ONE_DOT_CYCLE, 224 (Memory.FillRAM[0x2210] & 0x02) ? 1 : 0, SA1.VTimerIRQPos); 225 #endif 226 } 227 } 228 229 SA1.TimerIRQLastState = thisIRQ; 230 } 231