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)60 void 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)170 static 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