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, 0, 0);
185 DSVideoConfigureVRAM(ds, 1, 0);
186 DSVideoConfigureVRAM(ds, 2, 0);
187 DSVideoConfigureVRAM(ds, 3, 0);
188 DSVideoConfigureVRAM(ds, 4, 0);
189 DSVideoConfigureVRAM(ds, 5, 0);
190 DSVideoConfigureVRAM(ds, 6, 0);
191 DSVideoConfigureVRAM(ds, 7, 0);
192 DSVideoConfigureVRAM(ds, 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 ds->video.renderer->writePalette(ds->video.renderer, (address & (DS9_SIZE_PALETTE_RAM - 4)) + 2, value >> 16);
944 ds->video.renderer->writePalette(ds->video.renderer, address & (DS9_SIZE_PALETTE_RAM - 4), value);
945 break;
946 case DS_REGION_VRAM: {
947 unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
948 int i = 0;
949 for (i = 0; i < 9; ++i) {
950 if (mask & (1 << i)) {
951 STORE_32(value, address & _vramMask[i], memory->vramBank[i]);
952 }
953 }
954 break;
955 }
956 case DS9_REGION_OAM:
957 STORE_32(value, address & (DS9_SIZE_OAM - 4), ds->video.oam.raw);
958 break;
959 default:
960 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
961 STORE_32(value, address & (DS9_SIZE_DTCM - 4), memory->dtcm);
962 break;
963 }
964 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store32: %08X:%08X", address, value);
965 break;
966 }
967
968 if (cycleCounter) {
969 ++wait;
970 *cycleCounter += wait;
971 }
972}
973
974void DS9Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
975 struct DS* ds = (struct DS*) cpu->master;
976 struct DSMemory* memory = &ds->memory;
977 int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
978
979 switch (address >> DS_BASE_OFFSET) {
980 case DS9_REGION_ITCM:
981 case DS9_REGION_ITCM_MIRROR:
982 if (address < memory->itcmSize) {
983 STORE_16(value, address & (DS9_SIZE_ITCM - 2), memory->itcm);
984 break;
985 }
986 mLOG(DS_MEM, STUB, "Bad DS9 Store16: %08X:%04X", address, value);
987 break;
988 case DS_REGION_WORKING_RAM:
989 if (ds->memory.wramSize9) {
990 STORE_16(value, address & (ds->memory.wramSize9 - 2), memory->wramBase9);
991 break;
992 }
993 mLOG(DS_MEM, STUB, "Bad DS9 Store16: %08X:%04X", address, value);
994 break;
995 case DS_REGION_RAM:
996 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
997 STORE_16(value, address & (DS9_SIZE_DTCM - 2), memory->dtcm);
998 break;
999 }
1000 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1001 STORE_16(value, address & (DS_SIZE_RAM - 2), memory->ram);
1002 break;
1003 }
1004 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store16: %08X:%04X", address, value);
1005 break;
1006 case DS_REGION_IO:
1007 DS9IOWrite(ds, address & DS_OFFSET_MASK, value);
1008 break;
1009 case DS9_REGION_PALETTE_RAM:
1010 STORE_16(value, address & (DS9_SIZE_PALETTE_RAM - 2), ds->video.palette);
1011 ds->video.renderer->writePalette(ds->video.renderer, address & (DS9_SIZE_PALETTE_RAM - 2), value);
1012 break;
1013 case DS_REGION_VRAM: {
1014 unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
1015 int i = 0;
1016 for (i = 0; i < 9; ++i) {
1017 if (mask & (1 << i)) {
1018 STORE_16(value, address & _vramMask[i], memory->vramBank[i]);
1019 }
1020 }
1021 break;
1022 }
1023 case DS9_REGION_OAM:
1024 STORE_16(value, address & (DS9_SIZE_OAM - 2), ds->video.oam.raw);
1025 break;
1026 default:
1027 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1028 STORE_16(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1029 break;
1030 }
1031 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store16: %08X:%04X", address, value);
1032 break;
1033 }
1034
1035 if (cycleCounter) {
1036 ++wait;
1037 *cycleCounter += wait;
1038 }
1039}
1040
1041void DS9Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
1042 struct DS* ds = (struct DS*) cpu->master;
1043 struct DSMemory* memory = &ds->memory;
1044 int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
1045
1046 switch (address >> DS_BASE_OFFSET) {
1047 case DS9_REGION_ITCM:
1048 case DS9_REGION_ITCM_MIRROR:
1049 if (address < memory->itcmSize) {
1050 ((uint8_t*) memory->itcm)[address & (DS9_SIZE_ITCM - 1)] = value;
1051 break;
1052 }
1053 mLOG(DS_MEM, STUB, "Bad DS9 Store8: %08X:%02X", address, value);
1054 break;
1055 case DS_REGION_WORKING_RAM:
1056 if (ds->memory.wramSize9) {
1057 ((uint8_t*) memory->wramBase9)[address & (ds->memory.wramSize9 - 1)] = value;
1058 break;
1059 }
1060 mLOG(DS_MEM, STUB, "Bad DS9 Store8: %08X:%02X", address, value);
1061 break;
1062 case DS_REGION_RAM:
1063 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1064 ((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)] = value;
1065 break;
1066 }
1067 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1068 ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)] = value;
1069 break;
1070 }
1071 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store8: %08X:%02X", address, value);
1072 case DS_REGION_IO:
1073 DS9IOWrite8(ds, address & DS_OFFSET_MASK, value);
1074 break;
1075 default:
1076 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1077 ((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)] = value;
1078 break;
1079 }
1080 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store8: %08X:%02X", address, value);
1081 break;
1082 }
1083
1084 if (cycleCounter) {
1085 ++wait;
1086 *cycleCounter += wait;
1087 }
1088}
1089
1090uint32_t DS9LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
1091 struct DS* ds = (struct DS*) cpu->master;
1092 struct DSMemory* memory = &ds->memory;
1093 char* ws32 = ds->ds9.memory.waitstatesNonseq32;
1094 uint32_t value;
1095 int wait = 0;
1096
1097 int i;
1098 int offset = 4;
1099 int popcount = 0;
1100 if (direction & LSM_D) {
1101 offset = -4;
1102 popcount = popcount32(mask);
1103 address -= (popcount << 2) - 4;
1104 }
1105
1106 if (direction & LSM_B) {
1107 address += offset;
1108 }
1109
1110 uint32_t addressMisalign = address & 0x3;
1111 address &= 0xFFFFFFFC;
1112
1113 switch (address >> DS_BASE_OFFSET) {
1114 case DS9_REGION_ITCM:
1115 case DS9_REGION_ITCM_MIRROR:
1116 LDM_LOOP(if (address < memory->itcmSize) {
1117 LOAD_32(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
1118 } else {
1119 mLOG(DS_MEM, STUB, "Bad DS9 LDM: %08X:%08X", address, value);
1120 });
1121 break;
1122 case DS_REGION_WORKING_RAM:
1123 LDM_LOOP(if (ds->memory.wramSize9) {
1124 LOAD_32(value, address & (ds->memory.wramSize9 - 4), memory->wramBase9);
1125 } else {
1126 mLOG(DS_MEM, STUB, "Bad DS9 STM: %08X", address);
1127 });
1128 break;
1129 case DS_REGION_RAM:
1130 LDM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1131 LOAD_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1132 } else if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1133 LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
1134 } else {
1135 mLOG(DS_MEM, STUB, "Unimplemented DS9 LDM: %08X", address);
1136 });
1137 break;
1138 case DS_REGION_IO:
1139 LDM_LOOP(value = DS9IORead32(ds, address));
1140 break;
1141 case DS9_REGION_PALETTE_RAM:
1142 LDM_LOOP(LOAD_32(value, address & (DS9_SIZE_PALETTE_RAM - 1), ds->video.palette));
1143 break;
1144 case DS_REGION_VRAM:
1145 LDM_LOOP(unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
1146 value = 0;
1147 int i = 0;
1148 for (i = 0; i < 9; ++i) {
1149 if (mask & (1 << i)) {
1150 uint32_t newValue;
1151 LOAD_32(newValue, address & _vramMask[i], memory->vramBank[i]);
1152 value |= newValue;
1153 }
1154 });
1155 break;
1156 case DS9_REGION_OAM:
1157 LDM_LOOP(LOAD_32(value, address & (DS9_SIZE_OAM - 1), ds->video.oam.raw));
1158 break;
1159 default:
1160 LDM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1161 LOAD_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1162 } else {
1163 mLOG(DS_MEM, STUB, "Unimplemented DS9 LDM: %08X", address);
1164 });
1165 break;
1166 }
1167
1168 if (cycleCounter) {
1169 ++wait;
1170 *cycleCounter += wait;
1171 }
1172
1173 if (direction & LSM_B) {
1174 address -= offset;
1175 }
1176
1177 if (direction & LSM_D) {
1178 address -= (popcount << 2) + 4;
1179 }
1180
1181 return address | addressMisalign;
1182}
1183
1184
1185uint32_t DS9StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
1186 struct DS* ds = (struct DS*) cpu->master;
1187 struct DSMemory* memory = &ds->memory;
1188 char* ws32 = ds->ds9.memory.waitstatesNonseq32;
1189 uint32_t value;
1190 int wait = 0;
1191
1192 int i;
1193 int offset = 4;
1194 int popcount = 0;
1195 if (direction & LSM_D) {
1196 offset = -4;
1197 popcount = popcount32(mask);
1198 address -= (popcount << 2) - 4;
1199 }
1200
1201 if (direction & LSM_B) {
1202 address += offset;
1203 }
1204
1205 uint32_t addressMisalign = address & 0x3;
1206 address &= 0xFFFFFFFC;
1207
1208 switch (address >> DS_BASE_OFFSET) {
1209 case DS9_REGION_ITCM:
1210 case DS9_REGION_ITCM_MIRROR:
1211 STM_LOOP(if (address < memory->itcmSize) {
1212 STORE_32(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
1213 } else {
1214 mLOG(DS_MEM, STUB, "Bad DS9 STM: %08X:%08X", address, value);
1215 });
1216 break;
1217 case DS_REGION_WORKING_RAM:
1218 STM_LOOP(if (ds->memory.wramSize9) {
1219 STORE_32(value, address & (ds->memory.wramSize9 - 4), memory->wramBase9);
1220 } else {
1221 mLOG(DS_MEM, STUB, "Bad DS9 STM: %08X", address);
1222 });
1223 break;
1224 case DS_REGION_RAM:
1225 STM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1226 STORE_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1227 } else if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1228 STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
1229 } else {
1230 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
1231 });
1232 break;
1233 case DS9_REGION_PALETTE_RAM:
1234 STM_LOOP(STORE_32(value, address & (DS9_SIZE_PALETTE_RAM - 1), ds->video.palette);
1235 ds->video.renderer->writePalette(ds->video.renderer, (address & (DS9_SIZE_PALETTE_RAM - 4)) + 2, value >> 16);
1236 ds->video.renderer->writePalette(ds->video.renderer, address & (DS9_SIZE_PALETTE_RAM - 4), value));
1237 break;
1238 case DS_REGION_VRAM:
1239 STM_LOOP(unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
1240 int i = 0;
1241 for (i = 0; i < 9; ++i) {
1242 if (mask & (1 << i)) {
1243 STORE_32(value, address & _vramMask[i], memory->vramBank[i]);
1244 }
1245 });
1246 break;
1247 case DS9_REGION_OAM:
1248 STM_LOOP(STORE_32(value, address & (DS9_SIZE_OAM - 1), ds->video.oam.raw));
1249 break;
1250 default:
1251 STM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1252 STORE_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1253 } else {
1254 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
1255 });
1256 break;
1257 }
1258
1259 if (cycleCounter) {
1260 *cycleCounter += wait;
1261 }
1262
1263 if (direction & LSM_B) {
1264 address -= offset;
1265 }
1266
1267 if (direction & LSM_D) {
1268 address -= (popcount << 2) + 4;
1269 }
1270
1271 return address | addressMisalign;
1272}
1273
1274int32_t DSMemoryStall(struct ARMCore* cpu, int32_t wait) {
1275 return wait;
1276}
1277
1278void DSConfigureWRAM(struct DSMemory* memory, uint8_t config) {
1279 switch (config & 3) {
1280 case 0:
1281 memory->wramSize7 = 0;
1282 memory->wramBase7 = NULL;
1283 memory->wramSize9 = DS_SIZE_WORKING_RAM;
1284 memory->wramBase9 = memory->wram;
1285 break;
1286 case 1:
1287 memory->wramSize7 = DS_SIZE_WORKING_RAM >> 1;
1288 memory->wramBase7 = memory->wram;
1289 memory->wramSize9 = DS_SIZE_WORKING_RAM >> 1;
1290 memory->wramBase9 = &memory->wram[DS_SIZE_WORKING_RAM >> 3];
1291 break;
1292 case 2:
1293 memory->wramSize7 = DS_SIZE_WORKING_RAM >> 1;
1294 memory->wramBase7 = &memory->wram[DS_SIZE_WORKING_RAM >> 3];
1295 memory->wramSize9 = DS_SIZE_WORKING_RAM >> 1;
1296 memory->wramBase9 = memory->wram;
1297 break;
1298 case 3:
1299 memory->wramSize7 = DS_SIZE_WORKING_RAM;
1300 memory->wramBase7 = memory->wram;
1301 memory->wramSize9 = 0;
1302 memory->wramBase9 = NULL;
1303 break;
1304 }
1305}
1306
1307void DSConfigureExternalMemory(struct DS* ds, uint16_t config) {
1308 // TODO: GBA params
1309 ds->memory.slot1Owner = config & 0x0800;
1310 ds->memory.slot2Owner = config & 0x0080;
1311 ds->memory.io7[DS7_REG_EXMEMSTAT >> 1] = config;
1312
1313 ds->ds7.memory.slot1Access = ds->memory.slot1Owner;
1314 ds->ds9.memory.slot1Access = !ds->memory.slot1Owner;
1315}
1316
1317static unsigned _selectVRAM(struct DSMemory* memory, uint32_t offset) {
1318 unsigned mask = 0;
1319 offset &= 0x3FF;
1320 mask |= memory->vramMirror[0][offset & 0x3F] & memory->vramMode[0][offset >> 7];
1321 mask |= memory->vramMirror[1][offset & 0x3F] & memory->vramMode[1][offset >> 7];
1322 mask |= memory->vramMirror[2][offset & 0x3F] & memory->vramMode[2][offset >> 7];
1323 mask |= memory->vramMirror[3][offset & 0x3F] & memory->vramMode[3][offset >> 7];
1324 mask |= memory->vramMirror[4][offset & 0x3F] & memory->vramMode[4][offset >> 7];
1325 mask |= memory->vramMirror[5][offset & 0x3F] & memory->vramMode[5][offset >> 7];
1326 mask |= memory->vramMirror[6][offset & 0x3F] & memory->vramMode[6][offset >> 7];
1327 mask |= memory->vramMirror[7][offset & 0x3F] & memory->vramMode[7][offset >> 7];
1328 mask |= memory->vramMirror[8][offset & 0x3F] & memory->vramMode[8][offset >> 7];
1329 return mask;
1330}