Compare commits

...

59 Commits

Author SHA1 Message Date
Jeffrey Pfau daf3ce76e7 GBA Memory: Back out a hack that introduces incorrect behavior, even though it fixes a game 2015-05-13 22:07:20 -07:00
Jeffrey Pfau 3dfa8bc547 Update CHANGES for 0.2.1 2015-05-13 21:58:42 -07:00
Jeffrey Pfau 81f55ac4ba All: Increment patch version to 0.2.1 2015-05-11 22:25:37 -07:00
Jeffrey Pfau ce2bdd225b All: Fix dependencies for libavcodec on Debian-derived platforms 2015-05-10 14:35:44 -07:00
Jeffrey Pfau efa7f97012 Perf: Fix race condition if a game crashes immediately on start 2015-05-10 08:22:30 -07:00
Jeffrey Pfau a92d02c756 GBA Video: Fix second frame mode 5 2015-05-09 17:28:39 -07:00
Jeffrey Pfau a499b09e48 GBA Memory: Fix jumping to invalid memory when switching from Thumb to ARM 2015-05-09 17:14:28 -07:00
Jeffrey Pfau 0511a2cfd5 SDL: Fix potential build issues when Qt and SDL2 are in use 2015-05-09 13:53:30 -07:00
Jeffrey Pfau 3d1fbcefb0 ARM7: Fix ARM multiply instructions when PC is a destination register 2015-05-09 13:45:23 -07:00
Jeffrey Pfau f19c39946f GBA BIOS: Initialize a variable that may be uninitialized in very rare cases 2015-05-09 00:30:04 -07:00
Jeffrey Pfau 0cb0c185ff ARM7: Make illegal instruction decoding consistent between ARM and Thumb 2015-05-09 00:24:07 -07:00
Jeffrey Pfau 1984d042d1 GBA: Fix bounds-checking on EEPROM access 2015-05-09 00:09:45 -07:00
Jeffrey Pfau 1d82abedcc GBA: Handle out-of-bounds I/O access 2015-05-09 00:01:36 -07:00
Jeffrey Pfau 9b0b4db0d7 ARM7: Handle writeback for PC in addressing modes 2 and 3 2015-05-09 00:01:36 -07:00
Jeffrey Pfau 244f0e362a GBA Memory: Soft-crash if jumping past the end of a ROM 2015-05-09 00:01:34 -07:00
Jeffrey Pfau c01dfa3f83 SDL: Allocate properly sized input maps 2015-05-06 01:20:02 -07:00
Jeffrey Pfau 5080a29341 Util: Fix a null-pointer issue when attempting to delete a key 2015-05-02 01:14:53 -07:00
Jeffrey Pfau f8675a9004 Qt: Return early from setTurbo if possible 2015-04-26 03:31:28 -07:00
Jeffrey Pfau 745aab78d1 SDL: Fix boundary conditions for joystick adjustments 2015-04-24 00:07:27 -07:00
Jeffrey Pfau 248dbba88d Video: Fix an issue with very long filenames 2015-04-24 00:03:48 -07:00
Jeffrey Pfau 3426f953da Debugger: Fix boundary conditions in tab completion 2015-04-24 00:03:48 -07:00
Jeffrey Pfau e443b61c21 VFS: Fix resource leaks if some allocations fail 2015-04-22 22:10:44 -07:00
Jeffrey Pfau 2594015853 Util: Fix resource leak in UTF-8 handling code 2015-04-22 22:08:25 -07:00
Jeffrey Pfau 8aa9c4503a Debugger: Fix use-after-free in breakpoint clearing code 2015-04-22 21:25:20 -07:00
Jeffrey Pfau 2226b454fd Debugger: Fix uninitialized variables 2015-04-22 20:42:45 -07:00
Jeffrey Pfau 7950fac9e5 GBA: Fix hang when loading a savestate if sync to video is enabled 2015-04-22 20:41:02 -07:00
Jeffrey Pfau b0e12c3392 Qt: Fix a load of uninitialized members 2015-04-22 20:37:19 -07:00
Jeffrey Pfau 46d31796df Qt: Fix controllers sometimes not loading the right profile 2015-04-21 21:09:39 -07:00
Jeffrey Pfau d0e1a5d5d2 Qt: Fix multiplayer windows opening as the wrong size 2015-04-19 04:32:08 -07:00
Jeffrey Pfau 3b0e0c7178 Qt: Backport fix for solar sensor keybindings 2015-04-18 22:12:59 -07:00
Jeffrey Pfau 3e98fe68a0 All: Fix error in README about frameskip 2015-04-18 14:12:36 -07:00
Jeffrey Pfau 7db12fae96 GBA Memory: Fix 32-bit loads from unaddress cartridge space 2015-04-18 13:57:27 -07:00
Jeffrey Pfau 717f4ec493 Qt: Fix controller axis querying 2015-04-17 00:59:05 -07:00
Jeffrey Pfau 803914b30e GBA Memory: Allow SRAM to be 64kB 2015-04-15 23:03:15 -07:00
Jeffrey Pfau d5a6098448 Qt: Fix potential crash if a gamepad causes focus to change 2015-04-14 20:47:31 -07:00
Jeffrey Pfau 8891abaca8 GBA: Add initial I/O register settings for background matrix registers 2015-04-14 20:47:29 -07:00
Jeffrey Pfau ae41898206 GBA: Fix rewind boundary conditions 2015-04-12 20:23:28 -07:00
Jeffrey Pfau 6d2e81d246 Qt: Show multiplayer numbers in window title 2015-04-09 23:16:35 -07:00
Jeffrey Pfau 9324fedee4 GBA: Fix unintialized stack variable 2015-04-09 00:43:59 -07:00
Jeffrey Pfau c05d08759a All: VS cannot compile mGBA at the time 2015-04-08 00:56:11 -07:00
Jeffrey Pfau e9df5bc961 GBA Memory: Fix audio regression...may be a huge hack 2015-04-08 00:54:03 -07:00
Jeffrey Pfau 99ae62695e Qt: Follow-up fix for regression 2015-04-07 00:51:07 -07:00
Jeffrey Pfau 2f1937f953 Qt: Fix regression where video would not record if the game had already started 2015-04-06 22:19:22 -07:00
Jeffrey Pfau 1dcd40a5e9 Qt: Fix window not regaining focus after exiting savestate window 2015-04-06 22:05:04 -07:00
Jeffrey Pfau 3c5db2b7a1 GBA Memory: Ensure changing the timing of a DMA reschedules it 2015-04-06 03:48:18 -07:00
Jeffrey Pfau 7ed38b0a6d Qt: Fix "QOpenGLContext::swapBuffers() called with non-exposed window" warning 2015-04-05 18:04:01 -07:00
Jeffrey Pfau 630386e569 Qt: Fix tr missing or being present where it shouldn't be 2015-04-05 01:25:51 -07:00
Jeffrey Pfau 35cec4858f GBA Audio: FIFOs should not poll DMAs that are not scheduled for audio 2015-04-04 22:08:58 -07:00
Jeffrey Pfau 0de0347bf1 Qt: Fix .deb dependencies 2015-04-04 21:14:51 -07:00
Jeffrey Pfau 3186482281 Qt: Fix Display object leak when closing a window 2015-04-04 14:19:05 -07:00
Jeffrey Pfau 0e613d296a All: Fix sanitize-deb script not cleaning up after itself 2015-04-04 13:58:41 -07:00
Jeffrey Pfau 1c06cbd8d3 GBA: Fix timers not updating timing when writing to only the reload register 2015-04-03 23:52:33 -07:00
Jeffrey Pfau 12c6aaa213 Qt: Move solar sensor menu to emulation menu 2015-04-03 21:46:36 -07:00
Jeffrey Pfau 65181a737b All: Update CHANGES for 0.2.0 2015-04-03 21:25:25 -07:00
Jeffrey Pfau 51c405011f Qt: Fix shortcuts conflicting between views 2015-04-03 21:16:44 -07:00
Jeffrey Pfau 0a845c4e66 Qt: Fix build with some non-Apple versions of GCC 2015-04-03 21:16:44 -07:00
Jeffrey Pfau c818d506a7 Qt: Fix crash when attempting to pause if a game is not running 2015-04-03 21:09:03 -07:00
Jeffrey Pfau 3827f2b91f All: Update README 2015-04-02 23:25:22 -07:00
Jeffrey Pfau 767c6a039c Qt: Pause game while open file dialogs are open (fixes #6 on GitHub) 2015-04-02 22:34:41 -07:00
42 changed files with 339 additions and 143 deletions

105
CHANGES
View File

@ -1,14 +1,55 @@
0.2.0: (Future)
0.2.1: (2015-05-13)
Bugfixes:
- All: Fix sanitize-deb script not cleaning up after itself
- All: Fix dependencies for libavcodec on Debian-derived platforms
- ARM7: Handle writeback for PC in addressing modes 2 and 3
- ARM7: Make illegal instruction decoding consistent between ARM and Thumb
- ARM7: Fix ARM multiply instructions when PC is a destination register
- Debugger: Fix use-after-free in breakpoint clearing code
- Debugger: Fix boundary conditions in tab completion
- GBA: Fix timers not updating timing when writing to only the reload register
- GBA: Fix rewind boundary conditions
- GBA: Add initial I/O register settings for background matrix registers
- GBA: Fix hang when loading a savestate if sync to video is enabled
- GBA: Handle out-of-bounds I/O access
- GBA: Fix bounds-checking on EEPROM access
- GBA Audio: FIFOs should not poll DMAs that are not scheduled for audio
- GBA BIOS: Initialize a variable that may be uninitialized in very rare cases
- GBA Memory: Allow SRAM to be 64kB
- GBA Memory: Fix 32-bit loads from unaddress cartridge space
- GBA Memory: Fix jumping to invalid memory when switching from Thumb to ARM
- GBA Video: Fix second frame mode 5
- Perf: Fix race condition if a game crashes immediately on start
- Qt: Fix Display object leak when closing a window
- Qt: Fix .deb dependencies
- Qt: Fix "QOpenGLContext::swapBuffers() called with non-exposed window" warning
- Qt: Fix window not regaining focus after exiting savestate window
- Qt: Fix regression where video would not record if the game had already started
- Qt: Fix potential crash if a gamepad causes focus to change
- Qt: Fix controller axis querying
- Qt: Fix multiplayer windows opening as the wrong size
- Qt: Fix controllers sometimes not loading the right profile
- SDL: Fix boundary conditions for joystick adjustments
- SDL: Allocate properly sized input maps
- SDL: Fix potential build issues when Qt and SDL2 are in use
- Util: Fix resource leak in UTF-8 handling code
- Util: Fix a null-pointer issue when attempting to delete a key
- VFS: Fix resource leaks if some allocations fail
- Video: Fix an issue with very long filenames
Misc:
- GBA Memory: Soft-crash if jumping past the end of a ROM
- Qt: Show multiplayer numbers in window title
- Qt: Solar sensor can have shortcuts set
0.2.0: (2015-04-03)
Features:
- Support for gamepad axes, e.g. analog sticks or triggers
- Add scale presets for up to 6x
- Debugger: Add CLI "frame", frame advance command
- Settings window
- Bilinear resampling option
- Add option to skip BIOS start screen
- List of recently opened games
- Support for games using the Solar Sensor
- Debugger: Add CLI functions for writing to memory
- Better audio resampling via blip-buf
- Game Pak overrides dialog for setting savetype and sensor values
- Support for games using the tilt sensor
@ -23,9 +64,7 @@ Features:
- Support loading 7-Zip files
- Drag and drop game loading
- Cheat code support
- Debugger: Add CLI functions for examining memory regions
- Runtime configurable audio driver
- Debugger: Add CLI function for writing a register
- Libretro core for use with RetroArch and other front-ends
- Controller profiles for setting different bindings for different controllers
- Ability to lock aspect ratio
@ -33,59 +72,65 @@ Features:
- Ability to switch which game controller is in use per instance
- Ability to prevent opposing directional input
- Warning dialog if an unimplemented BIOS feature is called
- Debugger: Add CLI "frame", frame advance command
- Debugger: Add CLI functions for writing to memory
- Debugger: Add CLI functions for examining memory regions
- Debugger: Add CLI function for writing a register
Bugfixes:
- ARM7: Extend prefetch by one stage
- ARM7: Fix cycle counting for loads
- Debugger: Disassembly now lists PSR bitmasks (fixes #191)
- GBA: Fix savestate loading of DISPSTAT and WAITCNT registers
- GBA: Initialize gba.sync to null
- GBA: Fix timer initialization
- GBA Audio: Support 16-bit writes to FIFO audio
- GBA Audio: Audio buffer sizes are now correct sizes for both sample rates
- GBA BIOS: Fix BIOS prefetch after returning from an IRQ
- GBA BIOS: Fix BIOS prefetch after reset
- GBA Memory: Fix alignment of open bus 8- and 16-bit loads
- GBA Thread: Fix possible hang when loading an archive
- Perf: Fix crash when the GBA thread fails to start
- SDL: Properly clean up if a game doesn't launch
- Debugger: Disassembly now lists PSR bitmasks (fixes #191)
- GBA BIOS: Prevent CpuSet and CpuFastSet from using BIOS addresses as a source (fixes #184)
- GBA BIOS: Fix BIOS decompression routines with invalid source addresses
- GBA Memory: Fix alignment of open bus 8- and 16-bit loads
- GBA Memory: Fix I cycles that had been moved to ARM7 core
- GBA Memory: Fix cycle counting for 32-bit load/stores
- GBA RR: Fix fallthrough error when reading tags from a movie
- GBA Thread: Fix possible hang when loading an archive
- GBA Thread: Fix possible deadlock in video sync
- GBA: Fix savestate loading of DISPSTAT and WAITCNT registers
- Perf: Fix crash when the GBA thread fails to start
- Qt: Fix crash starting a GDB stub if a game isn't loaded
- Qt: Fix crash when adjusting settings after closing a game
- Qt: Fix crash when starting GDB stub after closing a game
- Qt: Fix patch loading while a game is running
- Util: Fix sockets on Windows
- Qt: Fix crash when loading a game after stopping GDB server
- GBA BIOS: Fix BIOS decompression routines with invalid source addresses
- GBA: Initialize gba.sync to null
- GBA: Fix timer initialization
- GBA Memory: Fix I cycles that had been moved to ARM7 core
- GBA Memory: Fix cycle counting for 32-bit load/stores
- ARM7: Fix cycle counting for loads
- Qt: Pause game while open file dialogs are open (fixes #6 on GitHub)
- Qt: Fix crash when attempting to pause if a game is not running
- SDL: Properly clean up if a game doesn't launch
- Util: Fix sockets on Windows
Misc:
- GBA Audio: Change internal audio sample buffer from 32-bit to 16-bit samples
- GBA Memory: Simplify memory API and use fixed bus width
- GBA Video: Start video at the last scanline instead of the first
- All: Enable link-time optimization
- Debugger: Watchpoints now work on STM/LDM instructions
- GBA: Improve accuracy of event timing
- Debugger: Clean up GDB stub network interfacing
- Debugger: Simplify debugger state machine to play nicer with the GBA thread loop
- Debugger: Merge Thumb BL instructions when disassembling
- Debugger: Clean up debugger interface, removing obsolete state (fixes #67)
- Debugger: Watchpoints now report address watched (fixes #68)
- Debugger: Add support for soft breakpoints
- Debugger: Make I/O register names be addresses instead of values
- Debugger: Rename read/write commands
- GBA: Improve accuracy of event timing
- GBA: Add API for getting Configuration structs for overrides and input
- GBA: Refactor gba-sensors and gba-gpio into gba-hardware
- GBA: Refactor gba directory, dropping gba- prefix and making supervisor directory
- Debugger: Add support for soft breakpoints
- Util: Use proper locale for reading and writing float values
- Debugger: Make I/O register names be addresses instead of values
- Debugger: Rename read/write commands
- Qt: Optimize logo drawing
- Qt: Move frame upload back onto main thread
- All: Enable link-time optimization
- GBA Thread: Make GBASyncWaitFrameStart time out
- GBA: Move A/V stream interface into core
- GBA: Savestates now take into account savedata state machines (fixes #109)
- GBA Audio: Change internal audio sample buffer from 32-bit to 16-bit samples
- GBA Memory: Simplify memory API and use fixed bus width
- GBA Thread: Make GBASyncWaitFrameStart time out
- GBA Video: Start video at the last scanline instead of the first
- Qt: Optimize logo drawing
- Qt: Move frame upload back onto main thread
- Qt: Remember window position
- Qt: Double-clicking on the window toggles full screen
- Util: Use proper locale for reading and writing float values
0.1.1: (2015-01-24)
Bugfixes:

View File

@ -72,7 +72,7 @@ endfunction()
# Version information
set(LIB_VERSION_MAJOR 0)
set(LIB_VERSION_MINOR 2)
set(LIB_VERSION_PATCH 0)
set(LIB_VERSION_PATCH 1)
set(LIB_VERSION_ABI 0.2)
set(LIB_VERSION_STRING ${LIB_VERSION_MAJOR}.${LIB_VERSION_MINOR}.${LIB_VERSION_PATCH})
@ -224,7 +224,7 @@ if(USE_FFMPEG)
string(REGEX MATCH "^[0-9]+" LIBAVUTIL_VERSION_MAJOR ${libavutil_VERSION})
string(REGEX MATCH "^[0-9]+" LIBSWSCALE_VERSION_MAJOR ${libswscale_VERSION})
list(APPEND DEPENDENCY_LIB ${LIBAVCODEC_LIBRARIES} ${LIBAVFORMAT_LIBRARIES} ${LIBAVRESAMPLE_LIBRARIES} ${LIBAVUTIL_LIBRARIES} ${LIBSWSCALE_LIBRARIES})
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libavcodec${LIBAVCODEC_VERSION_MAJOR},libavformat${LIBAVFORMAT_VERSION_MAJOR},libavresample${LIBAVRESAMPLE_VERSION_MAJOR},libavutil${LIBAVUTIL_VERSION_MAJOR},libswscale${LIBSWSCALE_VERSION_MAJOR}")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libavcodec${LIBAVCODEC_VERSION_MAJOR}|libavcodec-extra-${LIBAVCODEC_VERSION_MAJOR},libavformat${LIBAVFORMAT_VERSION_MAJOR},libavresample${LIBAVRESAMPLE_VERSION_MAJOR},libavutil${LIBAVUTIL_VERSION_MAJOR},libswscale${LIBSWSCALE_VERSION_MAJOR}")
set(CPACK_DEBIAN_PACKAGE_RECOMMENDS "libavcodec-extra")
endif()

View File

@ -3,7 +3,7 @@ mGBA
mGBA is a new emulator for running Game Boy Advance games. It aims to be faster and more accurate than many existing Game Boy Advance emulators, as well as adding features that other emulators lack.
Up-to-date news and downloads can be found at [endrift.com/mgba](https://endrift.com/mgba/).
Up-to-date news and downloads can be found at [mgba.io](http://mgba.io/).
![Build status](https://travis-ci.org/mgba-emu/mgba.svg?branch=master)
@ -13,11 +13,12 @@ Features
- Near full Game Boy Advance hardware support[<sup>[1]</sup>](#missing).
- Fast emulation. Known to run at full speed even on low end hardware, such as netbooks.
- Qt and SDL ports for a heavy-weight and a light-weight frontend.
- Local (same computer) link cable support.
- Save type detection, even for flash memory size[<sup>[2]</sup>](#flashdetect).
- Real-time clock support, even without configuration.
- A built-in BIOS implementation, and ability to load external BIOS files.
- Turbo/fast-forward support by holding Tab.
- Frameskip, configurable up to 9.
- Frameskip, configurable up to 10.
- Screenshot support.
- Cheat code support.
- 9 savestate slots. Savestates are also viewable as screenshots.
@ -30,12 +31,13 @@ Features
### Planned features
- Local and networked multiplayer link cable support ([Bug #1](https://endrift.com/mgba/bugs/show_bug.cgi?id=1)).
- Dolphin/JOY bus link cable support ([Bug #73](https://endrift.com/mgba/bugs/show_bug.cgi?id=73)).
- Networked multiplayer link cable support ([Bug #1](http://mgba.io/b/1)).
- Dolphin/JOY bus link cable support ([Bug #73](http://mgba.io/b/73)).
- Re-recording support for tool-assist runs. ([Bugzilla keyword "TASBlocker"](https://endrift.com/mgba/bugs/buglist.cgi?quicksearch=TASBlocker))
- Lua support for scripting ([Bug #62](https://endrift.com/mgba/bugs/show_bug.cgi?id=62)).
- A comprehensive debug suite ([Bug #132](https://endrift.com/mgba/bugs/show_bug.cgi?id=132)).
- libretro core for RetroArch and OpenEmu ([Bug #86](https://endrift.com/mgba/bugs/show_bug.cgi?id=86)).
- Lua support for scripting ([Bug #62](http://mgba.io/b/62)).
- A comprehensive debug suite ([Bug #132](http://mgba.io/b/132)).
- OpenEmu core.
- e-Reader support. ([Bug #171](http://mgba.io/b/171))
Supported Platforms
@ -46,7 +48,7 @@ Supported Platforms
- Linux
- FreeBSD
Other Unix-like platforms work as well, but are untested.
Other Unix-like platforms, such as OpenBSD, are known to work as well, but are untested and not fully supported.
### System requirements
@ -72,7 +74,7 @@ Controls are configurable in the menu. The default gamepad controls are mapped s
Compiling
---------
Compiling requires using CMake 2.8.11 or newer. To use CMake to build on a Unix-based system, the recommended commands are as follows:
Compiling requires using CMake 2.8.11 or newer. GCC and Clang are both known to work to compile mGBA, but Visual Studio 2013 and older are known not to work. To use CMake to build on a Unix-based system, the recommended commands are as follows:
mkdir build
cd build
@ -99,18 +101,18 @@ Footnotes
<a name="missing">[1]</a> Currently missing features are
- OBJ window for modes 3, 4 and 5 ([Bug #5](https://endrift.com/mgba/bugs/show_bug.cgi?id=5))
- Mosaic for transformed OBJs ([Bug #9](https://endrift.com/mgba/bugs/show_bug.cgi?id=9))
- BIOS call RegisterRamReset is partially stubbed out ([Bug #141](https://endrift.com/mgba/bugs/show_bug.cgi?id=141))
- Audio channel reset flags ([Bug #142](https://endrift.com/mgba/bugs/show_bug.cgi?id=142))
- Game Pak prefetch ([Bug #195](https://endrift.com/mgba/bugs/show_bug.cgi?id=195))
- BIOS call Stop, for entering sleep mode ([Bug #199](https://endrift.com/mgba/bugs/show_bug.cgi?id=199))
- OBJ window for modes 3, 4 and 5 ([Bug #5](http://mgba.io/b/5))
- Mosaic for transformed OBJs ([Bug #9](http://mgba.io/b/9))
- BIOS call RegisterRamReset is partially stubbed out ([Bug #141](http://mgba.io/b/141))
- Audio channel reset flags ([Bug #142](http://mgba.io/b/142))
- Game Pak prefetch ([Bug #195](http://mgba.io/b/195))
- BIOS call Stop, for entering sleep mode ([Bug #199](http://mgba.io/b/199))
<a name="flashdetect">[2]</a> Flash memory size detection does not work in some cases, and may require overrides, which are not yet user configurable. Filing a bug is recommended if such a case is encountered.
<a name="flashdetect">[2]</a> Flash memory size detection does not work in some cases. These can be configured at runtime, but filing a bug is recommended if such a case is encountered.
<a name="osxver">[3]</a> 10.7 is only needed for the Qt port. The SDL port is known to work on 10.6, and may work on older.
[downloads]: https://endrift.com/mgba/downloads.html
[downloads]: http://mgba.io/downloads.html
[source]: https://github.com/mgba-emu/mgba/
Copyright

View File

@ -380,8 +380,12 @@ DEFINE_DECODER_ARM(MRC, ILL, info->operandFormat = ARM_OPERAND_NONE;)
// Begin miscellaneous definitions
DEFINE_DECODER_ARM(BKPT, BKPT, info->operandFormat = ARM_OPERAND_NONE;) // Not strictly in ARMv4T, but here for convenience
DEFINE_DECODER_ARM(ILL, ILL, info->operandFormat = ARM_OPERAND_NONE;) // Illegal opcode
DEFINE_DECODER_ARM(BKPT, BKPT,
info->operandFormat = ARM_OPERAND_NONE;
info->traps = 1;) // Not strictly in ARMv4T, but here for convenience
DEFINE_DECODER_ARM(ILL, ILL,
info->operandFormat = ARM_OPERAND_NONE;
info->traps = 1;) // Illegal opcode
DEFINE_DECODER_ARM(MSR, MSR,
info->affectsCPSR = 1;

View File

@ -281,8 +281,13 @@ DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(POPR, ARM_SP, LDM, ARM_MEMORY_INCREMENT_AFTE
DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(PUSH, ARM_SP, STM, ARM_MEMORY_DECREMENT_BEFORE, 0)
DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(PUSHR, ARM_SP, STM, ARM_MEMORY_DECREMENT_BEFORE, 1 << ARM_LR)
DEFINE_THUMB_DECODER(ILL, ILL, info->traps = 1;)
DEFINE_THUMB_DECODER(BKPT, BKPT, info->traps = 1;)
DEFINE_THUMB_DECODER(ILL, ILL,
info->operandFormat = ARM_OPERAND_NONE;
info->traps = 1;)
DEFINE_THUMB_DECODER(BKPT, BKPT,
info->operandFormat = ARM_OPERAND_NONE;
info->traps = 1;)
DEFINE_THUMB_DECODER(B, B,
int16_t immediate = (opcode & 0x07FF) << 5;

View File

@ -233,7 +233,12 @@ static inline void _immediate(struct ARMCore* cpu, uint32_t opcode) {
#define ADDR_MODE_2_RM (cpu->gprs[rm])
#define ADDR_MODE_2_IMMEDIATE (opcode & 0x00000FFF)
#define ADDR_MODE_2_INDEX(U_OP, M) (cpu->gprs[rn] U_OP M)
#define ADDR_MODE_2_WRITEBACK(ADDR) (cpu->gprs[rn] = ADDR)
#define ADDR_MODE_2_WRITEBACK(ADDR) \
cpu->gprs[rn] = ADDR; \
if (UNLIKELY(rn == ARM_PC)) { \
ARM_WRITE_PC; \
}
#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)
@ -322,13 +327,12 @@ static inline void _immediate(struct ARMCore* cpu, uint32_t opcode) {
int rdHi = (opcode >> 16) & 0xF; \
int rs = (opcode >> 8) & 0xF; \
int rm = opcode & 0xF; \
UNUSED(rdHi); \
if (rdHi == ARM_PC || rd == ARM_PC) { \
return; \
} \
ARM_WAIT_MUL(cpu->gprs[rs]); \
BODY; \
S_BODY; \
if (rd == ARM_PC) { \
ARM_WRITE_PC; \
})
S_BODY;)
#define DEFINE_MULTIPLY_INSTRUCTION_ARM(NAME, BODY, S_BODY) \
DEFINE_MULTIPLY_INSTRUCTION_EX_ARM(NAME, BODY, ) \

View File

@ -816,7 +816,7 @@ static unsigned char _tabComplete(EditLine* elstate, int ch) {
}
const char* commandPtr;
int cmd = 0, len = 0;
size_t cmd = 0, len = 0;
const char* name = 0;
for (commandPtr = li->buffer; commandPtr <= li->cursor; ++commandPtr, ++len) {
for (; (name = _debuggerCommands[cmd].name); ++cmd) {
@ -832,7 +832,7 @@ static unsigned char _tabComplete(EditLine* elstate, int ch) {
if (!name) {
return CC_ERROR;
}
if (_debuggerCommands[cmd + 1].name && name[len - 2] == _debuggerCommands[cmd + 1].name[len - 2]) {
if (_debuggerCommands[cmd + 1].name && strlen(_debuggerCommands[cmd + 1].name) >= len - 1 && name[len - 2] == _debuggerCommands[cmd + 1].name[len - 2]) {
--len;
const char* next = 0;
int i;
@ -842,6 +842,9 @@ static unsigned char _tabComplete(EditLine* elstate, int ch) {
}
next = _debuggerCommands[i].name;
}
if (!next) {
return CC_ERROR;
}
for (; name[len]; ++len) {
if (name[len] != next[len]) {

View File

@ -149,11 +149,14 @@ bool ARMDebuggerSetSoftwareBreakpoint(struct ARMDebugger* debugger, uint32_t add
void ARMDebuggerClearBreakpoint(struct ARMDebugger* debugger, uint32_t address) {
struct DebugBreakpoint** previous = &debugger->breakpoints;
struct DebugBreakpoint* breakpoint;
for (; (breakpoint = *previous); previous = &breakpoint->next) {
struct DebugBreakpoint** next;
while ((breakpoint = *previous)) {
next = &breakpoint->next;
if (breakpoint->address == address) {
*previous = breakpoint->next;
*previous = *next;
free(breakpoint);
}
previous = next;
}
}
@ -169,12 +172,15 @@ void ARMDebuggerSetWatchpoint(struct ARMDebugger* debugger, uint32_t address) {
void ARMDebuggerClearWatchpoint(struct ARMDebugger* debugger, uint32_t address) {
struct DebugWatchpoint** previous = &debugger->watchpoints;
struct DebugWatchpoint* breakpoint;
for (; (breakpoint = *previous); previous = &breakpoint->next) {
if (breakpoint->address == address) {
*previous = breakpoint->next;
free(breakpoint);
struct DebugWatchpoint* watchpoint;
struct DebugWatchpoint** next;
while ((watchpoint = *previous)) {
next = &watchpoint->next;
if (watchpoint->address == address) {
*previous = *next;
free(watchpoint);
}
previous = next;
}
if (!debugger->watchpoints) {
ARMDebuggerRemoveMemoryShim(debugger);

View File

@ -464,6 +464,8 @@ void GDBStubCreate(struct GDBStub* stub) {
stub->d.custom = _gdbStubPoll;
stub->d.log = 0;
stub->untilPoll = GDB_STUB_INTERVAL;
stub->lineAck = GDB_ACK_PENDING;
stub->shouldBlock = false;
}
bool GDBStubListen(struct GDBStub* stub, int port, const struct Address* bindAddress) {

View File

@ -514,11 +514,15 @@ void GBAAudioSampleFIFO(struct GBAAudio* audio, int fifoId, int32_t cycles) {
GBALog(audio->p, GBA_LOG_ERROR, "Bad FIFO write to address 0x%03x", fifoId);
return;
}
if (CircleBufferSize(&channel->fifo) <= 4 * sizeof(int32_t)) {
if (CircleBufferSize(&channel->fifo) <= 4 * sizeof(int32_t) && channel->dmaSource > 0) {
struct GBADMA* dma = &audio->p->memory.dma[channel->dmaSource];
dma->nextCount = 4;
dma->nextEvent = 0;
GBAMemoryUpdateDMAs(audio->p, -cycles);
if (GBADMARegisterGetTiming(dma->reg) == DMA_TIMING_CUSTOM) {
dma->nextCount = 4;
dma->nextEvent = 0;
GBAMemoryUpdateDMAs(audio->p, -cycles);
} else {
channel->dmaSource = 0;
}
}
CircleBufferRead8(&channel->fifo, &channel->sample);
}

View File

@ -331,7 +331,7 @@ static void _unLz77(struct GBA* gba, int width) {
uint32_t disp;
int bytes;
int byte;
int halfword;
int halfword = 0;
while (remaining > 0) {
if (blocksRemaining) {
if (blockheader & 0x80) {

View File

@ -433,6 +433,7 @@ void GBATimerUpdateRegister(struct GBA* gba, int timer) {
void GBATimerWriteTMCNT_LO(struct GBA* gba, int timer, uint16_t reload) {
gba->timers[timer].reload = reload;
gba->timers[timer].overflowInterval = (0x10000 - gba->timers[timer].reload) << gba->timers[timer].prescaleBits;
}
void GBATimerWriteTMCNT_HI(struct GBA* gba, int timer, uint16_t control) {

View File

@ -95,7 +95,7 @@ static struct GBAInputMapImpl* _guaranteeMap(struct GBAInputMap* map, uint32_t t
map->numMaps = 1;
impl = &map->maps[0];
impl->type = type;
impl->map = calloc(GBA_KEY_MAX, sizeof(enum GBAKey));
impl->map = calloc(GBA_KEY_MAX, sizeof(int));
TableInit(&impl->axes, 2, free);
} else {
impl = _lookupMap(map, type);
@ -110,7 +110,7 @@ static struct GBAInputMapImpl* _guaranteeMap(struct GBAInputMap* map, uint32_t t
}
if (impl) {
impl->type = type;
impl->map = calloc(GBA_KEY_MAX, sizeof(enum GBAKey));
impl->map = calloc(GBA_KEY_MAX, sizeof(int));
} else {
map->maps = realloc(map->maps, sizeof(*map->maps) * map->numMaps * 2);
for (m = map->numMaps * 2 - 1; m > map->numMaps; --m) {
@ -120,7 +120,7 @@ static struct GBAInputMapImpl* _guaranteeMap(struct GBAInputMap* map, uint32_t t
map->numMaps *= 2;
impl = &map->maps[m];
impl->type = type;
impl->map = calloc(GBA_KEY_MAX, sizeof(enum GBAKey));
impl->map = calloc(GBA_KEY_MAX, sizeof(int));
}
TableInit(&impl->axes, 2, free);
}

View File

@ -286,6 +286,10 @@ void GBAIOInit(struct GBA* gba) {
gba->memory.io[REG_RCNT >> 1] = RCNT_INITIAL;
gba->memory.io[REG_KEYINPUT >> 1] = 0x3FF;
gba->memory.io[REG_SOUNDBIAS >> 1] = 0x200;
gba->memory.io[REG_BG2PA >> 1] = 0x100;
gba->memory.io[REG_BG2PD >> 1] = 0x100;
gba->memory.io[REG_BG3PA >> 1] = 0x100;
gba->memory.io[REG_BG3PD >> 1] = 0x100;
}
void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) {
@ -494,6 +498,10 @@ void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) {
break;
default:
GBALog(gba, GBA_LOG_STUB, "Stub I/O register write: %03x", address);
if (address >= REG_MAX) {
GBALog(gba, GBA_LOG_GAME_ERROR, "Write to unused I/O register: %03X", address);
return;
}
break;
}
}
@ -648,6 +656,10 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) {
break;
default:
GBALog(gba, GBA_LOG_STUB, "Stub I/O register read: %03x", address);
if (address >= REG_MAX) {
GBALog(gba, GBA_LOG_GAME_ERROR, "Read from unused I/O register: %03X", address);
return 0; // TODO: Reuse LOAD_BAD
}
break;
}
return gba->memory.io[address >> 1];

View File

@ -225,7 +225,7 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) {
}
gba->lastJump = address;
if (newRegion == memory->activeRegion) {
if (newRegion == memory->activeRegion && (newRegion < REGION_CART0 || (address & (SIZE_CART0 - 1)) < memory->romSize)) {
return;
}
@ -233,33 +233,37 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) {
memory->biosPrefetch = cpu->prefetch[1];
}
memory->activeRegion = newRegion;
switch (address & ~OFFSET_MASK) {
case BASE_BIOS:
switch (newRegion) {
case REGION_BIOS:
cpu->memory.activeRegion = memory->bios;
cpu->memory.activeMask = SIZE_BIOS - 1;
break;
case BASE_WORKING_RAM:
case REGION_WORKING_RAM:
cpu->memory.activeRegion = memory->wram;
cpu->memory.activeMask = SIZE_WORKING_RAM - 1;
break;
case BASE_WORKING_IRAM:
case REGION_WORKING_IRAM:
cpu->memory.activeRegion = memory->iwram;
cpu->memory.activeMask = SIZE_WORKING_IRAM - 1;
break;
case BASE_VRAM:
case REGION_VRAM:
cpu->memory.activeRegion = (uint32_t*) gba->video.renderer->vram;
cpu->memory.activeMask = 0x0000FFFF;
break;
case BASE_CART0:
case BASE_CART0_EX:
case BASE_CART1:
case BASE_CART1_EX:
case BASE_CART2:
case BASE_CART2_EX:
case REGION_CART0:
case REGION_CART0_EX:
case REGION_CART1:
case REGION_CART1_EX:
case REGION_CART2:
case REGION_CART2_EX:
cpu->memory.activeRegion = memory->rom;
cpu->memory.activeMask = SIZE_CART0 - 1;
break;
if ((address & (SIZE_CART0 - 1)) < memory->romSize) {
break;
}
// Fall through
default:
memory->activeRegion = 0;
cpu->memory.activeRegion = _deadbeef;
cpu->memory.activeMask = 0;
GBALog(gba, GBA_LOG_FATAL, "Jumped to invalid address");
@ -324,7 +328,7 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) {
} else { \
GBALog(gba, GBA_LOG_GAME_ERROR, "Out of bounds ROM Load32: 0x%08X", address); \
value = (address >> 1) & 0xFFFF; \
value |= value << 16; \
value |= ((address + 2) >> 1) << 16; \
}
#define LOAD_SRAM \

View File

@ -61,7 +61,7 @@ enum {
SIZE_CART0 = 0x02000000,
SIZE_CART1 = 0x02000000,
SIZE_CART2 = 0x02000000,
SIZE_CART_SRAM = 0x00008000,
SIZE_CART_SRAM = 0x00010000,
SIZE_CART_FLASH512 = 0x00010000,
SIZE_CART_FLASH1M = 0x00020000,
SIZE_CART_EEPROM = 0x00002000

View File

@ -1608,7 +1608,7 @@ static void _drawBackgroundMode5(struct GBAVideoSoftwareRenderer* renderer, stru
BACKGROUND_BITMAP_ITERATE(160, 128);
if (!mosaicWait) {
LOAD_16(color, (offset + (localX >> 8) + (localY >> 8) * 160) << 1, renderer->d.vram);
LOAD_16(color, offset + (localX >> 8) * 2 + (localY >> 8) * 320, renderer->d.vram);
#ifndef COLOR_16_BIT
unsigned color32 = 0;
color32 |= (color << 9) & 0xF80000;

View File

@ -345,12 +345,14 @@ void GBASavedataWriteEEPROM(struct GBASavedata* savedata, uint16_t value, uint32
savedata->writeAddress |= (value & 0x1) << 6;
} else if (writeSize == 1) {
savedata->command = EEPROM_COMMAND_NULL;
} else {
} else if ((savedata->writeAddress >> 3) < SIZE_CART_EEPROM) {
uint8_t current = savedata->data[savedata->writeAddress >> 3];
current &= ~(1 << (0x7 - (savedata->writeAddress & 0x7)));
current |= (value & 0x1) << (0x7 - (savedata->writeAddress & 0x7));
savedata->data[savedata->writeAddress >> 3] = current;
++savedata->writeAddress;
} else {
GBALog(0, GBA_LOG_GAME_ERROR, "Writing beyond end of EEPROM: %08X", (savedata->writeAddress >> 3));
}
break;
case EEPROM_COMMAND_READ_PENDING:
@ -375,7 +377,12 @@ uint16_t GBASavedataReadEEPROM(struct GBASavedata* savedata) {
--savedata->readBitsRemaining;
if (savedata->readBitsRemaining < 64) {
int step = 63 - savedata->readBitsRemaining;
uint8_t data = savedata->data[(savedata->readAddress + step) >> 3] >> (0x7 - (step & 0x7));
uint32_t address = (savedata->readAddress + step) >> 3;
if (address >= SIZE_CART_EEPROM) {
GBALog(0, GBA_LOG_GAME_ERROR, "Reading beyond end of EEPROM: %08X", address);
return 0xFF;
}
uint8_t data = savedata->data[address] >> (0x7 - (step & 0x7));
if (!savedata->readBitsRemaining) {
savedata->command = EEPROM_COMMAND_NULL;
}

View File

@ -178,7 +178,10 @@ static bool _loadPNGState(struct GBA* gba, struct VFile* vf) {
PNGReadFooter(png, end);
PNGReadClose(png, info, end);
gba->video.renderer->putPixels(gba->video.renderer, VIDEO_HORIZONTAL_PIXELS, pixels);
bool videoFrameWait = gba->sync->videoFrameWait;
gba->sync->videoFrameWait = false;
GBASyncPostFrame(gba->sync);
gba->sync->videoFrameWait = videoFrameWait;
free(pixels);
return true;
@ -291,14 +294,14 @@ void GBARewind(struct GBAThread* thread, int nStates) {
}
int offset = thread->rewindBufferWriteOffset - nStates;
if (offset < 0) {
offset += thread->rewindBufferSize;
offset += thread->rewindBufferCapacity;
}
struct GBASerializedState* state = thread->rewindBuffer[offset];
if (!state) {
return;
}
thread->rewindBufferSize -= nStates - 1;
thread->rewindBufferWriteOffset = (offset + 1) % thread->rewindBufferCapacity;
thread->rewindBufferSize -= nStates;
thread->rewindBufferWriteOffset = offset;
GBADeserialize(thread->gba, state);
}

View File

@ -145,7 +145,7 @@ bool GBAOverrideFind(const struct Configuration* config, struct GBACartridgeOver
override->savetype = SAVEDATA_AUTODETECT;
override->hardware = HW_NONE;
override->idleLoop = IDLE_LOOP_NONE;
bool found;
bool found = false;
if (override->id[0] == 'F') {
// Classic NES Series

View File

@ -202,7 +202,8 @@ bool FFmpegEncoderOpen(struct FFmpegEncoder* encoder, const char* outfile) {
avformat_alloc_output_context2(&encoder->context, oformat, 0, outfile);
#else
encoder->context = avformat_alloc_context();
strncpy(encoder->context->filename, outfile, sizeof(encoder->context->filename));
strncpy(encoder->context->filename, outfile, sizeof(encoder->context->filename) - 1);
encoder->context->filename[sizeof(encoder->context->filename) - 1] = '\0';
encoder->context->oformat = oformat;
#endif

View File

@ -95,7 +95,14 @@ int main(int argc, char** argv) {
if (!didStart) {
goto cleanup;
}
GBAThreadInterrupt(&context);
if (GBAThreadHasCrashed(&context)) {
GBAThreadJoin(&context);
goto cleanup;
}
GBAGetGameCode(context.gba, gameCode);
GBAThreadContinue(&context);
int frames = perfOpts.frames;
if (!frames) {

View File

@ -17,12 +17,13 @@ AudioDevice::AudioDevice(QObject* parent)
: QIODevice(parent)
, m_context(nullptr)
, m_drift(0)
, m_ratio(1.f)
{
setOpenMode(ReadOnly);
}
void AudioDevice::setFormat(const QAudioFormat& format) {
if (!GBAThreadIsActive(m_context)) {
if (!m_context || !GBAThreadIsActive(m_context)) {
return;
}
#if RESAMPLE_LIBRARY == RESAMPLE_NN

View File

@ -48,6 +48,8 @@ AudioProcessor* AudioProcessor::create() {
AudioProcessor::AudioProcessor(QObject* parent)
: QObject(parent)
, m_context(nullptr)
, m_samples(GBA_AUDIO_SAMPLES)
{
}

View File

@ -33,6 +33,10 @@ void AudioProcessorQt::setInput(GBAThread* input) {
}
void AudioProcessorQt::start() {
if (!input()) {
return;
}
if (!m_device) {
m_device = new AudioDevice(this);
}

View File

@ -22,6 +22,10 @@ AudioProcessorSDL::~AudioProcessorSDL() {
}
void AudioProcessorSDL::start() {
if (!input()) {
return;
}
if (m_audio.thread) {
GBASDLResumeAudio(&m_audio);
} else {

View File

@ -4,7 +4,10 @@ enable_language(CXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++11")
if(APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.7 -stdlib=libc++")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.7")
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
endif()
endif()
set(PLATFORM_SRC)
@ -74,7 +77,7 @@ qt5_wrap_ui(UI_FILES
VideoView.ui)
set(QT_LIBRARIES)
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libqt5widgets5,libqt5opengl5" PARENT_SCOPE)
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libqt5widgets5,libqt5opengl5")
set(AUDIO_SRC)
if(BUILD_SDL)
@ -87,7 +90,7 @@ if(Qt5Multimedia_FOUND)
AudioDevice.cpp)
list(APPEND QT_LIBRARIES Qt5::Multimedia)
add_definitions(-DBUILD_QT_MULTIMEDIA)
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libqt5multimedia5" PARENT_SCOPE)
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libqt5multimedia5")
endif()
if(NOT AUDIO_SRC)
@ -115,6 +118,7 @@ set_target_properties(${BINARY_NAME}-qt PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CM
list(APPEND QT_LIBRARIES Qt5::Widgets Qt5::OpenGL)
target_link_libraries(${BINARY_NAME}-qt ${PLATFORM_LIBRARY} ${OPENGL_LIBRARY} ${BINARY_NAME} ${QT_LIBRARIES})
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS}" PARENT_SCOPE)
install(TARGETS ${BINARY_NAME}-qt
RUNTIME DESTINATION bin COMPONENT ${BINARY_NAME}-qt

View File

@ -32,6 +32,9 @@ Display::Display(QGLFormat format, QWidget* parent)
: QGLWidget(format, parent)
, m_painter(nullptr)
, m_started(false)
, m_lockAspectRatio(false)
, m_filter(false)
, m_context(nullptr)
{
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
setMinimumSize(VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS);
@ -129,7 +132,6 @@ void Display::screenshot() {
void Display::initializeGL() {
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
swapBuffers();
}
void Display::resizeEvent(QResizeEvent* event) {
@ -146,6 +148,7 @@ Painter::Painter(Display* parent)
: m_gl(parent)
, m_lockAspectRatio(false)
, m_filter(false)
, m_context(nullptr)
{
m_size = parent->size();
}

View File

@ -334,7 +334,7 @@ bool GameController::isPaused() {
}
void GameController::setPaused(bool paused) {
if (paused == GBAThreadIsPaused(&m_threadContext)) {
if (!m_gameOpen || paused == GBAThreadIsPaused(&m_threadContext)) {
return;
}
if (paused) {
@ -500,6 +500,10 @@ void GameController::setTurbo(bool set, bool forced) {
if (m_turboForced && !forced) {
return;
}
if (m_turbo == set && m_turboForced == forced) {
// Don't interrupt the thread if we don't need to
return;
}
m_turbo = set;
m_turboForced = set && forced;
threadInterrupt();
@ -511,12 +515,18 @@ void GameController::setTurbo(bool set, bool forced) {
void GameController::setAVStream(GBAAVStream* stream) {
threadInterrupt();
m_threadContext.stream = stream;
if (m_gameOpen) {
m_threadContext.gba->stream = stream;
}
threadContinue();
}
void GameController::clearAVStream() {
threadInterrupt();
m_threadContext.stream = nullptr;
if (m_gameOpen) {
m_threadContext.gba->stream = nullptr;
}
threadContinue();
}

View File

@ -90,6 +90,11 @@ void InputController::setConfiguration(ConfigController* config) {
void InputController::loadConfiguration(uint32_t type) {
GBAInputMapLoad(&m_inputMap, type, m_config->input());
#ifdef BUILD_SDL
if (m_playerAttached) {
GBASDLPlayerLoadConfig(&m_sdlPlayer, m_config->input());
}
#endif
}
void InputController::loadProfile(uint32_t type, const QString& profile) {
@ -281,13 +286,18 @@ void InputController::testGamepad() {
GamepadAxisEvent* event = new GamepadAxisEvent(axis.first, axis.second, newlyAboveThreshold, this);
if (newlyAboveThreshold) {
postPendingEvent(event->gbaKey());
QApplication::sendEvent(QApplication::focusWidget(), event);
if (!event->isAccepted()) {
clearPendingEvent(event->gbaKey());
}
} else if (oldAxes.contains(axis)) {
clearPendingEvent(event->gbaKey());
QApplication::sendEvent(QApplication::focusWidget(), event);
}
QApplication::sendEvent(QApplication::focusWidget(), event);
}
if (!QApplication::focusWidget()) {
return;
}
activeButtons.subtract(oldButtons);

View File

@ -15,6 +15,7 @@ using namespace QGBA;
KeyEditor::KeyEditor(QWidget* parent)
: QLineEdit(parent)
, m_direction(GamepadAxisEvent::NEUTRAL)
, m_button(false)
{
setAlignment(Qt::AlignCenter);
}

View File

@ -43,6 +43,12 @@ LoadSaveState::LoadSaveState(GameController* controller, QWidget* parent)
m_slots[i]->installEventFilter(this);
connect(m_slots[i], &QAbstractButton::clicked, this, [this, i]() { triggerState(i + 1); });
}
QAction* escape = new QAction(this);
escape->connect(escape, SIGNAL(triggered()), this, SLOT(close()));
escape->setShortcut(QKeySequence("Esc"));
escape->setShortcutContext(Qt::WidgetWithChildrenShortcut);
addAction(escape);
}
void LoadSaveState::setMode(LoadSave mode) {
@ -80,9 +86,6 @@ bool LoadSaveState::eventFilter(QObject* object, QEvent* event) {
case Qt::Key_9:
triggerState(static_cast<QKeyEvent*>(event)->key() - Qt::Key_1 + 1);
break;
case Qt::Key_Escape:
close();
break;
case Qt::Key_Enter:
case Qt::Key_Return:
triggerState(m_currentFocus + 1);

View File

@ -47,7 +47,6 @@ private:
Ui::LoadSaveState m_ui;
GameController* m_controller;
InputController* m_inputController;
SavestateButton* m_slots[NUM_SLOTS];
LoadSave m_mode;

View File

@ -12,6 +12,9 @@ using namespace QGBA;
LogView::LogView(QWidget* parent)
: QWidget(parent)
, m_logLevel(0)
, m_lines(0)
, m_lineLimit(DEFAULT_LINE_LIMIT)
{
m_ui.setupUi(this);
connect(m_ui.levelDebug, SIGNAL(toggled(bool)), this, SLOT(setLevelDebug(bool)));
@ -24,8 +27,6 @@ LogView::LogView(QWidget* parent)
connect(m_ui.levelSWI, SIGNAL(toggled(bool)), this, SLOT(setLevelSWI(bool)));
connect(m_ui.clear, SIGNAL(clicked()), this, SLOT(clear()));
connect(m_ui.maxLines, SIGNAL(valueChanged(int)), this, SLOT(setMaxLines(int)));
m_logLevel = 0;
m_lines = 0;
m_ui.maxLines->setValue(DEFAULT_LINE_LIMIT);
}

View File

@ -67,7 +67,7 @@ Window::Window(ConfigController* config, int playerId, QWidget* parent)
QGLFormat format(QGLFormat(QGL::Rgba | QGL::DoubleBuffer));
format.setSwapInterval(1);
m_display = new Display(format);
m_display = new Display(format, this);
m_logo.setDevicePixelRatio(m_screenWidget->devicePixelRatio());
m_logo = m_logo; // Free memory left over in old pixmap
@ -196,7 +196,14 @@ void Window::saveConfig() {
}
void Window::selectROM() {
bool doPause = m_controller->isLoaded() && !m_controller->isPaused();
if (doPause) {
m_controller->setPaused(true);
}
QString filename = QFileDialog::getOpenFileName(this, tr("Select ROM"), m_config->getQtOption("lastDirectory").toString(), tr("Game Boy Advance ROMs (*.gba *.zip *.rom *.bin)"));
if (doPause) {
m_controller->setPaused(false);
}
if (!filename.isEmpty()) {
m_config->setQtOption("lastDirectory", QFileInfo(filename).dir().path());
m_controller->loadGame(filename);
@ -204,7 +211,14 @@ void Window::selectROM() {
}
void Window::selectBIOS() {
bool doPause = m_controller->isLoaded() && !m_controller->isPaused();
if (doPause) {
m_controller->setPaused(true);
}
QString filename = QFileDialog::getOpenFileName(this, tr("Select BIOS"), m_config->getQtOption("lastDirectory").toString());
if (doPause) {
m_controller->setPaused(false);
}
if (!filename.isEmpty()) {
m_config->setQtOption("lastDirectory", QFileInfo(filename).dir().path());
m_config->setOption("bios", filename);
@ -216,7 +230,14 @@ void Window::selectBIOS() {
}
void Window::selectPatch() {
bool doPause = m_controller->isLoaded() && !m_controller->isPaused();
if (doPause) {
m_controller->setPaused(true);
}
QString filename = QFileDialog::getOpenFileName(this, tr("Select patch"), m_config->getQtOption("lastDirectory").toString(), tr("Patches (*.ips *.ups *.bps)"));
if (doPause) {
m_controller->setPaused(false);
}
if (!filename.isEmpty()) {
m_config->setQtOption("lastDirectory", QFileInfo(filename).dir().path());
m_controller->loadPatch(filename);
@ -497,8 +518,14 @@ void Window::recordFrame() {
}
void Window::showFPS() {
char title[13] = { '\0' };
GBAGetGameTitle(m_controller->thread()->gba, title);
char gameTitle[13] = { '\0' };
GBAGetGameTitle(m_controller->thread()->gba, gameTitle);
QString title(gameTitle);
std::shared_ptr<MultiplayerController> multiplayer = m_controller->multiplayerController();
if (multiplayer && multiplayer->attached() > 1) {
title += tr(" - Player %1 of %2").arg(m_playerId + 1).arg(multiplayer->attached());
}
if (m_frameList.isEmpty()) {
setWindowTitle(tr(PROJECT_NAME " - %1").arg(title));
return;
@ -520,7 +547,7 @@ void Window::openStateWindow(LoadSave ls) {
connect(m_stateWindow, &LoadSaveState::closed, [this]() {
m_screenWidget->layout()->removeWidget(m_stateWindow);
m_stateWindow = nullptr;
setFocus();
QMetaObject::invokeMethod(this, "setFocus", Qt::QueuedConnection);
});
if (!wasPaused) {
m_controller->setPaused(true);
@ -585,9 +612,14 @@ void Window::setupMenu(QMenuBar* menubar) {
}
Window* w2 = new Window(m_config, multiplayer->attached());
w2->setAttribute(Qt::WA_DeleteOnClose);
#ifndef Q_OS_MAC
w2->show();
#endif
w2->loadConfig();
w2->controller()->setMultiplayerController(multiplayer);
#ifdef Q_OS_MAC
w2->show();
#endif
});
addControlledAction(fileMenu, multiWindow, "multiWindow");
@ -662,6 +694,26 @@ void Window::setupMenu(QMenuBar* menubar) {
}, this);
m_config->updateOption("audioSync");
emulationMenu->addSeparator();
QMenu* solarMenu = emulationMenu->addMenu(tr("Solar sensor"));
m_shortcutController->addMenu(solarMenu);
QAction* solarIncrease = new QAction(tr("Increase solar level"), solarMenu);
connect(solarIncrease, SIGNAL(triggered()), m_controller, SLOT(increaseLuminanceLevel()));
addControlledAction(solarMenu, solarIncrease, "increaseLuminanceLevel");
QAction* solarDecrease = new QAction(tr("Decrease solar level"), solarMenu);
connect(solarDecrease, SIGNAL(triggered()), m_controller, SLOT(decreaseLuminanceLevel()));
addControlledAction(solarMenu, solarDecrease, "decreaseLuminanceLevel");
QAction* maxSolar = new QAction(tr("Brightest solar level"), solarMenu);
connect(maxSolar, &QAction::triggered, [this]() { m_controller->setLuminanceLevel(10); });
addControlledAction(solarMenu, maxSolar, "maxLuminanceLevel");
QAction* minSolar = new QAction(tr("Darkest solar level"), solarMenu);
connect(minSolar, &QAction::triggered, [this]() { m_controller->setLuminanceLevel(0); });
addControlledAction(solarMenu, minSolar, "minLuminanceLevel");
QMenu* avMenu = menubar->addMenu(tr("Audio/&Video"));
m_shortcutController->addMenu(avMenu);
QMenu* frameMenu = avMenu->addMenu(tr("Frame size"));
@ -672,7 +724,7 @@ void Window::setupMenu(QMenuBar* menubar) {
showNormal();
resizeFrame(VIDEO_HORIZONTAL_PIXELS * i, VIDEO_VERTICAL_PIXELS * i);
});
addControlledAction(frameMenu, setSize, tr("frame%1x").arg(QString::number(i)));
addControlledAction(frameMenu, setSize, QString("frame%1x").arg(QString::number(i)));
}
addControlledAction(frameMenu, frameMenu->addAction(tr("Fullscreen"), this, SLOT(toggleFullScreen()), QKeySequence("Ctrl+F")), "fullscreen");
@ -716,7 +768,7 @@ void Window::setupMenu(QMenuBar* menubar) {
avMenu->addSeparator();
QMenu* target = avMenu->addMenu("FPS target");
QMenu* target = avMenu->addMenu(tr("FPS target"));
ConfigOption* fpsTargetOption = m_config->addOption("fpsTarget");
fpsTargetOption->connect([this](const QVariant& value) {
emit fpsTargetChanged(value.toInt());
@ -780,23 +832,6 @@ void Window::setupMenu(QMenuBar* menubar) {
addControlledAction(toolsMenu, gdbWindow, "gdbWindow");
#endif
QMenu* solarMenu = toolsMenu->addMenu(tr("Solar sensor"));
QAction* solarIncrease = new QAction(tr("Increase solar level"), solarMenu);
connect(solarIncrease, SIGNAL(triggered()), m_controller, SLOT(increaseLuminanceLevel()));
addControlledAction(solarMenu, solarIncrease, "increaseLuminanceLevel");
QAction* solarDecrease = new QAction(tr("Decrease solar level"), solarMenu);
connect(solarDecrease, SIGNAL(triggered()), m_controller, SLOT(decreaseLuminanceLevel()));
addControlledAction(solarMenu, solarDecrease, "decreaseLuminanceLevel");
QAction* maxSolar = new QAction(tr("Brightest solar level"), solarMenu);
connect(maxSolar, &QAction::triggered, [this]() { m_controller->setLuminanceLevel(10); });
addControlledAction(solarMenu, maxSolar, "maxLuminanceLevel");
QAction* minSolar = new QAction(tr("Darkest solar level"), solarMenu);
connect(minSolar, &QAction::triggered, [this]() { m_controller->setLuminanceLevel(0); });
addControlledAction(solarMenu, minSolar, "minLuminanceLevel");
toolsMenu->addSeparator();
addControlledAction(toolsMenu, toolsMenu->addAction(tr("Settings..."), this, SLOT(openSettingsWindow())), "settings");
addControlledAction(toolsMenu, toolsMenu->addAction(tr("Edit shortcuts..."), this, SLOT(openShortcutWindow())), "shortcuts");
@ -898,6 +933,7 @@ void Window::updateMRU() {
QAction* Window::addControlledAction(QMenu* menu, QAction* action, const QString& name) {
m_shortcutController->addAction(menu, action, name);
menu->addAction(action);
action->setShortcutContext(Qt::WidgetShortcut);
addAction(action);
return action;
}

View File

@ -39,6 +39,7 @@ include_directories(${CMAKE_SOURCE_DIR}/src/platform/sdl ${PIXMAN-1_INCLUDE_DIR}
set(SDL_INCLUDE_DIR "${SDL_INCLUDE_DIR}" PARENT_SCOPE)
set(SDL_LIBRARY "${SDL_LIBRARY}" PARENT_SCOPE)
set(SDLMAIN_LIBRARY "${SDLMAIN_LIBRARY}" PARENT_SCOPE)
set(MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/main.c)

View File

@ -190,7 +190,7 @@ void GBASDLPlayerLoadConfig(struct GBASDLPlayer* context, const struct Configura
}
void GBASDLPlayerChangeJoystick(struct GBASDLEvents* events, struct GBASDLPlayer* player, size_t index) {
if (player->playerId > MAX_PLAYERS || index >= events->nJoysticks) {
if (player->playerId >= MAX_PLAYERS || index >= events->nJoysticks) {
return;
}
events->joysticksClaimed[player->playerId] = index;

View File

@ -53,10 +53,14 @@ void ConfigurationSetValue(struct Configuration* configuration, const char* sect
struct Table* currentSection = &configuration->root;
if (section) {
currentSection = HashTableLookup(&configuration->sections, section);
if (!currentSection && value) {
currentSection = malloc(sizeof(*currentSection));
HashTableInit(currentSection, 0, _sectionDeinit);
HashTableInsert(&configuration->sections, section, currentSection);
if (!currentSection) {
if (value) {
currentSection = malloc(sizeof(*currentSection));
HashTableInit(currentSection, 0, _sectionDeinit);
HashTableInsert(&configuration->sections, section, currentSection);
} else {
return;
}
}
}
if (value) {

View File

@ -178,13 +178,14 @@ char* utf16to8(const uint16_t* utf16, size_t length) {
offset = utf8 + bytes;
} else if (utf8Length >= utf8TotalBytes) {
char* newUTF8 = realloc(utf8, utf8TotalBytes * 2);
offset = offset - utf8 + newUTF8;
if (newUTF8 != utf8) {
free(utf8);
}
if (!newUTF8) {
return 0;
}
offset = offset - utf8 + newUTF8;
utf8 = newUTF8;
memcpy(offset, buffer, bytes);
offset += bytes;
}

View File

@ -197,6 +197,7 @@ struct VDir* VDirOpen(const char* path) {
struct VDirDE* vd = malloc(sizeof(struct VDirDE));
if (!vd) {
closedir(de);
return 0;
}

View File

@ -65,12 +65,12 @@ static struct VFile* _vd7zOpenFile(struct VDir* vd, const char* path, int mode);
static const char* _vde7zName(struct VDirEntry* vde);
struct VDir* VDirOpen7z(const char* path, int flags) {
struct VDir7z* vd = malloc(sizeof(struct VDir7z));
if (flags & O_WRONLY || flags & O_CREAT) {
return 0;
}
struct VDir7z* vd = malloc(sizeof(struct VDir7z));
// What does any of this mean, Igor?
if (InFile_Open(&vd->archiveStream.file, path)) {
free(vd);

View File

@ -57,5 +57,6 @@ while [ $# -gt 0 ]; do
sed -i~ "/^[^:]*: $/d" deb-temp/DEBIAN/control
rm deb-temp/DEBIAN/control~
dpkg-deb -b deb-temp $DEB
rm -rf deb-temp
shift
done