From d4753076e89d42cdad4a4f1ca4688fad3c56d873 Mon Sep 17 00:00:00 2001 From: gameblabla Date: Sat, 5 Oct 2019 03:04:57 +0200 Subject: Port the libretro core and make it standalone. TODO : - Input should use our config file instead. - Missing audio in some games. (Star Ocean, doesn't happen with stock retroarch code. Odd...) --- shell/emu/core.c | 435 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ shell/emu/main.h | 9 ++ 2 files changed, 444 insertions(+) create mode 100644 shell/emu/core.c create mode 100644 shell/emu/main.h (limited to 'shell/emu') diff --git a/shell/emu/core.c b/shell/emu/core.c new file mode 100644 index 0000000..2edc457 --- /dev/null +++ b/shell/emu/core.c @@ -0,0 +1,435 @@ +// Author: skogaby +// Lots of examples were followed using other emulators found on github + +#include +#include +#include +#include + +#include "main.h" +#include "snes9x.h" +#include "soundux.h" +#include "memmap.h" +#include "apu.h" +#include "apu_blargg.h" +#include "cheats.h" +#include "display.h" +#include "gfx.h" +#include "cpuexec.h" +#include "spc7110.h" +#include "srtc.h" +#include "sa1.h" +#include "scaler.h" + +#include "shared.h" +#include "menu.h" +#include "video_blit.h" +#include "input.h" +#include "sound_output.h" + +char GameName_emu[512]; + +bool overclock_cycles = false; +bool reduce_sprite_flicker = true; +int one_c, slow_one_c, two_c; + +static int32_t samples_to_play = 0; +static int32_t samples_per_frame = 0; +static int32_t samplerate = (((SNES_CLOCK_SPEED * 6) / (32 * ONE_APU_CYCLE))); + +#ifdef USE_BLARGG_APU +static void S9xAudioCallback() +{ + size_t avail; + /* Just pick a big buffer. We won't use it all. */ + static int16_t audio_buf[0x20000]; + + S9xFinalizeSamples(); + avail = S9xGetSampleCount(); + S9xMixSamples(audio_buf, avail); + Audio_Write(audio_buf, avail >> 1); +} +#endif + +size_t retro_serialize_size(void) +{ + return sizeof(CPU) + sizeof(ICPU) + sizeof(PPU) + sizeof(DMA) + + 0x10000 + 0x20000 + 0x20000 + 0x8000 + +#ifndef USE_BLARGG_APU + sizeof(APU) + sizeof(IAPU) + 0x10000 + +#else + SPC_SAVE_STATE_BLOCK_SIZE + +#endif + sizeof(SA1) + sizeof(s7r) + sizeof(rtc_f9); +} + +void RTC_Save(char* path, uint_fast8_t state) +{ + FILE* savefp; + + /* If RTC is disabled then don't bother saving any RTC info */ + if (!Settings.SRTC) return; + + if (state == 1) + { + savefp = fopen(path, "rb"); + if (savefp) + { + if (Settings.SPC7110RTC) + { + fread(&rtc_f9, sizeof(uint8_t), sizeof(rtc_f9), savefp); + fclose(savefp); + S9xUpdateRTC(); + } + else + { + fread(&rtc, sizeof(uint8_t), sizeof(rtc), savefp); + fclose(savefp); + S9xSRTCPostLoadState(); + } + } + } + else + { + savefp = fopen(path, "wb"); + if (savefp) + { + if (Settings.SPC7110RTC) + { + fwrite(&rtc_f9, sizeof(uint8_t), sizeof(rtc_f9), savefp); + fclose(savefp); + S9xUpdateRTC(); + } + else + { + S9xSRTCPreSaveState(); + fwrite(&rtc, sizeof(uint8_t), sizeof(rtc), savefp); + fclose(savefp); + } + } + } +} + +void SRAM_Save(char* path, uint_fast8_t state) +{ + FILE* savefp; + + /* If SRAM is not used then don't bother saving any SRAM file */ + if (Memory.SRAMMask == 0) return; + + if (state == 1) + { + savefp = fopen(path, "rb"); + if (savefp) + { + fread(Memory.SRAM, sizeof(uint8_t), Memory.SRAMMask, savefp); + fclose(savefp); + } + } + else + { + savefp = fopen(path, "wb"); + if (savefp) + { + fwrite(Memory.SRAM, sizeof(uint8_t), Memory.SRAMMask, savefp); + fclose(savefp); + } + } +} + +void SaveState(char* path, uint_fast8_t state) +{ +#ifndef USE_BLARGG_APU + uint8_t* IAPU_RAM_current = IAPU.RAM; + uintptr_t IAPU_RAM_offset; +#endif + char* buffer; + FILE* savefp; + +#ifndef USE_BLARGG_APU + buffer = malloc(sizeof(APU) + sizeof(IAPU) + 0x10000); +#else + buffer = malloc(SPC_SAVE_STATE_BLOCK_SIZE); +#endif + + if (state == 1) + { + savefp = fopen(path, "rb"); + if (savefp) + { + S9xReset(); + + fread(&CPU, sizeof(uint8_t), sizeof(CPU), savefp); + fread(&ICPU, sizeof(uint8_t), sizeof(ICPU), savefp); + fread(&PPU, sizeof(uint8_t), sizeof(PPU), savefp); + fread(&DMA, sizeof(uint8_t), sizeof(DMA), savefp); + + fread(Memory.VRAM, sizeof(uint8_t), 0x10000, savefp); + fread(Memory.RAM, sizeof(uint8_t), 0x20000, savefp); + fread(Memory.SRAM, sizeof(uint8_t), 0x20000, savefp); + fread(Memory.FillRAM, sizeof(uint8_t), 0x8000, savefp); + + #ifndef USE_BLARGG_APU + fread(&APU, sizeof(uint8_t), sizeof(APU), savefp); + fread(&IAPU, sizeof(uint8_t), sizeof(IAPU), savefp); + IAPU_RAM_offset = IAPU_RAM_current - IAPU.RAM; + IAPU.PC += IAPU_RAM_offset; + IAPU.DirectPage += IAPU_RAM_offset; + IAPU.WaitAddress1 += IAPU_RAM_offset; + IAPU.WaitAddress2 += IAPU_RAM_offset; + IAPU.RAM = IAPU_RAM_current; + fread(IAPU.RAM, sizeof(uint8_t), 0x10000, savefp); + #else + S9xAPULoadState(buffer); + fread(buffer, sizeof(uint8_t), SPC_SAVE_STATE_BLOCK_SIZE, savefp); + #endif + + SA1.Registers.PC = SA1.PC - SA1.PCBase; + S9xSA1PackStatus(); + fread(&SA1, sizeof(uint8_t), sizeof(SA1), savefp); + fread(&s7r, sizeof(uint8_t), sizeof(s7r), savefp); + fread(&rtc_f9, sizeof(uint8_t), sizeof(rtc_f9), savefp); + fclose(savefp); + + S9xFixSA1AfterSnapshotLoad(); + FixROMSpeed(); + IPPU.ColorsChanged = true; + IPPU.OBJChanged = true; + CPU.InDMA = false; + S9xFixColourBrightness(); + S9xSA1UnpackStatus(); + #ifndef USE_BLARGG_APU + S9xAPUUnpackStatus(); + S9xFixSoundAfterSnapshotLoad(); + #endif + ICPU.ShiftedPB = ICPU.Registers.PB << 16; + ICPU.ShiftedDB = ICPU.Registers.DB << 16; + S9xSetPCBase(ICPU.ShiftedPB + ICPU.Registers.PC); + S9xUnpackStatus(); + S9xFixCycles(); + S9xReschedule(); + } + } + else + { + savefp = fopen(path, "wb"); + if (savefp) + { + #ifdef LAGFIX + S9xPackStatus(); + #ifndef USE_BLARGG_APU + S9xAPUPackStatus(); + #endif + #endif + + S9xUpdateRTC(); + S9xSRTCPreSaveState(); + fwrite(&CPU, sizeof(uint8_t), sizeof(CPU), savefp); + fwrite(&ICPU, sizeof(uint8_t), sizeof(ICPU), savefp); + fwrite(&PPU, sizeof(uint8_t), sizeof(PPU), savefp); + fwrite(&DMA, sizeof(uint8_t), sizeof(DMA), savefp); + + fwrite(Memory.VRAM, sizeof(uint8_t), 0x10000, savefp); + fwrite(Memory.RAM, sizeof(uint8_t), 0x20000, savefp); + fwrite(Memory.SRAM, sizeof(uint8_t), 0x20000, savefp); + fwrite(Memory.FillRAM, sizeof(uint8_t), 0x8000, savefp); + + #ifndef USE_BLARGG_APU + fwrite(&APU, sizeof(uint8_t), sizeof(APU), savefp); + fwrite(&IAPU, sizeof(uint8_t), sizeof(IAPU), savefp); + fwrite(IAPU.RAM, sizeof(uint8_t), 0x10000, savefp); + #else + S9xAPUSaveState(buffer); + fwrite(buffer, sizeof(uint8_t), SPC_SAVE_STATE_BLOCK_SIZE, savefp); + #endif + + SA1.Registers.PC = SA1.PC - SA1.PCBase; + S9xSA1PackStatus(); + fwrite(&SA1, sizeof(uint8_t), sizeof(SA1), savefp); + fwrite(&s7r, sizeof(uint8_t), sizeof(s7r), savefp); + fwrite(&rtc_f9, sizeof(uint8_t), sizeof(rtc_f9), savefp); + fclose(savefp); + } + } + + if (buffer) free(buffer); +} + +void Emulation_Run (void) +{ +#ifndef USE_BLARGG_APU + static int16_t audio_buf[2048]; +#endif + IPPU.RenderThisFrame = true; +#ifdef USE_BLARGG_APU + S9xSetSoundMute(false); +#endif + Settings.HardDisableAudio = false; + + S9xMainLoop(); + +#ifndef USE_BLARGG_APU + samples_to_play += samples_per_frame; + + if (samples_to_play > 512) + { + S9xMixSamples(audio_buf, samples_to_play * 2); + Audio_Write(audio_buf, samples_to_play); + samples_to_play = 0; + } +#else + S9xAudioCallback(); +#endif + + +#ifdef FRAMESKIP + if (IPPU.RenderThisFrame) + { +#endif + Update_Video_Ingame(); +#ifdef FRAMESKIP + IPPU.RenderThisFrame = false; + } + else + { + IPPU.RenderThisFrame = true; + } +#endif +} + + +bool Load_Game_Memory(char* game_path) +{ + uint64_t fps; + CPU.Flags = 0; + + if (!LoadROM(game_path)) + return false; + + Settings.FrameTime = (Settings.PAL ? Settings.FrameTimePAL : Settings.FrameTimeNTSC); + + if (!Settings.PAL) + fps = (SNES_CLOCK_SPEED * 6.0 / (SNES_CYCLES_PER_SCANLINE * SNES_MAX_NTSC_VCOUNTER)); + else + fps = (SNES_CLOCK_SPEED * 6.0 / (SNES_CYCLES_PER_SCANLINE * SNES_MAX_PAL_VCOUNTER)); + + samplerate = SOUND_OUTPUT_FREQUENCY; + Settings.SoundPlaybackRate = samplerate; + +#ifndef USE_BLARGG_APU + samples_per_frame = samplerate / fps; + S9xSetPlaybackRate(Settings.SoundPlaybackRate); +#endif + return true; +} + + +void init_sfc_setting(void) +{ + memset(&Settings, 0, sizeof(Settings)); + Settings.JoystickEnabled = false; + Settings.SoundPlaybackRate = samplerate; + Settings.CyclesPercentage = 100; + + Settings.DisableSoundEcho = false; + Settings.InterpolatedSound = true; + Settings.APUEnabled = true; + + Settings.H_Max = SNES_CYCLES_PER_SCANLINE; + Settings.FrameTimePAL = 20000; + Settings.FrameTimeNTSC = 16667; + Settings.DisableMasterVolume = false; + Settings.Mouse = true; + Settings.SuperScope = true; + Settings.MultiPlayer5 = true; + Settings.ControllerOption = SNES_JOYPAD; +#ifdef USE_BLARGG_APU + Settings.SoundSync = false; +#endif + Settings.ApplyCheats = true; + Settings.HBlankStart = (256 * Settings.H_Max) / SNES_HCOUNTER_MAX; +} + +void Init_SFC(void) +{ + init_sfc_setting(); + S9xInitMemory(); + S9xInitAPU(); + S9xInitDisplay(); + S9xInitGFX(); +#ifdef USE_BLARGG_APU + S9xInitSound(1000, 0); /* just give it a 1 second buffer */ + S9xSetSamplesAvailableCallback(S9xAudioCallback); +#else + S9xInitSound(); +#endif + CPU.SaveStateVersion = 0; +} + +void Deinit_SFC(void) +{ + if (Settings.SPC7110) + Del7110Gfx(); + + S9xDeinitGFX(); + S9xDeinitDisplay(); + S9xDeinitAPU(); + S9xDeinitMemory(); +} + + + +/* Main entrypoint of the emulator */ +int main(int argc, char* argv[]) +{ + int isloaded; + + printf("Starting Snes9x2005\n"); + + if (argc < 2) + { + printf("Specify a ROM to load in memory\n"); + return 0; + } + + snprintf(GameName_emu, sizeof(GameName_emu), "%s", basename(argv[1])); + Init_Video(); + + overclock_cycles = true; + one_c = 4; + slow_one_c = 5; + two_c = 6; + reduce_sprite_flicker = true; + + Audio_Init(); + Init_SFC(); + + isloaded = Load_Game_Memory(argv[1]); + if (!isloaded) + { + printf("Could not load ROM in memory\n"); + return 0; + } + + Init_Configuration(); + + // get the game ready + while (!exit_snes) + { + switch(emulator_state) + { + case 0: + Emulation_Run(); + break; + case 1: + Menu(); + break; + } + } + + Deinit_SFC(); + Audio_Close(); + Video_Close(); + + return 0; +} diff --git a/shell/emu/main.h b/shell/emu/main.h new file mode 100644 index 0000000..43688c3 --- /dev/null +++ b/shell/emu/main.h @@ -0,0 +1,9 @@ +#ifndef MAIN_H +#define MAIN_H + +int ResumeEmulation; +// utility functions that the core requires us to implement +extern const char* S9xGetFilename(const char* extension); +extern const char* S9xGetDirectory(uint32_t dirtype); + +#endif -- cgit v1.2.3