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