Merge branch 'master' (early part) into medusa

This commit is contained in:
Vicki Pfau 2020-02-17 16:35:15 -08:00
commit f03389bfca
39 changed files with 844 additions and 638 deletions

View File

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

103
CHANGES
View File

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

View File

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

View File

@ -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) { \

View File

@ -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, &currentCycles); ARM_LOAD_POST_BODY;)
DEFINE_LOAD_STORE_INSTRUCTION_ARM(LDRv5, cpu->gprs[rd] = cpu->memory.load32(cpu, address, &currentCycles); ARM_LOAD_POST_BODY_v5;)
DEFINE_LOAD_STORE_INSTRUCTION_ARM(LDRB, cpu->gprs[rd] = cpu->memory.load8(cpu, address, &currentCycles); ARM_LOAD_POST_BODY;)
DEFINE_LOAD_STORE_MODE_3_DOUBLE_INSTRUCTION_ARM(LDRD, cpu->gprs[rd & ~1] = cpu->memory.load32(cpu, address, &currentCycles); cpu->gprs[rd | 1] = cpu->memory.load32(cpu, address + 4, &currentCycles); ARM_LOAD_POST_BODY;)
DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(LDRH, cpu->gprs[rd] = cpu->memory.load16(cpu, address, &currentCycles); ARM_LOAD_POST_BODY;)
DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(LDRSB, cpu->gprs[rd] = ARM_SXT_8(cpu->memory.load8(cpu, address, &currentCycles)); 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, &currentCycles)) : ARM_SXT_16(cpu->memory.load16(cpu, address, &currentCycles)); ARM_LOAD_POST_BODY;)
DEFINE_LOAD_STORE_INSTRUCTION_ARM(STR, cpu->memory.store32(cpu, address, cpu->gprs[rd], &currentCycles); ARM_STORE_POST_BODY;)
DEFINE_LOAD_STORE_INSTRUCTION_ARM(STRB, cpu->memory.store8(cpu, address, cpu->gprs[rd], &currentCycles); ARM_STORE_POST_BODY;)
DEFINE_LOAD_STORE_MODE_3_DOUBLE_INSTRUCTION_ARM(STRD, cpu->memory.store32(cpu, address, cpu->gprs[rd & ~1], &currentCycles); cpu->memory.store32(cpu, address + 4, cpu->gprs[rd | 1], &currentCycles); ARM_STORE_POST_BODY;)
DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(STRH, cpu->memory.store16(cpu, address, cpu->gprs[rd], &currentCycles); ARM_STORE_POST_BODY;)
DEFINE_LOAD_STORE_INSTRUCTION_ARM(LDR, LOAD, cpu->gprs[rd] = cpu->memory.load32(cpu, address, &currentCycles); ARM_LOAD_POST_BODY;)
DEFINE_LOAD_STORE_INSTRUCTION_ARM(LDRv5, LOAD, cpu->gprs[rd] = cpu->memory.load32(cpu, address, &currentCycles); ARM_LOAD_POST_BODY_v5;)
DEFINE_LOAD_STORE_INSTRUCTION_ARM(LDRB, LOAD, cpu->gprs[rd] = cpu->memory.load8(cpu, address, &currentCycles); ARM_LOAD_POST_BODY;)
DEFINE_LOAD_STORE_MODE_3_DOUBLE_INSTRUCTION_ARM(LDRD, LOAD, cpu->gprs[rd & ~1] = cpu->memory.load32(cpu, address, &currentCycles); cpu->gprs[rd | 1] = cpu->memory.load32(cpu, address + 4, &currentCycles); ARM_LOAD_POST_BODY;)
DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(LDRH, LOAD, cpu->gprs[rd] = cpu->memory.load16(cpu, address, &currentCycles); ARM_LOAD_POST_BODY;)
DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(LDRSB, LOAD, cpu->gprs[rd] = ARM_SXT_8(cpu->memory.load8(cpu, address, &currentCycles)); 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, &currentCycles)) : ARM_SXT_16(cpu->memory.load16(cpu, address, &currentCycles)); ARM_LOAD_POST_BODY;)
DEFINE_LOAD_STORE_INSTRUCTION_ARM(STR, STORE, cpu->memory.store32(cpu, address, cpu->gprs[rd], &currentCycles); ARM_STORE_POST_BODY;)
DEFINE_LOAD_STORE_INSTRUCTION_ARM(STRB, STORE, cpu->memory.store8(cpu, address, cpu->gprs[rd], &currentCycles); ARM_STORE_POST_BODY;)
DEFINE_LOAD_STORE_MODE_3_DOUBLE_INSTRUCTION_ARM(STRD, STORE, cpu->memory.store32(cpu, address, cpu->gprs[rd & ~1], &currentCycles); cpu->memory.store32(cpu, address + 4, cpu->gprs[rd | 1], &currentCycles); ARM_STORE_POST_BODY;)
DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(STRH, STORE, cpu->memory.store16(cpu, address, cpu->gprs[rd], &currentCycles); 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, &currentCycles);
@ -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, &currentCycles);
@ -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);
})

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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]; \

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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<const uint8_t*>(tBuffer);
uint8_t* pixels = static_cast<uint8_t*>(buffer);
size_t base = stride * y + x;

View File

@ -129,7 +129,6 @@ void CheatsView::addSet() {
}
void CheatsView::removeSet() {
GBACheatSet* set;
QModelIndexList selection = m_ui.cheatList->selectionModel()->selectedIndexes();
if (selection.count() < 1) {
return;

View File

@ -637,12 +637,16 @@ void CoreController::yankPak() {
Interrupter interrupter(this);
switch (platform()) {
#ifdef M_CORE_GBA
case PLATFORM_GBA:
GBAYankROM(static_cast<GBA*>(m_threadContext.core->board));
break;
#endif
#ifdef M_CORE_GB
case PLATFORM_GB:
GBYankROM(static_cast<GB*>(m_threadContext.core->board));
break;
#endif
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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<mGLES2Shader*>(m_shaders->preprocessShader), "default", 0), tr("Preprocessing"));

View File

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

View File

@ -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<bool>(value.toInt()));
if (value.toInt()) {
m_config->setOption("fastForwardMute", true);
}
reloadConfig();
}, this);
m_config->updateOption("mute");

View File

@ -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() {

View File

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

View File

@ -3820,7 +3820,7 @@ Game Boy Advance ist ein eingetragenes Warenzeichen von Nintendo Co., Ltd.</tran
<message>
<location filename="../Window.cpp" line="1121"/>
<source>Load state file...</source>
<translation>Ssavestate-Datei laden...</translation>
<translation>Savestate-Datei laden...</translation>
</message>
<message>
<location filename="../Window.cpp" line="1126"/>

File diff suppressed because it is too large Load Diff

View File

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

View File

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