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/internal/ds/ds.h>
9
10mLOG_DEFINE_CATEGORY(DS_IO, "DS I/O");
11
12static void _writeIPCSync(struct ARMCore* remoteCpu, uint16_t* remoteIo, int16_t value) {
13 remoteIo[DS7_REG_IPCSYNC >> 1] &= 0xFFF0;
14 remoteIo[DS7_REG_IPCSYNC >> 1] |= (value >> 8) & 0x0F;
15 if (value & 0x2000 && remoteIo[DS7_REG_IPCSYNC >> 1] & 0x4000) {
16 mLOG(DS_IO, STUB, "Unimplemented IPC IRQ");
17 UNUSED(remoteCpu);
18 }
19}
20
21void DS7IOInit(struct DS* ds) {
22 memset(ds->memory.io7, 0, sizeof(ds->memory.io7));
23}
24
25void DS7IOWrite(struct DS* ds, uint32_t address, uint16_t value) {
26 switch (address) {
27 // Timers
28 case DS7_REG_TM0CNT_LO:
29 DSTimerWriteTMCNT_LO(&ds->timers7[0], value);
30 return;
31 case DS7_REG_TM1CNT_LO:
32 DSTimerWriteTMCNT_LO(&ds->timers7[1], value);
33 return;
34 case DS7_REG_TM2CNT_LO:
35 DSTimerWriteTMCNT_LO(&ds->timers7[2], value);
36 return;
37 case DS7_REG_TM3CNT_LO:
38 DSTimerWriteTMCNT_LO(&ds->timers7[3], value);
39 return;
40
41 case DS7_REG_TM0CNT_HI:
42 value &= 0x00C7;
43 DSTimerWriteTMCNT_HI(&ds->timers7[0], ds->arm7, &ds->memory.io7[(address - 2) >> 1], value);
44 ds->timersEnabled7 &= ~1;
45 ds->timersEnabled7 |= DSTimerFlagsGetEnable(ds->timers7[0].flags);
46 break;
47 case DS7_REG_TM1CNT_HI:
48 value &= 0x00C7;
49 DSTimerWriteTMCNT_HI(&ds->timers7[1], ds->arm7, &ds->memory.io7[(address - 2) >> 1], value);
50 ds->timersEnabled7 &= ~2;
51 ds->timersEnabled7 |= DSTimerFlagsGetEnable(ds->timers7[1].flags) << 1;
52 break;
53 case DS7_REG_TM2CNT_HI:
54 value &= 0x00C7;
55 DSTimerWriteTMCNT_HI(&ds->timers7[2], ds->arm7, &ds->memory.io7[(address - 2) >> 1], value);
56 ds->timersEnabled7 &= ~4;
57 ds->timersEnabled7 |= DSTimerFlagsGetEnable(ds->timers7[2].flags) << 2;
58 break;
59 case DS7_REG_TM3CNT_HI:
60 value &= 0x00C7;
61 DSTimerWriteTMCNT_HI(&ds->timers7[3], ds->arm7, &ds->memory.io7[(address - 2) >> 1], value);
62 ds->timersEnabled7 &= ~8;
63 ds->timersEnabled7 |= DSTimerFlagsGetEnable(ds->timers7[3].flags) << 3;
64 break;
65
66 case DS7_REG_IPCSYNC:
67 value &= 0x6F00;
68 value |= ds->memory.io7[address >> 1] & 0x000F;
69 _writeIPCSync(ds->arm9, ds->memory.io9, value);
70 break;
71 case DS7_REG_IME:
72 DSWriteIME(ds->arm7, ds->memory.io7, value);
73 break;
74 case DS7_REG_IF_LO:
75 case DS7_REG_IF_HI:
76 value = ds->memory.io7[address >> 1] & ~value;
77 break;
78 default:
79 mLOG(DS_IO, STUB, "Stub DS7 I/O register write: %06X:%04X", address, value);
80 if (address >= DS7_REG_MAX) {
81 mLOG(DS_IO, GAME_ERROR, "Write to unused DS7 I/O register: %06X:%04X", address, value);
82 return;
83 }
84 break;
85 }
86 ds->memory.io7[address >> 1] = value;
87}
88
89void DS7IOWrite8(struct DS* ds, uint32_t address, uint8_t value) {
90 if (address < DS7_REG_MAX) {
91 uint16_t value16 = value << (8 * (address & 1));
92 value16 |= (ds->memory.io7[(address & 0xFFF) >> 1]) & ~(0xFF << (8 * (address & 1)));
93 DS7IOWrite(ds, address & 0xFFFFFFFE, value16);
94 } else {
95 mLOG(DS, STUB, "Writing to unknown DS7 register: %08X:%02X", address, value);
96 }
97}
98
99void DS7IOWrite32(struct DS* ds, uint32_t address, uint32_t value) {
100 switch (address) {
101 case DS7_REG_IE_LO:
102 DSWriteIE(ds->arm7, ds->memory.io7, value);
103 break;
104 default:
105 DS7IOWrite(ds, address, value & 0xFFFF);
106 DS7IOWrite(ds, address | 2, value >> 16);
107 return;
108 }
109 ds->memory.io7[address >> 1] = value;
110 ds->memory.io7[(address >> 1) + 1] = value >> 16;
111}
112
113uint16_t DS7IORead(struct DS* ds, uint32_t address) {
114 switch (address) {
115 case DS7_REG_TM0CNT_LO:
116 DSTimerUpdateRegister(&ds->timers7[0], ds->arm7, &ds->memory.io7[address >> 1]);
117 break;
118 case DS7_REG_TM1CNT_LO:
119 DSTimerUpdateRegister(&ds->timers7[1], ds->arm7, &ds->memory.io7[address >> 1]);
120 break;
121 case DS7_REG_TM2CNT_LO:
122 DSTimerUpdateRegister(&ds->timers7[2], ds->arm7, &ds->memory.io7[address >> 1]);
123 break;
124 case DS7_REG_TM3CNT_LO:
125 DSTimerUpdateRegister(&ds->timers7[3], ds->arm7, &ds->memory.io7[address >> 1]);
126 break;
127
128 case DS7_REG_TM0CNT_HI:
129 case DS7_REG_TM1CNT_HI:
130 case DS7_REG_TM2CNT_HI:
131 case DS7_REG_TM3CNT_HI:
132 case DS7_REG_IPCSYNC:
133 case DS7_REG_IME:
134 case DS7_REG_IE_LO:
135 case DS7_REG_IE_HI:
136 case DS7_REG_IF_LO:
137 case DS7_REG_IF_HI:
138 // Handled transparently by the registers
139 break;
140 default:
141 mLOG(DS_IO, STUB, "Stub DS7 I/O register read: %06X", address);
142 }
143 if (address < DS7_REG_MAX) {
144 return ds->memory.io7[address >> 1];
145 }
146 return 0;
147}
148
149void DS9IOInit(struct DS* ds) {
150 memset(ds->memory.io9, 0, sizeof(ds->memory.io9));
151}
152
153void DS9IOWrite(struct DS* ds, uint32_t address, uint16_t value) {
154 switch (address) {
155 case DS9_REG_IPCSYNC:
156 value &= 0x6F00;
157 value |= ds->memory.io9[address >> 1] & 0x000F;
158 _writeIPCSync(ds->arm7, ds->memory.io7, value);
159 break;
160 default:
161 mLOG(DS_IO, STUB, "Stub DS9 I/O register write: %06X:%04X", address, value);
162 if (address >= DS7_REG_MAX) {
163 mLOG(DS_IO, GAME_ERROR, "Write to unused DS9 I/O register: %06X:%04X", address, value);
164 return;
165 }
166 break;
167 }
168 ds->memory.io9[address >> 1] = value;
169}
170
171void DS9IOWrite8(struct DS* ds, uint32_t address, uint8_t value) {
172 if (address < DS9_REG_MAX) {
173 uint16_t value16 = value << (8 * (address & 1));
174 value16 |= (ds->memory.io9[(address & 0x1FFF) >> 1]) & ~(0xFF << (8 * (address & 1)));
175 DS9IOWrite(ds, address & 0xFFFFFFFE, value16);
176 } else {
177 mLOG(DS, STUB, "Writing to unknown DS9 register: %08X:%02X", address, value);
178 }
179}
180
181void DS9IOWrite32(struct DS* ds, uint32_t address, uint32_t value) {
182 switch (address) {
183 default:
184 DS9IOWrite(ds, address, value & 0xFFFF);
185 DS9IOWrite(ds, address | 2, value >> 16);
186 return;
187 }
188 ds->memory.io9[address >> 1] = value;
189 ds->memory.io9[(address >> 1) + 1] = value >> 16;
190}
191
192uint16_t DS9IORead(struct DS* ds, uint32_t address) {
193 switch (address) {
194 case DS9_REG_IPCSYNC:
195 // Handled transparently by the registers
196 break;
197 default:
198 mLOG(DS_IO, STUB, "Stub DS9 I/O register read: %06X", address);
199 }
200 if (address < DS9_REG_MAX) {
201 return ds->memory.io9[address >> 1];
202 }
203 return 0;
204}