Merge branch 'master' into port/qt

This commit is contained in:
Jeffrey Pfau 2014-10-25 01:53:15 -07:00
commit c8d5219212
25 changed files with 615 additions and 357 deletions

View File

@ -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,13 +32,17 @@ function(find_feature FEATURE_NAME FEATURE_REQUIRES)
return()
endif()
foreach(REQUIRE ${FEATURE_REQUIRES})
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)
set(${UREQUIRE}_FOUND ${${REQUIRE}_FOUND} 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 @@ add_definitions(-DBINARY_NAME="${BINARY_NAME}" -DPROJECT_NAME="${PROJECT_NAME}"
# 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)
@ -103,10 +113,6 @@ if(BUILD_BBB OR BUILD_RASPI)
endif()
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
list(APPEND OS_LIB bsd)
endif()
# Features
set(DEBUGGER_SRC ${CMAKE_SOURCE_DIR}/src/debugger/debugger.c ${CMAKE_SOURCE_DIR}/src/debugger/memory-debugger.c)

View File

@ -48,6 +48,15 @@ enum RegisterBank {
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 @@ struct ARMMemory {
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 @@ struct ARMMemory {
uint32_t activeUncachedCycles32;
uint32_t activeUncachedCycles16;
void (*setActiveRegion)(struct ARMCore*, uint32_t address);
int (*waitMultiple)(struct ARMCore*, uint32_t startAddress, int count);
};
struct ARMInterruptHandler {

View File

@ -110,7 +110,7 @@
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 @@
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_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_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 @@ static const ARMDecoder _armDecoderTable[0x1000] = {
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;

View File

@ -135,7 +135,9 @@ DEFINE_DATA_FORM_5_DECODER_THUMB(MVN, MVN, ARM_OPERAND_AFFECTED_1)
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_LOAD_STORE_WITH_REGISTER_THUMB(STRH2, STR, STORE_CYCLES, ARM_ACCESS_HALFW
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_LOAD_STORE_MULTIPLE_THUMB(STM)
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(BL1, BLH,
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 @@ static const ThumbDecoder _thumbDecoderTable[0x400] = {
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;

View File

@ -227,10 +227,23 @@ static const char* _armAccessTypeStrings[] = {
"",
"",
"",
"",
"sb",
"sh",
""
"",
"",
"",
"",
"",
"",
"tb",
"",
"",
"t",
"",
"",
""
};

View File

@ -108,6 +108,13 @@ enum ARMMemoryAccessType {
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 @@ struct ARMInstructionInfo {
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 sDataCycles : 10;
unsigned nDataCycles : 10;
unsigned sInstructionCycles : 4;
unsigned nInstructionCycles : 4;
unsigned sDataCycles : 10;
unsigned nDataCycles : 10;
};
void ARMDecodeARM(uint32_t opcode, struct ARMInstructionInfo* info);

View File

@ -241,6 +241,8 @@ static inline void _immediate(struct ARMCore* cpu, uint32_t opcode) {
#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 @@ static inline void _immediate(struct ARMCore* cpu, uint32_t opcode) {
#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, &currentCycles); \
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 @@ DEFINE_LOAD_STORE_T_INSTRUCTION_ARM(STRT,
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,

View File

@ -289,39 +289,30 @@ DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STR2, cpu->memory.store32(cpu, cpu->gprs[r
DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STRB2, cpu->memory.store8(cpu, cpu->gprs[rn] + cpu->gprs[rm], cpu->gprs[rd], &currentCycles); THUMB_STORE_POST_BODY;)
DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STRH2, cpu->memory.store16(cpu, cpu->gprs[rn] + cpu->gprs[rm], cpu->gprs[rd], &currentCycles); 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, &currentCycles); \
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)

View File

@ -201,7 +201,7 @@ static void _printBin(struct CLIDebugger* debugger, struct DebugVector* dv) {
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 @@ static bool _parse(struct CLIDebugger* debugger, const char* line, size_t count)
_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);

View File

@ -43,7 +43,6 @@ CREATE_WATCHPOINT_SHIM(loadU8, 1, uint8_t, (struct ARMCore* cpu, uint32_t addres
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 @@ void ARMDebuggerInstallMemoryShim(struct ARMDebugger* debugger) {
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 @@ void ARMDebuggerRemoveMemoryShim(struct ARMDebugger* debugger) {
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;
}

View File

@ -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 @@ size_t lexExpression(struct LexVector* lv, const char* string, size_t length) {
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 @@ size_t lexExpression(struct LexVector* lv, const char* string, size_t length) {
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 @@ size_t lexExpression(struct LexVector* lv, const char* string, size_t length) {
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));

View File

@ -99,13 +99,15 @@ static void _MidiKey2Freq(struct GBA* gba) {
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 @@ static void _Div(struct ARMCore* cpu, int32_t num, int32_t denom) {
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 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
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 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
_MidiKey2Freq(gba);
break;
default:
GBALog(gba, GBA_LOG_STUB, "Stub software interrupt: %02x", immediate);
GBALog(gba, GBA_LOG_STUB, "Stub software interrupt: %02X", immediate);
}
}

View File

@ -62,9 +62,9 @@ static const int _isSpecialRegister[REG_MAX >> 1] = {
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

View File

@ -8,8 +8,9 @@
#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 @@ void GBAMemoryInit(struct GBA* gba) {
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 @@ void GBAMemoryInit(struct GBA* gba) {
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 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) {
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 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) {
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 @@ int32_t GBALoad32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
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 @@ int16_t GBALoad16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
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 @@ int16_t GBALoad16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
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 @@ int8_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
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 @@ int8_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
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 @@ void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle
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 @@ void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCo
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 @@ void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCo
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 @@ void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCo
}
}
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;
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:
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;
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 @@ void GBAMemoryServiceDMA(struct GBA* gba, int number, struct GBADMA* info) {
--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 @@ void GBAMemoryServiceDMA(struct GBA* gba, int number, struct GBADMA* info) {
}
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* s
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;
}

View File

@ -149,6 +149,9 @@ void GBAStore32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycle
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);

View File

@ -70,6 +70,9 @@ void GBASavedataMask(struct GBASavedata* savedata, struct VFile* vf) {
}
void GBASavedataUnmask(struct GBASavedata* savedata) {
if (savedata->mapMode != MAP_READ) {
return;
}
GBASavedataDeinit(savedata);
savedata->vf = savedata->realVf;
savedata->mapMode = MAP_WRITE;

View File

@ -114,7 +114,6 @@ static THREAD_ENTRY _GBAThreadRun(void* context) {
GBACreate(&gba);
ARMSetComponents(&cpu, &gba.d, numComponents, components);
ARMInit(&cpu);
ARMReset(&cpu);
threadContext->gba = &gba;
gba.sync = &threadContext->sync;
gba.logLevel = threadContext->logLevel;
@ -145,6 +144,8 @@ static THREAD_ENTRY _GBAThreadRun(void* context) {
}
}
ARMReset(&cpu);
if (threadContext->debugger) {
threadContext->debugger->log = GBADebuggerLogShim;
GBAAttachDebugger(&gba, threadContext->debugger);
@ -281,6 +282,7 @@ bool GBAThreadStart(struct GBAThread* threadContext) {
}
if (!threadContext->rom) {
threadContext->state = THREAD_SHUTDOWN;
return false;
}

View File

@ -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 @@ void GBALoadBIOS(struct GBA* gba, struct VFile* vf) {
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 GBAIllegal(struct ARMCore* cpu, uint32_t opcode) {
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:

View File

@ -43,7 +43,10 @@ enum GBALogLevel {
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 {

View File

@ -624,7 +624,7 @@ static void _drawScanline(struct GBAVideoSoftwareRenderer* renderer, int y) {
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,11 +1605,15 @@ static void _postprocessSprite(struct GBAVideoSoftwareRenderer* renderer, unsign
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) {
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;
@ -1617,7 +1621,18 @@ static void _postprocessSprite(struct GBAVideoSoftwareRenderer* renderer, unsign
_compositeBlendObjwin(renderer, pixel, color | flags, current);
}
}
} else {
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;
@ -1625,7 +1640,6 @@ static void _postprocessSprite(struct GBAVideoSoftwareRenderer* renderer, unsign
_compositeBlendNoObjwin(renderer, pixel, color | flags, current);
}
}
}
}
static void _updatePalettes(struct GBAVideoSoftwareRenderer* renderer) {

View File

@ -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();
}

View File

@ -76,10 +76,10 @@ int main(int argc, char** argv) {
}
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);

25
src/util/string.c Normal file
View File

@ -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;
}

9
src/util/string.h Normal file
View File

@ -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

View File

@ -1,5 +1,7 @@
#include "util/vfs.h"
#include "util/string.h"
#include <fcntl.h>
#include <dirent.h>
@ -37,6 +39,12 @@ static struct VFile* _vdOpenFile(struct VDir* vd, const char* path, int mode);
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 @@ static void* _vfdMap(struct VFile* vf, size_t size, int flags) {
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 @@ struct VFile* VDirOptionalOpenIncrementFile(struct VDir* dir, const char* realPa
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;
}