all repos — mgba @ 2c3a1c6f7177a1f99c475ec4fe53a9f55b2d9658

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