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