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