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 "memory.h"
7
8#include "arm/macros.h"
9
10#include "ds/ds.h"
11#include "ds/io.h"
12#include "util/math.h"
13#include "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->arm7;
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->arm9;
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->memory.activeRegion7 = -1;
115 ds->memory.activeRegion9 = -1;
116
117 arm7->memory.activeRegion = 0;
118 arm7->memory.activeMask = 0;
119 arm7->memory.setActiveRegion = DS7SetActiveRegion;
120 arm7->memory.activeSeqCycles32 = 0;
121 arm7->memory.activeSeqCycles16 = 0;
122 arm7->memory.activeNonseqCycles32 = 0;
123 arm7->memory.activeNonseqCycles16 = 0;
124
125 arm9->memory.activeRegion = 0;
126 arm9->memory.activeMask = 0;
127 arm9->memory.setActiveRegion = DS9SetActiveRegion;
128 arm9->memory.activeSeqCycles32 = 0;
129 arm9->memory.activeSeqCycles16 = 0;
130 arm9->memory.activeNonseqCycles32 = 0;
131 arm9->memory.activeNonseqCycles16 = 0;
132}
133
134void DSMemoryDeinit(struct DS* ds) {
135 mappedMemoryFree(ds->memory.wram, DS_SIZE_WORKING_RAM);
136 mappedMemoryFree(ds->memory.wram7, DS7_SIZE_WORKING_RAM);
137 mappedMemoryFree(ds->memory.ram, DS_SIZE_RAM);
138 mappedMemoryFree(ds->memory.itcm, DS9_SIZE_ITCM);
139 mappedMemoryFree(ds->memory.dtcm, DS9_SIZE_DTCM);
140}
141
142void DSMemoryReset(struct DS* ds) {
143 if (ds->memory.wram) {
144 mappedMemoryFree(ds->memory.wram, DS_SIZE_WORKING_RAM);
145 }
146 ds->memory.wram = anonymousMemoryMap(DS_SIZE_WORKING_RAM);
147
148 if (ds->memory.wram7) {
149 mappedMemoryFree(ds->memory.wram7, DS7_SIZE_WORKING_RAM);
150 }
151 ds->memory.wram7 = anonymousMemoryMap(DS7_SIZE_WORKING_RAM);
152
153 if (ds->memory.ram) {
154 mappedMemoryFree(ds->memory.ram, DS_SIZE_RAM);
155 }
156 ds->memory.ram = anonymousMemoryMap(DS_SIZE_RAM);
157
158 if (ds->memory.itcm) {
159 mappedMemoryFree(ds->memory.itcm, DS9_SIZE_ITCM);
160 }
161 ds->memory.itcm = anonymousMemoryMap(DS9_SIZE_ITCM);
162
163 if (ds->memory.dtcm) {
164 mappedMemoryFree(ds->memory.dtcm, DS9_SIZE_DTCM);
165 }
166 ds->memory.dtcm = anonymousMemoryMap(DS9_SIZE_DTCM);
167
168 memset(ds->memory.dma7, 0, sizeof(ds->memory.dma7));
169 memset(ds->memory.dma9, 0, sizeof(ds->memory.dma9));
170 ds->memory.activeDMA7 = -1;
171 ds->memory.activeDMA9 = -1;
172 ds->memory.nextDMA = INT_MAX;
173 ds->memory.eventDiff = 0;
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 memory->activeRegion7 = 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 default:
252 mLOG(DS_MEM, STUB, "Unimplemented DS7 Load32: %08X", address);
253 break;
254 }
255
256 if (cycleCounter) {
257 wait += 2;
258 *cycleCounter += wait;
259 }
260 // Unaligned 32-bit loads are "rotated" so they make some semblance of sense
261 int rotate = (address & 3) << 3;
262 return ROR(value, rotate);
263}
264
265uint32_t DS7Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
266 struct DS* ds = (struct DS*) cpu->master;
267 struct DSMemory* memory = &ds->memory;
268 uint32_t value = 0;
269 int wait = 0;
270
271 switch (address >> DS_BASE_OFFSET) {
272 case DS7_REGION_BIOS:
273 LOAD_16(value, address & (DS7_SIZE_BIOS - 1), memory->bios7);
274 break;
275 case DS_REGION_WORKING_RAM:
276 if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
277 LOAD_16(value, address & (DS7_SIZE_WORKING_RAM - 1), memory->wram7);
278 } else {
279 LOAD_16(value, address & (ds->memory.wramSize7 - 1), memory->wram);
280 }
281 break;
282 case DS_REGION_RAM:
283 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
284 LOAD_16(value, address & (DS_SIZE_RAM - 1), memory->ram);
285 break;
286 }
287 mLOG(DS_MEM, STUB, "Unimplemented DS7 Load16: %08X", address);
288 case DS_REGION_IO:
289 value = DS7IORead(ds, address & 0x00FFFFFF);
290 break;
291 default:
292 mLOG(DS_MEM, STUB, "Unimplemented DS7 Load16: %08X", address);
293 break;
294 }
295
296 if (cycleCounter) {
297 wait += 2;
298 *cycleCounter += wait;
299 }
300 // Unaligned 16-bit loads are "unpredictable", TODO: See what DS does
301 int rotate = (address & 1) << 3;
302 return ROR(value, rotate);
303}
304
305uint32_t DS7Load8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
306 struct DS* ds = (struct DS*) cpu->master;
307 struct DSMemory* memory = &ds->memory;
308 uint32_t value = 0;
309 int wait = 0;
310
311 switch (address >> DS_BASE_OFFSET) {
312 case DS_REGION_RAM:
313 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
314 value = ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)];
315 break;
316 }
317 mLOG(DS_MEM, STUB, "Unimplemented DS7 Load8: %08X", address);
318 default:
319 mLOG(DS_MEM, STUB, "Unimplemented DS7 Load8: %08X", address);
320 break;
321 }
322
323 if (cycleCounter) {
324 wait += 2;
325 *cycleCounter += wait;
326 }
327 return value;
328}
329
330void DS7Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) {
331 struct DS* ds = (struct DS*) cpu->master;
332 struct DSMemory* memory = &ds->memory;
333 int wait = 0;
334
335 switch (address >> DS_BASE_OFFSET) {
336 case DS_REGION_WORKING_RAM:
337 if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
338 STORE_32(value, address & (DS7_SIZE_WORKING_RAM - 1), memory->wram7);
339 } else {
340 STORE_32(value, address & (ds->memory.wramSize7 - 1), memory->wram);
341 }
342 break;
343 case DS_REGION_RAM:
344 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
345 STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
346 break;
347 }
348 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store32: %08X:%08X", address, value);
349 break;
350 default:
351 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store32: %08X:%08X", address, value);
352 break;
353 }
354
355 if (cycleCounter) {
356 ++wait;
357 *cycleCounter += wait;
358 }
359}
360
361void DS7Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
362 struct DS* ds = (struct DS*) cpu->master;
363 struct DSMemory* memory = &ds->memory;
364 int wait = 0;
365
366 switch (address >> DS_BASE_OFFSET) {
367 case DS_REGION_WORKING_RAM:
368 if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
369 STORE_16(value, address & (DS7_SIZE_WORKING_RAM - 1), memory->wram7);
370 } else {
371 STORE_16(value, address & (ds->memory.wramSize7 - 1), memory->wram);
372 }
373 break;
374 case DS_REGION_RAM:
375 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
376 STORE_16(value, address & (DS_SIZE_RAM - 1), memory->ram);
377 break;
378 }
379 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store16: %08X:%04X", address, value);
380 break;
381 case DS_REGION_IO:
382 DS7IOWrite(ds, address & 0x00FFFFFF, value);
383 break;
384 default:
385 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store16: %08X:%04X", address, value);
386 break;
387 }
388
389 if (cycleCounter) {
390 ++wait;
391 *cycleCounter += wait;
392 }
393}
394
395void DS7Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
396 struct DS* ds = (struct DS*) cpu->master;
397 struct DSMemory* memory = &ds->memory;
398 int wait = 0;
399
400 switch (address >> DS_BASE_OFFSET) {
401 case DS_REGION_RAM:
402 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
403 ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)] = value;
404 break;
405 }
406 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store8: %08X:%02X", address, value);
407 case DS_REGION_IO:
408 DS7IOWrite8(ds, address & 0x00FFFFFF, value);
409 break;
410 default:
411 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store8: %08X:%02X", address, value);
412 break;
413 }
414
415 if (cycleCounter) {
416 ++wait;
417 *cycleCounter += wait;
418 }
419}
420
421uint32_t DS7LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
422 struct DS* ds = (struct DS*) cpu->master;
423 struct DSMemory* memory = &ds->memory;
424 uint32_t value;
425 int wait = 0;
426
427 int i;
428 int offset = 4;
429 int popcount = 0;
430 if (direction & LSM_D) {
431 offset = -4;
432 popcount = popcount32(mask);
433 address -= (popcount << 2) - 4;
434 }
435
436 if (direction & LSM_B) {
437 address += offset;
438 }
439
440 uint32_t addressMisalign = address & 0x3;
441 address &= 0xFFFFFFFC;
442
443 switch (address >> DS_BASE_OFFSET) {
444 case DS_REGION_WORKING_RAM:
445 LDM_LOOP(if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
446 LOAD_32(value, address & (DS7_SIZE_WORKING_RAM - 1), memory->wram7);
447 } else {
448 LOAD_32(value, address & (ds->memory.wramSize7 - 1), memory->wram);
449 });
450 break;
451 case DS_REGION_RAM:
452 LDM_LOOP(if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
453 LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
454 } else {
455 mLOG(DS_MEM, STUB, "Unimplemented DS7 LDM: %08X", address);
456 });
457 break;
458 default:
459 mLOG(DS_MEM, STUB, "Unimplemented DS7 LDM: %08X", address);
460 LDM_LOOP(value = 0);
461 }
462
463 if (cycleCounter) {
464 ++wait;
465 *cycleCounter += wait;
466 }
467
468 if (direction & LSM_B) {
469 address -= offset;
470 }
471
472 if (direction & LSM_D) {
473 address -= (popcount << 2) + 4;
474 }
475
476 return address | addressMisalign;
477}
478
479
480uint32_t DS7StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
481 struct DS* ds = (struct DS*) cpu->master;
482 struct DSMemory* memory = &ds->memory;
483 uint32_t value;
484 int wait = 0;
485
486 int i;
487 int offset = 4;
488 int popcount = 0;
489 if (direction & LSM_D) {
490 offset = -4;
491 popcount = popcount32(mask);
492 address -= (popcount << 2) - 4;
493 }
494
495 if (direction & LSM_B) {
496 address += offset;
497 }
498
499 uint32_t addressMisalign = address & 0x3;
500 address &= 0xFFFFFFFC;
501
502 switch (address >> DS_BASE_OFFSET) {
503 case DS_REGION_WORKING_RAM:
504 STM_LOOP(if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
505 STORE_32(value, address & (DS7_SIZE_WORKING_RAM - 1), memory->wram7);
506 } else {
507 STORE_32(value, address & (ds->memory.wramSize7 - 1), memory->wram);
508 });
509 break;
510 case DS_REGION_RAM:
511 STM_LOOP(if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
512 STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
513 } else {
514 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
515 });
516 break;
517 default:
518 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
519 STM_LOOP();
520 break;
521 }
522
523 if (cycleCounter) {
524 *cycleCounter += wait;
525 }
526
527 if (direction & LSM_B) {
528 address -= offset;
529 }
530
531 if (direction & LSM_D) {
532 address -= (popcount << 2) + 4;
533 }
534
535 return address | addressMisalign;
536}
537
538static void DS9SetActiveRegion(struct ARMCore* cpu, uint32_t address) {
539 struct DS* ds = (struct DS*) cpu->master;
540 struct DSMemory* memory = &ds->memory;
541
542 int newRegion = address >> DS_BASE_OFFSET;
543
544 memory->activeRegion9 = newRegion;
545 switch (newRegion) {
546 case DS9_REGION_ITCM:
547 case DS9_REGION_ITCM_MIRROR:
548 if (address < (512U << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
549 cpu->memory.activeRegion = memory->itcm;
550 cpu->memory.activeMask = DS9_SIZE_ITCM - 1;
551 return;
552 }
553 goto jump_error;
554 case DS_REGION_RAM:
555 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
556 cpu->memory.activeRegion = memory->ram;
557 cpu->memory.activeMask = DS_SIZE_RAM - 1;
558 return;
559 }
560 goto jump_error;
561 case DS9_REGION_BIOS:
562 // TODO: Mask properly
563 if (memory->bios9) {
564 cpu->memory.activeRegion = memory->bios9;
565 cpu->memory.activeMask = DS9_SIZE_BIOS - 1;
566 } else {
567 cpu->memory.activeRegion = _deadbeef;
568 cpu->memory.activeMask = 0;
569 }
570 return;
571 default:
572 break;
573 }
574
575jump_error:
576 cpu->memory.activeRegion = _deadbeef;
577 cpu->memory.activeMask = 0;
578 mLOG(DS_MEM, FATAL, "Jumped to invalid address: %08X", address);
579}
580
581uint32_t DS9Load32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
582 struct DS* ds = (struct DS*) cpu->master;
583 struct DSMemory* memory = &ds->memory;
584 uint32_t value = 0;
585 int wait = 0;
586
587 switch (address >> DS_BASE_OFFSET) {
588 case DS_REGION_RAM:
589 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
590 LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
591 break;
592 }
593 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load32: %08X", address);
594 break;
595 default:
596 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load32: %08X", address);
597 break;
598 }
599
600 if (cycleCounter) {
601 wait += 2;
602 *cycleCounter += wait;
603 }
604 // Unaligned 32-bit loads are "rotated" so they make some semblance of sense
605 int rotate = (address & 3) << 3;
606 return ROR(value, rotate);
607}
608
609uint32_t DS9Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
610 struct DS* ds = (struct DS*) cpu->master;
611 struct DSMemory* memory = &ds->memory;
612 uint32_t value = 0;
613 int wait = 0;
614
615 switch (address >> DS_BASE_OFFSET) {
616 case DS_REGION_RAM:
617 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
618 LOAD_16(value, address & (DS_SIZE_RAM - 1), memory->ram);
619 break;
620 }
621 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load16: %08X", address);
622 case DS_REGION_IO:
623 value = DS9IORead(ds, address & 0x00FFFFFF);
624 break;
625 default:
626 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load16: %08X", address);
627 break;
628 }
629
630 if (cycleCounter) {
631 wait += 2;
632 *cycleCounter += wait;
633 }
634 // Unaligned 16-bit loads are "unpredictable", TODO: See what DS does
635 int rotate = (address & 1) << 3;
636 return ROR(value, rotate);
637}
638
639uint32_t DS9Load8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
640 struct DS* ds = (struct DS*) cpu->master;
641 struct DSMemory* memory = &ds->memory;
642 uint32_t value = 0;
643 int wait = 0;
644
645 switch (address >> DS_BASE_OFFSET) {
646 case DS_REGION_RAM:
647 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
648 value = ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)];
649 break;
650 }
651 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load8: %08X", address);
652 default:
653 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load8: %08X", address);
654 break;
655 }
656
657 if (cycleCounter) {
658 wait += 2;
659 *cycleCounter += wait;
660 }
661 return value;
662}
663
664void DS9Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) {
665 struct DS* ds = (struct DS*) cpu->master;
666 struct DSMemory* memory = &ds->memory;
667 int wait = 0;
668
669 switch (address >> DS_BASE_OFFSET) {
670 case DS9_REGION_ITCM:
671 case DS9_REGION_ITCM_MIRROR:
672 if (address < (512 << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
673 STORE_32(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
674 break;
675 }
676 mLOG(DS_MEM, STUB, "Bad DS9 Store32: %08X:%08X", address, value);
677 break;
678 case DS_REGION_RAM:
679 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
680 STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
681 break;
682 }
683 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store32: %08X:%08X", address, value);
684 break;
685 default:
686 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store32: %08X:%08X", address, value);
687 break;
688 }
689
690 if (cycleCounter) {
691 ++wait;
692 *cycleCounter += wait;
693 }
694}
695
696void DS9Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
697 struct DS* ds = (struct DS*) cpu->master;
698 struct DSMemory* memory = &ds->memory;
699 int wait = 0;
700
701 switch (address >> DS_BASE_OFFSET) {
702 case DS9_REGION_ITCM:
703 case DS9_REGION_ITCM_MIRROR:
704 if (address < (512 << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
705 STORE_16(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
706 break;
707 }
708 mLOG(DS_MEM, STUB, "Bad DS9 Store16: %08X:%04X", address, value);
709 break;
710 case DS_REGION_RAM:
711 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
712 STORE_16(value, address & (DS_SIZE_RAM - 1), memory->ram);
713 break;
714 }
715 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store16: %08X:%04X", address, value);
716 break;
717 case DS_REGION_IO:
718 DS9IOWrite(ds, address & 0x00FFFFFF, value);
719 break;
720 default:
721 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store16: %08X:%04X", address, value);
722 break;
723 }
724
725 if (cycleCounter) {
726 ++wait;
727 *cycleCounter += wait;
728 }
729}
730
731void DS9Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
732 struct DS* ds = (struct DS*) cpu->master;
733 struct DSMemory* memory = &ds->memory;
734 int wait = 0;
735
736 switch (address >> DS_BASE_OFFSET) {
737 case DS9_REGION_ITCM:
738 case DS9_REGION_ITCM_MIRROR:
739 if (address < (512U << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
740 ((uint8_t*) memory->itcm)[address & (DS9_SIZE_ITCM - 1)] = value;
741 break;
742 }
743 mLOG(DS_MEM, STUB, "Bad DS9 Store8: %08X:%02X", address, value);
744 break;
745 case DS_REGION_RAM:
746 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
747 ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)] = value;
748 break;
749 }
750 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store8: %08X:%02X", address, value);
751 case DS_REGION_IO:
752 DS9IOWrite8(ds, address & 0x00FFFFFF, value);
753 break;
754 default:
755 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store8: %08X:%02X", address, value);
756 break;
757 }
758
759 if (cycleCounter) {
760 ++wait;
761 *cycleCounter += wait;
762 }
763}
764
765uint32_t DS9LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
766 struct DS* ds = (struct DS*) cpu->master;
767 struct DSMemory* memory = &ds->memory;
768 uint32_t value;
769 int wait = 0;
770
771 int i;
772 int offset = 4;
773 int popcount = 0;
774 if (direction & LSM_D) {
775 offset = -4;
776 popcount = popcount32(mask);
777 address -= (popcount << 2) - 4;
778 }
779
780 if (direction & LSM_B) {
781 address += offset;
782 }
783
784 uint32_t addressMisalign = address & 0x3;
785 address &= 0xFFFFFFFC;
786
787 switch (address >> DS_BASE_OFFSET) {
788 case DS_REGION_RAM:
789 LDM_LOOP(if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
790 LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
791 } else {
792 mLOG(DS_MEM, STUB, "Unimplemented DS9 LDM: %08X", address);
793 });
794 break;
795 default:
796 mLOG(DS_MEM, STUB, "Unimplemented DS9 LDM: %08X", address);
797 LDM_LOOP(value = 0);
798 break;
799 }
800
801 if (cycleCounter) {
802 ++wait;
803 *cycleCounter += wait;
804 }
805
806 if (direction & LSM_B) {
807 address -= offset;
808 }
809
810 if (direction & LSM_D) {
811 address -= (popcount << 2) + 4;
812 }
813
814 return address | addressMisalign;
815}
816
817
818uint32_t DS9StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
819 struct DS* ds = (struct DS*) cpu->master;
820 struct DSMemory* memory = &ds->memory;
821 uint32_t value;
822 int wait = 0;
823
824 int i;
825 int offset = 4;
826 int popcount = 0;
827 if (direction & LSM_D) {
828 offset = -4;
829 popcount = popcount32(mask);
830 address -= (popcount << 2) - 4;
831 }
832
833 if (direction & LSM_B) {
834 address += offset;
835 }
836
837 uint32_t addressMisalign = address & 0x3;
838 address &= 0xFFFFFFFC;
839
840 switch (address >> DS_BASE_OFFSET) {
841 case DS9_REGION_ITCM:
842 case DS9_REGION_ITCM_MIRROR:
843 STM_LOOP(if (address < (512U << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
844 STORE_32(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
845 } else {
846 mLOG(DS_MEM, STUB, "Bad DS9 Store32: %08X:%08X", address, value);
847 });
848 break;
849 case DS_REGION_RAM:
850 STM_LOOP(if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
851 STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
852 } else {
853 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
854 });
855 break;
856 default:
857 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
858 STM_LOOP();
859 break;
860 }
861
862 if (cycleCounter) {
863 *cycleCounter += wait;
864 }
865
866 if (direction & LSM_B) {
867 address -= offset;
868 }
869
870 if (direction & LSM_D) {
871 address -= (popcount << 2) + 4;
872 }
873
874 return address | addressMisalign;
875}
876
877int32_t DSMemoryStall(struct ARMCore* cpu, int32_t wait) {
878 return wait;
879}
880