diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Sameboy.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Sameboy.cs index 453aaf65a0..8d93b7521f 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Sameboy.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Sameboy.cs @@ -59,8 +59,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy _cgb = (rom[0x143] & 0xc0) == 0xc0; Console.WriteLine("Automaticly detected CGB to " + _cgb); - var bios = Util.DecompressGzipFile(new MemoryStream( - _cgb ? Resources.SameboyCgbBoot : Resources.SameboyDmgBoot)); + var bios = Util.DecompressGzipFile(new MemoryStream(_cgb ? Resources.SameboyCgbBoot : Resources.SameboyDmgBoot)); + // var bios = comm.CoreFileProvider.GetFirmware(_cgb ? "GBC" : "GB", "World", true); _exe.AddReadonlyFile(rom, "game.rom"); _exe.AddReadonlyFile(bios, "boot.rom"); diff --git a/waterbox/sameboy/Makefile b/waterbox/sameboy/Makefile index f3824c30ee..640a98f0d7 100644 --- a/waterbox/sameboy/Makefile +++ b/waterbox/sameboy/Makefile @@ -6,12 +6,11 @@ FLAGS:=-Wall -Werror=pointer-to-int-cast -Werror=int-to-pointer-cast -Werror=imp -fomit-frame-pointer -fvisibility=hidden \ -O0 -g -CCFLAGS:=$(FLAGS) -Ilib \ - -I../emulibc \ +CCFLAGS:=$(FLAGS) \ -std=gnu99 \ -DLSB_FIRST -D_GNU_SOURCE -DGB_INTERNAL -CPPFLAGS:=$(FLAGS) -DSPC_NO_COPY_STATE_FUNCS -std=c++0x +CPPFLAGS:=$(FLAGS) -DSPC_NO_COPY_STATE_FUNCS -std=c++0x -D_GNU_SOURCE -DGB_INTERNAL TARGET = sameboy.wbx diff --git a/waterbox/sameboy/bizhawk.cpp b/waterbox/sameboy/bizhawk.cpp index 81b31201d0..15f462da84 100644 --- a/waterbox/sameboy/bizhawk.cpp +++ b/waterbox/sameboy/bizhawk.cpp @@ -65,6 +65,9 @@ ECL_EXPORT bool Init(bool cgb) GB_set_infrared_callback(&GB, InfraredCallback); GB_set_rumble_callback(&GB, RumbleCallback); + GB_set_sample_rate(&GB, 44100); + GB_set_audio_quality(&GB, 1); + return true; } @@ -76,9 +79,12 @@ struct MyFrameInfo : public FrameInfo ECL_EXPORT void FrameAdvance(MyFrameInfo &f) { GB_set_pixels_output(&GB, f.VideoBuffer); - // void GB_set_key_state(GB_gameboy_t *gb, GB_key_t index, bool pressed); - GB_run_frame(&GB); - f.Samples = 735; + for (int i = 0; i < (int)GB_KEY_MAX; i++) + GB_set_key_state(&GB, (GB_key_t)i, false); + + f.Cycles = GB_run_cycles(&GB, 35112); + f.Samples = GB_apu_get_current_buffer_length(&GB); + GB_apu_copy_buffer(&GB, (GB_sample_t*)f.SoundBuffer, f.Samples); f.Width = 160; f.Height = 144; } @@ -104,7 +110,7 @@ ECL_EXPORT void GetMemoryAreas(MemoryArea *m) SetMemoryArea(m + 6, GB_DIRECT_ACCESS_IO, "IO", MEMORYAREA_FLAGS_WORDSIZE1); SetMemoryArea(m + 7, GB_DIRECT_ACCESS_BOOTROM, "BOOTROM", MEMORYAREA_FLAGS_WORDSIZE1); SetMemoryArea(m + 8, GB_DIRECT_ACCESS_BGP, "BGP", MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_WRITABLE); - SetMemoryArea(m + 8, GB_DIRECT_ACCESS_OBP, "OBP", MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_WRITABLE); + SetMemoryArea(m + 9, GB_DIRECT_ACCESS_OBP, "OBP", MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_WRITABLE); } ECL_EXPORT void SetInputCallback(void (*callback)()) diff --git a/waterbox/sameboy/camera.c b/waterbox/sameboy/camera.c index 9b34998af3..6ce2c0d89e 100644 --- a/waterbox/sameboy/camera.c +++ b/waterbox/sameboy/camera.c @@ -125,7 +125,7 @@ void GB_camera_write_register(GB_gameboy_t *gb, uint16_t addr, uint8_t value) addr &= 0x7F; if (addr == GB_CAMERA_SHOOT_AND_1D_FLAGS) { value &= 0x7; - noise_seed = rand(); + noise_seed = 42; // rand(); if ((value & 1) && !(gb->camera_registers[GB_CAMERA_SHOOT_AND_1D_FLAGS] & 1) && gb->camera_update_request_callback) { /* If no callback is set, ignore the write as if the camera is instantly done */ gb->camera_registers[GB_CAMERA_SHOOT_AND_1D_FLAGS] |= 1; diff --git a/waterbox/sameboy/display.c b/waterbox/sameboy/display.c index e624ac93b6..d2ee911619 100644 --- a/waterbox/sameboy/display.c +++ b/waterbox/sameboy/display.c @@ -197,12 +197,6 @@ static uint32_t get_pixel(GB_gameboy_t *gb, uint8_t x, uint8_t y) static void display_vblank(GB_gameboy_t *gb) { - if (gb->turbo) { - if (GB_timing_sync_turbo(gb)) { - return; - } - } - if (!gb->disable_rendering && ((!(gb->io_registers[GB_IO_LCDC] & 0x80) || gb->stopped) || gb->frame_skip_state == GB_FRAMESKIP_LCD_TURNED_ON)) { /* LCD is off, set screen to white */ uint32_t white = gb->rgb_encode_callback(gb, 0xFF, 0xFF, 0xFF); @@ -212,7 +206,6 @@ static void display_vblank(GB_gameboy_t *gb) } gb->vblank_callback(gb); - GB_timing_sync(gb); gb->vblank_just_occured = true; } diff --git a/waterbox/sameboy/gb.c b/waterbox/sameboy/gb.c index d464734c4e..475d48f881 100644 --- a/waterbox/sameboy/gb.c +++ b/waterbox/sameboy/gb.c @@ -133,18 +133,6 @@ void GB_free(GB_gameboy_t *gb) if (gb->breakpoints) { free(gb->breakpoints); } - for (int i = 0x200; i--;) { - if (gb->bank_symbols[i]) { - GB_map_free(gb->bank_symbols[i]); - } - } - for (int i = 0x400; i--;) { - if (gb->reversed_symbol_map.buckets[i]) { - GB_symbol_t *next = gb->reversed_symbol_map.buckets[i]->next; - free(gb->reversed_symbol_map.buckets[i]); - gb->reversed_symbol_map.buckets[i] = next; - } - } memset(gb, 0, sizeof(*gb)); } @@ -267,24 +255,20 @@ void GB_run(GB_gameboy_t *gb) } } -uint64_t GB_run_frame(GB_gameboy_t *gb) +uint64_t GB_run_cycles(GB_gameboy_t *gb, uint32_t cycles) { - /* Configure turbo temporarily, the user wants to handle FPS capping manually. */ - bool old_turbo = gb->turbo; - bool old_dont_skip = gb->turbo_dont_skip; - gb->turbo = true; - gb->turbo_dont_skip = true; - - gb->cycles_since_last_sync = 0; - while (true) { + uint64_t start = gb->cycles_since_epoch; + uint64_t target = start + cycles; + while (gb->cycles_since_epoch < target) { GB_run(gb); if (gb->vblank_just_occured) { + // TODO: fix these up + GB_update_joyp(gb); + GB_rtc_run(gb); break; } } - gb->turbo = old_turbo; - gb->turbo_dont_skip = old_dont_skip; - return gb->cycles_since_last_sync * FRAME_LENGTH * LCDC_PERIOD; + return gb->cycles_since_epoch - start; } void GB_set_pixels_output(GB_gameboy_t *gb, uint32_t *output) @@ -416,12 +400,6 @@ bool GB_is_cgb(GB_gameboy_t *gb) return gb->is_cgb; } -void GB_set_turbo_mode(GB_gameboy_t *gb, bool on, bool no_frame_skip) -{ - gb->turbo = on; - gb->turbo_dont_skip = no_frame_skip; -} - void GB_set_rendering_disabled(GB_gameboy_t *gb, bool disabled) { gb->disable_rendering = disabled; @@ -441,7 +419,7 @@ void GB_reset(GB_gameboy_t *gb) { uint32_t mbc_ram_size = gb->mbc_ram_size; bool cgb = gb->is_cgb; - memset(gb, 0, (size_t)GB_GET_SECTION((GB_gameboy_t *) 0, unsaved)); + // memset(gb, 0, (size_t)GB_GET_SECTION((GB_gameboy_t *) 0, unsaved)); gb->version = GB_STRUCT_VERSION; gb->mbc_rom_bank = 1; diff --git a/waterbox/sameboy/gb.h b/waterbox/sameboy/gb.h index 4d7588b644..a80b89e5ec 100644 --- a/waterbox/sameboy/gb.h +++ b/waterbox/sameboy/gb.h @@ -4,9 +4,9 @@ #include #include #include +#include #include "gb_struct_def.h" -#include "save_state.h" #include "apu.h" #include "camera.h" @@ -17,7 +17,6 @@ #include "printer.h" #include "timing.h" #include "z80_cpu.h" -#include "symbol_hash.h" #define GB_STRUCT_VERSION 11 @@ -193,7 +192,6 @@ struct GB_gameboy_s { #else struct GB_gameboy_internal_s { #endif - GB_SECTION(header, /* The magic makes sure a state file is: - Indeed a SameBoy state file. - Has the same endianess has the current platform. */ @@ -201,9 +199,7 @@ struct GB_gameboy_internal_s { /* The version field makes sure we don't load save state files with a completely different structure. This happens when struct fields are removed/resized in an backward incompatible manner. */ uint32_t version; - ); - - GB_SECTION(core_state, + /* Registers */ uint16_t pc; union { @@ -249,10 +245,8 @@ struct GB_gameboy_internal_s { /* Misc state */ bool infrared_input; GB_printer_t printer; - ); /* DMA and HDMA */ - GB_SECTION(dma, bool hdma_on; bool hdma_on_hblank; uint8_t hdma_steps_left; @@ -264,10 +258,8 @@ struct GB_gameboy_internal_s { uint16_t dma_current_src; int16_t dma_cycles; bool is_dma_restarting; - ); /* MBC */ - GB_SECTION(mbc, uint16_t mbc_rom_bank; uint8_t mbc_ram_bank; uint32_t mbc_ram_size; @@ -311,32 +303,23 @@ struct GB_gameboy_internal_s { bool camera_registers_mapped; uint8_t camera_registers[0x36]; bool rumble_state; - ); /* HRAM and HW Registers */ - GB_SECTION(hram, uint8_t hram[0xFFFF - 0xFF80]; uint8_t io_registers[0x80]; - ); /* Timing */ - GB_SECTION(timing, uint32_t display_cycles; uint32_t div_cycles; uint8_t tima_reload_state; /* After TIMA overflows, it becomes 0 for 4 cycles before actually reloading. */ - GB_PADDING(uint16_t, serial_cycles); uint16_t serial_cycles; /* This field changed its meaning in v0.10 */ uint16_t serial_length; - ); /* APU */ - GB_SECTION(apu, GB_apu_t apu; - ); /* RTC */ - GB_SECTION(rtc, union { struct { uint8_t seconds; @@ -349,10 +332,8 @@ struct GB_gameboy_internal_s { } rtc_real, rtc_latched; time_t last_rtc_second; bool rtc_latch; - ); /* Video Display */ - GB_SECTION(video, uint32_t vram_size; // Different between CGB and DMG uint8_t cgb_vram_bank; uint8_t oam[0xA0]; @@ -379,11 +360,9 @@ struct GB_gameboy_internal_s { bool vram_read_blocked; bool oam_write_blocked; bool vram_write_blocked; - ); /* Unsaved data. This includes all pointers, as well as everything that shouldn't be on a save state */ /* This data is reserved on reset and must come last in the struct */ - GB_SECTION(unsaved, /* ROM */ uint8_t *rom; uint32_t rom_size; @@ -404,8 +383,7 @@ struct GB_gameboy_internal_s { bool keys[GB_KEY_MAX]; /* Timing */ - uint64_t last_sync; - uint64_t cycles_since_last_sync; + uint64_t cycles_since_epoch; /* Audio */ unsigned buffer_size; @@ -459,21 +437,11 @@ struct GB_gameboy_internal_s { uint16_t addr; } backtrace_returns[0x200]; - /* Symbol tables */ - GB_symbol_map_t *bank_symbols[0x200]; - GB_reversed_symbol_map_t reversed_symbol_map; - - /* Ticks command */ - unsigned long debugger_ticks; - /* Misc */ - bool turbo; - bool turbo_dont_skip; bool disable_rendering; uint32_t ram_size; // Different between CGB and DMG uint8_t boot_rom[0x900]; bool vblank_just_occured; // For slow operations involving syscalls; these should only run once per vblank - ); }; #ifndef GB_INTERNAL @@ -497,8 +465,7 @@ void GB_free(GB_gameboy_t *gb); void GB_reset(GB_gameboy_t *gb); void GB_switch_model_and_reset(GB_gameboy_t *gb, bool is_cgb); void GB_run(GB_gameboy_t *gb); -/* Returns the time passed since the last frame, in nanoseconds */ -uint64_t GB_run_frame(GB_gameboy_t *gb); +uint64_t GB_run_cycles(GB_gameboy_t *gb, uint32_t cycles); typedef enum { GB_DIRECT_ACCESS_ROM, @@ -526,7 +493,6 @@ int GB_load_rom(GB_gameboy_t *gb, const char *path); int GB_save_battery(GB_gameboy_t *gb, const char *path); void GB_load_battery(GB_gameboy_t *gb, const char *path); -void GB_set_turbo_mode(GB_gameboy_t *gb, bool on, bool no_frame_skip); void GB_set_rendering_disabled(GB_gameboy_t *gb, bool disabled); void GB_log(GB_gameboy_t *gb, const char *fmt, ...) __printflike(2, 3); diff --git a/waterbox/sameboy/joypad.c b/waterbox/sameboy/joypad.c index c5c4f08961..21e6d666b0 100644 --- a/waterbox/sameboy/joypad.c +++ b/waterbox/sameboy/joypad.c @@ -22,13 +22,6 @@ void GB_update_joyp(GB_gameboy_t *gb) for (uint8_t i = 0; i < 4; i++) { gb->io_registers[GB_IO_JOYP] |= (!gb->keys[i]) << i; } - /* Forbid pressing two opposing keys, this breaks a lot of games; even if it's somewhat possible. */ - if (!(gb->io_registers[GB_IO_JOYP] & 1)) { - gb->io_registers[GB_IO_JOYP] |= 2; - } - if (!(gb->io_registers[GB_IO_JOYP] & 4)) { - gb->io_registers[GB_IO_JOYP] |= 8; - } break; case 1: diff --git a/waterbox/sameboy/memory.c b/waterbox/sameboy/memory.c index f694d210a4..3e34895c97 100644 --- a/waterbox/sameboy/memory.c +++ b/waterbox/sameboy/memory.c @@ -456,10 +456,6 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value) gb->frame_skip_state = GB_FRAMESKIP_LCD_TURNED_ON; } } - else if (!(value & 0x80) && (gb->io_registers[GB_IO_LCDC] & 0x80)) { - /* Sync after turning off LCD */ - GB_timing_sync(gb); - } gb->io_registers[GB_IO_LCDC] = value; return; diff --git a/waterbox/sameboy/save_state.c b/waterbox/sameboy/save_state.c deleted file mode 100644 index cd579aa800..0000000000 --- a/waterbox/sameboy/save_state.c +++ /dev/null @@ -1,304 +0,0 @@ -#include "gb.h" -#include -#include - -static bool dump_section(FILE *f, const void *src, uint32_t size) -{ - if (fwrite(&size, 1, sizeof(size), f) != sizeof(size)) { - return false; - } - - if (fwrite(src, 1, size, f) != size) { - return false; - } - - return true; -} - -#define DUMP_SECTION(gb, f, section) dump_section(f, GB_GET_SECTION(gb, section), GB_SECTION_SIZE(section)) - -/* Todo: we need a sane and protable save state format. */ -int GB_save_state(GB_gameboy_t *gb, const char *path) -{ - FILE *f = fopen(path, "wb"); - if (!f) { - GB_log(gb, "Could not open save state: %s.\n", strerror(errno)); - return errno; - } - - if (fwrite(GB_GET_SECTION(gb, header), 1, GB_SECTION_SIZE(header), f) != GB_SECTION_SIZE(header)) goto error; - if (!DUMP_SECTION(gb, f, core_state)) goto error; - if (!DUMP_SECTION(gb, f, dma )) goto error; - if (!DUMP_SECTION(gb, f, mbc )) goto error; - if (!DUMP_SECTION(gb, f, hram )) goto error; - if (!DUMP_SECTION(gb, f, timing )) goto error; - if (!DUMP_SECTION(gb, f, apu )) goto error; - if (!DUMP_SECTION(gb, f, rtc )) goto error; - if (!DUMP_SECTION(gb, f, video )) goto error; - - - if (fwrite(gb->mbc_ram, 1, gb->mbc_ram_size, f) != gb->mbc_ram_size) { - goto error; - } - - if (fwrite(gb->ram, 1, gb->ram_size, f) != gb->ram_size) { - goto error; - } - - if (fwrite(gb->vram, 1, gb->vram_size, f) != gb->vram_size) { - goto error; - } - - errno = 0; - -error: - fclose(f); - return errno; -} - -#undef DUMP_SECTION - -size_t GB_get_save_state_size(GB_gameboy_t *gb) -{ - return GB_SECTION_SIZE(header) - + GB_SECTION_SIZE(core_state) + sizeof(uint32_t) - + GB_SECTION_SIZE(dma ) + sizeof(uint32_t) - + GB_SECTION_SIZE(mbc ) + sizeof(uint32_t) - + GB_SECTION_SIZE(hram ) + sizeof(uint32_t) - + GB_SECTION_SIZE(timing ) + sizeof(uint32_t) - + GB_SECTION_SIZE(apu ) + sizeof(uint32_t) - + GB_SECTION_SIZE(rtc ) + sizeof(uint32_t) - + GB_SECTION_SIZE(video ) + sizeof(uint32_t) - + gb->mbc_ram_size - + gb->ram_size - + gb->vram_size; -} - -/* A write-line function for memory copying */ -static void buffer_write(const void *src, size_t size, uint8_t **dest) -{ - memcpy(*dest, src, size); - *dest += size; -} - -static void buffer_dump_section(uint8_t **buffer, const void *src, uint32_t size) -{ - buffer_write(&size, sizeof(size), buffer); - buffer_write(src, size, buffer); -} - -#define DUMP_SECTION(gb, buffer, section) buffer_dump_section(&buffer, GB_GET_SECTION(gb, section), GB_SECTION_SIZE(section)) -void GB_save_state_to_buffer(GB_gameboy_t *gb, uint8_t *buffer) -{ - buffer_write(GB_GET_SECTION(gb, header), GB_SECTION_SIZE(header), &buffer); - DUMP_SECTION(gb, buffer, core_state); - DUMP_SECTION(gb, buffer, dma ); - DUMP_SECTION(gb, buffer, mbc ); - DUMP_SECTION(gb, buffer, hram ); - DUMP_SECTION(gb, buffer, timing ); - DUMP_SECTION(gb, buffer, apu ); - DUMP_SECTION(gb, buffer, rtc ); - DUMP_SECTION(gb, buffer, video ); - - - buffer_write(gb->mbc_ram, gb->mbc_ram_size, &buffer); - buffer_write(gb->ram, gb->ram_size, &buffer); - buffer_write(gb->vram, gb->vram_size, &buffer); -} - -/* Best-effort read function for maximum future compatibility. */ -static bool read_section(FILE *f, void *dest, uint32_t size) -{ - uint32_t saved_size = 0; - if (fread(&saved_size, 1, sizeof(size), f) != sizeof(size)) { - return false; - } - - if (saved_size <= size) { - if (fread(dest, 1, saved_size, f) != saved_size) { - return false; - } - } - else { - if (fread(dest, 1, size, f) != size) { - return false; - } - fseek(f, saved_size - size, SEEK_CUR); - } - - return true; -} -#undef DUMP_SECTION - -static bool verify_state_compatibility(GB_gameboy_t *gb, GB_gameboy_t *save) -{ - if (gb->magic != save->magic) { - GB_log(gb, "File is not a save state, or is from an incompatible operating system.\n"); - return false; - } - - if (gb->version != save->version) { - GB_log(gb, "Save state is for a different version of SameBoy.\n"); - return false; - } - - if (gb->mbc_ram_size < save->mbc_ram_size) { - GB_log(gb, "Save state has non-matching MBC RAM size.\n"); - return false; - } - - if (gb->ram_size != save->ram_size) { - GB_log(gb, "Save state has non-matching RAM size. Try changing emulated model.\n"); - return false; - } - - if (gb->vram_size != save->vram_size) { - GB_log(gb, "Save state has non-matching VRAM size. Try changing emulated model.\n"); - return false; - } - - return true; -} - -#define READ_SECTION(gb, f, section) read_section(f, GB_GET_SECTION(gb, section), GB_SECTION_SIZE(section)) - -int GB_load_state(GB_gameboy_t *gb, const char *path) -{ - GB_gameboy_t save; - - /* Every unread value should be kept the same. */ - memcpy(&save, gb, sizeof(save)); - - FILE *f = fopen(path, "rb"); - if (!f) { - GB_log(gb, "Could not open save state: %s.\n", strerror(errno)); - return errno; - } - - if (fread(GB_GET_SECTION(&save, header), 1, GB_SECTION_SIZE(header), f) != GB_SECTION_SIZE(header)) goto error; - if (!READ_SECTION(&save, f, core_state)) goto error; - if (!READ_SECTION(&save, f, dma )) goto error; - if (!READ_SECTION(&save, f, mbc )) goto error; - if (!READ_SECTION(&save, f, hram )) goto error; - if (!READ_SECTION(&save, f, timing )) goto error; - if (!READ_SECTION(&save, f, apu )) goto error; - if (!READ_SECTION(&save, f, rtc )) goto error; - if (!READ_SECTION(&save, f, video )) goto error; - - if (!verify_state_compatibility(gb, &save)) { - errno = -1; - goto error; - } - - memset(gb->mbc_ram + save.mbc_ram_size, 0xFF, gb->mbc_ram_size - save.mbc_ram_size); - if (fread(gb->mbc_ram, 1, save.mbc_ram_size, f) != save.mbc_ram_size) { - fclose(f); - return EIO; - } - - if (fread(gb->ram, 1, gb->ram_size, f) != gb->ram_size) { - fclose(f); - return EIO; - } - - if (fread(gb->vram, 1, gb->vram_size, f) != gb->vram_size) { - fclose(f); - return EIO; - } - - memcpy(gb, &save, sizeof(save)); - errno = 0; - - if (gb->cartridge_type->has_rumble && gb->rumble_callback) { - gb->rumble_callback(gb, gb->rumble_state); - } - -error: - fclose(f); - return errno; -} - -#undef READ_SECTION - -/* An read-like function for buffer-copying */ -static size_t buffer_read(void *dest, size_t length, const uint8_t **buffer, size_t *buffer_length) -{ - if (length > *buffer_length) { - length = *buffer_length; - } - - memcpy(dest, *buffer, length); - *buffer += length; - *buffer_length -= length; - - return length; -} - -static bool buffer_read_section(const uint8_t **buffer, size_t *buffer_length, void *dest, uint32_t size) -{ - uint32_t saved_size = 0; - if (buffer_read(&saved_size, sizeof(size), buffer, buffer_length) != sizeof(size)) { - return false; - } - - if (saved_size <= size) { - if (buffer_read(dest, saved_size, buffer, buffer_length) != saved_size) { - return false; - } - } - else { - if (buffer_read(dest, size, buffer, buffer_length) != size) { - return false; - } - *buffer += saved_size - size; - *buffer_length -= saved_size - size; - } - - return true; -} - -#define READ_SECTION(gb, buffer, length, section) buffer_read_section(&buffer, &length, GB_GET_SECTION(gb, section), GB_SECTION_SIZE(section)) -int GB_load_state_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t length) -{ - GB_gameboy_t save; - - /* Every unread value should be kept the same. */ - memcpy(&save, gb, sizeof(save)); - - if (buffer_read(GB_GET_SECTION(&save, header), GB_SECTION_SIZE(header), &buffer, &length) != GB_SECTION_SIZE(header)) return -1; - if (!READ_SECTION(&save, buffer, length, core_state)) return -1; - if (!READ_SECTION(&save, buffer, length, dma )) return -1; - if (!READ_SECTION(&save, buffer, length, mbc )) return -1; - if (!READ_SECTION(&save, buffer, length, hram )) return -1; - if (!READ_SECTION(&save, buffer, length, timing )) return -1; - if (!READ_SECTION(&save, buffer, length, apu )) return -1; - if (!READ_SECTION(&save, buffer, length, rtc )) return -1; - if (!READ_SECTION(&save, buffer, length, video )) return -1; - - if (!verify_state_compatibility(gb, &save)) { - return -1; - } - - memset(gb->mbc_ram + save.mbc_ram_size, 0xFF, gb->mbc_ram_size - save.mbc_ram_size); - if (buffer_read(gb->mbc_ram, save.mbc_ram_size, &buffer, &length) != save.mbc_ram_size) { - return -1; - } - - if (buffer_read(gb->ram, gb->ram_size, &buffer, &length) != gb->ram_size) { - return -1; - } - - if (buffer_read(gb->vram,gb->vram_size, &buffer, &length) != gb->vram_size) { - return -1; - } - - memcpy(gb, &save, sizeof(save)); - - if (gb->cartridge_type->has_rumble && gb->rumble_callback) { - gb->rumble_callback(gb, gb->rumble_state); - } - - return 0; -} - -#undef READ_SECTION diff --git a/waterbox/sameboy/save_state.h b/waterbox/sameboy/save_state.h deleted file mode 100644 index 546ac2d95a..0000000000 --- a/waterbox/sameboy/save_state.h +++ /dev/null @@ -1,24 +0,0 @@ -/* Macros to make the GB_gameboy_t struct more future compatible when state saving */ -#ifndef save_state_h -#define save_state_h -#include - -#define GB_PADDING(type, old_usage) type old_usage##__do_not_use - -#define GB_SECTION(name, ...) __attribute__ ((aligned (8))) struct {} name##_section_start; __VA_ARGS__; struct {} name##_section_end -#define GB_SECTION_OFFSET(name) (offsetof(GB_gameboy_t, name##_section_start)) -#define GB_SECTION_SIZE(name) (offsetof(GB_gameboy_t, name##_section_end) - offsetof(GB_gameboy_t, name##_section_start)) -#define GB_GET_SECTION(gb, name) ((void*)&((gb)->name##_section_start)) - -#define GB_aligned_double __attribute__ ((aligned (8))) double - - -/* Public calls related to save states */ -int GB_save_state(GB_gameboy_t *gb, const char *path); -size_t GB_get_save_state_size(GB_gameboy_t *gb); -/* Assumes buffer is big enough to contain the save state. Use with GB_get_save_state_size(). */ -void GB_save_state_to_buffer(GB_gameboy_t *gb, uint8_t *buffer); - -int GB_load_state(GB_gameboy_t *gb, const char *path); -int GB_load_state_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t length); -#endif /* save_state_h */ diff --git a/waterbox/sameboy/symbol_hash.c b/waterbox/sameboy/symbol_hash.c deleted file mode 100644 index 709421c233..0000000000 --- a/waterbox/sameboy/symbol_hash.c +++ /dev/null @@ -1,106 +0,0 @@ -#include "gb.h" - -static size_t GB_map_find_symbol_index(GB_symbol_map_t *map, uint16_t addr) -{ - if (!map->symbols) { - return 0; - } - ssize_t min = 0; - ssize_t max = map->n_symbols; - while (min < max) { - size_t pivot = (min + max) / 2; - if (map->symbols[pivot].addr == addr) return pivot; - if (map->symbols[pivot].addr > addr) { - max = pivot; - } - else { - min = pivot + 1; - } - } - return (size_t) min; -} - -GB_bank_symbol_t *GB_map_add_symbol(GB_symbol_map_t *map, uint16_t addr, const char *name) -{ - size_t index = GB_map_find_symbol_index(map, addr); - - if (index < map->n_symbols && map->symbols[index].addr == addr) return NULL; - - map->symbols = realloc(map->symbols, (map->n_symbols + 1) * sizeof(map->symbols[0])); - memmove(&map->symbols[index + 1], &map->symbols[index], (map->n_symbols - index) * sizeof(map->symbols[0])); - map->symbols[index].addr = addr; - map->symbols[index].name = strdup(name); - map->n_symbols++; - return &map->symbols[index]; -} - -const GB_bank_symbol_t *GB_map_find_symbol(GB_symbol_map_t *map, uint16_t addr) -{ - if (!map) return NULL; - size_t index = GB_map_find_symbol_index(map, addr); - if (index < map->n_symbols && map->symbols[index].addr != addr) { - index--; - } - if (index < map->n_symbols) { - return &map->symbols[index]; - } - return NULL; -} - -GB_symbol_map_t *GB_map_alloc(void) -{ - GB_symbol_map_t *map = malloc(sizeof(*map)); - memset(map, 0, sizeof(*map)); - return map; -} - -void GB_map_free(GB_symbol_map_t *map) -{ - for (unsigned i = 0; i < map->n_symbols; i++) { - free(map->symbols[i].name); - } - - if (map->symbols) { - free(map->symbols); - } - - free(map); -} - -static int hash_name(const char *name) -{ - int r = 0; - while (*name) { - r <<= 1; - if (r & 0x400) { - r ^= 0x401; - } - r += (unsigned char)*(name++); - } - - return r & 0x3FF; -} - -void GB_reversed_map_add_symbol(GB_reversed_symbol_map_t *map, uint16_t bank, GB_bank_symbol_t *bank_symbol) -{ - int hash = hash_name(bank_symbol->name); - GB_symbol_t *symbol = malloc(sizeof(*symbol)); - symbol->name = bank_symbol->name; - symbol->addr = bank_symbol->addr; - symbol->bank = bank; - symbol->next = map->buckets[hash]; - map->buckets[hash] = symbol; -} - -const GB_symbol_t *GB_reversed_map_find_symbol(GB_reversed_symbol_map_t *map, const char *name) -{ - int hash = hash_name(name); - GB_symbol_t *symbol = map->buckets[hash]; - - while (symbol) { - if (strcmp(symbol->name, name) == 0) return symbol; - symbol = symbol->next; - } - - return NULL; -} diff --git a/waterbox/sameboy/symbol_hash.h b/waterbox/sameboy/symbol_hash.h deleted file mode 100644 index 239b0e313e..0000000000 --- a/waterbox/sameboy/symbol_hash.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef symbol_hash_h -#define symbol_hash_h - -#include -#include - -typedef struct { - char *name; - uint16_t addr; -} GB_bank_symbol_t; - -typedef struct GB_symbol_s { - struct GB_symbol_s *next; - const char *name; - uint16_t bank; - uint16_t addr; -} GB_symbol_t; - -typedef struct { - GB_bank_symbol_t *symbols; - size_t n_symbols; -} GB_symbol_map_t; - -typedef struct { - GB_symbol_t *buckets[0x400]; -} GB_reversed_symbol_map_t; - -#ifdef GB_INTERNAL -void GB_reversed_map_add_symbol(GB_reversed_symbol_map_t *map, uint16_t bank, GB_bank_symbol_t *symbol); -const GB_symbol_t *GB_reversed_map_find_symbol(GB_reversed_symbol_map_t *map, const char *name); -GB_bank_symbol_t *GB_map_add_symbol(GB_symbol_map_t *map, uint16_t addr, const char *name); -const GB_bank_symbol_t *GB_map_find_symbol(GB_symbol_map_t *map, uint16_t addr); -GB_symbol_map_t *GB_map_alloc(void); -void GB_map_free(GB_symbol_map_t *map); -#endif - -#endif /* symbol_hash_h */ diff --git a/waterbox/sameboy/timing.c b/waterbox/sameboy/timing.c index d53c85a014..6e6c81e752 100644 --- a/waterbox/sameboy/timing.c +++ b/waterbox/sameboy/timing.c @@ -6,69 +6,6 @@ #include #endif -static int64_t get_nanoseconds(void) -{ -#ifndef _WIN32 - struct timeval now; - gettimeofday(&now, NULL); - return (now.tv_usec) * 1000 + now.tv_sec * 1000000000L; -#else - FILETIME time; - GetSystemTimeAsFileTime(&time); - return (((int64_t)time.dwHighDateTime << 32) | time.dwLowDateTime) * 100L; -#endif -} - -static void nsleep(uint64_t nanoseconds) -{ -#ifndef _WIN32 - struct timespec sleep = {0, nanoseconds}; - nanosleep(&sleep, NULL); -#else - HANDLE timer; - LARGE_INTEGER time; - timer = CreateWaitableTimer(NULL, true, NULL); - time.QuadPart = -(nanoseconds / 100L); - SetWaitableTimer(timer, &time, 0, NULL, NULL, false); - WaitForSingleObject(timer, INFINITE); - CloseHandle(timer); -#endif -} - -bool GB_timing_sync_turbo(GB_gameboy_t *gb) -{ - if (!gb->turbo_dont_skip) { - int64_t nanoseconds = get_nanoseconds(); - if (nanoseconds <= gb->last_sync + FRAME_LENGTH) { - return true; - } - gb->last_sync = nanoseconds; - } - return false; -} - -void GB_timing_sync(GB_gameboy_t *gb) -{ - if (gb->turbo) { - gb->cycles_since_last_sync = 0; - return; - } - /* Prevent syncing if not enough time has passed.*/ - if (gb->cycles_since_last_sync < LCDC_PERIOD / 4) return; - - uint64_t target_nanoseconds = gb->cycles_since_last_sync * FRAME_LENGTH / LCDC_PERIOD; - int64_t nanoseconds = get_nanoseconds(); - if (labs((signed long)(nanoseconds - gb->last_sync)) < target_nanoseconds ) { - nsleep(target_nanoseconds + gb->last_sync - nanoseconds); - gb->last_sync += target_nanoseconds; - } - else { - gb->last_sync = nanoseconds; - } - - gb->cycles_since_last_sync = 0; -} - static void GB_ir_run(GB_gameboy_t *gb) { if (gb->ir_queue_length == 0) return; @@ -136,7 +73,7 @@ void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles) gb->apu.apu_cycles += cycles; gb->cycles_since_ir_change += cycles; gb->cycles_since_input_ir_change += cycles; - gb->cycles_since_last_sync += cycles; + gb->cycles_since_epoch += cycles >> 1; GB_dma_run(gb); GB_hdma_run(gb); GB_apu_run(gb); diff --git a/waterbox/sameboy/timing.h b/waterbox/sameboy/timing.h index ed9e15a513..bd3b2f2732 100644 --- a/waterbox/sameboy/timing.h +++ b/waterbox/sameboy/timing.h @@ -7,9 +7,6 @@ void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles); void GB_set_internal_div_counter(GB_gameboy_t *gb, uint32_t value); void GB_rtc_run(GB_gameboy_t *gb); void GB_emulate_timer_glitch(GB_gameboy_t *gb, uint8_t old_tac, uint8_t new_tac); -bool GB_timing_sync_turbo(GB_gameboy_t *gb); /* Returns true if should skip frame */ -void GB_timing_sync(GB_gameboy_t *gb); - enum { GB_TIMA_RUNNING = 0, diff --git a/waterbox/sameboy/z80_cpu.c b/waterbox/sameboy/z80_cpu.c index 19adc82f47..9558765263 100644 --- a/waterbox/sameboy/z80_cpu.c +++ b/waterbox/sameboy/z80_cpu.c @@ -283,7 +283,7 @@ static void jr_r8(GB_gameboy_t *gb, uint8_t opcode) { /* Todo: Verify cycles are not 8 and 4 instead */ GB_advance_cycles(gb, 4); - gb->pc += (int8_t) GB_read_memory(gb, gb->pc++); + gb->pc += (int8_t)GB_read_memory(gb, gb->pc) + 1; GB_advance_cycles(gb, 8); } @@ -307,7 +307,7 @@ static void jr_cc_r8(GB_gameboy_t *gb, uint8_t opcode) { if (condition_code(gb, opcode)) { GB_advance_cycles(gb, 4); - gb->pc += (int8_t)GB_read_memory(gb, gb->pc++); + gb->pc += (int8_t)GB_read_memory(gb, gb->pc) + 1; GB_advance_cycles(gb, 8); } else {