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_WORKING_RAM:
304 if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
305 value = ((uint8_t*) memory->wram7)[address & (DS7_SIZE_WORKING_RAM - 1)];
306 } else {
307 value = ((uint8_t*) memory->wram)[address & (ds->memory.wramSize7 - 1)];
308 }
309 break;
310 case DS_REGION_RAM:
311 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
312 value = ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)];
313 break;
314 }
315 mLOG(DS_MEM, STUB, "Unimplemented DS7 Load8: %08X", address);
316 default:
317 mLOG(DS_MEM, STUB, "Unimplemented DS7 Load8: %08X", address);
318 break;
319 }
320
321 if (cycleCounter) {
322 wait += 2;
323 *cycleCounter += wait;
324 }
325 return value;
326}
327
328void DS7Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) {
329 struct DS* ds = (struct DS*) cpu->master;
330 struct DSMemory* memory = &ds->memory;
331 int wait = ds->ds7.memory.waitstatesNonseq32[address >> DS_BASE_OFFSET];
332
333 switch (address >> DS_BASE_OFFSET) {
334 case DS_REGION_WORKING_RAM:
335 if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
336 STORE_32(value, address & (DS7_SIZE_WORKING_RAM - 1), memory->wram7);
337 } else {
338 STORE_32(value, address & (ds->memory.wramSize7 - 1), memory->wram);
339 }
340 break;
341 case DS_REGION_RAM:
342 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
343 STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
344 break;
345 }
346 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store32: %08X:%08X", address, value);
347 break;
348 case DS_REGION_IO:
349 DS7IOWrite32(ds, address & 0x00FFFFFF, value);
350 break;
351 default:
352 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store32: %08X:%08X", address, value);
353 break;
354 }
355
356 if (cycleCounter) {
357 ++wait;
358 *cycleCounter += wait;
359 }
360}
361
362void DS7Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
363 struct DS* ds = (struct DS*) cpu->master;
364 struct DSMemory* memory = &ds->memory;
365 int wait = ds->ds7.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
366
367 switch (address >> DS_BASE_OFFSET) {
368 case DS_REGION_WORKING_RAM:
369 if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
370 STORE_16(value, address & (DS7_SIZE_WORKING_RAM - 1), memory->wram7);
371 } else {
372 STORE_16(value, address & (ds->memory.wramSize7 - 1), memory->wram);
373 }
374 break;
375 case DS_REGION_RAM:
376 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
377 STORE_16(value, address & (DS_SIZE_RAM - 1), memory->ram);
378 break;
379 }
380 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store16: %08X:%04X", address, value);
381 break;
382 case DS_REGION_IO:
383 DS7IOWrite(ds, address & 0x00FFFFFF, value);
384 break;
385 default:
386 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store16: %08X:%04X", address, value);
387 break;
388 }
389
390 if (cycleCounter) {
391 ++wait;
392 *cycleCounter += wait;
393 }
394}
395
396void DS7Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
397 struct DS* ds = (struct DS*) cpu->master;
398 struct DSMemory* memory = &ds->memory;
399 int wait = ds->ds7.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
400
401 switch (address >> DS_BASE_OFFSET) {
402 case DS_REGION_RAM:
403 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
404 ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)] = value;
405 break;
406 }
407 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store8: %08X:%02X", address, value);
408 case DS_REGION_IO:
409 DS7IOWrite8(ds, address & 0x00FFFFFF, value);
410 break;
411 default:
412 mLOG(DS_MEM, STUB, "Unimplemented DS7 Store8: %08X:%02X", address, value);
413 break;
414 }
415
416 if (cycleCounter) {
417 ++wait;
418 *cycleCounter += wait;
419 }
420}
421
422#define LDM_LOOP(LDM) \
423 for (i = 0; i < 16; i += 4) { \
424 if (UNLIKELY(mask & (1 << i))) { \
425 LDM; \
426 cpu->gprs[i] = value; \
427 ++wait; \
428 wait += ws32[address >> DS_BASE_OFFSET]; \
429 address += 4; \
430 } \
431 if (UNLIKELY(mask & (2 << i))) { \
432 LDM; \
433 cpu->gprs[i + 1] = value; \
434 ++wait; \
435 wait += ws32[address >> DS_BASE_OFFSET]; \
436 address += 4; \
437 } \
438 if (UNLIKELY(mask & (4 << i))) { \
439 LDM; \
440 cpu->gprs[i + 2] = value; \
441 ++wait; \
442 wait += ws32[address >> DS_BASE_OFFSET]; \
443 address += 4; \
444 } \
445 if (UNLIKELY(mask & (8 << i))) { \
446 LDM; \
447 cpu->gprs[i + 3] = value; \
448 ++wait; \
449 wait += ws32[address >> DS_BASE_OFFSET]; \
450 address += 4; \
451 } \
452 }
453
454#define STM_LOOP(STM) \
455 for (i = 0; i < 16; i += 4) { \
456 if (UNLIKELY(mask & (1 << i))) { \
457 value = cpu->gprs[i]; \
458 STM; \
459 ++wait; \
460 wait += ws32[address >> DS_BASE_OFFSET]; \
461 address += 4; \
462 } \
463 if (UNLIKELY(mask & (2 << i))) { \
464 value = cpu->gprs[i + 1]; \
465 STM; \
466 ++wait; \
467 wait += ws32[address >> DS_BASE_OFFSET]; \
468 address += 4; \
469 } \
470 if (UNLIKELY(mask & (4 << i))) { \
471 value = cpu->gprs[i + 2]; \
472 STM; \
473 ++wait; \
474 wait += ws32[address >> DS_BASE_OFFSET]; \
475 address += 4; \
476 } \
477 if (UNLIKELY(mask & (8 << i))) { \
478 value = cpu->gprs[i + 3]; \
479 STM; \
480 ++wait; \
481 wait += ws32[address >> DS_BASE_OFFSET]; \
482 address += 4; \
483 } \
484 }
485
486
487
488uint32_t DS7LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
489 struct DS* ds = (struct DS*) cpu->master;
490 struct DSMemory* memory = &ds->memory;
491 char* ws32 = ds->ds7.memory.waitstatesNonseq32;
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 LDM_LOOP(if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
514 LOAD_32(value, address & (DS7_SIZE_WORKING_RAM - 1), memory->wram7);
515 } else {
516 LOAD_32(value, address & (ds->memory.wramSize7 - 1), memory->wram);
517 });
518 break;
519 case DS_REGION_RAM:
520 LDM_LOOP(if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
521 LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
522 } else {
523 mLOG(DS_MEM, STUB, "Unimplemented DS7 LDM: %08X", address);
524 });
525 break;
526 case DS_REGION_IO:
527 LDM_LOOP(value = DS7IORead(ds, address & 0x00FFFFFC) | (DS7IORead(ds, (address & 0x00FFFFFC) | 2) << 16));
528 break;
529 default:
530 mLOG(DS_MEM, STUB, "Unimplemented DS7 LDM: %08X", address);
531 LDM_LOOP(value = 0);
532 }
533
534 if (cycleCounter) {
535 ++wait;
536 *cycleCounter += wait;
537 }
538
539 if (direction & LSM_B) {
540 address -= offset;
541 }
542
543 if (direction & LSM_D) {
544 address -= (popcount << 2) + 4;
545 }
546
547 return address | addressMisalign;
548}
549
550
551uint32_t DS7StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
552 struct DS* ds = (struct DS*) cpu->master;
553 struct DSMemory* memory = &ds->memory;
554 char* ws32 = ds->ds7.memory.waitstatesNonseq32;
555 uint32_t value;
556 int wait = 0;
557
558 int i;
559 int offset = 4;
560 int popcount = 0;
561 if (direction & LSM_D) {
562 offset = -4;
563 popcount = popcount32(mask);
564 address -= (popcount << 2) - 4;
565 }
566
567 if (direction & LSM_B) {
568 address += offset;
569 }
570
571 uint32_t addressMisalign = address & 0x3;
572 address &= 0xFFFFFFFC;
573
574 switch (address >> DS_BASE_OFFSET) {
575 case DS_REGION_WORKING_RAM:
576 STM_LOOP(if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
577 STORE_32(value, address & (DS7_SIZE_WORKING_RAM - 1), memory->wram7);
578 } else {
579 STORE_32(value, address & (ds->memory.wramSize7 - 1), memory->wram);
580 });
581 break;
582 case DS_REGION_RAM:
583 STM_LOOP(if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
584 STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
585 } else {
586 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
587 });
588 break;
589 default:
590 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
591 STM_LOOP();
592 break;
593 }
594
595 if (cycleCounter) {
596 *cycleCounter += wait;
597 }
598
599 if (direction & LSM_B) {
600 address -= offset;
601 }
602
603 if (direction & LSM_D) {
604 address -= (popcount << 2) + 4;
605 }
606
607 return address | addressMisalign;
608}
609
610static void DS9SetActiveRegion(struct ARMCore* cpu, uint32_t address) {
611 struct DS* ds = (struct DS*) cpu->master;
612 struct DSCoreMemory* memory = &ds->ds9.memory;
613
614 int newRegion = address >> DS_BASE_OFFSET;
615
616 memory->activeRegion = newRegion;
617 switch (newRegion) {
618 case DS9_REGION_ITCM:
619 case DS9_REGION_ITCM_MIRROR:
620 if (address < (512U << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
621 cpu->memory.activeRegion = ds->memory.itcm;
622 cpu->memory.activeMask = DS9_SIZE_ITCM - 1;
623 break;
624 }
625 goto jump_error;
626 case DS_REGION_RAM:
627 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
628 cpu->memory.activeRegion = ds->memory.ram;
629 cpu->memory.activeMask = DS_SIZE_RAM - 1;
630 break;
631 }
632 goto jump_error;
633 case DS9_REGION_BIOS:
634 // TODO: Mask properly
635 if (ds->memory.bios9) {
636 cpu->memory.activeRegion = ds->memory.bios9;
637 cpu->memory.activeMask = DS9_SIZE_BIOS - 1;
638 } else {
639 cpu->memory.activeRegion = _deadbeef;
640 cpu->memory.activeMask = 0;
641 }
642 break;
643 default:
644 jump_error:
645 memory->activeRegion = -1;
646 cpu->memory.activeRegion = _deadbeef;
647 cpu->memory.activeMask = 0;
648 mLOG(DS_MEM, FATAL, "Jumped to invalid address: %08X", address);
649 return;
650 }
651 cpu->memory.activeSeqCycles32 = memory->waitstatesPrefetchSeq32[memory->activeRegion];
652 cpu->memory.activeSeqCycles16 = memory->waitstatesPrefetchSeq16[memory->activeRegion];
653 cpu->memory.activeNonseqCycles32 = memory->waitstatesPrefetchNonseq32[memory->activeRegion];
654 cpu->memory.activeNonseqCycles16 = memory->waitstatesPrefetchNonseq16[memory->activeRegion];
655}
656
657uint32_t DS9Load32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
658 struct DS* ds = (struct DS*) cpu->master;
659 struct DSMemory* memory = &ds->memory;
660 uint32_t value = 0;
661 int wait = ds->ds9.memory.waitstatesNonseq32[address >> DS_BASE_OFFSET];
662
663 switch (address >> DS_BASE_OFFSET) {
664 case DS9_REGION_ITCM:
665 case DS9_REGION_ITCM_MIRROR:
666 if (address < (512U << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
667 LOAD_32(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
668 break;
669 }
670 mLOG(DS_MEM, STUB, "Bad DS9 Load32: %08X:%08X", address, value);
671 break;
672 case DS_REGION_RAM:
673 if ((address & ~(DS9_SIZE_DTCM - 1)) == DS9_BASE_DTCM) {
674 LOAD_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
675 break;
676 }
677 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
678 LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
679 break;
680 }
681 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load32: %08X", address);
682 break;
683 case DS_REGION_IO:
684 value = DS9IORead(ds, address & 0x00FFFFFC) | (DS9IORead(ds, (address & 0x00FFFFFC) | 2) << 16);
685 break;
686 case DS9_REGION_BIOS:
687 // TODO: Fix undersized BIOS
688 // TODO: Fix masking
689 LOAD_32(value, address & (DS9_SIZE_BIOS - 1), memory->bios9);
690 break;
691 default:
692 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load32: %08X", address);
693 break;
694 }
695
696 if (cycleCounter) {
697 wait += 2;
698 *cycleCounter += wait;
699 }
700 // Unaligned 32-bit loads are "rotated" so they make some semblance of sense
701 int rotate = (address & 3) << 3;
702 return ROR(value, rotate);
703}
704
705uint32_t DS9Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
706 struct DS* ds = (struct DS*) cpu->master;
707 struct DSMemory* memory = &ds->memory;
708 uint32_t value = 0;
709 int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
710
711 switch (address >> DS_BASE_OFFSET) {
712 case DS9_REGION_ITCM:
713 case DS9_REGION_ITCM_MIRROR:
714 if (address < (512U << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
715 LOAD_16(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
716 break;
717 }
718 mLOG(DS_MEM, STUB, "Bad DS9 Load16: %08X:%08X", address, value);
719 break;
720 case DS_REGION_RAM:
721 if ((address & ~(DS9_SIZE_DTCM - 1)) == DS9_BASE_DTCM) {
722 LOAD_16(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
723 break;
724 }
725 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
726 LOAD_16(value, address & (DS_SIZE_RAM - 1), memory->ram);
727 break;
728 }
729 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load16: %08X", address);
730 case DS_REGION_IO:
731 value = DS9IORead(ds, address & 0x00FFFFFF);
732 break;
733 case DS9_REGION_BIOS:
734 // TODO: Fix undersized BIOS
735 // TODO: Fix masking
736 LOAD_16(value, address & (DS9_SIZE_BIOS - 1), memory->bios9);
737 break;
738 default:
739 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load16: %08X", address);
740 break;
741 }
742
743 if (cycleCounter) {
744 wait += 2;
745 *cycleCounter += wait;
746 }
747 // Unaligned 16-bit loads are "unpredictable", TODO: See what DS does
748 int rotate = (address & 1) << 3;
749 return ROR(value, rotate);
750}
751
752uint32_t DS9Load8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
753 struct DS* ds = (struct DS*) cpu->master;
754 struct DSMemory* memory = &ds->memory;
755 uint32_t value = 0;
756 int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
757
758 switch (address >> DS_BASE_OFFSET) {
759 case DS9_REGION_ITCM:
760 case DS9_REGION_ITCM_MIRROR:
761 if (address < (512U << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
762 value = ((uint8_t*) memory->itcm)[address & (DS9_SIZE_ITCM - 1)];
763 break;
764 }
765 mLOG(DS_MEM, STUB, "Bad DS9 Load8: %08X:%08X", address, value);
766 break;
767 case DS_REGION_RAM:
768 if ((address & ~(DS9_SIZE_DTCM - 1)) == DS9_BASE_DTCM) {
769 value = ((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)];
770 break;
771 }
772 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
773 value = ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)];
774 break;
775 }
776 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load8: %08X", address);
777 case DS9_REGION_BIOS:
778 // TODO: Fix undersized BIOS
779 // TODO: Fix masking
780 value = ((uint8_t*) memory->bios9)[address & (DS9_SIZE_BIOS - 1)];
781 break;
782 default:
783 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load8: %08X", address);
784 break;
785 }
786
787 if (cycleCounter) {
788 wait += 2;
789 *cycleCounter += wait;
790 }
791 return value;
792}
793
794void DS9Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) {
795 struct DS* ds = (struct DS*) cpu->master;
796 struct DSMemory* memory = &ds->memory;
797 int wait = ds->ds9.memory.waitstatesNonseq32[address >> DS_BASE_OFFSET];
798
799 switch (address >> DS_BASE_OFFSET) {
800 case DS9_REGION_ITCM:
801 case DS9_REGION_ITCM_MIRROR:
802 if (address < (512U << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
803 STORE_32(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
804 break;
805 }
806 mLOG(DS_MEM, STUB, "Bad DS9 Store32: %08X:%08X", address, value);
807 break;
808 case DS_REGION_RAM:
809 if ((address & ~(DS9_SIZE_DTCM - 1)) == DS9_BASE_DTCM) {
810 STORE_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
811 break;
812 }
813 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
814 STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
815 break;
816 }
817 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store32: %08X:%08X", address, value);
818 break;
819 case DS_REGION_IO:
820 DS9IOWrite32(ds, address & 0x00FFFFFF, value);
821 break;
822 default:
823 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store32: %08X:%08X", address, value);
824 break;
825 }
826
827 if (cycleCounter) {
828 ++wait;
829 *cycleCounter += wait;
830 }
831}
832
833void DS9Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
834 struct DS* ds = (struct DS*) cpu->master;
835 struct DSMemory* memory = &ds->memory;
836 int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
837
838 switch (address >> DS_BASE_OFFSET) {
839 case DS9_REGION_ITCM:
840 case DS9_REGION_ITCM_MIRROR:
841 if (address < (512U << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
842 STORE_16(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
843 break;
844 }
845 mLOG(DS_MEM, STUB, "Bad DS9 Store16: %08X:%04X", address, value);
846 break;
847 case DS_REGION_RAM:
848 if ((address & ~(DS9_SIZE_DTCM - 1)) == DS9_BASE_DTCM) {
849 STORE_16(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
850 break;
851 }
852 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
853 STORE_16(value, address & (DS_SIZE_RAM - 1), memory->ram);
854 break;
855 }
856 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store16: %08X:%04X", address, value);
857 break;
858 case DS_REGION_IO:
859 DS9IOWrite(ds, address & 0x00FFFFFF, value);
860 break;
861 default:
862 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store16: %08X:%04X", address, value);
863 break;
864 }
865
866 if (cycleCounter) {
867 ++wait;
868 *cycleCounter += wait;
869 }
870}
871
872void DS9Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
873 struct DS* ds = (struct DS*) cpu->master;
874 struct DSMemory* memory = &ds->memory;
875 int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
876
877 switch (address >> DS_BASE_OFFSET) {
878 case DS9_REGION_ITCM:
879 case DS9_REGION_ITCM_MIRROR:
880 if (address < (512U << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
881 ((uint8_t*) memory->itcm)[address & (DS9_SIZE_ITCM - 1)] = value;
882 break;
883 }
884 mLOG(DS_MEM, STUB, "Bad DS9 Store8: %08X:%02X", address, value);
885 break;
886 case DS_REGION_RAM:
887 if ((address & ~(DS9_SIZE_DTCM - 1)) == DS9_BASE_DTCM) {
888 ((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)] = value;
889 break;
890 }
891 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
892 ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)] = value;
893 break;
894 }
895 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store8: %08X:%02X", address, value);
896 case DS_REGION_IO:
897 DS9IOWrite8(ds, address & 0x00FFFFFF, value);
898 break;
899 default:
900 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store8: %08X:%02X", address, value);
901 break;
902 }
903
904 if (cycleCounter) {
905 ++wait;
906 *cycleCounter += wait;
907 }
908}
909
910uint32_t DS9LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
911 struct DS* ds = (struct DS*) cpu->master;
912 struct DSMemory* memory = &ds->memory;
913 char* ws32 = ds->ds9.memory.waitstatesNonseq32;
914 uint32_t value;
915 int wait = 0;
916
917 int i;
918 int offset = 4;
919 int popcount = 0;
920 if (direction & LSM_D) {
921 offset = -4;
922 popcount = popcount32(mask);
923 address -= (popcount << 2) - 4;
924 }
925
926 if (direction & LSM_B) {
927 address += offset;
928 }
929
930 uint32_t addressMisalign = address & 0x3;
931 address &= 0xFFFFFFFC;
932
933 switch (address >> DS_BASE_OFFSET) {
934 case DS_REGION_RAM:
935 LDM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == DS9_BASE_DTCM) {
936 LOAD_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
937 } else if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
938 LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
939 } else {
940 mLOG(DS_MEM, STUB, "Unimplemented DS9 LDM: %08X", address);
941 });
942 break;
943 default:
944 mLOG(DS_MEM, STUB, "Unimplemented DS9 LDM: %08X", address);
945 LDM_LOOP(value = 0);
946 break;
947 }
948
949 if (cycleCounter) {
950 ++wait;
951 *cycleCounter += wait;
952 }
953
954 if (direction & LSM_B) {
955 address -= offset;
956 }
957
958 if (direction & LSM_D) {
959 address -= (popcount << 2) + 4;
960 }
961
962 return address | addressMisalign;
963}
964
965
966uint32_t DS9StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
967 struct DS* ds = (struct DS*) cpu->master;
968 struct DSMemory* memory = &ds->memory;
969 char* ws32 = ds->ds9.memory.waitstatesNonseq32;
970 uint32_t value;
971 int wait = 0;
972
973 int i;
974 int offset = 4;
975 int popcount = 0;
976 if (direction & LSM_D) {
977 offset = -4;
978 popcount = popcount32(mask);
979 address -= (popcount << 2) - 4;
980 }
981
982 if (direction & LSM_B) {
983 address += offset;
984 }
985
986 uint32_t addressMisalign = address & 0x3;
987 address &= 0xFFFFFFFC;
988
989 switch (address >> DS_BASE_OFFSET) {
990 case DS9_REGION_ITCM:
991 case DS9_REGION_ITCM_MIRROR:
992 STM_LOOP(if (address < (512U << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
993 STORE_32(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
994 } else {
995 mLOG(DS_MEM, STUB, "Bad DS9 Store32: %08X:%08X", address, value);
996 });
997 break;
998 case DS_REGION_RAM:
999 STM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == DS9_BASE_DTCM) {
1000 STORE_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1001 } else if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1002 STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
1003 } else {
1004 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
1005 });
1006 break;
1007 default:
1008 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
1009 STM_LOOP();
1010 break;
1011 }
1012
1013 if (cycleCounter) {
1014 *cycleCounter += wait;
1015 }
1016
1017 if (direction & LSM_B) {
1018 address -= offset;
1019 }
1020
1021 if (direction & LSM_D) {
1022 address -= (popcount << 2) + 4;
1023 }
1024
1025 return address | addressMisalign;
1026}
1027
1028int32_t DSMemoryStall(struct ARMCore* cpu, int32_t wait) {
1029 return wait;
1030}
1031