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