all repos — mgba @ 23609b4a8827437add59be7e4f3548912739d5f7

mGBA Game Boy Advance Emulator

Merge branch 'master' (early part) into medusa
Vicki Pfau vi@endrift.com
Fri, 28 Jun 2019 17:17:41 -0700
commit

23609b4a8827437add59be7e4f3548912739d5f7

parent

21e7d763206959ac325f1d5d6e55bb61433c700e

M CHANGESCHANGES

@@ -23,17 +23,28 @@ Features:

- Improved logging configuration - One-Player BattleChip/Progress/Beast Link Gate support - Add Game Boy Color palettes for original Game Boy games -Bugfixes: + - Debugger: Add unary operators and memory dereferencing + - GB: Expose platform information to CLI debugger +Emulation fixes: - GBA: All IRQs have 7 cycle delay (fixes mgba.io/i/539, mgba.io/i/1208) - GBA: Reset now reloads multiboot ROMs - GBA BIOS: Fix multiboot entry point (fixes Magic Floor) + - GB Video: Delay LYC STAT check (fixes mgba.io/i/1331) + - GB Video: Fix window being enabled mid-scanline (fixes mgba.io/i/1328) + - GB I/O: Filter IE top bits properly (fixes mgba.io/i/1329) +Other fixes: - Qt: More app metadata fixes + - Qt: Fix load recent from archive (fixes mgba.io/i/1325) + - LR35902: Fix disassembly of several CB-prefix instructions Misc: - GBA Savedata: EEPROM performance fixes - GBA Savedata: Automatically map 1Mbit Flash files as 1Mbit Flash - GB Memory: Support running from blocked memory - Qt: Don't unload ROM immediately if it crashes - Debugger: Add breakpoint and watchpoint listing + - Qt: Add missing HEVC NVENC option (fixes mgba.io/i/1323) + - LR35902: Support PC-relative opcode decoding + - Qt: Improve camera initialization 0.7.1: (2019-02-24) Bugfixes:
M CMakeLists.txtCMakeLists.txt

@@ -765,6 +765,7 @@ ${CMAKE_CURRENT_SOURCE_DIR}/src/lr35902/debugger/cli-debugger.c

