From e00987ddeba29be7aad3ecd82deae990f55fc43b Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 7 May 2021 14:37:19 -0700 Subject: [PATCH] GB: Support for combo "Super Game Boy Color" SGB + GBC ROM hacks --- CHANGES | 1 + include/mgba/gb/interface.h | 3 ++- src/gb/core.c | 2 ++ src/gb/gb.c | 12 +++++++++--- src/gb/renderers/software.c | 6 +++--- src/gb/video.c | 8 ++++---- src/platform/qt/GameBoy.cpp | 2 ++ 7 files changed, 23 insertions(+), 11 deletions(-) diff --git a/CHANGES b/CHANGES index 86492cdfc..f7821075a 100644 --- a/CHANGES +++ b/CHANGES @@ -3,6 +3,7 @@ Features: - Presets for Game Boy palettes - Tool for converting scanned pictures of e-Reader cards to raw dotcode data - Cheat code support in homebrew ports + - Support for combo "Super Game Boy Color" SGB + GBC ROM hacks Emulation fixes: - GB Video: Clear VRAM on reset (fixes mgba.io/i/2152) - GBA Video: Revert scanline latching changes (fixes mgba.io/i/2153, mgba.io/i/2149) diff --git a/include/mgba/gb/interface.h b/include/mgba/gb/interface.h index 20eccd38e..420a81840 100644 --- a/include/mgba/gb/interface.h +++ b/include/mgba/gb/interface.h @@ -17,8 +17,9 @@ enum GBModel { GB_MODEL_DMG = 0x00, GB_MODEL_SGB = 0x20, GB_MODEL_MGB = 0x40, - GB_MODEL_SGB2 = 0x60, + GB_MODEL_SGB2 = GB_MODEL_MGB | GB_MODEL_SGB, GB_MODEL_CGB = 0x80, + GB_MODEL_SCGB = GB_MODEL_CGB | GB_MODEL_SGB, GB_MODEL_AGB = 0xC0 }; diff --git a/src/gb/core.c b/src/gb/core.c index 3b0d8de34..784bc51cc 100644 --- a/src/gb/core.c +++ b/src/gb/core.c @@ -560,6 +560,7 @@ static void _GBCoreReset(struct mCore* core) { break; case GB_MODEL_CGB: case GB_MODEL_AGB: + case GB_MODEL_SCGB: configPath = mCoreConfigGetValue(&core->config, "gbc.bios"); break; default: @@ -589,6 +590,7 @@ static void _GBCoreReset(struct mCore* core) { break; case GB_MODEL_CGB: case GB_MODEL_AGB: + case GB_MODEL_SCGB: strncat(path, PATH_SEP "gbc_bios.bin", PATH_MAX - strlen(path)); break; default: diff --git a/src/gb/gb.c b/src/gb/gb.c index ad3f3bbcb..b94d7f482 100644 --- a/src/gb/gb.c +++ b/src/gb/gb.c @@ -546,6 +546,7 @@ void GBSkipBIOS(struct GB* gb) { cpu->b = 1; // Fall through case GB_MODEL_CGB: + case GB_MODEL_SCGB: cpu->a = 0x11; if (gb->model == GB_MODEL_AGB) { cpu->f.packed = 0x00; @@ -671,6 +672,7 @@ void GBDetectModel(struct GB* gb) { break; case GB_MODEL_AGB: case GB_MODEL_CGB: + case GB_MODEL_SCGB: gb->audio.style = GB_AUDIO_CGB; break; } @@ -932,11 +934,11 @@ void GBFrameEnded(struct GB* gb) { } enum GBModel GBNameToModel(const char* model) { - if (strcasecmp(model, "DMG") == 0) { + if (strcasecmp(model, "DMG") == 0 || strcasecmp(model, "GB") == 0) { return GB_MODEL_DMG; - } else if (strcasecmp(model, "CGB") == 0) { + } else if (strcasecmp(model, "CGB") == 0 || strcasecmp(model, "GBC") == 0) { return GB_MODEL_CGB; - } else if (strcasecmp(model, "AGB") == 0) { + } else if (strcasecmp(model, "AGB") == 0 || strcasecmp(model, "GBA") == 0) { return GB_MODEL_AGB; } else if (strcasecmp(model, "SGB") == 0) { return GB_MODEL_SGB; @@ -944,6 +946,8 @@ enum GBModel GBNameToModel(const char* model) { return GB_MODEL_MGB; } else if (strcasecmp(model, "SGB2") == 0) { return GB_MODEL_SGB2; + } else if (strcasecmp(model, "SCGB") == 0 || strcasecmp(model, "SGBC") == 0) { + return GB_MODEL_SCGB; } return GB_MODEL_AUTODETECT; } @@ -962,6 +966,8 @@ const char* GBModelToName(enum GBModel model) { return "CGB"; case GB_MODEL_AGB: return "AGB"; + case GB_MODEL_SCGB: + return "SCGB"; default: case GB_MODEL_AUTODETECT: return NULL; diff --git a/src/gb/renderers/software.c b/src/gb/renderers/software.c index f023d99b4..acbe5a0a8 100644 --- a/src/gb/renderers/software.c +++ b/src/gb/renderers/software.c @@ -629,7 +629,7 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i int p = 0; switch (softwareRenderer->d.sgbRenderMode) { case 0: - if (softwareRenderer->model & GB_MODEL_SGB) { + if ((softwareRenderer->model & (GB_MODEL_SGB | GB_MODEL_CGB)) == GB_MODEL_SGB) { p = softwareRenderer->d.sgbAttributes[(startX >> 5) + 5 * (y >> 3)]; p >>= 6 - ((x / 4) & 0x6); p &= 3; @@ -639,7 +639,7 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i row[x] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x] & OBJ_PRIO_MASK]]; } for (; x + 7 < (endX & ~7); x += 8) { - if (softwareRenderer->model & GB_MODEL_SGB) { + if ((softwareRenderer->model & (GB_MODEL_SGB | GB_MODEL_CGB)) == GB_MODEL_SGB) { p = softwareRenderer->d.sgbAttributes[(x >> 5) + 5 * (y >> 3)]; p >>= 6 - ((x / 4) & 0x6); p &= 3; @@ -654,7 +654,7 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i row[x + 6] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x + 6] & OBJ_PRIO_MASK]]; row[x + 7] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x + 7] & OBJ_PRIO_MASK]]; } - if (softwareRenderer->model & GB_MODEL_SGB) { + if ((softwareRenderer->model & (GB_MODEL_SGB | GB_MODEL_CGB)) == GB_MODEL_SGB) { p = softwareRenderer->d.sgbAttributes[(x >> 5) + 5 * (y >> 3)]; p >>= 6 - ((x / 4) & 0x6); p &= 3; diff --git a/src/gb/video.c b/src/gb/video.c index 6331bdb45..cd0d28778 100644 --- a/src/gb/video.c +++ b/src/gb/video.c @@ -238,7 +238,7 @@ void GBVideoSkipBIOS(struct GBVideo* video) { video->modeEvent.callback = _endMode1; int32_t next; - if (video->p->model == GB_MODEL_CGB) { + if (video->p->model & GB_MODEL_CGB) { video->ly = GB_VIDEO_VERTICAL_PIXELS; video->p->memory.io[GB_REG_LY] = video->ly; video->stat = GBRegisterSTATClearLYC(video->stat); @@ -536,9 +536,7 @@ void GBVideoWritePalette(struct GBVideo* video, uint16_t address, uint8_t value) video->renderer->writePalette(video->renderer, 9 * 4 + 3, video->palette[9 * 4 + 3]); break; } - } else if (video->p->model & GB_MODEL_SGB) { - video->renderer->writeVideoRegister(video->renderer, address, value); - } else { + } else if (video->p->model >= GB_MODEL_CGB) { switch (address) { case GB_REG_BCPD: if (video->mode != 3) { @@ -579,6 +577,8 @@ void GBVideoWritePalette(struct GBVideo* video, uint16_t address, uint8_t value) video->p->memory.io[GB_REG_OCPD] = video->palette[8 * 4 + (video->ocpIndex >> 1)] >> (8 * (video->ocpIndex & 1)); break; } + } else { + video->renderer->writeVideoRegister(video->renderer, address, value); } } diff --git a/src/platform/qt/GameBoy.cpp b/src/platform/qt/GameBoy.cpp index 63f26f1c1..1748152d7 100644 --- a/src/platform/qt/GameBoy.cpp +++ b/src/platform/qt/GameBoy.cpp @@ -15,6 +15,7 @@ static const QList s_gbModelList{ GB_MODEL_SGB, GB_MODEL_CGB, GB_MODEL_AGB, + GB_MODEL_SCGB, }; static const QList s_mbcList{ @@ -58,6 +59,7 @@ QString GameBoy::modelName(GBModel model) { s_gbModelNames[GB_MODEL_SGB2] = tr("Super Game Boy 2 (SGB)"); s_gbModelNames[GB_MODEL_CGB] = tr("Game Boy Color (CGB)"); s_gbModelNames[GB_MODEL_AGB] = tr("Game Boy Advance (AGB)"); + s_gbModelNames[GB_MODEL_SCGB] = tr("Super Game Boy Color (SGB + CGB)"); } return s_gbModelNames[model];