Merge branch 'master' (early part) into medusa

This commit is contained in:
Vicki Pfau 2019-06-28 17:17:41 -07:00
commit 23609b4a88
31 changed files with 319 additions and 113 deletions

13
CHANGES
View File

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

View File

@ -765,6 +765,7 @@ if(M_CORE_GB)
${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}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

View File

@ -38,6 +38,7 @@ enum Operation {
OP_NOT,
OP_SHIFT_L,
OP_SHIFT_R,
OP_DEREFERENCE,
};
struct Token {

View File

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

View File

@ -32,7 +32,9 @@ struct GBVideoSoftwareRenderer {
uint8_t wy;
uint8_t wx;
uint8_t currentWy;
uint8_t currentWx;
int lastY;
int lastX;
bool hasWindow;
GBRegisterLCDC lcdc;

View File

@ -20,6 +20,7 @@ struct LR35902Segment {
const char* name;
};
struct CLIDebuggerSystem;
struct LR35902Debugger {
struct mDebuggerPlatform d;
struct LR35902Core* cpu;
@ -31,6 +32,8 @@ struct LR35902Debugger {
ssize_t nextId;
const struct LR35902Segment* segments;
void (*printStatus)(struct CLIDebuggerSystem*);
};
struct mDebuggerPlatform* LR35902DebuggerPlatformCreate(void);

View File

@ -86,6 +86,7 @@ enum {
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 @@ struct LR35902InstructionInfo {
};
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

View File

@ -5,6 +5,7 @@
* 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 @@ static void _lexOperator(struct LexVector* lv, char operator, enum LexState* sta
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 @@ size_t lexExpression(struct LexVector* lv, const char* string, size_t length, co
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 @@ static const int _operatorPrecedence[] = {
[OP_NOT] = 2,
[OP_SHIFT_L] = 5,
[OP_SHIFT_R] = 5,
[OP_DEREFERENCE] = 2,
};
static struct ParseTree* _parseTreeCreate() {
@ -622,7 +655,7 @@ void parseFree(struct ParseTree* tree) {
}
}
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 @@ static bool _performOperation(enum Operation operation, int32_t current, int32_t
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 @@ bool mDebuggerEvaluateParseTree(struct mDebugger* debugger, struct ParseTree* tr
}
return mDebuggerEvaluateParseTree(debugger, tree->lhs, segment, NULL);
case TOKEN_OPERATOR_TYPE:
if (!mDebuggerEvaluateParseTree(debugger, tree->lhs, &lhs, 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;
}
if (!mDebuggerEvaluateParseTree(debugger, tree->rhs, &rhs, segment)) {
return false;
}
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:

View File

@ -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>
@ -42,20 +43,6 @@ static const struct mCoreChannelInfo _GBAudioChannels[] = {
{ 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[] = {
{ -1, "mem", "All", "All", 0, 0x10000, 0x10000, mCORE_MEMORY_VIRTUAL },
{ GB_REGION_CART_BANK0, "cart0", "ROM Bank", "Game Pak (32kiB)", GB_BASE_CART_BANK0, GB_SIZE_CART_BANK0 * 2, 0x800000, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED, 511 },
@ -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;

View File

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

View File

@ -630,7 +630,7 @@ void GBDetectModel(struct GB* gb) {
}
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;

View File

@ -190,7 +190,9 @@ static void GBVideoSoftwareRendererInit(struct GBVideoRenderer* renderer, enum G
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 @@ static void GBVideoSoftwareRendererUpdateWindow(struct GBVideoSoftwareRenderer*
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 GBVideoSoftwareRendererWriteOAM(struct GBVideoRenderer* renderer, ui
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 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i
}
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 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i
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 GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i
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 @@ static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer)
}
}
softwareRenderer->lastY = GB_VIDEO_VERTICAL_PIXELS;
softwareRenderer->lastX = 0;
softwareRenderer->currentWy = 0;
softwareRenderer->currentWx = 0;
softwareRenderer->hasWindow = false;
}

View File

@ -224,7 +224,6 @@ void _endMode0(struct mTiming* timing, void* context, uint32_t cyclesLate) {
++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 @@ void _endMode0(struct mTiming* timing, void* context, uint32_t cyclesLate) {
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);

View File

@ -548,16 +548,16 @@ void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t 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

View File

@ -74,7 +74,7 @@ static inline uint16_t _printLine(struct CLIDebugger* debugger, uint16_t address
};
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 @@ static void _printStatus(struct CLIDebuggerSystem* debugger) {
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 @@ static void _printStatus(struct CLIDebuggerSystem* debugger) {
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));
}

View File

@ -75,21 +75,22 @@ static bool LR35902DebuggerGetRegister(struct mDebuggerPlatform*, const char* na
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 @@ static void LR35902DebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t*
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,

View File

@ -199,6 +199,7 @@ DEFINE_DECODER_LR35902(ADDSP, info->mnemonic = LR35902_MN_ADD; \
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 @@ static const char* _lr35902MnemonicStrings[] = {
};
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 @@ static int _decodeOperand(struct LR35902Operand op, char* buffer, int blen) {
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 @@ static int _decodeOperand(struct LR35902Operand op, char* buffer, int blen) {
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 @@ int LR35902Disassemble(struct LR35902InstructionInfo* info, char* buffer, int bl
}
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 @@ int LR35902Disassemble(struct LR35902InstructionInfo* info, char* buffer, int bl
strncpy(buffer, ", ", blen - 1);
ADVANCE(2);
}
written = _decodeOperand(info->op2, buffer, blen);
written = _decodeOperand(info->op2, pc, buffer, blen);
ADVANCE(written);
}

View File

@ -85,5 +85,7 @@ void AbstractUpdater::updateDownloaded(QNetworkReply* reply) {
}
f.write(bytes);
}
f.flush();
f.close();
emit updateDone(true);
}

View File

@ -183,7 +183,7 @@ if(Qt5Multimedia_FOUND)
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()

View File

@ -49,7 +49,7 @@ CoreController* CoreManager::loadGame(const QString& path) {
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);
}

View File

@ -23,14 +23,18 @@ bool VideoDumper::present(const QVideoFrame& frame) {
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);

View File

@ -269,6 +269,11 @@
<string>HEVC</string>
</property>
</item>
<item>
<property name="text">
<string>HEVC (NVENC)</string>
</property>
</item>
<item>
<property name="text">
<string>VP8</string>

View File

@ -1253,7 +1253,7 @@ void Window::setupMenu(QMenuBar* menubar) {
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);

View File

@ -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 @@ void InputController::setupCam() {
}
}
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 @@ void InputController::setupCam() {
}
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
}

View File

@ -30,6 +30,7 @@
#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();

View File

@ -21,6 +21,7 @@
#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);