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