diff --git a/CHANGES b/CHANGES index 9415d4864..c22e64180 100644 --- a/CHANGES +++ b/CHANGES @@ -32,6 +32,7 @@ Features: - e-Reader card scanning - Add WebP and APNG recording - Support for unlicensed Pokemon Jade/Diamond Game Boy mapper + - Stack tracing tools in ARM debugger (by ahigerd) Emulation fixes: - ARM: Fix ALU reading PC after shifting - ARM: Fix STR storing PC after address calculation @@ -52,12 +53,14 @@ Emulation fixes: - GBA DMA: Linger last DMA on bus (fixes mgba.io/i/301 and mgba.io/i/1320) - GBA Memory: Improve gamepak prefetch timing - GBA Memory: Stall on VRAM access in mode 2 (fixes mgba.io/i/190) + - GBA Savedata: Fix potential corruption when loading a 1Mbit flash save - GBA SIO: Fix copying Normal mode transfer values - GBA Video: Latch scanline at end of Hblank (fixes mgba.io/i/1319) - GBA Video: Fix Hblank timing - GBA Video: Fix invalid read in mode 4 mosaic - GBA Video: Fix color of disabled screen - SM83: Emulate HALT bug + - SM83: Fix flags on little endian PowerPC Other fixes: - All: Improve export headers (fixes mgba.io/i/1738) - All: Correct format strings for some numbers on Windows (fixes mgba.io/i/1794) @@ -77,6 +80,7 @@ Other fixes: - Qt: Fix Italian RTC translation (fixes mgba.io/i/1798) - Qt: Add missing option for Wisdom Tree in overrides list - Util: Fix crash if PNG header fails to write + - SM83: Simplify register pair access on big endian Misc: - Debugger: Keep track of global cycle count - FFmpeg: Add looping option for GIF/APNG diff --git a/CMakeLists.txt b/CMakeLists.txt index 85273c5d0..617bc7a7f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,7 @@ if(NOT MSVC) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-format") endif() else() - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_CRT_SECURE_NO_WARNINGS /wd4003 /wd4244 /wd4146") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_CRT_SECURE_NO_WARNINGS /wd4003 /wd4244 /wd4146 /wd4267") endif() if(NOT DEFINED LIBMGBA_ONLY) diff --git a/include/mgba/debugger/debugger.h b/include/mgba/debugger/debugger.h index 2a4bc2dce..f3404c02b 100644 --- a/include/mgba/debugger/debugger.h +++ b/include/mgba/debugger/debugger.h @@ -13,6 +13,7 @@ CXX_GUARD_START #include #include #include +#include mLOG_DECLARE_CATEGORY(DEBUGGER); @@ -50,7 +51,8 @@ enum mDebuggerEntryReason { DEBUGGER_ENTER_ATTACHED, DEBUGGER_ENTER_BREAKPOINT, DEBUGGER_ENTER_WATCHPOINT, - DEBUGGER_ENTER_ILLEGAL_OP + DEBUGGER_ENTER_ILLEGAL_OP, + DEBUGGER_ENTER_STACK }; struct mDebuggerEntryInfo { @@ -67,6 +69,10 @@ struct mDebuggerEntryInfo { uint32_t opcode; enum mBreakpointType breakType; } bp; + + struct { + enum mStackTraceMode traceType; + } st; } type; ssize_t pointId; }; @@ -114,6 +120,10 @@ struct mDebuggerPlatform { bool (*getRegister)(struct mDebuggerPlatform*, const char* name, int32_t* value); bool (*setRegister)(struct mDebuggerPlatform*, const char* name, int32_t value); bool (*lookupIdentifier)(struct mDebuggerPlatform*, const char* name, int32_t* value, int* segment); + + uint32_t (*getStackTraceMode)(struct mDebuggerPlatform*); + void (*setStackTraceMode)(struct mDebuggerPlatform*, uint32_t mode); + bool (*updateStackTrace)(struct mDebuggerPlatform* d); }; struct mDebugger { @@ -123,6 +133,7 @@ struct mDebugger { enum mDebuggerType type; struct mCore* core; struct mScriptBridge* bridge; + struct mStackTrace stackTrace; void (*init)(struct mDebugger*); void (*deinit)(struct mDebugger*); diff --git a/include/mgba/internal/arm/arm.h b/include/mgba/internal/arm/arm.h index 61bd8b0c9..164218e9f 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(__BIG_ENDIAN__) +#ifdef __BIG_ENDIAN__ unsigned n : 1; unsigned z : 1; unsigned c : 1; @@ -96,7 +96,7 @@ union PSR { }; struct { -#if defined(__BIG_ENDIAN__) +#ifdef __BIG_ENDIAN__ uint8_t flags; uint8_t status; uint8_t extension; @@ -231,10 +231,21 @@ struct ARMCP15 { } r9; }; +#define ARM_REGISTER_FILE struct { \ + int32_t gprs[16]; \ + union PSR cpsr; \ + union PSR spsr; \ +} + +struct ARMRegisterFile { + ARM_REGISTER_FILE; +}; + struct ARMCore { - int32_t gprs[16]; - union PSR cpsr; - union PSR spsr; + union { + struct ARMRegisterFile regs; + ARM_REGISTER_FILE; + }; int32_t cycles; int32_t nextEvent; @@ -259,6 +270,7 @@ struct ARMCore { size_t numComponents; struct mCPUComponent** components; }; +#undef ARM_REGISTER_FILE void ARMInit(struct ARMCore* cpu); void ARMDeinit(struct ARMCore* cpu); diff --git a/include/mgba/internal/arm/debugger/debugger.h b/include/mgba/internal/arm/debugger/debugger.h index 5dc73485c..e3615049c 100644 --- a/include/mgba/internal/arm/debugger/debugger.h +++ b/include/mgba/internal/arm/debugger/debugger.h @@ -36,6 +36,7 @@ struct ARMDebugger { struct ARMMemory originalMemory; ssize_t nextId; + uint32_t stackTraceMode; void (*entered)(struct mDebugger*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*); diff --git a/include/mgba/internal/arm/decoder.h b/include/mgba/internal/arm/decoder.h index 3c697151f..8e245f8c7 100644 --- a/include/mgba/internal/arm/decoder.h +++ b/include/mgba/internal/arm/decoder.h @@ -14,7 +14,7 @@ CXX_GUARD_START // Bit 0: a register is involved with this operand // Bit 1: an immediate is invovled with this operand -// Bit 2: a memory access is invovled with this operand +// Bit 2: a memory access is involved with this operand // Bit 3: the destination of this operand is affected by this opcode // Bit 4: this operand is shifted by a register // Bit 5: this operand is shifted by an immediate diff --git a/include/mgba/internal/arm/isa-inlines.h b/include/mgba/internal/arm/isa-inlines.h index 6bb825c91..0cabcfee2 100644 --- a/include/mgba/internal/arm/isa-inlines.h +++ b/include/mgba/internal/arm/isa-inlines.h @@ -99,15 +99,12 @@ static inline void _ARMReadCPSR(struct ARMCore* cpu) { cpu->irqh.readCPSR(cpu); } +static inline uint32_t _ARMInstructionLength(struct ARMCore* cpu) { + return cpu->cpsr.t == MODE_ARM ? WORD_SIZE_ARM : WORD_SIZE_THUMB; +} + static inline uint32_t _ARMPCAddress(struct ARMCore* cpu) { - int instructionLength; - enum ExecutionMode mode = cpu->cpsr.t; - if (mode == MODE_ARM) { - instructionLength = WORD_SIZE_ARM; - } else { - instructionLength = WORD_SIZE_THUMB; - } - return cpu->gprs[ARM_PC] - instructionLength * 2; + return cpu->gprs[ARM_PC] - _ARMInstructionLength(cpu) * 2; } #endif diff --git a/include/mgba/internal/debugger/stack-trace.h b/include/mgba/internal/debugger/stack-trace.h new file mode 100644 index 000000000..443faa64c --- /dev/null +++ b/include/mgba/internal/debugger/stack-trace.h @@ -0,0 +1,56 @@ +/* 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 STACK_TRACE_H +#define STACK_TRACE_H + +#include + +CXX_GUARD_START + +#include +#include +#include + +enum mStackTraceMode { + STACK_TRACE_DISABLED = 0, + STACK_TRACE_ENABLED = 1, + STACK_TRACE_BREAK_ON_RETURN = 2, + STACK_TRACE_BREAK_ON_CALL = 4, + STACK_TRACE_BREAK_ON_BOTH = STACK_TRACE_BREAK_ON_RETURN | STACK_TRACE_BREAK_ON_CALL +}; + +struct mStackFrame { + uint32_t callAddress; + uint32_t entryAddress; + uint32_t frameBaseAddress; + void* regs; + bool finished; + bool breakWhenFinished; + bool interrupt; +}; + +DECLARE_VECTOR(mStackFrames, struct mStackFrame); + +struct mStackTrace { + struct mStackFrames stack; + size_t registersSize; + + void (*formatRegisters)(struct mStackFrame* frame, char* out, size_t* length); +}; + +void mStackTraceInit(struct mStackTrace* stack, size_t registersSize); +void mStackTraceDeinit(struct mStackTrace* stack); + +void mStackTraceClear(struct mStackTrace* stack); +size_t mStackTraceGetDepth(struct mStackTrace* stack); +struct mStackFrame* mStackTracePush(struct mStackTrace* stack, uint32_t pc, uint32_t destAddress, uint32_t sp, void* regs); +struct mStackFrame* mStackTraceGetFrame(struct mStackTrace* stack, uint32_t frame); +void mStackTraceFormatFrame(struct mStackTrace* stack, uint32_t frame, char* out, size_t* length); +void mStackTracePop(struct mStackTrace* stack); + +CXX_GUARD_END + +#endif diff --git a/include/mgba/internal/sm83/sm83.h b/include/mgba/internal/sm83/sm83.h index 3e36e4e26..10bbf8bc4 100644 --- a/include/mgba/internal/sm83/sm83.h +++ b/include/mgba/internal/sm83/sm83.h @@ -18,7 +18,7 @@ struct SM83Core; #pragma pack(push, 1) union FlagRegister { struct { -#if defined(__POWERPC__) || defined(__PPC__) +#ifdef __BIG_ENDIAN__ unsigned z : 1; unsigned n : 1; unsigned h : 1; @@ -74,39 +74,62 @@ struct SM83InterruptHandler { void (*hitIllegal)(struct SM83Core* cpu); }; +#ifdef __BIG_ENDIAN__ +#define SM83_REGISTER_PAIR(HIGH, LOW) union { \ + struct { \ + uint8_t HIGH; \ + uint8_t LOW; \ + }; \ + uint16_t HIGH ## LOW; \ + } + +#define SM83_AF_REGISTER union { \ + struct { \ + uint8_t a; \ + union FlagRegister f; \ + }; \ + uint16_t af; \ + } +#else +#define SM83_REGISTER_PAIR(HIGH, LOW) union { \ + struct { \ + uint8_t LOW; \ + uint8_t HIGH; \ + }; \ + uint16_t HIGH ## LOW; \ + } + +#define SM83_AF_REGISTER union { \ + struct { \ + union FlagRegister f; \ + uint8_t a; \ + }; \ + uint16_t af; \ + } +#endif + +#define SM83_REGISTER_FILE struct { \ + SM83_AF_REGISTER; \ + SM83_REGISTER_PAIR(b, c); \ + SM83_REGISTER_PAIR(d, e); \ + SM83_REGISTER_PAIR(h, l); \ + uint16_t sp; \ + uint16_t pc; \ +} + +struct SM83RegisterFile { +#pragma pack(push, 1) + SM83_REGISTER_FILE; +#pragma pack(pop) +}; + struct SM83Core { #pragma pack(push, 1) union { - struct { - union FlagRegister f; - uint8_t a; - }; - uint16_t af; + struct SM83RegisterFile regs; + SM83_REGISTER_FILE; }; #pragma pack(pop) - union { - struct { - uint8_t c; - uint8_t b; - }; - uint16_t bc; - }; - union { - struct { - uint8_t e; - uint8_t d; - }; - uint16_t de; - }; - union { - struct { - uint8_t l; - uint8_t h; - }; - uint16_t hl; - }; - uint16_t sp; - uint16_t pc; uint16_t index; @@ -129,6 +152,7 @@ struct SM83Core { size_t numComponents; struct mCPUComponent** components; }; +#undef SM83_REGISTER_FILE void SM83Init(struct SM83Core* cpu); void SM83Deinit(struct SM83Core* cpu); diff --git a/src/arm/debugger/debugger.c b/src/arm/debugger/debugger.c index 7449ece33..eff4bd91d 100644 --- a/src/arm/debugger/debugger.c +++ b/src/arm/debugger/debugger.c @@ -11,9 +11,102 @@ #include #include #include +#include +#include DEFINE_VECTOR(ARMDebugBreakpointList, struct ARMDebugBreakpoint); +static bool ARMDebuggerUpdateStackTraceInternal(struct mDebuggerPlatform* d, uint32_t pc) { + struct ARMDebugger* debugger = (struct ARMDebugger*) d; + struct ARMCore* cpu = debugger->cpu; + struct ARMInstructionInfo info; + uint32_t instruction = cpu->prefetch[0]; + struct mStackTrace* stack = &d->p->stackTrace; + bool interrupt = false; + ARMDecodeARM(instruction, &info); + + if (_ARMModeHasSPSR(cpu->cpsr.priv)) { + struct mStackFrame* irqFrame = mStackTraceGetFrame(stack, 0); + uint32_t ivtBase = ARMControlRegIsVE(cpu->cp15.r1.c0) ? 0xFFFF0000 : 0x00000000; + if (ivtBase <= pc && pc < ivtBase + 0x20 && !(irqFrame && _ARMModeHasSPSR(((struct ARMRegisterFile*) irqFrame->regs)->cpsr.priv))) { + // TODO: Potential enhancement opportunity: add break-on-exception mode + irqFrame = mStackTracePush(stack, pc, pc, cpu->gprs[ARM_SP], &cpu->regs); + irqFrame->interrupt = true; + interrupt = true; + } + } + + if (info.branchType == ARM_BRANCH_NONE && !interrupt) { + return false; + } + + struct mStackFrame* frame = mStackTraceGetFrame(stack, 0); + bool isCall = (info.branchType & ARM_BRANCH_LINKED); + uint32_t destAddress; + + if (frame && frame->finished) { + mStackTracePop(stack); + frame = NULL; + } + + if (interrupt && info.branchType == ARM_BRANCH_NONE) { + // The stack frame was already pushed up above, so there's no + // action necessary here, but we still want to check for a + // breakpoint down below. + // + // The first instruction could possibly be a call, which would + // need ANOTHER stack frame, so only skip if it's not. + } else if (info.operandFormat & ARM_OPERAND_MEMORY_1) { + // This is most likely ldmia ..., {..., pc}, which is a function return. + // To find which stack slot holds the return address, count the number of set bits. + int regCount = popcount32(info.op1.immediate); + uint32_t baseAddress = cpu->gprs[info.memory.baseReg] + ((regCount - 1) << 2); + destAddress = cpu->memory.load32(cpu, baseAddress, NULL); + } else if (info.operandFormat & ARM_OPERAND_IMMEDIATE_1) { + if (!isCall) { + return false; + } + destAddress = info.op1.immediate + cpu->gprs[ARM_PC]; + } else if (info.operandFormat & ARM_OPERAND_REGISTER_1) { + if (!isCall && info.op1.reg != ARM_LR && !(_ARMModeHasSPSR(cpu->cpsr.priv) && info.op1.reg == ARM_PC)) { + return false; + } + destAddress = cpu->gprs[info.op1.reg]; + } else { + mLOG(DEBUGGER, ERROR, "Unknown branch operand in stack trace"); + return false; + } + + if (info.branchType & ARM_BRANCH_INDIRECT) { + destAddress = cpu->memory.load32(cpu, destAddress, NULL); + } + + if (isCall) { + int instructionLength = _ARMInstructionLength(debugger->cpu); + frame = mStackTracePush(stack, pc, destAddress + instructionLength, cpu->gprs[ARM_SP], &cpu->regs); + if (!(debugger->stackTraceMode & STACK_TRACE_BREAK_ON_CALL)) { + return false; + } + } else { + frame = mStackTraceGetFrame(stack, 0); + if (!frame) { + return false; + } + if (!frame->breakWhenFinished && !(debugger->stackTraceMode & STACK_TRACE_BREAK_ON_RETURN)) { + mStackTracePop(stack); + return false; + } + frame->finished = true; + } + struct mDebuggerEntryInfo debuggerInfo = { + .address = pc, + .type.st.traceType = isCall ? STACK_TRACE_BREAK_ON_CALL : STACK_TRACE_BREAK_ON_RETURN, + .pointId = 0 + }; + mDebuggerEnter(d->p, DEBUGGER_ENTER_STACK, &debuggerInfo); + return true; +} + static struct ARMDebugBreakpoint* _lookupBreakpoint(struct ARMDebugBreakpointList* breakpoints, uint32_t address) { size_t i; for (i = 0; i < ARMDebugBreakpointListSize(breakpoints); ++i) { @@ -40,14 +133,12 @@ static void _destroyWatchpoint(struct mWatchpoint* watchpoint) { static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform* d) { struct ARMDebugger* debugger = (struct ARMDebugger*) d; - int instructionLength; - enum ExecutionMode mode = debugger->cpu->cpsr.t; - if (mode == MODE_ARM) { - instructionLength = WORD_SIZE_ARM; - } else { - instructionLength = WORD_SIZE_THUMB; + int instructionLength = _ARMInstructionLength(debugger->cpu); + uint32_t pc = debugger->cpu->gprs[ARM_PC] - instructionLength; + if (debugger->stackTraceMode != STACK_TRACE_DISABLED && ARMDebuggerUpdateStackTraceInternal(d, pc)) { + return; } - struct ARMDebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->breakpoints, debugger->cpu->gprs[ARM_PC] - instructionLength); + struct ARMDebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->breakpoints, pc); if (!breakpoint) { return; } @@ -79,8 +170,13 @@ static void ARMDebuggerListWatchpoints(struct mDebuggerPlatform*, struct mWatchp static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform*); static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform*); static void ARMDebuggerTrace(struct mDebuggerPlatform*, char* out, size_t* length); +static void ARMDebuggerFormatRegisters(struct ARMRegisterFile* regs, char* out, size_t* length); +static void ARMDebuggerFrameFormatRegisters(struct mStackFrame* frame, char* out, size_t* length); static bool ARMDebuggerGetRegister(struct mDebuggerPlatform*, const char* name, int32_t* value); static bool ARMDebuggerSetRegister(struct mDebuggerPlatform*, const char* name, int32_t value); +static uint32_t ARMDebuggerGetStackTraceMode(struct mDebuggerPlatform*); +static void ARMDebuggerSetStackTraceMode(struct mDebuggerPlatform*, uint32_t); +static bool ARMDebuggerUpdateStackTrace(struct mDebuggerPlatform* d); struct mDebuggerPlatform* ARMDebuggerPlatformCreate(void) { struct mDebuggerPlatform* platform = (struct mDebuggerPlatform*) malloc(sizeof(struct ARMDebugger)); @@ -97,6 +193,9 @@ struct mDebuggerPlatform* ARMDebuggerPlatformCreate(void) { platform->trace = ARMDebuggerTrace; platform->getRegister = ARMDebuggerGetRegister; platform->setRegister = ARMDebuggerSetRegister; + platform->getStackTraceMode = ARMDebuggerGetStackTraceMode; + platform->setStackTraceMode = ARMDebuggerSetStackTraceMode; + platform->updateStackTrace = ARMDebuggerUpdateStackTrace; return platform; } @@ -105,9 +204,13 @@ void ARMDebuggerInit(void* cpu, struct mDebuggerPlatform* platform) { debugger->cpu = cpu; debugger->originalMemory = debugger->cpu->memory; debugger->nextId = 1; + debugger->stackTraceMode = STACK_TRACE_DISABLED; ARMDebugBreakpointListInit(&debugger->breakpoints, 0); ARMDebugBreakpointListInit(&debugger->swBreakpoints, 0); mWatchpointListInit(&debugger->watchpoints, 0); + struct mStackTrace* stack = &platform->p->stackTrace; + mStackTraceInit(stack, sizeof(struct ARMRegisterFile)); + stack->formatRegisters = ARMDebuggerFrameFormatRegisters; } void ARMDebuggerDeinit(struct mDebuggerPlatform* platform) { @@ -133,6 +236,7 @@ void ARMDebuggerDeinit(struct mDebuggerPlatform* platform) { } ARMDebugBreakpointListDeinit(&debugger->swBreakpoints); mWatchpointListDeinit(&debugger->watchpoints); + mStackTraceDeinit(&platform->p->stackTrace); } static void ARMDebuggerEnter(struct mDebuggerPlatform* platform, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) { @@ -261,7 +365,7 @@ static void ARMDebuggerListBreakpoints(struct mDebuggerPlatform* d, struct mBrea ++i; } else if (sw) { *b = sw->d; - ++s; + ++s; } else { abort(); // Should be unreachable } @@ -270,7 +374,7 @@ static void ARMDebuggerListBreakpoints(struct mDebuggerPlatform* d, struct mBrea static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform* d) { struct ARMDebugger* debugger = (struct ARMDebugger*) d; - return ARMDebugBreakpointListSize(&debugger->breakpoints) || mWatchpointListSize(&debugger->watchpoints); + return ARMDebugBreakpointListSize(&debugger->breakpoints) || mWatchpointListSize(&debugger->watchpoints) || debugger->stackTraceMode != STACK_TRACE_DISABLED; } static ssize_t ARMDebuggerSetWatchpoint(struct mDebuggerPlatform* d, const struct mWatchpoint* info) { @@ -320,12 +424,23 @@ static void ARMDebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* len } } - *length = snprintf(out, *length, "%08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X cpsr: %08X | %s", - cpu->gprs[0], cpu->gprs[1], cpu->gprs[2], cpu->gprs[3], - cpu->gprs[4], cpu->gprs[5], cpu->gprs[6], cpu->gprs[7], - cpu->gprs[8], cpu->gprs[9], cpu->gprs[10], cpu->gprs[11], - cpu->gprs[12], cpu->gprs[13], cpu->gprs[14], cpu->gprs[15], - cpu->cpsr.packed, disassembly); + size_t regStringLen = *length; + ARMDebuggerFormatRegisters(&cpu->regs, out, ®StringLen); + regStringLen += snprintf(out + regStringLen, *length - regStringLen, " | %s", disassembly); + *length = regStringLen; +} + +static void ARMDebuggerFormatRegisters(struct ARMRegisterFile* regs, char* out, size_t* length) { + *length = snprintf(out, *length, "%08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X cpsr: %08X", + regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3], + regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7], + regs->gprs[8], regs->gprs[9], regs->gprs[10], regs->gprs[11], + regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15], + regs->cpsr.packed); +} + +static void ARMDebuggerFrameFormatRegisters(struct mStackFrame* frame, char* out, size_t* length) { + ARMDebuggerFormatRegisters(frame->regs, out, length); } bool ARMDebuggerGetRegister(struct mDebuggerPlatform* d, const char* name, int32_t* value) { @@ -403,3 +518,28 @@ bool ARMDebuggerSetRegister(struct mDebuggerPlatform* d, const char* name, int32 } return false; } + +static uint32_t ARMDebuggerGetStackTraceMode(struct mDebuggerPlatform* d) { + struct ARMDebugger* debugger = (struct ARMDebugger*) d; + return debugger->stackTraceMode; +} + +static void ARMDebuggerSetStackTraceMode(struct mDebuggerPlatform* d, uint32_t mode) { + struct ARMDebugger* debugger = (struct ARMDebugger*) d; + struct mStackTrace* stack = &d->p->stackTrace; + if (mode == STACK_TRACE_DISABLED && debugger->stackTraceMode != STACK_TRACE_DISABLED) { + mStackTraceClear(stack); + } + debugger->stackTraceMode = mode; +} + +static bool ARMDebuggerUpdateStackTrace(struct mDebuggerPlatform* d) { + struct ARMDebugger* debugger = (struct ARMDebugger*) d; + int instructionLength = _ARMInstructionLength(debugger->cpu); + uint32_t pc = debugger->cpu->gprs[ARM_PC] - instructionLength; + if (debugger->stackTraceMode != STACK_TRACE_DISABLED) { + return ARMDebuggerUpdateStackTraceInternal(d, pc); + } else { + return false; + } +} diff --git a/src/arm/isa-thumb.c b/src/arm/isa-thumb.c index 0d5caac15..ccd601e10 100644 --- a/src/arm/isa-thumb.c +++ b/src/arm/isa-thumb.c @@ -26,7 +26,6 @@ cpu->cpsr.v = ARM_V_SUBTRACTION(M, N, D); #define THUMB_SUBTRACTION_CARRY_S(M, N, D, C) \ - cpu->cpsr.flags = 0; \ cpu->cpsr.n = ARM_SIGN(D); \ cpu->cpsr.z = !(D); \ cpu->cpsr.c = ARM_BORROW_FROM_CARRY(M, N, D, C); \ diff --git a/src/debugger/CMakeLists.txt b/src/debugger/CMakeLists.txt index b555caf7d..a5c40eb31 100644 --- a/src/debugger/CMakeLists.txt +++ b/src/debugger/CMakeLists.txt @@ -3,7 +3,8 @@ set(SOURCE_FILES cli-debugger.c debugger.c parser.c - symbols.c) + symbols.c + stack-trace.c) set(TEST_FILES test/lexer.c @@ -13,4 +14,4 @@ source_group("Debugger" FILES ${SOURCE_FILES}) source_group("Debugger tests" FILES ${TEST_FILES}) export_directory(DEBUGGER SOURCE_FILES) -export_directory(DEBUGGER_TEST TEST_FILES) \ No newline at end of file +export_directory(DEBUGGER_TEST TEST_FILES) diff --git a/src/debugger/cli-debugger.c b/src/debugger/cli-debugger.c index ddac46952..178457c40 100644 --- a/src/debugger/cli-debugger.c +++ b/src/debugger/cli-debugger.c @@ -69,12 +69,17 @@ static void _dumpWord(struct CLIDebugger*, struct CLIDebugVector*); #ifdef ENABLE_SCRIPTING static void _source(struct CLIDebugger*, struct CLIDebugVector*); #endif +static void _backtrace(struct CLIDebugger*, struct CLIDebugVector*); +static void _finish(struct CLIDebugger*, struct CLIDebugVector*); +static void _setStackTraceMode(struct CLIDebugger*, struct CLIDebugVector*); static struct CLIDebuggerCommandSummary _debuggerCommands[] = { + { "backtrace", _backtrace, "i", "Print backtrace of all or specified frames" }, { "break", _setBreakpoint, "Is", "Set a breakpoint" }, { "continue", _continue, "", "Continue execution" }, { "delete", _clearBreakpoint, "I", "Delete a breakpoint or watchpoint" }, { "disassemble", _disassemble, "Ii", "Disassemble instructions" }, + { "finish", _finish, "", "Execute until current stack frame returns" }, { "help", _printHelp, "S", "Print help" }, { "listb", _listBreakpoints, "", "List breakpoints" }, { "listw", _listWatchpoints, "", "List watchpoints" }, @@ -87,6 +92,7 @@ static struct CLIDebuggerCommandSummary _debuggerCommands[] = { { "r/1", _readByte, "I", "Read a byte from a specified offset" }, { "r/2", _readHalfword, "I", "Read a halfword from a specified offset" }, { "r/4", _readWord, "I", "Read a word from a specified offset" }, + { "stack", _setStackTraceMode, "S", "Changes the stack tracing mode" }, { "status", _printStatus, "", "Print the current status" }, { "trace", _trace, "Is", "Trace a number of instructions" }, { "w/1", _writeByte, "II", "Write a byte at a specified offset" }, @@ -111,6 +117,7 @@ static struct CLIDebuggerCommandSummary _debuggerCommands[] = { static struct CLIDebuggerCommandAlias _debuggerCommandAliases[] = { { "b", "break" }, + { "bt", "backtrace" }, { "c", "continue" }, { "d", "delete" }, { "dis", "disassemble" }, @@ -153,6 +160,18 @@ static void _breakInto(struct CLIDebugger* debugger, struct CLIDebugVector* dv) } #endif +static bool CLIDebuggerCheckTraceMode(struct CLIDebugger* debugger, bool requireEnabled) { + struct mDebuggerPlatform* platform = debugger->d.platform; + if (!platform->getStackTraceMode) { + debugger->backend->printf(debugger->backend, "Stack tracing is not supported by this platform.\n"); + return false; + } else if (requireEnabled && platform->getStackTraceMode(platform) == STACK_TRACE_DISABLED) { + debugger->backend->printf(debugger->backend, "Stack tracing is not enabled.\n"); + return false; + } + return true; +} + static void _continue(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { UNUSED(dv); debugger->d.state = debugger->traceRemaining != 0 ? DEBUGGER_CALLBACK : DEBUGGER_RUNNING; @@ -160,7 +179,11 @@ static void _continue(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { static void _next(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { UNUSED(dv); + struct mDebuggerPlatform* platform = debugger->d.platform; debugger->d.core->step(debugger->d.core); + if (platform->getStackTraceMode && platform->getStackTraceMode(platform) != STACK_TRACE_DISABLED) { + platform->updateStackTrace(platform); + } _printStatus(debugger, 0); } @@ -327,6 +350,7 @@ static void _readByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { static void _reset(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { UNUSED(dv); + mStackTraceClear(&debugger->d.stackTrace); debugger->d.core->reset(debugger->d.core); _printStatus(debugger, 0); } @@ -979,7 +1003,7 @@ static void _reportEntry(struct mDebugger* debugger, enum mDebuggerEntryReason r if (info->pointId > 0) { cliDebugger->backend->printf(cliDebugger->backend, "Hit breakpoint %" PRIz "i at 0x%08X\n", info->pointId, info->address); } else { - cliDebugger->backend->printf(cliDebugger->backend, "Hit unknown breakpoint at 0x%08X\n", info->address); + cliDebugger->backend->printf(cliDebugger->backend, "Hit unknown breakpoint at 0x%08X\n", info->address); } } else { cliDebugger->backend->printf(cliDebugger->backend, "Hit breakpoint\n"); @@ -1003,6 +1027,18 @@ static void _reportEntry(struct mDebugger* debugger, enum mDebuggerEntryReason r cliDebugger->backend->printf(cliDebugger->backend, "Hit illegal opcode\n"); } break; + case DEBUGGER_ENTER_STACK: + if (info) { + if (info->type.st.traceType == STACK_TRACE_BREAK_ON_CALL) { + cliDebugger->backend->printf(cliDebugger->backend, "Hit function call at at 0x%08X\n", info->address); + } else { + cliDebugger->backend->printf(cliDebugger->backend, "Hit function return at at 0x%08X\n", info->address); + } + } else { + cliDebugger->backend->printf(cliDebugger->backend, "Hit function call or return\n"); + } + _backtrace(cliDebugger, NULL); + break; } } @@ -1131,3 +1167,68 @@ bool CLIDebuggerTabComplete(struct CLIDebugger* debugger, const char* token, boo debugger->backend->lineAppend(debugger->backend, " "); return true; } + +static void _backtrace(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { + if (!CLIDebuggerCheckTraceMode(debugger, true)) { + return; + } + struct mStackTrace* stack = &debugger->d.stackTrace; + ssize_t frames = mStackTraceGetDepth(stack); + if (dv && dv->type == CLIDV_INT_TYPE && dv->intValue < frames) { + frames = dv->intValue; + } + ssize_t i; + for (i = 0; i < frames; ++i) { + char trace[1024]; + size_t traceSize = sizeof(trace) - 2; + mStackTraceFormatFrame(stack, i, trace, &traceSize); + debugger->backend->printf(debugger->backend, "%s", trace); + } +} + +static void _finish(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { + UNUSED(dv); + if (!CLIDebuggerCheckTraceMode(debugger, true)) { + return; + } + struct mStackTrace* stack = &debugger->d.stackTrace; + struct mStackFrame* frame = mStackTraceGetFrame(stack, 0); + if (!frame) { + debugger->backend->printf(debugger->backend, "No current stack frame.\n"); + return; + } + frame->breakWhenFinished = true; + _continue(debugger, dv); +} + +static void _setStackTraceMode(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { + if (!CLIDebuggerCheckTraceMode(debugger, false)) { + return; + } + if (!dv) { + debugger->backend->printf(debugger->backend, "off disable stack tracing (default)\n"); + debugger->backend->printf(debugger->backend, "trace-only enable stack tracing\n"); + debugger->backend->printf(debugger->backend, "break-call break on function calls\n"); + debugger->backend->printf(debugger->backend, "break-return break on function returns\n"); + debugger->backend->printf(debugger->backend, "break-all break on function calls and returns\n"); + return; + } + if (dv->type != CLIDV_CHAR_TYPE) { + debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS); + return; + } + struct mDebuggerPlatform* platform = debugger->d.platform; + if (strcmp(dv->charValue, "off") == 0) { + platform->setStackTraceMode(platform, STACK_TRACE_DISABLED); + } else if (strcmp(dv->charValue, "trace-only") == 0) { + platform->setStackTraceMode(platform, STACK_TRACE_ENABLED); + } else if (strcmp(dv->charValue, "break-call") == 0) { + platform->setStackTraceMode(platform, STACK_TRACE_BREAK_ON_CALL); + } else if (strcmp(dv->charValue, "break-return") == 0) { + platform->setStackTraceMode(platform, STACK_TRACE_BREAK_ON_RETURN); + } else if (strcmp(dv->charValue, "break-all") == 0) { + platform->setStackTraceMode(platform, STACK_TRACE_BREAK_ON_BOTH); + } else { + debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS); + } +} diff --git a/src/debugger/stack-trace.c b/src/debugger/stack-trace.c new file mode 100644 index 000000000..acb7b505e --- /dev/null +++ b/src/debugger/stack-trace.c @@ -0,0 +1,100 @@ +/* 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 + +#include + +#define CHECK_LENGTH() \ + if (written >= *length) { \ + *length = written; \ + return; \ + } + +DEFINE_VECTOR(mStackFrames, struct mStackFrame); + +void mStackTraceInit(struct mStackTrace* stack, size_t registersSize) { + mStackFramesInit(&stack->stack, 0); + stack->registersSize = registersSize; +} + +void mStackTraceDeinit(struct mStackTrace* stack) { + mStackTraceClear(stack); + mStackFramesDeinit(&stack->stack); +} + +void mStackTraceClear(struct mStackTrace* stack) { + ssize_t i = mStackTraceGetDepth(stack) - 1; + while (i >= 0) { + free(mStackTraceGetFrame(stack, i)->regs); + --i; + } + mStackFramesClear(&stack->stack); +} + +size_t mStackTraceGetDepth(struct mStackTrace* stack) { + return mStackFramesSize(&stack->stack); +} + +struct mStackFrame* mStackTracePush(struct mStackTrace* stack, uint32_t pc, uint32_t destAddress, uint32_t sp, void* regs) { + struct mStackFrame* frame = mStackFramesAppend(&stack->stack); + frame->callAddress = pc; + frame->entryAddress = destAddress; + frame->frameBaseAddress = sp; + frame->regs = malloc(stack->registersSize); + frame->finished = false; + frame->breakWhenFinished = false; + frame->interrupt = false; + memcpy(frame->regs, regs, stack->registersSize); + return frame; +} + +struct mStackFrame* mStackTraceGetFrame(struct mStackTrace* stack, uint32_t frame) { + size_t depth = mStackTraceGetDepth(stack); + if (frame >= depth) { + return NULL; + } + return mStackFramesGetPointer(&stack->stack, depth - frame - 1); +} + +void mStackTraceFormatFrame(struct mStackTrace* stack, uint32_t frame, char* out, size_t* length) { + struct mStackFrame* stackFrame = mStackTraceGetFrame(stack, frame); + struct mStackFrame* prevFrame = mStackTraceGetFrame(stack, frame + 1); + size_t written = snprintf(out, *length, "#%d ", frame); + CHECK_LENGTH(); + if (prevFrame) { + written += snprintf(out + written, *length - written, "%08X ", prevFrame->entryAddress); + CHECK_LENGTH(); + } + if (!stackFrame) { + written += snprintf(out + written, *length - written, "no stack frame available)\n"); + *length = written; + return; + } else if (stack->formatRegisters) { + written += snprintf(out + written, *length - written, "("); + CHECK_LENGTH(); + char buffer[1024]; + size_t formattedSize = sizeof(buffer) - 2; + stack->formatRegisters(stackFrame, buffer, &formattedSize); + written += snprintf(out + written, *length - written, "%s)\n ", buffer); + CHECK_LENGTH(); + } + if (prevFrame) { + int32_t offset = stackFrame->callAddress - prevFrame->entryAddress; + written += snprintf(out + written, *length - written, "at %08X [%08X+%d]\n", stackFrame->callAddress, prevFrame->entryAddress, offset); + } else { + written += snprintf(out + written, *length - written, "at %08X\n", stackFrame->callAddress); + } + *length = written; +} + +void mStackTracePop(struct mStackTrace* stack) { + size_t depth = mStackTraceGetDepth(stack); + if (depth > 0) { + struct mStackFrame* frame = mStackFramesGetPointer(&stack->stack, depth - 1); + free(frame->regs); + mStackFramesResize(&stack->stack, -1); + } +} diff --git a/src/gba/savedata.c b/src/gba/savedata.c index 954d5b218..39a805725 100644 --- a/src/gba/savedata.c +++ b/src/gba/savedata.c @@ -599,7 +599,6 @@ void GBASavedataDeserialize(struct GBASavedata* savedata, const struct GBASerial void _flashSwitchBank(struct GBASavedata* savedata, int bank) { mLOG(GBA_SAVE, DEBUG, "Performing flash bank switch to bank %i", bank); - savedata->currentBank = &savedata->data[bank << 16]; if (bank > 0 && savedata->type == SAVEDATA_FLASH512) { mLOG(GBA_SAVE, INFO, "Updating flash chip from 512kb to 1Mb"); savedata->type = SAVEDATA_FLASH1M; @@ -614,6 +613,7 @@ void _flashSwitchBank(struct GBASavedata* savedata, int bank) { } } } + savedata->currentBank = &savedata->data[bank << 16]; } void _flashErase(struct GBASavedata* savedata) { diff --git a/src/platform/qt/ts/mgba-ja.ts b/src/platform/qt/ts/mgba-ja.ts new file mode 100644 index 000000000..cd6366318 --- /dev/null +++ b/src/platform/qt/ts/mgba-ja.ts @@ -0,0 +1,5681 @@ + + + + + AboutScreen + + + About + About + + + + <a href="http://mgba.io/">Website</a> • <a href="https://forums.mgba.io/">Forums / Support</a> • <a href="https://patreon.com/mgba">Donate</a> • <a href="https://github.com/mgba-emu/mgba/tree/{gitBranch}">Source</a> + <a href="http://mgba.io/">Website</a> • <a href="https://forums.mgba.io/">Forums / Support</a> • <a href="https://patreon.com/mgba">Donate</a> • <a href="https://github.com/mgba-emu/mgba/tree/{gitBranch}">Source</a> + + + + Branch: <tt>{gitBranch}</tt><br/>Revision: <tt>{gitCommit}</tt> + Branch: <tt>{gitBranch}</tt><br/>Revision: <tt>{gitCommit}</tt> + + + + {projectName} + {projectName} + + + + {projectName} would like to thank the following patrons from Patreon: + {projectName} would like to thank the following patrons from Patreon: + + + + © 2013 – 2020 Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0 +Game Boy Advance is a registered trademark of Nintendo Co., Ltd. + © 2013 – 2020 Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0 +Game Boy Advance is a registered trademark of Nintendo Co., Ltd. + + + © 2013 – 2018 Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0 +Game Boy Advance is a registered trademark of Nintendo Co., Ltd. + © 2013 – 2018 Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0 +Game Boy Advance is a registered trademark of Nintendo Co., Ltd. + + + + {projectVersion} + {projectVersion} + + + + {logo} + {logo} + + + + {projectName} is an open-source Game Boy Advance emulator + {projectName} is an open-source Game Boy Advance emulator + + + + {patrons} + {patrons} + + + + ArchiveInspector + + + Open in archive... + アーカイブを開く... + + + + Loading... + ロード中... + + + + AssetTile + + + AssetTile + タイルビューアー + + + + Tile # + タイル # + + + + + 0 + 0 + + + + Palette # + パレット # + + + + Address + アドレス + + + + 0x06000000 + 0x06000000 + + + + Red + Red + + + + Green + Green + + + + Blue + Blue + + + + + + 0x00 (00) + 0x00 (00) + + + + BattleChipView + + + BattleChip Gate + チップゲート + + + + Chip name + チップ名 + + + + Insert + 挿入 + + + + Save + 保存 + + + + Load + 読込 + + + + Add + 追加 + + + + Remove + 削除 + + + + Gate type + ゲートタイプ + + + + Ba&ttleChip Gate + バトルチップゲート (&T) + + + + Progress &Gate + プログレスチップゲート (&G) + + + + Beast &Link Gate + ビーストリンクゲート (&L) + + + + Inserted + 挿入完了 + + + + Chip ID + チップID + + + + Update Chip data + チップデータ更新 + + + + Show advanced + 詳細表示 + + + + CheatsView + + + Cheats + チート + + + + Remove + 削除 + + + + Save + 保存 + + + + Load + 読込 + + + + Add New Set + 新規セット追加 + + + + Add + 追加 + + + + Enter codes here... + ここにコードを入力してください... + + + + DebuggerConsole + + + Debugger + デバッガ + + + + Enter command (try `help` for more info) + コマンドを入力してください(`help`でヘルプ情報) + + + + Break + Break + + + + FrameView + + + Inspect frame + フレームインスペクタ + + + + × + × + + + + Magnification + 倍率 + + + + Freeze frame + フレームをフリーズ + + + + Backdrop color + 背景色 + + + + Disable scanline effects + スキャンライン効果を無効 + + + + Export + 保存 + + + + Reset + リセット + + + + GIFView + + + Record GIF/APNG + GIF/APNG録画 + + + + Start + 開始 + + + + Stop + 停止 + + + + Select File + ファイル選択 + + + + Loop + ループ + + + + Frameskip + フレームスキップ + + + Frame delay (ms) + Frame delay (ms) + + + Automatic + Automatic + + + + IOViewer + + + I/O Viewer + IOビューアー + + + + 0x0000 + 0x0000 + + + + 2 + 2 + + + + 5 + 5 + + + + 4 + 4 + + + + 7 + 7 + + + + 0 + 0 + + + + 9 + 9 + + + + 1 + 1 + + + + 3 + 3 + + + + 8 + 8 + + + + C + C + + + + E + E + + + + 6 + 6 + + + + D + D + + + + F + F + + + + A + A + + + + B + B + + + + LibraryTree + + + Name + ゲーム名 + + + + Location + 場所 + + + + Platform + プラットフォーム + + + + Size + サイズ + + + + CRC32 + CRC32 + + + + LoadSaveState + + + + %1 State + ステート %1 + + + + + + + + + + + + No Save + 保存しない + + + + 1 + 1 + + + + 2 + 2 + + + + Cancel + キャンセル + + + + 3 + 3 + + + + 4 + 4 + + + + 5 + 5 + + + + 6 + 6 + + + + 7 + 7 + + + + 8 + 8 + + + + 9 + 9 + + + + LogView + + + Logs + ログ + + + + Enabled Levels + 有効レベル + + + + Debug + Debug + + + + Stub + Stub + + + + Info + Info + + + + Warning + Warning + + + + Error + Error + + + + Fatal + Fatal + + + + Game Error + Game Error + + + + Clear + 消去 + + + + Max Lines + 最大行数 + + + + MapView + + + Maps + マップビューアー + + + + × + × + + + + Magnification + 倍率 + + + + Export + 保存 + + + + Copy + コピー + + + + MemoryDump + + + Save Memory Range + メモリ範囲を保存 + + + + Start Address: + 開始アドレス: + + + + : + : + + + + + 0x + 0x + + + + Byte Count: + バイト数: + + + + Dump across banks + Dump across banks + + + + MemorySearch + + + Memory Search + メモリサーチ + + + + Address + アドレス + + + + Current Value + 現在値 + + + + + Type + タイプ + + + + Value + + + + + Numeric + 数値 + + + + Text + 文字列 + + + + Width + データサイズ + + + + 1 Byte (8-bit) + 1 Byte (8-bit) + + + + 2 Bytes (16-bit) + 2 Bytes (16-bit) + + + + 4 Bytes (32-bit) + 4 Bytes (32-bit) + + + + Number type + 数値タイプ + + + + Hexadecimal + 16進数 + + + + Search type + サーチタイプ + + + + Equal to value + 同じ値 + + + + Greater than value + 大きい値 + + + + Less than value + 小さい値 + + + + Unknown/changed + 不明/変更 + + + + Changed by value + 変わった値 + + + + Unchanged + 変更なし + + + + Increased + 増加 + + + + Decreased + 減少 + + + + Search ROM + ROMサーチ + + + + New Search + 新規サーチ + + + + Decimal + 10進数 + + + + + Guess + 推測 + + + Compare + Compare + + + Equal + Equal + + + Greater + Greater + + + Less + Less + + + Delta + Delta + + + Search + Search + + + + Search Within + サーチ + + + + Open in Memory Viewer + メモリービューアーを開く + + + + Refresh + 更新 + + + + MemoryView + + + Memory + メモリービューアー + + + + Inspect Address: + アドレス: + + + + : + : + + + + 0x + 0x + + + + Set Alignment: + 表示: + + + 1 Byte + 1 Byte + + + 2 Bytes + 2 Bytes + + + 4 Bytes + 4 Bytes + + + + &1 Byte + &1 Byte + + + + &2 Bytes + &2 Bytes + + + + &4 Bytes + &4 Bytes + + + + Unsigned Integer: + 符号なし整数: + + + + Signed Integer: + 符号付き整数: + + + + String: + 文字列: + + + + Load TBL + TBLを開く + + + + Copy Selection + 選択値をコピー + + + + Paste + 貼り付け + + + + Save Selection + 選択値を保存 + + + + Save Range + 範囲で保存... + + + + Load + 読込 + + + + ObjView + + + Sprites + スプライトビューアー + + + + + × + × + + + + Magnification + 倍率 + + + + Export + 保存 + + + + Attributes + 属性 + + + + Transform + 変換 + + + + Off + Off + + + + Palette + パレット + + + + + + + 0 + 0 + + + + Copy + コピー + + + + Double Size + ダブルサイズ + + + + + + + Return, Ctrl+R + Return, Ctrl+R + + + + Flipped + 反転 + + + + H + + + + + V + + + + + Mode + モード + + + + Normal + ノーマル + + + + Mosaic + モザイク + + + + Enabled + 有効 + + + + Priority + 優先度 + + + + Tile + タイル + + + + Geometry + ジオメトリ + + + + Position + 位置 + + + + , + , + + + + Dimensions + サイズ + + + + + 8 + 8 + + + + Address + アドレス + + + + 0x07000000 + 0x07000000 + + + + OverrideView + + + Game Overrides + ゲーム別設定 + + + + Game Boy Advance + ゲームボーイアドバンス + + + + + + + Autodetect + 自動検出 + + + + Realtime clock + リアルタイムクロック + + + + Gyroscope + 回転センサー + + + + Tilt + 動きセンサー + + + + Light sensor + 光センサー + + + + Rumble + 振動 + + + + Save type + セーブ形式 + + + + + None + None + + + + SRAM + SRAM + + + + Flash 512kb + Flash 512kb + + + + Flash 1Mb + Flash 1Mb + + + + EEPROM + EEPROM + + + + Idle loop + アイドルループ + + + + Game Boy Player features + ゲームボーイプレイヤーモード + + + + Game Boy + ゲームボーイ + + + + Game Boy model + ゲームボーイモード + + + + Game Boy (DMG) + Game Boy (DMG) + + + + Super Game Boy (SGB) + Super Game Boy (SGB) + + + + Game Boy Color (CGB) + Game Boy Color (CGB) + + + + Game Boy Advance (AGB) + Game Boy Advance (AGB) + + + + Memory bank controller + メモリバンクコントローラ + + + + MBC1 + MBC1 + + + + MBC2 + MBC2 + + + + MBC3 + MBC3 + + + + MBC3 + RTC + MBC3 + RTC + + + + MBC5 + MBC5 + + + + MBC5 + Rumble + MBC5 + Rumble + + + + MBC6 + MBC6 + + + + MBC7 + MBC7 + + + + MMM01 + MMM01 + + + + Pocket Cam + ポケットカメラ + + + + TAMA5 + TAMA5 + + + + HuC-1 + HuC-1 + + + + HuC-3 + HuC-3 + + + + Wisdom Tree (Unlicensed) + Wisdom Tree (Unlicensed) + + + + Pokémon Jade/Diamond (Unlicensed) + Pokémon Jade/Diamond (Unlicensed) + + + + Background Colors + 背景色 + + + + Sprite Colors 1 + スプライト1 + + + + Sprite Colors 2 + スプライト2 + + + Colors + Colors + + + + PaletteView + + + Palette + パレットビュアー + + + + Background + バックグラウンド + + + + Objects + オブジェクト + + + + Selection + 選択 + + + + Red + Red + + + + Green + Green + + + + Blue + Blue + + + + + + 0x00 (00) + 0x00 (00) + + + + 16-bit value + + + + + Hex code + 16進数カラーコード + + + + Palette index + パレットインデックス + + + + 0x0000 + 0x0000 + + + + #000000 + #000000 + + + + 000 + 000 + + + + Export BG + BGの保存 + + + + Export OBJ + OBJの保存 + + + + PlacementControl + + + Adjust placement + 配置調整 + + + + All + All + + + + Offset + Offset + + + + X + X + + + + Y + Y + + + + PrinterView + + + Game Boy Printer + ポケットプリンタ + + + + Hurry up! + 急げ! + + + + Tear off + 切り取る + + + + × + × + + + + Magnification + 倍率 + + + + QGBA::AssetTile + + + %0%1%2 + %0%1%2 + + + + + + 0x%0 (%1) + 0x%0 (%1) + + + + QGBA::AudioDevice + + + Can't set format of context-less audio device + コンテキストレスオーディオデバイスのフォーマットを設定できません + + + + Audio device is missing its core + オーディオデバイスにコアがありません + + + + Writing data to read-only audio device + 読み取り専用オーディオデバイスへのデータの書き込み + + + + QGBA::AudioProcessorQt + + + Can't start an audio processor without input + 入力なしではオーディオプロセッサを起動できません + + + + QGBA::AudioProcessorSDL + + + Can't start an audio processor without input + 入力なしではオーディオプロセッサを起動できません + + + + QGBA::BattleChipView + + + BattleChip data missing + バトルチップデータがありません + + + + BattleChip data is missing. BattleChip Gates will still work, but some graphics will be missing. Would you like to download the data now? + バトルチップデータがありません。チップゲートは引き続き機能しますが、一部のグラフィックが表示されなくなります。今すぐチップデータをダウンロードしますか? + + + + + Select deck file + デッキファイルを選択 + + + + Incompatible deck + 互換性のないデッキ + + + + The selected deck is not compatible with this Chip Gate + 選択したデッキはこのチップゲートと互換性がありません + + + + QGBA::CheatsModel + + + (untitled) + (タイトルなし) + + + + Failed to open cheats file: %1 + チートファイルを開けませんでした: %1 + + + + QGBA::CheatsView + + + + Add GameShark + 追加(GameShark) + + + + Add Pro Action Replay + 追加(Pro Action Replay) + + + + Add CodeBreaker + 追加(CodeBreaker) + + + + Add GameGenie + 追加(GameGenie) + + + + + Select cheats file + チートファイルを選択 + + + + QGBA::CoreController + + + Failed to open save file: %1 + 保存ファイルを開けませんでした: %1 + + + + Failed to open game file: %1 + ゲームファイルを開けませんでした: %1 + + + + Failed to open snapshot file for reading: %1 + 読み取り用のスナップショットファイルを開けませんでした: %1 + + + + Failed to open snapshot file for writing: %1 + 書き込み用のスナップショットファイルを開けませんでした: %1 + + + + QGBA::CoreManager + + + Failed to open game file: %1 + ゲームファイルを開けませんでした: %1 + + + + QGBA::FrameView + + + Export frame + フレームを保存 + + + + Portable Network Graphics (*.png) + Portable Network Graphics (*.png) + + + + None + None + + + + Background + バックグラウンド + + + + Window + ウインドウ + + + + Sprite + スプライト + + + + Backdrop + 背景 + + + + %1 %2 + %1 %2 + + + + QGBA::GBAApp + + + Enable Discord Rich Presence + DiscordのRich Presence有効 + + + + QGBA::GBAKeyEditor + + + Clear Button + ボタンクリア + + + + Clear Analog + アナログクリア + + + + Refresh + 更新 + + + + Set all + すべて設定 + + + + QGBA::GDBWindow + + + Server settings + サーバ設定 + + + + Local port + ローカルポート + + + + Bind address + バインドアドレス + + + + Break + Break + + + + Stop + 停止 + + + + Start + 開始 + + + + Crash + クラッシュ + + + + Could not start GDB server + GDBサーバを起動できませんでした + + + + QGBA::GIFView + + + Failed to open output GIF file: %1 + 出力GIFファイルを開けませんでした: %1 + + + + Select output file + 出力ファイルを選択 + + + + Graphics Interchange Format (*.gif) + Graphics Interchange Format (*.gif) + + + + QGBA::GameController + + Failed to open game file: %1 + Failed to open game file: %1 + + + Failed to open save file: %1 + Failed to open save file: %1 + + + Failed to open snapshot file for reading: %1 + Failed to open snapshot file for reading: %1 + + + Failed to open snapshot file for writing: %1 + Failed to open snapshot file for writing: %1 + + + Failed to start audio processor + Failed to start audio processor + + + + QGBA::IOViewer + + + Background mode + Background mode + + + + Mode 0: 4 tile layers + Mode 0: 4 tile layers + + + + Mode 1: 2 tile layers + 1 rotated/scaled tile layer + Mode 1: 2 tile layers + 1 rotated/scaled tile layer + + + + Mode 2: 2 rotated/scaled tile layers + Mode 2: 2 rotated/scaled tile layers + + + + Mode 3: Full 15-bit bitmap + Mode 3: Full 15-bit bitmap + + + + Mode 4: Full 8-bit bitmap + Mode 4: Full 8-bit bitmap + + + + Mode 5: Small 15-bit bitmap + Mode 5: Small 15-bit bitmap + + + + CGB Mode + CGB Mode + + + + Frame select + Frame select + + + + Unlocked HBlank + Unlocked HBlank + + + + Linear OBJ tile mapping + Linear OBJ tile mapping + + + + Force blank screen + Force blank screen + + + + Enable background 0 + Enable background 0 + + + + Enable background 1 + Enable background 1 + + + + Enable background 2 + Enable background 2 + + + + Enable background 3 + Enable background 3 + + + + Enable OBJ + Enable OBJ + + + + Enable Window 0 + Enable Window 0 + + + + Enable Window 1 + Enable Window 1 + + + + Enable OBJ Window + Enable OBJ Window + + + + Currently in VBlank + Currently in VBlank + + + + Currently in HBlank + Currently in HBlank + + + + Currently in VCounter + Currently in VCounter + + + + Enable VBlank IRQ generation + Enable VBlank IRQ generation + + + + Enable HBlank IRQ generation + Enable HBlank IRQ generation + + + + Enable VCounter IRQ generation + Enable VCounter IRQ generation + + + + VCounter scanline + VCounter scanline + + + + Current scanline + Current scanline + + + + + + + Priority + Priority + + + + + + + Tile data base (* 16kB) + Tile data base (* 16kB) + + + + + + + Enable mosaic + Enable mosaic + + + + + + + Enable 256-color + Enable 256-color + + + + + + + Tile map base (* 2kB) + Tile map base (* 2kB) + + + + + + + Background dimensions + Background dimensions + + + + + Overflow wraps + Overflow wraps + + + + + + + Horizontal offset + Horizontal offset + + + + + + + Vertical offset + Vertical offset + + + + + + + + + + + + + + + Fractional part + Fractional part + + + + + + + + + + + Integer part + Integer part + + + + + + + Integer part (bottom) + Integer part (bottom) + + + + + + + Integer part (top) + Integer part (top) + + + + + End x + End x + + + + + Start x + Start x + + + + + End y + End y + + + + + Start y + Start y + + + + Window 0 enable BG 0 + Window 0 enable BG 0 + + + + Window 0 enable BG 1 + Window 0 enable BG 1 + + + + Window 0 enable BG 2 + Window 0 enable BG 2 + + + + Window 0 enable BG 3 + Window 0 enable BG 3 + + + + Window 0 enable OBJ + Window 0 enable OBJ + + + + Window 0 enable blend + Window 0 enable blend + + + + Window 1 enable BG 0 + Window 1 enable BG 0 + + + + Window 1 enable BG 1 + Window 1 enable BG 1 + + + + Window 1 enable BG 2 + Window 1 enable BG 2 + + + + Window 1 enable BG 3 + Window 1 enable BG 3 + + + + Window 1 enable OBJ + Window 1 enable OBJ + + + + Window 1 enable blend + Window 1 enable blend + + + + Outside window enable BG 0 + Outside window enable BG 0 + + + + Outside window enable BG 1 + Outside window enable BG 1 + + + + Outside window enable BG 2 + Outside window enable BG 2 + + + + Outside window enable BG 3 + Outside window enable BG 3 + + + + Outside window enable OBJ + Outside window enable OBJ + + + + Outside window enable blend + Outside window enable blend + + + + OBJ window enable BG 0 + OBJ window enable BG 0 + + + + OBJ window enable BG 1 + OBJ window enable BG 1 + + + + OBJ window enable BG 2 + OBJ window enable BG 2 + + + + OBJ window enable BG 3 + OBJ window enable BG 3 + + + + OBJ window enable OBJ + OBJ window enable OBJ + + + + OBJ window enable blend + OBJ window enable blend + + + + Background mosaic size vertical + Background mosaic size vertical + + + + Background mosaic size horizontal + Background mosaic size horizontal + + + + Object mosaic size vertical + Object mosaic size vertical + + + + Object mosaic size horizontal + Object mosaic size horizontal + + + + BG 0 target 1 + BG 0 target 1 + + + + BG 1 target 1 + BG 1 target 1 + + + + BG 2 target 1 + BG 2 target 1 + + + + BG 3 target 1 + BG 3 target 1 + + + + OBJ target 1 + OBJ target 1 + + + + Backdrop target 1 + Backdrop target 1 + + + + Blend mode + Blend mode + + + + Disabled + Disabled + + + + Additive blending + Additive blending + + + + Brighten + Brighten + + + + Darken + Darken + + + + BG 0 target 2 + BG 0 target 2 + + + + BG 1 target 2 + BG 1 target 2 + + + + BG 2 target 2 + BG 2 target 2 + + + + BG 3 target 2 + BG 3 target 2 + + + + OBJ target 2 + OBJ target 2 + + + + Backdrop target 2 + Backdrop target 2 + + + + Blend A (target 1) + Blend A (target 1) + + + + Blend B (target 2) + Blend B (target 2) + + + + Blend Y + Blend Y + + + + Sweep shifts + Sweep shifts + + + + Sweep subtract + Sweep subtract + + + + Sweep time (in 1/128s) + Sweep time (in 1/128s) + + + + + + + Sound length + Sound length + + + + + Duty cycle + Duty cycle + + + + + + Envelope step time + Envelope step time + + + + + + Envelope increase + Envelope increase + + + + + + Initial volume + Initial volume + + + + + + Sound frequency + Sound frequency + + + + + + + Timed + Timed + + + + + + + Reset + Reset + + + + Double-size wave table + Double-size wave table + + + + Active wave table + Active wave table + + + + Enable channel 3 + Enable channel 3 + + + + Volume + Volume + + + + 0% + 0% + + + + + 100% + 100% + + + + + 50% + 50% + + + + + 25% + 25% + + + + + + + 75% + 75% + + + + Clock divider + Clock divider + + + + Register stages + Register stages + + + + 15 + 15 + + + + 7 + 7 + + + + Shifter frequency + Shifter frequency + + + + PSG volume right + PSG volume right + + + + PSG volume left + PSG volume left + + + + Enable channel 1 right + Enable channel 1 right + + + + Enable channel 2 right + Enable channel 2 right + + + + Enable channel 3 right + Enable channel 3 right + + + + Enable channel 4 right + Enable channel 4 right + + + + Enable channel 1 left + Enable channel 1 left + + + + Enable channel 2 left + Enable channel 2 left + + + + Enable channel 3 left + Enable channel 3 left + + + + Enable channel 4 left + Enable channel 4 left + + + + PSG master volume + PSG master volume + + + + Loud channel A + Loud channel A + + + + Loud channel B + Loud channel B + + + + Enable channel A right + Enable channel A right + + + + Enable channel A left + Enable channel A left + + + + Channel A timer + Channel A timer + + + + + 0 + 0 + + + + + + + + + + + + 1 + 1 + + + + Channel A reset + Channel A reset + + + + Enable channel B right + Enable channel B right + + + + Enable channel B left + Enable channel B left + + + + Channel B timer + Canal B timer + + + + Channel B reset + Channel B reset + + + + Active channel 1 + Active channel 1 + + + + Active channel 2 + Active channel 2 + + + + Active channel 3 + Active channel 3 + + + + Active channel 4 + Active channel 4 + + + + Enable audio + Enable audio + + + + Bias + Bias + + + + Resolution + Resolution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Sample + Sample + + + + + + + + + + + Address (bottom) + Address (bottom) + + + + + + + + + + + Address (top) + Address (top) + + + + + + + Word count + Word count + + + + + + + Destination offset + Destination offset + + + + + + + + + + + Increment + Increment + + + + + + + + + + + Decrement + Decrement + + + + + + + + + + + Fixed + Fixed + + + + + + + Increment and reload + Increment and reload + + + + + + + Source offset + Source offset + + + + + + + Repeat + Repeat + + + + + + + 32-bit + 32-bit + + + + + + + Start timing + Start timing + + + + + + + Immediate + Immediate + + + + + + + + + VBlank + VBlank + + + + + + + + + HBlank + HBlank + + + + + + + + + + + + IRQ + IRQ + + + + + + + + + + + Enable + Enable + + + + + + Audio FIFO + Audio FIFO + + + + Video Capture + Video Capture + + + + DRQ + DRQ + + + + + + + Value + Value + + + + + + + Scale + Scale + + + + + + + 1/64 + 1/64 + + + + + + + 1/256 + 1/256 + + + + + + + 1/1024 + 1/1024 + + + + + + Cascade + Cascade + + + + + A + A + + + + + B + B + + + + + Select + Select + + + + + Start + Start + + + + + Right + Right + + + + + Left + Left + + + + + Up + Up + + + + + Down + Down + + + + + R + R + + + + + L + L + + + + Condition + Condition + + + + SC + SC + + + + SD + SD + + + + SI + SI + + + + SO + SO + + + + + VCounter + VCounter + + + + + Timer 0 + Timer 0 + + + + + Timer 1 + Timer 1 + + + + + Timer 2 + Timer 2 + + + + + Timer 3 + Timer 3 + + + + + SIO + SIO + + + + + DMA 0 + DMA 0 + + + + + DMA 1 + DMA 1 + + + + + DMA 2 + DMA 2 + + + + + DMA 3 + DMA 3 + + + + + Keypad + Keypad + + + + + Gamepak + Gamepak + + + + SRAM wait + SRAM wait + + + + + + + + 4 + 4 + + + + + + + 3 + 3 + + + + + + + + 2 + 2 + + + + + + + + 8 + 8 + + + + Cart 0 non-sequential + Cart 0 non-sequential + + + + Cart 0 sequential + Cart 0 sequential + + + + Cart 1 non-sequential + Cart 1 non-sequential + + + + Cart 1 sequential + Cart 1 sequential + + + + Cart 2 non-sequential + Cart 2 non-sequential + + + + Cart 2 sequential + Cart 2 sequential + + + + PHI terminal + PHI terminal + + + + Disable + Disable + + + + 4.19MHz + 4.19MHz + + + + 8.38MHz + 8.38MHz + + + + 16.78MHz + 16.78MHz + + + + Gamepak prefetch + Gamepak prefetch + + + + Enable IRQs + Enable IRQs + + + + QGBA::KeyEditor + + + + --- + --- + + + + QGBA::LoadSaveState + + + Load State + ステートロード + + + + Save State + ステートセーブ + + + + Empty + + + + + Corrupted + 破損 + + + + Slot %1 + スロット %1 + + + + QGBA::LogConfigModel + + + + Default + Default + + + + Fatal + Fatal + + + + Error + Error + + + + Warning + Warning + + + + Info + Info + + + + Debug + Debug + + + + Stub + Stub + + + + Game Error + Game Error + + + + QGBA::LogController + + + [%1] %2: %3 + [%1] %2: %3 + + + + An error occurred + エラーが発生しました + + + + DEBUG + DEBUG + + + + STUB + STUB + + + + INFO + INFO + + + + WARN + WARN + + + + ERROR + ERROR + + + + FATAL + FATAL + + + + GAME ERROR + GAME ERROR + + + + QGBA::MapView + + + Priority + 優先度 + + + + + Map base + マップベース + + + + + Tile base + タイルベース + + + + Size + サイズ + + + + + Offset + オフセット + + + + Xform + Xform + + + + Map Addr. + マップアドレス + + + + Mirror + ミラー + + + + None + None + + + + Both + Both + + + + Horizontal + + + + + Vertical + + + + + + + N/A + N/A + + + + Export map + マップを保存 + + + + Portable Network Graphics (*.png) + Portable Network Graphics (*.png) + + + Failed to open output PNG file: %1 + 出力PNGファイルを開けませんでした: %1 + + + + QGBA::MemoryDump + + + Save memory region + メモリ領域を保存 + + + + Failed to open output file: %1 + 出力ファイルを開けませんでした: %1 + + + + QGBA::MemoryModel + + + Copy selection + 選択値をコピー + + + + Save selection + 選択値を保存 + + + + Paste + 貼り付け + + + + Load + 読込 + + + + All + All + + + + Load TBL + TBLを開く + + + + Save selected memory + 選択したメモリを保存する + + + + Failed to open output file: %1 + 出力ファイルを開けませんでした: %1 + + + + Load memory + メモリをロード + + + + Failed to open input file: %1 + 入力ファイルを開けませんでした: %1 + + + + TBL + TBL + + + + ISO-8859-1 + ISO-8859-1 + + + + QGBA::MemorySearch + + + (%0/%1×) + (%0/%1×) + + + + (⅟%0×) + (⅟%0×) + + + + (%0×) + (%0×) + + + + %1 byte%2 + %1 byte%2 + + + 1 byte%0 + 1 byte%0 + + + 2 bytes%0 + 2 bytes%0 + + + 4 bytes%0 + 4 bytes%0 + + + + QGBA::ObjView + + + + 0x%0 + 0x%0 + + + + Off + Off + + + + Normal + Normal + + + + Trans + Trans + + + + OBJWIN + OBJWIN + + + + Invalid + Invalid + + + + + N/A + N/A + + + + Export sprite + OBJの保存 + + + + Portable Network Graphics (*.png) + Portable Network Graphics (*.png) + + + Failed to open output PNG file: %1 + Failed to open output PNG file: %1 + + + + QGBA::PaletteView + + + #%0 + #%0 + + + + 0x%0 + 0x%0 + + + + %0 + %0 + + + + + + 0x%0 (%1) + 0x%0 (%1) + + + + Export palette + パレットの保存 + + + + Windows PAL (*.pal);;Adobe Color Table (*.act) + Windows PAL (*.pal);;Adobe Color Table (*.act) + + + + Failed to open output palette file: %1 + 出力パレットファイルを開けませんでした: %1 + + + + QGBA::PrinterView + + + Save Printout + プリントアウトの保存 + + + + Portable Network Graphics (*.png) + Portable Network Graphics (*.png) + + + + QGBA::ROMInfo + + + + + + + (unknown) + (不明) + + + + + bytes + バイト + + + + (no database present) + (データベースがありません) + + + + QGBA::SettingsView + + + + Qt Multimedia + Qt Multimedia + + + + SDL + SDL + + + + Software (Qt) + Software (Qt) + + + + OpenGL + OpenGL + + + + OpenGL (force version 1.x) + OpenGL (force version 1.x) + + + + None (Still Image) + None(静止画) + + + + Keyboard + キーボード + + + + Controllers + コントローラー + + + + Shortcuts + ショートカット + + + + + Shaders + シェーダー + + + + Select BIOS + BIOS選択 + + + + (%1×%2) + (%1×%2) + + + + QGBA::ShaderSelector + + + No shader active + アクティブなシェーダーがありません + + + + Load shader + シェーダーを開く + + + + No shader loaded + シェーダーがロードされていません + + + + by %1 + by %1 + + + + Preprocessing + 前処理 + + + + Pass %1 + Pass %1 + + + + QGBA::ShortcutController + + Action + アクション + + + Keyboard + キーボード + + + Gamepad + ゲームパッド + + + + QGBA::ShortcutModel + + + Action + アクション + + + + Keyboard + キーボード + + + + Gamepad + ゲームパッド + + + + QGBA::TileView + + + Export tiles + タイルをすべて保存 + + + + + Portable Network Graphics (*.png) + Portable Network Graphics (*.png) + + + + Export tile + タイルを保存 + + + + QGBA::VideoView + + + Failed to open output video file: %1 + 出力ビデオファイルを開けませんでした: %1 + + + + Native (%0x%1) + Native (%0x%1) + + + + Select output file + 出力ファイルを選択 + + + + QGBA::Window + + + Game Boy Advance ROMs (%1) + ゲームボーイアドバンスファイル (%1) + + + + Game Boy ROMs (%1) + ゲームボーイファイル (%1) + + + + All ROMs (%1) + すべてのファイル (%1) + + + + %1 Video Logs (*.mvl) + %1ビデオログ (*.mvl) + + + + Archives (%1) + アーカイブファイル (%1) + + + + + + Select ROM + ROMファイルを開く + + + + Select folder + フォルダを開く + + + + Game Boy Advance save files (%1) + ゲームボーイアドバンスセーブファイル (%1) + + + + + + Select save + セーブファイルを開く + + + + mGBA savestate files (%1) + mGBAステートセーブファイル (%1) + + + + + Select savestate + ステートセーブファイルを開く + + + + Select patch + パッチを開く + + + + Patches (*.ips *.ups *.bps) + パッチファイル (*.ips *.ups *.bps) + + + + Select e-Reader dotcode + カードeを開く + + + + e-Reader card (*.raw *.bin *.bmp) + カードe (*.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 + ゲームは次のエラーでクラッシュしました: + +%1 + + + + Couldn't Load + 読み込めませんでした + + + + Could not load game. Are you sure it's in the correct format? + ゲームを読み込めませんでした。フォーマットは正しいですか? + + + + Unimplemented BIOS call + 未実装のBIOS呼び出し + + + + This game uses a BIOS call that is not implemented. Please use the official BIOS for best experience. + このゲームは実装されていない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 of %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ファイルを開く... + + + + Load ROM in archive... + アーカイブROMファイルを開く... + + + + Add folder to library... + ライブリーにフォルダを追加... + + + + Load alternate save... + セーブファイルを読み込む... + + + + Load temporary save... + 一時セーブファイルを読み込む... + + + + Load &patch... + パッチを開く... (&P) + + + + Boot BIOS + BIOS起動 + + + + Replace ROM... + ROMファイルを交換... + + + + Scan e-Reader dotcodes... + カードeをスキャン... + + + + ROM &info... + ROM情報... (&I) + + + + Recent + 最近開いたROMファイル + + + + Make portable + ポータブル化 + + + + &Load state + ステートロード (&L) + + + + About... + About... + + + + Game Pak sensors... + カートリッジセンサー... + + + + Clear + 消去 + + + F10 + F10 + + + + Load state file... + ステートファイルを開く... + + + + &Save state + ステートセーブ (&S) + + + Shift+F10 + Shift+F10 + + + + Save state file... + ステートファイルを保存... + + + + Quick load + クイックロード + + + + Quick save + クイックセーブ + + + + Load recent + 直近のクイックスロットからロード + + + + Save recent + 直近のクイックスロットにセーブ + + + + Undo load state + クイックロードを取り消す + + + F11 + F11 + + + + Undo save state + クイックセーブを取り消す + + + Shift+F11 + Shift+F11 + + + + + State &%1 + クイックスロット &%1 + + + F%1 + F%1 + + + Shift+F%1 + Shift+F%1 + + + + Load camera image... + カメラ画像を開く... + + + + Import GameShark Save... + GameSharkスナップショットをインポート + + + + Export GameShark Save... + GameSharkスナップショットにエクスポート + + + + New multiplayer window + 新しいウィンドウ(マルチプレイ) + + + + E&xit + 終了 (&X) + + + + &Emulation + エミュレーション (&E) + + + + &Reset + リセット (&R) + + + Ctrl+R + Ctrl+R + + + + Sh&utdown + 閉じる (&U) + + + + Yank game pak + Yank game pak + + + + &Pause + 一時停止 (&P) + + + Ctrl+P + Ctrl+P + + + + &Next frame + 次のフレーム (&N) + + + Ctrl+N + Ctrl+N + + + + Fast forward (held) + 早送り(固定) + + + + &Fast forward + 早送り (&F) + + + Shift+Tab + Shift+Tab + + + + Fast forward speed + 早送り速度 + + + + Unbounded + 制限なし + + + + %0x + %0x + + + + Rewind (held) + 巻戻し(固定) + + + + Re&wind + 巻戻し (&R) + + + ~ + ~ + + + + Step backwards + 後退 + + + Ctrl+B + Ctrl+B + + + + 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 + + + + Audio/&Video + ビデオ/オーディオ (&V) + + + + Frame size + 画面サイズ + + + %1x + %1x + + + + Toggle fullscreen + 全画面表示 + + + + Lock aspect ratio + アスペクト比を固定 + + + + Force integer scaling + 整数スケーリングを強制 + + + + Bilinear filtering + バイリニアフィルタリング + + + + Frame&skip + フレームスキップ (&S) + + + + Mute + ミュート + + + + FPS target + FPS + + + + Native (59.7275) + Native (59.7275) + + + 15 + 15 + + + 30 + 30 + + + 45 + 45 + + + Native (59.7) + Native (59.7) + + + 60 + 60 + + + 90 + 90 + + + 120 + 120 + + + 240 + 240 + + + + Take &screenshot + スクリーンショット (&S) + + + + F12 + F12 + + + Record output... + Record output... + + + + Record GIF/APNG... + GIF/APNG録画... + + + Record video log... + Record video log... + + + Stop video log + Stop video log + + + + Game Boy Printer... + ポケットプリンタ... + + + + BattleChip Gate... + チップゲート... + + + + %1× + %1× + + + + Interframe blending + フレーム間混合 + + + + Record A/V... + ビデオ録画... + + + + Video layers + ビデオレイヤー + + + + Audio channels + オーディオチャンネル + + + + Adjust layer placement... + レイヤーの配置を調整... + + + + &Tools + ツール (&T) + + + + View &logs... + ログビューアー... (&L) + + + + Game &overrides... + ゲーム別設定... (&O) + + + Game &Pak sensors... + カートリッジセンサー... (&P) + + + + &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... + IOビューアー... (&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 + 連打 左 + + + + QObject + + + GBA + GBA + + + + GB + GB + + + + ? + ? + + + + ROMInfo + + + ROM Info + ROM情報 + + + + Game name: + ゲーム名: + + + + {NAME} + {NAME} + + + + Internal name: + 内部名: + + + + {TITLE} + {TITLE} + + + + Game ID: + ゲームID: + + + + {ID} + {ID} + + + + File size: + ファイルサイズ: + + + + {SIZE} + {SIZE} + + + + CRC32: + CRC32: + + + + {CRC} + {CRC} + + + + SensorView + + + Sensors + カートリッジセンサー + + + + Realtime clock + リアルタイムクロック + + + + Fixed time + 定刻 + + + + System time + システム日時 + + + + Start time at + 日時指定 + + + + Now + 現在日時 + + + + MM/dd/yy hh:mm:ss AP + yyyy/MM/dd HH:mm:ss + + + + Light sensor + 光センサー + + + + Brightness + 明るさ + + + + Tilt sensor + 動きセンサー + + + + + Set Y + 垂直方向 + + + + + Set X + 水平方向 + + + + Gyroscope + 回転センサー + + + + Sensitivity + 感度 + + + + SettingsView + + + Settings + 設定 + + + + Audio/Video + ビデオ/オーディオ + + + + Interface + インターフェース + + + + Emulation + エミュレーション + + + + Enhancements + 機能強化 + + + + BIOS + BIOS + + + + Paths + ディレクトリ + + + + Logging + ロギング + + + + Game Boy + ゲームボーイ + + + + Audio driver: + オーディオドライバ: + + + + Audio buffer: + オーディオバッファ: + + + + + 1536 + 1536 + + + + 512 + 512 + + + + 768 + 768 + + + + 1024 + 1024 + + + + 2048 + 2048 + + + + 3072 + 3072 + + + + 4096 + 4096 + + + + samples + samples + + + + Sample rate: + サンプルレート: + + + + + 44100 + 44100 + + + + 22050 + 22050 + + + + 32000 + 32000 + + + + 48000 + 48000 + + + + Hz + Hz + + + + Volume: + 音量: + + + + + Mute + ミュート + + + + Fast forward volume: + 早送り音量: + + + + Display driver: + ディスプレイドライバ: + + + + Frameskip: + フレームスキップ: + + + + Skip every + 常時 + + + + + frames + フレーム + + + + FPS target: + FPS: + + + + frames per second + FPS + + + + Sync: + 同期: + + + + Video + ビデオ + + + + Audio + オーディオ + + + + Lock aspect ratio + アスペクト比を固定 + + + + Bilinear filtering + バイリニアフィルタリング + + + + Native (59.7275) + Native (59,7275) + + + + Interframe blending + フレーム間混合 + + + + Pause when minimized + 最小化時に停止 + + + + Show OSD messages + OSDメッセージ表示 + + + + Fast forward (held) speed: + 早送り(固定) 速度: + + + + (240×160) + (240×160) + + + + Log to file + ファイル出力 + + + + Log to console + コンソール出力 + + + + Select Log File + ファイル選択 + + + + Game Boy model: + ゲームボーイ: + + + + Super Game Boy model: + スーパーゲームボーイ: + + + + Game Boy Color model: + ゲームボーイカラー: + + + + Use GBC colors in GB games + GBゲームでGBCのカラーを使用 + + + + Camera: + カメラ: + + + + Force integer scaling + 整数スケーリングを強制 + + + + Language + 言語 + + + + English + English + + + + Library: + ライブラリー: + + + + List view + リスト表示 + + + + Tree view + ツリー表示 + + + + Show when no game open + ゲームが開いていないときに表示 + + + + Clear cache + キャッシュクリア + + + + Allow opposing input directions + Allow opposing input directions + + + + Suspend screensaver + スクリーンセーバー無効化 + + + + Pause when inactive + 非アクティブ時に停止 + + + + Show FPS in title bar + FPSをタイトルバーに表示 + + + + Automatically save cheats + チートの自動保存 + + + + Automatically load cheats + チートの自動読込 + + + + Automatically save state + ステートの自動保存 + + + + Automatically load state + ステートの自動読込 + + + + Enable Discord Rich Presence + DiscordのRich Presence有効 + + + + Show filename instead of ROM name in title bar + タイトルバーにゲーム名の代わりにファイル名を表示 + + + + Fast forward speed: + 早送り 速度: + + + + + + × + × + + + + + Unbounded + 制限なし + + + + Enable rewind + 巻戻し有効 + + + + Rewind history: + 巻戻し履歴: + + + + Idle loops: + アイドルループ: + + + + Run all + Run all + + + + Remove known + Remove known + + + + Detect and remove + Detect and remove + + + + Savestate extra data: + ステートセーブ追加データ: + + + + + Screenshot + スクリーンショット + + + + + Save data + セーブデータ + + + + + Cheat codes + チートコード + + + + Load extra data: + ロード追加データ: + + + Rewind affects save data + Rewind affects save data + + + + Preload entire ROM into memory + ROM全体をメモリにプリロード + + + + Autofire interval: + 連射間隔: + + + + Video renderer: + ビデオレンダラー: + + + + Software + Software + + + + OpenGL + OpenGL + + + + OpenGL enhancements + OpenGL追加機能 + + + + High-resolution scale: + 高解像度スケール: + + + + XQ GBA audio (experimental) + XQ GBA audio(実験的) + + + + GB BIOS file: + ゲームボーイBIOS: + + + + + + + + + + + + Browse + 参照 + + + + Use BIOS file if found + 存在する場合にBIOSファイルを使用 + + + + Skip BIOS intro + BIOSイントロをスキップ + + + + GBA BIOS file: + ゲームボーイアドバンスBIOS: + + + + GBC BIOS file: + ゲームボーイカラーBIOS: + + + + SGB BIOS file: + スーパーゲームボーイBIOS: + + + + Save games + セーブデータ + + + + + + + + Same directory as the ROM + ROMファイルと同じディレクトリ + + + + Save states + ステートセーブ + + + + Screenshots + スクリーンショット + + + + Patches + パッチ + + + + Cheats + チート + + + Game Boy model + Game Boy model + + + + + + Autodetect + 自動検出 + + + + + + Game Boy (DMG) + Game Boy (DMG) + + + + + + Super Game Boy (SGB) + Super Game Boy (SGB) + + + + + + Game Boy Color (CGB) + Game Boy Color (CGB) + + + + + + Game Boy Advance (AGB) + Game Boy Advance (AGB) + + + Super Game Boy model + Super Game Boy model + + + Game Boy Color model + Game Boy Color model + + + + Default BG colors: + 規定 背景色: + + + + Super Game Boy borders + Super Game Boy borders + + + + Camera driver: + カメラドライバ: + + + + Default sprite colors 1: + 規定 スプライト1: + + + + Default sprite colors 2: + 規定 スプライト2: + + + + ShaderSelector + + + Shaders + シェーダー + + + + Active Shader: + アクティブシェーダー: + + + + Name + 名称 + + + + Author + 製作者 + + + + Description + 説明 + + + + Unload Shader + シェーダーをアンロード + + + + Load New Shader + 新規シェーダーをロード + + + + ShortcutView + + + Edit Shortcuts + ショートカットキー編集 + + + + Keyboard + キーボード + + + + Gamepad + ゲームパッド + + + + Clear + 削除 + + + + TileView + + + Tiles + タイルビューワー + + + + Export Selected + 選択内容を保存 + + + + Export All + すべて保存 + + + + 256 colors + 256色 + + + + × + × + + + + Magnification + 倍率 + + + + Tiles per row + Tiles per row + + + + Fit to window + ウィンドウに合わせる + + + + Copy Selected + 選択内容をコピー + + + + Copy All + すべてコピー + + + + VideoView + + + Record Video + 録画 + + + + Start + 開始 + + + + Stop + 停止 + + + + Select File + ファイル選択 + + + + Presets + プリセット + + + High Quality + High Quality + + + YouTube + YouTube + + + + + WebM + WebM + + + Lossless + Lossless + + + 1080p + 1080p + + + 720p + 720p + + + 480p + 480p + + + Native + Native + + + + Format + 形式 + + + + MKV + MKV + + + + AVI + AVI + + + + MP4 + MP4 + + + PNG + PNG + + + + High &Quality + High &Quality + + + + &YouTube + &YouTube + + + + &Lossless + &Lossless + + + + &1080p + &1080p + + + + &720p + &720p + + + + &480p + &480p + + + + &Native + &Native + + + + h.264 + h.264 + + + + h.264 (NVENC) + h.264 (NVENC) + + + + HEVC + HEVC + + + + HEVC (NVENC) + HEVC (NVENC) + + + + VP8 + VP8 + + + + VP9 + VP9 + + + + FFV1 + FFV1 + + + + FLAC + FLAC + + + + Opus + Opus + + + + Vorbis + Vorbis + + + + MP3 + MP3 + + + + AAC + AAC + + + + Uncompressed + 圧縮なし + + + + Bitrate (kbps) + ビットレート(kbps) + + + + VBR + VBR + + + + ABR + ABR + + + + Dimensions + サイズ + + + + : + : + + + + × + × + + + + Lock aspect ratio + アスペクト比固定 + + + + Show advanced + 詳細表示 + + + diff --git a/src/sm83/debugger/debugger.c b/src/sm83/debugger/debugger.c index 8921ac095..c964a992d 100644 --- a/src/sm83/debugger/debugger.c +++ b/src/sm83/debugger/debugger.c @@ -90,6 +90,9 @@ struct mDebuggerPlatform* SM83DebuggerPlatformCreate(void) { platform->d.trace = SM83DebuggerTrace; platform->d.getRegister = SM83DebuggerGetRegister; platform->d.setRegister = SM83DebuggerSetRegister; + platform->d.getStackTraceMode = NULL; + platform->d.setStackTraceMode = NULL; + platform->d.updateStackTrace = NULL; platform->printStatus = NULL; return &platform->d; } diff --git a/src/sm83/isa-sm83.c b/src/sm83/isa-sm83.c index 8599d2af2..50b86407a 100644 --- a/src/sm83/isa-sm83.c +++ b/src/sm83/isa-sm83.c @@ -9,33 +9,27 @@ #include static inline uint16_t SM83ReadHL(struct SM83Core* cpu) { - uint16_t hl; - LOAD_16LE(hl, 0, &cpu->hl); - return hl; + return cpu->hl; } static inline void SM83WriteHL(struct SM83Core* cpu, uint16_t hl) { - STORE_16LE(hl, 0, &cpu->hl); + cpu->hl = hl; } static inline uint16_t SM83ReadBC(struct SM83Core* cpu) { - uint16_t bc; - LOAD_16LE(bc, 0, &cpu->bc); - return bc; + return cpu->bc; } static inline void SM83WriteBC(struct SM83Core* cpu, uint16_t bc) { - STORE_16LE(bc, 0, &cpu->bc); + cpu->bc = bc; } static inline uint16_t SM83ReadDE(struct SM83Core* cpu) { - uint16_t de; - LOAD_16LE(de, 0, &cpu->de); - return de; + return cpu->de; } static inline void SM83WriteDE(struct SM83Core* cpu, uint16_t de) { - STORE_16LE(de, 0, &cpu->de); + cpu->de = de; } #define DEFINE_INSTRUCTION_SM83(NAME, BODY) \ @@ -77,7 +71,7 @@ DEFINE_INSTRUCTION_SM83(JPDelay, DEFINE_CONDITIONAL_INSTRUCTION_SM83(JP); DEFINE_INSTRUCTION_SM83(JPHL, - cpu->pc = SM83ReadHL(cpu); + cpu->pc = cpu->hl; cpu->memory.setActiveRegion(cpu, cpu->pc);) DEFINE_INSTRUCTION_SM83(JRFinish, @@ -226,7 +220,7 @@ DEFINE_CONDITIONAL_ONLY_INSTRUCTION_SM83(RET) #define DEFINE_LDHL__INSTRUCTION_SM83(NAME, OPERAND) \ DEFINE_INSTRUCTION_SM83(LDHL_ ## NAME, \ cpu->bus = OPERAND; \ - cpu->index = SM83ReadHL(cpu); \ + cpu->index = cpu->hl; \ cpu->executionState = SM83_CORE_MEMORY_STORE; \ cpu->instruction = _SM83InstructionNOP;) @@ -244,7 +238,7 @@ DEFINE_CONDITIONAL_ONLY_INSTRUCTION_SM83(RET) DEFINE_ ## NAME ## _INSTRUCTION_SM83(L, cpu->l); DEFINE_INSTRUCTION_SM83(LDHL_Bus, \ - cpu->index = SM83ReadHL(cpu); \ + cpu->index = cpu->hl; \ cpu->executionState = SM83_CORE_MEMORY_STORE; \ cpu->instruction = _SM83InstructionNOP;) @@ -267,7 +261,7 @@ DEFINE_INSTRUCTION_SM83(LDHL_SP, cpu->instruction = _SM83InstructionLDHL_SPDelay;) DEFINE_INSTRUCTION_SM83(LDSP_HL, - cpu->sp = SM83ReadHL(cpu); + cpu->sp = cpu->hl; cpu->executionState = SM83_CORE_STALL;) #define DEFINE_ALU_INSTRUCTION_SM83_MEM(NAME, REG) \ @@ -378,7 +372,7 @@ DEFINE_INSTRUCTION_SM83(LDBC, \ cpu->instruction = _SM83InstructionLDBCDelay;) DEFINE_INSTRUCTION_SM83(LDBC_A, \ - cpu->index = SM83ReadBC(cpu); \ + cpu->index = cpu->bc; \ cpu->bus = cpu->a; \ cpu->executionState = SM83_CORE_MEMORY_STORE; \ cpu->instruction = _SM83InstructionNOP;) @@ -393,7 +387,7 @@ DEFINE_INSTRUCTION_SM83(LDDE, \ cpu->instruction = _SM83InstructionLDDEDelay;) DEFINE_INSTRUCTION_SM83(LDDE_A, \ - cpu->index = SM83ReadDE(cpu); \ + cpu->index = cpu->de; \ cpu->bus = cpu->a; \ cpu->executionState = SM83_CORE_MEMORY_STORE; \ cpu->instruction = _SM83InstructionNOP;) @@ -419,27 +413,27 @@ DEFINE_INSTRUCTION_SM83(LDSP, \ cpu->instruction = _SM83InstructionLDSPDelay;) DEFINE_INSTRUCTION_SM83(LDIHLA, \ - cpu->index = SM83ReadHL(cpu); \ + cpu->index = cpu->hl; \ SM83WriteHL(cpu, cpu->index + 1); \ cpu->bus = cpu->a; \ cpu->executionState = SM83_CORE_MEMORY_STORE; \ cpu->instruction = _SM83InstructionNOP;) DEFINE_INSTRUCTION_SM83(LDDHLA, \ - cpu->index = SM83ReadHL(cpu); \ + cpu->index = cpu->hl; \ SM83WriteHL(cpu, cpu->index - 1); \ cpu->bus = cpu->a; \ cpu->executionState = SM83_CORE_MEMORY_STORE; \ cpu->instruction = _SM83InstructionNOP;) DEFINE_INSTRUCTION_SM83(LDA_IHL, \ - cpu->index = SM83ReadHL(cpu); \ + cpu->index = cpu->hl; \ SM83WriteHL(cpu, cpu->index + 1); \ cpu->executionState = SM83_CORE_MEMORY_LOAD; \ cpu->instruction = _SM83InstructionLDA_Bus;) DEFINE_INSTRUCTION_SM83(LDA_DHL, \ - cpu->index = SM83ReadHL(cpu); \ + cpu->index = cpu->hl; \ SM83WriteHL(cpu, cpu->index - 1); \ cpu->executionState = SM83_CORE_MEMORY_LOAD; \ cpu->instruction = _SM83InstructionLDA_Bus;) @@ -587,7 +581,7 @@ DEFINE_INSTRUCTION_SM83(INC_HLDelay, cpu->executionState = SM83_CORE_MEMORY_STORE;) DEFINE_INSTRUCTION_SM83(INC_HL, - cpu->index = SM83ReadHL(cpu); + cpu->index = cpu->hl; cpu->instruction = _SM83InstructionINC_HLDelay; cpu->executionState = SM83_CORE_MEMORY_LOAD;) @@ -601,7 +595,7 @@ DEFINE_INSTRUCTION_SM83(DEC_HLDelay, cpu->executionState = SM83_CORE_MEMORY_STORE;) DEFINE_INSTRUCTION_SM83(DEC_HL, - cpu->index = SM83ReadHL(cpu); + cpu->index = cpu->hl; cpu->instruction = _SM83InstructionDEC_HLDelay; cpu->executionState = SM83_CORE_MEMORY_LOAD;) @@ -699,7 +693,7 @@ DEFINE_POPPUSH_INSTRUCTION_SM83(AF, A, a, f.packed); cpu->executionState = WB; \ cpu->instruction = _SM83InstructionNOP;) \ DEFINE_INSTRUCTION_SM83(NAME ## HL, \ - cpu->index = SM83ReadHL(cpu); \ + cpu->index = cpu->hl; \ cpu->executionState = SM83_CORE_MEMORY_LOAD; \ cpu->instruction = _SM83Instruction ## NAME ## HLDelay;) \ DEFINE_INSTRUCTION_SM83(NAME ## A, uint8_t reg = cpu->a; BODY; cpu->a = reg)