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