rename all cpp into c, as they're 99.9% C
[rofl0r-VisualBoyAdvance.git] / src / GBA.c
blob967688f7c570399c8c1c4ac04c2d91a46f67d2d8
1 // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
2 // Copyright (C) 1999-2003 Forgotten
3 // Copyright (C) 2005-2006 Forgotten and the VBA development team
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2, or(at your option)
8 // any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <memory.h>
22 #include <stdarg.h>
23 #include <string.h>
25 #include "GBA.h"
26 #include "GBAinline.h"
27 #include "Globals.h"
28 #include "Gfx.h"
29 #include "EEprom.h"
30 #include "Flash.h"
31 #include "Sound.h"
32 #include "Sram.h"
33 #include "bios.h"
34 #include "unzip.h"
35 #include "Cheats.h"
36 #include "NLS.h"
37 #include "elf.h"
38 #include "Util.h"
39 #include "Port.h"
40 #include "agbprint.h"
41 #ifdef PROFILING
42 #include "prof/prof.h"
43 #endif
45 #define UPDATE_REG(address, value)\
47 WRITE16LE(((u16 *)&ioMem[address]),value);\
50 #define ARM_PREFETCH \
52 cpuPrefetch[0] = CPUReadMemoryQuick(armNextPC);\
53 cpuPrefetch[1] = CPUReadMemoryQuick(armNextPC+4);\
56 #define THUMB_PREFETCH \
58 cpuPrefetch[0] = CPUReadHalfWordQuick(armNextPC);\
59 cpuPrefetch[1] = CPUReadHalfWordQuick(armNextPC+2);\
62 #define ARM_PREFETCH_NEXT \
63 cpuPrefetch[1] = CPUReadMemoryQuick(armNextPC+4);
65 #define THUMB_PREFETCH_NEXT\
66 cpuPrefetch[1] = CPUReadHalfWordQuick(armNextPC+2);
68 #ifdef __GNUC__
69 #define _stricmp strcasecmp
70 #endif
73 extern int emulating;
74 int SWITicks = 0;
75 int IRQTicks = 0;
77 u32 mastercode = 0;
78 int layerEnableDelay = 0;
79 bool busPrefetch = false;
80 bool busPrefetchEnable = false;
81 u32 busPrefetchCount = 0;
82 int cpuDmaTicksToUpdate = 0;
83 int cpuDmaCount = 0;
84 bool cpuDmaHack = false;
85 u32 cpuDmaLast = 0;
86 int dummyAddress = 0;
88 bool cpuBreakLoop = false;
89 int cpuNextEvent = 0;
91 int gbaSaveType = 0; // used to remember the save type on reset
92 bool intState = false;
93 bool stopState = false;
94 bool holdState = false;
95 int holdType = 0;
96 bool cpuSramEnabled = true;
97 bool cpuFlashEnabled = true;
98 bool cpuEEPROMEnabled = true;
99 bool cpuEEPROMSensorEnabled = false;
101 u32 cpuPrefetch[2];
103 int cpuTotalTicks = 0;
104 #ifdef PROFILING
105 int profilingTicks = 0;
106 int profilingTicksReload = 0;
107 static profile_segment *profilSegment = NULL;
108 #endif
110 #ifdef BKPT_SUPPORT
111 u8 freezeWorkRAM[0x40000];
112 u8 freezeInternalRAM[0x8000];
113 u8 freezeVRAM[0x18000];
114 u8 freezePRAM[0x400];
115 u8 freezeOAM[0x400];
116 bool debugger_last;
117 #endif
119 int lcdTicks = (useBios && !skipBios) ? 1008 : 208;
120 u8 timerOnOffDelay = 0;
121 u16 timer0Value = 0;
122 bool timer0On = false;
123 int timer0Ticks = 0;
124 int timer0Reload = 0;
125 int timer0ClockReload = 0;
126 u16 timer1Value = 0;
127 bool timer1On = false;
128 int timer1Ticks = 0;
129 int timer1Reload = 0;
130 int timer1ClockReload = 0;
131 u16 timer2Value = 0;
132 bool timer2On = false;
133 int timer2Ticks = 0;
134 int timer2Reload = 0;
135 int timer2ClockReload = 0;
136 u16 timer3Value = 0;
137 bool timer3On = false;
138 int timer3Ticks = 0;
139 int timer3Reload = 0;
140 int timer3ClockReload = 0;
141 u32 dma0Source = 0;
142 u32 dma0Dest = 0;
143 u32 dma1Source = 0;
144 u32 dma1Dest = 0;
145 u32 dma2Source = 0;
146 u32 dma2Dest = 0;
147 u32 dma3Source = 0;
148 u32 dma3Dest = 0;
149 void (*cpuSaveGameFunc)(u32,u8) = flashSaveDecide;
150 void (*renderLine)() = mode0RenderLine;
151 bool fxOn = false;
152 bool windowOn = false;
153 int frameCount = 0;
154 char buffer[1024];
155 FILE *out = NULL;
156 u32 lastTime = 0;
157 int count = 0;
159 int capture = 0;
160 int capturePrevious = 0;
161 int captureNumber = 0;
163 const int TIMER_TICKS[4] = {
170 const u32 objTilesAddress [3] = {0x010000, 0x014000, 0x014000};
171 const u8 gamepakRamWaitState[4] = { 4, 3, 2, 8 };
172 const u8 gamepakWaitState[4] = { 4, 3, 2, 8 };
173 const u8 gamepakWaitState0[2] = { 2, 1 };
174 const u8 gamepakWaitState1[2] = { 4, 1 };
175 const u8 gamepakWaitState2[2] = { 8, 1 };
176 const bool isInRom [16]=
177 { false, false, false, false, false, false, false, false,
178 true, true, true, true, true, true, false, false };
180 u8 memoryWait[16] =
181 { 0, 0, 2, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 0 };
182 u8 memoryWait32[16] =
183 { 0, 0, 5, 0, 0, 1, 1, 0, 7, 7, 9, 9, 13, 13, 4, 0 };
184 u8 memoryWaitSeq[16] =
185 { 0, 0, 2, 0, 0, 0, 0, 0, 2, 2, 4, 4, 8, 8, 4, 0 };
186 u8 memoryWaitSeq32[16] =
187 { 0, 0, 5, 0, 0, 1, 1, 0, 5, 5, 9, 9, 17, 17, 4, 0 };
189 // The videoMemoryWait constants are used to add some waitstates
190 // if the opcode access video memory data outside of vblank/hblank
191 // It seems to happen on only one ticks for each pixel.
192 // Not used for now (too problematic with current code).
193 //const u8 videoMemoryWait[16] =
194 // {0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
197 u8 biosProtected[4];
199 #ifdef WORDS_BIGENDIAN
200 bool cpuBiosSwapped = false;
201 #endif
203 u32 myROM[] = {
204 0xEA000006,
205 0xEA000093,
206 0xEA000006,
207 0x00000000,
208 0x00000000,
209 0x00000000,
210 0xEA000088,
211 0x00000000,
212 0xE3A00302,
213 0xE1A0F000,
214 0xE92D5800,
215 0xE55EC002,
216 0xE28FB03C,
217 0xE79BC10C,
218 0xE14FB000,
219 0xE92D0800,
220 0xE20BB080,
221 0xE38BB01F,
222 0xE129F00B,
223 0xE92D4004,
224 0xE1A0E00F,
225 0xE12FFF1C,
226 0xE8BD4004,
227 0xE3A0C0D3,
228 0xE129F00C,
229 0xE8BD0800,
230 0xE169F00B,
231 0xE8BD5800,
232 0xE1B0F00E,
233 0x0000009C,
234 0x0000009C,
235 0x0000009C,
236 0x0000009C,
237 0x000001F8,
238 0x000001F0,
239 0x000000AC,
240 0x000000A0,
241 0x000000FC,
242 0x00000168,
243 0xE12FFF1E,
244 0xE1A03000,
245 0xE1A00001,
246 0xE1A01003,
247 0xE2113102,
248 0x42611000,
249 0xE033C040,
250 0x22600000,
251 0xE1B02001,
252 0xE15200A0,
253 0x91A02082,
254 0x3AFFFFFC,
255 0xE1500002,
256 0xE0A33003,
257 0x20400002,
258 0xE1320001,
259 0x11A020A2,
260 0x1AFFFFF9,
261 0xE1A01000,
262 0xE1A00003,
263 0xE1B0C08C,
264 0x22600000,
265 0x42611000,
266 0xE12FFF1E,
267 0xE92D0010,
268 0xE1A0C000,
269 0xE3A01001,
270 0xE1500001,
271 0x81A000A0,
272 0x81A01081,
273 0x8AFFFFFB,
274 0xE1A0000C,
275 0xE1A04001,
276 0xE3A03000,
277 0xE1A02001,
278 0xE15200A0,
279 0x91A02082,
280 0x3AFFFFFC,
281 0xE1500002,
282 0xE0A33003,
283 0x20400002,
284 0xE1320001,
285 0x11A020A2,
286 0x1AFFFFF9,
287 0xE0811003,
288 0xE1B010A1,
289 0xE1510004,
290 0x3AFFFFEE,
291 0xE1A00004,
292 0xE8BD0010,
293 0xE12FFF1E,
294 0xE0010090,
295 0xE1A01741,
296 0xE2611000,
297 0xE3A030A9,
298 0xE0030391,
299 0xE1A03743,
300 0xE2833E39,
301 0xE0030391,
302 0xE1A03743,
303 0xE2833C09,
304 0xE283301C,
305 0xE0030391,
306 0xE1A03743,
307 0xE2833C0F,
308 0xE28330B6,
309 0xE0030391,
310 0xE1A03743,
311 0xE2833C16,
312 0xE28330AA,
313 0xE0030391,
314 0xE1A03743,
315 0xE2833A02,
316 0xE2833081,
317 0xE0030391,
318 0xE1A03743,
319 0xE2833C36,
320 0xE2833051,
321 0xE0030391,
322 0xE1A03743,
323 0xE2833CA2,
324 0xE28330F9,
325 0xE0000093,
326 0xE1A00840,
327 0xE12FFF1E,
328 0xE3A00001,
329 0xE3A01001,
330 0xE92D4010,
331 0xE3A03000,
332 0xE3A04001,
333 0xE3500000,
334 0x1B000004,
335 0xE5CC3301,
336 0xEB000002,
337 0x0AFFFFFC,
338 0xE8BD4010,
339 0xE12FFF1E,
340 0xE3A0C301,
341 0xE5CC3208,
342 0xE15C20B8,
343 0xE0110002,
344 0x10222000,
345 0x114C20B8,
346 0xE5CC4208,
347 0xE12FFF1E,
348 0xE92D500F,
349 0xE3A00301,
350 0xE1A0E00F,
351 0xE510F004,
352 0xE8BD500F,
353 0xE25EF004,
354 0xE59FD044,
355 0xE92D5000,
356 0xE14FC000,
357 0xE10FE000,
358 0xE92D5000,
359 0xE3A0C302,
360 0xE5DCE09C,
361 0xE35E00A5,
362 0x1A000004,
363 0x05DCE0B4,
364 0x021EE080,
365 0xE28FE004,
366 0x159FF018,
367 0x059FF018,
368 0xE59FD018,
369 0xE8BD5000,
370 0xE169F00C,
371 0xE8BD5000,
372 0xE25EF004,
373 0x03007FF0,
374 0x09FE2000,
375 0x09FFC000,
376 0x03007FE0
379 variable_desc saveGameStruct[] = {
380 { &DISPCNT , sizeof(u16) },
381 { &DISPSTAT , sizeof(u16) },
382 { &VCOUNT , sizeof(u16) },
383 { &BG0CNT , sizeof(u16) },
384 { &BG1CNT , sizeof(u16) },
385 { &BG2CNT , sizeof(u16) },
386 { &BG3CNT , sizeof(u16) },
387 { &BG0HOFS , sizeof(u16) },
388 { &BG0VOFS , sizeof(u16) },
389 { &BG1HOFS , sizeof(u16) },
390 { &BG1VOFS , sizeof(u16) },
391 { &BG2HOFS , sizeof(u16) },
392 { &BG2VOFS , sizeof(u16) },
393 { &BG3HOFS , sizeof(u16) },
394 { &BG3VOFS , sizeof(u16) },
395 { &BG2PA , sizeof(u16) },
396 { &BG2PB , sizeof(u16) },
397 { &BG2PC , sizeof(u16) },
398 { &BG2PD , sizeof(u16) },
399 { &BG2X_L , sizeof(u16) },
400 { &BG2X_H , sizeof(u16) },
401 { &BG2Y_L , sizeof(u16) },
402 { &BG2Y_H , sizeof(u16) },
403 { &BG3PA , sizeof(u16) },
404 { &BG3PB , sizeof(u16) },
405 { &BG3PC , sizeof(u16) },
406 { &BG3PD , sizeof(u16) },
407 { &BG3X_L , sizeof(u16) },
408 { &BG3X_H , sizeof(u16) },
409 { &BG3Y_L , sizeof(u16) },
410 { &BG3Y_H , sizeof(u16) },
411 { &WIN0H , sizeof(u16) },
412 { &WIN1H , sizeof(u16) },
413 { &WIN0V , sizeof(u16) },
414 { &WIN1V , sizeof(u16) },
415 { &WININ , sizeof(u16) },
416 { &WINOUT , sizeof(u16) },
417 { &MOSAIC , sizeof(u16) },
418 { &BLDMOD , sizeof(u16) },
419 { &COLEV , sizeof(u16) },
420 { &COLY , sizeof(u16) },
421 { &DM0SAD_L , sizeof(u16) },
422 { &DM0SAD_H , sizeof(u16) },
423 { &DM0DAD_L , sizeof(u16) },
424 { &DM0DAD_H , sizeof(u16) },
425 { &DM0CNT_L , sizeof(u16) },
426 { &DM0CNT_H , sizeof(u16) },
427 { &DM1SAD_L , sizeof(u16) },
428 { &DM1SAD_H , sizeof(u16) },
429 { &DM1DAD_L , sizeof(u16) },
430 { &DM1DAD_H , sizeof(u16) },
431 { &DM1CNT_L , sizeof(u16) },
432 { &DM1CNT_H , sizeof(u16) },
433 { &DM2SAD_L , sizeof(u16) },
434 { &DM2SAD_H , sizeof(u16) },
435 { &DM2DAD_L , sizeof(u16) },
436 { &DM2DAD_H , sizeof(u16) },
437 { &DM2CNT_L , sizeof(u16) },
438 { &DM2CNT_H , sizeof(u16) },
439 { &DM3SAD_L , sizeof(u16) },
440 { &DM3SAD_H , sizeof(u16) },
441 { &DM3DAD_L , sizeof(u16) },
442 { &DM3DAD_H , sizeof(u16) },
443 { &DM3CNT_L , sizeof(u16) },
444 { &DM3CNT_H , sizeof(u16) },
445 { &TM0D , sizeof(u16) },
446 { &TM0CNT , sizeof(u16) },
447 { &TM1D , sizeof(u16) },
448 { &TM1CNT , sizeof(u16) },
449 { &TM2D , sizeof(u16) },
450 { &TM2CNT , sizeof(u16) },
451 { &TM3D , sizeof(u16) },
452 { &TM3CNT , sizeof(u16) },
453 { &P1 , sizeof(u16) },
454 { &IE , sizeof(u16) },
455 { &IF , sizeof(u16) },
456 { &IME , sizeof(u16) },
457 { &holdState, sizeof(bool) },
458 { &holdType, sizeof(int) },
459 { &lcdTicks, sizeof(int) },
460 { &timer0On , sizeof(bool) },
461 { &timer0Ticks , sizeof(int) },
462 { &timer0Reload , sizeof(int) },
463 { &timer0ClockReload , sizeof(int) },
464 { &timer1On , sizeof(bool) },
465 { &timer1Ticks , sizeof(int) },
466 { &timer1Reload , sizeof(int) },
467 { &timer1ClockReload , sizeof(int) },
468 { &timer2On , sizeof(bool) },
469 { &timer2Ticks , sizeof(int) },
470 { &timer2Reload , sizeof(int) },
471 { &timer2ClockReload , sizeof(int) },
472 { &timer3On , sizeof(bool) },
473 { &timer3Ticks , sizeof(int) },
474 { &timer3Reload , sizeof(int) },
475 { &timer3ClockReload , sizeof(int) },
476 { &dma0Source , sizeof(u32) },
477 { &dma0Dest , sizeof(u32) },
478 { &dma1Source , sizeof(u32) },
479 { &dma1Dest , sizeof(u32) },
480 { &dma2Source , sizeof(u32) },
481 { &dma2Dest , sizeof(u32) },
482 { &dma3Source , sizeof(u32) },
483 { &dma3Dest , sizeof(u32) },
484 { &fxOn, sizeof(bool) },
485 { &windowOn, sizeof(bool) },
486 { &N_FLAG , sizeof(bool) },
487 { &C_FLAG , sizeof(bool) },
488 { &Z_FLAG , sizeof(bool) },
489 { &V_FLAG , sizeof(bool) },
490 { &armState , sizeof(bool) },
491 { &armIrqEnable , sizeof(bool) },
492 { &armNextPC , sizeof(u32) },
493 { &armMode , sizeof(int) },
494 { &saveType , sizeof(int) },
495 { NULL, 0 }
498 static int romSize = 0x2000000;
500 #ifdef PROFILING
501 void cpuProfil(profile_segment *seg)
503 profilSegment = seg;
506 void cpuEnableProfiling(int hz)
508 if(hz == 0)
509 hz = 100;
510 profilingTicks = profilingTicksReload = 16777216 / hz;
511 profSetHertz(hz);
513 #endif
516 // Waitstates when accessing data
517 inline int dataTicksAccess16(u32 address) // DATA 8/16bits NON SEQ
519 int addr = (address>>24)&15;
520 int value = memoryWait[addr];
522 if ((addr>=0x08) || (addr < 0x02))
524 busPrefetchCount=0;
525 busPrefetch=false;
527 else if (busPrefetch)
529 int waitState = value;
530 if (!waitState)
531 waitState = 1;
532 busPrefetchCount = ((++busPrefetchCount)<<waitState) - 1;
535 return value;
538 inline int dataTicksAccess32(u32 address) // DATA 32bits NON SEQ
540 int addr = (address>>24)&15;
541 int value = memoryWait32[addr];
543 if ((addr>=0x08) || (addr < 0x02))
545 busPrefetchCount=0;
546 busPrefetch=false;
548 else if (busPrefetch)
550 int waitState = value;
551 if (!waitState)
552 waitState = 1;
553 busPrefetchCount = ((++busPrefetchCount)<<waitState) - 1;
556 return value;
559 inline int dataTicksAccessSeq16(u32 address)// DATA 8/16bits SEQ
561 int addr = (address>>24)&15;
562 int value = memoryWaitSeq[addr];
564 if ((addr>=0x08) || (addr < 0x02))
566 busPrefetchCount=0;
567 busPrefetch=false;
569 else if (busPrefetch)
571 int waitState = value;
572 if (!waitState)
573 waitState = 1;
574 busPrefetchCount = ((++busPrefetchCount)<<waitState) - 1;
577 return value;
580 inline int dataTicksAccessSeq32(u32 address)// DATA 32bits SEQ
582 int addr = (address>>24)&15;
583 int value = memoryWaitSeq32[addr];
585 if ((addr>=0x08) || (addr < 0x02))
587 busPrefetchCount=0;
588 busPrefetch=false;
590 else if (busPrefetch)
592 int waitState = value;
593 if (!waitState)
594 waitState = 1;
595 busPrefetchCount = ((++busPrefetchCount)<<waitState) - 1;
598 return value;
602 // Waitstates when executing opcode
603 inline int codeTicksAccess16(u32 address) // THUMB NON SEQ
605 int addr = (address>>24)&15;
607 if ((addr>=0x08) && (addr<=0x0D))
609 if (busPrefetchCount&0x1)
611 if (busPrefetchCount&0x2)
613 busPrefetchCount = ((busPrefetchCount&0xFF)>>2) | (busPrefetchCount&0xFFFFFF00);
614 return 0;
616 busPrefetchCount = ((busPrefetchCount&0xFF)>>1) | (busPrefetchCount&0xFFFFFF00);
617 return memoryWaitSeq[addr]-1;
619 else
621 busPrefetchCount=0;
622 return memoryWait[addr];
625 else
627 busPrefetchCount = 0;
628 return memoryWait[addr];
632 inline int codeTicksAccess32(u32 address) // ARM NON SEQ
634 int addr = (address>>24)&15;
636 if ((addr>=0x08) && (addr<=0x0D))
638 if (busPrefetchCount&0x1)
640 if (busPrefetchCount&0x2)
642 busPrefetchCount = ((busPrefetchCount&0xFF)>>2) | (busPrefetchCount&0xFFFFFF00);
643 return 0;
645 busPrefetchCount = ((busPrefetchCount&0xFF)>>1) | (busPrefetchCount&0xFFFFFF00);
646 return memoryWaitSeq[addr] - 1;
648 else
650 busPrefetchCount = 0;
651 return memoryWait32[addr];
654 else
656 busPrefetchCount = 0;
657 return memoryWait32[addr];
661 inline int codeTicksAccessSeq16(u32 address) // THUMB SEQ
663 int addr = (address>>24)&15;
665 if ((addr>=0x08) && (addr<=0x0D))
667 if (busPrefetchCount&0x1)
669 busPrefetchCount = ((busPrefetchCount&0xFF)>>1) | (busPrefetchCount&0xFFFFFF00);
670 return 0;
672 else
673 if (busPrefetchCount>0xFF)
675 busPrefetchCount=0;
676 return memoryWait[addr];
678 else
679 return memoryWaitSeq[addr];
681 else
683 busPrefetchCount = 0;
684 return memoryWaitSeq[addr];
688 inline int codeTicksAccessSeq32(u32 address) // ARM SEQ
690 int addr = (address>>24)&15;
692 if ((addr>=0x08) && (addr<=0x0D))
694 if (busPrefetchCount&0x1)
696 if (busPrefetchCount&0x2)
698 busPrefetchCount = ((busPrefetchCount&0xFF)>>2) | (busPrefetchCount&0xFFFFFF00);
699 return 0;
701 busPrefetchCount = ((busPrefetchCount&0xFF)>>1) | (busPrefetchCount&0xFFFFFF00);
702 return memoryWaitSeq[addr];
704 else
705 if (busPrefetchCount>0xFF)
707 busPrefetchCount=0;
708 return memoryWait32[addr];
710 else
711 return memoryWaitSeq32[addr];
713 else
715 return memoryWaitSeq32[addr];
720 inline int CPUUpdateTicks()
722 int cpuLoopTicks = lcdTicks;
724 if(soundTicks < cpuLoopTicks)
725 cpuLoopTicks = soundTicks;
727 if(timer0On && (timer0Ticks < cpuLoopTicks)) {
728 cpuLoopTicks = timer0Ticks;
730 if(timer1On && !(TM1CNT & 4) && (timer1Ticks < cpuLoopTicks)) {
731 cpuLoopTicks = timer1Ticks;
733 if(timer2On && !(TM2CNT & 4) && (timer2Ticks < cpuLoopTicks)) {
734 cpuLoopTicks = timer2Ticks;
736 if(timer3On && !(TM3CNT & 4) && (timer3Ticks < cpuLoopTicks)) {
737 cpuLoopTicks = timer3Ticks;
739 #ifdef PROFILING
740 if(profilingTicksReload != 0) {
741 if(profilingTicks < cpuLoopTicks) {
742 cpuLoopTicks = profilingTicks;
745 #endif
747 if (SWITicks) {
748 if (SWITicks < cpuLoopTicks)
749 cpuLoopTicks = SWITicks;
752 if (IRQTicks) {
753 if (IRQTicks < cpuLoopTicks)
754 cpuLoopTicks = IRQTicks;
757 return cpuLoopTicks;
760 void CPUUpdateWindow0()
762 int x00 = WIN0H>>8;
763 int x01 = WIN0H & 255;
765 if(x00 <= x01) {
766 for(int i = 0; i < 240; i++) {
767 gfxInWin0[i] = (i >= x00 && i < x01);
769 } else {
770 for(int i = 0; i < 240; i++) {
771 gfxInWin0[i] = (i >= x00 || i < x01);
776 void CPUUpdateWindow1()
778 int x00 = WIN1H>>8;
779 int x01 = WIN1H & 255;
781 if(x00 <= x01) {
782 for(int i = 0; i < 240; i++) {
783 gfxInWin1[i] = (i >= x00 && i < x01);
785 } else {
786 for(int i = 0; i < 240; i++) {
787 gfxInWin1[i] = (i >= x00 || i < x01);
792 extern u32 line0[240];
793 extern u32 line1[240];
794 extern u32 line2[240];
795 extern u32 line3[240];
797 #define CLEAR_ARRAY(a) \
799 u32 *array = (a);\
800 for(int i = 0; i < 240; i++) {\
801 *array++ = 0x80000000;\
805 void CPUUpdateRenderBuffers(bool force)
807 if(!(layerEnable & 0x0100) || force) {
808 CLEAR_ARRAY(line0);
810 if(!(layerEnable & 0x0200) || force) {
811 CLEAR_ARRAY(line1);
813 if(!(layerEnable & 0x0400) || force) {
814 CLEAR_ARRAY(line2);
816 if(!(layerEnable & 0x0800) || force) {
817 CLEAR_ARRAY(line3);
821 static bool CPUWriteState(gzFile gzFile)
823 utilWriteInt(gzFile, SAVE_GAME_VERSION);
825 utilGzWrite(gzFile, &rom[0xa0], 16);
827 utilWriteInt(gzFile, useBios);
829 utilGzWrite(gzFile, &reg[0], sizeof(reg));
831 utilWriteData(gzFile, saveGameStruct);
833 // new to version 0.7.1
834 utilWriteInt(gzFile, stopState);
835 // new to version 0.8
836 utilWriteInt(gzFile, IRQTicks);
838 utilGzWrite(gzFile, internalRAM, 0x8000);
839 utilGzWrite(gzFile, paletteRAM, 0x400);
840 utilGzWrite(gzFile, workRAM, 0x40000);
841 utilGzWrite(gzFile, vram, 0x20000);
842 utilGzWrite(gzFile, oam, 0x400);
843 utilGzWrite(gzFile, pix, 4*241*162);
844 utilGzWrite(gzFile, ioMem, 0x400);
846 eepromSaveGame(gzFile);
847 flashSaveGame(gzFile);
848 soundSaveGame(gzFile);
850 cheatsSaveGame(gzFile);
852 // version 1.5
853 rtcSaveGame(gzFile);
855 return true;
858 bool CPUWriteState(const char *file)
860 gzFile gzFile = utilGzOpen(file, "wb");
862 if(gzFile == NULL) {
863 systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), file);
864 return false;
867 bool res = CPUWriteState(gzFile);
869 utilGzClose(gzFile);
871 return res;
874 bool CPUWriteMemState(char *memory, int available)
876 gzFile gzFile = utilMemGzOpen(memory, available, "w");
878 if(gzFile == NULL) {
879 return false;
882 bool res = CPUWriteState(gzFile);
884 long pos = utilGzMemTell(gzFile)+8;
886 if(pos >= (available))
887 res = false;
889 utilGzClose(gzFile);
891 return res;
894 static bool CPUReadState(gzFile gzFile)
896 int version = utilReadInt(gzFile);
898 if(version > SAVE_GAME_VERSION || version < SAVE_GAME_VERSION_1) {
899 systemMessage(MSG_UNSUPPORTED_VBA_SGM,
900 N_("Unsupported VisualBoyAdvance save game version %d"),
901 version);
902 return false;
905 u8 romname[17];
907 utilGzRead(gzFile, romname, 16);
909 if(memcmp(&rom[0xa0], romname, 16) != 0) {
910 romname[16]=0;
911 for(int i = 0; i < 16; i++)
912 if(romname[i] < 32)
913 romname[i] = 32;
914 systemMessage(MSG_CANNOT_LOAD_SGM, N_("Cannot load save game for %s"), romname);
915 return false;
918 bool ub = utilReadInt(gzFile) ? true : false;
920 if(ub != useBios) {
921 if(useBios)
922 systemMessage(MSG_SAVE_GAME_NOT_USING_BIOS,
923 N_("Save game is not using the BIOS files"));
924 else
925 systemMessage(MSG_SAVE_GAME_USING_BIOS,
926 N_("Save game is using the BIOS file"));
927 return false;
930 utilGzRead(gzFile, &reg[0], sizeof(reg));
932 utilReadData(gzFile, saveGameStruct);
934 if(version < SAVE_GAME_VERSION_3)
935 stopState = false;
936 else
937 stopState = utilReadInt(gzFile) ? true : false;
939 if(version < SAVE_GAME_VERSION_4)
941 IRQTicks = 0;
942 intState = false;
944 else
946 IRQTicks = utilReadInt(gzFile);
947 if (IRQTicks>0)
948 intState = true;
949 else
951 intState = false;
952 IRQTicks = 0;
956 utilGzRead(gzFile, internalRAM, 0x8000);
957 utilGzRead(gzFile, paletteRAM, 0x400);
958 utilGzRead(gzFile, workRAM, 0x40000);
959 utilGzRead(gzFile, vram, 0x20000);
960 utilGzRead(gzFile, oam, 0x400);
961 if(version < SAVE_GAME_VERSION_6)
962 utilGzRead(gzFile, pix, 4*240*160);
963 else
964 utilGzRead(gzFile, pix, 4*241*162);
965 utilGzRead(gzFile, ioMem, 0x400);
967 eepromReadGame(gzFile, version);
968 flashReadGame(gzFile, version);
969 soundReadGame(gzFile, version);
971 if(version > SAVE_GAME_VERSION_1) {
972 cheatsReadGame(gzFile, version);
974 if(version > SAVE_GAME_VERSION_6) {
975 rtcReadGame(gzFile);
978 if(version <= SAVE_GAME_VERSION_7) {
979 u32 temp;
980 #define SWAP(a,b,c) \
981 temp = (a);\
982 (a) = (b)<<16|(c);\
983 (b) = (temp) >> 16;\
984 (c) = (temp) & 0xFFFF;
986 SWAP(dma0Source, DM0SAD_H, DM0SAD_L);
987 SWAP(dma0Dest, DM0DAD_H, DM0DAD_L);
988 SWAP(dma1Source, DM1SAD_H, DM1SAD_L);
989 SWAP(dma1Dest, DM1DAD_H, DM1DAD_L);
990 SWAP(dma2Source, DM2SAD_H, DM2SAD_L);
991 SWAP(dma2Dest, DM2DAD_H, DM2DAD_L);
992 SWAP(dma3Source, DM3SAD_H, DM3SAD_L);
993 SWAP(dma3Dest, DM3DAD_H, DM3DAD_L);
996 if(version <= SAVE_GAME_VERSION_8) {
997 timer0ClockReload = TIMER_TICKS[TM0CNT & 3];
998 timer1ClockReload = TIMER_TICKS[TM1CNT & 3];
999 timer2ClockReload = TIMER_TICKS[TM2CNT & 3];
1000 timer3ClockReload = TIMER_TICKS[TM3CNT & 3];
1002 timer0Ticks = ((0x10000 - TM0D) << timer0ClockReload) - timer0Ticks;
1003 timer1Ticks = ((0x10000 - TM1D) << timer1ClockReload) - timer1Ticks;
1004 timer2Ticks = ((0x10000 - TM2D) << timer2ClockReload) - timer2Ticks;
1005 timer3Ticks = ((0x10000 - TM3D) << timer3ClockReload) - timer3Ticks;
1008 // set pointers!
1009 layerEnable = layerSettings & DISPCNT;
1011 CPUUpdateRender();
1012 CPUUpdateRenderBuffers(true);
1013 CPUUpdateWindow0();
1014 CPUUpdateWindow1();
1015 gbaSaveType = 0;
1016 switch(saveType) {
1017 case 0:
1018 cpuSaveGameFunc = flashSaveDecide;
1019 break;
1020 case 1:
1021 cpuSaveGameFunc = sramWrite;
1022 gbaSaveType = 1;
1023 break;
1024 case 2:
1025 cpuSaveGameFunc = flashWrite;
1026 gbaSaveType = 2;
1027 break;
1028 case 3:
1029 break;
1030 case 5:
1031 gbaSaveType = 5;
1032 break;
1033 default:
1034 systemMessage(MSG_UNSUPPORTED_SAVE_TYPE,
1035 N_("Unsupported save type %d"), saveType);
1036 break;
1038 if(eepromInUse)
1039 gbaSaveType = 3;
1041 systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
1042 if(armState) {
1043 ARM_PREFETCH;
1044 } else {
1045 THUMB_PREFETCH;
1048 CPUUpdateRegister(0x204, CPUReadHalfWordQuick(0x4000204));
1050 return true;
1053 bool CPUReadMemState(char *memory, int available)
1055 gzFile gzFile = utilMemGzOpen(memory, available, "r");
1057 bool res = CPUReadState(gzFile);
1059 utilGzClose(gzFile);
1061 return res;
1064 bool CPUReadState(const char * file)
1066 gzFile gzFile = utilGzOpen(file, "rb");
1068 if(gzFile == NULL)
1069 return false;
1071 bool res = CPUReadState(gzFile);
1073 utilGzClose(gzFile);
1075 return res;
1078 bool CPUExportEepromFile(const char *fileName)
1080 if(eepromInUse) {
1081 FILE *file = fopen(fileName, "wb");
1083 if(!file) {
1084 systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"),
1085 fileName);
1086 return false;
1089 for(int i = 0; i < eepromSize;) {
1090 for(int j = 0; j < 8; j++) {
1091 if(fwrite(&eepromData[i+7-j], 1, 1, file) != 1) {
1092 fclose(file);
1093 return false;
1096 i += 8;
1098 fclose(file);
1100 return true;
1103 bool CPUWriteBatteryFile(const char *fileName)
1105 if(gbaSaveType == 0) {
1106 if(eepromInUse)
1107 gbaSaveType = 3;
1108 else switch(saveType) {
1109 case 1:
1110 gbaSaveType = 1;
1111 break;
1112 case 2:
1113 gbaSaveType = 2;
1114 break;
1118 if((gbaSaveType) && (gbaSaveType!=5)) {
1119 FILE *file = fopen(fileName, "wb");
1121 if(!file) {
1122 systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"),
1123 fileName);
1124 return false;
1127 // only save if Flash/Sram in use or EEprom in use
1128 if(gbaSaveType != 3) {
1129 if(gbaSaveType == 2) {
1130 if(fwrite(flashSaveMemory, 1, flashSize, file) != (size_t)flashSize) {
1131 fclose(file);
1132 return false;
1134 } else {
1135 if(fwrite(flashSaveMemory, 1, 0x10000, file) != 0x10000) {
1136 fclose(file);
1137 return false;
1140 } else {
1141 if(fwrite(eepromData, 1, eepromSize, file) != (size_t)eepromSize) {
1142 fclose(file);
1143 return false;
1146 fclose(file);
1148 return true;
1151 bool CPUReadGSASnapshot(const char *fileName)
1153 int i;
1154 FILE *file = fopen(fileName, "rb");
1156 if(!file) {
1157 systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName);
1158 return false;
1161 // check file size to know what we should read
1162 fseek(file, 0, SEEK_END);
1164 // long size = ftell(file);
1165 fseek(file, 0x0, SEEK_SET);
1166 fread(&i, 1, 4, file);
1167 fseek(file, i, SEEK_CUR); // Skip SharkPortSave
1168 fseek(file, 4, SEEK_CUR); // skip some sort of flag
1169 fread(&i, 1, 4, file); // name length
1170 fseek(file, i, SEEK_CUR); // skip name
1171 fread(&i, 1, 4, file); // desc length
1172 fseek(file, i, SEEK_CUR); // skip desc
1173 fread(&i, 1, 4, file); // notes length
1174 fseek(file, i, SEEK_CUR); // skip notes
1175 int saveSize;
1176 fread(&saveSize, 1, 4, file); // read length
1177 saveSize -= 0x1c; // remove header size
1178 char buffer[17];
1179 char buffer2[17];
1180 fread(buffer, 1, 16, file);
1181 buffer[16] = 0;
1182 for(i = 0; i < 16; i++)
1183 if(buffer[i] < 32)
1184 buffer[i] = 32;
1185 memcpy(buffer2, &rom[0xa0], 16);
1186 buffer2[16] = 0;
1187 for(i = 0; i < 16; i++)
1188 if(buffer2[i] < 32)
1189 buffer2[i] = 32;
1190 if(memcmp(buffer, buffer2, 16)) {
1191 systemMessage(MSG_CANNOT_IMPORT_SNAPSHOT_FOR,
1192 N_("Cannot import snapshot for %s. Current game is %s"),
1193 buffer,
1194 buffer2);
1195 fclose(file);
1196 return false;
1198 fseek(file, 12, SEEK_CUR); // skip some flags
1199 if(saveSize >= 65536) {
1200 if(fread(flashSaveMemory, 1, saveSize, file) != (size_t)saveSize) {
1201 fclose(file);
1202 return false;
1204 } else {
1205 systemMessage(MSG_UNSUPPORTED_SNAPSHOT_FILE,
1206 N_("Unsupported snapshot file %s"),
1207 fileName);
1208 fclose(file);
1209 return false;
1211 fclose(file);
1212 CPUReset();
1213 return true;
1216 bool CPUWriteGSASnapshot(const char *fileName,
1217 const char *title,
1218 const char *desc,
1219 const char *notes)
1221 FILE *file = fopen(fileName, "wb");
1223 if(!file) {
1224 systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName);
1225 return false;
1228 u8 buffer[17];
1230 utilPutDword(buffer, 0x0d); // SharkPortSave length
1231 fwrite(buffer, 1, 4, file);
1232 fwrite("SharkPortSave", 1, 0x0d, file);
1233 utilPutDword(buffer, 0x000f0000);
1234 fwrite(buffer, 1, 4, file); // save type 0x000f0000 = GBA save
1235 utilPutDword(buffer, (u32)strlen(title));
1236 fwrite(buffer, 1, 4, file); // title length
1237 fwrite(title, 1, strlen(title), file);
1238 utilPutDword(buffer, (u32)strlen(desc));
1239 fwrite(buffer, 1, 4, file); // desc length
1240 fwrite(desc, 1, strlen(desc), file);
1241 utilPutDword(buffer, (u32)strlen(notes));
1242 fwrite(buffer, 1, 4, file); // notes length
1243 fwrite(notes, 1, strlen(notes), file);
1244 int saveSize = 0x10000;
1245 if(gbaSaveType == 2)
1246 saveSize = flashSize;
1247 int totalSize = saveSize + 0x1c;
1249 utilPutDword(buffer, totalSize); // length of remainder of save - CRC
1250 fwrite(buffer, 1, 4, file);
1252 char temp[0x2001c];
1253 memset(temp, 0, 28);
1254 memcpy(temp, &rom[0xa0], 16); // copy internal name
1255 temp[0x10] = rom[0xbe]; // reserved area (old checksum)
1256 temp[0x11] = rom[0xbf]; // reserved area (old checksum)
1257 temp[0x12] = rom[0xbd]; // complement check
1258 temp[0x13] = rom[0xb0]; // maker
1259 temp[0x14] = 1; // 1 save ?
1260 memcpy(&temp[0x1c], flashSaveMemory, saveSize); // copy save
1261 fwrite(temp, 1, totalSize, file); // write save + header
1262 u32 crc = 0;
1264 for(int i = 0; i < totalSize; i++) {
1265 crc += ((u32)temp[i] << (crc % 0x18));
1268 utilPutDword(buffer, crc);
1269 fwrite(buffer, 1, 4, file); // CRC?
1271 fclose(file);
1272 return true;
1275 bool CPUImportEepromFile(const char *fileName)
1277 FILE *file = fopen(fileName, "rb");
1279 if(!file)
1280 return false;
1282 // check file size to know what we should read
1283 fseek(file, 0, SEEK_END);
1285 long size = ftell(file);
1286 fseek(file, 0, SEEK_SET);
1287 if(size == 512 || size == 0x2000) {
1288 if(fread(eepromData, 1, size, file) != (size_t)size) {
1289 fclose(file);
1290 return false;
1292 for(int i = 0; i < size;) {
1293 u8 tmp = eepromData[i];
1294 eepromData[i] = eepromData[7-i];
1295 eepromData[7-i] = tmp;
1296 i++;
1297 tmp = eepromData[i];
1298 eepromData[i] = eepromData[7-i];
1299 eepromData[7-i] = tmp;
1300 i++;
1301 tmp = eepromData[i];
1302 eepromData[i] = eepromData[7-i];
1303 eepromData[7-i] = tmp;
1304 i++;
1305 tmp = eepromData[i];
1306 eepromData[i] = eepromData[7-i];
1307 eepromData[7-i] = tmp;
1308 i++;
1309 i += 4;
1311 } else
1312 return false;
1313 fclose(file);
1314 return true;
1317 bool CPUReadBatteryFile(const char *fileName)
1319 FILE *file = fopen(fileName, "rb");
1321 if(!file)
1322 return false;
1324 // check file size to know what we should read
1325 fseek(file, 0, SEEK_END);
1327 long size = ftell(file);
1328 fseek(file, 0, SEEK_SET);
1329 systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
1331 if(size == 512 || size == 0x2000) {
1332 if(fread(eepromData, 1, size, file) != (size_t)size) {
1333 fclose(file);
1334 return false;
1336 } else {
1337 if(size == 0x20000) {
1338 if(fread(flashSaveMemory, 1, 0x20000, file) != 0x20000) {
1339 fclose(file);
1340 return false;
1342 flashSetSize(0x20000);
1343 } else {
1344 if(fread(flashSaveMemory, 1, 0x10000, file) != 0x10000) {
1345 fclose(file);
1346 return false;
1348 flashSetSize(0x10000);
1351 fclose(file);
1352 return true;
1355 bool CPUWritePNGFile(const char *fileName)
1357 return utilWritePNGFile(fileName, 240, 160, pix);
1360 bool CPUWriteBMPFile(const char *fileName)
1362 return utilWriteBMPFile(fileName, 240, 160, pix);
1365 bool CPUIsZipFile(const char * file)
1367 if(strlen(file) > 4) {
1368 const char * p = strrchr(file,'.');
1370 if(p != NULL) {
1371 if(_stricmp(p, ".zip") == 0)
1372 return true;
1376 return false;
1379 bool CPUIsGBAImage(const char * file)
1381 cpuIsMultiBoot = false;
1382 if(strlen(file) > 4) {
1383 const char * p = strrchr(file,'.');
1385 if(p != NULL) {
1386 if(_stricmp(p, ".gba") == 0)
1387 return true;
1388 if(_stricmp(p, ".agb") == 0)
1389 return true;
1390 if(_stricmp(p, ".bin") == 0)
1391 return true;
1392 if(_stricmp(p, ".elf") == 0)
1393 return true;
1394 if(_stricmp(p, ".mb") == 0) {
1395 cpuIsMultiBoot = true;
1396 return true;
1401 return false;
1404 bool CPUIsGBABios(const char * file)
1406 if(strlen(file) > 4) {
1407 const char * p = strrchr(file,'.');
1409 if(p != NULL) {
1410 if(_stricmp(p, ".gba") == 0)
1411 return true;
1412 if(_stricmp(p, ".agb") == 0)
1413 return true;
1414 if(_stricmp(p, ".bin") == 0)
1415 return true;
1416 if(_stricmp(p, ".bios") == 0)
1417 return true;
1421 return false;
1424 bool CPUIsELF(const char *file)
1426 if(strlen(file) > 4) {
1427 const char * p = strrchr(file,'.');
1429 if(p != NULL) {
1430 if(_stricmp(p, ".elf") == 0)
1431 return true;
1434 return false;
1437 void CPUCleanUp()
1439 #ifdef PROFILING
1440 if(profilingTicksReload) {
1441 profCleanup();
1443 #endif
1445 if(rom != NULL) {
1446 free(rom);
1447 rom = NULL;
1450 if(vram != NULL) {
1451 free(vram);
1452 vram = NULL;
1455 if(paletteRAM != NULL) {
1456 free(paletteRAM);
1457 paletteRAM = NULL;
1460 if(internalRAM != NULL) {
1461 free(internalRAM);
1462 internalRAM = NULL;
1465 if(workRAM != NULL) {
1466 free(workRAM);
1467 workRAM = NULL;
1470 if(bios != NULL) {
1471 free(bios);
1472 bios = NULL;
1475 if(pix != NULL) {
1476 free(pix);
1477 pix = NULL;
1480 if(oam != NULL) {
1481 free(oam);
1482 oam = NULL;
1485 if(ioMem != NULL) {
1486 free(ioMem);
1487 ioMem = NULL;
1490 elfCleanUp();
1492 systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
1494 emulating = 0;
1497 int CPULoadRom(const char *szFile)
1499 romSize = 0x2000000;
1500 if(rom != NULL) {
1501 CPUCleanUp();
1504 systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
1506 rom = (u8 *)malloc(0x2000000);
1507 if(rom == NULL) {
1508 systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
1509 "ROM");
1510 return 0;
1512 workRAM = (u8 *)calloc(1, 0x40000);
1513 if(workRAM == NULL) {
1514 systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
1515 "WRAM");
1516 return 0;
1519 u8 *whereToLoad = rom;
1520 if(cpuIsMultiBoot)
1521 whereToLoad = workRAM;
1523 if(CPUIsELF(szFile)) {
1524 FILE *f = fopen(szFile, "rb");
1525 if(!f) {
1526 systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"),
1527 szFile);
1528 free(rom);
1529 rom = NULL;
1530 free(workRAM);
1531 workRAM = NULL;
1532 return 0;
1534 bool res = elfRead(szFile, romSize, f);
1535 if(!res || romSize == 0) {
1536 free(rom);
1537 rom = NULL;
1538 free(workRAM);
1539 workRAM = NULL;
1540 elfCleanUp();
1541 return 0;
1543 } else if(!utilLoad(szFile,
1544 utilIsGBAImage,
1545 whereToLoad,
1546 romSize)) {
1547 free(rom);
1548 rom = NULL;
1549 free(workRAM);
1550 workRAM = NULL;
1551 return 0;
1554 u16 *temp = (u16 *)(rom+((romSize+1)&~1));
1555 int i;
1556 for(i = (romSize+1)&~1; i < 0x2000000; i+=2) {
1557 WRITE16LE(temp, (i >> 1) & 0xFFFF);
1558 temp++;
1561 bios = (u8 *)calloc(1,0x4000);
1562 if(bios == NULL) {
1563 systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
1564 "BIOS");
1565 CPUCleanUp();
1566 return 0;
1568 internalRAM = (u8 *)calloc(1,0x8000);
1569 if(internalRAM == NULL) {
1570 systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
1571 "IRAM");
1572 CPUCleanUp();
1573 return 0;
1575 paletteRAM = (u8 *)calloc(1,0x400);
1576 if(paletteRAM == NULL) {
1577 systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
1578 "PRAM");
1579 CPUCleanUp();
1580 return 0;
1582 vram = (u8 *)calloc(1, 0x20000);
1583 if(vram == NULL) {
1584 systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
1585 "VRAM");
1586 CPUCleanUp();
1587 return 0;
1589 oam = (u8 *)calloc(1, 0x400);
1590 if(oam == NULL) {
1591 systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
1592 "OAM");
1593 CPUCleanUp();
1594 return 0;
1596 pix = (u8 *)calloc(1, 4 * 241 * 162);
1597 if(pix == NULL) {
1598 systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
1599 "PIX");
1600 CPUCleanUp();
1601 return 0;
1603 ioMem = (u8 *)calloc(1, 0x400);
1604 if(ioMem == NULL) {
1605 systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
1606 "IO");
1607 CPUCleanUp();
1608 return 0;
1611 flashInit();
1612 eepromInit();
1614 CPUUpdateRenderBuffers(true);
1616 return romSize;
1619 void doMirroring (bool b)
1621 u32 mirroredRomSize = (((romSize)>>20) & 0x3F)<<20;
1622 u32 mirroredRomAddress = romSize;
1623 if ((mirroredRomSize <=0x800000) && (b))
1625 mirroredRomAddress = mirroredRomSize;
1626 if (mirroredRomSize==0)
1627 mirroredRomSize=0x100000;
1628 while (mirroredRomAddress<0x01000000)
1630 memcpy ((u16 *)(rom+mirroredRomAddress), (u16 *)(rom), mirroredRomSize);
1631 mirroredRomAddress+=mirroredRomSize;
1636 void CPUUpdateRender()
1638 switch(DISPCNT & 7) {
1639 case 0:
1640 if((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
1641 cpuDisableSfx)
1642 renderLine = mode0RenderLine;
1643 else if(fxOn && !windowOn && !(layerEnable & 0x8000))
1644 renderLine = mode0RenderLineNoWindow;
1645 else
1646 renderLine = mode0RenderLineAll;
1647 break;
1648 case 1:
1649 if((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
1650 cpuDisableSfx)
1651 renderLine = mode1RenderLine;
1652 else if(fxOn && !windowOn && !(layerEnable & 0x8000))
1653 renderLine = mode1RenderLineNoWindow;
1654 else
1655 renderLine = mode1RenderLineAll;
1656 break;
1657 case 2:
1658 if((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
1659 cpuDisableSfx)
1660 renderLine = mode2RenderLine;
1661 else if(fxOn && !windowOn && !(layerEnable & 0x8000))
1662 renderLine = mode2RenderLineNoWindow;
1663 else
1664 renderLine = mode2RenderLineAll;
1665 break;
1666 case 3:
1667 if((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
1668 cpuDisableSfx)
1669 renderLine = mode3RenderLine;
1670 else if(fxOn && !windowOn && !(layerEnable & 0x8000))
1671 renderLine = mode3RenderLineNoWindow;
1672 else
1673 renderLine = mode3RenderLineAll;
1674 break;
1675 case 4:
1676 if((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
1677 cpuDisableSfx)
1678 renderLine = mode4RenderLine;
1679 else if(fxOn && !windowOn && !(layerEnable & 0x8000))
1680 renderLine = mode4RenderLineNoWindow;
1681 else
1682 renderLine = mode4RenderLineAll;
1683 break;
1684 case 5:
1685 if((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
1686 cpuDisableSfx)
1687 renderLine = mode5RenderLine;
1688 else if(fxOn && !windowOn && !(layerEnable & 0x8000))
1689 renderLine = mode5RenderLineNoWindow;
1690 else
1691 renderLine = mode5RenderLineAll;
1692 default:
1693 break;
1697 void CPUUpdateCPSR()
1699 u32 CPSR = reg[16].I & 0x40;
1700 if(N_FLAG)
1701 CPSR |= 0x80000000;
1702 if(Z_FLAG)
1703 CPSR |= 0x40000000;
1704 if(C_FLAG)
1705 CPSR |= 0x20000000;
1706 if(V_FLAG)
1707 CPSR |= 0x10000000;
1708 if(!armState)
1709 CPSR |= 0x00000020;
1710 if(!armIrqEnable)
1711 CPSR |= 0x80;
1712 CPSR |= (armMode & 0x1F);
1713 reg[16].I = CPSR;
1716 void CPUUpdateFlags(bool breakLoop)
1718 u32 CPSR = reg[16].I;
1720 N_FLAG = (CPSR & 0x80000000) ? true: false;
1721 Z_FLAG = (CPSR & 0x40000000) ? true: false;
1722 C_FLAG = (CPSR & 0x20000000) ? true: false;
1723 V_FLAG = (CPSR & 0x10000000) ? true: false;
1724 armState = (CPSR & 0x20) ? false : true;
1725 armIrqEnable = (CPSR & 0x80) ? false : true;
1726 if(breakLoop) {
1727 if (armIrqEnable && (IF & IE) && (IME & 1))
1728 cpuNextEvent = cpuTotalTicks;
1732 void CPUUpdateFlags()
1734 CPUUpdateFlags(true);
1737 #ifdef WORDS_BIGENDIAN
1738 static void CPUSwap(volatile u32 *a, volatile u32 *b)
1740 volatile u32 c = *b;
1741 *b = *a;
1742 *a = c;
1744 #else
1745 static void CPUSwap(u32 *a, u32 *b)
1747 u32 c = *b;
1748 *b = *a;
1749 *a = c;
1751 #endif
1753 void CPUSwitchMode(int mode, bool saveState, bool breakLoop)
1755 // if(armMode == mode)
1756 // return;
1758 CPUUpdateCPSR();
1760 switch(armMode) {
1761 case 0x10:
1762 case 0x1F:
1763 reg[R13_USR].I = reg[13].I;
1764 reg[R14_USR].I = reg[14].I;
1765 reg[17].I = reg[16].I;
1766 break;
1767 case 0x11:
1768 CPUSwap(&reg[R8_FIQ].I, &reg[8].I);
1769 CPUSwap(&reg[R9_FIQ].I, &reg[9].I);
1770 CPUSwap(&reg[R10_FIQ].I, &reg[10].I);
1771 CPUSwap(&reg[R11_FIQ].I, &reg[11].I);
1772 CPUSwap(&reg[R12_FIQ].I, &reg[12].I);
1773 reg[R13_FIQ].I = reg[13].I;
1774 reg[R14_FIQ].I = reg[14].I;
1775 reg[SPSR_FIQ].I = reg[17].I;
1776 break;
1777 case 0x12:
1778 reg[R13_IRQ].I = reg[13].I;
1779 reg[R14_IRQ].I = reg[14].I;
1780 reg[SPSR_IRQ].I = reg[17].I;
1781 break;
1782 case 0x13:
1783 reg[R13_SVC].I = reg[13].I;
1784 reg[R14_SVC].I = reg[14].I;
1785 reg[SPSR_SVC].I = reg[17].I;
1786 break;
1787 case 0x17:
1788 reg[R13_ABT].I = reg[13].I;
1789 reg[R14_ABT].I = reg[14].I;
1790 reg[SPSR_ABT].I = reg[17].I;
1791 break;
1792 case 0x1b:
1793 reg[R13_UND].I = reg[13].I;
1794 reg[R14_UND].I = reg[14].I;
1795 reg[SPSR_UND].I = reg[17].I;
1796 break;
1799 u32 CPSR = reg[16].I;
1800 u32 SPSR = reg[17].I;
1802 switch(mode) {
1803 case 0x10:
1804 case 0x1F:
1805 reg[13].I = reg[R13_USR].I;
1806 reg[14].I = reg[R14_USR].I;
1807 reg[16].I = SPSR;
1808 break;
1809 case 0x11:
1810 CPUSwap(&reg[8].I, &reg[R8_FIQ].I);
1811 CPUSwap(&reg[9].I, &reg[R9_FIQ].I);
1812 CPUSwap(&reg[10].I, &reg[R10_FIQ].I);
1813 CPUSwap(&reg[11].I, &reg[R11_FIQ].I);
1814 CPUSwap(&reg[12].I, &reg[R12_FIQ].I);
1815 reg[13].I = reg[R13_FIQ].I;
1816 reg[14].I = reg[R14_FIQ].I;
1817 if(saveState)
1818 reg[17].I = CPSR;
1819 else
1820 reg[17].I = reg[SPSR_FIQ].I;
1821 break;
1822 case 0x12:
1823 reg[13].I = reg[R13_IRQ].I;
1824 reg[14].I = reg[R14_IRQ].I;
1825 reg[16].I = SPSR;
1826 if(saveState)
1827 reg[17].I = CPSR;
1828 else
1829 reg[17].I = reg[SPSR_IRQ].I;
1830 break;
1831 case 0x13:
1832 reg[13].I = reg[R13_SVC].I;
1833 reg[14].I = reg[R14_SVC].I;
1834 reg[16].I = SPSR;
1835 if(saveState)
1836 reg[17].I = CPSR;
1837 else
1838 reg[17].I = reg[SPSR_SVC].I;
1839 break;
1840 case 0x17:
1841 reg[13].I = reg[R13_ABT].I;
1842 reg[14].I = reg[R14_ABT].I;
1843 reg[16].I = SPSR;
1844 if(saveState)
1845 reg[17].I = CPSR;
1846 else
1847 reg[17].I = reg[SPSR_ABT].I;
1848 break;
1849 case 0x1b:
1850 reg[13].I = reg[R13_UND].I;
1851 reg[14].I = reg[R14_UND].I;
1852 reg[16].I = SPSR;
1853 if(saveState)
1854 reg[17].I = CPSR;
1855 else
1856 reg[17].I = reg[SPSR_UND].I;
1857 break;
1858 default:
1859 systemMessage(MSG_UNSUPPORTED_ARM_MODE, N_("Unsupported ARM mode %02x"), mode);
1860 break;
1862 armMode = mode;
1863 CPUUpdateFlags(breakLoop);
1864 CPUUpdateCPSR();
1867 void CPUSwitchMode(int mode, bool saveState)
1869 CPUSwitchMode(mode, saveState, true);
1872 void CPUUndefinedException()
1874 u32 PC = reg[15].I;
1875 bool savedArmState = armState;
1876 CPUSwitchMode(0x1b, true, false);
1877 reg[14].I = PC - (savedArmState ? 4 : 2);
1878 reg[15].I = 0x04;
1879 armState = true;
1880 armIrqEnable = false;
1881 armNextPC = 0x04;
1882 ARM_PREFETCH;
1883 reg[15].I += 4;
1886 void CPUSoftwareInterrupt()
1888 u32 PC = reg[15].I;
1889 bool savedArmState = armState;
1890 CPUSwitchMode(0x13, true, false);
1891 reg[14].I = PC - (savedArmState ? 4 : 2);
1892 reg[15].I = 0x08;
1893 armState = true;
1894 armIrqEnable = false;
1895 armNextPC = 0x08;
1896 ARM_PREFETCH;
1897 reg[15].I += 4;
1900 void CPUSoftwareInterrupt(int comment)
1902 static bool disableMessage = false;
1903 if(armState) comment >>= 16;
1904 #ifdef BKPT_SUPPORT
1905 if(comment == 0xff) {
1906 extern void (*dbgOutput)(char *, u32);
1907 dbgOutput(NULL, reg[0].I);
1908 return;
1910 #endif
1911 #ifdef PROFILING
1912 if(comment == 0xfe) {
1913 profStartup(reg[0].I, reg[1].I);
1914 return;
1916 if(comment == 0xfd) {
1917 profControl(reg[0].I);
1918 return;
1920 if(comment == 0xfc) {
1921 profCleanup();
1922 return;
1924 if(comment == 0xfb) {
1925 profCount();
1926 return;
1928 #endif
1929 if(comment == 0xfa) {
1930 agbPrintFlush();
1931 return;
1933 #ifdef SDL
1934 if(comment == 0xf9) {
1935 emulating = 0;
1936 cpuNextEvent = cpuTotalTicks;
1937 cpuBreakLoop = true;
1938 return;
1940 #endif
1941 if(useBios) {
1942 #ifdef DEV_VERSION
1943 if(systemVerbose & VERBOSE_SWI) {
1944 log("SWI: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment,
1945 armState ? armNextPC - 4: armNextPC -2,
1946 reg[0].I,
1947 reg[1].I,
1948 reg[2].I,
1949 VCOUNT);
1951 #endif
1952 CPUSoftwareInterrupt();
1953 return;
1955 // This would be correct, but it causes problems if uncommented
1956 // else {
1957 // biosProtected = 0xe3a02004;
1958 // }
1960 switch(comment) {
1961 case 0x00:
1962 BIOS_SoftReset();
1963 ARM_PREFETCH;
1964 break;
1965 case 0x01:
1966 BIOS_RegisterRamReset();
1967 break;
1968 case 0x02:
1969 #ifdef DEV_VERSION
1970 if(systemVerbose & VERBOSE_SWI) {
1971 log("Halt: (VCOUNT = %2d)\n",
1972 VCOUNT);
1974 #endif
1975 holdState = true;
1976 holdType = -1;
1977 cpuNextEvent = cpuTotalTicks;
1978 break;
1979 case 0x03:
1980 #ifdef DEV_VERSION
1981 if(systemVerbose & VERBOSE_SWI) {
1982 log("Stop: (VCOUNT = %2d)\n",
1983 VCOUNT);
1985 #endif
1986 holdState = true;
1987 holdType = -1;
1988 stopState = true;
1989 cpuNextEvent = cpuTotalTicks;
1990 break;
1991 case 0x04:
1992 #ifdef DEV_VERSION
1993 if(systemVerbose & VERBOSE_SWI) {
1994 log("IntrWait: 0x%08x,0x%08x (VCOUNT = %2d)\n",
1995 reg[0].I,
1996 reg[1].I,
1997 VCOUNT);
1999 #endif
2000 CPUSoftwareInterrupt();
2001 break;
2002 case 0x05:
2003 #ifdef DEV_VERSION
2004 if(systemVerbose & VERBOSE_SWI) {
2005 log("VBlankIntrWait: (VCOUNT = %2d)\n",
2006 VCOUNT);
2008 #endif
2009 CPUSoftwareInterrupt();
2010 break;
2011 case 0x06:
2012 CPUSoftwareInterrupt();
2013 break;
2014 case 0x07:
2015 CPUSoftwareInterrupt();
2016 break;
2017 case 0x08:
2018 BIOS_Sqrt();
2019 break;
2020 case 0x09:
2021 BIOS_ArcTan();
2022 break;
2023 case 0x0A:
2024 BIOS_ArcTan2();
2025 break;
2026 case 0x0B:
2028 int len = (reg[2].I & 0x1FFFFF) >>1;
2029 if (!(((reg[0].I & 0xe000000) == 0) ||
2030 ((reg[0].I + len) & 0xe000000) == 0))
2032 if ((reg[2].I >> 24) & 1)
2034 if ((reg[2].I >> 26) & 1)
2035 SWITicks = (7 + memoryWait32[(reg[1].I>>24) & 0xF]) * (len>>1);
2036 else
2037 SWITicks = (8 + memoryWait[(reg[1].I>>24) & 0xF]) * (len);
2039 else
2041 if ((reg[2].I >> 26) & 1)
2042 SWITicks = (10 + memoryWait32[(reg[0].I>>24) & 0xF] +
2043 memoryWait32[(reg[1].I>>24) & 0xF]) * (len>>1);
2044 else
2045 SWITicks = (11 + memoryWait[(reg[0].I>>24) & 0xF] +
2046 memoryWait[(reg[1].I>>24) & 0xF]) * len;
2050 BIOS_CpuSet();
2051 break;
2052 case 0x0C:
2054 int len = (reg[2].I & 0x1FFFFF) >>5;
2055 if (!(((reg[0].I & 0xe000000) == 0) ||
2056 ((reg[0].I + len) & 0xe000000) == 0))
2058 if ((reg[2].I >> 24) & 1)
2059 SWITicks = (6 + memoryWait32[(reg[1].I>>24) & 0xF] +
2060 7 * (memoryWaitSeq32[(reg[1].I>>24) & 0xF] + 1)) * len;
2061 else
2062 SWITicks = (9 + memoryWait32[(reg[0].I>>24) & 0xF] +
2063 memoryWait32[(reg[1].I>>24) & 0xF] +
2064 7 * (memoryWaitSeq32[(reg[0].I>>24) & 0xF] +
2065 memoryWaitSeq32[(reg[1].I>>24) & 0xF] + 2)) * len;
2068 BIOS_CpuFastSet();
2069 break;
2070 case 0x0D:
2071 BIOS_GetBiosChecksum();
2072 break;
2073 case 0x0E:
2074 BIOS_BgAffineSet();
2075 break;
2076 case 0x0F:
2077 BIOS_ObjAffineSet();
2078 break;
2079 case 0x10:
2081 int len = CPUReadHalfWord(reg[2].I);
2082 if (!(((reg[0].I & 0xe000000) == 0) ||
2083 ((reg[0].I + len) & 0xe000000) == 0))
2084 SWITicks = (32 + memoryWait[(reg[0].I>>24) & 0xF]) * len;
2086 BIOS_BitUnPack();
2087 break;
2088 case 0x11:
2090 u32 len = CPUReadMemory(reg[0].I) >> 8;
2091 if(!(((reg[0].I & 0xe000000) == 0) ||
2092 ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0))
2093 SWITicks = (9 + memoryWait[(reg[1].I>>24) & 0xF]) * len;
2095 BIOS_LZ77UnCompWram();
2096 break;
2097 case 0x12:
2099 u32 len = CPUReadMemory(reg[0].I) >> 8;
2100 if(!(((reg[0].I & 0xe000000) == 0) ||
2101 ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0))
2102 SWITicks = (19 + memoryWait[(reg[1].I>>24) & 0xF]) * len;
2104 BIOS_LZ77UnCompVram();
2105 break;
2106 case 0x13:
2108 u32 len = CPUReadMemory(reg[0].I) >> 8;
2109 if(!(((reg[0].I & 0xe000000) == 0) ||
2110 ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0))
2111 SWITicks = (29 + (memoryWait[(reg[0].I>>24) & 0xF]<<1)) * len;
2113 BIOS_HuffUnComp();
2114 break;
2115 case 0x14:
2117 u32 len = CPUReadMemory(reg[0].I) >> 8;
2118 if(!(((reg[0].I & 0xe000000) == 0) ||
2119 ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0))
2120 SWITicks = (11 + memoryWait[(reg[0].I>>24) & 0xF] +
2121 memoryWait[(reg[1].I>>24) & 0xF]) * len;
2123 BIOS_RLUnCompWram();
2124 break;
2125 case 0x15:
2127 u32 len = CPUReadMemory(reg[0].I) >> 9;
2128 if(!(((reg[0].I & 0xe000000) == 0) ||
2129 ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0))
2130 SWITicks = (34 + (memoryWait[(reg[0].I>>24) & 0xF] << 1) +
2131 memoryWait[(reg[1].I>>24) & 0xF]) * len;
2133 BIOS_RLUnCompVram();
2134 break;
2135 case 0x16:
2137 u32 len = CPUReadMemory(reg[0].I) >> 8;
2138 if(!(((reg[0].I & 0xe000000) == 0) ||
2139 ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0))
2140 SWITicks = (13 + memoryWait[(reg[0].I>>24) & 0xF] +
2141 memoryWait[(reg[1].I>>24) & 0xF]) * len;
2143 BIOS_Diff8bitUnFilterWram();
2144 break;
2145 case 0x17:
2147 u32 len = CPUReadMemory(reg[0].I) >> 9;
2148 if(!(((reg[0].I & 0xe000000) == 0) ||
2149 ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0))
2150 SWITicks = (39 + (memoryWait[(reg[0].I>>24) & 0xF]<<1) +
2151 memoryWait[(reg[1].I>>24) & 0xF]) * len;
2153 BIOS_Diff8bitUnFilterVram();
2154 break;
2155 case 0x18:
2157 u32 len = CPUReadMemory(reg[0].I) >> 9;
2158 if(!(((reg[0].I & 0xe000000) == 0) ||
2159 ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0))
2160 SWITicks = (13 + memoryWait[(reg[0].I>>24) & 0xF] +
2161 memoryWait[(reg[1].I>>24) & 0xF]) * len;
2163 BIOS_Diff16bitUnFilter();
2164 break;
2165 case 0x19:
2166 #ifdef DEV_VERSION
2167 if(systemVerbose & VERBOSE_SWI) {
2168 log("SoundBiasSet: 0x%08x (VCOUNT = %2d)\n",
2169 reg[0].I,
2170 VCOUNT);
2172 #endif
2173 if(reg[0].I)
2174 systemSoundPause();
2175 else
2176 systemSoundResume();
2177 break;
2178 case 0x1F:
2179 BIOS_MidiKey2Freq();
2180 break;
2181 case 0x2A:
2182 BIOS_SndDriverJmpTableCopy();
2183 // let it go, because we don't really emulate this function
2184 default:
2185 #ifdef DEV_VERSION
2186 if(systemVerbose & VERBOSE_SWI) {
2187 log("SWI: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment,
2188 armState ? armNextPC - 4: armNextPC -2,
2189 reg[0].I,
2190 reg[1].I,
2191 reg[2].I,
2192 VCOUNT);
2194 #endif
2196 if(!disableMessage) {
2197 systemMessage(MSG_UNSUPPORTED_BIOS_FUNCTION,
2198 N_("Unsupported BIOS function %02x called from %08x. A BIOS file is needed in order to get correct behaviour."),
2199 comment,
2200 armMode ? armNextPC - 4: armNextPC - 2);
2201 disableMessage = true;
2203 break;
2207 void CPUCompareVCOUNT()
2209 if(VCOUNT == (DISPSTAT >> 8)) {
2210 DISPSTAT |= 4;
2211 UPDATE_REG(0x04, DISPSTAT);
2213 if(DISPSTAT & 0x20) {
2214 IF |= 4;
2215 UPDATE_REG(0x202, IF);
2217 } else {
2218 DISPSTAT &= 0xFFFB;
2219 UPDATE_REG(0x4, DISPSTAT);
2221 if (layerEnableDelay>0)
2223 layerEnableDelay--;
2224 if (layerEnableDelay==1)
2225 layerEnable = layerSettings & DISPCNT;
2230 void doDMA(u32 &s, u32 &d, u32 si, u32 di, u32 c, int transfer32)
2232 int sm = s >> 24;
2233 int dm = d >> 24;
2234 int sw = 0;
2235 int dw = 0;
2236 int sc = c;
2238 cpuDmaCount = c;
2239 // This is done to get the correct waitstates.
2240 if (sm>15)
2241 sm=15;
2242 if (dm>15)
2243 dm=15;
2245 //if ((sm>=0x05) && (sm<=0x07) || (dm>=0x05) && (dm <=0x07))
2246 // blank = (((DISPSTAT | ((DISPSTAT>>1)&1))==1) ? true : false);
2248 if(transfer32) {
2249 s &= 0xFFFFFFFC;
2250 if(s < 0x02000000 && (reg[15].I >> 24)) {
2251 while(c != 0) {
2252 CPUWriteMemory(d, 0);
2253 d += di;
2254 c--;
2256 } else {
2257 while(c != 0) {
2258 cpuDmaLast = CPUReadMemory(s);
2259 CPUWriteMemory(d, cpuDmaLast);
2260 d += di;
2261 s += si;
2262 c--;
2265 } else {
2266 s &= 0xFFFFFFFE;
2267 si = (int)si >> 1;
2268 di = (int)di >> 1;
2269 if(s < 0x02000000 && (reg[15].I >> 24)) {
2270 while(c != 0) {
2271 CPUWriteHalfWord(d, 0);
2272 d += di;
2273 c--;
2275 } else {
2276 while(c != 0) {
2277 cpuDmaLast = CPUReadHalfWord(s);
2278 CPUWriteHalfWord(d, cpuDmaLast);
2279 cpuDmaLast |= (cpuDmaLast<<16);
2280 d += di;
2281 s += si;
2282 c--;
2287 cpuDmaCount = 0;
2289 int totalTicks = 0;
2291 if(transfer32) {
2292 sw =1+memoryWaitSeq32[sm & 15];
2293 dw =1+memoryWaitSeq32[dm & 15];
2294 totalTicks = (sw+dw)*(sc-1) + 6 + memoryWait32[sm & 15] +
2295 memoryWaitSeq32[dm & 15];
2297 else
2299 sw = 1+memoryWaitSeq[sm & 15];
2300 dw = 1+memoryWaitSeq[dm & 15];
2301 totalTicks = (sw+dw)*(sc-1) + 6 + memoryWait[sm & 15] +
2302 memoryWaitSeq[dm & 15];
2305 cpuDmaTicksToUpdate += totalTicks;
2309 void CPUCheckDMA(int reason, int dmamask)
2311 // DMA 0
2312 if((DM0CNT_H & 0x8000) && (dmamask & 1)) {
2313 if(((DM0CNT_H >> 12) & 3) == reason) {
2314 u32 sourceIncrement = 4;
2315 u32 destIncrement = 4;
2316 switch((DM0CNT_H >> 7) & 3) {
2317 case 0:
2318 break;
2319 case 1:
2320 sourceIncrement = (u32)-4;
2321 break;
2322 case 2:
2323 sourceIncrement = 0;
2324 break;
2326 switch((DM0CNT_H >> 5) & 3) {
2327 case 0:
2328 break;
2329 case 1:
2330 destIncrement = (u32)-4;
2331 break;
2332 case 2:
2333 destIncrement = 0;
2334 break;
2336 #ifdef DEV_VERSION
2337 if(systemVerbose & VERBOSE_DMA0) {
2338 int count = (DM0CNT_L ? DM0CNT_L : 0x4000) << 1;
2339 if(DM0CNT_H & 0x0400)
2340 count <<= 1;
2341 log("DMA0: s=%08x d=%08x c=%04x count=%08x\n", dma0Source, dma0Dest,
2342 DM0CNT_H,
2343 count);
2345 #endif
2346 doDMA(dma0Source, dma0Dest, sourceIncrement, destIncrement,
2347 DM0CNT_L ? DM0CNT_L : 0x4000,
2348 DM0CNT_H & 0x0400);
2349 cpuDmaHack = true;
2351 if(DM0CNT_H & 0x4000) {
2352 IF |= 0x0100;
2353 UPDATE_REG(0x202, IF);
2354 cpuNextEvent = cpuTotalTicks;
2357 if(((DM0CNT_H >> 5) & 3) == 3) {
2358 dma0Dest = DM0DAD_L | (DM0DAD_H << 16);
2361 if(!(DM0CNT_H & 0x0200) || (reason == 0)) {
2362 DM0CNT_H &= 0x7FFF;
2363 UPDATE_REG(0xBA, DM0CNT_H);
2368 // DMA 1
2369 if((DM1CNT_H & 0x8000) && (dmamask & 2)) {
2370 if(((DM1CNT_H >> 12) & 3) == reason) {
2371 u32 sourceIncrement = 4;
2372 u32 destIncrement = 4;
2373 switch((DM1CNT_H >> 7) & 3) {
2374 case 0:
2375 break;
2376 case 1:
2377 sourceIncrement = (u32)-4;
2378 break;
2379 case 2:
2380 sourceIncrement = 0;
2381 break;
2383 switch((DM1CNT_H >> 5) & 3) {
2384 case 0:
2385 break;
2386 case 1:
2387 destIncrement = (u32)-4;
2388 break;
2389 case 2:
2390 destIncrement = 0;
2391 break;
2393 if(reason == 3) {
2394 #ifdef DEV_VERSION
2395 if(systemVerbose & VERBOSE_DMA1) {
2396 log("DMA1: s=%08x d=%08x c=%04x count=%08x\n", dma1Source, dma1Dest,
2397 DM1CNT_H,
2398 16);
2400 #endif
2401 doDMA(dma1Source, dma1Dest, sourceIncrement, 0, 4,
2402 0x0400);
2403 } else {
2404 #ifdef DEV_VERSION
2405 if(systemVerbose & VERBOSE_DMA1) {
2406 int count = (DM1CNT_L ? DM1CNT_L : 0x4000) << 1;
2407 if(DM1CNT_H & 0x0400)
2408 count <<= 1;
2409 log("DMA1: s=%08x d=%08x c=%04x count=%08x\n", dma1Source, dma1Dest,
2410 DM1CNT_H,
2411 count);
2413 #endif
2414 doDMA(dma1Source, dma1Dest, sourceIncrement, destIncrement,
2415 DM1CNT_L ? DM1CNT_L : 0x4000,
2416 DM1CNT_H & 0x0400);
2418 cpuDmaHack = true;
2420 if(DM1CNT_H & 0x4000) {
2421 IF |= 0x0200;
2422 UPDATE_REG(0x202, IF);
2423 cpuNextEvent = cpuTotalTicks;
2426 if(((DM1CNT_H >> 5) & 3) == 3) {
2427 dma1Dest = DM1DAD_L | (DM1DAD_H << 16);
2430 if(!(DM1CNT_H & 0x0200) || (reason == 0)) {
2431 DM1CNT_H &= 0x7FFF;
2432 UPDATE_REG(0xC6, DM1CNT_H);
2437 // DMA 2
2438 if((DM2CNT_H & 0x8000) && (dmamask & 4)) {
2439 if(((DM2CNT_H >> 12) & 3) == reason) {
2440 u32 sourceIncrement = 4;
2441 u32 destIncrement = 4;
2442 switch((DM2CNT_H >> 7) & 3) {
2443 case 0:
2444 break;
2445 case 1:
2446 sourceIncrement = (u32)-4;
2447 break;
2448 case 2:
2449 sourceIncrement = 0;
2450 break;
2452 switch((DM2CNT_H >> 5) & 3) {
2453 case 0:
2454 break;
2455 case 1:
2456 destIncrement = (u32)-4;
2457 break;
2458 case 2:
2459 destIncrement = 0;
2460 break;
2462 if(reason == 3) {
2463 #ifdef DEV_VERSION
2464 if(systemVerbose & VERBOSE_DMA2) {
2465 int count = (4) << 2;
2466 log("DMA2: s=%08x d=%08x c=%04x count=%08x\n", dma2Source, dma2Dest,
2467 DM2CNT_H,
2468 count);
2470 #endif
2471 doDMA(dma2Source, dma2Dest, sourceIncrement, 0, 4,
2472 0x0400);
2473 } else {
2474 #ifdef DEV_VERSION
2475 if(systemVerbose & VERBOSE_DMA2) {
2476 int count = (DM2CNT_L ? DM2CNT_L : 0x4000) << 1;
2477 if(DM2CNT_H & 0x0400)
2478 count <<= 1;
2479 log("DMA2: s=%08x d=%08x c=%04x count=%08x\n", dma2Source, dma2Dest,
2480 DM2CNT_H,
2481 count);
2483 #endif
2484 doDMA(dma2Source, dma2Dest, sourceIncrement, destIncrement,
2485 DM2CNT_L ? DM2CNT_L : 0x4000,
2486 DM2CNT_H & 0x0400);
2488 cpuDmaHack = true;
2490 if(DM2CNT_H & 0x4000) {
2491 IF |= 0x0400;
2492 UPDATE_REG(0x202, IF);
2493 cpuNextEvent = cpuTotalTicks;
2496 if(((DM2CNT_H >> 5) & 3) == 3) {
2497 dma2Dest = DM2DAD_L | (DM2DAD_H << 16);
2500 if(!(DM2CNT_H & 0x0200) || (reason == 0)) {
2501 DM2CNT_H &= 0x7FFF;
2502 UPDATE_REG(0xD2, DM2CNT_H);
2507 // DMA 3
2508 if((DM3CNT_H & 0x8000) && (dmamask & 8)) {
2509 if(((DM3CNT_H >> 12) & 3) == reason) {
2510 u32 sourceIncrement = 4;
2511 u32 destIncrement = 4;
2512 switch((DM3CNT_H >> 7) & 3) {
2513 case 0:
2514 break;
2515 case 1:
2516 sourceIncrement = (u32)-4;
2517 break;
2518 case 2:
2519 sourceIncrement = 0;
2520 break;
2522 switch((DM3CNT_H >> 5) & 3) {
2523 case 0:
2524 break;
2525 case 1:
2526 destIncrement = (u32)-4;
2527 break;
2528 case 2:
2529 destIncrement = 0;
2530 break;
2532 #ifdef DEV_VERSION
2533 if(systemVerbose & VERBOSE_DMA3) {
2534 int count = (DM3CNT_L ? DM3CNT_L : 0x10000) << 1;
2535 if(DM3CNT_H & 0x0400)
2536 count <<= 1;
2537 log("DMA3: s=%08x d=%08x c=%04x count=%08x\n", dma3Source, dma3Dest,
2538 DM3CNT_H,
2539 count);
2541 #endif
2542 doDMA(dma3Source, dma3Dest, sourceIncrement, destIncrement,
2543 DM3CNT_L ? DM3CNT_L : 0x10000,
2544 DM3CNT_H & 0x0400);
2545 if(DM3CNT_H & 0x4000) {
2546 IF |= 0x0800;
2547 UPDATE_REG(0x202, IF);
2548 cpuNextEvent = cpuTotalTicks;
2551 if(((DM3CNT_H >> 5) & 3) == 3) {
2552 dma3Dest = DM3DAD_L | (DM3DAD_H << 16);
2555 if(!(DM3CNT_H & 0x0200) || (reason == 0)) {
2556 DM3CNT_H &= 0x7FFF;
2557 UPDATE_REG(0xDE, DM3CNT_H);
2563 void CPUUpdateRegister(u32 address, u16 value)
2565 switch(address) {
2566 case 0x00:
2568 if ((value & 7) >5)
2569 DISPCNT = (value &7);
2570 bool change = ((DISPCNT ^ value) & 0x80) ? true : false;
2571 bool changeBG = ((DISPCNT ^ value) & 0x0F00) ? true : false;
2572 u16 changeBGon = (((~DISPCNT) & value) & 0x0F00);
2573 DISPCNT = (value & 0xFFF7);
2574 UPDATE_REG(0x00, DISPCNT);
2576 if (changeBGon)
2578 layerEnableDelay=4;
2579 layerEnable = layerSettings & value & (~changeBGon);
2581 else
2582 layerEnable = layerSettings & value;
2583 // CPUUpdateTicks();
2585 windowOn = (layerEnable & 0x6000) ? true : false;
2586 if(change && !((value & 0x80))) {
2587 if(!(DISPSTAT & 1)) {
2588 lcdTicks = 1008;
2589 // VCOUNT = 0;
2590 // UPDATE_REG(0x06, VCOUNT);
2591 DISPSTAT &= 0xFFFC;
2592 UPDATE_REG(0x04, DISPSTAT);
2593 CPUCompareVCOUNT();
2595 // (*renderLine)();
2597 CPUUpdateRender();
2598 // we only care about changes in BG0-BG3
2599 if(changeBG)
2600 CPUUpdateRenderBuffers(false);
2602 break;
2603 case 0x04:
2604 DISPSTAT = (value & 0xFF38) | (DISPSTAT & 7);
2605 UPDATE_REG(0x04, DISPSTAT);
2606 break;
2607 case 0x06:
2608 // not writable
2609 break;
2610 case 0x08:
2611 BG0CNT = (value & 0xDFCF);
2612 UPDATE_REG(0x08, BG0CNT);
2613 break;
2614 case 0x0A:
2615 BG1CNT = (value & 0xDFCF);
2616 UPDATE_REG(0x0A, BG1CNT);
2617 break;
2618 case 0x0C:
2619 BG2CNT = (value & 0xFFCF);
2620 UPDATE_REG(0x0C, BG2CNT);
2621 break;
2622 case 0x0E:
2623 BG3CNT = (value & 0xFFCF);
2624 UPDATE_REG(0x0E, BG3CNT);
2625 break;
2626 case 0x10:
2627 BG0HOFS = value & 511;
2628 UPDATE_REG(0x10, BG0HOFS);
2629 break;
2630 case 0x12:
2631 BG0VOFS = value & 511;
2632 UPDATE_REG(0x12, BG0VOFS);
2633 break;
2634 case 0x14:
2635 BG1HOFS = value & 511;
2636 UPDATE_REG(0x14, BG1HOFS);
2637 break;
2638 case 0x16:
2639 BG1VOFS = value & 511;
2640 UPDATE_REG(0x16, BG1VOFS);
2641 break;
2642 case 0x18:
2643 BG2HOFS = value & 511;
2644 UPDATE_REG(0x18, BG2HOFS);
2645 break;
2646 case 0x1A:
2647 BG2VOFS = value & 511;
2648 UPDATE_REG(0x1A, BG2VOFS);
2649 break;
2650 case 0x1C:
2651 BG3HOFS = value & 511;
2652 UPDATE_REG(0x1C, BG3HOFS);
2653 break;
2654 case 0x1E:
2655 BG3VOFS = value & 511;
2656 UPDATE_REG(0x1E, BG3VOFS);
2657 break;
2658 case 0x20:
2659 BG2PA = value;
2660 UPDATE_REG(0x20, BG2PA);
2661 break;
2662 case 0x22:
2663 BG2PB = value;
2664 UPDATE_REG(0x22, BG2PB);
2665 break;
2666 case 0x24:
2667 BG2PC = value;
2668 UPDATE_REG(0x24, BG2PC);
2669 break;
2670 case 0x26:
2671 BG2PD = value;
2672 UPDATE_REG(0x26, BG2PD);
2673 break;
2674 case 0x28:
2675 BG2X_L = value;
2676 UPDATE_REG(0x28, BG2X_L);
2677 gfxBG2Changed |= 1;
2678 break;
2679 case 0x2A:
2680 BG2X_H = (value & 0xFFF);
2681 UPDATE_REG(0x2A, BG2X_H);
2682 gfxBG2Changed |= 1;
2683 break;
2684 case 0x2C:
2685 BG2Y_L = value;
2686 UPDATE_REG(0x2C, BG2Y_L);
2687 gfxBG2Changed |= 2;
2688 break;
2689 case 0x2E:
2690 BG2Y_H = value & 0xFFF;
2691 UPDATE_REG(0x2E, BG2Y_H);
2692 gfxBG2Changed |= 2;
2693 break;
2694 case 0x30:
2695 BG3PA = value;
2696 UPDATE_REG(0x30, BG3PA);
2697 break;
2698 case 0x32:
2699 BG3PB = value;
2700 UPDATE_REG(0x32, BG3PB);
2701 break;
2702 case 0x34:
2703 BG3PC = value;
2704 UPDATE_REG(0x34, BG3PC);
2705 break;
2706 case 0x36:
2707 BG3PD = value;
2708 UPDATE_REG(0x36, BG3PD);
2709 break;
2710 case 0x38:
2711 BG3X_L = value;
2712 UPDATE_REG(0x38, BG3X_L);
2713 gfxBG3Changed |= 1;
2714 break;
2715 case 0x3A:
2716 BG3X_H = value & 0xFFF;
2717 UPDATE_REG(0x3A, BG3X_H);
2718 gfxBG3Changed |= 1;
2719 break;
2720 case 0x3C:
2721 BG3Y_L = value;
2722 UPDATE_REG(0x3C, BG3Y_L);
2723 gfxBG3Changed |= 2;
2724 break;
2725 case 0x3E:
2726 BG3Y_H = value & 0xFFF;
2727 UPDATE_REG(0x3E, BG3Y_H);
2728 gfxBG3Changed |= 2;
2729 break;
2730 case 0x40:
2731 WIN0H = value;
2732 UPDATE_REG(0x40, WIN0H);
2733 CPUUpdateWindow0();
2734 break;
2735 case 0x42:
2736 WIN1H = value;
2737 UPDATE_REG(0x42, WIN1H);
2738 CPUUpdateWindow1();
2739 break;
2740 case 0x44:
2741 WIN0V = value;
2742 UPDATE_REG(0x44, WIN0V);
2743 break;
2744 case 0x46:
2745 WIN1V = value;
2746 UPDATE_REG(0x46, WIN1V);
2747 break;
2748 case 0x48:
2749 WININ = value & 0x3F3F;
2750 UPDATE_REG(0x48, WININ);
2751 break;
2752 case 0x4A:
2753 WINOUT = value & 0x3F3F;
2754 UPDATE_REG(0x4A, WINOUT);
2755 break;
2756 case 0x4C:
2757 MOSAIC = value;
2758 UPDATE_REG(0x4C, MOSAIC);
2759 break;
2760 case 0x50:
2761 BLDMOD = value & 0x3FFF;
2762 UPDATE_REG(0x50, BLDMOD);
2763 fxOn = ((BLDMOD>>6)&3) != 0;
2764 CPUUpdateRender();
2765 break;
2766 case 0x52:
2767 COLEV = value & 0x1F1F;
2768 UPDATE_REG(0x52, COLEV);
2769 break;
2770 case 0x54:
2771 COLY = value & 0x1F;
2772 UPDATE_REG(0x54, COLY);
2773 break;
2774 case 0x60:
2775 case 0x62:
2776 case 0x64:
2777 case 0x68:
2778 case 0x6c:
2779 case 0x70:
2780 case 0x72:
2781 case 0x74:
2782 case 0x78:
2783 case 0x7c:
2784 case 0x80:
2785 case 0x84:
2786 soundEvent(address&0xFF, (u8)(value & 0xFF));
2787 soundEvent((address&0xFF)+1, (u8)(value>>8));
2788 break;
2789 case 0x82:
2790 case 0x88:
2791 case 0xa0:
2792 case 0xa2:
2793 case 0xa4:
2794 case 0xa6:
2795 case 0x90:
2796 case 0x92:
2797 case 0x94:
2798 case 0x96:
2799 case 0x98:
2800 case 0x9a:
2801 case 0x9c:
2802 case 0x9e:
2803 soundEvent(address&0xFF, value);
2804 break;
2805 case 0xB0:
2806 DM0SAD_L = value;
2807 UPDATE_REG(0xB0, DM0SAD_L);
2808 break;
2809 case 0xB2:
2810 DM0SAD_H = value & 0x07FF;
2811 UPDATE_REG(0xB2, DM0SAD_H);
2812 break;
2813 case 0xB4:
2814 DM0DAD_L = value;
2815 UPDATE_REG(0xB4, DM0DAD_L);
2816 break;
2817 case 0xB6:
2818 DM0DAD_H = value & 0x07FF;
2819 UPDATE_REG(0xB6, DM0DAD_H);
2820 break;
2821 case 0xB8:
2822 DM0CNT_L = value & 0x3FFF;
2823 UPDATE_REG(0xB8, 0);
2824 break;
2825 case 0xBA:
2827 bool start = ((DM0CNT_H ^ value) & 0x8000) ? true : false;
2828 value &= 0xF7E0;
2830 DM0CNT_H = value;
2831 UPDATE_REG(0xBA, DM0CNT_H);
2833 if(start && (value & 0x8000)) {
2834 dma0Source = DM0SAD_L | (DM0SAD_H << 16);
2835 dma0Dest = DM0DAD_L | (DM0DAD_H << 16);
2836 CPUCheckDMA(0, 1);
2839 break;
2840 case 0xBC:
2841 DM1SAD_L = value;
2842 UPDATE_REG(0xBC, DM1SAD_L);
2843 break;
2844 case 0xBE:
2845 DM1SAD_H = value & 0x0FFF;
2846 UPDATE_REG(0xBE, DM1SAD_H);
2847 break;
2848 case 0xC0:
2849 DM1DAD_L = value;
2850 UPDATE_REG(0xC0, DM1DAD_L);
2851 break;
2852 case 0xC2:
2853 DM1DAD_H = value & 0x07FF;
2854 UPDATE_REG(0xC2, DM1DAD_H);
2855 break;
2856 case 0xC4:
2857 DM1CNT_L = value & 0x3FFF;
2858 UPDATE_REG(0xC4, 0);
2859 break;
2860 case 0xC6:
2862 bool start = ((DM1CNT_H ^ value) & 0x8000) ? true : false;
2863 value &= 0xF7E0;
2865 DM1CNT_H = value;
2866 UPDATE_REG(0xC6, DM1CNT_H);
2868 if(start && (value & 0x8000)) {
2869 dma1Source = DM1SAD_L | (DM1SAD_H << 16);
2870 dma1Dest = DM1DAD_L | (DM1DAD_H << 16);
2871 CPUCheckDMA(0, 2);
2874 break;
2875 case 0xC8:
2876 DM2SAD_L = value;
2877 UPDATE_REG(0xC8, DM2SAD_L);
2878 break;
2879 case 0xCA:
2880 DM2SAD_H = value & 0x0FFF;
2881 UPDATE_REG(0xCA, DM2SAD_H);
2882 break;
2883 case 0xCC:
2884 DM2DAD_L = value;
2885 UPDATE_REG(0xCC, DM2DAD_L);
2886 break;
2887 case 0xCE:
2888 DM2DAD_H = value & 0x07FF;
2889 UPDATE_REG(0xCE, DM2DAD_H);
2890 break;
2891 case 0xD0:
2892 DM2CNT_L = value & 0x3FFF;
2893 UPDATE_REG(0xD0, 0);
2894 break;
2895 case 0xD2:
2897 bool start = ((DM2CNT_H ^ value) & 0x8000) ? true : false;
2899 value &= 0xF7E0;
2901 DM2CNT_H = value;
2902 UPDATE_REG(0xD2, DM2CNT_H);
2904 if(start && (value & 0x8000)) {
2905 dma2Source = DM2SAD_L | (DM2SAD_H << 16);
2906 dma2Dest = DM2DAD_L | (DM2DAD_H << 16);
2908 CPUCheckDMA(0, 4);
2911 break;
2912 case 0xD4:
2913 DM3SAD_L = value;
2914 UPDATE_REG(0xD4, DM3SAD_L);
2915 break;
2916 case 0xD6:
2917 DM3SAD_H = value & 0x0FFF;
2918 UPDATE_REG(0xD6, DM3SAD_H);
2919 break;
2920 case 0xD8:
2921 DM3DAD_L = value;
2922 UPDATE_REG(0xD8, DM3DAD_L);
2923 break;
2924 case 0xDA:
2925 DM3DAD_H = value & 0x0FFF;
2926 UPDATE_REG(0xDA, DM3DAD_H);
2927 break;
2928 case 0xDC:
2929 DM3CNT_L = value;
2930 UPDATE_REG(0xDC, 0);
2931 break;
2932 case 0xDE:
2934 bool start = ((DM3CNT_H ^ value) & 0x8000) ? true : false;
2936 value &= 0xFFE0;
2938 DM3CNT_H = value;
2939 UPDATE_REG(0xDE, DM3CNT_H);
2941 if(start && (value & 0x8000)) {
2942 dma3Source = DM3SAD_L | (DM3SAD_H << 16);
2943 dma3Dest = DM3DAD_L | (DM3DAD_H << 16);
2944 CPUCheckDMA(0,8);
2947 break;
2948 case 0x100:
2949 timer0Reload = value;
2950 break;
2951 case 0x102:
2952 timer0Value = value;
2953 timerOnOffDelay|=1;
2954 cpuNextEvent = cpuTotalTicks;
2955 break;
2956 case 0x104:
2957 timer1Reload = value;
2958 break;
2959 case 0x106:
2960 timer1Value = value;
2961 timerOnOffDelay|=2;
2962 cpuNextEvent = cpuTotalTicks;
2963 break;
2964 case 0x108:
2965 timer2Reload = value;
2966 break;
2967 case 0x10A:
2968 timer2Value = value;
2969 timerOnOffDelay|=4;
2970 cpuNextEvent = cpuTotalTicks;
2971 break;
2972 case 0x10C:
2973 timer3Reload = value;
2974 break;
2975 case 0x10E:
2976 timer3Value = value;
2977 timerOnOffDelay|=8;
2978 cpuNextEvent = cpuTotalTicks;
2979 break;
2980 case 0x128:
2981 if(value & 0x80) {
2982 value &= 0xff7f;
2983 if(value & 1 && (value & 0x4000)) {
2984 UPDATE_REG(0x12a, 0xFF);
2985 IF |= 0x80;
2986 UPDATE_REG(0x202, IF);
2987 value &= 0x7f7f;
2990 UPDATE_REG(0x128, value);
2991 break;
2992 case 0x130:
2993 P1 |= (value & 0x3FF);
2994 UPDATE_REG(0x130, P1);
2995 break;
2996 case 0x132:
2997 UPDATE_REG(0x132, value & 0xC3FF);
2998 break;
2999 case 0x200:
3000 IE = value & 0x3FFF;
3001 UPDATE_REG(0x200, IE);
3002 if ((IME & 1) && (IF & IE) && armIrqEnable)
3003 cpuNextEvent = cpuTotalTicks;
3004 break;
3005 case 0x202:
3006 IF ^= (value & IF);
3007 UPDATE_REG(0x202, IF);
3008 break;
3009 case 0x204:
3011 memoryWait[0x0e] = memoryWaitSeq[0x0e] = gamepakRamWaitState[value & 3];
3013 if(!speedHack) {
3014 memoryWait[0x08] = memoryWait[0x09] = gamepakWaitState[(value >> 2) & 3];
3015 memoryWaitSeq[0x08] = memoryWaitSeq[0x09] =
3016 gamepakWaitState0[(value >> 4) & 1];
3018 memoryWait[0x0a] = memoryWait[0x0b] = gamepakWaitState[(value >> 5) & 3];
3019 memoryWaitSeq[0x0a] = memoryWaitSeq[0x0b] =
3020 gamepakWaitState1[(value >> 7) & 1];
3022 memoryWait[0x0c] = memoryWait[0x0d] = gamepakWaitState[(value >> 8) & 3];
3023 memoryWaitSeq[0x0c] = memoryWaitSeq[0x0d] =
3024 gamepakWaitState2[(value >> 10) & 1];
3025 } else {
3026 memoryWait[0x08] = memoryWait[0x09] = 3;
3027 memoryWaitSeq[0x08] = memoryWaitSeq[0x09] = 1;
3029 memoryWait[0x0a] = memoryWait[0x0b] = 3;
3030 memoryWaitSeq[0x0a] = memoryWaitSeq[0x0b] = 1;
3032 memoryWait[0x0c] = memoryWait[0x0d] = 3;
3033 memoryWaitSeq[0x0c] = memoryWaitSeq[0x0d] = 1;
3036 for(int i = 8; i < 15; i++) {
3037 memoryWait32[i] = memoryWait[i] + memoryWaitSeq[i] + 1;
3038 memoryWaitSeq32[i] = memoryWaitSeq[i]*2 + 1;
3041 if((value & 0x4000) == 0x4000) {
3042 busPrefetchEnable = true;
3043 busPrefetch = false;
3044 busPrefetchCount = 0;
3045 } else {
3046 busPrefetchEnable = false;
3047 busPrefetch = false;
3048 busPrefetchCount = 0;
3050 UPDATE_REG(0x204, value & 0x7FFF);
3053 break;
3054 case 0x208:
3055 IME = value & 1;
3056 UPDATE_REG(0x208, IME);
3057 if ((IME & 1) && (IF & IE) && armIrqEnable)
3058 cpuNextEvent = cpuTotalTicks;
3059 break;
3060 case 0x300:
3061 if(value != 0)
3062 value &= 0xFFFE;
3063 UPDATE_REG(0x300, value);
3064 break;
3065 default:
3066 UPDATE_REG(address&0x3FE, value);
3067 break;
3071 void applyTimer ()
3073 if (timerOnOffDelay & 1)
3075 timer0ClockReload = TIMER_TICKS[timer0Value & 3];
3076 if(!timer0On && (timer0Value & 0x80)) {
3077 // reload the counter
3078 TM0D = timer0Reload;
3079 timer0Ticks = (0x10000 - TM0D) << timer0ClockReload;
3080 UPDATE_REG(0x100, TM0D);
3082 timer0On = timer0Value & 0x80 ? true : false;
3083 TM0CNT = timer0Value & 0xC7;
3084 UPDATE_REG(0x102, TM0CNT);
3085 // CPUUpdateTicks();
3087 if (timerOnOffDelay & 2)
3089 timer1ClockReload = TIMER_TICKS[timer1Value & 3];
3090 if(!timer1On && (timer1Value & 0x80)) {
3091 // reload the counter
3092 TM1D = timer1Reload;
3093 timer1Ticks = (0x10000 - TM1D) << timer1ClockReload;
3094 UPDATE_REG(0x104, TM1D);
3096 timer1On = timer1Value & 0x80 ? true : false;
3097 TM1CNT = timer1Value & 0xC7;
3098 UPDATE_REG(0x106, TM1CNT);
3100 if (timerOnOffDelay & 4)
3102 timer2ClockReload = TIMER_TICKS[timer2Value & 3];
3103 if(!timer2On && (timer2Value & 0x80)) {
3104 // reload the counter
3105 TM2D = timer2Reload;
3106 timer2Ticks = (0x10000 - TM2D) << timer2ClockReload;
3107 UPDATE_REG(0x108, TM2D);
3109 timer2On = timer2Value & 0x80 ? true : false;
3110 TM2CNT = timer2Value & 0xC7;
3111 UPDATE_REG(0x10A, TM2CNT);
3113 if (timerOnOffDelay & 8)
3115 timer3ClockReload = TIMER_TICKS[timer3Value & 3];
3116 if(!timer3On && (timer3Value & 0x80)) {
3117 // reload the counter
3118 TM3D = timer3Reload;
3119 timer3Ticks = (0x10000 - TM3D) << timer3ClockReload;
3120 UPDATE_REG(0x10C, TM3D);
3122 timer3On = timer3Value & 0x80 ? true : false;
3123 TM3CNT = timer3Value & 0xC7;
3124 UPDATE_REG(0x10E, TM3CNT);
3126 cpuNextEvent = CPUUpdateTicks();
3127 timerOnOffDelay = 0;
3130 void CPUWriteHalfWord(u32 address, u16 value)
3132 #ifdef DEV_VERSION
3133 if(address & 1) {
3134 if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) {
3135 log("Unaligned halfword write: %04x to %08x from %08x\n",
3136 value,
3137 address,
3138 armMode ? armNextPC - 4 : armNextPC - 2);
3141 #endif
3143 switch(address >> 24) {
3144 case 2:
3145 #ifdef BKPT_SUPPORT
3146 if(*((u16 *)&freezeWorkRAM[address & 0x3FFFE]))
3147 cheatsWriteHalfWord(address & 0x203FFFE,
3148 value);
3149 else
3150 #endif
3151 WRITE16LE(((u16 *)&workRAM[address & 0x3FFFE]),value);
3152 break;
3153 case 3:
3154 #ifdef BKPT_SUPPORT
3155 if(*((u16 *)&freezeInternalRAM[address & 0x7ffe]))
3156 cheatsWriteHalfWord(address & 0x3007ffe,
3157 value);
3158 else
3159 #endif
3160 WRITE16LE(((u16 *)&internalRAM[address & 0x7ffe]), value);
3161 break;
3162 case 4:
3163 if(address < 0x4000400)
3164 CPUUpdateRegister(address & 0x3fe, value);
3165 else goto unwritable;
3166 break;
3167 case 5:
3168 #ifdef BKPT_SUPPORT
3169 if(*((u16 *)&freezePRAM[address & 0x03fe]))
3170 cheatsWriteHalfWord(address & 0x70003fe,
3171 value);
3172 else
3173 #endif
3174 WRITE16LE(((u16 *)&paletteRAM[address & 0x3fe]), value);
3175 break;
3176 case 6:
3177 address = (address & 0x1fffe);
3178 if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000))
3179 return;
3180 if ((address & 0x18000) == 0x18000)
3181 address &= 0x17fff;
3182 #ifdef BKPT_SUPPORT
3183 if(*((u16 *)&freezeVRAM[address]))
3184 cheatsWriteHalfWord(address + 0x06000000,
3185 value);
3186 else
3187 #endif
3188 WRITE16LE(((u16 *)&vram[address]), value);
3189 break;
3190 case 7:
3191 #ifdef BKPT_SUPPORT
3192 if(*((u16 *)&freezeOAM[address & 0x03fe]))
3193 cheatsWriteHalfWord(address & 0x70003fe,
3194 value);
3195 else
3196 #endif
3197 WRITE16LE(((u16 *)&oam[address & 0x3fe]), value);
3198 break;
3199 case 8:
3200 case 9:
3201 if(address == 0x80000c4 || address == 0x80000c6 || address == 0x80000c8) {
3202 if(!rtcWrite(address, value))
3203 goto unwritable;
3204 } else if(!agbPrintWrite(address, value)) goto unwritable;
3205 break;
3206 case 13:
3207 if(cpuEEPROMEnabled) {
3208 eepromWrite(address, (u8)value);
3209 break;
3211 goto unwritable;
3212 case 14:
3213 if(!eepromInUse | cpuSramEnabled | cpuFlashEnabled) {
3214 (*cpuSaveGameFunc)(address, (u8)value);
3215 break;
3217 goto unwritable;
3218 default:
3219 unwritable:
3220 #ifdef DEV_VERSION
3221 if(systemVerbose & VERBOSE_ILLEGAL_WRITE) {
3222 log("Illegal halfword write: %04x to %08x from %08x\n",
3223 value,
3224 address,
3225 armMode ? armNextPC - 4 : armNextPC - 2);
3227 #endif
3228 break;
3232 void CPUWriteByte(u32 address, u8 b)
3234 switch(address >> 24) {
3235 case 2:
3236 #ifdef BKPT_SUPPORT
3237 if(freezeWorkRAM[address & 0x3FFFF])
3238 cheatsWriteByte(address & 0x203FFFF, b);
3239 else
3240 #endif
3241 workRAM[address & 0x3FFFF] = b;
3242 break;
3243 case 3:
3244 #ifdef BKPT_SUPPORT
3245 if(freezeInternalRAM[address & 0x7fff])
3246 cheatsWriteByte(address & 0x3007fff, b);
3247 else
3248 #endif
3249 internalRAM[address & 0x7fff] = b;
3250 break;
3251 case 4:
3252 if(address < 0x4000400) {
3253 switch(address & 0x3FF) {
3254 case 0x301:
3255 if(b == 0x80)
3256 stopState = true;
3257 holdState = 1;
3258 holdType = -1;
3259 cpuNextEvent = cpuTotalTicks;
3260 break;
3261 case 0x60:
3262 case 0x61:
3263 case 0x62:
3264 case 0x63:
3265 case 0x64:
3266 case 0x65:
3267 case 0x68:
3268 case 0x69:
3269 case 0x6c:
3270 case 0x6d:
3271 case 0x70:
3272 case 0x71:
3273 case 0x72:
3274 case 0x73:
3275 case 0x74:
3276 case 0x75:
3277 case 0x78:
3278 case 0x79:
3279 case 0x7c:
3280 case 0x7d:
3281 case 0x80:
3282 case 0x81:
3283 case 0x84:
3284 case 0x85:
3285 case 0x90:
3286 case 0x91:
3287 case 0x92:
3288 case 0x93:
3289 case 0x94:
3290 case 0x95:
3291 case 0x96:
3292 case 0x97:
3293 case 0x98:
3294 case 0x99:
3295 case 0x9a:
3296 case 0x9b:
3297 case 0x9c:
3298 case 0x9d:
3299 case 0x9e:
3300 case 0x9f:
3301 soundEvent(address&0xFF, b);
3302 break;
3303 default:
3304 if(address & 1)
3305 CPUUpdateRegister(address & 0x3fe,
3306 ((READ16LE(((u16 *)&ioMem[address & 0x3fe])))
3307 & 0x00FF) |
3308 b<<8);
3309 else
3310 CPUUpdateRegister(address & 0x3fe,
3311 ((READ16LE(((u16 *)&ioMem[address & 0x3fe])) & 0xFF00) | b));
3313 break;
3314 } else goto unwritable;
3315 break;
3316 case 5:
3317 // no need to switch
3318 *((u16 *)&paletteRAM[address & 0x3FE]) = (b << 8) | b;
3319 break;
3320 case 6:
3321 address = (address & 0x1fffe);
3322 if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000))
3323 return;
3324 if ((address & 0x18000) == 0x18000)
3325 address &= 0x17fff;
3327 // no need to switch
3328 // byte writes to OBJ VRAM are ignored
3329 if ((address) < objTilesAddress[((DISPCNT&7)+1)>>2])
3331 #ifdef BKPT_SUPPORT
3332 if(freezeVRAM[address])
3333 cheatsWriteByte(address + 0x06000000, b);
3334 else
3335 #endif
3336 *((u16 *)&vram[address]) = (b << 8) | b;
3338 break;
3339 case 7:
3340 // no need to switch
3341 // byte writes to OAM are ignored
3342 // *((u16 *)&oam[address & 0x3FE]) = (b << 8) | b;
3343 break;
3344 case 13:
3345 if(cpuEEPROMEnabled) {
3346 eepromWrite(address, b);
3347 break;
3349 goto unwritable;
3350 case 14:
3351 if (!(saveType == 5) && (!eepromInUse | cpuSramEnabled | cpuFlashEnabled)) {
3353 //if(!cpuEEPROMEnabled && (cpuSramEnabled | cpuFlashEnabled)) {
3355 (*cpuSaveGameFunc)(address, b);
3356 break;
3358 // default
3359 default:
3360 unwritable:
3361 #ifdef DEV_VERSION
3362 if(systemVerbose & VERBOSE_ILLEGAL_WRITE) {
3363 log("Illegal byte write: %02x to %08x from %08x\n",
3365 address,
3366 armMode ? armNextPC - 4 : armNextPC -2 );
3368 #endif
3369 break;
3373 u8 cpuBitsSet[256];
3374 u8 cpuLowestBitSet[256];
3376 void CPUInit(const char *biosFileName, bool useBiosFile)
3378 #ifdef WORDS_BIGENDIAN
3379 if(!cpuBiosSwapped) {
3380 for(unsigned int i = 0; i < sizeof(myROM)/4; i++) {
3381 WRITE32LE(&myROM[i], myROM[i]);
3383 cpuBiosSwapped = true;
3385 #endif
3386 gbaSaveType = 0;
3387 eepromInUse = 0;
3388 saveType = 0;
3389 useBios = false;
3391 if(useBiosFile) {
3392 int size = 0x4000;
3393 if(utilLoad(biosFileName,
3394 CPUIsGBABios,
3395 bios,
3396 size)) {
3397 if(size == 0x4000)
3398 useBios = true;
3399 else
3400 systemMessage(MSG_INVALID_BIOS_FILE_SIZE, N_("Invalid BIOS file size"));
3404 if(!useBios) {
3405 memcpy(bios, myROM, sizeof(myROM));
3408 int i = 0;
3410 biosProtected[0] = 0x00;
3411 biosProtected[1] = 0xf0;
3412 biosProtected[2] = 0x29;
3413 biosProtected[3] = 0xe1;
3415 for(i = 0; i < 256; i++) {
3416 int count = 0;
3417 int j;
3418 for(j = 0; j < 8; j++)
3419 if(i & (1 << j))
3420 count++;
3421 cpuBitsSet[i] = count;
3423 for(j = 0; j < 8; j++)
3424 if(i & (1 << j))
3425 break;
3426 cpuLowestBitSet[i] = j;
3429 for(i = 0; i < 0x400; i++)
3430 ioReadable[i] = true;
3431 for(i = 0x10; i < 0x48; i++)
3432 ioReadable[i] = false;
3433 for(i = 0x4c; i < 0x50; i++)
3434 ioReadable[i] = false;
3435 for(i = 0x54; i < 0x60; i++)
3436 ioReadable[i] = false;
3437 for(i = 0x8c; i < 0x90; i++)
3438 ioReadable[i] = false;
3439 for(i = 0xa0; i < 0xb8; i++)
3440 ioReadable[i] = false;
3441 for(i = 0xbc; i < 0xc4; i++)
3442 ioReadable[i] = false;
3443 for(i = 0xc8; i < 0xd0; i++)
3444 ioReadable[i] = false;
3445 for(i = 0xd4; i < 0xdc; i++)
3446 ioReadable[i] = false;
3447 for(i = 0xe0; i < 0x100; i++)
3448 ioReadable[i] = false;
3449 for(i = 0x110; i < 0x120; i++)
3450 ioReadable[i] = false;
3451 for(i = 0x12c; i < 0x130; i++)
3452 ioReadable[i] = false;
3453 for(i = 0x138; i < 0x140; i++)
3454 ioReadable[i] = false;
3455 for(i = 0x144; i < 0x150; i++)
3456 ioReadable[i] = false;
3457 for(i = 0x15c; i < 0x200; i++)
3458 ioReadable[i] = false;
3459 for(i = 0x20c; i < 0x300; i++)
3460 ioReadable[i] = false;
3461 for(i = 0x304; i < 0x400; i++)
3462 ioReadable[i] = false;
3464 if(romSize < 0x1fe2000) {
3465 *((u16 *)&rom[0x1fe209c]) = 0xdffa; // SWI 0xFA
3466 *((u16 *)&rom[0x1fe209e]) = 0x4770; // BX LR
3467 } else {
3468 agbPrintEnable(false);
3472 void CPUReset()
3474 if(gbaSaveType == 0) {
3475 if(eepromInUse)
3476 gbaSaveType = 3;
3477 else
3478 switch(saveType) {
3479 case 1:
3480 gbaSaveType = 1;
3481 break;
3482 case 2:
3483 gbaSaveType = 2;
3484 break;
3487 rtcReset();
3488 // clean registers
3489 memset(&reg[0], 0, sizeof(reg));
3490 // clean OAM
3491 memset(oam, 0, 0x400);
3492 // clean palette
3493 memset(paletteRAM, 0, 0x400);
3494 // clean picture
3495 memset(pix, 0, 4*160*240);
3496 // clean vram
3497 memset(vram, 0, 0x20000);
3498 // clean io memory
3499 memset(ioMem, 0, 0x400);
3501 DISPCNT = 0x0080;
3502 DISPSTAT = 0x0000;
3503 VCOUNT = (useBios && !skipBios) ? 0 :0x007E;
3504 BG0CNT = 0x0000;
3505 BG1CNT = 0x0000;
3506 BG2CNT = 0x0000;
3507 BG3CNT = 0x0000;
3508 BG0HOFS = 0x0000;
3509 BG0VOFS = 0x0000;
3510 BG1HOFS = 0x0000;
3511 BG1VOFS = 0x0000;
3512 BG2HOFS = 0x0000;
3513 BG2VOFS = 0x0000;
3514 BG3HOFS = 0x0000;
3515 BG3VOFS = 0x0000;
3516 BG2PA = 0x0100;
3517 BG2PB = 0x0000;
3518 BG2PC = 0x0000;
3519 BG2PD = 0x0100;
3520 BG2X_L = 0x0000;
3521 BG2X_H = 0x0000;
3522 BG2Y_L = 0x0000;
3523 BG2Y_H = 0x0000;
3524 BG3PA = 0x0100;
3525 BG3PB = 0x0000;
3526 BG3PC = 0x0000;
3527 BG3PD = 0x0100;
3528 BG3X_L = 0x0000;
3529 BG3X_H = 0x0000;
3530 BG3Y_L = 0x0000;
3531 BG3Y_H = 0x0000;
3532 WIN0H = 0x0000;
3533 WIN1H = 0x0000;
3534 WIN0V = 0x0000;
3535 WIN1V = 0x0000;
3536 WININ = 0x0000;
3537 WINOUT = 0x0000;
3538 MOSAIC = 0x0000;
3539 BLDMOD = 0x0000;
3540 COLEV = 0x0000;
3541 COLY = 0x0000;
3542 DM0SAD_L = 0x0000;
3543 DM0SAD_H = 0x0000;
3544 DM0DAD_L = 0x0000;
3545 DM0DAD_H = 0x0000;
3546 DM0CNT_L = 0x0000;
3547 DM0CNT_H = 0x0000;
3548 DM1SAD_L = 0x0000;
3549 DM1SAD_H = 0x0000;
3550 DM1DAD_L = 0x0000;
3551 DM1DAD_H = 0x0000;
3552 DM1CNT_L = 0x0000;
3553 DM1CNT_H = 0x0000;
3554 DM2SAD_L = 0x0000;
3555 DM2SAD_H = 0x0000;
3556 DM2DAD_L = 0x0000;
3557 DM2DAD_H = 0x0000;
3558 DM2CNT_L = 0x0000;
3559 DM2CNT_H = 0x0000;
3560 DM3SAD_L = 0x0000;
3561 DM3SAD_H = 0x0000;
3562 DM3DAD_L = 0x0000;
3563 DM3DAD_H = 0x0000;
3564 DM3CNT_L = 0x0000;
3565 DM3CNT_H = 0x0000;
3566 TM0D = 0x0000;
3567 TM0CNT = 0x0000;
3568 TM1D = 0x0000;
3569 TM1CNT = 0x0000;
3570 TM2D = 0x0000;
3571 TM2CNT = 0x0000;
3572 TM3D = 0x0000;
3573 TM3CNT = 0x0000;
3574 P1 = 0x03FF;
3575 IE = 0x0000;
3576 IF = 0x0000;
3577 IME = 0x0000;
3579 armMode = 0x1F;
3581 if(cpuIsMultiBoot) {
3582 reg[13].I = 0x03007F00;
3583 reg[15].I = 0x02000000;
3584 reg[16].I = 0x00000000;
3585 reg[R13_IRQ].I = 0x03007FA0;
3586 reg[R13_SVC].I = 0x03007FE0;
3587 armIrqEnable = true;
3588 } else {
3589 if(useBios && !skipBios) {
3590 reg[15].I = 0x00000000;
3591 armMode = 0x13;
3592 armIrqEnable = false;
3593 } else {
3594 reg[13].I = 0x03007F00;
3595 reg[15].I = 0x08000000;
3596 reg[16].I = 0x00000000;
3597 reg[R13_IRQ].I = 0x03007FA0;
3598 reg[R13_SVC].I = 0x03007FE0;
3599 armIrqEnable = true;
3602 armState = true;
3603 C_FLAG = V_FLAG = N_FLAG = Z_FLAG = false;
3604 UPDATE_REG(0x00, DISPCNT);
3605 UPDATE_REG(0x06, VCOUNT);
3606 UPDATE_REG(0x20, BG2PA);
3607 UPDATE_REG(0x26, BG2PD);
3608 UPDATE_REG(0x30, BG3PA);
3609 UPDATE_REG(0x36, BG3PD);
3610 UPDATE_REG(0x130, P1);
3611 UPDATE_REG(0x88, 0x200);
3613 // disable FIQ
3614 reg[16].I |= 0x40;
3616 CPUUpdateCPSR();
3618 armNextPC = reg[15].I;
3619 reg[15].I += 4;
3621 // reset internal state
3622 holdState = false;
3623 holdType = 0;
3625 biosProtected[0] = 0x00;
3626 biosProtected[1] = 0xf0;
3627 biosProtected[2] = 0x29;
3628 biosProtected[3] = 0xe1;
3630 lcdTicks = (useBios && !skipBios) ? 1008 : 208;
3631 timer0On = false;
3632 timer0Ticks = 0;
3633 timer0Reload = 0;
3634 timer0ClockReload = 0;
3635 timer1On = false;
3636 timer1Ticks = 0;
3637 timer1Reload = 0;
3638 timer1ClockReload = 0;
3639 timer2On = false;
3640 timer2Ticks = 0;
3641 timer2Reload = 0;
3642 timer2ClockReload = 0;
3643 timer3On = false;
3644 timer3Ticks = 0;
3645 timer3Reload = 0;
3646 timer3ClockReload = 0;
3647 dma0Source = 0;
3648 dma0Dest = 0;
3649 dma1Source = 0;
3650 dma1Dest = 0;
3651 dma2Source = 0;
3652 dma2Dest = 0;
3653 dma3Source = 0;
3654 dma3Dest = 0;
3655 cpuSaveGameFunc = flashSaveDecide;
3656 renderLine = mode0RenderLine;
3657 fxOn = false;
3658 windowOn = false;
3659 frameCount = 0;
3660 saveType = 0;
3661 layerEnable = DISPCNT & layerSettings;
3663 CPUUpdateRenderBuffers(true);
3665 for(int i = 0; i < 256; i++) {
3666 map[i].address = (u8 *)&dummyAddress;
3667 map[i].mask = 0;
3670 map[0].address = bios;
3671 map[0].mask = 0x3FFF;
3672 map[2].address = workRAM;
3673 map[2].mask = 0x3FFFF;
3674 map[3].address = internalRAM;
3675 map[3].mask = 0x7FFF;
3676 map[4].address = ioMem;
3677 map[4].mask = 0x3FF;
3678 map[5].address = paletteRAM;
3679 map[5].mask = 0x3FF;
3680 map[6].address = vram;
3681 map[6].mask = 0x1FFFF;
3682 map[7].address = oam;
3683 map[7].mask = 0x3FF;
3684 map[8].address = rom;
3685 map[8].mask = 0x1FFFFFF;
3686 map[9].address = rom;
3687 map[9].mask = 0x1FFFFFF;
3688 map[10].address = rom;
3689 map[10].mask = 0x1FFFFFF;
3690 map[12].address = rom;
3691 map[12].mask = 0x1FFFFFF;
3692 map[14].address = flashSaveMemory;
3693 map[14].mask = 0xFFFF;
3695 eepromReset();
3696 flashReset();
3698 soundReset();
3700 CPUUpdateWindow0();
3701 CPUUpdateWindow1();
3703 // make sure registers are correctly initialized if not using BIOS
3704 if(!useBios) {
3705 if(cpuIsMultiBoot)
3706 BIOS_RegisterRamReset(0xfe);
3707 else
3708 BIOS_RegisterRamReset(0xff);
3709 } else {
3710 if(cpuIsMultiBoot)
3711 BIOS_RegisterRamReset(0xfe);
3714 switch(cpuSaveType) {
3715 case 0: // automatic
3716 cpuSramEnabled = true;
3717 cpuFlashEnabled = true;
3718 cpuEEPROMEnabled = true;
3719 cpuEEPROMSensorEnabled = false;
3720 saveType = gbaSaveType = 0;
3721 break;
3722 case 1: // EEPROM
3723 cpuSramEnabled = false;
3724 cpuFlashEnabled = false;
3725 cpuEEPROMEnabled = true;
3726 cpuEEPROMSensorEnabled = false;
3727 saveType = gbaSaveType = 3;
3728 // EEPROM usage is automatically detected
3729 break;
3730 case 2: // SRAM
3731 cpuSramEnabled = true;
3732 cpuFlashEnabled = false;
3733 cpuEEPROMEnabled = false;
3734 cpuEEPROMSensorEnabled = false;
3735 cpuSaveGameFunc = sramDelayedWrite; // to insure we detect the write
3736 saveType = gbaSaveType = 1;
3737 break;
3738 case 3: // FLASH
3739 cpuSramEnabled = false;
3740 cpuFlashEnabled = true;
3741 cpuEEPROMEnabled = false;
3742 cpuEEPROMSensorEnabled = false;
3743 cpuSaveGameFunc = flashDelayedWrite; // to insure we detect the write
3744 saveType = gbaSaveType = 2;
3745 break;
3746 case 4: // EEPROM+Sensor
3747 cpuSramEnabled = false;
3748 cpuFlashEnabled = false;
3749 cpuEEPROMEnabled = true;
3750 cpuEEPROMSensorEnabled = true;
3751 // EEPROM usage is automatically detected
3752 saveType = gbaSaveType = 3;
3753 break;
3754 case 5: // NONE
3755 cpuSramEnabled = false;
3756 cpuFlashEnabled = false;
3757 cpuEEPROMEnabled = false;
3758 cpuEEPROMSensorEnabled = false;
3759 // no save at all
3760 saveType = gbaSaveType = 5;
3761 break;
3764 ARM_PREFETCH;
3766 systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
3768 cpuDmaHack = false;
3770 lastTime = systemGetClock();
3772 SWITicks = 0;
3775 void CPUInterrupt()
3777 u32 PC = reg[15].I;
3778 bool savedState = armState;
3779 CPUSwitchMode(0x12, true, false);
3780 reg[14].I = PC;
3781 if(!savedState)
3782 reg[14].I += 2;
3783 reg[15].I = 0x18;
3784 armState = true;
3785 armIrqEnable = false;
3787 armNextPC = reg[15].I;
3788 reg[15].I += 4;
3789 ARM_PREFETCH;
3791 // if(!holdState)
3792 biosProtected[0] = 0x02;
3793 biosProtected[1] = 0xc0;
3794 biosProtected[2] = 0x5e;
3795 biosProtected[3] = 0xe5;
3798 #ifdef SDL
3799 void log(const char *defaultMsg, ...)
3801 char buffer[2048];
3802 va_list valist;
3804 va_start(valist, defaultMsg);
3805 vsprintf(buffer, defaultMsg, valist);
3807 if(out == NULL) {
3808 out = fopen("trace.log","w");
3811 fputs(buffer, out);
3813 va_end(valist);
3815 #else
3816 extern void winlog(const char *, ...);
3817 #endif
3819 void CPULoop(int ticks)
3821 int clockTicks;
3822 int timerOverflow = 0;
3823 // variable used by the CPU core
3824 cpuTotalTicks = 0;
3825 cpuBreakLoop = false;
3826 cpuNextEvent = CPUUpdateTicks();
3827 if(cpuNextEvent > ticks)
3828 cpuNextEvent = ticks;
3831 for(;;) {
3832 #ifndef FINAL_VERSION
3833 if(systemDebug) {
3834 if(systemDebug >= 10 && !holdState) {
3835 CPUUpdateCPSR();
3836 #ifdef BKPT_SUPPORT
3837 if (debugger_last)
3839 sprintf(buffer, "R00=%08x R01=%08x R02=%08x R03=%08x R04=%08x R05=%08x R06=%08x R07=%08x R08=%08x R09=%08x R10=%08x R11=%08x R12=%08x R13=%08x R14=%08x R15=%08x R16=%08x R17=%08x\n",
3840 oldreg[0], oldreg[1], oldreg[2], oldreg[3], oldreg[4], oldreg[5],
3841 oldreg[6], oldreg[7], oldreg[8], oldreg[9], oldreg[10], oldreg[11],
3842 oldreg[12], oldreg[13], oldreg[14], oldreg[15], oldreg[16],
3843 oldreg[17]);
3845 #endif
3846 sprintf(buffer, "R00=%08x R01=%08x R02=%08x R03=%08x R04=%08x R05=%08x R06=%08x R07=%08x R08=%08x R09=%08x R10=%08x R11=%08x R12=%08x R13=%08x R14=%08x R15=%08x R16=%08x R17=%08x\n",
3847 reg[0].I, reg[1].I, reg[2].I, reg[3].I, reg[4].I, reg[5].I,
3848 reg[6].I, reg[7].I, reg[8].I, reg[9].I, reg[10].I, reg[11].I,
3849 reg[12].I, reg[13].I, reg[14].I, reg[15].I, reg[16].I,
3850 reg[17].I);
3851 #ifdef SDL
3852 log(buffer);
3853 #else
3854 winlog(buffer);
3855 #endif
3856 } else if(!holdState) {
3857 sprintf(buffer, "PC=%08x\n", armNextPC);
3858 #ifdef SDL
3859 log(buffer);
3860 #else
3861 winlog(buffer);
3862 #endif
3865 #endif /* FINAL_VERSION */
3867 if(!holdState && !SWITicks) {
3869 // Emulates the Cheat System (m) code
3870 if((cheatsEnabled) && (mastercode) && (mastercode == armNextPC))
3872 u32 joy = 0;
3873 if(systemReadJoypads())
3874 joy = systemReadJoypad(-1);
3875 u32 ext = (joy >> 10);
3876 cpuTotalTicks += cheatsCheckKeys(P1^0x3FF, ext);
3879 if ((armNextPC & 0x0803FFFF) == 0x08020000)
3880 busPrefetchCount=0x100;
3882 if(armState) {
3883 #include "arm-new.h"
3884 } else {
3885 #include "thumb.h"
3887 } else
3888 clockTicks = CPUUpdateTicks();
3890 cpuTotalTicks += clockTicks;
3893 if(cpuTotalTicks >= cpuNextEvent) {
3894 int remainingTicks = cpuTotalTicks - cpuNextEvent;
3896 if (SWITicks)
3898 SWITicks-=clockTicks;
3899 if (SWITicks<0)
3900 SWITicks = 0;
3903 clockTicks = cpuNextEvent;
3904 cpuTotalTicks = 0;
3905 cpuDmaHack = false;
3907 updateLoop:
3909 if (IRQTicks)
3911 IRQTicks -= clockTicks;
3912 if (IRQTicks<0)
3913 IRQTicks = 0;
3916 lcdTicks -= clockTicks;
3919 if(lcdTicks <= 0) {
3920 if(DISPSTAT & 1) { // V-BLANK
3921 // if in V-Blank mode, keep computing...
3922 if(DISPSTAT & 2) {
3923 lcdTicks += 1008;
3924 VCOUNT++;
3925 UPDATE_REG(0x06, VCOUNT);
3926 DISPSTAT &= 0xFFFD;
3927 UPDATE_REG(0x04, DISPSTAT);
3928 CPUCompareVCOUNT();
3929 } else {
3930 lcdTicks += 224;
3931 DISPSTAT |= 2;
3932 UPDATE_REG(0x04, DISPSTAT);
3933 if(DISPSTAT & 16) {
3934 IF |= 2;
3935 UPDATE_REG(0x202, IF);
3939 if(VCOUNT >= 228) { //Reaching last line
3940 DISPSTAT &= 0xFFFC;
3941 UPDATE_REG(0x04, DISPSTAT);
3942 VCOUNT = 0;
3943 UPDATE_REG(0x06, VCOUNT);
3944 CPUCompareVCOUNT();
3946 } else {
3947 int framesToSkip = systemFrameSkip;
3948 if(speedup)
3949 framesToSkip = 9; // try 6 FPS during speedup
3951 if(DISPSTAT & 2) {
3952 // if in H-Blank, leave it and move to drawing mode
3953 VCOUNT++;
3954 UPDATE_REG(0x06, VCOUNT);
3956 lcdTicks += 1008;
3957 DISPSTAT &= 0xFFFD;
3958 if(VCOUNT == 160) {
3959 count++;
3960 systemFrame();
3962 if((count % 10) == 0) {
3963 system10Frames(60);
3965 if(count == 60) {
3966 u32 time = systemGetClock();
3967 if(time != lastTime) {
3968 u32 t = 100000/(time - lastTime);
3969 systemShowSpeed(t);
3970 } else
3971 systemShowSpeed(0);
3972 lastTime = time;
3973 count = 0;
3975 u32 joy = 0;
3976 // update joystick information
3977 if(systemReadJoypads())
3978 // read default joystick
3979 joy = systemReadJoypad(-1);
3980 P1 = 0x03FF ^ (joy & 0x3FF);
3981 if(cpuEEPROMSensorEnabled)
3982 systemUpdateMotionSensor();
3983 UPDATE_REG(0x130, P1);
3984 u16 P1CNT = READ16LE(((u16 *)&ioMem[0x132]));
3985 // this seems wrong, but there are cases where the game
3986 // can enter the stop state without requesting an IRQ from
3987 // the joypad.
3988 if((P1CNT & 0x4000) || stopState) {
3989 u16 p1 = (0x3FF ^ P1) & 0x3FF;
3990 if(P1CNT & 0x8000) {
3991 if(p1 == (P1CNT & 0x3FF)) {
3992 IF |= 0x1000;
3993 UPDATE_REG(0x202, IF);
3995 } else {
3996 if(p1 & P1CNT) {
3997 IF |= 0x1000;
3998 UPDATE_REG(0x202, IF);
4003 u32 ext = (joy >> 10);
4004 // If no (m) code is enabled, apply the cheats at each LCDline
4005 if((cheatsEnabled) && (mastercode==0))
4006 remainingTicks += cheatsCheckKeys(P1^0x3FF, ext);
4007 speedup = (ext & 1) ? true : false;
4008 capture = (ext & 2) ? true : false;
4010 if(capture && !capturePrevious) {
4011 captureNumber++;
4012 systemScreenCapture(captureNumber);
4014 capturePrevious = capture;
4016 DISPSTAT |= 1;
4017 DISPSTAT &= 0xFFFD;
4018 UPDATE_REG(0x04, DISPSTAT);
4019 if(DISPSTAT & 0x0008) {
4020 IF |= 1;
4021 UPDATE_REG(0x202, IF);
4023 CPUCheckDMA(1, 0x0f);
4024 if(frameCount >= framesToSkip) {
4025 systemDrawScreen();
4026 frameCount = 0;
4027 } else
4028 frameCount++;
4029 if(systemPauseOnFrame())
4030 ticks = 0;
4033 UPDATE_REG(0x04, DISPSTAT);
4034 CPUCompareVCOUNT();
4036 } else {
4037 if(frameCount >= framesToSkip)
4039 (*renderLine)();
4040 switch(systemColorDepth) {
4041 case 16:
4043 u16 *dest = (u16 *)pix + 242 * (VCOUNT+1);
4044 for(int x = 0; x < 240;) {
4045 *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
4046 *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
4047 *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
4048 *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
4050 *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
4051 *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
4052 *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
4053 *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
4055 *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
4056 *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
4057 *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
4058 *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
4060 *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
4061 *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
4062 *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
4063 *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
4065 // for filters that read past the screen
4066 *dest++ = 0;
4068 break;
4069 case 24:
4071 u8 *dest = (u8 *)pix + 240 * VCOUNT * 3;
4072 for(int x = 0; x < 240;) {
4073 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
4074 dest += 3;
4075 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
4076 dest += 3;
4077 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
4078 dest += 3;
4079 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
4080 dest += 3;
4082 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
4083 dest += 3;
4084 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
4085 dest += 3;
4086 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
4087 dest += 3;
4088 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
4089 dest += 3;
4091 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
4092 dest += 3;
4093 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
4094 dest += 3;
4095 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
4096 dest += 3;
4097 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
4098 dest += 3;
4100 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
4101 dest += 3;
4102 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
4103 dest += 3;
4104 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
4105 dest += 3;
4106 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
4107 dest += 3;
4110 break;
4111 case 32:
4113 u32 *dest = (u32 *)pix + 241 * (VCOUNT+1);
4114 for(int x = 0; x < 240; ) {
4115 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
4116 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
4117 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
4118 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
4120 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
4121 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
4122 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
4123 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
4125 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
4126 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
4127 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
4128 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
4130 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
4131 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
4132 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
4133 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
4136 break;
4139 // entering H-Blank
4140 DISPSTAT |= 2;
4141 UPDATE_REG(0x04, DISPSTAT);
4142 lcdTicks += 224;
4143 CPUCheckDMA(2, 0x0f);
4144 if(DISPSTAT & 16) {
4145 IF |= 2;
4146 UPDATE_REG(0x202, IF);
4152 if(!stopState) {
4153 if(timer0On) {
4154 timer0Ticks -= clockTicks;
4155 if(timer0Ticks <= 0) {
4156 timer0Ticks += (0x10000 - timer0Reload) << timer0ClockReload;
4157 timerOverflow |= 1;
4158 soundTimerOverflow(0);
4159 if(TM0CNT & 0x40) {
4160 IF |= 0x08;
4161 UPDATE_REG(0x202, IF);
4164 TM0D = 0xFFFF - (timer0Ticks >> timer0ClockReload);
4165 UPDATE_REG(0x100, TM0D);
4168 if(timer1On) {
4169 if(TM1CNT & 4) {
4170 if(timerOverflow & 1) {
4171 TM1D++;
4172 if(TM1D == 0) {
4173 TM1D += timer1Reload;
4174 timerOverflow |= 2;
4175 soundTimerOverflow(1);
4176 if(TM1CNT & 0x40) {
4177 IF |= 0x10;
4178 UPDATE_REG(0x202, IF);
4181 UPDATE_REG(0x104, TM1D);
4183 } else {
4184 timer1Ticks -= clockTicks;
4185 if(timer1Ticks <= 0) {
4186 timer1Ticks += (0x10000 - timer1Reload) << timer1ClockReload;
4187 timerOverflow |= 2;
4188 soundTimerOverflow(1);
4189 if(TM1CNT & 0x40) {
4190 IF |= 0x10;
4191 UPDATE_REG(0x202, IF);
4194 TM1D = 0xFFFF - (timer1Ticks >> timer1ClockReload);
4195 UPDATE_REG(0x104, TM1D);
4199 if(timer2On) {
4200 if(TM2CNT & 4) {
4201 if(timerOverflow & 2) {
4202 TM2D++;
4203 if(TM2D == 0) {
4204 TM2D += timer2Reload;
4205 timerOverflow |= 4;
4206 if(TM2CNT & 0x40) {
4207 IF |= 0x20;
4208 UPDATE_REG(0x202, IF);
4211 UPDATE_REG(0x108, TM2D);
4213 } else {
4214 timer2Ticks -= clockTicks;
4215 if(timer2Ticks <= 0) {
4216 timer2Ticks += (0x10000 - timer2Reload) << timer2ClockReload;
4217 timerOverflow |= 4;
4218 if(TM2CNT & 0x40) {
4219 IF |= 0x20;
4220 UPDATE_REG(0x202, IF);
4223 TM2D = 0xFFFF - (timer2Ticks >> timer2ClockReload);
4224 UPDATE_REG(0x108, TM2D);
4228 if(timer3On) {
4229 if(TM3CNT & 4) {
4230 if(timerOverflow & 4) {
4231 TM3D++;
4232 if(TM3D == 0) {
4233 TM3D += timer3Reload;
4234 if(TM3CNT & 0x40) {
4235 IF |= 0x40;
4236 UPDATE_REG(0x202, IF);
4239 UPDATE_REG(0x10C, TM3D);
4241 } else {
4242 timer3Ticks -= clockTicks;
4243 if(timer3Ticks <= 0) {
4244 timer3Ticks += (0x10000 - timer3Reload) << timer3ClockReload;
4245 if(TM3CNT & 0x40) {
4246 IF |= 0x40;
4247 UPDATE_REG(0x202, IF);
4250 TM3D = 0xFFFF - (timer3Ticks >> timer3ClockReload);
4251 UPDATE_REG(0x10C, TM3D);
4256 timerOverflow = 0;
4258 // we shouldn't be doing sound in stop state, but we loose synchronization
4259 // if sound is disabled, so in stop state, soundTick will just produce
4260 // mute sound
4261 soundTicks -= clockTicks;
4262 if(soundTicks <= 0) {
4263 soundTick();
4264 soundTicks += SOUND_CLOCK_TICKS;
4267 #ifdef PROFILING
4268 profilingTicks -= clockTicks;
4269 if(profilingTicks <= 0) {
4270 profilingTicks += profilingTicksReload;
4271 if(profilSegment) {
4272 profile_segment *seg = profilSegment;
4273 do {
4274 u16 *b = (u16 *)seg->sbuf;
4275 int pc = ((reg[15].I - seg->s_lowpc) * seg->s_scale)/0x10000;
4276 if(pc >= 0 && pc < seg->ssiz) {
4277 b[pc]++;
4278 break;
4281 seg = seg->next;
4282 } while(seg);
4285 #endif
4287 ticks -= clockTicks;
4289 cpuNextEvent = CPUUpdateTicks();
4291 if(cpuDmaTicksToUpdate > 0) {
4292 if(cpuDmaTicksToUpdate > cpuNextEvent)
4293 clockTicks = cpuNextEvent;
4294 else
4295 clockTicks = cpuDmaTicksToUpdate;
4296 cpuDmaTicksToUpdate -= clockTicks;
4297 if(cpuDmaTicksToUpdate < 0)
4298 cpuDmaTicksToUpdate = 0;
4299 cpuDmaHack = true;
4300 goto updateLoop;
4303 if(IF && (IME & 1) && armIrqEnable) {
4304 int res = IF & IE;
4305 if(stopState)
4306 res &= 0x3080;
4307 if(res) {
4308 if (intState)
4310 if (!IRQTicks)
4312 CPUInterrupt();
4313 intState = false;
4314 holdState = false;
4315 stopState = false;
4316 holdType = 0;
4319 else
4321 if (!holdState)
4323 intState = true;
4324 IRQTicks=7;
4325 if (cpuNextEvent> IRQTicks)
4326 cpuNextEvent = IRQTicks;
4328 else
4330 CPUInterrupt();
4331 holdState = false;
4332 stopState = false;
4333 holdType = 0;
4337 // Stops the SWI Ticks emulation if an IRQ is executed
4338 //(to avoid problems with nested IRQ/SWI)
4339 if (SWITicks)
4340 SWITicks = 0;
4344 if(remainingTicks > 0) {
4345 if(remainingTicks > cpuNextEvent)
4346 clockTicks = cpuNextEvent;
4347 else
4348 clockTicks = remainingTicks;
4349 remainingTicks -= clockTicks;
4350 if(remainingTicks < 0)
4351 remainingTicks = 0;
4352 goto updateLoop;
4355 if (timerOnOffDelay)
4356 applyTimer();
4358 if(cpuNextEvent > ticks)
4359 cpuNextEvent = ticks;
4361 if(ticks <= 0 || cpuBreakLoop)
4362 break;
4370 struct EmulatedSystem GBASystem = {
4371 // emuMain
4372 CPULoop,
4373 // emuReset
4374 CPUReset,
4375 // emuCleanUp
4376 CPUCleanUp,
4377 // emuReadBattery
4378 CPUReadBatteryFile,
4379 // emuWriteBattery
4380 CPUWriteBatteryFile,
4381 // emuReadState
4382 CPUReadState,
4383 // emuWriteState
4384 CPUWriteState,
4385 // emuReadMemState
4386 CPUReadMemState,
4387 // emuWriteMemState
4388 CPUWriteMemState,
4389 // emuWritePNG
4390 CPUWritePNGFile,
4391 // emuWriteBMP
4392 CPUWriteBMPFile,
4393 // emuUpdateCPSR
4394 CPUUpdateCPSR,
4395 // emuHasDebugger
4396 true,
4397 // emuCount
4398 #ifdef FINAL_VERSION
4399 250000
4400 #else
4401 5000
4402 #endif