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