src/ds/memory.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/memory.h>
7
8#include <mgba/internal/arm/macros.h>
9
10#include <mgba/internal/ds/ds.h>
11#include <mgba/internal/ds/io.h>
12#include <mgba-util/math.h>
13#include <mgba-util/memory.h>
14
15mLOG_DEFINE_CATEGORY(DS_MEM, "DS Memory", "ds.memory");
16
17static uint32_t _deadbeef[1] = { 0xE710B710 }; // Illegal instruction on both ARM and Thumb
18const uint32_t redzoneInstruction = 0xE7F0DEF0;
19
20static const uint32_t _vramMask[9] = {
21 0x1FFFF,
22 0x1FFFF,
23 0x1FFFF,
24 0x1FFFF,
25 0x0FFFF,
26 0x03FFF,
27 0x03FFF,
28 0x07FFF,
29 0x03FFF
30};
31
32static void DS7SetActiveRegion(struct ARMCore* cpu, uint32_t region);
33static void DS9SetActiveRegion(struct ARMCore* cpu, uint32_t region);
34static int32_t DSMemoryStall(struct ARMCore* cpu, int32_t wait);
35
36static unsigned _selectVRAM(struct DSMemory* memory, uint32_t offset);
37
38static const char DS7_BASE_WAITSTATES[16] = { 0, 0, 8, 0, 0, 0, 0, 0 };
39static const char DS7_BASE_WAITSTATES_32[16] = { 0, 0, 9, 0, 0, 1, 1, 0 };
40static const char DS7_BASE_WAITSTATES_SEQ[16] = { 0, 0, 1, 0, 0, 0, 0, 0 };
41static const char DS7_BASE_WAITSTATES_SEQ_32[16] = { 0, 0, 2, 0, 0, 1, 1, 0 };
42
43static const char DS9_BASE_WAITSTATES[16] = { 0, 0, 2, 6, 6, 7, 7, 6 };
44static const char DS9_BASE_WAITSTATES_32[16] = { 0, 0, 4, 6, 6, 9, 9, 6 };
45static const char DS9_BASE_WAITSTATES_SEQ[16] = { 0, 0, 1, 1, 1, 2, 2, 1 };
46static const char DS9_BASE_WAITSTATES_SEQ_32[16] = { 0, 0, 2, 1, 1, 4, 4, 1 };
47
48void DSMemoryInit(struct DS* ds) {
49 struct ARMCore* arm7 = ds->ds7.cpu;
50 arm7->memory.load32 = DS7Load32;
51 arm7->memory.load16 = DS7Load16;
52 arm7->memory.load8 = DS7Load8;
53 arm7->memory.loadMultiple = DS7LoadMultiple;
54 arm7->memory.store32 = DS7Store32;
55 arm7->memory.store16 = DS7Store16;
56 arm7->memory.store8 = DS7Store8;
57 arm7->memory.storeMultiple = DS7StoreMultiple;
58 arm7->memory.stall = DSMemoryStall;
59
60 struct ARMCore* arm9 = ds->ds9.cpu;
61 arm9->memory.load32 = DS9Load32;
62 arm9->memory.load16 = DS9Load16;
63 arm9->memory.load8 = DS9Load8;
64 arm9->memory.loadMultiple = DS9LoadMultiple;
65 arm9->memory.store32 = DS9Store32;
66 arm9->memory.store16 = DS9Store16;
67 arm9->memory.store8 = DS9Store8;
68 arm9->memory.storeMultiple = DS9StoreMultiple;
69 arm9->memory.stall = DSMemoryStall;
70
71 int i;
72 for (i = 0; i < 8; ++i) {
73 // TODO: Formalize
74 ds->ds7.memory.waitstatesNonseq16[i] = DS7_BASE_WAITSTATES[i];
75 ds->ds7.memory.waitstatesSeq16[i] = DS7_BASE_WAITSTATES_SEQ[i];
76 ds->ds7.memory.waitstatesPrefetchNonseq16[i] = DS7_BASE_WAITSTATES[i];
77 ds->ds7.memory.waitstatesPrefetchSeq16[i] = DS7_BASE_WAITSTATES_SEQ[i];
78 ds->ds7.memory.waitstatesNonseq32[i] = DS7_BASE_WAITSTATES_32[i];
79 ds->ds7.memory.waitstatesSeq32[i] = DS7_BASE_WAITSTATES_SEQ_32[i];
80 ds->ds7.memory.waitstatesPrefetchNonseq32[i] = DS7_BASE_WAITSTATES_32[i];
81 ds->ds7.memory.waitstatesPrefetchSeq32[i] = DS7_BASE_WAITSTATES_SEQ_32[i];
82
83 ds->ds9.memory.waitstatesNonseq16[i] = DS9_BASE_WAITSTATES[i];
84 ds->ds9.memory.waitstatesSeq16[i] = DS9_BASE_WAITSTATES_SEQ[i];
85 ds->ds9.memory.waitstatesPrefetchNonseq16[i] = DS9_BASE_WAITSTATES[i];
86 ds->ds9.memory.waitstatesPrefetchSeq16[i] = DS9_BASE_WAITSTATES[i];
87 ds->ds9.memory.waitstatesNonseq32[i] = DS9_BASE_WAITSTATES_32[i];
88 ds->ds9.memory.waitstatesSeq32[i] = DS9_BASE_WAITSTATES_SEQ_32[i];
89 ds->ds9.memory.waitstatesPrefetchNonseq32[i] = DS9_BASE_WAITSTATES_32[i];
90 ds->ds9.memory.waitstatesPrefetchSeq32[i] = DS9_BASE_WAITSTATES_32[i];
91 }
92
93 ds->ds9.memory.waitstatesPrefetchNonseq16[2] = 0;
94 ds->ds9.memory.waitstatesPrefetchSeq16[2] = 0;
95 ds->ds9.memory.waitstatesPrefetchNonseq32[2] = 0;
96 ds->ds9.memory.waitstatesPrefetchSeq32[2] = 0;
97
98 for (; i < 256; ++i) {
99 ds->ds7.memory.waitstatesNonseq16[i] = 0;
100 ds->ds7.memory.waitstatesSeq16[i] = 0;
101 ds->ds7.memory.waitstatesNonseq32[i] = 0;
102 ds->ds7.memory.waitstatesSeq32[i] = 0;
103
104 ds->ds9.memory.waitstatesNonseq16[i] = 0;
105 ds->ds9.memory.waitstatesSeq16[i] = 0;
106 ds->ds9.memory.waitstatesNonseq32[i] = 0;
107 ds->ds9.memory.waitstatesSeq32[i] = 0;
108 }
109
110 ds->memory.bios7 = NULL;
111 ds->memory.bios9 = NULL;
112 ds->memory.wramBase = NULL;
113 ds->memory.wram7 = NULL;
114 ds->memory.ram = NULL;
115 ds->memory.itcm = NULL;
116 ds->memory.dtcm = NULL;
117 ds->memory.rom = NULL;
118
119 ds->ds7.memory.activeRegion = -1;
120 ds->ds9.memory.activeRegion = -1;
121 ds->ds7.memory.io = ds->memory.io7;
122 ds->ds9.memory.io = ds->memory.io9;
123
124 arm7->memory.activeRegion = 0;
125 arm7->memory.activeMask = 0;
126 arm7->memory.setActiveRegion = DS7SetActiveRegion;
127 arm7->memory.activeSeqCycles32 = 0;
128 arm7->memory.activeSeqCycles16 = 0;
129 arm7->memory.activeNonseqCycles32 = 0;
130 arm7->memory.activeNonseqCycles16 = 0;
131
132 arm9->memory.activeRegion = 0;
133 arm9->memory.activeMask = 0;
134 arm9->memory.setActiveRegion = DS9SetActiveRegion;
135 arm9->memory.activeSeqCycles32 = 0;
136 arm9->memory.activeSeqCycles16 = 0;
137 arm9->memory.activeNonseqCycles32 = 0;
138 arm9->memory.activeNonseqCycles16 = 0;
139}
140
141void DSMemoryDeinit(struct DS* ds) {
142 mappedMemoryFree(ds->memory.wram, DS_SIZE_WORKING_RAM);
143 mappedMemoryFree(ds->memory.wram7, DS7_SIZE_WORKING_RAM);
144 mappedMemoryFree(ds->memory.ram, DS_SIZE_RAM);
145 mappedMemoryFree(ds->memory.itcm, DS9_SIZE_ITCM);
146 mappedMemoryFree(ds->memory.dtcm, DS9_SIZE_DTCM);
147}
148
149void DSMemoryReset(struct DS* ds) {
150 if (ds->memory.wram) {
151 mappedMemoryFree(ds->memory.wramBase, DS_SIZE_WORKING_RAM * 2 + 12);
152 }
153 // XXX: This hack lets you roll over the end of the WRAM block without
154 // looping back to the beginning. It works by placing an undefined
155 // instruction in a redzone at the very beginning and end of the buffer.
156 // Using clever masking tricks, the ARM loop will mask the offset so that
157 // either the middle of the passed-in buffer is the actual buffer, and
158 // when the loop rolls over, it hits the redzone at the beginning, or the
159 // start of the passed-in buffer matches the actual buffer, causing the
160 // redzone at the end to be hit. This requires a lot of dead space in
161 // the middle, and a fake (too large) mask, but it is very fast.
162 ds->memory.wram = anonymousMemoryMap(DS_SIZE_WORKING_RAM * 2 + 12);
163 ds->memory.wram[0] = redzoneInstruction;
164 ds->memory.wram[1] = redzoneInstruction;
165 ds->memory.wram[2] = redzoneInstruction;
166 ds->memory.wram[DS_SIZE_WORKING_RAM >> 1] = redzoneInstruction;
167 ds->memory.wram[(DS_SIZE_WORKING_RAM >> 1) + 1] = redzoneInstruction;
168 ds->memory.wram[(DS_SIZE_WORKING_RAM >> 1) + 2] = redzoneInstruction;
169 ds->memory.wramBase = &ds->memory.wram[DS_SIZE_WORKING_RAM >> 2];
170
171 if (ds->memory.wram7) {
172 mappedMemoryFree(ds->memory.wram7, DS7_SIZE_WORKING_RAM);
173 }
174 ds->memory.wram7 = anonymousMemoryMap(DS7_SIZE_WORKING_RAM);
175
176 if (ds->memory.ram) {
177 mappedMemoryFree(ds->memory.ram, DS_SIZE_RAM);
178 }
179 ds->memory.ram = anonymousMemoryMap(DS_SIZE_RAM);
180
181 if (ds->memory.itcm) {
182 mappedMemoryFree(ds->memory.itcm, DS9_SIZE_ITCM);
183 }
184 ds->memory.itcm = anonymousMemoryMap(DS9_SIZE_ITCM);
185
186 if (ds->memory.dtcm) {
187 mappedMemoryFree(ds->memory.dtcm, DS9_SIZE_DTCM);
188 }
189 ds->memory.dtcm = anonymousMemoryMap(DS9_SIZE_DTCM);
190
191 memset(ds->ds7.memory.dma, 0, sizeof(ds->ds7.memory.dma));
192 memset(ds->ds9.memory.dma, 0, sizeof(ds->ds9.memory.dma));
193 ds->ds7.memory.activeDMA = -1;
194 ds->ds9.memory.activeDMA = -1;
195
196 // TODO: Correct size
197 ds->memory.wramSize7 = 0x8000;
198 ds->memory.wramBase7 = ds->memory.wram;
199 ds->memory.wramSize9 = 0;
200 ds->memory.wramBase9 = NULL;
201
202 ds->memory.slot1Owner = true;
203 ds->memory.slot2Owner = true;
204 ds->memory.slot1.savedataType = DS_SAVEDATA_AUTODETECT;
205 ds->ds7.memory.slot1Access = true;
206 ds->ds9.memory.slot1Access = false;
207
208 DSSPIReset(ds);
209 DSSlot1Reset(ds);
210
211 DSVideoConfigureVRAM(ds, 0, 0, 1);
212 DSVideoConfigureVRAM(ds, 1, 0, 1);
213 DSVideoConfigureVRAM(ds, 2, 0, 1);
214 DSVideoConfigureVRAM(ds, 3, 0, 1);
215 DSVideoConfigureVRAM(ds, 4, 0, 1);
216 DSVideoConfigureVRAM(ds, 5, 0, 1);
217 DSVideoConfigureVRAM(ds, 6, 0, 1);
218 DSVideoConfigureVRAM(ds, 7, 0, 1);
219 DSVideoConfigureVRAM(ds, 8, 0, 1);
220 DSConfigureWRAM(&ds->memory, 3);
221
222 if (!ds->memory.wram || !ds->memory.wram7 || !ds->memory.ram || !ds->memory.itcm || !ds->memory.dtcm) {
223 DSMemoryDeinit(ds);
224 mLOG(DS_MEM, FATAL, "Could not map memory");
225 }
226}
227
228static void DS7SetActiveRegion(struct ARMCore* cpu, uint32_t address) {
229 struct DS* ds = (struct DS*) cpu->master;
230 struct DSCoreMemory* memory = &ds->ds7.memory;
231
232 int newRegion = address >> DS_BASE_OFFSET;
233
234 memory->activeRegion = newRegion;
235 switch (newRegion) {
236 case DS_REGION_WORKING_RAM:
237 if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
238 cpu->memory.activeRegion = ds->memory.wram7;
239 cpu->memory.activeMask = DS7_SIZE_WORKING_RAM - 1;
240 } else if (ds->memory.wramSize7 == DS_SIZE_WORKING_RAM) {
241 if (address & DS_SIZE_WORKING_RAM) {
242 cpu->memory.activeRegion = ds->memory.wram;
243 } else {
244 cpu->memory.activeRegion = ds->memory.wramBase;
245 }
246 cpu->memory.activeMask = (ds->memory.wramSize7 << 1) - 1;
247 } else {
248 cpu->memory.activeRegion = ds->memory.wramBase;
249 cpu->memory.activeMask = (ds->memory.wramSize7 - 1);
250 }
251 break;
252 case DS7_REGION_BIOS:
253 if (ds->memory.bios7) {
254 cpu->memory.activeRegion = ds->memory.bios7;
255 cpu->memory.activeMask = DS9_SIZE_BIOS - 1;
256 } else {
257 cpu->memory.activeRegion = _deadbeef;
258 cpu->memory.activeMask = 0;
259 }
260 break;
261 case DS_REGION_RAM:
262 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
263 cpu->memory.activeRegion = ds->memory.ram;
264 cpu->memory.activeMask = DS_SIZE_RAM - 1;
265 break;
266 }
267 goto jump_error;
268 case DS_REGION_VRAM:
269 if (address < 0x06040000 && ds->memory.vram7[(address & 0x3FFFF) >> 17]) {
270 // TODO: redzones
271 cpu->memory.activeRegion = (uint32_t*) ds->memory.vram7[(address & 0x3FFFF) >> 17];
272 cpu->memory.activeMask = 0x1FFFF;
273 break;
274 }
275 // Fall through
276 default:
277 jump_error:
278 memory->activeRegion = -1;
279 cpu->memory.activeRegion = _deadbeef;
280 cpu->memory.activeMask = 0;
281 mLOG(DS_MEM, FATAL, "Jumped to invalid address: %08X", address);
282 break;
283 }
284 cpu->memory.activeSeqCycles32 = memory->waitstatesPrefetchSeq32[memory->activeRegion];
285 cpu->memory.activeSeqCycles16 = memory->waitstatesPrefetchSeq16[memory->activeRegion];
286 cpu->memory.activeNonseqCycles32 = memory->waitstatesPrefetchNonseq32[memory->activeRegion];
287 cpu->memory.activeNonseqCycles16 = memory->waitstatesPrefetchNonseq16[memory->activeRegion];
288}
289
290uint32_t DS7Load32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
291 struct DS* ds = (struct DS*) cpu->master;
292 struct DSMemory* memory = &ds->memory;
293 uint32_t value = 0;
294 int wait = ds->ds7.memory.waitstatesNonseq32[address >> DS_BASE_OFFSET];
295
296 switch (address >> DS_BASE_OFFSET) {
297 case DS7_REGION_BIOS:
298 LOAD_32(value, address & (DS7_SIZE_BIOS - 4), memory->bios7);
299 break;
300 case DS_REGION_WORKING_RAM:
301 if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
302 LOAD_32(value, address & (DS7_SIZE_WORKING_RAM - 4), memory->wram7);
303 } else {
304 LOAD_32(value, address & (ds->memory.wramSize7 - 4), memory->wramBase7);
305 }
306 break;
307 case DS_REGION_RAM:
308 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
309 LOAD_32(value, address & (DS_SIZE_RAM - 4), memory->ram);
310 break;
311 }
312 mLOG(DS_MEM, STUB, "Unimplemented DS7 Load32: %08X", address);
313 break;
314 case DS_REGION_IO:
315 value = DS7IORead32(ds, address & 0x00FFFFFC);
316 break;
317 case DS_REGION_VRAM:
318 if (address < 0x06040000 && memory->vram7[(address & 0x3FFFF) >> 17]) {
319 LOAD_32(value, address & 0x1FFFC, memory->vram7[(address & 0x3FFFF) >> 17]);
320 break;
321 }
322 // Fall through
323 default:
324 mLOG(DS_MEM, STUB, "Unimplemented DS7 Load32: %08X", address);
325 break;
326 }
327
328 if (cycleCounter) {
329 wait += 2;
330 *cycleCounter += wait;
331 }
332 // Unaligned 32-bit loads are "rotated" so they make some semblance of sense
333 int rotate = (address & 3) << 3;
334 return ROR(value, rotate);
335}
336
337uint32_t DS7Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
338 struct DS* ds = (struct DS*) cpu->master;
339 struct DSMemory* memory = &ds->memory;
340 uint32_t value = 0;
341 int wait = ds->ds7.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
342
343 switch (address >> DS_BASE_OFFSET) {
344 case DS7_REGION_BIOS:
345 LOAD_16(value, address & (DS7_SIZE_BIOS - 2), memory->bios7);
346 break;
347 case DS_REGION_WORKING_RAM:
348 if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
349 LOAD_16(value, address & (DS7_SIZE_WORKING_RAM - 2), memory->wram7);
350 } else {
351 LOAD_16(value, address & (ds->memory.wramSize7 - 2), memory->wramBase7);
352 }
353 break;
354 case DS_REGION_RAM:
355 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
356 LOAD_16(value, address & (DS_SIZE_RAM - 1), memory->ram);
357 break;
358 }
359 mLOG(DS_MEM, STUB, "Unimplemented DS7 Load16: %08X", address);
360 case DS_REGION_IO:
361 value = DS7IORead(ds, address & DS_OFFSET_MASK);
362 break;
363 case DS_REGION_VRAM:
364 if (address < 0x06040000 && memory->vram7[(address & 0x3FFFF) >> 17]) {
365 LOAD_16(value, address & 0x1FFFE, memory->vram7[(address & 0x3FFFF) >> 17]);
366 break;
367 }
368 // Fall through
369 default:
370 mLOG(DS_MEM, STUB, "Unimplemented DS7 Load16: %08X", address);
371 break;
372 }
373
374 if (cycleCounter) {
375 wait += 2;
376 *cycleCounter += wait;
377 }
378 // Unaligned 16-bit loads are "unpredictable", TODO: See what DS does
379 int rotate = (address & 1) << 3;
380 return ROR(value, rotate);
381}
382
383uint32_t DS7Load8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
384 struct DS* ds = (struct DS*) cpu->master;
385 struct DSMemory* memory = &ds->memory;
386 uint32_t value = 0;
387 int wait = ds->ds7.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
388
389 switch (address >> DS_BASE_OFFSET) {
390 case DS7_REGION_BIOS:
391 value = ((uint8_t*) memory->bios7)[address & (DS7_SIZE_BIOS - 1)];
392 break;
393 case DS_REGION_WORKING_RAM:
394 if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
395 value = ((uint8_t*) memory->wram7)[address & (DS7_SIZE_WORKING_RAM - 1)];
396 } else {
397 value = ((uint8_t*) memory->wramBase7)[address & (ds->memory.wramSize7 - 1)];
398 }
399 break;
400 case DS_REGION_RAM:
401 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
402 value = ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)];
403 break;
404 }
405 mLOG(DS_MEM, STUB, "Unimplemented DS7 Load8: %08X", address);
406 break;
407 case DS_REGION_IO:
408 value = (DS7IORead(ds, address & 0xFFFE) >> ((address & 0x0001) << 3)) & 0xFF;
409 break;
410 default:
411 mLOG(DS_MEM, STUB, "Unimplemented DS7 Load8: %08X", address);
412 break;
413 }
414
415 if (cycleCounter) {
416 wait += 2;
417 *cycleCounter += wait;
418 }
419 return value;
420}
421
422void DS7Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) {
423 struct DS* ds = (struct DS*) cpu->master;
424 struct DSMemory* memory = &ds->memory;
425 int wait = ds->ds7.memory.waitstatesNonseq32[address >> DS_BASE_OFFSET];
426
427 switch (address >> DS_BASE_OFFSET) {
428 case DS_REGION_WORKING_RAM:
429 if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
430 STORE_32(value, address & (DS7_SIZE_WORKING_RAM - 4), memory->wram7);
431 } else {
432 STORE_32(value, address & (ds->memory.wramSize7 - 4), memory->wramBase7);
433 }
434 break;
435 case DS_REGION_RAM:
436 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
437 STORE_32(value, address & (DS_SIZE_RAM - 4), memory->ram);
438 break;
439 }
440 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store32: %08X:%08X", address, value);
441 break;
442 case DS_REGION_IO:
443 DS7IOWrite32(ds, address & DS_OFFSET_MASK, value);
444 break;
445 case DS_REGION_VRAM:
446 if (address < 0x06040000 && memory->vram7[(address & 0x3FFFF) >> 17]) {
447 STORE_32(value, address & 0x1FFFC, memory->vram7[(address & 0x3FFFF) >> 17]);
448 break;
449 }
450 // Fall through
451 default:
452 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store32: %08X:%08X", address, value);
453 break;
454 }
455
456 if (cycleCounter) {
457 ++wait;
458 *cycleCounter += wait;
459 }
460}
461
462void DS7Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
463 struct DS* ds = (struct DS*) cpu->master;
464 struct DSMemory* memory = &ds->memory;
465 int wait = ds->ds7.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
466
467 switch (address >> DS_BASE_OFFSET) {
468 case DS_REGION_WORKING_RAM:
469 if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
470 STORE_16(value, address & (DS7_SIZE_WORKING_RAM - 2), memory->wram7);
471 } else {
472 STORE_16(value, address & (ds->memory.wramSize7 - 2), memory->wramBase7);
473 }
474 break;
475 case DS_REGION_RAM:
476 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
477 STORE_16(value, address & (DS_SIZE_RAM - 2), memory->ram);
478 break;
479 }
480 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store16: %08X:%04X", address, value);
481 break;
482 case DS_REGION_IO:
483 DS7IOWrite(ds, address & DS_OFFSET_MASK, value);
484 break;
485 case DS_REGION_VRAM:
486 if (address < 0x06040000 && memory->vram7[(address & 0x3FFFF) >> 17]) {
487 STORE_16(value, address & 0x1FFFE, memory->vram7[(address & 0x3FFFF) >> 17]);
488 break;
489 }
490 // Fall through
491 default:
492 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store16: %08X:%04X", address, value);
493 break;
494 }
495
496 if (cycleCounter) {
497 ++wait;
498 *cycleCounter += wait;
499 }
500}
501
502void DS7Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
503 struct DS* ds = (struct DS*) cpu->master;
504 struct DSMemory* memory = &ds->memory;
505 int wait = ds->ds7.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
506
507 switch (address >> DS_BASE_OFFSET) {
508 case DS_REGION_WORKING_RAM:
509 if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
510 ((uint8_t*) memory->wram7)[address & (DS7_SIZE_WORKING_RAM - 1)] = value;
511 } else {
512 ((uint8_t*) memory->wramBase7)[address & (ds->memory.wramSize7 - 1)] = value;
513 }
514 break;
515 case DS_REGION_RAM:
516 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
517 ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)] = value;
518 break;
519 }
520 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store8: %08X:%02X", address, value);
521 case DS_REGION_IO:
522 DS7IOWrite8(ds, address & DS_OFFSET_MASK, value);
523 break;
524 default:
525 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store8: %08X:%02X", address, value);
526 break;
527 }
528
529 if (cycleCounter) {
530 ++wait;
531 *cycleCounter += wait;
532 }
533}
534
535#define LDM_LOOP(LDM) \
536 for (i = 0; i < 16; i += 4) { \
537 if (UNLIKELY(mask & (1 << i))) { \
538 LDM; \
539 cpu->gprs[i] = value; \
540 ++wait; \
541 wait += ws32[address >> DS_BASE_OFFSET]; \
542 address += 4; \
543 } \
544 if (UNLIKELY(mask & (2 << i))) { \
545 LDM; \
546 cpu->gprs[i + 1] = value; \
547 ++wait; \
548 wait += ws32[address >> DS_BASE_OFFSET]; \
549 address += 4; \
550 } \
551 if (UNLIKELY(mask & (4 << i))) { \
552 LDM; \
553 cpu->gprs[i + 2] = value; \
554 ++wait; \
555 wait += ws32[address >> DS_BASE_OFFSET]; \
556 address += 4; \
557 } \
558 if (UNLIKELY(mask & (8 << i))) { \
559 LDM; \
560 cpu->gprs[i + 3] = value; \
561 ++wait; \
562 wait += ws32[address >> DS_BASE_OFFSET]; \
563 address += 4; \
564 } \
565 }
566
567#define STM_LOOP(STM) \
568 for (i = 0; i < 16; i += 4) { \
569 if (UNLIKELY(mask & (1 << i))) { \
570 value = cpu->gprs[i]; \
571 STM; \
572 ++wait; \
573 wait += ws32[address >> DS_BASE_OFFSET]; \
574 address += 4; \
575 } \
576 if (UNLIKELY(mask & (2 << i))) { \
577 value = cpu->gprs[i + 1]; \
578 STM; \
579 ++wait; \
580 wait += ws32[address >> DS_BASE_OFFSET]; \
581 address += 4; \
582 } \
583 if (UNLIKELY(mask & (4 << i))) { \
584 value = cpu->gprs[i + 2]; \
585 STM; \
586 ++wait; \
587 wait += ws32[address >> DS_BASE_OFFSET]; \
588 address += 4; \
589 } \
590 if (UNLIKELY(mask & (8 << i))) { \
591 value = cpu->gprs[i + 3]; \
592 STM; \
593 ++wait; \
594 wait += ws32[address >> DS_BASE_OFFSET]; \
595 address += 4; \
596 } \
597 }
598
599uint32_t DS7LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
600 struct DS* ds = (struct DS*) cpu->master;
601 struct DSMemory* memory = &ds->memory;
602 char* ws32 = ds->ds7.memory.waitstatesNonseq32;
603 uint32_t value;
604 int wait = 0;
605
606 int i;
607 int offset = 4;
608 int popcount = 0;
609 if (direction & LSM_D) {
610 offset = -4;
611 popcount = popcount32(mask);
612 address -= (popcount << 2) - 4;
613 }
614
615 if (direction & LSM_B) {
616 address += offset;
617 }
618
619 uint32_t addressMisalign = address & 0x3;
620 address &= 0xFFFFFFFC;
621
622 switch (address >> DS_BASE_OFFSET) {
623 case DS_REGION_WORKING_RAM:
624 LDM_LOOP(if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
625 LOAD_32(value, address & (DS7_SIZE_WORKING_RAM - 1), memory->wram7);
626 } else {
627 LOAD_32(value, address & (ds->memory.wramSize7 - 1), memory->wramBase7);
628 });
629 break;
630 case DS_REGION_RAM:
631 LDM_LOOP(if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
632 LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
633 } else {
634 mLOG(DS_MEM, STUB, "Unimplemented DS7 LDM: %08X", address);
635 });
636 break;
637 case DS_REGION_IO:
638 LDM_LOOP(value = DS7IORead32(ds, address));
639 break;
640 case DS_REGION_VRAM:
641 LDM_LOOP(if (address < 0x06040000 && memory->vram7[(address & 0x3FFFF) >> 17]) {
642 LOAD_32(value, address & 0x1FFFF, memory->vram7[(address & 0x3FFFF) >> 17]);
643 } else {
644 mLOG(DS_MEM, STUB, "Unimplemented DS7 LDM: %08X", address);
645 });
646 break;
647 default:
648 mLOG(DS_MEM, STUB, "Unimplemented DS7 LDM: %08X", address);
649 LDM_LOOP(value = 0);
650 }
651
652 if (cycleCounter) {
653 ++wait;
654 *cycleCounter += wait;
655 }
656
657 if (direction & LSM_B) {
658 address -= offset;
659 }
660
661 if (direction & LSM_D) {
662 address -= (popcount << 2) + 4;
663 }
664
665 return address | addressMisalign;
666}
667
668uint32_t DS7StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
669 struct DS* ds = (struct DS*) cpu->master;
670 struct DSMemory* memory = &ds->memory;
671 char* ws32 = ds->ds7.memory.waitstatesNonseq32;
672 uint32_t value;
673 int wait = 0;
674
675 int i;
676 int offset = 4;
677 int popcount = 0;
678 if (direction & LSM_D) {
679 offset = -4;
680 popcount = popcount32(mask);
681 address -= (popcount << 2) - 4;
682 }
683
684 if (direction & LSM_B) {
685 address += offset;
686 }
687
688 uint32_t addressMisalign = address & 0x3;
689 address &= 0xFFFFFFFC;
690
691 switch (address >> DS_BASE_OFFSET) {
692 case DS_REGION_WORKING_RAM:
693 STM_LOOP(if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
694 STORE_32(value, address & (DS7_SIZE_WORKING_RAM - 1), memory->wram7);
695 } else {
696 STORE_32(value, address & (ds->memory.wramSize7 - 1), memory->wramBase7);
697 });
698 break;
699 case DS_REGION_RAM:
700 STM_LOOP(if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
701 STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
702 } else {
703 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
704 });
705 break;
706 case DS_REGION_IO:
707 STM_LOOP(DS7IOWrite32(ds, address & DS_OFFSET_MASK, value));
708 break;
709 case DS_REGION_VRAM:
710 STM_LOOP(if (address < 0x06040000 && memory->vram7[(address & 0x3FFFF) >> 17]) {
711 STORE_32(value, address & 0x1FFFF, memory->vram7[(address & 0x3FFFF) >> 17]);
712 } else {
713 mLOG(DS_MEM, STUB, "Unimplemented DS7 STM: %08X", address);
714 });
715 break;
716 default:
717 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
718 STM_LOOP();
719 break;
720 }
721
722 if (cycleCounter) {
723 *cycleCounter += wait;
724 }
725
726 if (direction & LSM_B) {
727 address -= offset;
728 }
729
730 if (direction & LSM_D) {
731 address -= (popcount << 2) + 4;
732 }
733
734 return address | addressMisalign;
735}
736
737static void DS9SetActiveRegion(struct ARMCore* cpu, uint32_t address) {
738 struct DS* ds = (struct DS*) cpu->master;
739 struct DSCoreMemory* memory = &ds->ds9.memory;
740
741 int newRegion = address >> DS_BASE_OFFSET;
742
743 memory->activeRegion = newRegion;
744 switch (newRegion) {
745 case DS9_REGION_ITCM:
746 case DS9_REGION_ITCM_MIRROR:
747 if (address < ds->memory.itcmSize) {
748 cpu->memory.activeRegion = ds->memory.itcm;
749 cpu->memory.activeMask = DS9_SIZE_ITCM - 1;
750 break;
751 }
752 goto jump_error;
753 case DS_REGION_RAM:
754 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
755 cpu->memory.activeRegion = ds->memory.ram;
756 cpu->memory.activeMask = DS_SIZE_RAM - 1;
757 break;
758 }
759 goto jump_error;
760 case DS9_REGION_BIOS:
761 // TODO: Mask properly
762 if (ds->memory.bios9) {
763 cpu->memory.activeRegion = ds->memory.bios9;
764 cpu->memory.activeMask = DS9_SIZE_BIOS - 1;
765 } else {
766 cpu->memory.activeRegion = _deadbeef;
767 cpu->memory.activeMask = 0;
768 }
769 cpu->memory.activeSeqCycles32 = 0;
770 cpu->memory.activeSeqCycles16 = 0;
771 cpu->memory.activeNonseqCycles32 = 0;
772 cpu->memory.activeNonseqCycles16 = 0;
773 return;
774 default:
775 jump_error:
776 memory->activeRegion = -1;
777 cpu->memory.activeRegion = _deadbeef;
778 cpu->memory.activeMask = 0;
779 mLOG(DS_MEM, FATAL, "Jumped to invalid address: %08X", address);
780 return;
781 }
782 cpu->memory.activeSeqCycles32 = memory->waitstatesPrefetchSeq32[memory->activeRegion];
783 cpu->memory.activeSeqCycles16 = memory->waitstatesPrefetchSeq16[memory->activeRegion];
784 cpu->memory.activeNonseqCycles32 = memory->waitstatesPrefetchNonseq32[memory->activeRegion];
785 cpu->memory.activeNonseqCycles16 = memory->waitstatesPrefetchNonseq16[memory->activeRegion];
786}
787
788uint32_t DS9Load32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
789 struct DS* ds = (struct DS*) cpu->master;
790 struct DSMemory* memory = &ds->memory;
791 uint32_t value = 0;
792 int wait = ds->ds9.memory.waitstatesNonseq32[address >> DS_BASE_OFFSET];
793
794 switch (address >> DS_BASE_OFFSET) {
795 case DS9_REGION_ITCM:
796 case DS9_REGION_ITCM_MIRROR:
797 if (address < memory->itcmSize) {
798 LOAD_32(value, address & (DS9_SIZE_ITCM - 4), memory->itcm);
799 break;
800 }
801 mLOG(DS_MEM, STUB, "Bad DS9 Load32: %08X", address);
802 break;
803 case DS_REGION_WORKING_RAM:
804 if (ds->memory.wramSize9) {
805 LOAD_32(value, address & (ds->memory.wramSize9 - 4), memory->wramBase9);
806 break;
807 }
808 mLOG(DS_MEM, STUB, "Bad DS9 Load32: %08X", address);
809 break;
810 case DS_REGION_RAM:
811 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
812 LOAD_32(value, address & (DS9_SIZE_DTCM - 4), memory->dtcm);
813 break;
814 }
815 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
816 LOAD_32(value, address & (DS_SIZE_RAM - 4), memory->ram);
817 break;
818 }
819 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load32: %08X", address);
820 break;
821 case DS_REGION_IO:
822 value = DS9IORead32(ds, address & 0x00FFFFFC);
823 break;
824 case DS9_REGION_PALETTE_RAM:
825 LOAD_32(value, address & (DS9_SIZE_PALETTE_RAM - 4), ds->video.palette);
826 break;
827 case DS_REGION_VRAM: {
828 unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
829 int i = 0;
830 for (i = 0; i < 9; ++i) {
831 if (mask & (1 << i)) {
832 uint32_t newValue;
833 LOAD_32(newValue, address & _vramMask[i], memory->vramBank[i]);
834 value |= newValue;
835 }
836 }
837 break;
838 }
839 case DS9_REGION_OAM:
840 LOAD_32(value, address & (DS9_SIZE_OAM - 4), ds->video.oam.raw);
841 break;
842 case DS9_REGION_BIOS:
843 // TODO: Fix undersized BIOS
844 // TODO: Fix masking
845 LOAD_32(value, address & (DS9_SIZE_BIOS - 4), memory->bios9);
846 break;
847 default:
848 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
849 LOAD_32(value, address & (DS9_SIZE_DTCM - 4), memory->dtcm);
850 break;
851 }
852 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load32: %08X", address);
853 break;
854 }
855
856 if (cycleCounter) {
857 wait += 2;
858 *cycleCounter += wait;
859 }
860 // Unaligned 32-bit loads are "rotated" so they make some semblance of sense
861 int rotate = (address & 3) << 3;
862 return ROR(value, rotate);
863}
864
865uint32_t DS9Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
866 struct DS* ds = (struct DS*) cpu->master;
867 struct DSMemory* memory = &ds->memory;
868 uint32_t value = 0;
869 int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
870
871 switch (address >> DS_BASE_OFFSET) {
872 case DS9_REGION_ITCM:
873 case DS9_REGION_ITCM_MIRROR:
874 if (address < memory->itcmSize) {
875 LOAD_16(value, address & (DS9_SIZE_ITCM - 2), memory->itcm);
876 break;
877 }
878 mLOG(DS_MEM, STUB, "Bad DS9 Load16: %08X", address);
879 break;
880 case DS_REGION_WORKING_RAM:
881 if (ds->memory.wramSize9) {
882 LOAD_16(value, address & (ds->memory.wramSize9 - 2), memory->wramBase9);
883 break;
884 }
885 mLOG(DS_MEM, STUB, "Bad DS9 Load16: %08X", address);
886 break;
887 case DS_REGION_RAM:
888 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
889 LOAD_16(value, address & (DS9_SIZE_DTCM - 2), memory->dtcm);
890 break;
891 }
892 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
893 LOAD_16(value, address & (DS_SIZE_RAM - 2), memory->ram);
894 break;
895 }
896 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load16: %08X", address);
897 case DS_REGION_IO:
898 value = DS9IORead(ds, address & DS_OFFSET_MASK);
899 break;
900 case DS9_REGION_PALETTE_RAM:
901 LOAD_16(value, address & (DS9_SIZE_PALETTE_RAM - 2), ds->video.palette);
902 break;
903 case DS_REGION_VRAM: {
904 unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
905 int i = 0;
906 for (i = 0; i < 9; ++i) {
907 if (mask & (1 << i)) {
908 uint32_t newValue;
909 LOAD_16(newValue, address & _vramMask[i], memory->vramBank[i]);
910 value |= newValue;
911 }
912 }
913 break;
914 }
915 case DS9_REGION_OAM:
916 LOAD_16(value, address & (DS9_SIZE_OAM - 2), ds->video.oam.raw);
917 break;
918 case DS9_REGION_BIOS:
919 // TODO: Fix undersized BIOS
920 // TODO: Fix masking
921 LOAD_16(value, address & (DS9_SIZE_BIOS - 2), memory->bios9);
922 break;
923 default:
924 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
925 LOAD_16(value, address & (DS9_SIZE_DTCM - 2), memory->dtcm);
926 break;
927 }
928 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load16: %08X", address);
929 break;
930 }
931
932 if (cycleCounter) {
933 wait += 2;
934 *cycleCounter += wait;
935 }
936 // Unaligned 16-bit loads are "unpredictable", TODO: See what DS does
937 int rotate = (address & 1) << 3;
938 return ROR(value, rotate);
939}
940
941uint32_t DS9Load8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
942 struct DS* ds = (struct DS*) cpu->master;
943 struct DSMemory* memory = &ds->memory;
944 uint32_t value = 0;
945 int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
946
947 switch (address >> DS_BASE_OFFSET) {
948 case DS9_REGION_ITCM:
949 case DS9_REGION_ITCM_MIRROR:
950 if (address < memory->itcmSize) {
951 value = ((uint8_t*) memory->itcm)[address & (DS9_SIZE_ITCM - 1)];
952 break;
953 }
954 mLOG(DS_MEM, STUB, "Bad DS9 Load8: %08X", address);
955 break;
956 case DS_REGION_WORKING_RAM:
957 if (ds->memory.wramSize9) {
958 value = ((uint8_t*) memory->wramBase9)[address & (memory->wramSize9 - 1)];
959 break;
960 }
961 mLOG(DS_MEM, STUB, "Bad DS9 Load8: %08X", address);
962 break;
963 case DS_REGION_RAM:
964 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
965 value = ((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)];
966 break;
967 }
968 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
969 value = ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)];
970 break;
971 }
972 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load8: %08X", address);
973 case DS_REGION_IO:
974 value = (DS9IORead(ds, address & 0xFFFE) >> ((address & 0x0001) << 3)) & 0xFF;
975 break;
976 case DS_REGION_VRAM: {
977 unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
978 int i = 0;
979 for (i = 0; i < 9; ++i) {
980 if (mask & (1 << i)) {
981 value |= ((uint8_t*) memory->vramBank[i])[address & _vramMask[i]];
982 }
983 }
984 break;
985 }
986 case DS9_REGION_BIOS:
987 // TODO: Fix undersized BIOS
988 // TODO: Fix masking
989 value = ((uint8_t*) memory->bios9)[address & (DS9_SIZE_BIOS - 1)];
990 break;
991 default:
992 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
993 value = ((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)];
994 break;
995 }
996 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load8: %08X", address);
997 break;
998 }
999
1000 if (cycleCounter) {
1001 wait += 2;
1002 *cycleCounter += wait;
1003 }
1004 return value;
1005}
1006
1007void DS9Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) {
1008 struct DS* ds = (struct DS*) cpu->master;
1009 struct DSMemory* memory = &ds->memory;
1010 int wait = ds->ds9.memory.waitstatesNonseq32[address >> DS_BASE_OFFSET];
1011
1012 switch (address >> DS_BASE_OFFSET) {
1013 case DS9_REGION_ITCM:
1014 case DS9_REGION_ITCM_MIRROR:
1015 if (address < memory->itcmSize) {
1016 STORE_32(value, address & (DS9_SIZE_ITCM - 4), memory->itcm);
1017 break;
1018 }
1019 mLOG(DS_MEM, STUB, "Bad DS9 Store32: %08X:%08X", address, value);
1020 break;
1021 case DS_REGION_WORKING_RAM:
1022 if (ds->memory.wramSize9) {
1023 STORE_32(value, address & (ds->memory.wramSize9 - 4), memory->wramBase9);
1024 break;
1025 }
1026 mLOG(DS_MEM, STUB, "Bad DS9 Store32: %08X:%08X", address, value);
1027 break;
1028 case DS_REGION_RAM:
1029 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1030 STORE_32(value, address & (DS9_SIZE_DTCM - 4), memory->dtcm);
1031 break;
1032 }
1033 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1034 STORE_32(value, address & (DS_SIZE_RAM - 4), memory->ram);
1035 break;
1036 }
1037 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store32: %08X:%08X", address, value);
1038 break;
1039 case DS_REGION_IO:
1040 DS9IOWrite32(ds, address & DS_OFFSET_MASK, value);
1041 break;
1042 case DS9_REGION_PALETTE_RAM:
1043 STORE_32(value, address & (DS9_SIZE_PALETTE_RAM - 4), ds->video.palette);
1044 ds->video.renderer->writePalette(ds->video.renderer, (address & (DS9_SIZE_PALETTE_RAM - 4)) + 2, value >> 16);
1045 ds->video.renderer->writePalette(ds->video.renderer, address & (DS9_SIZE_PALETTE_RAM - 4), value);
1046 break;
1047 case DS_REGION_VRAM: {
1048 unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
1049 int i = 0;
1050 for (i = 0; i < 9; ++i) {
1051 if (mask & (1 << i)) {
1052 STORE_32(value, address & _vramMask[i], memory->vramBank[i]);
1053 }
1054 }
1055 break;
1056 }
1057 case DS9_REGION_OAM:
1058 STORE_32(value, address & (DS9_SIZE_OAM - 4), ds->video.oam.raw);
1059 ds->video.renderer->writeOAM(ds->video.renderer, (address & (DS9_SIZE_OAM - 4)) >> 1);
1060 ds->video.renderer->writeOAM(ds->video.renderer, ((address & (DS9_SIZE_OAM - 4)) >> 1) + 1);
1061 break;
1062 default:
1063 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1064 STORE_32(value, address & (DS9_SIZE_DTCM - 4), memory->dtcm);
1065 break;
1066 }
1067 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store32: %08X:%08X", address, value);
1068 break;
1069 }
1070
1071 if (cycleCounter) {
1072 ++wait;
1073 *cycleCounter += wait;
1074 }
1075}
1076
1077void DS9Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
1078 struct DS* ds = (struct DS*) cpu->master;
1079 struct DSMemory* memory = &ds->memory;
1080 int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
1081
1082 switch (address >> DS_BASE_OFFSET) {
1083 case DS9_REGION_ITCM:
1084 case DS9_REGION_ITCM_MIRROR:
1085 if (address < memory->itcmSize) {
1086 STORE_16(value, address & (DS9_SIZE_ITCM - 2), memory->itcm);
1087 break;
1088 }
1089 mLOG(DS_MEM, STUB, "Bad DS9 Store16: %08X:%04X", address, value);
1090 break;
1091 case DS_REGION_WORKING_RAM:
1092 if (ds->memory.wramSize9) {
1093 STORE_16(value, address & (ds->memory.wramSize9 - 2), memory->wramBase9);
1094 break;
1095 }
1096 mLOG(DS_MEM, STUB, "Bad DS9 Store16: %08X:%04X", address, value);
1097 break;
1098 case DS_REGION_RAM:
1099 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1100 STORE_16(value, address & (DS9_SIZE_DTCM - 2), memory->dtcm);
1101 break;
1102 }
1103 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1104 STORE_16(value, address & (DS_SIZE_RAM - 2), memory->ram);
1105 break;
1106 }
1107 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store16: %08X:%04X", address, value);
1108 break;
1109 case DS_REGION_IO:
1110 DS9IOWrite(ds, address & DS_OFFSET_MASK, value);
1111 break;
1112 case DS9_REGION_PALETTE_RAM:
1113 STORE_16(value, address & (DS9_SIZE_PALETTE_RAM - 2), ds->video.palette);
1114 ds->video.renderer->writePalette(ds->video.renderer, address & (DS9_SIZE_PALETTE_RAM - 2), value);
1115 break;
1116 case DS_REGION_VRAM: {
1117 unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
1118 int i = 0;
1119 for (i = 0; i < 9; ++i) {
1120 if (mask & (1 << i)) {
1121 STORE_16(value, address & _vramMask[i], memory->vramBank[i]);
1122 }
1123 }
1124 break;
1125 }
1126 case DS9_REGION_OAM:
1127 STORE_16(value, address & (DS9_SIZE_OAM - 2), ds->video.oam.raw);
1128 ds->video.renderer->writeOAM(ds->video.renderer, (address & (DS9_SIZE_OAM - 2)) >> 1);
1129 break;
1130 default:
1131 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1132 STORE_16(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1133 break;
1134 }
1135 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store16: %08X:%04X", address, value);
1136 break;
1137 }
1138
1139 if (cycleCounter) {
1140 ++wait;
1141 *cycleCounter += wait;
1142 }
1143}
1144
1145void DS9Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
1146 struct DS* ds = (struct DS*) cpu->master;
1147 struct DSMemory* memory = &ds->memory;
1148 int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
1149
1150 switch (address >> DS_BASE_OFFSET) {
1151 case DS9_REGION_ITCM:
1152 case DS9_REGION_ITCM_MIRROR:
1153 if (address < memory->itcmSize) {
1154 ((uint8_t*) memory->itcm)[address & (DS9_SIZE_ITCM - 1)] = value;
1155 break;
1156 }
1157 mLOG(DS_MEM, STUB, "Bad DS9 Store8: %08X:%02X", address, value);
1158 break;
1159 case DS_REGION_WORKING_RAM:
1160 if (ds->memory.wramSize9) {
1161 ((uint8_t*) memory->wramBase9)[address & (ds->memory.wramSize9 - 1)] = value;
1162 break;
1163 }
1164 mLOG(DS_MEM, STUB, "Bad DS9 Store8: %08X:%02X", address, value);
1165 break;
1166 case DS_REGION_RAM:
1167 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1168 ((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)] = value;
1169 break;
1170 }
1171 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1172 ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)] = value;
1173 break;
1174 }
1175 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store8: %08X:%02X", address, value);
1176 case DS_REGION_IO:
1177 DS9IOWrite8(ds, address & DS_OFFSET_MASK, value);
1178 break;
1179 default:
1180 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1181 ((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)] = value;
1182 break;
1183 }
1184 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store8: %08X:%02X", address, value);
1185 break;
1186 }
1187
1188 if (cycleCounter) {
1189 ++wait;
1190 *cycleCounter += wait;
1191 }
1192}
1193
1194uint32_t DS9LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
1195 struct DS* ds = (struct DS*) cpu->master;
1196 struct DSMemory* memory = &ds->memory;
1197 char* ws32 = ds->ds9.memory.waitstatesNonseq32;
1198 uint32_t value;
1199 int wait = 0;
1200
1201 int i;
1202 int offset = 4;
1203 int popcount = 0;
1204 if (direction & LSM_D) {
1205 offset = -4;
1206 popcount = popcount32(mask);
1207 address -= (popcount << 2) - 4;
1208 }
1209
1210 if (direction & LSM_B) {
1211 address += offset;
1212 }
1213
1214 uint32_t addressMisalign = address & 0x3;
1215 address &= 0xFFFFFFFC;
1216
1217 switch (address >> DS_BASE_OFFSET) {
1218 case DS9_REGION_ITCM:
1219 case DS9_REGION_ITCM_MIRROR:
1220 LDM_LOOP(if (address < memory->itcmSize) {
1221 LOAD_32(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
1222 } else {
1223 mLOG(DS_MEM, STUB, "Bad DS9 LDM: %08X:%08X", address, value);
1224 });
1225 break;
1226 case DS_REGION_WORKING_RAM:
1227 LDM_LOOP(if (ds->memory.wramSize9) {
1228 LOAD_32(value, address & (ds->memory.wramSize9 - 4), memory->wramBase9);
1229 } else {
1230 mLOG(DS_MEM, STUB, "Bad DS9 LDM: %08X", address);
1231 });
1232 break;
1233 case DS_REGION_RAM:
1234 LDM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1235 LOAD_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1236 } else if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1237 LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
1238 } else {
1239 mLOG(DS_MEM, STUB, "Unimplemented DS9 LDM: %08X", address);
1240 });
1241 break;
1242 case DS_REGION_IO:
1243 LDM_LOOP(value = DS9IORead32(ds, address));
1244 break;
1245 case DS9_REGION_PALETTE_RAM:
1246 LDM_LOOP(LOAD_32(value, address & (DS9_SIZE_PALETTE_RAM - 1), ds->video.palette));
1247 break;
1248 case DS_REGION_VRAM:
1249 LDM_LOOP(unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
1250 value = 0;
1251 int i = 0;
1252 for (i = 0; i < 9; ++i) {
1253 if (mask & (1 << i)) {
1254 uint32_t newValue;
1255 LOAD_32(newValue, address & _vramMask[i], memory->vramBank[i]);
1256 value |= newValue;
1257 }
1258 });
1259 break;
1260 case DS9_REGION_OAM:
1261 LDM_LOOP(LOAD_32(value, address & (DS9_SIZE_OAM - 1), ds->video.oam.raw));
1262 break;
1263 default:
1264 LDM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1265 LOAD_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1266 } else {
1267 mLOG(DS_MEM, STUB, "Unimplemented DS9 LDM: %08X", address);
1268 });
1269 break;
1270 }
1271
1272 if (cycleCounter) {
1273 ++wait;
1274 *cycleCounter += wait;
1275 }
1276
1277 if (direction & LSM_B) {
1278 address -= offset;
1279 }
1280
1281 if (direction & LSM_D) {
1282 address -= (popcount << 2) + 4;
1283 }
1284
1285 return address | addressMisalign;
1286}
1287
1288
1289uint32_t DS9StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
1290 struct DS* ds = (struct DS*) cpu->master;
1291 struct DSMemory* memory = &ds->memory;
1292 char* ws32 = ds->ds9.memory.waitstatesNonseq32;
1293 uint32_t value;
1294 int wait = 0;
1295
1296 int i;
1297 int offset = 4;
1298 int popcount = 0;
1299 if (direction & LSM_D) {
1300 offset = -4;
1301 popcount = popcount32(mask);
1302 address -= (popcount << 2) - 4;
1303 }
1304
1305 if (direction & LSM_B) {
1306 address += offset;
1307 }
1308
1309 uint32_t addressMisalign = address & 0x3;
1310 address &= 0xFFFFFFFC;
1311
1312 switch (address >> DS_BASE_OFFSET) {
1313 case DS9_REGION_ITCM:
1314 case DS9_REGION_ITCM_MIRROR:
1315 STM_LOOP(if (address < memory->itcmSize) {
1316 STORE_32(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
1317 } else {
1318 mLOG(DS_MEM, STUB, "Bad DS9 STM: %08X:%08X", address, value);
1319 });
1320 break;
1321 case DS_REGION_WORKING_RAM:
1322 STM_LOOP(if (ds->memory.wramSize9) {
1323 STORE_32(value, address & (ds->memory.wramSize9 - 4), memory->wramBase9);
1324 } else {
1325 mLOG(DS_MEM, STUB, "Bad DS9 STM: %08X", address);
1326 });
1327 break;
1328 case DS_REGION_RAM:
1329 STM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1330 STORE_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1331 } else if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1332 STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
1333 } else {
1334 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
1335 });
1336 break;
1337 case DS_REGION_IO:
1338 STM_LOOP(DS9IOWrite32(ds, address & DS_OFFSET_MASK, value));
1339 break;
1340 case DS9_REGION_PALETTE_RAM:
1341 STM_LOOP(STORE_32(value, address & (DS9_SIZE_PALETTE_RAM - 1), ds->video.palette);
1342 ds->video.renderer->writePalette(ds->video.renderer, (address & (DS9_SIZE_PALETTE_RAM - 4)) + 2, value >> 16);
1343 ds->video.renderer->writePalette(ds->video.renderer, address & (DS9_SIZE_PALETTE_RAM - 4), value));
1344 break;
1345 case DS_REGION_VRAM:
1346 STM_LOOP(unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
1347 int i = 0;
1348 for (i = 0; i < 9; ++i) {
1349 if (mask & (1 << i)) {
1350 STORE_32(value, address & _vramMask[i], memory->vramBank[i]);
1351 }
1352 });
1353 break;
1354 case DS9_REGION_OAM:
1355 STM_LOOP(STORE_32(value, address & (DS9_SIZE_OAM - 1), ds->video.oam.raw);
1356 ds->video.renderer->writeOAM(ds->video.renderer, (address & (DS9_SIZE_OAM - 4)) >> 1);
1357 ds->video.renderer->writeOAM(ds->video.renderer, ((address & (DS9_SIZE_OAM - 4)) >> 1) + 1));
1358 break;
1359 default:
1360 STM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1361 STORE_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1362 } else {
1363 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
1364 });
1365 break;
1366 }
1367
1368 if (cycleCounter) {
1369 *cycleCounter += wait;
1370 }
1371
1372 if (direction & LSM_B) {
1373 address -= offset;
1374 }
1375
1376 if (direction & LSM_D) {
1377 address -= (popcount << 2) + 4;
1378 }
1379
1380 return address | addressMisalign;
1381}
1382
1383int32_t DSMemoryStall(struct ARMCore* cpu, int32_t wait) {
1384 return wait;
1385}
1386
1387void DSConfigureWRAM(struct DSMemory* memory, uint8_t config) {
1388 switch (config & 3) {
1389 case 0:
1390 memory->wramSize7 = 0;
1391 memory->wramBase7 = NULL;
1392 memory->wramSize9 = DS_SIZE_WORKING_RAM;
1393 memory->wramBase9 = memory->wramBase;
1394 break;
1395 case 1:
1396 memory->wramSize7 = DS_SIZE_WORKING_RAM >> 1;
1397 memory->wramBase7 = memory->wram;
1398 memory->wramSize9 = DS_SIZE_WORKING_RAM >> 1;
1399 memory->wramBase9 = &memory->wramBase[DS_SIZE_WORKING_RAM >> 3];
1400 break;
1401 case 2:
1402 memory->wramSize7 = DS_SIZE_WORKING_RAM >> 1;
1403 memory->wramBase7 = &memory->wram[DS_SIZE_WORKING_RAM >> 3];
1404 memory->wramSize9 = DS_SIZE_WORKING_RAM >> 1;
1405 memory->wramBase9 = memory->wramBase;
1406 break;
1407 case 3:
1408 memory->wramSize7 = DS_SIZE_WORKING_RAM;
1409 memory->wramBase7 = memory->wramBase;
1410 memory->wramSize9 = 0;
1411 memory->wramBase9 = NULL;
1412 break;
1413 }
1414}
1415
1416void DSConfigureExternalMemory(struct DS* ds, uint16_t config) {
1417 // TODO: GBA params
1418 ds->memory.slot1Owner = config & 0x0800;
1419 ds->memory.slot2Owner = config & 0x0080;
1420 ds->memory.io7[DS7_REG_EXMEMSTAT >> 1] = config;
1421
1422 ds->ds7.memory.slot1Access = ds->memory.slot1Owner;
1423 ds->ds9.memory.slot1Access = !ds->memory.slot1Owner;
1424}
1425
1426static unsigned _selectVRAM(struct DSMemory* memory, uint32_t offset) {
1427 unsigned mask = 0;
1428 offset &= 0x3FF;
1429 mask |= memory->vramMirror[0][offset & 0x3F] & memory->vramMode[0][offset >> 7];
1430 mask |= memory->vramMirror[1][offset & 0x3F] & memory->vramMode[1][offset >> 7];
1431 mask |= memory->vramMirror[2][offset & 0x3F] & memory->vramMode[2][offset >> 7];
1432 mask |= memory->vramMirror[3][offset & 0x3F] & memory->vramMode[3][offset >> 7];
1433 mask |= memory->vramMirror[4][offset & 0x3F] & memory->vramMode[4][offset >> 7];
1434 mask |= memory->vramMirror[5][offset & 0x3F] & memory->vramMode[5][offset >> 7];
1435 mask |= memory->vramMirror[6][offset & 0x3F] & memory->vramMode[6][offset >> 7];
1436 mask |= memory->vramMirror[7][offset & 0x3F] & memory->vramMode[7][offset >> 7];
1437 mask |= memory->vramMirror[8][offset & 0x3F] & memory->vramMode[8][offset >> 7];
1438 return mask;
1439}