diff --git a/.travis-deps.sh b/.travis-deps.sh index cf70b5010..27f885203 100755 --- a/.travis-deps.sh +++ b/.travis-deps.sh @@ -1,8 +1,7 @@ #!/bin/sh -set -e if [ $TRAVIS_OS_NAME = "osx" ]; then brew update - brew install qt5 ffmpeg imagemagick sdl2 libedit libelf libpng libzip + brew install qt5 ffmpeg sdl2 libedit libelf libpng libzip else sudo apt-get update sudo apt-get -y install libseccomp2 diff --git a/CHANGES b/CHANGES index 5ffcfb0c1..9eae56ea6 100644 --- a/CHANGES +++ b/CHANGES @@ -43,68 +43,91 @@ Features: - GB: Yanking gamepak now supported - Qt: Memory range dumping (closes mgba.io/i/1298) Emulation fixes: + - GB: Fix using boot ROM with MMM01 games + - GB Audio: Only reset channel 3 sample in DMG mode + - GB Audio: Sample inactive channels (fixes mgba.io/i/1455, mgba.io/i/1456) + - GB Audio: Fix channel 4 volume (fixes mgba.io/i/1529) + - GB I/O: Filter IE top bits properly (fixes mgba.io/i/1329) + - GB Memory: Better emulate 0xFEA0 region on DMG, MGB and AGB + - GB Video: Delay LYC STAT check (fixes mgba.io/i/1331) + - GB Video: Fix window being enabled mid-scanline (fixes mgba.io/i/1328) + - GB Video: Fix mode 0 window edge case (fixes mgba.io/i/1519) + - GB Video: Fix color scaling in AGB mode - GBA: All IRQs have 7 cycle delay (fixes mgba.io/i/539, mgba.io/i/1208) - GBA: Reset now reloads multiboot ROMs - GBA BIOS: Fix multiboot entry point (fixes Magic Floor) - - GB Video: Delay LYC STAT check (fixes mgba.io/i/1331) - - GB Video: Fix window being enabled mid-scanline (fixes mgba.io/i/1328) - - GB I/O: Filter IE top bits properly (fixes mgba.io/i/1329) - - GB Audio: Only reset channel 3 sample in DMG mode - - GB Audio: Sample inactive channels (fixes mgba.io/i/1455, mgba.io/i/1456) - - GB Memory: Better emulate 0xFEA0 region on DMG, MGB and AGB - - GB Video: Fix mode 0 window edge case (fixes mgba.io/i/1519) - - GB Audio: Fix channel 4 volume (fixes mgba.io/i/1529) - - GB Video: Fix color scaling in AGB mode - - GB: Fix using boot ROM with MMM01 games Other fixes: - - Qt: Fix some Qt display driver race conditions - Core: Improved lockstep driver reliability (Le Hoang Quyen) - - Qt: Fix menu bar staying hidden in full screen (fixes mgba.io/i/317) - - GB SIO: Fix lockstep failing games aren't reloaded - - Libretro: Fix crash changing allowing opposing directions (hhromic) - - GBA Cheats: Fix value incrementing in CB slide codes (fixes mgba.io/i/1501) - - Qt: Only show emulator restart warning once per settings saving - FFmpeg: Drain recording buffers - - Shaders: Fix gba-color shader resolution (fixes mgba.io/i/1435) - - Qt: Fix LibraryController initialization (fixes mgba.io/i/1324) - - Switch: Fix audio when video rate desyncs (fixes mgba.io/i/1532) - GB: Fix reading ROM immediately after unmapping BIOS + - GB SIO: Fix lockstep failing games aren't reloaded + - GBA Cheats: Fix value incrementing in CB slide codes (fixes mgba.io/i/1501) + - Libretro: Fix crash changing allowing opposing directions (hhromic) + - Qt: Fix some Qt display driver race conditions + - Qt: Fix menu bar staying hidden in full screen (fixes mgba.io/i/317) + - Qt: Only show emulator restart warning once per settings saving + - Qt: Fix LibraryController initialization (fixes mgba.io/i/1324) + - Shaders: Fix gba-color shader resolution (fixes mgba.io/i/1435) + - Switch: Fix audio when video rate desyncs (fixes mgba.io/i/1532) Misc: - - GBA Savedata: EEPROM performance fixes - - GBA Savedata: Automatically map 1Mbit Flash files as 1Mbit Flash - - GB Memory: Support running from blocked memory - - Qt: Don't unload ROM immediately if it crashes - - Debugger: Add breakpoint and watchpoint listing - - LR35902: Support PC-relative opcode decoding - - Qt: Support switching webcams + - CMake: Don't use libzip on embedded platforms (fixes mgba.io/i/1527) - Core: Add keysRead callback - - Qt: Cap window size on start to monitor size - - GBA BIOS: Add timings for HLE BIOS math functions (fixes mgba.io/i/1396) + - Core: Create game-related paths if they don't exist (fixes mgba.io/i/1446) + - Core: Add more memory search ops (closes mgba.io/i/1510) - Debugger: Make tracing compatible with breakpoints/watchpoints - Debugger: Print breakpoint/watchpoint number when inserting - - Qt: Open a message box for Qt frontend errors + - Feature: Switch from ImageMagick to FFmpeg for GIF generation - FFmpeg: Support audio-only recording + - GB Memory: Support running from blocked memory + - GBA BIOS: Add timings for HLE BIOS math functions (fixes mgba.io/i/1396) + - GBA BIOS: Fix clobbered registers in CpuSet (fixes mgba.io/i/1531) + - GBA Savedata: EEPROM performance fixes + - GBA Savedata: Automatically map 1Mbit Flash files as 1Mbit Flash + - Debugger: Add breakpoint and watchpoint listing + - LR35902: Support PC-relative opcode decoding + - mGUI: Remember name and position of last loaded game + - OpenGL: Only resize textures when needed + - Qt: Don't unload ROM immediately if it crashes + - Qt: Support switching webcams + - Qt: Cap window size on start to monitor size + - Qt: Open a message box for Qt frontend errors - Qt: Increase maximum magnifications and scaling - Qt: Add native FPS button to settings view - Qt: Improve sync code - - Switch: Dynamic display resizing - - Vita: L2/R2 and L3/R3 can now be mapped on PSTV (fixes mgba.io/i/1292) - - mGUI: Remember name and position of last loaded game - - Core: Create game-related paths if they don't exist (fixes mgba.io/i/1446) - Qt: Add option to pause on minimizing window (closes mgba.io/i/1379) - - Switch: Support file associations - Qt: Scale pixel color values to full range (fixes mgba.io/i/1511) - - Qt, OpenGL: Disable integer scaling for dimensions that don't fit - - Feature: Switch from ImageMagick to FFmpeg for GIF generation - - OpenGL: Only resize textures when needed - - GBA BIOS: Fix clobbered registers in CpuSet (fixes mgba.io/i/1531) - Qt: Remove What's This icon from dialogs - - CMake: Don't use libzip on embedded platforms (fixes mgba.io/i/1527) - Qt: Printer quality of life improvements (fixes mgba.io/i/1540) - Qt: Add copy and QoL improvements to graphic views (closes mgba.io/i/1541) - Qt: Show list of all sprites in sprite view - Qt: Add option for disabling OSD messages - - Core: Add more memory search ops (closes mgba.io/i/1510) + - Qt, OpenGL: Disable integer scaling for dimensions that don't fit + - Switch: Dynamic display resizing + - Switch: Support file associations + - Vita: L2/R2 and L3/R3 can now be mapped on PSTV (fixes mgba.io/i/1292) +Changes from beta 1: +Emulation fixes: + - ARM: Fix STR writeback pipeline stage + - ARM: Partially fix LDM/STM writeback with empty register list + - ARM: Fix stepping when events are pending + - GBA DMA: Fix case where DMAs could get misaligned (fixes mgba.io/i/1092) + - GBA Video: Fix OpenGL renderer 512x512 backgrounds (fixes mgba.io/i/1572) + - GBA Memory: Fix open bus from IWRAM (fixes mgba.io/i/1575) +Other fixes: + - 3DS: Fix screen darkening (fixes mgba.io/i/1562) + - Core: Fix uninitialized memory issues with graphics caches + - Core: Return null for out of bounds cached tile VRAM querying + - Vita: Fix analog controls (fixes mgba.io/i/1554) + - Qt: Fix fast forward mute being reset (fixes mgba.io/i/1574) + - Qt: Fix scrollbar arrows in memory view (fixes mgba.io/i/1558) + - Qt: Fix several cases where shader selections don't get saved + - Qt: Fix division by zero error in invalid TilePainter state +Misc: + - GB Memory: Support manual SRAM editing (fixes mgba.io/i/1580) + - SDL: Use controller GUID instead of name + +0.8 beta 1: (2019-10-20) +- Initial beta for 0.8 0.7.3: (2019-09-15) Emulation fixes: diff --git a/CMakeLists.txt b/CMakeLists.txt index a2206d926..914e82bd2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -636,7 +636,7 @@ if(USE_LIBZIP) if (LIBZIP_VERSION_MAJOR LESS 1) set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libzip2") elseif(LIBZIP_VERSION_MAJOR EQUAL 1) - set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libzip4") + set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libzip4|libzip5") else() message(AUTHOR_WARNING Unknown version of libzip detected: ${libzip_VERSION}) endif() diff --git a/src/arm/arm.c b/src/arm/arm.c index e2bef1d3f..28649266a 100644 --- a/src/arm/arm.c +++ b/src/arm/arm.c @@ -299,16 +299,14 @@ void ARMHalt(struct ARMCore* cpu) { } \ \ void ARM ## VERSION ## Run(struct ARMCore* cpu) { \ - if (cpu->cycles < cpu->nextEvent) { \ - if (cpu->executionMode == MODE_THUMB) { \ - Thumb ## VERSION ## Step(cpu); \ - } else { \ - ARM ## VERSION ## Step(cpu); \ - } \ - } \ - if (cpu->cycles >= cpu->nextEvent) { \ + while (cpu->cycles >= cpu->nextEvent) { \ cpu->irqh.processEvents(cpu); \ } \ + if (cpu->executionMode == MODE_THUMB) { \ + Thumb ## VERSION ## Step(cpu); \ + } else { \ + ARM ## VERSION ## Step(cpu); \ + } \ } \ \ void ARM ## VERSION ## RunLoop(struct ARMCore* cpu) { \ diff --git a/src/arm/isa-arm.c b/src/arm/isa-arm.c index 433f01e91..88fac2742 100644 --- a/src/arm/isa-arm.c +++ b/src/arm/isa-arm.c @@ -259,6 +259,11 @@ ATTRIBUTE_NOINLINE static void _neutralS(struct ARMCore* cpu, int32_t d) { currentCycles += ARMWritePC(cpu); \ } +#define ADDR_MODE_2_WRITEBACK_PRE_STORE(WB) +#define ADDR_MODE_2_WRITEBACK_POST_STORE(WB) WB +#define ADDR_MODE_2_WRITEBACK_PRE_LOAD(WB) WB +#define ADDR_MODE_2_WRITEBACK_POST_LOAD(WB) + #define ADDR_MODE_2_LSL (cpu->gprs[rm] << ADDR_MODE_2_I) #define ADDR_MODE_2_LSR (ADDR_MODE_2_I_TEST ? ((uint32_t) cpu->gprs[rm]) >> ADDR_MODE_2_I : 0) #define ADDR_MODE_2_ASR (ADDR_MODE_2_I_TEST ? ((int32_t) cpu->gprs[rm]) >> ADDR_MODE_2_I : ((int32_t) cpu->gprs[rm]) >> 31) @@ -426,7 +431,7 @@ ATTRIBUTE_NOINLINE static void _neutralS(struct ARMCore* cpu, int32_t d) { y = ARM_SXT_16(cpu->gprs[rs] >> 16); \ BODY) \ -#define DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME, ADDRESS, WRITEBACK, BODY) \ +#define DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME, ADDRESS, WRITEBACK, LS, BODY) \ DEFINE_INSTRUCTION_ARM(NAME, \ uint32_t address; \ int rn = (opcode >> 16) & 0xF; \ @@ -434,57 +439,58 @@ ATTRIBUTE_NOINLINE static void _neutralS(struct ARMCore* cpu, int32_t d) { int rm = opcode & 0xF; \ UNUSED(rm); \ address = ADDRESS; \ - WRITEBACK; \ - BODY;) + ADDR_MODE_2_WRITEBACK_PRE_ ## LS (WRITEBACK); \ + BODY; \ + ADDR_MODE_2_WRITEBACK_POST_ ## LS (WRITEBACK);) -#define DEFINE_LOAD_STORE_INSTRUCTION_SHIFTER_ARM(NAME, SHIFTER, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME, ADDR_MODE_2_RN, ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_INDEX(-, SHIFTER)), BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## U, ADDR_MODE_2_RN, ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_INDEX(+, SHIFTER)), BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## P, ADDR_MODE_2_INDEX(-, SHIFTER), , BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## PW, ADDR_MODE_2_INDEX(-, SHIFTER), ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_ADDRESS), BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## PU, ADDR_MODE_2_INDEX(+, SHIFTER), , BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## PUW, ADDR_MODE_2_INDEX(+, SHIFTER), ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_ADDRESS), BODY) +#define DEFINE_LOAD_STORE_INSTRUCTION_SHIFTER_ARM(NAME, SHIFTER, LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME, ADDR_MODE_2_RN, ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_INDEX(-, SHIFTER)), LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## U, ADDR_MODE_2_RN, ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_INDEX(+, SHIFTER)), LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## P, ADDR_MODE_2_INDEX(-, SHIFTER), , LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## PW, ADDR_MODE_2_INDEX(-, SHIFTER), ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_ADDRESS), LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## PU, ADDR_MODE_2_INDEX(+, SHIFTER), , LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## PUW, ADDR_MODE_2_INDEX(+, SHIFTER), ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_ADDRESS), LS, BODY) -#define DEFINE_LOAD_STORE_INSTRUCTION_ARM(NAME, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_SHIFTER_ARM(NAME ## _LSL_, ADDR_MODE_2_LSL, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_SHIFTER_ARM(NAME ## _LSR_, ADDR_MODE_2_LSR, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_SHIFTER_ARM(NAME ## _ASR_, ADDR_MODE_2_ASR, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_SHIFTER_ARM(NAME ## _ROR_, ADDR_MODE_2_ROR, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## I, ADDR_MODE_2_RN, ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_INDEX(-, ADDR_MODE_2_IMMEDIATE)), BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IU, ADDR_MODE_2_RN, ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_INDEX(+, ADDR_MODE_2_IMMEDIATE)), BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IP, ADDR_MODE_2_INDEX(-, ADDR_MODE_2_IMMEDIATE), , BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IPW, ADDR_MODE_2_INDEX(-, ADDR_MODE_2_IMMEDIATE), ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_ADDRESS), BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IPU, ADDR_MODE_2_INDEX(+, ADDR_MODE_2_IMMEDIATE), , BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IPUW, ADDR_MODE_2_INDEX(+, ADDR_MODE_2_IMMEDIATE), ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_ADDRESS), BODY) \ +#define DEFINE_LOAD_STORE_INSTRUCTION_ARM(NAME, LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_SHIFTER_ARM(NAME ## _LSL_, ADDR_MODE_2_LSL, LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_SHIFTER_ARM(NAME ## _LSR_, ADDR_MODE_2_LSR, LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_SHIFTER_ARM(NAME ## _ASR_, ADDR_MODE_2_ASR, LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_SHIFTER_ARM(NAME ## _ROR_, ADDR_MODE_2_ROR, LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## I, ADDR_MODE_2_RN, ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_INDEX(-, ADDR_MODE_2_IMMEDIATE)), LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IU, ADDR_MODE_2_RN, ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_INDEX(+, ADDR_MODE_2_IMMEDIATE)), LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IP, ADDR_MODE_2_INDEX(-, ADDR_MODE_2_IMMEDIATE), , LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IPW, ADDR_MODE_2_INDEX(-, ADDR_MODE_2_IMMEDIATE), ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_ADDRESS), LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IPU, ADDR_MODE_2_INDEX(+, ADDR_MODE_2_IMMEDIATE), , LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IPUW, ADDR_MODE_2_INDEX(+, ADDR_MODE_2_IMMEDIATE), ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_ADDRESS), LS, BODY) \ -#define DEFINE_LOAD_STORE_MODE_3_WRITEBACK_WIDTH_INSTRUCTION_ARM(NAME, BODY, WRITEBACK) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME, ADDR_MODE_3_RN, WRITEBACK(ADDR_MODE_3_INDEX(-, ADDR_MODE_3_RM)), BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## U, ADDR_MODE_3_RN, WRITEBACK(ADDR_MODE_3_INDEX(+, ADDR_MODE_3_RM)), BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## P, ADDR_MODE_3_INDEX(-, ADDR_MODE_3_RM), , BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## PW, ADDR_MODE_3_INDEX(-, ADDR_MODE_3_RM), ADDR_MODE_3_WRITEBACK(ADDR_MODE_3_ADDRESS), BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## PU, ADDR_MODE_3_INDEX(+, ADDR_MODE_3_RM), , BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## PUW, ADDR_MODE_3_INDEX(+, ADDR_MODE_3_RM), ADDR_MODE_3_WRITEBACK(ADDR_MODE_3_ADDRESS), BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## I, ADDR_MODE_3_RN, WRITEBACK(ADDR_MODE_3_INDEX(-, ADDR_MODE_3_IMMEDIATE)), BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IU, ADDR_MODE_3_RN, WRITEBACK(ADDR_MODE_3_INDEX(+, ADDR_MODE_3_IMMEDIATE)), BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IP, ADDR_MODE_3_INDEX(-, ADDR_MODE_3_IMMEDIATE), , BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IPW, ADDR_MODE_3_INDEX(-, ADDR_MODE_3_IMMEDIATE), ADDR_MODE_3_WRITEBACK(ADDR_MODE_3_ADDRESS), BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IPU, ADDR_MODE_3_INDEX(+, ADDR_MODE_3_IMMEDIATE), , BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IPUW, ADDR_MODE_3_INDEX(+, ADDR_MODE_3_IMMEDIATE), ADDR_MODE_3_WRITEBACK(ADDR_MODE_3_ADDRESS), BODY) \ +#define DEFINE_LOAD_STORE_MODE_3_WRITEBACK_WIDTH_INSTRUCTION_ARM(NAME, LS, BODY, WRITEBACK) \ + DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME, ADDR_MODE_3_RN, WRITEBACK(ADDR_MODE_3_INDEX(-, ADDR_MODE_3_RM)), LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## U, ADDR_MODE_3_RN, WRITEBACK(ADDR_MODE_3_INDEX(+, ADDR_MODE_3_RM)), LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## P, ADDR_MODE_3_INDEX(-, ADDR_MODE_3_RM), , LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## PW, ADDR_MODE_3_INDEX(-, ADDR_MODE_3_RM), WRITEBACK(ADDR_MODE_3_ADDRESS), LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## PU, ADDR_MODE_3_INDEX(+, ADDR_MODE_3_RM), , LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## PUW, ADDR_MODE_3_INDEX(+, ADDR_MODE_3_RM), ADDR_MODE_3_WRITEBACK(ADDR_MODE_3_ADDRESS), LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## I, ADDR_MODE_3_RN, WRITEBACK(ADDR_MODE_3_INDEX(-, ADDR_MODE_3_IMMEDIATE)), LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IU, ADDR_MODE_3_RN, ADDR_MODE_3_WRITEBACK(ADDR_MODE_3_INDEX(+, ADDR_MODE_3_IMMEDIATE)), LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IP, ADDR_MODE_3_INDEX(-, ADDR_MODE_3_IMMEDIATE), , LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IPW, ADDR_MODE_3_INDEX(-, ADDR_MODE_3_IMMEDIATE), ADDR_MODE_3_WRITEBACK(ADDR_MODE_3_ADDRESS), LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IPU, ADDR_MODE_3_INDEX(+, ADDR_MODE_3_IMMEDIATE), , LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IPUW, ADDR_MODE_3_INDEX(+, ADDR_MODE_3_IMMEDIATE), ADDR_MODE_3_WRITEBACK(ADDR_MODE_3_ADDRESS), LS, BODY) \ -#define DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(NAME, BODY) DEFINE_LOAD_STORE_MODE_3_WRITEBACK_WIDTH_INSTRUCTION_ARM(NAME, BODY, ADDR_MODE_3_WRITEBACK) -#define DEFINE_LOAD_STORE_MODE_3_DOUBLE_INSTRUCTION_ARM(NAME, BODY) DEFINE_LOAD_STORE_MODE_3_WRITEBACK_WIDTH_INSTRUCTION_ARM(NAME, BODY, ADDR_MODE_3_WRITEBACK_64) +#define DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(NAME, LS, BODY) DEFINE_LOAD_STORE_MODE_3_WRITEBACK_WIDTH_INSTRUCTION_ARM(NAME, LS, BODY, ADDR_MODE_3_WRITEBACK) +#define DEFINE_LOAD_STORE_MODE_3_DOUBLE_INSTRUCTION_ARM(NAME, LS, BODY) DEFINE_LOAD_STORE_MODE_3_WRITEBACK_WIDTH_INSTRUCTION_ARM(NAME, LS, BODY, ADDR_MODE_3_WRITEBACK_64) -#define DEFINE_LOAD_STORE_T_INSTRUCTION_SHIFTER_ARM(NAME, SHIFTER, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME, SHIFTER, ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_INDEX(-, ADDR_MODE_2_RM)), BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## U, SHIFTER, ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_INDEX(+, ADDR_MODE_2_RM)), BODY) \ +#define DEFINE_LOAD_STORE_T_INSTRUCTION_SHIFTER_ARM(NAME, SHIFTER, LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME, SHIFTER, ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_INDEX(-, ADDR_MODE_2_RM)), LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## U, SHIFTER, ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_INDEX(+, ADDR_MODE_2_RM)), LS, BODY) \ -#define DEFINE_LOAD_STORE_T_INSTRUCTION_ARM(NAME, BODY) \ - DEFINE_LOAD_STORE_T_INSTRUCTION_SHIFTER_ARM(NAME ## _LSL_, ADDR_MODE_2_LSL, BODY) \ - DEFINE_LOAD_STORE_T_INSTRUCTION_SHIFTER_ARM(NAME ## _LSR_, ADDR_MODE_2_LSR, BODY) \ - DEFINE_LOAD_STORE_T_INSTRUCTION_SHIFTER_ARM(NAME ## _ASR_, ADDR_MODE_2_ASR, BODY) \ - DEFINE_LOAD_STORE_T_INSTRUCTION_SHIFTER_ARM(NAME ## _ROR_, ADDR_MODE_2_ROR, BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## I, ADDR_MODE_2_RN, ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_INDEX(-, ADDR_MODE_2_IMMEDIATE)), BODY) \ - DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IU, ADDR_MODE_2_RN, ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_INDEX(+, ADDR_MODE_2_IMMEDIATE)), BODY) \ +#define DEFINE_LOAD_STORE_T_INSTRUCTION_ARM(NAME, LS, BODY) \ + DEFINE_LOAD_STORE_T_INSTRUCTION_SHIFTER_ARM(NAME ## _LSL_, ADDR_MODE_2_LSL, LS, BODY) \ + DEFINE_LOAD_STORE_T_INSTRUCTION_SHIFTER_ARM(NAME ## _LSR_, ADDR_MODE_2_LSR, LS, BODY) \ + DEFINE_LOAD_STORE_T_INSTRUCTION_SHIFTER_ARM(NAME ## _ASR_, ADDR_MODE_2_ASR, LS, BODY) \ + DEFINE_LOAD_STORE_T_INSTRUCTION_SHIFTER_ARM(NAME ## _ROR_, ADDR_MODE_2_ROR, LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## I, ADDR_MODE_2_RN, ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_INDEX(-, ADDR_MODE_2_IMMEDIATE)), LS, BODY) \ + DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME ## IU, ADDR_MODE_2_RN, ADDR_MODE_2_WRITEBACK(ADDR_MODE_2_INDEX(+, ADDR_MODE_2_IMMEDIATE)), LS, BODY) \ #define ARM_MS_PRE \ enum PrivilegeMode privilegeMode = cpu->privilegeMode; \ @@ -636,19 +642,19 @@ DEFINE_MULTIPLY_INSTRUCTION_2_ARM(UMULL, // Begin load/store definitions -DEFINE_LOAD_STORE_INSTRUCTION_ARM(LDR, cpu->gprs[rd] = cpu->memory.load32(cpu, address, ¤tCycles); ARM_LOAD_POST_BODY;) -DEFINE_LOAD_STORE_INSTRUCTION_ARM(LDRv5, cpu->gprs[rd] = cpu->memory.load32(cpu, address, ¤tCycles); ARM_LOAD_POST_BODY_v5;) -DEFINE_LOAD_STORE_INSTRUCTION_ARM(LDRB, cpu->gprs[rd] = cpu->memory.load8(cpu, address, ¤tCycles); ARM_LOAD_POST_BODY;) -DEFINE_LOAD_STORE_MODE_3_DOUBLE_INSTRUCTION_ARM(LDRD, cpu->gprs[rd & ~1] = cpu->memory.load32(cpu, address, ¤tCycles); cpu->gprs[rd | 1] = cpu->memory.load32(cpu, address + 4, ¤tCycles); ARM_LOAD_POST_BODY;) -DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(LDRH, cpu->gprs[rd] = cpu->memory.load16(cpu, address, ¤tCycles); ARM_LOAD_POST_BODY;) -DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(LDRSB, cpu->gprs[rd] = ARM_SXT_8(cpu->memory.load8(cpu, address, ¤tCycles)); ARM_LOAD_POST_BODY;) -DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(LDRSH, cpu->gprs[rd] = address & 1 ? ARM_SXT_8(cpu->memory.load16(cpu, address, ¤tCycles)) : ARM_SXT_16(cpu->memory.load16(cpu, address, ¤tCycles)); ARM_LOAD_POST_BODY;) -DEFINE_LOAD_STORE_INSTRUCTION_ARM(STR, cpu->memory.store32(cpu, address, cpu->gprs[rd], ¤tCycles); ARM_STORE_POST_BODY;) -DEFINE_LOAD_STORE_INSTRUCTION_ARM(STRB, cpu->memory.store8(cpu, address, cpu->gprs[rd], ¤tCycles); ARM_STORE_POST_BODY;) -DEFINE_LOAD_STORE_MODE_3_DOUBLE_INSTRUCTION_ARM(STRD, cpu->memory.store32(cpu, address, cpu->gprs[rd & ~1], ¤tCycles); cpu->memory.store32(cpu, address + 4, cpu->gprs[rd | 1], ¤tCycles); ARM_STORE_POST_BODY;) -DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(STRH, cpu->memory.store16(cpu, address, cpu->gprs[rd], ¤tCycles); ARM_STORE_POST_BODY;) +DEFINE_LOAD_STORE_INSTRUCTION_ARM(LDR, LOAD, cpu->gprs[rd] = cpu->memory.load32(cpu, address, ¤tCycles); ARM_LOAD_POST_BODY;) +DEFINE_LOAD_STORE_INSTRUCTION_ARM(LDRv5, LOAD, cpu->gprs[rd] = cpu->memory.load32(cpu, address, ¤tCycles); ARM_LOAD_POST_BODY_v5;) +DEFINE_LOAD_STORE_INSTRUCTION_ARM(LDRB, LOAD, cpu->gprs[rd] = cpu->memory.load8(cpu, address, ¤tCycles); ARM_LOAD_POST_BODY;) +DEFINE_LOAD_STORE_MODE_3_DOUBLE_INSTRUCTION_ARM(LDRD, LOAD, cpu->gprs[rd & ~1] = cpu->memory.load32(cpu, address, ¤tCycles); cpu->gprs[rd | 1] = cpu->memory.load32(cpu, address + 4, ¤tCycles); ARM_LOAD_POST_BODY;) +DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(LDRH, LOAD, cpu->gprs[rd] = cpu->memory.load16(cpu, address, ¤tCycles); ARM_LOAD_POST_BODY;) +DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(LDRSB, LOAD, cpu->gprs[rd] = ARM_SXT_8(cpu->memory.load8(cpu, address, ¤tCycles)); ARM_LOAD_POST_BODY;) +DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(LDRSH, LOAD, cpu->gprs[rd] = address & 1 ? ARM_SXT_8(cpu->memory.load16(cpu, address, ¤tCycles)) : ARM_SXT_16(cpu->memory.load16(cpu, address, ¤tCycles)); ARM_LOAD_POST_BODY;) +DEFINE_LOAD_STORE_INSTRUCTION_ARM(STR, STORE, cpu->memory.store32(cpu, address, cpu->gprs[rd], ¤tCycles); ARM_STORE_POST_BODY;) +DEFINE_LOAD_STORE_INSTRUCTION_ARM(STRB, STORE, cpu->memory.store8(cpu, address, cpu->gprs[rd], ¤tCycles); ARM_STORE_POST_BODY;) +DEFINE_LOAD_STORE_MODE_3_DOUBLE_INSTRUCTION_ARM(STRD, STORE, cpu->memory.store32(cpu, address, cpu->gprs[rd & ~1], ¤tCycles); cpu->memory.store32(cpu, address + 4, cpu->gprs[rd | 1], ¤tCycles); ARM_STORE_POST_BODY;) +DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(STRH, STORE, cpu->memory.store16(cpu, address, cpu->gprs[rd], ¤tCycles); ARM_STORE_POST_BODY;) -DEFINE_LOAD_STORE_T_INSTRUCTION_ARM(LDRBT, +DEFINE_LOAD_STORE_T_INSTRUCTION_ARM(LDRBT, LOAD, enum PrivilegeMode priv = cpu->privilegeMode; ARMSetPrivilegeMode(cpu, MODE_USER); int32_t r = cpu->memory.load8(cpu, address, ¤tCycles); @@ -656,7 +662,7 @@ DEFINE_LOAD_STORE_T_INSTRUCTION_ARM(LDRBT, cpu->gprs[rd] = r; ARM_LOAD_POST_BODY;) -DEFINE_LOAD_STORE_T_INSTRUCTION_ARM(LDRT, +DEFINE_LOAD_STORE_T_INSTRUCTION_ARM(LDRT, LOAD, enum PrivilegeMode priv = cpu->privilegeMode; ARMSetPrivilegeMode(cpu, MODE_USER); int32_t r = cpu->memory.load32(cpu, address, ¤tCycles); @@ -664,7 +670,7 @@ DEFINE_LOAD_STORE_T_INSTRUCTION_ARM(LDRT, cpu->gprs[rd] = r; ARM_LOAD_POST_BODY;) -DEFINE_LOAD_STORE_T_INSTRUCTION_ARM(STRBT, +DEFINE_LOAD_STORE_T_INSTRUCTION_ARM(STRBT, STORE, enum PrivilegeMode priv = cpu->privilegeMode; int32_t r = cpu->gprs[rd]; ARMSetPrivilegeMode(cpu, MODE_USER); @@ -672,7 +678,7 @@ DEFINE_LOAD_STORE_T_INSTRUCTION_ARM(STRBT, ARMSetPrivilegeMode(cpu, priv); ARM_STORE_POST_BODY;) -DEFINE_LOAD_STORE_T_INSTRUCTION_ARM(STRT, +DEFINE_LOAD_STORE_T_INSTRUCTION_ARM(STRT, STORE, enum PrivilegeMode priv = cpu->privilegeMode; int32_t r = cpu->gprs[rd]; ARMSetPrivilegeMode(cpu, MODE_USER); @@ -683,7 +689,7 @@ DEFINE_LOAD_STORE_T_INSTRUCTION_ARM(STRT, DEFINE_LOAD_STORE_MULTIPLE_INSTRUCTION_ARM(LDM, load, currentCycles += cpu->memory.activeNonseqCycles32 - cpu->memory.activeSeqCycles32; - if (rs & 0x8000) { + if ((rs & 0x8000) || !rs) { currentCycles += ARMWritePC(cpu); }) diff --git a/src/arm/isa-thumb.c b/src/arm/isa-thumb.c index 85cc164cf..368c4f40f 100644 --- a/src/arm/isa-thumb.c +++ b/src/arm/isa-thumb.c @@ -295,6 +295,9 @@ DEFINE_LOAD_STORE_MULTIPLE_THUMB(LDMIA, IA, , THUMB_LOAD_POST_BODY; + if (!rs) { + currentCycles += ThumbWritePC(cpu); + } if (!((1 << rn) & rs)) { cpu->gprs[rn] = address; }) diff --git a/src/core/bitmap-cache.c b/src/core/bitmap-cache.c index c86768e45..cdbc90a0e 100644 --- a/src/core/bitmap-cache.c +++ b/src/core/bitmap-cache.c @@ -11,6 +11,7 @@ void mBitmapCacheInit(struct mBitmapCache* cache) { // TODO: Reconfigurable cache for space savings cache->cache = NULL; cache->config = mBitmapCacheConfigurationFillShouldStore(0); + cache->sysConfig = 0; cache->status = NULL; cache->palette = NULL; cache->buffer = 0; @@ -18,14 +19,18 @@ void mBitmapCacheInit(struct mBitmapCache* cache) { static void _freeCache(struct mBitmapCache* cache) { size_t size = mBitmapCacheSystemInfoGetHeight(cache->sysConfig) * mBitmapCacheSystemInfoGetBuffers(cache->sysConfig); - mappedMemoryFree(cache->cache, mBitmapCacheSystemInfoGetWidth(cache->sysConfig) * size * sizeof(color_t)); - mappedMemoryFree(cache->status, size * sizeof(*cache->status)); + if (cache->cache) { + mappedMemoryFree(cache->cache, mBitmapCacheSystemInfoGetWidth(cache->sysConfig) * size * sizeof(color_t)); + cache->cache = NULL; + } + if (cache->status) { + mappedMemoryFree(cache->status, size * sizeof(*cache->status)); + cache->status = NULL; + } if (cache->palette) { free(cache->palette); + cache->palette = NULL; } - cache->cache = NULL; - cache->status = NULL; - cache->palette = NULL; } static void _redoCacheSize(struct mBitmapCache* cache) { diff --git a/src/core/cheats.c b/src/core/cheats.c index fa45db291..acd994393 100644 --- a/src/core/cheats.c +++ b/src/core/cheats.c @@ -334,7 +334,7 @@ bool mCheatParseEZFChtFile(struct mCheatDevice* device, struct VFile* vf) { char cheat[MAX_LINE_LENGTH]; char cheatName[MAX_LINE_LENGTH]; char miniline[32]; - size_t cheatNameLength; + size_t cheatNameLength = 0; struct mCheatSet* set = NULL; cheatName[MAX_LINE_LENGTH - 1] = '\0'; diff --git a/src/core/map-cache.c b/src/core/map-cache.c index 495978672..470f72b89 100644 --- a/src/core/map-cache.c +++ b/src/core/map-cache.c @@ -11,15 +11,20 @@ void mMapCacheInit(struct mMapCache* cache) { // TODO: Reconfigurable cache for space savings cache->cache = NULL; cache->config = mMapCacheConfigurationFillShouldStore(0); + cache->sysConfig = 0; cache->status = NULL; } static void _freeCache(struct mMapCache* cache) { size_t tiles = (1 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig)) * (1 << mMapCacheSystemInfoGetTilesHigh(cache->sysConfig)); - mappedMemoryFree(cache->cache, 8 * 8 * sizeof(color_t) * tiles); - mappedMemoryFree(cache->status, tiles * sizeof(*cache->status)); - cache->cache = NULL; - cache->status = NULL; + if (cache->cache) { + mappedMemoryFree(cache->cache, 8 * 8 * sizeof(color_t) * tiles); + cache->cache = NULL; + } + if (cache->status) { + mappedMemoryFree(cache->status, tiles * sizeof(*cache->status)); + cache->status = NULL; + } } static void _redoCacheSize(struct mMapCache* cache) { diff --git a/src/core/tile-cache.c b/src/core/tile-cache.c index d1e1b9e25..89b4a52cb 100644 --- a/src/core/tile-cache.c +++ b/src/core/tile-cache.c @@ -51,6 +51,9 @@ static void _redoCacheSize(struct mTileCache* cache) { } void mTileCacheConfigure(struct mTileCache* cache, mTileCacheConfiguration config) { + if (cache->config == config) { + return; + } _freeCache(cache); cache->config = config; _redoCacheSize(cache); @@ -278,5 +281,9 @@ const color_t* mTileCacheGetPalette(struct mTileCache* cache, unsigned paletteId } const uint16_t* mTileCacheGetVRAM(struct mTileCache* cache, unsigned tileId) { + unsigned tiles = mTileCacheSystemInfoGetMaxTiles(cache->sysConfig); + if (tileId >= tiles) { + return NULL; + } return &cache->vram[tileId << (cache->bpp + 2)]; } diff --git a/src/gb/memory.c b/src/gb/memory.c index e5817cefe..e60fbde18 100644 --- a/src/gb/memory.c +++ b/src/gb/memory.c @@ -649,7 +649,15 @@ void GBPatch8(struct LR35902Core* cpu, uint16_t address, int8_t value, int8_t* o break; case GB_REGION_EXTERNAL_RAM: case GB_REGION_EXTERNAL_RAM + 1: - mLOG(GB_MEM, STUB, "Unimplemented memory Patch8: 0x%08X", address); + if (memory->rtcAccess) { + memory->rtcRegs[memory->activeRtcReg] = value; + } else if (memory->sramAccess && memory->sram && memory->mbcType != GB_MBC2) { + // TODO: Remove sramAccess check? + memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)] = value; + } else { + memory->mbcWrite(gb, address, value); + } + gb->sramDirty |= GB_SRAM_DIRT_NEW; return; case GB_REGION_WORKING_RAM_BANK0: case GB_REGION_WORKING_RAM_BANK0 + 2: diff --git a/src/gb/renderers/cache-set.c b/src/gb/renderers/cache-set.c index 9703c09c1..5426e5ac1 100644 --- a/src/gb/renderers/cache-set.c +++ b/src/gb/renderers/cache-set.c @@ -12,11 +12,13 @@ void GBVideoCacheInit(struct mCacheSet* cache) { mCacheSetInit(cache, 2, 0, 1); - mTileCacheConfiguration config = 0; - config = mTileCacheSystemInfoSetPaletteBPP(config, 1); // 2^(2^1) = 4 entries - config = mTileCacheSystemInfoSetPaletteCount(config, 4); // 16 palettes - config = mTileCacheSystemInfoSetMaxTiles(config, 1024); - mTileCacheConfigureSystem(mTileCacheSetGetPointer(&cache->tiles, 0), config, 0, 0); + mTileCacheSystemInfo sysconfig = 0; + mTileCacheConfiguration config = mTileCacheConfigurationFillShouldStore(0); + sysconfig = mTileCacheSystemInfoSetPaletteBPP(sysconfig, 1); // 2^(2^1) = 4 entries + sysconfig = mTileCacheSystemInfoSetPaletteCount(sysconfig, 4); // 16 palettes + sysconfig = mTileCacheSystemInfoSetMaxTiles(sysconfig, 1024); + mTileCacheConfigureSystem(mTileCacheSetGetPointer(&cache->tiles, 0), sysconfig, 0, 0); + mTileCacheConfigure(mTileCacheSetGetPointer(&cache->tiles, 0), config); mMapCacheSetGetPointer(&cache->maps, 0)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 0); mMapCacheSetGetPointer(&cache->maps, 1)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 0); diff --git a/src/gba/dma.c b/src/gba/dma.c index 765358da1..2c112716f 100644 --- a/src/gba/dma.c +++ b/src/gba/dma.c @@ -95,6 +95,8 @@ uint16_t GBADMAWriteCNT_HI(struct GBA* gba, int dma, uint16_t control) { if (currentDma->nextDest & (width - 1)) { mLOG(GBA_MEM, GAME_ERROR, "Misaligned DMA destination address: 0x%08X", currentDma->nextDest); } + currentDma->nextSource &= -width; + currentDma->nextDest &= -width; GBADMASchedule(gba, dma, currentDma); } @@ -242,8 +244,6 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) { } else { cycles += memory->waitstatesNonseq16[sourceRegion] + memory->waitstatesNonseq16[destRegion]; } - source &= -width; - dest &= -width; } else { if (width == 4) { cycles += memory->waitstatesSeq32[sourceRegion] + memory->waitstatesSeq32[destRegion]; diff --git a/src/gba/memory.c b/src/gba/memory.c index bc554b31b..062d83fd6 100644 --- a/src/gba/memory.c +++ b/src/gba/memory.c @@ -353,10 +353,10 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) { case REGION_WORKING_IRAM: \ /* This doesn't handle prefetch clobbering */ \ if (cpu->gprs[ARM_PC] & 2) { \ - value |= cpu->prefetch[0] << 16; \ - } else { \ value <<= 16; \ value |= cpu->prefetch[0]; \ + } else { \ + value |= cpu->prefetch[0] << 16; \ } \ break; \ default: \ @@ -1326,6 +1326,12 @@ void GBAPatch8(struct ARMCore* cpu, uint32_t address, int8_t value, int8_t* old) } #define LDM_LOOP(LDM) \ + if (UNLIKELY(!mask)) { \ + LDM; \ + cpu->gprs[ARM_PC] = value; \ + wait += 16; \ + address += 64; \ + } \ for (i = 0; i < 16; i += 4) { \ if (UNLIKELY(mask & (1 << i))) { \ LDM; \ @@ -1438,6 +1444,12 @@ uint32_t GBALoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum L } #define STM_LOOP(STM) \ + if (UNLIKELY(!mask)) { \ + value = cpu->gprs[ARM_PC] + (cpu->executionMode == MODE_ARM ? WORD_SIZE_ARM : WORD_SIZE_THUMB); \ + STM; \ + wait += 16; \ + address += 64; \ + } \ for (i = 0; i < 16; i += 4) { \ if (UNLIKELY(mask & (1 << i))) { \ value = cpu->gprs[i]; \ diff --git a/src/gba/renderers/cache-set.c b/src/gba/renderers/cache-set.c index 71a4b8617..bc84deadd 100644 --- a/src/gba/renderers/cache-set.c +++ b/src/gba/renderers/cache-set.c @@ -17,20 +17,20 @@ void GBAVideoCacheInit(struct mCacheSet* cache) { sysconfig = mTileCacheSystemInfoSetPaletteBPP(sysconfig, 2); // 2^(2^2) = 16 entries sysconfig = mTileCacheSystemInfoSetPaletteCount(sysconfig, 4); // 16 palettes sysconfig = mTileCacheSystemInfoSetMaxTiles(sysconfig, 2048); - mTileCacheConfigure(mTileCacheSetGetPointer(&cache->tiles, 0), config); mTileCacheConfigureSystem(mTileCacheSetGetPointer(&cache->tiles, 0), sysconfig, 0, 0); + mTileCacheConfigure(mTileCacheSetGetPointer(&cache->tiles, 0), config); sysconfig = mTileCacheSystemInfoSetMaxTiles(sysconfig, 1024); - mTileCacheConfigure(mTileCacheSetGetPointer(&cache->tiles, 2), config); mTileCacheConfigureSystem(mTileCacheSetGetPointer(&cache->tiles, 2), sysconfig, 0x10000, 0x100); + mTileCacheConfigure(mTileCacheSetGetPointer(&cache->tiles, 2), config); sysconfig = mTileCacheSystemInfoSetPaletteBPP(sysconfig, 3); // 2^(2^3) = 256 entries sysconfig = mTileCacheSystemInfoSetPaletteCount(sysconfig, 0); // 1 palettes sysconfig = mTileCacheSystemInfoSetMaxTiles(sysconfig, 2048); - mTileCacheConfigure(mTileCacheSetGetPointer(&cache->tiles, 1), config); mTileCacheConfigureSystem(mTileCacheSetGetPointer(&cache->tiles, 1), sysconfig, 0, 0); + mTileCacheConfigure(mTileCacheSetGetPointer(&cache->tiles, 1), config); sysconfig = mTileCacheSystemInfoSetMaxTiles(sysconfig, 1024); - mTileCacheConfigure(mTileCacheSetGetPointer(&cache->tiles, 3), config); mTileCacheConfigureSystem(mTileCacheSetGetPointer(&cache->tiles, 3), sysconfig, 0x10000, 0x100); + mTileCacheConfigure(mTileCacheSetGetPointer(&cache->tiles, 3), config); mBitmapCacheSystemInfo bitConfig; bitConfig = mBitmapCacheSystemInfoSetEntryBPP(0, 4); @@ -50,6 +50,11 @@ void GBAVideoCacheInit(struct mCacheSet* cache) { mBitmapCacheConfigureSystem(mBitmapCacheSetGetPointer(&cache->bitmaps, 1), bitConfig); mBitmapCacheSetGetPointer(&cache->bitmaps, 1)->bitsStart[0] = 0; mBitmapCacheSetGetPointer(&cache->bitmaps, 1)->bitsStart[1] = 0xA000; + + mMapCacheSetGetPointer(&cache->maps, 0)->context = NULL; + mMapCacheSetGetPointer(&cache->maps, 1)->context = NULL; + mMapCacheSetGetPointer(&cache->maps, 2)->context = NULL; + mMapCacheSetGetPointer(&cache->maps, 3)->context = NULL; } void GBAVideoCacheAssociate(struct mCacheSet* cache, struct GBAVideo* video) { diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index 844164829..e6596ab0f 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -145,21 +145,21 @@ static const char* const _renderMode0 = " if (mosaic.y > 1) {\n" " coord.y -= coord.y % mosaic.y;\n" " }\n" - " coord += (ivec2(0x3FF, 0x3FF000) & offset[int(texCoord.y)]) >> ivec2(0, 12);\n" - " ivec2 wrap = ivec2(255, 511);\n" - " if (size == 3) {\n" - " coord.y += (coord.y & 256) << 1;\n" - " wrap.y = 1023;\n" - " } else if (size == 0) {\n" - " wrap.y = 255;\n" - " }\n" - " if (size != 2) {\n" - " coord.y &= ~256;\n" - " }\n" + " coord += (ivec2(0x1FF, 0x1FF000) & offset[int(texCoord.y)]) >> ivec2(0, 12);\n" + " ivec2 wrap = ivec2(255, 255);\n" + " int doty = 0;\n" " if ((size & 1) == 1) {\n" - " coord.y += coord.x & 256;\n" + " wrap.x = 511;\n" + " ++doty;\n" + " }\n" + " if ((size & 2) == 2) {\n" + " wrap.y = 511;\n" + " ++doty;\n" " }\n" " coord &= wrap;\n" + " wrap = coord & 256;\n" + " coord &= 255;\n" + " coord.y += wrap.x + wrap.y * doty;\n" " int mapAddress = screenBase + (coord.x >> 3) + (coord.y >> 3) * 32;\n" " vec4 map = texelFetch(vram, ivec2(mapAddress & 255, mapAddress >> 8), 0);\n" " int tileFlags = int(map.g * 15.9);\n" diff --git a/src/gba/sio/lockstep.c b/src/gba/sio/lockstep.c index 506854a7e..d4392f47e 100644 --- a/src/gba/sio/lockstep.c +++ b/src/gba/sio/lockstep.c @@ -47,6 +47,7 @@ bool GBASIOLockstepAttachNode(struct GBASIOLockstep* lockstep, struct GBASIOLock lockstep->players[lockstep->d.attached] = node; node->p = lockstep; node->id = lockstep->d.attached; + node->transferFinished = true; ++lockstep->d.attached; return true; } diff --git a/src/platform/3ds/main.c b/src/platform/3ds/main.c index e3f9bcf51..db4f773f8 100644 --- a/src/platform/3ds/main.c +++ b/src/platform/3ds/main.c @@ -417,6 +417,46 @@ static void _gameUnloaded(struct mGUIRunner* runner) { } } +static u32 _setupTex(int out, bool faded) { + ctrActivateTexture(&outputTexture[out]); + u32 color; + if (!faded) { + color = 0xFFFFFFFF; + switch (darkenMode) { + case DM_NATIVE: + case DM_MAX: + break; + case DM_MULT_SCALE_BIAS: + ctrTextureBias(0x070707); + // Fall through + case DM_MULT_SCALE: + color = 0xFF707070; + // Fall through + case DM_MULT: + ctrTextureMultiply(); + break; + } + } else { + color = 0xFF484848; + switch (darkenMode) { + case DM_NATIVE: + case DM_MAX: + break; + case DM_MULT_SCALE_BIAS: + ctrTextureBias(0x030303); + // Fall through + case DM_MULT_SCALE: + color = 0xFF303030; + // Fall through + case DM_MULT: + ctrTextureMultiply(); + break; + } + + } + return color; +} + static void _drawTex(struct mCore* core, bool faded, bool both) { unsigned screen_w, screen_h; switch (screenMode) { @@ -485,45 +525,10 @@ static void _drawTex(struct mCore* core, bool faded, bool both) { break; } - u32 color; - if (!faded) { - color = 0xFFFFFFFF; - switch (darkenMode) { - case DM_NATIVE: - case DM_MAX: - break; - case DM_MULT_SCALE_BIAS: - ctrTextureBias(0x070707); - // Fall through - case DM_MULT_SCALE: - color = 0xFF707070; - // Fall through - case DM_MULT: - ctrTextureMultiply(); - break; - } - } else { - color = 0xFF484848; - switch (darkenMode) { - case DM_NATIVE: - case DM_MAX: - break; - case DM_MULT_SCALE_BIAS: - ctrTextureBias(0x030303); - // Fall through - case DM_MULT_SCALE: - color = 0xFF303030; - // Fall through - case DM_MULT: - ctrTextureMultiply(); - break; - } - - } - ctrActivateTexture(&outputTexture[activeOutputTexture]); + uint32_t color = _setupTex(activeOutputTexture, faded); ctrAddRectEx(color, x, y, w, h, 0, 0, corew, coreh, 0); if (both) { - ctrActivateTexture(&outputTexture[activeOutputTexture ^ 1]); + color = _setupTex(activeOutputTexture ^ 1, faded); ctrAddRectEx(color & 0x7FFFFFFF, x, y, w, h, 0, 0, corew, coreh, 0); } ctrFlushBatch(); diff --git a/src/platform/psp2/main.c b/src/platform/psp2/main.c index 594d9942f..8451515ea 100644 --- a/src/platform/psp2/main.c +++ b/src/platform/psp2/main.c @@ -165,6 +165,7 @@ int main() { sceTouchSetSamplingState(SCE_TOUCH_PORT_FRONT, SCE_TOUCH_SAMPLING_STATE_START); sceCtrlSetSamplingMode(SCE_CTRL_MODE_ANALOG_WIDE); + sceCtrlSetSamplingModeExt(SCE_CTRL_MODE_ANALOG_WIDE); sceSysmoduleLoadModule(SCE_SYSMODULE_PHOTO_EXPORT); sceSysmoduleLoadModule(SCE_SYSMODULE_APPUTIL); diff --git a/src/platform/qt/AssetView.cpp b/src/platform/qt/AssetView.cpp index f77b779bb..20dbd1641 100644 --- a/src/platform/qt/AssetView.cpp +++ b/src/platform/qt/AssetView.cpp @@ -66,6 +66,9 @@ void AssetView::showEvent(QShowEvent*) { } void AssetView::compositeTile(const void* tBuffer, void* buffer, size_t stride, size_t x, size_t y, int depth) { + if (!tBuffer) { + return; + } const uint8_t* tile = static_cast(tBuffer); uint8_t* pixels = static_cast(buffer); size_t base = stride * y + x; diff --git a/src/platform/qt/CheatsView.cpp b/src/platform/qt/CheatsView.cpp index 4a631c932..567400cdb 100644 --- a/src/platform/qt/CheatsView.cpp +++ b/src/platform/qt/CheatsView.cpp @@ -129,7 +129,6 @@ void CheatsView::addSet() { } void CheatsView::removeSet() { - GBACheatSet* set; QModelIndexList selection = m_ui.cheatList->selectionModel()->selectedIndexes(); if (selection.count() < 1) { return; diff --git a/src/platform/qt/CoreController.cpp b/src/platform/qt/CoreController.cpp index 86c7dd0a2..1e7f97299 100644 --- a/src/platform/qt/CoreController.cpp +++ b/src/platform/qt/CoreController.cpp @@ -637,12 +637,16 @@ void CoreController::yankPak() { Interrupter interrupter(this); switch (platform()) { +#ifdef M_CORE_GBA case PLATFORM_GBA: GBAYankROM(static_cast(m_threadContext.core->board)); break; +#endif +#ifdef M_CORE_GB case PLATFORM_GB: GBYankROM(static_cast(m_threadContext.core->board)); break; +#endif } } diff --git a/src/platform/qt/CoreController.h b/src/platform/qt/CoreController.h index 9925a3ad2..ecd810849 100644 --- a/src/platform/qt/CoreController.h +++ b/src/platform/qt/CoreController.h @@ -226,7 +226,7 @@ private: bool m_autosave; bool m_autoload; - int m_autosaveCounter; + int m_autosaveCounter = 0; int m_fastForward = false; int m_fastForwardForced = false; diff --git a/src/platform/qt/Display.cpp b/src/platform/qt/Display.cpp index 809d9c5ce..b9ba7484c 100644 --- a/src/platform/qt/Display.cpp +++ b/src/platform/qt/Display.cpp @@ -26,7 +26,11 @@ Display* Display::create(QWidget* parent) { switch (s_driver) { #if defined(BUILD_GL) || defined(BUILD_GLES2) || defined(USE_EPOXY) case Driver::OPENGL: - format.setVersion(3, 2); + if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) { + format.setVersion(3, 0); + } else { + format.setVersion(3, 2); + } format.setProfile(QSurfaceFormat::CoreProfile); return new DisplayGL(format, parent); #endif diff --git a/src/platform/qt/GBAKeyEditor.cpp b/src/platform/qt/GBAKeyEditor.cpp index 03d0769e2..f1ef98d61 100644 --- a/src/platform/qt/GBAKeyEditor.cpp +++ b/src/platform/qt/GBAKeyEditor.cpp @@ -232,7 +232,7 @@ void GBAKeyEditor::save() { #ifdef BUILD_SDL if (m_profileSelect) { - m_controller->setPreferredGamepad(m_type, m_profileSelect->currentText()); + m_controller->setPreferredGamepad(m_type, m_profileSelect->currentIndex()); } #endif diff --git a/src/platform/qt/MapView.cpp b/src/platform/qt/MapView.cpp index f71baf0fe..46b6ab814 100644 --- a/src/platform/qt/MapView.cpp +++ b/src/platform/qt/MapView.cpp @@ -167,6 +167,7 @@ void MapView::updateTilesGBA(bool force) { int frame = 0; QString offset(tr("N/A")); QString transform(tr("N/A")); +#ifdef M_CORE_GBA if (m_controller->platform() == PLATFORM_GBA) { uint16_t* io = static_cast(m_controller->thread()->core->board)->memory.io; int mode = GBARegisterDISPCNTGetMode(io[REG_DISPCNT >> 1]); @@ -199,12 +200,15 @@ void MapView::updateTilesGBA(bool force) { } } +#endif +#ifdef M_CORE_GB if (m_controller->platform() == PLATFORM_GB) { uint8_t* io = static_cast(m_controller->thread()->core->board)->memory.io; int x = io[m_map == 0 ? 0x42 : 0x4A]; int y = io[m_map == 0 ? 0x43 : 0x4B]; offset = QString("%1, %2").arg(x).arg(y); } +#endif if (bitmap >= 0) { mBitmapCache* bitmapCache = mBitmapCacheSetGetPointer(&m_cacheSet->bitmaps, bitmap); int width = mBitmapCacheSystemInfoGetWidth(bitmapCache->sysConfig); @@ -266,4 +270,4 @@ void MapView::exportMap() { void MapView::copyMap() { CoreController::Interrupter interrupter(m_controller); GBAApp::app()->clipboard()->setImage(m_rawMap); -} \ No newline at end of file +} diff --git a/src/platform/qt/MemoryModel.cpp b/src/platform/qt/MemoryModel.cpp index dfdc6c113..98d743067 100644 --- a/src/platform/qt/MemoryModel.cpp +++ b/src/platform/qt/MemoryModel.cpp @@ -88,6 +88,19 @@ MemoryModel::MemoryModel(QWidget* parent) update(); }); + connect(verticalScrollBar(), &QSlider::actionTriggered, [this](int action) { + if (action == QSlider::SliderSingleStepAdd) { + ++m_top; + } else if (action == QSlider::SliderSingleStepSub) { + --m_top; + } else { + return; + } + boundsCheck(); + verticalScrollBar()->setValue(m_top); + update(); + }); + setRegion(0, 0x10000000, tr("All")); } diff --git a/src/platform/qt/MultiplayerController.cpp b/src/platform/qt/MultiplayerController.cpp index 8387d3f03..ca2f048d3 100644 --- a/src/platform/qt/MultiplayerController.cpp +++ b/src/platform/qt/MultiplayerController.cpp @@ -22,11 +22,13 @@ MultiplayerController::Player::Player(CoreController* coreController, GBSIOLocks { } +#ifdef M_CORE_GBA MultiplayerController::Player::Player(CoreController* coreController, GBASIOLockstepNode* node) : controller(coreController) , gbaNode(node) { } +#endif MultiplayerController::MultiplayerController() { mLockstepInit(&m_lockstep); @@ -71,10 +73,12 @@ MultiplayerController::MultiplayerController() { if (!id) { for (int i = 1; i < controller->m_players.count(); ++i) { Player* player = &controller->m_players[i]; +#ifdef M_CORE_GBA if (player->controller->platform() == PLATFORM_GBA && player->gbaNode->d.p->mode != controller->m_players[0].gbaNode->d.p->mode) { player->controller->setSync(true); continue; } +#endif player->controller->setSync(false); player->cyclesPosted += cycles; if (player->awake < 1) { diff --git a/src/platform/qt/MultiplayerController.h b/src/platform/qt/MultiplayerController.h index 4614c5c6f..03aad86d8 100644 --- a/src/platform/qt/MultiplayerController.h +++ b/src/platform/qt/MultiplayerController.h @@ -45,8 +45,12 @@ signals: private: struct Player { +#ifdef M_CORE_GB Player(CoreController* controller, GBSIOLockstepNode* node); +#endif +#ifdef M_CORE_GBA Player(CoreController* controller, GBASIOLockstepNode* node); +#endif CoreController* controller; GBSIOLockstepNode* gbNode = nullptr; diff --git a/src/platform/qt/OverrideView.cpp b/src/platform/qt/OverrideView.cpp index f2957a5d2..f0d1fe772 100644 --- a/src/platform/qt/OverrideView.cpp +++ b/src/platform/qt/OverrideView.cpp @@ -69,6 +69,7 @@ OverrideView::OverrideView(ConfigController* config, QWidget* parent) m_ui.hwRumble->setEnabled(!enabled); }); +#ifdef M_CORE_GB m_colorPickers[0] = ColorPicker(m_ui.color0, QColor(0xF8, 0xF8, 0xF8)); m_colorPickers[1] = ColorPicker(m_ui.color1, QColor(0xA8, 0xA8, 0xA8)); m_colorPickers[2] = ColorPicker(m_ui.color2, QColor(0x50, 0x50, 0x50)); @@ -86,6 +87,7 @@ OverrideView::OverrideView(ConfigController* config, QWidget* parent) m_gbColors[colorId] = color.rgb() | 0xFF000000; }); } +#endif #ifndef M_CORE_GBA m_ui.tabWidget->removeTab(m_ui.tabWidget->indexOf(m_ui.tabGBA)); diff --git a/src/platform/qt/ShaderSelector.cpp b/src/platform/qt/ShaderSelector.cpp index 759cf6c7e..cf7f999a0 100644 --- a/src/platform/qt/ShaderSelector.cpp +++ b/src/platform/qt/ShaderSelector.cpp @@ -33,6 +33,7 @@ ShaderSelector::ShaderSelector(Display* display, ConfigController* config, QWidg : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint) , m_display(display) , m_config(config) + , m_shaderPath(config->getOption("shader")) { m_ui.setupUi(this); @@ -41,9 +42,6 @@ ShaderSelector::ShaderSelector(Display* display, ConfigController* config, QWidg connect(m_ui.load, &QAbstractButton::clicked, this, &ShaderSelector::selectShader); connect(m_ui.unload, &QAbstractButton::clicked, this, &ShaderSelector::clearShader); connect(m_ui.buttonBox, &QDialogButtonBox::clicked, this, &ShaderSelector::buttonPressed); - connect(this, &ShaderSelector::saved, [this]() { - m_config->setOption("shader", m_shaderPath); - }); } ShaderSelector::~ShaderSelector() { @@ -85,12 +83,14 @@ void ShaderSelector::loadShader(const QString& path) { m_display->setShaders(shader); shader->close(shader); m_shaderPath = path; + m_config->setOption("shader", m_shaderPath); } void ShaderSelector::clearShader() { m_display->clearShaders(); refreshShaders(); m_shaderPath = ""; + m_config->setOption("shader", m_shaderPath); } void ShaderSelector::refreshShaders() { @@ -119,10 +119,6 @@ void ShaderSelector::refreshShaders() { disconnect(this, &ShaderSelector::reset, 0, 0); disconnect(this, &ShaderSelector::resetToDefault, 0, 0); - connect(this, &ShaderSelector::saved, [this]() { - m_config->setOption("shader", m_shaderPath); - }); - #if !defined(_WIN32) || defined(USE_EPOXY) if (m_shaders->preprocessShader) { m_ui.passes->addTab(makePage(static_cast(m_shaders->preprocessShader), "default", 0), tr("Preprocessing")); diff --git a/src/platform/qt/TilePainter.cpp b/src/platform/qt/TilePainter.cpp index b9417b827..127b31058 100644 --- a/src/platform/qt/TilePainter.cpp +++ b/src/platform/qt/TilePainter.cpp @@ -26,6 +26,9 @@ void TilePainter::paintEvent(QPaintEvent* event) { void TilePainter::resizeEvent(QResizeEvent* event) { int w = width() / m_size; + if (!w) { + w = 1; + } int calculatedHeight = (m_tileCount + w - 1) * m_size / w; calculatedHeight -= calculatedHeight % m_size; if (width() / m_size != m_backing.width() / m_size || m_backing.height() != calculatedHeight) { diff --git a/src/platform/qt/Window.cpp b/src/platform/qt/Window.cpp index 71bc39c19..03ca72e7b 100644 --- a/src/platform/qt/Window.cpp +++ b/src/platform/qt/Window.cpp @@ -1497,7 +1497,9 @@ void Window::setupMenu(QMenuBar* menubar) { ConfigOption* mute = m_config->addOption("mute"); mute->addBoolean(tr("Mute"), &m_actions, "av"); mute->connect([this](const QVariant& value) { - m_config->setOption("fastForwardMute", static_cast(value.toInt())); + if (value.toInt()) { + m_config->setOption("fastForwardMute", true); + } reloadConfig(); }, this); m_config->updateOption("mute"); diff --git a/src/platform/qt/input/InputController.cpp b/src/platform/qt/input/InputController.cpp index abf2d7259..69e03e4ea 100644 --- a/src/platform/qt/input/InputController.cpp +++ b/src/platform/qt/input/InputController.cpp @@ -383,11 +383,13 @@ void InputController::setGamepad(uint32_t type, int index) { #endif } -void InputController::setPreferredGamepad(uint32_t type, const QString& device) { +void InputController::setPreferredGamepad(uint32_t type, int index) { if (!m_config) { return; } - mInputSetPreferredDevice(m_config->input(), "gba", type, m_playerId, device.toUtf8().constData()); + char name[34] = {0}; + SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, index)->joystick), name, sizeof(name)); + mInputSetPreferredDevice(m_config->input(), "gba", type, m_playerId, name); } mRumble* InputController::rumble() { diff --git a/src/platform/qt/input/InputController.h b/src/platform/qt/input/InputController.h index cdd3e47a7..1300d9b13 100644 --- a/src/platform/qt/input/InputController.h +++ b/src/platform/qt/input/InputController.h @@ -99,7 +99,7 @@ public: QStringList connectedGamepads(uint32_t type) const; int gamepad(uint32_t type) const; void setGamepad(uint32_t type, int index); - void setPreferredGamepad(uint32_t type, const QString& device); + void setPreferredGamepad(uint32_t type, int index); void registerTiltAxisX(int axis); void registerTiltAxisY(int axis); diff --git a/src/platform/qt/ts/medusa-emu-de.ts b/src/platform/qt/ts/medusa-emu-de.ts index 79322f4cc..b95877e67 100644 --- a/src/platform/qt/ts/medusa-emu-de.ts +++ b/src/platform/qt/ts/medusa-emu-de.ts @@ -3820,7 +3820,7 @@ Game Boy Advance ist ein eingetragenes Warenzeichen von Nintendo Co., Ltd. Load state file... - Ssavestate-Datei laden... + Savestate-Datei laden... diff --git a/src/platform/qt/ts/mgba-zh_CN.ts b/src/platform/qt/ts/mgba-zh_CN.ts index 6840ea2b2..32cf34542 100644 --- a/src/platform/qt/ts/mgba-zh_CN.ts +++ b/src/platform/qt/ts/mgba-zh_CN.ts @@ -589,20 +589,26 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 贴图 - - Export - 导出 - - + × × - + Magnification 缩放率 + + + Export + 导出 + + + + Copy + 复制 + MemoryDump @@ -641,124 +647,149 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 MemorySearch - + Memory Search 内存查找 - + Address 地址 - + Current Value 当前值 - - + + Type 类型 - + Value - + Numeric 数字 - + Text 文本 - + Width 位宽 - - + + Guess - 猜测 + 估计 - + 1 Byte (8-bit) 1 字节 (8 位) - + 2 Bytes (16-bit) 2 字节 (16 位) - + 4 Bytes (32-bit) 4 字节 (32 位) - + Number type 数字进制 - + Decimal 十进制 - + Hexadecimal 十六进制 - + Compare 比较 - - Equal - 等于 + + Equal to value + 约等于下值 - - Greater - 大于 + + Greater than value + 大于下值 - - Less - 小于 + + Less than value + 小于下值 - - Delta - 相差 + + Unknown/changed + 未知/已更改 - - Search - 查找 + + Changed by value + 由下值更改 - + + Unchanged + 无更改 + + + + Increased + 增加 + + + + Decreased + 减少 + + + + Search ROM + 查找 ROM + + + + New Search + 新的查找 + + + Search Within 在结果中查找 - + Open in Memory Viewer 在内存查看器中打开 - + Refresh 刷新 @@ -854,143 +885,148 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 精灵图 - - - × - × + + Copy + 复制 - - Magnification - 缩放率 + + Position + 位置 - - Export - 导出 - - - - Attributes - 属性 - - - - Transform - 变换 - - - - Off - - - - - Palette - 调色板 - - - - - - + + + + 0 0 - + + , + , + + + + Dimensions + 维度 + + + + + 8 + 8 + + + + + × + × + + + + Tile + 瓷贴 + + + + Export + 导出 + + + + Attributes + 属性 + + + + Transform + 变换 + + + + Off + + + + + Palette + 调色板 + + + Double Size 双倍大小 - - - - + + + + Return, Ctrl+R 回车键、Ctrl+R - + Flipped 已翻转 - + H 水平 - + V 垂直 - + Mode 模式 - + Normal 普通 - + Mosaic 马赛克 - + Enabled 已启用 - + Priority 优先级 - - - Tile - 瓷贴 - Geometry 几何图像 - - Position - 位置 - - - - , - , - - - - Dimensions - 维度 - - - - - 8 - 8 - - - + Address 地址 - + 0x07000000 0x07000000 + + + Magnification + 缩放率 + OverrideView @@ -1145,36 +1181,51 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 + MBC6 + MBC6 + + + MBC7 MBC7 - + + MMM01 + MMM01 + + + Pocket Cam Pocket Cam - + TAMA5 TAMA5 - + + HuC-1 + HuC-1 + + + HuC-3 HuC-3 - + Background Colors 背景颜色 - + Sprite Colors 1 精灵图颜色 1 - + Sprite Colors 2 精灵图颜色 2 @@ -1300,15 +1351,25 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 Game Boy 打印机 - + Hurry up! Hurry up! - + Tear off Tear off + + + × + × + + + + Magnification + 缩放率 + QGBA::AssetTile @@ -1318,9 +1379,9 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 %0%1%2 - - - + + + 0x%0 (%1) 0x%0 (%1) @@ -3097,83 +3158,85 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 QGBA::MapView - + Priority 优先级 - - + + Map base 映射基 - - + + Tile base 瓷贴基 - + Size 大小 - - + + offset 偏移 - + Xform 变换 - + Map Addr. 映射地址 - + Mirror 镜像 - + None - + Both 两者 - + Horizontal 水平 - + Vertical 垂直 - + + + + N/A + + + + Export map 导出映射 - + Portable Network Graphics (*.png) 便携式网络图形 (*.png) - - - Failed to open output PNG file: %1 - 打开输出 PNG 文件失败: %1 - QGBA::MemoryModel @@ -3248,22 +3311,22 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 QGBA::MemorySearch - + (%0/%1×) (%0/%1×) - + (⅟%0×) (⅟%0×) - + (%0×) (%0×) - + %1 byte%2 %1 字节%2 @@ -3271,49 +3334,49 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 QGBA::ObjView - - + + 0x%0 0x%0 - + Off - + Normal 一般 - + Trans 变换 - + OBJWIN OBJWIN - + Invalid 无效 - - + + N/A - + Export sprite 导出精灵图 - + Portable Network Graphics (*.png) 便携式网络图形 (*.png) @@ -3361,12 +3424,12 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 QGBA::PrinterView - + Save Printout 保存输出 - + Portable Network Graphics (*.png) 便携式网络图形 (*.png) @@ -3513,12 +3576,14 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 QGBA::TileView - + + Export tiles 导出文件 - + + Portable Network Graphics (*.png) 便携式网络图形 (*.png) @@ -3611,7 +3676,7 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 Patches (*.ips *.ups *.bps) - 补丁文件 (*.ips *.ups *.bps) + 补丁 (*.ips *.ups *.bps) @@ -3640,12 +3705,12 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 视频日志文件 (*.mvl) - + Crash 崩溃 - + The game has crashed with the following error: %1 @@ -3654,107 +3719,107 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 %1 - + Couldn't Load 无法载入 - + Could not load game. Are you sure it's in the correct format? 无法载入游戏。请确认游戏格式是否无误。 - + Unimplemented BIOS call 未实现的 BIOS 调用 - + This game uses a BIOS call that is not implemented. Please use the official BIOS for best experience. 该游戏使用了尚未实现的 BIOS 调用。请使用官方 BIOS 以获得最佳游戏体验。 - + Really make portable? 确定进行程序便携化? - + This will make the emulator load its configuration from the same directory as the executable. Do you want to continue? 进行此操作后,模拟器将从模拟器可执行文件所在目录内加载模拟器配置。您想继续吗? - + Restart needed 需要重新启动 - + Some changes will not take effect until the emulator is restarted. 更改将在模拟器下次启动时生效。 - + - Player %1 of %2 - 玩家 %1 共 %2 - + %1 - %2 %1 - %2 - + %1 - %2 - %3 %1 - %2 - %3 - + %1 - %2 (%3 fps) - %4 %1 - %2 (%3 fps) - %4 - + &File 文件(&F) - + Load &ROM... 载入 ROM(&R)... - + Load ROM in archive... 从压缩文件中载入 ROM... - + Add folder to library... 将文件夹添加到库中... - + Load alternate save... - 读取其他的存档... + 读取其他存档... - + Load temporary save... 读取临时存档... - + Load &patch... 载入补丁文件(&P)... - + Boot BIOS 引导 BIOS - + Replace ROM... 替换 ROM... @@ -3764,468 +3829,468 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 ROM 信息(&I)... - + Recent 最近打开 - + Make portable 程序便携化 - + &Load state 读取即时存档(&L) - + Load state file... 载入即时存档文件... - + &Save state 保存即时存档(&S) - + Save state file... 保存即时存档文件... - + Quick load 快速读档 - + Quick save 快速存档 - + Load recent 载入最近 - + Save recent 保存最近 - + Undo load state 撤消读档 - + Undo save state 撤消存档 - - + + State &%1 即时存档 1(&1) - + Load camera image... 读取相机图片... - + Import GameShark Save 导入 GameShark 存档 - + Export GameShark Save 导出 GameShark 存档 - + New multiplayer window 新建多人游戏窗口 - + About... 关于... - + E&xit 退出(&X) - + &Emulation 模拟(&E) - + &Reset - 复位(&R) + 重置(&R) - + Sh&utdown 关机(&U) - + Yank game pak 快速抽出游戏卡带 - + &Pause 暂停(&P) - + &Next frame 下一帧(&N) - + Fast forward (held) 快进 (长按) - + &Fast forward 快进(&F) - + Fast forward speed 快进速度 - + Unbounded 不限制 - + %0x %0x - + Rewind (held) - 回退 (长按) + 倒带 (长按) - + Re&wind - 回退(&W) + 倒带(&W) - + Step backwards - 后退 + 步退 - + Sync to &video 视频同步(&V) - + Sync to &audio 音频同步(&A) - + Solar sensor 光线传感器 - + Increase solar level 增加光线级别 - + Decrease solar level 降低光线级别 - + Brightest solar level 光线级别为最亮 - + Darkest solar level 光线级别为最暗 - + Brightness %1 亮度 %1 - + Game Boy Printer... Game Boy 打印机... - + BattleChip Gate... BattleChip Gate... - + Audio/&Video 音频/视频(&V) - + Frame size 帧率 - + %1× %1× - + Toggle fullscreen 切换全屏 - + Lock aspect ratio 锁定纵横比 - + Force integer scaling 强制整数缩放 - + Interframe blending 帧间混合 - + Bilinear filtering 双线性过滤 - + Frame&skip 跳帧(&S) - + Mute 静音 - + FPS target 目标 FPS - + Native (59.7275) 原生 (59.7275) - + Take &screenshot 截图(&S) - + Record A/V... 录制音频/视频... - + Record GIF... 录制 GIF... - + Video layers 视频图层 - + Audio channels 音频通道 - + Adjust layer placement... 调整图层布局... - + &Tools 工具(&T) - + View &logs... 查看日志(&L)... - + Game &overrides... 覆盖游戏(&O)... - + Game Pak sensors... 游戏卡带传感器... - + &Cheats... 作弊码(&C)... - + Settings... 设置... - + Open debugger console... 打开调试器控制台... - + Start &GDB server... 打开 GDB 服务器(&G)... - + View &palette... 查看调色板(&P)... - + View &sprites... 查看精灵图(&S)... - + View &tiles... 查看瓷贴(&T)... - + View &map... 查看映射(&M)... - - &Frame inspector - 框架检查(&F) + + &Frame inspector... + 框架检查(&F)... - + View memory... 查看内存... - + Search memory... 搜索内存... - + View &I/O registers... 查看 I/O 寄存器(&I)... - + Record debug video log... 记录调试视频日志... - + Stop debug video log 停止记录调试视频日志 - + Exit fullscreen 退出全屏 - + GameShark Button (held) GameShark 键 (长按) - + Autofire 连发 - + Autofire A 连发 A - + Autofire B 连发 B - + Autofire L 连发 L - + Autofire R 连发 R - + Autofire Start 连发 Start - + Autofire Select 连发 Select - + Autofire Up 连发 上 - + Autofire Right 连发 右 - + Autofire Down 连发 下 - + Autofire Left 连发 左 - + Clear 清除 @@ -4543,7 +4608,7 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 - + frames @@ -4615,12 +4680,12 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 List view - 列表查看 + 列表视图 Tree view - 树状查看 + 树状视图 @@ -4649,339 +4714,344 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 + Pause when minimized + 最小化时暂停 + + + Show FPS in title bar 在标题栏显示 FPS - Automatically save cheats - 自动保存作弊码 - - - - Automatically load cheats - 自动载入作弊码 - - - - Automatically save state - 自动存档 - - - - Automatically load state - 自动读档 - - - Enable Discord Rich Presence 启用 Enable Discord Rich Presence - - Pause when minimized - 最小化时暂停 + + Automatically save state + 自动存档 + + + + Automatically load state + 自动读档 + + + + Automatically save cheats + 自动保存作弊码 + + + + Automatically load cheats + 自动载入作弊码 + Show OSD messages + 显示 OSD 信息 + + + Fast forward speed: 快进速度: - - - + + + × × - - + + Unbounded 不限制 - + Fast forward (held) speed: 快进 (按住) 速度: - + Autofire interval: 连发间隔: - + Enable rewind - 启用回退 + 启用倒带 - + Rewind history: - 回退历史: + 倒带历史: - + Idle loops: 空循环: - + Run all 运行全部 - + Remove known 移除已知 - + Detect and remove 检测并移除 - + Preload entire ROM into memory 将整个 ROM 预加载到内存中 - + Savestate extra data: 即时存档额外数据: - - + + Screenshot 截图 - - + + Save data 保存数据 - - + + Cheat codes 作弊码 - + Load extra data: 载入额外数据: - + Video renderer: 视频渲染器: - + Software 软件 - + OpenGL OpenGL - + OpenGL enhancements OpenGL 增强 - + High-resolution scale: 高分辨率比例: - + (240×160) (240×160) - + XQ GBA audio (experimental) XQ GBA 音频 (实验) - + GB BIOS file: GB BIOS 文件: - - - - - - - - - + + + + + + + + + Browse 浏览 - + Use BIOS file if found 当可用时使用 BIOS 文件 - + Skip BIOS intro 跳过 BIOS 启动画面 - + GBA BIOS file: GBA BIOS 文件: - + GBC BIOS file: GBC BIOS 文件: - + SGB BIOS file: SGB BIOS 文件: - + Save games 游戏存档 - - - - - + + + + + Same directory as the ROM 保存在 ROM 所在目录 - + Save states 即时存档 - + Screenshots 截图 - + Patches 补丁 - + Cheats 作弊码 - + Log to file 记录日志到文件 - + Log to console 记录日志到控制台 - + Select Log File 选择日志文件 - + Game Boy model: Game Boy 模型: - - - + + + Autodetect 自动检测 - - - + + + Game Boy (DMG) Game Boy (DMG) - - - + + + Super Game Boy (SGB) Super Game Boy (SGB) - - - + + + Game Boy Color (CGB) Game Boy Color (CGB) - - - + + + Game Boy Advance (AGB) Game Boy Advance (AGB) - + Super Game Boy model: Super Game Boy 模型: - + Game Boy Color model: Game Boy Color 模型: - + Default BG colors: 默认背景颜色: - + Super Game Boy borders Super Game Boy 边框 - + Camera driver: 相机驱动: - + Default sprite colors 1: 默认精灵图颜色 1: - + Default sprite colors 2: 默认精灵图颜色 2: - + Use GBC colors in GB games 在 GB 游戏中使用 GBC 颜色 - + Camera: 相机: @@ -5055,34 +5125,49 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 瓷贴 - + + Export Selected + 导出所选 + + + + Export All + 导出全部 + + + 256 colors 256 色 - + × × - + Magnification 缩放率 - + Tiles per row 每行瓷贴 - + Fit to window 自适应窗口 - - Export - 导出 + + Copy Selected + 复制所选 + + + + Copy All + 复制全部 diff --git a/src/platform/sdl/sdl-events.c b/src/platform/sdl/sdl-events.c index 84d61ca58..9b8b3e17d 100644 --- a/src/platform/sdl/sdl-events.c +++ b/src/platform/sdl/sdl-events.c @@ -198,15 +198,15 @@ bool mSDLAttachPlayer(struct mSDLEvents* events, struct mSDLPlayer* player) { firstUnclaimed = i; } - const char* joystickName; #if SDL_VERSION_ATLEAST(2, 0, 0) - joystickName = SDL_JoystickName(SDL_JoystickListGetPointer(&events->joysticks, i)->joystick); + char joystickName[34] = {0}; + SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(SDL_JoystickListGetPointer(&events->joysticks, i)->joystick), joystickName, sizeof(joystickName)); #else - joystickName = SDL_JoystickName(SDL_JoystickIndex(SDL_JoystickListGetPointer(&events->joysticks, i)->joystick)); -#endif + const char* joystickName = SDL_JoystickName(SDL_JoystickIndex(SDL_JoystickListGetPointer(&events->joysticks, i)->joystick)); if (!joystickName) { continue; } +#endif if (events->preferredJoysticks[player->playerId] && strcmp(events->preferredJoysticks[player->playerId], joystickName) == 0) { index = i; break; @@ -253,13 +253,14 @@ void mSDLPlayerLoadConfig(struct mSDLPlayer* context, const struct Configuration if (context->joystick) { mInputMapLoad(context->bindings, SDL_BINDING_BUTTON, config); #if SDL_VERSION_ATLEAST(2, 0, 0) - const char* name = SDL_JoystickName(context->joystick->joystick); + char name[34] = {0}; + SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(context->joystick->joystick), name, sizeof(name)); #else const char* name = SDL_JoystickName(SDL_JoystickIndex(context->joystick->joystick)); -#endif if (!name) { return; } +#endif mInputProfileLoad(context->bindings, SDL_BINDING_BUTTON, config, name); const char* value; @@ -307,13 +308,14 @@ void mSDLPlayerLoadConfig(struct mSDLPlayer* context, const struct Configuration void mSDLPlayerSaveConfig(const struct mSDLPlayer* context, struct Configuration* config) { if (context->joystick) { #if SDL_VERSION_ATLEAST(2, 0, 0) - const char* name = SDL_JoystickName(context->joystick->joystick); + char name[34] = {0}; + SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(context->joystick->joystick), name, sizeof(name)); #else const char* name = SDL_JoystickName(SDL_JoystickIndex(context->joystick->joystick)); -#endif if (!name) { return; } +#endif char value[16]; snprintf(value, sizeof(value), "%i", context->rotation.axisX); mInputSetCustomValue(config, "gba", SDL_BINDING_BUTTON, "tiltAxisX", value, name); @@ -354,14 +356,15 @@ void mSDLUpdateJoysticks(struct mSDLEvents* events, const struct Configuration* joystick->haptic = SDL_HapticOpenFromJoystick(joystick->joystick); #endif - const char* joystickName; -#if SDL_VERSION_ATLEAST(2, 0, 0) - joystickName = SDL_JoystickName(joystick->joystick); -#else - joystickName = SDL_JoystickName(SDL_JoystickIndex(joystick->joystick)); -#endif size_t i; - if (joystickName) { +#if SDL_VERSION_ATLEAST(2, 0, 0) + char joystickName[34] = {0}; + SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick->joystick), joystickName, sizeof(joystickName)); +#else + const char* joystickName = SDL_JoystickName(SDL_JoystickIndex(joystick->joystick)); + if (joystickName) +#endif + { for (i = 0; (int) i < events->playersAttached; ++i) { if (events->players[i]->joystick) { continue; diff --git a/src/platform/windows/setup/setup.iss.in b/src/platform/windows/setup/setup.iss.in index c3771eadb..111b5bc09 100644 --- a/src/platform/windows/setup/setup.iss.in +++ b/src/platform/windows/setup/setup.iss.in @@ -48,15 +48,11 @@ LicenseFile={#BinDir}\LICENSE.txt #define IsRelease = 'no' AppVerName={#AppName} {#VersionString} (Development build) #endif -#if '{#WinBits}' == '64' - ArchitecturesInstallIn64BitMode=x64 - ArchitecturesAllows=x64 -#endif OutputBaseFilename={#AppName}-setup-{#CleanVersionString}-win{#WinBits} UsePreviousLanguage=False DisableWelcomePage=False VersionInfoDescription={#AppName} is an open-source Game Boy Advance emulator -VersionInfoCopyright= 20132018 Jeffrey Pfau +VersionInfoCopyright= 20132019 Jeffrey Pfau VersionInfoProductName={#AppName} VersionInfoVersion={#AppVer} Compression=lzma2/ultra64 @@ -64,6 +60,8 @@ SolidCompression=True VersionInfoTextVersion={#AppVer} VersionInfoProductVersion={#AppVer} VersionInfoProductTextVersion={#AppVer} +ArchitecturesInstallIn64BitMode=x64 +ArchitecturesAllowed=x86 x64 [Languages] Name: "english"; MessagesFile: "compiler:Default.isl"