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 cpu->memory.activeSeqCycles32 = 0;
711 cpu->memory.activeSeqCycles16 = 0;
712 cpu->memory.activeNonseqCycles32 = 0;
713 cpu->memory.activeNonseqCycles16 = 0;
714 return;
715 default:
716 jump_error:
717 memory->activeRegion = -1;
718 cpu->memory.activeRegion = _deadbeef;
719 cpu->memory.activeMask = 0;
720 mLOG(DS_MEM, FATAL, "Jumped to invalid address: %08X", address);
721 return;
722 }
723 cpu->memory.activeSeqCycles32 = memory->waitstatesPrefetchSeq32[memory->activeRegion];
724 cpu->memory.activeSeqCycles16 = memory->waitstatesPrefetchSeq16[memory->activeRegion];
725 cpu->memory.activeNonseqCycles32 = memory->waitstatesPrefetchNonseq32[memory->activeRegion];
726 cpu->memory.activeNonseqCycles16 = memory->waitstatesPrefetchNonseq16[memory->activeRegion];
727}
728
729uint32_t DS9Load32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
730 struct DS* ds = (struct DS*) cpu->master;
731 struct DSMemory* memory = &ds->memory;
732 uint32_t value = 0;
733 int wait = ds->ds9.memory.waitstatesNonseq32[address >> DS_BASE_OFFSET];
734
735 switch (address >> DS_BASE_OFFSET) {
736 case DS9_REGION_ITCM:
737 case DS9_REGION_ITCM_MIRROR:
738 if (address < memory->itcmSize) {
739 LOAD_32(value, address & (DS9_SIZE_ITCM - 4), memory->itcm);
740 break;
741 }
742 mLOG(DS_MEM, STUB, "Bad DS9 Load32: %08X", address);
743 break;
744 case DS_REGION_WORKING_RAM:
745 if (ds->memory.wramSize9) {
746 LOAD_32(value, address & (ds->memory.wramSize9 - 4), memory->wramBase9);
747 break;
748 }
749 mLOG(DS_MEM, STUB, "Bad DS9 Load32: %08X", address);
750 break;
751 case DS_REGION_RAM:
752 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
753 LOAD_32(value, address & (DS9_SIZE_DTCM - 4), memory->dtcm);
754 break;
755 }
756 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
757 LOAD_32(value, address & (DS_SIZE_RAM - 4), memory->ram);
758 break;
759 }
760 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load32: %08X", address);
761 break;
762 case DS_REGION_IO:
763 value = DS9IORead32(ds, address & 0x00FFFFFC);
764 break;
765 case DS9_REGION_PALETTE_RAM:
766 LOAD_32(value, address & (DS9_SIZE_PALETTE_RAM - 4), ds->video.palette);
767 break;
768 case DS_REGION_VRAM: {
769 unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
770 int i = 0;
771 for (i = 0; i < 9; ++i) {
772 if (mask & (1 << i)) {
773 uint32_t newValue;
774 LOAD_32(newValue, address & _vramMask[i], memory->vramBank[i]);
775 value |= newValue;
776 }
777 }
778 break;
779 }
780 case DS9_REGION_OAM:
781 LOAD_32(value, address & (DS9_SIZE_OAM - 4), ds->video.oam.raw);
782 break;
783 case DS9_REGION_BIOS:
784 // TODO: Fix undersized BIOS
785 // TODO: Fix masking
786 LOAD_32(value, address & (DS9_SIZE_BIOS - 4), memory->bios9);
787 break;
788 default:
789 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
790 LOAD_32(value, address & (DS9_SIZE_DTCM - 4), memory->dtcm);
791 break;
792 }
793 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load32: %08X", address);
794 break;
795 }
796
797 if (cycleCounter) {
798 wait += 2;
799 *cycleCounter += wait;
800 }
801 // Unaligned 32-bit loads are "rotated" so they make some semblance of sense
802 int rotate = (address & 3) << 3;
803 return ROR(value, rotate);
804}
805
806uint32_t DS9Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
807 struct DS* ds = (struct DS*) cpu->master;
808 struct DSMemory* memory = &ds->memory;
809 uint32_t value = 0;
810 int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
811
812 switch (address >> DS_BASE_OFFSET) {
813 case DS9_REGION_ITCM:
814 case DS9_REGION_ITCM_MIRROR:
815 if (address < memory->itcmSize) {
816 LOAD_16(value, address & (DS9_SIZE_ITCM - 2), memory->itcm);
817 break;
818 }
819 mLOG(DS_MEM, STUB, "Bad DS9 Load16: %08X", address);
820 break;
821 case DS_REGION_WORKING_RAM:
822 if (ds->memory.wramSize9) {
823 LOAD_16(value, address & (ds->memory.wramSize9 - 2), memory->wramBase9);
824 break;
825 }
826 mLOG(DS_MEM, STUB, "Bad DS9 Load16: %08X", address);
827 break;
828 case DS_REGION_RAM:
829 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
830 LOAD_16(value, address & (DS9_SIZE_DTCM - 2), memory->dtcm);
831 break;
832 }
833 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
834 LOAD_16(value, address & (DS_SIZE_RAM - 2), memory->ram);
835 break;
836 }
837 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load16: %08X", address);
838 case DS_REGION_IO:
839 value = DS9IORead(ds, address & DS_OFFSET_MASK);
840 break;
841 case DS9_REGION_PALETTE_RAM:
842 LOAD_16(value, address & (DS9_SIZE_PALETTE_RAM - 2), ds->video.palette);
843 break;
844 case DS_REGION_VRAM: {
845 unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
846 int i = 0;
847 for (i = 0; i < 9; ++i) {
848 if (mask & (1 << i)) {
849 uint32_t newValue;
850 LOAD_16(newValue, address & _vramMask[i], memory->vramBank[i]);
851 value |= newValue;
852 }
853 }
854 break;
855 }
856 case DS9_REGION_OAM:
857 LOAD_16(value, address & (DS9_SIZE_OAM - 2), ds->video.oam.raw);
858 break;
859 case DS9_REGION_BIOS:
860 // TODO: Fix undersized BIOS
861 // TODO: Fix masking
862 LOAD_16(value, address & (DS9_SIZE_BIOS - 2), memory->bios9);
863 break;
864 default:
865 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
866 LOAD_16(value, address & (DS9_SIZE_DTCM - 2), memory->dtcm);
867 break;
868 }
869 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load16: %08X", address);
870 break;
871 }
872
873 if (cycleCounter) {
874 wait += 2;
875 *cycleCounter += wait;
876 }
877 // Unaligned 16-bit loads are "unpredictable", TODO: See what DS does
878 int rotate = (address & 1) << 3;
879 return ROR(value, rotate);
880}
881
882uint32_t DS9Load8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
883 struct DS* ds = (struct DS*) cpu->master;
884 struct DSMemory* memory = &ds->memory;
885 uint32_t value = 0;
886 int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
887
888 switch (address >> DS_BASE_OFFSET) {
889 case DS9_REGION_ITCM:
890 case DS9_REGION_ITCM_MIRROR:
891 if (address < memory->itcmSize) {
892 value = ((uint8_t*) memory->itcm)[address & (DS9_SIZE_ITCM - 1)];
893 break;
894 }
895 mLOG(DS_MEM, STUB, "Bad DS9 Load8: %08X", address);
896 break;
897 case DS_REGION_WORKING_RAM:
898 if (ds->memory.wramSize9) {
899 value = ((uint8_t*) memory->wramBase9)[address & (memory->wramSize9 - 1)];
900 break;
901 }
902 mLOG(DS_MEM, STUB, "Bad DS9 Load8: %08X", address);
903 break;
904 case DS_REGION_RAM:
905 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
906 value = ((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)];
907 break;
908 }
909 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
910 value = ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)];
911 break;
912 }
913 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load8: %08X", address);
914 case DS_REGION_IO:
915 value = (DS9IORead(ds, address & 0xFFFE) >> ((address & 0x0001) << 3)) & 0xFF;
916 break;
917 case DS9_REGION_BIOS:
918 // TODO: Fix undersized BIOS
919 // TODO: Fix masking
920 value = ((uint8_t*) memory->bios9)[address & (DS9_SIZE_BIOS - 1)];
921 break;
922 default:
923 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
924 value = ((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)];
925 break;
926 }
927 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load8: %08X", address);
928 break;
929 }
930
931 if (cycleCounter) {
932 wait += 2;
933 *cycleCounter += wait;
934 }
935 return value;
936}
937
938void DS9Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) {
939 struct DS* ds = (struct DS*) cpu->master;
940 struct DSMemory* memory = &ds->memory;
941 int wait = ds->ds9.memory.waitstatesNonseq32[address >> DS_BASE_OFFSET];
942
943 switch (address >> DS_BASE_OFFSET) {
944 case DS9_REGION_ITCM:
945 case DS9_REGION_ITCM_MIRROR:
946 if (address < memory->itcmSize) {
947 STORE_32(value, address & (DS9_SIZE_ITCM - 4), memory->itcm);
948 break;
949 }
950 mLOG(DS_MEM, STUB, "Bad DS9 Store32: %08X:%08X", address, value);
951 break;
952 case DS_REGION_WORKING_RAM:
953 if (ds->memory.wramSize9) {
954 STORE_32(value, address & (ds->memory.wramSize9 - 4), memory->wramBase9);
955 break;
956 }
957 mLOG(DS_MEM, STUB, "Bad DS9 Store32: %08X:%08X", address, value);
958 break;
959 case DS_REGION_RAM:
960 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
961 STORE_32(value, address & (DS9_SIZE_DTCM - 4), memory->dtcm);
962 break;
963 }
964 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
965 STORE_32(value, address & (DS_SIZE_RAM - 4), memory->ram);
966 break;
967 }
968 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store32: %08X:%08X", address, value);
969 break;
970 case DS_REGION_IO:
971 DS9IOWrite32(ds, address & DS_OFFSET_MASK, value);
972 break;
973 case DS9_REGION_PALETTE_RAM:
974 STORE_32(value, address & (DS9_SIZE_PALETTE_RAM - 4), ds->video.palette);
975 ds->video.renderer->writePalette(ds->video.renderer, (address & (DS9_SIZE_PALETTE_RAM - 4)) + 2, value >> 16);
976 ds->video.renderer->writePalette(ds->video.renderer, address & (DS9_SIZE_PALETTE_RAM - 4), value);
977 break;
978 case DS_REGION_VRAM: {
979 unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
980 int i = 0;
981 for (i = 0; i < 9; ++i) {
982 if (mask & (1 << i)) {
983 STORE_32(value, address & _vramMask[i], memory->vramBank[i]);
984 }
985 }
986 break;
987 }
988 case DS9_REGION_OAM:
989 STORE_32(value, address & (DS9_SIZE_OAM - 4), ds->video.oam.raw);
990 ds->video.renderer->writeOAM(ds->video.renderer, (address & (DS9_SIZE_OAM - 4)) >> 1);
991 ds->video.renderer->writeOAM(ds->video.renderer, ((address & (DS9_SIZE_OAM - 4)) >> 1) + 1);
992 break;
993 default:
994 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
995 STORE_32(value, address & (DS9_SIZE_DTCM - 4), memory->dtcm);
996 break;
997 }
998 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store32: %08X:%08X", address, value);
999 break;
1000 }
1001
1002 if (cycleCounter) {
1003 ++wait;
1004 *cycleCounter += wait;
1005 }
1006}
1007
1008void DS9Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
1009 struct DS* ds = (struct DS*) cpu->master;
1010 struct DSMemory* memory = &ds->memory;
1011 int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
1012
1013 switch (address >> DS_BASE_OFFSET) {
1014 case DS9_REGION_ITCM:
1015 case DS9_REGION_ITCM_MIRROR:
1016 if (address < memory->itcmSize) {
1017 STORE_16(value, address & (DS9_SIZE_ITCM - 2), memory->itcm);
1018 break;
1019 }
1020 mLOG(DS_MEM, STUB, "Bad DS9 Store16: %08X:%04X", address, value);
1021 break;
1022 case DS_REGION_WORKING_RAM:
1023 if (ds->memory.wramSize9) {
1024 STORE_16(value, address & (ds->memory.wramSize9 - 2), memory->wramBase9);
1025 break;
1026 }
1027 mLOG(DS_MEM, STUB, "Bad DS9 Store16: %08X:%04X", address, value);
1028 break;
1029 case DS_REGION_RAM:
1030 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1031 STORE_16(value, address & (DS9_SIZE_DTCM - 2), memory->dtcm);
1032 break;
1033 }
1034 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1035 STORE_16(value, address & (DS_SIZE_RAM - 2), memory->ram);
1036 break;
1037 }
1038 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store16: %08X:%04X", address, value);
1039 break;
1040 case DS_REGION_IO:
1041 DS9IOWrite(ds, address & DS_OFFSET_MASK, value);
1042 break;
1043 case DS9_REGION_PALETTE_RAM:
1044 STORE_16(value, address & (DS9_SIZE_PALETTE_RAM - 2), ds->video.palette);
1045 ds->video.renderer->writePalette(ds->video.renderer, address & (DS9_SIZE_PALETTE_RAM - 2), value);
1046 break;
1047 case DS_REGION_VRAM: {
1048 unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
1049 int i = 0;
1050 for (i = 0; i < 9; ++i) {
1051 if (mask & (1 << i)) {
1052 STORE_16(value, address & _vramMask[i], memory->vramBank[i]);
1053 }
1054 }
1055 break;
1056 }
1057 case DS9_REGION_OAM:
1058 STORE_16(value, address & (DS9_SIZE_OAM - 2), ds->video.oam.raw);
1059 ds->video.renderer->writeOAM(ds->video.renderer, (address & (DS9_SIZE_OAM - 2)) >> 1);
1060 break;
1061 default:
1062 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1063 STORE_16(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1064 break;
1065 }
1066 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store16: %08X:%04X", address, value);
1067 break;
1068 }
1069
1070 if (cycleCounter) {
1071 ++wait;
1072 *cycleCounter += wait;
1073 }
1074}
1075
1076void DS9Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
1077 struct DS* ds = (struct DS*) cpu->master;
1078 struct DSMemory* memory = &ds->memory;
1079 int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
1080
1081 switch (address >> DS_BASE_OFFSET) {
1082 case DS9_REGION_ITCM:
1083 case DS9_REGION_ITCM_MIRROR:
1084 if (address < memory->itcmSize) {
1085 ((uint8_t*) memory->itcm)[address & (DS9_SIZE_ITCM - 1)] = value;
1086 break;
1087 }
1088 mLOG(DS_MEM, STUB, "Bad DS9 Store8: %08X:%02X", address, value);
1089 break;
1090 case DS_REGION_WORKING_RAM:
1091 if (ds->memory.wramSize9) {
1092 ((uint8_t*) memory->wramBase9)[address & (ds->memory.wramSize9 - 1)] = value;
1093 break;
1094 }
1095 mLOG(DS_MEM, STUB, "Bad DS9 Store8: %08X:%02X", address, value);
1096 break;
1097 case DS_REGION_RAM:
1098 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1099 ((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)] = value;
1100 break;
1101 }
1102 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1103 ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)] = value;
1104 break;
1105 }
1106 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store8: %08X:%02X", address, value);
1107 case DS_REGION_IO:
1108 DS9IOWrite8(ds, address & DS_OFFSET_MASK, value);
1109 break;
1110 default:
1111 if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1112 ((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)] = value;
1113 break;
1114 }
1115 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store8: %08X:%02X", address, value);
1116 break;
1117 }
1118
1119 if (cycleCounter) {
1120 ++wait;
1121 *cycleCounter += wait;
1122 }
1123}
1124
1125uint32_t DS9LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
1126 struct DS* ds = (struct DS*) cpu->master;
1127 struct DSMemory* memory = &ds->memory;
1128 char* ws32 = ds->ds9.memory.waitstatesNonseq32;
1129 uint32_t value;
1130 int wait = 0;
1131
1132 int i;
1133 int offset = 4;
1134 int popcount = 0;
1135 if (direction & LSM_D) {
1136 offset = -4;
1137 popcount = popcount32(mask);
1138 address -= (popcount << 2) - 4;
1139 }
1140
1141 if (direction & LSM_B) {
1142 address += offset;
1143 }
1144
1145 uint32_t addressMisalign = address & 0x3;
1146 address &= 0xFFFFFFFC;
1147
1148 switch (address >> DS_BASE_OFFSET) {
1149 case DS9_REGION_ITCM:
1150 case DS9_REGION_ITCM_MIRROR:
1151 LDM_LOOP(if (address < memory->itcmSize) {
1152 LOAD_32(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
1153 } else {
1154 mLOG(DS_MEM, STUB, "Bad DS9 LDM: %08X:%08X", address, value);
1155 });
1156 break;
1157 case DS_REGION_WORKING_RAM:
1158 LDM_LOOP(if (ds->memory.wramSize9) {
1159 LOAD_32(value, address & (ds->memory.wramSize9 - 4), memory->wramBase9);
1160 } else {
1161 mLOG(DS_MEM, STUB, "Bad DS9 LDM: %08X", address);
1162 });
1163 break;
1164 case DS_REGION_RAM:
1165 LDM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1166 LOAD_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1167 } else if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1168 LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
1169 } else {
1170 mLOG(DS_MEM, STUB, "Unimplemented DS9 LDM: %08X", address);
1171 });
1172 break;
1173 case DS_REGION_IO:
1174 LDM_LOOP(value = DS9IORead32(ds, address));
1175 break;
1176 case DS9_REGION_PALETTE_RAM:
1177 LDM_LOOP(LOAD_32(value, address & (DS9_SIZE_PALETTE_RAM - 1), ds->video.palette));
1178 break;
1179 case DS_REGION_VRAM:
1180 LDM_LOOP(unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
1181 value = 0;
1182 int i = 0;
1183 for (i = 0; i < 9; ++i) {
1184 if (mask & (1 << i)) {
1185 uint32_t newValue;
1186 LOAD_32(newValue, address & _vramMask[i], memory->vramBank[i]);
1187 value |= newValue;
1188 }
1189 });
1190 break;
1191 case DS9_REGION_OAM:
1192 LDM_LOOP(LOAD_32(value, address & (DS9_SIZE_OAM - 1), ds->video.oam.raw));
1193 break;
1194 default:
1195 LDM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1196 LOAD_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1197 } else {
1198 mLOG(DS_MEM, STUB, "Unimplemented DS9 LDM: %08X", address);
1199 });
1200 break;
1201 }
1202
1203 if (cycleCounter) {
1204 ++wait;
1205 *cycleCounter += wait;
1206 }
1207
1208 if (direction & LSM_B) {
1209 address -= offset;
1210 }
1211
1212 if (direction & LSM_D) {
1213 address -= (popcount << 2) + 4;
1214 }
1215
1216 return address | addressMisalign;
1217}
1218
1219
1220uint32_t DS9StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
1221 struct DS* ds = (struct DS*) cpu->master;
1222 struct DSMemory* memory = &ds->memory;
1223 char* ws32 = ds->ds9.memory.waitstatesNonseq32;
1224 uint32_t value;
1225 int wait = 0;
1226
1227 int i;
1228 int offset = 4;
1229 int popcount = 0;
1230 if (direction & LSM_D) {
1231 offset = -4;
1232 popcount = popcount32(mask);
1233 address -= (popcount << 2) - 4;
1234 }
1235
1236 if (direction & LSM_B) {
1237 address += offset;
1238 }
1239
1240 uint32_t addressMisalign = address & 0x3;
1241 address &= 0xFFFFFFFC;
1242
1243 switch (address >> DS_BASE_OFFSET) {
1244 case DS9_REGION_ITCM:
1245 case DS9_REGION_ITCM_MIRROR:
1246 STM_LOOP(if (address < memory->itcmSize) {
1247 STORE_32(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
1248 } else {
1249 mLOG(DS_MEM, STUB, "Bad DS9 STM: %08X:%08X", address, value);
1250 });
1251 break;
1252 case DS_REGION_WORKING_RAM:
1253 STM_LOOP(if (ds->memory.wramSize9) {
1254 STORE_32(value, address & (ds->memory.wramSize9 - 4), memory->wramBase9);
1255 } else {
1256 mLOG(DS_MEM, STUB, "Bad DS9 STM: %08X", address);
1257 });
1258 break;
1259 case DS_REGION_RAM:
1260 STM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1261 STORE_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1262 } else if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1263 STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
1264 } else {
1265 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
1266 });
1267 break;
1268 case DS_REGION_IO:
1269 STM_LOOP(DS9IOWrite32(ds, address & DS_OFFSET_MASK, value));
1270 break;
1271 case DS9_REGION_PALETTE_RAM:
1272 STM_LOOP(STORE_32(value, address & (DS9_SIZE_PALETTE_RAM - 1), ds->video.palette);
1273 ds->video.renderer->writePalette(ds->video.renderer, (address & (DS9_SIZE_PALETTE_RAM - 4)) + 2, value >> 16);
1274 ds->video.renderer->writePalette(ds->video.renderer, address & (DS9_SIZE_PALETTE_RAM - 4), value));
1275 break;
1276 case DS_REGION_VRAM:
1277 STM_LOOP(unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
1278 int i = 0;
1279 for (i = 0; i < 9; ++i) {
1280 if (mask & (1 << i)) {
1281 STORE_32(value, address & _vramMask[i], memory->vramBank[i]);
1282 }
1283 });
1284 break;
1285 case DS9_REGION_OAM:
1286 STM_LOOP(STORE_32(value, address & (DS9_SIZE_OAM - 1), ds->video.oam.raw);
1287 ds->video.renderer->writeOAM(ds->video.renderer, (address & (DS9_SIZE_OAM - 4)) >> 1);
1288 ds->video.renderer->writeOAM(ds->video.renderer, ((address & (DS9_SIZE_OAM - 4)) >> 1) + 1));
1289 break;
1290 default:
1291 STM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1292 STORE_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1293 } else {
1294 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
1295 });
1296 break;
1297 }
1298
1299 if (cycleCounter) {
1300 *cycleCounter += wait;
1301 }
1302
1303 if (direction & LSM_B) {
1304 address -= offset;
1305 }
1306
1307 if (direction & LSM_D) {
1308 address -= (popcount << 2) + 4;
1309 }
1310
1311 return address | addressMisalign;
1312}
1313
1314int32_t DSMemoryStall(struct ARMCore* cpu, int32_t wait) {
1315 return wait;
1316}
1317
1318void DSConfigureWRAM(struct DSMemory* memory, uint8_t config) {
1319 switch (config & 3) {
1320 case 0:
1321 memory->wramSize7 = 0;
1322 memory->wramBase7 = NULL;
1323 memory->wramSize9 = DS_SIZE_WORKING_RAM;
1324 memory->wramBase9 = memory->wramBase;
1325 break;
1326 case 1:
1327 memory->wramSize7 = DS_SIZE_WORKING_RAM >> 1;
1328 memory->wramBase7 = memory->wram;
1329 memory->wramSize9 = DS_SIZE_WORKING_RAM >> 1;
1330 memory->wramBase9 = &memory->wramBase[DS_SIZE_WORKING_RAM >> 3];
1331 break;
1332 case 2:
1333 memory->wramSize7 = DS_SIZE_WORKING_RAM >> 1;
1334 memory->wramBase7 = &memory->wram[DS_SIZE_WORKING_RAM >> 3];
1335 memory->wramSize9 = DS_SIZE_WORKING_RAM >> 1;
1336 memory->wramBase9 = memory->wramBase;
1337 break;
1338 case 3:
1339 memory->wramSize7 = DS_SIZE_WORKING_RAM;
1340 memory->wramBase7 = memory->wramBase;
1341 memory->wramSize9 = 0;
1342 memory->wramBase9 = NULL;
1343 break;
1344 }
1345}
1346
1347void DSConfigureExternalMemory(struct DS* ds, uint16_t config) {
1348 // TODO: GBA params
1349 ds->memory.slot1Owner = config & 0x0800;
1350 ds->memory.slot2Owner = config & 0x0080;
1351 ds->memory.io7[DS7_REG_EXMEMSTAT >> 1] = config;
1352
1353 ds->ds7.memory.slot1Access = ds->memory.slot1Owner;
1354 ds->ds9.memory.slot1Access = !ds->memory.slot1Owner;
1355}
1356
1357static unsigned _selectVRAM(struct DSMemory* memory, uint32_t offset) {
1358 unsigned mask = 0;
1359 offset &= 0x3FF;
1360 mask |= memory->vramMirror[0][offset & 0x3F] & memory->vramMode[0][offset >> 7];
1361 mask |= memory->vramMirror[1][offset & 0x3F] & memory->vramMode[1][offset >> 7];
1362 mask |= memory->vramMirror[2][offset & 0x3F] & memory->vramMode[2][offset >> 7];
1363 mask |= memory->vramMirror[3][offset & 0x3F] & memory->vramMode[3][offset >> 7];
1364 mask |= memory->vramMirror[4][offset & 0x3F] & memory->vramMode[4][offset >> 7];
1365 mask |= memory->vramMirror[5][offset & 0x3F] & memory->vramMode[5][offset >> 7];
1366 mask |= memory->vramMirror[6][offset & 0x3F] & memory->vramMode[6][offset >> 7];
1367 mask |= memory->vramMirror[7][offset & 0x3F] & memory->vramMode[7][offset >> 7];
1368 mask |= memory->vramMirror[8][offset & 0x3F] & memory->vramMode[8][offset >> 7];
1369 return mask;
1370}