all repos — mgba @ b4fa4fe77e23ed774e749608144fc0d1330b941c

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 <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 const uint32_t _vramMask[9] = {
  20	0x1FFFF,
  21	0x1FFFF,
  22	0x1FFFF,
  23	0x1FFFF,
  24	0x0FFFF,
  25	0x03FFF,
  26	0x03FFF,
  27	0x07FFF,
  28	0x03FFF
  29};
  30
  31static void DS7SetActiveRegion(struct ARMCore* cpu, uint32_t region);
  32static void DS9SetActiveRegion(struct ARMCore* cpu, uint32_t region);
  33static int32_t DSMemoryStall(struct ARMCore* cpu, int32_t wait);
  34
  35static unsigned _selectVRAM(struct DSMemory* memory, uint32_t offset);
  36
  37static const char DS7_BASE_WAITSTATES[16] =        { 0, 0, 8, 0, 0, 0, 0, 0 };
  38static const char DS7_BASE_WAITSTATES_32[16] =     { 0, 0, 9, 0, 0, 1, 1, 0 };
  39static const char DS7_BASE_WAITSTATES_SEQ[16] =    { 0, 0, 1, 0, 0, 0, 0, 0 };
  40static const char DS7_BASE_WAITSTATES_SEQ_32[16] = { 0, 0, 2, 0, 0, 1, 1, 0 };
  41
  42static const char DS9_BASE_WAITSTATES[16] =        { 6, 6, 17, 6, 6, 7, 7, 6 };
  43static const char DS9_BASE_WAITSTATES_32[16] =     { 6, 6, 19, 6, 6, 9, 9, 6 };
  44static const char DS9_BASE_WAITSTATES_SEQ[16] =    { 1, 1,  1, 1, 1, 2, 2, 1 };
  45static const char DS9_BASE_WAITSTATES_SEQ_32[16] = { 1, 1,  3, 1, 1, 4, 4, 1 };
  46
  47void DSMemoryInit(struct DS* ds) {
  48	struct ARMCore* arm7 = ds->ds7.cpu;
  49	arm7->memory.load32 = DS7Load32;
  50	arm7->memory.load16 = DS7Load16;
  51	arm7->memory.load8 = DS7Load8;
  52	arm7->memory.loadMultiple = DS7LoadMultiple;
  53	arm7->memory.store32 = DS7Store32;
  54	arm7->memory.store16 = DS7Store16;
  55	arm7->memory.store8 = DS7Store8;
  56	arm7->memory.storeMultiple = DS7StoreMultiple;
  57	arm7->memory.stall = DSMemoryStall;
  58
  59	struct ARMCore* arm9 = ds->ds9.cpu;
  60	arm9->memory.load32 = DS9Load32;
  61	arm9->memory.load16 = DS9Load16;
  62	arm9->memory.load8 = DS9Load8;
  63	arm9->memory.loadMultiple = DS9LoadMultiple;
  64	arm9->memory.store32 = DS9Store32;
  65	arm9->memory.store16 = DS9Store16;
  66	arm9->memory.store8 = DS9Store8;
  67	arm9->memory.storeMultiple = DS9StoreMultiple;
  68	arm9->memory.stall = DSMemoryStall;
  69
  70	int i;
  71	for (i = 0; i < 8; ++i) {
  72		// TODO: Formalize
  73		ds->ds7.memory.waitstatesNonseq16[i] = DS7_BASE_WAITSTATES[i];
  74		ds->ds7.memory.waitstatesSeq16[i] = DS7_BASE_WAITSTATES_SEQ[i];
  75		ds->ds7.memory.waitstatesPrefetchNonseq16[i] = DS7_BASE_WAITSTATES[i];
  76		ds->ds7.memory.waitstatesPrefetchSeq16[i] = DS7_BASE_WAITSTATES_SEQ[i];
  77		ds->ds7.memory.waitstatesNonseq32[i] = DS7_BASE_WAITSTATES_32[i];
  78		ds->ds7.memory.waitstatesSeq32[i] = DS7_BASE_WAITSTATES_SEQ_32[i];
  79		ds->ds7.memory.waitstatesPrefetchNonseq32[i] = DS7_BASE_WAITSTATES_32[i];
  80		ds->ds7.memory.waitstatesPrefetchSeq32[i] = DS7_BASE_WAITSTATES_SEQ_32[i];
  81
  82		ds->ds9.memory.waitstatesNonseq16[i] = DS9_BASE_WAITSTATES[i];
  83		ds->ds9.memory.waitstatesSeq16[i] = DS9_BASE_WAITSTATES_SEQ[i];
  84		ds->ds9.memory.waitstatesPrefetchNonseq16[i] = DS9_BASE_WAITSTATES[i];
  85		ds->ds9.memory.waitstatesPrefetchSeq16[i] = DS9_BASE_WAITSTATES[i];
  86		ds->ds9.memory.waitstatesNonseq32[i] = DS9_BASE_WAITSTATES_32[i];
  87		ds->ds9.memory.waitstatesSeq32[i] = DS9_BASE_WAITSTATES_SEQ_32[i];
  88		ds->ds9.memory.waitstatesPrefetchNonseq32[i] = DS9_BASE_WAITSTATES_32[i];
  89		ds->ds9.memory.waitstatesPrefetchSeq32[i] = DS9_BASE_WAITSTATES_32[i];
  90	}
  91	for (; i < 256; ++i) {
  92		ds->ds7.memory.waitstatesNonseq16[i] = 0;
  93		ds->ds7.memory.waitstatesSeq16[i] = 0;
  94		ds->ds7.memory.waitstatesNonseq32[i] = 0;
  95		ds->ds7.memory.waitstatesSeq32[i] = 0;
  96
  97		ds->ds9.memory.waitstatesNonseq16[i] = 0;
  98		ds->ds9.memory.waitstatesSeq16[i] = 0;
  99		ds->ds9.memory.waitstatesNonseq32[i] = 0;
 100		ds->ds9.memory.waitstatesSeq32[i] = 0;
 101	}
 102
 103	ds->memory.bios7 = NULL;
 104	ds->memory.bios9 = NULL;
 105	ds->memory.wram = NULL;
 106	ds->memory.wram7 = NULL;
 107	ds->memory.ram = NULL;
 108	ds->memory.itcm = NULL;
 109	ds->memory.dtcm = NULL;
 110	ds->memory.rom = NULL;
 111
 112	ds->ds7.memory.activeRegion = -1;
 113	ds->ds9.memory.activeRegion = -1;
 114	ds->ds7.memory.io = ds->memory.io7;
 115	ds->ds9.memory.io = ds->memory.io9;
 116
 117	arm7->memory.activeRegion = 0;
 118	arm7->memory.activeMask = 0;
 119	arm7->memory.setActiveRegion = DS7SetActiveRegion;
 120	arm7->memory.activeSeqCycles32 = 0;
 121	arm7->memory.activeSeqCycles16 = 0;
 122	arm7->memory.activeNonseqCycles32 = 0;
 123	arm7->memory.activeNonseqCycles16 = 0;
 124
 125	arm9->memory.activeRegion = 0;
 126	arm9->memory.activeMask = 0;
 127	arm9->memory.setActiveRegion = DS9SetActiveRegion;
 128	arm9->memory.activeSeqCycles32 = 0;
 129	arm9->memory.activeSeqCycles16 = 0;
 130	arm9->memory.activeNonseqCycles32 = 0;
 131	arm9->memory.activeNonseqCycles16 = 0;
 132}
 133
 134void DSMemoryDeinit(struct DS* ds) {
 135	mappedMemoryFree(ds->memory.wram, DS_SIZE_WORKING_RAM);
 136	mappedMemoryFree(ds->memory.wram7, DS7_SIZE_WORKING_RAM);
 137	mappedMemoryFree(ds->memory.ram, DS_SIZE_RAM);
 138	mappedMemoryFree(ds->memory.itcm, DS9_SIZE_ITCM);
 139	mappedMemoryFree(ds->memory.dtcm, DS9_SIZE_DTCM);
 140}
 141
 142void DSMemoryReset(struct DS* ds) {
 143	if (ds->memory.wram) {
 144		mappedMemoryFree(ds->memory.wram, DS_SIZE_WORKING_RAM);
 145	}
 146	ds->memory.wram = anonymousMemoryMap(DS_SIZE_WORKING_RAM);
 147
 148	if (ds->memory.wram7) {
 149		mappedMemoryFree(ds->memory.wram7, DS7_SIZE_WORKING_RAM);
 150	}
 151	ds->memory.wram7 = anonymousMemoryMap(DS7_SIZE_WORKING_RAM);
 152
 153	if (ds->memory.ram) {
 154		mappedMemoryFree(ds->memory.ram, DS_SIZE_RAM);
 155	}
 156	ds->memory.ram = anonymousMemoryMap(DS_SIZE_RAM);
 157
 158	if (ds->memory.itcm) {
 159		mappedMemoryFree(ds->memory.itcm, DS9_SIZE_ITCM);
 160	}
 161	ds->memory.itcm = anonymousMemoryMap(DS9_SIZE_ITCM);
 162
 163	if (ds->memory.dtcm) {
 164		mappedMemoryFree(ds->memory.dtcm, DS9_SIZE_DTCM);
 165	}
 166	ds->memory.dtcm = anonymousMemoryMap(DS9_SIZE_DTCM);
 167
 168	memset(ds->ds7.memory.dma, 0, sizeof(ds->ds7.memory.dma));
 169	memset(ds->ds9.memory.dma, 0, sizeof(ds->ds9.memory.dma));
 170	ds->ds7.memory.activeDMA = -1;
 171	ds->ds9.memory.activeDMA = -1;
 172
 173	// TODO: Correct size
 174	ds->memory.wramSize7 = 0x8000;
 175	ds->memory.wramSize9 = 0;
 176
 177	DSVideoConfigureVRAM(&ds->memory, 0, 0);
 178	DSVideoConfigureVRAM(&ds->memory, 1, 0);
 179	DSVideoConfigureVRAM(&ds->memory, 2, 0);
 180	DSVideoConfigureVRAM(&ds->memory, 3, 0);
 181	DSVideoConfigureVRAM(&ds->memory, 4, 0);
 182	DSVideoConfigureVRAM(&ds->memory, 5, 0);
 183	DSVideoConfigureVRAM(&ds->memory, 6, 0);
 184	DSVideoConfigureVRAM(&ds->memory, 7, 0);
 185	DSVideoConfigureVRAM(&ds->memory, 8, 0);
 186
 187	if (!ds->memory.wram || !ds->memory.wram7 || !ds->memory.ram || !ds->memory.itcm || !ds->memory.dtcm) {
 188		DSMemoryDeinit(ds);
 189		mLOG(DS_MEM, FATAL, "Could not map memory");
 190	}
 191}
 192
 193static void DS7SetActiveRegion(struct ARMCore* cpu, uint32_t address) {
 194	struct DS* ds = (struct DS*) cpu->master;
 195	struct DSCoreMemory* memory = &ds->ds7.memory;
 196
 197	int newRegion = address >> DS_BASE_OFFSET;
 198
 199	memory->activeRegion = newRegion;
 200	switch (newRegion) {
 201	case DS_REGION_WORKING_RAM:
 202		if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
 203			cpu->memory.activeRegion = ds->memory.wram7;
 204			cpu->memory.activeMask = DS7_SIZE_WORKING_RAM - 1;
 205		} else {
 206			cpu->memory.activeRegion = ds->memory.wram;
 207			cpu->memory.activeMask = ds->memory.wramSize7 - 1;
 208		}
 209		break;
 210	case DS7_REGION_BIOS:
 211		if (ds->memory.bios7) {
 212			cpu->memory.activeRegion = ds->memory.bios7;
 213			cpu->memory.activeMask = DS9_SIZE_BIOS - 1;
 214		} else {
 215			cpu->memory.activeRegion = _deadbeef;
 216			cpu->memory.activeMask = 0;
 217		}
 218		break;
 219	case DS_REGION_RAM:
 220		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
 221			cpu->memory.activeRegion = ds->memory.ram;
 222			cpu->memory.activeMask = DS_SIZE_RAM - 1;
 223			break;
 224		}
 225	// Fall through
 226	default:
 227		memory->activeRegion = -1;
 228		cpu->memory.activeRegion = _deadbeef;
 229		cpu->memory.activeMask = 0;
 230		mLOG(DS_MEM, FATAL, "Jumped to invalid address: %08X", address);
 231		break;
 232	}
 233	cpu->memory.activeSeqCycles32 = memory->waitstatesPrefetchSeq32[memory->activeRegion];
 234	cpu->memory.activeSeqCycles16 = memory->waitstatesPrefetchSeq16[memory->activeRegion];
 235	cpu->memory.activeNonseqCycles32 = memory->waitstatesPrefetchNonseq32[memory->activeRegion];
 236	cpu->memory.activeNonseqCycles16 = memory->waitstatesPrefetchNonseq16[memory->activeRegion];
 237}
 238
 239uint32_t DS7Load32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
 240	struct DS* ds = (struct DS*) cpu->master;
 241	struct DSMemory* memory = &ds->memory;
 242	uint32_t value = 0;
 243	int wait = ds->ds7.memory.waitstatesNonseq32[address >> DS_BASE_OFFSET];
 244
 245	switch (address >> DS_BASE_OFFSET) {
 246	case DS7_REGION_BIOS:
 247		LOAD_32(value, address & (DS7_SIZE_BIOS - 4), memory->bios7);
 248		break;
 249	case DS_REGION_WORKING_RAM:
 250		if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
 251			LOAD_32(value, address & (DS7_SIZE_WORKING_RAM - 4), memory->wram7);
 252		} else {
 253			LOAD_32(value, address & (ds->memory.wramSize7 - 4), memory->wram);
 254		}
 255		break;
 256	case DS_REGION_RAM:
 257		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
 258			LOAD_32(value, address & (DS_SIZE_RAM - 4), memory->ram);
 259			break;
 260		}
 261		mLOG(DS_MEM, STUB, "Unimplemented DS7 Load32: %08X", address);
 262		break;
 263	case DS_REGION_IO:
 264		value = DS7IORead32(ds, address & 0x00FFFFFC);
 265		break;
 266	default:
 267		mLOG(DS_MEM, STUB, "Unimplemented DS7 Load32: %08X", address);
 268		break;
 269	}
 270
 271	if (cycleCounter) {
 272		wait += 2;
 273		*cycleCounter += wait;
 274	}
 275	// Unaligned 32-bit loads are "rotated" so they make some semblance of sense
 276	int rotate = (address & 3) << 3;
 277	return ROR(value, rotate);
 278}
 279
 280uint32_t DS7Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
 281	struct DS* ds = (struct DS*) cpu->master;
 282	struct DSMemory* memory = &ds->memory;
 283	uint32_t value = 0;
 284	int wait = ds->ds7.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
 285
 286	switch (address >> DS_BASE_OFFSET) {
 287	case DS7_REGION_BIOS:
 288		LOAD_16(value, address & (DS7_SIZE_BIOS - 2), memory->bios7);
 289		break;
 290	case DS_REGION_WORKING_RAM:
 291		if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
 292			LOAD_16(value, address & (DS7_SIZE_WORKING_RAM - 2), memory->wram7);
 293		} else {
 294			LOAD_16(value, address & (ds->memory.wramSize7 - 2), memory->wram);
 295		}
 296		break;
 297	case DS_REGION_RAM:
 298		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
 299			LOAD_16(value, address & (DS_SIZE_RAM - 1), memory->ram);
 300			break;
 301		}
 302		mLOG(DS_MEM, STUB, "Unimplemented DS7 Load16: %08X", address);
 303	case DS_REGION_IO:
 304		value = DS7IORead(ds, address & DS_OFFSET_MASK);
 305		break;
 306	default:
 307		mLOG(DS_MEM, STUB, "Unimplemented DS7 Load16: %08X", address);
 308		break;
 309	}
 310
 311	if (cycleCounter) {
 312		wait += 2;
 313		*cycleCounter += wait;
 314	}
 315	// Unaligned 16-bit loads are "unpredictable", TODO: See what DS does
 316	int rotate = (address & 1) << 3;
 317	return ROR(value, rotate);
 318}
 319
 320uint32_t DS7Load8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
 321	struct DS* ds = (struct DS*) cpu->master;
 322	struct DSMemory* memory = &ds->memory;
 323	uint32_t value = 0;
 324	int wait = ds->ds7.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
 325
 326	switch (address >> DS_BASE_OFFSET) {
 327	case DS_REGION_WORKING_RAM:
 328		if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
 329			value = ((uint8_t*) memory->wram7)[address & (DS7_SIZE_WORKING_RAM - 1)];
 330		} else {
 331			value = ((uint8_t*) memory->wram)[address & (ds->memory.wramSize7 - 1)];
 332		}
 333		break;
 334	case DS_REGION_RAM:
 335		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
 336			value = ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)];
 337			break;
 338		}
 339		mLOG(DS_MEM, STUB, "Unimplemented DS7 Load8: %08X", address);
 340	default:
 341		mLOG(DS_MEM, STUB, "Unimplemented DS7 Load8: %08X", address);
 342		break;
 343	}
 344
 345	if (cycleCounter) {
 346		wait += 2;
 347		*cycleCounter += wait;
 348	}
 349	return value;
 350}
 351
 352void DS7Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) {
 353	struct DS* ds = (struct DS*) cpu->master;
 354	struct DSMemory* memory = &ds->memory;
 355	int wait = ds->ds7.memory.waitstatesNonseq32[address >> DS_BASE_OFFSET];
 356
 357	switch (address >> DS_BASE_OFFSET) {
 358	case DS_REGION_WORKING_RAM:
 359		if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
 360			STORE_32(value, address & (DS7_SIZE_WORKING_RAM - 4), memory->wram7);
 361		} else {
 362			STORE_32(value, address & (ds->memory.wramSize7 - 4), memory->wram);
 363		}
 364		break;
 365	case DS_REGION_RAM:
 366		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
 367			STORE_32(value, address & (DS_SIZE_RAM - 4), memory->ram);
 368			break;
 369		}
 370		mLOG(DS_MEM, STUB, "Unimplemented DS7 Store32: %08X:%08X", address, value);
 371		break;
 372	case DS_REGION_IO:
 373		DS7IOWrite32(ds, address & DS_OFFSET_MASK, value);
 374		break;
 375	default:
 376		mLOG(DS_MEM, STUB, "Unimplemented DS7 Store32: %08X:%08X", address, value);
 377		break;
 378	}
 379
 380	if (cycleCounter) {
 381		++wait;
 382		*cycleCounter += wait;
 383	}
 384}
 385
 386void DS7Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
 387	struct DS* ds = (struct DS*) cpu->master;
 388	struct DSMemory* memory = &ds->memory;
 389	int wait = ds->ds7.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
 390
 391	switch (address >> DS_BASE_OFFSET) {
 392	case DS_REGION_WORKING_RAM:
 393		if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
 394			STORE_16(value, address & (DS7_SIZE_WORKING_RAM - 2), memory->wram7);
 395		} else {
 396			STORE_16(value, address & (ds->memory.wramSize7 - 2), memory->wram);
 397		}
 398		break;
 399	case DS_REGION_RAM:
 400		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
 401			STORE_16(value, address & (DS_SIZE_RAM - 2), memory->ram);
 402			break;
 403		}
 404		mLOG(DS_MEM, STUB, "Unimplemented DS7 Store16: %08X:%04X", address, value);
 405		break;
 406	case DS_REGION_IO:
 407		DS7IOWrite(ds, address & DS_OFFSET_MASK, value);
 408		break;
 409	default:
 410		mLOG(DS_MEM, STUB, "Unimplemented DS7 Store16: %08X:%04X", address, value);
 411		break;
 412	}
 413
 414	if (cycleCounter) {
 415		++wait;
 416		*cycleCounter += wait;
 417	}
 418}
 419
 420void DS7Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
 421	struct DS* ds = (struct DS*) cpu->master;
 422	struct DSMemory* memory = &ds->memory;
 423	int wait = ds->ds7.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
 424
 425	switch (address >> DS_BASE_OFFSET) {
 426	case DS_REGION_WORKING_RAM:
 427		if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
 428			((uint8_t*) memory->wram7)[address & (DS7_SIZE_WORKING_RAM - 1)] = value;
 429		} else {
 430			((uint8_t*) memory->wram)[address & (ds->memory.wramSize7 - 1)] = value;
 431		}
 432		break;
 433	case DS_REGION_RAM:
 434		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
 435			((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)] = value;
 436			break;
 437		}
 438		mLOG(DS_MEM, STUB, "Unimplemented DS7 Store8: %08X:%02X", address, value);
 439	case DS_REGION_IO:
 440		DS7IOWrite8(ds, address & DS_OFFSET_MASK, value);
 441		break;
 442	default:
 443		mLOG(DS_MEM, STUB, "Unimplemented DS7 Store8: %08X:%02X", address, value);
 444		break;
 445	}
 446
 447	if (cycleCounter) {
 448		++wait;
 449		*cycleCounter += wait;
 450	}
 451}
 452
 453#define LDM_LOOP(LDM) \
 454	for (i = 0; i < 16; i += 4) { \
 455		if (UNLIKELY(mask & (1 << i))) { \
 456			LDM; \
 457			cpu->gprs[i] = value; \
 458			++wait; \
 459			wait += ws32[address >> DS_BASE_OFFSET]; \
 460			address += 4; \
 461		} \
 462		if (UNLIKELY(mask & (2 << i))) { \
 463			LDM; \
 464			cpu->gprs[i + 1] = value; \
 465			++wait; \
 466			wait += ws32[address >> DS_BASE_OFFSET]; \
 467			address += 4; \
 468		} \
 469		if (UNLIKELY(mask & (4 << i))) { \
 470			LDM; \
 471			cpu->gprs[i + 2] = value; \
 472			++wait; \
 473			wait += ws32[address >> DS_BASE_OFFSET]; \
 474			address += 4; \
 475		} \
 476		if (UNLIKELY(mask & (8 << i))) { \
 477			LDM; \
 478			cpu->gprs[i + 3] = value; \
 479			++wait; \
 480			wait += ws32[address >> DS_BASE_OFFSET]; \
 481			address += 4; \
 482		} \
 483	}
 484
 485#define STM_LOOP(STM) \
 486	for (i = 0; i < 16; i += 4) { \
 487		if (UNLIKELY(mask & (1 << i))) { \
 488			value = cpu->gprs[i]; \
 489			STM; \
 490			++wait; \
 491			wait += ws32[address >> DS_BASE_OFFSET]; \
 492			address += 4; \
 493		} \
 494		if (UNLIKELY(mask & (2 << i))) { \
 495			value = cpu->gprs[i + 1]; \
 496			STM; \
 497			++wait; \
 498			wait += ws32[address >> DS_BASE_OFFSET]; \
 499			address += 4; \
 500		} \
 501		if (UNLIKELY(mask & (4 << i))) { \
 502			value = cpu->gprs[i + 2]; \
 503			STM; \
 504			++wait; \
 505			wait += ws32[address >> DS_BASE_OFFSET]; \
 506			address += 4; \
 507		} \
 508		if (UNLIKELY(mask & (8 << i))) { \
 509			value = cpu->gprs[i + 3]; \
 510			STM; \
 511			++wait; \
 512			wait += ws32[address >> DS_BASE_OFFSET]; \
 513			address += 4; \
 514		} \
 515	}
 516
 517
 518
 519uint32_t DS7LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
 520	struct DS* ds = (struct DS*) cpu->master;
 521	struct DSMemory* memory = &ds->memory;
 522	char* ws32 = ds->ds7.memory.waitstatesNonseq32;
 523	uint32_t value;
 524	int wait = 0;
 525
 526	int i;
 527	int offset = 4;
 528	int popcount = 0;
 529	if (direction & LSM_D) {
 530		offset = -4;
 531		popcount = popcount32(mask);
 532		address -= (popcount << 2) - 4;
 533	}
 534
 535	if (direction & LSM_B) {
 536		address += offset;
 537	}
 538
 539	uint32_t addressMisalign = address & 0x3;
 540	address &= 0xFFFFFFFC;
 541
 542	switch (address >> DS_BASE_OFFSET) {
 543	case DS_REGION_WORKING_RAM:
 544		LDM_LOOP(if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
 545			LOAD_32(value, address & (DS7_SIZE_WORKING_RAM - 1), memory->wram7);
 546		} else {
 547			LOAD_32(value, address & (ds->memory.wramSize7 - 1), memory->wram);
 548		});
 549		break;
 550	case DS_REGION_RAM:
 551		LDM_LOOP(if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
 552			LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
 553		} else {
 554			mLOG(DS_MEM, STUB, "Unimplemented DS7 LDM: %08X", address);
 555		});
 556		break;
 557	case DS_REGION_IO:
 558		LDM_LOOP(value = DS7IORead32(ds, address));
 559		break;
 560	default:
 561		mLOG(DS_MEM, STUB, "Unimplemented DS7 LDM: %08X", address);
 562		LDM_LOOP(value = 0);
 563	}
 564
 565	if (cycleCounter) {
 566		++wait;
 567		*cycleCounter += wait;
 568	}
 569
 570	if (direction & LSM_B) {
 571		address -= offset;
 572	}
 573
 574	if (direction & LSM_D) {
 575		address -= (popcount << 2) + 4;
 576	}
 577
 578	return address | addressMisalign;
 579}
 580
 581
 582uint32_t DS7StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
 583	struct DS* ds = (struct DS*) cpu->master;
 584	struct DSMemory* memory = &ds->memory;
 585	char* ws32 = ds->ds7.memory.waitstatesNonseq32;
 586	uint32_t value;
 587	int wait = 0;
 588
 589	int i;
 590	int offset = 4;
 591	int popcount = 0;
 592	if (direction & LSM_D) {
 593		offset = -4;
 594		popcount = popcount32(mask);
 595		address -= (popcount << 2) - 4;
 596	}
 597
 598	if (direction & LSM_B) {
 599		address += offset;
 600	}
 601
 602	uint32_t addressMisalign = address & 0x3;
 603	address &= 0xFFFFFFFC;
 604
 605	switch (address >> DS_BASE_OFFSET) {
 606	case DS_REGION_WORKING_RAM:
 607		STM_LOOP(if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
 608			STORE_32(value, address & (DS7_SIZE_WORKING_RAM - 1), memory->wram7);
 609		} else {
 610			STORE_32(value, address & (ds->memory.wramSize7 - 1), memory->wram);
 611		});
 612		break;
 613	case DS_REGION_RAM:
 614		STM_LOOP(if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
 615			STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
 616		} else {
 617			mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
 618		});
 619		break;
 620	default:
 621		mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
 622		STM_LOOP();
 623		break;
 624	}
 625
 626	if (cycleCounter) {
 627		*cycleCounter += wait;
 628	}
 629
 630	if (direction & LSM_B) {
 631		address -= offset;
 632	}
 633
 634	if (direction & LSM_D) {
 635		address -= (popcount << 2) + 4;
 636	}
 637
 638	return address | addressMisalign;
 639}
 640
 641static void DS9SetActiveRegion(struct ARMCore* cpu, uint32_t address) {
 642	struct DS* ds = (struct DS*) cpu->master;
 643	struct DSCoreMemory* memory = &ds->ds9.memory;
 644
 645	int newRegion = address >> DS_BASE_OFFSET;
 646
 647	memory->activeRegion = newRegion;
 648	switch (newRegion) {
 649	case DS9_REGION_ITCM:
 650	case DS9_REGION_ITCM_MIRROR:
 651		if (address < ds->memory.itcmSize) {
 652			cpu->memory.activeRegion = ds->memory.itcm;
 653			cpu->memory.activeMask = DS9_SIZE_ITCM - 1;
 654			break;
 655		}
 656		goto jump_error;
 657	case DS_REGION_RAM:
 658		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
 659			cpu->memory.activeRegion = ds->memory.ram;
 660			cpu->memory.activeMask = DS_SIZE_RAM - 1;
 661			break;
 662		}
 663		goto jump_error;
 664	case DS9_REGION_BIOS:
 665		// TODO: Mask properly
 666		if (ds->memory.bios9) {
 667			cpu->memory.activeRegion = ds->memory.bios9;
 668			cpu->memory.activeMask = DS9_SIZE_BIOS - 1;
 669		} else {
 670			cpu->memory.activeRegion = _deadbeef;
 671			cpu->memory.activeMask = 0;
 672		}
 673		break;
 674	default:
 675	jump_error:
 676		memory->activeRegion = -1;
 677		cpu->memory.activeRegion = _deadbeef;
 678		cpu->memory.activeMask = 0;
 679		mLOG(DS_MEM, FATAL, "Jumped to invalid address: %08X", address);
 680		return;
 681	}
 682	cpu->memory.activeSeqCycles32 = memory->waitstatesPrefetchSeq32[memory->activeRegion];
 683	cpu->memory.activeSeqCycles16 = memory->waitstatesPrefetchSeq16[memory->activeRegion];
 684	cpu->memory.activeNonseqCycles32 = memory->waitstatesPrefetchNonseq32[memory->activeRegion];
 685	cpu->memory.activeNonseqCycles16 = memory->waitstatesPrefetchNonseq16[memory->activeRegion];
 686}
 687
 688uint32_t DS9Load32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
 689	struct DS* ds = (struct DS*) cpu->master;
 690	struct DSMemory* memory = &ds->memory;
 691	uint32_t value = 0;
 692	int wait = ds->ds9.memory.waitstatesNonseq32[address >> DS_BASE_OFFSET];
 693
 694	switch (address >> DS_BASE_OFFSET) {
 695	case DS9_REGION_ITCM:
 696	case DS9_REGION_ITCM_MIRROR:
 697		if (address < memory->itcmSize) {
 698			LOAD_32(value, address & (DS9_SIZE_ITCM - 4), memory->itcm);
 699			break;
 700		}
 701		mLOG(DS_MEM, STUB, "Bad DS9 Load32: %08X:%08X", address, value);
 702		break;
 703	case DS_REGION_RAM:
 704		if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
 705			LOAD_32(value, address & (DS9_SIZE_DTCM - 4), memory->dtcm);
 706			break;
 707		}
 708		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
 709			LOAD_32(value, address & (DS_SIZE_RAM - 4), memory->ram);
 710			break;
 711		}
 712		mLOG(DS_MEM, STUB, "Unimplemented DS9 Load32: %08X", address);
 713		break;
 714	case DS_REGION_IO:
 715		value = DS9IORead32(ds, address & 0x00FFFFFC);
 716		break;
 717	case DS_REGION_VRAM: {
 718		unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
 719		int i = 0;
 720		for (i = 0; i < 9; ++i) {
 721			if (mask & (1 << i)) {
 722				uint32_t newValue;
 723				LOAD_32(newValue, address & _vramMask[i], memory->vramBank[i]);
 724				value |= newValue;
 725			}
 726		}
 727		break;
 728	}
 729	case DS9_REGION_BIOS:
 730		// TODO: Fix undersized BIOS
 731		// TODO: Fix masking
 732		LOAD_32(value, address & (DS9_SIZE_BIOS - 4), memory->bios9);
 733		break;
 734	default:
 735		if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
 736			LOAD_32(value, address & (DS9_SIZE_DTCM - 4), memory->dtcm);
 737			break;
 738		}
 739		mLOG(DS_MEM, STUB, "Unimplemented DS9 Load32: %08X", address);
 740		break;
 741	}
 742
 743	if (cycleCounter) {
 744		wait += 2;
 745		*cycleCounter += wait;
 746	}
 747	// Unaligned 32-bit loads are "rotated" so they make some semblance of sense
 748	int rotate = (address & 3) << 3;
 749	return ROR(value, rotate);
 750}
 751
 752uint32_t DS9Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
 753	struct DS* ds = (struct DS*) cpu->master;
 754	struct DSMemory* memory = &ds->memory;
 755	uint32_t value = 0;
 756	int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
 757
 758	switch (address >> DS_BASE_OFFSET) {
 759	case DS9_REGION_ITCM:
 760	case DS9_REGION_ITCM_MIRROR:
 761		if (address < memory->itcmSize) {
 762			LOAD_16(value, address & (DS9_SIZE_ITCM - 2), memory->itcm);
 763			break;
 764		}
 765		mLOG(DS_MEM, STUB, "Bad DS9 Load16: %08X:%08X", address, value);
 766		break;
 767	case DS_REGION_RAM:
 768		if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
 769			LOAD_16(value, address & (DS9_SIZE_DTCM - 2), memory->dtcm);
 770			break;
 771		}
 772		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
 773			LOAD_16(value, address & (DS_SIZE_RAM - 2), memory->ram);
 774			break;
 775		}
 776		mLOG(DS_MEM, STUB, "Unimplemented DS9 Load16: %08X", address);
 777	case DS_REGION_IO:
 778		value = DS9IORead(ds, address & DS_OFFSET_MASK);
 779		break;
 780	case DS_REGION_VRAM: {
 781		unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
 782		int i = 0;
 783		for (i = 0; i < 9; ++i) {
 784			if (mask & (1 << i)) {
 785				uint32_t newValue;
 786				LOAD_16(newValue, address & _vramMask[i], memory->vramBank[i]);
 787				value |= newValue;
 788			}
 789		}
 790		break;
 791	}
 792	case DS9_REGION_BIOS:
 793		// TODO: Fix undersized BIOS
 794		// TODO: Fix masking
 795		LOAD_16(value, address & (DS9_SIZE_BIOS - 2), memory->bios9);
 796		break;
 797	default:
 798		if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
 799			LOAD_16(value, address & (DS9_SIZE_DTCM - 2), memory->dtcm);
 800			break;
 801		}
 802		mLOG(DS_MEM, STUB, "Unimplemented DS9 Load16: %08X", address);
 803		break;
 804	}
 805
 806	if (cycleCounter) {
 807		wait += 2;
 808		*cycleCounter += wait;
 809	}
 810	// Unaligned 16-bit loads are "unpredictable", TODO: See what DS does
 811	int rotate = (address & 1) << 3;
 812	return ROR(value, rotate);
 813}
 814
 815uint32_t DS9Load8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
 816	struct DS* ds = (struct DS*) cpu->master;
 817	struct DSMemory* memory = &ds->memory;
 818	uint32_t value = 0;
 819	int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
 820
 821	switch (address >> DS_BASE_OFFSET) {
 822	case DS9_REGION_ITCM:
 823	case DS9_REGION_ITCM_MIRROR:
 824		if (address < memory->itcmSize) {
 825			value = ((uint8_t*) memory->itcm)[address & (DS9_SIZE_ITCM - 1)];
 826			break;
 827		}
 828		mLOG(DS_MEM, STUB, "Bad DS9 Load8: %08X:%08X", address, value);
 829		break;
 830	case DS_REGION_RAM:
 831		if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
 832			value = ((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM- 1)];
 833			break;
 834		}
 835		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
 836			value = ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)];
 837			break;
 838		}
 839		mLOG(DS_MEM, STUB, "Unimplemented DS9 Load8: %08X", address);
 840	case DS9_REGION_BIOS:
 841		// TODO: Fix undersized BIOS
 842		// TODO: Fix masking
 843		value = ((uint8_t*) memory->bios9)[address & (DS9_SIZE_BIOS - 1)];
 844		break;
 845	default:
 846		if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
 847			value = ((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)];
 848			break;
 849		}
 850		mLOG(DS_MEM, STUB, "Unimplemented DS9 Load8: %08X", address);
 851		break;
 852	}
 853
 854	if (cycleCounter) {
 855		wait += 2;
 856		*cycleCounter += wait;
 857	}
 858	return value;
 859}
 860
 861void DS9Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) {
 862	struct DS* ds = (struct DS*) cpu->master;
 863	struct DSMemory* memory = &ds->memory;
 864	int wait = ds->ds9.memory.waitstatesNonseq32[address >> DS_BASE_OFFSET];
 865
 866	switch (address >> DS_BASE_OFFSET) {
 867	case DS9_REGION_ITCM:
 868	case DS9_REGION_ITCM_MIRROR:
 869		if (address < memory->itcmSize) {
 870			STORE_32(value, address & (DS9_SIZE_ITCM - 4), memory->itcm);
 871			break;
 872		}
 873		mLOG(DS_MEM, STUB, "Bad DS9 Store32: %08X:%08X", address, value);
 874		break;
 875	case DS_REGION_RAM:
 876		if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
 877			STORE_32(value, address & (DS9_SIZE_DTCM - 4), memory->dtcm);
 878			break;
 879		}
 880		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
 881			STORE_32(value, address & (DS_SIZE_RAM - 4), memory->ram);
 882			break;
 883		}
 884		mLOG(DS_MEM, STUB, "Unimplemented DS9 Store32: %08X:%08X", address, value);
 885		break;
 886	case DS_REGION_IO:
 887		DS9IOWrite32(ds, address & DS_OFFSET_MASK, value);
 888		break;
 889	case DS_REGION_VRAM: {
 890		unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
 891		int i = 0;
 892		for (i = 0; i < 9; ++i) {
 893			if (mask & (1 << i)) {
 894				STORE_32(value, address & _vramMask[i], memory->vramBank[i]);
 895			}
 896		}
 897		break;
 898	}
 899	default:
 900		if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
 901			STORE_32(value, address & (DS9_SIZE_DTCM - 4), memory->dtcm);
 902			break;
 903		}
 904		mLOG(DS_MEM, STUB, "Unimplemented DS9 Store32: %08X:%08X", address, value);
 905		break;
 906	}
 907
 908	if (cycleCounter) {
 909		++wait;
 910		*cycleCounter += wait;
 911	}
 912}
 913
 914void DS9Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
 915	struct DS* ds = (struct DS*) cpu->master;
 916	struct DSMemory* memory = &ds->memory;
 917	int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
 918
 919	switch (address >> DS_BASE_OFFSET) {
 920	case DS9_REGION_ITCM:
 921	case DS9_REGION_ITCM_MIRROR:
 922		if (address < memory->itcmSize) {
 923			STORE_16(value, address & (DS9_SIZE_ITCM - 2), memory->itcm);
 924			break;
 925		}
 926		mLOG(DS_MEM, STUB, "Bad DS9 Store16: %08X:%04X", address, value);
 927		break;
 928	case DS_REGION_RAM:
 929		if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
 930			STORE_16(value, address & (DS9_SIZE_DTCM - 2), memory->dtcm);
 931			break;
 932		}
 933		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
 934			STORE_16(value, address & (DS_SIZE_RAM - 2), memory->ram);
 935			break;
 936		}
 937		mLOG(DS_MEM, STUB, "Unimplemented DS9 Store16: %08X:%04X", address, value);
 938		break;
 939	case DS_REGION_IO:
 940		DS9IOWrite(ds, address & DS_OFFSET_MASK, value);
 941		break;
 942	case DS_REGION_VRAM: {
 943		unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
 944		int i = 0;
 945		for (i = 0; i < 9; ++i) {
 946			if (mask & (1 << i)) {
 947				STORE_16(value, address & _vramMask[i], memory->vramBank[i]);
 948			}
 949		}
 950		break;
 951	}
 952	default:
 953		if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
 954			STORE_16(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
 955			break;
 956		}
 957		mLOG(DS_MEM, STUB, "Unimplemented DS9 Store16: %08X:%04X", address, value);
 958		break;
 959	}
 960
 961	if (cycleCounter) {
 962		++wait;
 963		*cycleCounter += wait;
 964	}
 965}
 966
 967void DS9Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
 968	struct DS* ds = (struct DS*) cpu->master;
 969	struct DSMemory* memory = &ds->memory;
 970	int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
 971
 972	switch (address >> DS_BASE_OFFSET) {
 973	case DS9_REGION_ITCM:
 974	case DS9_REGION_ITCM_MIRROR:
 975		if (address < memory->itcmSize) {
 976			((uint8_t*) memory->itcm)[address & (DS9_SIZE_ITCM - 1)] = value;
 977			break;
 978		}
 979		mLOG(DS_MEM, STUB, "Bad DS9 Store8: %08X:%02X", address, value);
 980		break;
 981	case DS_REGION_RAM:
 982		if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
 983			((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)] = value;
 984			break;
 985		}
 986		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
 987			((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)] = value;
 988			break;
 989		}
 990		mLOG(DS_MEM, STUB, "Unimplemented DS9 Store8: %08X:%02X", address, value);
 991	case DS_REGION_IO:
 992		DS9IOWrite8(ds, address & DS_OFFSET_MASK, value);
 993		break;
 994	default:
 995		if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
 996			((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)] = value;
 997			break;
 998		}
 999		mLOG(DS_MEM, STUB, "Unimplemented DS9 Store8: %08X:%02X", address, value);
