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