src/ds/io.c (view raw)
1/* Copyright (c) 2013-2016 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/ds.h>
10#include <mgba/internal/ds/gx.h>
11#include <mgba/internal/ds/ipc.h>
12#include <mgba/internal/ds/slot1.h>
13#include <mgba/internal/ds/spi.h>
14
15mLOG_DEFINE_CATEGORY(DS_IO, "DS I/O", "ds.io");
16
17static void _DSHaltCNT(struct DSCommon* dscore, uint8_t value) {
18 switch (value >> 6) {
19 case 0:
20 default:
21 break;
22 case 1:
23 mLOG(DS_IO, STUB, "Enter GBA mode not supported");
24 break;
25 case 2:
26 ARMHalt(dscore->cpu);
27 break;
28 case 3:
29 mLOG(DS_IO, STUB, "Enter sleep mode not supported");
30 break;
31 }
32}
33
34static uint16_t _scheduleDiv(struct DS* ds, uint16_t control) {
35 mTimingDeschedule(&ds->ds9.timing, &ds->divEvent);
36 mTimingSchedule(&ds->ds9.timing, &ds->divEvent, (control & 3) ? 36 : 68);
37 return control | 0x8000;
38}
39
40static uint16_t _scheduleSqrt(struct DS* ds, uint16_t control) {
41 mTimingDeschedule(&ds->ds9.timing, &ds->sqrtEvent);
42 mTimingSchedule(&ds->ds9.timing, &ds->sqrtEvent, 26);
43 return control | 0x8000;
44}
45
46static uint32_t DSIOWrite(struct DSCommon* dscore, uint32_t address, uint16_t value) {
47 switch (address) {
48 // Video
49 case DS_REG_DISPSTAT:
50 DSVideoWriteDISPSTAT(dscore, value);
51 break;
52
53 // DMA Fill
54 case DS_REG_DMA0FILL_LO:
55 case DS_REG_DMA0FILL_HI:
56 case DS_REG_DMA1FILL_LO:
57 case DS_REG_DMA1FILL_HI:
58 case DS_REG_DMA2FILL_LO:
59 case DS_REG_DMA2FILL_HI:
60 case DS_REG_DMA3FILL_LO:
61 case DS_REG_DMA3FILL_HI:
62 break;
63
64 // Timers
65 case DS_REG_TM0CNT_LO:
66 GBATimerWriteTMCNT_LO(&dscore->timers[0], value);
67 return 0x20000;
68 case DS_REG_TM1CNT_LO:
69 GBATimerWriteTMCNT_LO(&dscore->timers[1], value);
70 return 0x20000;
71 case DS_REG_TM2CNT_LO:
72 GBATimerWriteTMCNT_LO(&dscore->timers[2], value);
73 return 0x20000;
74 case DS_REG_TM3CNT_LO:
75 GBATimerWriteTMCNT_LO(&dscore->timers[3], value);
76 return 0x20000;
77
78 case DS_REG_TM0CNT_HI:
79 value &= 0x00C7;
80 DSTimerWriteTMCNT_HI(&dscore->timers[0], &dscore->timing, dscore->cpu, &dscore->memory.io[DS_REG_TM0CNT_LO >> 1], value);
81 break;
82 case DS_REG_TM1CNT_HI:
83 value &= 0x00C7;
84 DSTimerWriteTMCNT_HI(&dscore->timers[1], &dscore->timing, dscore->cpu, &dscore->memory.io[DS_REG_TM1CNT_LO >> 1], value);
85 break;
86 case DS_REG_TM2CNT_HI:
87 value &= 0x00C7;
88 DSTimerWriteTMCNT_HI(&dscore->timers[2], &dscore->timing, dscore->cpu, &dscore->memory.io[DS_REG_TM2CNT_LO >> 1], value);
89 break;
90 case DS_REG_TM3CNT_HI:
91 value &= 0x00C7;
92 DSTimerWriteTMCNT_HI(&dscore->timers[3], &dscore->timing, dscore->cpu, &dscore->memory.io[DS_REG_TM3CNT_LO >> 1], value);
93 break;
94
95 // IPC
96 case DS_REG_IPCSYNC:
97 value &= 0x6F00;
98 value |= dscore->memory.io[address >> 1] & 0x000F;
99 DSIPCWriteSYNC(dscore->ipc->cpu, dscore->ipc->memory.io, value);
100 break;
101 case DS_REG_IPCFIFOCNT:
102 value = DSIPCWriteFIFOCNT(dscore, value);
103 break;
104
105 // Cart bus
106 case DS_REG_AUXSPICNT:
107 if (dscore->memory.slot1Access) {
108 value = DSSlot1Configure(dscore->p, value);
109 dscore->ipc->memory.io[address >> 1] = value;
110 } else {
111 mLOG(DS_IO, GAME_ERROR, "Invalid cart access");
112 return 0;
113 }
114 break;
115 case DS_REG_AUXSPIDATA:
116 if (dscore->memory.slot1Access) {
117 DSSlot1WriteSPI(dscore, value);
118 dscore->ipc->memory.io[address >> 1] = value;
119 } else {
120 mLOG(DS_IO, GAME_ERROR, "Invalid cart access");
121 return 0;
122 }
123 break;
124 case DS_REG_ROMCNT_HI:
125 if (dscore->memory.slot1Access) {
126 DSSlot1ROMCNT cnt = value << 16;
127 cnt |= dscore->memory.io[(address - 2) >> 1];
128 cnt = DSSlot1Control(dscore->p, cnt);
129 value = cnt >> 16;
130 dscore->ipc->memory.io[address >> 1] = value;
131 } else {
132 mLOG(DS_IO, GAME_ERROR, "Invalid cart access");
133 return 0;
134 }
135 break;
136 case DS_REG_ROMCNT_LO:
137 case DS_REG_ROMCMD_0:
138 case DS_REG_ROMCMD_2:
139 case DS_REG_ROMCMD_4:
140 case DS_REG_ROMCMD_6:
141 if (dscore->memory.slot1Access) {
142 dscore->ipc->memory.io[address >> 1] = value;
143 } else {
144 mLOG(DS_IO, GAME_ERROR, "Invalid cart access");
145 return 0;
146 }
147 break;
148
149 // Interrupts
150 case DS_REG_IME:
151 DSWriteIME(dscore->cpu, dscore->memory.io, value);
152 break;
153 case 0x20A:
154 value = 0;
155 // Some bad interrupt libraries will write to this
156 break;
157 case DS_REG_IF_LO:
158 case DS_REG_IF_HI:
159 value = dscore->memory.io[address >> 1] & ~value;
160 DSGXUpdateGXSTAT(&dscore->p->gx);
161 break;
162 default:
163 return 0;
164 }
165 return value | 0x10000;
166}
167
168uint32_t DSIOWrite32(struct DSCommon* dscore, uint32_t address, uint32_t value) {
169 switch (address) {
170 case DS_REG_DMA0SAD_LO:
171 value = DSDMAWriteSAD(dscore, 0, value);
172 break;
173 case DS_REG_DMA1SAD_LO:
174 value = DSDMAWriteSAD(dscore, 1, value);
175 break;
176 case DS_REG_DMA2SAD_LO:
177 value = DSDMAWriteSAD(dscore, 2, value);
178 break;
179 case DS_REG_DMA3SAD_LO:
180 value = DSDMAWriteSAD(dscore, 3, value);
181 break;
182
183 case DS_REG_DMA0DAD_LO:
184 value = DSDMAWriteDAD(dscore, 0, value);
185 break;
186 case DS_REG_DMA1DAD_LO:
187 value = DSDMAWriteDAD(dscore, 1, value);
188 break;
189 case DS_REG_DMA2DAD_LO:
190 value = DSDMAWriteDAD(dscore, 2, value);
191 break;
192 case DS_REG_DMA3DAD_LO:
193 value = DSDMAWriteDAD(dscore, 3, value);
194 break;
195
196 case DS_REG_IPCFIFOSEND_LO:
197 DSIPCWriteFIFO(dscore, value);
198 break;
199 case DS_REG_IE_LO:
200 DSWriteIE(dscore->cpu, dscore->memory.io, value);
201 break;
202 }
203
204 return value;
205}
206
207static uint16_t DSIOReadExKeyInput(struct DS* ds) {
208 uint16_t input = 0;
209 if (ds->keyCallback) {
210 input = ds->keyCallback->readKeys(ds->keyCallback);
211 } else if (ds->keySource) {
212 input = *ds->keySource;
213 }
214 input = ~(input >> 10) & 0x3;
215 input |= 0x3C;
216 input |= ds->memory.io7[DS7_REG_EXTKEYIN >> 1] & 0xC0;
217 return input;
218}
219
220static uint16_t DSIOReadKeyInput(struct DS* ds) {
221 uint16_t input = 0;
222 if (ds->keyCallback) {
223 input = ds->keyCallback->readKeys(ds->keyCallback);
224 } else if (ds->keySource) {
225 input = *ds->keySource;
226 }
227 // TODO: Put back
228 /*if (!dscore->p->allowOpposingDirections) {
229 unsigned rl = input & 0x030;
230 unsigned ud = input & 0x0C0;
231 input &= 0x30F;
232 if (rl != 0x030) {
233 input |= rl;
234 }
235 if (ud != 0x0C0) {
236 input |= ud;
237 }
238 }*/
239 return ~input & 0x3FF;
240}
241
242static void DSIOUpdateTimer(struct DSCommon* dscore, uint32_t address) {
243 switch (address) {
244 case DS_REG_TM0CNT_LO:
245 GBATimerUpdateRegisterInternal(&dscore->timers[0], &dscore->timing, dscore->cpu, &dscore->memory.io[address >> 1], 0);
246 break;
247 case DS_REG_TM1CNT_LO:
248 GBATimerUpdateRegisterInternal(&dscore->timers[1], &dscore->timing, dscore->cpu, &dscore->memory.io[address >> 1], 0);
249 break;
250 case DS_REG_TM2CNT_LO:
251 GBATimerUpdateRegisterInternal(&dscore->timers[2], &dscore->timing, dscore->cpu, &dscore->memory.io[address >> 1], 0);
252 break;
253 case DS_REG_TM3CNT_LO:
254 GBATimerUpdateRegisterInternal(&dscore->timers[3], &dscore->timing, dscore->cpu, &dscore->memory.io[address >> 1], 0);
255 break;
256 }
257}
258
259void DS7IOInit(struct DS* ds) {
260 memset(ds->memory.io7, 0, sizeof(ds->memory.io7));
261 ds->memory.io7[DS_REG_IPCFIFOCNT >> 1] = 0x0101;
262 ds->memory.io7[DS_REG_POSTFLG >> 1] = 0x0001;
263 ds->memory.io7[DS7_REG_EXTKEYIN >> 1] = 0x007F;
264}
265
266void DS7IOWrite(struct DS* ds, uint32_t address, uint16_t value) {
267 switch (address) {
268 case DS7_REG_SPICNT:
269 value &= 0xCF83;
270 value = DSSPIWriteControl(ds, value);
271 break;
272 case DS7_REG_SPIDATA:
273 DSSPIWrite(ds, value);
274 break;
275 default:
276 {
277 uint32_t v2 = DSIOWrite(&ds->ds7, address, value);
278 if (v2 & 0x10000) {
279 value = v2;
280 break;
281 } else if (v2 & 0x20000) {
282 return;
283 }
284 }
285 if (address >= DS7_IO_BASE_WIFI && address < DS7_IO_END_WIFI) {
286 DSWifiWriteIO(ds, address & 0x7FFF, value);
287 return;
288 }
289 mLOG(DS_IO, STUB, "Stub DS7 I/O register write: %06X:%04X", address, value);
290 if (address >= DS7_REG_MAX) {
291 mLOG(DS_IO, GAME_ERROR, "Write to unused DS7 I/O register: %06X:%04X", address, value);
292 return;
293 }
294 break;
295 }
296 ds->memory.io7[address >> 1] = value;
297}
298
299void DS7IOWrite8(struct DS* ds, uint32_t address, uint8_t value) {
300 if (address == DS7_REG_HALTCNT) {
301 _DSHaltCNT(&ds->ds7, value);
302 return;
303 }
304 if (address < DS7_REG_MAX) {
305 uint16_t value16 = value << (8 * (address & 1));
306 value16 |= (ds->ds7.memory.io[(address & 0xFFF) >> 1]) & ~(0xFF << (8 * (address & 1)));
307 DS7IOWrite(ds, address & 0xFFFFFFFE, value16);
308 } else {
309 mLOG(DS, STUB, "Writing to unknown DS7 register: %08X:%02X", address, value);
310 }
311}
312
313void DS7IOWrite32(struct DS* ds, uint32_t address, uint32_t value) {
314 switch (address) {
315 case DS_REG_DMA0SAD_LO:
316 case DS_REG_DMA1SAD_LO:
317 case DS_REG_DMA2SAD_LO:
318 case DS_REG_DMA3SAD_LO:
319 case DS_REG_DMA0DAD_LO:
320 case DS_REG_DMA1DAD_LO:
321 case DS_REG_DMA2DAD_LO:
322 case DS_REG_DMA3DAD_LO:
323 case DS_REG_IPCFIFOSEND_LO:
324 case DS_REG_IE_LO:
325 value = DSIOWrite32(&ds->ds7, address, value);
326 break;
327
328 case DS_REG_DMA0CNT_LO:
329 DS7DMAWriteCNT(&ds->ds7, 0, value);
330 break;
331 case DS_REG_DMA1CNT_LO:
332 DS7DMAWriteCNT(&ds->ds7, 1, value);
333 break;
334 case DS_REG_DMA2CNT_LO:
335 DS7DMAWriteCNT(&ds->ds7, 2, value);
336 break;
337 case DS_REG_DMA3CNT_LO:
338 DS7DMAWriteCNT(&ds->ds7, 3, value);
339 break;
340 default:
341 DS7IOWrite(ds, address, value & 0xFFFF);
342 DS7IOWrite(ds, address | 2, value >> 16);
343 return;
344 }
345 ds->ds7.memory.io[address >> 1] = value;
346 ds->ds7.memory.io[(address >> 1) + 1] = value >> 16;
347}
348
349uint16_t DS7IORead(struct DS* ds, uint32_t address) {
350 switch (address) {
351 case DS_REG_TM0CNT_LO:
352 case DS_REG_TM1CNT_LO:
353 case DS_REG_TM2CNT_LO:
354 case DS_REG_TM3CNT_LO:
355 DSIOUpdateTimer(&ds->ds7, address);
356 break;
357 case DS_REG_KEYINPUT:
358 return DSIOReadKeyInput(ds);
359 case DS7_REG_EXTKEYIN:
360 return DSIOReadExKeyInput(ds);
361 case DS_REG_VCOUNT:
362 case DS_REG_DMA0FILL_LO:
363 case DS_REG_DMA0FILL_HI:
364 case DS_REG_DMA1FILL_LO:
365 case DS_REG_DMA1FILL_HI:
366 case DS_REG_DMA2FILL_LO:
367 case DS_REG_DMA2FILL_HI:
368 case DS_REG_DMA3FILL_LO:
369 case DS_REG_DMA3FILL_HI:
370 case DS_REG_TM0CNT_HI:
371 case DS_REG_TM1CNT_HI:
372 case DS_REG_TM2CNT_HI:
373 case DS_REG_TM3CNT_HI:
374 case DS7_REG_SPICNT:
375 case DS7_REG_SPIDATA:
376 case DS_REG_IPCSYNC:
377 case DS_REG_IPCFIFOCNT:
378 case DS_REG_ROMCNT_LO:
379 case DS_REG_ROMCNT_HI:
380 case DS_REG_IME:
381 case 0x20A:
382 case DS_REG_IE_LO:
383 case DS_REG_IE_HI:
384 case DS_REG_IF_LO:
385 case DS_REG_IF_HI:
386 case DS_REG_POSTFLG:
387 // Handled transparently by the registers
388 break;
389 case DS_REG_AUXSPICNT:
390 case DS_REG_AUXSPIDATA:
391 if (ds->ds7.memory.slot1Access) {
392 break;
393 } else {
394 mLOG(DS_IO, GAME_ERROR, "Invalid cart access");
395 return 0;
396 }
397 default:
398 if (address >= DS7_IO_BASE_WIFI && address < DS7_IO_END_WIFI) {
399 return DSWifiReadIO(ds, address & 0x7FFF);
400 }
401 mLOG(DS_IO, STUB, "Stub DS7 I/O register read: %06X", address);
402 }
403 if (address < DS7_REG_MAX) {
404 return ds->memory.io7[address >> 1];
405 }
406
407 return 0;
408}
409
410uint32_t DS7IORead32(struct DS* ds, uint32_t address) {
411 switch (address) {
412 case DS_REG_IPCFIFORECV_LO:
413 return DSIPCReadFIFO(&ds->ds7);
414 case DS_REG_ROMDATA_0:
415 if (ds->ds7.memory.slot1Access) {
416 return DSSlot1Read(ds);
417 } else {
418 mLOG(DS_IO, GAME_ERROR, "Invalid cart access");
419 return 0;
420 }
421 default:
422 return DS7IORead(ds, address & 0x00FFFFFC) | (DS7IORead(ds, (address & 0x00FFFFFC) | 2) << 16);
423 }
424}
425
426void DS9IOInit(struct DS* ds) {
427 memset(ds->memory.io9, 0, sizeof(ds->memory.io9));
428 ds->memory.io9[DS_REG_IPCFIFOCNT >> 1] = 0x0101;
429 ds->memory.io9[DS_REG_POSTFLG >> 1] = 0x0001;
430 ds->memory.io9[DS9_REG_GXSTAT_HI >> 1] = 0x0600;
431 DS9IOWrite(ds, DS9_REG_VRAMCNT_G, 0x0300);
432}
433
434void DS9IOWrite(struct DS* ds, uint32_t address, uint16_t value) {
435 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) {
436 value = ds->video.renderer->writeVideoRegister(ds->video.renderer, address, value);
437 } else if ((address >= DS9_REG_B_DISPCNT_LO && address <= DS9_REG_B_BLDY) || address == DS9_REG_B_MASTER_BRIGHT) {
438 value = ds->video.renderer->writeVideoRegister(ds->video.renderer, address, value);
439 } else if ((address >= DS9_REG_RDLINES_COUNT && address <= DS9_REG_VECMTX_RESULT_12) || address == DS9_REG_DISP3DCNT) {
440 value = DSGXWriteRegister(&ds->gx, address, value);
441 } else {
442 uint16_t oldValue;
443 switch (address) {
444 // Other video
445 case DS9_REG_DISPCAPCNT_LO:
446 value &= 0x1F1F;
447 break;
448 case DS9_REG_DISPCAPCNT_HI:
449 value &= 0xEF3F;
450 break;
451
452 // VRAM control
453 case DS9_REG_VRAMCNT_A:
454 case DS9_REG_VRAMCNT_C:
455 case DS9_REG_VRAMCNT_E:
456 oldValue = ds->memory.io9[address >> 1];
457 value &= 0x9F9F;
458 DSVideoConfigureVRAM(ds, address - DS9_REG_VRAMCNT_A, value & 0xFF, oldValue & 0xFF);
459 DSVideoConfigureVRAM(ds, address - DS9_REG_VRAMCNT_A + 1, value >> 8, oldValue >> 8);
460 break;
461 case DS9_REG_VRAMCNT_G:
462 oldValue = ds->memory.io9[address >> 1];
463 value &= 0x039F;
464 DSVideoConfigureVRAM(ds, 6, value & 0xFF, oldValue & 0xFF);
465 DSConfigureWRAM(&ds->memory, value >> 8);
466 break;
467 case DS9_REG_VRAMCNT_H:
468 oldValue = ds->memory.io9[address >> 1];
469 value &= 0x9F9F;
470 DSVideoConfigureVRAM(ds, 7, value & 0xFF, oldValue & 0xFF);
471 DSVideoConfigureVRAM(ds, 8, value >> 8, oldValue >> 8);
472 break;
473
474 case DS9_REG_EXMEMCNT:
475 value &= 0xE8FF;
476 DSConfigureExternalMemory(ds, value);
477 break;
478
479 // Math
480 case DS9_REG_DIVCNT:
481 value = _scheduleDiv(ds, value);
482 break;
483 case DS9_REG_DIV_NUMER_0:
484 case DS9_REG_DIV_NUMER_1:
485 case DS9_REG_DIV_NUMER_2:
486 case DS9_REG_DIV_NUMER_3:
487 case DS9_REG_DIV_DENOM_0:
488 case DS9_REG_DIV_DENOM_1:
489 case DS9_REG_DIV_DENOM_2:
490 case DS9_REG_DIV_DENOM_3:
491 ds->memory.io9[DS9_REG_DIVCNT >> 1] = _scheduleDiv(ds, ds->memory.io9[DS9_REG_DIVCNT >> 1]);
492 break;
493 case DS9_REG_SQRTCNT:
494 value = _scheduleSqrt(ds, value);
495 break;
496 case DS9_REG_SQRT_PARAM_0:
497 case DS9_REG_SQRT_PARAM_1:
498 case DS9_REG_SQRT_PARAM_2:
499 case DS9_REG_SQRT_PARAM_3:
500 ds->memory.io9[DS9_REG_SQRTCNT >> 1] = _scheduleSqrt(ds, ds->memory.io9[DS9_REG_SQRTCNT >> 1]);
501 break;
502
503 // High Video
504 case DS9_REG_POWCNT1:
505 value = ds->video.renderer->writeVideoRegister(ds->video.renderer, address, value);
506 break;
507
508 default:
509 {
510 uint32_t v2 = DSIOWrite(&ds->ds9, address, value);
511 if (v2 & 0x10000) {
512 value = v2;
513 break;
514 } else if (v2 & 0x20000) {
515 return;
516 }
517 }
518 mLOG(DS_IO, STUB, "Stub DS9 I/O register write: %06X:%04X", address, value);
519 if (address >= DS7_REG_MAX) {
520 mLOG(DS_IO, GAME_ERROR, "Write to unused DS9 I/O register: %06X:%04X", address, value);
521 return;
522 }
523 break;
524 }
525 }
526 ds->memory.io9[address >> 1] = value;
527}
528
529void DS9IOWrite8(struct DS* ds, uint32_t address, uint8_t value) {
530 if (address < DS9_REG_MAX) {
531 uint16_t value16 = value << (8 * (address & 1));
532 value16 |= (ds->memory.io9[(address & 0x1FFF) >> 1]) & ~(0xFF << (8 * (address & 1)));
533 DS9IOWrite(ds, address & 0xFFFFFFFE, value16);
534 } else {
535 mLOG(DS, STUB, "Writing to unknown DS9 register: %08X:%02X", address, value);
536 }
537}
538
539void DS9IOWrite32(struct DS* ds, uint32_t address, uint32_t value) {
540 if ((address >= DS9_REG_RDLINES_COUNT && address <= DS9_REG_VECMTX_RESULT_12) || address == DS9_REG_DISP3DCNT) {
541 value = DSGXWriteRegister32(&ds->gx, address, value);
542 } else {
543 switch (address) {
544 case DS_REG_DMA0SAD_LO:
545 case DS_REG_DMA1SAD_LO:
546 case DS_REG_DMA2SAD_LO:
547 case DS_REG_DMA3SAD_LO:
548 case DS_REG_DMA0DAD_LO:
549 case DS_REG_DMA1DAD_LO:
550 case DS_REG_DMA2DAD_LO:
551 case DS_REG_DMA3DAD_LO:
552 case DS_REG_IPCFIFOSEND_LO:
553 case DS_REG_IE_LO:
554 value = DSIOWrite32(&ds->ds9, address, value);
555 break;
556
557 case DS_REG_DMA0CNT_LO:
558 DS9DMAWriteCNT(&ds->ds9, 0, value);
559 break;
560 case DS_REG_DMA1CNT_LO:
561 DS9DMAWriteCNT(&ds->ds9, 1, value);
562 break;
563 case DS_REG_DMA2CNT_LO:
564 DS9DMAWriteCNT(&ds->ds9, 2, value);
565 break;
566 case DS_REG_DMA3CNT_LO:
567 DS9DMAWriteCNT(&ds->ds9, 3, value);
568 break;
569
570 default:
571 DS9IOWrite(ds, address, value & 0xFFFF);
572 DS9IOWrite(ds, address | 2, value >> 16);
573 return;
574 }
575 }
576 ds->ds9.memory.io[address >> 1] = value;
577 ds->ds9.memory.io[(address >> 1) + 1] = value >> 16;
578}
579
580uint16_t DS9IORead(struct DS* ds, uint32_t address) {
581 switch (address) {
582 case DS_REG_TM0CNT_LO:
583 case DS_REG_TM1CNT_LO:
584 case DS_REG_TM2CNT_LO:
585 case DS_REG_TM3CNT_LO:
586 DSIOUpdateTimer(&ds->ds9, address);
587 break;
588 case DS_REG_KEYINPUT:
589 return DSIOReadKeyInput(ds);
590 case DS_REG_VCOUNT:
591 case DS_REG_DMA0FILL_LO:
592 case DS_REG_DMA0FILL_HI:
593 case DS_REG_DMA1FILL_LO:
594 case DS_REG_DMA1FILL_HI:
595 case DS_REG_DMA2FILL_LO:
596 case DS_REG_DMA2FILL_HI:
597 case DS_REG_DMA3FILL_LO:
598 case DS_REG_DMA3FILL_HI:
599 case DS_REG_TM0CNT_HI:
600 case DS_REG_TM1CNT_HI:
601 case DS_REG_TM2CNT_HI:
602 case DS_REG_TM3CNT_HI:
603 case DS_REG_IPCSYNC:
604 case DS_REG_IPCFIFOCNT:
605 case DS_REG_ROMCNT_LO:
606 case DS_REG_ROMCNT_HI:
607 case DS_REG_IME:
608 case 0x20A:
609 case DS_REG_IE_LO:
610 case DS_REG_IE_HI:
611 case DS_REG_IF_LO:
612 case DS_REG_IF_HI:
613 case DS9_REG_DIVCNT:
614 case DS9_REG_DIV_NUMER_0:
615 case DS9_REG_DIV_NUMER_1:
616 case DS9_REG_DIV_NUMER_2:
617 case DS9_REG_DIV_NUMER_3:
618 case DS9_REG_DIV_DENOM_0:
619 case DS9_REG_DIV_DENOM_1:
620 case DS9_REG_DIV_DENOM_2:
621 case DS9_REG_DIV_DENOM_3:
622 case DS9_REG_DIV_RESULT_0:
623 case DS9_REG_DIV_RESULT_1:
624 case DS9_REG_DIV_RESULT_2:
625 case DS9_REG_DIV_RESULT_3:
626 case DS9_REG_DIVREM_RESULT_0:
627 case DS9_REG_DIVREM_RESULT_1:
628 case DS9_REG_DIVREM_RESULT_2:
629 case DS9_REG_DIVREM_RESULT_3:
630 case DS9_REG_SQRTCNT:
631 case DS9_REG_SQRT_PARAM_0:
632 case DS9_REG_SQRT_PARAM_1:
633 case DS9_REG_SQRT_PARAM_2:
634 case DS9_REG_SQRT_PARAM_3:
635 case DS9_REG_SQRT_RESULT_LO:
636 case DS9_REG_SQRT_RESULT_HI:
637 case DS_REG_POSTFLG:
638 case DS9_REG_GXSTAT_LO:
639 case DS9_REG_GXSTAT_HI:
640 case DS9_REG_CLIPMTX_RESULT_00:
641 case DS9_REG_CLIPMTX_RESULT_01:
642 case DS9_REG_CLIPMTX_RESULT_02:
643 case DS9_REG_CLIPMTX_RESULT_03:
644 case DS9_REG_CLIPMTX_RESULT_04:
645 case DS9_REG_CLIPMTX_RESULT_05:
646 case DS9_REG_CLIPMTX_RESULT_06:
647 case DS9_REG_CLIPMTX_RESULT_07:
648 case DS9_REG_CLIPMTX_RESULT_08:
649 case DS9_REG_CLIPMTX_RESULT_09:
650 case DS9_REG_CLIPMTX_RESULT_0A:
651 case DS9_REG_CLIPMTX_RESULT_0B:
652 case DS9_REG_CLIPMTX_RESULT_0C:
653 case DS9_REG_CLIPMTX_RESULT_0D:
654 case DS9_REG_CLIPMTX_RESULT_0E:
655 case DS9_REG_CLIPMTX_RESULT_0F:
656 case DS9_REG_CLIPMTX_RESULT_10:
657 case DS9_REG_CLIPMTX_RESULT_11:
658 case DS9_REG_CLIPMTX_RESULT_12:
659 case DS9_REG_CLIPMTX_RESULT_13:
660 case DS9_REG_CLIPMTX_RESULT_14:
661 case DS9_REG_CLIPMTX_RESULT_15:
662 case DS9_REG_CLIPMTX_RESULT_16:
663 case DS9_REG_CLIPMTX_RESULT_17:
664 case DS9_REG_CLIPMTX_RESULT_18:
665 case DS9_REG_CLIPMTX_RESULT_19:
666 case DS9_REG_CLIPMTX_RESULT_1A:
667 case DS9_REG_CLIPMTX_RESULT_1B:
668 case DS9_REG_CLIPMTX_RESULT_1C:
669 case DS9_REG_CLIPMTX_RESULT_1D:
670 case DS9_REG_CLIPMTX_RESULT_1E:
671 case DS9_REG_CLIPMTX_RESULT_1F:
672 // Handled transparently by the registers
673 break;
674 case DS_REG_AUXSPICNT:
675 case DS_REG_AUXSPIDATA:
676 if (ds->ds9.memory.slot1Access) {
677 break;
678 } else {
679 mLOG(DS_IO, GAME_ERROR, "Invalid cart access");
680 return 0;
681 }
682 default:
683 mLOG(DS_IO, STUB, "Stub DS9 I/O register read: %06X", address);
684 }
685 if (address < DS9_REG_MAX) {
686 return ds->ds9.memory.io[address >> 1];
687 }
688 return 0;
689}
690
691uint32_t DS9IORead32(struct DS* ds, uint32_t address) {
692 switch (address) {
693 case DS_REG_IPCFIFORECV_LO:
694 return DSIPCReadFIFO(&ds->ds9);
695 case DS_REG_ROMDATA_0:
696 if (ds->ds9.memory.slot1Access) {
697 return DSSlot1Read(ds);
698 } else {
699 mLOG(DS_IO, GAME_ERROR, "Invalid cart access");
700 return 0;
701 }
702 default:
703 return DS9IORead(ds, address & 0x00FFFFFC) | (DS9IORead(ds, (address & 0x00FFFFFC) | 2) << 16);
704 }
705}