summaryrefslogtreecommitdiff
path: root/shell/emu/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/emu/core.c')
-rw-r--r--shell/emu/core.c358
1 files changed, 358 insertions, 0 deletions
diff --git a/shell/emu/core.c b/shell/emu/core.c
new file mode 100644
index 0000000..99759a6
--- /dev/null
+++ b/shell/emu/core.c
@@ -0,0 +1,358 @@
+// Author: skogaby
+// Lots of examples were followed using other emulators found on github
+
+#include <SDL/SDL.h>
+#include <libgen.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include "main.h"
+#include "snes9x.h"
+#include "soundux.h"
+#include "memmap.h"
+#include "apu.h"
+#ifdef USE_BLARGG_APU
+#include "apu_blargg.h"
+#endif
+#include "cheats.h"
+#include "display.h"
+#include "gfx.h"
+#include "cpuexec.h"
+#ifdef USE_SPC7110
+#include "spc7110.h"
+#endif
+#include "srtc.h"
+#include "sa1.h"
+#include "snapshot.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
+
+bool8 S9xInitUpdate() { return TRUE; }
+bool8 S9xDeinitUpdate(int width, int height, bool8_32 sixteen_bit)
+{
+ if (IPPU.RenderThisFrame) {
+ Update_Video_Ingame(width, height);
+ }
+}
+
+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 (CPU.Memory_SRAMMask == 0) return;
+
+ if (state == 1)
+ {
+ savefp = fopen(path, "rb");
+ if (savefp)
+ {
+ fread(Memory.SRAM, sizeof(uint8_t), CPU.Memory_SRAMMask, savefp);
+ fclose(savefp);
+ }
+ }
+ else
+ {
+ savefp = fopen(path, "wb");
+ if (savefp)
+ {
+ fwrite(Memory.SRAM, sizeof(uint8_t), CPU.Memory_SRAMMask, savefp);
+ fclose(savefp);
+ }
+ }
+}
+
+void SaveState(char* path, uint_fast8_t state)
+{
+ if (state == 1)
+ {
+ S9xUnfreezeGame(path);
+ }
+ else
+ {
+ S9xFreezeGame(path);
+ }
+}
+
+
+#ifdef FRAMESKIP
+static uint32_t Timer_Read(void)
+{
+ /* Timing. */
+ struct timeval tval;
+ gettimeofday(&tval, 0);
+ return (((tval.tv_sec*1000000) + (tval.tv_usec)));
+}
+static long lastTick = 0, newTick;
+static uint32_t SkipCnt = 0, video_frames = 0, FPS = 60, FrameSkip;
+static const uint32_t TblSkip[4][4] = {
+ {0, 0, 0, 0},
+ {0, 0, 0, 1},
+ {0, 0, 1, 1},
+ {0, 1, 1, 1}
+};
+#endif
+
+#ifdef AUDIO_FRAMESKIP
+#define MAX_SKIP_COUNT 3
+static uint32_t SkipCnt = 0;
+#endif
+
+void Emulation_Run (void)
+{
+#ifndef USE_BLARGG_APU
+ static int16_t audio_buf[2048];
+#endif
+
+#ifdef FRAMESKIP
+ SkipCnt++;
+ if (SkipCnt > 3) SkipCnt = 0;
+ if (TblSkip[FrameSkip][SkipCnt]) IPPU.RenderThisFrame = false;
+ else IPPU.RenderThisFrame = true;
+#else
+ IPPU.RenderThisFrame = true;
+#endif
+
+#ifdef USE_BLARGG_APU
+ S9xSetSoundMute(false);
+#endif
+ //Settings.HardDisableAudio = false;
+
+#ifdef AUDIO_FRAMESKIP
+ if (IPPU.RenderThisFrame) {
+ if (Audio_Underrun_Likely()) {
+ if (SkipCnt < MAX_SKIP_COUNT) {
+ SkipCnt++;
+ IPPU.RenderThisFrame = false;
+ } else {
+ SkipCnt = 0;
+ }
+ }
+ } else {
+ SkipCnt = 0;
+ }
+#endif
+
+ S9xMainLoop();
+
+#ifndef USE_BLARGG_APU
+ samples_to_play += samples_per_frame;
+
+ if (samples_to_play > 512)
+ {
+ S9xMixSamples(audio_buf, samples_to_play);
+ Audio_Write(audio_buf, samples_to_play / 2);
+ samples_to_play = 0;
+ }
+#else
+ S9xAudioCallback();
+#endif
+
+#ifdef FRAMESKIP
+ video_frames++;
+ newTick = Timer_Read();
+ if ( (newTick) - (lastTick) > 1000000)
+ {
+ FPS = video_frames;
+ video_frames = 0;
+ lastTick = newTick;
+ if (FPS >= 60)
+ {
+ FrameSkip = 0;
+ }
+ else
+ {
+ FrameSkip = 60 / FPS;
+ if (FrameSkip > 3) FrameSkip = 3;
+ }
+ }
+#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
+ Settings.SixteenBitSound = true;
+ so.stereo = Settings.Stereo;
+ so.playback_rate = Settings.SoundPlaybackRate;
+ S9xSetPlaybackRate(so.playback_rate);
+
+ samples_per_frame = samplerate / fps << 1;
+#endif
+ return true;
+}
+
+
+void init_sfc_setting(void)
+{
+ memset(&Settings, 0, sizeof(Settings));
+ Settings.JoystickEnabled = false;
+ Settings.SoundPlaybackRate = samplerate;
+ Settings.Stereo = true;
+ Settings.SoundBufferSize = 0;
+ Settings.CyclesPercentage = 100;
+
+ Settings.DisableSoundEcho = false;
+ Settings.InterpolatedSound = true;
+ Settings.APUEnabled = true;
+
+ Settings.H_Max = SNES_CYCLES_PER_SCANLINE;
+ Settings.SkipFrames = AUTO_FRAMERATE;
+ Settings.FrameTimePAL = 20000;
+ Settings.FrameTimeNTSC = 16667;
+ Settings.Shutdown = Settings.ShutdownMaster = true;
+ Settings.DisableSampleCaching = false;
+ Settings.DisableMasterVolume = false;
+ Settings.Mouse = false;
+ Settings.SuperScope = false;
+ Settings.MultiPlayer5 = false;
+ Settings.ControllerOption = SNES_JOYPAD;
+#ifdef USE_BLARGG_APU
+ Settings.SoundSync = true;
+#endif
+
+ Settings.ForceTransparency = false;
+ Settings.Transparency = true;
+ Settings.SixteenBit = true;
+ Settings.SupportHiRes = false;
+ Settings.AutoSaveDelay = 30;
+ Settings.ApplyCheats = true;
+ Settings.TurboMode = false;
+ Settings.TurboSkipFrames = 15;
+#ifdef ASM_SPC700
+ Settings.asmspc700 = true;
+#endif
+ Settings.SpeedHacks = true;
+ Settings.HBlankStart = (256 * Settings.H_Max) / SNES_HCOUNTER_MAX;
+}
+
+void Init_SFC(void)
+{
+ init_sfc_setting();
+ MemoryInit();
+ S9xInitAPU();
+ S9xInitDisplay(NULL, NULL);
+ S9xGraphicsInit();
+#ifdef USE_BLARGG_APU
+ S9xInitSound(1000, 0); /* just give it a 1 second buffer */
+ S9xSetSamplesAvailableCallback(S9xAudioCallback);
+#else
+ S9xInitSound();
+#endif
+}
+
+void Deinit_SFC(void)
+{
+#ifdef USE_SPC7110
+ if (Settings.SPC7110)
+ Del7110Gfx();
+#endif
+
+ S9xGraphicsDeinit();
+ S9xDeinitDisplay();
+ S9xDeinitAPU();
+ MemoryDeinit();
+}
+
+
+
+/* Main entrypoint of the emulator */
+int main(int argc, char* argv[])
+{
+ int isloaded;
+
+ printf("Starting Snes9x2002\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_SFC();
+
+ Init_Video();
+ Audio_Init();
+
+ overclock_cycles = false;
+ one_c = 4;
+ slow_one_c = 5;
+ two_c = 6;
+ reduce_sprite_flicker = false;
+
+ 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;
+}