Merge branch 'master' into port/qt
jump to
@@ -1,8 +1,7 @@
cmake_minimum_required(VERSION 2.6) project(mGBA C) set(BINARY_NAME mgba CACHE INTERNAL "Name of output binaries") -set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g -Wall -Wextra -std=gnu99") -set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3 -Wall -Wextra -std=gnu99") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -std=gnu99") set(USE_CLI_DEBUGGER ON CACHE BOOL "Whether or not to enable the CLI-mode ARM debugger") set(USE_GDB_STUB ON CACHE BOOL "Whether or not to enable the GDB stub ARM debugger") set(USE_FFMPEG ON CACHE BOOL "Whether or not to enable FFmpeg support")@@ -33,12 +32,16 @@ if (NOT ${FEATURE_NAME})
return() endif() foreach(REQUIRE ${FEATURE_REQUIRES}) - find_package(${REQUIRE} QUIET) - pkg_search_module(${REQUIRE} ${REQUIRE}) - if (NOT ${REQUIRE}_FOUND) - message(WARNING "Requested module ${REQUIRE} missing for feature ${FEATURE_NAME}. Feature disabled.") - set(${FEATURE_NAME} OFF PARENT_SCOPE) - return() + if(NOT ${REQUIRE}_FOUND) + find_package(${REQUIRE} QUIET) + if(NOT ${REQUIRE}_FOUND) + pkg_search_module(${REQUIRE} ${REQUIRE}) + if (NOT ${REQUIRE}_FOUND) + message(WARNING "Requested module ${REQUIRE} missing for feature ${FEATURE_NAME}. Feature disabled.") + set(${FEATURE_NAME} OFF PARENT_SCOPE) + return() + endif() + endif() endif() string(TOUPPER ${REQUIRE} UREQUIRE) set(${UREQUIRE}_CFLAGS_OTHER ${${REQUIRE}_CFLAGS_OTHER} PARENT_SCOPE)@@ -62,8 +65,8 @@ set(BUILD_PGO CACHE BOOL "Build with profiling-guided optimization")
set(PGO_STAGE_2 CACHE BOOL "Rebuild for profiling-guided optimization after profiles have been generated") set(PGO_DIR "/tmp/gba-pgo/" CACHE PATH "Profiling-guided optimization profiles path") mark_as_advanced(BUILD_PGO PGO_STAGE_2 PGO_DIR) -set(PGO_PRE_FLAGS "-pg -fprofile-generate=${PGO_DIR}") -set(PGO_POST_FLAGS "-fprofile-use=${PGO_DIR}") +set(PGO_PRE_FLAGS "-pg -fprofile-generate=${PGO_DIR} -fprofile-arcs") +set(PGO_POST_FLAGS "-fprofile-use=${PGO_DIR} -fbranch-probabilities") if(BUILD_PGO AND NOT PGO_STAGE_2) set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${PGO_PRE_FLAGS}")@@ -80,9 +83,16 @@
# Feature dependencies find_feature(USE_CLI_DEBUGGER "libedit") find_feature(USE_FFMPEG "libavcodec;libavformat;libavutil") -find_feature(USE_PNG "PNG;ZLIB") +find_feature(USE_PNG "ZLIB;PNG") find_feature(USE_LIBZIP "libzip") +include(CheckFunctionExists) +check_function_exists(strndup HAVE_STRNDUP) + +if(HAVE_STRNDUP) + add_definitions(-DHAVE_STRNDUP) +endif() + # Platform support if(WIN32) add_definitions(-D_WIN32_WINNT=0x0600)@@ -101,10 +111,6 @@ enable_language(ASM)
if(NOT BUILD_EGL) add_definitions(-DCOLOR_16_BIT -DCOLOR_5_6_5) endif() -endif() - -if(CMAKE_SYSTEM_NAME STREQUAL "Linux") - list(APPEND OS_LIB bsd) endif() # Features
@@ -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 {
@@ -110,7 +110,7 @@ } else if (SKIPPED == 2) { \
info->operandFormat &= ~ARM_OPERAND_2; \ } \ if (info->op1.reg == ARM_PC) { \ - info->branches = 1; \ + info->branchType = ARM_BRANCH_INDIRECT; \ }) #define DEFINE_ALU_DECODER_ARM(NAME, SKIPPED) \@@ -157,7 +157,7 @@ ARM_OPERAND_REGISTER_3 | \
OTHER_AFFECTED; \ info->affectsCPSR = S; \ if (info->op1.reg == ARM_PC) { \ - info->branches = 1; \ + info->branchType = ARM_BRANCH_INDIRECT; \ }) #define DEFINE_LONG_MULTIPLY_DECODER_EX_ARM(NAME, MNEMONIC, S) \@@ -174,7 +174,7 @@ ARM_OPERAND_REGISTER_3 | \
ARM_OPERAND_REGISTER_4; \ info->affectsCPSR = S; \ if (info->op1.reg == ARM_PC) { \ - info->branches = 1; \ + info->branchType = ARM_BRANCH_INDIRECT; \ }) #define DEFINE_MULTIPLY_DECODER_ARM(NAME, OTHER_AFFECTED) \@@ -255,7 +255,9 @@ #define DEFINE_LOAD_STORE_MULTIPLE_DECODER_EX_ARM(NAME, MNEMONIC, DIRECTION, WRITEBACK) \
DEFINE_DECODER_ARM(NAME, MNEMONIC, \ info->memory.baseReg = (opcode >> 16) & 0xF; \ info->op1.immediate = opcode & 0x0000FFFF; \ - info->branches = info->op1.immediate & (1 << ARM_PC); \ + if (info->op1.immediate & (1 << ARM_PC)) { \ + info->branchType = ARM_BRANCH_INDIRECT; \ + } \ info->operandFormat = ARM_OPERAND_MEMORY_1; \ info->memory.format = ARM_MEMORY_REGISTER_BASE | \ ARM_MEMORY_WRITEBACK | \@@ -348,18 +350,18 @@ DEFINE_DECODER_ARM(B, B,
int32_t offset = opcode << 8; info->op1.immediate = offset >> 6; info->operandFormat = ARM_OPERAND_IMMEDIATE_1; - info->branches = 1;) + info->branchType = ARM_BRANCH;) DEFINE_DECODER_ARM(BL, BL, int32_t offset = opcode << 8; info->op1.immediate = offset >> 6; info->operandFormat = ARM_OPERAND_IMMEDIATE_1; - info->branches = 1;) + info->branchType = ARM_BRANCH_LINKED;) DEFINE_DECODER_ARM(BX, BX, info->op1.reg = opcode & 0x0000000F; info->operandFormat = ARM_OPERAND_REGISTER_1; - info->branches = 1;) + info->branchType = ARM_BRANCH_INDIRECT;) // End branch definitions@@ -441,7 +443,7 @@
void ARMDecodeARM(uint32_t opcode, struct ARMInstructionInfo* info) { info->execMode = MODE_ARM; info->opcode = opcode; - info->branches = 0; + info->branchType = ARM_BRANCH_NONE; info->traps = 0; info->affectsCPSR = 0; info->condition = opcode >> 28;
@@ -135,7 +135,9 @@ #define DEFINE_DECODER_WITH_HIGH_EX_THUMB(NAME, H1, H2, MNEMONIC, AFFECTED, CPSR) \
DEFINE_THUMB_DECODER(NAME, MNEMONIC, \ info->op1.reg = (opcode & 0x0007) | H1; \ info->op2.reg = ((opcode >> 3) & 0x0007) | H2; \ - info->branches = info->op1.reg == ARM_PC; \ + if (info->op1.reg == ARM_PC) { \ + info->branchType = ARM_BRANCH_INDIRECT; \ + } \ info->affectsCPSR = CPSR; \ info->operandFormat = ARM_OPERAND_REGISTER_1 | \ AFFECTED | \@@ -221,7 +223,9 @@ #define DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(NAME, RN, MNEMONIC, DIRECTION, ADDITIONAL_REG) \
DEFINE_THUMB_DECODER(NAME, MNEMONIC, \ info->memory.baseReg = RN; \ info->op1.immediate = (opcode & 0xFF) | ADDITIONAL_REG; \ - info->branches = info->op1.immediate & (1 << ARM_PC); \ + if (info->op1.immediate & (1 << ARM_PC)) { \ + info->branchType = ARM_BRANCH_INDIRECT; \ + } \ info->operandFormat = ARM_OPERAND_MEMORY_1; \ info->memory.format = ARM_MEMORY_REGISTER_BASE | \ ARM_MEMORY_WRITEBACK | \@@ -237,7 +241,7 @@ #define DEFINE_CONDITIONAL_BRANCH_THUMB(COND) \
DEFINE_THUMB_DECODER(B ## COND, B, \ int8_t immediate = opcode; \ info->op1.immediate = immediate << 1; \ - info->branches = 1; \ + info->branchType = ARM_BRANCH; \ info->condition = ARM_CONDITION_ ## COND; \ info->operandFormat = ARM_OPERAND_IMMEDIATE_1;)@@ -279,7 +283,7 @@ DEFINE_THUMB_DECODER(B, B,
int16_t immediate = (opcode & 0x07FF) << 5; info->op1.immediate = (((int32_t) immediate) >> 4); info->operandFormat = ARM_OPERAND_IMMEDIATE_1; - info->branches = 1;) + info->branchType = ARM_BRANCH;) DEFINE_THUMB_DECODER(BL1, BLH, int16_t immediate = (opcode & 0x07FF) << 5;@@ -289,12 +293,12 @@
DEFINE_THUMB_DECODER(BL2, BL, info->op1.immediate = (opcode & 0x07FF) << 1; info->operandFormat = ARM_OPERAND_IMMEDIATE_1; - info->branches = 1;) + info->branchType = ARM_BRANCH_LINKED;) DEFINE_THUMB_DECODER(BX, BX, info->op1.reg = (opcode >> 3) & 0xF; info->operandFormat = ARM_OPERAND_REGISTER_1; - info->branches = 1;) + info->branchType = ARM_BRANCH_INDIRECT;) DEFINE_THUMB_DECODER(SWI, SWI, info->op1.immediate = opcode & 0xFF;@@ -310,7 +314,7 @@
void ARMDecodeThumb(uint16_t opcode, struct ARMInstructionInfo* info) { info->execMode = MODE_THUMB; info->opcode = opcode; - info->branches = 0; + info->branchType = ARM_BRANCH_NONE; info->traps = 0; info->affectsCPSR = 0; info->condition = ARM_CONDITION_AL;
@@ -227,10 +227,23 @@ "",
"", "", "", + "", "sb", "sh", - "" + "", + "", + "", + "", + "", + + "", + "tb", + "", + "", + "t", + "", + "", "" };
@@ -108,6 +108,13 @@ ARM_ACCESS_TRANSLATED_WORD = 20,
ARM_ACCESS_TRANSLATED_BYTE = 17 }; +enum ARMBranchType { + ARM_BRANCH_NONE = 0, + ARM_BRANCH = 1, + ARM_BRANCH_INDIRECT = 2, + ARM_BRANCH_LINKED = 4 +}; + struct ARMMemoryAccess { uint8_t baseReg; uint8_t width;@@ -175,17 +182,17 @@ union ARMOperand op4;
struct ARMMemoryAccess memory; int operandFormat; unsigned execMode : 1; - bool branches : 1; bool traps : 1; bool affectsCPSR : 1; + unsigned branchType : 3; unsigned condition : 4; unsigned mnemonic : 6; - unsigned iCycles : 2; + unsigned iCycles : 3; unsigned cCycles : 4; + unsigned sInstructionCycles : 4; + unsigned nInstructionCycles : 4; unsigned sDataCycles : 10; unsigned nDataCycles : 10; - unsigned sInstructionCycles : 4; - unsigned nInstructionCycles : 4; }; void ARMDecodeARM(uint32_t opcode, struct ARMInstructionInfo* info);
@@ -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)
@@ -201,7 +201,7 @@ for ( ; dv; dv = dv->next) {
printf(" 0b"); int i = 32; while (i--) { - printf("%u", (dv->intValue >> i) & 1); + printf(" %u", (dv->intValue >> i) & 1); } } printf("\n");@@ -518,11 +518,10 @@ printf("Parse error\n");
_DVFree(dv); return false; } - } else { - printf("Wrong number of arguments"); } } else if (firstSpace) { - printf("Wrong number of arguments"); + printf("Wrong number of arguments\n"); + return false; } _debuggerCommands[i].command(debugger, dv); _DVFree(dv);
@@ -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; }
@@ -1,16 +1,6 @@
#include "parser.h" -static inline char* _strndup(const char* start, size_t len) { -#ifdef HAVE_STRNDUP - return strndup(start, len); -#else - // This is suboptimal, but anything recent should have strndup - char* out = malloc((len + 1) * sizeof(char)); - strncpy(out, start, len); - out[len] = '\0'; - return out; -#endif -} +#include "util/string.h" static struct LexVector* _lexOperator(struct LexVector* lv, char operator) { struct LexVector* lvNext = malloc(sizeof(struct LexVector));@@ -108,13 +98,13 @@ case '-':
case '*': case '/': lv->token.type = TOKEN_IDENTIFIER_TYPE; - lv->token.identifierValue = _strndup(tokenStart, string - tokenStart - 1); + lv->token.identifierValue = strndup(tokenStart, string - tokenStart - 1); lv = _lexOperator(lv, token); state = LEX_ROOT; break; case ')': lv->token.type = TOKEN_IDENTIFIER_TYPE; - lv->token.identifierValue = _strndup(tokenStart, string - tokenStart - 1); + lv->token.identifierValue = strndup(tokenStart, string - tokenStart - 1); state = LEX_EXPECT_OPERATOR; break; default:@@ -263,6 +253,21 @@ lv->token.type = TOKEN_UINT_TYPE;
lv->token.uintValue = next; state = LEX_EXPECT_OPERATOR; break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + next = token - '0'; + state = LEX_EXPECT_DECIMAL; + break; + default: + state = LEX_ERROR; } break; case LEX_EXPECT_OPERATOR:@@ -298,7 +303,7 @@ lv->token.uintValue = next;
break; case LEX_EXPECT_IDENTIFIER: lv->token.type = TOKEN_IDENTIFIER_TYPE; - lv->token.identifierValue = _strndup(tokenStart, string - tokenStart); + lv->token.identifierValue = strndup(tokenStart, string - tokenStart); break; case LEX_EXPECT_OPERATOR: lvNext = malloc(sizeof(struct LexVector));
@@ -99,13 +99,15 @@ uint32_t key = cpu->memory.load32(cpu, cpu->gprs[0] + 4, 0);
cpu->gprs[0] = key / powf(2, (180.f - cpu->gprs[1] - cpu->gprs[2] / 256.f) / 12.f); } -static void _Div(struct ARMCore* cpu, int32_t num, int32_t denom) { +static void _Div(struct GBA* gba, int32_t num, int32_t denom) { + struct ARMCore* cpu = gba->cpu; if (denom != 0) { div_t result = div(num, denom); cpu->gprs[0] = result.quot; cpu->gprs[1] = result.rem; cpu->gprs[3] = abs(result.quot); } else { + GBALog(gba, GBA_LOG_GAME_ERROR, "Attempting to divide %i by zero!", num); // If abs(num) > 1, this should hang, but that would be painful to // emulate in HLE, and no game will get into a state where it hangs... cpu->gprs[0] = (num < 0) ? -1 : 1;@@ -116,7 +118,8 @@ }
void GBASwi16(struct ARMCore* cpu, int immediate) { struct GBA* gba = (struct GBA*) cpu->master; - GBALog(gba, GBA_LOG_DEBUG, "SWI: %02x", immediate); + GBALog(gba, GBA_LOG_SWI, "SWI: %02X r0: %08X r1: %08X r2: %08X r3: %08X", + immediate, cpu->gprs[0], cpu->gprs[1], cpu->gprs[2], cpu->gprs[3]); if (gba->memory.fullBios) { ARMRaiseSWI(cpu);@@ -137,10 +140,10 @@ // IntrWait
ARMRaiseSWI(cpu); break; case 0x6: - _Div(cpu, cpu->gprs[0], cpu->gprs[1]); + _Div(gba, cpu->gprs[0], cpu->gprs[1]); break; case 0x7: - _Div(cpu, cpu->gprs[1], cpu->gprs[0]); + _Div(gba, cpu->gprs[1], cpu->gprs[0]); break; case 0x8: cpu->gprs[0] = sqrt(cpu->gprs[0]);@@ -226,7 +229,7 @@ case 0x1F:
_MidiKey2Freq(gba); break; default: - GBALog(gba, GBA_LOG_STUB, "Stub software interrupt: %02x", immediate); + GBALog(gba, GBA_LOG_STUB, "Stub software interrupt: %02X", immediate); } }
@@ -62,9 +62,9 @@ 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, // DMA - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Timers
@@ -8,8 +8,9 @@ #include "gba-serialize.h"
#include "hle-bios.h" #include "util/memory.h" +static uint32_t _popcount32(unsigned bits); + 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 +28,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 +70,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) {@@ -136,6 +138,10 @@ case BASE_WORKING_IRAM:
cpu->memory.activeRegion = memory->iwram; cpu->memory.activeMask = SIZE_WORKING_IRAM - 1; break; + case BASE_VRAM: + cpu->memory.activeRegion = (uint32_t*) gba->video.renderer->vram; + cpu->memory.activeMask = 0x0000FFFF; + break; case BASE_CART0: case BASE_CART0_EX: case BASE_CART1:@@ -159,42 +165,83 @@ cpu->memory.activeUncachedCycles32 = memory->waitstatesNonseq32[memory->activeRegion];
cpu->memory.activeUncachedCycles16 = memory->waitstatesNonseq16[memory->activeRegion]; } +#define LOAD_BIOS \ + if (memory->activeRegion == REGION_BIOS) { \ + if (address < SIZE_BIOS) { \ + LOAD_32(value, address, memory->bios); \ + } else { \ + value = 0; \ + } \ + } else { \ + value = memory->biosPrefetch; \ + } + +#define LOAD_WORKING_RAM \ + LOAD_32(value, address & (SIZE_WORKING_RAM - 1), memory->wram); \ + wait += waitstatesRegion[REGION_WORKING_RAM]; + +#define LOAD_WORKING_IRAM LOAD_32(value, address & (SIZE_WORKING_IRAM - 1), memory->iwram); +#define LOAD_IO value = GBAIORead(gba, (address & (SIZE_IO - 1)) & ~2) | (GBAIORead(gba, (address & (SIZE_IO - 1)) | 2) << 16); + +#define LOAD_PALETTE_RAM \ + LOAD_32(value, address & (SIZE_PALETTE_RAM - 1), gba->video.palette); \ + ++wait; + +#define LOAD_VRAM \ + LOAD_32(value, address & 0x0001FFFF, gba->video.renderer->vram); \ + ++wait; + +#define LOAD_OAM LOAD_32(value, address & (SIZE_OAM - 1), gba->video.oam.raw); + +#define LOAD_CART \ + wait += waitstatesRegion[address >> BASE_OFFSET]; \ + if ((address & (SIZE_CART0 - 1)) < memory->romSize) { \ + LOAD_32(value, address & (SIZE_CART0 - 1), memory->rom); \ + } else { \ + GBALog(gba, GBA_LOG_GAME_ERROR, "Out of bounds ROM Load32: 0x%08X", address); \ + value = (address >> 1) & 0xFFFF; \ + value |= value << 16; \ + } + +#define LOAD_SRAM \ + GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Load32: 0x%08X", address); \ + value = 0xDEADBEEF; + +#define LOAD_BAD \ + GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Load32: 0x%08X", address); \ + value = cpu->prefetch; \ + if (cpu->executionMode == MODE_THUMB) { \ + value |= value << 16; \ + } + int32_t GBALoad32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { struct GBA* gba = (struct GBA*) cpu->master; struct GBAMemory* memory = &gba->memory; uint32_t value = 0; int wait = 0; + char* waitstatesRegion = memory->waitstatesNonseq32; 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; - } + LOAD_BIOS; break; case REGION_WORKING_RAM: - LOAD_32(value, address & (SIZE_WORKING_RAM - 1), memory->wram); - wait = memory->waitstatesNonseq32[REGION_WORKING_RAM]; + LOAD_WORKING_RAM; break; case REGION_WORKING_IRAM: - LOAD_32(value, address & (SIZE_WORKING_IRAM - 1), memory->iwram); + LOAD_WORKING_IRAM; break; case REGION_IO: - value = GBAIORead(gba, (address & (SIZE_IO - 1)) & ~2) | (GBAIORead(gba, (address & (SIZE_IO - 1)) | 2) << 16); + LOAD_IO; break; case REGION_PALETTE_RAM: - LOAD_32(value, address & (SIZE_PALETTE_RAM - 1), gba->video.palette); + LOAD_PALETTE_RAM; break; case REGION_VRAM: - LOAD_32(value, address & 0x0001FFFF, gba->video.renderer->vram); + LOAD_VRAM; break; case REGION_OAM: - LOAD_32(value, address & (SIZE_OAM - 1), gba->video.oam.raw); + LOAD_OAM; break; case REGION_CART0: case REGION_CART0_EX:@@ -202,21 +249,14 @@ case REGION_CART1:
case REGION_CART1_EX: case REGION_CART2: case REGION_CART2_EX: - wait = memory->waitstatesNonseq32[address >> BASE_OFFSET]; - if ((address & (SIZE_CART0 - 1)) < memory->romSize) { - LOAD_32(value, address & (SIZE_CART0 - 1), memory->rom); - } + LOAD_CART; break; case REGION_CART_SRAM: case REGION_CART_SRAM_MIRROR: - GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Load32: 0x%08X", address); + LOAD_SRAM; 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; - } + LOAD_BAD; break; }@@ -277,6 +317,9 @@ case REGION_CART2:
wait = memory->waitstatesNonseq16[address >> BASE_OFFSET]; if ((address & (SIZE_CART0 - 1)) < memory->romSize) { LOAD_16(value, address & (SIZE_CART0 - 1), memory->rom); + } else { + GBALog(gba, GBA_LOG_GAME_ERROR, "Out of bounds ROM Load16: 0x%08X", address); + value = (address >> 1) & 0xFFFF; \ } break; case REGION_CART2_EX:@@ -285,6 +328,9 @@ if (memory->savedata.type == SAVEDATA_EEPROM) {
value = GBASavedataReadEEPROM(&memory->savedata); } else if ((address & (SIZE_CART0 - 1)) < memory->romSize) { LOAD_16(value, address & (SIZE_CART0 - 1), memory->rom); + } else { + GBALog(gba, GBA_LOG_GAME_ERROR, "Out of bounds ROM Load16: 0x%08X", address); + value = (address >> 1) & 0xFFFF; \ } break; case REGION_CART_SRAM:@@ -355,18 +401,25 @@ case REGION_CART2_EX:
wait = memory->waitstatesNonseq16[address >> BASE_OFFSET]; if ((address & (SIZE_CART0 - 1)) < memory->romSize) { value = ((int8_t*) memory->rom)[address & (SIZE_CART0 - 1)]; + } else { + GBALog(gba, GBA_LOG_GAME_ERROR, "Out of bounds ROM Load8: 0x%08X", address); + value = (address >> 1) & 0xFF; \ } break; case REGION_CART_SRAM: case REGION_CART_SRAM_MIRROR: wait = memory->waitstatesNonseq16[address >> BASE_OFFSET]; if (memory->savedata.type == SAVEDATA_NONE) { + GBALog(gba, GBA_LOG_INFO, "Detected SRAM savegame"); GBASavedataInitSRAM(&memory->savedata); } if (memory->savedata.type == SAVEDATA_SRAM) { value = memory->savedata.data[address & (SIZE_CART_SRAM - 1)]; } else if (memory->savedata.type == SAVEDATA_FLASH512 || memory->savedata.type == SAVEDATA_FLASH1M) { value = GBASavedataReadFlash(&memory->savedata, address); + } else { + GBALog(gba, GBA_LOG_GAME_ERROR, "Reading from non-existent SRAM: 0x%08X", address); + value = 7; } break; default:@@ -381,48 +434,83 @@ }
return value; } +#define STORE_WORKING_RAM \ + STORE_32(value, address & (SIZE_WORKING_RAM - 1), memory->wram); \ + wait += waitstatesRegion[REGION_WORKING_RAM]; + +#define STORE_WORKING_IRAM \ + STORE_32(value, address & (SIZE_WORKING_IRAM - 1), memory->iwram); + +#define STORE_IO \ + GBAIOWrite32(gba, address & (SIZE_IO - 1), value); + +#define STORE_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); \ + ++wait; \ + gba->video.renderer->writePalette(gba->video.renderer, address & (SIZE_PALETTE_RAM - 1), value); + +#define STORE_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); \ + } \ + ++wait; + +#define STORE_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); + +#define STORE_CART \ + GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Store32: 0x%08X", address); + +#define STORE_SRAM \ + GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Store32: 0x%08X", address); + +#define STORE_BAD \ + GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Store32: 0x%08X", address); + void GBAStore32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) { struct GBA* gba = (struct GBA*) cpu->master; struct GBAMemory* memory = &gba->memory; int wait = 0; + char* waitstatesRegion = memory->waitstatesNonseq32; switch (address >> BASE_OFFSET) { case REGION_WORKING_RAM: - STORE_32(value, address & (SIZE_WORKING_RAM - 1), memory->wram); - wait = memory->waitstatesNonseq32[REGION_WORKING_RAM]; + STORE_WORKING_RAM; break; case REGION_WORKING_IRAM: - STORE_32(value, address & (SIZE_WORKING_IRAM - 1), memory->iwram); + STORE_WORKING_IRAM break; case REGION_IO: - GBAIOWrite32(gba, address & (SIZE_IO - 1), value); + STORE_IO; 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); + STORE_PALETTE_RAM; 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); - } + STORE_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); + STORE_OAM; break; case REGION_CART0: - GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Store32: 0x%08X", address); + case REGION_CART0_EX: + case REGION_CART1: + case REGION_CART1_EX: + case REGION_CART2: + case REGION_CART2_EX: + STORE_CART; break; case REGION_CART_SRAM: case REGION_CART_SRAM_MIRROR: - GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Store32: 0x%08X", address); + STORE_SRAM; break; default: - GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Store32: 0x%08X", address); + STORE_BAD; break; }@@ -472,6 +560,7 @@ }
break; case REGION_CART2_EX: if (memory->savedata.type == SAVEDATA_NONE) { + GBALog(gba, GBA_LOG_INFO, "Detected EEPROM savegame"); GBASavedataInitEEPROM(&memory->savedata); } GBASavedataWriteEEPROM(&memory->savedata, value, 1);@@ -528,8 +617,10 @@ case REGION_CART_SRAM:
case REGION_CART_SRAM_MIRROR: if (memory->savedata.type == SAVEDATA_NONE) { if (address == SAVEDATA_FLASH_BASE) { + GBALog(gba, GBA_LOG_INFO, "Detected Flash savegame"); GBASavedataInitFlash(&memory->savedata); } else { + GBALog(gba, GBA_LOG_INFO, "Detected SRAM savegame"); GBASavedataInitSRAM(&memory->savedata); } }@@ -537,6 +628,8 @@ if (memory->savedata.type == SAVEDATA_FLASH512 || memory->savedata.type == SAVEDATA_FLASH1M) {
GBASavedataWriteFlash(&memory->savedata, address, value); } else if (memory->savedata.type == SAVEDATA_SRAM) { memory->savedata.data[address & (SIZE_CART_SRAM - 1)] = value; + } else { + GBALog(gba, GBA_LOG_GAME_ERROR, "Writing to non-existent SRAM: 0x%08X", address); } wait = memory->waitstatesNonseq16[REGION_CART_SRAM]; break;@@ -550,12 +643,212 @@ *cycleCounter += 1 + wait;
} } -static int GBAWaitMultiple(struct ARMCore* cpu, uint32_t startAddress, int count) { +#define LDM_LOOP_BEGIN \ + for (i = 0; i < 16; ++i) { \ + if (!(mask & (1 << i))) { \ + continue; \ + } + +#define LDM_LOOP_END \ + waitstatesRegion = memory->waitstatesSeq32; \ + cpu->gprs[i] = value; \ + ++wait; \ + address += 4; \ + } + +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 = 0; + char* waitstatesRegion = memory->waitstatesNonseq32; + + int i; + int offset = 4; + int popcount = 0; + if (direction & LSM_D) { + offset = -4; + popcount = _popcount32(mask); + address -= (popcount << 2) - 4; + } + + if (direction & LSM_B) { + address += offset; + } + + address &= 0xFFFFFFFC; + + switch (address >> BASE_OFFSET) { + case REGION_WORKING_RAM: + LDM_LOOP_BEGIN; + LOAD_WORKING_RAM; + LDM_LOOP_END; + break; + case REGION_WORKING_IRAM: + LDM_LOOP_BEGIN; + LOAD_WORKING_IRAM; + LDM_LOOP_END; + break; + case REGION_IO: + LDM_LOOP_BEGIN; + LOAD_IO; + LDM_LOOP_END; + break; + case REGION_PALETTE_RAM: + LDM_LOOP_BEGIN; + LOAD_PALETTE_RAM; + LDM_LOOP_END; + break; + case REGION_VRAM: + LDM_LOOP_BEGIN; + LOAD_VRAM; + LDM_LOOP_END; + break; + case REGION_OAM: + LDM_LOOP_BEGIN; + LOAD_OAM; + LDM_LOOP_END; + break; + case REGION_CART0: + case REGION_CART0_EX: + case REGION_CART1: + case REGION_CART1_EX: + case REGION_CART2: + case REGION_CART2_EX: + LDM_LOOP_BEGIN; + LOAD_CART; + LDM_LOOP_END; + break; + case REGION_CART_SRAM: + case REGION_CART_SRAM_MIRROR: + LDM_LOOP_BEGIN; + LOAD_SRAM; + LDM_LOOP_END; + break; + default: + LDM_LOOP_BEGIN; + LOAD_BAD; + LDM_LOOP_END; + break; + } + + if (cycleCounter) { + *cycleCounter += wait; + } + + if (direction & LSM_B) { + address -= offset; + } + + if (direction & LSM_D) { + address -= (popcount << 2) + 4; + } + + return address; +} + +#define STM_LOOP_BEGIN \ + for (i = 0; i < 16; ++i) { \ + if (!(mask & (1 << i))) { \ + continue; \ + } \ + value = cpu->gprs[i]; + +#define STM_LOOP_END \ + waitstatesRegion = memory->waitstatesSeq32; \ + ++wait; \ + address += 4; \ + } + +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 = 0; + char* waitstatesRegion = memory->waitstatesNonseq32; + + int i; + int offset = 4; + int popcount = 0; + if (direction & LSM_D) { + offset = -4; + popcount = _popcount32(mask); + address -= (popcount << 2) - 4; + } + + if (direction & LSM_B) { + address += offset; + } + + address &= 0xFFFFFFFC; + + switch (address >> BASE_OFFSET) { + case REGION_WORKING_RAM: + STM_LOOP_BEGIN; + STORE_WORKING_RAM; + STM_LOOP_END; + break; + case REGION_WORKING_IRAM: + STM_LOOP_BEGIN; + STORE_WORKING_IRAM; + STM_LOOP_END; + break; + case REGION_IO: + STM_LOOP_BEGIN; + STORE_IO; + STM_LOOP_END; + break; + case REGION_PALETTE_RAM: + STM_LOOP_BEGIN; + STORE_PALETTE_RAM; + STM_LOOP_END; + break; + case REGION_VRAM: + STM_LOOP_BEGIN; + STORE_VRAM; + STM_LOOP_END; + break; + case REGION_OAM: + STM_LOOP_BEGIN; + STORE_OAM; + STM_LOOP_END; + break; + case REGION_CART0: + case REGION_CART0_EX: + case REGION_CART1: + case REGION_CART1_EX: + case REGION_CART2: + case REGION_CART2_EX: + STM_LOOP_BEGIN; + STORE_CART; + STM_LOOP_END; + break; + case REGION_CART_SRAM: + case REGION_CART_SRAM_MIRROR: + STM_LOOP_BEGIN; + STORE_SRAM; + STM_LOOP_END; + break; + default: + STM_LOOP_BEGIN; + STORE_BAD; + STM_LOOP_END; + break; + } + + if (cycleCounter) { + *cycleCounter += wait; + } + + if (direction & LSM_B) { + address -= offset; + } + + if (direction & LSM_D) { + address -= (popcount << 2) + 4; + } + + return address; } void GBAAdjustWaitstates(struct GBA* gba, uint16_t parameters) {@@ -813,6 +1106,7 @@ dest += destOffset;
--wordsRemaining; } else if (destRegion == REGION_CART2_EX) { if (memory->savedata.type == SAVEDATA_NONE) { + GBALog(gba, GBA_LOG_INFO, "Detected EEPROM savegame"); GBASavedataInitEEPROM(&memory->savedata); } word = cpu->memory.load16(cpu, source, 0);@@ -852,11 +1146,8 @@ info->nextCount = wordsRemaining;
} info->nextSource = source; - int i; - for (i = 0; i < 4; ++i) { - if (memory->dma[i].nextEvent != INT_MAX) { - memory->dma[i].nextEvent += cycles; - } + if (info->nextEvent != INT_MAX) { + info->nextEvent += cycles; } cpu->cycles += cycles; }@@ -870,3 +1161,9 @@ void GBAMemoryDeserialize(struct GBAMemory* memory, struct GBASerializedState* state) {
memcpy(memory->wram, state->wram, SIZE_WORKING_RAM); memcpy(memory->iwram, state->iwram, SIZE_WORKING_IRAM); } + +uint32_t _popcount32(unsigned bits) { + bits = bits - ((bits >> 1) & 0x55555555); + bits = (bits & 0x33333333) + ((bits >> 2) & 0x33333333); + return (((bits + (bits >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; +}
@@ -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);
@@ -70,6 +70,9 @@ savedata->mapMode = MAP_READ;
} void GBASavedataUnmask(struct GBASavedata* savedata) { + if (savedata->mapMode != MAP_READ) { + return; + } GBASavedataDeinit(savedata); savedata->vf = savedata->realVf; savedata->mapMode = MAP_WRITE;
@@ -114,7 +114,6 @@
GBACreate(&gba); ARMSetComponents(&cpu, &gba.d, numComponents, components); ARMInit(&cpu); - ARMReset(&cpu); threadContext->gba = &gba; gba.sync = &threadContext->sync; gba.logLevel = threadContext->logLevel;@@ -144,6 +143,8 @@ if (threadContext->patch && loadPatch(threadContext->patch, &patch)) {
GBAApplyPatch(&gba, &patch); } } + + ARMReset(&cpu); if (threadContext->debugger) { threadContext->debugger->log = GBADebuggerLogShim;@@ -281,6 +282,7 @@
} if (!threadContext->rom) { + threadContext->state = THREAD_SHUTDOWN; return false; }
@@ -14,8 +14,8 @@
const uint32_t GBA_ARM7TDMI_FREQUENCY = 0x1000000; const uint32_t GBA_COMPONENT_MAGIC = 0x1000000; -static const size_t GBA_ROM_MAGIC_OFFSET = 4; -static const uint8_t GBA_ROM_MAGIC[] = { 0x24, 0xFF, 0xAE, 0x51, 0x69, 0x9A, 0xA2, 0x21 }; +static const size_t GBA_ROM_MAGIC_OFFSET = 2; +static const uint8_t GBA_ROM_MAGIC[] = { 0x00, 0xEA }; enum { SP_BASE_SYSTEM = 0x03FFFF00,@@ -427,8 +427,8 @@ } else {
GBALog(gba, GBA_LOG_WARN, "BIOS checksum incorrect"); } gba->biosChecksum = checksum; - if ((gba->cpu->gprs[ARM_PC] >> BASE_OFFSET) == BASE_BIOS) { - gba->cpu->memory.setActiveRegion(gba->cpu, gba->cpu->gprs[ARM_PC]); + if (gba->memory.activeRegion == REGION_BIOS) { + gba->cpu->memory.activeRegion = gba->memory.bios; } // TODO: error check }@@ -651,9 +651,15 @@
void _checkOverrides(struct GBA* gba, uint32_t id) { int i; gba->busyLoop = -1; + if ((id & 0xFF) == 'F') { + GBALog(gba, GBA_LOG_DEBUG, "Found Classic NES Series game, using EEPROM saves"); + GBASavedataInitEEPROM(&gba->memory.savedata); + return; + } for (i = 0; _overrides[i].id[0]; ++i) { const uint32_t* overrideId = (const uint32_t*) _overrides[i].id; if (*overrideId == id) { + GBALog(gba, GBA_LOG_DEBUG, "Found override for game %s!", _overrides[i].id); switch (_overrides[i].type) { case SAVEDATA_FLASH512: case SAVEDATA_FLASH1M:
@@ -43,7 +43,10 @@ GBA_LOG_INFO = 0x08,
GBA_LOG_DEBUG = 0x10, GBA_LOG_STUB = 0x20, - GBA_LOG_GAME_ERROR = 0x100 + GBA_LOG_GAME_ERROR = 0x100, + GBA_LOG_SWI = 0x200, + + GBA_LOG_ALL = 0x33F }; enum GBAKey {
@@ -624,7 +624,7 @@ for (w = 0; w < renderer->nWindows; ++w) {
renderer->start = renderer->end; renderer->end = renderer->windows[w].endX; renderer->currentWindow = renderer->windows[w].control; - if (!GBAWindowControlIsObjEnable(renderer->currentWindow.packed)) { + if (!GBAWindowControlIsObjEnable(renderer->currentWindow.packed) && !GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt)) { continue; } int i;@@ -1605,25 +1605,39 @@ uint32_t* pixel = renderer->row;
uint32_t flags = FLAG_TARGET_2 * renderer->target2Obj; int objwinSlowPath = GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt); - int objwinDisable = 0; + bool objwinDisable = false; + bool objwinOnly = false; if (objwinSlowPath) { objwinDisable = !GBAWindowControlIsObjEnable(renderer->objwin.packed); + // TODO: Fix this for current window when WIN0/1 are enabled + objwinOnly = !objwinDisable && !GBAWindowControlIsObjEnable(renderer->winout.packed); } - if (objwinSlowPath && objwinDisable) { - for (x = 0; x < VIDEO_HORIZONTAL_PIXELS; ++x, ++pixel) { - uint32_t color = renderer->spriteLayer[x] & ~FLAG_OBJWIN; - uint32_t current = *pixel; - if ((color & FLAG_UNWRITTEN) != FLAG_UNWRITTEN && !(current & FLAG_OBJWIN) && (color & FLAG_PRIORITY) >> OFFSET_PRIORITY == priority) { - _compositeBlendObjwin(renderer, pixel, color | flags, current); + if (objwinSlowPath) { + if (objwinDisable) { + for (x = 0; x < VIDEO_HORIZONTAL_PIXELS; ++x, ++pixel) { + uint32_t color = renderer->spriteLayer[x] & ~FLAG_OBJWIN; + uint32_t current = *pixel; + if ((color & FLAG_UNWRITTEN) != FLAG_UNWRITTEN && !(current & FLAG_OBJWIN) && (color & FLAG_PRIORITY) >> OFFSET_PRIORITY == priority) { + _compositeBlendObjwin(renderer, pixel, color | flags, current); + } } - } - } else { - for (x = 0; x < VIDEO_HORIZONTAL_PIXELS; ++x, ++pixel) { - uint32_t color = renderer->spriteLayer[x] & ~FLAG_OBJWIN; - uint32_t current = *pixel; - if ((color & FLAG_UNWRITTEN) != FLAG_UNWRITTEN && (color & FLAG_PRIORITY) >> OFFSET_PRIORITY == priority) { - _compositeBlendNoObjwin(renderer, pixel, color | flags, current); + return; + } else if (objwinOnly) { + for (x = 0; x < VIDEO_HORIZONTAL_PIXELS; ++x, ++pixel) { + uint32_t color = renderer->spriteLayer[x] & ~FLAG_OBJWIN; + uint32_t current = *pixel; + if ((color & FLAG_UNWRITTEN) != FLAG_UNWRITTEN && (current & FLAG_OBJWIN) && (color & FLAG_PRIORITY) >> OFFSET_PRIORITY == priority) { + _compositeBlendObjwin(renderer, pixel, color | flags, current); + } } + return; + } + } + for (x = 0; x < VIDEO_HORIZONTAL_PIXELS; ++x, ++pixel) { + uint32_t color = renderer->spriteLayer[x] & ~FLAG_OBJWIN; + uint32_t current = *pixel; + if ((color & FLAG_UNWRITTEN) != FLAG_UNWRITTEN && (color & FLAG_PRIORITY) >> OFFSET_PRIORITY == priority) { + _compositeBlendNoObjwin(renderer, pixel, color | flags, current); } } }
@@ -1,103 +0,0 @@
-#include "debugger.h" -#include "gba-thread.h" -#include "gba.h" -#include "renderers/video-glsl.h" -#include "sdl-events.h" - -#include <SDL.h> -#ifdef __APPLE__ -#include <OpenGL/gl.h> -#else -#include <GL/gl.h> -#endif - -#include <fcntl.h> -#include <errno.h> -#include <signal.h> -#include <sys/time.h> - -static int _GBASDLInit(void); -static void _GBASDLDeinit(void); -static void _GBASDLRunloop(struct GBAThread* context, struct GBAVideoGLSLRenderer* renderer); - -int main(int argc, char** argv) { - const char* fname = "test.rom"; - if (argc > 1) { - fname = argv[1]; - } - int fd = open(fname, O_RDONLY); - if (fd < 0) { - return 1; - } - - struct GBAThread context; - struct GBAVideoGLSLRenderer renderer; - - if (!_GBASDLInit()) { - return 1; - } - GBAVideoGLSLRendererCreate(&renderer); - - context.fd = fd; - context.renderer = &renderer.d; - GBAThreadStart(&context); - - _GBASDLRunloop(&context, &renderer); - - GBAThreadJoin(&context); - close(fd); - - _GBASDLDeinit(); - - return 0; -} - -static int _GBASDLInit() { - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - return 0; - } - - GBASDLInitEvents(); - - SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1); - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); - SDL_SetVideoMode(240, 160, 32, SDL_OPENGL); - - glViewport(0, 0, 240, 160); - - return 1; -} - -static void _GBASDLRunloop(struct GBAThread* context, struct GBAVideoGLSLRenderer* renderer) { - SDL_Event event; - - glEnable(GL_TEXTURE_2D); - while (context->state < THREAD_EXITING) { - GBAVideoGLSLRendererProcessEvents(renderer); - pthread_mutex_lock(&renderer->mutex); - if (renderer->d.framesPending) { - renderer->d.framesPending = 0; - pthread_mutex_unlock(&renderer->mutex); - - SDL_GL_SwapBuffers(); - - while (SDL_PollEvent(&event)) { - GBASDLHandleEvent(context, &event); - } - pthread_mutex_lock(&renderer->mutex); - pthread_cond_broadcast(&renderer->downCond); - } else { - pthread_cond_broadcast(&renderer->downCond); - pthread_cond_wait(&renderer->upCond, &renderer->mutex); - } - pthread_mutex_unlock(&renderer->mutex); - } -} - -static void _GBASDLDeinit() { - GBASDLDeinitEvents(); - SDL_Quit(); -}
@@ -76,10 +76,10 @@ frames = perfOpts.duration * 60;
} struct timeval tv; gettimeofday(&tv, 0); - uint64_t start = 1000000 * tv.tv_sec + tv.tv_usec; + uint64_t start = 1000000LL * tv.tv_sec + tv.tv_usec; _GBAPerfRunloop(&context, &frames, perfOpts.csv); gettimeofday(&tv, 0); - uint64_t end = 1000000 * tv.tv_sec + tv.tv_usec; + uint64_t end = 1000000LL * tv.tv_sec + tv.tv_usec; uint64_t duration = end - start; GBAThreadJoin(&context);
@@ -0,0 +1,25 @@
+#include "util/string.h" + +#include <string.h> + +#ifndef HAVE_STRNDUP +char* strndup(const char* start, size_t len) { + // This is suboptimal, but anything recent should have strndup + char* out = malloc((len + 1) * sizeof(char)); + strncpy(out, start, len); + out[len] = '\0'; + return out; +} +#endif + +char* strnrstr(const char* restrict haystack, const char* restrict needle, size_t len) { + char* last = 0; + const char* next = haystack; + size_t needleLen = strlen(needle); + for (; len >= needleLen; --len, ++next) { + if (strncmp(needle, next, needleLen) == 0) { + last = (char*) next; + } + } + return last; +}
@@ -0,0 +1,9 @@
+#ifndef UTIL_STRING_H +#define UTIL_STRING_H + +#include "util/common.h" + +char* strndup(const char* start, size_t len); +char* strnrstr(const char* restrict s1, const char* restrict s2, size_t len); + +#endif
@@ -1,5 +1,7 @@
#include "util/vfs.h" +#include "util/string.h" + #include <fcntl.h> #include <dirent.h>@@ -37,6 +39,12 @@
static const char* _vdeName(struct VDirEntry* vde); struct VFile* VFileOpen(const char* path, int flags) { + if (!path) { + return 0; + } +#ifdef _WIN32 + flags |= O_BINARY; +#endif int fd = open(path, flags, 0666); return VFileFromFD(fd); }@@ -131,7 +139,7 @@ if (size > fileSize) {
size = fileSize; } vfd->hMap = CreateFileMapping((HANDLE) _get_osfhandle(vfd->fd), 0, createFlags, 0, size & 0xFFFFFFFF, 0); - return MapViewOfFile(hMap, mapFiles, 0, 0, size); + return MapViewOfFile(vfd->hMap, mapFiles, 0, 0, size); } static void _vfdUnmap(struct VFile* vf, void* memory, size_t size) {@@ -273,14 +281,7 @@ size_t len = strlen(filename);
if (dotPoint) { len = (dotPoint - filename); } - const char* separator = 0; - const char* nextSeparator = filename; - size_t strstrlen = len; - while ((nextSeparator = strnstr(nextSeparator, infix, strstrlen))) { - strstrlen -= nextSeparator - separator - 1; - separator = nextSeparator; - ++nextSeparator; - } + const char* separator = strnrstr(filename, infix, len); if (!separator) { continue; }