Core: Expose more ROM information from the API

This commit is contained in:
Vicki Pfau 2024-08-10 21:23:00 -07:00
parent ff216ad83b
commit 8ab2681bca
18 changed files with 129 additions and 109 deletions

View File

@ -49,6 +49,7 @@ Misc:
- Qt: Handle multiple save game files for disparate games separately (fixes mgba.io/i/2887)
- Qt: Remove maligned double-click-to-fullscreen shortcut (closes mgba.io/i/2632)
- Qt: Pass logging context through to video proxy thread (fixes mgba.io/i/3095)
- Qt: Show maker code and game version in ROM info
- Scripting: Add `callbacks:oneshot` for single-call callbacks
- Switch: Add bilinear filtering option (closes mgba.io/i/3111)
- Vita: Add imc0 and xmc0 mount point support

View File

@ -119,8 +119,7 @@ struct mCore {
int32_t (*frameCycles)(const struct mCore*);
int32_t (*frequency)(const struct mCore*);
void (*getGameTitle)(const struct mCore*, char* title);
void (*getGameCode)(const struct mCore*, char* title);
void (*getGameInfo)(const struct mCore*, struct mGameInfo* info);
void (*setPeripheral)(struct mCore*, int type, void*);
void* (*getPeripheral)(struct mCore*, int type);

View File

@ -22,6 +22,14 @@ enum mCoreFeature {
mCORE_FEATURE_OPENGL = 1,
};
struct mGameInfo {
char title[17];
char system[4];
char code[5];
char maker[3];
uint8_t version;
};
struct mCoreCallbacks {
void* context;
void (*videoFrameStarted)(void* context);

View File

@ -190,8 +190,7 @@ void GBSavedataUnmask(struct GB* gb);
struct Patch;
void GBApplyPatch(struct GB* gb, struct Patch* patch);
void GBGetGameTitle(const struct GB* gba, char* out);
void GBGetGameCode(const struct GB* gba, char* out);
void GBGetGameInfo(const struct GB* gba, struct mGameInfo* info);
void GBTestKeypadIRQ(struct GB* gb);

View File

@ -182,8 +182,7 @@ void GBAUnloadMB(struct GBA* gba);
bool GBALoadNull(struct GBA* gba);
void GBAGetGameCode(const struct GBA* gba, char* out);
void GBAGetGameTitle(const struct GBA* gba, char* out);
void GBAGetGameInfo(const struct GBA* gba, struct mGameInfo* info);
void GBATestKeypadIRQ(struct GBA* gba);

View File

@ -6,6 +6,7 @@
#include <mgba/core/library.h>
#include <mgba/core/core.h>
#include <mgba-util/string.h>
#include <mgba-util/vfs.h>
#ifdef USE_SQLITE3
@ -291,8 +292,10 @@ bool _mLibraryAddEntry(struct mLibrary* library, const char* filename, const cha
core->init(core);
core->loadROM(core, vf);
core->getGameTitle(core, entry.internalTitle);
core->getGameCode(core, entry.internalCode);
struct mGameInfo info;
core->getGameInfo(core, &info);
snprintf(entry.internalCode, sizeof(entry.internalCode), "%s-%s", info.system, info.code);
strlcpy(entry.internalTitle, info.title, sizeof(entry.internalTitle));
core->checksum(core, &entry.crc32, mCHECKSUM_CRC32);
entry.platform = core->platform(core);
entry.title = NULL;

View File

@ -332,15 +332,15 @@ mSCRIPT_DEFINE_STRUCT(mScriptMemoryDomain)
mSCRIPT_DEFINE_END;
static struct mScriptValue* _mScriptCoreGetGameTitle(const struct mCore* core) {
char title[32] = {0};
core->getGameTitle(core, title);
return mScriptStringCreateFromASCII(title);
struct mGameInfo info;
core->getGameInfo(core, &info);
return mScriptStringCreateFromASCII(info.title);
}
static struct mScriptValue* _mScriptCoreGetGameCode(const struct mCore* core) {
char code[16] = {0};
core->getGameCode(core, code);
return mScriptStringCreateFromASCII(code);
struct mGameInfo info;
core->getGameInfo(core, &info);
return mScriptStringCreateFromASCII(info.code);
}
static struct mScriptValue* _mScriptCoreChecksum(const struct mCore* core, int t) {

View File

@ -781,12 +781,8 @@ static int32_t _GBCoreFrequency(const struct mCore* core) {
return DMG_SM83_FREQUENCY;
}
static void _GBCoreGetGameTitle(const struct mCore* core, char* title) {
GBGetGameTitle(core->board, title);
}
static void _GBCoreGetGameCode(const struct mCore* core, char* title) {
GBGetGameCode(core->board, title);
static void _GBCoreGetGameInfo(const struct mCore* core, struct mGameInfo* info) {
GBGetGameInfo(core->board, info);
}
static void _GBCoreSetPeripheral(struct mCore* core, int type, void* periph) {
@ -1332,8 +1328,7 @@ struct mCore* GBCoreCreate(void) {
core->frameCounter = _GBCoreFrameCounter;
core->frameCycles = _GBCoreFrameCycles;
core->frequency = _GBCoreFrequency;
core->getGameTitle = _GBCoreGetGameTitle;
core->getGameCode = _GBCoreGetGameCode;
core->getGameInfo = _GBCoreGetGameInfo;
core->setPeripheral = _GBCoreSetPeripheral;
core->getPeripheral = _GBCoreGetPeripheral;
core->busRead8 = _GBCoreBusRead8;

View File

@ -16,6 +16,7 @@
#include <mgba-util/memory.h>
#include <mgba-util/math.h>
#include <mgba-util/patch.h>
#include <mgba-util/string.h>
#include <mgba-util/vfs.h>
const uint32_t CGB_SM83_FREQUENCY = 0x800000;
@ -1116,38 +1117,28 @@ bool GBIsROM(struct VFile* vf) {
return false;
}
void GBGetGameTitle(const struct GB* gb, char* out) {
void GBGetGameInfo(const struct GB* gb, struct mGameInfo* info) {
memset(info, 0, sizeof(*info));
const struct GBCartridge* cart = NULL;
if (gb->memory.rom) {
cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
}
if (!cart) {
return;
}
if (cart->oldLicensee != 0x33) {
memcpy(out, cart->titleLong, 16);
} else {
memcpy(out, cart->titleShort, 11);
}
}
void GBGetGameCode(const struct GB* gb, char* out) {
memset(out, 0, 8);
const struct GBCartridge* cart = NULL;
if (gb->memory.rom) {
cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
}
if (!cart) {
return;
}
if (cart->cgb == 0xC0) {
memcpy(out, "CGB-????", 8);
strlcpy(info->system, "CGB", sizeof(info->system));
} else {
memcpy(out, "DMG-????", 8);
strlcpy(info->system, "DMG", sizeof(info->system));
}
if (cart->oldLicensee == 0x33) {
memcpy(&out[4], cart->maker, 4);
if (cart->oldLicensee != 0x33) {
memcpy(info->title, cart->titleLong, 16);
snprintf(info->maker, sizeof(info->maker), "%02X", cart->oldLicensee);
} else {
memcpy(info->title, cart->titleShort, 11);
memcpy(info->code, cart->maker, 4);
memcpy(info->maker, &cart->licensee, 2);
}
info->version = cart->version;
}
void GBFrameStarted(struct GB* gb) {

View File

@ -870,12 +870,8 @@ static int32_t _GBACoreFrequency(const struct mCore* core) {
return GBA_ARM7TDMI_FREQUENCY;
}
static void _GBACoreGetGameTitle(const struct mCore* core, char* title) {
GBAGetGameTitle(core->board, title);
}
static void _GBACoreGetGameCode(const struct mCore* core, char* title) {
GBAGetGameCode(core->board, title);
static void _GBACoreGetGameInfo(const struct mCore* core, struct mGameInfo* info) {
GBAGetGameInfo(core->board, info);
}
static void _GBACoreSetPeripheral(struct mCore* core, int type, void* periph) {
@ -1550,8 +1546,7 @@ struct mCore* GBACoreCreate(void) {
core->frameCounter = _GBACoreFrameCounter;
core->frameCycles = _GBACoreFrameCycles;
core->frequency = _GBACoreFrequency;
core->getGameTitle = _GBACoreGetGameTitle;
core->getGameCode = _GBACoreGetGameCode;
core->getGameInfo = _GBACoreGetGameInfo;
core->setPeripheral = _GBACoreSetPeripheral;
core->getPeripheral = _GBACoreGetPeripheral;
core->busRead8 = _GBACoreBusRead8;

View File

@ -18,6 +18,7 @@
#include <mgba-util/crc32.h>
#include <mgba-util/math.h>
#include <mgba-util/memory.h>
#include <mgba-util/string.h>
#include <mgba-util/vfs.h>
#ifdef USE_ELF
@ -849,26 +850,24 @@ bool GBAIsBIOS(struct VFile* vf) {
return true;
}
void GBAGetGameCode(const struct GBA* gba, char* out) {
memset(out, 0, 8);
if (!gba->memory.rom) {
return;
}
memcpy(out, "AGB-", 4);
memcpy(&out[4], &((struct GBACartridge*) gba->memory.rom)->id, 4);
}
void GBAGetGameTitle(const struct GBA* gba, char* out) {
void GBAGetGameInfo(const struct GBA* gba, struct mGameInfo* info) {
memset(info, 0, sizeof(*info));
strlcpy(info->system, "AGB", sizeof(info->system));
struct GBACartridge* cart = NULL;
if (gba->memory.rom) {
memcpy(out, &((struct GBACartridge*) gba->memory.rom)->title, 12);
return;
cart = (struct GBACartridge*) gba->memory.rom;
} else if (gba->isPristine && gba->memory.wram) {
cart = (struct GBACartridge*) gba->memory.wram;
}
if (gba->isPristine && gba->memory.wram) {
memcpy(out, &((struct GBACartridge*) gba->memory.wram)->title, 12);
return;
if (cart) {
memcpy(info->title, &cart->title, 12);
memcpy(info->code, &cart->id, 4);
memcpy(info->maker, &cart->maker, 2);
info->version = cart->version;
} else {
strlcpy(info->title, "(BIOS)", 12);
}
strncpy(out, "(BIOS)", 12);
}
void GBAHitStub(struct ARMCore* cpu, uint32_t opcode) {

View File

@ -30,12 +30,11 @@ BattleChipView::BattleChipView(std::shared_ptr<CoreController> controller, Windo
m_ui.setupUi(this);
m_ui.chipList->setModel(&m_model);
char title[9];
CoreController::Interrupter interrupter(m_controller);
mCore* core = m_controller->thread()->core;
title[8] = '\0';
core->getGameCode(core, title);
QString qtitle(title);
mGameInfo info;
core->getGameInfo(core, &info);
QString qtitle(info.title);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
int size = QFontMetrics(QFont()).height() / ((int) ceil(devicePixelRatioF()) * 12);
@ -101,11 +100,11 @@ BattleChipView::BattleChipView(std::shared_ptr<CoreController> controller, Windo
m_controller->attachBattleChipGate();
setFlavor(4);
if (qtitle.startsWith("AGB-B4B") || qtitle.startsWith("AGB-B4W") || qtitle.startsWith("AGB-BR4") || qtitle.startsWith("AGB-BZ3")) {
if (qtitle.startsWith("B4B") || qtitle.startsWith("B4W") || qtitle.startsWith("BR4") || qtitle.startsWith("BZ3")) {
m_ui.gateBattleChip->setChecked(true);
} else if (qtitle.startsWith("AGB-BRB") || qtitle.startsWith("AGB-BRK")) {
} else if (qtitle.startsWith("BRB") || qtitle.startsWith("BRK")) {
m_ui.gateProgress->setChecked(true);
} else if (qtitle.startsWith("AGB-BR5") || qtitle.startsWith("AGB-BR6")) {
} else if (qtitle.startsWith("BR5") || qtitle.startsWith("BR6")) {
m_ui.gateBeastLink->setChecked(true);
}

View File

@ -1318,9 +1318,9 @@ void CoreController::updateROMInfo() {
mCore* core = m_threadContext.core;
core->checksum(core, &m_crc32, mCHECKSUM_CRC32);
char gameTitle[17] = { '\0' };
core->getGameTitle(core, gameTitle);
m_internalTitle = QLatin1String(gameTitle);
mGameInfo info;
core->getGameInfo(core, &info);
m_internalTitle = QLatin1String(info.title);
#ifdef USE_SQLITE3
if (db && m_crc32 && NoIntroDBLookupGameByCRC(db, m_crc32, &game)) {

View File

@ -14,9 +14,9 @@ void GBAOverride::identify(const struct mCore* core) {
if (core->platform(core) != mPLATFORM_GBA) {
return;
}
char gameId[8];
core->getGameCode(core, gameId);
memcpy(override.id, &gameId[4], 4);
mGameInfo info;
core->getGameInfo(core, &info);
memcpy(override.id, info.code, 4);
}
void GBAOverride::save(struct Configuration* config) const {

View File

@ -27,16 +27,16 @@ ROMInfo::ROMInfo(std::shared_ptr<CoreController> controller, QWidget* parent)
CoreController::Interrupter interrupter(controller);
mCore* core = controller->thread()->core;
char title[17] = {};
core->getGameTitle(core, title);
m_ui.title->setText(QLatin1String(title));
title[8] = '\0';
core->getGameCode(core, title);
if (title[0]) {
m_ui.id->setText(QLatin1String(title));
mGameInfo info;
core->getGameInfo(core, &info);
m_ui.title->setText(QLatin1String(info.title));
if (info.code[0]) {
m_ui.id->setText(QLatin1String(info.code));
} else {
m_ui.id->setText(tr("(unknown)"));
}
m_ui.maker->setText(QLatin1String(info.maker));
m_ui.version->setText(QString::number(info.version));
core->checksum(core, &crc32, mCHECKSUM_CRC32);

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>236</width>
<height>146</height>
<width>178</width>
<height>198</height>
</rect>
</property>
<property name="windowTitle">
@ -75,13 +75,47 @@
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Maker Code:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="maker">
<property name="text">
<string notr="true">{MAKER}</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Revision:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="version">
<property name="text">
<string notr="true">{VERSION}</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>File size:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<item row="5" column="1">
<widget class="QLabel" name="size">
<property name="text">
<string notr="true">{SIZE}</string>
@ -91,14 +125,14 @@
</property>
</widget>
</item>
<item row="4" column="0">
<item row="6" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>CRC32:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<item row="6" column="1">
<widget class="QLabel" name="crc">
<property name="text">
<string notr="true">{CRC}</string>
@ -108,14 +142,14 @@
</property>
</widget>
</item>
<item row="5" column="0">
<item row="7" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Save file:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<item row="7" column="1">
<widget class="QLabel" name="savefile">
<property name="text">
<string notr="true">{SAVEFILE}</string>

View File

@ -497,17 +497,16 @@ void ReportView::addROMInfo(QStringList& report, CoreController* controller) {
report << QString("Currently paused: %1").arg(yesNo[controller->isPaused()]);
mCore* core = controller->thread()->core;
char title[17] = {};
core->getGameTitle(core, title);
report << QString("Internal title: %1").arg(QLatin1String(title));
title[8] = '\0';
core->getGameCode(core, title);
if (title[0]) {
report << QString("Game code: %1").arg(QLatin1String(title));
struct mGameInfo info;
core->getGameInfo(core, &info);
report << QString("Internal title: %1").arg(QLatin1String(info.title));
if (info.code[0]) {
report << QString("Game code: %1").arg(QLatin1String(info.code));
} else {
report << QString("Invalid game code");
}
report << QString("Game maker: %1").arg(QLatin1String(info.maker));
report << QString("Game version: %1").arg(info.version);
uint32_t crc32 = 0;
core->checksum(core, &crc32, mCHECKSUM_CRC32);

View File

@ -196,8 +196,6 @@ bool _mPerfRunCore(const char* fname, const struct mArguments* args, const struc
}
// TODO: Put back debugger
char gameCode[9] = { 0 };
core->init(core);
if (!perfOpts->noVideo) {
core->setVideoBuffer(core, _outputBuffer, 256);
@ -226,7 +224,8 @@ bool _mPerfRunCore(const char* fname, const struct mArguments* args, const struc
mCoreLoadStateNamed(core, _savestate, 0);
}
core->getGameCode(core, gameCode);
struct mGameInfo info;
core->getGameInfo(core, &info);
int frames = perfOpts->frames;
if (!frames) {
@ -255,7 +254,7 @@ bool _mPerfRunCore(const char* fname, const struct mArguments* args, const struc
} else {
rendererName = "software";
}
snprintf(buffer, sizeof(buffer), "%s,%i,%" PRIu64 ",%s\n", gameCode, frames, duration, rendererName);
snprintf(buffer, sizeof(buffer), "%s-%s,%i,%" PRIu64 ",%s\n", info.system, info.code, frames, duration, rendererName);
printf("%s", buffer);
if (_socket != INVALID_SOCKET) {
SocketSend(_socket, buffer, strlen(buffer));