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, 2, 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, 1, 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_SLOT2:
318 case DS_REGION_SLOT2_EX:
319 case DS_REGION_SLOT2_SRAM:
320 value = 0xFFFFFFFF;
321 break;
322 case DS_REGION_VRAM:
323 if (address < 0x06040000 && memory->vram7[(address & 0x3FFFF) >> 17]) {
324 LOAD_32(value, address & 0x1FFFC, memory->vram7[(address & 0x3FFFF) >> 17]);
325 break;
326 }
327 // Fall through
328 default:
329 mLOG(DS_MEM, STUB, "Unimplemented DS7 Load32: %08X", address);
330 break;
331 }
332
333 if (cycleCounter) {
334 wait += 2;
335 *cycleCounter += wait;
336 }
337 // Unaligned 32-bit loads are "rotated" so they make some semblance of sense
338 int rotate = (address & 3) << 3;
339 return ROR(value, rotate);
340}
341
342uint32_t DS7Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
343 struct DS* ds = (struct DS*) cpu->master;
344 struct DSMemory* memory = &ds->memory;
345 uint32_t value = 0;
346 int wait = ds->ds7.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
347
348 switch (address >> DS_BASE_OFFSET) {
349 case DS7_REGION_BIOS:
350 LOAD_16(value, address & (DS7_SIZE_BIOS - 2), memory->bios7);
351 break;
352 case DS_REGION_WORKING_RAM:
353 if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
354 LOAD_16(value, address & (DS7_SIZE_WORKING_RAM - 2), memory->wram7);
355 } else {
356 LOAD_16(value, address & (ds->memory.wramSize7 - 2), memory->wramBase7);
357 }
358 break;
359 case DS_REGION_RAM:
360 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
361 LOAD_16(value, address & (DS_SIZE_RAM - 1), memory->ram);
362 break;
363 }
364 mLOG(DS_MEM, STUB, "Unimplemented DS7 Load16: %08X", address);
365 case DS_REGION_IO:
366 value = DS7IORead(ds, address & DS_OFFSET_MASK);
367 break;
368 case DS_REGION_SLOT2:
369 case DS_REGION_SLOT2_EX:
370 case DS_REGION_SLOT2_SRAM:
371 value = 0xFFFF;
372 break;
373 case DS_REGION_VRAM:
374 if (address < 0x06040000 && memory->vram7[(address & 0x3FFFF) >> 17]) {
375 LOAD_16(value, address & 0x1FFFE, memory->vram7[(address & 0x3FFFF) >> 17]);
376 break;
377 }
378 // Fall through
379 default:
380 mLOG(DS_MEM, STUB, "Unimplemented DS7 Load16: %08X", address);
381 break;
382 }
383
384 if (cycleCounter) {
385 wait += 2;
386 *cycleCounter += wait;
387 }
388 // Unaligned 16-bit loads are "unpredictable", TODO: See what DS does
389 int rotate = (address & 1) << 3;
390 return ROR(value, rotate);
391}
392
393uint32_t DS7Load8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
394 struct DS* ds = (struct DS*) cpu->master;
395 struct DSMemory* memory = &ds->memory;
396 uint32_t value = 0;
397 int wait = ds->ds7.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
398
399 switch (address >> DS_BASE_OFFSET) {
400 case DS7_REGION_BIOS:
401 value = ((uint8_t*) memory->bios7)[address & (DS7_SIZE_BIOS - 1)];
402 break;
403 case DS_REGION_WORKING_RAM:
404 if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
405 value = ((uint8_t*) memory->wram7)[address & (DS7_SIZE_WORKING_RAM - 1)];
406 } else {
407 value = ((uint8_t*) memory->wramBase7)[address & (ds->memory.wramSize7 - 1)];
408 }
409 break;
410 case DS_REGION_RAM:
411 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
412 value = ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)];
413 break;
414 }
415 mLOG(DS_MEM, STUB, "Unimplemented DS7 Load8: %08X", address);
416 break;
417 case DS_REGION_IO:
418 value = (DS7IORead(ds, address & 0xFFFE) >> ((address & 0x0001) << 3)) & 0xFF;
419 break;
420 case DS_REGION_SLOT2:
421 case DS_REGION_SLOT2_EX:
422 case DS_REGION_SLOT2_SRAM:
423 value = 0xFF;
424 break;
425 default:
426 mLOG(DS_MEM, STUB, "Unimplemented DS7 Load8: %08X", address);
427 break;
428 }
429
430 if (cycleCounter) {
431 wait += 2;
432 *cycleCounter += wait;
433 }
434 return value;
435}
436
437void DS7Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) {
438 struct DS* ds = (struct DS*) cpu->master;
439 struct DSMemory* memory = &ds->memory;
440 int wait = ds->ds7.memory.waitstatesNonseq32[address >> DS_BASE_OFFSET];
441
442 switch (address >> DS_BASE_OFFSET) {
443 case DS_REGION_WORKING_RAM:
444 if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
445 STORE_32(value, address & (DS7_SIZE_WORKING_RAM - 4), memory->wram7);
446 } else {
447 STORE_32(value, address & (ds->memory.wramSize7 - 4), memory->wramBase7);
448 }
449 break;
450 case DS_REGION_RAM:
451 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
452 STORE_32(value, address & (DS_SIZE_RAM - 4), memory->ram);
453 break;
454 }
455 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store32: %08X:%08X", address, value);
456 break;
457 case DS_REGION_IO:
458 DS7IOWrite32(ds, address & DS_OFFSET_MASK, value);
459 break;
460 case DS_REGION_VRAM:
461 if (address < 0x06040000 && memory->vram7[(address & 0x3FFFF) >> 17]) {
462 STORE_32(value, address & 0x1FFFC, memory->vram7[(address & 0x3FFFF) >> 17]);
463 break;
464 }
465 // Fall through
466 default:
467 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store32: %08X:%08X", address, value);
468 break;
469 }
470
471 if (cycleCounter) {
472 ++wait;
473 *cycleCounter += wait;
474 }
475}
476
477void DS7Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
478 struct DS* ds = (struct DS*) cpu->master;
479 struct DSMemory* memory = &ds->memory;
480 int wait = ds->ds7.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
481
482 switch (address >> DS_BASE_OFFSET) {
483 case DS_REGION_WORKING_RAM:
484 if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
485 STORE_16(value, address & (DS7_SIZE_WORKING_RAM - 2), memory->wram7);
486 } else {
487 STORE_16(value, address & (ds->memory.wramSize7 - 2), memory->wramBase7);
488 }
489 break;
490 case DS_REGION_RAM:
491 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
492 STORE_16(value, address & (DS_SIZE_RAM - 2), memory->ram);
493 break;
494 }
495 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store16: %08X:%04X", address, value);
496 break;
497 case DS_REGION_IO:
498 DS7IOWrite(ds, address & DS_OFFSET_MASK, value);
499 break;
500 case DS_REGION_VRAM:
501 if (address < 0x06040000 && memory->vram7[(address & 0x3FFFF) >> 17]) {
502 STORE_16(value, address & 0x1FFFE, memory->vram7[(address & 0x3FFFF) >> 17]);
503 break;
504 }
505 // Fall through
506 default:
507 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store16: %08X:%04X", address, value);
508 break;
509 }
510
511 if (cycleCounter) {
512 ++wait;
513 *cycleCounter += wait;
514 }
515}
516
517void DS7Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
518 struct DS* ds = (struct DS*) cpu->master;
519 struct DSMemory* memory = &ds->memory;
520 int wait = ds->ds7.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
521
522 switch (address >> DS_BASE_OFFSET) {
523 case DS_REGION_WORKING_RAM:
524 if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
525 ((uint8_t*) memory->wram7)[address & (DS7_SIZE_WORKING_RAM - 1)] = value;
526 } else {
527 ((uint8_t*) memory->wramBase7)[address & (ds->memory.wramSize7 - 1)] = value;
528 }
529 break;
530 case DS_REGION_RAM:
531 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
532 ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)] = value;
533 break;
534 }
535 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store8: %08X:%02X", address, value);
536 case DS_REGION_IO:
537 DS7IOWrite8(ds, address & DS_OFFSET_MASK, value);
538 break;
539 default:
540 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store8: %08X:%02X", address, value);
541 break;
542 }
543
544 if (cycleCounter) {
545 ++wait;
546 *cycleCounter += wait;
547 }
548}
549
550#define LDM_LOOP(LDM) \
551 for (i = 0; i < 16; i += 4) { \
552 if (UNLIKELY(mask & (1 << i))) { \
553 LDM; \
554 cpu->gprs[i] = value; \
555 ++wait; \
556 wait += ws32[address >> DS_BASE_OFFSET]; \
557 address += 4; \
558 } \
559 if (UNLIKELY(mask & (2 << i))) { \
560 LDM; \
561 cpu->gprs[i + 1] = value; \
562 ++wait; \
563 wait += ws32[address >> DS_BASE_OFFSET]; \
564 address += 4; \
565 } \
566 if (UNLIKELY(mask & (4 << i))) { \
567 LDM; \
568 cpu->gprs[i + 2] = value; \
569 ++wait; \
570 wait += ws32[address >> DS_BASE_OFFSET]; \
571 address += 4; \
572 } \
573 if (UNLIKELY(mask & (8 << i))) { \
574 LDM; \
575 cpu->gprs[i + 3] = value; \
576 ++wait; \
577 wait += ws32[address >> DS_BASE_OFFSET]; \
578 address += 4; \
579 } \
580 }
581
582#define STM_LOOP(STM) \
583 for (i = 0; i < 16; i += 4) { \
584 if (UNLIKELY(mask & (1 << i))) { \
585 value = cpu->gprs[i]; \
586 STM; \
587 ++wait; \
588 wait += ws32[address >> DS_BASE_OFFSET]; \
589 address += 4; \
590 } \
591 if (UNLIKELY(mask & (2 << i))) { \
592 value = cpu->gprs[i + 1]; \
593 STM; \
594 ++wait; \
595 wait += ws32[address >> DS_BASE_OFFSET]; \
596 address += 4; \
597 } \
598 if (UNLIKELY(mask & (4 << i))) { \
599 value = cpu->gprs[i + 2]; \
600 STM; \
601 ++wait; \
602 wait += ws32[address >> DS_BASE_OFFSET]; \
603 address += 4; \
604 } \
605 if (UNLIKELY(mask & (8 << i))) { \
606 value = cpu->gprs[i + 3]; \
607 STM; \
608 ++wait; \
609 wait += ws32[address >> DS_BASE_OFFSET]; \
610 address += 4; \
611 } \
612 }
613
614uint32_t DS7LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
615 struct DS* ds = (struct DS*) cpu->master;
616 struct DSMemory* memory = &ds->memory;
617 char* ws32 = ds->ds7.memory.waitstatesNonseq32;
618 uint32_t value;
619 int wait = 0;
620
621 int i;
622 int offset = 4;
623 int popcount = 0;
624 if (direction & LSM_D) {
625 offset = -4;
626 popcount = popcount32(mask);
627 address -= (popcount << 2) - 4;
628 }
629
630 if (direction & LSM_B) {
631 address += offset;
632 }
633
634 uint32_t addressMisalign = address & 0x3;
635 address &= 0xFFFFFFFC;
636
637 switch (address >> DS_BASE_OFFSET) {
638 case DS_REGION_WORKING_RAM:
639 LDM_LOOP(if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
640 LOAD_32(value, address & (DS7_SIZE_WORKING_RAM - 1), memory->wram7);
641 } else {
642 LOAD_32(value, address & (ds->memory.wramSize7 - 1), memory->wramBase7);
643 });
644 break;
645 case DS_REGION_RAM:
646 LDM_LOOP(if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
647 LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
648 } else {
649 mLOG(DS_MEM, STUB, "Unimplemented DS7 LDM: %08X", address);
650 });
651 break;
652 case DS_REGION_IO:
653 LDM_LOOP(value = DS7IORead32(ds, address));
654 break;
655 case DS_REGION_VRAM:
656 LDM_LOOP(if (address < 0x06040000 && memory->vram7[(address & 0x3FFFF) >> 17]) {
657 LOAD_32(value, address & 0x1FFFF, memory->vram7[(address & 0x3FFFF) >> 17]);
658 } else {
659 value = 0;
660 mLOG(DS_MEM, STUB, "Unimplemented DS7 LDM: %08X", address);
661 });
662 break;
663 default:
664 mLOG(DS_MEM, STUB, "Unimplemented DS7 LDM: %08X", address);
665 LDM_LOOP(value = 0);
666 }
667
668 if (cycleCounter) {
669 ++wait;
670 *cycleCounter += wait;
671 }
672
673 if (direction & LSM_B) {
674 address -= offset;
675 }
676
677 if (direction & LSM_D) {
678 address -= (popcount << 2) + 4;
679 }
680
681 return address | addressMisalign;
682}
683
684uint32_t DS7StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
685 struct DS* ds = (struct DS*) cpu->master;
686 struct DSMemory* memory = &ds->memory;
687 char* ws32 = ds->ds7.memory.waitstatesNonseq32;
688 uint32_t value;
689 int wait = 0;
690
691 int i;
692 int offset = 4;
693 int popcount = 0;
694 if (direction & LSM_D) {
695 offset = -4;
696 popcount = popcount32(mask);
697 address -= (popcount << 2) - 4;
698 }
699
700 if (direction & LSM_B) {
701 address += offset;
702 }
703
704 uint32_t addressMisalign = address & 0x3;
705 address &= 0xFFFFFFFC;
706
707 switch (address >> DS_BASE_OFFSET) {
708 case DS_REGION_WORKING_RAM:
709 STM_LOOP(if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
710 STORE_32(value, address & (DS7_SIZE_WORKING_RAM - 1), memory->wram7);
711 } else {
712 STORE_32(value, address & (ds->memory.wramSize7 - 1), memory->wramBase7);
713 });
714 break;
715 case DS_REGION_RAM:
716 STM_LOOP(if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
717 STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
718 } else {
719 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
720 });
721 break;
722 case DS_REGION_IO:
723 STM_LOOP(DS7IOWrite32(ds, address & DS_OFFSET_MASK, value));
724 break;
725 case DS_REGION_VRAM:
726 STM_LOOP(if (address < 0x06040000 && memory->vram7[(address & 0x3FFFF) >> 17]) {
727 STORE_32(value, address & 0x1FFFF, memory->vram7[(address & 0x3FFFF) >> 17]);
728 } else {
729 mLOG(DS_MEM, STUB, "Unimplemented DS7 STM: %08X", address);
730 });
731 break;
732 default:
733 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
734 STM_LOOP();
735 break;
736 }
737
738 if (cycleCounter) {
739 *cycleCounter += wait;
740 }
741
742 if (direction & LSM_B) {
743 address -= offset;
744 }
745
746 if (direction & LSM_D) {
747 address -= (popcount << 2) + 4;
748 }
749
750 return address | addressMisalign;
751}
752
753static void DS9SetActiveRegion(struct ARMCore* cpu, uint32_t address) {
754 struct DS* ds = (struct DS*) cpu->master;
755 struct DSCoreMemory* memory = &ds->ds9.memory;
756
757 int newRegion = address >> DS_BASE_OFFSET;
758
759 memory->activeRegion = newRegion;
760 switch (newRegion) {
761 case DS9_REGION_ITCM:
762 case DS9_REGION_ITCM_MIRROR:
763 if (address < ds->memory.itcmSize) {
764 cpu->memory.activeRegion = ds->memory.itcm;
765 cpu->memory.activeMask = DS9_SIZE_ITCM - 1;
766 break;
767 }
768 goto jump_error;
769 case DS_REGION_RAM:
770 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
771 cpu->memory.activeRegion = ds->memory.ram;
772 cpu->memory.activeMask = DS_SIZE_RAM - 1;
773 break;
774 }
775 goto jump_error;
776 case DS9_REGION_BIOS:
777 // TODO: Mask properly
778 if (ds->memory.bios9) {
779 cpu->memory.activeRegion = ds->memory.bios9;
780 cpu->memory.activeMask = DS9_SIZE_BIOS - 1;
781 } else {
782 cpu->memory.activeRegion = _deadbeef;
783 cpu->memory.activeMask = 0;
784 }
785 cpu->memory.activeSeqCycles32 = 0;
786 cpu->memory.activeSeqCycles16 = 0;
787 cpu->memory.activeNonseqCycles32 = 0;
788 cpu->memory.activeNonseqCycles16 = 0;
789 return;
790 case DS_REGION_VRAM:
791 if (address >= 0x06800000) {
792 unsigned mask = _selectVRAM(&ds->memory, address >> DS_VRAM_OFFSET);
793 if (mask) {
794 int i = 0;
795 for (i = 0; i < 9; ++i) {
796 if (mask & (1 << i)) {
797 cpu->memory.activeRegion = (uint32_t*) ds->memory.vramBank[i];
798 cpu->memory.activeMask = _vramMask[i];
799 break;
800 }
801 }
802 break;
803 }
804 }
805 // Fall through
806 default:
807 jump_error:
808 memory->activeRegion = -1;
809 cpu->memory.activeRegion = _deadbeef;
810 cpu->memory.activeMask = 0;
811 mLOG(DS_MEM, FATAL, "Jumped to invalid address: %08X", address);
812 return;
813 }
814 cpu->memory.activeSeqCycles32 = memory->waitstatesPrefetchSeq32[memory->activeRegion];
815 cpu->memory.activeSeqCycles16 = memory->waitstatesPrefetchSeq16[memory->activeRegion];
816 cpu->memory.activeNonseqCycles32 = memory->waitstatesPrefetchNonseq32[memory->activeRegion];
817 cpu->memory.activeNonseqCycles16 = memory->waitstatesPrefetchNonseq16[memory->activeRegion];
818}
819
820uint32_t DS9Load32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
821 struct DS* ds = (struct DS*) cpu->master;
822 struct DSMemory* memory = &ds->memory;
823 uint32_t value = 0;
824 int wait = ds->ds9.memory.waitstatesNonseq32[address >> DS_BASE_OFFSET];
825
826 switch (address >> DS_BASE_OFFSET) {
827 case DS9_REGION_ITCM:
828 case DS9_REGION_ITCM_MIRROR:
829 if (address < memory->itcmSize) {
830 LOAD_32(value, address & (DS9_SIZE_ITCM - 4), memory->itcm);
831 break;
832 }
833 mLOG(DS_MEM, STUB, "Bad DS9 Load32: %08X", address);
834 break;
835 case DS_REGION_WORKING_RAM:
836 if (ds->memory.wramSize9) {
837 LOAD_32(value, address & (ds->memory.wramSize9 - 4), memory->wramBase9);
838 break;
839 }
840 mLOG(DS_MEM, STUB, "Bad DS9 Load32: %08X", address);
841 break;
842 case DS_REGION_RAM:
843 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
844 LOAD_32(value, address & (DS9_SIZE_DTCM - 4), memory->dtcm);
845 break;
846 }
847 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
848 LOAD_32(value, address & (DS_SIZE_RAM - 4), memory->ram);
849 break;
850 }
851 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load32: %08X", address);
852 break;
853 case DS_REGION_IO:
854 value = DS9IORead32(ds, address & 0x00FFFFFC);
855 break;
856 case DS9_REGION_PALETTE_RAM:
857 LOAD_32(value, address & (DS9_SIZE_PALETTE_RAM - 4), ds->video.palette);
858 break;
859 case DS_REGION_VRAM: {
860 unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
861 int i = 0;
862 for (i = 0; i < 9; ++i) {
863 if (mask & (1 << i)) {
864 uint32_t newValue;
865 LOAD_32(newValue, address & _vramMask[i], memory->vramBank[i]);
866 value |= newValue;
867 }
868 }
869 break;
870 }
871 case DS9_REGION_OAM:
872 LOAD_32(value, address & (DS9_SIZE_OAM - 4), ds->video.oam.raw);
873 break;
874 case DS_REGION_SLOT2:
875 case DS_REGION_SLOT2_EX:
876 case DS_REGION_SLOT2_SRAM:
877 value = 0xFFFFFFFF;
878 break;
879 case DS9_REGION_BIOS:
880 // TODO: Fix undersized BIOS
881 // TODO: Fix masking
882 LOAD_32(value, address & (DS9_SIZE_BIOS - 4), memory->bios9);
883 break;
884 default:
885 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
886 LOAD_32(value, address & (DS9_SIZE_DTCM - 4), memory->dtcm);
887 break;
888 }
889 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load32: %08X", address);
890 break;
891 }
892
893 if (cycleCounter) {
894 wait += 2;
895 *cycleCounter += wait;
896 }
897 // Unaligned 32-bit loads are "rotated" so they make some semblance of sense
898 int rotate = (address & 3) << 3;
899 return ROR(value, rotate);
900}
901
902uint32_t DS9Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
903 struct DS* ds = (struct DS*) cpu->master;
904 struct DSMemory* memory = &ds->memory;
905 uint32_t value = 0;
906 int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
907
908 switch (address >> DS_BASE_OFFSET) {
909 case DS9_REGION_ITCM:
910 case DS9_REGION_ITCM_MIRROR:
911 if (address < memory->itcmSize) {
912 LOAD_16(value, address & (DS9_SIZE_ITCM - 2), memory->itcm);
913 break;
914 }
915 mLOG(DS_MEM, STUB, "Bad DS9 Load16: %08X", address);
916 break;
917 case DS_REGION_WORKING_RAM:
918 if (ds->memory.wramSize9) {
919 LOAD_16(value, address & (ds->memory.wramSize9 - 2), memory->wramBase9);
920 break;
921 }
922 mLOG(DS_MEM, STUB, "Bad DS9 Load16: %08X", address);
923 break;
924 case DS_REGION_RAM:
925 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
926 LOAD_16(value, address & (DS9_SIZE_DTCM - 2), memory->dtcm);
927 break;
928 }
929 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
930 LOAD_16(value, address & (DS_SIZE_RAM - 2), memory->ram);
931 break;
932 }
933 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load16: %08X", address);
934 case DS_REGION_IO:
935 value = DS9IORead(ds, address & DS_OFFSET_MASK);
936 break;
937 case DS9_REGION_PALETTE_RAM:
938 LOAD_16(value, address & (DS9_SIZE_PALETTE_RAM - 2), ds->video.palette);
939 break;
940 case DS_REGION_VRAM: {
941 unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
942 int i = 0;
943 for (i = 0; i < 9; ++i) {
944 if (mask & (1 << i)) {
945 uint32_t newValue;
946 LOAD_16(newValue, address & _vramMask[i], memory->vramBank[i]);
947 value |= newValue;
948 }
949 }
950 break;
951 }
952 case DS9_REGION_OAM:
953 LOAD_16(value, address & (DS9_SIZE_OAM - 2), ds->video.oam.raw);
954 break;
955 case DS_REGION_SLOT2:
956 case DS_REGION_SLOT2_EX:
957 case DS_REGION_SLOT2_SRAM:
958 value = 0xFFFF;
959 break;
960 case DS9_REGION_BIOS:
961 // TODO: Fix undersized BIOS
962 // TODO: Fix masking
963 LOAD_16(value, address & (DS9_SIZE_BIOS - 2), memory->bios9);
964 break;
965 default:
966 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
967 LOAD_16(value, address & (DS9_SIZE_DTCM - 2), memory->dtcm);
968 break;
969 }
970 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load16: %08X", address);
971 break;
972 }
973
974 if (cycleCounter) {
975 wait += 2;
976 *cycleCounter += wait;
977 }
978 // Unaligned 16-bit loads are "unpredictable", TODO: See what DS does
979 int rotate = (address & 1) << 3;
980 return ROR(value, rotate);
981}
982
983uint32_t DS9Load8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
984 struct DS* ds = (struct DS*) cpu->master;
985 struct DSMemory* memory = &ds->memory;
986 uint32_t value = 0;
987 int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
988
989 switch (address >> DS_BASE_OFFSET) {
990 case DS9_REGION_ITCM:
991 case DS9_REGION_ITCM_MIRROR:
992 if (address < memory->itcmSize) {
993 value = ((uint8_t*) memory->itcm)[address & (DS9_SIZE_ITCM - 1)];
994 break;
995 }
996 mLOG(DS_MEM, STUB, "Bad DS9 Load8: %08X", address);
997 break;
998 case DS_REGION_WORKING_RAM:
999 if (ds->memory.wramSize9) {
1000 value = ((uint8_t*) memory->wramBase9)[address & (memory->wramSize9 - 1)];
1001 break;
1002 }
1003 mLOG(DS_MEM, STUB, "Bad DS9 Load8: %08X", address);
1004 break;
1005 case DS_REGION_RAM:
1006 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1007 value = ((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)];
1008 break;
1009 }
1010 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1011 value = ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)];
1012 break;
1013 }
1014 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load8: %08X", address);
1015 case DS_REGION_IO:
1016 value = (DS9IORead(ds, address & 0xFFFE) >> ((address & 0x0001) << 3)) & 0xFF;
1017 break;
1018 case DS_REGION_VRAM: {
1019 unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
1020 int i = 0;
1021 for (i = 0; i < 9; ++i) {
1022 if (mask & (1 << i)) {
1023 value |= ((uint8_t*) memory->vramBank[i])[address & _vramMask[i]];
1024 }
1025 }
1026 break;
1027 }
1028 case DS_REGION_SLOT2:
1029 case DS_REGION_SLOT2_EX:
1030 case DS_REGION_SLOT2_SRAM:
1031 value = 0xFF;
1032 break;
1033 case DS9_REGION_BIOS:
1034 // TODO: Fix undersized BIOS
1035 // TODO: Fix masking
1036 value = ((uint8_t*) memory->bios9)[address & (DS9_SIZE_BIOS - 1)];
1037 break;
1038 default:
1039 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1040 value = ((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)];
1041 break;
1042 }
1043 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load8: %08X", address);
1044 break;
1045 }
1046
1047 if (cycleCounter) {
1048 wait += 2;
1049 *cycleCounter += wait;
1050 }
1051 return value;
1052}
1053
1054void DS9Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) {
1055 struct DS* ds = (struct DS*) cpu->master;
1056 struct DSMemory* memory = &ds->memory;
1057 int wait = ds->ds9.memory.waitstatesNonseq32[address >> DS_BASE_OFFSET];
1058
1059 switch (address >> DS_BASE_OFFSET) {
1060 case DS9_REGION_ITCM:
1061 case DS9_REGION_ITCM_MIRROR:
1062 if (address < memory->itcmSize) {
1063 STORE_32(value, address & (DS9_SIZE_ITCM - 4), memory->itcm);
1064 break;
1065 }
1066 mLOG(DS_MEM, STUB, "Bad DS9 Store32: %08X:%08X", address, value);
1067 break;
1068 case DS_REGION_WORKING_RAM:
1069 if (ds->memory.wramSize9) {
1070 STORE_32(value, address & (ds->memory.wramSize9 - 4), memory->wramBase9);
1071 break;
1072 }
1073 mLOG(DS_MEM, STUB, "Bad DS9 Store32: %08X:%08X", address, value);
1074 break;
1075 case DS_REGION_RAM:
1076 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1077 STORE_32(value, address & (DS9_SIZE_DTCM - 4), memory->dtcm);
1078 break;
1079 }
1080 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1081 STORE_32(value, address & (DS_SIZE_RAM - 4), memory->ram);
1082 break;
1083 }
1084 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store32: %08X:%08X", address, value);
1085 break;
1086 case DS_REGION_IO:
1087 DS9IOWrite32(ds, address & DS_OFFSET_MASK, value);
1088 break;
1089 case DS9_REGION_PALETTE_RAM:
1090 STORE_32(value, address & (DS9_SIZE_PALETTE_RAM - 4), ds->video.palette);
1091 ds->video.renderer->writePalette(ds->video.renderer, (address & (DS9_SIZE_PALETTE_RAM - 4)) + 2, value >> 16);
1092 ds->video.renderer->writePalette(ds->video.renderer, address & (DS9_SIZE_PALETTE_RAM - 4), value);
1093 break;
1094 case DS_REGION_VRAM: {
1095 unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
1096 int i = 0;
1097 for (i = 0; i < 9; ++i) {
1098 if (mask & (1 << i)) {
1099 STORE_32(value, address & _vramMask[i], memory->vramBank[i]);
1100 }
1101 }
1102 break;
1103 }
1104 case DS9_REGION_OAM:
1105 STORE_32(value, address & (DS9_SIZE_OAM - 4), ds->video.oam.raw);
1106 ds->video.renderer->writeOAM(ds->video.renderer, (address & (DS9_SIZE_OAM - 4)) >> 1);
1107 ds->video.renderer->writeOAM(ds->video.renderer, ((address & (DS9_SIZE_OAM - 4)) >> 1) + 1);
1108 break;
1109 default:
1110 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1111 STORE_32(value, address & (DS9_SIZE_DTCM - 4), memory->dtcm);
1112 break;
1113 }
1114 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store32: %08X:%08X", address, value);
1115 break;
1116 }
1117
1118 if (cycleCounter) {
1119 ++wait;
1120 *cycleCounter += wait;
1121 }
1122}
1123
1124void DS9Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
1125 struct DS* ds = (struct DS*) cpu->master;
1126 struct DSMemory* memory = &ds->memory;
1127 int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
1128
1129 switch (address >> DS_BASE_OFFSET) {
1130 case DS9_REGION_ITCM:
1131 case DS9_REGION_ITCM_MIRROR:
1132 if (address < memory->itcmSize) {
1133 STORE_16(value, address & (DS9_SIZE_ITCM - 2), memory->itcm);
1134 break;
1135 }
1136 mLOG(DS_MEM, STUB, "Bad DS9 Store16: %08X:%04X", address, value);
1137 break;
1138 case DS_REGION_WORKING_RAM:
1139 if (ds->memory.wramSize9) {
1140 STORE_16(value, address & (ds->memory.wramSize9 - 2), memory->wramBase9);
1141 break;
1142 }
1143 mLOG(DS_MEM, STUB, "Bad DS9 Store16: %08X:%04X", address, value);
1144 break;
1145 case DS_REGION_RAM:
1146 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1147 STORE_16(value, address & (DS9_SIZE_DTCM - 2), memory->dtcm);
1148 break;
1149 }
1150 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1151 STORE_16(value, address & (DS_SIZE_RAM - 2), memory->ram);
1152 break;
1153 }
1154 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store16: %08X:%04X", address, value);
1155 break;
1156 case DS_REGION_IO:
1157 DS9IOWrite(ds, address & DS_OFFSET_MASK, value);
1158 break;
1159 case DS9_REGION_PALETTE_RAM:
1160 STORE_16(value, address & (DS9_SIZE_PALETTE_RAM - 2), ds->video.palette);
1161 ds->video.renderer->writePalette(ds->video.renderer, address & (DS9_SIZE_PALETTE_RAM - 2), value);
1162 break;
1163 case DS_REGION_VRAM: {
1164 unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
1165 int i = 0;
1166 for (i = 0; i < 9; ++i) {
1167 if (mask & (1 << i)) {
1168 STORE_16(value, address & _vramMask[i], memory->vramBank[i]);
1169 }
1170 }
1171 break;
1172 }
1173 case DS9_REGION_OAM:
1174 STORE_16(value, address & (DS9_SIZE_OAM - 2), ds->video.oam.raw);
1175 ds->video.renderer->writeOAM(ds->video.renderer, (address & (DS9_SIZE_OAM - 2)) >> 1);
1176 break;
1177 default:
1178 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1179 STORE_16(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1180 break;
1181 }
1182 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store16: %08X:%04X", address, value);
1183 break;
1184 }
1185
1186 if (cycleCounter) {
1187 ++wait;
1188 *cycleCounter += wait;
1189 }
1190}
1191
1192void DS9Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
1193 struct DS* ds = (struct DS*) cpu->master;
1194 struct DSMemory* memory = &ds->memory;
1195 int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
1196
1197 switch (address >> DS_BASE_OFFSET) {
1198 case DS9_REGION_ITCM:
1199 case DS9_REGION_ITCM_MIRROR:
1200 if (address < memory->itcmSize) {
1201 ((uint8_t*) memory->itcm)[address & (DS9_SIZE_ITCM - 1)] = value;
1202 break;
1203 }
1204 mLOG(DS_MEM, STUB, "Bad DS9 Store8: %08X:%02X", address, value);
1205 break;
1206 case DS_REGION_WORKING_RAM:
1207 if (ds->memory.wramSize9) {
1208 ((uint8_t*) memory->wramBase9)[address & (ds->memory.wramSize9 - 1)] = value;
1209 break;
1210 }
1211 mLOG(DS_MEM, STUB, "Bad DS9 Store8: %08X:%02X", address, value);
1212 break;
1213 case DS_REGION_RAM:
1214 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1215 ((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)] = value;
1216 break;
1217 }
1218 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1219 ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)] = value;
1220 break;
1221 }
1222 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store8: %08X:%02X", address, value);
1223 case DS_REGION_IO:
1224 DS9IOWrite8(ds, address & DS_OFFSET_MASK, value);
1225 break;
1226 default:
1227 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1228 ((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)] = value;
1229 break;
1230 }
1231 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store8: %08X:%02X", address, value);
1232 break;
1233 }
1234
1235 if (cycleCounter) {
1236 ++wait;
1237 *cycleCounter += wait;
1238 }
1239}
1240
1241uint32_t DS9LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
1242 struct DS* ds = (struct DS*) cpu->master;
1243 struct DSMemory* memory = &ds->memory;
1244 char* ws32 = ds->ds9.memory.waitstatesNonseq32;
1245 uint32_t value;
1246 int wait = 0;
1247
1248 int i;
1249 int offset = 4;
1250 int popcount = 0;
1251 if (direction & LSM_D) {
1252 offset = -4;
1253 popcount = popcount32(mask);
1254 address -= (popcount << 2) - 4;
1255 }
1256
1257 if (direction & LSM_B) {
1258 address += offset;
1259 }
1260
1261 uint32_t addressMisalign = address & 0x3;
1262 address &= 0xFFFFFFFC;
1263
1264 switch (address >> DS_BASE_OFFSET) {
1265 case DS9_REGION_BIOS:
1266 // TODO: Fix undersized BIOS
1267 // TODO: Fix masking
1268 LDM_LOOP(LOAD_32(value, address & (DS9_SIZE_BIOS - 1), memory->bios9));
1269 break;
1270 case DS9_REGION_ITCM:
1271 case DS9_REGION_ITCM_MIRROR:
1272 LDM_LOOP(if (address < memory->itcmSize) {
1273 LOAD_32(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
1274 } else {
1275 value = 0;
1276 mLOG(DS_MEM, STUB, "Bad DS9 LDM: %08X", address);
1277 });
1278 break;
1279 case DS_REGION_WORKING_RAM:
1280 LDM_LOOP(if (ds->memory.wramSize9) {
1281 LOAD_32(value, address & (ds->memory.wramSize9 - 4), memory->wramBase9);
1282 } else {
1283 value = 0;
1284 mLOG(DS_MEM, STUB, "Bad DS9 LDM: %08X", address);
1285 });
1286 break;
1287 case DS_REGION_RAM:
1288 LDM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1289 LOAD_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1290 } else if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1291 LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
1292 } else {
1293 value = 0;
1294 mLOG(DS_MEM, STUB, "Unimplemented DS9 LDM: %08X", address);
1295 });
1296 break;
1297 case DS_REGION_IO:
1298 LDM_LOOP(value = DS9IORead32(ds, address));
1299 break;
1300 case DS9_REGION_PALETTE_RAM:
1301 LDM_LOOP(LOAD_32(value, address & (DS9_SIZE_PALETTE_RAM - 1), ds->video.palette));
1302 break;
1303 case DS_REGION_VRAM:
1304 LDM_LOOP(unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
1305 value = 0;
1306 int j = 0;
1307 for (j = 0; j < 9; ++j) {
1308 if (mask & (1 << j)) {
1309 uint32_t newValue;
1310 LOAD_32(newValue, address & _vramMask[j], memory->vramBank[j]);
1311 value |= newValue;
1312 }
1313 });
1314 break;
1315 case DS9_REGION_OAM:
1316 LDM_LOOP(LOAD_32(value, address & (DS9_SIZE_OAM - 1), ds->video.oam.raw));
1317 break;
1318 default:
1319 LDM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1320 LOAD_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1321 } else {
1322 value = 0;
1323 mLOG(DS_MEM, STUB, "Unimplemented DS9 LDM: %08X", address);
1324 });
1325 break;
1326 }
1327
1328 if (cycleCounter) {
1329 ++wait;
1330 *cycleCounter += wait;
1331 }
1332
1333 if (direction & LSM_B) {
1334 address -= offset;
1335 }
1336
1337 if (direction & LSM_D) {
1338 address -= (popcount << 2) + 4;
1339 }
1340
1341 return address | addressMisalign;
1342}
1343
1344
1345uint32_t DS9StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
1346 struct DS* ds = (struct DS*) cpu->master;
1347 struct DSMemory* memory = &ds->memory;
1348 char* ws32 = ds->ds9.memory.waitstatesNonseq32;
1349 uint32_t value;
1350 int wait = 0;
1351
1352 int i;
1353 int offset = 4;
1354 int popcount = 0;
1355 if (direction & LSM_D) {
1356 offset = -4;
1357 popcount = popcount32(mask);
1358 address -= (popcount << 2) - 4;
1359 }
1360
1361 if (direction & LSM_B) {
1362 address += offset;
1363 }
1364
1365 uint32_t addressMisalign = address & 0x3;
1366 address &= 0xFFFFFFFC;
1367
1368 switch (address >> DS_BASE_OFFSET) {
1369 case DS9_REGION_ITCM:
1370 case DS9_REGION_ITCM_MIRROR:
1371 STM_LOOP(if (address < memory->itcmSize) {
1372 STORE_32(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
1373 } else {
1374 mLOG(DS_MEM, STUB, "Bad DS9 STM: %08X:%08X", address, value);
1375 });
1376 break;
1377 case DS_REGION_WORKING_RAM:
1378 STM_LOOP(if (ds->memory.wramSize9) {
1379 STORE_32(value, address & (ds->memory.wramSize9 - 4), memory->wramBase9);
1380 } else {
1381 mLOG(DS_MEM, STUB, "Bad DS9 STM: %08X", address);
1382 });
1383 break;
1384 case DS_REGION_RAM:
1385 STM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1386 STORE_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1387 } else if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1388 STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
1389 } else {
1390 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
1391 });
1392 break;
1393 case DS_REGION_IO:
1394 STM_LOOP(DS9IOWrite32(ds, address & DS_OFFSET_MASK, value));
1395 break;
1396 case DS9_REGION_PALETTE_RAM:
1397 STM_LOOP(STORE_32(value, address & (DS9_SIZE_PALETTE_RAM - 1), ds->video.palette);
1398 ds->video.renderer->writePalette(ds->video.renderer, (address & (DS9_SIZE_PALETTE_RAM - 4)) + 2, value >> 16);
1399 ds->video.renderer->writePalette(ds->video.renderer, address & (DS9_SIZE_PALETTE_RAM - 4), value));
1400 break;
1401 case DS_REGION_VRAM:
1402 STM_LOOP(unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
1403 int j = 0;
1404 for (j = 0; j < 9; ++j) {
1405 if (mask & (1 << j)) {
1406 STORE_32(value, address & _vramMask[j], memory->vramBank[j]);
1407 }
1408 });
1409 break;
1410 case DS9_REGION_OAM:
1411 STM_LOOP(STORE_32(value, address & (DS9_SIZE_OAM - 1), ds->video.oam.raw);
1412 ds->video.renderer->writeOAM(ds->video.renderer, (address & (DS9_SIZE_OAM - 4)) >> 1);
1413 ds->video.renderer->writeOAM(ds->video.renderer, ((address & (DS9_SIZE_OAM - 4)) >> 1) + 1));
1414 break;
1415 default:
1416 STM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1417 STORE_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1418 } else {
1419 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
1420 });
1421 break;
1422 }
1423
1424 if (cycleCounter) {
1425 *cycleCounter += wait;
1426 }
1427
1428 if (direction & LSM_B) {
1429 address -= offset;
1430 }
1431
1432 if (direction & LSM_D) {
1433 address -= (popcount << 2) + 4;
1434 }
1435
1436 return address | addressMisalign;
1437}
1438
1439int32_t DSMemoryStall(struct ARMCore* cpu, int32_t wait) {
1440 return wait;
1441}
1442
1443void DSConfigureWRAM(struct DSMemory* memory, uint8_t config) {
1444 switch (config & 3) {
1445 case 0:
1446 memory->wramSize7 = 0;
1447 memory->wramBase7 = NULL;
1448 memory->wramSize9 = DS_SIZE_WORKING_RAM;
1449 memory->wramBase9 = memory->wramBase;
1450 break;
1451 case 1:
1452 memory->wramSize7 = DS_SIZE_WORKING_RAM >> 1;
1453 memory->wramBase7 = memory->wram;
1454 memory->wramSize9 = DS_SIZE_WORKING_RAM >> 1;
1455 memory->wramBase9 = &memory->wramBase[DS_SIZE_WORKING_RAM >> 3];
1456 break;
1457 case 2:
1458 memory->wramSize7 = DS_SIZE_WORKING_RAM >> 1;
1459 memory->wramBase7 = &memory->wram[DS_SIZE_WORKING_RAM >> 3];
1460 memory->wramSize9 = DS_SIZE_WORKING_RAM >> 1;
1461 memory->wramBase9 = memory->wramBase;
1462 break;
1463 case 3:
1464 memory->wramSize7 = DS_SIZE_WORKING_RAM;
1465 memory->wramBase7 = memory->wramBase;
1466 memory->wramSize9 = 0;
1467 memory->wramBase9 = NULL;
1468 break;
1469 }
1470}
1471
1472void DSConfigureExternalMemory(struct DS* ds, uint16_t config) {
1473 // TODO: GBA params
1474 ds->memory.slot1Owner = config & 0x0800;
1475 ds->memory.slot2Owner = config & 0x0080;
1476 ds->memory.io7[DS7_REG_EXMEMSTAT >> 1] = config;
1477
1478 ds->ds7.memory.slot1Access = ds->memory.slot1Owner;
1479 ds->ds9.memory.slot1Access = !ds->memory.slot1Owner;
1480}
1481
1482static unsigned _selectVRAM(struct DSMemory* memory, uint32_t offset) {
1483 unsigned mask = 0;
1484 offset &= 0x3FF;
1485 mask |= memory->vramMirror[0][offset & 0x3F] & memory->vramMode[0][offset >> 7];
1486 mask |= memory->vramMirror[1][offset & 0x3F] & memory->vramMode[1][offset >> 7];
1487 mask |= memory->vramMirror[2][offset & 0x3F] & memory->vramMode[2][offset >> 7];
1488 mask |= memory->vramMirror[3][offset & 0x3F] & memory->vramMode[3][offset >> 7];
1489 mask |= memory->vramMirror[4][offset & 0x3F] & memory->vramMode[4][offset >> 7];
1490 mask |= memory->vramMirror[5][offset & 0x3F] & memory->vramMode[5][offset >> 7];
1491 mask |= memory->vramMirror[6][offset & 0x3F] & memory->vramMode[6][offset >> 7];
1492 mask |= memory->vramMirror[7][offset & 0x3F] & memory->vramMode[7][offset >> 7];
1493 mask |= memory->vramMirror[8][offset & 0x3F] & memory->vramMode[8][offset >> 7];
1494 return mask;
1495}