rlm@1
|
1 #include <cstdio>
|
rlm@1
|
2 #include <cstdlib>
|
rlm@1
|
3 #include <cstdarg>
|
rlm@1
|
4 #include <cstring>
|
rlm@1
|
5
|
rlm@1
|
6 #include "../Port.h"
|
rlm@1
|
7 #include "../NLS.h"
|
rlm@1
|
8 #include "GBA.h"
|
rlm@1
|
9 //#include "GBAGlobals.h"
|
rlm@1
|
10 #include "GBACheats.h" // FIXME: SDL requires this included before "GBAinline.h"
|
rlm@1
|
11 #include "GBAinline.h"
|
rlm@1
|
12 #include "GBAGfx.h"
|
rlm@1
|
13 #include "GBASound.h"
|
rlm@1
|
14 #include "EEprom.h"
|
rlm@1
|
15 #include "Flash.h"
|
rlm@1
|
16 #include "Sram.h"
|
rlm@1
|
17 #include "bios.h"
|
rlm@1
|
18 #include "elf.h"
|
rlm@1
|
19 #include "agbprint.h"
|
rlm@1
|
20 #include "../common/unzip.h"
|
rlm@1
|
21 #include "../common/Util.h"
|
rlm@1
|
22 #include "../common/movie.h"
|
rlm@1
|
23 #include "../common/vbalua.h"
|
rlm@1
|
24
|
rlm@1
|
25 #ifdef PROFILING
|
rlm@1
|
26 #include "../prof/prof.h"
|
rlm@1
|
27 #endif
|
rlm@1
|
28
|
rlm@1
|
29 #define UPDATE_REG(address, value) WRITE16LE(((u16 *)&ioMem[address]), value)
|
rlm@1
|
30
|
rlm@1
|
31 #ifdef __GNUC__
|
rlm@1
|
32 #define _stricmp strcasecmp
|
rlm@1
|
33 #endif
|
rlm@1
|
34
|
rlm@1
|
35 #define CPU_BREAK_LOOP \
|
rlm@1
|
36 cpuSavedTicks = cpuSavedTicks - *extCpuLoopTicks; \
|
rlm@1
|
37 *extCpuLoopTicks = *extClockTicks;
|
rlm@1
|
38
|
rlm@1
|
39 #define CPU_BREAK_LOOP_2 \
|
rlm@1
|
40 cpuSavedTicks = cpuSavedTicks - *extCpuLoopTicks; \
|
rlm@1
|
41 *extCpuLoopTicks = *extClockTicks; \
|
rlm@1
|
42 *extTicks = *extClockTicks;
|
rlm@1
|
43
|
rlm@1
|
44 int32 cpuDmaTicksToUpdate = 0;
|
rlm@1
|
45 int32 cpuDmaCount = 0;
|
rlm@1
|
46 bool8 cpuDmaHack = 0;
|
rlm@1
|
47 u32 cpuDmaLast = 0;
|
rlm@1
|
48 int32 dummyAddress = 0;
|
rlm@1
|
49
|
rlm@1
|
50 int32 *extCpuLoopTicks = NULL;
|
rlm@1
|
51 int32 *extClockTicks = NULL;
|
rlm@1
|
52 int32 *extTicks = NULL;
|
rlm@1
|
53
|
rlm@1
|
54 #if (defined(WIN32) && !defined(SDL))
|
rlm@1
|
55 HANDLE mapROM; // shared memory handles
|
rlm@1
|
56 HANDLE mapWORKRAM;
|
rlm@1
|
57 HANDLE mapBIOS;
|
rlm@1
|
58 HANDLE mapIRAM;
|
rlm@1
|
59 HANDLE mapPALETTERAM;
|
rlm@1
|
60 HANDLE mapVRAM;
|
rlm@1
|
61 HANDLE mapOAM;
|
rlm@1
|
62 HANDLE mapPIX;
|
rlm@1
|
63 HANDLE mapIOMEM;
|
rlm@1
|
64 #endif
|
rlm@1
|
65
|
rlm@1
|
66 int32 gbaSaveType = 0; // used to remember the save type on reset
|
rlm@1
|
67 bool8 intState = false;
|
rlm@1
|
68 bool8 stopState = false;
|
rlm@1
|
69 bool8 holdState = false;
|
rlm@1
|
70 int32 holdType = 0;
|
rlm@1
|
71 bool8 cpuSramEnabled = true;
|
rlm@1
|
72 bool8 cpuFlashEnabled = true;
|
rlm@1
|
73 bool8 cpuEEPROMEnabled = true;
|
rlm@1
|
74 bool8 cpuEEPROMSensorEnabled = false;
|
rlm@1
|
75
|
rlm@1
|
76 #ifdef PROFILING
|
rlm@1
|
77 int profilingTicks = 0;
|
rlm@1
|
78 int profilingTicksReload = 0;
|
rlm@1
|
79 static char *profilBuffer = NULL;
|
rlm@1
|
80 static int profilSize = 0;
|
rlm@1
|
81 static u32 profilLowPC = 0;
|
rlm@1
|
82 static int profilScale = 0;
|
rlm@1
|
83 #endif
|
rlm@1
|
84 bool8 freezeWorkRAM[0x40000];
|
rlm@1
|
85 bool8 freezeInternalRAM[0x8000];
|
rlm@1
|
86 int32 lcdTicks = 960;
|
rlm@1
|
87 bool8 timer0On = false;
|
rlm@1
|
88 int32 timer0Ticks = 0;
|
rlm@1
|
89 int32 timer0Reload = 0;
|
rlm@1
|
90 int32 timer0ClockReload = 0;
|
rlm@1
|
91 bool8 timer1On = false;
|
rlm@1
|
92 int32 timer1Ticks = 0;
|
rlm@1
|
93 int32 timer1Reload = 0;
|
rlm@1
|
94 int32 timer1ClockReload = 0;
|
rlm@1
|
95 bool8 timer2On = false;
|
rlm@1
|
96 int32 timer2Ticks = 0;
|
rlm@1
|
97 int32 timer2Reload = 0;
|
rlm@1
|
98 int32 timer2ClockReload = 0;
|
rlm@1
|
99 bool8 timer3On = false;
|
rlm@1
|
100 int32 timer3Ticks = 0;
|
rlm@1
|
101 int32 timer3Reload = 0;
|
rlm@1
|
102 int32 timer3ClockReload = 0;
|
rlm@1
|
103 u32 dma0Source = 0;
|
rlm@1
|
104 u32 dma0Dest = 0;
|
rlm@1
|
105 u32 dma1Source = 0;
|
rlm@1
|
106 u32 dma1Dest = 0;
|
rlm@1
|
107 u32 dma2Source = 0;
|
rlm@1
|
108 u32 dma2Dest = 0;
|
rlm@1
|
109 u32 dma3Source = 0;
|
rlm@1
|
110 u32 dma3Dest = 0;
|
rlm@1
|
111 void (*cpuSaveGameFunc)(u32, u8) = flashSaveDecide;
|
rlm@1
|
112 void (*renderLine)() = mode0RenderLine;
|
rlm@1
|
113 bool8 fxOn = false;
|
rlm@1
|
114 bool8 windowOn = false;
|
rlm@1
|
115 int32 frameSkipCount = 0;
|
rlm@1
|
116 u32 gbaLastTime = 0;
|
rlm@1
|
117 int32 gbaFrameCount = 0;
|
rlm@1
|
118 bool8 prefetchActive = false, prefetchPrevActive = false, prefetchApplies = false;
|
rlm@1
|
119 char buffer[1024];
|
rlm@1
|
120 FILE *out = NULL;
|
rlm@1
|
121
|
rlm@1
|
122 static bool newFrame = true;
|
rlm@1
|
123 static bool pauseAfterFrameAdvance = false;
|
rlm@1
|
124
|
rlm@1
|
125 const int32 TIMER_TICKS[4] = {
|
rlm@1
|
126 1,
|
rlm@1
|
127 64,
|
rlm@1
|
128 256,
|
rlm@1
|
129 1024
|
rlm@1
|
130 };
|
rlm@1
|
131
|
rlm@1
|
132 const int32 thumbCycles[] = {
|
rlm@1
|
133 // 0 1 2 3 4 5 6 7 8 9 a b c d e f
|
rlm@1
|
134 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
|
rlm@1
|
135 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
|
rlm@1
|
136 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
|
rlm@1
|
137 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3
|
rlm@1
|
138 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 4
|
rlm@1
|
139 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 5
|
rlm@1
|
140 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 6
|
rlm@1
|
141 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 7
|
rlm@1
|
142 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 8
|
rlm@1
|
143 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 9
|
rlm@1
|
144 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // a
|
rlm@1
|
145 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 4, 1, 1, // b
|
rlm@1
|
146 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // c
|
rlm@1
|
147 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, // d
|
rlm@1
|
148 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // e
|
rlm@1
|
149 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 // f
|
rlm@1
|
150 };
|
rlm@1
|
151
|
rlm@1
|
152 const int32 gamepakRamWaitState[4] = { 4, 3, 2, 8 };
|
rlm@1
|
153 const int32 gamepakWaitState[8] = { 4, 3, 2, 8, 4, 3, 2, 8 };
|
rlm@1
|
154 const int32 gamepakWaitState0[8] = { 2, 2, 2, 2, 1, 1, 1, 1 };
|
rlm@1
|
155 const int32 gamepakWaitState1[8] = { 4, 4, 4, 4, 1, 1, 1, 1 };
|
rlm@1
|
156 const int32 gamepakWaitState2[8] = { 8, 8, 8, 8, 1, 1, 1, 1 };
|
rlm@1
|
157
|
rlm@1
|
158 int32 memoryWait[16] =
|
rlm@1
|
159 { 0, 0, 2, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 0 };
|
rlm@1
|
160 int32 memoryWait32[16] =
|
rlm@1
|
161 { 0, 0, 9, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 0 };
|
rlm@1
|
162 int32 memoryWaitSeq[16] =
|
rlm@1
|
163 { 0, 0, 2, 0, 0, 0, 0, 0, 2, 2, 4, 4, 8, 8, 4, 0 };
|
rlm@1
|
164 int32 memoryWaitSeq32[16] =
|
rlm@1
|
165 { 2, 0, 3, 0, 0, 2, 2, 0, 4, 4, 8, 8, 16, 16, 8, 0 };
|
rlm@1
|
166 int32 memoryWaitFetch[16] =
|
rlm@1
|
167 { 3, 0, 3, 0, 0, 1, 1, 0, 4, 4, 4, 4, 4, 4, 4, 0 };
|
rlm@1
|
168 int32 memoryWaitFetch32[16] =
|
rlm@1
|
169 { 6, 0, 6, 0, 0, 2, 2, 0, 8, 8, 8, 8, 8, 8, 8, 0 };
|
rlm@1
|
170
|
rlm@1
|
171 const int32 cpuMemoryWait[16] = {
|
rlm@1
|
172 0, 0, 2, 0, 0, 0, 0, 0,
|
rlm@1
|
173 2, 2, 2, 2, 2, 2, 0, 0
|
rlm@1
|
174 };
|
rlm@1
|
175 const int32 cpuMemoryWait32[16] = {
|
rlm@1
|
176 0, 0, 3, 0, 0, 0, 0, 0,
|
rlm@1
|
177 3, 3, 3, 3, 3, 3, 0, 0
|
rlm@1
|
178 };
|
rlm@1
|
179
|
rlm@1
|
180 const bool8 memory32[16] = {
|
rlm@1
|
181 true, false, false, true, true, false, false, true, false, false, false, false, false, false, true, false
|
rlm@1
|
182 };
|
rlm@1
|
183
|
rlm@1
|
184 u8 biosProtected[4];
|
rlm@1
|
185
|
rlm@1
|
186 u8 cpuBitsSet[256];
|
rlm@1
|
187 u8 cpuLowestBitSet[256];
|
rlm@1
|
188
|
rlm@1
|
189 #ifdef WORDS_BIGENDIAN
|
rlm@1
|
190 bool8 cpuBiosSwapped = false;
|
rlm@1
|
191 #endif
|
rlm@1
|
192
|
rlm@1
|
193 u32 myROM[] = {
|
rlm@1
|
194 0xEA000006,
|
rlm@1
|
195 0xEA000093,
|
rlm@1
|
196 0xEA000006,
|
rlm@1
|
197 0x00000000,
|
rlm@1
|
198 0x00000000,
|
rlm@1
|
199 0x00000000,
|
rlm@1
|
200 0xEA000088,
|
rlm@1
|
201 0x00000000,
|
rlm@1
|
202 0xE3A00302,
|
rlm@1
|
203 0xE1A0F000,
|
rlm@1
|
204 0xE92D5800,
|
rlm@1
|
205 0xE55EC002,
|
rlm@1
|
206 0xE28FB03C,
|
rlm@1
|
207 0xE79BC10C,
|
rlm@1
|
208 0xE14FB000,
|
rlm@1
|
209 0xE92D0800,
|
rlm@1
|
210 0xE20BB080,
|
rlm@1
|
211 0xE38BB01F,
|
rlm@1
|
212 0xE129F00B,
|
rlm@1
|
213 0xE92D4004,
|
rlm@1
|
214 0xE1A0E00F,
|
rlm@1
|
215 0xE12FFF1C,
|
rlm@1
|
216 0xE8BD4004,
|
rlm@1
|
217 0xE3A0C0D3,
|
rlm@1
|
218 0xE129F00C,
|
rlm@1
|
219 0xE8BD0800,
|
rlm@1
|
220 0xE169F00B,
|
rlm@1
|
221 0xE8BD5800,
|
rlm@1
|
222 0xE1B0F00E,
|
rlm@1
|
223 0x0000009C,
|
rlm@1
|
224 0x0000009C,
|
rlm@1
|
225 0x0000009C,
|
rlm@1
|
226 0x0000009C,
|
rlm@1
|
227 0x000001F8,
|
rlm@1
|
228 0x000001F0,
|
rlm@1
|
229 0x000000AC,
|
rlm@1
|
230 0x000000A0,
|
rlm@1
|
231 0x000000FC,
|
rlm@1
|
232 0x00000168,
|
rlm@1
|
233 0xE12FFF1E,
|
rlm@1
|
234 0xE1A03000,
|
rlm@1
|
235 0xE1A00001,
|
rlm@1
|
236 0xE1A01003,
|
rlm@1
|
237 0xE2113102,
|
rlm@1
|
238 0x42611000,
|
rlm@1
|
239 0xE033C040,
|
rlm@1
|
240 0x22600000,
|
rlm@1
|
241 0xE1B02001,
|
rlm@1
|
242 0xE15200A0,
|
rlm@1
|
243 0x91A02082,
|
rlm@1
|
244 0x3AFFFFFC,
|
rlm@1
|
245 0xE1500002,
|
rlm@1
|
246 0xE0A33003,
|
rlm@1
|
247 0x20400002,
|
rlm@1
|
248 0xE1320001,
|
rlm@1
|
249 0x11A020A2,
|
rlm@1
|
250 0x1AFFFFF9,
|
rlm@1
|
251 0xE1A01000,
|
rlm@1
|
252 0xE1A00003,
|
rlm@1
|
253 0xE1B0C08C,
|
rlm@1
|
254 0x22600000,
|
rlm@1
|
255 0x42611000,
|
rlm@1
|
256 0xE12FFF1E,
|
rlm@1
|
257 0xE92D0010,
|
rlm@1
|
258 0xE1A0C000,
|
rlm@1
|
259 0xE3A01001,
|
rlm@1
|
260 0xE1500001,
|
rlm@1
|
261 0x81A000A0,
|
rlm@1
|
262 0x81A01081,
|
rlm@1
|
263 0x8AFFFFFB,
|
rlm@1
|
264 0xE1A0000C,
|
rlm@1
|
265 0xE1A04001,
|
rlm@1
|
266 0xE3A03000,
|
rlm@1
|
267 0xE1A02001,
|
rlm@1
|
268 0xE15200A0,
|
rlm@1
|
269 0x91A02082,
|
rlm@1
|
270 0x3AFFFFFC,
|
rlm@1
|
271 0xE1500002,
|
rlm@1
|
272 0xE0A33003,
|
rlm@1
|
273 0x20400002,
|
rlm@1
|
274 0xE1320001,
|
rlm@1
|
275 0x11A020A2,
|
rlm@1
|
276 0x1AFFFFF9,
|
rlm@1
|
277 0xE0811003,
|
rlm@1
|
278 0xE1B010A1,
|
rlm@1
|
279 0xE1510004,
|
rlm@1
|
280 0x3AFFFFEE,
|
rlm@1
|
281 0xE1A00004,
|
rlm@1
|
282 0xE8BD0010,
|
rlm@1
|
283 0xE12FFF1E,
|
rlm@1
|
284 0xE0010090,
|
rlm@1
|
285 0xE1A01741,
|
rlm@1
|
286 0xE2611000,
|
rlm@1
|
287 0xE3A030A9,
|
rlm@1
|
288 0xE0030391,
|
rlm@1
|
289 0xE1A03743,
|
rlm@1
|
290 0xE2833E39,
|
rlm@1
|
291 0xE0030391,
|
rlm@1
|
292 0xE1A03743,
|
rlm@1
|
293 0xE2833C09,
|
rlm@1
|
294 0xE283301C,
|
rlm@1
|
295 0xE0030391,
|
rlm@1
|
296 0xE1A03743,
|
rlm@1
|
297 0xE2833C0F,
|
rlm@1
|
298 0xE28330B6,
|
rlm@1
|
299 0xE0030391,
|
rlm@1
|
300 0xE1A03743,
|
rlm@1
|
301 0xE2833C16,
|
rlm@1
|
302 0xE28330AA,
|
rlm@1
|
303 0xE0030391,
|
rlm@1
|
304 0xE1A03743,
|
rlm@1
|
305 0xE2833A02,
|
rlm@1
|
306 0xE2833081,
|
rlm@1
|
307 0xE0030391,
|
rlm@1
|
308 0xE1A03743,
|
rlm@1
|
309 0xE2833C36,
|
rlm@1
|
310 0xE2833051,
|
rlm@1
|
311 0xE0030391,
|
rlm@1
|
312 0xE1A03743,
|
rlm@1
|
313 0xE2833CA2,
|
rlm@1
|
314 0xE28330F9,
|
rlm@1
|
315 0xE0000093,
|
rlm@1
|
316 0xE1A00840,
|
rlm@1
|
317 0xE12FFF1E,
|
rlm@1
|
318 0xE3A00001,
|
rlm@1
|
319 0xE3A01001,
|
rlm@1
|
320 0xE92D4010,
|
rlm@1
|
321 0xE3A0C301,
|
rlm@1
|
322 0xE3A03000,
|
rlm@1
|
323 0xE3A04001,
|
rlm@1
|
324 0xE3500000,
|
rlm@1
|
325 0x1B000004,
|
rlm@1
|
326 0xE5CC3301,
|
rlm@1
|
327 0xEB000002,
|
rlm@1
|
328 0x0AFFFFFC,
|
rlm@1
|
329 0xE8BD4010,
|
rlm@1
|
330 0xE12FFF1E,
|
rlm@1
|
331 0xE5CC3208,
|
rlm@1
|
332 0xE15C20B8,
|
rlm@1
|
333 0xE0110002,
|
rlm@1
|
334 0x10200002,
|
rlm@1
|
335 0x114C00B8,
|
rlm@1
|
336 0xE5CC4208,
|
rlm@1
|
337 0xE12FFF1E,
|
rlm@1
|
338 0xE92D500F,
|
rlm@1
|
339 0xE3A00301,
|
rlm@1
|
340 0xE1A0E00F,
|
rlm@1
|
341 0xE510F004,
|
rlm@1
|
342 0xE8BD500F,
|
rlm@1
|
343 0xE25EF004,
|
rlm@1
|
344 0xE59FD044,
|
rlm@1
|
345 0xE92D5000,
|
rlm@1
|
346 0xE14FC000,
|
rlm@1
|
347 0xE10FE000,
|
rlm@1
|
348 0xE92D5000,
|
rlm@1
|
349 0xE3A0C302,
|
rlm@1
|
350 0xE5DCE09C,
|
rlm@1
|
351 0xE35E00A5,
|
rlm@1
|
352 0x1A000004,
|
rlm@1
|
353 0x05DCE0B4,
|
rlm@1
|
354 0x021EE080,
|
rlm@1
|
355 0xE28FE004,
|
rlm@1
|
356 0x159FF018,
|
rlm@1
|
357 0x059FF018,
|
rlm@1
|
358 0xE59FD018,
|
rlm@1
|
359 0xE8BD5000,
|
rlm@1
|
360 0xE169F00C,
|
rlm@1
|
361 0xE8BD5000,
|
rlm@1
|
362 0xE25EF004,
|
rlm@1
|
363 0x03007FF0,
|
rlm@1
|
364 0x09FE2000,
|
rlm@1
|
365 0x09FFC000,
|
rlm@1
|
366 0x03007FE0
|
rlm@1
|
367 };
|
rlm@1
|
368
|
rlm@1
|
369 variable_desc saveGameStruct[] = {
|
rlm@1
|
370 { &DISPCNT, sizeof(u16) },
|
rlm@1
|
371 { &DISPSTAT, sizeof(u16) },
|
rlm@1
|
372 { &VCOUNT, sizeof(u16) },
|
rlm@1
|
373 { &BG0CNT, sizeof(u16) },
|
rlm@1
|
374 { &BG1CNT, sizeof(u16) },
|
rlm@1
|
375 { &BG2CNT, sizeof(u16) },
|
rlm@1
|
376 { &BG3CNT, sizeof(u16) },
|
rlm@1
|
377 { &BG0HOFS, sizeof(u16) },
|
rlm@1
|
378 { &BG0VOFS, sizeof(u16) },
|
rlm@1
|
379 { &BG1HOFS, sizeof(u16) },
|
rlm@1
|
380 { &BG1VOFS, sizeof(u16) },
|
rlm@1
|
381 { &BG2HOFS, sizeof(u16) },
|
rlm@1
|
382 { &BG2VOFS, sizeof(u16) },
|
rlm@1
|
383 { &BG3HOFS, sizeof(u16) },
|
rlm@1
|
384 { &BG3VOFS, sizeof(u16) },
|
rlm@1
|
385 { &BG2PA, sizeof(u16) },
|
rlm@1
|
386 { &BG2PB, sizeof(u16) },
|
rlm@1
|
387 { &BG2PC, sizeof(u16) },
|
rlm@1
|
388 { &BG2PD, sizeof(u16) },
|
rlm@1
|
389 { &BG2X_L, sizeof(u16) },
|
rlm@1
|
390 { &BG2X_H, sizeof(u16) },
|
rlm@1
|
391 { &BG2Y_L, sizeof(u16) },
|
rlm@1
|
392 { &BG2Y_H, sizeof(u16) },
|
rlm@1
|
393 { &BG3PA, sizeof(u16) },
|
rlm@1
|
394 { &BG3PB, sizeof(u16) },
|
rlm@1
|
395 { &BG3PC, sizeof(u16) },
|
rlm@1
|
396 { &BG3PD, sizeof(u16) },
|
rlm@1
|
397 { &BG3X_L, sizeof(u16) },
|
rlm@1
|
398 { &BG3X_H, sizeof(u16) },
|
rlm@1
|
399 { &BG3Y_L, sizeof(u16) },
|
rlm@1
|
400 { &BG3Y_H, sizeof(u16) },
|
rlm@1
|
401 { &WIN0H, sizeof(u16) },
|
rlm@1
|
402 { &WIN1H, sizeof(u16) },
|
rlm@1
|
403 { &WIN0V, sizeof(u16) },
|
rlm@1
|
404 { &WIN1V, sizeof(u16) },
|
rlm@1
|
405 { &WININ, sizeof(u16) },
|
rlm@1
|
406 { &WINOUT, sizeof(u16) },
|
rlm@1
|
407 { &MOSAIC, sizeof(u16) },
|
rlm@1
|
408 { &BLDMOD, sizeof(u16) },
|
rlm@1
|
409 { &COLEV, sizeof(u16) },
|
rlm@1
|
410 { &COLY, sizeof(u16) },
|
rlm@1
|
411 { &DM0SAD_L, sizeof(u16) },
|
rlm@1
|
412 { &DM0SAD_H, sizeof(u16) },
|
rlm@1
|
413 { &DM0DAD_L, sizeof(u16) },
|
rlm@1
|
414 { &DM0DAD_H, sizeof(u16) },
|
rlm@1
|
415 { &DM0CNT_L, sizeof(u16) },
|
rlm@1
|
416 { &DM0CNT_H, sizeof(u16) },
|
rlm@1
|
417 { &DM1SAD_L, sizeof(u16) },
|
rlm@1
|
418 { &DM1SAD_H, sizeof(u16) },
|
rlm@1
|
419 { &DM1DAD_L, sizeof(u16) },
|
rlm@1
|
420 { &DM1DAD_H, sizeof(u16) },
|
rlm@1
|
421 { &DM1CNT_L, sizeof(u16) },
|
rlm@1
|
422 { &DM1CNT_H, sizeof(u16) },
|
rlm@1
|
423 { &DM2SAD_L, sizeof(u16) },
|
rlm@1
|
424 { &DM2SAD_H, sizeof(u16) },
|
rlm@1
|
425 { &DM2DAD_L, sizeof(u16) },
|
rlm@1
|
426 { &DM2DAD_H, sizeof(u16) },
|
rlm@1
|
427 { &DM2CNT_L, sizeof(u16) },
|
rlm@1
|
428 { &DM2CNT_H, sizeof(u16) },
|
rlm@1
|
429 { &DM3SAD_L, sizeof(u16) },
|
rlm@1
|
430 { &DM3SAD_H, sizeof(u16) },
|
rlm@1
|
431 { &DM3DAD_L, sizeof(u16) },
|
rlm@1
|
432 { &DM3DAD_H, sizeof(u16) },
|
rlm@1
|
433 { &DM3CNT_L, sizeof(u16) },
|
rlm@1
|
434 { &DM3CNT_H, sizeof(u16) },
|
rlm@1
|
435 { &TM0D, sizeof(u16) },
|
rlm@1
|
436 { &TM0CNT, sizeof(u16) },
|
rlm@1
|
437 { &TM1D, sizeof(u16) },
|
rlm@1
|
438 { &TM1CNT, sizeof(u16) },
|
rlm@1
|
439 { &TM2D, sizeof(u16) },
|
rlm@1
|
440 { &TM2CNT, sizeof(u16) },
|
rlm@1
|
441 { &TM3D, sizeof(u16) },
|
rlm@1
|
442 { &TM3CNT, sizeof(u16) },
|
rlm@1
|
443 { &P1, sizeof(u16) },
|
rlm@1
|
444 { &IE, sizeof(u16) },
|
rlm@1
|
445 { &IF, sizeof(u16) },
|
rlm@1
|
446 { &IME, sizeof(u16) },
|
rlm@1
|
447 { &holdState, sizeof(bool8) },
|
rlm@1
|
448 { &holdType, sizeof(int32) },
|
rlm@1
|
449 { &lcdTicks, sizeof(int32) },
|
rlm@1
|
450 { &timer0On, sizeof(bool8) },
|
rlm@1
|
451 { &timer0Ticks, sizeof(int32) },
|
rlm@1
|
452 { &timer0Reload, sizeof(int32) },
|
rlm@1
|
453 { &timer0ClockReload, sizeof(int32) },
|
rlm@1
|
454 { &timer1On, sizeof(bool8) },
|
rlm@1
|
455 { &timer1Ticks, sizeof(int32) },
|
rlm@1
|
456 { &timer1Reload, sizeof(int32) },
|
rlm@1
|
457 { &timer1ClockReload, sizeof(int32) },
|
rlm@1
|
458 { &timer2On, sizeof(bool8) },
|
rlm@1
|
459 { &timer2Ticks, sizeof(int32) },
|
rlm@1
|
460 { &timer2Reload, sizeof(int32) },
|
rlm@1
|
461 { &timer2ClockReload, sizeof(int32) },
|
rlm@1
|
462 { &timer3On, sizeof(bool8) },
|
rlm@1
|
463 { &timer3Ticks, sizeof(int32) },
|
rlm@1
|
464 { &timer3Reload, sizeof(int32) },
|
rlm@1
|
465 { &timer3ClockReload, sizeof(int32) },
|
rlm@1
|
466 { &dma0Source, sizeof(u32) },
|
rlm@1
|
467 { &dma0Dest, sizeof(u32) },
|
rlm@1
|
468 { &dma1Source, sizeof(u32) },
|
rlm@1
|
469 { &dma1Dest, sizeof(u32) },
|
rlm@1
|
470 { &dma2Source, sizeof(u32) },
|
rlm@1
|
471 { &dma2Dest, sizeof(u32) },
|
rlm@1
|
472 { &dma3Source, sizeof(u32) },
|
rlm@1
|
473 { &dma3Dest, sizeof(u32) },
|
rlm@1
|
474 { &fxOn, sizeof(bool8) },
|
rlm@1
|
475 { &windowOn, sizeof(bool8) },
|
rlm@1
|
476 { &N_FLAG, sizeof(bool8) },
|
rlm@1
|
477 { &C_FLAG, sizeof(bool8) },
|
rlm@1
|
478 { &Z_FLAG, sizeof(bool8) },
|
rlm@1
|
479 { &V_FLAG, sizeof(bool8) },
|
rlm@1
|
480 { &armState, sizeof(bool8) },
|
rlm@1
|
481 { &armIrqEnable, sizeof(bool8) },
|
rlm@1
|
482 { &armNextPC, sizeof(u32) },
|
rlm@1
|
483 { &armMode, sizeof(int32) },
|
rlm@1
|
484 { &saveType, sizeof(int32) },
|
rlm@1
|
485 { NULL, 0 }
|
rlm@1
|
486 };
|
rlm@1
|
487
|
rlm@1
|
488 //int cpuLoopTicks = 0;
|
rlm@1
|
489 int cpuSavedTicks = 0;
|
rlm@1
|
490
|
rlm@1
|
491 #ifdef PROFILING
|
rlm@1
|
492 void cpuProfil(char *buf, int size, u32 lowPC, int scale)
|
rlm@1
|
493 {
|
rlm@1
|
494 profilBuffer = buf;
|
rlm@1
|
495 profilSize = size;
|
rlm@1
|
496 profilLowPC = lowPC;
|
rlm@1
|
497 profilScale = scale;
|
rlm@1
|
498 }
|
rlm@1
|
499
|
rlm@1
|
500 void cpuEnableProfiling(int hz)
|
rlm@1
|
501 {
|
rlm@1
|
502 if (hz == 0)
|
rlm@1
|
503 hz = 100;
|
rlm@1
|
504 profilingTicks = profilingTicksReload = 16777216 / hz;
|
rlm@1
|
505 profSetHertz(hz);
|
rlm@1
|
506 }
|
rlm@1
|
507
|
rlm@1
|
508 #endif
|
rlm@1
|
509
|
rlm@1
|
510 inline int CPUUpdateTicksAccess32(u32 address)
|
rlm@1
|
511 {
|
rlm@1
|
512 return memoryWait32[(address >> 24) & 15];
|
rlm@1
|
513 }
|
rlm@1
|
514
|
rlm@1
|
515 inline int CPUUpdateTicksAccess16(u32 address)
|
rlm@1
|
516 {
|
rlm@1
|
517 return memoryWait[(address >> 24) & 15];
|
rlm@1
|
518 }
|
rlm@1
|
519
|
rlm@1
|
520 inline int CPUUpdateTicksAccessSeq32(u32 address)
|
rlm@1
|
521 {
|
rlm@1
|
522 return memoryWaitSeq32[(address >> 24) & 15];
|
rlm@1
|
523 }
|
rlm@1
|
524
|
rlm@1
|
525 inline int CPUUpdateTicksAccessSeq16(u32 address)
|
rlm@1
|
526 {
|
rlm@1
|
527 return memoryWaitSeq[(address >> 24) & 15];
|
rlm@1
|
528 }
|
rlm@1
|
529
|
rlm@1
|
530 inline int CPUUpdateTicks()
|
rlm@1
|
531 {
|
rlm@1
|
532 int cpuLoopTicks = lcdTicks;
|
rlm@1
|
533
|
rlm@1
|
534 if (soundTicks < cpuLoopTicks)
|
rlm@1
|
535 cpuLoopTicks = soundTicks;
|
rlm@1
|
536
|
rlm@1
|
537 if (timer0On && !(TM0CNT & 4) && (timer0Ticks < cpuLoopTicks))
|
rlm@1
|
538 {
|
rlm@1
|
539 cpuLoopTicks = timer0Ticks;
|
rlm@1
|
540 }
|
rlm@1
|
541 if (timer1On && !(TM1CNT & 4) && (timer1Ticks < cpuLoopTicks))
|
rlm@1
|
542 {
|
rlm@1
|
543 cpuLoopTicks = timer1Ticks;
|
rlm@1
|
544 }
|
rlm@1
|
545 if (timer2On && !(TM2CNT & 4) && (timer2Ticks < cpuLoopTicks))
|
rlm@1
|
546 {
|
rlm@1
|
547 cpuLoopTicks = timer2Ticks;
|
rlm@1
|
548 }
|
rlm@1
|
549 if (timer3On && !(TM3CNT & 4) && (timer3Ticks < cpuLoopTicks))
|
rlm@1
|
550 {
|
rlm@1
|
551 cpuLoopTicks = timer3Ticks;
|
rlm@1
|
552 }
|
rlm@1
|
553 #ifdef PROFILING
|
rlm@1
|
554 if (profilingTicksReload != 0)
|
rlm@1
|
555 {
|
rlm@1
|
556 if (profilingTicks < cpuLoopTicks)
|
rlm@1
|
557 {
|
rlm@1
|
558 cpuLoopTicks = profilingTicks;
|
rlm@1
|
559 }
|
rlm@1
|
560 }
|
rlm@1
|
561 #endif
|
rlm@1
|
562 cpuSavedTicks = cpuLoopTicks;
|
rlm@1
|
563 return cpuLoopTicks;
|
rlm@1
|
564 }
|
rlm@1
|
565
|
rlm@1
|
566 void CPUUpdateWindow0()
|
rlm@1
|
567 {
|
rlm@1
|
568 int x00 = WIN0H >> 8;
|
rlm@1
|
569 int x01 = WIN0H & 255;
|
rlm@1
|
570
|
rlm@1
|
571 if (x00 <= x01)
|
rlm@1
|
572 {
|
rlm@1
|
573 for (int i = 0; i < 240; i++)
|
rlm@1
|
574 {
|
rlm@1
|
575 gfxInWin0[i] = (i >= x00 && i < x01);
|
rlm@1
|
576 }
|
rlm@1
|
577 }
|
rlm@1
|
578 else
|
rlm@1
|
579 {
|
rlm@1
|
580 for (int i = 0; i < 240; i++)
|
rlm@1
|
581 {
|
rlm@1
|
582 gfxInWin0[i] = (i >= x00 || i < x01);
|
rlm@1
|
583 }
|
rlm@1
|
584 }
|
rlm@1
|
585 }
|
rlm@1
|
586
|
rlm@1
|
587 void CPUUpdateWindow1()
|
rlm@1
|
588 {
|
rlm@1
|
589 int x00 = WIN1H >> 8;
|
rlm@1
|
590 int x01 = WIN1H & 255;
|
rlm@1
|
591
|
rlm@1
|
592 if (x00 <= x01)
|
rlm@1
|
593 {
|
rlm@1
|
594 for (int i = 0; i < 240; i++)
|
rlm@1
|
595 {
|
rlm@1
|
596 gfxInWin1[i] = (i >= x00 && i < x01);
|
rlm@1
|
597 }
|
rlm@1
|
598 }
|
rlm@1
|
599 else
|
rlm@1
|
600 {
|
rlm@1
|
601 for (int i = 0; i < 240; i++)
|
rlm@1
|
602 {
|
rlm@1
|
603 gfxInWin1[i] = (i >= x00 || i < x01);
|
rlm@1
|
604 }
|
rlm@1
|
605 }
|
rlm@1
|
606 }
|
rlm@1
|
607
|
rlm@1
|
608 #define CLEAR_ARRAY(a) \
|
rlm@1
|
609 { \
|
rlm@1
|
610 u32 *array = (a); \
|
rlm@1
|
611 for (int i = 0; i < 240; i++) { \
|
rlm@1
|
612 *array++ = 0x80000000; \
|
rlm@1
|
613 } \
|
rlm@1
|
614 } \
|
rlm@1
|
615
|
rlm@1
|
616 void CPUUpdateRenderBuffers(bool force)
|
rlm@1
|
617 {
|
rlm@1
|
618 if (!(layerEnable & 0x0100) || force)
|
rlm@1
|
619 {
|
rlm@1
|
620 CLEAR_ARRAY(line0);
|
rlm@1
|
621 }
|
rlm@1
|
622 if (!(layerEnable & 0x0200) || force)
|
rlm@1
|
623 {
|
rlm@1
|
624 CLEAR_ARRAY(line1);
|
rlm@1
|
625 }
|
rlm@1
|
626 if (!(layerEnable & 0x0400) || force)
|
rlm@1
|
627 {
|
rlm@1
|
628 CLEAR_ARRAY(line2);
|
rlm@1
|
629 }
|
rlm@1
|
630 if (!(layerEnable & 0x0800) || force)
|
rlm@1
|
631 {
|
rlm@1
|
632 CLEAR_ARRAY(line3);
|
rlm@1
|
633 }
|
rlm@1
|
634 }
|
rlm@1
|
635
|
rlm@1
|
636 bool CPUWriteStateToStream(gzFile gzFile)
|
rlm@1
|
637 {
|
rlm@1
|
638 utilWriteInt(gzFile, SAVE_GAME_VERSION);
|
rlm@1
|
639
|
rlm@1
|
640 utilGzWrite(gzFile, &rom[0xa0], 16);
|
rlm@1
|
641
|
rlm@1
|
642 utilWriteInt(gzFile, useBios);
|
rlm@1
|
643
|
rlm@1
|
644 utilGzWrite(gzFile, ®[0], sizeof(reg));
|
rlm@1
|
645
|
rlm@1
|
646 utilWriteData(gzFile, saveGameStruct);
|
rlm@1
|
647
|
rlm@1
|
648 // new to version 0.7.1
|
rlm@1
|
649 utilWriteInt(gzFile, stopState);
|
rlm@1
|
650 // new to version 0.8
|
rlm@1
|
651 utilWriteInt(gzFile, intState);
|
rlm@1
|
652
|
rlm@1
|
653 utilGzWrite(gzFile, internalRAM, 0x8000);
|
rlm@1
|
654 utilGzWrite(gzFile, paletteRAM, 0x400);
|
rlm@1
|
655 utilGzWrite(gzFile, workRAM, 0x40000);
|
rlm@1
|
656 utilGzWrite(gzFile, vram, 0x20000);
|
rlm@1
|
657 utilGzWrite(gzFile, oam, 0x400);
|
rlm@1
|
658 utilGzWrite(gzFile, pix, 4 * 241 * 162);
|
rlm@1
|
659 utilGzWrite(gzFile, ioMem, 0x400);
|
rlm@1
|
660
|
rlm@1
|
661 eepromSaveGame(gzFile);
|
rlm@1
|
662 flashSaveGame(gzFile);
|
rlm@1
|
663 soundSaveGame(gzFile);
|
rlm@1
|
664
|
rlm@1
|
665 cheatsSaveGame(gzFile);
|
rlm@1
|
666
|
rlm@1
|
667 // version 1.5
|
rlm@1
|
668 rtcSaveGame(gzFile);
|
rlm@1
|
669
|
rlm@1
|
670 // SAVE_GAME_VERSION_9 (new to re-recording version which is based on 1.72)
|
rlm@1
|
671 {
|
rlm@1
|
672 extern int32 sensorX, sensorY; // from SDL.cpp
|
rlm@1
|
673 utilGzWrite(gzFile, &sensorX, sizeof(sensorX));
|
rlm@1
|
674 utilGzWrite(gzFile, &sensorY, sizeof(sensorY));
|
rlm@1
|
675 bool8 movieActive = VBAMovieActive();
|
rlm@1
|
676 utilGzWrite(gzFile, &movieActive, sizeof(movieActive));
|
rlm@1
|
677 if (movieActive)
|
rlm@1
|
678 {
|
rlm@1
|
679 uint8 *movie_freeze_buf = NULL;
|
rlm@1
|
680 uint32 movie_freeze_size = 0;
|
rlm@1
|
681
|
rlm@1
|
682 VBAMovieFreeze(&movie_freeze_buf, &movie_freeze_size);
|
rlm@1
|
683 if (movie_freeze_buf)
|
rlm@1
|
684 {
|
rlm@1
|
685 utilGzWrite(gzFile, &movie_freeze_size, sizeof(movie_freeze_size));
|
rlm@1
|
686 utilGzWrite(gzFile, movie_freeze_buf, movie_freeze_size);
|
rlm@1
|
687 delete [] movie_freeze_buf;
|
rlm@1
|
688 }
|
rlm@1
|
689 else
|
rlm@1
|
690 {
|
rlm@1
|
691 systemMessage(0, N_("Failed to save movie snapshot."));
|
rlm@1
|
692 return false;
|
rlm@1
|
693 }
|
rlm@1
|
694 }
|
rlm@1
|
695 utilGzWrite(gzFile, &GBASystemCounters.frameCount, sizeof(GBASystemCounters.frameCount));
|
rlm@1
|
696 }
|
rlm@1
|
697
|
rlm@1
|
698 // SAVE_GAME_VERSION_10
|
rlm@1
|
699 {
|
rlm@1
|
700 utilGzWrite(gzFile, memoryWait, 16 * sizeof(int32));
|
rlm@1
|
701 utilGzWrite(gzFile, memoryWait32, 16 * sizeof(int32));
|
rlm@1
|
702 utilGzWrite(gzFile, memoryWaitSeq, 16 * sizeof(int32));
|
rlm@1
|
703 utilGzWrite(gzFile, memoryWaitSeq32, 16 * sizeof(int32));
|
rlm@1
|
704 utilGzWrite(gzFile, memoryWaitFetch, 16 * sizeof(int32));
|
rlm@1
|
705 utilGzWrite(gzFile, memoryWaitFetch32, 16 * sizeof(int32));
|
rlm@1
|
706 }
|
rlm@1
|
707
|
rlm@1
|
708 // SAVE_GAME_VERSION_11
|
rlm@1
|
709 {
|
rlm@1
|
710 utilGzWrite(gzFile, &prefetchActive, sizeof(bool8));
|
rlm@1
|
711 utilGzWrite(gzFile, &prefetchPrevActive, sizeof(bool8));
|
rlm@1
|
712 utilGzWrite(gzFile, &prefetchApplies, sizeof(bool8));
|
rlm@1
|
713 }
|
rlm@1
|
714
|
rlm@1
|
715 // SAVE_GAME_VERSION_12
|
rlm@1
|
716 {
|
rlm@1
|
717 utilGzWrite(gzFile, &memLagTempEnabled, sizeof(bool8)); // necessary
|
rlm@1
|
718 utilGzWrite(gzFile, &speedHack, sizeof(bool8)); // just in case it's ever used...
|
rlm@1
|
719 }
|
rlm@1
|
720
|
rlm@1
|
721 // SAVE_GAME_VERSION_13
|
rlm@1
|
722 {
|
rlm@1
|
723 utilGzWrite(gzFile, &GBASystemCounters.lagCount, sizeof(GBASystemCounters.lagCount));
|
rlm@1
|
724 utilGzWrite(gzFile, &GBASystemCounters.lagged, sizeof(GBASystemCounters.lagged));
|
rlm@1
|
725 utilGzWrite(gzFile, &GBASystemCounters.laggedLast, sizeof(GBASystemCounters.laggedLast));
|
rlm@1
|
726 }
|
rlm@1
|
727
|
rlm@1
|
728 return true;
|
rlm@1
|
729 }
|
rlm@1
|
730
|
rlm@1
|
731 bool CPUWriteState(const char *file)
|
rlm@1
|
732 {
|
rlm@1
|
733 gzFile gzFile = utilGzOpen(file, "wb");
|
rlm@1
|
734
|
rlm@1
|
735 if (gzFile == NULL)
|
rlm@1
|
736 {
|
rlm@1
|
737 systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), file);
|
rlm@1
|
738 return false;
|
rlm@1
|
739 }
|
rlm@1
|
740
|
rlm@1
|
741 bool res = CPUWriteStateToStream(gzFile);
|
rlm@1
|
742
|
rlm@1
|
743 utilGzClose(gzFile);
|
rlm@1
|
744
|
rlm@1
|
745 return res;
|
rlm@1
|
746 }
|
rlm@1
|
747
|
rlm@1
|
748 bool CPUWriteMemState(char *memory, int available)
|
rlm@1
|
749 {
|
rlm@1
|
750 gzFile gzFile = utilMemGzOpen(memory, available, "w");
|
rlm@1
|
751
|
rlm@1
|
752 if (gzFile == NULL)
|
rlm@1
|
753 {
|
rlm@1
|
754 return false;
|
rlm@1
|
755 }
|
rlm@1
|
756
|
rlm@1
|
757 bool res = CPUWriteStateToStream(gzFile);
|
rlm@1
|
758
|
rlm@1
|
759 long pos = utilGzTell(gzFile) + 8;
|
rlm@1
|
760
|
rlm@1
|
761 if (pos >= (available))
|
rlm@1
|
762 res = false;
|
rlm@1
|
763
|
rlm@1
|
764 utilGzClose(gzFile);
|
rlm@1
|
765
|
rlm@1
|
766 return res;
|
rlm@1
|
767 }
|
rlm@1
|
768
|
rlm@1
|
769 static int tempStateID = 0;
|
rlm@1
|
770 static int tempFailCount = 0;
|
rlm@1
|
771 static bool backupSafe = true;
|
rlm@1
|
772
|
rlm@1
|
773 bool CPUReadStateFromStream(gzFile gzFile)
|
rlm@1
|
774 {
|
rlm@1
|
775 bool8 ub;
|
rlm@1
|
776 char tempBackupName [128];
|
rlm@1
|
777 if (backupSafe)
|
rlm@1
|
778 {
|
rlm@1
|
779 sprintf(tempBackupName, "gbatempsave%d.sav", tempStateID++);
|
rlm@1
|
780 CPUWriteState(tempBackupName);
|
rlm@1
|
781 }
|
rlm@1
|
782
|
rlm@1
|
783 int version = utilReadInt(gzFile);
|
rlm@1
|
784
|
rlm@1
|
785 if (version > SAVE_GAME_VERSION || version < SAVE_GAME_VERSION_1)
|
rlm@1
|
786 {
|
rlm@1
|
787 systemMessage(MSG_UNSUPPORTED_VBA_SGM,
|
rlm@1
|
788 N_("Unsupported VisualBoyAdvance save game version %d"),
|
rlm@1
|
789 version);
|
rlm@1
|
790 goto failedLoad;
|
rlm@1
|
791 }
|
rlm@1
|
792
|
rlm@1
|
793 u8 romname[17];
|
rlm@1
|
794
|
rlm@1
|
795 utilGzRead(gzFile, romname, 16);
|
rlm@1
|
796
|
rlm@1
|
797 if (memcmp(&rom[0xa0], romname, 16) != 0)
|
rlm@1
|
798 {
|
rlm@1
|
799 romname[16] = 0;
|
rlm@1
|
800 for (int i = 0; i < 16; i++)
|
rlm@1
|
801 if (romname[i] < 32)
|
rlm@1
|
802 romname[i] = 32;
|
rlm@1
|
803 systemMessage(MSG_CANNOT_LOAD_SGM, N_("Cannot load save game for %s"), romname);
|
rlm@1
|
804 goto failedLoad;
|
rlm@1
|
805 }
|
rlm@1
|
806
|
rlm@1
|
807 ub = utilReadInt(gzFile) ? true : false;
|
rlm@1
|
808
|
rlm@1
|
809 if (ub != useBios)
|
rlm@1
|
810 {
|
rlm@1
|
811 if (useBios)
|
rlm@1
|
812 systemMessage(MSG_SAVE_GAME_NOT_USING_BIOS,
|
rlm@1
|
813 N_("Save game is not using the BIOS files"));
|
rlm@1
|
814 else
|
rlm@1
|
815 systemMessage(MSG_SAVE_GAME_USING_BIOS,
|
rlm@1
|
816 N_("Save game is using the BIOS file"));
|
rlm@1
|
817 goto failedLoad;
|
rlm@1
|
818 }
|
rlm@1
|
819
|
rlm@1
|
820 utilGzRead(gzFile, ®[0], sizeof(reg));
|
rlm@1
|
821
|
rlm@1
|
822 utilReadData(gzFile, saveGameStruct);
|
rlm@1
|
823
|
rlm@1
|
824 if (version < SAVE_GAME_VERSION_3)
|
rlm@1
|
825 stopState = false;
|
rlm@1
|
826 else
|
rlm@1
|
827 stopState = utilReadInt(gzFile) ? true : false;
|
rlm@1
|
828
|
rlm@1
|
829 if (version < SAVE_GAME_VERSION_4)
|
rlm@1
|
830 intState = false;
|
rlm@1
|
831 else
|
rlm@1
|
832 intState = utilReadInt(gzFile) ? true : false;
|
rlm@1
|
833
|
rlm@1
|
834 utilGzRead(gzFile, internalRAM, 0x8000);
|
rlm@1
|
835 utilGzRead(gzFile, paletteRAM, 0x400);
|
rlm@1
|
836 utilGzRead(gzFile, workRAM, 0x40000);
|
rlm@1
|
837 utilGzRead(gzFile, vram, 0x20000);
|
rlm@1
|
838 utilGzRead(gzFile, oam, 0x400);
|
rlm@1
|
839 if (version < SAVE_GAME_VERSION_6)
|
rlm@1
|
840 utilGzRead(gzFile, pix, 4 * 240 * 160);
|
rlm@1
|
841 else
|
rlm@1
|
842 utilGzRead(gzFile, pix, 4 * 241 * 162);
|
rlm@1
|
843 utilGzRead(gzFile, ioMem, 0x400);
|
rlm@1
|
844
|
rlm@1
|
845 eepromReadGame(gzFile, version);
|
rlm@1
|
846 flashReadGame(gzFile, version);
|
rlm@1
|
847 soundReadGame(gzFile, version);
|
rlm@1
|
848
|
rlm@1
|
849 if (version > SAVE_GAME_VERSION_1)
|
rlm@1
|
850 {
|
rlm@1
|
851 cheatsReadGame(gzFile);
|
rlm@1
|
852 }
|
rlm@1
|
853 if (version > SAVE_GAME_VERSION_6)
|
rlm@1
|
854 {
|
rlm@1
|
855 rtcReadGame(gzFile);
|
rlm@1
|
856 }
|
rlm@1
|
857
|
rlm@1
|
858 if (version <= SAVE_GAME_VERSION_7)
|
rlm@1
|
859 {
|
rlm@1
|
860 u32 temp;
|
rlm@1
|
861 #define SWAP(a, b, c) \
|
rlm@1
|
862 temp = (a); \
|
rlm@1
|
863 (a) = (b) << 16 | (c); \
|
rlm@1
|
864 (b) = (temp) >> 16; \
|
rlm@1
|
865 (c) = (temp) & 0xFFFF;
|
rlm@1
|
866
|
rlm@1
|
867 SWAP(dma0Source, DM0SAD_H, DM0SAD_L);
|
rlm@1
|
868 SWAP(dma0Dest, DM0DAD_H, DM0DAD_L);
|
rlm@1
|
869 SWAP(dma1Source, DM1SAD_H, DM1SAD_L);
|
rlm@1
|
870 SWAP(dma1Dest, DM1DAD_H, DM1DAD_L);
|
rlm@1
|
871 SWAP(dma2Source, DM2SAD_H, DM2SAD_L);
|
rlm@1
|
872 SWAP(dma2Dest, DM2DAD_H, DM2DAD_L);
|
rlm@1
|
873 SWAP(dma3Source, DM3SAD_H, DM3SAD_L);
|
rlm@1
|
874 SWAP(dma3Dest, DM3DAD_H, DM3DAD_L);
|
rlm@1
|
875 }
|
rlm@1
|
876
|
rlm@1
|
877 // set pointers!
|
rlm@1
|
878 layerEnable = layerSettings & DISPCNT;
|
rlm@1
|
879
|
rlm@1
|
880 CPUUpdateRender();
|
rlm@1
|
881 CPUUpdateRenderBuffers(true);
|
rlm@1
|
882 CPUUpdateWindow0();
|
rlm@1
|
883 CPUUpdateWindow1();
|
rlm@1
|
884 gbaSaveType = 0;
|
rlm@1
|
885 switch (saveType)
|
rlm@1
|
886 {
|
rlm@1
|
887 case 0:
|
rlm@1
|
888 cpuSaveGameFunc = flashSaveDecide;
|
rlm@1
|
889 break;
|
rlm@1
|
890 case 1:
|
rlm@1
|
891 cpuSaveGameFunc = sramWrite;
|
rlm@1
|
892 gbaSaveType = 1;
|
rlm@1
|
893 break;
|
rlm@1
|
894 case 2:
|
rlm@1
|
895 cpuSaveGameFunc = flashWrite;
|
rlm@1
|
896 gbaSaveType = 2;
|
rlm@1
|
897 break;
|
rlm@1
|
898 default:
|
rlm@1
|
899 systemMessage(MSG_UNSUPPORTED_SAVE_TYPE,
|
rlm@1
|
900 N_("Unsupported save type %d"), saveType);
|
rlm@1
|
901 break;
|
rlm@1
|
902 }
|
rlm@1
|
903 if (eepromInUse)
|
rlm@1
|
904 gbaSaveType = 3;
|
rlm@1
|
905
|
rlm@1
|
906 systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
|
rlm@1
|
907
|
rlm@1
|
908 if (version >= SAVE_GAME_VERSION_9) // new to re-recording version:
|
rlm@1
|
909 {
|
rlm@1
|
910 extern int32 sensorX, sensorY; // from SDL.cpp
|
rlm@1
|
911 utilGzRead(gzFile, &sensorX, sizeof(sensorX));
|
rlm@1
|
912 utilGzRead(gzFile, &sensorY, sizeof(sensorY));
|
rlm@1
|
913
|
rlm@1
|
914 bool8 movieSnapshot;
|
rlm@1
|
915 utilGzRead(gzFile, &movieSnapshot, sizeof(movieSnapshot));
|
rlm@1
|
916 if (VBAMovieActive() && !movieSnapshot)
|
rlm@1
|
917 {
|
rlm@1
|
918 systemMessage(0, N_("Can't load a non-movie snapshot while a movie is active."));
|
rlm@1
|
919 goto failedLoad;
|
rlm@1
|
920 }
|
rlm@1
|
921
|
rlm@1
|
922 if (movieSnapshot) // even if a movie isn't active we still want to parse through this in case other stuff is added
|
rlm@1
|
923 // later on in the save format
|
rlm@1
|
924 {
|
rlm@1
|
925 uint32 movieInputDataSize = 0;
|
rlm@1
|
926 utilGzRead(gzFile, &movieInputDataSize, sizeof(movieInputDataSize));
|
rlm@1
|
927 uint8 *local_movie_data = new uint8[movieInputDataSize];
|
rlm@1
|
928 int readBytes = utilGzRead(gzFile, local_movie_data, movieInputDataSize);
|
rlm@1
|
929 if (readBytes != movieInputDataSize)
|
rlm@1
|
930 {
|
rlm@1
|
931 systemMessage(0, N_("Corrupt movie snapshot."));
|
rlm@1
|
932 if (local_movie_data)
|
rlm@1
|
933 delete [] local_movie_data;
|
rlm@1
|
934 goto failedLoad;
|
rlm@1
|
935 }
|
rlm@1
|
936 int code = VBAMovieUnfreeze(local_movie_data, movieInputDataSize);
|
rlm@1
|
937 if (local_movie_data)
|
rlm@1
|
938 delete [] local_movie_data;
|
rlm@1
|
939 if (code != MOVIE_SUCCESS && VBAMovieActive())
|
rlm@1
|
940 {
|
rlm@1
|
941 char errStr [1024];
|
rlm@1
|
942 strcpy(errStr, "Failed to load movie snapshot");
|
rlm@1
|
943 switch (code)
|
rlm@1
|
944 {
|
rlm@1
|
945 case MOVIE_NOT_FROM_THIS_MOVIE:
|
rlm@1
|
946 strcat(errStr, ";\nSnapshot not from this movie"); break;
|
rlm@1
|
947 case MOVIE_NOT_FROM_A_MOVIE:
|
rlm@1
|
948 strcat(errStr, ";\nNot a movie snapshot"); break; // shouldn't get here...
|
rlm@1
|
949 case MOVIE_SNAPSHOT_INCONSISTENT:
|
rlm@1
|
950 strcat(errStr, ";\nSnapshot inconsistent with movie"); break;
|
rlm@1
|
951 case MOVIE_WRONG_FORMAT:
|
rlm@1
|
952 strcat(errStr, ";\nWrong format"); break;
|
rlm@1
|
953 }
|
rlm@1
|
954 strcat(errStr, ".");
|
rlm@1
|
955 systemMessage(0, N_(errStr));
|
rlm@1
|
956 goto failedLoad;
|
rlm@1
|
957 }
|
rlm@1
|
958 }
|
rlm@1
|
959 utilGzRead(gzFile, &GBASystemCounters.frameCount, sizeof(GBASystemCounters.frameCount));
|
rlm@1
|
960 }
|
rlm@1
|
961 if (version >= SAVE_GAME_VERSION_10)
|
rlm@1
|
962 {
|
rlm@1
|
963 utilGzRead(gzFile, memoryWait, 16 * sizeof(int32));
|
rlm@1
|
964 utilGzRead(gzFile, memoryWait32, 16 * sizeof(int32));
|
rlm@1
|
965 utilGzRead(gzFile, memoryWaitSeq, 16 * sizeof(int32));
|
rlm@1
|
966 utilGzRead(gzFile, memoryWaitSeq32, 16 * sizeof(int32));
|
rlm@1
|
967 utilGzRead(gzFile, memoryWaitFetch, 16 * sizeof(int32));
|
rlm@1
|
968 utilGzRead(gzFile, memoryWaitFetch32, 16 * sizeof(int32));
|
rlm@1
|
969 }
|
rlm@1
|
970 if (version >= SAVE_GAME_VERSION_11)
|
rlm@1
|
971 {
|
rlm@1
|
972 utilGzRead(gzFile, &prefetchActive, sizeof(bool8));
|
rlm@1
|
973 //if(prefetchActive && !prefetchPrevActive) systemScreenMessage("pre-fetch enabled",3,600);
|
rlm@1
|
974 //if(!prefetchActive && prefetchPrevActive) systemScreenMessage("pre-fetch disabled",3,600);
|
rlm@1
|
975 utilGzRead(gzFile, &prefetchPrevActive, sizeof(bool8));
|
rlm@1
|
976 utilGzRead(gzFile, &prefetchApplies, sizeof(bool8));
|
rlm@1
|
977 }
|
rlm@1
|
978 if (version >= SAVE_GAME_VERSION_12)
|
rlm@1
|
979 {
|
rlm@1
|
980 utilGzRead(gzFile, &memLagTempEnabled, sizeof(bool8)); // necessary
|
rlm@1
|
981 utilGzRead(gzFile, &speedHack, sizeof(bool8)); // just in case it's ever used...
|
rlm@1
|
982 }
|
rlm@1
|
983 if (version >= SAVE_GAME_VERSION_13)
|
rlm@1
|
984 {
|
rlm@1
|
985 utilGzRead(gzFile, &GBASystemCounters.lagCount, sizeof(GBASystemCounters.lagCount));
|
rlm@1
|
986 utilGzRead(gzFile, &GBASystemCounters.lagged, sizeof(GBASystemCounters.lagged));
|
rlm@1
|
987 utilGzRead(gzFile, &GBASystemCounters.laggedLast, sizeof(GBASystemCounters.laggedLast));
|
rlm@1
|
988 }
|
rlm@1
|
989
|
rlm@1
|
990 if (backupSafe)
|
rlm@1
|
991 {
|
rlm@1
|
992 remove(tempBackupName);
|
rlm@1
|
993 tempFailCount = 0;
|
rlm@1
|
994 }
|
rlm@1
|
995 systemSetJoypad(0, ~P1 & 0x3FF);
|
rlm@1
|
996 VBAUpdateButtonPressDisplay();
|
rlm@1
|
997 VBAUpdateFrameCountDisplay();
|
rlm@1
|
998 systemRefreshScreen();
|
rlm@1
|
999 return true;
|
rlm@1
|
1000
|
rlm@1
|
1001 failedLoad:
|
rlm@1
|
1002 if (backupSafe)
|
rlm@1
|
1003 {
|
rlm@1
|
1004 tempFailCount++;
|
rlm@1
|
1005 if (tempFailCount < 3) // fail no more than 2 times in a row
|
rlm@1
|
1006 CPUReadState(tempBackupName);
|
rlm@1
|
1007 remove(tempBackupName);
|
rlm@1
|
1008 }
|
rlm@1
|
1009 return false;
|
rlm@1
|
1010 }
|
rlm@1
|
1011
|
rlm@1
|
1012 bool CPUReadMemState(char *memory, int available)
|
rlm@1
|
1013 {
|
rlm@1
|
1014 gzFile gzFile = utilMemGzOpen(memory, available, "r");
|
rlm@1
|
1015
|
rlm@1
|
1016 backupSafe = false;
|
rlm@1
|
1017 bool res = CPUReadStateFromStream(gzFile);
|
rlm@1
|
1018 backupSafe = true;
|
rlm@1
|
1019
|
rlm@1
|
1020 utilGzClose(gzFile);
|
rlm@1
|
1021
|
rlm@1
|
1022 return res;
|
rlm@1
|
1023 }
|
rlm@1
|
1024
|
rlm@1
|
1025 bool CPUReadState(const char *file)
|
rlm@1
|
1026 {
|
rlm@1
|
1027 gzFile gzFile = utilGzOpen(file, "rb");
|
rlm@1
|
1028
|
rlm@1
|
1029 if (gzFile == NULL)
|
rlm@1
|
1030 return false;
|
rlm@1
|
1031
|
rlm@1
|
1032 bool res = CPUReadStateFromStream(gzFile);
|
rlm@1
|
1033
|
rlm@1
|
1034 utilGzClose(gzFile);
|
rlm@1
|
1035
|
rlm@1
|
1036 return res;
|
rlm@1
|
1037 }
|
rlm@1
|
1038
|
rlm@1
|
1039 bool CPUExportEepromFile(const char *fileName)
|
rlm@1
|
1040 {
|
rlm@1
|
1041 if (eepromInUse)
|
rlm@1
|
1042 {
|
rlm@1
|
1043 FILE *file = fopen(fileName, "wb");
|
rlm@1
|
1044
|
rlm@1
|
1045 if (!file)
|
rlm@1
|
1046 {
|
rlm@1
|
1047 systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"),
|
rlm@1
|
1048 fileName);
|
rlm@1
|
1049 return false;
|
rlm@1
|
1050 }
|
rlm@1
|
1051
|
rlm@1
|
1052 for (int i = 0; i < eepromSize; )
|
rlm@1
|
1053 {
|
rlm@1
|
1054 for (int j = 0; j < 8; j++)
|
rlm@1
|
1055 {
|
rlm@1
|
1056 if (fwrite(&eepromData[i + 7 - j], 1, 1, file) != 1)
|
rlm@1
|
1057 {
|
rlm@1
|
1058 fclose(file);
|
rlm@1
|
1059 return false;
|
rlm@1
|
1060 }
|
rlm@1
|
1061 }
|
rlm@1
|
1062 i += 8;
|
rlm@1
|
1063 }
|
rlm@1
|
1064 fclose(file);
|
rlm@1
|
1065 }
|
rlm@1
|
1066 return true;
|
rlm@1
|
1067 }
|
rlm@1
|
1068
|
rlm@1
|
1069 bool CPUWriteBatteryToStream(gzFile gzFile)
|
rlm@1
|
1070 {
|
rlm@1
|
1071 if (!gzFile)
|
rlm@1
|
1072 return false;
|
rlm@1
|
1073
|
rlm@1
|
1074 utilWriteInt(gzFile, SAVE_GAME_VERSION);
|
rlm@1
|
1075
|
rlm@1
|
1076 // for simplicity, we put both types of battery files should be in the stream, even if one's empty
|
rlm@1
|
1077 eepromSaveGame(gzFile);
|
rlm@1
|
1078 flashSaveGame(gzFile);
|
rlm@1
|
1079
|
rlm@1
|
1080 return true;
|
rlm@1
|
1081 }
|
rlm@1
|
1082
|
rlm@1
|
1083 bool CPUWriteBatteryFile(const char *fileName)
|
rlm@1
|
1084 {
|
rlm@1
|
1085 if (gbaSaveType == 0)
|
rlm@1
|
1086 {
|
rlm@1
|
1087 if (eepromInUse)
|
rlm@1
|
1088 gbaSaveType = 3;
|
rlm@1
|
1089 else
|
rlm@1
|
1090 switch (saveType)
|
rlm@1
|
1091 {
|
rlm@1
|
1092 case 1:
|
rlm@1
|
1093 gbaSaveType = 1;
|
rlm@1
|
1094 break;
|
rlm@1
|
1095 case 2:
|
rlm@1
|
1096 gbaSaveType = 2;
|
rlm@1
|
1097 break;
|
rlm@1
|
1098 }
|
rlm@1
|
1099 }
|
rlm@1
|
1100
|
rlm@1
|
1101 if (gbaSaveType)
|
rlm@1
|
1102 {
|
rlm@1
|
1103 FILE *file = fopen(fileName, "wb");
|
rlm@1
|
1104
|
rlm@1
|
1105 if (!file)
|
rlm@1
|
1106 {
|
rlm@1
|
1107 systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"),
|
rlm@1
|
1108 fileName);
|
rlm@1
|
1109 return false;
|
rlm@1
|
1110 }
|
rlm@1
|
1111
|
rlm@1
|
1112 // only save if Flash/Sram in use or EEprom in use
|
rlm@1
|
1113 if (gbaSaveType != 3)
|
rlm@1
|
1114 {
|
rlm@1
|
1115 if (gbaSaveType == 2)
|
rlm@1
|
1116 {
|
rlm@1
|
1117 if (fwrite(flashSaveMemory, 1, flashSize, file) != (size_t)flashSize)
|
rlm@1
|
1118 {
|
rlm@1
|
1119 fclose(file);
|
rlm@1
|
1120 return false;
|
rlm@1
|
1121 }
|
rlm@1
|
1122 }
|
rlm@1
|
1123 else
|
rlm@1
|
1124 {
|
rlm@1
|
1125 if (fwrite(flashSaveMemory, 1, 0x10000, file) != 0x10000)
|
rlm@1
|
1126 {
|
rlm@1
|
1127 fclose(file);
|
rlm@1
|
1128 return false;
|
rlm@1
|
1129 }
|
rlm@1
|
1130 }
|
rlm@1
|
1131 }
|
rlm@1
|
1132 else
|
rlm@1
|
1133 {
|
rlm@1
|
1134 if (fwrite(eepromData, 1, eepromSize, file) != (size_t)eepromSize)
|
rlm@1
|
1135 {
|
rlm@1
|
1136 fclose(file);
|
rlm@1
|
1137 return false;
|
rlm@1
|
1138 }
|
rlm@1
|
1139 }
|
rlm@1
|
1140 fclose(file);
|
rlm@1
|
1141 }
|
rlm@1
|
1142
|
rlm@1
|
1143 return true;
|
rlm@1
|
1144 }
|
rlm@1
|
1145
|
rlm@1
|
1146 bool CPUReadGSASnapshot(const char *fileName)
|
rlm@1
|
1147 {
|
rlm@1
|
1148 int i;
|
rlm@1
|
1149 FILE *file = fopen(fileName, "rb");
|
rlm@1
|
1150
|
rlm@1
|
1151 if (!file)
|
rlm@1
|
1152 {
|
rlm@1
|
1153 systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName);
|
rlm@1
|
1154 return false;
|
rlm@1
|
1155 }
|
rlm@1
|
1156
|
rlm@1
|
1157 // check file size to know what we should read
|
rlm@1
|
1158 fseek(file, 0, SEEK_END);
|
rlm@1
|
1159
|
rlm@1
|
1160 // long size = ftell(file);
|
rlm@1
|
1161 fseek(file, 0x0, SEEK_SET);
|
rlm@1
|
1162 fread(&i, 1, 4, file);
|
rlm@1
|
1163 fseek(file, i, SEEK_CUR); // Skip SharkPortSave
|
rlm@1
|
1164 fseek(file, 4, SEEK_CUR); // skip some sort of flag
|
rlm@1
|
1165 fread(&i, 1, 4, file); // name length
|
rlm@1
|
1166 fseek(file, i, SEEK_CUR); // skip name
|
rlm@1
|
1167 fread(&i, 1, 4, file); // desc length
|
rlm@1
|
1168 fseek(file, i, SEEK_CUR); // skip desc
|
rlm@1
|
1169 fread(&i, 1, 4, file); // notes length
|
rlm@1
|
1170 fseek(file, i, SEEK_CUR); // skip notes
|
rlm@1
|
1171 int saveSize;
|
rlm@1
|
1172 fread(&saveSize, 1, 4, file); // read length
|
rlm@1
|
1173 saveSize -= 0x1c; // remove header size
|
rlm@1
|
1174 char buffer[17];
|
rlm@1
|
1175 char buffer2[17];
|
rlm@1
|
1176 fread(buffer, 1, 16, file);
|
rlm@1
|
1177 buffer[16] = 0;
|
rlm@1
|
1178 for (i = 0; i < 16; i++)
|
rlm@1
|
1179 if (buffer[i] < 32)
|
rlm@1
|
1180 buffer[i] = 32;
|
rlm@1
|
1181 memcpy(buffer2, &rom[0xa0], 16);
|
rlm@1
|
1182 buffer2[16] = 0;
|
rlm@1
|
1183 for (i = 0; i < 16; i++)
|
rlm@1
|
1184 if (buffer2[i] < 32)
|
rlm@1
|
1185 buffer2[i] = 32;
|
rlm@1
|
1186 if (memcmp(buffer, buffer2, 16))
|
rlm@1
|
1187 {
|
rlm@1
|
1188 systemMessage(MSG_CANNOT_IMPORT_SNAPSHOT_FOR,
|
rlm@1
|
1189 N_("Cannot import snapshot for %s. Current game is %s"),
|
rlm@1
|
1190 buffer,
|
rlm@1
|
1191 buffer2);
|
rlm@1
|
1192 fclose(file);
|
rlm@1
|
1193 return false;
|
rlm@1
|
1194 }
|
rlm@1
|
1195 fseek(file, 12, SEEK_CUR); // skip some flags
|
rlm@1
|
1196 if (saveSize >= 65536)
|
rlm@1
|
1197 {
|
rlm@1
|
1198 if (fread(flashSaveMemory, 1, saveSize, file) != (size_t)saveSize)
|
rlm@1
|
1199 {
|
rlm@1
|
1200 fclose(file);
|
rlm@1
|
1201 return false;
|
rlm@1
|
1202 }
|
rlm@1
|
1203 }
|
rlm@1
|
1204 else
|
rlm@1
|
1205 {
|
rlm@1
|
1206 systemMessage(MSG_UNSUPPORTED_SNAPSHOT_FILE,
|
rlm@1
|
1207 N_("Unsupported snapshot file %s"),
|
rlm@1
|
1208 fileName);
|
rlm@1
|
1209 fclose(file);
|
rlm@1
|
1210 return false;
|
rlm@1
|
1211 }
|
rlm@1
|
1212 fclose(file);
|
rlm@1
|
1213 CPUReset();
|
rlm@1
|
1214 return true;
|
rlm@1
|
1215 }
|
rlm@1
|
1216
|
rlm@1
|
1217 bool CPUWriteGSASnapshot(const char *fileName,
|
rlm@1
|
1218 const char *title,
|
rlm@1
|
1219 const char *desc,
|
rlm@1
|
1220 const char *notes)
|
rlm@1
|
1221 {
|
rlm@1
|
1222 FILE *file = fopen(fileName, "wb");
|
rlm@1
|
1223
|
rlm@1
|
1224 if (!file)
|
rlm@1
|
1225 {
|
rlm@1
|
1226 systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName);
|
rlm@1
|
1227 return false;
|
rlm@1
|
1228 }
|
rlm@1
|
1229
|
rlm@1
|
1230 u8 buffer[17];
|
rlm@1
|
1231
|
rlm@1
|
1232 utilPutDword(buffer, 0x0d); // SharkPortSave length
|
rlm@1
|
1233 fwrite(buffer, 1, 4, file);
|
rlm@1
|
1234 fwrite("SharkPortSave", 1, 0x0d, file);
|
rlm@1
|
1235 utilPutDword(buffer, 0x000f0000);
|
rlm@1
|
1236 fwrite(buffer, 1, 4, file); // save type 0x000f0000 = GBA save
|
rlm@1
|
1237 utilPutDword(buffer, strlen(title));
|
rlm@1
|
1238 fwrite(buffer, 1, 4, file); // title length
|
rlm@1
|
1239 fwrite(title, 1, strlen(title), file);
|
rlm@1
|
1240 utilPutDword(buffer, strlen(desc));
|
rlm@1
|
1241 fwrite(buffer, 1, 4, file); // desc length
|
rlm@1
|
1242 fwrite(desc, 1, strlen(desc), file);
|
rlm@1
|
1243 utilPutDword(buffer, strlen(notes));
|
rlm@1
|
1244 fwrite(buffer, 1, 4, file); // notes length
|
rlm@1
|
1245 fwrite(notes, 1, strlen(notes), file);
|
rlm@1
|
1246 int saveSize = 0x10000;
|
rlm@1
|
1247 if (gbaSaveType == 2)
|
rlm@1
|
1248 saveSize = flashSize;
|
rlm@1
|
1249 int totalSize = saveSize + 0x1c;
|
rlm@1
|
1250
|
rlm@1
|
1251 utilPutDword(buffer, totalSize); // length of remainder of save - CRC
|
rlm@1
|
1252 fwrite(buffer, 1, 4, file);
|
rlm@1
|
1253
|
rlm@1
|
1254 char temp[0x2001c];
|
rlm@1
|
1255 memset(temp, 0, 28);
|
rlm@1
|
1256 memcpy(temp, &rom[0xa0], 16); // copy internal name
|
rlm@1
|
1257 temp[0x10] = rom[0xbe]; // reserved area (old checksum)
|
rlm@1
|
1258 temp[0x11] = rom[0xbf]; // reserved area (old checksum)
|
rlm@1
|
1259 temp[0x12] = rom[0xbd]; // complement check
|
rlm@1
|
1260 temp[0x13] = rom[0xb0]; // maker
|
rlm@1
|
1261 temp[0x14] = 1; // 1 save ?
|
rlm@1
|
1262 memcpy(&temp[0x1c], flashSaveMemory, saveSize); // copy save
|
rlm@1
|
1263 fwrite(temp, 1, totalSize, file); // write save + header
|
rlm@1
|
1264 u32 crc = 0;
|
rlm@1
|
1265
|
rlm@1
|
1266 for (int i = 0; i < totalSize; i++)
|
rlm@1
|
1267 {
|
rlm@1
|
1268 crc += ((u32)temp[i] << (crc % 0x18));
|
rlm@1
|
1269 }
|
rlm@1
|
1270
|
rlm@1
|
1271 utilPutDword(buffer, crc);
|
rlm@1
|
1272 fwrite(buffer, 1, 4, file); // CRC?
|
rlm@1
|
1273
|
rlm@1
|
1274 fclose(file);
|
rlm@1
|
1275 return true;
|
rlm@1
|
1276 }
|
rlm@1
|
1277
|
rlm@1
|
1278 bool CPUImportEepromFile(const char *fileName)
|
rlm@1
|
1279 {
|
rlm@1
|
1280 FILE *file = fopen(fileName, "rb");
|
rlm@1
|
1281
|
rlm@1
|
1282 if (!file)
|
rlm@1
|
1283 return false;
|
rlm@1
|
1284
|
rlm@1
|
1285 // check file size to know what we should read
|
rlm@1
|
1286 fseek(file, 0, SEEK_END);
|
rlm@1
|
1287
|
rlm@1
|
1288 long size = ftell(file);
|
rlm@1
|
1289 fseek(file, 0, SEEK_SET);
|
rlm@1
|
1290 if (size == 512 || size == 0x2000)
|
rlm@1
|
1291 {
|
rlm@1
|
1292 if (fread(eepromData, 1, size, file) != (size_t)size)
|
rlm@1
|
1293 {
|
rlm@1
|
1294 fclose(file);
|
rlm@1
|
1295 return false;
|
rlm@1
|
1296 }
|
rlm@1
|
1297 for (int i = 0; i < size; )
|
rlm@1
|
1298 {
|
rlm@1
|
1299 u8 tmp = eepromData[i];
|
rlm@1
|
1300 eepromData[i] = eepromData[7 - i];
|
rlm@1
|
1301 eepromData[7 - i] = tmp;
|
rlm@1
|
1302 i++;
|
rlm@1
|
1303 tmp = eepromData[i];
|
rlm@1
|
1304 eepromData[i] = eepromData[7 - i];
|
rlm@1
|
1305 eepromData[7 - i] = tmp;
|
rlm@1
|
1306 i++;
|
rlm@1
|
1307 tmp = eepromData[i];
|
rlm@1
|
1308 eepromData[i] = eepromData[7 - i];
|
rlm@1
|
1309 eepromData[7 - i] = tmp;
|
rlm@1
|
1310 i++;
|
rlm@1
|
1311 tmp = eepromData[i];
|
rlm@1
|
1312 eepromData[i] = eepromData[7 - i];
|
rlm@1
|
1313 eepromData[7 - i] = tmp;
|
rlm@1
|
1314 i++;
|
rlm@1
|
1315 i += 4;
|
rlm@1
|
1316 }
|
rlm@1
|
1317 }
|
rlm@1
|
1318 else
|
rlm@1
|
1319 {
|
rlm@1
|
1320 fclose(file);
|
rlm@1
|
1321 return false;
|
rlm@1
|
1322 }
|
rlm@1
|
1323 fclose(file);
|
rlm@1
|
1324 return true;
|
rlm@1
|
1325 }
|
rlm@1
|
1326
|
rlm@1
|
1327 bool CPUReadBatteryFromStream(gzFile gzFile)
|
rlm@1
|
1328 {
|
rlm@1
|
1329 if (!gzFile)
|
rlm@1
|
1330 return false;
|
rlm@1
|
1331
|
rlm@1
|
1332 int version = utilReadInt(gzFile);
|
rlm@1
|
1333
|
rlm@1
|
1334 // for simplicity, we put both types of battery files should be in the stream, even if one's empty
|
rlm@1
|
1335 eepromReadGame(gzFile, version);
|
rlm@1
|
1336 flashReadGame(gzFile, version);
|
rlm@1
|
1337
|
rlm@1
|
1338 return true;
|
rlm@1
|
1339 }
|
rlm@1
|
1340
|
rlm@1
|
1341 bool CPUReadBatteryFile(const char *fileName)
|
rlm@1
|
1342 {
|
rlm@1
|
1343 FILE *file = fopen(fileName, "rb");
|
rlm@1
|
1344
|
rlm@1
|
1345 if (!file)
|
rlm@1
|
1346 return false;
|
rlm@1
|
1347
|
rlm@1
|
1348 // check file size to know what we should read
|
rlm@1
|
1349 fseek(file, 0, SEEK_END);
|
rlm@1
|
1350
|
rlm@1
|
1351 long size = ftell(file);
|
rlm@1
|
1352 fseek(file, 0, SEEK_SET);
|
rlm@1
|
1353 systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
|
rlm@1
|
1354
|
rlm@1
|
1355 if (size == 512 || size == 0x2000)
|
rlm@1
|
1356 {
|
rlm@1
|
1357 if (fread(eepromData, 1, size, file) != (size_t)size)
|
rlm@1
|
1358 {
|
rlm@1
|
1359 fclose(file);
|
rlm@1
|
1360 return false;
|
rlm@1
|
1361 }
|
rlm@1
|
1362 }
|
rlm@1
|
1363 else
|
rlm@1
|
1364 {
|
rlm@1
|
1365 if (size == 0x20000)
|
rlm@1
|
1366 {
|
rlm@1
|
1367 if (fread(flashSaveMemory, 1, 0x20000, file) != 0x20000)
|
rlm@1
|
1368 {
|
rlm@1
|
1369 fclose(file);
|
rlm@1
|
1370 return false;
|
rlm@1
|
1371 }
|
rlm@1
|
1372 flashSetSize(0x20000);
|
rlm@1
|
1373 }
|
rlm@1
|
1374 else
|
rlm@1
|
1375 {
|
rlm@1
|
1376 if (fread(flashSaveMemory, 1, 0x10000, file) != 0x10000)
|
rlm@1
|
1377 {
|
rlm@1
|
1378 fclose(file);
|
rlm@1
|
1379 return false;
|
rlm@1
|
1380 }
|
rlm@1
|
1381 flashSetSize(0x10000);
|
rlm@1
|
1382 }
|
rlm@1
|
1383 }
|
rlm@1
|
1384 fclose(file);
|
rlm@1
|
1385 return true;
|
rlm@1
|
1386 }
|
rlm@1
|
1387
|
rlm@1
|
1388 bool CPUWritePNGFile(const char *fileName)
|
rlm@1
|
1389 {
|
rlm@1
|
1390 return utilWritePNGFile(fileName, 240, 160, pix);
|
rlm@1
|
1391 }
|
rlm@1
|
1392
|
rlm@1
|
1393 bool CPUWriteBMPFile(const char *fileName)
|
rlm@1
|
1394 {
|
rlm@1
|
1395 return utilWriteBMPFile(fileName, 240, 160, pix);
|
rlm@1
|
1396 }
|
rlm@1
|
1397
|
rlm@1
|
1398 void CPUCleanUp()
|
rlm@1
|
1399 {
|
rlm@1
|
1400 newFrame = true;
|
rlm@1
|
1401
|
rlm@1
|
1402 GBASystemCounters.frameCount = 0;
|
rlm@1
|
1403 GBASystemCounters.lagCount = 0;
|
rlm@1
|
1404 GBASystemCounters.extraCount = 0;
|
rlm@1
|
1405 GBASystemCounters.lagged = true;
|
rlm@1
|
1406 GBASystemCounters.laggedLast = true;
|
rlm@1
|
1407
|
rlm@1
|
1408 #ifdef PROFILING
|
rlm@1
|
1409 if (profilingTicksReload)
|
rlm@1
|
1410 {
|
rlm@1
|
1411 profCleanup();
|
rlm@1
|
1412 }
|
rlm@1
|
1413 #endif
|
rlm@1
|
1414
|
rlm@1
|
1415 #if (defined(WIN32) && !defined(SDL))
|
rlm@1
|
1416 #define FreeMappedMem(name, mapName, offset) \
|
rlm@1
|
1417 if (name != NULL) { \
|
rlm@1
|
1418 UnmapViewOfFile((name) - (offset)); \
|
rlm@1
|
1419 name = NULL; \
|
rlm@1
|
1420 CloseHandle(mapName); \
|
rlm@1
|
1421 }
|
rlm@1
|
1422 #else
|
rlm@1
|
1423 #define FreeMappedMem(name, mapName, offset) \
|
rlm@1
|
1424 if (name != NULL) { \
|
rlm@1
|
1425 free(name); \
|
rlm@1
|
1426 name = NULL; \
|
rlm@1
|
1427 }
|
rlm@1
|
1428 #endif
|
rlm@1
|
1429
|
rlm@1
|
1430 FreeMappedMem(rom, mapROM, 0);
|
rlm@1
|
1431 FreeMappedMem(vram, mapVRAM, 0);
|
rlm@1
|
1432 FreeMappedMem(paletteRAM, mapPALETTERAM, 0);
|
rlm@1
|
1433 FreeMappedMem(internalRAM, mapIRAM, 0);
|
rlm@1
|
1434 FreeMappedMem(workRAM, mapWORKRAM, 0);
|
rlm@1
|
1435 FreeMappedMem(bios, mapBIOS, 0);
|
rlm@1
|
1436 FreeMappedMem(pix, mapPIX, 4);
|
rlm@1
|
1437 FreeMappedMem(oam, mapOAM, 0);
|
rlm@1
|
1438 FreeMappedMem(ioMem, mapIOMEM, 0);
|
rlm@1
|
1439
|
rlm@1
|
1440 eepromErase();
|
rlm@1
|
1441 flashErase();
|
rlm@1
|
1442
|
rlm@1
|
1443 elfCleanUp();
|
rlm@1
|
1444
|
rlm@1
|
1445 systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
|
rlm@1
|
1446
|
rlm@1
|
1447 systemClearJoypads();
|
rlm@1
|
1448 systemResetSensor();
|
rlm@1
|
1449
|
rlm@1
|
1450 // gbaLastTime = gbaFrameCount = 0;
|
rlm@1
|
1451 systemRefreshScreen();
|
rlm@1
|
1452 }
|
rlm@1
|
1453
|
rlm@1
|
1454 int CPULoadRom(const char *szFile)
|
rlm@1
|
1455 {
|
rlm@1
|
1456 int size = 0x2000000;
|
rlm@1
|
1457
|
rlm@1
|
1458 if (rom != NULL)
|
rlm@1
|
1459 {
|
rlm@1
|
1460 CPUCleanUp();
|
rlm@1
|
1461 }
|
rlm@1
|
1462
|
rlm@1
|
1463 systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
|
rlm@1
|
1464
|
rlm@1
|
1465 // size+4 is so RAM search and watch are safe to read any byte in the allocated region as a 4-byte int
|
rlm@1
|
1466 #if (defined(WIN32) && !defined(SDL))
|
rlm@1
|
1467 #define AllocMappedMem(name, mapName, nameStr, size, useCalloc, offset) \
|
rlm@1
|
1468 mapName = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (size) + (offset) + (4), nameStr); \
|
rlm@1
|
1469 if ((mapName) && GetLastError() == ERROR_ALREADY_EXISTS) { \
|
rlm@1
|
1470 CloseHandle(mapName); \
|
rlm@1
|
1471 mapName = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (size) + (offset) + (4), NULL); \
|
rlm@1
|
1472 } \
|
rlm@1
|
1473 name = (u8 *)MapViewOfFile(mapName, FILE_MAP_WRITE, 0, 0, 0) + (offset); \
|
rlm@1
|
1474 if ((name) == NULL) { \
|
rlm@1
|
1475 systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), nameStr); \
|
rlm@1
|
1476 CPUCleanUp(); \
|
rlm@1
|
1477 return 0; \
|
rlm@1
|
1478 } \
|
rlm@1
|
1479 memset(name, 0, size + 4);
|
rlm@1
|
1480 #else
|
rlm@1
|
1481 #define AllocMappedMem(name, mapName, nameStr, size, useCalloc, offset) \
|
rlm@1
|
1482 name = (u8 *)(useCalloc ? calloc(1, size + 4) : malloc(size + 4)); \
|
rlm@1
|
1483 if ((name) == NULL) { \
|
rlm@1
|
1484 systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), nameStr); \
|
rlm@1
|
1485 CPUCleanUp(); \
|
rlm@1
|
1486 return 0; \
|
rlm@1
|
1487 } \
|
rlm@1
|
1488 memset(name, 0, size + 4);
|
rlm@1
|
1489 #endif
|
rlm@1
|
1490
|
rlm@1
|
1491 AllocMappedMem(rom, mapROM, "vbaROM", 0x2000000, false, 0);
|
rlm@1
|
1492 AllocMappedMem(workRAM, mapWORKRAM, "vbaWORKRAM", 0x40000, true, 0);
|
rlm@1
|
1493
|
rlm@1
|
1494 u8 *whereToLoad = rom;
|
rlm@1
|
1495 if (cpuIsMultiBoot)
|
rlm@1
|
1496 whereToLoad = workRAM;
|
rlm@1
|
1497
|
rlm@1
|
1498 if (utilIsELF(szFile))
|
rlm@1
|
1499 {
|
rlm@1
|
1500 FILE *f = fopen(szFile, "rb");
|
rlm@1
|
1501 if (!f)
|
rlm@1
|
1502 {
|
rlm@1
|
1503 systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"),
|
rlm@1
|
1504 szFile);
|
rlm@1
|
1505 FreeMappedMem(rom, mapROM, 0);
|
rlm@1
|
1506 FreeMappedMem(workRAM, mapWORKRAM, 0);
|
rlm@1
|
1507 return 0;
|
rlm@1
|
1508 }
|
rlm@1
|
1509 bool res = elfRead(szFile, size, f);
|
rlm@1
|
1510 if (!res || size == 0)
|
rlm@1
|
1511 {
|
rlm@1
|
1512 FreeMappedMem(rom, mapROM, 0);
|
rlm@1
|
1513 FreeMappedMem(workRAM, mapWORKRAM, 0);
|
rlm@1
|
1514 elfCleanUp();
|
rlm@1
|
1515 return 0;
|
rlm@1
|
1516 }
|
rlm@1
|
1517 }
|
rlm@1
|
1518 else if (!utilLoad(szFile,
|
rlm@1
|
1519 utilIsGBAImage,
|
rlm@1
|
1520 whereToLoad,
|
rlm@1
|
1521 size))
|
rlm@1
|
1522 {
|
rlm@1
|
1523 FreeMappedMem(rom, mapROM, 0);
|
rlm@1
|
1524 FreeMappedMem(workRAM, mapWORKRAM, 0);
|
rlm@1
|
1525 return 0;
|
rlm@1
|
1526 }
|
rlm@1
|
1527
|
rlm@1
|
1528 u16 *temp = (u16 *)(rom + ((size + 1) & ~1));
|
rlm@1
|
1529 int i;
|
rlm@1
|
1530 for (i = (size + 1) & ~1; i < 0x2000000; i += 2)
|
rlm@1
|
1531 {
|
rlm@1
|
1532 WRITE16LE(temp, (i >> 1) & 0xFFFF);
|
rlm@1
|
1533 temp++;
|
rlm@1
|
1534 }
|
rlm@1
|
1535
|
rlm@1
|
1536 AllocMappedMem(bios, mapBIOS, "vbaBIOS", 0x4000, true, 0);
|
rlm@1
|
1537 AllocMappedMem(internalRAM, mapIRAM, "vbaIRAM", 0x8000, true, 0);
|
rlm@1
|
1538 AllocMappedMem(paletteRAM, mapPALETTERAM, "vbaPALETTERAM", 0x400, true, 0);
|
rlm@1
|
1539 AllocMappedMem(vram, mapVRAM, "vbaVRAM", 0x20000, true, 0);
|
rlm@1
|
1540 AllocMappedMem(oam, mapOAM, "vbaOAM", 0x400, true, 0);
|
rlm@1
|
1541
|
rlm@1
|
1542 // HACK: +4 at start to accomodate the 2xSaI filter reading out of bounds of the leftmost pixel
|
rlm@1
|
1543 AllocMappedMem(pix, mapPIX, "vbaPIX", 4 * 241 * 162, true, 4);
|
rlm@1
|
1544 AllocMappedMem(ioMem, mapIOMEM, "vbaIOMEM", 0x400, true, 0);
|
rlm@1
|
1545
|
rlm@1
|
1546 CPUUpdateRenderBuffers(true);
|
rlm@1
|
1547
|
rlm@1
|
1548 return size;
|
rlm@1
|
1549 }
|
rlm@1
|
1550
|
rlm@1
|
1551 void CPUUpdateRender()
|
rlm@1
|
1552 {
|
rlm@1
|
1553 switch (DISPCNT & 7)
|
rlm@1
|
1554 {
|
rlm@1
|
1555 case 0:
|
rlm@1
|
1556 if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
|
rlm@1
|
1557 cpuDisableSfx)
|
rlm@1
|
1558 renderLine = mode0RenderLine;
|
rlm@1
|
1559 else if (fxOn && !windowOn && !(layerEnable & 0x8000))
|
rlm@1
|
1560 renderLine = mode0RenderLineNoWindow;
|
rlm@1
|
1561 else
|
rlm@1
|
1562 renderLine = mode0RenderLineAll;
|
rlm@1
|
1563 break;
|
rlm@1
|
1564 case 1:
|
rlm@1
|
1565 if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
|
rlm@1
|
1566 cpuDisableSfx)
|
rlm@1
|
1567 renderLine = mode1RenderLine;
|
rlm@1
|
1568 else if (fxOn && !windowOn && !(layerEnable & 0x8000))
|
rlm@1
|
1569 renderLine = mode1RenderLineNoWindow;
|
rlm@1
|
1570 else
|
rlm@1
|
1571 renderLine = mode1RenderLineAll;
|
rlm@1
|
1572 break;
|
rlm@1
|
1573 case 2:
|
rlm@1
|
1574 if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
|
rlm@1
|
1575 cpuDisableSfx)
|
rlm@1
|
1576 renderLine = mode2RenderLine;
|
rlm@1
|
1577 else if (fxOn && !windowOn && !(layerEnable & 0x8000))
|
rlm@1
|
1578 renderLine = mode2RenderLineNoWindow;
|
rlm@1
|
1579 else
|
rlm@1
|
1580 renderLine = mode2RenderLineAll;
|
rlm@1
|
1581 break;
|
rlm@1
|
1582 case 3:
|
rlm@1
|
1583 if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
|
rlm@1
|
1584 cpuDisableSfx)
|
rlm@1
|
1585 renderLine = mode3RenderLine;
|
rlm@1
|
1586 else if (fxOn && !windowOn && !(layerEnable & 0x8000))
|
rlm@1
|
1587 renderLine = mode3RenderLineNoWindow;
|
rlm@1
|
1588 else
|
rlm@1
|
1589 renderLine = mode3RenderLineAll;
|
rlm@1
|
1590 break;
|
rlm@1
|
1591 case 4:
|
rlm@1
|
1592 if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
|
rlm@1
|
1593 cpuDisableSfx)
|
rlm@1
|
1594 renderLine = mode4RenderLine;
|
rlm@1
|
1595 else if (fxOn && !windowOn && !(layerEnable & 0x8000))
|
rlm@1
|
1596 renderLine = mode4RenderLineNoWindow;
|
rlm@1
|
1597 else
|
rlm@1
|
1598 renderLine = mode4RenderLineAll;
|
rlm@1
|
1599 break;
|
rlm@1
|
1600 case 5:
|
rlm@1
|
1601 if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
|
rlm@1
|
1602 cpuDisableSfx)
|
rlm@1
|
1603 renderLine = mode5RenderLine;
|
rlm@1
|
1604 else if (fxOn && !windowOn && !(layerEnable & 0x8000))
|
rlm@1
|
1605 renderLine = mode5RenderLineNoWindow;
|
rlm@1
|
1606 else
|
rlm@1
|
1607 renderLine = mode5RenderLineAll;
|
rlm@1
|
1608 default:
|
rlm@1
|
1609 break;
|
rlm@1
|
1610 }
|
rlm@1
|
1611 }
|
rlm@1
|
1612
|
rlm@1
|
1613 void CPUUpdateCPSR()
|
rlm@1
|
1614 {
|
rlm@1
|
1615 u32 CPSR = reg[16].I & 0x40;
|
rlm@1
|
1616 if (N_FLAG)
|
rlm@1
|
1617 CPSR |= 0x80000000;
|
rlm@1
|
1618 if (Z_FLAG)
|
rlm@1
|
1619 CPSR |= 0x40000000;
|
rlm@1
|
1620 if (C_FLAG)
|
rlm@1
|
1621 CPSR |= 0x20000000;
|
rlm@1
|
1622 if (V_FLAG)
|
rlm@1
|
1623 CPSR |= 0x10000000;
|
rlm@1
|
1624 if (!armState)
|
rlm@1
|
1625 CPSR |= 0x00000020;
|
rlm@1
|
1626 if (!armIrqEnable)
|
rlm@1
|
1627 CPSR |= 0x80;
|
rlm@1
|
1628 CPSR |= (armMode & 0x1F);
|
rlm@1
|
1629 reg[16].I = CPSR;
|
rlm@1
|
1630 }
|
rlm@1
|
1631
|
rlm@1
|
1632 void CPUUpdateFlags(bool breakLoop)
|
rlm@1
|
1633 {
|
rlm@1
|
1634 u32 CPSR = reg[16].I;
|
rlm@1
|
1635
|
rlm@1
|
1636 N_FLAG = (CPSR & 0x80000000) ? true : false;
|
rlm@1
|
1637 Z_FLAG = (CPSR & 0x40000000) ? true : false;
|
rlm@1
|
1638 C_FLAG = (CPSR & 0x20000000) ? true : false;
|
rlm@1
|
1639 V_FLAG = (CPSR & 0x10000000) ? true : false;
|
rlm@1
|
1640 armState = (CPSR & 0x20) ? false : true;
|
rlm@1
|
1641 armIrqEnable = (CPSR & 0x80) ? false : true;
|
rlm@1
|
1642 if (breakLoop)
|
rlm@1
|
1643 {
|
rlm@1
|
1644 if (armIrqEnable && (IF & IE) && (IME & 1))
|
rlm@1
|
1645 {
|
rlm@1
|
1646 CPU_BREAK_LOOP_2;
|
rlm@1
|
1647 }
|
rlm@1
|
1648 }
|
rlm@1
|
1649 }
|
rlm@1
|
1650
|
rlm@1
|
1651 void CPUUpdateFlags()
|
rlm@1
|
1652 {
|
rlm@1
|
1653 CPUUpdateFlags(true);
|
rlm@1
|
1654 }
|
rlm@1
|
1655
|
rlm@1
|
1656 #ifdef WORDS_BIGENDIAN
|
rlm@1
|
1657 static void CPUSwap(volatile u32 *a, volatile u32 *b)
|
rlm@1
|
1658 {
|
rlm@1
|
1659 volatile u32 c = *b;
|
rlm@1
|
1660 *b = *a;
|
rlm@1
|
1661 *a = c;
|
rlm@1
|
1662 }
|
rlm@1
|
1663
|
rlm@1
|
1664 #else
|
rlm@1
|
1665 static void CPUSwap(u32 *a, u32 *b)
|
rlm@1
|
1666 {
|
rlm@1
|
1667 u32 c = *b;
|
rlm@1
|
1668 *b = *a;
|
rlm@1
|
1669 *a = c;
|
rlm@1
|
1670 }
|
rlm@1
|
1671
|
rlm@1
|
1672 #endif
|
rlm@1
|
1673
|
rlm@1
|
1674 void CPUSwitchMode(int mode, bool saveState, bool breakLoop)
|
rlm@1
|
1675 {
|
rlm@1
|
1676 // if(armMode == mode)
|
rlm@1
|
1677 // return;
|
rlm@1
|
1678
|
rlm@1
|
1679 CPUUpdateCPSR();
|
rlm@1
|
1680
|
rlm@1
|
1681 switch (armMode)
|
rlm@1
|
1682 {
|
rlm@1
|
1683 case 0x10:
|
rlm@1
|
1684 case 0x1F:
|
rlm@1
|
1685 reg[R13_USR].I = reg[13].I;
|
rlm@1
|
1686 reg[R14_USR].I = reg[14].I;
|
rlm@1
|
1687 reg[17].I = reg[16].I;
|
rlm@1
|
1688 break;
|
rlm@1
|
1689 case 0x11:
|
rlm@1
|
1690 CPUSwap(®[R8_FIQ].I, ®[8].I);
|
rlm@1
|
1691 CPUSwap(®[R9_FIQ].I, ®[9].I);
|
rlm@1
|
1692 CPUSwap(®[R10_FIQ].I, ®[10].I);
|
rlm@1
|
1693 CPUSwap(®[R11_FIQ].I, ®[11].I);
|
rlm@1
|
1694 CPUSwap(®[R12_FIQ].I, ®[12].I);
|
rlm@1
|
1695 reg[R13_FIQ].I = reg[13].I;
|
rlm@1
|
1696 reg[R14_FIQ].I = reg[14].I;
|
rlm@1
|
1697 reg[SPSR_FIQ].I = reg[17].I;
|
rlm@1
|
1698 break;
|
rlm@1
|
1699 case 0x12:
|
rlm@1
|
1700 reg[R13_IRQ].I = reg[13].I;
|
rlm@1
|
1701 reg[R14_IRQ].I = reg[14].I;
|
rlm@1
|
1702 reg[SPSR_IRQ].I = reg[17].I;
|
rlm@1
|
1703 break;
|
rlm@1
|
1704 case 0x13:
|
rlm@1
|
1705 reg[R13_SVC].I = reg[13].I;
|
rlm@1
|
1706 reg[R14_SVC].I = reg[14].I;
|
rlm@1
|
1707 reg[SPSR_SVC].I = reg[17].I;
|
rlm@1
|
1708 break;
|
rlm@1
|
1709 case 0x17:
|
rlm@1
|
1710 reg[R13_ABT].I = reg[13].I;
|
rlm@1
|
1711 reg[R14_ABT].I = reg[14].I;
|
rlm@1
|
1712 reg[SPSR_ABT].I = reg[17].I;
|
rlm@1
|
1713 break;
|
rlm@1
|
1714 case 0x1b:
|
rlm@1
|
1715 reg[R13_UND].I = reg[13].I;
|
rlm@1
|
1716 reg[R14_UND].I = reg[14].I;
|
rlm@1
|
1717 reg[SPSR_UND].I = reg[17].I;
|
rlm@1
|
1718 break;
|
rlm@1
|
1719 }
|
rlm@1
|
1720
|
rlm@1
|
1721 u32 CPSR = reg[16].I;
|
rlm@1
|
1722 u32 SPSR = reg[17].I;
|
rlm@1
|
1723
|
rlm@1
|
1724 switch (mode)
|
rlm@1
|
1725 {
|
rlm@1
|
1726 case 0x10:
|
rlm@1
|
1727 case 0x1F:
|
rlm@1
|
1728 reg[13].I = reg[R13_USR].I;
|
rlm@1
|
1729 reg[14].I = reg[R14_USR].I;
|
rlm@1
|
1730 reg[16].I = SPSR;
|
rlm@1
|
1731 break;
|
rlm@1
|
1732 case 0x11:
|
rlm@1
|
1733 CPUSwap(®[8].I, ®[R8_FIQ].I);
|
rlm@1
|
1734 CPUSwap(®[9].I, ®[R9_FIQ].I);
|
rlm@1
|
1735 CPUSwap(®[10].I, ®[R10_FIQ].I);
|
rlm@1
|
1736 CPUSwap(®[11].I, ®[R11_FIQ].I);
|
rlm@1
|
1737 CPUSwap(®[12].I, ®[R12_FIQ].I);
|
rlm@1
|
1738 reg[13].I = reg[R13_FIQ].I;
|
rlm@1
|
1739 reg[14].I = reg[R14_FIQ].I;
|
rlm@1
|
1740 if (saveState)
|
rlm@1
|
1741 reg[17].I = CPSR;
|
rlm@1
|
1742 else
|
rlm@1
|
1743 reg[17].I = reg[SPSR_FIQ].I;
|
rlm@1
|
1744 break;
|
rlm@1
|
1745 case 0x12:
|
rlm@1
|
1746 reg[13].I = reg[R13_IRQ].I;
|
rlm@1
|
1747 reg[14].I = reg[R14_IRQ].I;
|
rlm@1
|
1748 reg[16].I = SPSR;
|
rlm@1
|
1749 if (saveState)
|
rlm@1
|
1750 reg[17].I = CPSR;
|
rlm@1
|
1751 else
|
rlm@1
|
1752 reg[17].I = reg[SPSR_IRQ].I;
|
rlm@1
|
1753 break;
|
rlm@1
|
1754 case 0x13:
|
rlm@1
|
1755 reg[13].I = reg[R13_SVC].I;
|
rlm@1
|
1756 reg[14].I = reg[R14_SVC].I;
|
rlm@1
|
1757 reg[16].I = SPSR;
|
rlm@1
|
1758 if (saveState)
|
rlm@1
|
1759 reg[17].I = CPSR;
|
rlm@1
|
1760 else
|
rlm@1
|
1761 reg[17].I = reg[SPSR_SVC].I;
|
rlm@1
|
1762 break;
|
rlm@1
|
1763 case 0x17:
|
rlm@1
|
1764 reg[13].I = reg[R13_ABT].I;
|
rlm@1
|
1765 reg[14].I = reg[R14_ABT].I;
|
rlm@1
|
1766 reg[16].I = SPSR;
|
rlm@1
|
1767 if (saveState)
|
rlm@1
|
1768 reg[17].I = CPSR;
|
rlm@1
|
1769 else
|
rlm@1
|
1770 reg[17].I = reg[SPSR_ABT].I;
|
rlm@1
|
1771 break;
|
rlm@1
|
1772 case 0x1b:
|
rlm@1
|
1773 reg[13].I = reg[R13_UND].I;
|
rlm@1
|
1774 reg[14].I = reg[R14_UND].I;
|
rlm@1
|
1775 reg[16].I = SPSR;
|
rlm@1
|
1776 if (saveState)
|
rlm@1
|
1777 reg[17].I = CPSR;
|
rlm@1
|
1778 else
|
rlm@1
|
1779 reg[17].I = reg[SPSR_UND].I;
|
rlm@1
|
1780 break;
|
rlm@1
|
1781 default:
|
rlm@1
|
1782 systemMessage(MSG_UNSUPPORTED_ARM_MODE, N_("Unsupported ARM mode %02x"), mode);
|
rlm@1
|
1783 break;
|
rlm@1
|
1784 }
|
rlm@1
|
1785 armMode = mode;
|
rlm@1
|
1786 CPUUpdateFlags(breakLoop);
|
rlm@1
|
1787 CPUUpdateCPSR();
|
rlm@1
|
1788 }
|
rlm@1
|
1789
|
rlm@1
|
1790 void CPUSwitchMode(int mode, bool saveState)
|
rlm@1
|
1791 {
|
rlm@1
|
1792 CPUSwitchMode(mode, saveState, true);
|
rlm@1
|
1793 }
|
rlm@1
|
1794
|
rlm@1
|
1795 void CPUUndefinedException()
|
rlm@1
|
1796 {
|
rlm@1
|
1797 u32 PC = reg[15].I;
|
rlm@1
|
1798 bool savedArmState = armState;
|
rlm@1
|
1799 CPUSwitchMode(0x1b, true, false);
|
rlm@1
|
1800 reg[14].I = PC - (savedArmState ? 4 : 2);
|
rlm@1
|
1801 reg[15].I = 0x04;
|
rlm@1
|
1802 armState = true;
|
rlm@1
|
1803 armIrqEnable = false;
|
rlm@1
|
1804 armNextPC = 0x04;
|
rlm@1
|
1805 reg[15].I += 4;
|
rlm@1
|
1806 }
|
rlm@1
|
1807
|
rlm@1
|
1808 void CPUSoftwareInterrupt()
|
rlm@1
|
1809 {
|
rlm@1
|
1810 u32 PC = reg[15].I;
|
rlm@1
|
1811 bool savedArmState = armState;
|
rlm@1
|
1812 CPUSwitchMode(0x13, true, false);
|
rlm@1
|
1813 reg[14].I = PC - (savedArmState ? 4 : 2);
|
rlm@1
|
1814 reg[15].I = 0x08;
|
rlm@1
|
1815 armState = true;
|
rlm@1
|
1816 armIrqEnable = false;
|
rlm@1
|
1817 armNextPC = 0x08;
|
rlm@1
|
1818 reg[15].I += 4;
|
rlm@1
|
1819 }
|
rlm@1
|
1820
|
rlm@1
|
1821 void CPUSoftwareInterrupt(int comment)
|
rlm@1
|
1822 {
|
rlm@1
|
1823 static bool disableMessage = false;
|
rlm@1
|
1824 if (armState)
|
rlm@1
|
1825 comment >>= 16;
|
rlm@1
|
1826 #ifdef BKPT_SUPPORT
|
rlm@1
|
1827 if (comment == 0xff)
|
rlm@1
|
1828 {
|
rlm@1
|
1829 extern void (*dbgOutput)(char *, u32);
|
rlm@1
|
1830 dbgOutput(NULL, reg[0].I);
|
rlm@1
|
1831 return;
|
rlm@1
|
1832 }
|
rlm@1
|
1833 #endif
|
rlm@1
|
1834 #ifdef PROFILING
|
rlm@1
|
1835 if (comment == 0xfe)
|
rlm@1
|
1836 {
|
rlm@1
|
1837 profStartup(reg[0].I, reg[1].I);
|
rlm@1
|
1838 return;
|
rlm@1
|
1839 }
|
rlm@1
|
1840 if (comment == 0xfd)
|
rlm@1
|
1841 {
|
rlm@1
|
1842 profControl(reg[0].I);
|
rlm@1
|
1843 return;
|
rlm@1
|
1844 }
|
rlm@1
|
1845 if (comment == 0xfc)
|
rlm@1
|
1846 {
|
rlm@1
|
1847 profCleanup();
|
rlm@1
|
1848 return;
|
rlm@1
|
1849 }
|
rlm@1
|
1850 if (comment == 0xfb)
|
rlm@1
|
1851 {
|
rlm@1
|
1852 profCount();
|
rlm@1
|
1853 return;
|
rlm@1
|
1854 }
|
rlm@1
|
1855 #endif
|
rlm@1
|
1856 if (comment == 0xfa)
|
rlm@1
|
1857 {
|
rlm@1
|
1858 agbPrintFlush();
|
rlm@1
|
1859 return;
|
rlm@1
|
1860 }
|
rlm@1
|
1861 #ifdef SDL
|
rlm@1
|
1862 if (comment == 0xf9)
|
rlm@1
|
1863 {
|
rlm@1
|
1864 emulating = 0;
|
rlm@1
|
1865 CPU_BREAK_LOOP_2;
|
rlm@1
|
1866 return;
|
rlm@1
|
1867 }
|
rlm@1
|
1868 #endif
|
rlm@1
|
1869 if (useBios)
|
rlm@1
|
1870 {
|
rlm@1
|
1871 #ifdef GBA_LOGGING
|
rlm@1
|
1872 if (systemVerbose & VERBOSE_SWI)
|
rlm@1
|
1873 {
|
rlm@1
|
1874 log("SWI: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment,
|
rlm@1
|
1875 armState ? armNextPC - 4 : armNextPC - 2,
|
rlm@1
|
1876 reg[0].I,
|
rlm@1
|
1877 reg[1].I,
|
rlm@1
|
1878 reg[2].I,
|
rlm@1
|
1879 VCOUNT);
|
rlm@1
|
1880 }
|
rlm@1
|
1881 #endif
|
rlm@1
|
1882 CPUSoftwareInterrupt();
|
rlm@1
|
1883 return;
|
rlm@1
|
1884 }
|
rlm@1
|
1885 // This would be correct, but it causes problems if uncommented
|
rlm@1
|
1886 // else {
|
rlm@1
|
1887 // biosProtected = 0xe3a02004;
|
rlm@1
|
1888 // }
|
rlm@1
|
1889
|
rlm@1
|
1890 switch (comment)
|
rlm@1
|
1891 {
|
rlm@1
|
1892 case 0x00:
|
rlm@1
|
1893 BIOS_SoftReset();
|
rlm@1
|
1894 break;
|
rlm@1
|
1895 case 0x01:
|
rlm@1
|
1896 BIOS_RegisterRamReset();
|
rlm@1
|
1897 break;
|
rlm@1
|
1898 case 0x02:
|
rlm@1
|
1899 #ifdef GBA_LOGGING
|
rlm@1
|
1900 if (systemVerbose & VERBOSE_SWI)
|
rlm@1
|
1901 {
|
rlm@1
|
1902 log("Halt: (VCOUNT = %2d)\n",
|
rlm@1
|
1903 VCOUNT);
|
rlm@1
|
1904 }
|
rlm@1
|
1905 #endif
|
rlm@1
|
1906 holdState = true;
|
rlm@1
|
1907 holdType = -1;
|
rlm@1
|
1908 break;
|
rlm@1
|
1909 case 0x03:
|
rlm@1
|
1910 #ifdef GBA_LOGGING
|
rlm@1
|
1911 if (systemVerbose & VERBOSE_SWI)
|
rlm@1
|
1912 {
|
rlm@1
|
1913 log("Stop: (VCOUNT = %2d)\n",
|
rlm@1
|
1914 VCOUNT);
|
rlm@1
|
1915 }
|
rlm@1
|
1916 #endif
|
rlm@1
|
1917 holdState = true;
|
rlm@1
|
1918 holdType = -1;
|
rlm@1
|
1919 stopState = true;
|
rlm@1
|
1920 break;
|
rlm@1
|
1921 case 0x04:
|
rlm@1
|
1922 #ifdef GBA_LOGGING
|
rlm@1
|
1923 if (systemVerbose & VERBOSE_SWI)
|
rlm@1
|
1924 {
|
rlm@1
|
1925 log("IntrWait: 0x%08x,0x%08x (VCOUNT = %2d)\n",
|
rlm@1
|
1926 reg[0].I,
|
rlm@1
|
1927 reg[1].I,
|
rlm@1
|
1928 VCOUNT);
|
rlm@1
|
1929 }
|
rlm@1
|
1930 #endif
|
rlm@1
|
1931 CPUSoftwareInterrupt();
|
rlm@1
|
1932 break;
|
rlm@1
|
1933 case 0x05:
|
rlm@1
|
1934 #ifdef GBA_LOGGING
|
rlm@1
|
1935 if (systemVerbose & VERBOSE_SWI)
|
rlm@1
|
1936 {
|
rlm@1
|
1937 log("VBlankIntrWait: (VCOUNT = %2d)\n",
|
rlm@1
|
1938 VCOUNT);
|
rlm@1
|
1939 }
|
rlm@1
|
1940 #endif
|
rlm@1
|
1941 CPUSoftwareInterrupt();
|
rlm@1
|
1942 break;
|
rlm@1
|
1943 case 0x06:
|
rlm@1
|
1944 CPUSoftwareInterrupt();
|
rlm@1
|
1945 break;
|
rlm@1
|
1946 case 0x07:
|
rlm@1
|
1947 CPUSoftwareInterrupt();
|
rlm@1
|
1948 break;
|
rlm@1
|
1949 case 0x08:
|
rlm@1
|
1950 BIOS_Sqrt();
|
rlm@1
|
1951 break;
|
rlm@1
|
1952 case 0x09:
|
rlm@1
|
1953 BIOS_ArcTan();
|
rlm@1
|
1954 break;
|
rlm@1
|
1955 case 0x0A:
|
rlm@1
|
1956 BIOS_ArcTan2();
|
rlm@1
|
1957 break;
|
rlm@1
|
1958 case 0x0B:
|
rlm@1
|
1959 BIOS_CpuSet();
|
rlm@1
|
1960 break;
|
rlm@1
|
1961 case 0x0C:
|
rlm@1
|
1962 BIOS_CpuFastSet();
|
rlm@1
|
1963 break;
|
rlm@1
|
1964 case 0x0E:
|
rlm@1
|
1965 BIOS_BgAffineSet();
|
rlm@1
|
1966 break;
|
rlm@1
|
1967 case 0x0F:
|
rlm@1
|
1968 BIOS_ObjAffineSet();
|
rlm@1
|
1969 break;
|
rlm@1
|
1970 case 0x10:
|
rlm@1
|
1971 BIOS_BitUnPack();
|
rlm@1
|
1972 break;
|
rlm@1
|
1973 case 0x11:
|
rlm@1
|
1974 BIOS_LZ77UnCompWram();
|
rlm@1
|
1975 break;
|
rlm@1
|
1976 case 0x12:
|
rlm@1
|
1977 BIOS_LZ77UnCompVram();
|
rlm@1
|
1978 break;
|
rlm@1
|
1979 case 0x13:
|
rlm@1
|
1980 BIOS_HuffUnComp();
|
rlm@1
|
1981 break;
|
rlm@1
|
1982 case 0x14:
|
rlm@1
|
1983 BIOS_RLUnCompWram();
|
rlm@1
|
1984 break;
|
rlm@1
|
1985 case 0x15:
|
rlm@1
|
1986 BIOS_RLUnCompVram();
|
rlm@1
|
1987 break;
|
rlm@1
|
1988 case 0x16:
|
rlm@1
|
1989 BIOS_Diff8bitUnFilterWram();
|
rlm@1
|
1990 break;
|
rlm@1
|
1991 case 0x17:
|
rlm@1
|
1992 BIOS_Diff8bitUnFilterVram();
|
rlm@1
|
1993 break;
|
rlm@1
|
1994 case 0x18:
|
rlm@1
|
1995 BIOS_Diff16bitUnFilter();
|
rlm@1
|
1996 break;
|
rlm@1
|
1997 case 0x19:
|
rlm@1
|
1998 #ifdef GBA_LOGGING
|
rlm@1
|
1999 if (systemVerbose & VERBOSE_SWI)
|
rlm@1
|
2000 {
|
rlm@1
|
2001 log("SoundBiasSet: 0x%08x (VCOUNT = %2d)\n",
|
rlm@1
|
2002 reg[0].I,
|
rlm@1
|
2003 VCOUNT);
|
rlm@1
|
2004 }
|
rlm@1
|
2005 #endif
|
rlm@1
|
2006 if (reg[0].I)
|
rlm@1
|
2007 soundPause();
|
rlm@1
|
2008 else
|
rlm@1
|
2009 soundResume();
|
rlm@1
|
2010 break;
|
rlm@1
|
2011 case 0x1F:
|
rlm@1
|
2012 BIOS_MidiKey2Freq();
|
rlm@1
|
2013 break;
|
rlm@1
|
2014 case 0x2A:
|
rlm@1
|
2015 BIOS_SndDriverJmpTableCopy();
|
rlm@1
|
2016 // let it go, because we don't really emulate this function // FIXME (?)
|
rlm@1
|
2017 default:
|
rlm@1
|
2018 #ifdef GBA_LOGGING
|
rlm@1
|
2019 if (systemVerbose & VERBOSE_SWI)
|
rlm@1
|
2020 {
|
rlm@1
|
2021 log("SWI: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment,
|
rlm@1
|
2022 armState ? armNextPC - 4 : armNextPC - 2,
|
rlm@1
|
2023 reg[0].I,
|
rlm@1
|
2024 reg[1].I,
|
rlm@1
|
2025 reg[2].I,
|
rlm@1
|
2026 VCOUNT);
|
rlm@1
|
2027 }
|
rlm@1
|
2028 #endif
|
rlm@1
|
2029
|
rlm@1
|
2030 if (!disableMessage)
|
rlm@1
|
2031 {
|
rlm@1
|
2032 systemMessage(MSG_UNSUPPORTED_BIOS_FUNCTION,
|
rlm@1
|
2033 N_(
|
rlm@1
|
2034 "Unsupported BIOS function %02x called from %08x. A BIOS file is needed in order to get correct behaviour."),
|
rlm@1
|
2035 comment,
|
rlm@1
|
2036 armMode ? armNextPC - 4 : armNextPC - 2);
|
rlm@1
|
2037 disableMessage = true;
|
rlm@1
|
2038 }
|
rlm@1
|
2039 break;
|
rlm@1
|
2040 }
|
rlm@1
|
2041 }
|
rlm@1
|
2042
|
rlm@1
|
2043 void CPUCompareVCOUNT()
|
rlm@1
|
2044 {
|
rlm@1
|
2045 if (VCOUNT == (DISPSTAT >> 8))
|
rlm@1
|
2046 {
|
rlm@1
|
2047 DISPSTAT |= 4;
|
rlm@1
|
2048 UPDATE_REG(0x04, DISPSTAT);
|
rlm@1
|
2049
|
rlm@1
|
2050 if (DISPSTAT & 0x20)
|
rlm@1
|
2051 {
|
rlm@1
|
2052 IF |= 4;
|
rlm@1
|
2053 UPDATE_REG(0x202, IF);
|
rlm@1
|
2054 }
|
rlm@1
|
2055 }
|
rlm@1
|
2056 else
|
rlm@1
|
2057 {
|
rlm@1
|
2058 DISPSTAT &= 0xFFFB;
|
rlm@1
|
2059 UPDATE_REG(0x4, DISPSTAT);
|
rlm@1
|
2060 }
|
rlm@1
|
2061 }
|
rlm@1
|
2062
|
rlm@1
|
2063 void doDMA(u32 &s, u32 &d, u32 si, u32 di, u32 c, int transfer32)
|
rlm@1
|
2064 {
|
rlm@1
|
2065 int sm = s >> 24;
|
rlm@1
|
2066 int dm = d >> 24;
|
rlm@1
|
2067
|
rlm@1
|
2068 int sc = c;
|
rlm@1
|
2069
|
rlm@1
|
2070 cpuDmaCount = c;
|
rlm@1
|
2071
|
rlm@1
|
2072 if (transfer32)
|
rlm@1
|
2073 {
|
rlm@1
|
2074 s &= 0xFFFFFFFC;
|
rlm@1
|
2075 if (s < 0x02000000 && (reg[15].I >> 24))
|
rlm@1
|
2076 {
|
rlm@1
|
2077 while (c != 0)
|
rlm@1
|
2078 {
|
rlm@1
|
2079 CPUWriteMemory(d, 0);
|
rlm@1
|
2080 d += di;
|
rlm@1
|
2081 c--;
|
rlm@1
|
2082 }
|
rlm@1
|
2083 }
|
rlm@1
|
2084 else
|
rlm@1
|
2085 {
|
rlm@1
|
2086 while (c != 0)
|
rlm@1
|
2087 {
|
rlm@1
|
2088 CPUWriteMemory(d, CPUReadMemory(s));
|
rlm@1
|
2089 d += di;
|
rlm@1
|
2090 s += si;
|
rlm@1
|
2091 c--;
|
rlm@1
|
2092 }
|
rlm@1
|
2093 }
|
rlm@1
|
2094 }
|
rlm@1
|
2095 else
|
rlm@1
|
2096 {
|
rlm@1
|
2097 s &= 0xFFFFFFFE;
|
rlm@1
|
2098 si = (int)si >> 1;
|
rlm@1
|
2099 di = (int)di >> 1;
|
rlm@1
|
2100 if (s < 0x02000000 && (reg[15].I >> 24))
|
rlm@1
|
2101 {
|
rlm@1
|
2102 while (c != 0)
|
rlm@1
|
2103 {
|
rlm@1
|
2104 CPUWriteHalfWord(d, 0);
|
rlm@1
|
2105 d += di;
|
rlm@1
|
2106 c--;
|
rlm@1
|
2107 }
|
rlm@1
|
2108 }
|
rlm@1
|
2109 else
|
rlm@1
|
2110 {
|
rlm@1
|
2111 while (c != 0)
|
rlm@1
|
2112 {
|
rlm@1
|
2113 cpuDmaLast = CPUReadHalfWord(s);
|
rlm@1
|
2114 CPUWriteHalfWord(d, cpuDmaLast);
|
rlm@1
|
2115 d += di;
|
rlm@1
|
2116 s += si;
|
rlm@1
|
2117 c--;
|
rlm@1
|
2118 }
|
rlm@1
|
2119 }
|
rlm@1
|
2120 }
|
rlm@1
|
2121
|
rlm@1
|
2122 cpuDmaCount = 0;
|
rlm@1
|
2123
|
rlm@1
|
2124 int sw = 1 + memoryWaitSeq[sm & 15];
|
rlm@1
|
2125 int dw = 1 + memoryWaitSeq[dm & 15];
|
rlm@1
|
2126
|
rlm@1
|
2127 int totalTicks = 0;
|
rlm@1
|
2128
|
rlm@1
|
2129 if (transfer32)
|
rlm@1
|
2130 {
|
rlm@1
|
2131 if (!memory32[sm & 15])
|
rlm@1
|
2132 sw <<= 1;
|
rlm@1
|
2133 if (!memory32[dm & 15])
|
rlm@1
|
2134 dw <<= 1;
|
rlm@1
|
2135 }
|
rlm@1
|
2136
|
rlm@1
|
2137 totalTicks = (sw + dw) * sc;
|
rlm@1
|
2138
|
rlm@1
|
2139 cpuDmaTicksToUpdate += totalTicks;
|
rlm@1
|
2140
|
rlm@1
|
2141 if (*extCpuLoopTicks >= 0)
|
rlm@1
|
2142 {
|
rlm@1
|
2143 CPU_BREAK_LOOP;
|
rlm@1
|
2144 }
|
rlm@1
|
2145 }
|
rlm@1
|
2146
|
rlm@1
|
2147 void CPUCheckDMA(int reason, int dmamask)
|
rlm@1
|
2148 {
|
rlm@1
|
2149 cpuDmaHack = 0;
|
rlm@1
|
2150 // DMA 0
|
rlm@1
|
2151 if ((DM0CNT_H & 0x8000) && (dmamask & 1))
|
rlm@1
|
2152 {
|
rlm@1
|
2153 if (((DM0CNT_H >> 12) & 3) == reason)
|
rlm@1
|
2154 {
|
rlm@1
|
2155 u32 sourceIncrement = 4;
|
rlm@1
|
2156 u32 destIncrement = 4;
|
rlm@1
|
2157 switch ((DM0CNT_H >> 7) & 3)
|
rlm@1
|
2158 {
|
rlm@1
|
2159 case 0:
|
rlm@1
|
2160 break;
|
rlm@1
|
2161 case 1:
|
rlm@1
|
2162 sourceIncrement = (u32) - 4;
|
rlm@1
|
2163 break;
|
rlm@1
|
2164 case 2:
|
rlm@1
|
2165 sourceIncrement = 0;
|
rlm@1
|
2166 break;
|
rlm@1
|
2167 }
|
rlm@1
|
2168 switch ((DM0CNT_H >> 5) & 3)
|
rlm@1
|
2169 {
|
rlm@1
|
2170 case 0:
|
rlm@1
|
2171 break;
|
rlm@1
|
2172 case 1:
|
rlm@1
|
2173 destIncrement = (u32) - 4;
|
rlm@1
|
2174 break;
|
rlm@1
|
2175 case 2:
|
rlm@1
|
2176 destIncrement = 0;
|
rlm@1
|
2177 break;
|
rlm@1
|
2178 }
|
rlm@1
|
2179 #ifdef GBA_LOGGING
|
rlm@1
|
2180 if (systemVerbose & VERBOSE_DMA0)
|
rlm@1
|
2181 {
|
rlm@1
|
2182 int count = (DM0CNT_L ? DM0CNT_L : 0x4000) << 1;
|
rlm@1
|
2183 if (DM0CNT_H & 0x0400)
|
rlm@1
|
2184 count <<= 1;
|
rlm@1
|
2185 log("DMA0: s=%08x d=%08x c=%04x count=%08x\n", dma0Source, dma0Dest,
|
rlm@1
|
2186 DM0CNT_H,
|
rlm@1
|
2187 count);
|
rlm@1
|
2188 }
|
rlm@1
|
2189 #endif
|
rlm@1
|
2190 doDMA(dma0Source, dma0Dest, sourceIncrement, destIncrement,
|
rlm@1
|
2191 DM0CNT_L ? DM0CNT_L : 0x4000,
|
rlm@1
|
2192 DM0CNT_H & 0x0400);
|
rlm@1
|
2193 cpuDmaHack = 1;
|
rlm@1
|
2194 if (DM0CNT_H & 0x4000)
|
rlm@1
|
2195 {
|
rlm@1
|
2196 IF |= 0x0100;
|
rlm@1
|
2197 UPDATE_REG(0x202, IF);
|
rlm@1
|
2198 }
|
rlm@1
|
2199
|
rlm@1
|
2200 if (((DM0CNT_H >> 5) & 3) == 3)
|
rlm@1
|
2201 {
|
rlm@1
|
2202 dma0Dest = DM0DAD_L | (DM0DAD_H << 16);
|
rlm@1
|
2203 }
|
rlm@1
|
2204
|
rlm@1
|
2205 if (!(DM0CNT_H & 0x0200) || (reason == 0))
|
rlm@1
|
2206 {
|
rlm@1
|
2207 DM0CNT_H &= 0x7FFF;
|
rlm@1
|
2208 UPDATE_REG(0xBA, DM0CNT_H);
|
rlm@1
|
2209 }
|
rlm@1
|
2210 }
|
rlm@1
|
2211 }
|
rlm@1
|
2212
|
rlm@1
|
2213 // DMA 1
|
rlm@1
|
2214 if ((DM1CNT_H & 0x8000) && (dmamask & 2))
|
rlm@1
|
2215 {
|
rlm@1
|
2216 if (((DM1CNT_H >> 12) & 3) == reason)
|
rlm@1
|
2217 {
|
rlm@1
|
2218 u32 sourceIncrement = 4;
|
rlm@1
|
2219 u32 destIncrement = 4;
|
rlm@1
|
2220 switch ((DM1CNT_H >> 7) & 3)
|
rlm@1
|
2221 {
|
rlm@1
|
2222 case 0:
|
rlm@1
|
2223 break;
|
rlm@1
|
2224 case 1:
|
rlm@1
|
2225 sourceIncrement = (u32) - 4;
|
rlm@1
|
2226 break;
|
rlm@1
|
2227 case 2:
|
rlm@1
|
2228 sourceIncrement = 0;
|
rlm@1
|
2229 break;
|
rlm@1
|
2230 }
|
rlm@1
|
2231 switch ((DM1CNT_H >> 5) & 3)
|
rlm@1
|
2232 {
|
rlm@1
|
2233 case 0:
|
rlm@1
|
2234 break;
|
rlm@1
|
2235 case 1:
|
rlm@1
|
2236 destIncrement = (u32) - 4;
|
rlm@1
|
2237 break;
|
rlm@1
|
2238 case 2:
|
rlm@1
|
2239 destIncrement = 0;
|
rlm@1
|
2240 break;
|
rlm@1
|
2241 }
|
rlm@1
|
2242 if (reason == 3)
|
rlm@1
|
2243 {
|
rlm@1
|
2244 #ifdef GBA_LOGGING
|
rlm@1
|
2245 if (systemVerbose & VERBOSE_DMA1)
|
rlm@1
|
2246 {
|
rlm@1
|
2247 log("DMA1: s=%08x d=%08x c=%04x count=%08x\n", dma1Source, dma1Dest,
|
rlm@1
|
2248 DM1CNT_H,
|
rlm@1
|
2249 16);
|
rlm@1
|
2250 }
|
rlm@1
|
2251 #endif
|
rlm@1
|
2252 doDMA(dma1Source, dma1Dest, sourceIncrement, 0, 4,
|
rlm@1
|
2253 0x0400);
|
rlm@1
|
2254 }
|
rlm@1
|
2255 else
|
rlm@1
|
2256 {
|
rlm@1
|
2257 #ifdef GBA_LOGGING
|
rlm@1
|
2258 if (systemVerbose & VERBOSE_DMA1)
|
rlm@1
|
2259 {
|
rlm@1
|
2260 int count = (DM1CNT_L ? DM1CNT_L : 0x4000) << 1;
|
rlm@1
|
2261 if (DM1CNT_H & 0x0400)
|
rlm@1
|
2262 count <<= 1;
|
rlm@1
|
2263 log("DMA1: s=%08x d=%08x c=%04x count=%08x\n", dma1Source, dma1Dest,
|
rlm@1
|
2264 DM1CNT_H,
|
rlm@1
|
2265 count);
|
rlm@1
|
2266 }
|
rlm@1
|
2267 #endif
|
rlm@1
|
2268 doDMA(dma1Source, dma1Dest, sourceIncrement, destIncrement,
|
rlm@1
|
2269 DM1CNT_L ? DM1CNT_L : 0x4000,
|
rlm@1
|
2270 DM1CNT_H & 0x0400);
|
rlm@1
|
2271 }
|
rlm@1
|
2272 cpuDmaHack = 1;
|
rlm@1
|
2273
|
rlm@1
|
2274 if (DM1CNT_H & 0x4000)
|
rlm@1
|
2275 {
|
rlm@1
|
2276 IF |= 0x0200;
|
rlm@1
|
2277 UPDATE_REG(0x202, IF);
|
rlm@1
|
2278 }
|
rlm@1
|
2279
|
rlm@1
|
2280 if (((DM1CNT_H >> 5) & 3) == 3)
|
rlm@1
|
2281 {
|
rlm@1
|
2282 dma1Dest = DM1DAD_L | (DM1DAD_H << 16);
|
rlm@1
|
2283 }
|
rlm@1
|
2284
|
rlm@1
|
2285 if (!(DM1CNT_H & 0x0200) || (reason == 0))
|
rlm@1
|
2286 {
|
rlm@1
|
2287 DM1CNT_H &= 0x7FFF;
|
rlm@1
|
2288 UPDATE_REG(0xC6, DM1CNT_H);
|
rlm@1
|
2289 }
|
rlm@1
|
2290 }
|
rlm@1
|
2291 }
|
rlm@1
|
2292
|
rlm@1
|
2293 // DMA 2
|
rlm@1
|
2294 if ((DM2CNT_H & 0x8000) && (dmamask & 4))
|
rlm@1
|
2295 {
|
rlm@1
|
2296 if (((DM2CNT_H >> 12) & 3) == reason)
|
rlm@1
|
2297 {
|
rlm@1
|
2298 u32 sourceIncrement = 4;
|
rlm@1
|
2299 u32 destIncrement = 4;
|
rlm@1
|
2300 switch ((DM2CNT_H >> 7) & 3)
|
rlm@1
|
2301 {
|
rlm@1
|
2302 case 0:
|
rlm@1
|
2303 break;
|
rlm@1
|
2304 case 1:
|
rlm@1
|
2305 sourceIncrement = (u32) - 4;
|
rlm@1
|
2306 break;
|
rlm@1
|
2307 case 2:
|
rlm@1
|
2308 sourceIncrement = 0;
|
rlm@1
|
2309 break;
|
rlm@1
|
2310 }
|
rlm@1
|
2311 switch ((DM2CNT_H >> 5) & 3)
|
rlm@1
|
2312 {
|
rlm@1
|
2313 case 0:
|
rlm@1
|
2314 break;
|
rlm@1
|
2315 case 1:
|
rlm@1
|
2316 destIncrement = (u32) - 4;
|
rlm@1
|
2317 break;
|
rlm@1
|
2318 case 2:
|
rlm@1
|
2319 destIncrement = 0;
|
rlm@1
|
2320 break;
|
rlm@1
|
2321 }
|
rlm@1
|
2322 if (reason == 3)
|
rlm@1
|
2323 {
|
rlm@1
|
2324 #ifdef GBA_LOGGING
|
rlm@1
|
2325 if (systemVerbose & VERBOSE_DMA2)
|
rlm@1
|
2326 {
|
rlm@1
|
2327 int count = (4) << 2;
|
rlm@1
|
2328 log("DMA2: s=%08x d=%08x c=%04x count=%08x\n", dma2Source, dma2Dest,
|
rlm@1
|
2329 DM2CNT_H,
|
rlm@1
|
2330 count);
|
rlm@1
|
2331 }
|
rlm@1
|
2332 #endif
|
rlm@1
|
2333 doDMA(dma2Source, dma2Dest, sourceIncrement, 0, 4,
|
rlm@1
|
2334 0x0400);
|
rlm@1
|
2335 }
|
rlm@1
|
2336 else
|
rlm@1
|
2337 {
|
rlm@1
|
2338 #ifdef GBA_LOGGING
|
rlm@1
|
2339 if (systemVerbose & VERBOSE_DMA2)
|
rlm@1
|
2340 {
|
rlm@1
|
2341 int count = (DM2CNT_L ? DM2CNT_L : 0x4000) << 1;
|
rlm@1
|
2342 if (DM2CNT_H & 0x0400)
|
rlm@1
|
2343 count <<= 1;
|
rlm@1
|
2344 log("DMA2: s=%08x d=%08x c=%04x count=%08x\n", dma2Source, dma2Dest,
|
rlm@1
|
2345 DM2CNT_H,
|
rlm@1
|
2346 count);
|
rlm@1
|
2347 }
|
rlm@1
|
2348 #endif
|
rlm@1
|
2349 doDMA(dma2Source, dma2Dest, sourceIncrement, destIncrement,
|
rlm@1
|
2350 DM2CNT_L ? DM2CNT_L : 0x4000,
|
rlm@1
|
2351 DM2CNT_H & 0x0400);
|
rlm@1
|
2352 }
|
rlm@1
|
2353 cpuDmaHack = 1;
|
rlm@1
|
2354 if (DM2CNT_H & 0x4000)
|
rlm@1
|
2355 {
|
rlm@1
|
2356 IF |= 0x0400;
|
rlm@1
|
2357 UPDATE_REG(0x202, IF);
|
rlm@1
|
2358 }
|
rlm@1
|
2359
|
rlm@1
|
2360 if (((DM2CNT_H >> 5) & 3) == 3)
|
rlm@1
|
2361 {
|
rlm@1
|
2362 dma2Dest = DM2DAD_L | (DM2DAD_H << 16);
|
rlm@1
|
2363 }
|
rlm@1
|
2364
|
rlm@1
|
2365 if (!(DM2CNT_H & 0x0200) || (reason == 0))
|
rlm@1
|
2366 {
|
rlm@1
|
2367 DM2CNT_H &= 0x7FFF;
|
rlm@1
|
2368 UPDATE_REG(0xD2, DM2CNT_H);
|
rlm@1
|
2369 }
|
rlm@1
|
2370 }
|
rlm@1
|
2371 }
|
rlm@1
|
2372
|
rlm@1
|
2373 // DMA 3
|
rlm@1
|
2374 if ((DM3CNT_H & 0x8000) && (dmamask & 8))
|
rlm@1
|
2375 {
|
rlm@1
|
2376 if (((DM3CNT_H >> 12) & 3) == reason)
|
rlm@1
|
2377 {
|
rlm@1
|
2378 u32 sourceIncrement = 4;
|
rlm@1
|
2379 u32 destIncrement = 4;
|
rlm@1
|
2380 switch ((DM3CNT_H >> 7) & 3)
|
rlm@1
|
2381 {
|
rlm@1
|
2382 case 0:
|
rlm@1
|
2383 break;
|
rlm@1
|
2384 case 1:
|
rlm@1
|
2385 sourceIncrement = (u32) - 4;
|
rlm@1
|
2386 break;
|
rlm@1
|
2387 case 2:
|
rlm@1
|
2388 sourceIncrement = 0;
|
rlm@1
|
2389 break;
|
rlm@1
|
2390 }
|
rlm@1
|
2391 switch ((DM3CNT_H >> 5) & 3)
|
rlm@1
|
2392 {
|
rlm@1
|
2393 case 0:
|
rlm@1
|
2394 break;
|
rlm@1
|
2395 case 1:
|
rlm@1
|
2396 destIncrement = (u32) - 4;
|
rlm@1
|
2397 break;
|
rlm@1
|
2398 case 2:
|
rlm@1
|
2399 destIncrement = 0;
|
rlm@1
|
2400 break;
|
rlm@1
|
2401 }
|
rlm@1
|
2402 #ifdef GBA_LOGGING
|
rlm@1
|
2403 if (systemVerbose & VERBOSE_DMA3)
|
rlm@1
|
2404 {
|
rlm@1
|
2405 int count = (DM3CNT_L ? DM3CNT_L : 0x10000) << 1;
|
rlm@1
|
2406 if (DM3CNT_H & 0x0400)
|
rlm@1
|
2407 count <<= 1;
|
rlm@1
|
2408 log("DMA3: s=%08x d=%08x c=%04x count=%08x\n", dma3Source, dma3Dest,
|
rlm@1
|
2409 DM3CNT_H,
|
rlm@1
|
2410 count);
|
rlm@1
|
2411 }
|
rlm@1
|
2412 #endif
|
rlm@1
|
2413 doDMA(dma3Source, dma3Dest, sourceIncrement, destIncrement,
|
rlm@1
|
2414 DM3CNT_L ? DM3CNT_L : 0x10000,
|
rlm@1
|
2415 DM3CNT_H & 0x0400);
|
rlm@1
|
2416 if (DM3CNT_H & 0x4000)
|
rlm@1
|
2417 {
|
rlm@1
|
2418 IF |= 0x0800;
|
rlm@1
|
2419 UPDATE_REG(0x202, IF);
|
rlm@1
|
2420 }
|
rlm@1
|
2421
|
rlm@1
|
2422 if (((DM3CNT_H >> 5) & 3) == 3)
|
rlm@1
|
2423 {
|
rlm@1
|
2424 dma3Dest = DM3DAD_L | (DM3DAD_H << 16);
|
rlm@1
|
2425 }
|
rlm@1
|
2426
|
rlm@1
|
2427 if (!(DM3CNT_H & 0x0200) || (reason == 0))
|
rlm@1
|
2428 {
|
rlm@1
|
2429 DM3CNT_H &= 0x7FFF;
|
rlm@1
|
2430 UPDATE_REG(0xDE, DM3CNT_H);
|
rlm@1
|
2431 }
|
rlm@1
|
2432 }
|
rlm@1
|
2433 }
|
rlm@1
|
2434 cpuDmaHack = 0;
|
rlm@1
|
2435 }
|
rlm@1
|
2436
|
rlm@1
|
2437 void CPUUpdateRegister(u32 address, u16 value)
|
rlm@1
|
2438 {
|
rlm@1
|
2439 switch (address)
|
rlm@1
|
2440 {
|
rlm@1
|
2441 case 0x00:
|
rlm@1
|
2442 {
|
rlm@1
|
2443 bool change = ((DISPCNT ^ value) & 0x80) ? true : false;
|
rlm@1
|
2444 bool changeBG = ((DISPCNT ^ value) & 0x0F00) ? true : false;
|
rlm@1
|
2445 DISPCNT = (value & 0xFFF7);
|
rlm@1
|
2446 UPDATE_REG(0x00, DISPCNT);
|
rlm@1
|
2447 layerEnable = layerSettings & value;
|
rlm@1
|
2448 windowOn = (layerEnable & 0x6000) ? true : false;
|
rlm@1
|
2449 if (change && !((value & 0x80)))
|
rlm@1
|
2450 {
|
rlm@1
|
2451 if (!(DISPSTAT & 1))
|
rlm@1
|
2452 {
|
rlm@1
|
2453 lcdTicks = 960;
|
rlm@1
|
2454 // VCOUNT = 0;
|
rlm@1
|
2455 // UPDATE_REG(0x06, VCOUNT);
|
rlm@1
|
2456 DISPSTAT &= 0xFFFC;
|
rlm@1
|
2457 UPDATE_REG(0x04, DISPSTAT);
|
rlm@1
|
2458 CPUCompareVCOUNT();
|
rlm@1
|
2459 }
|
rlm@1
|
2460 // (*renderLine)();
|
rlm@1
|
2461 }
|
rlm@1
|
2462 CPUUpdateRender();
|
rlm@1
|
2463 // we only care about changes in BG0-BG3
|
rlm@1
|
2464 if (changeBG)
|
rlm@1
|
2465 CPUUpdateRenderBuffers(false);
|
rlm@1
|
2466 // CPUUpdateTicks();
|
rlm@1
|
2467 break;
|
rlm@1
|
2468 }
|
rlm@1
|
2469 case 0x04:
|
rlm@1
|
2470 DISPSTAT = (value & 0xFF38) | (DISPSTAT & 7);
|
rlm@1
|
2471 UPDATE_REG(0x04, DISPSTAT);
|
rlm@1
|
2472 break;
|
rlm@1
|
2473 case 0x06:
|
rlm@1
|
2474 // not writable
|
rlm@1
|
2475 break;
|
rlm@1
|
2476 case 0x08:
|
rlm@1
|
2477 BG0CNT = (value & 0xDFCF);
|
rlm@1
|
2478 UPDATE_REG(0x08, BG0CNT);
|
rlm@1
|
2479 break;
|
rlm@1
|
2480 case 0x0A:
|
rlm@1
|
2481 BG1CNT = (value & 0xDFCF);
|
rlm@1
|
2482 UPDATE_REG(0x0A, BG1CNT);
|
rlm@1
|
2483 break;
|
rlm@1
|
2484 case 0x0C:
|
rlm@1
|
2485 BG2CNT = (value & 0xFFCF);
|
rlm@1
|
2486 UPDATE_REG(0x0C, BG2CNT);
|
rlm@1
|
2487 break;
|
rlm@1
|
2488 case 0x0E:
|
rlm@1
|
2489 BG3CNT = (value & 0xFFCF);
|
rlm@1
|
2490 UPDATE_REG(0x0E, BG3CNT);
|
rlm@1
|
2491 break;
|
rlm@1
|
2492 case 0x10:
|
rlm@1
|
2493 BG0HOFS = value & 511;
|
rlm@1
|
2494 UPDATE_REG(0x10, BG0HOFS);
|
rlm@1
|
2495 break;
|
rlm@1
|
2496 case 0x12:
|
rlm@1
|
2497 BG0VOFS = value & 511;
|
rlm@1
|
2498 UPDATE_REG(0x12, BG0VOFS);
|
rlm@1
|
2499 break;
|
rlm@1
|
2500 case 0x14:
|
rlm@1
|
2501 BG1HOFS = value & 511;
|
rlm@1
|
2502 UPDATE_REG(0x14, BG1HOFS);
|
rlm@1
|
2503 break;
|
rlm@1
|
2504 case 0x16:
|
rlm@1
|
2505 BG1VOFS = value & 511;
|
rlm@1
|
2506 UPDATE_REG(0x16, BG1VOFS);
|
rlm@1
|
2507 break;
|
rlm@1
|
2508 case 0x18:
|
rlm@1
|
2509 BG2HOFS = value & 511;
|
rlm@1
|
2510 UPDATE_REG(0x18, BG2HOFS);
|
rlm@1
|
2511 break;
|
rlm@1
|
2512 case 0x1A:
|
rlm@1
|
2513 BG2VOFS = value & 511;
|
rlm@1
|
2514 UPDATE_REG(0x1A, BG2VOFS);
|
rlm@1
|
2515 break;
|
rlm@1
|
2516 case 0x1C:
|
rlm@1
|
2517 BG3HOFS = value & 511;
|
rlm@1
|
2518 UPDATE_REG(0x1C, BG3HOFS);
|
rlm@1
|
2519 break;
|
rlm@1
|
2520 case 0x1E:
|
rlm@1
|
2521 BG3VOFS = value & 511;
|
rlm@1
|
2522 UPDATE_REG(0x1E, BG3VOFS);
|
rlm@1
|
2523 break;
|
rlm@1
|
2524 case 0x20:
|
rlm@1
|
2525 BG2PA = value;
|
rlm@1
|
2526 UPDATE_REG(0x20, BG2PA);
|
rlm@1
|
2527 break;
|
rlm@1
|
2528 case 0x22:
|
rlm@1
|
2529 BG2PB = value;
|
rlm@1
|
2530 UPDATE_REG(0x22, BG2PB);
|
rlm@1
|
2531 break;
|
rlm@1
|
2532 case 0x24:
|
rlm@1
|
2533 BG2PC = value;
|
rlm@1
|
2534 UPDATE_REG(0x24, BG2PC);
|
rlm@1
|
2535 break;
|
rlm@1
|
2536 case 0x26:
|
rlm@1
|
2537 BG2PD = value;
|
rlm@1
|
2538 UPDATE_REG(0x26, BG2PD);
|
rlm@1
|
2539 break;
|
rlm@1
|
2540 case 0x28:
|
rlm@1
|
2541 BG2X_L = value;
|
rlm@1
|
2542 UPDATE_REG(0x28, BG2X_L);
|
rlm@1
|
2543 gfxBG2Changed |= 1;
|
rlm@1
|
2544 break;
|
rlm@1
|
2545 case 0x2A:
|
rlm@1
|
2546 BG2X_H = (value & 0xFFF);
|
rlm@1
|
2547 UPDATE_REG(0x2A, BG2X_H);
|
rlm@1
|
2548 gfxBG2Changed |= 1;
|
rlm@1
|
2549 break;
|
rlm@1
|
2550 case 0x2C:
|
rlm@1
|
2551 BG2Y_L = value;
|
rlm@1
|
2552 UPDATE_REG(0x2C, BG2Y_L);
|
rlm@1
|
2553 gfxBG2Changed |= 2;
|
rlm@1
|
2554 break;
|
rlm@1
|
2555 case 0x2E:
|
rlm@1
|
2556 BG2Y_H = value & 0xFFF;
|
rlm@1
|
2557 UPDATE_REG(0x2E, BG2Y_H);
|
rlm@1
|
2558 gfxBG2Changed |= 2;
|
rlm@1
|
2559 break;
|
rlm@1
|
2560 case 0x30:
|
rlm@1
|
2561 BG3PA = value;
|
rlm@1
|
2562 UPDATE_REG(0x30, BG3PA);
|
rlm@1
|
2563 break;
|
rlm@1
|
2564 case 0x32:
|
rlm@1
|
2565 BG3PB = value;
|
rlm@1
|
2566 UPDATE_REG(0x32, BG3PB);
|
rlm@1
|
2567 break;
|
rlm@1
|
2568 case 0x34:
|
rlm@1
|
2569 BG3PC = value;
|
rlm@1
|
2570 UPDATE_REG(0x34, BG3PC);
|
rlm@1
|
2571 break;
|
rlm@1
|
2572 case 0x36:
|
rlm@1
|
2573 BG3PD = value;
|
rlm@1
|
2574 UPDATE_REG(0x36, BG3PD);
|
rlm@1
|
2575 break;
|
rlm@1
|
2576 case 0x38:
|
rlm@1
|
2577 BG3X_L = value;
|
rlm@1
|
2578 UPDATE_REG(0x38, BG3X_L);
|
rlm@1
|
2579 gfxBG3Changed |= 1;
|
rlm@1
|
2580 break;
|
rlm@1
|
2581 case 0x3A:
|
rlm@1
|
2582 BG3X_H = value & 0xFFF;
|
rlm@1
|
2583 UPDATE_REG(0x3A, BG3X_H);
|
rlm@1
|
2584 gfxBG3Changed |= 1;
|
rlm@1
|
2585 break;
|
rlm@1
|
2586 case 0x3C:
|
rlm@1
|
2587 BG3Y_L = value;
|
rlm@1
|
2588 UPDATE_REG(0x3C, BG3Y_L);
|
rlm@1
|
2589 gfxBG3Changed |= 2;
|
rlm@1
|
2590 break;
|
rlm@1
|
2591 case 0x3E:
|
rlm@1
|
2592 BG3Y_H = value & 0xFFF;
|
rlm@1
|
2593 UPDATE_REG(0x3E, BG3Y_H);
|
rlm@1
|
2594 gfxBG3Changed |= 2;
|
rlm@1
|
2595 break;
|
rlm@1
|
2596 case 0x40:
|
rlm@1
|
2597 WIN0H = value;
|
rlm@1
|
2598 UPDATE_REG(0x40, WIN0H);
|
rlm@1
|
2599 CPUUpdateWindow0();
|
rlm@1
|
2600 break;
|
rlm@1
|
2601 case 0x42:
|
rlm@1
|
2602 WIN1H = value;
|
rlm@1
|
2603 UPDATE_REG(0x42, WIN1H);
|
rlm@1
|
2604 CPUUpdateWindow1();
|
rlm@1
|
2605 break;
|
rlm@1
|
2606 case 0x44:
|
rlm@1
|
2607 WIN0V = value;
|
rlm@1
|
2608 UPDATE_REG(0x44, WIN0V);
|
rlm@1
|
2609 break;
|
rlm@1
|
2610 case 0x46:
|
rlm@1
|
2611 WIN1V = value;
|
rlm@1
|
2612 UPDATE_REG(0x46, WIN1V);
|
rlm@1
|
2613 break;
|
rlm@1
|
2614 case 0x48:
|
rlm@1
|
2615 WININ = value & 0x3F3F;
|
rlm@1
|
2616 UPDATE_REG(0x48, WININ);
|
rlm@1
|
2617 break;
|
rlm@1
|
2618 case 0x4A:
|
rlm@1
|
2619 WINOUT = value & 0x3F3F;
|
rlm@1
|
2620 UPDATE_REG(0x4A, WINOUT);
|
rlm@1
|
2621 break;
|
rlm@1
|
2622 case 0x4C:
|
rlm@1
|
2623 MOSAIC = value;
|
rlm@1
|
2624 UPDATE_REG(0x4C, MOSAIC);
|
rlm@1
|
2625 break;
|
rlm@1
|
2626 case 0x50:
|
rlm@1
|
2627 BLDMOD = value & 0x3FFF;
|
rlm@1
|
2628 UPDATE_REG(0x50, BLDMOD);
|
rlm@1
|
2629 fxOn = ((BLDMOD >> 6) & 3) != 0;
|
rlm@1
|
2630 CPUUpdateRender();
|
rlm@1
|
2631 break;
|
rlm@1
|
2632 case 0x52:
|
rlm@1
|
2633 COLEV = value & 0x1F1F;
|
rlm@1
|
2634 UPDATE_REG(0x52, COLEV);
|
rlm@1
|
2635 break;
|
rlm@1
|
2636 case 0x54:
|
rlm@1
|
2637 COLY = value & 0x1F;
|
rlm@1
|
2638 UPDATE_REG(0x54, COLY);
|
rlm@1
|
2639 break;
|
rlm@1
|
2640 case 0x60:
|
rlm@1
|
2641 case 0x62:
|
rlm@1
|
2642 case 0x64:
|
rlm@1
|
2643 case 0x68:
|
rlm@1
|
2644 case 0x6c:
|
rlm@1
|
2645 case 0x70:
|
rlm@1
|
2646 case 0x72:
|
rlm@1
|
2647 case 0x74:
|
rlm@1
|
2648 case 0x78:
|
rlm@1
|
2649 case 0x7c:
|
rlm@1
|
2650 case 0x80:
|
rlm@1
|
2651 case 0x84:
|
rlm@1
|
2652 soundEvent(address & 0xFF, (u8)(value & 0xFF));
|
rlm@1
|
2653 soundEvent((address & 0xFF) + 1, (u8)(value >> 8));
|
rlm@1
|
2654 break;
|
rlm@1
|
2655 case 0x82:
|
rlm@1
|
2656 case 0x88:
|
rlm@1
|
2657 case 0xa0:
|
rlm@1
|
2658 case 0xa2:
|
rlm@1
|
2659 case 0xa4:
|
rlm@1
|
2660 case 0xa6:
|
rlm@1
|
2661 case 0x90:
|
rlm@1
|
2662 case 0x92:
|
rlm@1
|
2663 case 0x94:
|
rlm@1
|
2664 case 0x96:
|
rlm@1
|
2665 case 0x98:
|
rlm@1
|
2666 case 0x9a:
|
rlm@1
|
2667 case 0x9c:
|
rlm@1
|
2668 case 0x9e:
|
rlm@1
|
2669 soundEvent(address & 0xFF, value);
|
rlm@1
|
2670 break;
|
rlm@1
|
2671 case 0xB0:
|
rlm@1
|
2672 DM0SAD_L = value;
|
rlm@1
|
2673 UPDATE_REG(0xB0, DM0SAD_L);
|
rlm@1
|
2674 break;
|
rlm@1
|
2675 case 0xB2:
|
rlm@1
|
2676 DM0SAD_H = value & 0x07FF;
|
rlm@1
|
2677 UPDATE_REG(0xB2, DM0SAD_H);
|
rlm@1
|
2678 break;
|
rlm@1
|
2679 case 0xB4:
|
rlm@1
|
2680 DM0DAD_L = value;
|
rlm@1
|
2681 UPDATE_REG(0xB4, DM0DAD_L);
|
rlm@1
|
2682 break;
|
rlm@1
|
2683 case 0xB6:
|
rlm@1
|
2684 DM0DAD_H = value & 0x07FF;
|
rlm@1
|
2685 UPDATE_REG(0xB6, DM0DAD_H);
|
rlm@1
|
2686 break;
|
rlm@1
|
2687 case 0xB8:
|
rlm@1
|
2688 DM0CNT_L = value & 0x3FFF;
|
rlm@1
|
2689 UPDATE_REG(0xB8, 0);
|
rlm@1
|
2690 break;
|
rlm@1
|
2691 case 0xBA:
|
rlm@1
|
2692 {
|
rlm@1
|
2693 bool start = ((DM0CNT_H ^ value) & 0x8000) ? true : false;
|
rlm@1
|
2694 value &= 0xF7E0;
|
rlm@1
|
2695
|
rlm@1
|
2696 DM0CNT_H = value;
|
rlm@1
|
2697 UPDATE_REG(0xBA, DM0CNT_H);
|
rlm@1
|
2698
|
rlm@1
|
2699 if (start && (value & 0x8000))
|
rlm@1
|
2700 {
|
rlm@1
|
2701 dma0Source = DM0SAD_L | (DM0SAD_H << 16);
|
rlm@1
|
2702 dma0Dest = DM0DAD_L | (DM0DAD_H << 16);
|
rlm@1
|
2703 CPUCheckDMA(0, 1);
|
rlm@1
|
2704 }
|
rlm@1
|
2705 break;
|
rlm@1
|
2706 }
|
rlm@1
|
2707 case 0xBC:
|
rlm@1
|
2708 DM1SAD_L = value;
|
rlm@1
|
2709 UPDATE_REG(0xBC, DM1SAD_L);
|
rlm@1
|
2710 break;
|
rlm@1
|
2711 case 0xBE:
|
rlm@1
|
2712 DM1SAD_H = value & 0x0FFF;
|
rlm@1
|
2713 UPDATE_REG(0xBE, DM1SAD_H);
|
rlm@1
|
2714 break;
|
rlm@1
|
2715 case 0xC0:
|
rlm@1
|
2716 DM1DAD_L = value;
|
rlm@1
|
2717 UPDATE_REG(0xC0, DM1DAD_L);
|
rlm@1
|
2718 break;
|
rlm@1
|
2719 case 0xC2:
|
rlm@1
|
2720 DM1DAD_H = value & 0x07FF;
|
rlm@1
|
2721 UPDATE_REG(0xC2, DM1DAD_H);
|
rlm@1
|
2722 break;
|
rlm@1
|
2723 case 0xC4:
|
rlm@1
|
2724 DM1CNT_L = value & 0x3FFF;
|
rlm@1
|
2725 UPDATE_REG(0xC4, 0);
|
rlm@1
|
2726 break;
|
rlm@1
|
2727 case 0xC6:
|
rlm@1
|
2728 {
|
rlm@1
|
2729 bool start = ((DM1CNT_H ^ value) & 0x8000) ? true : false;
|
rlm@1
|
2730 value &= 0xF7E0;
|
rlm@1
|
2731
|
rlm@1
|
2732 DM1CNT_H = value;
|
rlm@1
|
2733 UPDATE_REG(0xC6, DM1CNT_H);
|
rlm@1
|
2734
|
rlm@1
|
2735 if (start && (value & 0x8000))
|
rlm@1
|
2736 {
|
rlm@1
|
2737 dma1Source = DM1SAD_L | (DM1SAD_H << 16);
|
rlm@1
|
2738 dma1Dest = DM1DAD_L | (DM1DAD_H << 16);
|
rlm@1
|
2739 CPUCheckDMA(0, 2);
|
rlm@1
|
2740 }
|
rlm@1
|
2741 break;
|
rlm@1
|
2742 }
|
rlm@1
|
2743 case 0xC8:
|
rlm@1
|
2744 DM2SAD_L = value;
|
rlm@1
|
2745 UPDATE_REG(0xC8, DM2SAD_L);
|
rlm@1
|
2746 break;
|
rlm@1
|
2747 case 0xCA:
|
rlm@1
|
2748 DM2SAD_H = value & 0x0FFF;
|
rlm@1
|
2749 UPDATE_REG(0xCA, DM2SAD_H);
|
rlm@1
|
2750 break;
|
rlm@1
|
2751 case 0xCC:
|
rlm@1
|
2752 DM2DAD_L = value;
|
rlm@1
|
2753 UPDATE_REG(0xCC, DM2DAD_L);
|
rlm@1
|
2754 break;
|
rlm@1
|
2755 case 0xCE:
|
rlm@1
|
2756 DM2DAD_H = value & 0x07FF;
|
rlm@1
|
2757 UPDATE_REG(0xCE, DM2DAD_H);
|
rlm@1
|
2758 break;
|
rlm@1
|
2759 case 0xD0:
|
rlm@1
|
2760 DM2CNT_L = value & 0x3FFF;
|
rlm@1
|
2761 UPDATE_REG(0xD0, 0);
|
rlm@1
|
2762 break;
|
rlm@1
|
2763 case 0xD2:
|
rlm@1
|
2764 {
|
rlm@1
|
2765 bool start = ((DM2CNT_H ^ value) & 0x8000) ? true : false;
|
rlm@1
|
2766
|
rlm@1
|
2767 value &= 0xF7E0;
|
rlm@1
|
2768
|
rlm@1
|
2769 DM2CNT_H = value;
|
rlm@1
|
2770 UPDATE_REG(0xD2, DM2CNT_H);
|
rlm@1
|
2771
|
rlm@1
|
2772 if (start && (value & 0x8000))
|
rlm@1
|
2773 {
|
rlm@1
|
2774 dma2Source = DM2SAD_L | (DM2SAD_H << 16);
|
rlm@1
|
2775 dma2Dest = DM2DAD_L | (DM2DAD_H << 16);
|
rlm@1
|
2776
|
rlm@1
|
2777 CPUCheckDMA(0, 4);
|
rlm@1
|
2778 }
|
rlm@1
|
2779 break;
|
rlm@1
|
2780 }
|
rlm@1
|
2781 case 0xD4:
|
rlm@1
|
2782 DM3SAD_L = value;
|
rlm@1
|
2783 UPDATE_REG(0xD4, DM3SAD_L);
|
rlm@1
|
2784 break;
|
rlm@1
|
2785 case 0xD6:
|
rlm@1
|
2786 DM3SAD_H = value & 0x0FFF;
|
rlm@1
|
2787 UPDATE_REG(0xD6, DM3SAD_H);
|
rlm@1
|
2788 break;
|
rlm@1
|
2789 case 0xD8:
|
rlm@1
|
2790 DM3DAD_L = value;
|
rlm@1
|
2791 UPDATE_REG(0xD8, DM3DAD_L);
|
rlm@1
|
2792 break;
|
rlm@1
|
2793 case 0xDA:
|
rlm@1
|
2794 DM3DAD_H = value & 0x0FFF;
|
rlm@1
|
2795 UPDATE_REG(0xDA, DM3DAD_H);
|
rlm@1
|
2796 break;
|
rlm@1
|
2797 case 0xDC:
|
rlm@1
|
2798 DM3CNT_L = value;
|
rlm@1
|
2799 UPDATE_REG(0xDC, 0);
|
rlm@1
|
2800 break;
|
rlm@1
|
2801 case 0xDE:
|
rlm@1
|
2802 {
|
rlm@1
|
2803 bool start = ((DM3CNT_H ^ value) & 0x8000) ? true : false;
|
rlm@1
|
2804
|
rlm@1
|
2805 value &= 0xFFE0;
|
rlm@1
|
2806
|
rlm@1
|
2807 DM3CNT_H = value;
|
rlm@1
|
2808 UPDATE_REG(0xDE, DM3CNT_H);
|
rlm@1
|
2809
|
rlm@1
|
2810 if (start && (value & 0x8000))
|
rlm@1
|
2811 {
|
rlm@1
|
2812 dma3Source = DM3SAD_L | (DM3SAD_H << 16);
|
rlm@1
|
2813 dma3Dest = DM3DAD_L | (DM3DAD_H << 16);
|
rlm@1
|
2814 CPUCheckDMA(0, 8);
|
rlm@1
|
2815 }
|
rlm@1
|
2816 break;
|
rlm@1
|
2817 }
|
rlm@1
|
2818 case 0x100:
|
rlm@1
|
2819 timer0Reload = value;
|
rlm@1
|
2820 break;
|
rlm@1
|
2821 case 0x102:
|
rlm@1
|
2822 timer0Ticks = timer0ClockReload = TIMER_TICKS[value & 3];
|
rlm@1
|
2823 if (!timer0On && (value & 0x80))
|
rlm@1
|
2824 {
|
rlm@1
|
2825 // reload the counter
|
rlm@1
|
2826 TM0D = timer0Reload;
|
rlm@1
|
2827 if (timer0ClockReload == 1)
|
rlm@1
|
2828 timer0Ticks = 0x10000 - TM0D;
|
rlm@1
|
2829 UPDATE_REG(0x100, TM0D);
|
rlm@1
|
2830 }
|
rlm@1
|
2831 timer0On = value & 0x80 ? true : false;
|
rlm@1
|
2832 TM0CNT = value & 0xC7;
|
rlm@1
|
2833 UPDATE_REG(0x102, TM0CNT);
|
rlm@1
|
2834 // CPUUpdateTicks();
|
rlm@1
|
2835 break;
|
rlm@1
|
2836 case 0x104:
|
rlm@1
|
2837 timer1Reload = value;
|
rlm@1
|
2838 break;
|
rlm@1
|
2839 case 0x106:
|
rlm@1
|
2840 timer1Ticks = timer1ClockReload = TIMER_TICKS[value & 3];
|
rlm@1
|
2841 if (!timer1On && (value & 0x80))
|
rlm@1
|
2842 {
|
rlm@1
|
2843 // reload the counter
|
rlm@1
|
2844 TM1D = timer1Reload;
|
rlm@1
|
2845 if (timer1ClockReload == 1)
|
rlm@1
|
2846 timer1Ticks = 0x10000 - TM1D;
|
rlm@1
|
2847 UPDATE_REG(0x104, TM1D);
|
rlm@1
|
2848 }
|
rlm@1
|
2849 timer1On = value & 0x80 ? true : false;
|
rlm@1
|
2850 TM1CNT = value & 0xC7;
|
rlm@1
|
2851 UPDATE_REG(0x106, TM1CNT);
|
rlm@1
|
2852 break;
|
rlm@1
|
2853 case 0x108:
|
rlm@1
|
2854 timer2Reload = value;
|
rlm@1
|
2855 break;
|
rlm@1
|
2856 case 0x10A:
|
rlm@1
|
2857 timer2Ticks = timer2ClockReload = TIMER_TICKS[value & 3];
|
rlm@1
|
2858 if (!timer2On && (value & 0x80))
|
rlm@1
|
2859 {
|
rlm@1
|
2860 // reload the counter
|
rlm@1
|
2861 TM2D = timer2Reload;
|
rlm@1
|
2862 if (timer2ClockReload == 1)
|
rlm@1
|
2863 timer2Ticks = 0x10000 - TM2D;
|
rlm@1
|
2864 UPDATE_REG(0x108, TM2D);
|
rlm@1
|
2865 }
|
rlm@1
|
2866 timer2On = value & 0x80 ? true : false;
|
rlm@1
|
2867 TM2CNT = value & 0xC7;
|
rlm@1
|
2868 UPDATE_REG(0x10A, TM2CNT);
|
rlm@1
|
2869 break;
|
rlm@1
|
2870 case 0x10C:
|
rlm@1
|
2871 timer3Reload = value;
|
rlm@1
|
2872 break;
|
rlm@1
|
2873 case 0x10E:
|
rlm@1
|
2874 timer3Ticks = timer3ClockReload = TIMER_TICKS[value & 3];
|
rlm@1
|
2875 if (!timer3On && (value & 0x80))
|
rlm@1
|
2876 {
|
rlm@1
|
2877 // reload the counter
|
rlm@1
|
2878 TM3D = timer3Reload;
|
rlm@1
|
2879 if (timer3ClockReload == 1)
|
rlm@1
|
2880 timer3Ticks = 0x10000 - TM3D;
|
rlm@1
|
2881 UPDATE_REG(0x10C, TM3D);
|
rlm@1
|
2882 }
|
rlm@1
|
2883 timer3On = value & 0x80 ? true : false;
|
rlm@1
|
2884 TM3CNT = value & 0xC7;
|
rlm@1
|
2885 UPDATE_REG(0x10E, TM3CNT);
|
rlm@1
|
2886 break;
|
rlm@1
|
2887 case 0x128:
|
rlm@1
|
2888 if (value & 0x80)
|
rlm@1
|
2889 {
|
rlm@1
|
2890 value &= 0xff7f;
|
rlm@1
|
2891 if (value & 1 && (value & 0x4000))
|
rlm@1
|
2892 {
|
rlm@1
|
2893 UPDATE_REG(0x12a, 0xFF);
|
rlm@1
|
2894 IF |= 0x80;
|
rlm@1
|
2895 UPDATE_REG(0x202, IF);
|
rlm@1
|
2896 value &= 0x7f7f;
|
rlm@1
|
2897 }
|
rlm@1
|
2898 }
|
rlm@1
|
2899 UPDATE_REG(0x128, value);
|
rlm@1
|
2900 break;
|
rlm@1
|
2901 case 0x130:
|
rlm@1
|
2902 P1 |= (value & 0x3FF);
|
rlm@1
|
2903 UPDATE_REG(0x130, P1);
|
rlm@1
|
2904 break;
|
rlm@1
|
2905 case 0x132:
|
rlm@1
|
2906 UPDATE_REG(0x132, value & 0xC3FF);
|
rlm@1
|
2907 break;
|
rlm@1
|
2908 case 0x200:
|
rlm@1
|
2909 IE = value & 0x3FFF;
|
rlm@1
|
2910 UPDATE_REG(0x200, IE);
|
rlm@1
|
2911 if ((IME & 1) && (IF & IE) && armIrqEnable)
|
rlm@1
|
2912 {
|
rlm@1
|
2913 CPU_BREAK_LOOP_2;
|
rlm@1
|
2914 }
|
rlm@1
|
2915 break;
|
rlm@1
|
2916 case 0x202:
|
rlm@1
|
2917 IF ^= (value & IF);
|
rlm@1
|
2918 UPDATE_REG(0x202, IF);
|
rlm@1
|
2919 break;
|
rlm@1
|
2920 case 0x204:
|
rlm@1
|
2921 {
|
rlm@1
|
2922 int i;
|
rlm@1
|
2923 memoryWait[0x0e] = memoryWaitSeq[0x0e] = gamepakRamWaitState[value & 3];
|
rlm@1
|
2924
|
rlm@1
|
2925 if (!speedHack)
|
rlm@1
|
2926 {
|
rlm@1
|
2927 memoryWait[0x08] = memoryWait[0x09] = gamepakWaitState[(value >> 2) & 7];
|
rlm@1
|
2928 memoryWaitSeq[0x08] = memoryWaitSeq[0x09] =
|
rlm@1
|
2929 gamepakWaitState0[(value >> 2) & 7];
|
rlm@1
|
2930
|
rlm@1
|
2931 memoryWait[0x0a] = memoryWait[0x0b] = gamepakWaitState[(value >> 5) & 7];
|
rlm@1
|
2932 memoryWaitSeq[0x0a] = memoryWaitSeq[0x0b] =
|
rlm@1
|
2933 gamepakWaitState1[(value >> 5) & 7];
|
rlm@1
|
2934
|
rlm@1
|
2935 memoryWait[0x0c] = memoryWait[0x0d] = gamepakWaitState[(value >> 8) & 7];
|
rlm@1
|
2936 memoryWaitSeq[0x0c] = memoryWaitSeq[0x0d] =
|
rlm@1
|
2937 gamepakWaitState2[(value >> 8) & 7];
|
rlm@1
|
2938 }
|
rlm@1
|
2939 else
|
rlm@1
|
2940 {
|
rlm@1
|
2941 memoryWait[0x08] = memoryWait[0x09] = 4;
|
rlm@1
|
2942 memoryWaitSeq[0x08] = memoryWaitSeq[0x09] = 2;
|
rlm@1
|
2943
|
rlm@1
|
2944 memoryWait[0x0a] = memoryWait[0x0b] = 4;
|
rlm@1
|
2945 memoryWaitSeq[0x0a] = memoryWaitSeq[0x0b] = 4;
|
rlm@1
|
2946
|
rlm@1
|
2947 memoryWait[0x0c] = memoryWait[0x0d] = 4;
|
rlm@1
|
2948 memoryWaitSeq[0x0c] = memoryWaitSeq[0x0d] = 8;
|
rlm@1
|
2949 }
|
rlm@1
|
2950 for (i = 0; i < 16; i++)
|
rlm@1
|
2951 {
|
rlm@1
|
2952 memoryWaitFetch32[i] = memoryWait32[i] = memoryWait[i] *
|
rlm@1
|
2953 (memory32[i] ? 1 : 2);
|
rlm@1
|
2954 memoryWaitFetch[i] = memoryWait[i];
|
rlm@1
|
2955 }
|
rlm@1
|
2956 memoryWaitFetch32[3] += 1;
|
rlm@1
|
2957 memoryWaitFetch32[2] += 3;
|
rlm@1
|
2958
|
rlm@1
|
2959 prefetchActive = false;
|
rlm@1
|
2960 prefetchApplies = false;
|
rlm@1
|
2961 if (value & 0x4000)
|
rlm@1
|
2962 {
|
rlm@1
|
2963 for (i = 8; i < 16; i++)
|
rlm@1
|
2964 {
|
rlm@1
|
2965 memoryWaitFetch32[i] = 2 * cpuMemoryWait[i];
|
rlm@1
|
2966 memoryWaitFetch[i] = cpuMemoryWait[i];
|
rlm@1
|
2967 }
|
rlm@1
|
2968 if (((value & 3) == 3))
|
rlm@1
|
2969 {
|
rlm@1
|
2970 if (!memLagTempEnabled)
|
rlm@1
|
2971 {
|
rlm@1
|
2972 memoryWaitFetch[8]--; // hack to prevent inaccurately extreme lag at some points of many games (possibly
|
rlm@1
|
2973 // from no pre-fetch emulation)
|
rlm@1
|
2974 /// FIXME: how correct is this? Should it set the fetch to 0 or change fetch32 or
|
rlm@1
|
2975 // anything else?
|
rlm@1
|
2976
|
rlm@1
|
2977 prefetchActive = true;
|
rlm@1
|
2978 }
|
rlm@1
|
2979 prefetchApplies = true;
|
rlm@1
|
2980 }
|
rlm@1
|
2981 }
|
rlm@1
|
2982 //if(prefetchActive && !prefetchPrevActive) systemScreenMessage("pre-fetch enabled",3,600);
|
rlm@1
|
2983 //if(!prefetchActive && prefetchPrevActive) systemScreenMessage("pre-fetch disabled",3,600);
|
rlm@1
|
2984 prefetchPrevActive = prefetchActive;
|
rlm@1
|
2985
|
rlm@1
|
2986 UPDATE_REG(0x204, value);
|
rlm@1
|
2987 break;
|
rlm@1
|
2988 }
|
rlm@1
|
2989 case 0x208:
|
rlm@1
|
2990 IME = value & 1;
|
rlm@1
|
2991 UPDATE_REG(0x208, IME);
|
rlm@1
|
2992 if ((IME & 1) && (IF & IE) && armIrqEnable)
|
rlm@1
|
2993 {
|
rlm@1
|
2994 CPU_BREAK_LOOP_2;
|
rlm@1
|
2995 }
|
rlm@1
|
2996 break;
|
rlm@1
|
2997 case 0x300:
|
rlm@1
|
2998 if (value != 0)
|
rlm@1
|
2999 value &= 0xFFFE;
|
rlm@1
|
3000 UPDATE_REG(0x300, value);
|
rlm@1
|
3001 break;
|
rlm@1
|
3002 default:
|
rlm@1
|
3003 UPDATE_REG(address & 0x3FE, value);
|
rlm@1
|
3004 break;
|
rlm@1
|
3005 }
|
rlm@1
|
3006 }
|
rlm@1
|
3007
|
rlm@1
|
3008 void CPUWriteHalfWordWrapped(u32 address, u16 value)
|
rlm@1
|
3009 {
|
rlm@1
|
3010 #ifdef GBA_LOGGING
|
rlm@1
|
3011 if (address & 1)
|
rlm@1
|
3012 {
|
rlm@1
|
3013 if (systemVerbose & VERBOSE_UNALIGNED_MEMORY)
|
rlm@1
|
3014 {
|
rlm@1
|
3015 log("Unaligned halfword write: %04x to %08x from %08x\n",
|
rlm@1
|
3016 value,
|
rlm@1
|
3017 address,
|
rlm@1
|
3018 armMode ? armNextPC - 4 : armNextPC - 2);
|
rlm@1
|
3019 }
|
rlm@1
|
3020 }
|
rlm@1
|
3021 #endif
|
rlm@1
|
3022
|
rlm@1
|
3023 switch (address >> 24)
|
rlm@1
|
3024 {
|
rlm@1
|
3025 case 2:
|
rlm@1
|
3026 #ifdef SDL
|
rlm@1
|
3027 if (*((u16 *)&freezeWorkRAM[address & 0x3FFFE]))
|
rlm@1
|
3028 cheatsWriteHalfWord((u16 *)&workRAM[address & 0x3FFFE],
|
rlm@1
|
3029 value,
|
rlm@1
|
3030 *((u16 *)&freezeWorkRAM[address & 0x3FFFE]));
|
rlm@1
|
3031 else
|
rlm@1
|
3032 #endif
|
rlm@1
|
3033 WRITE16LE(((u16 *)&workRAM[address & 0x3FFFE]), value);
|
rlm@1
|
3034 break;
|
rlm@1
|
3035 case 3:
|
rlm@1
|
3036 #ifdef SDL
|
rlm@1
|
3037 if (*((u16 *)&freezeInternalRAM[address & 0x7ffe]))
|
rlm@1
|
3038 cheatsWriteHalfWord((u16 *)&internalRAM[address & 0x7ffe],
|
rlm@1
|
3039 value,
|
rlm@1
|
3040 *((u16 *)&freezeInternalRAM[address & 0x7ffe]));
|
rlm@1
|
3041 else
|
rlm@1
|
3042 #endif
|
rlm@1
|
3043 WRITE16LE(((u16 *)&internalRAM[address & 0x7ffe]), value);
|
rlm@1
|
3044 break;
|
rlm@1
|
3045 case 4:
|
rlm@1
|
3046 CPUUpdateRegister(address & 0x3fe, value);
|
rlm@1
|
3047 break;
|
rlm@1
|
3048 case 5:
|
rlm@1
|
3049 WRITE16LE(((u16 *)&paletteRAM[address & 0x3fe]), value);
|
rlm@1
|
3050 break;
|
rlm@1
|
3051 case 6:
|
rlm@1
|
3052 if (address & 0x10000)
|
rlm@1
|
3053 WRITE16LE(((u16 *)&vram[address & 0x17ffe]), value);
|
rlm@1
|
3054 else
|
rlm@1
|
3055 WRITE16LE(((u16 *)&vram[address & 0x1fffe]), value);
|
rlm@1
|
3056 break;
|
rlm@1
|
3057 case 7:
|
rlm@1
|
3058 WRITE16LE(((u16 *)&oam[address & 0x3fe]), value);
|
rlm@1
|
3059 break;
|
rlm@1
|
3060 case 8:
|
rlm@1
|
3061 case 9:
|
rlm@1
|
3062 if (address == 0x80000c4 || address == 0x80000c6 || address == 0x80000c8)
|
rlm@1
|
3063 {
|
rlm@1
|
3064 if (!rtcWrite(address, value))
|
rlm@1
|
3065 goto unwritable;
|
rlm@1
|
3066 }
|
rlm@1
|
3067 else if (!agbPrintWrite(address, value))
|
rlm@1
|
3068 goto unwritable;
|
rlm@1
|
3069 break;
|
rlm@1
|
3070 case 13:
|
rlm@1
|
3071 if (cpuEEPROMEnabled)
|
rlm@1
|
3072 {
|
rlm@1
|
3073 eepromWrite(address, (u8)(value & 0xFF));
|
rlm@1
|
3074 break;
|
rlm@1
|
3075 }
|
rlm@1
|
3076 goto unwritable;
|
rlm@1
|
3077 case 14:
|
rlm@1
|
3078 if (!eepromInUse | cpuSramEnabled | cpuFlashEnabled)
|
rlm@1
|
3079 {
|
rlm@1
|
3080 (*cpuSaveGameFunc)(address, (u8)(value & 0xFF));
|
rlm@1
|
3081 break;
|
rlm@1
|
3082 }
|
rlm@1
|
3083 goto unwritable;
|
rlm@1
|
3084 default:
|
rlm@1
|
3085 unwritable:
|
rlm@1
|
3086 #ifdef GBA_LOGGING
|
rlm@1
|
3087 if (systemVerbose & VERBOSE_ILLEGAL_WRITE)
|
rlm@1
|
3088 {
|
rlm@1
|
3089 log("Illegal halfword write: %04x to %08x from %08x\n",
|
rlm@1
|
3090 value,
|
rlm@1
|
3091 address,
|
rlm@1
|
3092 armMode ? armNextPC - 4 : armNextPC - 2);
|
rlm@1
|
3093 }
|
rlm@1
|
3094 #endif
|
rlm@1
|
3095 break;
|
rlm@1
|
3096 }
|
rlm@1
|
3097 }
|
rlm@1
|
3098
|
rlm@1
|
3099 void CPUWriteHalfWord(u32 address, u16 value)
|
rlm@1
|
3100 {
|
rlm@1
|
3101 CPUWriteHalfWordWrapped(address, value);
|
rlm@1
|
3102 CallRegisteredLuaMemHook(address, 2, value, LUAMEMHOOK_WRITE);
|
rlm@1
|
3103 }
|
rlm@1
|
3104
|
rlm@1
|
3105 void CPUWriteByteWrapped(u32 address, u8 b)
|
rlm@1
|
3106 {
|
rlm@1
|
3107 switch (address >> 24)
|
rlm@1
|
3108 {
|
rlm@1
|
3109 case 2:
|
rlm@1
|
3110 #ifdef SDL
|
rlm@1
|
3111 if (freezeWorkRAM[address & 0x3FFFF])
|
rlm@1
|
3112 cheatsWriteByte(&workRAM[address & 0x3FFFF], b);
|
rlm@1
|
3113 else
|
rlm@1
|
3114 #endif
|
rlm@1
|
3115 workRAM[address & 0x3FFFF] = b;
|
rlm@1
|
3116 break;
|
rlm@1
|
3117 case 3:
|
rlm@1
|
3118 #ifdef SDL
|
rlm@1
|
3119 if (freezeInternalRAM[address & 0x7fff])
|
rlm@1
|
3120 cheatsWriteByte(&internalRAM[address & 0x7fff], b);
|
rlm@1
|
3121 else
|
rlm@1
|
3122 #endif
|
rlm@1
|
3123 internalRAM[address & 0x7fff] = b;
|
rlm@1
|
3124 break;
|
rlm@1
|
3125 case 4:
|
rlm@1
|
3126 switch (address & 0x3FF)
|
rlm@1
|
3127 {
|
rlm@1
|
3128 case 0x301:
|
rlm@1
|
3129 if (b == 0x80)
|
rlm@1
|
3130 stopState = true;
|
rlm@1
|
3131 holdState = 1;
|
rlm@1
|
3132 holdType = -1;
|
rlm@1
|
3133 break;
|
rlm@1
|
3134 case 0x60:
|
rlm@1
|
3135 case 0x61:
|
rlm@1
|
3136 case 0x62:
|
rlm@1
|
3137 case 0x63:
|
rlm@1
|
3138 case 0x64:
|
rlm@1
|
3139 case 0x65:
|
rlm@1
|
3140 case 0x68:
|
rlm@1
|
3141 case 0x69:
|
rlm@1
|
3142 case 0x6c:
|
rlm@1
|
3143 case 0x6d:
|
rlm@1
|
3144 case 0x70:
|
rlm@1
|
3145 case 0x71:
|
rlm@1
|
3146 case 0x72:
|
rlm@1
|
3147 case 0x73:
|
rlm@1
|
3148 case 0x74:
|
rlm@1
|
3149 case 0x75:
|
rlm@1
|
3150 case 0x78:
|
rlm@1
|
3151 case 0x79:
|
rlm@1
|
3152 case 0x7c:
|
rlm@1
|
3153 case 0x7d:
|
rlm@1
|
3154 case 0x80:
|
rlm@1
|
3155 case 0x81:
|
rlm@1
|
3156 case 0x84:
|
rlm@1
|
3157 case 0x85:
|
rlm@1
|
3158 case 0x90:
|
rlm@1
|
3159 case 0x91:
|
rlm@1
|
3160 case 0x92:
|
rlm@1
|
3161 case 0x93:
|
rlm@1
|
3162 case 0x94:
|
rlm@1
|
3163 case 0x95:
|
rlm@1
|
3164 case 0x96:
|
rlm@1
|
3165 case 0x97:
|
rlm@1
|
3166 case 0x98:
|
rlm@1
|
3167 case 0x99:
|
rlm@1
|
3168 case 0x9a:
|
rlm@1
|
3169 case 0x9b:
|
rlm@1
|
3170 case 0x9c:
|
rlm@1
|
3171 case 0x9d:
|
rlm@1
|
3172 case 0x9e:
|
rlm@1
|
3173 case 0x9f:
|
rlm@1
|
3174 soundEvent(address & 0xFF, b);
|
rlm@1
|
3175 break;
|
rlm@1
|
3176 default:
|
rlm@1
|
3177 // if(address & 1) {
|
rlm@1
|
3178 // CPUWriteHalfWord(address-1, (CPUReadHalfWord(address-1)&0x00FF)|((int)b<<8));
|
rlm@1
|
3179 // } else
|
rlm@1
|
3180 if (address & 1)
|
rlm@1
|
3181 CPUUpdateRegister(address & 0x3fe,
|
rlm@1
|
3182 ((READ16LE(((u16 *)&ioMem[address & 0x3fe])))
|
rlm@1
|
3183 & 0x00FF) |
|
rlm@1
|
3184 b << 8);
|
rlm@1
|
3185 else
|
rlm@1
|
3186 CPUUpdateRegister(address & 0x3fe,
|
rlm@1
|
3187 ((READ16LE(((u16 *)&ioMem[address & 0x3fe])) & 0xFF00) | b));
|
rlm@1
|
3188 }
|
rlm@1
|
3189 break;
|
rlm@1
|
3190 case 5:
|
rlm@1
|
3191 // no need to switch
|
rlm@1
|
3192 *((u16 *)&paletteRAM[address & 0x3FE]) = (b << 8) | b;
|
rlm@1
|
3193 break;
|
rlm@1
|
3194 case 6:
|
rlm@1
|
3195 // no need to switch
|
rlm@1
|
3196 if (address & 0x10000)
|
rlm@1
|
3197 *((u16 *)&vram[address & 0x17FFE]) = (b << 8) | b;
|
rlm@1
|
3198 else
|
rlm@1
|
3199 *((u16 *)&vram[address & 0x1FFFE]) = (b << 8) | b;
|
rlm@1
|
3200 break;
|
rlm@1
|
3201 case 7:
|
rlm@1
|
3202 // no need to switch
|
rlm@1
|
3203 *((u16 *)&oam[address & 0x3FE]) = (b << 8) | b;
|
rlm@1
|
3204 break;
|
rlm@1
|
3205 case 13:
|
rlm@1
|
3206 if (cpuEEPROMEnabled)
|
rlm@1
|
3207 {
|
rlm@1
|
3208 eepromWrite(address, b);
|
rlm@1
|
3209 break;
|
rlm@1
|
3210 }
|
rlm@1
|
3211 goto unwritable;
|
rlm@1
|
3212 case 14:
|
rlm@1
|
3213 if (!eepromInUse | cpuSramEnabled | cpuFlashEnabled)
|
rlm@1
|
3214 {
|
rlm@1
|
3215 (*cpuSaveGameFunc)(address, b);
|
rlm@1
|
3216 break;
|
rlm@1
|
3217 }
|
rlm@1
|
3218 // default
|
rlm@1
|
3219 default:
|
rlm@1
|
3220 unwritable:
|
rlm@1
|
3221 #ifdef GBA_LOGGING
|
rlm@1
|
3222 if (systemVerbose & VERBOSE_ILLEGAL_WRITE)
|
rlm@1
|
3223 {
|
rlm@1
|
3224 log("Illegal byte write: %02x to %08x from %08x\n",
|
rlm@1
|
3225 b,
|
rlm@1
|
3226 address,
|
rlm@1
|
3227 armMode ? armNextPC - 4 : armNextPC - 2);
|
rlm@1
|
3228 }
|
rlm@1
|
3229 #endif
|
rlm@1
|
3230 break;
|
rlm@1
|
3231 }
|
rlm@1
|
3232 }
|
rlm@1
|
3233
|
rlm@1
|
3234 void CPUWriteByte(u32 address, u8 b)
|
rlm@1
|
3235 {
|
rlm@1
|
3236 CPUWriteByteWrapped(address, b);
|
rlm@1
|
3237 CallRegisteredLuaMemHook(address, 1, b, LUAMEMHOOK_WRITE);
|
rlm@1
|
3238 }
|
rlm@1
|
3239
|
rlm@1
|
3240 bool CPULoadBios(const char *biosFileName, bool useBiosFile)
|
rlm@1
|
3241 {
|
rlm@1
|
3242 useBios = false;
|
rlm@1
|
3243 if (useBiosFile)
|
rlm@1
|
3244 {
|
rlm@1
|
3245 useBios = utilLoadBIOS(bios, biosFileName, 4);
|
rlm@1
|
3246 if (!useBios)
|
rlm@1
|
3247 {
|
rlm@1
|
3248 systemMessage(MSG_INVALID_BIOS_FILE_SIZE, N_("Invalid GBA BIOS file"));
|
rlm@1
|
3249 }
|
rlm@1
|
3250 }
|
rlm@1
|
3251
|
rlm@1
|
3252 if (!useBios)
|
rlm@1
|
3253 {
|
rlm@1
|
3254 // load internal BIOS
|
rlm@1
|
3255 memcpy(bios, myROM, sizeof(myROM));
|
rlm@1
|
3256 }
|
rlm@1
|
3257
|
rlm@1
|
3258 return useBios;
|
rlm@1
|
3259 }
|
rlm@1
|
3260
|
rlm@1
|
3261 void CPUInit()
|
rlm@1
|
3262 {
|
rlm@1
|
3263 #ifdef WORDS_BIGENDIAN
|
rlm@1
|
3264 if (!cpuBiosSwapped)
|
rlm@1
|
3265 {
|
rlm@1
|
3266 for (unsigned int i = 0; i < sizeof(myROM) / 4; i++)
|
rlm@1
|
3267 {
|
rlm@1
|
3268 WRITE32LE(&myROM[i], myROM[i]);
|
rlm@1
|
3269 }
|
rlm@1
|
3270 cpuBiosSwapped = true;
|
rlm@1
|
3271 }
|
rlm@1
|
3272 #endif
|
rlm@1
|
3273 gbaSaveType = 0;
|
rlm@1
|
3274 eepromInUse = 0;
|
rlm@1
|
3275 saveType = 0;
|
rlm@1
|
3276
|
rlm@1
|
3277 if (!useBios)
|
rlm@1
|
3278 {
|
rlm@1
|
3279 // load internal BIOS
|
rlm@1
|
3280 memcpy(bios, myROM, sizeof(myROM));
|
rlm@1
|
3281 }
|
rlm@1
|
3282
|
rlm@1
|
3283 biosProtected[0] = 0x00;
|
rlm@1
|
3284 biosProtected[1] = 0xf0;
|
rlm@1
|
3285 biosProtected[2] = 0x29;
|
rlm@1
|
3286 biosProtected[3] = 0xe1;
|
rlm@1
|
3287
|
rlm@1
|
3288 int i = 0;
|
rlm@1
|
3289 for (i = 0; i < 256; i++)
|
rlm@1
|
3290 {
|
rlm@1
|
3291 int cpuBitSetCount = 0;
|
rlm@1
|
3292 int j;
|
rlm@1
|
3293 for (j = 0; j < 8; j++)
|
rlm@1
|
3294 if (i & (1 << j))
|
rlm@1
|
3295 cpuBitSetCount++;
|
rlm@1
|
3296 cpuBitsSet[i] = cpuBitSetCount;
|
rlm@1
|
3297
|
rlm@1
|
3298 for (j = 0; j < 8; j++)
|
rlm@1
|
3299 if (i & (1 << j))
|
rlm@1
|
3300 break;
|
rlm@1
|
3301 cpuLowestBitSet[i] = j;
|
rlm@1
|
3302 }
|
rlm@1
|
3303
|
rlm@1
|
3304 for (i = 0; i < 0x400; i++)
|
rlm@1
|
3305 ioReadable[i] = true;
|
rlm@1
|
3306 for (i = 0x10; i < 0x48; i++)
|
rlm@1
|
3307 ioReadable[i] = false;
|
rlm@1
|
3308 for (i = 0x4c; i < 0x50; i++)
|
rlm@1
|
3309 ioReadable[i] = false;
|
rlm@1
|
3310 for (i = 0x54; i < 0x60; i++)
|
rlm@1
|
3311 ioReadable[i] = false;
|
rlm@1
|
3312 for (i = 0x8c; i < 0x90; i++)
|
rlm@1
|
3313 ioReadable[i] = false;
|
rlm@1
|
3314 for (i = 0xa0; i < 0xb8; i++)
|
rlm@1
|
3315 ioReadable[i] = false;
|
rlm@1
|
3316 for (i = 0xbc; i < 0xc4; i++)
|
rlm@1
|
3317 ioReadable[i] = false;
|
rlm@1
|
3318 for (i = 0xc8; i < 0xd0; i++)
|
rlm@1
|
3319 ioReadable[i] = false;
|
rlm@1
|
3320 for (i = 0xd4; i < 0xdc; i++)
|
rlm@1
|
3321 ioReadable[i] = false;
|
rlm@1
|
3322 for (i = 0xe0; i < 0x100; i++)
|
rlm@1
|
3323 ioReadable[i] = false;
|
rlm@1
|
3324 for (i = 0x110; i < 0x120; i++)
|
rlm@1
|
3325 ioReadable[i] = false;
|
rlm@1
|
3326 for (i = 0x12c; i < 0x130; i++)
|
rlm@1
|
3327 ioReadable[i] = false;
|
rlm@1
|
3328 for (i = 0x138; i < 0x140; i++)
|
rlm@1
|
3329 ioReadable[i] = false;
|
rlm@1
|
3330 for (i = 0x144; i < 0x150; i++)
|
rlm@1
|
3331 ioReadable[i] = false;
|
rlm@1
|
3332 for (i = 0x15c; i < 0x200; i++)
|
rlm@1
|
3333 ioReadable[i] = false;
|
rlm@1
|
3334 for (i = 0x20c; i < 0x300; i++)
|
rlm@1
|
3335 ioReadable[i] = false;
|
rlm@1
|
3336 for (i = 0x304; i < 0x400; i++)
|
rlm@1
|
3337 ioReadable[i] = false;
|
rlm@1
|
3338
|
rlm@1
|
3339 *((u16 *)&rom[0x1fe209c]) = 0xdffa; // SWI 0xFA
|
rlm@1
|
3340 *((u16 *)&rom[0x1fe209e]) = 0x4770; // BX LR
|
rlm@1
|
3341
|
rlm@1
|
3342 {
|
rlm@1
|
3343 int32 origMemoryWaitFetch[16] = { 3, 0, 3, 0, 0, 1, 1, 0, 4, 4, 4, 4, 4, 4, 4, 0 };
|
rlm@1
|
3344 int32 origMemoryWaitFetch32[16] = { 6, 0, 6, 0, 0, 2, 2, 0, 8, 8, 8, 8, 8, 8, 8, 0 };
|
rlm@1
|
3345 memcpy(memoryWaitFetch, origMemoryWaitFetch, 16 * sizeof(int32));
|
rlm@1
|
3346 memcpy(memoryWaitFetch32, origMemoryWaitFetch32, 16 * sizeof(int32));
|
rlm@1
|
3347 }
|
rlm@1
|
3348 }
|
rlm@1
|
3349
|
rlm@1
|
3350 void CPUReset(bool userReset)
|
rlm@1
|
3351 {
|
rlm@1
|
3352 // movie must be closed while opening/creating a movie
|
rlm@1
|
3353 if (userReset && VBAMovieRecording())
|
rlm@1
|
3354 {
|
rlm@1
|
3355 VBAMovieSignalReset();
|
rlm@1
|
3356 return;
|
rlm@1
|
3357 }
|
rlm@1
|
3358
|
rlm@1
|
3359 if (!VBAMovieActive())
|
rlm@1
|
3360 {
|
rlm@1
|
3361 GBASystemCounters.frameCount = 0;
|
rlm@1
|
3362 GBASystemCounters.lagCount = 0;
|
rlm@1
|
3363 GBASystemCounters.extraCount = 0;
|
rlm@1
|
3364 GBASystemCounters.lagged = true;
|
rlm@1
|
3365 GBASystemCounters.laggedLast = true;
|
rlm@1
|
3366 }
|
rlm@1
|
3367
|
rlm@1
|
3368 if (gbaSaveType == 0)
|
rlm@1
|
3369 {
|
rlm@1
|
3370 if (eepromInUse)
|
rlm@1
|
3371 gbaSaveType = 3;
|
rlm@1
|
3372 else
|
rlm@1
|
3373 switch (saveType)
|
rlm@1
|
3374 {
|
rlm@1
|
3375 case 1:
|
rlm@1
|
3376 gbaSaveType = 1;
|
rlm@1
|
3377 break;
|
rlm@1
|
3378 case 2:
|
rlm@1
|
3379 gbaSaveType = 2;
|
rlm@1
|
3380 break;
|
rlm@1
|
3381 }
|
rlm@1
|
3382 }
|
rlm@1
|
3383
|
rlm@1
|
3384 rtcReset();
|
rlm@1
|
3385 // clean registers
|
rlm@1
|
3386 memset(®[0], 0, sizeof(reg));
|
rlm@1
|
3387 // clean OAM
|
rlm@1
|
3388 memset(oam, 0, 0x400);
|
rlm@1
|
3389 // clean palette
|
rlm@1
|
3390 memset(paletteRAM, 0, 0x400);
|
rlm@1
|
3391 // clean picture
|
rlm@1
|
3392 memset(pix, 0, 4 * 241 * 162);
|
rlm@1
|
3393 // clean vram
|
rlm@1
|
3394 memset(vram, 0, 0x20000);
|
rlm@1
|
3395 // clean io memory
|
rlm@1
|
3396 memset(ioMem, 0, 0x400);
|
rlm@1
|
3397 // clean RAM
|
rlm@1
|
3398 memset(internalRAM, 0, 0x8000); /// FIXME: is it unsafe to erase ALL of this? Even the init code doesn't.
|
rlm@1
|
3399 memset(workRAM, 0, 0x40000); /// ditto
|
rlm@1
|
3400
|
rlm@1
|
3401 DISPCNT = 0x0080;
|
rlm@1
|
3402 DISPSTAT = 0x0000;
|
rlm@1
|
3403 VCOUNT = 0x0000;
|
rlm@1
|
3404 BG0CNT = 0x0000;
|
rlm@1
|
3405 BG1CNT = 0x0000;
|
rlm@1
|
3406 BG2CNT = 0x0000;
|
rlm@1
|
3407 BG3CNT = 0x0000;
|
rlm@1
|
3408 BG0HOFS = 0x0000;
|
rlm@1
|
3409 BG0VOFS = 0x0000;
|
rlm@1
|
3410 BG1HOFS = 0x0000;
|
rlm@1
|
3411 BG1VOFS = 0x0000;
|
rlm@1
|
3412 BG2HOFS = 0x0000;
|
rlm@1
|
3413 BG2VOFS = 0x0000;
|
rlm@1
|
3414 BG3HOFS = 0x0000;
|
rlm@1
|
3415 BG3VOFS = 0x0000;
|
rlm@1
|
3416 BG2PA = 0x0100;
|
rlm@1
|
3417 BG2PB = 0x0000;
|
rlm@1
|
3418 BG2PC = 0x0000;
|
rlm@1
|
3419 BG2PD = 0x0100;
|
rlm@1
|
3420 BG2X_L = 0x0000;
|
rlm@1
|
3421 BG2X_H = 0x0000;
|
rlm@1
|
3422 BG2Y_L = 0x0000;
|
rlm@1
|
3423 BG2Y_H = 0x0000;
|
rlm@1
|
3424 BG3PA = 0x0100;
|
rlm@1
|
3425 BG3PB = 0x0000;
|
rlm@1
|
3426 BG3PC = 0x0000;
|
rlm@1
|
3427 BG3PD = 0x0100;
|
rlm@1
|
3428 BG3X_L = 0x0000;
|
rlm@1
|
3429 BG3X_H = 0x0000;
|
rlm@1
|
3430 BG3Y_L = 0x0000;
|
rlm@1
|
3431 BG3Y_H = 0x0000;
|
rlm@1
|
3432 WIN0H = 0x0000;
|
rlm@1
|
3433 WIN1H = 0x0000;
|
rlm@1
|
3434 WIN0V = 0x0000;
|
rlm@1
|
3435 WIN1V = 0x0000;
|
rlm@1
|
3436 WININ = 0x0000;
|
rlm@1
|
3437 WINOUT = 0x0000;
|
rlm@1
|
3438 MOSAIC = 0x0000;
|
rlm@1
|
3439 BLDMOD = 0x0000;
|
rlm@1
|
3440 COLEV = 0x0000;
|
rlm@1
|
3441 COLY = 0x0000;
|
rlm@1
|
3442 DM0SAD_L = 0x0000;
|
rlm@1
|
3443 DM0SAD_H = 0x0000;
|
rlm@1
|
3444 DM0DAD_L = 0x0000;
|
rlm@1
|
3445 DM0DAD_H = 0x0000;
|
rlm@1
|
3446 DM0CNT_L = 0x0000;
|
rlm@1
|
3447 DM0CNT_H = 0x0000;
|
rlm@1
|
3448 DM1SAD_L = 0x0000;
|
rlm@1
|
3449 DM1SAD_H = 0x0000;
|
rlm@1
|
3450 DM1DAD_L = 0x0000;
|
rlm@1
|
3451 DM1DAD_H = 0x0000;
|
rlm@1
|
3452 DM1CNT_L = 0x0000;
|
rlm@1
|
3453 DM1CNT_H = 0x0000;
|
rlm@1
|
3454 DM2SAD_L = 0x0000;
|
rlm@1
|
3455 DM2SAD_H = 0x0000;
|
rlm@1
|
3456 DM2DAD_L = 0x0000;
|
rlm@1
|
3457 DM2DAD_H = 0x0000;
|
rlm@1
|
3458 DM2CNT_L = 0x0000;
|
rlm@1
|
3459 DM2CNT_H = 0x0000;
|
rlm@1
|
3460 DM3SAD_L = 0x0000;
|
rlm@1
|
3461 DM3SAD_H = 0x0000;
|
rlm@1
|
3462 DM3DAD_L = 0x0000;
|
rlm@1
|
3463 DM3DAD_H = 0x0000;
|
rlm@1
|
3464 DM3CNT_L = 0x0000;
|
rlm@1
|
3465 DM3CNT_H = 0x0000;
|
rlm@1
|
3466 TM0D = 0x0000;
|
rlm@1
|
3467 TM0CNT = 0x0000;
|
rlm@1
|
3468 TM1D = 0x0000;
|
rlm@1
|
3469 TM1CNT = 0x0000;
|
rlm@1
|
3470 TM2D = 0x0000;
|
rlm@1
|
3471 TM2CNT = 0x0000;
|
rlm@1
|
3472 TM3D = 0x0000;
|
rlm@1
|
3473 TM3CNT = 0x0000;
|
rlm@1
|
3474 P1 = 0x03FF;
|
rlm@1
|
3475 IE = 0x0000;
|
rlm@1
|
3476 IF = 0x0000;
|
rlm@1
|
3477 IME = 0x0000;
|
rlm@1
|
3478
|
rlm@1
|
3479 armMode = 0x1F;
|
rlm@1
|
3480
|
rlm@1
|
3481 if (cpuIsMultiBoot)
|
rlm@1
|
3482 {
|
rlm@1
|
3483 reg[13].I = 0x03007F00;
|
rlm@1
|
3484 reg[15].I = 0x02000000;
|
rlm@1
|
3485 reg[16].I = 0x00000000;
|
rlm@1
|
3486 reg[R13_IRQ].I = 0x03007FA0;
|
rlm@1
|
3487 reg[R13_SVC].I = 0x03007FE0;
|
rlm@1
|
3488 armIrqEnable = true;
|
rlm@1
|
3489 }
|
rlm@1
|
3490 else
|
rlm@1
|
3491 {
|
rlm@1
|
3492 if (useBios && !skipBios)
|
rlm@1
|
3493 {
|
rlm@1
|
3494 reg[15].I = 0x00000000;
|
rlm@1
|
3495 armMode = 0x13;
|
rlm@1
|
3496 armIrqEnable = false;
|
rlm@1
|
3497 }
|
rlm@1
|
3498 else
|
rlm@1
|
3499 {
|
rlm@1
|
3500 reg[13].I = 0x03007F00;
|
rlm@1
|
3501 reg[15].I = 0x08000000;
|
rlm@1
|
3502 reg[16].I = 0x00000000;
|
rlm@1
|
3503 reg[R13_IRQ].I = 0x03007FA0;
|
rlm@1
|
3504 reg[R13_SVC].I = 0x03007FE0;
|
rlm@1
|
3505 armIrqEnable = true;
|
rlm@1
|
3506 }
|
rlm@1
|
3507 }
|
rlm@1
|
3508 armState = true;
|
rlm@1
|
3509 C_FLAG = V_FLAG = N_FLAG = Z_FLAG = false;
|
rlm@1
|
3510 UPDATE_REG(0x00, DISPCNT);
|
rlm@1
|
3511 UPDATE_REG(0x20, BG2PA);
|
rlm@1
|
3512 UPDATE_REG(0x26, BG2PD);
|
rlm@1
|
3513 UPDATE_REG(0x30, BG3PA);
|
rlm@1
|
3514 UPDATE_REG(0x36, BG3PD);
|
rlm@1
|
3515 UPDATE_REG(0x130, P1);
|
rlm@1
|
3516 UPDATE_REG(0x88, 0x200);
|
rlm@1
|
3517
|
rlm@1
|
3518 // disable FIQ
|
rlm@1
|
3519 reg[16].I |= 0x40;
|
rlm@1
|
3520 CPUUpdateCPSR();
|
rlm@1
|
3521
|
rlm@1
|
3522 armNextPC = reg[15].I;
|
rlm@1
|
3523 reg[15].I += 4;
|
rlm@1
|
3524
|
rlm@1
|
3525 // reset internal state
|
rlm@1
|
3526 holdState = false;
|
rlm@1
|
3527 holdType = 0;
|
rlm@1
|
3528
|
rlm@1
|
3529 biosProtected[0] = 0x00;
|
rlm@1
|
3530 biosProtected[1] = 0xf0;
|
rlm@1
|
3531 biosProtected[2] = 0x29;
|
rlm@1
|
3532 biosProtected[3] = 0xe1;
|
rlm@1
|
3533
|
rlm@1
|
3534 BIOS_RegisterRamReset();
|
rlm@1
|
3535
|
rlm@1
|
3536 lcdTicks = 960;
|
rlm@1
|
3537 timer0On = false;
|
rlm@1
|
3538 timer0Ticks = 0;
|
rlm@1
|
3539 timer0Reload = 0;
|
rlm@1
|
3540 timer0ClockReload = 0;
|
rlm@1
|
3541 timer1On = false;
|
rlm@1
|
3542 timer1Ticks = 0;
|
rlm@1
|
3543 timer1Reload = 0;
|
rlm@1
|
3544 timer1ClockReload = 0;
|
rlm@1
|
3545 timer2On = false;
|
rlm@1
|
3546 timer2Ticks = 0;
|
rlm@1
|
3547 timer2Reload = 0;
|
rlm@1
|
3548 timer2ClockReload = 0;
|
rlm@1
|
3549 timer3On = false;
|
rlm@1
|
3550 timer3Ticks = 0;
|
rlm@1
|
3551 timer3Reload = 0;
|
rlm@1
|
3552 timer3ClockReload = 0;
|
rlm@1
|
3553 dma0Source = 0;
|
rlm@1
|
3554 dma0Dest = 0;
|
rlm@1
|
3555 dma1Source = 0;
|
rlm@1
|
3556 dma1Dest = 0;
|
rlm@1
|
3557 dma2Source = 0;
|
rlm@1
|
3558 dma2Dest = 0;
|
rlm@1
|
3559 dma3Source = 0;
|
rlm@1
|
3560 dma3Dest = 0;
|
rlm@1
|
3561 cpuSaveGameFunc = flashSaveDecide;
|
rlm@1
|
3562 renderLine = mode0RenderLine;
|
rlm@1
|
3563 fxOn = false;
|
rlm@1
|
3564 windowOn = false;
|
rlm@1
|
3565 frameSkipCount = 0;
|
rlm@1
|
3566 saveType = 0;
|
rlm@1
|
3567 layerEnable = DISPCNT & layerSettings;
|
rlm@1
|
3568
|
rlm@1
|
3569 CPUUpdateRenderBuffers(true);
|
rlm@1
|
3570
|
rlm@1
|
3571 for (int i = 0; i < 256; i++)
|
rlm@1
|
3572 {
|
rlm@1
|
3573 map[i].address = (u8 *)&dummyAddress;
|
rlm@1
|
3574 map[i].mask = 0;
|
rlm@1
|
3575 }
|
rlm@1
|
3576
|
rlm@1
|
3577 map[0].address = bios;
|
rlm@1
|
3578 map[0].mask = 0x3FFF;
|
rlm@1
|
3579 map[2].address = workRAM;
|
rlm@1
|
3580 map[2].mask = 0x3FFFF;
|
rlm@1
|
3581 map[3].address = internalRAM;
|
rlm@1
|
3582 map[3].mask = 0x7FFF;
|
rlm@1
|
3583 map[4].address = ioMem;
|
rlm@1
|
3584 map[4].mask = 0x3FF;
|
rlm@1
|
3585 map[5].address = paletteRAM;
|
rlm@1
|
3586 map[5].mask = 0x3FF;
|
rlm@1
|
3587 map[6].address = vram;
|
rlm@1
|
3588 map[6].mask = 0x1FFFF;
|
rlm@1
|
3589 map[7].address = oam;
|
rlm@1
|
3590 map[7].mask = 0x3FF;
|
rlm@1
|
3591 map[8].address = rom;
|
rlm@1
|
3592 map[8].mask = 0x1FFFFFF;
|
rlm@1
|
3593 map[9].address = rom;
|
rlm@1
|
3594 map[9].mask = 0x1FFFFFF;
|
rlm@1
|
3595 map[10].address = rom;
|
rlm@1
|
3596 map[10].mask = 0x1FFFFFF;
|
rlm@1
|
3597 map[12].address = rom;
|
rlm@1
|
3598 map[12].mask = 0x1FFFFFF;
|
rlm@1
|
3599 map[14].address = flashSaveMemory;
|
rlm@1
|
3600 map[14].mask = 0xFFFF;
|
rlm@1
|
3601
|
rlm@1
|
3602 eepromReset();
|
rlm@1
|
3603 flashReset();
|
rlm@1
|
3604
|
rlm@1
|
3605 soundReset();
|
rlm@1
|
3606
|
rlm@1
|
3607 CPUUpdateWindow0();
|
rlm@1
|
3608 CPUUpdateWindow1();
|
rlm@1
|
3609
|
rlm@1
|
3610 // make sure registers are correctly initialized if not using BIOS
|
rlm@1
|
3611 if (!useBios)
|
rlm@1
|
3612 {
|
rlm@1
|
3613 if (cpuIsMultiBoot)
|
rlm@1
|
3614 BIOS_RegisterRamReset(0xfe);
|
rlm@1
|
3615 else
|
rlm@1
|
3616 BIOS_RegisterRamReset(0xff);
|
rlm@1
|
3617 }
|
rlm@1
|
3618 else
|
rlm@1
|
3619 {
|
rlm@1
|
3620 if (cpuIsMultiBoot)
|
rlm@1
|
3621 BIOS_RegisterRamReset(0xfe);
|
rlm@1
|
3622 }
|
rlm@1
|
3623
|
rlm@1
|
3624 switch (cpuSaveType)
|
rlm@1
|
3625 {
|
rlm@1
|
3626 case 0: // automatic
|
rlm@1
|
3627 cpuSramEnabled = true;
|
rlm@1
|
3628 cpuFlashEnabled = true;
|
rlm@1
|
3629 cpuEEPROMEnabled = true;
|
rlm@1
|
3630 cpuEEPROMSensorEnabled = false;
|
rlm@1
|
3631 break;
|
rlm@1
|
3632 case 1: // EEPROM
|
rlm@1
|
3633 cpuSramEnabled = false;
|
rlm@1
|
3634 cpuFlashEnabled = false;
|
rlm@1
|
3635 cpuEEPROMEnabled = true;
|
rlm@1
|
3636 cpuEEPROMSensorEnabled = false;
|
rlm@1
|
3637 break;
|
rlm@1
|
3638 case 2: // SRAM
|
rlm@1
|
3639 cpuSramEnabled = true;
|
rlm@1
|
3640 cpuFlashEnabled = false;
|
rlm@1
|
3641 cpuEEPROMEnabled = false;
|
rlm@1
|
3642 cpuEEPROMSensorEnabled = false;
|
rlm@1
|
3643 cpuSaveGameFunc = sramWrite;
|
rlm@1
|
3644 break;
|
rlm@1
|
3645 case 3: // FLASH
|
rlm@1
|
3646 cpuSramEnabled = false;
|
rlm@1
|
3647 cpuFlashEnabled = true;
|
rlm@1
|
3648 cpuEEPROMEnabled = false;
|
rlm@1
|
3649 cpuEEPROMSensorEnabled = false;
|
rlm@1
|
3650 cpuSaveGameFunc = flashWrite;
|
rlm@1
|
3651 break;
|
rlm@1
|
3652 case 4: // EEPROM+Sensor
|
rlm@1
|
3653 cpuSramEnabled = false;
|
rlm@1
|
3654 cpuFlashEnabled = false;
|
rlm@1
|
3655 cpuEEPROMEnabled = true;
|
rlm@1
|
3656 cpuEEPROMSensorEnabled = true;
|
rlm@1
|
3657 break;
|
rlm@1
|
3658 case 5: // NONE
|
rlm@1
|
3659 cpuSramEnabled = false;
|
rlm@1
|
3660 cpuFlashEnabled = false;
|
rlm@1
|
3661 cpuEEPROMEnabled = false;
|
rlm@1
|
3662 cpuEEPROMSensorEnabled = false;
|
rlm@1
|
3663 break;
|
rlm@1
|
3664 }
|
rlm@1
|
3665
|
rlm@1
|
3666 systemResetSensor();
|
rlm@1
|
3667
|
rlm@1
|
3668 systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
|
rlm@1
|
3669
|
rlm@1
|
3670 gbaLastTime = systemGetClock();
|
rlm@1
|
3671 gbaFrameCount = 0;
|
rlm@1
|
3672
|
rlm@1
|
3673 systemRefreshScreen();
|
rlm@1
|
3674 }
|
rlm@1
|
3675
|
rlm@1
|
3676 void CPUInterrupt()
|
rlm@1
|
3677 {
|
rlm@1
|
3678 u32 PC = reg[15].I;
|
rlm@1
|
3679 bool savedState = armState;
|
rlm@1
|
3680 CPUSwitchMode(0x12, true, false);
|
rlm@1
|
3681 reg[14].I = PC;
|
rlm@1
|
3682 if (!savedState)
|
rlm@1
|
3683 reg[14].I += 2;
|
rlm@1
|
3684 reg[15].I = 0x18;
|
rlm@1
|
3685 armState = true;
|
rlm@1
|
3686 armIrqEnable = false;
|
rlm@1
|
3687
|
rlm@1
|
3688 armNextPC = reg[15].I;
|
rlm@1
|
3689 reg[15].I += 4;
|
rlm@1
|
3690
|
rlm@1
|
3691 // if(!holdState)
|
rlm@1
|
3692 biosProtected[0] = 0x02;
|
rlm@1
|
3693 biosProtected[1] = 0xc0;
|
rlm@1
|
3694 biosProtected[2] = 0x5e;
|
rlm@1
|
3695 biosProtected[3] = 0xe5;
|
rlm@1
|
3696 }
|
rlm@1
|
3697
|
rlm@1
|
3698 void TogglePrefetchHack()
|
rlm@1
|
3699 {
|
rlm@1
|
3700 memLagTempEnabled = !memLagTempEnabled;
|
rlm@1
|
3701
|
rlm@1
|
3702 if (emulating)
|
rlm@1
|
3703 {
|
rlm@1
|
3704 extern bool8 prefetchActive, prefetchPrevActive, prefetchApplies;
|
rlm@1
|
3705 if (prefetchApplies && prefetchActive == memLagTempEnabled)
|
rlm@1
|
3706 {
|
rlm@1
|
3707 prefetchActive = !prefetchActive;
|
rlm@1
|
3708 //if(prefetchActive && !prefetchPrevActive) systemScreenMessage("pre-fetch enabled",3,600);
|
rlm@1
|
3709 //if(!prefetchActive && prefetchPrevActive) systemScreenMessage("pre-fetch disabled",3,600);
|
rlm@1
|
3710 extern int32 memoryWaitFetch [16];
|
rlm@1
|
3711 if (prefetchActive)
|
rlm@1
|
3712 memoryWaitFetch[8]--;
|
rlm@1
|
3713 else
|
rlm@1
|
3714 memoryWaitFetch[8]++;
|
rlm@1
|
3715 prefetchPrevActive = prefetchActive;
|
rlm@1
|
3716 }
|
rlm@1
|
3717 }
|
rlm@1
|
3718 }
|
rlm@1
|
3719
|
rlm@1
|
3720 void SetPrefetchHack(bool set)
|
rlm@1
|
3721 {
|
rlm@1
|
3722 if ((bool)memLagTempEnabled == set)
|
rlm@1
|
3723 TogglePrefetchHack();
|
rlm@1
|
3724 }
|
rlm@1
|
3725
|
rlm@1
|
3726 #ifdef SDL
|
rlm@1
|
3727 void log(const char *defaultMsg, ...)
|
rlm@1
|
3728 {
|
rlm@1
|
3729 char buffer[2048];
|
rlm@1
|
3730 va_list valist;
|
rlm@1
|
3731
|
rlm@1
|
3732 va_start(valist, defaultMsg);
|
rlm@1
|
3733 vsprintf(buffer, defaultMsg, valist);
|
rlm@1
|
3734
|
rlm@1
|
3735 if (out == NULL)
|
rlm@1
|
3736 {
|
rlm@1
|
3737 out = fopen("trace.log", "w");
|
rlm@1
|
3738 }
|
rlm@1
|
3739
|
rlm@1
|
3740 fputs(buffer, out);
|
rlm@1
|
3741
|
rlm@1
|
3742 va_end(valist);
|
rlm@1
|
3743 }
|
rlm@1
|
3744
|
rlm@1
|
3745 #else
|
rlm@1
|
3746 extern void winlog(const char *, ...);
|
rlm@1
|
3747 #endif
|
rlm@1
|
3748
|
rlm@92
|
3749 void CPULoop2(int _ticks)
|
rlm@1
|
3750 {
|
rlm@1
|
3751 int32 ticks = _ticks;
|
rlm@1
|
3752 int32 clockTicks;
|
rlm@1
|
3753 int32 cpuLoopTicks = 0;
|
rlm@1
|
3754 int32 timerOverflow = 0;
|
rlm@1
|
3755 // variables used by the CPU core
|
rlm@1
|
3756
|
rlm@1
|
3757 extCpuLoopTicks = &cpuLoopTicks;
|
rlm@1
|
3758 extClockTicks = &clockTicks;
|
rlm@1
|
3759 extTicks = &ticks;
|
rlm@1
|
3760
|
rlm@1
|
3761 cpuLoopTicks = CPUUpdateTicks();
|
rlm@1
|
3762 if (cpuLoopTicks > ticks)
|
rlm@1
|
3763 {
|
rlm@1
|
3764 cpuLoopTicks = ticks;
|
rlm@1
|
3765 cpuSavedTicks = ticks;
|
rlm@1
|
3766 }
|
rlm@1
|
3767
|
rlm@1
|
3768 if (intState)
|
rlm@1
|
3769 {
|
rlm@1
|
3770 cpuLoopTicks = 5;
|
rlm@1
|
3771 cpuSavedTicks = 5;
|
rlm@1
|
3772 }
|
rlm@1
|
3773
|
rlm@1
|
3774 if (newFrame)
|
rlm@1
|
3775 {
|
rlm@1
|
3776 extern void VBAOnExitingFrameBoundary();
|
rlm@1
|
3777 VBAOnExitingFrameBoundary();
|
rlm@1
|
3778
|
rlm@1
|
3779 // update joystick information
|
rlm@1
|
3780 systemReadJoypads();
|
rlm@1
|
3781
|
rlm@1
|
3782 u32 joy = systemGetJoypad(0, cpuEEPROMSensorEnabled);
|
rlm@1
|
3783
|
rlm@1
|
3784 // if (cpuEEPROMSensorEnabled)
|
rlm@1
|
3785 // systemUpdateMotionSensor(0);
|
rlm@1
|
3786
|
rlm@1
|
3787 P1 = 0x03FF ^ (joy & 0x3FF);
|
rlm@1
|
3788 UPDATE_REG(0x130, P1);
|
rlm@1
|
3789 u16 P1CNT = READ16LE(((u16 *)&ioMem[0x132]));
|
rlm@1
|
3790 // this seems wrong, but there are cases where the game
|
rlm@1
|
3791 // can enter the stop state without requesting an IRQ from
|
rlm@1
|
3792 // the joypad.
|
rlm@1
|
3793 if ((P1CNT & 0x4000) || stopState)
|
rlm@1
|
3794 {
|
rlm@1
|
3795 u16 p1 = (0x3FF ^ P1) & 0x3FF;
|
rlm@1
|
3796 if (P1CNT & 0x8000)
|
rlm@1
|
3797 {
|
rlm@1
|
3798 if (p1 == (P1CNT & 0x3FF))
|
rlm@1
|
3799 {
|
rlm@1
|
3800 IF |= 0x1000;
|
rlm@1
|
3801 UPDATE_REG(0x202, IF);
|
rlm@1
|
3802 }
|
rlm@1
|
3803 }
|
rlm@1
|
3804 else
|
rlm@1
|
3805 {
|
rlm@1
|
3806 if (p1 & P1CNT)
|
rlm@1
|
3807 {
|
rlm@1
|
3808 IF |= 0x1000;
|
rlm@1
|
3809 UPDATE_REG(0x202, IF);
|
rlm@1
|
3810 }
|
rlm@1
|
3811 }
|
rlm@1
|
3812 }
|
rlm@1
|
3813
|
rlm@1
|
3814 // HACK: some special "buttons"
|
rlm@1
|
3815 extButtons = (joy >> 18);
|
rlm@1
|
3816 speedup = (extButtons & 1) != 0;
|
rlm@1
|
3817
|
rlm@1
|
3818 VBAMovieResetIfRequested();
|
rlm@1
|
3819
|
rlm@1
|
3820 CallRegisteredLuaFunctions(LUACALL_BEFOREEMULATION);
|
rlm@1
|
3821
|
rlm@1
|
3822 newFrame = false;
|
rlm@1
|
3823 }
|
rlm@1
|
3824
|
rlm@1
|
3825 for (;; )
|
rlm@1
|
3826 {
|
rlm@1
|
3827 #ifndef FINAL_VERSION
|
rlm@1
|
3828 if (systemDebug)
|
rlm@1
|
3829 {
|
rlm@1
|
3830 if (systemDebug >= 10 && !holdState)
|
rlm@1
|
3831 {
|
rlm@1
|
3832 CPUUpdateCPSR();
|
rlm@1
|
3833 sprintf(
|
rlm@1
|
3834 buffer,
|
rlm@1
|
3835 "R00=%08x R01=%08x R02=%08x R03=%08x R04=%08x R05=%08x R06=%08x R07=%08x R08=%08x"
|
rlm@1
|
3836 "R09=%08x R10=%08x R11=%08x R12=%08x R13=%08x R14=%08x R15=%08x R16=%08x R17=%08x\n",
|
rlm@1
|
3837 reg[0].I,
|
rlm@1
|
3838 reg[1].I,
|
rlm@1
|
3839 reg[2].I,
|
rlm@1
|
3840 reg[3].I,
|
rlm@1
|
3841 reg[4].I,
|
rlm@1
|
3842 reg[5].I,
|
rlm@1
|
3843 reg[6].I,
|
rlm@1
|
3844 reg[7].I,
|
rlm@1
|
3845 reg[8].I,
|
rlm@1
|
3846 reg[9].I,
|
rlm@1
|
3847 reg[10].I,
|
rlm@1
|
3848 reg[11].I,
|
rlm@1
|
3849 reg[12].I,
|
rlm@1
|
3850 reg[13].I,
|
rlm@1
|
3851 reg[14].I,
|
rlm@1
|
3852 reg[15].I,
|
rlm@1
|
3853 reg[16].I,
|
rlm@1
|
3854 reg[17].I);
|
rlm@1
|
3855 #ifdef SDL
|
rlm@1
|
3856 log(buffer);
|
rlm@1
|
3857 #else
|
rlm@1
|
3858 winlog(buffer);
|
rlm@1
|
3859 #endif
|
rlm@1
|
3860 }
|
rlm@1
|
3861 else if (!holdState)
|
rlm@1
|
3862 {
|
rlm@1
|
3863 sprintf(buffer, "PC=%08x\n", armNextPC);
|
rlm@1
|
3864 #ifdef SDL
|
rlm@1
|
3865 log(buffer);
|
rlm@1
|
3866 #else
|
rlm@1
|
3867 winlog(buffer);
|
rlm@1
|
3868 #endif
|
rlm@1
|
3869 }
|
rlm@1
|
3870 }
|
rlm@1
|
3871 #endif
|
rlm@1
|
3872
|
rlm@1
|
3873 if (!holdState)
|
rlm@1
|
3874 {
|
rlm@1
|
3875 if (armState)
|
rlm@1
|
3876 {
|
rlm@1
|
3877 CallRegisteredLuaMemHook(armNextPC, 4, CPUReadMemoryQuick(armNextPC), LUAMEMHOOK_EXEC);
|
rlm@1
|
3878 #include "arm-new.h"
|
rlm@1
|
3879 }
|
rlm@1
|
3880 else
|
rlm@1
|
3881 {
|
rlm@1
|
3882 CallRegisteredLuaMemHook(armNextPC, 2, CPUReadHalfWordQuick(armNextPC), LUAMEMHOOK_EXEC);
|
rlm@1
|
3883 #include "thumb.h"
|
rlm@1
|
3884 }
|
rlm@1
|
3885 }
|
rlm@1
|
3886 else
|
rlm@1
|
3887 {
|
rlm@1
|
3888 clockTicks = lcdTicks;
|
rlm@1
|
3889
|
rlm@1
|
3890 if (soundTicks < clockTicks)
|
rlm@1
|
3891 clockTicks = soundTicks;
|
rlm@1
|
3892
|
rlm@1
|
3893 if (timer0On && (timer0Ticks < clockTicks))
|
rlm@1
|
3894 {
|
rlm@1
|
3895 clockTicks = timer0Ticks;
|
rlm@1
|
3896 }
|
rlm@1
|
3897 if (timer1On && (timer1Ticks < clockTicks))
|
rlm@1
|
3898 {
|
rlm@1
|
3899 clockTicks = timer1Ticks;
|
rlm@1
|
3900 }
|
rlm@1
|
3901 if (timer2On && (timer2Ticks < clockTicks))
|
rlm@1
|
3902 {
|
rlm@1
|
3903 clockTicks = timer2Ticks;
|
rlm@1
|
3904 }
|
rlm@1
|
3905 if (timer3On && (timer3Ticks < clockTicks))
|
rlm@1
|
3906 {
|
rlm@1
|
3907 clockTicks = timer3Ticks;
|
rlm@1
|
3908 }
|
rlm@1
|
3909 #ifdef PROFILING
|
rlm@1
|
3910 if (profilingTicksReload != 0)
|
rlm@1
|
3911 {
|
rlm@1
|
3912 if (profilingTicks < clockTicks)
|
rlm@1
|
3913 {
|
rlm@1
|
3914 clockTicks = profilingTicks;
|
rlm@1
|
3915 }
|
rlm@1
|
3916 }
|
rlm@1
|
3917 #endif
|
rlm@1
|
3918 }
|
rlm@1
|
3919
|
rlm@1
|
3920 cpuLoopTicks -= clockTicks;
|
rlm@1
|
3921 if ((cpuLoopTicks <= 0))
|
rlm@1
|
3922 {
|
rlm@1
|
3923 if (cpuSavedTicks)
|
rlm@1
|
3924 {
|
rlm@1
|
3925 clockTicks = cpuSavedTicks; // + cpuLoopTicks;
|
rlm@1
|
3926 }
|
rlm@1
|
3927 cpuDmaTicksToUpdate = -cpuLoopTicks;
|
rlm@1
|
3928
|
rlm@1
|
3929 updateLoop:
|
rlm@1
|
3930 lcdTicks -= clockTicks;
|
rlm@1
|
3931
|
rlm@1
|
3932 if (lcdTicks <= 0)
|
rlm@1
|
3933 {
|
rlm@1
|
3934 if (DISPSTAT & 1) // V-BLANK
|
rlm@1
|
3935 { // if in V-Blank mode, keep computing...
|
rlm@1
|
3936 if (DISPSTAT & 2)
|
rlm@1
|
3937 {
|
rlm@1
|
3938 lcdTicks += 960;
|
rlm@1
|
3939 VCOUNT++;
|
rlm@1
|
3940 UPDATE_REG(0x06, VCOUNT);
|
rlm@1
|
3941 DISPSTAT &= 0xFFFD;
|
rlm@1
|
3942 UPDATE_REG(0x04, DISPSTAT);
|
rlm@1
|
3943 CPUCompareVCOUNT();
|
rlm@1
|
3944 }
|
rlm@1
|
3945 else
|
rlm@1
|
3946 {
|
rlm@1
|
3947 lcdTicks += 272;
|
rlm@1
|
3948 DISPSTAT |= 2;
|
rlm@1
|
3949 UPDATE_REG(0x04, DISPSTAT);
|
rlm@1
|
3950 if (DISPSTAT & 16)
|
rlm@1
|
3951 {
|
rlm@1
|
3952 IF |= 2;
|
rlm@1
|
3953 UPDATE_REG(0x202, IF);
|
rlm@1
|
3954 }
|
rlm@1
|
3955 }
|
rlm@1
|
3956
|
rlm@1
|
3957 if (VCOUNT >= 228)
|
rlm@1
|
3958 {
|
rlm@1
|
3959 DISPSTAT &= 0xFFFC;
|
rlm@1
|
3960 UPDATE_REG(0x04, DISPSTAT);
|
rlm@1
|
3961 VCOUNT = 0;
|
rlm@1
|
3962 UPDATE_REG(0x06, VCOUNT);
|
rlm@1
|
3963 CPUCompareVCOUNT();
|
rlm@1
|
3964 }
|
rlm@1
|
3965 }
|
rlm@1
|
3966 else
|
rlm@1
|
3967 {
|
rlm@1
|
3968 int framesToSkip = systemFramesToSkip();
|
rlm@1
|
3969
|
rlm@1
|
3970 if (DISPSTAT & 2)
|
rlm@1
|
3971 {
|
rlm@1
|
3972 // if in H-Blank, leave it and move to drawing mode
|
rlm@1
|
3973 VCOUNT++;
|
rlm@1
|
3974 UPDATE_REG(0x06, VCOUNT);
|
rlm@1
|
3975
|
rlm@1
|
3976 lcdTicks += 960;
|
rlm@1
|
3977 DISPSTAT &= 0xFFFD;
|
rlm@1
|
3978 if (VCOUNT == 160)
|
rlm@1
|
3979 {
|
rlm@1
|
3980 DISPSTAT |= 1;
|
rlm@1
|
3981 DISPSTAT &= 0xFFFD;
|
rlm@1
|
3982 UPDATE_REG(0x04, DISPSTAT);
|
rlm@1
|
3983 if (DISPSTAT & 0x0008)
|
rlm@1
|
3984 {
|
rlm@1
|
3985 IF |= 1;
|
rlm@1
|
3986 UPDATE_REG(0x202, IF);
|
rlm@1
|
3987 }
|
rlm@1
|
3988 CPUCheckDMA(1, 0x0f);
|
rlm@1
|
3989
|
rlm@1
|
3990 systemFrame();
|
rlm@1
|
3991
|
rlm@1
|
3992 ++gbaFrameCount;
|
rlm@1
|
3993 u32 gbaCurrentTime = systemGetClock();
|
rlm@1
|
3994 if (gbaCurrentTime - gbaLastTime >= 1000)
|
rlm@1
|
3995 {
|
rlm@1
|
3996 systemShowSpeed(int(float(gbaFrameCount) * 100000 / (float(gbaCurrentTime - gbaLastTime) * 60) + .5f));
|
rlm@1
|
3997 gbaLastTime = gbaCurrentTime;
|
rlm@1
|
3998 gbaFrameCount = 0;
|
rlm@1
|
3999 }
|
rlm@1
|
4000
|
rlm@1
|
4001 ++GBASystemCounters.frameCount;
|
rlm@1
|
4002 if (GBASystemCounters.lagged)
|
rlm@1
|
4003 {
|
rlm@1
|
4004 ++GBASystemCounters.lagCount;
|
rlm@1
|
4005 }
|
rlm@1
|
4006 GBASystemCounters.laggedLast = GBASystemCounters.lagged;
|
rlm@1
|
4007 GBASystemCounters.lagged = true;
|
rlm@1
|
4008
|
rlm@1
|
4009 if (cheatsEnabled)
|
rlm@1
|
4010 cheatsCheckKeys(P1 ^ 0x3FF, extButtons);
|
rlm@1
|
4011
|
rlm@1
|
4012 extern void VBAOnEnteringFrameBoundary();
|
rlm@1
|
4013 VBAOnEnteringFrameBoundary();
|
rlm@1
|
4014
|
rlm@1
|
4015 newFrame = true;
|
rlm@1
|
4016
|
rlm@1
|
4017 pauseAfterFrameAdvance = systemPauseOnFrame();
|
rlm@1
|
4018
|
rlm@1
|
4019 if (frameSkipCount >= framesToSkip || pauseAfterFrameAdvance)
|
rlm@1
|
4020 {
|
rlm@1
|
4021 systemRenderFrame();
|
rlm@1
|
4022 frameSkipCount = 0;
|
rlm@1
|
4023
|
rlm@1
|
4024 bool capturePressed = (extButtons & 2) != 0;
|
rlm@1
|
4025 if (capturePressed && !capturePrevious)
|
rlm@1
|
4026 {
|
rlm@1
|
4027 captureNumber = systemScreenCapture(captureNumber);
|
rlm@1
|
4028 }
|
rlm@1
|
4029 capturePrevious = capturePressed && !pauseAfterFrameAdvance;
|
rlm@1
|
4030 }
|
rlm@1
|
4031 else
|
rlm@1
|
4032 {
|
rlm@1
|
4033 ++frameSkipCount;
|
rlm@1
|
4034 }
|
rlm@1
|
4035
|
rlm@1
|
4036 if (pauseAfterFrameAdvance)
|
rlm@1
|
4037 {
|
rlm@1
|
4038 systemSetPause(true);
|
rlm@1
|
4039 }
|
rlm@1
|
4040 }
|
rlm@1
|
4041
|
rlm@1
|
4042 UPDATE_REG(0x04, DISPSTAT);
|
rlm@1
|
4043 CPUCompareVCOUNT();
|
rlm@1
|
4044 }
|
rlm@1
|
4045 else
|
rlm@1
|
4046 {
|
rlm@1
|
4047 if (frameSkipCount >= framesToSkip || pauseAfterFrameAdvance)
|
rlm@1
|
4048 {
|
rlm@1
|
4049 (*renderLine)();
|
rlm@1
|
4050
|
rlm@1
|
4051 switch (systemColorDepth)
|
rlm@1
|
4052 {
|
rlm@1
|
4053 case 16:
|
rlm@1
|
4054 {
|
rlm@1
|
4055 u16 *dest = (u16 *)pix + 242 * (VCOUNT + 1);
|
rlm@1
|
4056 for (int x = 0; x < 240; )
|
rlm@1
|
4057 {
|
rlm@1
|
4058 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4059 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4060 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4061 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4062
|
rlm@1
|
4063 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4064 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4065 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4066 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4067
|
rlm@1
|
4068 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4069 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4070 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4071 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4072
|
rlm@1
|
4073 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4074 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4075 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4076 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4077 }
|
rlm@1
|
4078 // for filters that read past the screen
|
rlm@1
|
4079 *dest++ = 0;
|
rlm@1
|
4080 break;
|
rlm@1
|
4081 }
|
rlm@1
|
4082 case 24:
|
rlm@1
|
4083 {
|
rlm@1
|
4084 u8 *dest = (u8 *)pix + 240 * VCOUNT * 3;
|
rlm@1
|
4085 for (int x = 0; x < 240; )
|
rlm@1
|
4086 {
|
rlm@1
|
4087 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4088 dest += 3;
|
rlm@1
|
4089 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4090 dest += 3;
|
rlm@1
|
4091 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4092 dest += 3;
|
rlm@1
|
4093 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4094 dest += 3;
|
rlm@1
|
4095
|
rlm@1
|
4096 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4097 dest += 3;
|
rlm@1
|
4098 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4099 dest += 3;
|
rlm@1
|
4100 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4101 dest += 3;
|
rlm@1
|
4102 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4103 dest += 3;
|
rlm@1
|
4104
|
rlm@1
|
4105 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4106 dest += 3;
|
rlm@1
|
4107 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4108 dest += 3;
|
rlm@1
|
4109 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4110 dest += 3;
|
rlm@1
|
4111 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4112 dest += 3;
|
rlm@1
|
4113
|
rlm@1
|
4114 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4115 dest += 3;
|
rlm@1
|
4116 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4117 dest += 3;
|
rlm@1
|
4118 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4119 dest += 3;
|
rlm@1
|
4120 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4121 dest += 3;
|
rlm@1
|
4122 }
|
rlm@1
|
4123 break;
|
rlm@1
|
4124 }
|
rlm@1
|
4125 case 32:
|
rlm@1
|
4126 {
|
rlm@1
|
4127 u32 *dest = (u32 *)pix + 241 * (VCOUNT + 1);
|
rlm@1
|
4128 for (int x = 0; x < 240; )
|
rlm@1
|
4129 {
|
rlm@1
|
4130 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4131 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4132 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4133 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4134
|
rlm@1
|
4135 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4136 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4137 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4138 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4139
|
rlm@1
|
4140 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4141 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4142 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4143 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4144
|
rlm@1
|
4145 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4146 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4147 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4148 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
|
rlm@1
|
4149 }
|
rlm@1
|
4150 break;
|
rlm@1
|
4151 }
|
rlm@1
|
4152 }
|
rlm@1
|
4153 }
|
rlm@1
|
4154 // entering H-Blank
|
rlm@1
|
4155 DISPSTAT |= 2;
|
rlm@1
|
4156 UPDATE_REG(0x04, DISPSTAT);
|
rlm@1
|
4157 lcdTicks += 272;
|
rlm@1
|
4158 CPUCheckDMA(2, 0x0f);
|
rlm@1
|
4159 if (DISPSTAT & 16)
|
rlm@1
|
4160 {
|
rlm@1
|
4161 IF |= 2;
|
rlm@1
|
4162 UPDATE_REG(0x202, IF);
|
rlm@1
|
4163 }
|
rlm@1
|
4164 }
|
rlm@1
|
4165 }
|
rlm@1
|
4166 }
|
rlm@1
|
4167
|
rlm@1
|
4168 if (!stopState)
|
rlm@1
|
4169 {
|
rlm@1
|
4170 if (timer0On)
|
rlm@1
|
4171 {
|
rlm@1
|
4172 if (timer0ClockReload == 1)
|
rlm@1
|
4173 {
|
rlm@1
|
4174 u32 tm0d = TM0D + clockTicks;
|
rlm@1
|
4175 if (tm0d > 0xffff)
|
rlm@1
|
4176 {
|
rlm@1
|
4177 tm0d += timer0Reload;
|
rlm@1
|
4178 timerOverflow |= 1;
|
rlm@1
|
4179 soundTimerOverflow(0);
|
rlm@1
|
4180 if (TM0CNT & 0x40)
|
rlm@1
|
4181 {
|
rlm@1
|
4182 IF |= 0x08;
|
rlm@1
|
4183 UPDATE_REG(0x202, IF);
|
rlm@1
|
4184 }
|
rlm@1
|
4185 }
|
rlm@1
|
4186 TM0D = tm0d & 0xFFFF;
|
rlm@1
|
4187 timer0Ticks = 0x10000 - TM0D;
|
rlm@1
|
4188 UPDATE_REG(0x100, TM0D);
|
rlm@1
|
4189 }
|
rlm@1
|
4190 else
|
rlm@1
|
4191 {
|
rlm@1
|
4192 timer0Ticks -= clockTicks;
|
rlm@1
|
4193 if (timer0Ticks <= 0)
|
rlm@1
|
4194 {
|
rlm@1
|
4195 timer0Ticks += timer0ClockReload;
|
rlm@1
|
4196 TM0D++;
|
rlm@1
|
4197 if (TM0D == 0)
|
rlm@1
|
4198 {
|
rlm@1
|
4199 TM0D = timer0Reload;
|
rlm@1
|
4200 timerOverflow |= 1;
|
rlm@1
|
4201 soundTimerOverflow(0);
|
rlm@1
|
4202 if (TM0CNT & 0x40)
|
rlm@1
|
4203 {
|
rlm@1
|
4204 IF |= 0x08;
|
rlm@1
|
4205 UPDATE_REG(0x202, IF);
|
rlm@1
|
4206 }
|
rlm@1
|
4207 }
|
rlm@1
|
4208 UPDATE_REG(0x100, TM0D);
|
rlm@1
|
4209 }
|
rlm@1
|
4210 }
|
rlm@1
|
4211 }
|
rlm@1
|
4212
|
rlm@1
|
4213 if (timer1On)
|
rlm@1
|
4214 {
|
rlm@1
|
4215 if (TM1CNT & 4)
|
rlm@1
|
4216 {
|
rlm@1
|
4217 if (timerOverflow & 1)
|
rlm@1
|
4218 {
|
rlm@1
|
4219 TM1D++;
|
rlm@1
|
4220 if (TM1D == 0)
|
rlm@1
|
4221 {
|
rlm@1
|
4222 TM1D += timer1Reload;
|
rlm@1
|
4223 timerOverflow |= 2;
|
rlm@1
|
4224 soundTimerOverflow(1);
|
rlm@1
|
4225 if (TM1CNT & 0x40)
|
rlm@1
|
4226 {
|
rlm@1
|
4227 IF |= 0x10;
|
rlm@1
|
4228 UPDATE_REG(0x202, IF);
|
rlm@1
|
4229 }
|
rlm@1
|
4230 }
|
rlm@1
|
4231 UPDATE_REG(0x104, TM1D);
|
rlm@1
|
4232 }
|
rlm@1
|
4233 }
|
rlm@1
|
4234 else
|
rlm@1
|
4235 {
|
rlm@1
|
4236 if (timer1ClockReload == 1)
|
rlm@1
|
4237 {
|
rlm@1
|
4238 u32 tm1d = TM1D + clockTicks;
|
rlm@1
|
4239 if (tm1d > 0xffff)
|
rlm@1
|
4240 {
|
rlm@1
|
4241 tm1d += timer1Reload;
|
rlm@1
|
4242 timerOverflow |= 2;
|
rlm@1
|
4243 soundTimerOverflow(1);
|
rlm@1
|
4244 if (TM1CNT & 0x40)
|
rlm@1
|
4245 {
|
rlm@1
|
4246 IF |= 0x10;
|
rlm@1
|
4247 UPDATE_REG(0x202, IF);
|
rlm@1
|
4248 }
|
rlm@1
|
4249 }
|
rlm@1
|
4250 TM1D = tm1d & 0xFFFF;
|
rlm@1
|
4251 timer1Ticks = 0x10000 - TM1D;
|
rlm@1
|
4252 UPDATE_REG(0x104, TM1D);
|
rlm@1
|
4253 }
|
rlm@1
|
4254 else
|
rlm@1
|
4255 {
|
rlm@1
|
4256 timer1Ticks -= clockTicks;
|
rlm@1
|
4257 if (timer1Ticks <= 0)
|
rlm@1
|
4258 {
|
rlm@1
|
4259 timer1Ticks += timer1ClockReload;
|
rlm@1
|
4260 TM1D++;
|
rlm@1
|
4261
|
rlm@1
|
4262 if (TM1D == 0)
|
rlm@1
|
4263 {
|
rlm@1
|
4264 TM1D = timer1Reload;
|
rlm@1
|
4265 timerOverflow |= 2;
|
rlm@1
|
4266 soundTimerOverflow(1);
|
rlm@1
|
4267 if (TM1CNT & 0x40)
|
rlm@1
|
4268 {
|
rlm@1
|
4269 IF |= 0x10;
|
rlm@1
|
4270 UPDATE_REG(0x202, IF);
|
rlm@1
|
4271 }
|
rlm@1
|
4272 }
|
rlm@1
|
4273 UPDATE_REG(0x104, TM1D);
|
rlm@1
|
4274 }
|
rlm@1
|
4275 }
|
rlm@1
|
4276 }
|
rlm@1
|
4277 }
|
rlm@1
|
4278
|
rlm@1
|
4279 if (timer2On)
|
rlm@1
|
4280 {
|
rlm@1
|
4281 if (TM2CNT & 4)
|
rlm@1
|
4282 {
|
rlm@1
|
4283 if (timerOverflow & 2)
|
rlm@1
|
4284 {
|
rlm@1
|
4285 TM2D++;
|
rlm@1
|
4286 if (TM2D == 0)
|
rlm@1
|
4287 {
|
rlm@1
|
4288 TM2D += timer2Reload;
|
rlm@1
|
4289 timerOverflow |= 4;
|
rlm@1
|
4290 if (TM2CNT & 0x40)
|
rlm@1
|
4291 {
|
rlm@1
|
4292 IF |= 0x20;
|
rlm@1
|
4293 UPDATE_REG(0x202, IF);
|
rlm@1
|
4294 }
|
rlm@1
|
4295 }
|
rlm@1
|
4296 UPDATE_REG(0x108, TM2D);
|
rlm@1
|
4297 }
|
rlm@1
|
4298 }
|
rlm@1
|
4299 else
|
rlm@1
|
4300 {
|
rlm@1
|
4301 if (timer2ClockReload == 1)
|
rlm@1
|
4302 {
|
rlm@1
|
4303 u32 tm2d = TM2D + clockTicks;
|
rlm@1
|
4304 if (tm2d > 0xffff)
|
rlm@1
|
4305 {
|
rlm@1
|
4306 tm2d += timer2Reload;
|
rlm@1
|
4307 timerOverflow |= 4;
|
rlm@1
|
4308 if (TM2CNT & 0x40)
|
rlm@1
|
4309 {
|
rlm@1
|
4310 IF |= 0x20;
|
rlm@1
|
4311 UPDATE_REG(0x202, IF);
|
rlm@1
|
4312 }
|
rlm@1
|
4313 }
|
rlm@1
|
4314 TM2D = tm2d & 0xFFFF;
|
rlm@1
|
4315 timer2Ticks = 0x10000 - TM2D;
|
rlm@1
|
4316 UPDATE_REG(0x108, TM2D);
|
rlm@1
|
4317 }
|
rlm@1
|
4318 else
|
rlm@1
|
4319 {
|
rlm@1
|
4320 timer2Ticks -= clockTicks;
|
rlm@1
|
4321 if (timer2Ticks <= 0)
|
rlm@1
|
4322 {
|
rlm@1
|
4323 timer2Ticks += timer2ClockReload;
|
rlm@1
|
4324 TM2D++;
|
rlm@1
|
4325
|
rlm@1
|
4326 if (TM2D == 0)
|
rlm@1
|
4327 {
|
rlm@1
|
4328 TM2D = timer2Reload;
|
rlm@1
|
4329 timerOverflow |= 4;
|
rlm@1
|
4330 if (TM2CNT & 0x40)
|
rlm@1
|
4331 {
|
rlm@1
|
4332 IF |= 0x20;
|
rlm@1
|
4333 UPDATE_REG(0x202, IF);
|
rlm@1
|
4334 }
|
rlm@1
|
4335 }
|
rlm@1
|
4336 UPDATE_REG(0x108, TM2D);
|
rlm@1
|
4337 }
|
rlm@1
|
4338 }
|
rlm@1
|
4339 }
|
rlm@1
|
4340 }
|
rlm@1
|
4341
|
rlm@1
|
4342 if (timer3On)
|
rlm@1
|
4343 {
|
rlm@1
|
4344 if (TM3CNT & 4)
|
rlm@1
|
4345 {
|
rlm@1
|
4346 if (timerOverflow & 4)
|
rlm@1
|
4347 {
|
rlm@1
|
4348 TM3D++;
|
rlm@1
|
4349 if (TM3D == 0)
|
rlm@1
|
4350 {
|
rlm@1
|
4351 TM3D += timer3Reload;
|
rlm@1
|
4352 if (TM3CNT & 0x40)
|
rlm@1
|
4353 {
|
rlm@1
|
4354 IF |= 0x40;
|
rlm@1
|
4355 UPDATE_REG(0x202, IF);
|
rlm@1
|
4356 }
|
rlm@1
|
4357 }
|
rlm@1
|
4358 UPDATE_REG(0x10c, TM3D);
|
rlm@1
|
4359 }
|
rlm@1
|
4360 }
|
rlm@1
|
4361 else
|
rlm@1
|
4362 {
|
rlm@1
|
4363 if (timer3ClockReload == 1)
|
rlm@1
|
4364 {
|
rlm@1
|
4365 u32 tm3d = TM3D + clockTicks;
|
rlm@1
|
4366 if (tm3d > 0xffff)
|
rlm@1
|
4367 {
|
rlm@1
|
4368 tm3d += timer3Reload;
|
rlm@1
|
4369 if (TM3CNT & 0x40)
|
rlm@1
|
4370 {
|
rlm@1
|
4371 IF |= 0x40;
|
rlm@1
|
4372 UPDATE_REG(0x202, IF);
|
rlm@1
|
4373 }
|
rlm@1
|
4374 }
|
rlm@1
|
4375 TM3D = tm3d & 0xFFFF;
|
rlm@1
|
4376 timer3Ticks = 0x10000 - TM3D;
|
rlm@1
|
4377 UPDATE_REG(0x10C, TM3D);
|
rlm@1
|
4378 }
|
rlm@1
|
4379 else
|
rlm@1
|
4380 {
|
rlm@1
|
4381 timer3Ticks -= clockTicks;
|
rlm@1
|
4382 if (timer3Ticks <= 0)
|
rlm@1
|
4383 {
|
rlm@1
|
4384 timer3Ticks += timer3ClockReload;
|
rlm@1
|
4385 TM3D++;
|
rlm@1
|
4386
|
rlm@1
|
4387 if (TM3D == 0)
|
rlm@1
|
4388 {
|
rlm@1
|
4389 TM3D = timer3Reload;
|
rlm@1
|
4390 if (TM3CNT & 0x40)
|
rlm@1
|
4391 {
|
rlm@1
|
4392 IF |= 0x40;
|
rlm@1
|
4393 UPDATE_REG(0x202, IF);
|
rlm@1
|
4394 }
|
rlm@1
|
4395 }
|
rlm@1
|
4396 UPDATE_REG(0x10C, TM3D);
|
rlm@1
|
4397 }
|
rlm@1
|
4398 }
|
rlm@1
|
4399 }
|
rlm@1
|
4400 }
|
rlm@1
|
4401 }
|
rlm@1
|
4402 // we shouldn't be doing sound in stop state, but we lose synchronization
|
rlm@1
|
4403 // if sound is disabled, so in stop state, soundTick will just produce
|
rlm@1
|
4404 // mute sound
|
rlm@1
|
4405 soundTicks -= clockTicks;
|
rlm@1
|
4406 if (soundTicks < 1)
|
rlm@1
|
4407 {
|
rlm@1
|
4408 soundTick();
|
rlm@1
|
4409 soundTicks += SOUND_CLOCK_TICKS;
|
rlm@1
|
4410 }
|
rlm@1
|
4411 timerOverflow = 0;
|
rlm@1
|
4412
|
rlm@1
|
4413 #ifdef PROFILING
|
rlm@1
|
4414 profilingTicks -= clockTicks;
|
rlm@1
|
4415 if (profilingTicks <= 0)
|
rlm@1
|
4416 {
|
rlm@1
|
4417 profilingTicks += profilingTicksReload;
|
rlm@1
|
4418 if (profilBuffer && profilSize)
|
rlm@1
|
4419 {
|
rlm@1
|
4420 u16 *b = (u16 *)profilBuffer;
|
rlm@1
|
4421 int pc = ((reg[15].I - profilLowPC) * profilScale) / 0x10000;
|
rlm@1
|
4422 if (pc >= 0 && pc < profilSize)
|
rlm@1
|
4423 {
|
rlm@1
|
4424 b[pc]++;
|
rlm@1
|
4425 }
|
rlm@1
|
4426 }
|
rlm@1
|
4427 }
|
rlm@1
|
4428 #endif
|
rlm@1
|
4429
|
rlm@1
|
4430 ticks -= clockTicks;
|
rlm@1
|
4431 cpuLoopTicks = CPUUpdateTicks();
|
rlm@1
|
4432
|
rlm@1
|
4433 // FIXME: it is too bad that it is still not determined whether the loop can be exited at this point
|
rlm@1
|
4434 if (cpuDmaTicksToUpdate > 0)
|
rlm@1
|
4435 {
|
rlm@1
|
4436 clockTicks = cpuSavedTicks;
|
rlm@1
|
4437 if (clockTicks > cpuDmaTicksToUpdate)
|
rlm@1
|
4438 clockTicks = cpuDmaTicksToUpdate;
|
rlm@1
|
4439 cpuDmaTicksToUpdate -= clockTicks;
|
rlm@1
|
4440 if (cpuDmaTicksToUpdate < 0)
|
rlm@1
|
4441 cpuDmaTicksToUpdate = 0;
|
rlm@1
|
4442 goto updateLoop; // this is evil
|
rlm@1
|
4443 }
|
rlm@1
|
4444
|
rlm@1
|
4445 if (IF && (IME & 1) && armIrqEnable)
|
rlm@1
|
4446 {
|
rlm@1
|
4447 int res = IF & IE;
|
rlm@1
|
4448 if (stopState)
|
rlm@1
|
4449 res &= 0x3080;
|
rlm@1
|
4450 if (res)
|
rlm@1
|
4451 {
|
rlm@1
|
4452 if (intState)
|
rlm@1
|
4453 {
|
rlm@1
|
4454 CPUInterrupt();
|
rlm@1
|
4455 intState = false;
|
rlm@1
|
4456 if (holdState)
|
rlm@1
|
4457 {
|
rlm@1
|
4458 holdState = false;
|
rlm@1
|
4459 stopState = false;
|
rlm@1
|
4460 }
|
rlm@1
|
4461 }
|
rlm@1
|
4462 else
|
rlm@1
|
4463 {
|
rlm@1
|
4464 if (!holdState)
|
rlm@1
|
4465 {
|
rlm@1
|
4466 intState = true;
|
rlm@1
|
4467 cpuLoopTicks = 5;
|
rlm@1
|
4468 cpuSavedTicks = 5;
|
rlm@1
|
4469 }
|
rlm@1
|
4470 else
|
rlm@1
|
4471 {
|
rlm@1
|
4472 CPUInterrupt();
|
rlm@1
|
4473 if (holdState)
|
rlm@1
|
4474 {
|
rlm@1
|
4475 holdState = false;
|
rlm@1
|
4476 stopState = false;
|
rlm@1
|
4477 }
|
rlm@1
|
4478 }
|
rlm@1
|
4479 }
|
rlm@1
|
4480 }
|
rlm@1
|
4481 }
|
rlm@1
|
4482
|
rlm@1
|
4483 if (useOldFrameTiming)
|
rlm@1
|
4484 {
|
rlm@1
|
4485 if (ticks <= 0)
|
rlm@1
|
4486 {
|
rlm@1
|
4487 newFrame = true;
|
rlm@1
|
4488 break;
|
rlm@1
|
4489 }
|
rlm@1
|
4490 }
|
rlm@1
|
4491 else if (newFrame)
|
rlm@1
|
4492 {
|
rlm@1
|
4493 // FIXME: it should be enough to use frameBoundary only if there were no need for supporting the old timing
|
rlm@1
|
4494 // but is there still any GBA .vbm that uses the old timing?
|
rlm@1
|
4495 /// extern void VBAOnEnteringFrameBoundary();
|
rlm@1
|
4496 /// VBAOnEnteringFrameBoundary();
|
rlm@1
|
4497
|
rlm@1
|
4498 break;
|
rlm@1
|
4499 }
|
rlm@1
|
4500 }
|
rlm@1
|
4501 }
|
rlm@1
|
4502 }
|
rlm@1
|
4503
|
rlm@92
|
4504
|
rlm@92
|
4505 // RLM:
|
rlm@92
|
4506 int CPULoop(int _ticks){
|
rlm@92
|
4507 CPULoop2(_ticks);
|
rlm@92
|
4508 return 1;
|
rlm@92
|
4509 }
|
rlm@92
|
4510
|
rlm@92
|
4511
|
rlm@1
|
4512 struct EmulatedSystem GBASystem =
|
rlm@1
|
4513 {
|
rlm@1
|
4514 // emuMain
|
rlm@1
|
4515 CPULoop,
|
rlm@1
|
4516 // emuReset
|
rlm@1
|
4517 CPUReset,
|
rlm@1
|
4518 // emuCleanUp
|
rlm@1
|
4519 CPUCleanUp,
|
rlm@1
|
4520 // emuReadBattery
|
rlm@1
|
4521 CPUReadBatteryFile,
|
rlm@1
|
4522 // emuWriteBattery
|
rlm@1
|
4523 CPUWriteBatteryFile,
|
rlm@1
|
4524 // emuReadBatteryFromStream
|
rlm@1
|
4525 CPUReadBatteryFromStream,
|
rlm@1
|
4526 // emuWriteBatteryToStream
|
rlm@1
|
4527 CPUWriteBatteryToStream,
|
rlm@1
|
4528 // emuReadState
|
rlm@1
|
4529 CPUReadState,
|
rlm@1
|
4530 // emuWriteState
|
rlm@1
|
4531 CPUWriteState,
|
rlm@1
|
4532 // emuReadStateFromStream
|
rlm@1
|
4533 CPUReadStateFromStream,
|
rlm@1
|
4534 // emuWriteStateToStream
|
rlm@1
|
4535 CPUWriteStateToStream,
|
rlm@1
|
4536 // emuReadMemState
|
rlm@1
|
4537 CPUReadMemState,
|
rlm@1
|
4538 // emuWriteMemState
|
rlm@1
|
4539 CPUWriteMemState,
|
rlm@1
|
4540 // emuWritePNG
|
rlm@1
|
4541 CPUWritePNGFile,
|
rlm@1
|
4542 // emuWriteBMP
|
rlm@1
|
4543 CPUWriteBMPFile,
|
rlm@1
|
4544 // emuUpdateCPSR
|
rlm@1
|
4545 CPUUpdateCPSR,
|
rlm@1
|
4546 // emuHasDebugger
|
rlm@1
|
4547 true,
|
rlm@1
|
4548 // emuCount
|
rlm@1
|
4549 #ifdef FINAL_VERSION
|
rlm@1
|
4550 250000,
|
rlm@1
|
4551 #else
|
rlm@1
|
4552 5000,
|
rlm@1
|
4553 #endif
|
rlm@1
|
4554 };
|
rlm@1
|
4555
|
rlm@1
|
4556 // is there a reason to use more than one set of counters?
|
rlm@1
|
4557 EmulatedSystemCounters &GBASystemCounters = systemCounters;
|
rlm@1
|
4558
|
rlm@1
|
4559 /*
|
rlm@1
|
4560 EmulatedSystemCounters GBASystemCounters =
|
rlm@1
|
4561 {
|
rlm@1
|
4562 // frameCount
|
rlm@1
|
4563 0,
|
rlm@1
|
4564 // lagCount
|
rlm@1
|
4565 0,
|
rlm@1
|
4566 // lagged
|
rlm@1
|
4567 true,
|
rlm@1
|
4568 // laggedLast
|
rlm@1
|
4569 true,
|
rlm@1
|
4570 };
|
rlm@1
|
4571 */
|
rlm@1
|
4572
|
rlm@1
|
4573
|
rlm@1
|
4574 #undef CPU_BREAK_LOOP
|
rlm@1
|
4575 #undef CPU_BREAK_LOOP2
|