diff --git a/CHANGES b/CHANGES index a8db3efb0..47c65b5cf 100644 --- a/CHANGES +++ b/CHANGES @@ -25,8 +25,16 @@ Features: Emulation fixes: - ARM: Fix ALU reading PC after shifting - ARM: Fix STR storing PC after address calculation + - ARM: Fix timing on Thumb shift instructions + - GB: Fix GBC game registers after skipping BIOS + - GB MBC: Support 4MB MBC30 ROMs (fixes mgba.io/i/1713) + - GB Video: Fix state after skipping BIOS (fixes mgba.io/i/1715 and mgba.io/i/1716) + - GB Video: Fix BGPS value after skipping BIOS (fixes mgba.io/i/1717) + - GBA: Add missing RTC overrides for Legendz games + - GBA: Fix timing advancing too quickly in rare cases - GBA BIOS: Implement dummy sound driver calls - GBA BIOS: Improve HLE BIOS timing + - GBA BIOS: Reset renderer when RegisterRamReset called (fixes mgba.io/i/1756) - GBA DMA: Linger last DMA on bus (fixes mgba.io/i/301 and mgba.io/i/1320) - GBA Memory: Improve gamepak prefetch timing - GBA SIO: Fix Multiplayer busy bit @@ -35,7 +43,14 @@ Emulation fixes: - GBA Timers: Fix deserializing count-up timers - GBA Video: Latch scanline at end of Hblank (fixes mgba.io/i/1319) - GBA Video: Fix Hblank timing + - GBA Video: Fix mosaic objects drawing past the end (fixes mgba.io/i/1702) + - GBA Video: Fix disabling OBJWIN in GL renderer (fixes mgba.io/i/1759) + - GBA Video: Add missing parts of 256-color mode 0 mosaic (fixes mgba.io/1701) + - GBA Video: Fix double-size OBJ wrapping in GL renderer (fixes mgba.io/1712) Other fixes: + - All: Improve export headers (fixes mgba.io/i/1738) + - ARM Debugger: Clear low bit on breakpoint addresses (fixes mgba.io/i/1764) + - CMake: Always use devkitPro toolchain when applicable (fixes mgba.io/i/1755) - Core: Ensure ELF regions can be written before trying - Core: Fix ELF loading regression (fixes mgba.io/i/1669) - Core: Fix crash modifying hash table entry (fixes mgba.io/i/1673) @@ -44,8 +59,12 @@ Other fixes: - Debugger: Don't skip undefined instructions when debugger attached - Qt: Force OpenGL paint engine creation thread (fixes mgba.io/i/1642) - Qt: Fix OpenGL 2.1 support (fixes mgba.io/i/1678) + - Qt: Fix static compilation in MinGW (fixes mgba.io/i/1769) Misc: + - 3DS: Clean up legacy initialization (fixes mgba.io/i/1768) + - Debugger: Keep track of global cycle count - FFmpeg: Add looping option for GIF/APNG + - GBA Serialize: Only flunk BIOS check if official BIOS was expected - Qt: Renderer can be changed while a game is running - Qt: Add hex index to palette view - Qt: Add transformation matrix info to sprite view diff --git a/CMakeLists.txt b/CMakeLists.txt index c28ff75da..ad777c064 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,14 +9,17 @@ if(POLICY CMP0072) endif() project(medusa) set(BINARY_NAME medusa-emu CACHE INTERNAL "Name of output binaries") +set(CMAKE_C_STANDARD 99) if(NOT MSVC) - set(GCC_STD "c99") + set(CMAKE_C_STANDARD_REQUIRED ON) + set(CMAKE_C_EXTENSIONS OFF) if(SWITCH) - set(GCC_STD "gnu11") - elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_COMPILER_VERSION VERSION_LESS "4.3") - set(GCC_STD "gnu99") + set(CMAKE_C_STANDARD 11) + set(CMAKE_C_EXTENSIONS ON) + elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS "4.3") + set(CMAKE_C_EXTENSIONS ON) endif() - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wno-missing-field-initializers -std=${GCC_STD}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wno-missing-field-initializers") else() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_CRT_SECURE_NO_WARNINGS /wd4003 /wd4244 /wd4146") endif() @@ -174,9 +177,9 @@ endif() if(WIN32) set(WIN32_VERSION "${LIB_VERSION_MAJOR},${LIB_VERSION_MINOR},${LIB_VERSION_PATCH}") add_definitions(-D_WIN32_WINNT=0x0600) + set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) if(MSVC) add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN) - set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) add_definitions(-D_UNICODE -DUNICODE) else() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -municode") @@ -848,6 +851,7 @@ if(NOT SKIP_LIBRARY) if(BUILD_SHARED) add_library(${BINARY_NAME} SHARED ${SRC} ${VFS_SRC}) + set(EXPORT_DEFINES MGBA_DLL) if(BUILD_STATIC) add_library(${BINARY_NAME}-static STATIC ${SRC}) target_include_directories(${BINARY_NAME}-static BEFORE PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_BINARY_DIR}/include) @@ -861,12 +865,10 @@ if(NOT SKIP_LIBRARY) endif() target_include_directories(${BINARY_NAME} BEFORE PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_BINARY_DIR}/include) - set_target_properties(${BINARY_NAME} PROPERTIES VERSION ${LIB_VERSION_STRING} SOVERSION ${LIB_VERSION_ABI} COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}" COMPILE_OPTIONS "${FEATURE_FLAGS}") + set_target_properties(${BINARY_NAME} PROPERTIES VERSION ${LIB_VERSION_STRING} SOVERSION ${LIB_VERSION_ABI} COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES};${EXPORT_DEFINES}" COMPILE_OPTIONS "${FEATURE_FLAGS}") add_dependencies(${BINARY_NAME} version-info) - include(GenerateExportHeader) file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/mgba-util) - generate_export_header(${BINARY_NAME} BASE_NAME MGBA STATIC_DEFINE BUILD_STATIC EXPORT_FILE_NAME ${CMAKE_CURRENT_BINARY_DIR}/include/mgba-util/dllexports.h) target_link_libraries(${BINARY_NAME} ${DEBUGGER_LIB} ${DEPENDENCY_LIB} ${OS_LIB}) install(TARGETS ${BINARY_NAME} LIBRARY DESTINATION ${LIBDIR} COMPONENT lib${BINARY_NAME} NAMELINK_SKIP ARCHIVE DESTINATION ${LIBDIR} RUNTIME DESTINATION ${LIBDIR} COMPONENT lib${BINARY_NAME}) diff --git a/README.md b/README.md index 8d3a91dc4..38d2ac943 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,8 @@ This will produce a `build-win32` directory with the build products. Replace `mg - mgba/ubuntu:bionic - mgba/ubuntu:cosmic - mgba/ubuntu:disco +- mgba/ubuntu:eoan +- mgba/ubuntu:focal - mgba/vita - mgba/wii - mgba/windows:w32 diff --git a/README_DE.md b/README_DE.md index b7343ff2f..0847bbe3b 100644 --- a/README_DE.md +++ b/README_DE.md @@ -126,6 +126,8 @@ Dieser Befehl erzeugt ein Verzeichnis `build-win32` mit den erzeugten Programmda - mgba/ubuntu:bionic - mgba/ubuntu:cosmic - mgba/ubuntu:disco +- mgba/ubuntu:eoan +- mgba/ubuntu:focal - mgba/vita - mgba/wii - mgba/windows:w32 diff --git a/include/mgba-util/common.h b/include/mgba-util/common.h index 9a40f4a7b..8b032a8db 100644 --- a/include/mgba-util/common.h +++ b/include/mgba-util/common.h @@ -65,12 +65,7 @@ typedef intptr_t ssize_t; #include #endif -#ifndef MGBA_STANDALONE #include -#else -#define MGBA_EXPORT -#define MGBA_NO_EXPORT -#endif #ifndef SSIZE_MAX #define SSIZE_MAX ((ssize_t) (SIZE_MAX >> 1)) diff --git a/include/mgba-util/dllexports.h b/include/mgba-util/dllexports.h new file mode 100644 index 000000000..a44480df6 --- /dev/null +++ b/include/mgba-util/dllexports.h @@ -0,0 +1,19 @@ +/* Copyright (c) 2013-2020 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef MGBA_EXPORT_H +#define MGBA_EXPORT_H + +#if defined(BUILD_STATIC) || !defined(_MSC_VER) || defined(MGBA_STANDALONE) +#define MGBA_EXPORT +#else +#ifdef MGBA_DLL +#define MGBA_EXPORT __declspec(dllexport) +#else +#define MGBA_EXPORT __declspec(dllimport) +#endif +#endif + +#endif diff --git a/include/mgba/core/timing.h b/include/mgba/core/timing.h index 16154ba9c..10a64171e 100644 --- a/include/mgba/core/timing.h +++ b/include/mgba/core/timing.h @@ -25,6 +25,7 @@ struct mTiming { struct mTimingEvent* root; struct mTimingEvent* reroot; + uint64_t globalCycles; uint32_t masterCycles; int32_t* relativeCycles; int32_t* nextEvent; @@ -38,6 +39,7 @@ void mTimingDeschedule(struct mTiming* timing, struct mTimingEvent*); bool mTimingIsScheduled(const struct mTiming* timing, const struct mTimingEvent*); int32_t mTimingTick(struct mTiming* timing, int32_t cycles); int32_t mTimingCurrentTime(const struct mTiming* timing); +uint64_t mTimingGlobalTime(const struct mTiming* timing); int32_t mTimingNextEvent(struct mTiming* timing); int32_t mTimingUntil(const struct mTiming* timing, const struct mTimingEvent*); diff --git a/include/mgba/core/version.h b/include/mgba/core/version.h index 7749723c1..b261ab6d3 100644 --- a/include/mgba/core/version.h +++ b/include/mgba/core/version.h @@ -10,11 +10,7 @@ extern "C" { #endif -#ifdef MGBA_STANDALONE -#define MGBA_EXPORT -#else #include -#endif extern MGBA_EXPORT const char* const gitCommit; extern MGBA_EXPORT const char* const gitCommitShort; diff --git a/include/mgba/internal/arm/arm.h b/include/mgba/internal/arm/arm.h index 6ee342eb9..61bd8b0c9 100644 --- a/include/mgba/internal/arm/arm.h +++ b/include/mgba/internal/arm/arm.h @@ -70,7 +70,7 @@ struct ARMCore; union PSR { struct { -#if defined(__POWERPC__) || defined(__PPC__) +#if defined(__BIG_ENDIAN__) unsigned n : 1; unsigned z : 1; unsigned c : 1; diff --git a/include/mgba/internal/gb/io.h b/include/mgba/internal/gb/io.h index 1df09da2f..92917d70a 100644 --- a/include/mgba/internal/gb/io.h +++ b/include/mgba/internal/gb/io.h @@ -84,7 +84,7 @@ enum GBIORegisters { REG_WX = 0x4B, // CGB - REG_UNK4C = 0x4C, + REG_KEY0 = 0x4C, REG_KEY1 = 0x4D, REG_VBK = 0x4F, REG_HDMA1 = 0x51, @@ -97,7 +97,7 @@ enum GBIORegisters { REG_BCPD = 0x69, REG_OCPS = 0x6A, REG_OCPD = 0x6B, - REG_UNK6C = 0x6C, + REG_OPRI = 0x6C, REG_SVBK = 0x70, REG_UNK72 = 0x72, REG_UNK73 = 0x73, diff --git a/include/mgba/internal/gb/serialize.h b/include/mgba/internal/gb/serialize.h index ef2d5c4bc..68b7d8533 100644 --- a/include/mgba/internal/gb/serialize.h +++ b/include/mgba/internal/gb/serialize.h @@ -155,7 +155,8 @@ mLOG_DECLARE_CATEGORY(GB_STATE); * | bit 4: Is HDMA active? * | bits 5 - 7: Active RTC register * | 0x00196 - 0x00197: Reserved (leave zero) - * 0x00198 - 0x0025F: Reserved (leave zero) + * 0x00198 - 0x0019F: Global cycle counter + * 0x001A0 - 0x0025F: Reserved (leave zero) * 0x00260 - 0x002FF: OAM * 0x00300 - 0x0037F: I/O memory * 0x00380 - 0x003FE: HRAM @@ -388,7 +389,9 @@ struct GBSerializedState { uint16_t reserved; } memory; - uint32_t reserved[50]; + uint64_t globalCycles; + + uint32_t reserved[48]; uint8_t oam[GB_SIZE_OAM]; diff --git a/include/mgba/internal/gb/video.h b/include/mgba/internal/gb/video.h index 69a3b0420..b7dc54ecf 100644 --- a/include/mgba/internal/gb/video.h +++ b/include/mgba/internal/gb/video.h @@ -161,6 +161,7 @@ void GBVideoInit(struct GBVideo* video); void GBVideoReset(struct GBVideo* video); void GBVideoDeinit(struct GBVideo* video); void GBVideoAssociateRenderer(struct GBVideo* video, struct GBVideoRenderer* renderer); +void GBVideoSkipBIOS(struct GBVideo* video); void GBVideoProcessDots(struct GBVideo* video, uint32_t cyclesLate); void GBVideoWriteLCDC(struct GBVideo* video, GBRegisterLCDC value); diff --git a/include/mgba/internal/gba/serialize.h b/include/mgba/internal/gba/serialize.h index 672d182cf..a5dabae2c 100644 --- a/include/mgba/internal/gba/serialize.h +++ b/include/mgba/internal/gba/serialize.h @@ -193,7 +193,8 @@ mLOG_DECLARE_CATEGORY(GBA_STATE); * | 0x002F4 - 0x002F7: GBA BIOS bus prefetch * | 0x002F8 - 0x002FB: CPU prefecth (decode slot) * | 0x002FC - 0x002FF: CPU prefetch (fetch slot) - * 0x00300 - 0x00317: Reserved (leave zero) + * 0x00300 - 0x0030F: Reserved (leave zero) + * 0x00310 - 0x00317: Global cycle counter * 0x00318 - 0x0031B: Last prefetched program counter * 0x0031C - 0x0031F: Miscellaneous flags * | bit 0: Is CPU halted? @@ -326,8 +327,9 @@ struct GBASerializedState { uint32_t biosPrefetch; uint32_t cpuPrefetch[2]; - uint32_t reservedCpu[6]; + uint32_t reservedCpu[4]; + uint64_t globalCycles; uint32_t lastPrefetchedPc; GBASerializedMiscFlags miscFlags; uint32_t nextIrq; diff --git a/src/arm/debugger/cli-debugger.c b/src/arm/debugger/cli-debugger.c index c393f8c1e..d5ee883be 100644 --- a/src/arm/debugger/cli-debugger.c +++ b/src/arm/debugger/cli-debugger.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -138,6 +139,7 @@ static void _printStatus(struct CLIDebuggerSystem* debugger) { } be->printf(be, "cpsr: "); _printPSR(be, cpu->cpsr); + be->printf(be, "Cycle: %" PRIu64 "\n", mTimingGlobalTime(debugger->p->d.core->timing)); int instructionLength; enum ExecutionMode mode = cpu->cpsr.t; if (mode == MODE_ARM) { diff --git a/src/arm/debugger/debugger.c b/src/arm/debugger/debugger.c index 11df366c6..7449ece33 100644 --- a/src/arm/debugger/debugger.c +++ b/src/arm/debugger/debugger.c @@ -171,7 +171,7 @@ ssize_t ARMDebuggerSetSoftwareBreakpoint(struct mDebuggerPlatform* d, uint32_t a ssize_t id = debugger->nextId; ++debugger->nextId; breakpoint->d.id = id; - breakpoint->d.address = address; + breakpoint->d.address = address & ~1; // Clear Thumb bit since it's not part of a valid address breakpoint->d.segment = -1; breakpoint->d.condition = NULL; breakpoint->d.type = BREAKPOINT_SOFTWARE; @@ -187,6 +187,7 @@ static ssize_t ARMDebuggerSetBreakpoint(struct mDebuggerPlatform* d, const struc ssize_t id = debugger->nextId; ++debugger->nextId; breakpoint->d = *info; + breakpoint->d.address &= ~1; // Clear Thumb bit since it's not part of a valid address breakpoint->d.id = id; if (info->type == BREAKPOINT_SOFTWARE) { // TODO diff --git a/src/arm/isa-thumb.c b/src/arm/isa-thumb.c index 368c4f40f..42b14e30b 100644 --- a/src/arm/isa-thumb.c +++ b/src/arm/isa-thumb.c @@ -157,6 +157,7 @@ DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(LSL2, cpu->gprs[rd] = 0; } } + ++currentCycles; THUMB_NEUTRAL_S( , , cpu->gprs[rd])) DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(LSR2, @@ -174,6 +175,7 @@ DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(LSR2, cpu->gprs[rd] = 0; } } + ++currentCycles; THUMB_NEUTRAL_S( , , cpu->gprs[rd])) DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(ASR2, @@ -191,6 +193,7 @@ DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(ASR2, } } } + ++currentCycles; THUMB_NEUTRAL_S( , , cpu->gprs[rd])) DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(ADC, @@ -215,6 +218,7 @@ DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(ROR, cpu->cpsr.c = ARM_SIGN(cpu->gprs[rd]); } } + ++currentCycles; THUMB_NEUTRAL_S( , , cpu->gprs[rd]);) DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(TST, int32_t aluOut = cpu->gprs[rd] & cpu->gprs[rn]; THUMB_NEUTRAL_S(cpu->gprs[rd], cpu->gprs[rn], aluOut)) DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(NEG, THUMB_SUBTRACTION(cpu->gprs[rd], 0, cpu->gprs[rn])) diff --git a/src/core/timing.c b/src/core/timing.c index 88bcf2743..f9854c6ac 100644 --- a/src/core/timing.c +++ b/src/core/timing.c @@ -8,6 +8,7 @@ void mTimingInit(struct mTiming* timing, int32_t* relativeCycles, int32_t* nextEvent) { timing->root = NULL; timing->reroot = NULL; + timing->globalCycles = 0; timing->masterCycles = 0; timing->relativeCycles = relativeCycles; timing->nextEvent = nextEvent; @@ -20,6 +21,7 @@ void mTimingDeinit(struct mTiming* timing) { void mTimingClear(struct mTiming* timing) { timing->root = NULL; timing->reroot = NULL; + timing->globalCycles = 0; timing->masterCycles = 0; } @@ -103,6 +105,10 @@ int32_t mTimingCurrentTime(const struct mTiming* timing) { return timing->masterCycles + *timing->relativeCycles; } +uint64_t mTimingGlobalTime(const struct mTiming* timing) { + return timing->globalCycles + *timing->relativeCycles; +} + int32_t mTimingNextEvent(struct mTiming* timing) { struct mTimingEvent* next = timing->root; if (!next) { diff --git a/src/gb/gb.c b/src/gb/gb.c index 1d73937d3..0aaa6ae54 100644 --- a/src/gb/gb.c +++ b/src/gb/gb.c @@ -460,13 +460,13 @@ void GBReset(struct SM83Core* cpu) { GBVideoReset(&gb->video); GBTimerReset(&gb->timer); + GBIOReset(gb); if (!gb->biosVf) { GBSkipBIOS(gb); } else { mTimingSchedule(&gb->timing, &gb->timer.event, 0); } - GBIOReset(gb); GBAudioReset(&gb->audio); GBSIOReset(&gb->sio); @@ -478,6 +478,7 @@ void GBReset(struct SM83Core* cpu) { void GBSkipBIOS(struct GB* gb) { struct SM83Core* cpu = gb->cpu; + const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100]; int nextDiv = 0; switch (gb->model) { @@ -539,9 +540,15 @@ void GBSkipBIOS(struct GB* gb) { cpu->a = 0x11; cpu->f.packed = 0x80; cpu->c = 0; - cpu->e = 0x08; cpu->h = 0; - cpu->l = 0x7C; + if (cart->cgb & 0x80) { + cpu->d = 0xFF; + cpu->e = 0x56; + cpu->l = 0x0D; + } else { + cpu->e = 0x08; + cpu->l = 0x7C; + } gb->timer.internalDiv = 0x1EA; nextDiv = 0xC; break; @@ -554,6 +561,7 @@ void GBSkipBIOS(struct GB* gb) { mTimingSchedule(&gb->timing, &gb->timer.event, 0); GBIOWrite(gb, REG_LCDC, 0x91); + GBVideoSkipBIOS(&gb->video); if (gb->biosVf) { GBUnmapBIOS(gb); @@ -666,6 +674,9 @@ void GBProcessEvents(struct SM83Core* cpu) { int32_t nextEvent; cpu->cycles = 0; +#ifdef USE_DEBUGGERS + gb->timing.globalCycles += cycles; +#endif cpu->nextEvent = INT_MAX; nextEvent = cycles; diff --git a/src/gb/io.c b/src/gb/io.c index 155c2c624..134454e12 100644 --- a/src/gb/io.c +++ b/src/gb/io.c @@ -53,6 +53,7 @@ MGBA_EXPORT const char* const GBIORegisterNames[] = { [REG_OBP1] = "OBP1", [REG_WY] = "WY", [REG_WX] = "WX", + [REG_KEY0] = "KEY0", [REG_KEY1] = "KEY1", [REG_VBK] = "VBK", [REG_HDMA1] = "HDMA1", @@ -65,6 +66,7 @@ MGBA_EXPORT const char* const GBIORegisterNames[] = { [REG_BCPD] = "BCPD", [REG_OCPS] = "OCPS", [REG_OCPD] = "OCPD", + [REG_OPRI] = "OPRI", [REG_SVBK] = "SVBK", [REG_IE] = "IE", }; @@ -99,7 +101,7 @@ static const uint8_t _registerMask[] = { [REG_VBK] = 0xFE, [REG_OCPS] = 0x40, [REG_BCPS] = 0x40, - [REG_UNK6C] = 0xFE, + [REG_OPRI] = 0xFE, [REG_SVBK] = 0xF8, [REG_IE] = 0xE0, }; @@ -200,10 +202,10 @@ void GBIOReset(struct GB* gb) { GBIOWrite(gb, REG_WY, 0x00); GBIOWrite(gb, REG_WX, 0x00); if (gb->model & GB_MODEL_CGB) { - GBIOWrite(gb, REG_UNK4C, 0); + GBIOWrite(gb, REG_KEY0, 0); GBIOWrite(gb, REG_JOYP, 0xFF); GBIOWrite(gb, REG_VBK, 0); - GBIOWrite(gb, REG_BCPS, 0); + GBIOWrite(gb, REG_BCPS, 0x80); GBIOWrite(gb, REG_OCPS, 0); GBIOWrite(gb, REG_SVBK, 1); GBIOWrite(gb, REG_HDMA1, 0xFF); @@ -462,7 +464,7 @@ void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) { break; } GBUnmapBIOS(gb); - if (gb->model >= GB_MODEL_CGB && gb->memory.io[REG_UNK4C] < 0x80) { + if (gb->model >= GB_MODEL_CGB && gb->memory.io[REG_KEY0] < 0x80) { gb->model = GB_MODEL_DMG; GBVideoDisableCGB(&gb->video); } @@ -474,7 +476,7 @@ void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) { default: if (gb->model >= GB_MODEL_CGB) { switch (address) { - case REG_UNK4C: + case REG_KEY0: break; case REG_KEY1: value &= 0x1; diff --git a/src/gb/mbc.c b/src/gb/mbc.c index 6efe8b64d..be03f1511 100644 --- a/src/gb/mbc.c +++ b/src/gb/mbc.c @@ -518,7 +518,7 @@ static uint8_t _GBMBC2Read(struct GBMemory* memory, uint16_t address) { void _GBMBC3(struct GB* gb, uint16_t address, uint8_t value) { struct GBMemory* memory = &gb->memory; - int bank = value & 0x7F; + int bank = value; switch (address >> 13) { case 0x0: switch (value) { @@ -536,6 +536,9 @@ void _GBMBC3(struct GB* gb, uint16_t address, uint8_t value) { } break; case 0x1: + if (gb->memory.romSize < GB_SIZE_CART_BANK0 * 0x80) { + bank &= 0x7F; + } if (!bank) { ++bank; } diff --git a/src/gb/serialize.c b/src/gb/serialize.c index e8eaeefc7..539f87c2a 100644 --- a/src/gb/serialize.c +++ b/src/gb/serialize.c @@ -23,6 +23,7 @@ void GBSerialize(struct GB* gb, struct GBSerializedState* state) { STORE_32LE(GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, 0, &state->versionMagic); STORE_32LE(gb->romCrc32, 0, &state->romCrc32); STORE_32LE(gb->timing.masterCycles, 0, &state->masterCycles); + STORE_64LE(gb->timing.globalCycles, 0, &state->globalCycles); if (gb->memory.rom) { memcpy(state->title, ((struct GBCartridge*) &gb->memory.rom[0x100])->titleLong, sizeof(state->title)); @@ -150,6 +151,7 @@ bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) { } mTimingClear(&gb->timing); LOAD_32LE(gb->timing.masterCycles, 0, &state->masterCycles); + LOAD_64LE(gb->timing.globalCycles, 0, &state->globalCycles); gb->cpu->a = state->cpu.a; gb->cpu->f.packed = state->cpu.f; diff --git a/src/gb/video.c b/src/gb/video.c index 0859b13c9..575bdeb2f 100644 --- a/src/gb/video.c +++ b/src/gb/video.c @@ -214,6 +214,30 @@ static bool _statIRQAsserted(GBRegisterSTAT stat) { return false; } +void GBVideoSkipBIOS(struct GBVideo* video) { + video->mode = 1; + video->modeEvent.callback = _endMode1; + + int32_t next; + if (video->p->model == GB_MODEL_CGB) { + video->ly = GB_VIDEO_VERTICAL_PIXELS; + video->p->memory.io[REG_LY] = video->ly; + video->stat = GBRegisterSTATClearLYC(video->stat); + next = 20; + } else { + video->ly = GB_VIDEO_VERTICAL_TOTAL_PIXELS; + video->p->memory.io[REG_LY] = 0; + next = 56; + } + video->stat = GBRegisterSTATSetMode(video->stat, video->mode); + + video->p->memory.io[REG_IF] |= (1 << GB_IRQ_VBLANK); + GBUpdateIRQs(video->p); + video->p->memory.io[REG_STAT] = video->stat; + mTimingDeschedule(&video->p->timing, &video->modeEvent); + mTimingSchedule(&video->p->timing, &video->modeEvent, next); +} + void _endMode0(struct mTiming* timing, void* context, uint32_t cyclesLate) { struct GBVideo* video = context; if (video->frameskipCounter <= 0) { diff --git a/src/gba/bios.c b/src/gba/bios.c index b3c89f388..80a0075f6 100644 --- a/src/gba/bios.c +++ b/src/gba/bios.c @@ -177,6 +177,9 @@ static void _RegisterRamReset(struct GBA* gba) { cpu->memory.store16(cpu, BASE_IO | 0x204, 0, 0); cpu->memory.store16(cpu, BASE_IO | 0x208, 0, 0); } + if (registers & 0x9C) { + gba->video.renderer->reset(gba->video.renderer); + } } static void _BgAffineSet(struct GBA* gba) { diff --git a/src/gba/gba.c b/src/gba/gba.c index b5474a509..c2158e592 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -277,12 +277,15 @@ static void GBAProcessEvents(struct ARMCore* cpu) { do { int32_t cycles = cpu->cycles; cpu->cycles = 0; +#ifdef USE_DEBUGGERS + gba->timing.globalCycles += cycles; +#endif #ifndef NDEBUG if (cycles < 0) { mLOG(GBA, FATAL, "Negative cycles passed: %i", cycles); } #endif - nextEvent = mTimingTick(&gba->timing, nextEvent + cycles); + nextEvent = mTimingTick(&gba->timing, cycles < nextEvent ? nextEvent : cycles); } while (gba->cpuBlocked); cpu->nextEvent = nextEvent; diff --git a/src/gba/overrides.c b/src/gba/overrides.c index fc0320b2a..ec40e4449 100644 --- a/src/gba/overrides.c +++ b/src/gba/overrides.c @@ -71,6 +71,13 @@ static const struct GBACartridgeOverride _overrides[] = { // Koro Koro Puzzle - Happy Panechu! { "KHPJ", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE, false }, + // Legendz - Yomigaeru Shiren no Shima + { "BLJJ", SAVEDATA_FLASH512, HW_RTC, IDLE_LOOP_NONE, false }, + { "BLJK", SAVEDATA_FLASH512, HW_RTC, IDLE_LOOP_NONE, false }, + + // Legendz - Sign of Nekuromu + { "BLVJ", SAVEDATA_FLASH512, HW_RTC, IDLE_LOOP_NONE, false }, + // Mega Man Battle Network { "AREE", SAVEDATA_SRAM, HW_NONE, 0x800032E, false }, diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index 29ba0a16f..aa3b77de2 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -1640,10 +1640,6 @@ void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GB unsigned charBase = (BASE_TILE >> 1) + (GBAObjAttributesCGetTile(sprite->c) & ~align) * 0x10; int stride = GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt) ? (width >> 3) : (0x20 >> GBAObjAttributesAGet256Color(sprite->a)); - if (spriteY + height >= 256) { - spriteY -= 256; - } - int totalWidth = width; int totalHeight = height; if (GBAObjAttributesAIsTransformed(sprite->a) && GBAObjAttributesAIsDoubleSize(sprite->a)) { @@ -1651,6 +1647,10 @@ void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GB totalHeight <<= 1; } + if (spriteY + totalHeight >= 256) { + spriteY -= 256; + } + const struct GBAVideoGLShader* shader = &renderer->objShader[GBAObjAttributesAGet256Color(sprite->a)]; const GLuint* uniforms = shader->uniforms; glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_OBJ]); @@ -1710,7 +1710,9 @@ void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GB glUniform4i(uniforms[GBA_GL_OBJ_MOSAIC], 0, 0, 0, 0); } glStencilFunc(GL_ALWAYS, 1, 1); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + if (GBAObjAttributesAGetMode(sprite->a) != OBJ_MODE_OBJWIN || GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt)) { + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + } shader = &renderer->objShader[2]; uniforms = shader->uniforms; diff --git a/src/gba/renderers/software-mode0.c b/src/gba/renderers/software-mode0.c index 01a1d0fcf..e001dfe55 100644 --- a/src/gba/renderers/software-mode0.c +++ b/src/gba/renderers/software-mode0.c @@ -473,8 +473,57 @@ } #define DRAW_BACKGROUND_MODE_0_MOSAIC_256EXT(BLEND, OBJWIN) \ + x = inX & 7; \ + if (mosaicWait) { \ + int baseX = x - (mosaicH - mosaicWait); \ + if (baseX < 0) { \ + int disturbX = (16 + baseX) >> 3; \ + inX -= disturbX << 3; \ + localX = tileX * 8 + inX; \ + BACKGROUND_TEXT_SELECT_CHARACTER; \ + localY = inY & 0x7; \ + if (GBA_TEXT_MAP_VFLIP(mapData)) { \ + localY = 7 - localY; \ + } \ + baseX -= disturbX << 3; \ + inX += disturbX << 3; \ + } else { \ + localX = tileX * 8 + inX; \ + BACKGROUND_TEXT_SELECT_CHARACTER; \ + localY = inY & 0x7; \ + if (GBA_TEXT_MAP_VFLIP(mapData)) { \ + localY = 7 - localY; \ + } \ + } \ + charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \ + if (UNLIKELY(charBase >= 0x10000)) { \ + carryData = 0; \ + } else { \ + vram = renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET]; \ + LOAD_32(tileData, charBase, vram); \ + if (!GBA_TEXT_MAP_HFLIP(mapData)) { \ + if (x >= 4) { \ + LOAD_32(tileData, charBase + 4, vram); \ + tileData >>= (x - 4) * 8; \ + } else { \ + LOAD_32(tileData, charBase, vram); \ + tileData >>= x * 8; \ + } \ + } else { \ + if (x >= 4) { \ + LOAD_32(tileData, charBase, vram); \ + tileData >>= (7 - x) * 8; \ + } else { \ + LOAD_32(tileData, charBase + 4, vram); \ + tileData >>= (3 - x) * 8; \ + } \ + } \ + tileData &= 0xFF; \ + carryData = tileData; \ + } \ + } \ localX = tileX * 8 + inX; \ - for (; tileX < tileEnd; ++tileX) { \ + for (; length; ++tileX) { \ mapData = background->mapCache[(localX >> 3) & 0x3F]; \ localX += 8; \ localY = inY & 0x7; \ @@ -484,7 +533,7 @@ charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \ vram = renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET]; \ tileData = carryData; \ - for (x = 0; x < 8; ++x) { \ + for (x = 0; x < 8 && length; ++x, --length) { \ if (!mosaicWait) { \ paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 8; \ palette = &mainPalette[paletteData]; \ diff --git a/src/gba/renderers/software-obj.c b/src/gba/renderers/software-obj.c index 4b487039c..440ac4c05 100644 --- a/src/gba/renderers/software-obj.c +++ b/src/gba/renderers/software-obj.c @@ -326,7 +326,7 @@ int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* re int mosaicH = 1; if (GBAObjAttributesAIsMosaic(sprite->a)) { mosaicH = GBAMosaicControlGetObjH(renderer->mosaic) + 1; - if (condition % mosaicH) { + if (condition != end && condition % mosaicH) { condition += mosaicH - (condition % mosaicH); } } diff --git a/src/gba/serialize.c b/src/gba/serialize.c index bd543482a..00a80c6b7 100644 --- a/src/gba/serialize.c +++ b/src/gba/serialize.c @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -28,6 +29,7 @@ void GBASerialize(struct GBA* gba, struct GBASerializedState* state) { STORE_32(gba->biosChecksum, 0, &state->biosChecksum); STORE_32(gba->romCrc32, 0, &state->romCrc32); STORE_32(gba->timing.masterCycles, 0, &state->masterCycles); + STORE_64LE(gba->timing.globalCycles, 0, &state->globalCycles); if (gba->memory.rom) { state->id = ((struct GBACartridge*) gba->memory.rom)->id; @@ -93,7 +95,7 @@ bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) { mLOG(GBA_STATE, WARN, "Savestate created using a different version of the BIOS: expected %08X, got %08X", gba->biosChecksum, ucheck); uint32_t pc; LOAD_32(pc, ARM_PC * sizeof(state->cpu.gprs[0]), state->cpu.gprs); - if (pc < SIZE_BIOS && pc >= 0x20) { + if ((ucheck == GBA_BIOS_CHECKSUM || gba->biosChecksum == GBA_BIOS_CHECKSUM) && pc < SIZE_BIOS && pc >= 0x20) { error = true; } } @@ -128,6 +130,7 @@ bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) { } mTimingClear(&gba->timing); LOAD_32(gba->timing.masterCycles, 0, &state->masterCycles); + LOAD_64LE(gba->timing.globalCycles, 0, &state->globalCycles); size_t i; for (i = 0; i < 16; ++i) { diff --git a/src/platform/3ds/CMakeLists.txt b/src/platform/3ds/CMakeLists.txt index f61ab45fd..7e2e26910 100644 --- a/src/platform/3ds/CMakeLists.txt +++ b/src/platform/3ds/CMakeLists.txt @@ -7,7 +7,7 @@ find_program(BANNERTOOL bannertool) find_program(MAKEROM makerom) find_program(PICASSO picasso) find_program(RAW2C raw2c) -find_program(STRIP ${cross_prefix}strip) +set(STRIP "${cross_prefix_path}strip" CACHE INTERNAL "symbol stripper") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-format" PARENT_SCOPE) set(OS_DEFINES COLOR_16_BIT COLOR_5_6_5 IOAPI_NO_64) diff --git a/src/platform/3ds/ctru-heap.c b/src/platform/3ds/ctru-heap.c index 42608f8b9..ccd38090e 100644 --- a/src/platform/3ds/ctru-heap.c +++ b/src/platform/3ds/ctru-heap.c @@ -1,92 +1,31 @@ -/* This code is mostly from ctrulib, which contains the following license: - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - * The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software in - a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - * Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - * This notice may not be removed or altered from any source distribution. -*/ - -#include <3ds/types.h> -#include <3ds/srv.h> -#include <3ds/gfx.h> -#include <3ds/sdmc.h> -#include <3ds/services/apt.h> -#include <3ds/services/fs.h> -#include <3ds/services/hid.h> -#include <3ds/svc.h> +/* Copyright (c) 2013-2020 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include <3ds/archive.h> #include -extern char* fake_heap_start; -extern char* fake_heap_end; -extern u32 __ctru_linear_heap; -extern u32 __ctru_heap; -extern u32 __ctru_heap_size; -extern u32 __ctru_linear_heap_size; -static u32 __custom_heap_size = 0x02400000; -static u32 __custom_linear_heap_size = 0x01400000; +u32 __ctru_heap_size = 0x02400000; +u32 __ctru_linear_heap_size = 0x01400000; uint32_t* romBuffer = NULL; size_t romBufferSize; FS_Archive sdmcArchive; -bool allocateRomBuffer(void) { - if (romBuffer) { - return true; - } +__attribute__((constructor)) static void init(void) { + FSUSER_OpenArchive(&sdmcArchive, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, "")); + romBuffer = malloc(0x02000000); if (romBuffer) { romBufferSize = 0x02000000; - return true; + return; } romBuffer = malloc(0x01000000); if (romBuffer) { romBufferSize = 0x01000000; - return true; + return; } - return false; -} - -void __system_allocateHeaps() { - u32 tmp=0; - - __ctru_heap_size = __custom_heap_size; - __ctru_linear_heap_size = __custom_linear_heap_size; - - // Allocate the application heap - __ctru_heap = 0x08000000; - svcControlMemory(&tmp, __ctru_heap, 0x0, __ctru_heap_size, MEMOP_ALLOC, MEMPERM_READ | MEMPERM_WRITE); - - // Allocate the linear heap - svcControlMemory(&__ctru_linear_heap, 0x0, 0x0, __ctru_linear_heap_size, MEMOP_ALLOC_LINEAR, MEMPERM_READ | MEMPERM_WRITE); - // Set up newlib heap - fake_heap_start = (char*)__ctru_heap; - fake_heap_end = fake_heap_start + __ctru_heap_size; -} - -void __appInit(void) { - // Initialize services - srvInit(); - aptInit(); - hidInit(); - - fsInit(); - sdmcInit(); - - FSUSER_OpenArchive(&sdmcArchive, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, "")); - allocateRomBuffer(); } diff --git a/src/platform/3ds/main.c b/src/platform/3ds/main.c index db4f773f8..aef065b49 100644 --- a/src/platform/3ds/main.c +++ b/src/platform/3ds/main.c @@ -109,8 +109,6 @@ static bool sgbCrop = false; static aptHookCookie cookie; static bool core2; -extern bool allocateRomBuffer(void); - static bool _initGpu(void) { if (!C3D_Init(C3D_DEFAULT_CMDBUF_SIZE)) { return false; @@ -124,7 +122,7 @@ static bool _initGpu(void) { return false; } - if (!C3D_TexInitVRAM(&upscaleBufferTex, 512, 512, GPU_RB_RGB8)) { + if (!C3D_TexInitVRAM(&upscaleBufferTex, 512, 512, GPU_RGB8)) { return false; } upscaleBuffer = C3D_RenderTargetCreateFromTex(&upscaleBufferTex, GPU_TEXFACE_2D, 0, 0); @@ -810,10 +808,6 @@ int main() { camera.bufferSize = 0; camera.cam = SELECT_IN1; - if (!allocateRomBuffer()) { - return 1; - } - aptHook(&cookie, _aptHook, 0); ptmuInit(); diff --git a/src/platform/cmake/devkitPro.cmake b/src/platform/cmake/devkitPro.cmake index 23f20cc28..51cb3ad5b 100644 --- a/src/platform/cmake/devkitPro.cmake +++ b/src/platform/cmake/devkitPro.cmake @@ -8,24 +8,27 @@ set(CMAKE_SYSTEM_NAME Generic CACHE INTERNAL "system name") function(create_devkit DEVKIT) if(DEFINED ENV{DEVKIT${DEVKIT}}) - set(DEVKIT${DEVKIT} $ENV{DEVKIT${DEVKIT}} PARENT_SCOPE) + set(DEVKIT${DEVKIT} $ENV{DEVKIT${DEVKIT}}) else() - set(DEVKIT${DEVKIT} ${DEVKITPRO}/devkit${DEVKIT} PARENT_SCOPE) + set(DEVKIT${DEVKIT} ${DEVKITPRO}/devkit${DEVKIT}) endif() + set(DEVKIT${DEVKIT} "${DEVKIT${DEVKIT}}" PARENT_SCOPE) - set(CMAKE_PROGRAM_PATH ${DEVKIT${DEVKIT}}/bin CACHE INTERNAL "program path") + set(CMAKE_PROGRAM_PATH "${DEVKIT${DEVKIT}}/bin" CACHE INTERNAL "program path") + set(cross_prefix_path "${CMAKE_PROGRAM_PATH}/${cross_prefix}") + set(cross_prefix_path "${cross_prefix_path}" PARENT_SCOPE) set(extension) if (CMAKE_HOST_WIN32) set(extension .exe) endif() - find_program(CMAKE_AR ${cross_prefix}gcc-ar${extension}) - find_program(CMAKE_RANLIB ${cross_prefix}gcc-ranlib${extension}) - find_program(CMAKE_C_COMPILER ${cross_prefix}gcc${extension}) - find_program(CMAKE_CXX_COMPILER ${cross_prefix}g++${extension}) - find_program(CMAKE_ASM_COMPILER ${cross_prefix}gcc${extension}) - find_program(CMAKE_LINKER ${cross_prefix}ld${extension}) + set(CMAKE_AR "${cross_prefix_path}gcc-ar${extension}" CACHE INTERNAL "archiver") + set(CMAKE_RANLIB "${cross_prefix_path}gcc-ranlib${extension}" CACHE INTERNAL "archiver") + set(CMAKE_C_COMPILER "${cross_prefix_path}gcc${extension}" CACHE INTERNAL "c compiler") + set(CMAKE_CXX_COMPILER "${cross_prefix_path}g++${extension}" CACHE INTERNAL "cxx compiler") + set(CMAKE_ASM_COMPILER "${cross_prefix_path}gcc${extension}" CACHE INTERNAL "assembler") + set(CMAKE_LINKER "${cross_prefix_path}ld${extension}" CACHE INTERNAL "linker") set(CMAKE_C_FLAGS ${inc_flags} CACHE INTERNAL "c compiler flags") set(CMAKE_ASM_FLAGS ${inc_flags} CACHE INTERNAL "assembler flags") set(CMAKE_CXX_FLAGS ${inc_flags} CACHE INTERNAL "cxx compiler flags") @@ -38,4 +41,4 @@ function(create_devkit DEVKIT) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY CACHE INTERNAL "") set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY CACHE INTERNAL "") set(PKG_CONFIG_EXECUTABLE "/dev/null" CACHE INTERNAL "" FORCE) -endfunction() \ No newline at end of file +endfunction() diff --git a/src/platform/qt/CMakeLists.txt b/src/platform/qt/CMakeLists.txt index 7ae7bb693..11b5a12f4 100644 --- a/src/platform/qt/CMakeLists.txt +++ b/src/platform/qt/CMakeLists.txt @@ -292,7 +292,10 @@ endif() if(QT_STATIC) find_library(QTPCRE NAMES qtpcre2 qtpcre) if(WIN32) - list(APPEND QT_LIBRARIES qwindows dwmapi imm32 uxtheme Qt5EventDispatcherSupport Qt5FontDatabaseSupport Qt5ThemeSupport Qt5WindowsUIAutomationSupport) + if(CMAKE_CROSSCOMPILING) + set(QWINDOWS_DEPS Qt5EventDispatcherSupport Qt5FontDatabaseSupport Qt5ThemeSupport Qt5WindowsUIAutomationSupport) + endif() + list(APPEND QT_LIBRARIES Qt5::QWindowsIntegrationPlugin ${QWINDOWS_DEPS} dwmapi uxtheme imm32 -static-libgcc -static-libstdc++) set_target_properties(Qt5::Core PROPERTIES INTERFACE_LINK_LIBRARIES "${QTPCRE};version;winmm;ssl;crypto;ws2_32;iphlpapi;crypt32;userenv;netapi32;wtsapi32") set_target_properties(Qt5::Gui PROPERTIES INTERFACE_LINK_LIBRARIES ${OPENGL_LIBRARY} ${OPENGLES2_LIBRARY}) elseif(APPLE) diff --git a/src/platform/qt/ts/mgba-zh_CN.ts b/src/platform/qt/ts/mgba-zh_CN.ts index 487b171ef..031a1f643 100644 --- a/src/platform/qt/ts/mgba-zh_CN.ts +++ b/src/platform/qt/ts/mgba-zh_CN.ts @@ -26,7 +26,7 @@ {projectName} would like to thank the following patrons from Patreon: - {projectName} 感谢以下来自 Patreon 平台的赞助者: + {projectName} 感谢以下来自 Patreon 的赞助者: @@ -66,7 +66,7 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 Loading... - 载入中... + 正在载入... @@ -135,7 +135,7 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 Chip name - 晶片名称 + 芯片名称 @@ -165,7 +165,7 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 Gate type - 装置类型 + Gate 类型 @@ -180,7 +180,7 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 Beast &Link Gate - Beast Link(&L) + Beast Link Gate(&L) @@ -190,12 +190,12 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 Chip ID - 晶片ID + 芯片 ID Update Chip data - 更新晶片数据 + 更新芯片数据 @@ -306,29 +306,44 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 GIFView - Record GIF - 录制 GIF + Record GIF/APNG + 录制 GIF/APNG - - Frameskip - 跳帧 + + APNG + APNG - + Start 开始 - + Stop 停止 - + Select File 选择文件 + + + Frameskip + 跳帧 + + + + GIF + GIF + + + + Loop + 循环 + IOViewer @@ -885,148 +900,165 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 精灵图 - - Copy - 复制 - - - - Position - 位置 - - - - - - - 0 - 0 - - - - , - , - - - - Dimensions - 维度 - - - - - 8 - 8 - - - - - × - × - - - - Tile - 瓷贴 - - - - Export - 导出 - - - - Attributes - 属性 - - - - Transform - 变换 - - - - Off - - - - - Palette - 调色板 - - - - Double Size - 双倍大小 - - - - - - - Return, Ctrl+R - 回车键、Ctrl+R - - - - Flipped - 已翻转 - - - - H - 水平 - - - - V - 垂直 - - - - Mode - 模式 - - - - Normal - 普通 - - - - Mosaic - 马赛克 - - - - Enabled - 已启用 - - - - Priority - 优先级 - - - - Geometry - 几何图像 - - - + Address 地址 - - + + 0x07000000 0x07000000 - + + Copy + 复制 + + + + + × + × + + + Magnification 缩放率 + + + Geometry + 几何图 + + + + Position + 位置 + + + + + + + 0 + 0 + + + + , + , + + + + Dimensions + 维度 + + + + + 8 + 8 + + + + + +0.00 + +0.00 + + + + + +1.00 + +1.00 + + + + Matrix + 矩阵 + + + + Export + 导出 + + + + Attributes + 属性 + + + + Transform + 变换 + + + + Off + + + + + Palette + 调色板 + + + + Double Size + 双倍大小 + + + + + + + Return, Ctrl+R + 回车键、Ctrl+R + + + + Flipped + 已翻转 + + + + H + H + + + + V + V + + + + Mode + 模式 + + + + Normal + 普通 + + + + Mosaic + 马赛克 + + + + Enabled + 已启用 + + + + Priority + 优先级 + + + + Tile + 瓷贴 + OverrideView @@ -1122,7 +1154,7 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 Game Boy model - Game Boy 模型 + Game Boy 型号 @@ -1255,17 +1287,17 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 Red - 红色 + Green - 绿色 + 绿 Blue - 蓝色 + @@ -1277,7 +1309,7 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 16-bit value - 16 位数值 + 16 位值 @@ -1301,8 +1333,8 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 - 000 - 000 + 0x000 (000) + 0x000 (000) @@ -1430,7 +1462,7 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 BattleChip data is missing. BattleChip Gates will still work, but some graphics will be missing. Would you like to download the data now? - BattleChip 数据已丢失。您仍然可以使用 BattleChip Gate,但部分图形会丢失。您想立即下载数据吗? + BattleChip 数据已丢失。BattleChip Gate 仍然能够工作,但部分图形会丢失。您想立即下载数据吗? @@ -1446,7 +1478,7 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 The selected deck is not compatible with this Chip Gate - 所选卡组与本 Chip Gate 不兼容 + 所选卡组与此 Chip Gate 不兼容 @@ -1510,12 +1542,12 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 打开游戏文件失败: %1 - + Failed to open snapshot file for reading: %1 读取快照文件失败: %1 - + Failed to open snapshot file for writing: %1 写入快照文件失败: %1 @@ -1527,6 +1559,11 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 Failed to open game file: %1 打开游戏文件失败: %1 + + + Could not load game. Are you sure it's in the correct format? + 无法载入游戏。请确认游戏格式是否无误。 + QGBA::FrameView @@ -1599,7 +1636,7 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 Set all - 设置全部 + 全部设置 @@ -1642,25 +1679,25 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 Could not start GDB server - 无法打开 GDB 服务端 + 无法打开 GDB 服务器 QGBA::GIFView - + Failed to open output GIF file: %1 打开输出 GIF 文件失败: %1 - + Select output file 选择输出文件 - - Graphics Interchange Format (*.gif) - 图形交换格式 (*.gif) + + Graphics Interchange Format (*.gif);;Animated Portable Network Graphics (*.png *.apng)" + 图形交换格式 (*.gif);;动画便携式网络图形 (*.png *.apng)" @@ -2196,7 +2233,7 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 Sweep time (in 1/128s) - 扫描时间 (1/128秒) + 扫描时间 (1/128 秒) @@ -2968,32 +3005,32 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 Cart 0 non-sequential - Cart 0 (非顺序) + 卡带 0 (非顺序) Cart 0 sequential - Cart 0 (顺序) + 卡带 0 (顺序) Cart 1 non-sequential - Cart 1 (非顺序) + 卡带 1 (非顺序) Cart 1 sequential - Cart 1 (顺序) + 卡带 1 (顺序) Cart 2 non-sequential - Cart 2 (非顺序) + 卡带 2 (非顺序) Cart 2 sequential - Cart 2 (顺序) + 卡带 2 (顺序) @@ -3034,11 +3071,26 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 QGBA::KeyEditor - - + + --- --- + + + Super (L) + Super (L) + + + + Super (R) + Super (R) + + + + Menu + 菜单 + QGBA::LoadSaveState @@ -3309,22 +3361,22 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 QGBA::MemorySearch - + (%0/%1×) (%0/%1×) - + (⅟%0×) (⅟%0×) - + (%0×) (%0×) - + %1 byte%2 %1 字节%2 @@ -3332,49 +3384,61 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 QGBA::ObjView - - + + 0x%0 0x%0 - + Off - + + + + + + + + + --- + --- + + + Normal 一般 - + Trans 变换 - + OBJWIN OBJWIN - + Invalid 无效 - - + + N/A - + Export sprite 导出精灵图 - + Portable Network Graphics (*.png) 便携式网络图形 (*.png) @@ -3393,10 +3457,6 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 - %0 - %0 - - @@ -3525,7 +3585,7 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 No shader active - 无活动的着色器 + 无激活的着色器 @@ -3571,17 +3631,17 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 QGBA::VideoView - + Failed to open output video file: %1 打开输出视频文件失败: %1 - + Native (%0x%1) 原生 (%0x%1) - + Select output file 选择输出文件 @@ -3632,8 +3692,8 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 - + Select save 选择存档 @@ -3659,38 +3719,48 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 补丁 (*.ips *.ups *.bps) - + + Select e-Reader dotcode + 选择 e-Reader 点码 + + + + e-Reader card (*.raw *.bin *.bmp) + e-Reader 卡 (*.raw *.bin *.bmp) + + + Select image 选择图片 - + Image file (*.png *.gif *.jpg *.jpeg);;All files (*) 图像文件 (*.png *.gif *.jpg *.jpeg);;所有文件 (*) - + GameShark saves (*.sps *.xps) GameShark 存档 (*.sps *.xps) - + Select video log 选择视频日志 - + Video logs (*.mvl) 视频日志文件 (*.mvl) - + Crash 崩溃 - + The game has crashed with the following error: %1 @@ -3699,578 +3769,588 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 %1 - - Couldn't Load - 无法载入 + + Couldn't Start + 无法启动 - - Could not load game. Are you sure it's in the correct format? - 无法载入游戏。请确认游戏格式是否无误。 + + Could not start game. + 无法启动游戏。 - + Unimplemented BIOS call 未实现的 BIOS 调用 - + This game uses a BIOS call that is not implemented. Please use the official BIOS for best experience. - 该游戏使用了尚未实现的 BIOS 调用。请使用官方 BIOS 以获得最佳游戏体验。 + 此游戏使用了尚未实现的 BIOS 调用。请使用官方 BIOS 以获得最佳体验。 - + Really make portable? 确定进行程序便携化? - + This will make the emulator load its configuration from the same directory as the executable. Do you want to continue? - 进行此操作后,模拟器将从模拟器可执行文件所在目录内载入模拟器配置。您想继续吗? + 进行此操作后,模拟器将从其可执行文件所在目录中载入模拟器配置。您想继续吗? - + Restart needed 需要重新启动 - + Some changes will not take effect until the emulator is restarted. 更改将在模拟器下次启动时生效。 - + - Player %1 of %2 - 玩家 %1 共 %2 - + %1 - %2 %1 - %2 - + %1 - %2 - %3 %1 - %2 - %3 - + %1 - %2 (%3 fps) - %4 %1 - %2 (%3 fps) - %4 - + &File 文件(&F) - + Load &ROM... 载入 ROM(&R)... - + Load ROM in archive... 从压缩文件中载入 ROM... - + Add folder to library... 将文件夹添加到库中... - + Load alternate save... 载入其他存档... - + Load temporary save... 载入临时存档... - + Load &patch... - 载入补丁文件(&P)... + 载入补丁(&P)... - + Boot BIOS 引导 BIOS - + Replace ROM... 替换 ROM... - + + Scan e-Reader dotcodes... + 扫描 e-Reader 点码... + + + ROM &info... ROM 信息(&I)... - + Recent 最近打开 - + Make portable 程序便携化 - + &Load state 载入即时存档(&L) - + Load state file... 载入即时存档文件... - + &Save state 保存即时存档(&S) - + Save state file... 保存即时存档文件... - + Quick load 快速读档 - + Quick save 快速存档 - - - Load recent - 载入最近 - - - - Save recent - 保存最近 - + Load recent + 载入最近存档 + + + + Save recent + 保存最近存档 + + + Undo load state 撤消读档 - + Undo save state 撤消存档 - - + + State &%1 即时存档 1(&1) - + Load camera image... 载入相机图片... - + Import GameShark Save 导入 GameShark 存档 - + Export GameShark Save 导出 GameShark 存档 - + New multiplayer window 新建多人游戏窗口 - + About... 关于... - + E&xit 退出(&X) - + &Emulation 模拟(&E) - + &Reset 重置(&R) - + Sh&utdown 关机(&U) - + Yank game pak 快速抽出游戏卡带 - + &Pause 暂停(&P) - + &Next frame 下一帧(&N) - + Fast forward (held) 快进 (长按) - + &Fast forward 快进(&F) - + Fast forward speed 快进速度 - + Unbounded 不限制 - + %0x %0x - + Rewind (held) 倒带 (长按) - + Re&wind 倒带(&W) - + Step backwards 步退 - + Sync to &video 视频同步(&V) - + Sync to &audio 音频同步(&A) - + Solar sensor - 光线传感器 + 太阳光传感器 - + Increase solar level - 增加光线级别 + 增加太阳光等级 - + Decrease solar level - 降低光线级别 + 降低太阳光等级 - + Brightest solar level - 光线级别为最亮 + 太阳光等级为最亮 - + Darkest solar level - 光线级别为最暗 + 太阳光等级为最暗 - + Brightness %1 亮度 %1 - + Game Boy Printer... Game Boy 打印机... - + BattleChip Gate... BattleChip Gate... - + Audio/&Video 音频/视频(&V) - + Frame size 帧率 - + %1× %1× - + Toggle fullscreen 切换全屏 - + Lock aspect ratio 锁定纵横比 - + Force integer scaling 强制整数缩放 - + Interframe blending 帧间混合 - + Bilinear filtering 双线性过滤 - + Frame&skip 跳帧(&S) - + Mute 静音 - + FPS target 目标 FPS - + Native (59.7275) 原生 (59.7275) - + Take &screenshot 截图(&S) - + + F12 + F12 + + + Record A/V... 录制音频/视频... - + Record GIF... 录制 GIF... - + Video layers 视频图层 - + Audio channels 音频通道 - + Adjust layer placement... 调整图层布局... - + &Tools 工具(&T) - + View &logs... 查看日志(&L)... - + Game &overrides... 覆盖游戏(&O)... - + Game Pak sensors... 游戏卡带传感器... - + &Cheats... 作弊码(&C)... - + Settings... 设置... - + Open debugger console... 打开调试器控制台... - + Start &GDB server... 打开 GDB 服务器(&G)... - + View &palette... 查看调色板(&P)... - + View &sprites... 查看精灵图(&S)... - + View &tiles... 查看瓷贴(&T)... - + View &map... 查看映射(&M)... - + &Frame inspector... 框架检查(&F)... - + View memory... 查看内存... - + Search memory... 搜索内存... - + View &I/O registers... 查看 I/O 寄存器(&I)... - + Record debug video log... 记录调试视频日志... - + Stop debug video log 停止记录调试视频日志 - + Exit fullscreen 退出全屏 - + GameShark Button (held) GameShark 键 (长按) - + Autofire 连发 - + Autofire A 连发 A - + Autofire B 连发 B - + Autofire L 连发 L - + Autofire R 连发 R - + Autofire Start 连发 Start - + Autofire Select 连发 Select - + Autofire Up 连发 上 - + Autofire Right 连发 右 - + Autofire Down 连发 下 - + Autofire Left 连发 左 - + Clear 清除 @@ -4376,12 +4456,12 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 Start time at - 起始时间 + 开始时间 Now - 现在 + 立即 @@ -4476,7 +4556,7 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 Audio driver: - 音频驱动: + 音频驱动程序: @@ -4778,7 +4858,7 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 Run all - 运行全部 + 全部运行 @@ -4913,7 +4993,7 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 Same directory as the ROM - 保存在 ROM 所在目录 + 与 ROM 所在目录相同 @@ -4953,7 +5033,7 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 Game Boy model: - Game Boy 模型: + Game Boy 型号: @@ -4993,12 +5073,12 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 Super Game Boy model: - Super Game Boy 模型: + Super Game Boy 型号: Game Boy Color model: - Game Boy Color 模型: + Game Boy Color 型号: @@ -5013,7 +5093,7 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 Camera driver: - 相机驱动: + 相机驱动程序: @@ -5046,7 +5126,7 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 Active Shader: - 活动着色器: + 激活着色器: @@ -5112,7 +5192,7 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 Export All - 导出全部 + 全部导出 @@ -5147,7 +5227,7 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 Copy All - 复制全部 + 全部复制 @@ -5195,151 +5275,172 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 - &Lossless - 无损(&L) - - - - &1080p - 1080p(&1) - - - - &720p - 720p(&7) - - - - &480p - 480p(&4) - - - - &Native - 原生(&N) - - - - Format - 格式 - - - - MKV - MKV - - - - AVI - AVI - - - MP4 MP4 - + + &Lossless + 无损(&L) + + + + 4K + 4K + + + + &1080p + 1080p(&1) + + + + &720p + 720p(&7) + + + + &480p + 480p(&4) + + + + &Native + 原生(&N) + + + + Format + 格式 + + + + MKV + MKV + + + + WebM + WebM + + + + AVI + AVI + + + + MP4 + MP4 + + + h.264 h.264 - + h.264 (NVENC) h.264 (NVENC) - + HEVC HEVC - + HEVC (NVENC) HEVC (NVENC) - + VP8 VP8 - + VP9 VP9 - + FFV1 FFV1 - + + + None + + + + FLAC FLAC - + Opus Opus - + Vorbis Vorbis - + MP3 MP3 - + AAC AAC - + Uncompressed 未压缩 - + Bitrate (kbps) 比特率 (kbps) - - VBR + + VBR VBR - + ABR ABR - + Dimensions 维度 - + : : - + × × - + Lock aspect ratio 锁定纵横比 - + Show advanced 显示高级选项 diff --git a/src/platform/test/perf-main.c b/src/platform/test/perf-main.c index 86262c5e2..bbf008c9e 100644 --- a/src/platform/test/perf-main.c +++ b/src/platform/test/perf-main.c @@ -58,10 +58,6 @@ struct PerfOpts { bool server; }; -#ifdef _3DS -extern bool allocateRomBuffer(void); -FS_Archive sdmcArchive; -#endif #ifdef __SWITCH__ TimeType __nx_time_type = TimeType_LocalSystemClock; #endif @@ -85,9 +81,6 @@ int main(int argc, char** argv) { gfxInitDefault(); osSetSpeedupEnable(true); consoleInit(GFX_BOTTOM, NULL); - if (!allocateRomBuffer()) { - return 1; - } #elif defined(__SWITCH__) UNUSED(_mPerfShutdown); consoleInit(NULL); diff --git a/src/sm83/debugger/cli-debugger.c b/src/sm83/debugger/cli-debugger.c index c227d845e..1c3d2a473 100644 --- a/src/sm83/debugger/cli-debugger.c +++ b/src/sm83/debugger/cli-debugger.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -88,6 +89,7 @@ static void _printStatus(struct CLIDebuggerSystem* debugger) { be->printf(be, "H: %02X L: %02X (HL: %04X)\n", cpu->h, cpu->l, cpu->hl); be->printf(be, "PC: %04X SP: %04X\n", cpu->pc, cpu->sp); _printFlags(be, cpu->f); + be->printf(be, "T-cycle: %" PRIu64 "\n", mTimingGlobalTime(debugger->p->d.core->timing)); struct SM83Debugger* platDebugger = (struct SM83Debugger*) debugger->p->d.platform; size_t i;