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
57static void S9xSA1UpdateTimer (void);
58
59
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
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