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