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