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