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