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