From cb7bc351138da46a41990ce52f08fa3b1cc4a3b1 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Fri, 21 Aug 2015 00:14:22 -0700 Subject: [PATCH] GBA: Add "GBAContext" for threadless operation and use with libretro --- src/gba/supervisor/context.c | 156 +++++++++++++++++++++++++++++++ src/gba/supervisor/context.h | 38 ++++++++ src/platform/libretro/libretro.c | 82 +++++++--------- 3 files changed, 227 insertions(+), 49 deletions(-) create mode 100644 src/gba/supervisor/context.c create mode 100644 src/gba/supervisor/context.h diff --git a/src/gba/supervisor/context.c b/src/gba/supervisor/context.c new file mode 100644 index 000000000..c4161c763 --- /dev/null +++ b/src/gba/supervisor/context.c @@ -0,0 +1,156 @@ +/* Copyright (c) 2013-2015 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 "gba/supervisor/context.h" + +#include "gba/supervisor/overrides.h" + +#include "util/memory.h" +#include "util/vfs.h" + +bool GBAContextInit(struct GBAContext* context, const char* port) { + context->gba = anonymousMemoryMap(sizeof(struct GBA)); + context->cpu = anonymousMemoryMap(sizeof(struct ARMCore)); + context->rom = 0; + context->save = 0; + context->renderer = 0; + + if (!context->gba || !context->cpu) { + if (context->gba) { + mappedMemoryFree(context->gba, sizeof(struct GBA)); + } + if (context->cpu) { + mappedMemoryFree(context->cpu, sizeof(struct ARMCore)); + } + return false; + } + + GBAConfigInit(&context->config, port); + if (port) { + GBAConfigLoad(&context->config); + } + + GBACreate(context->gba); + ARMSetComponents(context->cpu, &context->gba->d, 0, 0); + ARMInit(context->cpu); + + context->gba->sync = 0; + return true; +} + +void GBAContextDeinit(struct GBAContext* context) { + if (context->bios) { + context->bios->close(context->bios); + context->bios = 0; + } + if (context->rom) { + context->rom->close(context->rom); + context->rom = 0; + } + if (context->save) { + context->save->close(context->save); + context->save = 0; + } + ARMDeinit(context->cpu); + GBADestroy(context->gba); + mappedMemoryFree(context->gba, 0); + mappedMemoryFree(context->cpu, 0); + GBAConfigDeinit(&context->config); +} + +bool GBAContextLoadROM(struct GBAContext* context, const char* path, bool autoloadSave) { + context->rom = VFileOpen(path, O_RDONLY); + if (!context->rom) { + return false; + } + + if (!GBAIsROM(context->rom)) { + context->rom->close(context->rom); + context->rom = 0; + return false; + } + + if (autoloadSave) { + context->save = VDirOptionalOpenFile(0, path, 0, ".sav", O_RDWR | O_CREAT); + } + return true; +} + +bool GBAContextLoadROMFromVFile(struct GBAContext* context, struct VFile* rom, struct VFile* save) { + context->rom = rom; + if (!GBAIsROM(context->rom)) { + context->rom = 0; + return false; + } + context->save = save; + return true; +} + +bool GBAContextLoadBIOS(struct GBAContext* context, const char* path) { + context->bios = VFileOpen(path, O_RDONLY); + if (!context->bios) { + return false; + } + + if (!GBAIsBIOS(context->bios)) { + context->bios->close(context->bios); + context->bios = 0; + return false; + } + return true; +} + +bool GBAContextLoadBIOSFromVFile(struct GBAContext* context, struct VFile* bios) { + context->bios = bios; + if (!GBAIsBIOS(context->bios)) { + context->bios = 0; + return false; + } + return true; +} + +bool GBAContextStart(struct GBAContext* context) { + struct GBAOptions opts = {}; + GBAConfigMap(&context->config, &opts); + + if (context->renderer) { + GBAVideoAssociateRenderer(&context->gba->video, context->renderer); + } + + GBALoadROM(context->gba, context->rom, context->save, 0); + if (opts.useBios && context->bios) { + GBALoadBIOS(context->gba, context->bios); + } + + ARMReset(context->cpu); + + if (opts.skipBios) { + GBASkipBIOS(context->cpu); + } + + struct GBACartridgeOverride override; + const struct GBACartridge* cart = (const struct GBACartridge*) context->gba->memory.rom; + memcpy(override.id, &cart->id, sizeof(override.id)); + if (GBAOverrideFind(GBAConfigGetOverrides(&context->config), &override)) { + GBAOverrideApply(context->gba, &override); + } + GBAConfigFreeOpts(&opts); + return true; +} + +void GBAContextStop(struct GBAContext* context) { + UNUSED(context); + // TODO? +} + +void GBAContextFrame(struct GBAContext* context, uint16_t keys) { + int activeKeys = keys; + context->gba->keySource = &activeKeys; + + int frameCounter = context->gba->video.frameCounter; + while (frameCounter == context->gba->video.frameCounter) { + ARMRunLoop(context->cpu); + } +} diff --git a/src/gba/supervisor/context.h b/src/gba/supervisor/context.h new file mode 100644 index 000000000..15b4d3949 --- /dev/null +++ b/src/gba/supervisor/context.h @@ -0,0 +1,38 @@ +/* Copyright (c) 2013-2015 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 CONTEXT_H +#define CONTEXT_H + +#include "util/common.h" + +#include "gba/supervisor/config.h" +#include "gba/input.h" + +struct GBAContext { + struct GBA* gba; + struct ARMCore* cpu; + struct GBAVideoRenderer* renderer; + struct VFile* rom; + struct VFile* save; + struct VFile* bios; + struct GBAConfig config; + struct GBAOptions opts; + struct GBAInputMap inputMap; +}; + +bool GBAContextInit(struct GBAContext* context, const char* port); +void GBAContextDeinit(struct GBAContext* context); + +bool GBAContextLoadROM(struct GBAContext* context, const char* path, bool autoloadSave); +bool GBAContextLoadROMFromVFile(struct GBAContext* context, struct VFile* rom, struct VFile* save); +bool GBAContextLoadBIOS(struct GBAContext* context, const char* path); +bool GBAContextLoadBIOSFromVFile(struct GBAContext* context, struct VFile* bios); + +bool GBAContextStart(struct GBAContext* context); +void GBAContextStop(struct GBAContext* context); +void GBAContextFrame(struct GBAContext* context, uint16_t keys); + +#endif diff --git a/src/platform/libretro/libretro.c b/src/platform/libretro/libretro.c index 9a986dd0e..caf2c9f74 100644 --- a/src/platform/libretro/libretro.c +++ b/src/platform/libretro/libretro.c @@ -7,12 +7,9 @@ #include "util/common.h" -#include "gba/gba.h" -#include "gba/interface.h" #include "gba/renderers/video-software.h" #include "gba/serialize.h" -#include "gba/supervisor/overrides.h" -#include "gba/video.h" +#include "gba/supervisor/context.h" #include "util/circle-buffer.h" #include "util/vfs.h" @@ -37,14 +34,10 @@ static void _setRumble(struct GBARumble* rumble, int enable); static uint8_t _readLux(struct GBALuminanceSource* lux); static void _updateLux(struct GBALuminanceSource* lux); -static struct GBA gba; -static struct ARMCore cpu; +static struct GBAContext context; static struct GBAVideoSoftwareRenderer renderer; -static struct VFile* rom; static void* data; -static struct VFile* save; static void* savedata; -static struct VFile* bios; static struct GBAAVStream stream; static int rumbleLevel; static struct CircleBuffer rumbleHistory; @@ -162,53 +155,49 @@ void retro_init(void) { stream.postAudioBuffer = _postAudioBuffer; stream.postVideoFrame = _postVideoFrame; - GBACreate(&gba); - ARMSetComponents(&cpu, &gba.d, 0, 0); - ARMInit(&cpu); - gba.logLevel = 0; // TODO: Settings - gba.logHandler = GBARetroLog; - gba.stream = &stream; - gba.idleOptimization = IDLE_LOOP_REMOVE; // TODO: Settings + GBAContextInit(&context, 0); + struct GBAOptions opts = { + .useBios = true, + .logLevel = 0, + .idleOptimization = IDLE_LOOP_REMOVE + }; + GBAConfigLoadDefaults(&context.config, &opts); + context.gba->logHandler = GBARetroLog; + context.gba->stream = &stream; if (rumbleCallback) { - gba.rumble = &rumble; + context.gba->rumble = &rumble; } - gba.luminanceSource = &lux; - rom = 0; + context.gba->luminanceSource = &lux; const char* sysDir = 0; if (environCallback(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &sysDir)) { char biosPath[PATH_MAX]; snprintf(biosPath, sizeof(biosPath), "%s%s%s", sysDir, PATH_SEP, "gba_bios.bin"); - bios = VFileOpen(biosPath, O_RDONLY); + struct VFile* bios = VFileOpen(biosPath, O_RDONLY); if (bios) { - GBALoadBIOS(&gba, bios); + GBAContextLoadBIOSFromVFile(&context, bios); } } GBAVideoSoftwareRendererCreate(&renderer); renderer.outputBuffer = malloc(256 * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL); renderer.outputBufferStride = 256; - GBAVideoAssociateRenderer(&gba.video, &renderer.d); + GBAVideoAssociateRenderer(&context.gba->video, &renderer.d); - GBAAudioResizeBuffer(&gba.audio, SAMPLES); + GBAAudioResizeBuffer(&context.gba->audio, SAMPLES); #if RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF - blip_set_rates(gba.audio.left, GBA_ARM7TDMI_FREQUENCY, 32768); - blip_set_rates(gba.audio.right, GBA_ARM7TDMI_FREQUENCY, 32768); + blip_set_rates(context.gba->audio.left, GBA_ARM7TDMI_FREQUENCY, 32768); + blip_set_rates(context.gba->audio.right, GBA_ARM7TDMI_FREQUENCY, 32768); #endif } void retro_deinit(void) { - if (bios) { - bios->close(bios); - bios = 0; - } - GBADestroy(&gba); + GBAContextDeinit(&context); } void retro_run(void) { - int keys; - gba.keySource = &keys; + uint16_t keys; inputPollCallback(); keys = 0; @@ -243,14 +232,11 @@ void retro_run(void) { } } - int frameCount = gba.video.frameCounter; - while (gba.video.frameCounter == frameCount) { - ARMRunLoop(&cpu); - } + GBAContextFrame(&context, keys); } void retro_reset(void) { - ARMReset(&cpu); + ARMReset(context.cpu); if (rumbleCallback) { CircleBufferClear(&rumbleHistory); @@ -258,6 +244,7 @@ void retro_reset(void) { } bool retro_load_game(const struct retro_game_info* game) { + struct VFile* rom; if (game->data) { data = malloc(game->size); memcpy(data, game->data, game->size); @@ -270,26 +257,23 @@ bool retro_load_game(const struct retro_game_info* game) { return false; } if (!GBAIsROM(rom)) { + rom->close(rom); + free(data); return false; } savedata = malloc(SIZE_CART_FLASH1M); - save = VFileFromMemory(savedata, SIZE_CART_FLASH1M); + struct VFile* save = VFileFromMemory(savedata, SIZE_CART_FLASH1M); - GBALoadROM(&gba, rom, save, game->path); - GBAOverrideApplyDefaults(&gba); - - ARMReset(&cpu); + GBAContextLoadROMFromVFile(&context, rom, save); + GBAContextStart(&context); return true; } void retro_unload_game(void) { - rom->close(rom); - rom = 0; + GBAContextStop(&context); free(data); data = 0; - save->close(save); - save = 0; free(savedata); savedata = 0; CircleBufferDeinit(&rumbleHistory); @@ -303,7 +287,7 @@ bool retro_serialize(void* data, size_t size) { if (size != retro_serialize_size()) { return false; } - GBASerialize(&gba, data); + GBASerialize(context.gba, data); return true; } @@ -311,7 +295,7 @@ bool retro_unserialize(const void* data, size_t size) { if (size != retro_serialize_size()) { return false; } - GBADeserialize(&gba, data); + GBADeserialize(context.gba, data); return true; } @@ -353,7 +337,7 @@ size_t retro_get_memory_size(unsigned id) { if (id != RETRO_MEMORY_SAVE_RAM) { return 0; } - switch (gba.memory.savedata.type) { + switch (context.gba->memory.savedata.type) { case SAVEDATA_AUTODETECT: case SAVEDATA_FLASH1M: return SIZE_CART_FLASH1M;