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:
|
||||
- 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
|
||||
|
|
13
CHANGES
13
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
|
||||
|
|
|
@ -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}")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
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
|
||||
|
||||
#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
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -129,6 +129,7 @@ struct GBAVideoSoftwareRenderer {
|
|||
uint16_t bldy;
|
||||
|
||||
GBAMosaicControl mosaic;
|
||||
bool greenswap;
|
||||
|
||||
struct WindowN {
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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: "));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <mgba/internal/arm/decoder.h>
|
||||
|
||||
#include <mgba/internal/arm/decoder-inlines.h>
|
||||
#include <mgba/internal/debugger/symbols.h>
|
||||
#include <mgba-util/string.h>
|
||||
|
||||
#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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
28
src/gb/gb.c
28
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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
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 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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)) {
|
||||
|
|
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})
|
||||
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()
|
||||
|
|
|
@ -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;)
|
||||
|
|
Loading…
Reference in New Issue