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