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