all repos — mgba @ ad492cab49fecd0f6495b8b2d83456d8bba6cca7

mGBA Game Boy Advance Emulator

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 "memory.h"
  7
  8#include "arm/macros.h"
  9
 10#include "ds/ds.h"
 11#include "util/math.h"
 12#include "util/memory.h"
 13
 14mLOG_DEFINE_CATEGORY(DS_MEM, "DS Memory");
 15
 16#define LDM_LOOP(LDM) \
 17	for (i = 0; i < 16; i += 4) { \
 18		if (UNLIKELY(mask & (1 << i))) { \
 19			LDM; \
 20			cpu->gprs[i] = value; \
 21			++wait; \
 22			address += 4; \
 23		} \
 24		if (UNLIKELY(mask & (2 << i))) { \
 25			LDM; \
 26			cpu->gprs[i + 1] = value; \
 27			++wait; \
 28			address += 4; \
 29		} \
 30		if (UNLIKELY(mask & (4 << i))) { \
 31			LDM; \
 32			cpu->gprs[i + 2] = value; \
 33			++wait; \
 34			address += 4; \
 35		} \
 36		if (UNLIKELY(mask & (8 << i))) { \
 37			LDM; \
 38			cpu->gprs[i + 3] = value; \
 39			++wait; \
 40			address += 4; \
 41		} \
 42	}
 43
 44#define STM_LOOP(STM) \
 45	for (i = 0; i < 16; i += 4) { \
 46		if (UNLIKELY(mask & (1 << i))) { \
 47			value = cpu->gprs[i]; \
 48			STM; \
 49			++wait; \
 50			address += 4; \
 51		} \
 52		if (UNLIKELY(mask & (2 << i))) { \
 53			value = cpu->gprs[i + 1]; \
 54			STM; \
 55			++wait; \
 56			address += 4; \
 57		} \
 58		if (UNLIKELY(mask & (4 << i))) { \
 59			value = cpu->gprs[i + 2]; \
 60			STM; \
 61			++wait; \
 62			address += 4; \
 63		} \
 64		if (UNLIKELY(mask & (8 << i))) { \
 65			value = cpu->gprs[i + 3]; \
 66			STM; \
 67			++wait; \
 68			address += 4; \
 69		} \
 70	}
 71
 72
 73static uint32_t _deadbeef[1] = { 0xE710B710 }; // Illegal instruction on both ARM and Thumb
 74
 75static void DS7SetActiveRegion(struct ARMCore* cpu, uint32_t region);
 76static void DS9SetActiveRegion(struct ARMCore* cpu, uint32_t region);
 77static int32_t DSMemoryStall(struct ARMCore* cpu, int32_t wait);
 78
 79static const int DMA_OFFSET[] = { 1, -1, 0, 1 };
 80
 81void DSMemoryInit(struct DS* ds) {
 82	struct ARMCore* arm7 = ds->arm7;
 83	arm7->memory.load32 = DS7Load32;
 84	arm7->memory.load16 = DS7Load16;
 85	arm7->memory.load8 = DS7Load8;
 86	arm7->memory.loadMultiple = DS7LoadMultiple;
 87	arm7->memory.store32 = DS7Store32;
 88	arm7->memory.store16 = DS7Store16;
 89	arm7->memory.store8 = DS7Store8;
 90	arm7->memory.storeMultiple = DS7StoreMultiple;
 91	arm7->memory.stall = DSMemoryStall;
 92
 93	struct ARMCore* arm9 = ds->arm9;
 94	arm9->memory.load32 = DS9Load32;
 95	arm9->memory.load16 = DS9Load16;
 96	arm9->memory.load8 = DS9Load8;
 97	arm9->memory.loadMultiple = DS9LoadMultiple;
 98	arm9->memory.store32 = DS9Store32;
 99	arm9->memory.store16 = DS9Store16;
100	arm9->memory.store8 = DS9Store8;
101	arm9->memory.storeMultiple = DS9StoreMultiple;
102	arm9->memory.stall = DSMemoryStall;
103
104	ds->memory.bios7 = NULL;
105	ds->memory.bios9 = NULL;
106	ds->memory.wram = NULL;
107	ds->memory.ram = NULL;
108	ds->memory.itcm = NULL;
109	ds->memory.dtcm = NULL;
110	ds->memory.rom = NULL;
111
112	ds->memory.activeRegion7 = -1;
113	ds->memory.activeRegion9 = -1;
114
115	arm7->memory.activeRegion = 0;
116	arm7->memory.activeMask = 0;
117	arm7->memory.setActiveRegion = DS7SetActiveRegion;
118	arm7->memory.activeSeqCycles32 = 0;
119	arm7->memory.activeSeqCycles16 = 0;
120	arm7->memory.activeNonseqCycles32 = 0;
121	arm7->memory.activeNonseqCycles16 = 0;
122
123	arm9->memory.activeRegion = 0;
124	arm9->memory.activeMask = 0;
125	arm9->memory.setActiveRegion = DS9SetActiveRegion;
126	arm9->memory.activeSeqCycles32 = 0;
127	arm9->memory.activeSeqCycles16 = 0;
128	arm9->memory.activeNonseqCycles32 = 0;
129	arm9->memory.activeNonseqCycles16 = 0;
130}
131
132void DSMemoryDeinit(struct DS* ds) {
133	mappedMemoryFree(ds->memory.wram, DS_SIZE_WORKING_RAM);
134	mappedMemoryFree(ds->memory.ram, DS_SIZE_RAM);
135	mappedMemoryFree(ds->memory.itcm, DS9_SIZE_ITCM);
136	mappedMemoryFree(ds->memory.dtcm, DS9_SIZE_DTCM);
137}
138
139void DSMemoryReset(struct DS* ds) {
140	if (ds->memory.wram) {
141		mappedMemoryFree(ds->memory.wram, DS_SIZE_WORKING_RAM);
142	}
143	ds->memory.wram = anonymousMemoryMap(DS_SIZE_WORKING_RAM);
144
145	if (ds->memory.ram) {
146		mappedMemoryFree(ds->memory.ram, DS_SIZE_RAM);
147	}
148	ds->memory.ram = anonymousMemoryMap(DS_SIZE_RAM);
149
150	if (ds->memory.itcm) {
151		mappedMemoryFree(ds->memory.itcm, DS9_SIZE_ITCM);
152	}
153	ds->memory.itcm = anonymousMemoryMap(DS9_SIZE_ITCM);
154
155	if (ds->memory.dtcm) {
156		mappedMemoryFree(ds->memory.dtcm, DS9_SIZE_DTCM);
157	}
158	ds->memory.dtcm = anonymousMemoryMap(DS9_SIZE_DTCM);
159
160	memset(ds->memory.dma7, 0, sizeof(ds->memory.dma7));
161	memset(ds->memory.dma9, 0, sizeof(ds->memory.dma9));
162	ds->memory.activeDMA7 = -1;
163	ds->memory.activeDMA9 = -1;
164	ds->memory.nextDMA = INT_MAX;
165	ds->memory.eventDiff = 0;
166
167	if (!ds->memory.wram || !ds->memory.ram || !ds->memory.itcm || !ds->memory.dtcm) {
168		DSMemoryDeinit(ds);
169		mLOG(DS_MEM, FATAL, "Could not map memory");
170	}
171}
172
173static void DS7SetActiveRegion(struct ARMCore* cpu, uint32_t address) {
174	struct DS* ds = (struct DS*) cpu->master;
175	struct DSMemory* memory = &ds->memory;
176
177	int newRegion = address >> DS_BASE_OFFSET;
178
179	memory->activeRegion7 = newRegion;
180	switch (newRegion) {
181	case DS_REGION_RAM:
182		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
183			cpu->memory.activeRegion = memory->ram;
184			cpu->memory.activeMask = DS_SIZE_RAM - 1;
185			return;
186		}
187		break;
188	case DS7_REGION_BIOS:
189		if (memory->bios7) {
190			cpu->memory.activeRegion = memory->bios9;
191			cpu->memory.activeMask = DS9_SIZE_BIOS - 1;
192		} else {
193			cpu->memory.activeRegion = _deadbeef;
194			cpu->memory.activeMask = 0;
195		}
196		return;
197	default:
198		break;
199	}
200	cpu->memory.activeRegion = _deadbeef;
201	cpu->memory.activeMask = 0;
202	mLOG(DS_MEM, FATAL, "Jumped to invalid address: %08X", address);
203	return;
204}
205
206uint32_t DS7Load32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
207	struct DS* ds = (struct DS*) cpu->master;
208	struct DSMemory* memory = &ds->memory;
209	uint32_t value = 0;
210	int wait = 0;
211
212	switch (address >> DS_BASE_OFFSET) {
213	case DS_REGION_RAM:
214		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
215			LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
216		}
217		break;
218	default:
219		break;
220	}
221
222	if (cycleCounter) {
223		wait += 2;
224		*cycleCounter += wait;
225	}
226	// Unaligned 32-bit loads are "rotated" so they make some semblance of sense
227	int rotate = (address & 3) << 3;
228	return ROR(value, rotate);
229}
230
231uint32_t DS7Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
232	struct DS* ds = (struct DS*) cpu->master;
233	struct DSMemory* memory = &ds->memory;
234	uint32_t value = 0;
235	int wait = 0;
236
237	switch (address >> DS_BASE_OFFSET) {
238	default:
239		break;
240	}
241
242	if (cycleCounter) {
243		wait += 2;
244		*cycleCounter += wait;
245	}
246	// Unaligned 16-bit loads are "unpredictable", TODO: See what DS does
247	int rotate = (address & 1) << 3;
248	return ROR(value, rotate);
249}
250
251uint32_t DS7Load8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
252	struct DS* ds = (struct DS*) cpu->master;
253	struct DSMemory* memory = &ds->memory;
254	uint32_t value = 0;
255	int wait = 0;
256
257	switch (address >> DS_BASE_OFFSET) {
258	default:
259		break;
260	}
261
262	if (cycleCounter) {
263		wait += 2;
264		*cycleCounter += wait;
265	}
266	return value;
267}
268
269void DS7Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) {
270	struct DS* ds = (struct DS*) cpu->master;
271	struct DSMemory* memory = &ds->memory;
272	int wait = 0;
273
274	switch (address >> DS_BASE_OFFSET) {
275	default:
276		break;
277	}
278
279	if (cycleCounter) {
280		++wait;
281		*cycleCounter += wait;
282	}
283}
284
285void DS7Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
286	struct DS* ds = (struct DS*) cpu->master;
287	struct DSMemory* memory = &ds->memory;
288	int wait = 0;
289
290	switch (address >> DS_BASE_OFFSET) {
291	default:
292		break;
293	}
294
295	if (cycleCounter) {
296		++wait;
297		*cycleCounter += wait;
298	}
299}
300
301void DS7Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
302	struct DS* ds = (struct DS*) cpu->master;
303	struct DSMemory* memory = &ds->memory;
304	int wait = 0;
305
306	switch (address >> DS_BASE_OFFSET) {
307	default:
308		break;
309	}
310
311	if (cycleCounter) {
312		++wait;
313		*cycleCounter += wait;
314	}
315}
316
317uint32_t DS7LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
318	struct DS* ds = (struct DS*) cpu->master;
319	struct DSMemory* memory = &ds->memory;
320	uint32_t value;
321	int wait = 0;
322
323	int i;
324	int offset = 4;
325	int popcount = 0;
326	if (direction & LSM_D) {
327		offset = -4;
328		popcount = popcount32(mask);
329		address -= (popcount << 2) - 4;
330	}
331
332	if (direction & LSM_B) {
333		address += offset;
334	}
335
336	uint32_t addressMisalign = address & 0x3;
337	address &= 0xFFFFFFFC;
338
339	switch (address >> DS_BASE_OFFSET) {
340	default:
341		break;
342	}
343
344	if (cycleCounter) {
345		++wait;
346		*cycleCounter += wait;
347	}
348
349	if (direction & LSM_B) {
350		address -= offset;
351	}
352
353	if (direction & LSM_D) {
354		address -= (popcount << 2) + 4;
355	}
356
357	return address | addressMisalign;
358}
359
360
361uint32_t DS7StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
362	struct DS* ds = (struct DS*) cpu->master;
363	struct DSMemory* memory = &ds->memory;
364	uint32_t value;
365	int wait = 0;
366
367	int i;
368	int offset = 4;
369	int popcount = 0;
370	if (direction & LSM_D) {
371		offset = -4;
372		popcount = popcount32(mask);
373		address -= (popcount << 2) - 4;
374	}
375
376	if (direction & LSM_B) {
377		address += offset;
378	}
379
380	uint32_t addressMisalign = address & 0x3;
381	address &= 0xFFFFFFFC;
382
383	switch (address >> DS_BASE_OFFSET) {
384	default:
385		break;
386	}
387
388	if (cycleCounter) {
389		*cycleCounter += wait;
390	}
391
392	if (direction & LSM_B) {
393		address -= offset;
394	}
395
396	if (direction & LSM_D) {
397		address -= (popcount << 2) + 4;
398	}
399
400	return address | addressMisalign;
401}
402
403static void DS9SetActiveRegion(struct ARMCore* cpu, uint32_t address) {
404	struct DS* ds = (struct DS*) cpu->master;
405	struct DSMemory* memory = &ds->memory;
406
407	int newRegion = address >> DS_BASE_OFFSET;
408
409	memory->activeRegion9 = newRegion;
410	switch (newRegion) {
411	case DS9_REGION_ITCM:
412	case DS9_REGION_ITCM_MIRROR:
413		if (address < (512U << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
414			cpu->memory.activeRegion = memory->itcm;
415			cpu->memory.activeMask = DS9_SIZE_ITCM - 1;
416			return;
417		}
418		goto jump_error;
419	case DS_REGION_RAM:
420		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
421			cpu->memory.activeRegion = memory->ram;
422			cpu->memory.activeMask = DS_SIZE_RAM - 1;
423			return;
424		}
425		goto jump_error;
426	case DS9_REGION_BIOS:
427		// TODO: Mask properly
428		if (memory->bios9) {
429			cpu->memory.activeRegion = memory->bios9;
430			cpu->memory.activeMask = DS9_SIZE_BIOS - 1;
431		} else {
432			cpu->memory.activeRegion = _deadbeef;
433			cpu->memory.activeMask = 0;
434		}
435		return;
436	default:
437		break;
438	}
439
440jump_error:
441	cpu->memory.activeRegion = _deadbeef;
442	cpu->memory.activeMask = 0;
443	mLOG(DS_MEM, FATAL, "Jumped to invalid address: %08X", address);
444}
445
446uint32_t DS9Load32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
447	struct DS* ds = (struct DS*) cpu->master;
448	struct DSMemory* memory = &ds->memory;
449	uint32_t value = 0;
450	int wait = 0;
451
452	switch (address >> DS_BASE_OFFSET) {
453	case DS_REGION_RAM:
454		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
455			LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
456			break;
457		}
458		mLOG(DS_MEM, STUB, "Unimplemented DS9 Load32: %08X", address);
459		break;
460	default:
461		mLOG(DS_MEM, STUB, "Unimplemented DS9 Load32: %08X", address);
462		break;
463	}
464
465	if (cycleCounter) {
466		wait += 2;
467		*cycleCounter += wait;
468	}
469	// Unaligned 32-bit loads are "rotated" so they make some semblance of sense
470	int rotate = (address & 3) << 3;
471	return ROR(value, rotate);
472}
473
474uint32_t DS9Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
475	struct DS* ds = (struct DS*) cpu->master;
476	struct DSMemory* memory = &ds->memory;
477	uint32_t value = 0;
478	int wait = 0;
479
480	switch (address >> DS_BASE_OFFSET) {
481	case DS_REGION_RAM:
482		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
483			LOAD_16(value, address & (DS_SIZE_RAM - 1), memory->ram);
484			break;
485		}
486		mLOG(DS_MEM, STUB, "Unimplemented DS9 Load16: %08X", address);
487	default:
488		mLOG(DS_MEM, STUB, "Unimplemented DS9 Load16: %08X", address);
489		break;
490	}
491
492	if (cycleCounter) {
493		wait += 2;
494		*cycleCounter += wait;
495	}
496	// Unaligned 16-bit loads are "unpredictable", TODO: See what DS does
497	int rotate = (address & 1) << 3;
498	return ROR(value, rotate);
499}
500
501uint32_t DS9Load8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
502	struct DS* ds = (struct DS*) cpu->master;
503	struct DSMemory* memory = &ds->memory;
504	uint32_t value = 0;
505	int wait = 0;
506
507	switch (address >> DS_BASE_OFFSET) {
508	case DS_REGION_RAM:
509		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
510			value = ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)];
511			break;
512		}
513		mLOG(DS_MEM, STUB, "Unimplemented DS9 Load8: %08X", address);
514	default:
515		mLOG(DS_MEM, STUB, "Unimplemented DS9 Load8: %08X", address);
516		break;
517	}
518
519	if (cycleCounter) {
520		wait += 2;
521		*cycleCounter += wait;
522	}
523	return value;
524}
525
526void DS9Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) {
527	struct DS* ds = (struct DS*) cpu->master;
528	struct DSMemory* memory = &ds->memory;
529	int wait = 0;
530
531	switch (address >> DS_BASE_OFFSET) {
532	case DS9_REGION_ITCM:
533	case DS9_REGION_ITCM_MIRROR:
534		if (address < (512 << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
535			STORE_32(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
536			break;
537		}
538		mLOG(DS_MEM, STUB, "Bad DS9 Store32: %08X:%08X", address, value);
539		break;
540	case DS_REGION_RAM:
541		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
542			STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
543			break;
544		}
545		mLOG(DS_MEM, STUB, "Unimplemented DS9 Store32: %08X:%08X", address, value);
546		break;
547	default:
548		mLOG(DS_MEM, STUB, "Unimplemented DS9 Store32: %08X:%08X", address, value);
549		break;
550	}
551
552	if (cycleCounter) {
553		++wait;
554		*cycleCounter += wait;
555	}
556}
557
558void DS9Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
559	struct DS* ds = (struct DS*) cpu->master;
560	struct DSMemory* memory = &ds->memory;
561	int wait = 0;
562
563	switch (address >> DS_BASE_OFFSET) {
564	case DS9_REGION_ITCM:
565	case DS9_REGION_ITCM_MIRROR:
566		if (address < (512 << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
567			STORE_16(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
568			break;
569		}
570		mLOG(DS_MEM, STUB, "Bad DS9 Store16: %08X:%04X", address, value);
571		break;
572	case DS_REGION_RAM:
573		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
574			STORE_16(value, address & (DS_SIZE_RAM - 1), memory->ram);
575			break;
576		}
577		mLOG(DS_MEM, STUB, "Unimplemented DS9 Store16: %08X:%04X", address, value);
578		break;
579	default:
580		mLOG(DS_MEM, STUB, "Unimplemented DS9 Store16: %08X:%04X", address, value);
581		break;
582	}
583
584	if (cycleCounter) {
585		++wait;
586		*cycleCounter += wait;
587	}
588}
589
590void DS9Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
591	struct DS* ds = (struct DS*) cpu->master;
592	struct DSMemory* memory = &ds->memory;
593	int wait = 0;
594
595	switch (address >> DS_BASE_OFFSET) {
596	case DS9_REGION_ITCM:
597	case DS9_REGION_ITCM_MIRROR:
598		if (address < (512U << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
599			((uint8_t*) memory->itcm)[address & (DS9_SIZE_ITCM - 1)] = value;
600			break;
601		}
602		mLOG(DS_MEM, STUB, "Bad DS9 Store8: %08X:%02X", address, value);
603		break;
604	case DS_REGION_RAM:
605		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
606			((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)] = value;
607			break;
608		}
609		mLOG(DS_MEM, STUB, "Unimplemented DS9 Store8: %08X:%02X", address, value);
610	default:
611		mLOG(DS_MEM, STUB, "Unimplemented DS9 Store8: %08X:%02X", address, value);
612		break;
613	}
614
615	if (cycleCounter) {
616		++wait;
617		*cycleCounter += wait;
618	}
619}
620
621uint32_t DS9LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
622	struct DS* ds = (struct DS*) cpu->master;
623	struct DSMemory* memory = &ds->memory;
624	uint32_t value;
625	int wait = 0;
626
627	int i;
628	int offset = 4;
629	int popcount = 0;
630	if (direction & LSM_D) {
631		offset = -4;
632		popcount = popcount32(mask);
633		address -= (popcount << 2) - 4;
634	}
635
636	if (direction & LSM_B) {
637		address += offset;
638	}
639
640	uint32_t addressMisalign = address & 0x3;
641	address &= 0xFFFFFFFC;
642
643	switch (address >> DS_BASE_OFFSET) {
644	case DS_REGION_RAM:
645		LDM_LOOP(if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
646			LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
647		} else {
648			mLOG(DS_MEM, STUB, "Unimplemented DS9 LDM: %08X", address);
649		});
650		break;
651	default:
652		mLOG(DS_MEM, STUB, "Unimplemented DS9 LDM: %08X", address);
653		LDM_LOOP(value = 0);
654		break;
655	}
656
657	if (cycleCounter) {
658		++wait;
659		*cycleCounter += wait;
660	}
661
662	if (direction & LSM_B) {
663		address -= offset;
664	}
665
666	if (direction & LSM_D) {
667		address -= (popcount << 2) + 4;
668	}
669
670	return address | addressMisalign;
671}
672
673
674uint32_t DS9StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
675	struct DS* ds = (struct DS*) cpu->master;
676	struct DSMemory* memory = &ds->memory;
677	uint32_t value;
678	int wait = 0;
679
680	int i;
681	int offset = 4;
682	int popcount = 0;
683	if (direction & LSM_D) {
684		offset = -4;
685		popcount = popcount32(mask);
686		address -= (popcount << 2) - 4;
687	}
688
689	if (direction & LSM_B) {
690		address += offset;
691	}
692
693	uint32_t addressMisalign = address & 0x3;
694	address &= 0xFFFFFFFC;
695
696	switch (address >> DS_BASE_OFFSET) {
697	case DS9_REGION_ITCM:
698	case DS9_REGION_ITCM_MIRROR:
699		STM_LOOP(if (address < (512U << ARMTCMControlGetVirtualSize(cpu->cp15.r9.i))) {
700			STORE_32(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
701		} else {
702			mLOG(DS_MEM, STUB, "Bad DS9 Store32: %08X:%08X", address, value);
703		});
704		break;
705	case DS_REGION_RAM:
706		STM_LOOP(if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
707			STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
708		} else {
709			mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
710		});
711		break;
712	default:
713		mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
714		STM_LOOP();
715		break;
716	}
717
718	if (cycleCounter) {
719		*cycleCounter += wait;
720	}
721
722	if (direction & LSM_B) {
723		address -= offset;
724	}
725
726	if (direction & LSM_D) {
727		address -= (popcount << 2) + 4;
728	}
729
730	return address | addressMisalign;
731}
732
733int32_t DSMemoryStall(struct ARMCore* cpu, int32_t wait) {
734	return wait;
735}
736