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