all repos — mgba @ 0bdf30f650b219c7f17b9a015f63c5cb681a2399

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", "ds.memory");
  16
  17static uint32_t _deadbeef[1] = { 0xE710B710 }; // Illegal instruction on both ARM and Thumb
  18const uint32_t redzoneInstruction = 0xE7F0DEF0;
  19
  20static const uint32_t _vramMask[9] = {
  21	0x1FFFF,
  22	0x1FFFF,
  23	0x1FFFF,
  24	0x1FFFF,
  25	0x0FFFF,
  26	0x03FFF,
  27	0x03FFF,
  28	0x07FFF,
  29	0x03FFF
  30};
  31
  32static void DS7SetActiveRegion(struct ARMCore* cpu, uint32_t region);
  33static void DS9SetActiveRegion(struct ARMCore* cpu, uint32_t region);
  34static int32_t DSMemoryStall(struct ARMCore* cpu, int32_t wait);
  35
  36static unsigned _selectVRAM(struct DSMemory* memory, uint32_t offset);
  37
  38static const char DS7_BASE_WAITSTATES[16] =        { 0, 0, 8, 0, 0, 0, 0, 0 };
  39static const char DS7_BASE_WAITSTATES_32[16] =     { 0, 0, 9, 0, 0, 1, 1, 0 };
  40static const char DS7_BASE_WAITSTATES_SEQ[16] =    { 0, 0, 1, 0, 0, 0, 0, 0 };
  41static const char DS7_BASE_WAITSTATES_SEQ_32[16] = { 0, 0, 2, 0, 0, 1, 1, 0 };
  42
  43static const char DS9_BASE_WAITSTATES[16] =        { 0, 0, 2, 6, 6, 7, 7, 6 };
  44static const char DS9_BASE_WAITSTATES_32[16] =     { 0, 0, 2, 6, 6, 9, 9, 6 };
  45static const char DS9_BASE_WAITSTATES_SEQ[16] =    { 0, 0, 1, 1, 1, 2, 2, 1 };
  46static const char DS9_BASE_WAITSTATES_SEQ_32[16] = { 0, 0, 1, 1, 1, 4, 4, 1 };
  47
  48void DSMemoryInit(struct DS* ds) {
  49	struct ARMCore* arm7 = ds->ds7.cpu;
  50	arm7->memory.load32 = DS7Load32;
  51	arm7->memory.load16 = DS7Load16;
  52	arm7->memory.load8 = DS7Load8;
  53	arm7->memory.loadMultiple = DS7LoadMultiple;
  54	arm7->memory.store32 = DS7Store32;
  55	arm7->memory.store16 = DS7Store16;
  56	arm7->memory.store8 = DS7Store8;
  57	arm7->memory.storeMultiple = DS7StoreMultiple;
  58	arm7->memory.stall = DSMemoryStall;
  59
  60	struct ARMCore* arm9 = ds->ds9.cpu;
  61	arm9->memory.load32 = DS9Load32;
  62	arm9->memory.load16 = DS9Load16;
  63	arm9->memory.load8 = DS9Load8;
  64	arm9->memory.loadMultiple = DS9LoadMultiple;
  65	arm9->memory.store32 = DS9Store32;
  66	arm9->memory.store16 = DS9Store16;
  67	arm9->memory.store8 = DS9Store8;
  68	arm9->memory.storeMultiple = DS9StoreMultiple;
  69	arm9->memory.stall = DSMemoryStall;
  70
  71	int i;
  72	for (i = 0; i < 8; ++i) {
  73		// TODO: Formalize
  74		ds->ds7.memory.waitstatesNonseq16[i] = DS7_BASE_WAITSTATES[i];
  75		ds->ds7.memory.waitstatesSeq16[i] = DS7_BASE_WAITSTATES_SEQ[i];
  76		ds->ds7.memory.waitstatesPrefetchNonseq16[i] = DS7_BASE_WAITSTATES[i];
  77		ds->ds7.memory.waitstatesPrefetchSeq16[i] = DS7_BASE_WAITSTATES_SEQ[i];
  78		ds->ds7.memory.waitstatesNonseq32[i] = DS7_BASE_WAITSTATES_32[i];
  79		ds->ds7.memory.waitstatesSeq32[i] = DS7_BASE_WAITSTATES_SEQ_32[i];
  80		ds->ds7.memory.waitstatesPrefetchNonseq32[i] = DS7_BASE_WAITSTATES_32[i];
  81		ds->ds7.memory.waitstatesPrefetchSeq32[i] = DS7_BASE_WAITSTATES_SEQ_32[i];
  82
  83		ds->ds9.memory.waitstatesNonseq16[i] = DS9_BASE_WAITSTATES[i];
  84		ds->ds9.memory.waitstatesSeq16[i] = DS9_BASE_WAITSTATES_SEQ[i];
  85		ds->ds9.memory.waitstatesPrefetchNonseq16[i] = DS9_BASE_WAITSTATES[i];
  86		ds->ds9.memory.waitstatesPrefetchSeq16[i] = DS9_BASE_WAITSTATES[i];
  87		ds->ds9.memory.waitstatesNonseq32[i] = DS9_BASE_WAITSTATES_32[i];
  88		ds->ds9.memory.waitstatesSeq32[i] = DS9_BASE_WAITSTATES_SEQ_32[i];
  89		ds->ds9.memory.waitstatesPrefetchNonseq32[i] = DS9_BASE_WAITSTATES_32[i];
  90		ds->ds9.memory.waitstatesPrefetchSeq32[i] = DS9_BASE_WAITSTATES_32[i];
  91	}
  92
  93	ds->ds9.memory.waitstatesPrefetchNonseq16[2] = 0;
  94	ds->ds9.memory.waitstatesPrefetchSeq16[2] = 0;
  95	ds->ds9.memory.waitstatesPrefetchNonseq32[2] = 0;
  96	ds->ds9.memory.waitstatesPrefetchSeq32[2] = 0;
  97
  98	for (; i < 256; ++i) {
  99		ds->ds7.memory.waitstatesNonseq16[i] = 0;
 100		ds->ds7.memory.waitstatesSeq16[i] = 0;
 101		ds->ds7.memory.waitstatesNonseq32[i] = 0;
 102		ds->ds7.memory.waitstatesSeq32[i] = 0;
 103
 104		ds->ds9.memory.waitstatesNonseq16[i] = 0;
 105		ds->ds9.memory.waitstatesSeq16[i] = 0;
 106		ds->ds9.memory.waitstatesNonseq32[i] = 0;
 107		ds->ds9.memory.waitstatesSeq32[i] = 0;
 108	}
 109
 110	ds->memory.bios7 = NULL;
 111	ds->memory.bios9 = NULL;
 112	ds->memory.wramBase = NULL;
 113	ds->memory.wram7 = NULL;
 114	ds->memory.ram = NULL;
 115	ds->memory.itcm = NULL;
 116	ds->memory.dtcm = NULL;
 117	ds->memory.rom = NULL;
 118
 119	ds->ds7.memory.activeRegion = -1;
 120	ds->ds9.memory.activeRegion = -1;
 121	ds->ds7.memory.io = ds->memory.io7;
 122	ds->ds9.memory.io = ds->memory.io9;
 123
 124	arm7->memory.activeRegion = 0;
 125	arm7->memory.activeMask = 0;
 126	arm7->memory.setActiveRegion = DS7SetActiveRegion;
 127	arm7->memory.activeSeqCycles32 = 0;
 128	arm7->memory.activeSeqCycles16 = 0;
 129	arm7->memory.activeNonseqCycles32 = 0;
 130	arm7->memory.activeNonseqCycles16 = 0;
 131
 132	arm9->memory.activeRegion = 0;
 133	arm9->memory.activeMask = 0;
 134	arm9->memory.setActiveRegion = DS9SetActiveRegion;
 135	arm9->memory.activeSeqCycles32 = 0;
 136	arm9->memory.activeSeqCycles16 = 0;
 137	arm9->memory.activeNonseqCycles32 = 0;
 138	arm9->memory.activeNonseqCycles16 = 0;
 139}
 140
 141void DSMemoryDeinit(struct DS* ds) {
 142	mappedMemoryFree(ds->memory.wram, DS_SIZE_WORKING_RAM);
 143	mappedMemoryFree(ds->memory.wram7, DS7_SIZE_WORKING_RAM);
 144	mappedMemoryFree(ds->memory.ram, DS_SIZE_RAM);
 145	mappedMemoryFree(ds->memory.itcm, DS9_SIZE_ITCM);
 146	mappedMemoryFree(ds->memory.dtcm, DS9_SIZE_DTCM);
 147}
 148
 149void DSMemoryReset(struct DS* ds) {
 150	if (ds->memory.wram) {
 151		mappedMemoryFree(ds->memory.wramBase, DS_SIZE_WORKING_RAM * 2 + 12);
 152	}
 153	// XXX: This hack lets you roll over the end of the WRAM block without
 154	// looping back to the beginning. It works by placing an undefined
 155	// instruction in a redzone at the very beginning and end of the buffer.
 156	// Using clever masking tricks, the ARM loop will mask the offset so that
 157	// either the middle of the passed-in buffer is the actual buffer, and
 158	// when the loop rolls over, it hits the redzone at the beginning, or the
 159	// start of the passed-in buffer matches the actual buffer, causing the
 160	// redzone at the end to be hit. This requires a lot of dead space in
 161	// the middle, and a fake (too large) mask, but it is very fast.
 162	ds->memory.wram = anonymousMemoryMap(DS_SIZE_WORKING_RAM * 2 + 12);
 163	ds->memory.wram[0] = redzoneInstruction;
 164	ds->memory.wram[1] = redzoneInstruction;
 165	ds->memory.wram[2] = redzoneInstruction;
 166	ds->memory.wram[DS_SIZE_WORKING_RAM >> 1] = redzoneInstruction;
 167	ds->memory.wram[(DS_SIZE_WORKING_RAM >> 1) + 1] = redzoneInstruction;
 168	ds->memory.wram[(DS_SIZE_WORKING_RAM >> 1) + 2] = redzoneInstruction;
 169	ds->memory.wramBase = &ds->memory.wram[DS_SIZE_WORKING_RAM >> 2];
 170
 171	if (ds->memory.wram7) {
 172		mappedMemoryFree(ds->memory.wram7, DS7_SIZE_WORKING_RAM);
 173	}
 174	ds->memory.wram7 = anonymousMemoryMap(DS7_SIZE_WORKING_RAM);
 175
 176	if (ds->memory.ram) {
 177		mappedMemoryFree(ds->memory.ram, DS_SIZE_RAM);
 178	}
 179	ds->memory.ram = anonymousMemoryMap(DS_SIZE_RAM);
 180
 181	if (ds->memory.itcm) {
 182		mappedMemoryFree(ds->memory.itcm, DS9_SIZE_ITCM);
 183	}
 184	ds->memory.itcm = anonymousMemoryMap(DS9_SIZE_ITCM);
 185
 186	if (ds->memory.dtcm) {
 187		mappedMemoryFree(ds->memory.dtcm, DS9_SIZE_DTCM);
 188	}
 189	ds->memory.dtcm = anonymousMemoryMap(DS9_SIZE_DTCM);
 190
 191	memset(ds->ds7.memory.dma, 0, sizeof(ds->ds7.memory.dma));
 192	memset(ds->ds9.memory.dma, 0, sizeof(ds->ds9.memory.dma));
 193	ds->ds7.memory.activeDMA = -1;
 194	ds->ds9.memory.activeDMA = -1;
 195
 196	// TODO: Correct size
 197	ds->memory.wramSize7 = 0x8000;
 198	ds->memory.wramBase7 = ds->memory.wram;
 199	ds->memory.wramSize9 = 0;
 200	ds->memory.wramBase9 = NULL;
 201
 202	ds->memory.slot1Owner = true;
 203	ds->memory.slot2Owner = true;
 204	ds->memory.slot1.savedataType = DS_SAVEDATA_AUTODETECT;
 205	ds->ds7.memory.slot1Access = true;
 206	ds->ds9.memory.slot1Access = false;
 207
 208	DSSPIReset(ds);
 209	DSSlot1Reset(ds);
 210
 211	DSVideoConfigureVRAM(ds, 0, 0, 1);
 212	DSVideoConfigureVRAM(ds, 1, 0, 1);
 213	DSVideoConfigureVRAM(ds, 2, 0, 1);
 214	DSVideoConfigureVRAM(ds, 3, 0, 1);
 215	DSVideoConfigureVRAM(ds, 4, 0, 1);
 216	DSVideoConfigureVRAM(ds, 5, 0, 1);
 217	DSVideoConfigureVRAM(ds, 6, 0, 1);
 218	DSVideoConfigureVRAM(ds, 7, 0, 1);
 219	DSVideoConfigureVRAM(ds, 8, 0, 1);
 220	DSConfigureWRAM(&ds->memory, 3);
 221
 222	if (!ds->memory.wram || !ds->memory.wram7 || !ds->memory.ram || !ds->memory.itcm || !ds->memory.dtcm) {
 223		DSMemoryDeinit(ds);
 224		mLOG(DS_MEM, FATAL, "Could not map memory");
 225	}
 226}
 227
 228static void DS7SetActiveRegion(struct ARMCore* cpu, uint32_t address) {
 229	struct DS* ds = (struct DS*) cpu->master;
 230	struct DSCoreMemory* memory = &ds->ds7.memory;
 231
 232	int newRegion = address >> DS_BASE_OFFSET;
 233
 234	memory->activeRegion = newRegion;
 235	switch (newRegion) {
 236	case DS_REGION_WORKING_RAM:
 237		if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
 238			cpu->memory.activeRegion = ds->memory.wram7;
 239			cpu->memory.activeMask = DS7_SIZE_WORKING_RAM - 1;
 240		} else if (ds->memory.wramSize7 == DS_SIZE_WORKING_RAM) {
 241			if (address & DS_SIZE_WORKING_RAM) {
 242				cpu->memory.activeRegion = ds->memory.wram;
 243			} else {
 244				cpu->memory.activeRegion = ds->memory.wramBase;
 245			}
 246			cpu->memory.activeMask = (ds->memory.wramSize7 << 1) - 1;
 247		} else {
 248			cpu->memory.activeRegion = ds->memory.wramBase;
 249			cpu->memory.activeMask = (ds->memory.wramSize7 - 1);
 250		}
 251		break;
 252	case DS7_REGION_BIOS:
 253		if (ds->memory.bios7) {
 254			cpu->memory.activeRegion = ds->memory.bios7;
 255			cpu->memory.activeMask = DS9_SIZE_BIOS - 1;
 256		} else {
 257			cpu->memory.activeRegion = _deadbeef;
 258			cpu->memory.activeMask = 0;
 259		}
 260		break;
 261	case DS_REGION_RAM:
 262		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
 263			cpu->memory.activeRegion = ds->memory.ram;
 264			cpu->memory.activeMask = DS_SIZE_RAM - 1;
 265			break;
 266		}
 267		goto jump_error;
 268	case DS_REGION_VRAM:
 269		if (address < 0x06040000 && ds->memory.vram7[(address & 0x3FFFF) >> 17]) {
 270			// TODO: redzones
 271			cpu->memory.activeRegion = (uint32_t*) ds->memory.vram7[(address & 0x3FFFF) >> 17];
 272			cpu->memory.activeMask = 0x1FFFF;
 273			break;
 274		}
 275		// Fall through
 276	default:
 277	jump_error:
 278		memory->activeRegion = -1;
 279		cpu->memory.activeRegion = _deadbeef;
 280		cpu->memory.activeMask = 0;
 281		mLOG(DS_MEM, FATAL, "Jumped to invalid address: %08X", address);
 282		break;
 283	}
 284	cpu->memory.activeSeqCycles32 = memory->waitstatesPrefetchSeq32[memory->activeRegion];
 285	cpu->memory.activeSeqCycles16 = memory->waitstatesPrefetchSeq16[memory->activeRegion];
 286	cpu->memory.activeNonseqCycles32 = memory->waitstatesPrefetchNonseq32[memory->activeRegion];
 287	cpu->memory.activeNonseqCycles16 = memory->waitstatesPrefetchNonseq16[memory->activeRegion];
 288}
 289
 290uint32_t DS7Load32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
 291	struct DS* ds = (struct DS*) cpu->master;
 292	struct DSMemory* memory = &ds->memory;
 293	uint32_t value = 0;
 294	int wait = ds->ds7.memory.waitstatesNonseq32[address >> DS_BASE_OFFSET];
 295
 296	switch (address >> DS_BASE_OFFSET) {
 297	case DS7_REGION_BIOS:
 298		LOAD_32(value, address & (DS7_SIZE_BIOS - 4), memory->bios7);
 299		break;
 300	case DS_REGION_WORKING_RAM:
 301		if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
 302			LOAD_32(value, address & (DS7_SIZE_WORKING_RAM - 4), memory->wram7);
 303		} else {
 304			LOAD_32(value, address & (ds->memory.wramSize7 - 4), memory->wramBase7);
 305		}
 306		break;
 307	case DS_REGION_RAM:
 308		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
 309			LOAD_32(value, address & (DS_SIZE_RAM - 4), memory->ram);
 310			break;
 311		}
 312		mLOG(DS_MEM, STUB, "Unimplemented DS7 Load32: %08X", address);
 313		break;
 314	case DS_REGION_IO:
 315		value = DS7IORead32(ds, address & 0x00FFFFFC);
 316		break;
 317	case DS_REGION_SLOT2:
 318	case DS_REGION_SLOT2_EX:
 319	case DS_REGION_SLOT2_SRAM:
 320		value = 0xFFFFFFFF;
 321		break;
 322	case DS_REGION_VRAM:
 323		if (address < 0x06040000 && memory->vram7[(address & 0x3FFFF) >> 17]) {
 324			LOAD_32(value, address & 0x1FFFC, memory->vram7[(address & 0x3FFFF) >> 17]);
 325			break;
 326		}
 327		// Fall through
 328	default:
 329		mLOG(DS_MEM, STUB, "Unimplemented DS7 Load32: %08X", address);
 330		break;
 331	}
 332
 333	if (cycleCounter) {
 334		wait += 2;
 335		*cycleCounter += wait;
 336	}
 337	// Unaligned 32-bit loads are "rotated" so they make some semblance of sense
 338	int rotate = (address & 3) << 3;
 339	return ROR(value, rotate);
 340}
 341
 342uint32_t DS7Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
 343	struct DS* ds = (struct DS*) cpu->master;
 344	struct DSMemory* memory = &ds->memory;
 345	uint32_t value = 0;
 346	int wait = ds->ds7.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
 347
 348	switch (address >> DS_BASE_OFFSET) {
 349	case DS7_REGION_BIOS:
 350		LOAD_16(value, address & (DS7_SIZE_BIOS - 2), memory->bios7);
 351		break;
 352	case DS_REGION_WORKING_RAM:
 353		if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
 354			LOAD_16(value, address & (DS7_SIZE_WORKING_RAM - 2), memory->wram7);
 355		} else {
 356			LOAD_16(value, address & (ds->memory.wramSize7 - 2), memory->wramBase7);
 357		}
 358		break;
 359	case DS_REGION_RAM:
 360		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
 361			LOAD_16(value, address & (DS_SIZE_RAM - 1), memory->ram);
 362			break;
 363		}
 364		mLOG(DS_MEM, STUB, "Unimplemented DS7 Load16: %08X", address);
 365	case DS_REGION_IO:
 366		value = DS7IORead(ds, address & DS_OFFSET_MASK);
 367		break;
 368	case DS_REGION_SLOT2:
 369	case DS_REGION_SLOT2_EX:
 370	case DS_REGION_SLOT2_SRAM:
 371		value = 0xFFFF;
 372		break;
 373	case DS_REGION_VRAM:
 374		if (address < 0x06040000 && memory->vram7[(address & 0x3FFFF) >> 17]) {
 375			LOAD_16(value, address & 0x1FFFE, memory->vram7[(address & 0x3FFFF) >> 17]);
 376			break;
 377		}
 378		// Fall through
 379	default:
 380		mLOG(DS_MEM, STUB, "Unimplemented DS7 Load16: %08X", address);
 381		break;
 382	}
 383
 384	if (cycleCounter) {
 385		wait += 2;
 386		*cycleCounter += wait;
 387	}
 388	// Unaligned 16-bit loads are "unpredictable", TODO: See what DS does
 389	int rotate = (address & 1) << 3;
 390	return ROR(value, rotate);
 391}
 392
 393uint32_t DS7Load8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
 394	struct DS* ds = (struct DS*) cpu->master;
 395	struct DSMemory* memory = &ds->memory;
 396	uint32_t value = 0;
 397	int wait = ds->ds7.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
 398
 399	switch (address >> DS_BASE_OFFSET) {
 400	case DS7_REGION_BIOS:
 401		value = ((uint8_t*) memory->bios7)[address & (DS7_SIZE_BIOS - 1)];
 402		break;
 403	case DS_REGION_WORKING_RAM:
 404		if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
 405			value = ((uint8_t*) memory->wram7)[address & (DS7_SIZE_WORKING_RAM - 1)];
 406		} else {
 407			value = ((uint8_t*) memory->wramBase7)[address & (ds->memory.wramSize7 - 1)];
 408		}
 409		break;
 410	case DS_REGION_RAM:
 411		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
 412			value = ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)];
 413			break;
 414		}
 415		mLOG(DS_MEM, STUB, "Unimplemented DS7 Load8: %08X", address);
 416		break;
 417	case DS_REGION_IO:
 418		value = (DS7IORead(ds, address & 0xFFFE) >> ((address & 0x0001) << 3)) & 0xFF;
 419		break;
 420	case DS_REGION_SLOT2:
 421	case DS_REGION_SLOT2_EX:
 422	case DS_REGION_SLOT2_SRAM:
 423		value = 0xFF;
 424		break;
 425	default:
 426		mLOG(DS_MEM, STUB, "Unimplemented DS7 Load8: %08X", address);
 427		break;
 428	}
 429
 430	if (cycleCounter) {
 431		wait += 2;
 432		*cycleCounter += wait;
 433	}
 434	return value;
 435}
 436
 437void DS7Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) {
 438	struct DS* ds = (struct DS*) cpu->master;
 439	struct DSMemory* memory = &ds->memory;
 440	int wait = ds->ds7.memory.waitstatesNonseq32[address >> DS_BASE_OFFSET];
 441
 442	switch (address >> DS_BASE_OFFSET) {
 443	case DS_REGION_WORKING_RAM:
 444		if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
 445			STORE_32(value, address & (DS7_SIZE_WORKING_RAM - 4), memory->wram7);
 446		} else {
 447			STORE_32(value, address & (ds->memory.wramSize7 - 4), memory->wramBase7);
 448		}
 449		break;
 450	case DS_REGION_RAM:
 451		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
 452			STORE_32(value, address & (DS_SIZE_RAM - 4), memory->ram);
 453			break;
 454		}
 455		mLOG(DS_MEM, STUB, "Unimplemented DS7 Store32: %08X:%08X", address, value);
 456		break;
 457	case DS_REGION_IO:
 458		DS7IOWrite32(ds, address & DS_OFFSET_MASK, value);
 459		break;
 460	case DS_REGION_VRAM:
 461		if (address < 0x06040000 && memory->vram7[(address & 0x3FFFF) >> 17]) {
 462			STORE_32(value, address & 0x1FFFC, memory->vram7[(address & 0x3FFFF) >> 17]);
 463			break;
 464		}
 465		// Fall through
 466	default:
 467		mLOG(DS_MEM, STUB, "Unimplemented DS7 Store32: %08X:%08X", address, value);
 468		break;
 469	}
 470
 471	if (cycleCounter) {
 472		++wait;
 473		*cycleCounter += wait;
 474	}
 475}
 476
 477void DS7Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
 478	struct DS* ds = (struct DS*) cpu->master;
 479	struct DSMemory* memory = &ds->memory;
 480	int wait = ds->ds7.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
 481
 482	switch (address >> DS_BASE_OFFSET) {
 483	case DS_REGION_WORKING_RAM:
 484		if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
 485			STORE_16(value, address & (DS7_SIZE_WORKING_RAM - 2), memory->wram7);
 486		} else {
 487			STORE_16(value, address & (ds->memory.wramSize7 - 2), memory->wramBase7);
 488		}
 489		break;
 490	case DS_REGION_RAM:
 491		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
 492			STORE_16(value, address & (DS_SIZE_RAM - 2), memory->ram);
 493			break;
 494		}
 495		mLOG(DS_MEM, STUB, "Unimplemented DS7 Store16: %08X:%04X", address, value);
 496		break;
 497	case DS_REGION_IO:
 498		DS7IOWrite(ds, address & DS_OFFSET_MASK, value);
 499		break;
 500	case DS_REGION_VRAM:
 501		if (address < 0x06040000 && memory->vram7[(address & 0x3FFFF) >> 17]) {
 502			STORE_16(value, address & 0x1FFFE, memory->vram7[(address & 0x3FFFF) >> 17]);
 503			break;
 504		}
 505		// Fall through
 506	default:
 507		mLOG(DS_MEM, STUB, "Unimplemented DS7 Store16: %08X:%04X", address, value);
 508		break;
 509	}
 510
 511	if (cycleCounter) {
 512		++wait;
 513		*cycleCounter += wait;
 514	}
 515}
 516
 517void DS7Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
 518	struct DS* ds = (struct DS*) cpu->master;
 519	struct DSMemory* memory = &ds->memory;
 520	int wait = ds->ds7.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
 521
 522	switch (address >> DS_BASE_OFFSET) {
 523	case DS_REGION_WORKING_RAM:
 524		if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
 525			((uint8_t*) memory->wram7)[address & (DS7_SIZE_WORKING_RAM - 1)] = value;
 526		} else {
 527			((uint8_t*) memory->wramBase7)[address & (ds->memory.wramSize7 - 1)] = value;
 528		}
 529		break;
 530	case DS_REGION_RAM:
 531		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
 532			((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)] = value;
 533			break;
 534		}
 535		mLOG(DS_MEM, STUB, "Unimplemented DS7 Store8: %08X:%02X", address, value);
 536	case DS_REGION_IO:
 537		DS7IOWrite8(ds, address & DS_OFFSET_MASK, value);
 538		break;
 539	default:
 540		mLOG(DS_MEM, STUB, "Unimplemented DS7 Store8: %08X:%02X", address, value);
 541		break;
 542	}
 543
 544	if (cycleCounter) {
 545		++wait;
 546		*cycleCounter += wait;
 547	}
 548}
 549
 550#define LDM_LOOP(LDM) \
 551	for (i = 0; i < 16; i += 4) { \
 552		if (UNLIKELY(mask & (1 << i))) { \
 553			LDM; \
 554			cpu->gprs[i] = value; \
 555			++wait; \
 556			wait += ws32[address >> DS_BASE_OFFSET]; \
 557			address += 4; \
 558		} \
 559		if (UNLIKELY(mask & (2 << i))) { \
 560			LDM; \
 561			cpu->gprs[i + 1] = value; \
 562			++wait; \
 563			wait += ws32[address >> DS_BASE_OFFSET]; \
 564			address += 4; \
 565		} \
 566		if (UNLIKELY(mask & (4 << i))) { \
 567			LDM; \
 568			cpu->gprs[i + 2] = value; \
 569			++wait; \
 570			wait += ws32[address >> DS_BASE_OFFSET]; \
 571			address += 4; \
 572		} \
 573		if (UNLIKELY(mask & (8 << i))) { \
 574			LDM; \
 575			cpu->gprs[i + 3] = value; \
 576			++wait; \
 577			wait += ws32[address >> DS_BASE_OFFSET]; \
 578			address += 4; \
 579		} \
 580	}
 581
 582#define STM_LOOP(STM) \
 583	for (i = 0; i < 16; i += 4) { \
 584		if (UNLIKELY(mask & (1 << i))) { \
 585			value = cpu->gprs[i]; \
 586			STM; \
 587			++wait; \
 588			wait += ws32[address >> DS_BASE_OFFSET]; \
 589			address += 4; \
 590		} \
 591		if (UNLIKELY(mask & (2 << i))) { \
 592			value = cpu->gprs[i + 1]; \
 593			STM; \
 594			++wait; \
 595			wait += ws32[address >> DS_BASE_OFFSET]; \
 596			address += 4; \
 597		} \
 598		if (UNLIKELY(mask & (4 << i))) { \
 599			value = cpu->gprs[i + 2]; \
 600			STM; \
 601			++wait; \
 602			wait += ws32[address >> DS_BASE_OFFSET]; \
 603			address += 4; \
 604		} \
 605		if (UNLIKELY(mask & (8 << i))) { \
 606			value = cpu->gprs[i + 3]; \
 607			STM; \
 608			++wait; \
 609			wait += ws32[address >> DS_BASE_OFFSET]; \
 610			address += 4; \
 611		} \
 612	}
 613
 614uint32_t DS7LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
 615	struct DS* ds = (struct DS*) cpu->master;
 616	struct DSMemory* memory = &ds->memory;
 617	char* ws32 = ds->ds7.memory.waitstatesNonseq32;
 618	uint32_t value;
 619	int wait = 0;
 620
 621	int i;
 622	int offset = 4;
 623	int popcount = 0;
 624	if (direction & LSM_D) {
 625		offset = -4;
 626		popcount = popcount32(mask);
 627		address -= (popcount << 2) - 4;
 628	}
 629
 630	if (direction & LSM_B) {
 631		address += offset;
 632	}
 633
 634	uint32_t addressMisalign = address & 0x3;
 635	address &= 0xFFFFFFFC;
 636
 637	switch (address >> DS_BASE_OFFSET) {
 638	case DS_REGION_WORKING_RAM:
 639		LDM_LOOP(if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
 640			LOAD_32(value, address & (DS7_SIZE_WORKING_RAM - 1), memory->wram7);
 641		} else {
 642			LOAD_32(value, address & (ds->memory.wramSize7 - 1), memory->wramBase7);
 643		});
 644		break;
 645	case DS_REGION_RAM:
 646		LDM_LOOP(if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
 647			LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
 648		} else {
 649			mLOG(DS_MEM, STUB, "Unimplemented DS7 LDM: %08X", address);
 650		});
 651		break;
 652	case DS_REGION_IO:
 653		LDM_LOOP(value = DS7IORead32(ds, address));
 654		break;
 655	case DS_REGION_VRAM:
 656		LDM_LOOP(if (address < 0x06040000 && memory->vram7[(address & 0x3FFFF) >> 17]) {
 657			LOAD_32(value, address & 0x1FFFF, memory->vram7[(address & 0x3FFFF) >> 17]);
 658		} else {
 659			mLOG(DS_MEM, STUB, "Unimplemented DS7 LDM: %08X", address);
 660		});
 661		break;
 662	default:
 663		mLOG(DS_MEM, STUB, "Unimplemented DS7 LDM: %08X", address);
 664		LDM_LOOP(value = 0);
 665	}
 666
 667	if (cycleCounter) {
 668		++wait;
 669		*cycleCounter += wait;
 670	}
 671
 672	if (direction & LSM_B) {
 673		address -= offset;
 674	}
 675
 676	if (direction & LSM_D) {
 677		address -= (popcount << 2) + 4;
 678	}
 679
 680	return address | addressMisalign;
 681}
 682
 683uint32_t DS7StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
 684	struct DS* ds = (struct DS*) cpu->master;
 685	struct DSMemory* memory = &ds->memory;
 686	char* ws32 = ds->ds7.memory.waitstatesNonseq32;
 687	uint32_t value;
 688	int wait = 0;
 689
 690	int i;
 691	int offset = 4;
 692	int popcount = 0;
 693	if (direction & LSM_D) {
 694		offset = -4;
 695		popcount = popcount32(mask);
 696		address -= (popcount << 2) - 4;
 697	}
 698
 699	if (direction & LSM_B) {
 700		address += offset;
 701	}
 702
 703	uint32_t addressMisalign = address & 0x3;
 704	address &= 0xFFFFFFFC;
 705
 706	switch (address >> DS_BASE_OFFSET) {
 707	case DS_REGION_WORKING_RAM:
 708		STM_LOOP(if (address >= DS7_BASE_WORKING_RAM || !ds->memory.wramSize7) {
 709			STORE_32(value, address & (DS7_SIZE_WORKING_RAM - 1), memory->wram7);
 710		} else {
 711			STORE_32(value, address & (ds->memory.wramSize7 - 1), memory->wramBase7);
 712		});
 713		break;
 714	case DS_REGION_RAM:
 715		STM_LOOP(if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
 716			STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
 717		} else {
 718			mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
 719		});
 720		break;
 721	case DS_REGION_IO:
 722		STM_LOOP(DS7IOWrite32(ds, address & DS_OFFSET_MASK, value));
 723		break;
 724	case DS_REGION_VRAM:
 725		STM_LOOP(if (address < 0x06040000 && memory->vram7[(address & 0x3FFFF) >> 17]) {
 726			STORE_32(value, address & 0x1FFFF, memory->vram7[(address & 0x3FFFF) >> 17]);
 727		} else {
 728			mLOG(DS_MEM, STUB, "Unimplemented DS7 STM: %08X", address);
 729		});
 730		break;
 731	default:
 732		mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
 733		STM_LOOP();
 734		break;
 735	}
 736
 737	if (cycleCounter) {
 738		*cycleCounter += wait;
 739	}
 740
 741	if (direction & LSM_B) {
 742		address -= offset;
 743	}
 744
 745	if (direction & LSM_D) {
 746		address -= (popcount << 2) + 4;
 747	}
 748
 749	return address | addressMisalign;
 750}
 751
 752static void DS9SetActiveRegion(struct ARMCore* cpu, uint32_t address) {
 753	struct DS* ds = (struct DS*) cpu->master;
 754	struct DSCoreMemory* memory = &ds->ds9.memory;
 755
 756	int newRegion = address >> DS_BASE_OFFSET;
 757
 758	memory->activeRegion = newRegion;
 759	switch (newRegion) {
 760	case DS9_REGION_ITCM:
 761	case DS9_REGION_ITCM_MIRROR:
 762		if (address < ds->memory.itcmSize) {
 763			cpu->memory.activeRegion = ds->memory.itcm;
 764			cpu->memory.activeMask = DS9_SIZE_ITCM - 1;
 765			break;
 766		}
 767		goto jump_error;
 768	case DS_REGION_RAM:
 769		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
 770			cpu->memory.activeRegion = ds->memory.ram;
 771			cpu->memory.activeMask = DS_SIZE_RAM - 1;
 772			break;
 773		}
 774		goto jump_error;
 775	case DS9_REGION_BIOS:
 776		// TODO: Mask properly
 777		if (ds->memory.bios9) {
 778			cpu->memory.activeRegion = ds->memory.bios9;
 779			cpu->memory.activeMask = DS9_SIZE_BIOS - 1;
 780		} else {
 781			cpu->memory.activeRegion = _deadbeef;
 782			cpu->memory.activeMask = 0;
 783		}
 784		cpu->memory.activeSeqCycles32 = 0;
 785		cpu->memory.activeSeqCycles16 = 0;
 786		cpu->memory.activeNonseqCycles32 = 0;
 787		cpu->memory.activeNonseqCycles16 = 0;
 788		return;
 789	case DS_REGION_VRAM:
 790		if (address >= 0x06800000) {
 791			unsigned mask = _selectVRAM(&ds->memory, address >> DS_VRAM_OFFSET);
 792			if (mask) {
 793				int i = 0;
 794				for (i = 0; i < 9; ++i) {
 795					if (mask & (1 << i)) {
 796						cpu->memory.activeRegion = (uint32_t*) ds->memory.vramBank[i];
 797						cpu->memory.activeMask = _vramMask[i];
 798						break;
 799					}
 800				}
 801				break;
 802			}
 803		}
 804		// Fall through
 805	default:
 806	jump_error:
 807		memory->activeRegion = -1;
 808		cpu->memory.activeRegion = _deadbeef;
 809		cpu->memory.activeMask = 0;
 810		mLOG(DS_MEM, FATAL, "Jumped to invalid address: %08X", address);
 811		return;
 812	}
 813	cpu->memory.activeSeqCycles32 = memory->waitstatesPrefetchSeq32[memory->activeRegion];
 814	cpu->memory.activeSeqCycles16 = memory->waitstatesPrefetchSeq16[memory->activeRegion];
 815	cpu->memory.activeNonseqCycles32 = memory->waitstatesPrefetchNonseq32[memory->activeRegion];
 816	cpu->memory.activeNonseqCycles16 = memory->waitstatesPrefetchNonseq16[memory->activeRegion];
 817}
 818
 819uint32_t DS9Load32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
 820	struct DS* ds = (struct DS*) cpu->master;
 821	struct DSMemory* memory = &ds->memory;
 822	uint32_t value = 0;
 823	int wait = ds->ds9.memory.waitstatesNonseq32[address >> DS_BASE_OFFSET];
 824
 825	switch (address >> DS_BASE_OFFSET) {
 826	case DS9_REGION_ITCM:
 827	case DS9_REGION_ITCM_MIRROR:
 828		if (address < memory->itcmSize) {
 829			LOAD_32(value, address & (DS9_SIZE_ITCM - 4), memory->itcm);
 830			break;
 831		}
 832		mLOG(DS_MEM, STUB, "Bad DS9 Load32: %08X", address);
 833		break;
 834	case DS_REGION_WORKING_RAM:
 835		if (ds->memory.wramSize9) {
 836			LOAD_32(value, address & (ds->memory.wramSize9 - 4), memory->wramBase9);
 837			break;
 838		}
 839		mLOG(DS_MEM, STUB, "Bad DS9 Load32: %08X", address);
 840		break;
 841	case DS_REGION_RAM:
 842		if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
 843			LOAD_32(value, address & (DS9_SIZE_DTCM - 4), memory->dtcm);
 844			break;
 845		}
 846		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
 847			LOAD_32(value, address & (DS_SIZE_RAM - 4), memory->ram);
 848			break;
 849		}
 850		mLOG(DS_MEM, STUB, "Unimplemented DS9 Load32: %08X", address);
 851		break;
 852	case DS_REGION_IO:
 853		value = DS9IORead32(ds, address & 0x00FFFFFC);
 854		break;
 855	case DS9_REGION_PALETTE_RAM:
 856		LOAD_32(value, address & (DS9_SIZE_PALETTE_RAM - 4), ds->video.palette);
 857		break;
 858	case DS_REGION_VRAM: {
 859		unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
 860		int i = 0;
 861		for (i = 0; i < 9; ++i) {
 862			if (mask & (1 << i)) {
 863				uint32_t newValue;
 864				LOAD_32(newValue, address & _vramMask[i], memory->vramBank[i]);
 865				value |= newValue;
 866			}
 867		}
 868		break;
 869	}
 870	case DS9_REGION_OAM:
 871		LOAD_32(value, address & (DS9_SIZE_OAM - 4), ds->video.oam.raw);
 872		break;
 873	case DS_REGION_SLOT2:
 874	case DS_REGION_SLOT2_EX:
 875	case DS_REGION_SLOT2_SRAM:
 876		value = 0xFFFFFFFF;
 877		break;
 878	case DS9_REGION_BIOS:
 879		// TODO: Fix undersized BIOS
 880		// TODO: Fix masking
 881		LOAD_32(value, address & (DS9_SIZE_BIOS - 4), memory->bios9);
 882		break;
 883	default:
 884		if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
 885			LOAD_32(value, address & (DS9_SIZE_DTCM - 4), memory->dtcm);
 886			break;
 887		}
 888		mLOG(DS_MEM, STUB, "Unimplemented DS9 Load32: %08X", address);
 889		break;
 890	}
 891
 892	if (cycleCounter) {
 893		wait += 2;
 894		*cycleCounter += wait;
 895	}
 896	// Unaligned 32-bit loads are "rotated" so they make some semblance of sense
 897	int rotate = (address & 3) << 3;
 898	return ROR(value, rotate);
 899}
 900
 901uint32_t DS9Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
 902	struct DS* ds = (struct DS*) cpu->master;
 903	struct DSMemory* memory = &ds->memory;
 904	uint32_t value = 0;
 905	int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
 906
 907	switch (address >> DS_BASE_OFFSET) {
 908	case DS9_REGION_ITCM:
 909	case DS9_REGION_ITCM_MIRROR:
 910		if (address < memory->itcmSize) {
 911			LOAD_16(value, address & (DS9_SIZE_ITCM - 2), memory->itcm);
 912			break;
 913		}
 914		mLOG(DS_MEM, STUB, "Bad DS9 Load16: %08X", address);
 915		break;
 916	case DS_REGION_WORKING_RAM:
 917		if (ds->memory.wramSize9) {
 918			LOAD_16(value, address & (ds->memory.wramSize9 - 2), memory->wramBase9);
 919			break;
 920		}
 921		mLOG(DS_MEM, STUB, "Bad DS9 Load16: %08X", address);
 922		break;
 923	case DS_REGION_RAM:
 924		if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
 925			LOAD_16(value, address & (DS9_SIZE_DTCM - 2), memory->dtcm);
 926			break;
 927		}
 928		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
 929			LOAD_16(value, address & (DS_SIZE_RAM - 2), memory->ram);
 930			break;
 931		}
 932		mLOG(DS_MEM, STUB, "Unimplemented DS9 Load16: %08X", address);
 933	case DS_REGION_IO:
 934		value = DS9IORead(ds, address & DS_OFFSET_MASK);
 935		break;
 936	case DS9_REGION_PALETTE_RAM:
 937		LOAD_16(value, address & (DS9_SIZE_PALETTE_RAM - 2), ds->video.palette);
 938		break;
 939	case DS_REGION_VRAM: {
 940		unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
 941		int i = 0;
 942		for (i = 0; i < 9; ++i) {
 943			if (mask & (1 << i)) {
 944				uint32_t newValue;
 945				LOAD_16(newValue, address & _vramMask[i], memory->vramBank[i]);
 946				value |= newValue;
 947			}
 948		}
 949		break;
 950	}
 951	case DS9_REGION_OAM:
 952		LOAD_16(value, address & (DS9_SIZE_OAM - 2), ds->video.oam.raw);
 953		break;
 954	case DS_REGION_SLOT2:
 955	case DS_REGION_SLOT2_EX:
 956	case DS_REGION_SLOT2_SRAM:
 957		value = 0xFFFF;
 958		break;
 959	case DS9_REGION_BIOS:
 960		// TODO: Fix undersized BIOS
 961		// TODO: Fix masking
 962		LOAD_16(value, address & (DS9_SIZE_BIOS - 2), memory->bios9);
 963		break;
 964	default:
 965		if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
 966			LOAD_16(value, address & (DS9_SIZE_DTCM - 2), memory->dtcm);
 967			break;
 968		}
 969		mLOG(DS_MEM, STUB, "Unimplemented DS9 Load16: %08X", address);
 970		break;
 971	}
 972
 973	if (cycleCounter) {
 974		wait += 2;
 975		*cycleCounter += wait;
 976	}
 977	// Unaligned 16-bit loads are "unpredictable", TODO: See what DS does
 978	int rotate = (address & 1) << 3;
 979	return ROR(value, rotate);
 980}
 981
 982uint32_t DS9Load8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
 983	struct DS* ds = (struct DS*) cpu->master;
 984	struct DSMemory* memory = &ds->memory;
 985	uint32_t value = 0;
 986	int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
 987
 988	switch (address >> DS_BASE_OFFSET) {
 989	case DS9_REGION_ITCM:
 990	case DS9_REGION_ITCM_MIRROR:
 991		if (address < memory->itcmSize) {
 992			value = ((uint8_t*) memory->itcm)[address & (DS9_SIZE_ITCM - 1)];
 993			break;
 994		}
 995		mLOG(DS_MEM, STUB, "Bad DS9 Load8: %08X", address);
 996		break;
 997	case DS_REGION_WORKING_RAM:
 998		if (ds->memory.wramSize9) {
 999			value = ((uint8_t*) memory->wramBase9)[address & (memory->wramSize9 - 1)];
1000			break;
1001		}
1002		mLOG(DS_MEM, STUB, "Bad DS9 Load8: %08X", address);
1003		break;
1004	case DS_REGION_RAM:
1005		if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1006			value = ((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)];
1007			break;
1008		}
1009		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1010			value = ((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)];
1011			break;
1012		}
1013		mLOG(DS_MEM, STUB, "Unimplemented DS9 Load8: %08X", address);
1014	case DS_REGION_IO:
1015		value = (DS9IORead(ds, address & 0xFFFE) >> ((address & 0x0001) << 3)) & 0xFF;
1016		break;
1017	case DS_REGION_VRAM: {
1018		unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
1019		int i = 0;
1020		for (i = 0; i < 9; ++i) {
1021			if (mask & (1 << i)) {
1022				value |= ((uint8_t*) memory->vramBank[i])[address & _vramMask[i]];
1023			}
1024		}
1025		break;
1026	}
1027	case DS_REGION_SLOT2:
1028	case DS_REGION_SLOT2_EX:
1029	case DS_REGION_SLOT2_SRAM:
1030		value = 0xFF;
1031		break;
1032	case DS9_REGION_BIOS:
1033		// TODO: Fix undersized BIOS
1034		// TODO: Fix masking
1035		value = ((uint8_t*) memory->bios9)[address & (DS9_SIZE_BIOS - 1)];
1036		break;
1037	default:
1038		if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1039			value = ((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)];
1040			break;
1041		}
1042		mLOG(DS_MEM, STUB, "Unimplemented DS9 Load8: %08X", address);
1043		break;
1044	}
1045
1046	if (cycleCounter) {
1047		wait += 2;
1048		*cycleCounter += wait;
1049	}
1050	return value;
1051}
1052
1053void DS9Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) {
1054	struct DS* ds = (struct DS*) cpu->master;
1055	struct DSMemory* memory = &ds->memory;
1056	int wait = ds->ds9.memory.waitstatesNonseq32[address >> DS_BASE_OFFSET];
1057
1058	switch (address >> DS_BASE_OFFSET) {
1059	case DS9_REGION_ITCM:
1060	case DS9_REGION_ITCM_MIRROR:
1061		if (address < memory->itcmSize) {
1062			STORE_32(value, address & (DS9_SIZE_ITCM - 4), memory->itcm);
1063			break;
1064		}
1065		mLOG(DS_MEM, STUB, "Bad DS9 Store32: %08X:%08X", address, value);
1066		break;
1067	case DS_REGION_WORKING_RAM:
1068		if (ds->memory.wramSize9) {
1069			STORE_32(value, address & (ds->memory.wramSize9 - 4), memory->wramBase9);
1070			break;
1071		}
1072		mLOG(DS_MEM, STUB, "Bad DS9 Store32: %08X:%08X", address, value);
1073		break;
1074	case DS_REGION_RAM:
1075		if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1076			STORE_32(value, address & (DS9_SIZE_DTCM - 4), memory->dtcm);
1077			break;
1078		}
1079		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1080			STORE_32(value, address & (DS_SIZE_RAM - 4), memory->ram);
1081			break;
1082		}
1083		mLOG(DS_MEM, STUB, "Unimplemented DS9 Store32: %08X:%08X", address, value);
1084		break;
1085	case DS_REGION_IO:
1086		DS9IOWrite32(ds, address & DS_OFFSET_MASK, value);
1087		break;
1088	case DS9_REGION_PALETTE_RAM:
1089		STORE_32(value, address & (DS9_SIZE_PALETTE_RAM - 4), ds->video.palette);
1090		ds->video.renderer->writePalette(ds->video.renderer, (address & (DS9_SIZE_PALETTE_RAM - 4)) + 2, value >> 16);
1091		ds->video.renderer->writePalette(ds->video.renderer, address & (DS9_SIZE_PALETTE_RAM - 4), value);
1092		break;
1093	case DS_REGION_VRAM: {
1094		unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
1095		int i = 0;
1096		for (i = 0; i < 9; ++i) {
1097			if (mask & (1 << i)) {
1098				STORE_32(value, address & _vramMask[i], memory->vramBank[i]);
1099			}
1100		}
1101		break;
1102	}
1103	case DS9_REGION_OAM:
1104		STORE_32(value, address & (DS9_SIZE_OAM - 4), ds->video.oam.raw);
1105		ds->video.renderer->writeOAM(ds->video.renderer, (address & (DS9_SIZE_OAM - 4)) >> 1);
1106		ds->video.renderer->writeOAM(ds->video.renderer, ((address & (DS9_SIZE_OAM - 4)) >> 1) + 1);
1107		break;
1108	default:
1109		if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1110			STORE_32(value, address & (DS9_SIZE_DTCM - 4), memory->dtcm);
1111			break;
1112		}
1113		mLOG(DS_MEM, STUB, "Unimplemented DS9 Store32: %08X:%08X", address, value);
1114		break;
1115	}
1116
1117	if (cycleCounter) {
1118		++wait;
1119		*cycleCounter += wait;
1120	}
1121}
1122
1123void DS9Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
1124	struct DS* ds = (struct DS*) cpu->master;
1125	struct DSMemory* memory = &ds->memory;
1126	int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
1127
1128	switch (address >> DS_BASE_OFFSET) {
1129	case DS9_REGION_ITCM:
1130	case DS9_REGION_ITCM_MIRROR:
1131		if (address < memory->itcmSize) {
1132			STORE_16(value, address & (DS9_SIZE_ITCM - 2), memory->itcm);
1133			break;
1134		}
1135		mLOG(DS_MEM, STUB, "Bad DS9 Store16: %08X:%04X", address, value);
1136		break;
1137	case DS_REGION_WORKING_RAM:
1138		if (ds->memory.wramSize9) {
1139			STORE_16(value, address & (ds->memory.wramSize9 - 2), memory->wramBase9);
1140			break;
1141		}
1142		mLOG(DS_MEM, STUB, "Bad DS9 Store16: %08X:%04X", address, value);
1143		break;
1144	case DS_REGION_RAM:
1145		if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1146			STORE_16(value, address & (DS9_SIZE_DTCM - 2), memory->dtcm);
1147			break;
1148		}
1149		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1150			STORE_16(value, address & (DS_SIZE_RAM - 2), memory->ram);
1151			break;
1152		}
1153		mLOG(DS_MEM, STUB, "Unimplemented DS9 Store16: %08X:%04X", address, value);
1154		break;
1155	case DS_REGION_IO:
1156		DS9IOWrite(ds, address & DS_OFFSET_MASK, value);
1157		break;
1158	case DS9_REGION_PALETTE_RAM:
1159		STORE_16(value, address & (DS9_SIZE_PALETTE_RAM - 2), ds->video.palette);
1160		ds->video.renderer->writePalette(ds->video.renderer, address & (DS9_SIZE_PALETTE_RAM - 2), value);
1161		break;
1162	case DS_REGION_VRAM: {
1163		unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
1164		int i = 0;
1165		for (i = 0; i < 9; ++i) {
1166			if (mask & (1 << i)) {
1167				STORE_16(value, address & _vramMask[i], memory->vramBank[i]);
1168			}
1169		}
1170		break;
1171	}
1172	case DS9_REGION_OAM:
1173		STORE_16(value, address & (DS9_SIZE_OAM - 2), ds->video.oam.raw);
1174		ds->video.renderer->writeOAM(ds->video.renderer, (address & (DS9_SIZE_OAM - 2)) >> 1);
1175		break;
1176	default:
1177		if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1178			STORE_16(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1179			break;
1180		}
1181		mLOG(DS_MEM, STUB, "Unimplemented DS9 Store16: %08X:%04X", address, value);
1182		break;
1183	}
1184
1185	if (cycleCounter) {
1186		++wait;
1187		*cycleCounter += wait;
1188	}
1189}
1190
1191void DS9Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
1192	struct DS* ds = (struct DS*) cpu->master;
1193	struct DSMemory* memory = &ds->memory;
1194	int wait = ds->ds9.memory.waitstatesNonseq16[address >> DS_BASE_OFFSET];
1195
1196	switch (address >> DS_BASE_OFFSET) {
1197	case DS9_REGION_ITCM:
1198	case DS9_REGION_ITCM_MIRROR:
1199		if (address < memory->itcmSize) {
1200			((uint8_t*) memory->itcm)[address & (DS9_SIZE_ITCM - 1)] = value;
1201			break;
1202		}
1203		mLOG(DS_MEM, STUB, "Bad DS9 Store8: %08X:%02X", address, value);
1204		break;
1205	case DS_REGION_WORKING_RAM:
1206		if (ds->memory.wramSize9) {
1207			((uint8_t*) memory->wramBase9)[address & (ds->memory.wramSize9 - 1)] = value;
1208			break;
1209		}
1210		mLOG(DS_MEM, STUB, "Bad DS9 Store8: %08X:%02X", address, value);
1211		break;
1212	case DS_REGION_RAM:
1213		if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1214			((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)] = value;
1215			break;
1216		}
1217		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1218			((uint8_t*) memory->ram)[address & (DS_SIZE_RAM - 1)] = value;
1219			break;
1220		}
1221		mLOG(DS_MEM, STUB, "Unimplemented DS9 Store8: %08X:%02X", address, value);
1222	case DS_REGION_IO:
1223		DS9IOWrite8(ds, address & DS_OFFSET_MASK, value);
1224		break;
1225	default:
1226		if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1227			((uint8_t*) memory->dtcm)[address & (DS9_SIZE_DTCM - 1)] = value;
1228			break;
1229		}
1230		mLOG(DS_MEM, STUB, "Unimplemented DS9 Store8: %08X:%02X", address, value);
1231		break;
1232	}
1233
1234	if (cycleCounter) {
1235		++wait;
1236		*cycleCounter += wait;
1237	}
1238}
1239
1240uint32_t DS9LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
1241	struct DS* ds = (struct DS*) cpu->master;
1242	struct DSMemory* memory = &ds->memory;
1243	char* ws32 = ds->ds9.memory.waitstatesNonseq32;
1244	uint32_t value;
1245	int wait = 0;
1246
1247	int i;
1248	int offset = 4;
1249	int popcount = 0;
1250	if (direction & LSM_D) {
1251		offset = -4;
1252		popcount = popcount32(mask);
1253		address -= (popcount << 2) - 4;
1254	}
1255
1256	if (direction & LSM_B) {
1257		address += offset;
1258	}
1259
1260	uint32_t addressMisalign = address & 0x3;
1261	address &= 0xFFFFFFFC;
1262
1263	switch (address >> DS_BASE_OFFSET) {
1264	case DS9_REGION_BIOS:
1265		// TODO: Fix undersized BIOS
1266		// TODO: Fix masking
1267		LDM_LOOP(LOAD_32(value, address & (DS9_SIZE_BIOS - 1), memory->bios9));
1268		break;
1269	case DS9_REGION_ITCM:
1270	case DS9_REGION_ITCM_MIRROR:
1271		LDM_LOOP(if (address < memory->itcmSize) {
1272			LOAD_32(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
1273		} else {
1274			mLOG(DS_MEM, STUB, "Bad DS9 LDM: %08X:%08X", address, value);
1275		});
1276		break;
1277	case DS_REGION_WORKING_RAM:
1278		LDM_LOOP(if (ds->memory.wramSize9) {
1279			LOAD_32(value, address & (ds->memory.wramSize9 - 4), memory->wramBase9);
1280		} else {
1281			mLOG(DS_MEM, STUB, "Bad DS9 LDM: %08X", address);
1282		});
1283		break;
1284	case DS_REGION_RAM:
1285		LDM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1286			LOAD_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1287		} else if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1288			LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
1289		} else {
1290			mLOG(DS_MEM, STUB, "Unimplemented DS9 LDM: %08X", address);
1291		});
1292		break;
1293	case DS_REGION_IO:
1294		LDM_LOOP(value = DS9IORead32(ds, address));
1295		break;
1296	case DS9_REGION_PALETTE_RAM:
1297		LDM_LOOP(LOAD_32(value, address & (DS9_SIZE_PALETTE_RAM - 1), ds->video.palette));
1298		break;
1299	case DS_REGION_VRAM:
1300		LDM_LOOP(unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
1301		value = 0;
1302		int j = 0;
1303		for (j = 0; j < 9; ++j) {
1304			if (mask & (1 << j)) {
1305				uint32_t newValue;
1306				LOAD_32(newValue, address & _vramMask[j], memory->vramBank[j]);
1307				value |= newValue;
1308			}
1309		});
1310		break;
1311	case DS9_REGION_OAM:
1312		LDM_LOOP(LOAD_32(value, address & (DS9_SIZE_OAM - 1), ds->video.oam.raw));
1313		break;
1314	default:
1315		LDM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1316			LOAD_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1317		} else {
1318			value = 0;
1319			mLOG(DS_MEM, STUB, "Unimplemented DS9 LDM: %08X", address);
1320		});
1321		break;
1322	}
1323
1324	if (cycleCounter) {
1325		++wait;
1326		*cycleCounter += wait;
1327	}
1328
1329	if (direction & LSM_B) {
1330		address -= offset;
1331	}
1332
1333	if (direction & LSM_D) {
1334		address -= (popcount << 2) + 4;
1335	}
1336
1337	return address | addressMisalign;
1338}
1339
1340
1341uint32_t DS9StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
1342	struct DS* ds = (struct DS*) cpu->master;
1343	struct DSMemory* memory = &ds->memory;
1344	char* ws32 = ds->ds9.memory.waitstatesNonseq32;
1345	uint32_t value;
1346	int wait = 0;
1347
1348	int i;
1349	int offset = 4;
1350	int popcount = 0;
1351	if (direction & LSM_D) {
1352		offset = -4;
1353		popcount = popcount32(mask);
1354		address -= (popcount << 2) - 4;
1355	}
1356
1357	if (direction & LSM_B) {
1358		address += offset;
1359	}
1360
1361	uint32_t addressMisalign = address & 0x3;
1362	address &= 0xFFFFFFFC;
1363
1364	switch (address >> DS_BASE_OFFSET) {
1365	case DS9_REGION_ITCM:
1366	case DS9_REGION_ITCM_MIRROR:
1367		STM_LOOP(if (address < memory->itcmSize) {
1368			STORE_32(value, address & (DS9_SIZE_ITCM - 1), memory->itcm);
1369		} else {
1370			mLOG(DS_MEM, STUB, "Bad DS9 STM: %08X:%08X", address, value);
1371		});
1372		break;
1373	case DS_REGION_WORKING_RAM:
1374		STM_LOOP(if (ds->memory.wramSize9) {
1375			STORE_32(value, address & (ds->memory.wramSize9 - 4), memory->wramBase9);
1376		} else {
1377			mLOG(DS_MEM, STUB, "Bad DS9 STM: %08X", address);
1378		});
1379		break;
1380	case DS_REGION_RAM:
1381		STM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1382			STORE_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1383		} else if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
1384			STORE_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
1385		} else {
1386			mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
1387		});
1388		break;
1389	case DS_REGION_IO:
1390		STM_LOOP(DS9IOWrite32(ds, address & DS_OFFSET_MASK, value));
1391		break;
1392	case DS9_REGION_PALETTE_RAM:
1393		STM_LOOP(STORE_32(value, address & (DS9_SIZE_PALETTE_RAM - 1), ds->video.palette);
1394		ds->video.renderer->writePalette(ds->video.renderer, (address & (DS9_SIZE_PALETTE_RAM - 4)) + 2, value >> 16);
1395		ds->video.renderer->writePalette(ds->video.renderer, address & (DS9_SIZE_PALETTE_RAM - 4), value));
1396		break;
1397	case DS_REGION_VRAM:
1398		STM_LOOP(unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
1399		int j = 0;
1400		for (j = 0; j < 9; ++j) {
1401			if (mask & (1 << j)) {
1402				STORE_32(value, address & _vramMask[j], memory->vramBank[j]);
1403			}
1404		});
1405		break;
1406	case DS9_REGION_OAM:
1407		STM_LOOP(STORE_32(value, address & (DS9_SIZE_OAM - 1), ds->video.oam.raw);
1408		ds->video.renderer->writeOAM(ds->video.renderer, (address & (DS9_SIZE_OAM - 4)) >> 1);
1409		ds->video.renderer->writeOAM(ds->video.renderer, ((address & (DS9_SIZE_OAM - 4)) >> 1) + 1));
1410		break;
1411	default:
1412		STM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
1413			STORE_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
1414		} else {
1415			mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
1416		});
1417		break;
1418	}
1419
1420	if (cycleCounter) {
1421		*cycleCounter += wait;
1422	}
1423
1424	if (direction & LSM_B) {
1425		address -= offset;
1426	}
1427
1428	if (direction & LSM_D) {
1429		address -= (popcount << 2) + 4;
1430	}
1431
1432	return address | addressMisalign;
1433}
1434
1435int32_t DSMemoryStall(struct ARMCore* cpu, int32_t wait) {
1436	return wait;
1437}
1438
1439void DSConfigureWRAM(struct DSMemory* memory, uint8_t config) {
1440	switch (config & 3) {
1441	case 0:
1442		memory->wramSize7 = 0;
1443		memory->wramBase7 = NULL;
1444		memory->wramSize9 = DS_SIZE_WORKING_RAM;
1445		memory->wramBase9 = memory->wramBase;
1446		break;
1447	case 1:
1448		memory->wramSize7 = DS_SIZE_WORKING_RAM >> 1;
1449		memory->wramBase7 = memory->wram;
1450		memory->wramSize9 = DS_SIZE_WORKING_RAM >> 1;
1451		memory->wramBase9 = &memory->wramBase[DS_SIZE_WORKING_RAM >> 3];
1452		break;
1453	case 2:
1454		memory->wramSize7 = DS_SIZE_WORKING_RAM >> 1;
1455		memory->wramBase7 = &memory->wram[DS_SIZE_WORKING_RAM >> 3];
1456		memory->wramSize9 = DS_SIZE_WORKING_RAM >> 1;
1457		memory->wramBase9 = memory->wramBase;
1458		break;
1459	case 3:
1460		memory->wramSize7 = DS_SIZE_WORKING_RAM;
1461		memory->wramBase7 = memory->wramBase;
1462		memory->wramSize9 = 0;
1463		memory->wramBase9 = NULL;
1464		break;
1465	}
1466}
1467
1468void DSConfigureExternalMemory(struct DS* ds, uint16_t config) {
1469	// TODO: GBA params
1470	ds->memory.slot1Owner = config & 0x0800;
1471	ds->memory.slot2Owner = config & 0x0080;
1472	ds->memory.io7[DS7_REG_EXMEMSTAT >> 1] = config;
1473
1474	ds->ds7.memory.slot1Access = ds->memory.slot1Owner;
1475	ds->ds9.memory.slot1Access = !ds->memory.slot1Owner;
1476}
1477
1478static unsigned _selectVRAM(struct DSMemory* memory, uint32_t offset) {
1479	unsigned mask = 0;
1480	offset &= 0x3FF;
1481	mask |= memory->vramMirror[0][offset & 0x3F] & memory->vramMode[0][offset >> 7];
1482	mask |= memory->vramMirror[1][offset & 0x3F] & memory->vramMode[1][offset >> 7];
1483	mask |= memory->vramMirror[2][offset & 0x3F] & memory->vramMode[2][offset >> 7];
1484	mask |= memory->vramMirror[3][offset & 0x3F] & memory->vramMode[3][offset >> 7];
1485	mask |= memory->vramMirror[4][offset & 0x3F] & memory->vramMode[4][offset >> 7];
1486	mask |= memory->vramMirror[5][offset & 0x3F] & memory->vramMode[5][offset >> 7];
1487	mask |= memory->vramMirror[6][offset & 0x3F] & memory->vramMode[6][offset >> 7];
1488	mask |= memory->vramMirror[7][offset & 0x3F] & memory->vramMode[7][offset >> 7];
1489	mask |= memory->vramMirror[8][offset & 0x3F] & memory->vramMode[8][offset >> 7];
1490	return mask;
1491}