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 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 memory->activeRegion9 = 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 & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
599 LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
600 break;
601 }
602 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load32: %08X", address);
603 break;
604 case DS_REGION_IO:
605 value = DS9IORead(ds, address & 0x00FFFFFC) | (DS9IORead(ds, (address & 0x00FFFFFC) | 2) << 16);
606 break;
607 default:
608 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load32: %08X", address);
609 break;
610 }
611
612 if (cycleCounter) {
613 wait += 2;
614 *cycleCounter += wait;
615 }
616 // Unaligned 32-bit loads are "rotated" so they make some semblance of sense
617 int rotate = (address & 3) << 3;
618 return ROR(value, rotate);
619}
620
621uint32_t DS9Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
622 struct DS* ds = (struct DS*) cpu->master;
623 struct DSMemory* memory = &ds->memory;
624 uint32_t value = 0;
625 int wait = 0;
626
627 switch (address >> DS_BASE_OFFSET) {
628 case DS_REGION_RAM:
629 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
630 LOAD_16(value, address & (DS_SIZE_RAM - 1), memory->ram);
631 break;
632 }
633 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load16: %08X", address);
634 case DS_REGION_IO:
635 value = DS9IORead(ds, address & 0x00FFFFFF);
636 break;
637 default:
638 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load16: %08X", address);
639 break;
640 }
641
642 if (cycleCounter) {
643 wait += 2;
644 *cycleCounter += wait;
645 }
646 // Unaligned 16-bit loads are "unpredictable", TODO: See what DS does
647 int rotate = (address & 1) << 3;
648 return ROR(value, rotate);
649}
650
651uint32_t DS9Load8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
652 struct DS* ds = (struct DS*) cpu->master;
653 struct DSMemory* memory = &ds->memory;
654 uint32_t value = 0;
655 int wait = 0;
656
657 switch (address >> DS_BASE_OFFSET) {
658 case DS_REGION_RAM:
659 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
660 value = ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)];
661 break;
662 }
663 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load8: %08X", address);
664 default:
665 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load8: %08X", address);
666 break;
667 }
668
669 if (cycleCounter) {
670 wait += 2;
671 *cycleCounter += wait;
672 }
673 return value;
674}
675
676void DS9Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) {
677 struct DS* ds = (struct DS*) cpu->master;
678 struct DSMemory* memory = &ds->memory;
679 int wait = 0;
680
681 switch (address >> DS_BASE_OFFSET) {
682 case DS9_REGION_ITCM:
683 case DS9_REGION_ITCM_MIRROR:
684 if (address < (512 << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
685 STORE_32(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
686 break;
687 }
688 mLOG(DS_MEM, STUB, "Bad DS9 Store32: %08X:%08X", address, value);
689 break;
690 case DS_REGION_RAM:
691 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
692 STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
693 break;
694 }
695 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store32: %08X:%08X", address, value);
696 break;
697 case DS_REGION_IO:
698 DS9IOWrite32(ds, address & 0x00FFFFFF, value);
699 break;
700 default:
701 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store32: %08X:%08X", address, value);
702 break;
703 }
704
705 if (cycleCounter) {
706 ++wait;
707 *cycleCounter += wait;
708 }
709}
710
711void DS9Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
712 struct DS* ds = (struct DS*) cpu->master;
713 struct DSMemory* memory = &ds->memory;
714 int wait = 0;
715
716 switch (address >> DS_BASE_OFFSET) {
717 case DS9_REGION_ITCM:
718 case DS9_REGION_ITCM_MIRROR:
719 if (address < (512 << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
720 STORE_16(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
721 break;
722 }
723 mLOG(DS_MEM, STUB, "Bad DS9 Store16: %08X:%04X", address, value);
724 break;
725 case DS_REGION_RAM:
726 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
727 STORE_16(value, address & (DS_SIZE_RAM - 1), memory->ram);
728 break;
729 }
730 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store16: %08X:%04X", address, value);
731 break;
732 case DS_REGION_IO:
733 DS9IOWrite(ds, address & 0x00FFFFFF, value);
734 break;
735 default:
736 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store16: %08X:%04X", address, value);
737 break;
738 }
739
740 if (cycleCounter) {
741 ++wait;
742 *cycleCounter += wait;
743 }
744}
745
746void DS9Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
747 struct DS* ds = (struct DS*) cpu->master;
748 struct DSMemory* memory = &ds->memory;
749 int wait = 0;
750
751 switch (address >> DS_BASE_OFFSET) {
752 case DS9_REGION_ITCM:
753 case DS9_REGION_ITCM_MIRROR:
754 if (address < (512U << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
755 ((uint8_t*) memory->itcm)[address & (DS9_SIZE_ITCM - 1)] = value;
756 break;
757 }
758 mLOG(DS_MEM, STUB, "Bad DS9 Store8: %08X:%02X", address, value);
759 break;
760 case DS_REGION_RAM:
761 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
762 ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)] = value;
763 break;
764 }
765 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store8: %08X:%02X", address, value);
766 case DS_REGION_IO:
767 DS9IOWrite8(ds, address & 0x00FFFFFF, value);
768 break;
769 default:
770 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store8: %08X:%02X", address, value);
771 break;
772 }
773
774 if (cycleCounter) {
775 ++wait;
776 *cycleCounter += wait;
777 }
778}
779
780uint32_t DS9LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
781 struct DS* ds = (struct DS*) cpu->master;
782 struct DSMemory* memory = &ds->memory;
783 uint32_t value;
784 int wait = 0;
785
786 int i;
787 int offset = 4;
788 int popcount = 0;
789 if (direction & LSM_D) {
790 offset = -4;
791 popcount = popcount32(mask);
792 address -= (popcount << 2) - 4;
793 }
794
795 if (direction & LSM_B) {
796 address += offset;
797 }
798
799 uint32_t addressMisalign = address & 0x3;
800 address &= 0xFFFFFFFC;
801
802 switch (address >> DS_BASE_OFFSET) {
803 case DS_REGION_RAM:
804 LDM_LOOP(if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
805 LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
806 } else {
807 mLOG(DS_MEM, STUB, "Unimplemented DS9 LDM: %08X", address);
808 });
809 break;
810 default:
811 mLOG(DS_MEM, STUB, "Unimplemented DS9 LDM: %08X", address);
812 LDM_LOOP(value = 0);
813 break;
814 }
815
816 if (cycleCounter) {
817 ++wait;
818 *cycleCounter += wait;
819 }
820
821 if (direction & LSM_B) {
822 address -= offset;
823 }
824
825 if (direction & LSM_D) {
826 address -= (popcount << 2) + 4;
827 }
828
829 return address | addressMisalign;
830}
831
832
833uint32_t DS9StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
834 struct DS* ds = (struct DS*) cpu->master;
835 struct DSMemory* memory = &ds->memory;
836 uint32_t value;
837 int wait = 0;
838
839 int i;
840 int offset = 4;
841 int popcount = 0;
842 if (direction & LSM_D) {
843 offset = -4;
844 popcount = popcount32(mask);
845 address -= (popcount << 2) - 4;
846 }
847
848 if (direction & LSM_B) {
849 address += offset;
850 }
851
852 uint32_t addressMisalign = address & 0x3;
853 address &= 0xFFFFFFFC;
854
855 switch (address >> DS_BASE_OFFSET) {
856 case DS9_REGION_ITCM:
857 case DS9_REGION_ITCM_MIRROR:
858 STM_LOOP(if (address < (512U << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
859 STORE_32(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
860 } else {
861 mLOG(DS_MEM, STUB, "Bad DS9 Store32: %08X:%08X", address, value);
862 });
863 break;
864 case DS_REGION_RAM:
865 STM_LOOP(if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
866 STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
867 } else {
868 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
869 });
870 break;
871 default:
872 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
873 STM_LOOP();
874 break;
875 }
876
877 if (cycleCounter) {
878 *cycleCounter += wait;
879 }
880
881 if (direction & LSM_B) {
882 address -= offset;
883 }
884
885 if (direction & LSM_D) {
886 address -= (popcount << 2) + 4;
887 }
888
889 return address | addressMisalign;
890}
891
892int32_t DSMemoryStall(struct ARMCore* cpu, int32_t wait) {
893 return wait;
894}
895