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