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