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 mLOG(DS_MEM, STUB, "Unimplemented DS7 LDM: %08X", address);
660 });
661 break;
662 default:
663 mLOG(DS_MEM, STUB, "Unimplemented DS7 LDM: %08X", address);
664 LDM_LOOP(value = 0);
665 }
666
667 if (cycleCounter) {
668 ++wait;
669 *cycleCounter += wait;
670 }
671
672 if (direction & LSM_B) {
673 address -= offset;
674 }
675
676 if (direction & LSM_D) {
677 address -= (popcount << 2) + 4;
678 }
679
680 return address | addressMisalign;
681}
682
683uint32_t DS7StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
684 struct DS* ds = (struct DS*) cpu->master;
685 struct DSMemory* memory = &ds->memory;
686 char* ws32 = ds->ds7.memory.waitstatesNonseq32;
687 uint32_t value;
688 int wait = 0;
689
690 int i;
691 int offset = 4;
692 int popcount = 0;
693 if (direction & LSM_D) {
694 offset = -4;
695 popcount = popcount32(mask);
696 address -= (popcount << 2) - 4;
697 }
698
699 if (direction & LSM_B) {
700 address += offset;
701 }
702
703 uint32_t addressMisalign = address & 0x3;
704 address &= 0xFFFFFFFC;
705
706 switch (address >> DS_BASE_OFFSET) {
707 case DS_REGION_WORKING_RAM:
708 STM_LOOP(if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
709 STORE_32(value, address & (DS7_SIZE_WORKING_RAM - 1), memory->wram7);
710 } else {
711 STORE_32(value, address & (ds->memory.wramSize7 - 1), memory->wramBase7);
712 });
713 break;
714 case DS_REGION_RAM:
715 STM_LOOP(if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
716 STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
717 } else {
718 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
719 });
720 break;
721 case DS_REGION_IO:
722 STM_LOOP(DS7IOWrite32(ds, address & DS_OFFSET_MASK, value));
723 break;
724 case DS_REGION_VRAM:
725 STM_LOOP(if (address < 0x06040000 && memory->vram7[(address & 0x3FFFF) >> 17]) {
726 STORE_32(value, address & 0x1FFFF, memory->vram7[(address & 0x3FFFF) >> 17]);
727 } else {
728 mLOG(DS_MEM, STUB, "Unimplemented DS7 STM: %08X", address);
729 });
730 break;
731 default:
732 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
733 STM_LOOP();
734 break;
735 }
736
737 if (cycleCounter) {
738 *cycleCounter += wait;
739 }
740
741 if (direction & LSM_B) {
742 address -= offset;
743 }
744
745 if (direction & LSM_D) {
746 address -= (popcount << 2) + 4;
747 }
748
749 return address | addressMisalign;
750}
751
752static void DS9SetActiveRegion(struct ARMCore* cpu, uint32_t address) {
753 struct DS* ds = (struct DS*) cpu->master;
754 struct DSCoreMemory* memory = &ds->ds9.memory;
755
756 int newRegion = address >> DS_BASE_OFFSET;
757
758 memory->activeRegion = newRegion;
759 switch (newRegion) {
760 case DS9_REGION_ITCM:
761 case DS9_REGION_ITCM_MIRROR:
762 if (address < ds->memory.itcmSize) {
763 cpu->memory.activeRegion = ds->memory.itcm;
764 cpu->memory.activeMask = DS9_SIZE_ITCM - 1;
765 break;
766 }
767 goto jump_error;
768 case DS_REGION_RAM:
769 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
770 cpu->memory.activeRegion = ds->memory.ram;
771 cpu->memory.activeMask = DS_SIZE_RAM - 1;
772 break;
773 }
774 goto jump_error;
775 case DS9_REGION_BIOS:
776 // TODO: Mask properly
777 if (ds->memory.bios9) {
778 cpu->memory.activeRegion = ds->memory.bios9;
779 cpu->memory.activeMask = DS9_SIZE_BIOS - 1;
780 } else {
781 cpu->memory.activeRegion = _deadbeef;
782 cpu->memory.activeMask = 0;
783 }
784 cpu->memory.activeSeqCycles32 = 0;
785 cpu->memory.activeSeqCycles16 = 0;
786 cpu->memory.activeNonseqCycles32 = 0;
787 cpu->memory.activeNonseqCycles16 = 0;
788 return;
789 default:
790 jump_error:
791 memory->activeRegion = -1;
792 cpu->memory.activeRegion = _deadbeef;
793 cpu->memory.activeMask = 0;
794 mLOG(DS_MEM, FATAL, "Jumped to invalid address: %08X", address);
795 return;
796 }
797 cpu->memory.activeSeqCycles32 = memory->waitstatesPrefetchSeq32[memory->activeRegion];
798 cpu->memory.activeSeqCycles16 = memory->waitstatesPrefetchSeq16[memory->activeRegion];
799 cpu->memory.activeNonseqCycles32 = memory->waitstatesPrefetchNonseq32[memory->activeRegion];
800 cpu->memory.activeNonseqCycles16 = memory->waitstatesPrefetchNonseq16[memory->activeRegion];
801}
802
803uint32_t DS9Load32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
804 struct DS* ds = (struct DS*) cpu->master;
805 struct DSMemory* memory = &ds->memory;
806 uint32_t value = 0;
807 int wait = ds->ds9.memory.waitstatesNonseq32[address >> DS_BASE_OFFSET];
808
809 switch (address >> DS_BASE_OFFSET) {
810 case DS9_REGION_ITCM:
811 case DS9_REGION_ITCM_MIRROR:
812 if (address < memory->itcmSize) {
813 LOAD_32(value, address & (DS9_SIZE_ITCM - 4), memory->itcm);
814 break;
815 }
816 mLOG(DS_MEM, STUB, "Bad DS9 Load32: %08X", address);
817 break;
818 case DS_REGION_WORKING_RAM:
819 if (ds->memory.wramSize9) {
820 LOAD_32(value, address & (ds->memory.wramSize9 - 4), memory->wramBase9);
821 break;
822 }
823 mLOG(DS_MEM, STUB, "Bad DS9 Load32: %08X", address);
824 break;
825 case DS_REGION_RAM:
826 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
827 LOAD_32(value, address & (DS9_SIZE_DTCM - 4), memory->dtcm);
828 break;
829 }
830 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
831 LOAD_32(value, address & (DS_SIZE_RAM - 4), memory->ram);
832 break;
833 }
834 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load32: %08X", address);
835 break;
836 case DS_REGION_IO:
837 value = DS9IORead32(ds, address & 0x00FFFFFC);
838 break;
839 case DS9_REGION_PALETTE_RAM:
840 LOAD_32(value, address & (DS9_SIZE_PALETTE_RAM - 4), ds->video.palette);
841 break;
842 case DS_REGION_VRAM: {
843 unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
844 int i = 0;
845 for (i = 0; i < 9; ++i) {
846 if (mask & (1 << i)) {
847 uint32_t newValue;
848 LOAD_32(newValue, address & _vramMask[i], memory->vramBank[i]);
849 value |= newValue;
850 }
851 }
852 break;
853 }
854 case DS9_REGION_OAM:
855 LOAD_32(value, address & (DS9_SIZE_OAM - 4), ds->video.oam.raw);
856 break;
857 case DS_REGION_SLOT2:
858 case DS_REGION_SLOT2_EX:
859 case DS_REGION_SLOT2_SRAM:
860 value = 0xFFFFFFFF;
861 break;
862 case DS9_REGION_BIOS:
863 // TODO: Fix undersized BIOS
864 // TODO: Fix masking
865 LOAD_32(value, address & (DS9_SIZE_BIOS - 4), memory->bios9);
866 break;
867 default:
868 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
869 LOAD_32(value, address & (DS9_SIZE_DTCM - 4), memory->dtcm);
870 break;
871 }
872 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load32: %08X", address);
873 break;
874 }
875
876 if (cycleCounter) {
877 wait += 2;
878 *cycleCounter += wait;
879 }
880 // Unaligned 32-bit loads are "rotated" so they make some semblance of sense
881 int rotate = (address & 3) << 3;
882 return ROR(value, rotate);
883}
884
885uint32_t DS9Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
886 struct DS* ds = (struct DS*) cpu->master;
887 struct DSMemory* memory = &ds->memory;
888 uint32_t value = 0;
889 int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
890
891 switch (address >> DS_BASE_OFFSET) {
892 case DS9_REGION_ITCM:
893 case DS9_REGION_ITCM_MIRROR:
894 if (address < memory->itcmSize) {
895 LOAD_16(value, address & (DS9_SIZE_ITCM - 2), memory->itcm);
896 break;
897 }
898 mLOG(DS_MEM, STUB, "Bad DS9 Load16: %08X", address);
899 break;
900 case DS_REGION_WORKING_RAM:
901 if (ds->memory.wramSize9) {
902 LOAD_16(value, address & (ds->memory.wramSize9 - 2), memory->wramBase9);
903 break;
904 }
905 mLOG(DS_MEM, STUB, "Bad DS9 Load16: %08X", address);
906 break;
907 case DS_REGION_RAM:
908 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
909 LOAD_16(value, address & (DS9_SIZE_DTCM - 2), memory->dtcm);
910 break;
911 }
912 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
913 LOAD_16(value, address & (DS_SIZE_RAM - 2), memory->ram);
914 break;
915 }
916 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load16: %08X", address);
917 case DS_REGION_IO:
918 value = DS9IORead(ds, address & DS_OFFSET_MASK);
919 break;
920 case DS9_REGION_PALETTE_RAM:
921 LOAD_16(value, address & (DS9_SIZE_PALETTE_RAM - 2), ds->video.palette);
922 break;
923 case DS_REGION_VRAM: {
924 unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
925 int i = 0;
926 for (i = 0; i < 9; ++i) {
927 if (mask & (1 << i)) {
928 uint32_t newValue;
929 LOAD_16(newValue, address & _vramMask[i], memory->vramBank[i]);
930 value |= newValue;
931 }
932 }
933 break;
934 }
935 case DS9_REGION_OAM:
936 LOAD_16(value, address & (DS9_SIZE_OAM - 2), ds->video.oam.raw);
937 break;
938 case DS_REGION_SLOT2:
939 case DS_REGION_SLOT2_EX:
940 case DS_REGION_SLOT2_SRAM:
941 value = 0xFFFF;
942 break;
943 case DS9_REGION_BIOS:
944 // TODO: Fix undersized BIOS
945 // TODO: Fix masking
946 LOAD_16(value, address & (DS9_SIZE_BIOS - 2), memory->bios9);
947 break;
948 default:
949 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
950 LOAD_16(value, address & (DS9_SIZE_DTCM - 2), memory->dtcm);
951 break;
952 }
953 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load16: %08X", address);
954 break;
955 }
956
957 if (cycleCounter) {
958 wait += 2;
959 *cycleCounter += wait;
960 }
961 // Unaligned 16-bit loads are "unpredictable", TODO: See what DS does
962 int rotate = (address & 1) << 3;
963 return ROR(value, rotate);
964}
965
966uint32_t DS9Load8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
967 struct DS* ds = (struct DS*) cpu->master;
968 struct DSMemory* memory = &ds->memory;
969 uint32_t value = 0;
970 int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
971
972 switch (address >> DS_BASE_OFFSET) {
973 case DS9_REGION_ITCM:
974 case DS9_REGION_ITCM_MIRROR:
975 if (address < memory->itcmSize) {
976 value = ((uint8_t*) memory->itcm)[address & (DS9_SIZE_ITCM - 1)];
977 break;
978 }
979 mLOG(DS_MEM, STUB, "Bad DS9 Load8: %08X", address);
980 break;
981 case DS_REGION_WORKING_RAM:
982 if (ds->memory.wramSize9) {
983 value = ((uint8_t*) memory->wramBase9)[address & (memory->wramSize9 - 1)];
984 break;
985 }
986 mLOG(DS_MEM, STUB, "Bad DS9 Load8: %08X", address);
987 break;
988 case DS_REGION_RAM:
989 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
990 value = ((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)];
991 break;
992 }
993 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
994 value = ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)];
995 break;
996 }
997 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load8: %08X", address);
998 case DS_REGION_IO:
999 value = (DS9IORead(ds, address & 0xFFFE) >> ((address & 0x0001) << 3)) & 0xFF;
1000 break;
1001 case DS_REGION_VRAM: {
1002 unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
1003 int i = 0;
1004 for (i = 0; i < 9; ++i) {
1005 if (mask & (1 << i)) {
1006 value |= ((uint8_t*) memory->vramBank[i])[address & _vramMask[i]];
1007 }
1008 }
1009 break;
1010 }
1011 case DS_REGION_SLOT2:
1012 case DS_REGION_SLOT2_EX:
1013 case DS_REGION_SLOT2_SRAM:
1014 value = 0xFF;
1015 break;
1016 case DS9_REGION_BIOS:
1017 // TODO: Fix undersized BIOS
1018 // TODO: Fix masking
1019 value = ((uint8_t*) memory->bios9)[address & (DS9_SIZE_BIOS - 1)];
1020 break;
1021 default:
1022 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1023 value = ((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)];
1024 break;
1025 }
1026 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load8: %08X", address);
1027 break;
1028 }
1029
1030 if (cycleCounter) {
1031 wait += 2;
1032 *cycleCounter += wait;
1033 }
1034 return value;
1035}
1036
1037void DS9Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) {
1038 struct DS* ds = (struct DS*) cpu->master;
1039 struct DSMemory* memory = &ds->memory;
1040 int wait = ds->ds9.memory.waitstatesNonseq32[address >> DS_BASE_OFFSET];
1041
1042 switch (address >> DS_BASE_OFFSET) {
1043 case DS9_REGION_ITCM:
1044 case DS9_REGION_ITCM_MIRROR:
1045 if (address < memory->itcmSize) {
1046 STORE_32(value, address & (DS9_SIZE_ITCM - 4), memory->itcm);
1047 break;
1048 }
1049 mLOG(DS_MEM, STUB, "Bad DS9 Store32: %08X:%08X", address, value);
1050 break;
1051 case DS_REGION_WORKING_RAM:
1052 if (ds->memory.wramSize9) {
1053 STORE_32(value, address & (ds->memory.wramSize9 - 4), memory->wramBase9);
1054 break;
1055 }
1056 mLOG(DS_MEM, STUB, "Bad DS9 Store32: %08X:%08X", address, value);
1057 break;
1058 case DS_REGION_RAM:
1059 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1060 STORE_32(value, address & (DS9_SIZE_DTCM - 4), memory->dtcm);
1061 break;
1062 }
1063 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1064 STORE_32(value, address & (DS_SIZE_RAM - 4), memory->ram);
1065 break;
1066 }
1067 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store32: %08X:%08X", address, value);
1068 break;
1069 case DS_REGION_IO:
1070 DS9IOWrite32(ds, address & DS_OFFSET_MASK, value);
1071 break;
1072 case DS9_REGION_PALETTE_RAM:
1073 STORE_32(value, address & (DS9_SIZE_PALETTE_RAM - 4), ds->video.palette);
1074 ds->video.renderer->writePalette(ds->video.renderer, (address & (DS9_SIZE_PALETTE_RAM - 4)) + 2, value >> 16);
1075 ds->video.renderer->writePalette(ds->video.renderer, address & (DS9_SIZE_PALETTE_RAM - 4), value);
1076 break;
1077 case DS_REGION_VRAM: {
1078 unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
1079 int i = 0;
1080 for (i = 0; i < 9; ++i) {
1081 if (mask & (1 << i)) {
1082 STORE_32(value, address & _vramMask[i], memory->vramBank[i]);
1083 }
1084 }
1085 break;
1086 }
1087 case DS9_REGION_OAM:
1088 STORE_32(value, address & (DS9_SIZE_OAM - 4), ds->video.oam.raw);
1089 ds->video.renderer->writeOAM(ds->video.renderer, (address & (DS9_SIZE_OAM - 4)) >> 1);
1090 ds->video.renderer->writeOAM(ds->video.renderer, ((address & (DS9_SIZE_OAM - 4)) >> 1) + 1);
1091 break;
1092 default:
1093 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1094 STORE_32(value, address & (DS9_SIZE_DTCM - 4), memory->dtcm);
1095 break;
1096 }
1097 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store32: %08X:%08X", address, value);
1098 break;
1099 }
1100
1101 if (cycleCounter) {
1102 ++wait;
1103 *cycleCounter += wait;
1104 }
1105}
1106
1107void DS9Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
1108 struct DS* ds = (struct DS*) cpu->master;
1109 struct DSMemory* memory = &ds->memory;
1110 int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
1111
1112 switch (address >> DS_BASE_OFFSET) {
1113 case DS9_REGION_ITCM:
1114 case DS9_REGION_ITCM_MIRROR:
1115 if (address < memory->itcmSize) {
1116 STORE_16(value, address & (DS9_SIZE_ITCM - 2), memory->itcm);
1117 break;
1118 }
1119 mLOG(DS_MEM, STUB, "Bad DS9 Store16: %08X:%04X", address, value);
1120 break;
1121 case DS_REGION_WORKING_RAM:
1122 if (ds->memory.wramSize9) {
1123 STORE_16(value, address & (ds->memory.wramSize9 - 2), memory->wramBase9);
1124 break;
1125 }
1126 mLOG(DS_MEM, STUB, "Bad DS9 Store16: %08X:%04X", address, value);
1127 break;
1128 case DS_REGION_RAM:
1129 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1130 STORE_16(value, address & (DS9_SIZE_DTCM - 2), memory->dtcm);
1131 break;
1132 }
1133 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1134 STORE_16(value, address & (DS_SIZE_RAM - 2), memory->ram);
1135 break;
1136 }
1137 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store16: %08X:%04X", address, value);
1138 break;
1139 case DS_REGION_IO:
1140 DS9IOWrite(ds, address & DS_OFFSET_MASK, value);
1141 break;
1142 case DS9_REGION_PALETTE_RAM:
1143 STORE_16(value, address & (DS9_SIZE_PALETTE_RAM - 2), ds->video.palette);
1144 ds->video.renderer->writePalette(ds->video.renderer, address & (DS9_SIZE_PALETTE_RAM - 2), value);
1145 break;
1146 case DS_REGION_VRAM: {
1147 unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
1148 int i = 0;
1149 for (i = 0; i < 9; ++i) {
1150 if (mask & (1 << i)) {
1151 STORE_16(value, address & _vramMask[i], memory->vramBank[i]);
1152 }
1153 }
1154 break;
1155 }
1156 case DS9_REGION_OAM:
1157 STORE_16(value, address & (DS9_SIZE_OAM - 2), ds->video.oam.raw);
1158 ds->video.renderer->writeOAM(ds->video.renderer, (address & (DS9_SIZE_OAM - 2)) >> 1);
1159 break;
1160 default:
1161 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1162 STORE_16(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1163 break;
1164 }
1165 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store16: %08X:%04X", address, value);
1166 break;
1167 }
1168
1169 if (cycleCounter) {
1170 ++wait;
1171 *cycleCounter += wait;
1172 }
1173}
1174
1175void DS9Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
1176 struct DS* ds = (struct DS*) cpu->master;
1177 struct DSMemory* memory = &ds->memory;
1178 int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
1179
1180 switch (address >> DS_BASE_OFFSET) {
1181 case DS9_REGION_ITCM:
1182 case DS9_REGION_ITCM_MIRROR:
1183 if (address < memory->itcmSize) {
1184 ((uint8_t*) memory->itcm)[address & (DS9_SIZE_ITCM - 1)] = value;
1185 break;
1186 }
1187 mLOG(DS_MEM, STUB, "Bad DS9 Store8: %08X:%02X", address, value);
1188 break;
1189 case DS_REGION_WORKING_RAM:
1190 if (ds->memory.wramSize9) {
1191 ((uint8_t*) memory->wramBase9)[address & (ds->memory.wramSize9 - 1)] = value;
1192 break;
1193 }
1194 mLOG(DS_MEM, STUB, "Bad DS9 Store8: %08X:%02X", address, value);
1195 break;
1196 case DS_REGION_RAM:
1197 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1198 ((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)] = value;
1199 break;
1200 }
1201 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1202 ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)] = value;
1203 break;
1204 }
1205 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store8: %08X:%02X", address, value);
1206 case DS_REGION_IO:
1207 DS9IOWrite8(ds, address & DS_OFFSET_MASK, value);
1208 break;
1209 default:
1210 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1211 ((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)] = value;
1212 break;
1213 }
1214 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store8: %08X:%02X", address, value);
1215 break;
1216 }
1217
1218 if (cycleCounter) {
1219 ++wait;
1220 *cycleCounter += wait;
1221 }
1222}
1223
1224uint32_t DS9LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
1225 struct DS* ds = (struct DS*) cpu->master;
1226 struct DSMemory* memory = &ds->memory;
1227 char* ws32 = ds->ds9.memory.waitstatesNonseq32;
1228 uint32_t value;
1229 int wait = 0;
1230
1231 int i;
1232 int offset = 4;
1233 int popcount = 0;
1234 if (direction & LSM_D) {
1235 offset = -4;
1236 popcount = popcount32(mask);
1237 address -= (popcount << 2) - 4;
1238 }
1239
1240 if (direction & LSM_B) {
1241 address += offset;
1242 }
1243
1244 uint32_t addressMisalign = address & 0x3;
1245 address &= 0xFFFFFFFC;
1246
1247 switch (address >> DS_BASE_OFFSET) {
1248 case DS9_REGION_BIOS:
1249 // TODO: Fix undersized BIOS
1250 // TODO: Fix masking
1251 LDM_LOOP(LOAD_32(value, address & (DS9_SIZE_BIOS - 1), memory->bios9));
1252 break;
1253 case DS9_REGION_ITCM:
1254 case DS9_REGION_ITCM_MIRROR:
1255 LDM_LOOP(if (address < memory->itcmSize) {
1256 LOAD_32(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
1257 } else {
1258 mLOG(DS_MEM, STUB, "Bad DS9 LDM: %08X:%08X", address, value);
1259 });
1260 break;
1261 case DS_REGION_WORKING_RAM:
1262 LDM_LOOP(if (ds->memory.wramSize9) {
1263 LOAD_32(value, address & (ds->memory.wramSize9 - 4), memory->wramBase9);
1264 } else {
1265 mLOG(DS_MEM, STUB, "Bad DS9 LDM: %08X", address);
1266 });
1267 break;
1268 case DS_REGION_RAM:
1269 LDM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1270 LOAD_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1271 } else if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1272 LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
1273 } else {
1274 mLOG(DS_MEM, STUB, "Unimplemented DS9 LDM: %08X", address);
1275 });
1276 break;
1277 case DS_REGION_IO:
1278 LDM_LOOP(value = DS9IORead32(ds, address));
1279 break;
1280 case DS9_REGION_PALETTE_RAM:
1281 LDM_LOOP(LOAD_32(value, address & (DS9_SIZE_PALETTE_RAM - 1), ds->video.palette));
1282 break;
1283 case DS_REGION_VRAM:
1284 LDM_LOOP(unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
1285 value = 0;
1286 int j = 0;
1287 for (j = 0; j < 9; ++j) {
1288 if (mask & (1 << j)) {
1289 uint32_t newValue;
1290 LOAD_32(newValue, address & _vramMask[j], memory->vramBank[j]);
1291 value |= newValue;
1292 }
1293 });
1294 break;
1295 case DS9_REGION_OAM:
1296 LDM_LOOP(LOAD_32(value, address & (DS9_SIZE_OAM - 1), ds->video.oam.raw));
1297 break;
1298 default:
1299 LDM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1300 LOAD_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1301 } else {
1302 value = 0;
1303 mLOG(DS_MEM, STUB, "Unimplemented DS9 LDM: %08X", address);
1304 });
1305 break;
1306 }
1307
1308 if (cycleCounter) {
1309 ++wait;
1310 *cycleCounter += wait;
1311 }
1312
1313 if (direction & LSM_B) {
1314 address -= offset;
1315 }
1316
1317 if (direction & LSM_D) {
1318 address -= (popcount << 2) + 4;
1319 }
1320
1321 return address | addressMisalign;
1322}
1323
1324
1325uint32_t DS9StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
1326 struct DS* ds = (struct DS*) cpu->master;
1327 struct DSMemory* memory = &ds->memory;
1328 char* ws32 = ds->ds9.memory.waitstatesNonseq32;
1329 uint32_t value;
1330 int wait = 0;
1331
1332 int i;
1333 int offset = 4;
1334 int popcount = 0;
1335 if (direction & LSM_D) {
1336 offset = -4;
1337 popcount = popcount32(mask);
1338 address -= (popcount << 2) - 4;
1339 }
1340
1341 if (direction & LSM_B) {
1342 address += offset;
1343 }
1344
1345 uint32_t addressMisalign = address & 0x3;
1346 address &= 0xFFFFFFFC;
1347
1348 switch (address >> DS_BASE_OFFSET) {
1349 case DS9_REGION_ITCM:
1350 case DS9_REGION_ITCM_MIRROR:
1351 STM_LOOP(if (address < memory->itcmSize) {
1352 STORE_32(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
1353 } else {
1354 mLOG(DS_MEM, STUB, "Bad DS9 STM: %08X:%08X", address, value);
1355 });
1356 break;
1357 case DS_REGION_WORKING_RAM:
1358 STM_LOOP(if (ds->memory.wramSize9) {
1359 STORE_32(value, address & (ds->memory.wramSize9 - 4), memory->wramBase9);
1360 } else {
1361 mLOG(DS_MEM, STUB, "Bad DS9 STM: %08X", address);
1362 });
1363 break;
1364 case DS_REGION_RAM:
1365 STM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1366 STORE_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1367 } else if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1368 STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
1369 } else {
1370 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
1371 });
1372 break;
1373 case DS_REGION_IO:
1374 STM_LOOP(DS9IOWrite32(ds, address & DS_OFFSET_MASK, value));
1375 break;
1376 case DS9_REGION_PALETTE_RAM:
1377 STM_LOOP(STORE_32(value, address & (DS9_SIZE_PALETTE_RAM - 1), ds->video.palette);
1378 ds->video.renderer->writePalette(ds->video.renderer, (address & (DS9_SIZE_PALETTE_RAM - 4)) + 2, value >> 16);
1379 ds->video.renderer->writePalette(ds->video.renderer, address & (DS9_SIZE_PALETTE_RAM - 4), value));
1380 break;
1381 case DS_REGION_VRAM:
1382 STM_LOOP(unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
1383 int j = 0;
1384 for (j = 0; j < 9; ++j) {
1385 if (mask & (1 << j)) {
1386 STORE_32(value, address & _vramMask[j], memory->vramBank[j]);
1387 }
1388 });
1389 break;
1390 case DS9_REGION_OAM:
1391 STM_LOOP(STORE_32(value, address & (DS9_SIZE_OAM - 1), ds->video.oam.raw);
1392 ds->video.renderer->writeOAM(ds->video.renderer, (address & (DS9_SIZE_OAM - 4)) >> 1);
1393 ds->video.renderer->writeOAM(ds->video.renderer, ((address & (DS9_SIZE_OAM - 4)) >> 1) + 1));
1394 break;
1395 default:
1396 STM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1397 STORE_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1398 } else {
1399 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
1400 });
1401 break;
1402 }
1403
1404 if (cycleCounter) {
1405 *cycleCounter += wait;
1406 }
1407
1408 if (direction & LSM_B) {
1409 address -= offset;
1410 }
1411
1412 if (direction & LSM_D) {
1413 address -= (popcount << 2) + 4;
1414 }
1415
1416 return address | addressMisalign;
1417}
1418
1419int32_t DSMemoryStall(struct ARMCore* cpu, int32_t wait) {
1420 return wait;
1421}
1422
1423void DSConfigureWRAM(struct DSMemory* memory, uint8_t config) {
1424 switch (config & 3) {
1425 case 0:
1426 memory->wramSize7 = 0;
1427 memory->wramBase7 = NULL;
1428 memory->wramSize9 = DS_SIZE_WORKING_RAM;
1429 memory->wramBase9 = memory->wramBase;
1430 break;
1431 case 1:
1432 memory->wramSize7 = DS_SIZE_WORKING_RAM >> 1;
1433 memory->wramBase7 = memory->wram;
1434 memory->wramSize9 = DS_SIZE_WORKING_RAM >> 1;
1435 memory->wramBase9 = &memory->wramBase[DS_SIZE_WORKING_RAM >> 3];
1436 break;
1437 case 2:
1438 memory->wramSize7 = DS_SIZE_WORKING_RAM >> 1;
1439 memory->wramBase7 = &memory->wram[DS_SIZE_WORKING_RAM >> 3];
1440 memory->wramSize9 = DS_SIZE_WORKING_RAM >> 1;
1441 memory->wramBase9 = memory->wramBase;
1442 break;
1443 case 3:
1444 memory->wramSize7 = DS_SIZE_WORKING_RAM;
1445 memory->wramBase7 = memory->wramBase;
1446 memory->wramSize9 = 0;
1447 memory->wramBase9 = NULL;
1448 break;
1449 }
1450}
1451
1452void DSConfigureExternalMemory(struct DS* ds, uint16_t config) {
1453 // TODO: GBA params
1454 ds->memory.slot1Owner = config & 0x0800;
1455 ds->memory.slot2Owner = config & 0x0080;
1456 ds->memory.io7[DS7_REG_EXMEMSTAT >> 1] = config;
1457
1458 ds->ds7.memory.slot1Access = ds->memory.slot1Owner;
1459 ds->ds9.memory.slot1Access = !ds->memory.slot1Owner;
1460}
1461
1462static unsigned _selectVRAM(struct DSMemory* memory, uint32_t offset) {
1463 unsigned mask = 0;
1464 offset &= 0x3FF;
1465 mask |= memory->vramMirror[0][offset & 0x3F] & memory->vramMode[0][offset >> 7];
1466 mask |= memory->vramMirror[1][offset & 0x3F] & memory->vramMode[1][offset >> 7];
1467 mask |= memory->vramMirror[2][offset & 0x3F] & memory->vramMode[2][offset >> 7];
1468 mask |= memory->vramMirror[3][offset & 0x3F] & memory->vramMode[3][offset >> 7];
1469 mask |= memory->vramMirror[4][offset & 0x3F] & memory->vramMode[4][offset >> 7];
1470 mask |= memory->vramMirror[5][offset & 0x3F] & memory->vramMode[5][offset >> 7];
1471 mask |= memory->vramMirror[6][offset & 0x3F] & memory->vramMode[6][offset >> 7];
1472 mask |= memory->vramMirror[7][offset & 0x3F] & memory->vramMode[7][offset >> 7];
1473 mask |= memory->vramMirror[8][offset & 0x3F] & memory->vramMode[8][offset >> 7];
1474 return mask;
1475}