all repos — mgba @ 793cad8f301e4f42bcf682ff5d324b63c4561ee7

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