src/gba/io.c (view raw)
1/* Copyright (c) 2013-2015 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "io.h"
7
8#include "gba/rr/rr.h"
9#include "gba/serialize.h"
10#include "gba/sio.h"
11#include "gba/video.h"
12
13const char* GBAIORegisterNames[] = {
14 // Video
15 "DISPCNT",
16 0,
17 "DISPSTAT",
18 "VCOUNT",
19 "BG0CNT",
20 "BG1CNT",
21 "BG2CNT",
22 "BG3CNT",
23 "BG0HOFS",
24 "BG0VOFS",
25 "BG1HOFS",
26 "BG1VOFS",
27 "BG2HOFS",
28 "BG2VOFS",
29 "BG3HOFS",
30 "BG3VOFS",
31 "BG2PA",
32 "BG2PB",
33 "BG2PC",
34 "BG2PD",
35 "BG2X_LO",
36 "BG2X_HI",
37 "BG2Y_LO",
38 "BG2Y_HI",
39 "BG3PA",
40 "BG3PB",
41 "BG3PC",
42 "BG3PD",
43 "BG3X_LO",
44 "BG3X_HI",
45 "BG3Y_LO",
46 "BG3Y_HI",
47 "WIN0H",
48 "WIN1H",
49 "WIN0V",
50 "WIN1V",
51 "WININ",
52 "WINOUT",
53 "MOSAIC",
54 0,
55 "BLDCNT",
56 "BLDALPHA",
57 "BLDY",
58 0,
59 0,
60 0,
61 0,
62 0,
63
64 // Sound
65 "SOUND1CNT_LO",
66 "SOUND1CNT_HI",
67 "SOUND1CNT_X",
68 0,
69 "SOUND2CNT_LO",
70 0,
71 "SOUND2CNT_HI",
72 0,
73 "SOUND3CNT_LO",
74 "SOUND3CNT_HI",
75 "SOUND3CNT_X",
76 0,
77 "SOUND4CNT_LO",
78 0,
79 "SOUND4CNT_HI",
80 0,
81 "SOUNDCNT_LO",
82 "SOUNDCNT_HI",
83 "SOUNDCNT_X",
84 0,
85 "SOUNDBIAS",
86 0,
87 0,
88 0,
89 "WAVE_RAM0_LO",
90 "WAVE_RAM0_HI",
91 "WAVE_RAM1_LO",
92 "WAVE_RAM1_HI",
93 "WAVE_RAM2_LO",
94 "WAVE_RAM2_HI",
95 "WAVE_RAM3_LO",
96 "WAVE_RAM3_HI",
97 "FIFO_A_LO",
98 "FIFO_A_HI",
99 "FIFO_B_LO",
100 "FIFO_B_HI",
101 0,
102 0,
103 0,
104 0,
105
106 // DMA
107 "DMA0SAD_LO",
108 "DMA0SAD_HI",
109 "DMA0DAD_LO",
110 "DMA0DAD_HI",
111 "DMA0CNT_LO",
112 "DMA0CNT_HI",
113 "DMA1SAD_LO",
114 "DMA1SAD_HI",
115 "DMA1DAD_LO",
116 "DMA1DAD_HI",
117 "DMA1CNT_LO",
118 "DMA1CNT_HI",
119 "DMA2SAD_LO",
120 "DMA2SAD_HI",
121 "DMA2DAD_LO",
122 "DMA2DAD_HI",
123 "DMA2CNT_LO",
124 "DMA2CNT_HI",
125 "DMA3SAD_LO",
126 "DMA3SAD_HI",
127 "DMA3DAD_LO",
128 "DMA3DAD_HI",
129 "DMA3CNT_LO",
130 "DMA3CNT_HI",
131
132 0, 0, 0, 0, 0, 0, 0, 0,
133 0, 0, 0, 0, 0, 0, 0, 0,
134
135 // Timers
136 "TM0CNT_LO",
137 "TM0CNT_HI",
138 "TM1CNT_LO",
139 "TM1CNT_HI",
140 "TM2CNT_LO",
141 "TM2CNT_HI",
142 "TM3CNT_LO",
143 "TM3CNT_HI",
144
145 0, 0, 0, 0, 0, 0, 0, 0,
146
147 // SIO
148 "SIOMULTI0",
149 "SIOMULTI1",
150 "SIOMULTI2",
151 "SIOMULTI3",
152 "SIOCNT",
153 "SIOMLT_SEND",
154 0,
155 0,
156 "KEYINPUT",
157 "KEYCNT",
158 "RCNT",
159 0,
160 0,
161 0,
162 0,
163 0,
164 "JOYCNT",
165 0,
166 0,
167 0,
168 0,
169 0,
170 0,
171 0,
172 "JOY_RECV_LO",
173 "JOY_RECV_HI",
174 "JOY_TRANS_LO",
175 "JOY_TRANS_HI",
176 "JOYSTAT",
177 0,
178 0,
179 0,
180
181 0, 0, 0, 0, 0, 0, 0, 0,
182 0, 0, 0, 0, 0, 0, 0, 0,
183 0, 0, 0, 0, 0, 0, 0, 0,
184 0, 0, 0, 0, 0, 0, 0, 0,
185 0, 0, 0, 0, 0, 0, 0, 0,
186 0, 0, 0, 0, 0, 0, 0, 0,
187 0, 0, 0, 0, 0, 0, 0, 0,
188 0, 0, 0, 0, 0, 0, 0, 0,
189 0, 0, 0, 0, 0, 0, 0, 0,
190 0, 0, 0, 0, 0, 0, 0, 0,
191
192 // Interrupts, etc
193 "IE",
194 "IF",
195 "WAITCNT",
196 0,
197 "IME"
198};
199
200static const int _isValidRegister[REG_MAX >> 1] = {
201 // Video
202 1, 0, 1, 1, 1, 1, 1, 1,
203 1, 1, 1, 1, 1, 1, 1, 1,
204 1, 1, 1, 1, 1, 1, 1, 1,
205 1, 1, 1, 1, 1, 1, 1, 1,
206 1, 1, 1, 1, 1, 1, 1, 0,
207 1, 1, 1, 0, 0, 0, 0, 0,
208 // Audio
209 1, 1, 1, 0, 1, 0, 1, 0,
210 1, 1, 1, 0, 1, 0, 1, 0,
211 1, 1, 1, 0, 1, 0, 0, 0,
212 1, 1, 1, 1, 1, 1, 1, 1,
213 1, 1, 1, 1, 1, 0, 0, 0,
214 // DMA
215 1, 1, 1, 1, 1, 1, 1, 1,
216 1, 1, 1, 1, 1, 1, 1, 1,
217 1, 1, 1, 1, 1, 1, 1, 1,
218 0, 0, 0, 0, 0, 0, 0, 0,
219 0, 0, 0, 0, 0, 0, 0, 0,
220 // Timers
221 1, 1, 1, 1, 1, 1, 1, 1,
222 0, 0, 0, 0, 0, 0, 0, 0,
223 // SIO
224 1, 1, 1, 1, 1, 0, 0, 0,
225 1, 1, 1, 0, 0, 0, 0, 0,
226 1, 0, 0, 0, 0, 0, 0, 0,
227 1, 0, 1, 0, 1, 0, 0, 0,
228 0, 0, 0, 0, 0, 0, 0, 0,
229 0, 0, 0, 0, 0, 0, 0, 0,
230 0, 0, 0, 0, 0, 0, 0, 0,
231 0, 0, 0, 0, 0, 0, 0, 0,
232 0, 0, 0, 0, 0, 0, 0, 0,
233 0, 0, 0, 0, 0, 0, 0, 0,
234 0, 0, 0, 0, 0, 0, 0, 0,
235 0, 0, 0, 0, 0, 0, 0, 0,
236 0, 0, 0, 0, 0, 0, 0, 0,
237 0, 0, 0, 0, 0, 0, 0, 0,
238 // Interrupts
239 1, 1, 1, 0, 1
240};
241
242static const int _isSpecialRegister[REG_MAX >> 1] = {
243 // Video
244 0, 0, 1, 1, 0, 0, 0, 0,
245 0, 0, 0, 0, 0, 0, 0, 0,
246 0, 0, 0, 0, 0, 0, 0, 0,
247 0, 0, 0, 0, 0, 0, 0, 0,
248 0, 0, 0, 0, 0, 0, 0, 0,
249 0, 0, 0, 0, 0, 0, 0, 0,
250 // Audio
251 0, 0, 0, 0, 0, 0, 0, 0,
252 0, 0, 0, 0, 0, 0, 0, 0,
253 0, 0, 0, 0, 0, 0, 0, 0,
254 1, 1, 1, 1, 1, 1, 1, 1,
255 1, 1, 1, 1, 0, 0, 0, 0,
256 // DMA
257 0, 0, 0, 0, 0, 1, 0, 0,
258 0, 0, 0, 1, 0, 0, 0, 0,
259 0, 1, 0, 0, 0, 0, 0, 1,
260 0, 0, 0, 0, 0, 0, 0, 0,
261 0, 0, 0, 0, 0, 0, 0, 0,
262 // Timers
263 1, 1, 1, 1, 1, 1, 1, 1,
264 0, 0, 0, 0, 0, 0, 0, 0,
265 // SIO
266 1, 1, 1, 1, 1, 0, 0, 0,
267 1, 1, 1, 0, 0, 0, 0, 0,
268 1, 0, 0, 0, 0, 0, 0, 0,
269 1, 0, 1, 0, 1, 0, 0, 0,
270 0, 0, 0, 0, 0, 0, 0, 0,
271 0, 0, 0, 0, 0, 0, 0, 0,
272 0, 0, 0, 0, 0, 0, 0, 0,
273 0, 0, 0, 0, 0, 0, 0, 0,
274 0, 0, 0, 0, 0, 0, 0, 0,
275 0, 0, 0, 0, 0, 0, 0, 0,
276 0, 0, 0, 0, 0, 0, 0, 0,
277 0, 0, 0, 0, 0, 0, 0, 0,
278 0, 0, 0, 0, 0, 0, 0, 0,
279 0, 0, 0, 0, 0, 0, 0, 0,
280 // Interrupts
281 1, 1, 0, 0, 1
282};
283
284void GBAIOInit(struct GBA* gba) {
285 gba->memory.io[REG_DISPCNT >> 1] = 0x0080;
286 gba->memory.io[REG_RCNT >> 1] = RCNT_INITIAL;
287 gba->memory.io[REG_KEYINPUT >> 1] = 0x3FF;
288 gba->memory.io[REG_SOUNDBIAS >> 1] = 0x200;
289 gba->memory.io[REG_BG2PA >> 1] = 0x100;
290 gba->memory.io[REG_BG2PD >> 1] = 0x100;
291 gba->memory.io[REG_BG3PA >> 1] = 0x100;
292 gba->memory.io[REG_BG3PD >> 1] = 0x100;
293}
294
295void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) {
296 if (address < REG_SOUND1CNT_LO && address != REG_DISPSTAT) {
297 value = gba->video.renderer->writeVideoRegister(gba->video.renderer, address, value);
298 } else {
299 switch (address) {
300 // Video
301 case REG_DISPSTAT:
302 value &= 0xFFF8;
303 GBAVideoWriteDISPSTAT(&gba->video, value);
304 return;
305
306 // Audio
307 case REG_SOUND1CNT_LO:
308 GBAAudioWriteSOUND1CNT_LO(&gba->audio, value);
309 value &= 0x00FF;
310 break;
311 case REG_SOUND1CNT_HI:
312 GBAAudioWriteSOUND1CNT_HI(&gba->audio, value);
313 break;
314 case REG_SOUND1CNT_X:
315 GBAAudioWriteSOUND1CNT_X(&gba->audio, value);
316 value &= 0x47FF;
317 break;
318 case REG_SOUND2CNT_LO:
319 GBAAudioWriteSOUND2CNT_LO(&gba->audio, value);
320 break;
321 case REG_SOUND2CNT_HI:
322 GBAAudioWriteSOUND2CNT_HI(&gba->audio, value);
323 value &= 0x47FF;
324 break;
325 case REG_SOUND3CNT_LO:
326 GBAAudioWriteSOUND3CNT_LO(&gba->audio, value);
327 value &= 0x00E0;
328 break;
329 case REG_SOUND3CNT_HI:
330 GBAAudioWriteSOUND3CNT_HI(&gba->audio, value);
331 value &= 0xE03F;
332 break;
333 case REG_SOUND3CNT_X:
334 GBAAudioWriteSOUND3CNT_X(&gba->audio, value);
335 // TODO: The low bits need to not be readable, but still 8-bit writable
336 value &= 0x47FF;
337 break;
338 case REG_SOUND4CNT_LO:
339 GBAAudioWriteSOUND4CNT_LO(&gba->audio, value);
340 value &= 0xFF3F;
341 break;
342 case REG_SOUND4CNT_HI:
343 GBAAudioWriteSOUND4CNT_HI(&gba->audio, value);
344 value &= 0x40FF;
345 break;
346 case REG_SOUNDCNT_LO:
347 GBAAudioWriteSOUNDCNT_LO(&gba->audio, value);
348 break;
349 case REG_SOUNDCNT_HI:
350 GBAAudioWriteSOUNDCNT_HI(&gba->audio, value);
351 break;
352 case REG_SOUNDCNT_X:
353 GBAAudioWriteSOUNDCNT_X(&gba->audio, value);
354 value &= 0xFFFF;
355 value |= gba->memory.io[REG_SOUNDCNT_X >> 1] & 0xF;
356 break;
357 case REG_SOUNDBIAS:
358 GBAAudioWriteSOUNDBIAS(&gba->audio, value);
359 break;
360
361 case REG_WAVE_RAM0_LO:
362 case REG_WAVE_RAM1_LO:
363 case REG_WAVE_RAM2_LO:
364 case REG_WAVE_RAM3_LO:
365 GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
366 break;
367
368 case REG_WAVE_RAM0_HI:
369 case REG_WAVE_RAM1_HI:
370 case REG_WAVE_RAM2_HI:
371 case REG_WAVE_RAM3_HI:
372 GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
373 break;
374
375 case REG_FIFO_A_LO:
376 case REG_FIFO_B_LO:
377 GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
378 break;
379
380 case REG_FIFO_A_HI:
381 case REG_FIFO_B_HI:
382 GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
383 break;
384
385 // DMA
386 case REG_DMA0SAD_LO:
387 case REG_DMA0DAD_LO:
388 case REG_DMA1SAD_LO:
389 case REG_DMA1DAD_LO:
390 case REG_DMA2SAD_LO:
391 case REG_DMA2DAD_LO:
392 case REG_DMA3SAD_LO:
393 case REG_DMA3DAD_LO:
394 GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
395 break;
396
397 case REG_DMA0SAD_HI:
398 case REG_DMA0DAD_HI:
399 case REG_DMA1SAD_HI:
400 case REG_DMA1DAD_HI:
401 case REG_DMA2SAD_HI:
402 case REG_DMA2DAD_HI:
403 case REG_DMA3SAD_HI:
404 case REG_DMA3DAD_HI:
405 GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
406 break;
407
408 case REG_DMA0CNT_LO:
409 GBAMemoryWriteDMACNT_LO(gba, 0, value);
410 break;
411 case REG_DMA0CNT_HI:
412 value = GBAMemoryWriteDMACNT_HI(gba, 0, value);
413 break;
414 case REG_DMA1CNT_LO:
415 GBAMemoryWriteDMACNT_LO(gba, 1, value);
416 break;
417 case REG_DMA1CNT_HI:
418 value = GBAMemoryWriteDMACNT_HI(gba, 1, value);
419 break;
420 case REG_DMA2CNT_LO:
421 GBAMemoryWriteDMACNT_LO(gba, 2, value);
422 break;
423 case REG_DMA2CNT_HI:
424 value = GBAMemoryWriteDMACNT_HI(gba, 2, value);
425 break;
426 case REG_DMA3CNT_LO:
427 GBAMemoryWriteDMACNT_LO(gba, 3, value);
428 break;
429 case REG_DMA3CNT_HI:
430 value = GBAMemoryWriteDMACNT_HI(gba, 3, value);
431 break;
432
433 // Timers
434 case REG_TM0CNT_LO:
435 GBATimerWriteTMCNT_LO(gba, 0, value);
436 return;
437 case REG_TM1CNT_LO:
438 GBATimerWriteTMCNT_LO(gba, 1, value);
439 return;
440 case REG_TM2CNT_LO:
441 GBATimerWriteTMCNT_LO(gba, 2, value);
442 return;
443 case REG_TM3CNT_LO:
444 GBATimerWriteTMCNT_LO(gba, 3, value);
445 return;
446
447 case REG_TM0CNT_HI:
448 value &= 0x00C7;
449 GBATimerWriteTMCNT_HI(gba, 0, value);
450 break;
451 case REG_TM1CNT_HI:
452 value &= 0x00C7;
453 GBATimerWriteTMCNT_HI(gba, 1, value);
454 break;
455 case REG_TM2CNT_HI:
456 value &= 0x00C7;
457 GBATimerWriteTMCNT_HI(gba, 2, value);
458 break;
459 case REG_TM3CNT_HI:
460 value &= 0x00C7;
461 GBATimerWriteTMCNT_HI(gba, 3, value);
462 break;
463
464 // SIO
465 case REG_SIOCNT:
466 GBASIOWriteSIOCNT(&gba->sio, value);
467 break;
468 case REG_RCNT:
469 value &= 0xC1FF;
470 GBASIOWriteRCNT(&gba->sio, value);
471 break;
472 case REG_SIOMLT_SEND:
473 GBASIOWriteSIOMLT_SEND(&gba->sio, value);
474 break;
475
476 // Interrupts and misc
477 case REG_WAITCNT:
478 GBAAdjustWaitstates(gba, value);
479 break;
480 case REG_IE:
481 GBAWriteIE(gba, value);
482 break;
483 case REG_IF:
484 value = gba->memory.io[REG_IF >> 1] & ~value;
485 break;
486 case REG_IME:
487 GBAWriteIME(gba, value);
488 break;
489 case REG_MAX:
490 // Some bad interrupt libraries will write to this
491 break;
492 default:
493 GBALog(gba, GBA_LOG_STUB, "Stub I/O register write: %03x", address);
494 if (address >= REG_MAX) {
495 GBALog(gba, GBA_LOG_GAME_ERROR, "Write to unused I/O register: %03X", address);
496 return;
497 }
498 break;
499 }
500 }
501 gba->memory.io[address >> 1] = value;
502}
503
504void GBAIOWrite8(struct GBA* gba, uint32_t address, uint8_t value) {
505 if (address == REG_HALTCNT) {
506 value &= 0x80;
507 if (!value) {
508 GBAHalt(gba);
509 } else {
510 GBAStop(gba);
511 }
512 return;
513 }
514 uint16_t value16 = value << (8 * (address & 1));
515 value16 |= (gba->memory.io[(address & (SIZE_IO - 1)) >> 1]) & ~(0xFF << (8 * (address & 1)));
516 GBAIOWrite(gba, address & 0xFFFFFFFE, value16);
517}
518
519void GBAIOWrite32(struct GBA* gba, uint32_t address, uint32_t value) {
520 switch (address) {
521 case REG_WAVE_RAM0_LO:
522 GBAAudioWriteWaveRAM(&gba->audio, 0, value);
523 break;
524 case REG_WAVE_RAM1_LO:
525 GBAAudioWriteWaveRAM(&gba->audio, 1, value);
526 break;
527 case REG_WAVE_RAM2_LO:
528 GBAAudioWriteWaveRAM(&gba->audio, 2, value);
529 break;
530 case REG_WAVE_RAM3_LO:
531 GBAAudioWriteWaveRAM(&gba->audio, 3, value);
532 break;
533 case REG_FIFO_A_LO:
534 case REG_FIFO_B_LO:
535 GBAAudioWriteFIFO(&gba->audio, address, value);
536 break;
537 case REG_DMA0SAD_LO:
538 value = GBAMemoryWriteDMASAD(gba, 0, value);
539 break;
540 case REG_DMA0DAD_LO:
541 value = GBAMemoryWriteDMADAD(gba, 0, value);
542 break;
543 case REG_DMA1SAD_LO:
544 value = GBAMemoryWriteDMASAD(gba, 1, value);
545 break;
546 case REG_DMA1DAD_LO:
547 value = GBAMemoryWriteDMADAD(gba, 1, value);
548 break;
549 case REG_DMA2SAD_LO:
550 value = GBAMemoryWriteDMASAD(gba, 2, value);
551 break;
552 case REG_DMA2DAD_LO:
553 value = GBAMemoryWriteDMADAD(gba, 2, value);
554 break;
555 case REG_DMA3SAD_LO:
556 value = GBAMemoryWriteDMASAD(gba, 3, value);
557 break;
558 case REG_DMA3DAD_LO:
559 value = GBAMemoryWriteDMADAD(gba, 3, value);
560 break;
561 default:
562 GBAIOWrite(gba, address, value & 0xFFFF);
563 GBAIOWrite(gba, address | 2, value >> 16);
564 return;
565 }
566 gba->memory.io[address >> 1] = value;
567 gba->memory.io[(address >> 1) + 1] = value >> 16;
568}
569
570bool GBAIOIsReadConstant(uint32_t address) {
571 switch (address) {
572 default:
573 return false;
574 case REG_BG0CNT:
575 case REG_BG1CNT:
576 case REG_BG2CNT:
577 case REG_BG3CNT:
578 case REG_WININ:
579 case REG_WINOUT:
580 case REG_BLDCNT:
581 case REG_BLDALPHA:
582 case REG_DMA0CNT_LO:
583 case REG_DMA1CNT_LO:
584 case REG_DMA2CNT_LO:
585 case REG_DMA3CNT_LO:
586 case REG_KEYINPUT:
587 case REG_IE:
588 return true;
589 }
590}
591
592uint16_t GBAIORead(struct GBA* gba, uint32_t address) {
593 if (!GBAIOIsReadConstant(address)) {
594 // Most IO reads need to disable idle removal
595 gba->haltPending = false;
596 }
597
598 switch (address) {
599 case REG_TM0CNT_LO:
600 GBATimerUpdateRegister(gba, 0);
601 break;
602 case REG_TM1CNT_LO:
603 GBATimerUpdateRegister(gba, 1);
604 break;
605 case REG_TM2CNT_LO:
606 GBATimerUpdateRegister(gba, 2);
607 break;
608 case REG_TM3CNT_LO:
609 GBATimerUpdateRegister(gba, 3);
610 break;
611
612 case REG_KEYINPUT:
613 if (gba->rr && gba->rr->isPlaying(gba->rr)) {
614 return 0x3FF ^ gba->rr->queryInput(gba->rr);
615 } else {
616 uint16_t input = 0x3FF;
617 if (gba->keyCallback) {
618 input = gba->keyCallback->readKeys(gba->keyCallback);
619 } else if (gba->keySource) {
620 input = *gba->keySource;
621 }
622 if (gba->rr && gba->rr->isRecording(gba->rr)) {
623 gba->rr->logInput(gba->rr, input);
624 }
625 return 0x3FF ^ input;
626 }
627
628 case REG_SIOCNT:
629 return gba->sio.siocnt;
630 case REG_RCNT:
631 return gba->sio.rcnt;
632
633 case REG_DMA0CNT_LO:
634 case REG_DMA1CNT_LO:
635 case REG_DMA2CNT_LO:
636 case REG_DMA3CNT_LO:
637 // Write-only register
638 return 0;
639 case REG_BG0HOFS:
640 case REG_BG0VOFS:
641 case REG_BG1HOFS:
642 case REG_BG1VOFS:
643 case REG_BG2HOFS:
644 case REG_BG2VOFS:
645 case REG_BG3HOFS:
646 case REG_BG3VOFS:
647 case REG_BG2PA:
648 case REG_BG2PB:
649 case REG_BG2PC:
650 case REG_BG2PD:
651 case REG_BG2X_LO:
652 case REG_BG2X_HI:
653 case REG_BG2Y_LO:
654 case REG_BG2Y_HI:
655 case REG_BG3PA:
656 case REG_BG3PB:
657 case REG_BG3PC:
658 case REG_BG3PD:
659 case REG_BG3X_LO:
660 case REG_BG3X_HI:
661 case REG_BG3Y_LO:
662 case REG_BG3Y_HI:
663 case REG_WIN0H:
664 case REG_WIN1H:
665 case REG_WIN0V:
666 case REG_WIN1V:
667 case REG_MOSAIC:
668 case REG_BLDY:
669 // Write-only register
670 return GBALoad16(gba->cpu, 0x01000000, 0); // Simulate a bad load
671 case REG_DISPCNT:
672 case REG_DISPSTAT:
673 case REG_VCOUNT:
674 case REG_BG0CNT:
675 case REG_BG1CNT:
676 case REG_BG2CNT:
677 case REG_BG3CNT:
678 case REG_WININ:
679 case REG_WINOUT:
680 case REG_BLDCNT:
681 case REG_BLDALPHA:
682 case REG_SOUND1CNT_LO:
683 case REG_SOUND1CNT_HI:
684 case REG_SOUND1CNT_X:
685 case REG_SOUND2CNT_LO:
686 case REG_SOUND2CNT_HI:
687 case REG_SOUND3CNT_LO:
688 case REG_SOUND3CNT_HI:
689 case REG_SOUND3CNT_X:
690 case REG_SOUND4CNT_LO:
691 case REG_SOUND4CNT_HI:
692 case REG_SOUNDCNT_LO:
693 case REG_SOUNDCNT_HI:
694 case REG_DMA0CNT_HI:
695 case REG_DMA1CNT_HI:
696 case REG_DMA2CNT_HI:
697 case REG_DMA3CNT_HI:
698 case REG_SIOMULTI0:
699 case REG_SIOMULTI1:
700 case REG_SIOMULTI2:
701 case REG_SIOMULTI3:
702 case REG_SIOMLT_SEND:
703 case REG_IE:
704 case REG_IF:
705 case REG_WAITCNT:
706 case REG_IME:
707 // Handled transparently by registers
708 break;
709 case REG_MAX:
710 // Some bad interrupt libraries will read from this
711 break;
712 default:
713 GBALog(gba, GBA_LOG_STUB, "Stub I/O register read: %03x", address);
714 if (address >= REG_MAX) {
715 GBALog(gba, GBA_LOG_GAME_ERROR, "Read from unused I/O register: %03X", address);
716 return 0; // TODO: Reuse LOAD_BAD
717 }
718 break;
719 }
720 return gba->memory.io[address >> 1];
721}
722
723void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) {
724 int i;
725 for (i = 0; i < REG_MAX; i += 2) {
726 if (_isSpecialRegister[i >> 1]) {
727 STORE_16(gba->memory.io[i >> 1], i, state->io);
728 } else if (_isValidRegister[i >> 1]) {
729 uint16_t reg = GBAIORead(gba, i);
730 STORE_16(reg, i, state->io);
731 }
732 }
733
734 for (i = 0; i < 4; ++i) {
735 STORE_16(gba->memory.io[(REG_DMA0CNT_LO + i * 12) >> 1], (REG_DMA0CNT_LO + i * 12), state->io);
736 STORE_16(gba->timers[i].reload, 0, &state->timers[i].reload);
737 STORE_16(gba->timers[i].oldReload, 0, &state->timers[i].oldReload);
738 STORE_32(gba->timers[i].lastEvent, 0, &state->timers[i].lastEvent);
739 STORE_32(gba->timers[i].nextEvent, 0, &state->timers[i].nextEvent);
740 STORE_32(gba->timers[i].overflowInterval, 0, &state->timers[i].overflowInterval);
741 STORE_32(gba->timers[i].flags, 0, &state->timers[i].flags);
742 STORE_32(gba->memory.dma[i].nextSource, 0, &state->dma[i].nextSource);
743 STORE_32(gba->memory.dma[i].nextDest, 0, &state->dma[i].nextDest);
744 STORE_32(gba->memory.dma[i].nextCount, 0, &state->dma[i].nextCount);
745 STORE_32(gba->memory.dma[i].nextEvent, 0, &state->dma[i].nextEvent);
746 }
747
748 GBAHardwareSerialize(&gba->memory.hw, state);
749}
750
751void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) {
752 int i;
753 for (i = 0; i < REG_MAX; i += 2) {
754 if (_isSpecialRegister[i >> 1]) {
755 LOAD_16(gba->memory.io[i >> 1], i, state->io);
756 } else if (_isValidRegister[i >> 1]) {
757 uint16_t reg;
758 LOAD_16(reg, i, state->io);
759 GBAIOWrite(gba, i, reg);
760 }
761 }
762
763 gba->timersEnabled = 0;
764 for (i = 0; i < 4; ++i) {
765 LOAD_16(gba->timers[i].reload, 0, &state->timers[i].reload);
766 LOAD_16(gba->timers[i].oldReload, 0, &state->timers[i].oldReload);
767 LOAD_32(gba->timers[i].lastEvent, 0, &state->timers[i].lastEvent);
768 LOAD_32(gba->timers[i].nextEvent, 0, &state->timers[i].nextEvent);
769 LOAD_32(gba->timers[i].overflowInterval, 0, &state->timers[i].overflowInterval);
770 LOAD_32(gba->timers[i].flags, 0, &state->timers[i].flags);
771 LOAD_16(gba->memory.dma[i].reg, (REG_DMA0CNT_HI + i * 12), state->io);
772 LOAD_32(gba->memory.dma[i].nextSource, 0, &state->dma[i].nextSource);
773 LOAD_32(gba->memory.dma[i].nextDest, 0, &state->dma[i].nextDest);
774 LOAD_32(gba->memory.dma[i].nextCount, 0, &state->dma[i].nextCount);
775 LOAD_32(gba->memory.dma[i].nextEvent, 0, &state->dma[i].nextEvent);
776 if (GBADMARegisterGetTiming(gba->memory.dma[i].reg) != DMA_TIMING_NOW) {
777 GBAMemoryScheduleDMA(gba, i, &gba->memory.dma[i]);
778 }
779
780 if (GBATimerFlagsIsEnable(gba->timers[i].flags)) {
781 gba->timersEnabled |= 1 << i;
782 }
783 }
784 GBAMemoryUpdateDMAs(gba, 0);
785 GBAHardwareDeserialize(&gba->memory.hw, state);
786}