all repos — mgba @ 035998e3f027a5514c5a31a4b0bd63466e22a1c0

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