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, ®[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, ®[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(®[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, ®[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(®[R8_FIQ].I, ®[8].I);
1926 CPUSwap(®[R9_FIQ].I, ®[9].I);
1927 CPUSwap(®[R10_FIQ].I, ®[10].I);
1928 CPUSwap(®[R11_FIQ].I, ®[11].I);
1929 CPUSwap(®[R12_FIQ].I, ®[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(®[8].I, ®[R8_FIQ].I);
1968 CPUSwap(®[9].I, ®[R9_FIQ].I);
1969 CPUSwap(®[10].I, ®[R10_FIQ].I);
1970 CPUSwap(®[11].I, ®[R11_FIQ].I);
1971 CPUSwap(®[12].I, ®[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(®[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