src/ds/io.c (view raw)
1/* Copyright (c) 2013-2017 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 <mgba/internal/ds/io.h>
7
8#include <mgba/core/interface.h>
9#include <mgba/internal/ds/audio.h>
10#include <mgba/internal/ds/ds.h>
11#include <mgba/internal/ds/gx.h>
12#include <mgba/internal/ds/ipc.h>
13#include <mgba/internal/ds/slot1.h>
14#include <mgba/internal/ds/spi.h>
15
16mLOG_DEFINE_CATEGORY(DS_IO, "DS I/O", "ds.io");
17
18static void _DSHaltCNT(struct DSCommon* dscore, uint8_t value) {
19 switch (value >> 6) {
20 case 0:
21 default:
22 break;
23 case 1:
24 mLOG(DS_IO, STUB, "Enter GBA mode not supported");
25 break;
26 case 2:
27 ARMHalt(dscore->cpu);
28 break;
29 case 3:
30 mLOG(DS_IO, STUB, "Enter sleep mode not supported");
31 break;
32 }
33}
34
35static uint16_t _scheduleDiv(struct DS* ds, uint16_t control) {
36 mTimingDeschedule(&ds->ds9.timing, &ds->divEvent);
37 mTimingSchedule(&ds->ds9.timing, &ds->divEvent, (control & 3) ? 36 : 68);
38 return control | 0x8000;
39}
40
41static uint16_t _scheduleSqrt(struct DS* ds, uint16_t control) {
42 mTimingDeschedule(&ds->ds9.timing, &ds->sqrtEvent);
43 mTimingSchedule(&ds->ds9.timing, &ds->sqrtEvent, 26);
44 return control | 0x8000;
45}
46
47static uint32_t DSIOWrite(struct DSCommon* dscore, uint32_t address, uint16_t value) {
48 switch (address) {
49 // Video
50 case DS_REG_DISPSTAT:
51 DSVideoWriteDISPSTAT(dscore, value);
52 break;
53
54 // DMA Fill
55 case DS_REG_DMA0FILL_LO:
56 case DS_REG_DMA0FILL_HI:
57 case DS_REG_DMA1FILL_LO:
58 case DS_REG_DMA1FILL_HI:
59 case DS_REG_DMA2FILL_LO:
60 case DS_REG_DMA2FILL_HI:
61 case DS_REG_DMA3FILL_LO:
62 case DS_REG_DMA3FILL_HI:
63 break;
64
65 // Timers
66 case DS_REG_TM0CNT_LO:
67 GBATimerWriteTMCNT_LO(&dscore->timers[0], value);
68 return 0x20000;
69 case DS_REG_TM1CNT_LO:
70 GBATimerWriteTMCNT_LO(&dscore->timers[1], value);
71 return 0x20000;
72 case DS_REG_TM2CNT_LO:
73 GBATimerWriteTMCNT_LO(&dscore->timers[2], value);
74 return 0x20000;
75 case DS_REG_TM3CNT_LO:
76 GBATimerWriteTMCNT_LO(&dscore->timers[3], value);
77 return 0x20000;
78
79 case DS_REG_TM0CNT_HI:
80 value &= 0x00C7;
81 DSTimerWriteTMCNT_HI(&dscore->timers[0], &dscore->timing, &dscore->memory.io[DS_REG_TM0CNT_LO >> 1], value);
82 break;
83 case DS_REG_TM1CNT_HI:
84 value &= 0x00C7;
85 DSTimerWriteTMCNT_HI(&dscore->timers[1], &dscore->timing, &dscore->memory.io[DS_REG_TM1CNT_LO >> 1], value);
86 break;
87 case DS_REG_TM2CNT_HI:
88 value &= 0x00C7;
89 DSTimerWriteTMCNT_HI(&dscore->timers[2], &dscore->timing, &dscore->memory.io[DS_REG_TM2CNT_LO >> 1], value);
90 break;
91 case DS_REG_TM3CNT_HI:
92 value &= 0x00C7;
93 DSTimerWriteTMCNT_HI(&dscore->timers[3], &dscore->timing, &dscore->memory.io[DS_REG_TM3CNT_LO >> 1], value);
94 break;
95
96 // IPC
97 case DS_REG_IPCSYNC:
98 value &= 0x6F00;
99 value |= dscore->memory.io[address >> 1] & 0x000F;
100 DSIPCWriteSYNC(dscore->ipc->cpu, dscore->ipc->memory.io, value);
101 break;
102 case DS_REG_IPCFIFOCNT:
103 value = DSIPCWriteFIFOCNT(dscore, value);
104 break;
105
106 // Cart bus
107 case DS_REG_AUXSPICNT:
108 if (dscore->memory.slot1Access) {
109 value = DSSlot1Configure(dscore->p, value);
110 dscore->ipc->memory.io[address >> 1] = value;
111 } else {
112 mLOG(DS_IO, GAME_ERROR, "Invalid cart access");
113 return 0;
114 }
115 break;
116 case DS_REG_AUXSPIDATA:
117 if (dscore->memory.slot1Access) {
118 DSSlot1WriteSPI(dscore, value);
119 dscore->ipc->memory.io[address >> 1] = value;
120 } else {
121 mLOG(DS_IO, GAME_ERROR, "Invalid cart access");
122 return 0;
123 }
124 break;
125 case DS_REG_ROMCNT_HI:
126 if (dscore->memory.slot1Access) {
127 DSSlot1ROMCNT cnt = value << 16;
128 cnt |= dscore->memory.io[(address - 2) >> 1];
129 cnt = DSSlot1Control(dscore->p, cnt);
130 value = cnt >> 16;
131 dscore->ipc->memory.io[address >> 1] = value;
132 } else {
133 mLOG(DS_IO, GAME_ERROR, "Invalid cart access");
134 return 0;
135 }
136 break;
137 case DS_REG_ROMCNT_LO:
138 case DS_REG_ROMCMD_0:
139 case DS_REG_ROMCMD_2:
140 case DS_REG_ROMCMD_4:
141 case DS_REG_ROMCMD_6:
142 if (dscore->memory.slot1Access) {
143 dscore->ipc->memory.io[address >> 1] = value;
144 } else {
145 mLOG(DS_IO, GAME_ERROR, "Invalid cart access");
146 return 0;
147 }
148 break;
149
150 // Interrupts
151 case DS_REG_IME:
152 DSWriteIME(dscore->cpu, dscore->memory.io, value);
153 break;
154 case 0x20A:
155 value = 0;
156 // Some bad interrupt libraries will write to this
157 break;
158 case DS_REG_IF_LO:
159 case DS_REG_IF_HI:
160 value = dscore->memory.io[address >> 1] & ~value;
161 DSGXUpdateGXSTAT(&dscore->p->gx);
162 break;
163 default:
164 return 0;
165 }
166 return value | 0x10000;
167}
168
169uint32_t DSIOWrite32(struct DSCommon* dscore, uint32_t address, uint32_t value) {
170 switch (address) {
171 case DS_REG_DMA0SAD_LO:
172 value = DSDMAWriteSAD(dscore, 0, value);
173 break;
174 case DS_REG_DMA1SAD_LO:
175 value = DSDMAWriteSAD(dscore, 1, value);
176 break;
177 case DS_REG_DMA2SAD_LO:
178 value = DSDMAWriteSAD(dscore, 2, value);
179 break;
180 case DS_REG_DMA3SAD_LO:
181 value = DSDMAWriteSAD(dscore, 3, value);
182 break;
183
184 case DS_REG_DMA0DAD_LO:
185 value = DSDMAWriteDAD(dscore, 0, value);
186 break;
187 case DS_REG_DMA1DAD_LO:
188 value = DSDMAWriteDAD(dscore, 1, value);
189 break;
190 case DS_REG_DMA2DAD_LO:
191 value = DSDMAWriteDAD(dscore, 2, value);
192 break;
193 case DS_REG_DMA3DAD_LO:
194 value = DSDMAWriteDAD(dscore, 3, value);
195 break;
196
197 case DS_REG_IPCFIFOSEND_LO:
198 DSIPCWriteFIFO(dscore, value);
199 break;
200 case DS_REG_IE_LO:
201 DSWriteIE(dscore->cpu, dscore->memory.io, value);
202 break;
203 }
204
205 return value;
206}
207
208static uint16_t DSIOReadExKeyInput(struct DS* ds) {
209 uint16_t input = 0;
210 if (ds->keyCallback) {
211 input = ds->keyCallback->readKeys(ds->keyCallback);
212 } else if (ds->keySource) {
213 input = *ds->keySource;
214 }
215 input = ~(input >> 10) & 0x3;
216 input |= 0x3C;
217 input |= ds->memory.io7[DS7_REG_EXTKEYIN >> 1] & 0xC0;
218 return input;
219}
220
221static uint16_t DSIOReadKeyInput(struct DS* ds) {
222 uint16_t input = 0;
223 if (ds->keyCallback) {
224 input = ds->keyCallback->readKeys(ds->keyCallback);
225 } else if (ds->keySource) {
226 input = *ds->keySource;
227 }
228 // TODO: Put back
229 /*if (!dscore->p->allowOpposingDirections) {
230 unsigned rl = input & 0x030;
231 unsigned ud = input & 0x0C0;
232 input &= 0x30F;
233 if (rl != 0x030) {
234 input |= rl;
235 }
236 if (ud != 0x0C0) {
237 input |= ud;
238 }
239 }*/
240 return ~input & 0x3FF;
241}
242
243static void DSIOUpdateTimer(struct DSCommon* dscore, uint32_t address) {
244 switch (address) {
245 case DS_REG_TM0CNT_LO:
246 GBATimerUpdateRegisterInternal(&dscore->timers[0], &dscore->timing, &dscore->memory.io[address >> 1], 0);
247 break;
248 case DS_REG_TM1CNT_LO:
249 GBATimerUpdateRegisterInternal(&dscore->timers[1], &dscore->timing, &dscore->memory.io[address >> 1], 0);
250 break;
251 case DS_REG_TM2CNT_LO:
252 GBATimerUpdateRegisterInternal(&dscore->timers[2], &dscore->timing, &dscore->memory.io[address >> 1], 0);
253 break;
254 case DS_REG_TM3CNT_LO:
255 GBATimerUpdateRegisterInternal(&dscore->timers[3], &dscore->timing, &dscore->memory.io[address >> 1], 0);
256 break;
257 }
258}
259
260void DS7IOInit(struct DS* ds) {
261 memset(ds->memory.io7, 0, sizeof(ds->memory.io7));
262 ds->memory.io7[DS_REG_IPCFIFOCNT >> 1] = 0x0101;
263 ds->memory.io7[DS_REG_POSTFLG >> 1] = 0x0001;
264 ds->memory.io7[DS7_REG_EXTKEYIN >> 1] = 0x007F;
265}
266
267void DS7IOWrite(struct DS* ds, uint32_t address, uint16_t value) {
268 switch (address) {
269 case DS_REG_DMA0CNT_HI:
270 DS7DMAWriteCNT(&ds->ds7, 0, (value << 16) | ds->ds7.memory.io[(address - 2) >> 1]);
271 break;
272 case DS_REG_DMA1CNT_HI:
273 DS7DMAWriteCNT(&ds->ds7, 1, (value << 16) | ds->ds7.memory.io[(address - 2) >> 1]);
274 break;
275 case DS_REG_DMA2CNT_HI:
276 DS7DMAWriteCNT(&ds->ds7, 2, (value << 16) | ds->ds7.memory.io[(address - 2) >> 1]);
277 break;
278 case DS_REG_DMA3CNT_HI:
279 DS7DMAWriteCNT(&ds->ds7, 3, (value << 16) | ds->ds7.memory.io[(address - 2) >> 1]);
280 break;
281 case DS7_REG_SPICNT:
282 value &= 0xCF83;
283 value = DSSPIWriteControl(ds, value);
284 break;
285 case DS7_REG_SPIDATA:
286 DSSPIWrite(ds, value);
287 break;
288 case DS7_REG_RTC:
289 value = DSWriteRTC(ds, value);
290 break;
291 case DS7_REG_SOUND0CNT_LO:
292 case DS7_REG_SOUND1CNT_LO:
293 case DS7_REG_SOUND2CNT_LO:
294 case DS7_REG_SOUND3CNT_LO:
295 case DS7_REG_SOUND4CNT_LO:
296 case DS7_REG_SOUND5CNT_LO:
297 case DS7_REG_SOUND6CNT_LO:
298 case DS7_REG_SOUND7CNT_LO:
299 case DS7_REG_SOUND8CNT_LO:
300 case DS7_REG_SOUND9CNT_LO:
301 case DS7_REG_SOUNDACNT_LO:
302 case DS7_REG_SOUNDBCNT_LO:
303 case DS7_REG_SOUNDCCNT_LO:
304 case DS7_REG_SOUNDDCNT_LO:
305 case DS7_REG_SOUNDECNT_LO:
306 case DS7_REG_SOUNDFCNT_LO:
307 value &= 0x837F;
308 DSAudioWriteSOUNDCNT_LO(&ds->audio, (address - DS7_REG_SOUND0CNT_LO) >> 4, value);
309 break;
310 case DS7_REG_SOUND0CNT_HI:
311 case DS7_REG_SOUND1CNT_HI:
312 case DS7_REG_SOUND2CNT_HI:
313 case DS7_REG_SOUND3CNT_HI:
314 case DS7_REG_SOUND4CNT_HI:
315 case DS7_REG_SOUND5CNT_HI:
316 case DS7_REG_SOUND6CNT_HI:
317 case DS7_REG_SOUND7CNT_HI:
318 case DS7_REG_SOUND8CNT_HI:
319 case DS7_REG_SOUND9CNT_HI:
320 case DS7_REG_SOUNDACNT_HI:
321 case DS7_REG_SOUNDBCNT_HI:
322 case DS7_REG_SOUNDCCNT_HI:
323 case DS7_REG_SOUNDDCNT_HI:
324 case DS7_REG_SOUNDECNT_HI:
325 case DS7_REG_SOUNDFCNT_HI:
326 value &= 0xFF7F;
327 DSAudioWriteSOUNDCNT_HI(&ds->audio, (address - DS7_REG_SOUND0CNT_HI) >> 4, value);
328 break;
329 case DS7_REG_SOUND0TMR:
330 case DS7_REG_SOUND1TMR:
331 case DS7_REG_SOUND2TMR:
332 case DS7_REG_SOUND3TMR:
333 case DS7_REG_SOUND4TMR:
334 case DS7_REG_SOUND5TMR:
335 case DS7_REG_SOUND6TMR:
336 case DS7_REG_SOUND7TMR:
337 case DS7_REG_SOUND8TMR:
338 case DS7_REG_SOUND9TMR:
339 case DS7_REG_SOUNDATMR:
340 case DS7_REG_SOUNDBTMR:
341 case DS7_REG_SOUNDCTMR:
342 case DS7_REG_SOUNDDTMR:
343 case DS7_REG_SOUNDETMR:
344 case DS7_REG_SOUNDFTMR:
345 DSAudioWriteSOUNDTMR(&ds->audio, (address - DS7_REG_SOUND0TMR) >> 4, value);
346 break;
347 case DS7_REG_SOUND0PNT:
348 case DS7_REG_SOUND1PNT:
349 case DS7_REG_SOUND2PNT:
350 case DS7_REG_SOUND3PNT:
351 case DS7_REG_SOUND4PNT:
352 case DS7_REG_SOUND5PNT:
353 case DS7_REG_SOUND6PNT:
354 case DS7_REG_SOUND7PNT:
355 case DS7_REG_SOUND8PNT:
356 case DS7_REG_SOUND9PNT:
357 case DS7_REG_SOUNDAPNT:
358 case DS7_REG_SOUNDBPNT:
359 case DS7_REG_SOUNDCPNT:
360 case DS7_REG_SOUNDDPNT:
361 case DS7_REG_SOUNDEPNT:
362 case DS7_REG_SOUNDFPNT:
363 DSAudioWriteSOUNDPNT(&ds->audio, (address - DS7_REG_SOUND0PNT) >> 4, value);
364 break;
365 default:
366 {
367 uint32_t v2 = DSIOWrite(&ds->ds7, address, value);
368 if (v2 & 0x10000) {
369 value = v2;
370 break;
371 } else if (v2 & 0x20000) {
372 return;
373 }
374 }
375 if (address >= DS7_IO_BASE_WIFI && address < DS7_IO_END_WIFI) {
376 DSWifiWriteIO(ds, address & 0x7FFF, value);
377 return;
378 }
379 mLOG(DS_IO, STUB, "Stub DS7 I/O register write: %06X:%04X", address, value);
380 if (address >= DS7_REG_MAX) {
381 mLOG(DS_IO, GAME_ERROR, "Write to unused DS7 I/O register: %06X:%04X", address, value);
382 return;
383 }
384 break;
385 }
386 ds->memory.io7[address >> 1] = value;
387}
388
389void DS7IOWrite8(struct DS* ds, uint32_t address, uint8_t value) {
390 if (address == DS7_REG_HALTCNT) {
391 _DSHaltCNT(&ds->ds7, value);
392 return;
393 }
394 if (address < DS7_REG_MAX) {
395 uint16_t value16 = value << (8 * (address & 1));
396 value16 |= (ds->ds7.memory.io[(address & 0xFFF) >> 1]) & ~(0xFF << (8 * (address & 1)));
397 DS7IOWrite(ds, address & 0xFFFFFFFE, value16);
398 } else {
399 mLOG(DS, STUB, "Writing to unknown DS7 register: %08X:%02X", address, value);
400 }
401}
402
403void DS7IOWrite32(struct DS* ds, uint32_t address, uint32_t value) {
404 switch (address) {
405 case DS_REG_DMA0SAD_LO:
406 case DS_REG_DMA1SAD_LO:
407 case DS_REG_DMA2SAD_LO:
408 case DS_REG_DMA3SAD_LO:
409 case DS_REG_DMA0DAD_LO:
410 case DS_REG_DMA1DAD_LO:
411 case DS_REG_DMA2DAD_LO:
412 case DS_REG_DMA3DAD_LO:
413 case DS_REG_IPCFIFOSEND_LO:
414 case DS_REG_IE_LO:
415 value = DSIOWrite32(&ds->ds7, address, value);
416 break;
417
418 case DS_REG_DMA0CNT_LO:
419 DS7DMAWriteCNT(&ds->ds7, 0, value);
420 break;
421 case DS_REG_DMA1CNT_LO:
422 DS7DMAWriteCNT(&ds->ds7, 1, value);
423 break;
424 case DS_REG_DMA2CNT_LO:
425 DS7DMAWriteCNT(&ds->ds7, 2, value);
426 break;
427 case DS_REG_DMA3CNT_LO:
428 DS7DMAWriteCNT(&ds->ds7, 3, value);
429 break;
430
431 case DS7_REG_SOUND0SAD_LO:
432 case DS7_REG_SOUND1SAD_LO:
433 case DS7_REG_SOUND2SAD_LO:
434 case DS7_REG_SOUND3SAD_LO:
435 case DS7_REG_SOUND4SAD_LO:
436 case DS7_REG_SOUND5SAD_LO:
437 case DS7_REG_SOUND6SAD_LO:
438 case DS7_REG_SOUND7SAD_LO:
439 case DS7_REG_SOUND8SAD_LO:
440 case DS7_REG_SOUND9SAD_LO:
441 case DS7_REG_SOUNDASAD_LO:
442 case DS7_REG_SOUNDBSAD_LO:
443 case DS7_REG_SOUNDCSAD_LO:
444 case DS7_REG_SOUNDDSAD_LO:
445 case DS7_REG_SOUNDESAD_LO:
446 case DS7_REG_SOUNDFSAD_LO:
447 DSAudioWriteSOUNDSAD(&ds->audio, (address - DS7_REG_SOUND0SAD_LO) >> 4, value);
448 break;
449
450 case DS7_REG_SOUND0LEN_LO:
451 case DS7_REG_SOUND1LEN_LO:
452 case DS7_REG_SOUND2LEN_LO:
453 case DS7_REG_SOUND3LEN_LO:
454 case DS7_REG_SOUND4LEN_LO:
455 case DS7_REG_SOUND5LEN_LO:
456 case DS7_REG_SOUND6LEN_LO:
457 case DS7_REG_SOUND7LEN_LO:
458 case DS7_REG_SOUND8LEN_LO:
459 case DS7_REG_SOUND9LEN_LO:
460 case DS7_REG_SOUNDALEN_LO:
461 case DS7_REG_SOUNDBLEN_LO:
462 case DS7_REG_SOUNDCLEN_LO:
463 case DS7_REG_SOUNDDLEN_LO:
464 case DS7_REG_SOUNDELEN_LO:
465 case DS7_REG_SOUNDFLEN_LO:
466 value &= 0x3FFFFF;
467 DSAudioWriteSOUNDLEN(&ds->audio, (address - DS7_REG_SOUND0LEN_LO) >> 4, value);
468 break;
469
470 default:
471 DS7IOWrite(ds, address, value & 0xFFFF);
472 DS7IOWrite(ds, address | 2, value >> 16);
473 return;
474 }
475 ds->ds7.memory.io[address >> 1] = value;
476 ds->ds7.memory.io[(address >> 1) + 1] = value >> 16;
477}
478
479uint16_t DS7IORead(struct DS* ds, uint32_t address) {
480 switch (address) {
481 case DS_REG_TM0CNT_LO:
482 case DS_REG_TM1CNT_LO:
483 case DS_REG_TM2CNT_LO:
484 case DS_REG_TM3CNT_LO:
485 DSIOUpdateTimer(&ds->ds7, address);
486 break;
487 case DS_REG_KEYINPUT:
488 return DSIOReadKeyInput(ds);
489 case DS7_REG_EXTKEYIN:
490 return DSIOReadExKeyInput(ds);
491 case DS_REG_VCOUNT:
492 case DS_REG_DMA0CNT_HI:
493 case DS_REG_DMA1CNT_HI:
494 case DS_REG_DMA2CNT_HI:
495 case DS_REG_DMA3CNT_HI:
496 case DS_REG_DMA0FILL_LO:
497 case DS_REG_DMA0FILL_HI:
498 case DS_REG_DMA1FILL_LO:
499 case DS_REG_DMA1FILL_HI:
500 case DS_REG_DMA2FILL_LO:
501 case DS_REG_DMA2FILL_HI:
502 case DS_REG_DMA3FILL_LO:
503 case DS_REG_DMA3FILL_HI:
504 case DS_REG_TM0CNT_HI:
505 case DS_REG_TM1CNT_HI:
506 case DS_REG_TM2CNT_HI:
507 case DS_REG_TM3CNT_HI:
508 case DS7_REG_RTC:
509 case DS7_REG_SPICNT:
510 case DS7_REG_SPIDATA:
511 case DS_REG_IPCSYNC:
512 case DS_REG_IPCFIFOCNT:
513 case DS_REG_ROMCNT_LO:
514 case DS_REG_ROMCNT_HI:
515 case DS_REG_IME:
516 case 0x20A:
517 case DS_REG_IE_LO:
518 case DS_REG_IE_HI:
519 case DS_REG_IF_LO:
520 case DS_REG_IF_HI:
521 case DS_REG_POSTFLG:
522 case DS7_REG_SOUND0CNT_LO:
523 case DS7_REG_SOUND1CNT_LO:
524 case DS7_REG_SOUND2CNT_LO:
525 case DS7_REG_SOUND3CNT_LO:
526 case DS7_REG_SOUND4CNT_LO:
527 case DS7_REG_SOUND5CNT_LO:
528 case DS7_REG_SOUND6CNT_LO:
529 case DS7_REG_SOUND7CNT_LO:
530 case DS7_REG_SOUND8CNT_LO:
531 case DS7_REG_SOUND9CNT_LO:
532 case DS7_REG_SOUNDACNT_LO:
533 case DS7_REG_SOUNDBCNT_LO:
534 case DS7_REG_SOUNDCCNT_LO:
535 case DS7_REG_SOUNDDCNT_LO:
536 case DS7_REG_SOUNDECNT_LO:
537 case DS7_REG_SOUNDFCNT_LO:
538 case DS7_REG_SOUND0CNT_HI:
539 case DS7_REG_SOUND1CNT_HI:
540 case DS7_REG_SOUND2CNT_HI:
541 case DS7_REG_SOUND3CNT_HI:
542 case DS7_REG_SOUND4CNT_HI:
543 case DS7_REG_SOUND5CNT_HI:
544 case DS7_REG_SOUND6CNT_HI:
545 case DS7_REG_SOUND7CNT_HI:
546 case DS7_REG_SOUND8CNT_HI:
547 case DS7_REG_SOUND9CNT_HI:
548 case DS7_REG_SOUNDACNT_HI:
549 case DS7_REG_SOUNDBCNT_HI:
550 case DS7_REG_SOUNDCCNT_HI:
551 case DS7_REG_SOUNDDCNT_HI:
552 case DS7_REG_SOUNDECNT_HI:
553 case DS7_REG_SOUNDFCNT_HI:
554 // Handled transparently by the registers
555 break;
556 case DS_REG_AUXSPICNT:
557 case DS_REG_AUXSPIDATA:
558 if (ds->ds7.memory.slot1Access) {
559 break;
560 } else {
561 mLOG(DS_IO, GAME_ERROR, "Invalid cart access");
562 return 0;
563 }
564 default:
565 if (address >= DS7_IO_BASE_WIFI && address < DS7_IO_END_WIFI) {
566 return DSWifiReadIO(ds, address & 0x7FFF);
567 }
568 mLOG(DS_IO, STUB, "Stub DS7 I/O register read: %06X", address);
569 }
570 if (address < DS7_REG_MAX) {
571 return ds->memory.io7[address >> 1];
572 }
573
574 return 0;
575}
576
577uint32_t DS7IORead32(struct DS* ds, uint32_t address) {
578 switch (address) {
579 case DS_REG_IPCFIFORECV_LO:
580 return DSIPCReadFIFO(&ds->ds7);
581 case DS_REG_ROMDATA_0:
582 if (ds->ds7.memory.slot1Access) {
583 return DSSlot1Read(ds);
584 } else {
585 mLOG(DS_IO, GAME_ERROR, "Invalid cart access");
586 return 0;
587 }
588 default:
589 return DS7IORead(ds, address & 0x00FFFFFC) | (DS7IORead(ds, (address & 0x00FFFFFC) | 2) << 16);
590 }
591}
592
593void DS9IOInit(struct DS* ds) {
594 memset(ds->memory.io9, 0, sizeof(ds->memory.io9));
595 ds->memory.io9[DS_REG_IPCFIFOCNT >> 1] = 0x0101;
596 ds->memory.io9[DS_REG_POSTFLG >> 1] = 0x0001;
597 ds->memory.io9[DS9_REG_GXSTAT_HI >> 1] = 0x0600;
598 DS9IOWrite(ds, DS9_REG_VRAMCNT_G, 0x0300);
599 DS9IOWrite(ds, DS9_REG_POWCNT1, 0x0001);
600}
601
602void DS9IOWrite(struct DS* ds, uint32_t address, uint16_t value) {
603 if ((address <= DS9_REG_A_BLDY && address > DS_REG_VCOUNT) || address == DS9_REG_A_DISPCNT_LO || address == DS9_REG_A_DISPCNT_HI || address == DS9_REG_A_MASTER_BRIGHT) {
604 value = ds->video.renderer->writeVideoRegister(ds->video.renderer, address, value);
605 } else if ((address >= DS9_REG_B_DISPCNT_LO && address <= DS9_REG_B_BLDY) || address == DS9_REG_B_MASTER_BRIGHT) {
606 value = ds->video.renderer->writeVideoRegister(ds->video.renderer, address, value);
607 } else if ((address >= DS9_REG_RDLINES_COUNT && address <= DS9_REG_VECMTX_RESULT_12) || address == DS9_REG_DISP3DCNT) {
608 value = DSGXWriteRegister(&ds->gx, address, value);
609 } else {
610 uint16_t oldValue;
611 switch (address) {
612 // DMA
613 case DS_REG_DMA0CNT_HI:
614 DS9DMAWriteCNT(&ds->ds9, 0, (value << 16) | ds->ds9.memory.io[(address - 2) >> 1]);
615 break;
616 case DS_REG_DMA1CNT_HI:
617 DS9DMAWriteCNT(&ds->ds9, 1, (value << 16) | ds->ds9.memory.io[(address - 2) >> 1]);
618 break;
619 case DS_REG_DMA2CNT_HI:
620 DS9DMAWriteCNT(&ds->ds9, 2, (value << 16) | ds->ds9.memory.io[(address - 2) >> 1]);
621 break;
622 case DS_REG_DMA3CNT_HI:
623 DS9DMAWriteCNT(&ds->ds9, 3, (value << 16) | ds->ds9.memory.io[(address - 2) >> 1]);
624 break;
625
626 // Other video
627 case DS9_REG_DISPCAPCNT_LO:
628 value &= 0x1F1F;
629 break;
630 case DS9_REG_DISPCAPCNT_HI:
631 value &= 0xEF3F;
632 break;
633
634 // VRAM control
635 case DS9_REG_VRAMCNT_A:
636 case DS9_REG_VRAMCNT_C:
637 case DS9_REG_VRAMCNT_E:
638 oldValue = ds->memory.io9[address >> 1];
639 value &= 0x9F9F;
640 DSVideoConfigureVRAM(ds, address - DS9_REG_VRAMCNT_A, value & 0xFF, oldValue & 0xFF);
641 DSVideoConfigureVRAM(ds, address - DS9_REG_VRAMCNT_A + 1, value >> 8, oldValue >> 8);
642 break;
643 case DS9_REG_VRAMCNT_G:
644 oldValue = ds->memory.io9[address >> 1];
645 value &= 0x039F;
646 DSVideoConfigureVRAM(ds, 6, value & 0xFF, oldValue & 0xFF);
647 DSConfigureWRAM(&ds->memory, value >> 8);
648 break;
649 case DS9_REG_VRAMCNT_H:
650 oldValue = ds->memory.io9[address >> 1];
651 value &= 0x9F9F;
652 DSVideoConfigureVRAM(ds, 7, value & 0xFF, oldValue & 0xFF);
653 DSVideoConfigureVRAM(ds, 8, value >> 8, oldValue >> 8);
654 break;
655
656 case DS9_REG_EXMEMCNT:
657 value &= 0xE8FF;
658 DSConfigureExternalMemory(ds, value);
659 break;
660
661 // Math
662 case DS9_REG_DIVCNT:
663 value = _scheduleDiv(ds, value);
664 break;
665 case DS9_REG_DIV_NUMER_0:
666 case DS9_REG_DIV_NUMER_1:
667 case DS9_REG_DIV_NUMER_2:
668 case DS9_REG_DIV_NUMER_3:
669 case DS9_REG_DIV_DENOM_0:
670 case DS9_REG_DIV_DENOM_1:
671 case DS9_REG_DIV_DENOM_2:
672 case DS9_REG_DIV_DENOM_3:
673 ds->memory.io9[DS9_REG_DIVCNT >> 1] = _scheduleDiv(ds, ds->memory.io9[DS9_REG_DIVCNT >> 1]);
674 break;
675 case DS9_REG_SQRTCNT:
676 value = _scheduleSqrt(ds, value);
677 break;
678 case DS9_REG_SQRT_PARAM_0:
679 case DS9_REG_SQRT_PARAM_1:
680 case DS9_REG_SQRT_PARAM_2:
681 case DS9_REG_SQRT_PARAM_3:
682 ds->memory.io9[DS9_REG_SQRTCNT >> 1] = _scheduleSqrt(ds, ds->memory.io9[DS9_REG_SQRTCNT >> 1]);
683 break;
684
685 // High Video
686 case DS9_REG_POWCNT1:
687 value = ds->video.renderer->writeVideoRegister(ds->video.renderer, address, value);
688 break;
689
690 default:
691 {
692 uint32_t v2 = DSIOWrite(&ds->ds9, address, value);
693 if (v2 & 0x10000) {
694 value = v2;
695 break;
696 } else if (v2 & 0x20000) {
697 return;
698 }
699 }
700 mLOG(DS_IO, STUB, "Stub DS9 I/O register write: %06X:%04X", address, value);
701 if (address >= DS7_REG_MAX) {
702 mLOG(DS_IO, GAME_ERROR, "Write to unused DS9 I/O register: %06X:%04X", address, value);
703 return;
704 }
705 break;
706 }
707 }
708 ds->memory.io9[address >> 1] = value;
709}
710
711void DS9IOWrite8(struct DS* ds, uint32_t address, uint8_t value) {
712 if (address < DS9_REG_MAX) {
713 uint16_t value16 = value << (8 * (address & 1));
714 value16 |= (ds->memory.io9[(address & 0x1FFF) >> 1]) & ~(0xFF << (8 * (address & 1)));
715 DS9IOWrite(ds, address & 0xFFFFFFFE, value16);
716 } else {
717 mLOG(DS, STUB, "Writing to unknown DS9 register: %08X:%02X", address, value);
718 }
719}
720
721void DS9IOWrite32(struct DS* ds, uint32_t address, uint32_t value) {
722 if ((address >= DS9_REG_RDLINES_COUNT && address <= DS9_REG_VECMTX_RESULT_12) || address == DS9_REG_DISP3DCNT) {
723 value = DSGXWriteRegister32(&ds->gx, address, value);
724 } else {
725 switch (address) {
726 case DS_REG_DMA0SAD_LO:
727 case DS_REG_DMA1SAD_LO:
728 case DS_REG_DMA2SAD_LO:
729 case DS_REG_DMA3SAD_LO:
730 case DS_REG_DMA0DAD_LO:
731 case DS_REG_DMA1DAD_LO:
732 case DS_REG_DMA2DAD_LO:
733 case DS_REG_DMA3DAD_LO:
734 case DS_REG_IPCFIFOSEND_LO:
735 case DS_REG_IE_LO:
736 value = DSIOWrite32(&ds->ds9, address, value);
737 break;
738
739 case DS_REG_DMA0CNT_LO:
740 DS9DMAWriteCNT(&ds->ds9, 0, value);
741 break;
742 case DS_REG_DMA1CNT_LO:
743 DS9DMAWriteCNT(&ds->ds9, 1, value);
744 break;
745 case DS_REG_DMA2CNT_LO:
746 DS9DMAWriteCNT(&ds->ds9, 2, value);
747 break;
748 case DS_REG_DMA3CNT_LO:
749 DS9DMAWriteCNT(&ds->ds9, 3, value);
750 break;
751
752 default:
753 DS9IOWrite(ds, address, value & 0xFFFF);
754 DS9IOWrite(ds, address | 2, value >> 16);
755 return;
756 }
757 }
758 ds->ds9.memory.io[address >> 1] = value;
759 ds->ds9.memory.io[(address >> 1) + 1] = value >> 16;
760}
761
762uint16_t DS9IORead(struct DS* ds, uint32_t address) {
763 switch (address) {
764 case DS_REG_TM0CNT_LO:
765 case DS_REG_TM1CNT_LO:
766 case DS_REG_TM2CNT_LO:
767 case DS_REG_TM3CNT_LO:
768 DSIOUpdateTimer(&ds->ds9, address);
769 break;
770 case DS_REG_KEYINPUT:
771 return DSIOReadKeyInput(ds);
772 case DS_REG_VCOUNT:
773 case DS_REG_DMA0CNT_HI:
774 case DS_REG_DMA1CNT_HI:
775 case DS_REG_DMA2CNT_HI:
776 case DS_REG_DMA3CNT_HI:
777 case DS_REG_DMA0FILL_LO:
778 case DS_REG_DMA0FILL_HI:
779 case DS_REG_DMA1FILL_LO:
780 case DS_REG_DMA1FILL_HI:
781 case DS_REG_DMA2FILL_LO:
782 case DS_REG_DMA2FILL_HI:
783 case DS_REG_DMA3FILL_LO:
784 case DS_REG_DMA3FILL_HI:
785 case DS_REG_TM0CNT_HI:
786 case DS_REG_TM1CNT_HI:
787 case DS_REG_TM2CNT_HI:
788 case DS_REG_TM3CNT_HI:
789 case DS_REG_IPCSYNC:
790 case DS_REG_IPCFIFOCNT:
791 case DS_REG_ROMCNT_LO:
792 case DS_REG_ROMCNT_HI:
793 case DS_REG_IME:
794 case 0x20A:
795 case DS_REG_IE_LO:
796 case DS_REG_IE_HI:
797 case DS_REG_IF_LO:
798 case DS_REG_IF_HI:
799 case DS9_REG_DIVCNT:
800 case 0x282:
801 case DS9_REG_DIV_NUMER_0:
802 case DS9_REG_DIV_NUMER_1:
803 case DS9_REG_DIV_NUMER_2:
804 case DS9_REG_DIV_NUMER_3:
805 case DS9_REG_DIV_DENOM_0:
806 case DS9_REG_DIV_DENOM_1:
807 case DS9_REG_DIV_DENOM_2:
808 case DS9_REG_DIV_DENOM_3:
809 case DS9_REG_DIV_RESULT_0:
810 case DS9_REG_DIV_RESULT_1:
811 case DS9_REG_DIV_RESULT_2:
812 case DS9_REG_DIV_RESULT_3:
813 case DS9_REG_DIVREM_RESULT_0:
814 case DS9_REG_DIVREM_RESULT_1:
815 case DS9_REG_DIVREM_RESULT_2:
816 case DS9_REG_DIVREM_RESULT_3:
817 case DS9_REG_SQRTCNT:
818 case DS9_REG_SQRT_PARAM_0:
819 case DS9_REG_SQRT_PARAM_1:
820 case DS9_REG_SQRT_PARAM_2:
821 case DS9_REG_SQRT_PARAM_3:
822 case DS9_REG_SQRT_RESULT_LO:
823 case DS9_REG_SQRT_RESULT_HI:
824 case DS_REG_POSTFLG:
825 case DS9_REG_TOON_TABLE_00:
826 case DS9_REG_TOON_TABLE_01:
827 case DS9_REG_TOON_TABLE_02:
828 case DS9_REG_TOON_TABLE_03:
829 case DS9_REG_TOON_TABLE_04:
830 case DS9_REG_TOON_TABLE_05:
831 case DS9_REG_TOON_TABLE_06:
832 case DS9_REG_TOON_TABLE_07:
833 case DS9_REG_TOON_TABLE_08:
834 case DS9_REG_TOON_TABLE_09:
835 case DS9_REG_TOON_TABLE_0A:
836 case DS9_REG_TOON_TABLE_0B:
837 case DS9_REG_TOON_TABLE_0C:
838 case DS9_REG_TOON_TABLE_0D:
839 case DS9_REG_TOON_TABLE_0E:
840 case DS9_REG_TOON_TABLE_0F:
841 case DS9_REG_TOON_TABLE_10:
842 case DS9_REG_TOON_TABLE_11:
843 case DS9_REG_TOON_TABLE_12:
844 case DS9_REG_TOON_TABLE_13:
845 case DS9_REG_TOON_TABLE_14:
846 case DS9_REG_TOON_TABLE_15:
847 case DS9_REG_TOON_TABLE_16:
848 case DS9_REG_TOON_TABLE_17:
849 case DS9_REG_TOON_TABLE_18:
850 case DS9_REG_TOON_TABLE_19:
851 case DS9_REG_TOON_TABLE_1A:
852 case DS9_REG_TOON_TABLE_1B:
853 case DS9_REG_TOON_TABLE_1C:
854 case DS9_REG_TOON_TABLE_1D:
855 case DS9_REG_TOON_TABLE_1E:
856 case DS9_REG_TOON_TABLE_1F:
857 case DS9_REG_GXSTAT_LO:
858 case DS9_REG_GXSTAT_HI:
859 case DS9_REG_CLIPMTX_RESULT_00:
860 case DS9_REG_CLIPMTX_RESULT_01:
861 case DS9_REG_CLIPMTX_RESULT_02:
862 case DS9_REG_CLIPMTX_RESULT_03:
863 case DS9_REG_CLIPMTX_RESULT_04:
864 case DS9_REG_CLIPMTX_RESULT_05:
865 case DS9_REG_CLIPMTX_RESULT_06:
866 case DS9_REG_CLIPMTX_RESULT_07:
867 case DS9_REG_CLIPMTX_RESULT_08:
868 case DS9_REG_CLIPMTX_RESULT_09:
869 case DS9_REG_CLIPMTX_RESULT_0A:
870 case DS9_REG_CLIPMTX_RESULT_0B:
871 case DS9_REG_CLIPMTX_RESULT_0C:
872 case DS9_REG_CLIPMTX_RESULT_0D:
873 case DS9_REG_CLIPMTX_RESULT_0E:
874 case DS9_REG_CLIPMTX_RESULT_0F:
875 case DS9_REG_CLIPMTX_RESULT_10:
876 case DS9_REG_CLIPMTX_RESULT_11:
877 case DS9_REG_CLIPMTX_RESULT_12:
878 case DS9_REG_CLIPMTX_RESULT_13:
879 case DS9_REG_CLIPMTX_RESULT_14:
880 case DS9_REG_CLIPMTX_RESULT_15:
881 case DS9_REG_CLIPMTX_RESULT_16:
882 case DS9_REG_CLIPMTX_RESULT_17:
883 case DS9_REG_CLIPMTX_RESULT_18:
884 case DS9_REG_CLIPMTX_RESULT_19:
885 case DS9_REG_CLIPMTX_RESULT_1A:
886 case DS9_REG_CLIPMTX_RESULT_1B:
887 case DS9_REG_CLIPMTX_RESULT_1C:
888 case DS9_REG_CLIPMTX_RESULT_1D:
889 case DS9_REG_CLIPMTX_RESULT_1E:
890 case DS9_REG_CLIPMTX_RESULT_1F:
891 // Handled transparently by the registers
892 break;
893 case DS_REG_AUXSPICNT:
894 case DS_REG_AUXSPIDATA:
895 if (ds->ds9.memory.slot1Access) {
896 break;
897 } else {
898 mLOG(DS_IO, GAME_ERROR, "Invalid cart access");
899 return 0;
900 }
901 default:
902 mLOG(DS_IO, STUB, "Stub DS9 I/O register read: %06X", address);
903 }
904 if (address < DS9_REG_MAX) {
905 return ds->ds9.memory.io[address >> 1];
906 }
907 return 0;
908}
909
910uint32_t DS9IORead32(struct DS* ds, uint32_t address) {
911 switch (address) {
912 case DS_REG_IPCFIFORECV_LO:
913 return DSIPCReadFIFO(&ds->ds9);
914 case DS_REG_ROMDATA_0:
915 if (ds->ds9.memory.slot1Access) {
916 return DSSlot1Read(ds);
917 } else {
918 mLOG(DS_IO, GAME_ERROR, "Invalid cart access");
919 return 0;
920 }
921 default:
922 return DS9IORead(ds, address & 0x00FFFFFC) | (DS9IORead(ds, (address & 0x00FFFFFC) | 2) << 16);
923 }
924}