1000		break;
1001	}
1002
1003	if (cycleCounter) {
1004		++wait;
1005		*cycleCounter += wait;
1006	}
1007}
1008
1009uint32_t DS9LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
1010	struct DS* ds = (struct DS*) cpu->master;
1011	struct DSMemory* memory = &ds->memory;
1012	char* ws32 = ds->ds9.memory.waitstatesNonseq32;
1013	uint32_t value;
1014	int wait = 0;
1015
1016	int i;
1017	int offset = 4;
1018	int popcount = 0;
1019	if (direction & LSM_D) {
1020		offset = -4;
1021		popcount = popcount32(mask);
1022		address -= (popcount << 2) - 4;
1023	}
1024
1025	if (direction & LSM_B) {
1026		address += offset;
1027	}
1028
1029	uint32_t addressMisalign = address & 0x3;
1030	address &= 0xFFFFFFFC;
1031
1032	switch (address >> DS_BASE_OFFSET) {
1033	case DS9_REGION_ITCM:
1034	case DS9_REGION_ITCM_MIRROR:
1035		LDM_LOOP(if (address < memory->itcmSize) {
1036			LOAD_32(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
1037		} else {
1038			mLOG(DS_MEM, STUB, "Bad DS9 LDM: %08X:%08X", address, value);
1039		});
1040		break;
1041	case DS_REGION_RAM:
1042		LDM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1043			LOAD_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1044		} else if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1045			LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
1046		} else {
1047			mLOG(DS_MEM, STUB, "Unimplemented DS9 LDM: %08X", address);
1048		});
1049		break;
1050	case DS_REGION_IO:
1051		LDM_LOOP(value = DS9IORead32(ds, address));
1052		break;
1053	case DS_REGION_VRAM:
1054		LDM_LOOP(unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
1055		value = 0;
1056		int i = 0;
1057		for (i = 0; i < 9; ++i) {
1058			if (mask & (1 << i)) {
1059				uint32_t newValue;
1060				LOAD_32(newValue, address & _vramMask[i], memory->vramBank[i]);
1061				value |= newValue;
1062			}
1063		});
1064		break;
1065	default:
1066		LDM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1067			LOAD_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1068		} else {
1069			mLOG(DS_MEM, STUB, "Unimplemented DS9 LDM: %08X", address);
1070		});
1071		break;
1072	}
1073
1074	if (cycleCounter) {
1075		++wait;
1076		*cycleCounter += wait;
1077	}
1078
1079	if (direction & LSM_B) {
1080		address -= offset;
1081	}
1082
1083	if (direction & LSM_D) {
1084		address -= (popcount << 2) + 4;
1085	}
1086
1087	return address | addressMisalign;
1088}
1089
1090
1091uint32_t DS9StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
1092	struct DS* ds = (struct DS*) cpu->master;
1093	struct DSMemory* memory = &ds->memory;
1094	char* ws32 = ds->ds9.memory.waitstatesNonseq32;
1095	uint32_t value;
1096	int wait = 0;
1097
1098	int i;
1099	int offset = 4;
1100	int popcount = 0;
1101	if (direction & LSM_D) {
1102		offset = -4;
1103		popcount = popcount32(mask);
1104		address -= (popcount << 2) - 4;
1105	}
1106
1107	if (direction & LSM_B) {
1108		address += offset;
1109	}
1110
1111	uint32_t addressMisalign = address & 0x3;
1112	address &= 0xFFFFFFFC;
1113
1114	switch (address >> DS_BASE_OFFSET) {
1115	case DS9_REGION_ITCM:
1116	case DS9_REGION_ITCM_MIRROR:
1117		STM_LOOP(if (address < memory->itcmSize) {
1118			STORE_32(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
1119		} else {
1120			mLOG(DS_MEM, STUB, "Bad DS9 Store32: %08X:%08X", address, value);
1121		});
1122		break;
1123	case DS_REGION_RAM:
1124		STM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1125			STORE_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1126		} else if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1127			STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
1128		} else {
1129			mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
1130		});
1131		break;
1132	case DS_REGION_VRAM:
1133		STM_LOOP(unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
1134		int i = 0;
1135		for (i = 0; i < 9; ++i) {
1136			if (mask & (1 << i)) {
1137				STORE_32(value, address & _vramMask[i], memory->vramBank[i]);
1138			}
1139		});
1140		break;
1141	default:
1142		STM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1143			STORE_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1144		} else {
1145			mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
1146		});
1147		break;
1148	}
1149
1150	if (cycleCounter) {
1151		*cycleCounter += wait;
1152	}
1153
1154	if (direction & LSM_B) {
1155		address -= offset;
1156	}
1157
1158	if (direction & LSM_D) {
1159		address -= (popcount << 2) + 4;
1160	}
1161
1162	return address | addressMisalign;
1163}
1164
1165int32_t DSMemoryStall(struct ARMCore* cpu, int32_t wait) {
1166	return wait;
1167}
1168
1169static unsigned _selectVRAM(struct DSMemory* memory, uint32_t offset) {
1170	unsigned mask = 0;
1171	offset &= 0x3FF;
1172	mask |= memory->vramMirror[0][offset & 0x3F] & memory->vramMode[0][offset >> 7];
1173	mask |= memory->vramMirror[1][offset & 0x3F] & memory->vramMode[1][offset >> 7];
1174	mask |= memory->vramMirror[2][offset & 0x3F] & memory->vramMode[2][offset >> 7];
1175	mask |= memory->vramMirror[3][offset & 0x3F] & memory->vramMode[3][offset >> 7];
1176	mask |= memory->vramMirror[4][offset & 0x3F] & memory->vramMode[4][offset >> 7];
1177	mask |= memory->vramMirror[5][offset & 0x3F] & memory->vramMode[5][offset >> 7];
1178	mask |= memory->vramMirror[6][offset & 0x3F] & memory->vramMode[6][offset >> 7];
1179	mask |= memory->vramMirror[7][offset & 0x3F] & memory->vramMode[7][offset >> 7];
1180	mask |= memory->vramMirror[8][offset & 0x3F] & memory->vramMode[8][offset >> 7];
1181	return mask;
1182}