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.ram = NULL;
108 ds->memory.rom = NULL;
109
110 ds->memory.activeRegion7 = -1;
111 ds->memory.activeRegion9 = -1;
112
113 arm7->memory.activeRegion = 0;
114 arm7->memory.activeMask = 0;
115 arm7->memory.setActiveRegion = DS7SetActiveRegion;
116 arm7->memory.activeSeqCycles32 = 0;
117 arm7->memory.activeSeqCycles16 = 0;
118 arm7->memory.activeNonseqCycles32 = 0;
119 arm7->memory.activeNonseqCycles16 = 0;
120
121 arm9->memory.activeRegion = 0;
122 arm9->memory.activeMask = 0;
123 arm9->memory.setActiveRegion = DS9SetActiveRegion;
124 arm9->memory.activeSeqCycles32 = 0;
125 arm9->memory.activeSeqCycles16 = 0;
126 arm9->memory.activeNonseqCycles32 = 0;
127 arm9->memory.activeNonseqCycles16 = 0;
128}
129
130void DSMemoryDeinit(struct DS* ds) {
131 mappedMemoryFree(ds->memory.wram, DS_SIZE_WORKING_RAM);
132 mappedMemoryFree(ds->memory.ram, DS_SIZE_RAM);
133}
134
135void DSMemoryReset(struct DS* ds) {
136 if (ds->memory.wram) {
137 mappedMemoryFree(ds->memory.wram, DS_SIZE_WORKING_RAM);
138 }
139 ds->memory.wram = anonymousMemoryMap(DS_SIZE_WORKING_RAM);
140
141 if (ds->memory.ram) {
142 mappedMemoryFree(ds->memory.ram, DS_SIZE_RAM);
143 }
144 ds->memory.ram = anonymousMemoryMap(DS_SIZE_RAM);
145
146 memset(ds->memory.dma7, 0, sizeof(ds->memory.dma7));
147 memset(ds->memory.dma9, 0, sizeof(ds->memory.dma9));
148 ds->memory.activeDMA7 = -1;
149 ds->memory.activeDMA9 = -1;
150 ds->memory.nextDMA = INT_MAX;
151 ds->memory.eventDiff = 0;
152
153 if (!ds->memory.wram || !ds->memory.ram) {
154 DSMemoryDeinit(ds);
155 mLOG(DS_MEM, FATAL, "Could not map memory");
156 }
157}
158
159static void DS7SetActiveRegion(struct ARMCore* cpu, uint32_t address) {
160 struct DS* ds = (struct DS*) cpu->master;
161 struct DSMemory* memory = &ds->memory;
162
163 int newRegion = address >> DS_BASE_OFFSET;
164
165 memory->activeRegion7 = newRegion;
166 switch (newRegion) {
167 case DS_REGION_RAM:
168 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
169 cpu->memory.activeRegion = memory->ram;
170 cpu->memory.activeMask = DS_SIZE_RAM - 1;
171 return;
172 }
173 break;
174 case DS7_REGION_BIOS:
175 if (memory->bios7) {
176 cpu->memory.activeRegion = memory->bios9;
177 cpu->memory.activeMask = DS9_SIZE_BIOS - 1;
178 } else {
179 cpu->memory.activeRegion = _deadbeef;
180 cpu->memory.activeMask = 0;
181 }
182 return;
183 default:
184 break;
185 }
186 cpu->memory.activeRegion = _deadbeef;
187 cpu->memory.activeMask = 0;
188 mLOG(DS_MEM, FATAL, "Jumped to invalid address: %08X", address);
189 return;
190}
191
192uint32_t DS7Load32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
193 struct DS* ds = (struct DS*) cpu->master;
194 struct DSMemory* memory = &ds->memory;
195 uint32_t value = 0;
196 int wait = 0;
197
198 switch (address >> DS_BASE_OFFSET) {
199 case DS_REGION_RAM:
200 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
201 LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
202 }
203 break;
204 default:
205 break;
206 }
207
208 if (cycleCounter) {
209 wait += 2;
210 *cycleCounter += wait;
211 }
212 // Unaligned 32-bit loads are "rotated" so they make some semblance of sense
213 int rotate = (address & 3) << 3;
214 return ROR(value, rotate);
215}
216
217uint32_t DS7Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
218 struct DS* ds = (struct DS*) cpu->master;
219 struct DSMemory* memory = &ds->memory;
220 uint32_t value = 0;
221 int wait = 0;
222
223 switch (address >> DS_BASE_OFFSET) {
224 default:
225 break;
226 }
227
228 if (cycleCounter) {
229 wait += 2;
230 *cycleCounter += wait;
231 }
232 // Unaligned 16-bit loads are "unpredictable", TODO: See what DS does
233 int rotate = (address & 1) << 3;
234 return ROR(value, rotate);
235}
236
237uint32_t DS7Load8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
238 struct DS* ds = (struct DS*) cpu->master;
239 struct DSMemory* memory = &ds->memory;
240 uint32_t value = 0;
241 int wait = 0;
242
243 switch (address >> DS_BASE_OFFSET) {
244 default:
245 break;
246 }
247
248 if (cycleCounter) {
249 wait += 2;
250 *cycleCounter += wait;
251 }
252 return value;
253}
254
255void DS7Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) {
256 struct DS* ds = (struct DS*) cpu->master;
257 struct DSMemory* memory = &ds->memory;
258 int wait = 0;
259
260 switch (address >> DS_BASE_OFFSET) {
261 break;
262 }
263
264 if (cycleCounter) {
265 ++wait;
266 *cycleCounter += wait;
267 }
268}
269
270void DS7Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
271 struct DS* ds = (struct DS*) cpu->master;
272 struct DSMemory* memory = &ds->memory;
273 int wait = 0;
274
275 switch (address >> DS_BASE_OFFSET) {
276 default:
277 break;
278 }
279
280 if (cycleCounter) {
281 ++wait;
282 *cycleCounter += wait;
283 }
284}
285
286void DS7Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
287 struct DS* ds = (struct DS*) cpu->master;
288 struct DSMemory* memory = &ds->memory;
289 int wait = 0;
290
291 switch (address >> DS_BASE_OFFSET) {
292 default:
293 break;
294 }
295
296 if (cycleCounter) {
297 ++wait;
298 *cycleCounter += wait;
299 }
300}
301
302uint32_t DS7LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
303 struct DS* ds = (struct DS*) cpu->master;
304 struct DSMemory* memory = &ds->memory;
305 uint32_t value;
306 int wait = 0;
307
308 int i;
309 int offset = 4;
310 int popcount = 0;
311 if (direction & LSM_D) {
312 offset = -4;
313 popcount = popcount32(mask);
314 address -= (popcount << 2) - 4;
315 }
316
317 if (direction & LSM_B) {
318 address += offset;
319 }
320
321 uint32_t addressMisalign = address & 0x3;
322 address &= 0xFFFFFFFC;
323
324 switch (address >> DS_BASE_OFFSET) {
325 default:
326 break;
327 }
328
329 if (cycleCounter) {
330 ++wait;
331 *cycleCounter += wait;
332 }
333
334 if (direction & LSM_B) {
335 address -= offset;
336 }
337
338 if (direction & LSM_D) {
339 address -= (popcount << 2) + 4;
340 }
341
342 return address | addressMisalign;
343}
344
345
346uint32_t DS7StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
347 struct DS* ds = (struct DS*) cpu->master;
348 struct DSMemory* memory = &ds->memory;
349 uint32_t value;
350 int wait = 0;
351
352 int i;
353 int offset = 4;
354 int popcount = 0;
355 if (direction & LSM_D) {
356 offset = -4;
357 popcount = popcount32(mask);
358 address -= (popcount << 2) - 4;
359 }
360
361 if (direction & LSM_B) {
362 address += offset;
363 }
364
365 uint32_t addressMisalign = address & 0x3;
366 address &= 0xFFFFFFFC;
367
368 switch (address >> DS_BASE_OFFSET) {
369 default:
370 break;
371 }
372
373 if (cycleCounter) {
374 *cycleCounter += wait;
375 }
376
377 if (direction & LSM_B) {
378 address -= offset;
379 }
380
381 if (direction & LSM_D) {
382 address -= (popcount << 2) + 4;
383 }
384
385 return address | addressMisalign;
386}
387
388static void DS9SetActiveRegion(struct ARMCore* cpu, uint32_t address) {
389 struct DS* ds = (struct DS*) cpu->master;
390 struct DSMemory* memory = &ds->memory;
391
392 int newRegion = address >> DS_BASE_OFFSET;
393
394 memory->activeRegion9 = newRegion;
395 switch (newRegion) {
396 case DS_REGION_RAM:
397 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
398 cpu->memory.activeRegion = memory->ram;
399 cpu->memory.activeMask = DS_SIZE_RAM - 1;
400 return;
401 }
402 break;
403 case DS9_REGION_BIOS:
404 // TODO: Mask properly
405 if (memory->bios9) {
406 cpu->memory.activeRegion = memory->bios9;
407 cpu->memory.activeMask = DS9_SIZE_BIOS - 1;
408 } else {
409 cpu->memory.activeRegion = _deadbeef;
410 cpu->memory.activeMask = 0;
411 }
412 return;
413 default:
414 break;
415 }
416 cpu->memory.activeRegion = _deadbeef;
417 cpu->memory.activeMask = 0;
418 mLOG(DS_MEM, FATAL, "Jumped to invalid address: %08X", address);
419 return;
420}
421
422uint32_t DS9Load32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
423 struct DS* ds = (struct DS*) cpu->master;
424 struct DSMemory* memory = &ds->memory;
425 uint32_t value = 0;
426 int wait = 0;
427
428 switch (address >> DS_BASE_OFFSET) {
429 case DS_REGION_RAM:
430 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
431 LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
432 }
433 break;
434 default:
435 break;
436 }
437
438 if (cycleCounter) {
439 wait += 2;
440 *cycleCounter += wait;
441 }
442 // Unaligned 32-bit loads are "rotated" so they make some semblance of sense
443 int rotate = (address & 3) << 3;
444 return ROR(value, rotate);
445}
446
447uint32_t DS9Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
448 struct DS* ds = (struct DS*) cpu->master;
449 struct DSMemory* memory = &ds->memory;
450 uint32_t value = 0;
451 int wait = 0;
452
453 switch (address >> DS_BASE_OFFSET) {
454 default:
455 break;
456 }
457
458 if (cycleCounter) {
459 wait += 2;
460 *cycleCounter += wait;
461 }
462 // Unaligned 16-bit loads are "unpredictable", TODO: See what DS does
463 int rotate = (address & 1) << 3;
464 return ROR(value, rotate);
465}
466
467uint32_t DS9Load8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
468 struct DS* ds = (struct DS*) cpu->master;
469 struct DSMemory* memory = &ds->memory;
470 uint32_t value = 0;
471 int wait = 0;
472
473 switch (address >> DS_BASE_OFFSET) {
474 default:
475 break;
476 }
477
478 if (cycleCounter) {
479 wait += 2;
480 *cycleCounter += wait;
481 }
482 return value;
483}
484
485void DS9Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) {
486 struct DS* ds = (struct DS*) cpu->master;
487 struct DSMemory* memory = &ds->memory;
488 int wait = 0;
489
490 switch (address >> DS_BASE_OFFSET) {
491 break;
492 }
493
494 if (cycleCounter) {
495 ++wait;
496 *cycleCounter += wait;
497 }
498}
499
500void DS9Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
501 struct DS* ds = (struct DS*) cpu->master;
502 struct DSMemory* memory = &ds->memory;
503 int wait = 0;
504
505 switch (address >> DS_BASE_OFFSET) {
506 default:
507 break;
508 }
509
510 if (cycleCounter) {
511 ++wait;
512 *cycleCounter += wait;
513 }
514}
515
516void DS9Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
517 struct DS* ds = (struct DS*) cpu->master;
518 struct DSMemory* memory = &ds->memory;
519 int wait = 0;
520
521 switch (address >> DS_BASE_OFFSET) {
522 default:
523 break;
524 }
525
526 if (cycleCounter) {
527 ++wait;
528 *cycleCounter += wait;
529 }
530}
531
532uint32_t DS9LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
533 struct DS* ds = (struct DS*) cpu->master;
534 struct DSMemory* memory = &ds->memory;
535 uint32_t value;
536 int wait = 0;
537
538 int i;
539 int offset = 4;
540 int popcount = 0;
541 if (direction & LSM_D) {
542 offset = -4;
543 popcount = popcount32(mask);
544 address -= (popcount << 2) - 4;
545 }
546
547 if (direction & LSM_B) {
548 address += offset;
549 }
550
551 uint32_t addressMisalign = address & 0x3;
552 address &= 0xFFFFFFFC;
553
554 switch (address >> DS_BASE_OFFSET) {
555 default:
556 break;
557 }
558
559 if (cycleCounter) {
560 ++wait;
561 *cycleCounter += wait;
562 }
563
564 if (direction & LSM_B) {
565 address -= offset;
566 }
567
568 if (direction & LSM_D) {
569 address -= (popcount << 2) + 4;
570 }
571
572 return address | addressMisalign;
573}
574
575
576uint32_t DS9StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
577 struct DS* ds = (struct DS*) cpu->master;
578 struct DSMemory* memory = &ds->memory;
579 uint32_t value;
580 int wait = 0;
581
582 int i;
583 int offset = 4;
584 int popcount = 0;
585 if (direction & LSM_D) {
586 offset = -4;
587 popcount = popcount32(mask);
588 address -= (popcount << 2) - 4;
589 }
590
591 if (direction & LSM_B) {
592 address += offset;
593 }
594
595 uint32_t addressMisalign = address & 0x3;
596 address &= 0xFFFFFFFC;
597
598 switch (address >> DS_BASE_OFFSET) {
599 default:
600 break;
601 }
602
603 if (cycleCounter) {
604 *cycleCounter += wait;
605 }
606
607 if (direction & LSM_B) {
608 address -= offset;
609 }
610
611 if (direction & LSM_D) {
612 address -= (popcount << 2) + 4;
613 }
614
615 return address | addressMisalign;
616}
617
618int32_t DSMemoryStall(struct ARMCore* cpu, int32_t wait) {
619 return wait;
620}
621