src/ds/memory.c (view raw)
1/* Copyright (c) 2013-2016 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include <mgba/internal/ds/memory.h>
7
8#include <mgba/internal/arm/macros.h>
9
10#include <mgba/internal/ds/ds.h>
11#include <mgba/internal/ds/io.h>
12#include <mgba-util/math.h>
13#include <mgba-util/memory.h>
14
15mLOG_DEFINE_CATEGORY(DS_MEM, "DS Memory");
16
17static uint32_t _deadbeef[1] = { 0xE710B710 }; // Illegal instruction on both ARM and Thumb
18
19static void DS7SetActiveRegion(struct ARMCore* cpu, uint32_t region);
20static void DS9SetActiveRegion(struct ARMCore* cpu, uint32_t region);
21static int32_t DSMemoryStall(struct ARMCore* cpu, int32_t wait);
22
23static const char DS7_BASE_WAITSTATES[16] = { 0, 0, 8, 0, 0, 0, 0, 0 };
24static const char DS7_BASE_WAITSTATES_32[16] = { 0, 0, 9, 0, 0, 1, 1, 0 };
25static const char DS7_BASE_WAITSTATES_SEQ[16] = { 0, 0, 1, 0, 0, 0, 0, 0 };
26static const char DS7_BASE_WAITSTATES_SEQ_32[16] = { 0, 0, 2, 0, 0, 1, 1, 0 };
27
28static const char DS9_BASE_WAITSTATES[16] = { 6, 6, 17, 6, 6, 7, 7, 6 };
29static const char DS9_BASE_WAITSTATES_32[16] = { 6, 6, 19, 6, 6, 9, 9, 6 };
30static const char DS9_BASE_WAITSTATES_SEQ[16] = { 1, 1, 1, 1, 1, 2, 2, 1 };
31static const char DS9_BASE_WAITSTATES_SEQ_32[16] = { 1, 1, 3, 1, 1, 4, 4, 1 };
32
33void DSMemoryInit(struct DS* ds) {
34 struct ARMCore* arm7 = ds->ds7.cpu;
35 arm7->memory.load32 = DS7Load32;
36 arm7->memory.load16 = DS7Load16;
37 arm7->memory.load8 = DS7Load8;
38 arm7->memory.loadMultiple = DS7LoadMultiple;
39 arm7->memory.store32 = DS7Store32;
40 arm7->memory.store16 = DS7Store16;
41 arm7->memory.store8 = DS7Store8;
42 arm7->memory.storeMultiple = DS7StoreMultiple;
43 arm7->memory.stall = DSMemoryStall;
44
45 struct ARMCore* arm9 = ds->ds9.cpu;
46 arm9->memory.load32 = DS9Load32;
47 arm9->memory.load16 = DS9Load16;
48 arm9->memory.load8 = DS9Load8;
49 arm9->memory.loadMultiple = DS9LoadMultiple;
50 arm9->memory.store32 = DS9Store32;
51 arm9->memory.store16 = DS9Store16;
52 arm9->memory.store8 = DS9Store8;
53 arm9->memory.storeMultiple = DS9StoreMultiple;
54 arm9->memory.stall = DSMemoryStall;
55
56 int i;
57 for (i = 0; i < 8; ++i) {
58 // TODO: Formalize
59 ds->ds7.memory.waitstatesNonseq16[i] = DS7_BASE_WAITSTATES[i];
60 ds->ds7.memory.waitstatesSeq16[i] = DS7_BASE_WAITSTATES_SEQ[i];
61 ds->ds7.memory.waitstatesPrefetchNonseq16[i] = DS7_BASE_WAITSTATES[i];
62 ds->ds7.memory.waitstatesPrefetchSeq16[i] = DS7_BASE_WAITSTATES_SEQ[i];
63 ds->ds7.memory.waitstatesNonseq32[i] = DS7_BASE_WAITSTATES_32[i];
64 ds->ds7.memory.waitstatesSeq32[i] = DS7_BASE_WAITSTATES_SEQ_32[i];
65 ds->ds7.memory.waitstatesPrefetchNonseq32[i] = DS7_BASE_WAITSTATES_32[i];
66 ds->ds7.memory.waitstatesPrefetchSeq32[i] = DS7_BASE_WAITSTATES_SEQ_32[i];
67
68 ds->ds9.memory.waitstatesNonseq16[i] = DS9_BASE_WAITSTATES[i];
69 ds->ds9.memory.waitstatesSeq16[i] = DS9_BASE_WAITSTATES_SEQ[i];
70 ds->ds9.memory.waitstatesPrefetchNonseq16[i] = DS9_BASE_WAITSTATES[i];
71 ds->ds9.memory.waitstatesPrefetchSeq16[i] = DS9_BASE_WAITSTATES[i];
72 ds->ds9.memory.waitstatesNonseq32[i] = DS9_BASE_WAITSTATES_32[i];
73 ds->ds9.memory.waitstatesSeq32[i] = DS9_BASE_WAITSTATES_SEQ_32[i];
74 ds->ds9.memory.waitstatesPrefetchNonseq32[i] = DS9_BASE_WAITSTATES_32[i];
75 ds->ds9.memory.waitstatesPrefetchSeq32[i] = DS9_BASE_WAITSTATES_32[i];
76 }
77 for (; i < 256; ++i) {
78 ds->ds7.memory.waitstatesNonseq16[i] = 0;
79 ds->ds7.memory.waitstatesSeq16[i] = 0;
80 ds->ds7.memory.waitstatesNonseq32[i] = 0;
81 ds->ds7.memory.waitstatesSeq32[i] = 0;
82
83 ds->ds9.memory.waitstatesNonseq16[i] = 0;
84 ds->ds9.memory.waitstatesSeq16[i] = 0;
85 ds->ds9.memory.waitstatesNonseq32[i] = 0;
86 ds->ds9.memory.waitstatesSeq32[i] = 0;
87 }
88
89 ds->memory.bios7 = NULL;
90 ds->memory.bios9 = NULL;
91 ds->memory.wram = NULL;
92 ds->memory.wram7 = NULL;
93 ds->memory.ram = NULL;
94 ds->memory.itcm = NULL;
95 ds->memory.dtcm = NULL;
96 ds->memory.rom = NULL;
97
98 ds->ds7.memory.activeRegion = -1;
99 ds->ds9.memory.activeRegion = -1;
100 ds->ds7.memory.io = ds->memory.io7;
101 ds->ds9.memory.io = ds->memory.io9;
102
103 arm7->memory.activeRegion = 0;
104 arm7->memory.activeMask = 0;
105 arm7->memory.setActiveRegion = DS7SetActiveRegion;
106 arm7->memory.activeSeqCycles32 = 0;
107 arm7->memory.activeSeqCycles16 = 0;
108 arm7->memory.activeNonseqCycles32 = 0;
109 arm7->memory.activeNonseqCycles16 = 0;
110
111 arm9->memory.activeRegion = 0;
112 arm9->memory.activeMask = 0;
113 arm9->memory.setActiveRegion = DS9SetActiveRegion;
114 arm9->memory.activeSeqCycles32 = 0;
115 arm9->memory.activeSeqCycles16 = 0;
116 arm9->memory.activeNonseqCycles32 = 0;
117 arm9->memory.activeNonseqCycles16 = 0;
118}
119
120void DSMemoryDeinit(struct DS* ds) {
121 mappedMemoryFree(ds->memory.wram, DS_SIZE_WORKING_RAM);
122 mappedMemoryFree(ds->memory.wram7, DS7_SIZE_WORKING_RAM);
123 mappedMemoryFree(ds->memory.ram, DS_SIZE_RAM);
124 mappedMemoryFree(ds->memory.itcm, DS9_SIZE_ITCM);
125 mappedMemoryFree(ds->memory.dtcm, DS9_SIZE_DTCM);
126}
127
128void DSMemoryReset(struct DS* ds) {
129 if (ds->memory.wram) {
130 mappedMemoryFree(ds->memory.wram, DS_SIZE_WORKING_RAM);
131 }
132 ds->memory.wram = anonymousMemoryMap(DS_SIZE_WORKING_RAM);
133
134 if (ds->memory.wram7) {
135 mappedMemoryFree(ds->memory.wram7, DS7_SIZE_WORKING_RAM);
136 }
137 ds->memory.wram7 = anonymousMemoryMap(DS7_SIZE_WORKING_RAM);
138
139 if (ds->memory.ram) {
140 mappedMemoryFree(ds->memory.ram, DS_SIZE_RAM);
141 }
142 ds->memory.ram = anonymousMemoryMap(DS_SIZE_RAM);
143
144 if (ds->memory.itcm) {
145 mappedMemoryFree(ds->memory.itcm, DS9_SIZE_ITCM);
146 }
147 ds->memory.itcm = anonymousMemoryMap(DS9_SIZE_ITCM);
148
149 if (ds->memory.dtcm) {
150 mappedMemoryFree(ds->memory.dtcm, DS9_SIZE_DTCM);
151 }
152 ds->memory.dtcm = anonymousMemoryMap(DS9_SIZE_DTCM);
153
154 memset(ds->ds7.memory.dma, 0, sizeof(ds->ds7.memory.dma));
155 memset(ds->ds9.memory.dma, 0, sizeof(ds->ds9.memory.dma));
156 ds->ds7.memory.activeDMA = -1;
157 ds->ds9.memory.activeDMA = -1;
158
159 // TODO: Correct size
160 ds->memory.wramSize7 = 0x8000;
161 ds->memory.wramSize9 = 0;
162
163 if (!ds->memory.wram || !ds->memory.wram7 || !ds->memory.ram || !ds->memory.itcm || !ds->memory.dtcm) {
164 DSMemoryDeinit(ds);
165 mLOG(DS_MEM, FATAL, "Could not map memory");
166 }
167}
168
169static void DS7SetActiveRegion(struct ARMCore* cpu, uint32_t address) {
170 struct DS* ds = (struct DS*) cpu->master;
171 struct DSCoreMemory* memory = &ds->ds7.memory;
172
173 int newRegion = address >> DS_BASE_OFFSET;
174
175 memory->activeRegion = newRegion;
176 switch (newRegion) {
177 case DS_REGION_WORKING_RAM:
178 if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
179 cpu->memory.activeRegion = ds->memory.wram7;
180 cpu->memory.activeMask = DS7_SIZE_WORKING_RAM - 1;
181 } else {
182 cpu->memory.activeRegion = ds->memory.wram;
183 cpu->memory.activeMask = ds->memory.wramSize7 - 1;
184 }
185 break;
186 case DS7_REGION_BIOS:
187 if (ds->memory.bios7) {
188 cpu->memory.activeRegion = ds->memory.bios7;
189 cpu->memory.activeMask = DS9_SIZE_BIOS - 1;
190 } else {
191 cpu->memory.activeRegion = _deadbeef;
192 cpu->memory.activeMask = 0;
193 }
194 break;
195 case DS_REGION_RAM:
196 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
197 cpu->memory.activeRegion = ds->memory.ram;
198 cpu->memory.activeMask = DS_SIZE_RAM - 1;
199 break;
200 }
201 // Fall through
202 default:
203 memory->activeRegion = -1;
204 cpu->memory.activeRegion = _deadbeef;
205 cpu->memory.activeMask = 0;
206 mLOG(DS_MEM, FATAL, "Jumped to invalid address: %08X", address);
207 break;
208 }
209 cpu->memory.activeSeqCycles32 = memory->waitstatesPrefetchSeq32[memory->activeRegion];
210 cpu->memory.activeSeqCycles16 = memory->waitstatesPrefetchSeq16[memory->activeRegion];
211 cpu->memory.activeNonseqCycles32 = memory->waitstatesPrefetchNonseq32[memory->activeRegion];
212 cpu->memory.activeNonseqCycles16 = memory->waitstatesPrefetchNonseq16[memory->activeRegion];
213}
214
215uint32_t DS7Load32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
216 struct DS* ds = (struct DS*) cpu->master;
217 struct DSMemory* memory = &ds->memory;
218 uint32_t value = 0;
219 int wait = ds->ds7.memory.waitstatesNonseq32[address >> DS_BASE_OFFSET];
220
221 switch (address >> DS_BASE_OFFSET) {
222 case DS7_REGION_BIOS:
223 LOAD_32(value, address & (DS7_SIZE_BIOS - 1), memory->bios7);
224 break;
225 case DS_REGION_WORKING_RAM:
226 if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
227 LOAD_32(value, address & (DS7_SIZE_WORKING_RAM - 1), memory->wram7);
228 } else {
229 LOAD_32(value, address & (ds->memory.wramSize7 - 1), memory->wram);
230 }
231 break;
232 case DS_REGION_RAM:
233 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
234 LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
235 break;
236 }
237 mLOG(DS_MEM, STUB, "Unimplemented DS7 Load32: %08X", address);
238 break;
239 case DS_REGION_IO:
240 value = DS7IORead32(ds, address & 0x00FFFFFC);
241 break;
242 default:
243 mLOG(DS_MEM, STUB, "Unimplemented DS7 Load32: %08X", address);
244 break;
245 }
246
247 if (cycleCounter) {
248 wait += 2;
249 *cycleCounter += wait;
250 }
251 // Unaligned 32-bit loads are "rotated" so they make some semblance of sense
252 int rotate = (address & 3) << 3;
253 return ROR(value, rotate);
254}
255
256uint32_t DS7Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
257 struct DS* ds = (struct DS*) cpu->master;
258 struct DSMemory* memory = &ds->memory;
259 uint32_t value = 0;
260 int wait = ds->ds7.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
261
262 switch (address >> DS_BASE_OFFSET) {
263 case DS7_REGION_BIOS:
264 LOAD_16(value, address & (DS7_SIZE_BIOS - 1), memory->bios7);
265 break;
266 case DS_REGION_WORKING_RAM:
267 if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
268 LOAD_16(value, address & (DS7_SIZE_WORKING_RAM - 1), memory->wram7);
269 } else {
270 LOAD_16(value, address & (ds->memory.wramSize7 - 1), memory->wram);
271 }
272 break;
273 case DS_REGION_RAM:
274 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
275 LOAD_16(value, address & (DS_SIZE_RAM - 1), memory->ram);
276 break;
277 }
278 mLOG(DS_MEM, STUB, "Unimplemented DS7 Load16: %08X", address);
279 case DS_REGION_IO:
280 value = DS7IORead(ds, address & 0x00FFFFFF);
281 break;
282 default:
283 mLOG(DS_MEM, STUB, "Unimplemented DS7 Load16: %08X", address);
284 break;
285 }
286
287 if (cycleCounter) {
288 wait += 2;
289 *cycleCounter += wait;
290 }
291 // Unaligned 16-bit loads are "unpredictable", TODO: See what DS does
292 int rotate = (address & 1) << 3;
293 return ROR(value, rotate);
294}
295
296uint32_t DS7Load8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
297 struct DS* ds = (struct DS*) cpu->master;
298 struct DSMemory* memory = &ds->memory;
299 uint32_t value = 0;
300 int wait = ds->ds7.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
301
302 switch (address >> DS_BASE_OFFSET) {
303 case DS_REGION_WORKING_RAM:
304 if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
305 value = ((uint8_t*) memory->wram7)[address & (DS7_SIZE_WORKING_RAM - 1)];
306 } else {
307 value = ((uint8_t*) memory->wram)[address & (ds->memory.wramSize7 - 1)];
308 }
309 break;
310 case DS_REGION_RAM:
311 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
312 value = ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)];
313 break;
314 }
315 mLOG(DS_MEM, STUB, "Unimplemented DS7 Load8: %08X", address);
316 default:
317 mLOG(DS_MEM, STUB, "Unimplemented DS7 Load8: %08X", address);
318 break;
319 }
320
321 if (cycleCounter) {
322 wait += 2;
323 *cycleCounter += wait;
324 }
325 return value;
326}
327
328void DS7Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) {
329 struct DS* ds = (struct DS*) cpu->master;
330 struct DSMemory* memory = &ds->memory;
331 int wait = ds->ds7.memory.waitstatesNonseq32[address >> DS_BASE_OFFSET];
332
333 switch (address >> DS_BASE_OFFSET) {
334 case DS_REGION_WORKING_RAM:
335 if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
336 STORE_32(value, address & (DS7_SIZE_WORKING_RAM - 1), memory->wram7);
337 } else {
338 STORE_32(value, address & (ds->memory.wramSize7 - 1), memory->wram);
339 }
340 break;
341 case DS_REGION_RAM:
342 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
343 STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
344 break;
345 }
346 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store32: %08X:%08X", address, value);
347 break;
348 case DS_REGION_IO:
349 DS7IOWrite32(ds, address & 0x00FFFFFF, value);
350 break;
351 default:
352 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store32: %08X:%08X", address, value);
353 break;
354 }
355
356 if (cycleCounter) {
357 ++wait;
358 *cycleCounter += wait;
359 }
360}
361
362void DS7Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
363 struct DS* ds = (struct DS*) cpu->master;
364 struct DSMemory* memory = &ds->memory;
365 int wait = ds->ds7.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
366
367 switch (address >> DS_BASE_OFFSET) {
368 case DS_REGION_WORKING_RAM:
369 if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
370 STORE_16(value, address & (DS7_SIZE_WORKING_RAM - 1), memory->wram7);
371 } else {
372 STORE_16(value, address & (ds->memory.wramSize7 - 1), memory->wram);
373 }
374 break;
375 case DS_REGION_RAM:
376 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
377 STORE_16(value, address & (DS_SIZE_RAM - 1), memory->ram);
378 break;
379 }
380 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store16: %08X:%04X", address, value);
381 break;
382 case DS_REGION_IO:
383 DS7IOWrite(ds, address & 0x00FFFFFF, value);
384 break;
385 default:
386 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store16: %08X:%04X", address, value);
387 break;
388 }
389
390 if (cycleCounter) {
391 ++wait;
392 *cycleCounter += wait;
393 }
394}
395
396void DS7Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
397 struct DS* ds = (struct DS*) cpu->master;
398 struct DSMemory* memory = &ds->memory;
399 int wait = ds->ds7.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
400
401 switch (address >> DS_BASE_OFFSET) {
402 case DS_REGION_WORKING_RAM:
403 if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
404 ((uint8_t*) memory->wram7)[address & (DS7_SIZE_WORKING_RAM - 1)] = value;
405 } else {
406 ((uint8_t*) memory->wram)[address & (ds->memory.wramSize7 - 1)] = value;
407 }
408 break;
409 case DS_REGION_RAM:
410 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
411 ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)] = value;
412 break;
413 }
414 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store8: %08X:%02X", address, value);
415 case DS_REGION_IO:
416 DS7IOWrite8(ds, address & 0x00FFFFFF, value);
417 break;
418 default:
419 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store8: %08X:%02X", address, value);
420 break;
421 }
422
423 if (cycleCounter) {
424 ++wait;
425 *cycleCounter += wait;
426 }
427}
428
429#define LDM_LOOP(LDM) \
430 for (i = 0; i < 16; i += 4) { \
431 if (UNLIKELY(mask & (1 << i))) { \
432 LDM; \
433 cpu->gprs[i] = value; \
434 ++wait; \
435 wait += ws32[address >> DS_BASE_OFFSET]; \
436 address += 4; \
437 } \
438 if (UNLIKELY(mask & (2 << i))) { \
439 LDM; \
440 cpu->gprs[i + 1] = value; \
441 ++wait; \
442 wait += ws32[address >> DS_BASE_OFFSET]; \
443 address += 4; \
444 } \
445 if (UNLIKELY(mask & (4 << i))) { \
446 LDM; \
447 cpu->gprs[i + 2] = value; \
448 ++wait; \
449 wait += ws32[address >> DS_BASE_OFFSET]; \
450 address += 4; \
451 } \
452 if (UNLIKELY(mask & (8 << i))) { \
453 LDM; \
454 cpu->gprs[i + 3] = value; \
455 ++wait; \
456 wait += ws32[address >> DS_BASE_OFFSET]; \
457 address += 4; \
458 } \
459 }
460
461#define STM_LOOP(STM) \
462 for (i = 0; i < 16; i += 4) { \
463 if (UNLIKELY(mask & (1 << i))) { \
464 value = cpu->gprs[i]; \
465 STM; \
466 ++wait; \
467 wait += ws32[address >> DS_BASE_OFFSET]; \
468 address += 4; \
469 } \
470 if (UNLIKELY(mask & (2 << i))) { \
471 value = cpu->gprs[i + 1]; \
472 STM; \
473 ++wait; \
474 wait += ws32[address >> DS_BASE_OFFSET]; \
475 address += 4; \
476 } \
477 if (UNLIKELY(mask & (4 << i))) { \
478 value = cpu->gprs[i + 2]; \
479 STM; \
480 ++wait; \
481 wait += ws32[address >> DS_BASE_OFFSET]; \
482 address += 4; \
483 } \
484 if (UNLIKELY(mask & (8 << i))) { \
485 value = cpu->gprs[i + 3]; \
486 STM; \
487 ++wait; \
488 wait += ws32[address >> DS_BASE_OFFSET]; \
489 address += 4; \
490 } \
491 }
492
493
494
495uint32_t DS7LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
496 struct DS* ds = (struct DS*) cpu->master;
497 struct DSMemory* memory = &ds->memory;
498 char* ws32 = ds->ds7.memory.waitstatesNonseq32;
499 uint32_t value;
500 int wait = 0;
501
502 int i;
503 int offset = 4;
504 int popcount = 0;
505 if (direction & LSM_D) {
506 offset = -4;
507 popcount = popcount32(mask);
508 address -= (popcount << 2) - 4;
509 }
510
511 if (direction & LSM_B) {
512 address += offset;
513 }
514
515 uint32_t addressMisalign = address & 0x3;
516 address &= 0xFFFFFFFC;
517
518 switch (address >> DS_BASE_OFFSET) {
519 case DS_REGION_WORKING_RAM:
520 LDM_LOOP(if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
521 LOAD_32(value, address & (DS7_SIZE_WORKING_RAM - 1), memory->wram7);
522 } else {
523 LOAD_32(value, address & (ds->memory.wramSize7 - 1), memory->wram);
524 });
525 break;
526 case DS_REGION_RAM:
527 LDM_LOOP(if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
528 LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
529 } else {
530 mLOG(DS_MEM, STUB, "Unimplemented DS7 LDM: %08X", address);
531 });
532 break;
533 case DS_REGION_IO:
534 LDM_LOOP(value = DS7IORead(ds, address & 0x00FFFFFC) | (DS7IORead(ds, (address & 0x00FFFFFC) | 2) << 16));
535 break;
536 default:
537 mLOG(DS_MEM, STUB, "Unimplemented DS7 LDM: %08X", address);
538 LDM_LOOP(value = 0);
539 }
540
541 if (cycleCounter) {
542 ++wait;
543 *cycleCounter += wait;
544 }
545
546 if (direction & LSM_B) {
547 address -= offset;
548 }
549
550 if (direction & LSM_D) {
551 address -= (popcount << 2) + 4;
552 }
553
554 return address | addressMisalign;
555}
556
557
558uint32_t DS7StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
559 struct DS* ds = (struct DS*) cpu->master;
560 struct DSMemory* memory = &ds->memory;
561 char* ws32 = ds->ds7.memory.waitstatesNonseq32;
562 uint32_t value;
563 int wait = 0;
564
565 int i;
566 int offset = 4;
567 int popcount = 0;
568 if (direction & LSM_D) {
569 offset = -4;
570 popcount = popcount32(mask);
571 address -= (popcount << 2) - 4;
572 }
573
574 if (direction & LSM_B) {
575 address += offset;
576 }
577
578 uint32_t addressMisalign = address & 0x3;
579 address &= 0xFFFFFFFC;
580
581 switch (address >> DS_BASE_OFFSET) {
582 case DS_REGION_WORKING_RAM:
583 STM_LOOP(if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
584 STORE_32(value, address & (DS7_SIZE_WORKING_RAM - 1), memory->wram7);
585 } else {
586 STORE_32(value, address & (ds->memory.wramSize7 - 1), memory->wram);
587 });
588 break;
589 case DS_REGION_RAM:
590 STM_LOOP(if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
591 STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
592 } else {
593 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
594 });
595 break;
596 default:
597 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
598 STM_LOOP();
599 break;
600 }
601
602 if (cycleCounter) {
603 *cycleCounter += wait;
604 }
605
606 if (direction & LSM_B) {
607 address -= offset;
608 }
609
610 if (direction & LSM_D) {
611 address -= (popcount << 2) + 4;
612 }
613
614 return address | addressMisalign;
615}
616
617static void DS9SetActiveRegion(struct ARMCore* cpu, uint32_t address) {
618 struct DS* ds = (struct DS*) cpu->master;
619 struct DSCoreMemory* memory = &ds->ds9.memory;
620
621 int newRegion = address >> DS_BASE_OFFSET;
622
623 memory->activeRegion = newRegion;
624 switch (newRegion) {
625 case DS9_REGION_ITCM:
626 case DS9_REGION_ITCM_MIRROR:
627 if (address < (512U << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
628 cpu->memory.activeRegion = ds->memory.itcm;
629 cpu->memory.activeMask = DS9_SIZE_ITCM - 1;
630 break;
631 }
632 goto jump_error;
633 case DS_REGION_RAM:
634 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
635 cpu->memory.activeRegion = ds->memory.ram;
636 cpu->memory.activeMask = DS_SIZE_RAM - 1;
637 break;
638 }
639 goto jump_error;
640 case DS9_REGION_BIOS:
641 // TODO: Mask properly
642 if (ds->memory.bios9) {
643 cpu->memory.activeRegion = ds->memory.bios9;
644 cpu->memory.activeMask = DS9_SIZE_BIOS - 1;
645 } else {
646 cpu->memory.activeRegion = _deadbeef;
647 cpu->memory.activeMask = 0;
648 }
649 break;
650 default:
651 jump_error:
652 memory->activeRegion = -1;
653 cpu->memory.activeRegion = _deadbeef;
654 cpu->memory.activeMask = 0;
655 mLOG(DS_MEM, FATAL, "Jumped to invalid address: %08X", address);
656 return;
657 }
658 cpu->memory.activeSeqCycles32 = memory->waitstatesPrefetchSeq32[memory->activeRegion];
659 cpu->memory.activeSeqCycles16 = memory->waitstatesPrefetchSeq16[memory->activeRegion];
660 cpu->memory.activeNonseqCycles32 = memory->waitstatesPrefetchNonseq32[memory->activeRegion];
661 cpu->memory.activeNonseqCycles16 = memory->waitstatesPrefetchNonseq16[memory->activeRegion];
662}
663
664uint32_t DS9Load32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
665 struct DS* ds = (struct DS*) cpu->master;
666 struct DSMemory* memory = &ds->memory;
667 uint32_t value = 0;
668 int wait = ds->ds9.memory.waitstatesNonseq32[address >> DS_BASE_OFFSET];
669
670 switch (address >> DS_BASE_OFFSET) {
671 case DS9_REGION_ITCM:
672 case DS9_REGION_ITCM_MIRROR:
673 if (address < (512U << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
674 LOAD_32(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
675 break;
676 }
677 mLOG(DS_MEM, STUB, "Bad DS9 Load32: %08X:%08X", address, value);
678 break;
679 case DS_REGION_RAM:
680 if ((address & ~(DS9_SIZE_DTCM - 1)) == DS9_BASE_DTCM) {
681 LOAD_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
682 break;
683 }
684 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
685 LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
686 break;
687 }
688 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load32: %08X", address);
689 break;
690 case DS_REGION_IO:
691 value = DS9IORead32(ds, address & 0x00FFFFFC);
692 break;
693 case DS9_REGION_BIOS:
694 // TODO: Fix undersized BIOS
695 // TODO: Fix masking
696 LOAD_32(value, address & (DS9_SIZE_BIOS - 1), memory->bios9);
697 break;
698 default:
699 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load32: %08X", address);
700 break;
701 }
702
703 if (cycleCounter) {
704 wait += 2;
705 *cycleCounter += wait;
706 }
707 // Unaligned 32-bit loads are "rotated" so they make some semblance of sense
708 int rotate = (address & 3) << 3;
709 return ROR(value, rotate);
710}
711
712uint32_t DS9Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
713 struct DS* ds = (struct DS*) cpu->master;
714 struct DSMemory* memory = &ds->memory;
715 uint32_t value = 0;
716 int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
717
718 switch (address >> DS_BASE_OFFSET) {
719 case DS9_REGION_ITCM:
720 case DS9_REGION_ITCM_MIRROR:
721 if (address < (512U << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
722 LOAD_16(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
723 break;
724 }
725 mLOG(DS_MEM, STUB, "Bad DS9 Load16: %08X:%08X", address, value);
726 break;
727 case DS_REGION_RAM:
728 if ((address & ~(DS9_SIZE_DTCM - 1)) == DS9_BASE_DTCM) {
729 LOAD_16(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
730 break;
731 }
732 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
733 LOAD_16(value, address & (DS_SIZE_RAM - 1), memory->ram);
734 break;
735 }
736 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load16: %08X", address);
737 case DS_REGION_IO:
738 value = DS9IORead(ds, address & 0x00FFFFFF);
739 break;
740 case DS9_REGION_BIOS:
741 // TODO: Fix undersized BIOS
742 // TODO: Fix masking
743 LOAD_16(value, address & (DS9_SIZE_BIOS - 1), memory->bios9);
744 break;
745 default:
746 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load16: %08X", address);
747 break;
748 }
749
750 if (cycleCounter) {
751 wait += 2;
752 *cycleCounter += wait;
753 }
754 // Unaligned 16-bit loads are "unpredictable", TODO: See what DS does
755 int rotate = (address & 1) << 3;
756 return ROR(value, rotate);
757}
758
759uint32_t DS9Load8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
760 struct DS* ds = (struct DS*) cpu->master;
761 struct DSMemory* memory = &ds->memory;
762 uint32_t value = 0;
763 int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
764
765 switch (address >> DS_BASE_OFFSET) {
766 case DS9_REGION_ITCM:
767 case DS9_REGION_ITCM_MIRROR:
768 if (address < (512U << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
769 value = ((uint8_t*) memory->itcm)[address & (DS9_SIZE_ITCM - 1)];
770 break;
771 }
772 mLOG(DS_MEM, STUB, "Bad DS9 Load8: %08X:%08X", address, value);
773 break;
774 case DS_REGION_RAM:
775 if ((address & ~(DS9_SIZE_DTCM - 1)) == DS9_BASE_DTCM) {
776 value = ((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)];
777 break;
778 }
779 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
780 value = ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)];
781 break;
782 }
783 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load8: %08X", address);
784 case DS9_REGION_BIOS:
785 // TODO: Fix undersized BIOS
786 // TODO: Fix masking
787 value = ((uint8_t*) memory->bios9)[address & (DS9_SIZE_BIOS - 1)];
788 break;
789 default:
790 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load8: %08X", address);
791 break;
792 }
793
794 if (cycleCounter) {
795 wait += 2;
796 *cycleCounter += wait;
797 }
798 return value;
799}
800
801void DS9Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) {
802 struct DS* ds = (struct DS*) cpu->master;
803 struct DSMemory* memory = &ds->memory;
804 int wait = ds->ds9.memory.waitstatesNonseq32[address >> DS_BASE_OFFSET];
805
806 switch (address >> DS_BASE_OFFSET) {
807 case DS9_REGION_ITCM:
808 case DS9_REGION_ITCM_MIRROR:
809 if (address < (512U << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
810 STORE_32(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
811 break;
812 }
813 mLOG(DS_MEM, STUB, "Bad DS9 Store32: %08X:%08X", address, value);
814 break;
815 case DS_REGION_RAM:
816 if ((address & ~(DS9_SIZE_DTCM - 1)) == DS9_BASE_DTCM) {
817 STORE_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
818 break;
819 }
820 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
821 STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
822 break;
823 }
824 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store32: %08X:%08X", address, value);
825 break;
826 case DS_REGION_IO:
827 DS9IOWrite32(ds, address & 0x00FFFFFF, value);
828 break;
829 default:
830 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store32: %08X:%08X", address, value);
831 break;
832 }
833
834 if (cycleCounter) {
835 ++wait;
836 *cycleCounter += wait;
837 }
838}
839
840void DS9Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
841 struct DS* ds = (struct DS*) cpu->master;
842 struct DSMemory* memory = &ds->memory;
843 int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
844
845 switch (address >> DS_BASE_OFFSET) {
846 case DS9_REGION_ITCM:
847 case DS9_REGION_ITCM_MIRROR:
848 if (address < (512U << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
849 STORE_16(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
850 break;
851 }
852 mLOG(DS_MEM, STUB, "Bad DS9 Store16: %08X:%04X", address, value);
853 break;
854 case DS_REGION_RAM:
855 if ((address & ~(DS9_SIZE_DTCM - 1)) == DS9_BASE_DTCM) {
856 STORE_16(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
857 break;
858 }
859 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
860 STORE_16(value, address & (DS_SIZE_RAM - 1), memory->ram);
861 break;
862 }
863 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store16: %08X:%04X", address, value);
864 break;
865 case DS_REGION_IO:
866 DS9IOWrite(ds, address & 0x00FFFFFF, value);
867 break;
868 default:
869 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store16: %08X:%04X", address, value);
870 break;
871 }
872
873 if (cycleCounter) {
874 ++wait;
875 *cycleCounter += wait;
876 }
877}
878
879void DS9Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
880 struct DS* ds = (struct DS*) cpu->master;
881 struct DSMemory* memory = &ds->memory;
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 < (512U << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
888 ((uint8_t*) memory->itcm)[address & (DS9_SIZE_ITCM - 1)] = value;
889 break;
890 }
891 mLOG(DS_MEM, STUB, "Bad DS9 Store8: %08X:%02X", address, value);
892 break;
893 case DS_REGION_RAM:
894 if ((address & ~(DS9_SIZE_DTCM - 1)) == DS9_BASE_DTCM) {
895 ((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)] = value;
896 break;
897 }
898 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
899 ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)] = value;
900 break;
901 }
902 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store8: %08X:%02X", address, value);
903 case DS_REGION_IO:
904 DS9IOWrite8(ds, address & 0x00FFFFFF, value);
905 break;
906 default:
907 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store8: %08X:%02X", address, value);
908 break;
909 }
910
911 if (cycleCounter) {
912 ++wait;
913 *cycleCounter += wait;
914 }
915}
916
917uint32_t DS9LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
918 struct DS* ds = (struct DS*) cpu->master;
919 struct DSMemory* memory = &ds->memory;
920 char* ws32 = ds->ds9.memory.waitstatesNonseq32;
921 uint32_t value;
922 int wait = 0;
923
924 int i;
925 int offset = 4;
926 int popcount = 0;
927 if (direction & LSM_D) {
928 offset = -4;
929 popcount = popcount32(mask);
930 address -= (popcount << 2) - 4;
931 }
932
933 if (direction & LSM_B) {
934 address += offset;
935 }
936
937 uint32_t addressMisalign = address & 0x3;
938 address &= 0xFFFFFFFC;
939
940 switch (address >> DS_BASE_OFFSET) {
941 case DS_REGION_RAM:
942 LDM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == DS9_BASE_DTCM) {
943 LOAD_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
944 } else if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
945 LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
946 } else {
947 mLOG(DS_MEM, STUB, "Unimplemented DS9 LDM: %08X", address);
948 });
949 break;
950 default:
951 mLOG(DS_MEM, STUB, "Unimplemented DS9 LDM: %08X", address);
952 LDM_LOOP(value = 0);
953 break;
954 }
955
956 if (cycleCounter) {
957 ++wait;
958 *cycleCounter += wait;
959 }
960
961 if (direction & LSM_B) {
962 address -= offset;
963 }
964
965 if (direction & LSM_D) {
966 address -= (popcount << 2) + 4;
967 }
968
969 return address | addressMisalign;
970}
971
972
973uint32_t DS9StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
974 struct DS* ds = (struct DS*) cpu->master;
975 struct DSMemory* memory = &ds->memory;
976 char* ws32 = ds->ds9.memory.waitstatesNonseq32;
977 uint32_t value;
978 int wait = 0;
979
980 int i;
981 int offset = 4;
982 int popcount = 0;
983 if (direction & LSM_D) {
984 offset = -4;
985 popcount = popcount32(mask);
986 address -= (popcount << 2) - 4;
987 }
988
989 if (direction & LSM_B) {
990 address += offset;
991 }
992
993 uint32_t addressMisalign = address & 0x3;
994 address &= 0xFFFFFFFC;
995
996 switch (address >> DS_BASE_OFFSET) {
997 case DS9_REGION_ITCM:
998 case DS9_REGION_ITCM_MIRROR:
999 STM_LOOP(if (address < (512U << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
1000 STORE_32(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
1001 } else {
1002 mLOG(DS_MEM, STUB, "Bad DS9 Store32: %08X:%08X", address, value);
1003 });
1004 break;
1005 case DS_REGION_RAM:
1006 STM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == DS9_BASE_DTCM) {
1007 STORE_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1008 } else if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1009 STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
1010 } else {
1011 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
1012 });
1013 break;
1014 default:
1015 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
1016 STM_LOOP();
1017 break;
1018 }
1019
1020 if (cycleCounter) {
1021 *cycleCounter += wait;
1022 }
1023
1024 if (direction & LSM_B) {
1025 address -= offset;
1026 }
1027
1028 if (direction & LSM_D) {
1029 address -= (popcount << 2) + 4;
1030 }
1031
1032 return address | addressMisalign;
1033}
1034
1035int32_t DSMemoryStall(struct ARMCore* cpu, int32_t wait) {
1036 return wait;
1037}
1038