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 "ds/ds.h"
9#include "util/math.h"
10
11mLOG_DEFINE_CATEGORY(DS_MEM, "DS Memory");
12
13#define LDM_LOOP(LDM) \
14 for (i = 0; i < 16; i += 4) { \
15 if (UNLIKELY(mask & (1 << i))) { \
16 LDM; \
17 cpu->gprs[i] = value; \
18 ++wait; \
19 address += 4; \
20 } \
21 if (UNLIKELY(mask & (2 << i))) { \
22 LDM; \
23 cpu->gprs[i + 1] = value; \
24 ++wait; \
25 address += 4; \
26 } \
27 if (UNLIKELY(mask & (4 << i))) { \
28 LDM; \
29 cpu->gprs[i + 2] = value; \
30 ++wait; \
31 address += 4; \
32 } \
33 if (UNLIKELY(mask & (8 << i))) { \
34 LDM; \
35 cpu->gprs[i + 3] = value; \
36 ++wait; \
37 address += 4; \
38 } \
39 }
40
41#define STM_LOOP(STM) \
42 for (i = 0; i < 16; i += 4) { \
43 if (UNLIKELY(mask & (1 << i))) { \
44 value = cpu->gprs[i]; \
45 STM; \
46 ++wait; \
47 address += 4; \
48 } \
49 if (UNLIKELY(mask & (2 << i))) { \
50 value = cpu->gprs[i + 1]; \
51 STM; \
52 ++wait; \
53 address += 4; \
54 } \
55 if (UNLIKELY(mask & (4 << i))) { \
56 value = cpu->gprs[i + 2]; \
57 STM; \
58 ++wait; \
59 address += 4; \
60 } \
61 if (UNLIKELY(mask & (8 << i))) { \
62 value = cpu->gprs[i + 3]; \
63 STM; \
64 ++wait; \
65 address += 4; \
66 } \
67 }
68
69
70static uint32_t _deadbeef[1] = { 0xE710B710 }; // Illegal instruction on both ARM and Thumb
71
72static void DS7SetActiveRegion(struct ARMCore* cpu, uint32_t region);
73static void DS9SetActiveRegion(struct ARMCore* cpu, uint32_t region);
74static int32_t DSMemoryStall(struct ARMCore* cpu, int32_t wait);
75
76static const int DMA_OFFSET[] = { 1, -1, 0, 1 };
77
78void DSMemoryInit(struct DS* ds) {
79 struct ARMCore* arm7 = ds->arm7;
80 arm7->memory.load32 = DS7Load32;
81 arm7->memory.load16 = DS7Load16;
82 arm7->memory.load8 = DS7Load8;
83 arm7->memory.loadMultiple = DS7LoadMultiple;
84 arm7->memory.store32 = DS7Store32;
85 arm7->memory.store16 = DS7Store16;
86 arm7->memory.store8 = DS7Store8;
87 arm7->memory.storeMultiple = DS7StoreMultiple;
88 arm7->memory.stall = DSMemoryStall;
89
90 struct ARMCore* arm9 = ds->arm9;
91 arm9->memory.load32 = DS9Load32;
92 arm9->memory.load16 = DS9Load16;
93 arm9->memory.load8 = DS9Load8;
94 arm9->memory.loadMultiple = DS9LoadMultiple;
95 arm9->memory.store32 = DS9Store32;
96 arm9->memory.store16 = DS9Store16;
97 arm9->memory.store8 = DS9Store8;
98 arm9->memory.storeMultiple = DS9StoreMultiple;
99 arm9->memory.stall = DSMemoryStall;
100
101 ds->memory.bios7 = NULL;
102 ds->memory.bios9 = NULL;
103 ds->memory.wram = NULL;
104 ds->memory.ram = NULL;
105 ds->memory.rom = NULL;
106
107 ds->memory.activeRegion7 = -1;
108 ds->memory.activeRegion9 = -1;
109
110 arm7->memory.activeRegion = 0;
111 arm7->memory.activeMask = 0;
112 arm7->memory.setActiveRegion = DS7SetActiveRegion;
113 arm7->memory.activeSeqCycles32 = 0;
114 arm7->memory.activeSeqCycles16 = 0;
115 arm7->memory.activeNonseqCycles32 = 0;
116 arm7->memory.activeNonseqCycles16 = 0;
117
118 arm9->memory.activeRegion = 0;
119 arm9->memory.activeMask = 0;
120 arm9->memory.setActiveRegion = DS9SetActiveRegion;
121 arm9->memory.activeSeqCycles32 = 0;
122 arm9->memory.activeSeqCycles16 = 0;
123 arm9->memory.activeNonseqCycles32 = 0;
124 arm9->memory.activeNonseqCycles16 = 0;
125}
126
127void DSMemoryDeinit(struct DS* ds) {
128 mappedMemoryFree(ds->memory.wram, DS_SIZE_WORKING_RAM);
129 mappedMemoryFree(ds->memory.ram, DS_SIZE_RAM);
130}
131
132void DSMemoryReset(struct DS* ds) {
133 if (ds->memory.wram) {
134 mappedMemoryFree(ds->memory.wram, DS_SIZE_WORKING_RAM);
135 }
136 ds->memory.wram = anonymousMemoryMap(DS_SIZE_WORKING_RAM);
137
138 if (ds->memory.ram) {
139 mappedMemoryFree(ds->memory.ram, DS_SIZE_RAM);
140 }
141 ds->memory.ram = anonymousMemoryMap(DS_SIZE_RAM);
142
143 memset(ds->memory.dma7, 0, sizeof(ds->memory.dma7));
144 memset(ds->memory.dma9, 0, sizeof(ds->memory.dma9));
145 ds->memory.activeDMA7 = -1;
146 ds->memory.activeDMA9 = -1;
147 ds->memory.nextDMA = INT_MAX;
148 ds->memory.eventDiff = 0;
149
150 if (!ds->memory.wram || !ds->memory.ram) {
151 DSMemoryDeinit(ds);
152 mLOG(DS_MEM, FATAL, "Could not map memory");
153 }
154}
155
156static void DS7SetActiveRegion(struct ARMCore* cpu, uint32_t address) {
157 struct DS* ds = (struct DS*) cpu->master;
158 struct DSMemory* memory = &ds->memory;
159
160 int newRegion = address >> DS_BASE_OFFSET;
161
162 memory->activeRegion7 = newRegion;
163 switch (newRegion) {
164 case DS7_REGION_BIOS:
165 cpu->memory.activeRegion = memory->bios7;
166 cpu->memory.activeMask = DS7_SIZE_BIOS - 1;
167 break;
168 default:
169 mLOG(DS_MEM, FATAL, "Jumped to invalid address: %08X", address);
170 return;
171 }
172}
173
174uint32_t DS7Load32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
175 struct DS* ds = (struct DS*) cpu->master;
176 struct DSMemory* memory = &ds->memory;
177 uint32_t value = 0;
178 int wait = 0;
179
180 switch (address >> DS_BASE_OFFSET) {
181 default:
182 break;
183 }
184
185 if (cycleCounter) {
186 wait += 2;
187 *cycleCounter += wait;
188 }
189 // Unaligned 32-bit loads are "rotated" so they make some semblance of sense
190 int rotate = (address & 3) << 3;
191 return ROR(value, rotate);
192}
193
194uint32_t DS7Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
195 struct DS* ds = (struct DS*) cpu->master;
196 struct DSMemory* memory = &ds->memory;
197 uint32_t value = 0;
198 int wait = 0;
199
200 switch (address >> DS_BASE_OFFSET) {
201 default:
202 break;
203 }
204
205 if (cycleCounter) {
206 wait += 2;
207 *cycleCounter += wait;
208 }
209 // Unaligned 16-bit loads are "unpredictable", TODO: See what DS does
210 int rotate = (address & 1) << 3;
211 return ROR(value, rotate);
212}
213
214uint32_t DS7Load8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
215 struct DS* ds = (struct DS*) cpu->master;
216 struct DSMemory* memory = &ds->memory;
217 uint32_t value = 0;
218 int wait = 0;
219
220 switch (address >> DS_BASE_OFFSET) {
221 default:
222 break;
223 }
224
225 if (cycleCounter) {
226 wait += 2;
227 *cycleCounter += wait;
228 }
229 return value;
230}
231
232void DS7Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) {
233 struct DS* ds = (struct DS*) cpu->master;
234 struct DSMemory* memory = &ds->memory;
235 int wait = 0;
236
237 switch (address >> DS_BASE_OFFSET) {
238 break;
239 }
240
241 if (cycleCounter) {
242 ++wait;
243 *cycleCounter += wait;
244 }
245}
246
247void DS7Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
248 struct DS* ds = (struct DS*) cpu->master;
249 struct DSMemory* memory = &ds->memory;
250 int wait = 0;
251
252 switch (address >> DS_BASE_OFFSET) {
253 default:
254 break;
255 }
256
257 if (cycleCounter) {
258 ++wait;
259 *cycleCounter += wait;
260 }
261}
262
263void DS7Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
264 struct DS* ds = (struct DS*) cpu->master;
265 struct DSMemory* memory = &ds->memory;
266 int wait = 0;
267
268 switch (address >> DS_BASE_OFFSET) {
269 default:
270 break;
271 }
272
273 if (cycleCounter) {
274 ++wait;
275 *cycleCounter += wait;
276 }
277}
278
279uint32_t DS7LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
280 struct DS* ds = (struct DS*) cpu->master;
281 struct DSMemory* memory = &ds->memory;
282 uint32_t value;
283 int wait = 0;
284
285 int i;
286 int offset = 4;
287 int popcount = 0;
288 if (direction & LSM_D) {
289 offset = -4;
290 popcount = popcount32(mask);
291 address -= (popcount << 2) - 4;
292 }
293
294 if (direction & LSM_B) {
295 address += offset;
296 }
297
298 uint32_t addressMisalign = address & 0x3;
299 address &= 0xFFFFFFFC;
300
301 switch (address >> DS_BASE_OFFSET) {
302 default:
303 break;
304 }
305
306 if (cycleCounter) {
307 ++wait;
308 *cycleCounter += wait;
309 }
310
311 if (direction & LSM_B) {
312 address -= offset;
313 }
314
315 if (direction & LSM_D) {
316 address -= (popcount << 2) + 4;
317 }
318
319 return address | addressMisalign;
320}
321
322
323uint32_t DS7StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
324 struct DS* ds = (struct ds*) cpu->master;
325 struct DSMemory* memory = &ds->memory;
326 uint32_t value;
327 int wait = 0;
328
329 int i;
330 int offset = 4;
331 int popcount = 0;
332 if (direction & LSM_D) {
333 offset = -4;
334 popcount = popcount32(mask);
335 address -= (popcount << 2) - 4;
336 }
337
338 if (direction & LSM_B) {
339 address += offset;
340 }
341
342 uint32_t addressMisalign = address & 0x3;
343 address &= 0xFFFFFFFC;
344
345 switch (address >> DS_BASE_OFFSET) {
346 default:
347 break;
348 }
349
350 if (cycleCounter) {
351 *cycleCounter += wait;
352 }
353
354 if (direction & LSM_B) {
355 address -= offset;
356 }
357
358 if (direction & LSM_D) {
359 address -= (popcount << 2) + 4;
360 }
361
362 return address | addressMisalign;
363}
364
365static void DS9SetActiveRegion(struct ARMCore* cpu, uint32_t address) {
366 struct DS* ds = (struct DS*) cpu->master;
367 struct DSMemory* memory = &ds->memory;
368
369 int newRegion = address >> DS_BASE_OFFSET;
370
371 memory->activeRegion7 = newRegion;
372 switch (newRegion) {
373 case DS9_REGION_BIOS:
374 // TODO: Mask properly
375 if (memory->bios9) {
376 cpu->memory.activeRegion = memory->bios9;
377 cpu->memory.activeMask = DS9_SIZE_BIOS - 1;
378 } else {
379 cpu->memory.activeRegion = _deadbeef;
380 cpu->memory.activeMask = 0;
381 }
382 break;
383 default:
384 mLOG(DS_MEM, FATAL, "Jumped to invalid address: %08X", address);
385 return;
386 }
387}
388
389uint32_t DS9Load32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
390 struct DS* ds = (struct DS*) cpu->master;
391 struct DSMemory* memory = &ds->memory;
392 uint32_t value = 0;
393 int wait = 0;
394
395 switch (address >> DS_BASE_OFFSET) {
396 default:
397 break;
398 }
399
400 if (cycleCounter) {
401 wait += 2;
402 *cycleCounter += wait;
403 }
404 // Unaligned 32-bit loads are "rotated" so they make some semblance of sense
405 int rotate = (address & 3) << 3;
406 return ROR(value, rotate);
407}
408
409uint32_t DS9Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
410 struct DS* ds = (struct DS*) cpu->master;
411 struct DSMemory* memory = &ds->memory;
412 uint32_t value = 0;
413 int wait = 0;
414
415 switch (address >> DS_BASE_OFFSET) {
416 default:
417 break;
418 }
419
420 if (cycleCounter) {
421 wait += 2;
422 *cycleCounter += wait;
423 }
424 // Unaligned 16-bit loads are "unpredictable", TODO: See what DS does
425 int rotate = (address & 1) << 3;
426 return ROR(value, rotate);
427}
428
429uint32_t DS9Load8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
430 struct DS* ds = (struct DS*) cpu->master;
431 struct DSMemory* memory = &ds->memory;
432 uint32_t value = 0;
433 int wait = 0;
434
435 switch (address >> DS_BASE_OFFSET) {
436 default:
437 break;
438 }
439
440 if (cycleCounter) {
441 wait += 2;
442 *cycleCounter += wait;
443 }
444 return value;
445}
446
447void DS9Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) {
448 struct DS* ds = (struct DS*) cpu->master;
449 struct DSMemory* memory = &ds->memory;
450 int wait = 0;
451
452 switch (address >> DS_BASE_OFFSET) {
453 break;
454 }
455
456 if (cycleCounter) {
457 ++wait;
458 *cycleCounter += wait;
459 }
460}
461
462void DS9Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
463 struct DS* ds = (struct DS*) cpu->master;
464 struct DSMemory* memory = &ds->memory;
465 int wait = 0;
466
467 switch (address >> DS_BASE_OFFSET) {
468 default:
469 break;
470 }
471
472 if (cycleCounter) {
473 ++wait;
474 *cycleCounter += wait;
475 }
476}
477
478void DS9Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
479 struct DS* ds = (struct DS*) cpu->master;
480 struct DSMemory* memory = &ds->memory;
481 int wait = 0;
482
483 switch (address >> DS_BASE_OFFSET) {
484 default:
485 break;
486 }
487
488 if (cycleCounter) {
489 ++wait;
490 *cycleCounter += wait;
491 }
492}
493
494uint32_t DS9LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
495 struct DS* ds = (struct DS*) cpu->master;
496 struct DSMemory* memory = &ds->memory;
497 uint32_t value;
498 int wait = 0;
499
500 int i;
501 int offset = 4;
502 int popcount = 0;
503 if (direction & LSM_D) {
504 offset = -4;
505 popcount = popcount32(mask);
506 address -= (popcount << 2) - 4;
507 }
508
509 if (direction & LSM_B) {
510 address += offset;
511 }
512
513 uint32_t addressMisalign = address & 0x3;
514 address &= 0xFFFFFFFC;
515
516 switch (address >> DS_BASE_OFFSET) {
517 default:
518 break;
519 }
520
521 if (cycleCounter) {
522 ++wait;
523 *cycleCounter += wait;
524 }
525
526 if (direction & LSM_B) {
527 address -= offset;
528 }
529
530 if (direction & LSM_D) {
531 address -= (popcount << 2) + 4;
532 }
533
534 return address | addressMisalign;
535}
536
537
538uint32_t DS9StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
539 struct DS* ds = (struct ds*) cpu->master;
540 struct DSMemory* memory = &ds->memory;
541 uint32_t value;
542 int wait = 0;
543
544 int i;
545 int offset = 4;
546 int popcount = 0;
547 if (direction & LSM_D) {
548 offset = -4;
549 popcount = popcount32(mask);
550 address -= (popcount << 2) - 4;
551 }
552
553 if (direction & LSM_B) {
554 address += offset;
555 }
556
557 uint32_t addressMisalign = address & 0x3;
558 address &= 0xFFFFFFFC;
559
560 switch (address >> DS_BASE_OFFSET) {
561 default:
562 break;
563 }
564
565 if (cycleCounter) {
566 *cycleCounter += wait;
567 }
568
569 if (direction & LSM_B) {
570 address -= offset;
571 }
572
573 if (direction & LSM_D) {
574 address -= (popcount << 2) + 4;
575 }
576
577 return address | addressMisalign;
578}
579
580int32_t DSMemoryStall(struct ARMCore* cpu, int32_t wait) {
581 return wait;
582}
583