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