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 DS_REGION_RAM:
665 if ((address & ~(DS9_SIZE_DTCM - 1)) == DS9_BASE_DTCM) {
666 LOAD_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
667 break;
668 }
669 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
670 LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
671 break;
672 }
673 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load32: %08X", address);
674 break;
675 case DS_REGION_IO:
676 value = DS9IORead(ds, address & 0x00FFFFFC) | (DS9IORead(ds, (address & 0x00FFFFFC) | 2) << 16);
677 break;
678 case DS9_REGION_BIOS:
679 // TODO: Fix undersized BIOS
680 // TODO: Fix masking
681 LOAD_32(value, address & (DS9_SIZE_BIOS - 1), memory->bios9);
682 break;
683 default:
684 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load32: %08X", address);
685 break;
686 }
687
688 if (cycleCounter) {
689 wait += 2;
690 *cycleCounter += wait;
691 }
692 // Unaligned 32-bit loads are "rotated" so they make some semblance of sense
693 int rotate = (address & 3) << 3;
694 return ROR(value, rotate);
695}
696
697uint32_t DS9Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
698 struct DS* ds = (struct DS*) cpu->master;
699 struct DSMemory* memory = &ds->memory;
700 uint32_t value = 0;
701 int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
702
703 switch (address >> DS_BASE_OFFSET) {
704 case DS_REGION_RAM:
705 if ((address & ~(DS9_SIZE_DTCM - 1)) == DS9_BASE_DTCM) {
706 LOAD_16(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
707 break;
708 }
709 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
710 LOAD_16(value, address & (DS_SIZE_RAM - 1), memory->ram);
711 break;
712 }
713 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load16: %08X", address);
714 case DS_REGION_IO:
715 value = DS9IORead(ds, address & 0x00FFFFFF);
716 break;
717 case DS9_REGION_BIOS:
718 // TODO: Fix undersized BIOS
719 // TODO: Fix masking
720 LOAD_16(value, address & (DS9_SIZE_BIOS - 1), memory->bios9);
721 break;
722 default:
723 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load16: %08X", address);
724 break;
725 }
726
727 if (cycleCounter) {
728 wait += 2;
729 *cycleCounter += wait;
730 }
731 // Unaligned 16-bit loads are "unpredictable", TODO: See what DS does
732 int rotate = (address & 1) << 3;
733 return ROR(value, rotate);
734}
735
736uint32_t DS9Load8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
737 struct DS* ds = (struct DS*) cpu->master;
738 struct DSMemory* memory = &ds->memory;
739 uint32_t value = 0;
740 int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
741
742 switch (address >> DS_BASE_OFFSET) {
743 case DS_REGION_RAM:
744 if ((address & ~(DS9_SIZE_DTCM - 1)) == DS9_BASE_DTCM) {
745 value = ((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)];
746 break;
747 }
748 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
749 value = ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)];
750 break;
751 }
752 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load8: %08X", address);
753 case DS9_REGION_BIOS:
754 // TODO: Fix undersized BIOS
755 // TODO: Fix masking
756 value = ((uint8_t*) memory->bios9)[address & (DS9_SIZE_BIOS - 1)];
757 break;
758 default:
759 mLOG(DS_MEM, STUB, "Unimplemented DS9 Load8: %08X", address);
760 break;
761 }
762
763 if (cycleCounter) {
764 wait += 2;
765 *cycleCounter += wait;
766 }
767 return value;
768}
769
770void DS9Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) {
771 struct DS* ds = (struct DS*) cpu->master;
772 struct DSMemory* memory = &ds->memory;
773 int wait = ds->ds9.memory.waitstatesNonseq32[address >> DS_BASE_OFFSET];
774
775 switch (address >> DS_BASE_OFFSET) {
776 case DS9_REGION_ITCM:
777 case DS9_REGION_ITCM_MIRROR:
778 if (address < (512 << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
779 STORE_32(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
780 break;
781 }
782 mLOG(DS_MEM, STUB, "Bad DS9 Store32: %08X:%08X", address, value);
783 break;
784 case DS_REGION_RAM:
785 if ((address & ~(DS9_SIZE_DTCM - 1)) == DS9_BASE_DTCM) {
786 STORE_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
787 break;
788 }
789 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
790 STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
791 break;
792 }
793 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store32: %08X:%08X", address, value);
794 break;
795 case DS_REGION_IO:
796 DS9IOWrite32(ds, address & 0x00FFFFFF, value);
797 break;
798 default:
799 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store32: %08X:%08X", address, value);
800 break;
801 }
802
803 if (cycleCounter) {
804 ++wait;
805 *cycleCounter += wait;
806 }
807}
808
809void DS9Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
810 struct DS* ds = (struct DS*) cpu->master;
811 struct DSMemory* memory = &ds->memory;
812 int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
813
814 switch (address >> DS_BASE_OFFSET) {
815 case DS9_REGION_ITCM:
816 case DS9_REGION_ITCM_MIRROR:
817 if (address < (512 << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
818 STORE_16(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
819 break;
820 }
821 mLOG(DS_MEM, STUB, "Bad DS9 Store16: %08X:%04X", address, value);
822 break;
823 case DS_REGION_RAM:
824 if ((address & ~(DS9_SIZE_DTCM - 1)) == DS9_BASE_DTCM) {
825 STORE_16(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
826 break;
827 }
828 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
829 STORE_16(value, address & (DS_SIZE_RAM - 1), memory->ram);
830 break;
831 }
832 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store16: %08X:%04X", address, value);
833 break;
834 case DS_REGION_IO:
835 DS9IOWrite(ds, address & 0x00FFFFFF, value);
836 break;
837 default:
838 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store16: %08X:%04X", address, value);
839 break;
840 }
841
842 if (cycleCounter) {
843 ++wait;
844 *cycleCounter += wait;
845 }
846}
847
848void DS9Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
849 struct DS* ds = (struct DS*) cpu->master;
850 struct DSMemory* memory = &ds->memory;
851 int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
852
853 switch (address >> DS_BASE_OFFSET) {
854 case DS9_REGION_ITCM:
855 case DS9_REGION_ITCM_MIRROR:
856 if (address < (512U << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
857 ((uint8_t*) memory->itcm)[address & (DS9_SIZE_ITCM - 1)] = value;
858 break;
859 }
860 mLOG(DS_MEM, STUB, "Bad DS9 Store8: %08X:%02X", address, value);
861 break;
862 case DS_REGION_RAM:
863 if ((address & ~(DS9_SIZE_DTCM - 1)) == DS9_BASE_DTCM) {
864 ((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)] = value;
865 break;
866 }
867 if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
868 ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)] = value;
869 break;
870 }
871 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store8: %08X:%02X", address, value);
872 case DS_REGION_IO:
873 DS9IOWrite8(ds, address & 0x00FFFFFF, value);
874 break;
875 default:
876 mLOG(DS_MEM, STUB, "Unimplemented DS9 Store8: %08X:%02X", address, value);
877 break;
878 }
879
880 if (cycleCounter) {
881 ++wait;
882 *cycleCounter += wait;
883 }
884}
885
886uint32_t DS9LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
887 struct DS* ds = (struct DS*) cpu->master;
888 struct DSMemory* memory = &ds->memory;
889 char* ws32 = ds->ds9.memory.waitstatesNonseq32;
890 uint32_t value;
891 int wait = 0;
892
893 int i;
894 int offset = 4;
895 int popcount = 0;
896 if (direction & LSM_D) {
897 offset = -4;
898 popcount = popcount32(mask);
899 address -= (popcount << 2) - 4;
900 }
901
902 if (direction & LSM_B) {
903 address += offset;
904 }
905
906 uint32_t addressMisalign = address & 0x3;
907 address &= 0xFFFFFFFC;
908
909 switch (address >> DS_BASE_OFFSET) {
910 case DS_REGION_RAM:
911 LDM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == DS9_BASE_DTCM) {
912 LOAD_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
913 } else if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
914 LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
915 } else {
916 mLOG(DS_MEM, STUB, "Unimplemented DS9 LDM: %08X", address);
917 });
918 break;
919 default:
920 mLOG(DS_MEM, STUB, "Unimplemented DS9 LDM: %08X", address);
921 LDM_LOOP(value = 0);
922 break;
923 }
924
925 if (cycleCounter) {
926 ++wait;
927 *cycleCounter += wait;
928 }
929
930 if (direction & LSM_B) {
931 address -= offset;
932 }
933
934 if (direction & LSM_D) {
935 address -= (popcount << 2) + 4;
936 }
937
938 return address | addressMisalign;
939}
940
941
942uint32_t DS9StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
943 struct DS* ds = (struct DS*) cpu->master;
944 struct DSMemory* memory = &ds->memory;
945 char* ws32 = ds->ds9.memory.waitstatesNonseq32;
946 uint32_t value;
947 int wait = 0;
948
949 int i;
950 int offset = 4;
951 int popcount = 0;
952 if (direction & LSM_D) {
953 offset = -4;
954 popcount = popcount32(mask);
955 address -= (popcount << 2) - 4;
956 }
957
958 if (direction & LSM_B) {
959 address += offset;
960 }
961
962 uint32_t addressMisalign = address & 0x3;
963 address &= 0xFFFFFFFC;
964
965 switch (address >> DS_BASE_OFFSET) {
966 case DS9_REGION_ITCM:
967 case DS9_REGION_ITCM_MIRROR:
968 STM_LOOP(if (address < (512U << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
969 STORE_32(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
970 } else {
971 mLOG(DS_MEM, STUB, "Bad DS9 Store32: %08X:%08X", address, value);
972 });
973 break;
974 case DS_REGION_RAM:
975 STM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == DS9_BASE_DTCM) {
976 STORE_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
977 } else if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
978 STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
979 } else {
980 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
981 });
982 break;
983 default:
984 mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
985 STM_LOOP();
986 break;
987 }
988
989 if (cycleCounter) {
990 *cycleCounter += wait;
991 }
992
993 if (direction & LSM_B) {
994 address -= offset;
995 }
996
997 if (direction & LSM_D) {
998 address -= (popcount << 2) + 4;
999 }
1000
1001 return address | addressMisalign;
1002}
1003
1004int32_t DSMemoryStall(struct ARMCore* cpu, int32_t wait) {
1005 return wait;
1006}
1007