diff --git a/.appveyor.yml b/.appveyor.yml index 3067d854c..35d0e983e 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -7,7 +7,8 @@ configuration: cache: - C:\Tools\vcpkg install: -- git -C C:\Tools\vcpkg pull --quiet +- git -C C:\Tools\vcpkg clean -dfq ports toolsrc +- git -C C:\Tools\vcpkg pull --force --quiet - C:\Tools\vcpkg\bootstrap-vcpkg - vcpkg --triplet x64-windows --recurse install ffmpeg libepoxy libpng libzip sdl2 sqlite3 - vcpkg --no-dry-run upgrade diff --git a/CHANGES b/CHANGES index 8135c8931..0cd2d6513 100644 --- a/CHANGES +++ b/CHANGES @@ -40,11 +40,11 @@ Features: - Separate overrides for GBC games that can also run on SGB or regular GB - Mute option in homebrew ports - Status indicators for fast-forward and mute in homebrew ports - - Support for unlicensed Pokemon Jade/Diamond Game Boy mapper - - Support for unlicensed BBD Game Boy mapper - - Support for unlicensed Hitek Game Boy mapper + - Read-only support for MBC6 flash memory + - New unlicensed GB mappers: Pokémon Jade/Diamond, BBD, and Hitek - Stack tracing tools in ARM debugger (by ahigerd) - Command scripts for CLI debugger (by ahigerd) + - ARM disassembler now resolves addresses to symbol names Emulation fixes: - ARM: Fix ALU reading PC after shifting - ARM: Fix STR storing PC after address calculation @@ -67,6 +67,7 @@ Emulation fixes: - GBA DMA: Linger last DMA on bus (fixes mgba.io/i/301 and mgba.io/i/1320) - GBA DMA: Fix ordering and timing of overlapping DMAs - GBA Hardware: Fix GB Player detection on big endian platforms + - GBA I/O: Green swap register should be readable - GBA Memory: Improve gamepak prefetch timing - GBA Memory: Stall on VRAM access in mode 2 (fixes mgba.io/i/190) - GBA Memory: Improve robustness of Matrix memory support @@ -77,6 +78,8 @@ Emulation fixes: - GBA Video: Fix Hblank timing - GBA Video: Invalidate map cache when modifying BGCNT (fixes mgba.io/i/1846) - GBA Video: Don't draw sprites using unmapped VRAM in GL renderer (fixes mgba.io/i/1865) + - GBA Video: Implement green swap (fixes mgba.io/i/1609) + - GBA Video: Fix rare regression blending semitransparent sprites (fixes mgba.io/i/1876) - SM83: Emulate HALT bug Other fixes: - 3DS: Redo video sync to be more precise @@ -100,10 +103,14 @@ Other fixes: - mGUI: Fix closing down a game if an exit is signalled - mVL: Fix injecting accidentally draining non-injection buffer - SM83: Simplify register pair access on big endian + - SM83: Disassemble STOP as one byte - VFS: Fix directory node listing on some filesystems Misc: - 3DS: Use "wide mode" where applicable for slightly better filtering + - Core: Add savedataUpdated callback + - Core: Add shutdown callback - GB: Allow pausing event loop while CPU is blocked + - GB: Add support for sleep and shutdown callbacks - GBA: Allow pausing event loop while CPU is blocked - Debugger: Keep track of global cycle count - FFmpeg: Add looping option for GIF/APNG diff --git a/CMakeLists.txt b/CMakeLists.txt index a2e353a9c..bfebfff19 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -171,6 +171,10 @@ mark_as_advanced(BUILD_LTO BUILD_PGO PGO_STAGE_2 PGO_DIR) set(PGO_PRE_FLAGS "-fprofile-generate=${PGO_DIR} -fprofile-arcs") set(PGO_POST_FLAGS "-fprofile-use=${PGO_DIR} -fbranch-probabilities") +if(BUILD_PGO AND CMAKE_SYSTEM_NAME STREQUAL "Generic") + add_definitions(-DTARGET_POSIX_IO) +endif() + if(BUILD_PGO AND NOT PGO_STAGE_2) set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${PGO_PRE_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${PGO_PRE_FLAGS}") diff --git a/README.md b/README.md index 84356ece8..6506d56d5 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ The following mappers are fully supported: The following mappers are partially supported: -- MBC6 (missing flash memory support) +- MBC6 (missing flash memory write support) - MMM01 - Pocket Cam - TAMA5 (missing RTC support) @@ -146,10 +146,8 @@ This will produce a `build-win32` directory with the build products. Replace `mg - mgba/switch - mgba/ubuntu:xenial - mgba/ubuntu:bionic -- mgba/ubuntu:cosmic -- mgba/ubuntu:disco -- mgba/ubuntu:eoan - mgba/ubuntu:focal +- mgba/ubuntu:groovy - mgba/vita - mgba/wii - mgba/windows:w32 diff --git a/README_DE.md b/README_DE.md index 781aaa284..d1b3d5d84 100644 --- a/README_DE.md +++ b/README_DE.md @@ -57,7 +57,7 @@ Die folgenden Mapper werden vollständig unterstützt: Die folgenden Mapper werden teilweise unterstützt: -- MBC6 (fehlende Flash-Unterstützung) +- MBC6 (fehlende Unterstützung für Schreibzugriffe auf den Flash-Speicher) - MMM01 - Pocket Cam - TAMA5 (fehlende RTC-Unterstützung) @@ -128,10 +128,8 @@ Dieser Befehl erzeugt ein Verzeichnis `build-win32` mit den erzeugten Programmda - mgba/switch - mgba/ubuntu:xenial - mgba/ubuntu:bionic -- mgba/ubuntu:cosmic -- mgba/ubuntu:disco -- mgba/ubuntu:eoan - mgba/ubuntu:focal +- mgba/ubuntu:groovy - mgba/vita - mgba/wii - mgba/windows:w32 diff --git a/cinema/gba/blend/sma2-semitrans/baseline_0000.png b/cinema/gba/blend/sma2-semitrans/baseline_0000.png new file mode 100644 index 000000000..89538bf1e Binary files /dev/null and b/cinema/gba/blend/sma2-semitrans/baseline_0000.png differ diff --git a/cinema/gba/blend/sma2-semitrans/baseline_0001.png b/cinema/gba/blend/sma2-semitrans/baseline_0001.png new file mode 100644 index 000000000..89538bf1e Binary files /dev/null and b/cinema/gba/blend/sma2-semitrans/baseline_0001.png differ diff --git a/cinema/gba/blend/sma2-semitrans/baseline_0002.png b/cinema/gba/blend/sma2-semitrans/baseline_0002.png new file mode 100644 index 000000000..89538bf1e Binary files /dev/null and b/cinema/gba/blend/sma2-semitrans/baseline_0002.png differ diff --git a/cinema/gba/blend/sma2-semitrans/baseline_0003.png b/cinema/gba/blend/sma2-semitrans/baseline_0003.png new file mode 100644 index 000000000..2d6d7c61a Binary files /dev/null and b/cinema/gba/blend/sma2-semitrans/baseline_0003.png differ diff --git a/cinema/gba/blend/sma2-semitrans/baseline_0004.png b/cinema/gba/blend/sma2-semitrans/baseline_0004.png new file mode 100644 index 000000000..2d6d7c61a Binary files /dev/null and b/cinema/gba/blend/sma2-semitrans/baseline_0004.png differ diff --git a/cinema/gba/blend/sma2-semitrans/baseline_0005.png b/cinema/gba/blend/sma2-semitrans/baseline_0005.png new file mode 100644 index 000000000..2d6d7c61a Binary files /dev/null and b/cinema/gba/blend/sma2-semitrans/baseline_0005.png differ diff --git a/cinema/gba/blend/sma2-semitrans/test.mvl b/cinema/gba/blend/sma2-semitrans/test.mvl new file mode 100644 index 000000000..d094a6403 Binary files /dev/null and b/cinema/gba/blend/sma2-semitrans/test.mvl differ diff --git a/include/mgba-util/common.h b/include/mgba-util/common.h index dfd2a11ff..cdb7e025a 100644 --- a/include/mgba-util/common.h +++ b/include/mgba-util/common.h @@ -126,8 +126,20 @@ typedef intptr_t ssize_t; #endif #if defined __BIG_ENDIAN__ +#define LOAD_64BE(DEST, ADDR, ARR) DEST = *(uint64_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) #define LOAD_32BE(DEST, ADDR, ARR) DEST = *(uint32_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) -#if defined(__PPC__) || defined(__POWERPC__) +#define LOAD_16BE(DEST, ADDR, ARR) DEST = *(uint16_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) +#define STORE_64BE(SRC, ADDR, ARR) *(uint64_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = SRC +#define STORE_32BE(SRC, ADDR, ARR) *(uint32_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = SRC +#define STORE_16BE(SRC, ADDR, ARR) *(uint16_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = SRC +#if defined(__llvm__) || (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) +#define LOAD_64LE(DEST, ADDR, ARR) DEST = __builtin_bswap64(*(uint64_t*) ((uintptr_t) (ARR) + (size_t) (ADDR))) +#define LOAD_32LE(DEST, ADDR, ARR) DEST = __builtin_bswap32(*(uint32_t*) ((uintptr_t) (ARR) + (size_t) (ADDR))) +#define LOAD_16LE(DEST, ADDR, ARR) DEST = __builtin_bswap16(*(uint16_t*) ((uintptr_t) (ARR) + (size_t) (ADDR))) +#define STORE_64LE(SRC, ADDR, ARR) *(uint64_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = __builtin_bswap64(SRC) +#define STORE_32LE(SRC, ADDR, ARR) *(uint32_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = __builtin_bswap32(SRC) +#define STORE_16LE(SRC, ADDR, ARR) *(uint16_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = __builtin_bswap16(SRC) +#elif defined(__PPC__) || defined(__POWERPC__) #define LOAD_32LE(DEST, ADDR, ARR) { \ size_t _addr = (ADDR); \ const void* _ptr = (ARR); \ @@ -198,14 +210,6 @@ typedef intptr_t ssize_t; __asm__("stdbrx %0, %1, %2" : : "r"(SRC), "b"(_ptr), "r"(_addr) : "memory"); \ } #endif - -#elif defined(__llvm__) || (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) -#define LOAD_64LE(DEST, ADDR, ARR) DEST = __builtin_bswap64(((uint64_t*) ARR)[(ADDR) >> 3]) -#define LOAD_32LE(DEST, ADDR, ARR) DEST = __builtin_bswap32(((uint32_t*) ARR)[(ADDR) >> 2]) -#define LOAD_16LE(DEST, ADDR, ARR) DEST = __builtin_bswap16(((uint16_t*) ARR)[(ADDR) >> 1]) -#define STORE_64LE(SRC, ADDR, ARR) ((uint64_t*) ARR)[(ADDR) >> 3] = __builtin_bswap64(SRC) -#define STORE_32LE(SRC, ADDR, ARR) ((uint32_t*) ARR)[(ADDR) >> 2] = __builtin_bswap32(SRC) -#define STORE_16LE(SRC, ADDR, ARR) ((uint16_t*) ARR)[(ADDR) >> 1] = __builtin_bswap16(SRC) #else #error Big endian build not supported on this platform. #endif @@ -217,9 +221,19 @@ typedef intptr_t ssize_t; #define STORE_32LE(SRC, ADDR, ARR) *(uint32_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = SRC #define STORE_16LE(SRC, ADDR, ARR) *(uint16_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = SRC #ifdef _MSC_VER -#define LOAD_32BE(DEST, ADDR, ARR) DEST = _byteswap_ulong(((uint32_t*) ARR)[(ADDR) >> 2]) +#define LOAD_64BE(DEST, ADDR, ARR) DEST = _byteswap_uint64(*(uint64_t*) ((uintptr_t) (ARR) + (size_t) (ADDR))) +#define LOAD_32BE(DEST, ADDR, ARR) DEST = _byteswap_ulong(*(uint32_t*) ((uintptr_t) (ARR) + (size_t) (ADDR))) +#define LOAD_16BE(DEST, ADDR, ARR) DEST = _byteswap_ushort(*(uint16_t*) ((uintptr_t) (ARR) + (size_t) (ADDR))) +#define STORE_64BE(SRC, ADDR, ARR) *(uint64_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = _byteswap_uint64(SRC) +#define STORE_32BE(SRC, ADDR, ARR) *(uint32_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = _byteswap_ulong(SRC) +#define STORE_16BE(SRC, ADDR, ARR) *(uint16_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = _byteswap_ushort(SRC) #else -#define LOAD_32BE(DEST, ADDR, ARR) DEST = __builtin_bswap32(((uint32_t*) ARR)[(ADDR) >> 2]) +#define LOAD_64BE(DEST, ADDR, ARR) DEST = __builtin_bswap64(*(uint64_t*) ((uintptr_t) (ARR) + (size_t) (ADDR))) +#define LOAD_32BE(DEST, ADDR, ARR) DEST = __builtin_bswap32(*(uint32_t*) ((uintptr_t) (ARR) + (size_t) (ADDR))) +#define LOAD_16BE(DEST, ADDR, ARR) DEST = __builtin_bswap16(*(uint16_t*) ((uintptr_t) (ARR) + (size_t) (ADDR))) +#define STORE_64BE(SRC, ADDR, ARR) *(uint64_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = __builtin_bswap64(SRC) +#define STORE_32BE(SRC, ADDR, ARR) *(uint32_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = __builtin_bswap32(SRC) +#define STORE_16BE(SRC, ADDR, ARR) *(uint16_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = __builtin_bswap16(SRC) #endif #endif diff --git a/include/mgba/core/interface.h b/include/mgba/core/interface.h index b06d35497..0ca3cd7ce 100644 --- a/include/mgba/core/interface.h +++ b/include/mgba/core/interface.h @@ -36,6 +36,23 @@ typedef uint32_t color_t; #define M_RGB8_TO_BGR5(X) ((((X) & 0xF8) >> 3) | (((X) & 0xF800) >> 6) | (((X) & 0xF80000) >> 9)) #define M_RGB8_TO_RGB5(X) ((((X) & 0xF8) << 7) | (((X) & 0xF800) >> 6) | (((X) & 0xF80000) >> 19)) +#ifndef COLOR_16_BIT +#define M_COLOR_RED 0x000000FF +#define M_COLOR_GREEN 0x0000FF00 +#define M_COLOR_BLUE 0x00FF0000 +#define M_COLOR_ALPHA 0xFF000000 +#elif defined(COLOR_5_6_5) +#define M_COLOR_RED 0x001F +#define M_COLOR_GREEN 0x07E0 +#define M_COLOR_BLUE 0xF800 +#define M_COLOR_ALPHA 0x0000 +#else +#define M_COLOR_RED 0x001F +#define M_COLOR_GREEN 0x03E0 +#define M_COLOR_BLUE 0x7C00 +#define M_COLOR_ALPHA 0x1000 +#endif + #ifndef PYCPARSE static inline color_t mColorFrom555(uint16_t value) { #ifdef COLOR_16_BIT @@ -90,6 +107,7 @@ struct mCoreCallbacks { void (*videoFrameEnded)(void* context); void (*coreCrashed)(void* context); void (*sleep)(void* context); + void (*shutdown)(void* context); void (*keysRead)(void* context); void (*savedataUpdated)(void* context); }; diff --git a/include/mgba/internal/arm/decoder.h b/include/mgba/internal/arm/decoder.h index 6d21f5ae7..dea17fc1e 100644 --- a/include/mgba/internal/arm/decoder.h +++ b/include/mgba/internal/arm/decoder.h @@ -245,11 +245,12 @@ struct ARMInstructionInfo { struct ARMCoprocessor cp; }; +struct mDebuggerSymbols; void ARMDecodeARM(uint32_t opcode, struct ARMInstructionInfo* info); void ARMDecodeThumb(uint16_t opcode, struct ARMInstructionInfo* info); bool ARMDecodeThumbCombine(struct ARMInstructionInfo* info1, struct ARMInstructionInfo* info2, struct ARMInstructionInfo* out); -int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, int blen); +int ARMDisassemble(struct ARMInstructionInfo* info, struct ARMCore* core, const struct mDebuggerSymbols* symbols, uint32_t pc, char* buffer, int blen); uint32_t ARMResolveMemoryAccess(struct ARMInstructionInfo* info, struct ARMRegisterFile* regs, uint32_t pc); CXX_GUARD_END diff --git a/include/mgba/internal/gb/io.h b/include/mgba/internal/gb/io.h index 92917d70a..169199230 100644 --- a/include/mgba/internal/gb/io.h +++ b/include/mgba/internal/gb/io.h @@ -87,6 +87,7 @@ enum GBIORegisters { REG_KEY0 = 0x4C, REG_KEY1 = 0x4D, REG_VBK = 0x4F, + REG_BANK = 0x50, REG_HDMA1 = 0x51, REG_HDMA2 = 0x52, REG_HDMA3 = 0x53, diff --git a/include/mgba/internal/gb/memory.h b/include/mgba/internal/gb/memory.h index 676a8d5bb..d11260bac 100644 --- a/include/mgba/internal/gb/memory.h +++ b/include/mgba/internal/gb/memory.h @@ -61,6 +61,8 @@ enum { GB_SIZE_OAM = 0xA0, GB_SIZE_IO = 0x80, GB_SIZE_HRAM = 0x7F, + + GB_SIZE_MBC6_FLASH = 0x100000, }; enum { @@ -118,6 +120,8 @@ struct GBMBC6State { bool sramAccess; int currentSramBank1; uint8_t* sramBank1; + bool flashBank0; + bool flashBank1; }; struct GBMBC7State { diff --git a/include/mgba/internal/gba/renderers/video-software.h b/include/mgba/internal/gba/renderers/video-software.h index fb62baaea..acef5d312 100644 --- a/include/mgba/internal/gba/renderers/video-software.h +++ b/include/mgba/internal/gba/renderers/video-software.h @@ -129,6 +129,7 @@ struct GBAVideoSoftwareRenderer { uint16_t bldy; GBAMosaicControl mosaic; + bool greenswap; struct WindowN { struct GBAVideoWindowRegion h; diff --git a/src/arm/debugger/cli-debugger.c b/src/arm/debugger/cli-debugger.c index d5ee883be..df3e04c1c 100644 --- a/src/arm/debugger/cli-debugger.c +++ b/src/arm/debugger/cli-debugger.c @@ -98,28 +98,29 @@ static void _disassembleMode(struct CLIDebugger* debugger, struct CLIDebugVector static inline uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode) { struct CLIDebuggerBackend* be = debugger->backend; + struct mCore* core = debugger->d.core; char disassembly[64]; struct ARMInstructionInfo info; be->printf(be, "%08X: ", address); if (mode == MODE_ARM) { - uint32_t instruction = debugger->d.core->busRead32(debugger->d.core, address); + uint32_t instruction = core->busRead32(core, address); ARMDecodeARM(instruction, &info); - ARMDisassemble(&info, address + WORD_SIZE_ARM * 2, disassembly, sizeof(disassembly)); + ARMDisassemble(&info, core->cpu, core->symbolTable, address + WORD_SIZE_ARM * 2, disassembly, sizeof(disassembly)); be->printf(be, "%08X\t%s\n", instruction, disassembly); return WORD_SIZE_ARM; } else { struct ARMInstructionInfo info2; struct ARMInstructionInfo combined; - uint16_t instruction = debugger->d.core->busRead16(debugger->d.core, address); - uint16_t instruction2 = debugger->d.core->busRead16(debugger->d.core, address + WORD_SIZE_THUMB); + uint16_t instruction = core->busRead16(core, address); + uint16_t instruction2 = core->busRead16(core, address + WORD_SIZE_THUMB); ARMDecodeThumb(instruction, &info); ARMDecodeThumb(instruction2, &info2); if (ARMDecodeThumbCombine(&info, &info2, &combined)) { - ARMDisassemble(&combined, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly)); + ARMDisassemble(&combined, core->cpu, core->symbolTable, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly)); be->printf(be, "%04X %04X\t%s\n", instruction, instruction2, disassembly); return WORD_SIZE_THUMB * 2; } else { - ARMDisassemble(&info, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly)); + ARMDisassemble(&info, core->cpu, core->symbolTable, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly)); be->printf(be, "%04X \t%s\n", instruction, disassembly); return WORD_SIZE_THUMB; } diff --git a/src/arm/debugger/debugger.c b/src/arm/debugger/debugger.c index 4e49096ff..dec74a49a 100644 --- a/src/arm/debugger/debugger.c +++ b/src/arm/debugger/debugger.c @@ -466,6 +466,7 @@ static void ARMDebuggerListWatchpoints(struct mDebuggerPlatform* d, struct mWatc static void ARMDebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* length) { struct ARMDebugger* debugger = (struct ARMDebugger*) d; struct ARMCore* cpu = debugger->cpu; + struct mCore* core = d->p->core; char disassembly[64]; @@ -474,17 +475,17 @@ static void ARMDebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* len if (cpu->executionMode == MODE_ARM) { uint32_t instruction = cpu->prefetch[0]; sprintf(disassembly, "%08X: ", instruction); - ARMDisassemble(&info, cpu->gprs[ARM_PC], disassembly + strlen("00000000: "), sizeof(disassembly) - strlen("00000000: ")); + ARMDisassemble(&info, cpu, core->symbolTable, cpu->gprs[ARM_PC], disassembly + strlen("00000000: "), sizeof(disassembly) - strlen("00000000: ")); } else { uint16_t instruction = cpu->prefetch[0]; ARMDecodeThumb(instruction, &info); if (isWideInstruction) { uint16_t instruction2 = cpu->prefetch[1]; sprintf(disassembly, "%04X%04X: ", instruction, instruction2); - ARMDisassemble(&info, cpu->gprs[ARM_PC], disassembly + strlen("00000000: "), sizeof(disassembly) - strlen("00000000: ")); + ARMDisassemble(&info, cpu, core->symbolTable, cpu->gprs[ARM_PC], disassembly + strlen("00000000: "), sizeof(disassembly) - strlen("00000000: ")); } else { sprintf(disassembly, " %04X: ", instruction); - ARMDisassemble(&info, cpu->gprs[ARM_PC], disassembly + strlen("00000000: "), sizeof(disassembly) - strlen("00000000: ")); + ARMDisassemble(&info, cpu, core->symbolTable, cpu->gprs[ARM_PC], disassembly + strlen("00000000: "), sizeof(disassembly) - strlen("00000000: ")); } } diff --git a/src/arm/decoder.c b/src/arm/decoder.c index 30da5f76c..c4d675c7f 100644 --- a/src/arm/decoder.c +++ b/src/arm/decoder.c @@ -6,6 +6,7 @@ #include #include +#include #include #define ADVANCE(AMOUNT) \ @@ -20,8 +21,8 @@ static int _decodeRegister(int reg, char* buffer, int blen); static int _decodeRegisterList(int list, char* buffer, int blen); static int _decodePSR(int bits, char* buffer, int blen); -static int _decodePCRelative(uint32_t address, uint32_t pc, char* buffer, int blen); -static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, int blen); +static int _decodePCRelative(uint32_t address, const struct mDebuggerSymbols* symbols, uint32_t pc, bool thumbBranch, char* buffer, int blen); +static int _decodeMemory(struct ARMMemoryAccess memory, struct ARMCore* cpu, const struct mDebuggerSymbols* symbols, int pc, char* buffer, int blen); static int _decodeShift(union ARMOperand operand, bool reg, char* buffer, int blen); static const char* _armConditions[] = { @@ -141,23 +142,66 @@ static int _decodePSR(int psrBits, char* buffer, int blen) { return total; } -static int _decodePCRelative(uint32_t address, uint32_t pc, char* buffer, int blen) { - return snprintf(buffer, blen, "$%08X", address + pc); +static int _decodePCRelative(uint32_t address, const struct mDebuggerSymbols* symbols, uint32_t pc, bool thumbBranch, char* buffer, int blen) { + address += pc; + const char* label = NULL; + if (symbols) { + label = mDebuggerSymbolReverseLookup(symbols, address, -1); + if (!label && thumbBranch) { + label = mDebuggerSymbolReverseLookup(symbols, address | 1, -1); + } + } + if (label) { + return strlcpy(buffer, label, blen); + } else { + return snprintf(buffer, blen, "0x%08X", address); + } } -static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, int blen) { +static int _decodeMemory(struct ARMMemoryAccess memory, struct ARMCore* cpu, const struct mDebuggerSymbols* symbols, int pc, char* buffer, int blen) { if (blen <= 1) { return 0; } int total = 0; - strlcpy(buffer, "[", blen); - ADVANCE(1); + bool elideClose = false; int written; if (memory.format & ARM_MEMORY_REGISTER_BASE) { if (memory.baseReg == ARM_PC && memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) { - written = _decodePCRelative(memory.format & ARM_MEMORY_OFFSET_SUBTRACT ? -memory.offset.immediate : memory.offset.immediate, pc & 0xFFFFFFFC, buffer, blen); - ADVANCE(written); + uint32_t addrBase = memory.format & ARM_MEMORY_OFFSET_SUBTRACT ? -memory.offset.immediate : memory.offset.immediate; + if (!cpu) { + strlcpy(buffer, "[", blen); + ADVANCE(1); + written = _decodePCRelative(addrBase, symbols, pc & 0xFFFFFFFC, false, buffer, blen); + ADVANCE(written); + } else { + uint32_t value; + addrBase += pc & 0xFFFFFFFC; // Thumb does not have PC-relative LDRH/LDRB + switch (memory.width & 7) { + case 1: + value = cpu->memory.load8(cpu, addrBase, NULL); + break; + case 2: + value = cpu->memory.load16(cpu, addrBase, NULL); + break; + case 4: + value = cpu->memory.load32(cpu, addrBase, NULL); + break; + } + const char* label = NULL; + if (symbols) { + label = mDebuggerSymbolReverseLookup(symbols, value, -1); + } + if (label) { + written = snprintf(buffer, blen, "=%s", label); + } else { + written = snprintf(buffer, blen, "=0x%08X", value); + } + ADVANCE(written); + elideClose = true; + } } else { + strlcpy(buffer, "[", blen); + ADVANCE(1); written = _decodeRegister(memory.baseReg, buffer, blen); ADVANCE(written); if (memory.format & (ARM_MEMORY_REGISTER_OFFSET | ARM_MEMORY_IMMEDIATE_OFFSET) && !(memory.format & ARM_MEMORY_POST_INCREMENT)) { @@ -165,10 +209,14 @@ static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, in ADVANCE(2); } } + } else { + strlcpy(buffer, "[", blen); + ADVANCE(1); } if (memory.format & ARM_MEMORY_POST_INCREMENT) { strlcpy(buffer, "], ", blen); ADVANCE(3); + elideClose = true; } if (memory.format & ARM_MEMORY_IMMEDIATE_OFFSET && memory.baseReg != ARM_PC) { if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) { @@ -191,7 +239,7 @@ static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, in ADVANCE(written); } - if (!(memory.format & ARM_MEMORY_POST_INCREMENT)) { + if (!elideClose) { strlcpy(buffer, "]", blen); ADVANCE(1); } @@ -341,7 +389,7 @@ static const char* _armAccessTypeStrings[] = { "" }; -int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, int blen) { +int ARMDisassemble(struct ARMInstructionInfo* info, struct ARMCore* cpu, const struct mDebuggerSymbols* symbols, uint32_t pc, char* buffer, int blen) { const char* mnemonic = _armMnemonicStrings[info->mnemonic]; int written; int total = 0; @@ -414,7 +462,7 @@ int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, i case ARM_MN_BL: case ARM_MN_BLX: if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) { - written = _decodePCRelative(info->op1.immediate, pc, buffer, blen); + written = _decodePCRelative(info->op1.immediate, symbols, pc, true, buffer, blen); ADVANCE(written); } else if (info->operandFormat & ARM_OPERAND_REGISTER_1) { written = _decodeRegister(info->op1.reg, buffer, blen); @@ -434,7 +482,7 @@ int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, i written = snprintf(buffer, blen, "#%i", info->op1.immediate); ADVANCE(written); } else if (info->operandFormat & ARM_OPERAND_MEMORY_1) { - written = _decodeMemory(info->memory, pc, buffer, blen); + written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen); ADVANCE(written); } else if (info->operandFormat & ARM_OPERAND_REGISTER_1) { written = _decodeRegister(info->op1.reg, buffer, blen); @@ -461,7 +509,7 @@ int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, i written = snprintf(buffer, blen, "#%i", info->op2.immediate); ADVANCE(written); } else if (info->operandFormat & ARM_OPERAND_MEMORY_2) { - written = _decodeMemory(info->memory, pc, buffer, blen); + written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen); ADVANCE(written); } else if (info->operandFormat & ARM_OPERAND_REGISTER_2) { written = _decodeRegister(info->op2.reg, buffer, blen); @@ -485,7 +533,7 @@ int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, i written = snprintf(buffer, blen, "#%i", info->op3.immediate); ADVANCE(written); } else if (info->operandFormat & ARM_OPERAND_MEMORY_3) { - written = _decodeMemory(info->memory, pc, buffer, blen); + written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen); ADVANCE(written); } else if (info->operandFormat & ARM_OPERAND_REGISTER_3) { written = _decodeRegister(info->op3.reg, buffer, blen); @@ -509,7 +557,7 @@ int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, i written = snprintf(buffer, blen, "#%i", info->op4.immediate); ADVANCE(written); } else if (info->operandFormat & ARM_OPERAND_MEMORY_4) { - written = _decodeMemory(info->memory, pc, buffer, blen); + written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen); ADVANCE(written); } else if (info->operandFormat & ARM_OPERAND_REGISTER_4) { written = _decodeRegister(info->op4.reg, buffer, blen); diff --git a/src/core/thread.c b/src/core/thread.c index 218dc92cf..4fbe6e95c 100644 --- a/src/core/thread.c +++ b/src/core/thread.c @@ -139,6 +139,14 @@ void _coreSleep(void* context) { } } +void _coreShutdown(void* context) { + struct mCoreThread* thread = context; + if (!thread) { + return; + } + _changeState(thread->impl, THREAD_EXITING, true); +} + static THREAD_ENTRY _mCoreThreadRun(void* context) { struct mCoreThread* threadContext = context; #ifdef USE_PTHREADS @@ -162,6 +170,7 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) { .videoFrameEnded = _frameEnded, .coreCrashed = _crashed, .sleep = _coreSleep, + .shutdown = _coreShutdown, .context = threadContext }; core->addCoreCallbacks(core, &callbacks); diff --git a/src/debugger/gdb-stub.c b/src/debugger/gdb-stub.c index 3c0a77f37..518425b83 100644 --- a/src/debugger/gdb-stub.c +++ b/src/debugger/gdb-stub.c @@ -362,11 +362,7 @@ static void _writeRegister(struct GDBStub* stub, const char* message) { uint32_t value = _readHex(readAddress, &i); -#ifdef _MSC_VER - value = _byteswap_ulong(value); -#else LOAD_32BE(value, 0, &value); -#endif if (reg <= ARM_PC) { cpu->gprs[reg] = value; diff --git a/src/debugger/symbols.c b/src/debugger/symbols.c index 1cfa246a3..8b76bd5a0 100644 --- a/src/debugger/symbols.c +++ b/src/debugger/symbols.c @@ -97,6 +97,13 @@ void mDebuggerLoadARMIPSSymbols(struct mDebuggerSymbols* st, struct VFile* vf) { continue; } + char* buf2 = strchr(buf, ','); + + if (buf2 != NULL) { + // Commas separate names from function sizes + *buf2 = '\0'; + } + mDebuggerSymbolAdd(st, buf, address, -1); } } diff --git a/src/gb/gb.c b/src/gb/gb.c index fb407425e..bc7221957 100644 --- a/src/gb/gb.c +++ b/src/gb/gb.c @@ -783,29 +783,23 @@ void GBHalt(struct SM83Core* cpu) { void GBStop(struct SM83Core* cpu) { struct GB* gb = (struct GB*) cpu->master; - if (cpu->bus) { - mLOG(GB, GAME_ERROR, "Hit illegal stop at address %04X:%02X", cpu->pc, cpu->bus); - } - if (gb->memory.io[REG_KEY1] & 1) { + if (gb->model >= GB_MODEL_CGB && gb->memory.io[REG_KEY1] & 1) { gb->doubleSpeed ^= 1; gb->audio.timingFactor = gb->doubleSpeed + 1; gb->memory.io[REG_KEY1] = 0; gb->memory.io[REG_KEY1] |= gb->doubleSpeed << 7; - } else if (cpu->bus) { -#ifdef USE_DEBUGGERS - if (cpu->components && cpu->components[CPU_COMPONENT_DEBUGGER]) { - struct mDebuggerEntryInfo info = { - .address = cpu->pc - 1, - .type.bp.opcode = 0x1000 | cpu->bus, - }; - mDebuggerEnter((struct mDebugger*) cpu->components[CPU_COMPONENT_DEBUGGER], DEBUGGER_ENTER_ILLEGAL_OP, &info); + } else { + int sleep = ~(gb->memory.io[REG_JOYP] & 0x30); + size_t c; + for (c = 0; c < mCoreCallbacksListSize(&gb->coreCallbacks); ++c) { + struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gb->coreCallbacks, c); + if (sleep && callbacks->sleep) { + callbacks->sleep(callbacks->context); + } else if (callbacks->shutdown) { + callbacks->shutdown(callbacks->context); + } } -#endif - // Hang forever - gb->memory.ime = 0; - cpu->pc -= 2; } - // TODO: Actually stop } void GBIllegal(struct SM83Core* cpu) { diff --git a/src/gb/io.c b/src/gb/io.c index ea9eb7b2e..280ca1ddf 100644 --- a/src/gb/io.c +++ b/src/gb/io.c @@ -56,6 +56,7 @@ MGBA_EXPORT const char* const GBIORegisterNames[] = { [REG_KEY0] = "KEY0", [REG_KEY1] = "KEY1", [REG_VBK] = "VBK", + [REG_BANK] = "BANK", [REG_HDMA1] = "HDMA1", [REG_HDMA2] = "HDMA2", [REG_HDMA3] = "HDMA3", @@ -185,10 +186,10 @@ void GBIOReset(struct GB* gb) { GBIOWrite(gb, REG_NR51, 0xF3); if (!gb->biosVf) { GBIOWrite(gb, REG_LCDC, 0x91); - gb->memory.io[0x50] = 1; + gb->memory.io[REG_BANK] = 1; } else { GBIOWrite(gb, REG_LCDC, 0x00); - gb->memory.io[0x50] = 0xFF; + gb->memory.io[REG_BANK] = 0xFF; } GBIOWrite(gb, REG_SCY, 0x00); GBIOWrite(gb, REG_SCX, 0x00); @@ -459,8 +460,8 @@ void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) { GBVideoWriteSTAT(&gb->video, value); value = gb->video.stat; break; - case 0x50: - if (gb->memory.io[0x50] != 0xFF) { + case REG_BANK: + if (gb->memory.io[REG_BANK] != 0xFF) { break; } GBUnmapBIOS(gb); diff --git a/src/gb/mbc.c b/src/gb/mbc.c index 310c8bb95..cdbbbef44 100644 --- a/src/gb/mbc.c +++ b/src/gb/mbc.c @@ -53,6 +53,8 @@ static uint8_t _GBHitekRead(struct GBMemory*, uint16_t address); static uint8_t _GBPocketCamRead(struct GBMemory*, uint16_t address); static void _GBPocketCamCapture(struct GBMemory*); +static void _GBMBC6MapChip(struct GB*, int half, uint8_t value); + void GBMBCSwitchBank(struct GB* gb, int bank) { size_t bankStart = bank * GB_SIZE_CART_BANK0; if (bankStart + GB_SIZE_CART_BANK0 > gb->memory.romSize) { @@ -81,19 +83,37 @@ void GBMBCSwitchBank0(struct GB* gb, int bank) { void GBMBCSwitchHalfBank(struct GB* gb, int half, int bank) { size_t bankStart = bank * GB_SIZE_CART_HALFBANK; - if (bankStart + GB_SIZE_CART_HALFBANK > gb->memory.romSize) { - mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid ROM bank: %0X", bank); - bankStart &= (gb->memory.romSize - 1); - bank = bankStart / GB_SIZE_CART_HALFBANK; - if (!bank) { - ++bank; + bool isFlash = half ? gb->memory.mbcState.mbc6.flashBank1 : gb->memory.mbcState.mbc6.flashBank0; + if (isFlash) { + if (bankStart + GB_SIZE_CART_HALFBANK > GB_SIZE_MBC6_FLASH) { + mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid Flash bank: %0X", bank); + bankStart &= GB_SIZE_MBC6_FLASH - 1; + bank = bankStart / GB_SIZE_CART_HALFBANK; + } + bankStart += gb->sramSize - GB_SIZE_MBC6_FLASH; + } else { + if (bankStart + GB_SIZE_CART_HALFBANK > gb->memory.romSize) { + mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid ROM bank: %0X", bank); + bankStart &= gb->memory.romSize - 1; + bank = bankStart / GB_SIZE_CART_HALFBANK; + if (!bank) { + ++bank; + } } } if (!half) { - gb->memory.romBank = &gb->memory.rom[bankStart]; + if (isFlash) { + gb->memory.romBank = &gb->memory.sram[bankStart]; + } else { + gb->memory.romBank = &gb->memory.rom[bankStart]; + } gb->memory.currentBank = bank; } else { - gb->memory.mbcState.mbc6.romBank1 = &gb->memory.rom[bankStart]; + if (isFlash) { + gb->memory.mbcState.mbc6.romBank1 = &gb->memory.sram[bankStart]; + } else { + gb->memory.mbcState.mbc6.romBank1 = &gb->memory.rom[bankStart]; + } gb->memory.mbcState.mbc6.currentBank1 = bank; } if (gb->cpu->pc < GB_BASE_VRAM) { @@ -187,9 +207,10 @@ void GBMBCSwitchSramBank(struct GB* gb, int bank) { void GBMBCSwitchSramHalfBank(struct GB* gb, int half, int bank) { size_t bankStart = bank * GB_SIZE_EXTERNAL_RAM_HALFBANK; - if (bankStart + GB_SIZE_EXTERNAL_RAM_HALFBANK > gb->sramSize) { + size_t sramSize = gb->sramSize - GB_SIZE_MBC6_FLASH; + if (bankStart + GB_SIZE_EXTERNAL_RAM_HALFBANK > sramSize) { mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid RAM bank: %0X", bank); - bankStart &= (gb->sramSize - 1); + bankStart &= (sramSize - 1); bank = bankStart / GB_SIZE_EXTERNAL_RAM_HALFBANK; } if (!half) { @@ -334,6 +355,7 @@ void GBMBCInit(struct GB* gb) { gb->memory.mbcWrite = _GBMBC6; gb->memory.mbcRead = _GBMBC6Read; gb->memory.directSramAccess = false; + gb->sramSize += GB_SIZE_MBC6_FLASH; // Flash is concatenated at the end break; case GB_MBC7: gb->memory.mbcWrite = _GBMBC7; @@ -689,14 +711,28 @@ void _GBMBC6(struct GB* gb, uint16_t address, uint8_t value) { case 0x2: GBMBCSwitchSramHalfBank(gb, 1, bank); break; + case 0x3: + mLOG(GB_MBC, STUB, "MBC6 unimplemented flash OE write: %04X:%02X", address, value); + break; + case 0x4: + mLOG(GB_MBC, STUB, "MBC6 unimplemented flash WE write: %04X:%02X", address, value); + break; case 0x8: case 0x9: GBMBCSwitchHalfBank(gb, 0, bank); break; + case 0xA: + case 0xB: + _GBMBC6MapChip(gb, 0, value); + break; case 0xC: case 0xD: GBMBCSwitchHalfBank(gb, 1, bank); break; + case 0xE: + case 0xF: + _GBMBC6MapChip(gb, 1, value); + break; case 0x28: case 0x29: case 0x2A: @@ -732,6 +768,16 @@ uint8_t _GBMBC6Read(struct GBMemory* memory, uint16_t address) { return 0xFF; } +static void _GBMBC6MapChip(struct GB* gb, int half, uint8_t value) { + if (!half) { + gb->memory.mbcState.mbc6.flashBank0 = !!(value & 0x08); + GBMBCSwitchHalfBank(gb, half, gb->memory.currentBank); + } else { + gb->memory.mbcState.mbc6.flashBank1 = !!(value & 0x08); + GBMBCSwitchHalfBank(gb, half, gb->memory.mbcState.mbc6.currentBank1); + } +} + void _GBMBC7(struct GB* gb, uint16_t address, uint8_t value) { int bank = value & 0x7F; switch (address >> 13) { diff --git a/src/gb/serialize.c b/src/gb/serialize.c index e6b053b9b..002b5a650 100644 --- a/src/gb/serialize.c +++ b/src/gb/serialize.c @@ -139,7 +139,7 @@ bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) { mLOG(GB_STATE, WARN, "Savestate is corrupted: OCPS is out of range"); } bool differentBios = !gb->biosVf || gb->model != state->model; - if (state->io[0x50] == 0xFF) { + if (state->io[REG_BANK] == 0xFF) { if (differentBios) { mLOG(GB_STATE, WARN, "Incompatible savestate, please restart with correct BIOS in %s mode", GBModelToName(state->model)); error = true; @@ -206,7 +206,7 @@ bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) { GBTimerDeserialize(&gb->timer, state); GBAudioDeserialize(&gb->audio, state); - if (gb->memory.io[0x50] == 0xFF) { + if (gb->memory.io[REG_BANK] == 0xFF) { GBMapBIOS(gb); } else { GBUnmapBIOS(gb); diff --git a/src/gba/gba.c b/src/gba/gba.c index 50ff7086f..dd2e0bd25 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -524,11 +524,15 @@ void GBAHalt(struct GBA* gba) { } void GBAStop(struct GBA* gba) { + int validIrqs = (1 << IRQ_GAMEPAK) | (1 << IRQ_KEYPAD) | (1 << IRQ_SIO); + int sleep = gba->memory.io[REG_IE >> 1] & validIrqs; size_t c; for (c = 0; c < mCoreCallbacksListSize(&gba->coreCallbacks); ++c) { struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gba->coreCallbacks, c); - if (callbacks->sleep) { + if (sleep && callbacks->sleep) { callbacks->sleep(callbacks->context); + } else if (callbacks->shutdown) { + callbacks->shutdown(callbacks->context); } } gba->cpu->nextEvent = gba->cpu->cycles; diff --git a/src/gba/io.c b/src/gba/io.c index 8e22ed9d3..881c01ea0 100644 --- a/src/gba/io.c +++ b/src/gba/io.c @@ -341,7 +341,7 @@ void GBAIOInit(struct GBA* gba) { } void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { - if (address < REG_SOUND1CNT_LO && (address > REG_VCOUNT || address == REG_DISPCNT)) { + if (address < REG_SOUND1CNT_LO && (address > REG_VCOUNT || address < REG_DISPSTAT)) { value = gba->video.renderer->writeVideoRegister(gba->video.renderer, address, value); } else { switch (address) { @@ -850,6 +850,7 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) { } // Fall through case REG_DISPCNT: + case REG_GREENSWP: case REG_DISPSTAT: case REG_VCOUNT: case REG_BG0CNT: diff --git a/src/gba/memory.c b/src/gba/memory.c index 6c118524d..722dd1441 100644 --- a/src/gba/memory.c +++ b/src/gba/memory.c @@ -484,7 +484,7 @@ uint32_t GBALoad32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { if (cycleCounter) { wait += 2; - if (address >> BASE_OFFSET < REGION_CART0) { + if (address < BASE_CART0) { wait = GBAMemoryStall(cpu, wait); } *cycleCounter += wait; @@ -603,7 +603,7 @@ uint32_t GBALoad16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { if (cycleCounter) { wait += 2; - if (address >> BASE_OFFSET < REGION_CART0) { + if (address < BASE_CART0) { wait = GBAMemoryStall(cpu, wait); } *cycleCounter += wait; @@ -714,7 +714,7 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { if (cycleCounter) { wait += 2; - if (address >> BASE_OFFSET < REGION_CART0) { + if (address < BASE_CART0) { wait = GBAMemoryStall(cpu, wait); } *cycleCounter += wait; @@ -840,7 +840,7 @@ void GBAStore32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycle if (cycleCounter) { ++wait; - if (address >> BASE_OFFSET < REGION_CART0) { + if (address < BASE_CART0) { wait = GBAMemoryStall(cpu, wait); } *cycleCounter += wait; @@ -956,7 +956,7 @@ void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle if (cycleCounter) { ++wait; - if (address >> BASE_OFFSET < REGION_CART0) { + if (address < BASE_CART0) { wait = GBAMemoryStall(cpu, wait); } *cycleCounter += wait; @@ -1039,7 +1039,7 @@ void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCo if (cycleCounter) { ++wait; - if (address >> BASE_OFFSET < REGION_CART0) { + if (address < BASE_CART0) { wait = GBAMemoryStall(cpu, wait); } *cycleCounter += wait; @@ -1454,7 +1454,7 @@ uint32_t GBALoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum L if (cycleCounter) { ++wait; - if (address >> BASE_OFFSET < REGION_CART0) { + if (address < BASE_CART0) { wait = GBAMemoryStall(cpu, wait); } *cycleCounter += wait; @@ -1572,7 +1572,7 @@ uint32_t GBAStoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum } if (cycleCounter) { - if (address >> BASE_OFFSET < REGION_CART0) { + if (address < BASE_CART0) { wait = GBAMemoryStall(cpu, wait); } *cycleCounter += wait; diff --git a/src/gba/renderers/software-obj.c b/src/gba/renderers/software-obj.c index 33e89df32..47035b2d4 100644 --- a/src/gba/renderers/software-obj.c +++ b/src/gba/renderers/software-obj.c @@ -251,7 +251,7 @@ int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* re } int objwinSlowPath = GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt) && GBAWindowControlGetBlendEnable(renderer->objwin.packed) != GBAWindowControlIsBlendEnable(renderer->currentWindow.packed); - int variant = (renderer->target1Obj || GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT) && + int variant = renderer->target1Obj && GBAWindowControlIsBlendEnable(renderer->currentWindow.packed) && (renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN); if (GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT || (renderer->target1Obj && renderer->blendEffect == BLEND_ALPHA) || objwinSlowPath) { diff --git a/src/gba/renderers/video-software.c b/src/gba/renderers/video-software.c index 0593bc19c..083b3d230 100644 --- a/src/gba/renderers/video-software.c +++ b/src/gba/renderers/video-software.c @@ -130,6 +130,7 @@ static void GBAVideoSoftwareRendererReset(struct GBAVideoRenderer* renderer) { softwareRenderer->oamMax = 0; softwareRenderer->mosaic = 0; + softwareRenderer->greenswap = false; softwareRenderer->nextY = 0; softwareRenderer->objOffsetX = 0; @@ -189,6 +190,9 @@ static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRender softwareRenderer->dispcnt = value; GBAVideoSoftwareRendererUpdateDISPCNT(softwareRenderer); break; + case REG_GREENSWP: + softwareRenderer->greenswap = value & 1; + break; case REG_BG0CNT: value &= 0xDFFF; GBAVideoSoftwareRendererWriteBGCNT(softwareRenderer, &softwareRenderer->bg[0], value); @@ -406,9 +410,6 @@ static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRender case REG_MOSAIC: softwareRenderer->mosaic = value; break; - case REG_GREENSWP: - mLOG(GBA_VIDEO, STUB, "Stub video register write: 0x%03X", address); - break; default: mLOG(GBA_VIDEO, GAME_ERROR, "Invalid video register: 0x%03X", address); } @@ -530,7 +531,7 @@ static void _breakWindowInner(struct GBAVideoSoftwareRenderer* softwareRenderer, static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer; - if (y == GBA_VIDEO_VERTICAL_PIXELS - 1) { + if (y == softwareRenderer->masterHeight - 1) { softwareRenderer->nextY = 0; } else { softwareRenderer->nextY = y + 1; @@ -711,17 +712,31 @@ static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* render GBAVideoSoftwareRendererPostprocessBuffer(softwareRenderer); + int x; + if (softwareRenderer->greenswap) { + for (x = 0; x < softwareRenderer->masterEnd; x += 4) { + row[x] = softwareRenderer->row[x] & (M_COLOR_RED | M_COLOR_BLUE); + row[x] |= softwareRenderer->row[x + 1] & M_COLOR_GREEN; + row[x + 1] = softwareRenderer->row[x + 1] & (M_COLOR_RED | M_COLOR_BLUE); + row[x + 1] |= softwareRenderer->row[x] & M_COLOR_GREEN; + row[x + 2] = softwareRenderer->row[x + 2] & (M_COLOR_RED | M_COLOR_BLUE); + row[x + 2] |= softwareRenderer->row[x + 3] & M_COLOR_GREEN; + row[x + 3] = softwareRenderer->row[x + 3] & (M_COLOR_RED | M_COLOR_BLUE); + row[x + 3] |= softwareRenderer->row[x + 2] & M_COLOR_GREEN; + + } + } else { #ifdef COLOR_16_BIT - size_t x; - for (x = 0; x < softwareRenderer->masterEnd; ++x) { - row[x] = softwareRenderer->row[x]; - row[x + 1] = softwareRenderer->row[x + 1]; - row[x + 2] = softwareRenderer->row[x + 2]; - row[x + 3] = softwareRenderer->row[x + 3]; - } + for (x = 0; x < softwareRenderer->masterEnd; x += 4) { + row[x] = softwareRenderer->row[x]; + row[x + 1] = softwareRenderer->row[x + 1]; + row[x + 2] = softwareRenderer->row[x + 2]; + row[x + 3] = softwareRenderer->row[x + 3]; + } #else - memcpy(row, softwareRenderer->row, softwareRenderer->masterEnd * sizeof(*row)); + memcpy(row, softwareRenderer->row, softwareRenderer->masterEnd * sizeof(*row)); #endif + } } static void GBAVideoSoftwareRendererFinishFrame(struct GBAVideoRenderer* renderer) { @@ -973,7 +988,7 @@ int GBAVideoSoftwareRendererPreprocessSpriteLayer(struct GBAVideoSoftwareRendere } if (GBAObjAttributesAIsMosaic(sprite->obj.a) && mosaicV > 1) { localY = mosaicY; - if (localY < sprite->y && sprite->y < GBA_VIDEO_VERTICAL_PIXELS) { + if (localY < sprite->y && sprite->y < renderer->masterHeight) { localY = sprite->y; } if (localY >= (sprite->endY & 0xFF)) { diff --git a/src/platform/qt/ts/mgba-fr.ts b/src/platform/qt/ts/mgba-fr.ts index cb91feeb9..fd510dd55 100644 --- a/src/platform/qt/ts/mgba-fr.ts +++ b/src/platform/qt/ts/mgba-fr.ts @@ -135,32 +135,32 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Chip name - + Nom de la puce Insert - + Insérer Save - Sauvegarder + Sauvegarder Load - Charger + Charger Add - Ajouter + Ajouter Remove - Supprimer + Supprimer @@ -185,22 +185,22 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Inserted - + Inséré Chip ID - + ID de la puce Update Chip data - + Mettre à jour les données de la puce Show advanced - Paramètres avancés + Paramètres avancés @@ -239,7 +239,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Enter codes here... - + Entrez les codes ici… @@ -265,42 +265,42 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Inspect frame - + Inspecter l'image × - × + × Magnification - Agrandissement + Agrandissement Freeze frame - + Figer l'image Backdrop color - + Couleur de fond Disable scanline effects - + Désactiver les effets de lignes de balayage Export - Exporter + Exporter Reset - Réinitialiser + Réinitialiser @@ -308,12 +308,12 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Record GIF/APNG - + Enregistrer GIF/APNG Loop - + Boucle @@ -333,17 +333,17 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. APNG - + APNG GIF - + GIF WebP - + WebP @@ -506,7 +506,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Cancel - + Annuler @@ -627,7 +627,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Copy - + Copier @@ -635,33 +635,33 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Save Memory Range - + Sauvegarder la plage de mémoire Start Address: - + Adresse de départ : : - : + : 0x - 0x + 0x Byte Count: - + Nombre d'octets : Dump across banks - + Dump across banks @@ -746,57 +746,57 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Search type - + Type de recherche Equal to value - + Égale à la valeur Greater than value - + Supérieur à la valeur Less than value - + Inférieur à la valeur Unknown/changed - + Inconnu/changé Changed by value - + Modifié par la valeur Unchanged - + Inchangé Increased - + Augmentation Decreased - + Diminution Search ROM - + Recherche dans la ROM New Search - + Nouvelle recherche @@ -829,7 +829,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. : - : + : @@ -844,17 +844,17 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. &1 Byte - + &1 Octet &2 Bytes - + &2 Octets &4 Bytes - + &4 Octets @@ -894,7 +894,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Save Range - + Sauvegarder la plage @@ -956,24 +956,24 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Copy - + Copier +0.00 - + +0.00 +1.00 - + +1.00 Matrix - + Matrice @@ -1224,7 +1224,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. MBC6 - MBC6 + MBC6 @@ -1234,7 +1234,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. MMM01 - + MMM01 @@ -1249,7 +1249,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. HuC-1 - HuC-1 + HuC-1 @@ -1259,12 +1259,12 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Wisdom Tree (Unlicensed) - + Wisdom Tree (sans licence) Pokémon Jade/Diamond (Unlicensed) - + Pokémon Jade/Diamond (sans licence) @@ -1354,7 +1354,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. 0x000 (000) - 0x000 (000) {0x?} + 0x000 (000) @@ -1410,17 +1410,17 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Tear off - Tear off + Déchirer (Tear off) × - × + × Magnification - Agrandissement + Agrandissement @@ -1514,12 +1514,12 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Could not load game. Are you sure it's in the correct format? - Impossible de charger le jeu. Êtes-vous sûr qu'il est dans le bon format ? + Impossible de charger le jeu. Êtes-vous sûr qu'il est dans le bon format ? Failed to open save file. Is the save directory writable? - + Impossible d'ouvrir le fichier de sauvegarde. Le répertoire de sauvegarde est-il accessible en écriture ? @@ -1527,42 +1527,42 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Export frame - + Exporter l'image Portable Network Graphics (*.png) - Portable Network Graphics (*.png) + Portable Network Graphics (*.png) None - Aucun + Aucun Background - Arrière plan + Arrière plan Window - + Fenêtre Sprite - + Sprite Backdrop - + Toile de fond %1 %2 - %1x {1 %2?} + %1 %2 @@ -1570,7 +1570,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Enable Discord Rich Presence - + Activer intégration avec Discord @@ -1644,7 +1644,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Failed to open output file: %1 - Impossible d'ouvrir le fichier de sortie : %1 + Impossible d'ouvrir le fichier de sortie : %1 @@ -1654,7 +1654,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Graphics Interchange Format (*.gif);;Animated Portable Network Graphics (*.png *.webp *.apng) - + Graphics Interchange Format (*.gif);;Animated Portable Network Graphics (*.png *.webp *.apng) @@ -1667,17 +1667,17 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Mode 0: 4 tile layers - Mode 0: 4 tile layers + Mode 0: 4 tile layers Mode 1: 2 tile layers + 1 rotated/scaled tile layer - Mode 1: 2 tile layers + 1 rotated/scaled tile layer + Mode 1: 2 tile layers + 1 rotated/scaled tile layer Mode 2: 2 rotated/scaled tile layers - Mode 2: 2 rotated/scaled tile layers + Mode 2: 2 rotated/scaled tile layers @@ -2384,12 +2384,12 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Loud channel A - Canal fort A + Canal fort A Loud channel B - Canal fort B + Canal fort B @@ -3047,17 +3047,17 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Super (L) - + Super (L) Super (R) - + Super (R) Menu - + Menu @@ -3094,42 +3094,42 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Default - + Défaut Fatal - Fatal + Fatal Error - Erreur + Erreur Warning - Avertissement + Avertissement Info - Info + Info Debug - Débogage + Débogage Stub - Stub + Stub Game Error - Erreur du jeu + Erreur du jeu @@ -3137,12 +3137,12 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. [%1] %2: %3 - + [%1] %2: %3 An error occurred - + Une erreur est survenue @@ -3192,35 +3192,35 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Priority - Priorité + Priorité Map base - + Fond de carte Tile base - + Fond de tuile Size - Taille + Taille Offset - Offset + Compensation Xform - + Xform @@ -3257,7 +3257,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. N/A - N/A + N/A @@ -3275,12 +3275,12 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Save memory region - + Sauvegarder la région de la mémoire Failed to open output file: %1 - Impossible d'ouvrir le fichier de sortie : %1 + Impossible d'ouvrir le fichier de sortie : %1 @@ -3392,7 +3392,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. --- - --- + --- @@ -3402,7 +3402,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Trans - Trans + Trans @@ -3552,7 +3552,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. (%1×%2) - + (%1×%2) @@ -3593,17 +3593,17 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Action - Action + Action Keyboard - Clavier + Clavier Gamepad - Manette de jeu + Manette de jeu @@ -3611,18 +3611,18 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Export tiles - + Exporter les tuiles Portable Network Graphics (*.png) - Portable Network Graphics (*.png) + Portable Network Graphics (*.png) Export tile - + Exporter une tuile @@ -3697,13 +3697,13 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. mGBA savestate files (%1) - + mGBA fichiers d'état (%1) Select savestate - + Sélectionner un fichier d'état @@ -3718,12 +3718,12 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Select e-Reader dotcode - + Sélectionnez le numéro de point du e-Reader e-Reader card (*.raw *.bin *.bmp) - + e-Reader carte (*.raw *.bin *.bmp) @@ -3954,7 +3954,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Yank game pak - Extraire game pak + Yank game pak @@ -3984,7 +3984,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Unbounded - Non lié + Sans limites @@ -4034,7 +4034,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Brightest solar level - Tester le niveau solaire + Tester le niveau solaire @@ -4134,47 +4134,47 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Game &overrides... - Passer &outre le jeu… + Couldn't Start - + N'a pas pu démarrer Could not start game. - + Impossible de démarrer le jeu. Scan e-Reader dotcodes... - + Scanner les dotcodes e-Reader... Load state file... - + Charger le fichier d'état... Save state file... - + Enregistrer le fichier d'état... Import GameShark Save... - + Importer la sauvegarde de GameShark... Export GameShark Save... - + Exporter la sauvegarde de GameShark... About... - + À propos de... @@ -4184,32 +4184,32 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. %1× - %1x {1×?} + %1× Interframe blending - + Mélange d'images Native (59.7275) - Natif (59.7) {59.7275)?} + Natif (59.7275) Record A/V... - + Enregistrer A/V... Record GIF/WebP/APNG... - + Enregistrer GIF/WebP/APNG... Game Pak sensors... - + Capteurs de la Game Pak... @@ -4254,7 +4254,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. &Frame inspector... - + Inspecteur de &frame... @@ -4274,12 +4274,12 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Record debug video log... - + Enregistrer le journal vidéo de débogage... Stop debug video log - + Arrêtez le journal vidéo de débogage @@ -4349,7 +4349,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Clear - Vider + Vider @@ -4375,22 +4375,22 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Shift - + Shift Control - + Control Alt - + Alt Meta - + Méta/Super @@ -4552,7 +4552,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Enhancements - + Améliorations @@ -4567,7 +4567,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Logging - + Journalisation @@ -4670,7 +4670,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Fast forward volume: - + Volume en avance rapide : @@ -4731,42 +4731,42 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Log to file - + Journalisation vers le fichier Log to console - + Journalisation vers la console Select Log File - + Sélectionner le fichier de journalisation Game Boy model: - + Modèle de Game Boy : Super Game Boy model: - + Modèle de Super Game Boy : Game Boy Color model: - + Modèle de Game Boy Color : Use GBC colors in GB games - + Utiliser les couleurs GBC dans les jeux en GB Camera: - + Caméra : @@ -4846,22 +4846,22 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Native (59.7275) - Natif (59.7) {59.7275)?} + Natif (59.7275) Interframe blending - + Mélange d'images Pause when minimized - + Pause lorsqu'elle est minimisée Enable Discord Rich Presence - + Activer l'intégration avec Discord @@ -4871,12 +4871,12 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Show OSD messages - + Afficher les messages OSD Show filename instead of ROM name in title bar - + Afficher le nom du fichier au lieu du nom de la ROM dans la barre de titre @@ -4899,7 +4899,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Fast forward (held) speed: - + Vitesse d'avance rapide (maintenue) : @@ -4972,37 +4972,37 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Video renderer: - + Rendu vidéo : Software - + Logiciel(s) OpenGL - OpenGL + OpenGL OpenGL enhancements - + Améliorations OpenGL High-resolution scale: - + Échelle haute résolution : (240×160) - + (240×160) XQ GBA audio (experimental) - + XQ GBA audio (expérimental) @@ -5213,12 +5213,12 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Export Selected - + Exportation sélectionnée Export All - + Exporter tous @@ -5238,22 +5238,22 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. Tiles per row - + Tuiles par rangée Fit to window - + Adaptation à la fenêtre Copy Selected - + Copier la sélection Copy All - + Copier tout @@ -5313,42 +5313,42 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. High &Quality - + Haute &Qualité &YouTube - + &YouTube &Lossless - + &Lossless 4K - 480p {4K?} + 4K &1080p - + &1080p &720p - + &720p &480p - + &480p &Native - + &Natif @@ -5368,7 +5368,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. HEVC (NVENC) - + HEVC (NVENC) @@ -5378,7 +5378,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. VP9 - VP9 + VP9 @@ -5389,7 +5389,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. None - Aucun + Aucun diff --git a/src/platform/test/CMakeLists.txt b/src/platform/test/CMakeLists.txt index c81b339f8..2517e83bf 100644 --- a/src/platform/test/CMakeLists.txt +++ b/src/platform/test/CMakeLists.txt @@ -44,4 +44,5 @@ if(BUILD_CINEMA) target_link_libraries(${BINARY_NAME}-cinema ${BINARY_NAME} ${PLATFORM_LIBRARY}) set_target_properties(${BINARY_NAME}-cinema PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}") add_test(cinema ${BINARY_NAME}-cinema -v) + install(TARGETS ${BINARY_NAME}-cinema DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${BINARY_NAME}-test) endif() diff --git a/src/sm83/decoder.c b/src/sm83/decoder.c index 7ad565d68..1240d5841 100644 --- a/src/sm83/decoder.c +++ b/src/sm83/decoder.c @@ -365,7 +365,7 @@ DEFINE_DECODER_SM83(DI, info->mnemonic = SM83_MN_DI) DEFINE_DECODER_SM83(EI, info->mnemonic = SM83_MN_EI) DEFINE_DECODER_SM83(HALT, info->mnemonic = SM83_MN_HALT) DEFINE_DECODER_SM83(ILL, info->mnemonic = SM83_MN_ILL) -DEFINE_DECODER_SM83(STOP, info->mnemonic = SM83_MN_STOP; return 1) +DEFINE_DECODER_SM83(STOP, info->mnemonic = SM83_MN_STOP) #define DEFINE_RST_DECODER_SM83(VEC) \ DEFINE_DECODER_SM83(RST ## VEC, info->op1.immediate = 0x ## VEC;)