Load/Store multiple functions
@@ -48,6 +48,15 @@ BANK_ABORT = 4,
BANK_UNDEFINED = 5 }; +enum LSMDirection { + LSM_B = 1, + LSM_D = 2, + LSM_IA = 0, + LSM_IB = 1, + LSM_DA = 2, + LSM_DB = 3 +}; + struct ARMCore; union PSR {@@ -89,6 +98,9 @@ void (*store32)(struct ARMCore*, uint32_t address, int32_t value, int* cycleCounter);
void (*store16)(struct ARMCore*, uint32_t address, int16_t value, int* cycleCounter); void (*store8)(struct ARMCore*, uint32_t address, int8_t value, int* cycleCounter); + uint32_t (*loadMultiple)(struct ARMCore*, uint32_t baseAddress, int mask, enum LSMDirection direction, int* cycleCounter); + uint32_t (*storeMultiple)(struct ARMCore*, uint32_t baseAddress, int mask, enum LSMDirection direction, int* cycleCounter); + uint32_t* activeRegion; uint32_t activeMask; uint32_t activeSeqCycles32;@@ -98,7 +110,6 @@ uint32_t activeNonseqCycles16;
uint32_t activeUncachedCycles32; uint32_t activeUncachedCycles16; void (*setActiveRegion)(struct ARMCore*, uint32_t address); - int (*waitMultiple)(struct ARMCore*, uint32_t startAddress, int count); }; struct ARMInterruptHandler {
@@ -241,6 +241,8 @@ #define ADDR_MODE_3_IMMEDIATE (((opcode & 0x00000F00) >> 4) | (opcode & 0x0000000F))
#define ADDR_MODE_3_INDEX(U_OP, M) ADDR_MODE_2_INDEX(U_OP, M) #define ADDR_MODE_3_WRITEBACK(ADDR) ADDR_MODE_2_WRITEBACK(ADDR) +#define ADDR_MODE_4_WRITEBACK cpu->gprs[rn] = address + #define ARM_LOAD_POST_BODY \ ++currentCycles; \ if (rd == ARM_PC) { \@@ -385,66 +387,35 @@ ARMSetPrivilegeMode(cpu, MODE_SYSTEM);
#define ARM_MS_POST ARMSetPrivilegeMode(cpu, privilegeMode); -#define ADDR_MODE_4_DA uint32_t addr = cpu->gprs[rn] -#define ADDR_MODE_4_IA uint32_t addr = cpu->gprs[rn] -#define ADDR_MODE_4_DB uint32_t addr = cpu->gprs[rn] - 4 -#define ADDR_MODE_4_IB uint32_t addr = cpu->gprs[rn] + 4 -#define ADDR_MODE_4_DAW cpu->gprs[rn] = addr -#define ADDR_MODE_4_IAW cpu->gprs[rn] = addr -#define ADDR_MODE_4_DBW cpu->gprs[rn] = addr + 4 -#define ADDR_MODE_4_IBW cpu->gprs[rn] = addr - 4 - -#define ARM_M_INCREMENT(BODY) \ - for (m = rs, i = 0; m; m >>= 1, ++i) { \ - if (m & 1) { \ - BODY; \ - addr += 4; \ - total += 1; \ - } \ - } - -#define ARM_M_DECREMENT(BODY) \ - for (m = 0x8000, i = 15; m; m >>= 1, --i) { \ - if (rs & m) { \ - BODY; \ - addr -= 4; \ - total += 1; \ - } \ - } - -#define DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME, ADDRESS, WRITEBACK, LOOP, S_PRE, S_POST, BODY, POST_BODY) \ +#define DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME, LS, WRITEBACK, S_PRE, S_POST, DIRECTION, POST_BODY) \ DEFINE_INSTRUCTION_ARM(NAME, \ int rn = (opcode >> 16) & 0xF; \ int rs = opcode & 0x0000FFFF; \ - int m; \ - int i; \ - int total = 0; \ - ADDRESS; \ + uint32_t address = cpu->gprs[rn]; \ S_PRE; \ - LOOP(BODY); \ + address = cpu->memory. LS ## Multiple(cpu, address, rs, LSM_ ## DIRECTION, ¤tCycles); \ S_POST; \ - currentCycles += cpu->memory.waitMultiple(cpu, addr, total); \ POST_BODY; \ WRITEBACK;) -#define DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_ARM(NAME, BODY, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## DA, ADDR_MODE_4_DA, , ARM_M_DECREMENT, , , BODY, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## DAW, ADDR_MODE_4_DA, ADDR_MODE_4_DAW, ARM_M_DECREMENT, , , BODY, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## DB, ADDR_MODE_4_DB, , ARM_M_DECREMENT, , , BODY, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## DBW, ADDR_MODE_4_DB, ADDR_MODE_4_DBW, ARM_M_DECREMENT, , , BODY, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## IA, ADDR_MODE_4_IA, , ARM_M_INCREMENT, , , BODY, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## IAW, ADDR_MODE_4_IA, ADDR_MODE_4_IAW, ARM_M_INCREMENT, , , BODY, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## IB, ADDR_MODE_4_IB, , ARM_M_INCREMENT, , , BODY, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## IBW, ADDR_MODE_4_IB, ADDR_MODE_4_IBW, ARM_M_INCREMENT, , , BODY, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## SDA, ADDR_MODE_4_DA, , ARM_M_DECREMENT, ARM_MS_PRE, ARM_MS_POST, BODY, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## SDAW, ADDR_MODE_4_DA, ADDR_MODE_4_DAW, ARM_M_DECREMENT, ARM_MS_PRE, ARM_MS_POST, BODY, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## SDB, ADDR_MODE_4_DB, , ARM_M_DECREMENT, ARM_MS_PRE, ARM_MS_POST, BODY, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## SDBW, ADDR_MODE_4_DB, ADDR_MODE_4_DBW, ARM_M_DECREMENT, ARM_MS_PRE, ARM_MS_POST, BODY, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## SIA, ADDR_MODE_4_IA, , ARM_M_INCREMENT, ARM_MS_PRE, ARM_MS_POST, BODY, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## SIAW, ADDR_MODE_4_IA, ADDR_MODE_4_IAW, ARM_M_INCREMENT, ARM_MS_PRE, ARM_MS_POST, BODY, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## SIB, ADDR_MODE_4_IB, , ARM_M_INCREMENT, ARM_MS_PRE, ARM_MS_POST, BODY, POST_BODY) \ - DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## SIBW, ADDR_MODE_4_IB, ADDR_MODE_4_IBW, ARM_M_INCREMENT, ARM_MS_PRE, ARM_MS_POST, BODY, POST_BODY) +#define DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_ARM(NAME, LS, POST_BODY) \ + DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## DA, LS, , , , DA, POST_BODY) \ + DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## DAW, LS, ADDR_MODE_4_WRITEBACK, , , DA, POST_BODY) \ + DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## DB, LS, , , , DB, POST_BODY) \ + DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## DBW, LS, ADDR_MODE_4_WRITEBACK, , , DB, POST_BODY) \ + DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## IA, LS, , , , IA, POST_BODY) \ + DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## IAW, LS, ADDR_MODE_4_WRITEBACK, , , IA, POST_BODY) \ + DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## IB, LS, , , , IB, POST_BODY) \ + DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## IBW, LS, ADDR_MODE_4_WRITEBACK, , , IB, POST_BODY) \ + DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## SDA, LS, , ARM_MS_PRE, ARM_MS_POST, DA, POST_BODY) \ + DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## SDAW, LS, ADDR_MODE_4_WRITEBACK, ARM_MS_PRE, ARM_MS_POST, DA, POST_BODY) \ + DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## SDB, LS, , ARM_MS_PRE, ARM_MS_POST, DB, POST_BODY) \ + DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## SDBW, LS, ADDR_MODE_4_WRITEBACK, ARM_MS_PRE, ARM_MS_POST, DB, POST_BODY) \ + DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## SIA, LS, , ARM_MS_PRE, ARM_MS_POST, IA, POST_BODY) \ + DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## SIAW, LS, ADDR_MODE_4_WRITEBACK, ARM_MS_PRE, ARM_MS_POST, IA, POST_BODY) \ + DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## SIB, LS, , ARM_MS_PRE, ARM_MS_POST, IB, POST_BODY) \ + DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_EX_ARM(NAME ## SIBW, LS, ADDR_MODE_4_WRITEBACK, ARM_MS_PRE, ARM_MS_POST, IB, POST_BODY) // Begin ALU definitions@@ -580,14 +551,14 @@ ARMSetPrivilegeMode(cpu, priv);
ARM_STORE_POST_BODY;) DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_ARM(LDM, - cpu->gprs[i] = cpu->memory.load32(cpu, addr & 0xFFFFFFFC, 0);, + load, ++currentCycles; if (rs & 0x8000) { ARM_WRITE_PC; }) DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_ARM(STM, - cpu->memory.store32(cpu, addr, cpu->gprs[i], 0);, + store, currentCycles += cpu->memory.activeNonseqCycles32 - cpu->memory.activeSeqCycles32) DEFINE_INSTRUCTION_ARM(SWP,
@@ -289,39 +289,30 @@ DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STR2, cpu->memory.store32(cpu, cpu->gprs[rn] + cpu->gprs[rm], cpu->gprs[rd], ¤tCycles); THUMB_STORE_POST_BODY;)
DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STRB2, cpu->memory.store8(cpu, cpu->gprs[rn] + cpu->gprs[rm], cpu->gprs[rd], ¤tCycles); THUMB_STORE_POST_BODY;) DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STRH2, cpu->memory.store16(cpu, cpu->gprs[rn] + cpu->gprs[rm], cpu->gprs[rd], ¤tCycles); THUMB_STORE_POST_BODY;) -#define DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(NAME, RN, ADDRESS, LOOP, BODY, OP, PRE_BODY, POST_BODY, WRITEBACK) \ +#define DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(NAME, RN, LS, DIRECTION, PRE_BODY, WRITEBACK) \ DEFINE_INSTRUCTION_THUMB(NAME, \ int rn = RN; \ UNUSED(rn); \ int rs = opcode & 0xFF; \ - int32_t address = ADDRESS; \ - int m; \ - int i; \ - int total = 0; \ + int32_t address = cpu->gprs[RN]; \ PRE_BODY; \ - for LOOP { \ - if (rs & m) { \ - BODY; \ - address OP 4; \ - ++total; \ - } \ - } \ - POST_BODY; \ - currentCycles += cpu->memory.waitMultiple(cpu, address, total); \ + address = cpu->memory. LS ## Multiple(cpu, address, rs, LSM_ ## DIRECTION, ¤tCycles); \ WRITEBACK;) -#define DEFINE_LOAD_STORE_MULTIPLE_THUMB(NAME, BODY, WRITEBACK) \ - COUNT_CALL_3(DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB, NAME ## _R, cpu->gprs[rn], (m = 0x01, i = 0; i < 8; m <<= 1, ++i), BODY, +=, , , WRITEBACK) +#define DEFINE_LOAD_STORE_MULTIPLE_THUMB(NAME, LS, DIRECTION, WRITEBACK) \ + COUNT_CALL_3(DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB, NAME ## _R, LS, DIRECTION, , WRITEBACK) DEFINE_LOAD_STORE_MULTIPLE_THUMB(LDMIA, - cpu->gprs[i] = cpu->memory.load32(cpu, address, 0), + load, + IA, THUMB_LOAD_POST_BODY; if (!((1 << rn) & rs)) { cpu->gprs[rn] = address; }) DEFINE_LOAD_STORE_MULTIPLE_THUMB(STMIA, - cpu->memory.store32(cpu, address, cpu->gprs[i], 0), + store, + IA, THUMB_STORE_POST_BODY; cpu->gprs[rn] = address;)@@ -352,48 +343,37 @@ DEFINE_INSTRUCTION_THUMB(ADD7, cpu->gprs[ARM_SP] += (opcode & 0x7F) << 2)
DEFINE_INSTRUCTION_THUMB(SUB4, cpu->gprs[ARM_SP] -= (opcode & 0x7F) << 2) DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(POP, - opcode & 0x00FF, - cpu->gprs[ARM_SP], - (m = 0x01, i = 0; i < 8; m <<= 1, ++i), - cpu->gprs[i] = cpu->memory.load32(cpu, address, 0), - +=, + ARM_SP, + load, + IA, , - THUMB_LOAD_POST_BODY;, + THUMB_LOAD_POST_BODY; cpu->gprs[ARM_SP] = address) DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(POPR, - opcode & 0x00FF, - cpu->gprs[ARM_SP], - (m = 0x01, i = 0; i < 8; m <<= 1, ++i), - cpu->gprs[i] = cpu->memory.load32(cpu, address, 0), - +=, - , - cpu->gprs[ARM_PC] = cpu->memory.load32(cpu, address, 0) & 0xFFFFFFFE; - address += 4; - THUMB_LOAD_POST_BODY;, + ARM_SP, + load, + IA, + rs |= 1 << ARM_PC, + THUMB_LOAD_POST_BODY; cpu->gprs[ARM_SP] = address; THUMB_WRITE_PC;) DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(PUSH, - opcode & 0x00FF, - cpu->gprs[ARM_SP] - 4, - (m = 0x80, i = 7; m; m >>= 1, --i), - cpu->memory.store32(cpu, address, cpu->gprs[i], 0), - -=, + ARM_SP, + store, + DB, , - THUMB_STORE_POST_BODY, - cpu->gprs[ARM_SP] = address + 4) + THUMB_STORE_POST_BODY; + cpu->gprs[ARM_SP] = address) DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(PUSHR, - opcode & 0x00FF, - cpu->gprs[ARM_SP] - 4, - (m = 0x80, i = 7; m; m >>= 1, --i), - cpu->memory.store32(cpu, address, cpu->gprs[i], 0), - -=, - cpu->memory.store32(cpu, address, cpu->gprs[ARM_LR], 0); - address -= 4;, - THUMB_STORE_POST_BODY, - cpu->gprs[ARM_SP] = address + 4) + ARM_SP, + store, + DB, + rs |= 1 << ARM_LR, + THUMB_STORE_POST_BODY; + cpu->gprs[ARM_SP] = address) DEFINE_INSTRUCTION_THUMB(ILL, ARM_ILL) DEFINE_INSTRUCTION_THUMB(BKPT, ARM_STUB)
@@ -43,7 +43,6 @@ CREATE_WATCHPOINT_SHIM(loadU8, 1, uint8_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), address, cycleCounter)
CREATE_WATCHPOINT_SHIM(store32, 4, void, (struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter), address, value, cycleCounter) CREATE_WATCHPOINT_SHIM(store16, 2, void, (struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter), address, value, cycleCounter) CREATE_WATCHPOINT_SHIM(store8, 1, void, (struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter), address, value, cycleCounter) -CREATE_SHIM(waitMultiple, int, (struct ARMCore* cpu, uint32_t startAddress, int count), startAddress, count) CREATE_SHIM(setActiveRegion, void, (struct ARMCore* cpu, uint32_t address), address) static bool _checkWatchpoints(struct DebugBreakpoint* watchpoints, uint32_t address, int width) {@@ -67,7 +66,6 @@ debugger->cpu->memory.loadU16 = ARMDebuggerShim_loadU16;
debugger->cpu->memory.load8 = ARMDebuggerShim_load8; debugger->cpu->memory.loadU8 = ARMDebuggerShim_loadU8; debugger->cpu->memory.setActiveRegion = ARMDebuggerShim_setActiveRegion; - debugger->cpu->memory.waitMultiple = ARMDebuggerShim_waitMultiple; } void ARMDebuggerRemoveMemoryShim(struct ARMDebugger* debugger) {@@ -80,5 +78,4 @@ debugger->cpu->memory.loadU16 = debugger->originalMemory.loadU16;
debugger->cpu->memory.load8 = debugger->originalMemory.load8; debugger->cpu->memory.loadU8 = debugger->originalMemory.loadU8; debugger->cpu->memory.setActiveRegion = debugger->originalMemory.setActiveRegion; - debugger->cpu->memory.waitMultiple = debugger->originalMemory.waitMultiple; }
@@ -9,7 +9,6 @@ #include "hle-bios.h"
#include "util/memory.h" static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t region); -static int GBAWaitMultiple(struct ARMCore* cpu, uint32_t startAddress, int count); static void GBAMemoryServiceDMA(struct GBA* gba, int number, struct GBADMA* info); static const char GBA_BASE_WAITSTATES[16] = { 0, 0, 2, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4 };@@ -27,9 +26,11 @@ cpu->memory.load16 = GBALoad16;
cpu->memory.loadU16 = GBALoadU16; cpu->memory.load8 = GBALoad8; cpu->memory.loadU8 = GBALoadU8; + cpu->memory.loadMultiple = GBALoadMultiple; cpu->memory.store32 = GBAStore32; cpu->memory.store16 = GBAStore16; cpu->memory.store8 = GBAStore8; + cpu->memory.storeMultiple = GBAStoreMultiple; gba->memory.bios = (uint32_t*) hleBios; gba->memory.fullBios = 0;@@ -67,7 +68,6 @@ cpu->memory.activeNonseqCycles16 = 0;
cpu->memory.activeUncachedCycles32 = 0; cpu->memory.activeUncachedCycles16 = 0; gba->memory.biosPrefetch = 0; - cpu->memory.waitMultiple = GBAWaitMultiple; } void GBAMemoryDeinit(struct GBA* gba) {@@ -558,12 +558,203 @@ *cycleCounter += 1 + wait;
} } -static int GBAWaitMultiple(struct ARMCore* cpu, uint32_t startAddress, int count) { +uint32_t GBALoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) { + struct GBA* gba = (struct GBA*) cpu->master; + struct GBAMemory* memory = &gba->memory; + uint32_t value; + int wait; + int totalWait = 0; + char* waitstatesRegion = memory->waitstatesNonseq32; + + int i; + int offset = 4; + int popcount = 0; + if (direction & LSM_D) { + offset = -4; + for (i = 0; i < 16; ++i) { + if (mask & (1 << i)) { + ++popcount; + } + } + address -= (popcount << 2) - 4; + } + + if (direction & LSM_B) { + address += offset; + } + + address &= 0xFFFFFFFC; + + for (i = 0; i < 16; ++i) { + wait = 0; + if (~mask & (1 << i)) { + continue; + } + switch (address >> BASE_OFFSET) { + case REGION_BIOS: + if (memory->activeRegion == REGION_BIOS) { + if (address < SIZE_BIOS) { + LOAD_32(value, address, memory->bios); + } else { + value = 0; + } + } else { + value = memory->biosPrefetch; + } + break; + case REGION_WORKING_RAM: + LOAD_32(value, address & (SIZE_WORKING_RAM - 1), memory->wram); + wait = waitstatesRegion[REGION_WORKING_RAM]; + break; + case REGION_WORKING_IRAM: + LOAD_32(value, address & (SIZE_WORKING_IRAM - 1), memory->iwram); + break; + case REGION_IO: + value = GBAIORead(gba, (address & (SIZE_IO - 1)) & ~2) | (GBAIORead(gba, (address & (SIZE_IO - 1)) | 2) << 16); + break; + case REGION_PALETTE_RAM: + LOAD_32(value, address & (SIZE_PALETTE_RAM - 1), gba->video.palette); + break; + case REGION_VRAM: + LOAD_32(value, address & 0x0001FFFF, gba->video.renderer->vram); + break; + case REGION_OAM: + LOAD_32(value, address & (SIZE_OAM - 1), gba->video.oam.raw); + break; + case REGION_CART0: + case REGION_CART0_EX: + case REGION_CART1: + case REGION_CART1_EX: + case REGION_CART2: + case REGION_CART2_EX: + wait = waitstatesRegion[address >> BASE_OFFSET]; + if ((address & (SIZE_CART0 - 1)) < memory->romSize) { + LOAD_32(value, address & (SIZE_CART0 - 1), memory->rom); + } + break; + case REGION_CART_SRAM: + case REGION_CART_SRAM_MIRROR: + GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Load32: 0x%08X", address); + break; + default: + GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Load32: 0x%08X", address); + value = cpu->prefetch; + if (cpu->executionMode == MODE_THUMB) { + value |= value << 16; + } + break; + } + waitstatesRegion = memory->waitstatesSeq32; + cpu->gprs[i] = value; + totalWait += 1 + wait; + address += 4; + } + + if (cycleCounter) { + *cycleCounter += totalWait; + } + + if (direction & LSM_B) { + address -= offset; + } + + if (direction & LSM_D) { + address -= (popcount << 2) + 4; + } + + return address; +} + +uint32_t GBAStoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) { struct GBA* gba = (struct GBA*) cpu->master; struct GBAMemory* memory = &gba->memory; - int wait = 1 + memory->waitstatesNonseq32[startAddress >> BASE_OFFSET]; - wait += (1 + memory->waitstatesSeq32[startAddress >> BASE_OFFSET]) * (count - 1); - return wait; + uint32_t value; + int wait; + int totalWait = 0; + char* waitstatesRegion = memory->waitstatesNonseq32; + + int i; + int offset = 4; + int popcount = 0; + if (direction & LSM_D) { + offset = -4; + for (i = 0; i < 16; ++i) { + if (mask & (1 << i)) { + ++popcount; + } + } + address -= (popcount << 2) - 4; + } + + if (direction & LSM_B) { + address += offset; + } + + address &= 0xFFFFFFFC; + + for (i = 0; i < 16; ++i) { + wait = 0; + if (~mask & (1 << i)) { + continue; + } + value = cpu->gprs[i]; + switch (address >> BASE_OFFSET) { + case REGION_WORKING_RAM: + STORE_32(value, address & (SIZE_WORKING_RAM - 1), memory->wram); + wait = waitstatesRegion[REGION_WORKING_RAM]; + break; + case REGION_WORKING_IRAM: + STORE_32(value, address & (SIZE_WORKING_IRAM - 1), memory->iwram); + break; + case REGION_IO: + GBAIOWrite32(gba, address & (SIZE_IO - 1), value); + break; + case REGION_PALETTE_RAM: + STORE_32(value, address & (SIZE_PALETTE_RAM - 1), gba->video.palette); + gba->video.renderer->writePalette(gba->video.renderer, (address & (SIZE_PALETTE_RAM - 1)) + 2, value >> 16); + gba->video.renderer->writePalette(gba->video.renderer, address & (SIZE_PALETTE_RAM - 1), value); + break; + case REGION_VRAM: + if ((address & OFFSET_MASK) < SIZE_VRAM) { + STORE_32(value, address & 0x0001FFFF, gba->video.renderer->vram); + } else if ((address & OFFSET_MASK) < 0x00020000) { + STORE_32(value, address & 0x00017FFF, gba->video.renderer->vram); + } + break; + case REGION_OAM: + STORE_32(value, address & (SIZE_OAM - 1), gba->video.oam.raw); + gba->video.renderer->writeOAM(gba->video.renderer, (address & (SIZE_OAM - 4)) >> 1); + gba->video.renderer->writeOAM(gba->video.renderer, ((address & (SIZE_OAM - 4)) >> 1) + 1); + break; + case REGION_CART0: + GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Store32: 0x%08X", address); + break; + case REGION_CART_SRAM: + case REGION_CART_SRAM_MIRROR: + GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Store32: 0x%08X", address); + break; + default: + GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Store32: 0x%08X", address); + break; + } + waitstatesRegion = memory->waitstatesSeq32; + totalWait += 1 + wait; + address += 4; + } + + if (cycleCounter) { + *cycleCounter += totalWait; + } + + if (direction & LSM_B) { + address -= offset; + } + + if (direction & LSM_D) { + address -= (popcount << 2) + 4; + } + + return address; } void GBAAdjustWaitstates(struct GBA* gba, uint16_t parameters) {
@@ -149,6 +149,9 @@ void GBAStore32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter);
void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter); void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter); +uint32_t GBALoadMultiple(struct ARMCore*, uint32_t baseAddress, int mask, enum LSMDirection direction, int* cycleCounter); +uint32_t GBAStoreMultiple(struct ARMCore*, uint32_t baseAddress, int mask, enum LSMDirection direction, int* cycleCounter); + void GBAAdjustWaitstates(struct GBA* gba, uint16_t parameters); void GBAMemoryWriteDMASAD(struct GBA* gba, int dma, uint32_t address);