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