mirror of https://github.com/mgba-emu/mgba.git
Merge branch 'master' (early part) into medusa
This commit is contained in:
commit
03146379bd
|
@ -7,7 +7,8 @@ configuration:
|
||||||
cache:
|
cache:
|
||||||
- C:\Tools\vcpkg
|
- C:\Tools\vcpkg
|
||||||
install:
|
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
|
- C:\Tools\vcpkg\bootstrap-vcpkg
|
||||||
- vcpkg --triplet x64-windows --recurse install ffmpeg libepoxy libpng libzip sdl2 sqlite3
|
- vcpkg --triplet x64-windows --recurse install ffmpeg libepoxy libpng libzip sdl2 sqlite3
|
||||||
- vcpkg --no-dry-run upgrade
|
- vcpkg --no-dry-run upgrade
|
||||||
|
|
13
CHANGES
13
CHANGES
|
@ -40,11 +40,11 @@ Features:
|
||||||
- Separate overrides for GBC games that can also run on SGB or regular GB
|
- Separate overrides for GBC games that can also run on SGB or regular GB
|
||||||
- Mute option in homebrew ports
|
- Mute option in homebrew ports
|
||||||
- Status indicators for fast-forward and mute in homebrew ports
|
- Status indicators for fast-forward and mute in homebrew ports
|
||||||
- Support for unlicensed Pokemon Jade/Diamond Game Boy mapper
|
- Read-only support for MBC6 flash memory
|
||||||
- Support for unlicensed BBD Game Boy mapper
|
- New unlicensed GB mappers: Pokémon Jade/Diamond, BBD, and Hitek
|
||||||
- Support for unlicensed Hitek Game Boy mapper
|
|
||||||
- Stack tracing tools in ARM debugger (by ahigerd)
|
- Stack tracing tools in ARM debugger (by ahigerd)
|
||||||
- Command scripts for CLI debugger (by ahigerd)
|
- Command scripts for CLI debugger (by ahigerd)
|
||||||
|
- ARM disassembler now resolves addresses to symbol names
|
||||||
Emulation fixes:
|
Emulation fixes:
|
||||||
- ARM: Fix ALU reading PC after shifting
|
- ARM: Fix ALU reading PC after shifting
|
||||||
- ARM: Fix STR storing PC after address calculation
|
- 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: 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 DMA: Fix ordering and timing of overlapping DMAs
|
||||||
- GBA Hardware: Fix GB Player detection on big endian platforms
|
- 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: Improve gamepak prefetch timing
|
||||||
- GBA Memory: Stall on VRAM access in mode 2 (fixes mgba.io/i/190)
|
- GBA Memory: Stall on VRAM access in mode 2 (fixes mgba.io/i/190)
|
||||||
- GBA Memory: Improve robustness of Matrix memory support
|
- GBA Memory: Improve robustness of Matrix memory support
|
||||||
|
@ -77,6 +78,8 @@ Emulation fixes:
|
||||||
- GBA Video: Fix Hblank timing
|
- GBA Video: Fix Hblank timing
|
||||||
- GBA Video: Invalidate map cache when modifying BGCNT (fixes mgba.io/i/1846)
|
- 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: 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
|
- SM83: Emulate HALT bug
|
||||||
Other fixes:
|
Other fixes:
|
||||||
- 3DS: Redo video sync to be more precise
|
- 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
|
- mGUI: Fix closing down a game if an exit is signalled
|
||||||
- mVL: Fix injecting accidentally draining non-injection buffer
|
- mVL: Fix injecting accidentally draining non-injection buffer
|
||||||
- SM83: Simplify register pair access on big endian
|
- SM83: Simplify register pair access on big endian
|
||||||
|
- SM83: Disassemble STOP as one byte
|
||||||
- VFS: Fix directory node listing on some filesystems
|
- VFS: Fix directory node listing on some filesystems
|
||||||
Misc:
|
Misc:
|
||||||
- 3DS: Use "wide mode" where applicable for slightly better filtering
|
- 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: 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
|
- GBA: Allow pausing event loop while CPU is blocked
|
||||||
- Debugger: Keep track of global cycle count
|
- Debugger: Keep track of global cycle count
|
||||||
- FFmpeg: Add looping option for GIF/APNG
|
- FFmpeg: Add looping option for GIF/APNG
|
||||||
|
|
|
@ -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_PRE_FLAGS "-fprofile-generate=${PGO_DIR} -fprofile-arcs")
|
||||||
set(PGO_POST_FLAGS "-fprofile-use=${PGO_DIR} -fbranch-probabilities")
|
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)
|
if(BUILD_PGO AND NOT PGO_STAGE_2)
|
||||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${PGO_PRE_FLAGS}")
|
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${PGO_PRE_FLAGS}")
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${PGO_PRE_FLAGS}")
|
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${PGO_PRE_FLAGS}")
|
||||||
|
|
|
@ -58,7 +58,7 @@ The following mappers are fully supported:
|
||||||
|
|
||||||
The following mappers are partially supported:
|
The following mappers are partially supported:
|
||||||
|
|
||||||
- MBC6 (missing flash memory support)
|
- MBC6 (missing flash memory write support)
|
||||||
- MMM01
|
- MMM01
|
||||||
- Pocket Cam
|
- Pocket Cam
|
||||||
- TAMA5 (missing RTC support)
|
- TAMA5 (missing RTC support)
|
||||||
|
@ -146,10 +146,8 @@ This will produce a `build-win32` directory with the build products. Replace `mg
|
||||||
- mgba/switch
|
- mgba/switch
|
||||||
- mgba/ubuntu:xenial
|
- mgba/ubuntu:xenial
|
||||||
- mgba/ubuntu:bionic
|
- mgba/ubuntu:bionic
|
||||||
- mgba/ubuntu:cosmic
|
|
||||||
- mgba/ubuntu:disco
|
|
||||||
- mgba/ubuntu:eoan
|
|
||||||
- mgba/ubuntu:focal
|
- mgba/ubuntu:focal
|
||||||
|
- mgba/ubuntu:groovy
|
||||||
- mgba/vita
|
- mgba/vita
|
||||||
- mgba/wii
|
- mgba/wii
|
||||||
- mgba/windows:w32
|
- mgba/windows:w32
|
||||||
|
|
|
@ -57,7 +57,7 @@ Die folgenden Mapper werden vollständig unterstützt:
|
||||||
|
|
||||||
Die folgenden Mapper werden teilweise 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
|
- MMM01
|
||||||
- Pocket Cam
|
- Pocket Cam
|
||||||
- TAMA5 (fehlende RTC-Unterstützung)
|
- TAMA5 (fehlende RTC-Unterstützung)
|
||||||
|
@ -128,10 +128,8 @@ Dieser Befehl erzeugt ein Verzeichnis `build-win32` mit den erzeugten Programmda
|
||||||
- mgba/switch
|
- mgba/switch
|
||||||
- mgba/ubuntu:xenial
|
- mgba/ubuntu:xenial
|
||||||
- mgba/ubuntu:bionic
|
- mgba/ubuntu:bionic
|
||||||
- mgba/ubuntu:cosmic
|
|
||||||
- mgba/ubuntu:disco
|
|
||||||
- mgba/ubuntu:eoan
|
|
||||||
- mgba/ubuntu:focal
|
- mgba/ubuntu:focal
|
||||||
|
- mgba/ubuntu:groovy
|
||||||
- mgba/vita
|
- mgba/vita
|
||||||
- mgba/wii
|
- mgba/wii
|
||||||
- mgba/windows:w32
|
- mgba/windows:w32
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 9.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 9.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 9.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
Binary file not shown.
|
@ -126,8 +126,20 @@ typedef intptr_t ssize_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined __BIG_ENDIAN__
|
#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))
|
#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) { \
|
#define LOAD_32LE(DEST, ADDR, ARR) { \
|
||||||
size_t _addr = (ADDR); \
|
size_t _addr = (ADDR); \
|
||||||
const void* _ptr = (ARR); \
|
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"); \
|
__asm__("stdbrx %0, %1, %2" : : "r"(SRC), "b"(_ptr), "r"(_addr) : "memory"); \
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
#else
|
||||||
#error Big endian build not supported on this platform.
|
#error Big endian build not supported on this platform.
|
||||||
#endif
|
#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_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
|
#define STORE_16LE(SRC, ADDR, ARR) *(uint16_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = SRC
|
||||||
#ifdef _MSC_VER
|
#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
|
#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
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -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_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))
|
#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
|
#ifndef PYCPARSE
|
||||||
static inline color_t mColorFrom555(uint16_t value) {
|
static inline color_t mColorFrom555(uint16_t value) {
|
||||||
#ifdef COLOR_16_BIT
|
#ifdef COLOR_16_BIT
|
||||||
|
@ -90,6 +107,7 @@ struct mCoreCallbacks {
|
||||||
void (*videoFrameEnded)(void* context);
|
void (*videoFrameEnded)(void* context);
|
||||||
void (*coreCrashed)(void* context);
|
void (*coreCrashed)(void* context);
|
||||||
void (*sleep)(void* context);
|
void (*sleep)(void* context);
|
||||||
|
void (*shutdown)(void* context);
|
||||||
void (*keysRead)(void* context);
|
void (*keysRead)(void* context);
|
||||||
void (*savedataUpdated)(void* context);
|
void (*savedataUpdated)(void* context);
|
||||||
};
|
};
|
||||||
|
|
|
@ -245,11 +245,12 @@ struct ARMInstructionInfo {
|
||||||
struct ARMCoprocessor cp;
|
struct ARMCoprocessor cp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct mDebuggerSymbols;
|
||||||
void ARMDecodeARM(uint32_t opcode, struct ARMInstructionInfo* info);
|
void ARMDecodeARM(uint32_t opcode, struct ARMInstructionInfo* info);
|
||||||
void ARMDecodeThumb(uint16_t opcode, struct ARMInstructionInfo* info);
|
void ARMDecodeThumb(uint16_t opcode, struct ARMInstructionInfo* info);
|
||||||
bool ARMDecodeThumbCombine(struct ARMInstructionInfo* info1, struct ARMInstructionInfo* info2,
|
bool ARMDecodeThumbCombine(struct ARMInstructionInfo* info1, struct ARMInstructionInfo* info2,
|
||||||
struct ARMInstructionInfo* out);
|
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);
|
uint32_t ARMResolveMemoryAccess(struct ARMInstructionInfo* info, struct ARMRegisterFile* regs, uint32_t pc);
|
||||||
|
|
||||||
CXX_GUARD_END
|
CXX_GUARD_END
|
||||||
|
|
|
@ -87,6 +87,7 @@ enum GBIORegisters {
|
||||||
REG_KEY0 = 0x4C,
|
REG_KEY0 = 0x4C,
|
||||||
REG_KEY1 = 0x4D,
|
REG_KEY1 = 0x4D,
|
||||||
REG_VBK = 0x4F,
|
REG_VBK = 0x4F,
|
||||||
|
REG_BANK = 0x50,
|
||||||
REG_HDMA1 = 0x51,
|
REG_HDMA1 = 0x51,
|
||||||
REG_HDMA2 = 0x52,
|
REG_HDMA2 = 0x52,
|
||||||
REG_HDMA3 = 0x53,
|
REG_HDMA3 = 0x53,
|
||||||
|
|
|
@ -61,6 +61,8 @@ enum {
|
||||||
GB_SIZE_OAM = 0xA0,
|
GB_SIZE_OAM = 0xA0,
|
||||||
GB_SIZE_IO = 0x80,
|
GB_SIZE_IO = 0x80,
|
||||||
GB_SIZE_HRAM = 0x7F,
|
GB_SIZE_HRAM = 0x7F,
|
||||||
|
|
||||||
|
GB_SIZE_MBC6_FLASH = 0x100000,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -118,6 +120,8 @@ struct GBMBC6State {
|
||||||
bool sramAccess;
|
bool sramAccess;
|
||||||
int currentSramBank1;
|
int currentSramBank1;
|
||||||
uint8_t* sramBank1;
|
uint8_t* sramBank1;
|
||||||
|
bool flashBank0;
|
||||||
|
bool flashBank1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GBMBC7State {
|
struct GBMBC7State {
|
||||||
|
|
|
@ -129,6 +129,7 @@ struct GBAVideoSoftwareRenderer {
|
||||||
uint16_t bldy;
|
uint16_t bldy;
|
||||||
|
|
||||||
GBAMosaicControl mosaic;
|
GBAMosaicControl mosaic;
|
||||||
|
bool greenswap;
|
||||||
|
|
||||||
struct WindowN {
|
struct WindowN {
|
||||||
struct GBAVideoWindowRegion h;
|
struct GBAVideoWindowRegion h;
|
||||||
|
|
|
@ -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) {
|
static inline uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode) {
|
||||||
struct CLIDebuggerBackend* be = debugger->backend;
|
struct CLIDebuggerBackend* be = debugger->backend;
|
||||||
|
struct mCore* core = debugger->d.core;
|
||||||
char disassembly[64];
|
char disassembly[64];
|
||||||
struct ARMInstructionInfo info;
|
struct ARMInstructionInfo info;
|
||||||
be->printf(be, "%08X: ", address);
|
be->printf(be, "%08X: ", address);
|
||||||
if (mode == MODE_ARM) {
|
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);
|
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);
|
be->printf(be, "%08X\t%s\n", instruction, disassembly);
|
||||||
return WORD_SIZE_ARM;
|
return WORD_SIZE_ARM;
|
||||||
} else {
|
} else {
|
||||||
struct ARMInstructionInfo info2;
|
struct ARMInstructionInfo info2;
|
||||||
struct ARMInstructionInfo combined;
|
struct ARMInstructionInfo combined;
|
||||||
uint16_t instruction = debugger->d.core->busRead16(debugger->d.core, address);
|
uint16_t instruction = core->busRead16(core, address);
|
||||||
uint16_t instruction2 = debugger->d.core->busRead16(debugger->d.core, address + WORD_SIZE_THUMB);
|
uint16_t instruction2 = core->busRead16(core, address + WORD_SIZE_THUMB);
|
||||||
ARMDecodeThumb(instruction, &info);
|
ARMDecodeThumb(instruction, &info);
|
||||||
ARMDecodeThumb(instruction2, &info2);
|
ARMDecodeThumb(instruction2, &info2);
|
||||||
if (ARMDecodeThumbCombine(&info, &info2, &combined)) {
|
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);
|
be->printf(be, "%04X %04X\t%s\n", instruction, instruction2, disassembly);
|
||||||
return WORD_SIZE_THUMB * 2;
|
return WORD_SIZE_THUMB * 2;
|
||||||
} else {
|
} 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);
|
be->printf(be, "%04X \t%s\n", instruction, disassembly);
|
||||||
return WORD_SIZE_THUMB;
|
return WORD_SIZE_THUMB;
|
||||||
}
|
}
|
||||||
|
|
|
@ -466,6 +466,7 @@ static void ARMDebuggerListWatchpoints(struct mDebuggerPlatform* d, struct mWatc
|
||||||
static void ARMDebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* length) {
|
static void ARMDebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* length) {
|
||||||
struct ARMDebugger* debugger = (struct ARMDebugger*) d;
|
struct ARMDebugger* debugger = (struct ARMDebugger*) d;
|
||||||
struct ARMCore* cpu = debugger->cpu;
|
struct ARMCore* cpu = debugger->cpu;
|
||||||
|
struct mCore* core = d->p->core;
|
||||||
|
|
||||||
char disassembly[64];
|
char disassembly[64];
|
||||||
|
|
||||||
|
@ -474,17 +475,17 @@ static void ARMDebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* len
|
||||||
if (cpu->executionMode == MODE_ARM) {
|
if (cpu->executionMode == MODE_ARM) {
|
||||||
uint32_t instruction = cpu->prefetch[0];
|
uint32_t instruction = cpu->prefetch[0];
|
||||||
sprintf(disassembly, "%08X: ", instruction);
|
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 {
|
} else {
|
||||||
uint16_t instruction = cpu->prefetch[0];
|
uint16_t instruction = cpu->prefetch[0];
|
||||||
ARMDecodeThumb(instruction, &info);
|
ARMDecodeThumb(instruction, &info);
|
||||||
if (isWideInstruction) {
|
if (isWideInstruction) {
|
||||||
uint16_t instruction2 = cpu->prefetch[1];
|
uint16_t instruction2 = cpu->prefetch[1];
|
||||||
sprintf(disassembly, "%04X%04X: ", instruction, instruction2);
|
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 {
|
} else {
|
||||||
sprintf(disassembly, " %04X: ", instruction);
|
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: "));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <mgba/internal/arm/decoder.h>
|
#include <mgba/internal/arm/decoder.h>
|
||||||
|
|
||||||
#include <mgba/internal/arm/decoder-inlines.h>
|
#include <mgba/internal/arm/decoder-inlines.h>
|
||||||
|
#include <mgba/internal/debugger/symbols.h>
|
||||||
#include <mgba-util/string.h>
|
#include <mgba-util/string.h>
|
||||||
|
|
||||||
#define ADVANCE(AMOUNT) \
|
#define ADVANCE(AMOUNT) \
|
||||||
|
@ -20,8 +21,8 @@
|
||||||
static int _decodeRegister(int reg, char* buffer, int blen);
|
static int _decodeRegister(int reg, char* buffer, int blen);
|
||||||
static int _decodeRegisterList(int list, char* buffer, int blen);
|
static int _decodeRegisterList(int list, char* buffer, int blen);
|
||||||
static int _decodePSR(int bits, 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 _decodePCRelative(uint32_t address, const struct mDebuggerSymbols* symbols, uint32_t pc, bool thumbBranch, char* buffer, int blen);
|
||||||
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);
|
||||||
static int _decodeShift(union ARMOperand operand, bool reg, char* buffer, int blen);
|
static int _decodeShift(union ARMOperand operand, bool reg, char* buffer, int blen);
|
||||||
|
|
||||||
static const char* _armConditions[] = {
|
static const char* _armConditions[] = {
|
||||||
|
@ -141,23 +142,66 @@ static int _decodePSR(int psrBits, char* buffer, int blen) {
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _decodePCRelative(uint32_t address, uint32_t pc, char* buffer, int blen) {
|
static int _decodePCRelative(uint32_t address, const struct mDebuggerSymbols* symbols, uint32_t pc, bool thumbBranch, char* buffer, int blen) {
|
||||||
return snprintf(buffer, blen, "$%08X", address + pc);
|
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) {
|
if (blen <= 1) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int total = 0;
|
int total = 0;
|
||||||
strlcpy(buffer, "[", blen);
|
bool elideClose = false;
|
||||||
ADVANCE(1);
|
|
||||||
int written;
|
int written;
|
||||||
if (memory.format & ARM_MEMORY_REGISTER_BASE) {
|
if (memory.format & ARM_MEMORY_REGISTER_BASE) {
|
||||||
if (memory.baseReg == ARM_PC && memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
|
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);
|
uint32_t addrBase = memory.format & ARM_MEMORY_OFFSET_SUBTRACT ? -memory.offset.immediate : memory.offset.immediate;
|
||||||
ADVANCE(written);
|
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 {
|
} else {
|
||||||
|
strlcpy(buffer, "[", blen);
|
||||||
|
ADVANCE(1);
|
||||||
written = _decodeRegister(memory.baseReg, buffer, blen);
|
written = _decodeRegister(memory.baseReg, buffer, blen);
|
||||||
ADVANCE(written);
|
ADVANCE(written);
|
||||||
if (memory.format & (ARM_MEMORY_REGISTER_OFFSET | ARM_MEMORY_IMMEDIATE_OFFSET) && !(memory.format & ARM_MEMORY_POST_INCREMENT)) {
|
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);
|
ADVANCE(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
strlcpy(buffer, "[", blen);
|
||||||
|
ADVANCE(1);
|
||||||
}
|
}
|
||||||
if (memory.format & ARM_MEMORY_POST_INCREMENT) {
|
if (memory.format & ARM_MEMORY_POST_INCREMENT) {
|
||||||
strlcpy(buffer, "], ", blen);
|
strlcpy(buffer, "], ", blen);
|
||||||
ADVANCE(3);
|
ADVANCE(3);
|
||||||
|
elideClose = true;
|
||||||
}
|
}
|
||||||
if (memory.format & ARM_MEMORY_IMMEDIATE_OFFSET && memory.baseReg != ARM_PC) {
|
if (memory.format & ARM_MEMORY_IMMEDIATE_OFFSET && memory.baseReg != ARM_PC) {
|
||||||
if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
|
if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
|
||||||
|
@ -191,7 +239,7 @@ static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, in
|
||||||
ADVANCE(written);
|
ADVANCE(written);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(memory.format & ARM_MEMORY_POST_INCREMENT)) {
|
if (!elideClose) {
|
||||||
strlcpy(buffer, "]", blen);
|
strlcpy(buffer, "]", blen);
|
||||||
ADVANCE(1);
|
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];
|
const char* mnemonic = _armMnemonicStrings[info->mnemonic];
|
||||||
int written;
|
int written;
|
||||||
int total = 0;
|
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_BL:
|
||||||
case ARM_MN_BLX:
|
case ARM_MN_BLX:
|
||||||
if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
|
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);
|
ADVANCE(written);
|
||||||
} else if (info->operandFormat & ARM_OPERAND_REGISTER_1) {
|
} else if (info->operandFormat & ARM_OPERAND_REGISTER_1) {
|
||||||
written = _decodeRegister(info->op1.reg, buffer, blen);
|
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);
|
written = snprintf(buffer, blen, "#%i", info->op1.immediate);
|
||||||
ADVANCE(written);
|
ADVANCE(written);
|
||||||
} else if (info->operandFormat & ARM_OPERAND_MEMORY_1) {
|
} 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);
|
ADVANCE(written);
|
||||||
} else if (info->operandFormat & ARM_OPERAND_REGISTER_1) {
|
} else if (info->operandFormat & ARM_OPERAND_REGISTER_1) {
|
||||||
written = _decodeRegister(info->op1.reg, buffer, blen);
|
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);
|
written = snprintf(buffer, blen, "#%i", info->op2.immediate);
|
||||||
ADVANCE(written);
|
ADVANCE(written);
|
||||||
} else if (info->operandFormat & ARM_OPERAND_MEMORY_2) {
|
} 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);
|
ADVANCE(written);
|
||||||
} else if (info->operandFormat & ARM_OPERAND_REGISTER_2) {
|
} else if (info->operandFormat & ARM_OPERAND_REGISTER_2) {
|
||||||
written = _decodeRegister(info->op2.reg, buffer, blen);
|
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);
|
written = snprintf(buffer, blen, "#%i", info->op3.immediate);
|
||||||
ADVANCE(written);
|
ADVANCE(written);
|
||||||
} else if (info->operandFormat & ARM_OPERAND_MEMORY_3) {
|
} 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);
|
ADVANCE(written);
|
||||||
} else if (info->operandFormat & ARM_OPERAND_REGISTER_3) {
|
} else if (info->operandFormat & ARM_OPERAND_REGISTER_3) {
|
||||||
written = _decodeRegister(info->op3.reg, buffer, blen);
|
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);
|
written = snprintf(buffer, blen, "#%i", info->op4.immediate);
|
||||||
ADVANCE(written);
|
ADVANCE(written);
|
||||||
} else if (info->operandFormat & ARM_OPERAND_MEMORY_4) {
|
} 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);
|
ADVANCE(written);
|
||||||
} else if (info->operandFormat & ARM_OPERAND_REGISTER_4) {
|
} else if (info->operandFormat & ARM_OPERAND_REGISTER_4) {
|
||||||
written = _decodeRegister(info->op4.reg, buffer, blen);
|
written = _decodeRegister(info->op4.reg, buffer, blen);
|
||||||
|
|
|
@ -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) {
|
static THREAD_ENTRY _mCoreThreadRun(void* context) {
|
||||||
struct mCoreThread* threadContext = context;
|
struct mCoreThread* threadContext = context;
|
||||||
#ifdef USE_PTHREADS
|
#ifdef USE_PTHREADS
|
||||||
|
@ -162,6 +170,7 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
|
||||||
.videoFrameEnded = _frameEnded,
|
.videoFrameEnded = _frameEnded,
|
||||||
.coreCrashed = _crashed,
|
.coreCrashed = _crashed,
|
||||||
.sleep = _coreSleep,
|
.sleep = _coreSleep,
|
||||||
|
.shutdown = _coreShutdown,
|
||||||
.context = threadContext
|
.context = threadContext
|
||||||
};
|
};
|
||||||
core->addCoreCallbacks(core, &callbacks);
|
core->addCoreCallbacks(core, &callbacks);
|
||||||
|
|
|
@ -362,11 +362,7 @@ static void _writeRegister(struct GDBStub* stub, const char* message) {
|
||||||
|
|
||||||
uint32_t value = _readHex(readAddress, &i);
|
uint32_t value = _readHex(readAddress, &i);
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
value = _byteswap_ulong(value);
|
|
||||||
#else
|
|
||||||
LOAD_32BE(value, 0, &value);
|
LOAD_32BE(value, 0, &value);
|
||||||
#endif
|
|
||||||
|
|
||||||
if (reg <= ARM_PC) {
|
if (reg <= ARM_PC) {
|
||||||
cpu->gprs[reg] = value;
|
cpu->gprs[reg] = value;
|
||||||
|
|
|
@ -97,6 +97,13 @@ void mDebuggerLoadARMIPSSymbols(struct mDebuggerSymbols* st, struct VFile* vf) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* buf2 = strchr(buf, ',');
|
||||||
|
|
||||||
|
if (buf2 != NULL) {
|
||||||
|
// Commas separate names from function sizes
|
||||||
|
*buf2 = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
mDebuggerSymbolAdd(st, buf, address, -1);
|
mDebuggerSymbolAdd(st, buf, address, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
28
src/gb/gb.c
28
src/gb/gb.c
|
@ -783,29 +783,23 @@ void GBHalt(struct SM83Core* cpu) {
|
||||||
|
|
||||||
void GBStop(struct SM83Core* cpu) {
|
void GBStop(struct SM83Core* cpu) {
|
||||||
struct GB* gb = (struct GB*) cpu->master;
|
struct GB* gb = (struct GB*) cpu->master;
|
||||||
if (cpu->bus) {
|
if (gb->model >= GB_MODEL_CGB && gb->memory.io[REG_KEY1] & 1) {
|
||||||
mLOG(GB, GAME_ERROR, "Hit illegal stop at address %04X:%02X", cpu->pc, cpu->bus);
|
|
||||||
}
|
|
||||||
if (gb->memory.io[REG_KEY1] & 1) {
|
|
||||||
gb->doubleSpeed ^= 1;
|
gb->doubleSpeed ^= 1;
|
||||||
gb->audio.timingFactor = gb->doubleSpeed + 1;
|
gb->audio.timingFactor = gb->doubleSpeed + 1;
|
||||||
gb->memory.io[REG_KEY1] = 0;
|
gb->memory.io[REG_KEY1] = 0;
|
||||||
gb->memory.io[REG_KEY1] |= gb->doubleSpeed << 7;
|
gb->memory.io[REG_KEY1] |= gb->doubleSpeed << 7;
|
||||||
} else if (cpu->bus) {
|
} else {
|
||||||
#ifdef USE_DEBUGGERS
|
int sleep = ~(gb->memory.io[REG_JOYP] & 0x30);
|
||||||
if (cpu->components && cpu->components[CPU_COMPONENT_DEBUGGER]) {
|
size_t c;
|
||||||
struct mDebuggerEntryInfo info = {
|
for (c = 0; c < mCoreCallbacksListSize(&gb->coreCallbacks); ++c) {
|
||||||
.address = cpu->pc - 1,
|
struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gb->coreCallbacks, c);
|
||||||
.type.bp.opcode = 0x1000 | cpu->bus,
|
if (sleep && callbacks->sleep) {
|
||||||
};
|
callbacks->sleep(callbacks->context);
|
||||||
mDebuggerEnter((struct mDebugger*) cpu->components[CPU_COMPONENT_DEBUGGER], DEBUGGER_ENTER_ILLEGAL_OP, &info);
|
} 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) {
|
void GBIllegal(struct SM83Core* cpu) {
|
||||||
|
|
|
@ -56,6 +56,7 @@ MGBA_EXPORT const char* const GBIORegisterNames[] = {
|
||||||
[REG_KEY0] = "KEY0",
|
[REG_KEY0] = "KEY0",
|
||||||
[REG_KEY1] = "KEY1",
|
[REG_KEY1] = "KEY1",
|
||||||
[REG_VBK] = "VBK",
|
[REG_VBK] = "VBK",
|
||||||
|
[REG_BANK] = "BANK",
|
||||||
[REG_HDMA1] = "HDMA1",
|
[REG_HDMA1] = "HDMA1",
|
||||||
[REG_HDMA2] = "HDMA2",
|
[REG_HDMA2] = "HDMA2",
|
||||||
[REG_HDMA3] = "HDMA3",
|
[REG_HDMA3] = "HDMA3",
|
||||||
|
@ -185,10 +186,10 @@ void GBIOReset(struct GB* gb) {
|
||||||
GBIOWrite(gb, REG_NR51, 0xF3);
|
GBIOWrite(gb, REG_NR51, 0xF3);
|
||||||
if (!gb->biosVf) {
|
if (!gb->biosVf) {
|
||||||
GBIOWrite(gb, REG_LCDC, 0x91);
|
GBIOWrite(gb, REG_LCDC, 0x91);
|
||||||
gb->memory.io[0x50] = 1;
|
gb->memory.io[REG_BANK] = 1;
|
||||||
} else {
|
} else {
|
||||||
GBIOWrite(gb, REG_LCDC, 0x00);
|
GBIOWrite(gb, REG_LCDC, 0x00);
|
||||||
gb->memory.io[0x50] = 0xFF;
|
gb->memory.io[REG_BANK] = 0xFF;
|
||||||
}
|
}
|
||||||
GBIOWrite(gb, REG_SCY, 0x00);
|
GBIOWrite(gb, REG_SCY, 0x00);
|
||||||
GBIOWrite(gb, REG_SCX, 0x00);
|
GBIOWrite(gb, REG_SCX, 0x00);
|
||||||
|
@ -459,8 +460,8 @@ void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) {
|
||||||
GBVideoWriteSTAT(&gb->video, value);
|
GBVideoWriteSTAT(&gb->video, value);
|
||||||
value = gb->video.stat;
|
value = gb->video.stat;
|
||||||
break;
|
break;
|
||||||
case 0x50:
|
case REG_BANK:
|
||||||
if (gb->memory.io[0x50] != 0xFF) {
|
if (gb->memory.io[REG_BANK] != 0xFF) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
GBUnmapBIOS(gb);
|
GBUnmapBIOS(gb);
|
||||||
|
|
66
src/gb/mbc.c
66
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 uint8_t _GBPocketCamRead(struct GBMemory*, uint16_t address);
|
||||||
static void _GBPocketCamCapture(struct GBMemory*);
|
static void _GBPocketCamCapture(struct GBMemory*);
|
||||||
|
|
||||||
|
static void _GBMBC6MapChip(struct GB*, int half, uint8_t value);
|
||||||
|
|
||||||
void GBMBCSwitchBank(struct GB* gb, int bank) {
|
void GBMBCSwitchBank(struct GB* gb, int bank) {
|
||||||
size_t bankStart = bank * GB_SIZE_CART_BANK0;
|
size_t bankStart = bank * GB_SIZE_CART_BANK0;
|
||||||
if (bankStart + GB_SIZE_CART_BANK0 > gb->memory.romSize) {
|
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) {
|
void GBMBCSwitchHalfBank(struct GB* gb, int half, int bank) {
|
||||||
size_t bankStart = bank * GB_SIZE_CART_HALFBANK;
|
size_t bankStart = bank * GB_SIZE_CART_HALFBANK;
|
||||||
if (bankStart + GB_SIZE_CART_HALFBANK > gb->memory.romSize) {
|
bool isFlash = half ? gb->memory.mbcState.mbc6.flashBank1 : gb->memory.mbcState.mbc6.flashBank0;
|
||||||
mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid ROM bank: %0X", bank);
|
if (isFlash) {
|
||||||
bankStart &= (gb->memory.romSize - 1);
|
if (bankStart + GB_SIZE_CART_HALFBANK > GB_SIZE_MBC6_FLASH) {
|
||||||
bank = bankStart / GB_SIZE_CART_HALFBANK;
|
mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid Flash bank: %0X", bank);
|
||||||
if (!bank) {
|
bankStart &= GB_SIZE_MBC6_FLASH - 1;
|
||||||
++bank;
|
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) {
|
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;
|
gb->memory.currentBank = bank;
|
||||||
} else {
|
} 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;
|
gb->memory.mbcState.mbc6.currentBank1 = bank;
|
||||||
}
|
}
|
||||||
if (gb->cpu->pc < GB_BASE_VRAM) {
|
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) {
|
void GBMBCSwitchSramHalfBank(struct GB* gb, int half, int bank) {
|
||||||
size_t bankStart = bank * GB_SIZE_EXTERNAL_RAM_HALFBANK;
|
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);
|
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;
|
bank = bankStart / GB_SIZE_EXTERNAL_RAM_HALFBANK;
|
||||||
}
|
}
|
||||||
if (!half) {
|
if (!half) {
|
||||||
|
@ -334,6 +355,7 @@ void GBMBCInit(struct GB* gb) {
|
||||||
gb->memory.mbcWrite = _GBMBC6;
|
gb->memory.mbcWrite = _GBMBC6;
|
||||||
gb->memory.mbcRead = _GBMBC6Read;
|
gb->memory.mbcRead = _GBMBC6Read;
|
||||||
gb->memory.directSramAccess = false;
|
gb->memory.directSramAccess = false;
|
||||||
|
gb->sramSize += GB_SIZE_MBC6_FLASH; // Flash is concatenated at the end
|
||||||
break;
|
break;
|
||||||
case GB_MBC7:
|
case GB_MBC7:
|
||||||
gb->memory.mbcWrite = _GBMBC7;
|
gb->memory.mbcWrite = _GBMBC7;
|
||||||
|
@ -689,14 +711,28 @@ void _GBMBC6(struct GB* gb, uint16_t address, uint8_t value) {
|
||||||
case 0x2:
|
case 0x2:
|
||||||
GBMBCSwitchSramHalfBank(gb, 1, bank);
|
GBMBCSwitchSramHalfBank(gb, 1, bank);
|
||||||
break;
|
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 0x8:
|
||||||
case 0x9:
|
case 0x9:
|
||||||
GBMBCSwitchHalfBank(gb, 0, bank);
|
GBMBCSwitchHalfBank(gb, 0, bank);
|
||||||
break;
|
break;
|
||||||
|
case 0xA:
|
||||||
|
case 0xB:
|
||||||
|
_GBMBC6MapChip(gb, 0, value);
|
||||||
|
break;
|
||||||
case 0xC:
|
case 0xC:
|
||||||
case 0xD:
|
case 0xD:
|
||||||
GBMBCSwitchHalfBank(gb, 1, bank);
|
GBMBCSwitchHalfBank(gb, 1, bank);
|
||||||
break;
|
break;
|
||||||
|
case 0xE:
|
||||||
|
case 0xF:
|
||||||
|
_GBMBC6MapChip(gb, 1, value);
|
||||||
|
break;
|
||||||
case 0x28:
|
case 0x28:
|
||||||
case 0x29:
|
case 0x29:
|
||||||
case 0x2A:
|
case 0x2A:
|
||||||
|
@ -732,6 +768,16 @@ uint8_t _GBMBC6Read(struct GBMemory* memory, uint16_t address) {
|
||||||
return 0xFF;
|
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) {
|
void _GBMBC7(struct GB* gb, uint16_t address, uint8_t value) {
|
||||||
int bank = value & 0x7F;
|
int bank = value & 0x7F;
|
||||||
switch (address >> 13) {
|
switch (address >> 13) {
|
||||||
|
|
|
@ -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");
|
mLOG(GB_STATE, WARN, "Savestate is corrupted: OCPS is out of range");
|
||||||
}
|
}
|
||||||
bool differentBios = !gb->biosVf || gb->model != state->model;
|
bool differentBios = !gb->biosVf || gb->model != state->model;
|
||||||
if (state->io[0x50] == 0xFF) {
|
if (state->io[REG_BANK] == 0xFF) {
|
||||||
if (differentBios) {
|
if (differentBios) {
|
||||||
mLOG(GB_STATE, WARN, "Incompatible savestate, please restart with correct BIOS in %s mode", GBModelToName(state->model));
|
mLOG(GB_STATE, WARN, "Incompatible savestate, please restart with correct BIOS in %s mode", GBModelToName(state->model));
|
||||||
error = true;
|
error = true;
|
||||||
|
@ -206,7 +206,7 @@ bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
|
||||||
GBTimerDeserialize(&gb->timer, state);
|
GBTimerDeserialize(&gb->timer, state);
|
||||||
GBAudioDeserialize(&gb->audio, state);
|
GBAudioDeserialize(&gb->audio, state);
|
||||||
|
|
||||||
if (gb->memory.io[0x50] == 0xFF) {
|
if (gb->memory.io[REG_BANK] == 0xFF) {
|
||||||
GBMapBIOS(gb);
|
GBMapBIOS(gb);
|
||||||
} else {
|
} else {
|
||||||
GBUnmapBIOS(gb);
|
GBUnmapBIOS(gb);
|
||||||
|
|
|
@ -524,11 +524,15 @@ void GBAHalt(struct GBA* gba) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBAStop(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;
|
size_t c;
|
||||||
for (c = 0; c < mCoreCallbacksListSize(&gba->coreCallbacks); ++c) {
|
for (c = 0; c < mCoreCallbacksListSize(&gba->coreCallbacks); ++c) {
|
||||||
struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gba->coreCallbacks, c);
|
struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gba->coreCallbacks, c);
|
||||||
if (callbacks->sleep) {
|
if (sleep && callbacks->sleep) {
|
||||||
callbacks->sleep(callbacks->context);
|
callbacks->sleep(callbacks->context);
|
||||||
|
} else if (callbacks->shutdown) {
|
||||||
|
callbacks->shutdown(callbacks->context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gba->cpu->nextEvent = gba->cpu->cycles;
|
gba->cpu->nextEvent = gba->cpu->cycles;
|
||||||
|
|
|
@ -341,7 +341,7 @@ void GBAIOInit(struct GBA* gba) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) {
|
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);
|
value = gba->video.renderer->writeVideoRegister(gba->video.renderer, address, value);
|
||||||
} else {
|
} else {
|
||||||
switch (address) {
|
switch (address) {
|
||||||
|
@ -850,6 +850,7 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) {
|
||||||
}
|
}
|
||||||
// Fall through
|
// Fall through
|
||||||
case REG_DISPCNT:
|
case REG_DISPCNT:
|
||||||
|
case REG_GREENSWP:
|
||||||
case REG_DISPSTAT:
|
case REG_DISPSTAT:
|
||||||
case REG_VCOUNT:
|
case REG_VCOUNT:
|
||||||
case REG_BG0CNT:
|
case REG_BG0CNT:
|
||||||
|
|
|
@ -484,7 +484,7 @@ uint32_t GBALoad32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
|
||||||
|
|
||||||
if (cycleCounter) {
|
if (cycleCounter) {
|
||||||
wait += 2;
|
wait += 2;
|
||||||
if (address >> BASE_OFFSET < REGION_CART0) {
|
if (address < BASE_CART0) {
|
||||||
wait = GBAMemoryStall(cpu, wait);
|
wait = GBAMemoryStall(cpu, wait);
|
||||||
}
|
}
|
||||||
*cycleCounter += wait;
|
*cycleCounter += wait;
|
||||||
|
@ -603,7 +603,7 @@ uint32_t GBALoad16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
|
||||||
|
|
||||||
if (cycleCounter) {
|
if (cycleCounter) {
|
||||||
wait += 2;
|
wait += 2;
|
||||||
if (address >> BASE_OFFSET < REGION_CART0) {
|
if (address < BASE_CART0) {
|
||||||
wait = GBAMemoryStall(cpu, wait);
|
wait = GBAMemoryStall(cpu, wait);
|
||||||
}
|
}
|
||||||
*cycleCounter += wait;
|
*cycleCounter += wait;
|
||||||
|
@ -714,7 +714,7 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
|
||||||
|
|
||||||
if (cycleCounter) {
|
if (cycleCounter) {
|
||||||
wait += 2;
|
wait += 2;
|
||||||
if (address >> BASE_OFFSET < REGION_CART0) {
|
if (address < BASE_CART0) {
|
||||||
wait = GBAMemoryStall(cpu, wait);
|
wait = GBAMemoryStall(cpu, wait);
|
||||||
}
|
}
|
||||||
*cycleCounter += wait;
|
*cycleCounter += wait;
|
||||||
|
@ -840,7 +840,7 @@ void GBAStore32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycle
|
||||||
|
|
||||||
if (cycleCounter) {
|
if (cycleCounter) {
|
||||||
++wait;
|
++wait;
|
||||||
if (address >> BASE_OFFSET < REGION_CART0) {
|
if (address < BASE_CART0) {
|
||||||
wait = GBAMemoryStall(cpu, wait);
|
wait = GBAMemoryStall(cpu, wait);
|
||||||
}
|
}
|
||||||
*cycleCounter += wait;
|
*cycleCounter += wait;
|
||||||
|
@ -956,7 +956,7 @@ void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle
|
||||||
|
|
||||||
if (cycleCounter) {
|
if (cycleCounter) {
|
||||||
++wait;
|
++wait;
|
||||||
if (address >> BASE_OFFSET < REGION_CART0) {
|
if (address < BASE_CART0) {
|
||||||
wait = GBAMemoryStall(cpu, wait);
|
wait = GBAMemoryStall(cpu, wait);
|
||||||
}
|
}
|
||||||
*cycleCounter += wait;
|
*cycleCounter += wait;
|
||||||
|
@ -1039,7 +1039,7 @@ void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCo
|
||||||
|
|
||||||
if (cycleCounter) {
|
if (cycleCounter) {
|
||||||
++wait;
|
++wait;
|
||||||
if (address >> BASE_OFFSET < REGION_CART0) {
|
if (address < BASE_CART0) {
|
||||||
wait = GBAMemoryStall(cpu, wait);
|
wait = GBAMemoryStall(cpu, wait);
|
||||||
}
|
}
|
||||||
*cycleCounter += wait;
|
*cycleCounter += wait;
|
||||||
|
@ -1454,7 +1454,7 @@ uint32_t GBALoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum L
|
||||||
|
|
||||||
if (cycleCounter) {
|
if (cycleCounter) {
|
||||||
++wait;
|
++wait;
|
||||||
if (address >> BASE_OFFSET < REGION_CART0) {
|
if (address < BASE_CART0) {
|
||||||
wait = GBAMemoryStall(cpu, wait);
|
wait = GBAMemoryStall(cpu, wait);
|
||||||
}
|
}
|
||||||
*cycleCounter += wait;
|
*cycleCounter += wait;
|
||||||
|
@ -1572,7 +1572,7 @@ uint32_t GBAStoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cycleCounter) {
|
if (cycleCounter) {
|
||||||
if (address >> BASE_OFFSET < REGION_CART0) {
|
if (address < BASE_CART0) {
|
||||||
wait = GBAMemoryStall(cpu, wait);
|
wait = GBAMemoryStall(cpu, wait);
|
||||||
}
|
}
|
||||||
*cycleCounter += wait;
|
*cycleCounter += wait;
|
||||||
|
|
|
@ -251,7 +251,7 @@ int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* re
|
||||||
}
|
}
|
||||||
|
|
||||||
int objwinSlowPath = GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt) && GBAWindowControlGetBlendEnable(renderer->objwin.packed) != GBAWindowControlIsBlendEnable(renderer->currentWindow.packed);
|
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) &&
|
GBAWindowControlIsBlendEnable(renderer->currentWindow.packed) &&
|
||||||
(renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN);
|
(renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN);
|
||||||
if (GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT || (renderer->target1Obj && renderer->blendEffect == BLEND_ALPHA) || objwinSlowPath) {
|
if (GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT || (renderer->target1Obj && renderer->blendEffect == BLEND_ALPHA) || objwinSlowPath) {
|
||||||
|
|
|
@ -130,6 +130,7 @@ static void GBAVideoSoftwareRendererReset(struct GBAVideoRenderer* renderer) {
|
||||||
softwareRenderer->oamMax = 0;
|
softwareRenderer->oamMax = 0;
|
||||||
|
|
||||||
softwareRenderer->mosaic = 0;
|
softwareRenderer->mosaic = 0;
|
||||||
|
softwareRenderer->greenswap = false;
|
||||||
softwareRenderer->nextY = 0;
|
softwareRenderer->nextY = 0;
|
||||||
|
|
||||||
softwareRenderer->objOffsetX = 0;
|
softwareRenderer->objOffsetX = 0;
|
||||||
|
@ -189,6 +190,9 @@ static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRender
|
||||||
softwareRenderer->dispcnt = value;
|
softwareRenderer->dispcnt = value;
|
||||||
GBAVideoSoftwareRendererUpdateDISPCNT(softwareRenderer);
|
GBAVideoSoftwareRendererUpdateDISPCNT(softwareRenderer);
|
||||||
break;
|
break;
|
||||||
|
case REG_GREENSWP:
|
||||||
|
softwareRenderer->greenswap = value & 1;
|
||||||
|
break;
|
||||||
case REG_BG0CNT:
|
case REG_BG0CNT:
|
||||||
value &= 0xDFFF;
|
value &= 0xDFFF;
|
||||||
GBAVideoSoftwareRendererWriteBGCNT(softwareRenderer, &softwareRenderer->bg[0], value);
|
GBAVideoSoftwareRendererWriteBGCNT(softwareRenderer, &softwareRenderer->bg[0], value);
|
||||||
|
@ -406,9 +410,6 @@ static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRender
|
||||||
case REG_MOSAIC:
|
case REG_MOSAIC:
|
||||||
softwareRenderer->mosaic = value;
|
softwareRenderer->mosaic = value;
|
||||||
break;
|
break;
|
||||||
case REG_GREENSWP:
|
|
||||||
mLOG(GBA_VIDEO, STUB, "Stub video register write: 0x%03X", address);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
mLOG(GBA_VIDEO, GAME_ERROR, "Invalid video register: 0x%03X", address);
|
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) {
|
static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
|
||||||
struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer;
|
struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer;
|
||||||
|
|
||||||
if (y == GBA_VIDEO_VERTICAL_PIXELS - 1) {
|
if (y == softwareRenderer->masterHeight - 1) {
|
||||||
softwareRenderer->nextY = 0;
|
softwareRenderer->nextY = 0;
|
||||||
} else {
|
} else {
|
||||||
softwareRenderer->nextY = y + 1;
|
softwareRenderer->nextY = y + 1;
|
||||||
|
@ -711,17 +712,31 @@ static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* render
|
||||||
|
|
||||||
GBAVideoSoftwareRendererPostprocessBuffer(softwareRenderer);
|
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
|
#ifdef COLOR_16_BIT
|
||||||
size_t x;
|
for (x = 0; x < softwareRenderer->masterEnd; x += 4) {
|
||||||
for (x = 0; x < softwareRenderer->masterEnd; ++x) {
|
row[x] = softwareRenderer->row[x];
|
||||||
row[x] = softwareRenderer->row[x];
|
row[x + 1] = softwareRenderer->row[x + 1];
|
||||||
row[x + 1] = softwareRenderer->row[x + 1];
|
row[x + 2] = softwareRenderer->row[x + 2];
|
||||||
row[x + 2] = softwareRenderer->row[x + 2];
|
row[x + 3] = softwareRenderer->row[x + 3];
|
||||||
row[x + 3] = softwareRenderer->row[x + 3];
|
}
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
memcpy(row, softwareRenderer->row, softwareRenderer->masterEnd * sizeof(*row));
|
memcpy(row, softwareRenderer->row, softwareRenderer->masterEnd * sizeof(*row));
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GBAVideoSoftwareRendererFinishFrame(struct GBAVideoRenderer* renderer) {
|
static void GBAVideoSoftwareRendererFinishFrame(struct GBAVideoRenderer* renderer) {
|
||||||
|
@ -973,7 +988,7 @@ int GBAVideoSoftwareRendererPreprocessSpriteLayer(struct GBAVideoSoftwareRendere
|
||||||
}
|
}
|
||||||
if (GBAObjAttributesAIsMosaic(sprite->obj.a) && mosaicV > 1) {
|
if (GBAObjAttributesAIsMosaic(sprite->obj.a) && mosaicV > 1) {
|
||||||
localY = mosaicY;
|
localY = mosaicY;
|
||||||
if (localY < sprite->y && sprite->y < GBA_VIDEO_VERTICAL_PIXELS) {
|
if (localY < sprite->y && sprite->y < renderer->masterHeight) {
|
||||||
localY = sprite->y;
|
localY = sprite->y;
|
||||||
}
|
}
|
||||||
if (localY >= (sprite->endY & 0xFF)) {
|
if (localY >= (sprite->endY & 0xFF)) {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -44,4 +44,5 @@ if(BUILD_CINEMA)
|
||||||
target_link_libraries(${BINARY_NAME}-cinema ${BINARY_NAME} ${PLATFORM_LIBRARY})
|
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}")
|
set_target_properties(${BINARY_NAME}-cinema PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}")
|
||||||
add_test(cinema ${BINARY_NAME}-cinema -v)
|
add_test(cinema ${BINARY_NAME}-cinema -v)
|
||||||
|
install(TARGETS ${BINARY_NAME}-cinema DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${BINARY_NAME}-test)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -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(EI, info->mnemonic = SM83_MN_EI)
|
||||||
DEFINE_DECODER_SM83(HALT, info->mnemonic = SM83_MN_HALT)
|
DEFINE_DECODER_SM83(HALT, info->mnemonic = SM83_MN_HALT)
|
||||||
DEFINE_DECODER_SM83(ILL, info->mnemonic = SM83_MN_ILL)
|
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 DEFINE_RST_DECODER_SM83(VEC) \
|
||||||
DEFINE_DECODER_SM83(RST ## VEC, info->op1.immediate = 0x ## VEC;)
|
DEFINE_DECODER_SM83(RST ## VEC, info->op1.immediate = 0x ## VEC;)
|
||||||
|
|
Loading…
Reference in New Issue