Merge branch 'master' (early part) into medusa

This commit is contained in:
Vicki Pfau 2021-06-11 02:20:17 -07:00
commit 03146379bd
36 changed files with 464 additions and 293 deletions

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -129,6 +129,7 @@ struct GBAVideoSoftwareRenderer {
uint16_t bldy;
GBAMosaicControl mosaic;
bool greenswap;
struct WindowN {
struct GBAVideoWindowRegion h;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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