${CMAKE_CURRENT_SOURCE_DIR}/src/lr35902/debugger/debugger.c ${CMAKE_CURRENT_SOURCE_DIR}/src/lr35902/debugger/memory-debugger.c ${CMAKE_CURRENT_SOURCE_DIR}/src/gb/debugger/cli.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/gb/debugger/debugger.c ${CMAKE_CURRENT_SOURCE_DIR}/src/gb/debugger/symbols.c) list(APPEND TEST_SRC ${LR35902_TEST_SRC}
M include/mgba/internal/debugger/parser.hinclude/mgba/internal/debugger/parser.h

@@ -38,6 +38,7 @@ OP_FLIP,

OP_NOT, OP_SHIFT_L, OP_SHIFT_R, + OP_DEREFERENCE, }; struct Token {
A include/mgba/internal/gb/debugger/debugger.h

@@ -0,0 +1,20 @@

+/* Copyright (c) 2013-2019 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 GB_DEBUGGER_H +#define GB_DEBUGGER_H + +#include <mgba-util/common.h> + +CXX_GUARD_START + +struct GB; +struct mDebuggerPlatform; + +struct mDebuggerPlatform* GBDebuggerCreate(struct GB* gb); + +CXX_GUARD_END + +#endif
M include/mgba/internal/gb/renderers/software.hinclude/mgba/internal/gb/renderers/software.h

@@ -32,7 +32,9 @@ uint8_t scx;

uint8_t wy; uint8_t wx; uint8_t currentWy; + uint8_t currentWx; int lastY; + int lastX; bool hasWindow; GBRegisterLCDC lcdc;
M include/mgba/internal/lr35902/debugger/debugger.hinclude/mgba/internal/lr35902/debugger/debugger.h

@@ -20,6 +20,7 @@ uint16_t end;

const char* name; }; +struct CLIDebuggerSystem; struct LR35902Debugger { struct mDebuggerPlatform d; struct LR35902Core* cpu;

@@ -31,6 +32,8 @@

ssize_t nextId; const struct LR35902Segment* segments; + + void (*printStatus)(struct CLIDebuggerSystem*); }; struct mDebuggerPlatform* LR35902DebuggerPlatformCreate(void);
M include/mgba/internal/lr35902/decoder.hinclude/mgba/internal/lr35902/decoder.h

@@ -86,6 +86,7 @@ LR35902_OP_FLAG_IMPLICIT = 1,

LR35902_OP_FLAG_MEMORY = 2, LR35902_OP_FLAG_INCREMENT = 4, LR35902_OP_FLAG_DECREMENT = 8, + LR35902_OP_FLAG_RELATIVE = 16, }; struct LR35902Operand {

@@ -104,7 +105,7 @@ unsigned condition;

}; size_t LR35902Decode(uint8_t opcode, struct LR35902InstructionInfo* info); -int LR35902Disassemble(struct LR35902InstructionInfo* info, char* buffer, int blen); +int LR35902Disassemble(struct LR35902InstructionInfo* info, uint16_t pc, char* buffer, int blen); CXX_GUARD_END
M src/debugger/parser.csrc/debugger/parser.c

@@ -5,6 +5,7 @@ * 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 <mgba/internal/debugger/parser.h> +#include <mgba/core/core.h> #include <mgba/debugger/debugger.h> #include <mgba-util/string.h>

@@ -89,52 +90,77 @@ default:

break; } *state = LEX_ERROR; + } + if (*state == LEX_ROOT || *state == LEX_ERROR) { + struct Token lvNext; + lvNext.type = TOKEN_OPERATOR_TYPE; + *state = LEX_ROOT; + switch (operator) { + case '-': + lvNext.operatorValue = OP_NEGATE; + break; + case '~': + lvNext.operatorValue = OP_FLIP; + break; + case '!': + lvNext.operatorValue = OP_NOT; + break; + case '*': + lvNext.operatorValue = OP_DEREFERENCE; + break; + default: + lvNext.type = TOKEN_ERROR_TYPE; + *state = LEX_ERROR; + return; + } + *LexVectorAppend(lv) = lvNext; return; } - struct Token* lvNext = LexVectorAppend(lv); - lvNext->type = TOKEN_OPERATOR_TYPE; - *state = LEX_EXPECT_OPERATOR2; + struct Token lvNext; + lvNext.type = TOKEN_OPERATOR_TYPE; switch (operator) { case '=': - lvNext->operatorValue = OP_ASSIGN; + lvNext.operatorValue = OP_ASSIGN; break; case '+': - lvNext->operatorValue = OP_ADD; + lvNext.operatorValue = OP_ADD; break; case '-': - lvNext->operatorValue = OP_SUBTRACT; + lvNext.operatorValue = OP_SUBTRACT; break; case '*': - lvNext->operatorValue = OP_MULTIPLY; + lvNext.operatorValue = OP_MULTIPLY; break; case '/': - lvNext->operatorValue = OP_DIVIDE; + lvNext.operatorValue = OP_DIVIDE; break; case '%': - lvNext->operatorValue = OP_MODULO; + lvNext.operatorValue = OP_MODULO; break; case '&': - lvNext->operatorValue = OP_AND; + lvNext.operatorValue = OP_AND; break; case '|': - lvNext->operatorValue = OP_OR; + lvNext.operatorValue = OP_OR; break; case '^': - lvNext->operatorValue = OP_XOR; + lvNext.operatorValue = OP_XOR; break; case '<': - lvNext->operatorValue = OP_LESS; + lvNext.operatorValue = OP_LESS; break; case '>': - lvNext->operatorValue = OP_GREATER; + lvNext.operatorValue = OP_GREATER; break; case '!': - lvNext->operatorValue = OP_NOT; + lvNext.operatorValue = OP_NOT; break; default: - lvNext->type = TOKEN_ERROR_TYPE; - break; + *state = LEX_ERROR; + return; } + *state = LEX_EXPECT_OPERATOR2; + *LexVectorAppend(lv) = lvNext; } static void _lexValue(struct LexVector* lv, char token, uint32_t next, enum LexState* state) {

@@ -247,6 +273,12 @@ state = LEX_ROOT;

lvNext = LexVectorAppend(lv); lvNext->type = TOKEN_OPEN_PAREN_TYPE; break; + case '!': + case '-': + case '~': + case '*': + _lexOperator(lv, token, &state); + break; case ' ': case '\t': break;

@@ -499,6 +531,7 @@ [OP_FLIP] = 2,

[OP_NOT] = 2, [OP_SHIFT_L] = 5, [OP_SHIFT_R] = 5, + [OP_DEREFERENCE] = 2, }; static struct ParseTree* _parseTreeCreate() {

@@ -622,7 +655,7 @@ free(tree->token.identifierValue);

} } -static bool _performOperation(enum Operation operation, int32_t current, int32_t next, int32_t* value) { +static bool _performOperation(struct mDebugger* debugger, enum Operation operation, int32_t current, int32_t next, int32_t* value, int* segment) { switch (operation) { case OP_ASSIGN: current = next;

@@ -683,12 +716,29 @@ break;

case OP_GE: current = current >= next; break; + case OP_NEGATE: + current = -next; + break; + case OP_FLIP: + current = ~next; + break; + case OP_NOT: + current = !next; + break; case OP_SHIFT_L: current <<= next; break; case OP_SHIFT_R: current >>= next; break; + case OP_DEREFERENCE: + if (*segment < 0) { + current = debugger->core->busRead8(debugger->core, next); + } else { + current = debugger->core->rawRead8(debugger->core, next, *segment); + } + *segment = -1; + break; default: return false; }

@@ -714,13 +764,37 @@ return false;

} return mDebuggerEvaluateParseTree(debugger, tree->lhs, segment, NULL); case TOKEN_OPERATOR_TYPE: - if (!mDebuggerEvaluateParseTree(debugger, tree->lhs, &lhs, segment)) { - return false; - } - if (!mDebuggerEvaluateParseTree(debugger, tree->rhs, &rhs, segment)) { - return false; + switch (tree->token.operatorValue) { + case OP_ASSIGN: + case OP_ADD: + case OP_SUBTRACT: + case OP_MULTIPLY: + case OP_DIVIDE: + case OP_MODULO: + case OP_AND: + case OP_OR: + case OP_XOR: + case OP_LESS: + case OP_GREATER: + case OP_EQUAL: + case OP_NOT_EQUAL: + case OP_LOGICAL_AND: + case OP_LOGICAL_OR: + case OP_LE: + case OP_GE: + case OP_SHIFT_L: + case OP_SHIFT_R: + if (!mDebuggerEvaluateParseTree(debugger, tree->lhs, &lhs, segment)) { + return false; + } + // Fall through + default: + if (!mDebuggerEvaluateParseTree(debugger, tree->rhs, &rhs, segment)) { + return false; + } + break; } - return _performOperation(tree->token.operatorValue, lhs, rhs, value); + return _performOperation(debugger, tree->token.operatorValue, lhs, rhs, value, segment); case TOKEN_IDENTIFIER_TYPE: return mDebuggerLookupIdentifier(debugger, tree->token.identifierValue, value, segment); case TOKEN_ERROR_TYPE:
M src/gb/core.csrc/gb/core.c

@@ -8,6 +8,7 @@

#include <mgba/core/core.h> #include <mgba/internal/debugger/symbols.h> #include <mgba/internal/gb/cheats.h> +#include <mgba/internal/gb/debugger/debugger.h> #include <mgba/internal/gb/debugger/symbols.h> #include <mgba/internal/gb/extra/cli.h> #include <mgba/internal/gb/io.h>

@@ -40,20 +41,6 @@ { 0, "ch1", "Channel 1", "Square/Sweep" },

{ 1, "ch2", "Channel 2", "Square" }, { 2, "ch3", "Channel 3", "PCM" }, { 3, "ch4", "Channel 4", "Noise" }, -}; - -static const struct LR35902Segment _GBSegments[] = { - { .name = "ROM", .start = GB_BASE_CART_BANK1, .end = GB_BASE_VRAM }, - { .name = "RAM", .start = GB_BASE_EXTERNAL_RAM, .end = GB_BASE_WORKING_RAM_BANK0 }, - { 0 } -}; - -static const struct LR35902Segment _GBCSegments[] = { - { .name = "ROM", .start = GB_BASE_CART_BANK1, .end = GB_BASE_VRAM }, - { .name = "RAM", .start = GB_BASE_EXTERNAL_RAM, .end = GB_BASE_WORKING_RAM_BANK0 }, - { .name = "WRAM", .start = GB_BASE_WORKING_RAM_BANK1, .end = 0xE000 }, - { .name = "VRAM", .start = GB_BASE_VRAM, .end = GB_BASE_EXTERNAL_RAM }, - { 0 } }; static const struct mCoreMemoryBlock _GBMemoryBlocks[] = {

@@ -715,12 +702,7 @@ static struct mDebuggerPlatform* _GBCoreDebuggerPlatform(struct mCore* core) {

struct GBCore* gbcore = (struct GBCore*) core; struct GB* gb = core->board; if (!gbcore->debuggerPlatform) { - struct LR35902Debugger* platform = (struct LR35902Debugger*) LR35902DebuggerPlatformCreate(); - if (gb->model >= GB_MODEL_CGB) { - platform->segments = _GBCSegments; - } else { - platform->segments = _GBSegments; - } + struct LR35902Debugger* platform = (struct LR35902Debugger*) GBDebuggerCreate(gb); gbcore->debuggerPlatform = &platform->d; } return gbcore->debuggerPlatform;
A src/gb/debugger/debugger.c

@@ -0,0 +1,46 @@

+/* Copyright (c) 2013-2019 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 <mgba/internal/gb/debugger/debugger.h> + + #include <mgba/core/core.h> + #include <mgba/internal/debugger/cli-debugger.h> + #include <mgba/internal/gb/gb.h> + #include <mgba/internal/gb/io.h> + #include <mgba/internal/gb/memory.h> + #include <mgba/internal/lr35902/debugger/debugger.h> + +static const struct LR35902Segment _GBSegments[] = { + { .name = "ROM", .start = GB_BASE_CART_BANK1, .end = GB_BASE_VRAM }, + { .name = "RAM", .start = GB_BASE_EXTERNAL_RAM, .end = GB_BASE_WORKING_RAM_BANK0 }, + { 0 } +}; + +static const struct LR35902Segment _GBCSegments[] = { + { .name = "ROM", .start = GB_BASE_CART_BANK1, .end = GB_BASE_VRAM }, + { .name = "RAM", .start = GB_BASE_EXTERNAL_RAM, .end = GB_BASE_WORKING_RAM_BANK0 }, + { .name = "WRAM", .start = GB_BASE_WORKING_RAM_BANK1, .end = 0xE000 }, + { .name = "VRAM", .start = GB_BASE_VRAM, .end = GB_BASE_EXTERNAL_RAM }, + { 0 } +}; + +static void _printStatus(struct CLIDebuggerSystem* debugger) { + struct CLIDebuggerBackend* be = debugger->p->backend; + struct GB* gb = debugger->p->d.core->board; + be->printf(be, "IE: %02X IF: %02X IME: %i\n", gb->memory.ie, gb->memory.io[REG_IF], gb->memory.ime); + be->printf(be, "LCDC: %02X STAT: %02X LY: %02X\n", gb->memory.io[REG_LCDC], gb->memory.io[REG_STAT] | 0x80, gb->memory.io[REG_LY]); + be->printf(be, "Next video mode: %i\n", mTimingUntil(&gb->timing, &gb->video.modeEvent) / 4); +} + +struct mDebuggerPlatform* GBDebuggerCreate(struct GB* gb) { + struct LR35902Debugger* platform = (struct LR35902Debugger*) LR35902DebuggerPlatformCreate(); + if (gb->model >= GB_MODEL_CGB) { + platform->segments = _GBCSegments; + } else { + platform->segments = _GBSegments; + } + platform->printStatus = _printStatus; + return &platform->d; +}
M src/gb/gb.csrc/gb/gb.c

@@ -630,7 +630,7 @@ }

} void GBUpdateIRQs(struct GB* gb) { - int irqs = gb->memory.ie & gb->memory.io[REG_IF]; + int irqs = gb->memory.ie & gb->memory.io[REG_IF] & 0x1F; if (!irqs) { gb->cpu->irqPending = false; return;
M src/gb/renderers/software.csrc/gb/renderers/software.c

@@ -190,7 +190,9 @@ softwareRenderer->scy = 0;

softwareRenderer->scx = 0; softwareRenderer->wy = 0; softwareRenderer->currentWy = 0; + softwareRenderer->currentWx = 0; softwareRenderer->lastY = GB_VIDEO_VERTICAL_PIXELS; + softwareRenderer->lastX = 0; softwareRenderer->hasWindow = false; softwareRenderer->wx = 0; softwareRenderer->model = model;

@@ -232,6 +234,9 @@ if (renderer->lastY > renderer->wy) {

renderer->currentWy = GB_VIDEO_VERTICAL_PIXELS; } else { renderer->currentWy = renderer->lastY - renderer->wy; + if (renderer->lastY == renderer->wy && renderer->lastX > renderer->wx) { + ++renderer->currentWy; + } } } else { renderer->currentWy += renderer->lastY;

@@ -489,6 +494,7 @@

static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, int startX, int endX, int y, struct GBObj* obj, size_t oamMax) { struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; softwareRenderer->lastY = y; + softwareRenderer->lastX = endX; uint8_t* maps = &softwareRenderer->d.vram[GB_BASE_MAP]; if (GBRegisterLCDCIsTileMap(softwareRenderer->lcdc)) { maps += GB_SIZE_MAP;

@@ -498,9 +504,10 @@ memset(&softwareRenderer->row[startX], 0, endX - startX);

} if (GBRegisterLCDCIsBgEnable(softwareRenderer->lcdc) || softwareRenderer->model >= GB_MODEL_CGB) { int wy = softwareRenderer->wy + softwareRenderer->currentWy; - if (GBRegisterLCDCIsWindow(softwareRenderer->lcdc) && wy <= y && endX >= softwareRenderer->wx - 7) { - if (softwareRenderer->wx - 7 > 0 && !softwareRenderer->d.disableBG) { - GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, startX, softwareRenderer->wx - 7, softwareRenderer->scx - softwareRenderer->offsetScx, softwareRenderer->scy + y - softwareRenderer->offsetScy); + int wx = softwareRenderer->wx + softwareRenderer->currentWx - 7; + if (GBRegisterLCDCIsWindow(softwareRenderer->lcdc) && wy <= y && wx <= endX) { + if (wx > 0 && !softwareRenderer->d.disableBG) { + GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, startX, wx, softwareRenderer->scx - softwareRenderer->offsetScx, softwareRenderer->scy + y - softwareRenderer->offsetScy); } maps = &softwareRenderer->d.vram[GB_BASE_MAP];

@@ -508,7 +515,7 @@ if (GBRegisterLCDCIsWindowTileMap(softwareRenderer->lcdc)) {

maps += GB_SIZE_MAP; } if (!softwareRenderer->d.disableWIN) { - GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, softwareRenderer->wx - 7, endX, 7 - softwareRenderer->wx - softwareRenderer->offsetWx, y - wy - softwareRenderer->offsetWy); + GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, wx, endX, -wx - softwareRenderer->offsetWx, y - wy - softwareRenderer->offsetWy); } } else if (!softwareRenderer->d.disableBG) { GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, startX, endX, softwareRenderer->scx - softwareRenderer->offsetScx, softwareRenderer->scy + y - softwareRenderer->offsetScy);

@@ -612,6 +619,9 @@

static void GBVideoSoftwareRendererFinishScanline(struct GBVideoRenderer* renderer, int y) { struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; + softwareRenderer->lastX = 0; + softwareRenderer->currentWx = 0; + if (softwareRenderer->sgbTransfer == 1) { size_t offset = 2 * ((y & 7) + (y >> 3) * GB_VIDEO_HORIZONTAL_PIXELS); if (offset >= 0x1000) {

@@ -702,7 +712,9 @@ break;

} } softwareRenderer->lastY = GB_VIDEO_VERTICAL_PIXELS; + softwareRenderer->lastX = 0; softwareRenderer->currentWy = 0; + softwareRenderer->currentWx = 0; softwareRenderer->hasWindow = false; }
M src/gb/video.csrc/gb/video.c

@@ -224,7 +224,6 @@ int32_t next;

++video->ly; video->p->memory.io[REG_LY] = video->ly; GBRegisterSTAT oldStat = video->stat; - video->stat = GBRegisterSTATSetLYC(video->stat, lyc == video->ly); if (video->ly < GB_VIDEO_VERTICAL_PIXELS) { next = GB_VIDEO_MODE_2_LENGTH; video->mode = 2;

@@ -246,6 +245,14 @@ video->stat = GBRegisterSTATSetMode(video->stat, video->mode);

if (!_statIRQAsserted(video, oldStat) && _statIRQAsserted(video, video->stat)) { video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT); } + + // LYC stat is delayed 1 T-cycle + oldStat = video->stat; + video->stat = GBRegisterSTATSetLYC(video->stat, lyc == video->ly); + if (!_statIRQAsserted(video, oldStat) && _statIRQAsserted(video, video->stat)) { + video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT); + } + GBUpdateIRQs(video->p); video->p->memory.io[REG_STAT] = video->stat; mTimingSchedule(timing, &video->modeEvent, (next << video->p->doubleSpeed) - cyclesLate);
M src/gba/io.csrc/gba/io.c

@@ -548,16 +548,16 @@ GBAAdjustWaitstates(gba, value);

break; case REG_IE: gba->memory.io[REG_IE >> 1] = value; - GBATestIRQ(gba->cpu, 1); + GBATestIRQ(gba, 1); return; case REG_IF: value = gba->memory.io[REG_IF >> 1] & ~value; gba->memory.io[REG_IF >> 1] = value; - GBATestIRQ(gba->cpu, 1); + GBATestIRQ(gba, 1); return; case REG_IME: gba->memory.io[REG_IME >> 1] = value; - GBATestIRQ(gba->cpu, 1); + GBATestIRQ(gba, 1); return; case REG_MAX: // Some bad interrupt libraries will write to this
M src/lr35902/debugger/cli-debugger.csrc/lr35902/debugger/cli-debugger.c

@@ -74,7 +74,7 @@ bytesRemaining += LR35902Decode(instruction, &info);

}; disPtr[0] = '\t'; ++disPtr; - LR35902Disassemble(&info, disPtr, sizeof(disassembly) - (disPtr - disassembly)); + LR35902Disassemble(&info, address, disPtr, sizeof(disassembly) - (disPtr - disassembly)); be->printf(be, "%s\n", disassembly); return address; }

@@ -87,6 +87,7 @@ be->printf(be, "B: %02X C: %02X (BC: %04X)\n", cpu->b, cpu->c, cpu->bc);

be->printf(be, "D: %02X E: %02X (DE: %04X)\n", cpu->d, cpu->e, cpu->de); 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); struct LR35902Debugger* platDebugger = (struct LR35902Debugger*) debugger->p->d.platform; size_t i;

@@ -96,7 +97,9 @@ }

if (i) { be->printf(be, "\n"); } - _printFlags(be, cpu->f); + if (platDebugger->printStatus) { + platDebugger->printStatus(debugger); + } _printLine(debugger->p, cpu->pc, cpu->memory.currentSegment(cpu, cpu->pc)); }
M src/lr35902/debugger/debugger.csrc/lr35902/debugger/debugger.c

@@ -75,21 +75,22 @@ static bool LR35902DebuggerGetRegister(struct mDebuggerPlatform*, const char* name, int32_t* value);

static bool LR35902DebuggerSetRegister(struct mDebuggerPlatform*, const char* name, int32_t value); struct mDebuggerPlatform* LR35902DebuggerPlatformCreate(void) { - struct mDebuggerPlatform* platform = (struct mDebuggerPlatform*) malloc(sizeof(struct LR35902Debugger)); - platform->entered = LR35902DebuggerEnter; - platform->init = LR35902DebuggerInit; - platform->deinit = LR35902DebuggerDeinit; - platform->setBreakpoint = LR35902DebuggerSetBreakpoint; - platform->listBreakpoints = LR35902DebuggerListBreakpoints; - platform->clearBreakpoint = LR35902DebuggerClearBreakpoint; - platform->setWatchpoint = LR35902DebuggerSetWatchpoint; - platform->listWatchpoints = LR35902DebuggerListWatchpoints; - platform->checkBreakpoints = LR35902DebuggerCheckBreakpoints; - platform->hasBreakpoints = LR35902DebuggerHasBreakpoints; - platform->trace = LR35902DebuggerTrace; - platform->getRegister = LR35902DebuggerGetRegister; - platform->setRegister = LR35902DebuggerSetRegister; - return platform; + struct LR35902Debugger* platform = malloc(sizeof(struct LR35902Debugger)); + platform->d.entered = LR35902DebuggerEnter; + platform->d.init = LR35902DebuggerInit; + platform->d.deinit = LR35902DebuggerDeinit; + platform->d.setBreakpoint = LR35902DebuggerSetBreakpoint; + platform->d.listBreakpoints = LR35902DebuggerListBreakpoints; + platform->d.clearBreakpoint = LR35902DebuggerClearBreakpoint; + platform->d.setWatchpoint = LR35902DebuggerSetWatchpoint; + platform->d.listWatchpoints = LR35902DebuggerListWatchpoints; + platform->d.checkBreakpoints = LR35902DebuggerCheckBreakpoints; + platform->d.hasBreakpoints = LR35902DebuggerHasBreakpoints; + platform->d.trace = LR35902DebuggerTrace; + platform->d.getRegister = LR35902DebuggerGetRegister; + platform->d.setRegister = LR35902DebuggerSetRegister; + platform->printStatus = NULL; + return &platform->d; } void LR35902DebuggerInit(void* cpu, struct mDebuggerPlatform* platform) {

@@ -215,7 +216,7 @@ };

disPtr[0] = ':'; disPtr[1] = ' '; disPtr += 2; - LR35902Disassemble(&info, disPtr, sizeof(disassembly) - (disPtr - disassembly)); + LR35902Disassemble(&info, address, disPtr, sizeof(disassembly) - (disPtr - disassembly)); *length = snprintf(out, *length, "A: %02X F: %02X B: %02X C: %02X D: %02X E: %02X H: %02X L: %02X SP: %04X PC: %02X:%04X | %s", cpu->a, cpu->f.packed, cpu->b, cpu->c,
M src/lr35902/decoder.csrc/lr35902/decoder.c

@@ -199,6 +199,7 @@ #define DEFINE_JR_INSTRUCTION_LR35902(CONDITION_NAME, CONDITION) \

DEFINE_DECODER_LR35902(JR ## CONDITION_NAME, \ info->mnemonic = LR35902_MN_JR; \ info->condition = CONDITION; \ + info->op1.flags = LR35902_OP_FLAG_RELATIVE; \ return 1;) #define DEFINE_CALL_INSTRUCTION_LR35902(CONDITION_NAME, CONDITION) \

@@ -314,15 +315,21 @@ DEFINE_POPPUSH_DECODER_LR35902(DE);

DEFINE_POPPUSH_DECODER_LR35902(HL); DEFINE_POPPUSH_DECODER_LR35902(AF); +#define DEFINE_CB_OP_DECODER_LR35902(NAME, BODY, OP) \ + DEFINE_DECODER_LR35902(NAME ## B, info->OP.reg = LR35902_REG_B; BODY) \ + DEFINE_DECODER_LR35902(NAME ## C, info->OP.reg = LR35902_REG_C; BODY) \ + DEFINE_DECODER_LR35902(NAME ## D, info->OP.reg = LR35902_REG_D; BODY) \ + DEFINE_DECODER_LR35902(NAME ## E, info->OP.reg = LR35902_REG_E; BODY) \ + DEFINE_DECODER_LR35902(NAME ## H, info->OP.reg = LR35902_REG_H; BODY) \ + DEFINE_DECODER_LR35902(NAME ## L, info->OP.reg = LR35902_REG_L; BODY) \ + DEFINE_DECODER_LR35902(NAME ## HL, info->OP.reg = LR35902_REG_HL; info->OP.flags = LR35902_OP_FLAG_MEMORY; BODY) \ + DEFINE_DECODER_LR35902(NAME ## A, info->OP.reg = LR35902_REG_A; BODY) + #define DEFINE_CB_2_DECODER_LR35902(NAME, BODY) \ - DEFINE_DECODER_LR35902(NAME ## B, info->op2.reg = LR35902_REG_B; BODY) \ - DEFINE_DECODER_LR35902(NAME ## C, info->op2.reg = LR35902_REG_C; BODY) \ - DEFINE_DECODER_LR35902(NAME ## D, info->op2.reg = LR35902_REG_D; BODY) \ - DEFINE_DECODER_LR35902(NAME ## E, info->op2.reg = LR35902_REG_E; BODY) \ - DEFINE_DECODER_LR35902(NAME ## H, info->op2.reg = LR35902_REG_H; BODY) \ - DEFINE_DECODER_LR35902(NAME ## L, info->op2.reg = LR35902_REG_L; BODY) \ - DEFINE_DECODER_LR35902(NAME ## HL, info->op2.reg = LR35902_REG_HL; info->op2.flags = LR35902_OP_FLAG_MEMORY; BODY) \ - DEFINE_DECODER_LR35902(NAME ## A, info->op2.reg = LR35902_REG_A; BODY) + DEFINE_CB_OP_DECODER_LR35902(NAME, BODY, op2) + +#define DEFINE_CB_1_DECODER_LR35902(NAME, BODY) \ + DEFINE_CB_OP_DECODER_LR35902(NAME, BODY, op1) #define DEFINE_CB_DECODER_LR35902(NAME, BODY) \ DEFINE_CB_2_DECODER_LR35902(NAME ## 0, info->op1.immediate = 0; BODY) \

@@ -339,17 +346,19 @@ DEFINE_CB_DECODER_LR35902(RES, info->mnemonic = LR35902_MN_RES)

DEFINE_CB_DECODER_LR35902(SET, info->mnemonic = LR35902_MN_SET) #define DEFINE_CB_X_DECODER_LR35902(NAME) \ - DEFINE_CB_2_DECODER_LR35902(NAME, info->mnemonic = LR35902_MN_ ## NAME) \ - DEFINE_DECODER_LR35902(NAME ## A_, info->mnemonic = LR35902_MN_ ## NAME; info->op1.reg = LR35902_REG_A) + DEFINE_CB_1_DECODER_LR35902(NAME, info->mnemonic = LR35902_MN_ ## NAME) \ + DEFINE_DECODER_LR35902(NAME ## A_, info->mnemonic = LR35902_MN_ ## NAME; \ + info->op1.flags = LR35902_OP_FLAG_IMPLICIT; \ + info->op1.reg = LR35902_REG_A;) DEFINE_CB_X_DECODER_LR35902(RL) DEFINE_CB_X_DECODER_LR35902(RLC) DEFINE_CB_X_DECODER_LR35902(RR) DEFINE_CB_X_DECODER_LR35902(RRC) -DEFINE_CB_2_DECODER_LR35902(SLA, info->mnemonic = LR35902_MN_SLA) -DEFINE_CB_2_DECODER_LR35902(SRA, info->mnemonic = LR35902_MN_SRA) -DEFINE_CB_2_DECODER_LR35902(SRL, info->mnemonic = LR35902_MN_SRL) -DEFINE_CB_2_DECODER_LR35902(SWAP, info->mnemonic = LR35902_MN_SWAP) +DEFINE_CB_1_DECODER_LR35902(SLA, info->mnemonic = LR35902_MN_SLA) +DEFINE_CB_1_DECODER_LR35902(SRA, info->mnemonic = LR35902_MN_SRA) +DEFINE_CB_1_DECODER_LR35902(SRL, info->mnemonic = LR35902_MN_SRL) +DEFINE_CB_1_DECODER_LR35902(SWAP, info->mnemonic = LR35902_MN_SWAP) DEFINE_DECODER_LR35902(DI, info->mnemonic = LR35902_MN_DI) DEFINE_DECODER_LR35902(EI, info->mnemonic = LR35902_MN_EI)

@@ -489,7 +498,7 @@ "ill"

}; -static int _decodeOperand(struct LR35902Operand op, char* buffer, int blen) { +static int _decodeOperand(struct LR35902Operand op, uint16_t pc, char* buffer, int blen) { int total = 0; if (op.flags & LR35902_OP_FLAG_IMPLICIT) { return 0;

@@ -503,7 +512,12 @@ if (op.reg) {

int written = snprintf(buffer, blen - 1, "%s", _lr35902Registers[op.reg]); ADVANCE(written); } else { - int written = snprintf(buffer, blen - 1, "$%02X", op.immediate); + int written; + if (op.flags & LR35902_OP_FLAG_RELATIVE) { + written = snprintf(buffer, blen - 1, "$%04X", pc + (int8_t) op.immediate); + } else { + written = snprintf(buffer, blen - 1, "$%02X", op.immediate); + } ADVANCE(written); if (op.reg) { strncpy(buffer, "+", blen - 1);

@@ -525,7 +539,7 @@ }

return total; } -int LR35902Disassemble(struct LR35902InstructionInfo* info, char* buffer, int blen) { +int LR35902Disassemble(struct LR35902InstructionInfo* info, uint16_t pc, char* buffer, int blen) { const char* mnemonic = _lr35902MnemonicStrings[info->mnemonic]; int written; int total = 0;

@@ -545,7 +559,7 @@ }

} if (info->op1.reg || info->op1.immediate || info->op2.reg || info->op2.immediate) { - written = _decodeOperand(info->op1, buffer, blen); + written = _decodeOperand(info->op1, pc, buffer, blen); ADVANCE(written); }

@@ -554,7 +568,7 @@ if (written) {

strncpy(buffer, ", ", blen - 1); ADVANCE(2); } - written = _decodeOperand(info->op2, buffer, blen); + written = _decodeOperand(info->op2, pc, buffer, blen); ADVANCE(written); }
M src/platform/qt/AbstractUpdater.cppsrc/platform/qt/AbstractUpdater.cpp

@@ -85,5 +85,7 @@ break;

} f.write(bytes); } + f.flush(); + f.close(); emit updateDone(true); }
M src/platform/qt/CMakeLists.txtsrc/platform/qt/CMakeLists.txt

@@ -183,7 +183,7 @@ AudioDevice.cpp)

list(APPEND SOURCE_FILES VideoDumper.cpp) if (WIN32 AND QT_STATIC) - list(APPEND QT_LIBRARIES Qt5::QWindowsAudioPlugin Qt5::DSServicePlugin + list(APPEND QT_LIBRARIES Qt5::QWindowsAudioPlugin Qt5::DSServicePlugin Qt5::QWindowsVistaStylePlugin strmiids mfuuid mfplat mf ksguid dxva2 evr d3d9) endif() list(APPEND QT_LIBRARIES Qt5::Multimedia)

@@ -287,15 +287,15 @@ endif()

if(QT_STATIC) find_library(QTPCRE NAMES qtpcre2 qtpcre) if(WIN32) - list(APPEND QT_LIBRARIES qwindows dwmapi imm32 uxtheme Qt5EventDispatcherSupport Qt5FontDatabaseSupport Qt5ThemeSupport) - set_target_properties(Qt5::Core PROPERTIES INTERFACE_LINK_LIBRARIES "${QTPCRE};version;winmm;ws2_32") + list(APPEND QT_LIBRARIES qwindows dwmapi imm32 uxtheme Qt5EventDispatcherSupport Qt5FontDatabaseSupport Qt5ThemeSupport Qt5WindowsUIAutomationSupport) + set_target_properties(Qt5::Core PROPERTIES INTERFACE_LINK_LIBRARIES "${QTPCRE};version;winmm;ssl;crypto;ws2_32;iphlpapi;crypt32;userenv;netapi32;wtsapi32") elseif(APPLE) find_package(Cups) find_package(Qt5PrintSupport) find_library(QTFREETYPE NAMES qtfreetype) find_library(QTHARFBUZZ NAMES qtharfbuzzng qtharfbuzz) find_library(QTPLATFORMSUPPORT NAMES Qt5PlatformSupport) - list(APPEND QT_LIBRARIES Cups Qt5::PrintSupport Qt5::QCocoaIntegrationPlugin Qt5::CoreAudioPlugin Qt5::AVFServicePlugin Qt5::QCocoaPrinterSupportPlugin ${QTPLATFORMSUPPORT} "-framework AVFoundation" "-framework CoreMedia") + list(APPEND QT_LIBRARIES Cups Qt5::PrintSupport Qt5::QCocoaIntegrationPlugin Qt5::CoreAudioPlugin Qt5::AVFServicePlugin Qt5::QCocoaPrinterSupportPlugin ${QTPLATFORMSUPPORT} "-framework AVFoundation" "-framework CoreMedia" "-framework SystemConfiguration" "-framework Security") set_target_properties(Qt5::Core PROPERTIES INTERFACE_LINK_LIBRARIES "${QTPCRE};${QTHARFBUZZ};${QTFREETYPE}") link_directories() endif()
M src/platform/qt/CoreManager.cppsrc/platform/qt/CoreManager.cpp

@@ -49,7 +49,7 @@ vf->close(vf);

vf = vfclone; } dir->close(dir); - loadGame(vf, fname, base); + return loadGame(vf, fname, base); } else { LOG(QT, ERROR) << tr("Failed to open game file: %1").arg(path); }
M src/platform/qt/VideoDumper.cppsrc/platform/qt/VideoDumper.cpp

@@ -23,14 +23,18 @@ QVideoFrame::PixelFormat vFormat = mappedFrame.pixelFormat();

QImage::Format format = QVideoFrame::imageFormatFromPixelFormat(vFormat); bool swap = false; if (format == QImage::Format_Invalid) { - vFormat = static_cast<QVideoFrame::PixelFormat>(vFormat - QVideoFrame::Format_BGRA32 + QVideoFrame::Format_ARGB32); - format = QVideoFrame::imageFormatFromPixelFormat(vFormat); - if (format == QImage::Format_ARGB32) { - format = QImage::Format_RGBA8888; - } else if (format == QImage::Format_ARGB32_Premultiplied) { - format = QImage::Format_RGBA8888_Premultiplied; + if (vFormat < QVideoFrame::Format_BGRA5658_Premultiplied) { + vFormat = static_cast<QVideoFrame::PixelFormat>(vFormat - QVideoFrame::Format_BGRA32 + QVideoFrame::Format_ARGB32); + format = QVideoFrame::imageFormatFromPixelFormat(vFormat); + if (format == QImage::Format_ARGB32) { + format = QImage::Format_RGBA8888; + } else if (format == QImage::Format_ARGB32_Premultiplied) { + format = QImage::Format_RGBA8888_Premultiplied; + } + swap = true; + } else { + return false; } - swap = true; } uchar* bits = mappedFrame.bits(); QImage image(bits, mappedFrame.width(), mappedFrame.height(), mappedFrame.bytesPerLine(), format);
M src/platform/qt/VideoView.uisrc/platform/qt/VideoView.ui

@@ -271,6 +271,11 @@ </property>

</item> <item> <property name="text"> + <string>HEVC (NVENC)</string> + </property> + </item> + <item> + <property name="text"> <string>VP8</string> </property> </item>
M src/platform/qt/Window.cppsrc/platform/qt/Window.cpp

@@ -1253,7 +1253,7 @@ #ifndef Q_OS_MAC

fileMenu->addSeparator(); #endif - QAction* about = new QAction(tr("About"), fileMenu); + QAction* about = new QAction(tr("About..."), fileMenu); connect(about, &QAction::triggered, openTView<AboutScreen>()); fileMenu->addAction(about);
M src/platform/qt/input/InputController.cppsrc/platform/qt/input/InputController.cpp

@@ -994,12 +994,23 @@ void InputController::setupCam() {

#ifdef BUILD_QT_MULTIMEDIA if (!m_camera) { m_camera = std::make_unique<QCamera>(); + connect(m_camera.get(), &QCamera::statusChanged, this, &InputController::prepareCamSettings); } - QVideoFrame::PixelFormat format(QVideoFrame::Format_RGB32); -#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)) + m_camera->setCaptureMode(QCamera::CaptureVideo); + m_camera->setViewfinder(&m_videoDumper); m_camera->load(); +#endif +} + +#ifdef BUILD_QT_MULTIMEDIA +void InputController::prepareCamSettings(QCamera::Status status) { + if (status != QCamera::LoadedStatus || m_camera->state() == QCamera::ActiveState) { + return; + } +#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)) + QVideoFrame::PixelFormat format(QVideoFrame::Format_RGB32); QCameraViewfinderSettings settings; - QSize size(1920, 1080); + QSize size(1280, 720); auto cameraRes = m_camera->supportedViewfinderResolutions(settings); for (auto& cameraSize : cameraRes) { if (cameraSize.width() < m_image.w || cameraSize.height() < m_image.h) {

@@ -1010,10 +1021,11 @@ size = cameraSize;

} } settings.setResolution(size); + auto cameraFormats = m_camera->supportedViewfinderPixelFormats(settings); auto goodFormats = m_videoDumper.supportedPixelFormats(); bool goodFormatFound = false; - for (auto& goodFormat : goodFormats) { + for (const auto& goodFormat : goodFormats) { if (cameraFormats.contains(goodFormat)) { settings.setPixelFormat(goodFormat); format = goodFormat;

@@ -1023,20 +1035,20 @@ }

} if (!goodFormatFound) { LOG(QT, WARN) << "Could not find a valid camera format!"; + for (const auto& format : cameraFormats) { + LOG(QT, WARN) << "Camera supported format: " << QString::number(format); + } } m_camera->setViewfinderSettings(settings); #endif - m_camera->setCaptureMode(QCamera::CaptureVideo); - m_camera->setViewfinder(&m_videoDumper); m_camera->start(); -#endif } +#endif void InputController::teardownCam() { #ifdef BUILD_QT_MULTIMEDIA if (m_camera) { m_camera->stop(); - m_camera.reset(); } #endif }
M src/platform/qt/input/InputController.hsrc/platform/qt/input/InputController.h

@@ -30,6 +30,7 @@ #endif

#ifdef BUILD_QT_MULTIMEDIA #include "VideoDumper.h" +#include <QCamera> #endif struct mRotationSource;

@@ -144,6 +145,9 @@ protected:

bool eventFilter(QObject*, QEvent*) override; private slots: +#ifdef BUILD_QT_MULTIMEDIA + void prepareCamSettings(QCamera::Status); +#endif void setupCam(); void teardownCam();
M src/platform/qt/main.cppsrc/platform/qt/main.cpp

@@ -21,6 +21,7 @@ #ifdef QT_STATIC

#include <QtPlugin> #ifdef Q_OS_WIN Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); +Q_IMPORT_PLUGIN(QWindowsVistaStylePlugin); #ifdef BUILD_QT_MULTIMEDIA Q_IMPORT_PLUGIN(QWindowsAudioPlugin); Q_IMPORT_PLUGIN(DSServicePlugin);