diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibPizza.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibPizza.cs index dd60e92de3..e8306aea35 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibPizza.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibPizza.cs @@ -26,6 +26,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy [StructLayout(LayoutKind.Sequential)] public new class FrameInfo : LibWaterboxCore.FrameInfo { + public long Time; public Buttons Keys; } [BizImport(CC)] diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Pizza.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Pizza.cs index 727dc8faf3..836923fea3 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Pizza.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Pizza.cs @@ -56,6 +56,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy BufferWidth = 256; BufferHeight = 224; } + InitializeRtc(new DateTime(2010, 1, 1)); // TODO: connect to syncsettings Console.WriteLine("Pizza Initialized: CGB {0} SGB {1}", IsCGBMode(), IsSGBMode()); } @@ -124,6 +125,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy { return _tmp = new LibPizza.FrameInfo { + Time = GetRtcTime(false), Keys = GetButtons(controller) }; } diff --git a/BizHawk.Emulation.Cores/Consoles/SNK/NeoGeoPort.cs b/BizHawk.Emulation.Cores/Consoles/SNK/NeoGeoPort.cs index 1b41de8eaf..b7f1f06b28 100644 --- a/BizHawk.Emulation.Cores/Consoles/SNK/NeoGeoPort.cs +++ b/BizHawk.Emulation.Cores/Consoles/SNK/NeoGeoPort.cs @@ -23,8 +23,6 @@ namespace BizHawk.Emulation.Cores.Consoles.SNK ISettable { internal LibNeoGeoPort _neopop; - private long _clockTime; - private int _clockDen; [CoreConstructor("NGP")] public NeoGeoPort(CoreComm comm, byte[] rom, SyncSettings syncSettings, bool deterministic) @@ -66,47 +64,22 @@ namespace BizHawk.Emulation.Cores.Consoles.SNK PostInit(); DeterministicEmulation = deterministic || !_syncSettings.UseRealTime; - _clockTime = (long)((_syncSettings.InitialTime - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds); + InitializeRtc(_syncSettings.InitialTime); } protected override LibWaterboxCore.FrameInfo FrameAdvancePrep(IController controller, bool render, bool rendersound) { - _clockDen += VsyncDenominator; - if (_clockDen >= VsyncNumerator) - { - _clockDen -= VsyncNumerator; - _clockTime++; - } - - long clockTime = DeterministicEmulation ? _clockTime : (long)((_syncSettings.InitialTime - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds); - if (controller.IsPressed("Power")) _neopop.HardReset(); return new LibNeoGeoPort.FrameInfo { - FrontendTime = clockTime, + FrontendTime = GetRtcTime(!DeterministicEmulation), Buttons = GetButtons(controller), SkipRendering = render ? 0 : 1, }; } - #region IStatable - - protected override void SaveStateBinaryInternal(BinaryWriter writer) - { - writer.Write(_clockTime); - writer.Write(_clockDen); - } - - protected override void LoadStateBinaryInternal(BinaryReader reader) - { - _clockTime = reader.ReadInt64(); - _clockDen = reader.ReadInt32(); - } - - #endregion - #region Controller private static int GetButtons(IController c) diff --git a/BizHawk.Emulation.Cores/Waterbox/WaterboxCore.cs b/BizHawk.Emulation.Cores/Waterbox/WaterboxCore.cs index 29181e2530..02824114a5 100644 --- a/BizHawk.Emulation.Cores/Waterbox/WaterboxCore.cs +++ b/BizHawk.Emulation.Cores/Waterbox/WaterboxCore.cs @@ -88,6 +88,36 @@ namespace BizHawk.Emulation.Cores.Waterbox } } + #region RTC + + private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0); + private long _clockTime; + private int _clockRemainder; + + protected void InitializeRtc(DateTime start) + { + _clockTime = (long)(start - Epoch).TotalSeconds; + } + + protected long GetRtcTime(bool realTime) + { + if (realTime && DeterministicEmulation) + throw new InvalidOperationException(); + return realTime ? (long)(DateTime.Now - Epoch).TotalSeconds : _clockTime; + } + + private void AdvanceRtc() + { + _clockRemainder += VsyncDenominator; + if (_clockRemainder >= VsyncNumerator) + { + _clockRemainder -= VsyncNumerator; + _clockTime++; + } + } + + #endregion + #region ISaveRam private LibWaterboxCore.MemoryArea[] _saveramAreas; @@ -179,6 +209,7 @@ namespace BizHawk.Emulation.Cores.Waterbox Frame++; if (IsLagFrame = frame.Lagged != 0) LagCount++; + AdvanceRtc(); BufferWidth = frame.Width; BufferHeight = frame.Height; @@ -246,6 +277,8 @@ namespace BizHawk.Emulation.Cores.Waterbox IsLagFrame = reader.ReadBoolean(); BufferWidth = reader.ReadInt32(); BufferHeight = reader.ReadInt32(); + _clockTime = reader.ReadInt64(); + _clockRemainder = reader.ReadInt32(); // reset pointers here! _core.SetInputCallback(null); //_exe.PrintDebuggingInfo(); @@ -261,6 +294,8 @@ namespace BizHawk.Emulation.Cores.Waterbox writer.Write(IsLagFrame); writer.Write(BufferWidth); writer.Write(BufferHeight); + writer.Write(_clockTime); + writer.Write(_clockRemainder); SaveStateBinaryInternal(writer); } diff --git a/output/dll/pizza.wbx.gz b/output/dll/pizza.wbx.gz index 66eb3a5fb3..df14acf500 100644 Binary files a/output/dll/pizza.wbx.gz and b/output/dll/pizza.wbx.gz differ diff --git a/waterbox/pizza/lib/cycles.c b/waterbox/pizza/lib/cycles.c index 19da4ba499..f8a350462e 100644 --- a/waterbox/pizza/lib/cycles.c +++ b/waterbox/pizza/lib/cycles.c @@ -18,8 +18,6 @@ */ #include -#include - #include "cycles.h" #include "global.h" #include "gpu.h" @@ -33,91 +31,90 @@ interrupts_flags_t *cycles_if; /* instance of the main struct */ -cycles_t cycles = { 0, 0, 0, 0 }; +cycles_t cycles = {0, 0, 0, 0}; #define CYCLES_PAUSES 256 /* hard sync stuff (for remote connection) */ -uint8_t cycles_hs_mode = 0; +uint8_t cycles_hs_mode = 0; /* type of next */ -typedef enum -{ - CYCLES_NEXT_TYPE_CYCLES, - CYCLES_NEXT_TYPE_CYCLES_HS, - CYCLES_NEXT_TYPE_DMA, +typedef enum { + CYCLES_NEXT_TYPE_CYCLES, + CYCLES_NEXT_TYPE_CYCLES_HS, + CYCLES_NEXT_TYPE_DMA, } cycles_next_type_enum_e; /* closest next and its type */ -uint_fast32_t cycles_very_next; -cycles_next_type_enum_e cycles_next_type; +uint_fast32_t cycles_very_next; +cycles_next_type_enum_e cycles_next_type; /* set hard sync mode. sync is given by the remote peer + local timer */ void cycles_start_hs() { - utils_log("Hard sync mode ON\n"); + utils_log("Hard sync mode ON\n"); - /* boolean set to on */ - cycles_hs_mode = 1; + /* boolean set to on */ + cycles_hs_mode = 1; } void cycles_stop_hs() { - utils_log("Hard sync mode OFF\n"); + utils_log("Hard sync mode OFF\n"); - /* boolean set to on */ - cycles_hs_mode = 0; + /* boolean set to on */ + cycles_hs_mode = 0; } /* set double or normal speed */ void cycles_set_speed(char dbl) { - /* set global */ - global_cpu_double_speed = dbl; + /* set global */ + global_cpu_double_speed = dbl; - /* update clock */ - if (global_cpu_double_speed) - cycles.clock = 4194304 * 2; - else - cycles.clock = 4194304; + /* update clock */ + if (global_cpu_double_speed) + cycles.clock = 4194304 * 2; + else + cycles.clock = 4194304; - /* calculate the mask */ - cycles_change_emulation_speed(); + /* calculate the mask */ + cycles_change_emulation_speed(); } /* set emulation speed */ void cycles_change_emulation_speed() { - cycles.step = ((4194304 / CYCLES_PAUSES) - << global_cpu_double_speed); + cycles.step = ((4194304 / CYCLES_PAUSES) + << global_cpu_double_speed); } void cycles_closest_next() { - int_fast32_t diff = cycles.cnt - cycles.next; + int_fast32_t diff = cycles.cnt - cycles.next; - /* init */ - cycles_very_next = cycles.next; - cycles_next_type = CYCLES_NEXT_TYPE_CYCLES; + /* init */ + cycles_very_next = cycles.next; + cycles_next_type = CYCLES_NEXT_TYPE_CYCLES; - int_fast32_t diff_new = cycles.cnt - mmu.dma_next; + int_fast32_t diff_new = cycles.cnt - mmu.dma_next; - /* DMA? */ - if (diff_new < diff) - { - /* this is the new lowest */ - cycles_very_next = mmu.dma_next; - cycles_next_type = CYCLES_NEXT_TYPE_DMA; - } + /* DMA? */ + if (diff_new < diff) + { + /* this is the new lowest */ + cycles_very_next = mmu.dma_next; + cycles_next_type = CYCLES_NEXT_TYPE_DMA; + } } /* this function is gonna be called every M-cycle = 4 ticks of CPU */ void cycles_step() { - cycles.cnt += 4; + cycles.cnt += 4; cycles.sampleclock += 2 >> global_cpu_double_speed; -/* + /* while (cycles.cnt >= cycles_very_next) { switch (cycles_next_type) @@ -157,173 +154,168 @@ void cycles_step() } */ - /* 65536 == cpu clock / CYCLES_PAUSES pauses every second */ - if (cycles.cnt == cycles.next) - { - cycles.next += cycles.step; + /* 65536 == cpu clock / CYCLES_PAUSES pauses every second */ + if (cycles.cnt == cycles.next) + { + cycles.next += cycles.step; + } - /* update current running seconds */ - if (cycles.cnt % cycles.clock == 0) - cycles.seconds++; - } + /* hard sync next step */ + if (cycles.cnt == cycles.hs_next) + { + /* set cycles for hard sync */ + cycles.hs_next += ((4096 * 4) << global_cpu_double_speed); - /* hard sync next step */ - if (cycles.cnt == cycles.hs_next) - { - /* set cycles for hard sync */ - cycles.hs_next += ((4096 * 4) << global_cpu_double_speed); + /* hard sync is on? */ + if (cycles_hs_mode) + { + /* send my status and wait for peer status back */ + serial_send_byte(); - /* hard sync is on? */ - if (cycles_hs_mode) - { - /* send my status and wait for peer status back */ - serial_send_byte(); + /* wait for reply */ + serial_wait_data(); - /* wait for reply */ - serial_wait_data(); + /* verify if we need to trigger an interrupt */ + serial_verify_intr(); + } + } - /* verify if we need to trigger an interrupt */ - serial_verify_intr(); - } - } + /* DMA */ + if (mmu.dma_next == cycles.cnt) + { + memcpy(&mmu.memory[0xFE00], &mmu.memory[mmu.dma_address], 160); - /* DMA */ - if (mmu.dma_next == cycles.cnt) - { - memcpy(&mmu.memory[0xFE00], &mmu.memory[mmu.dma_address], 160); + /* reset address */ + mmu.dma_address = 0x0000; - /* reset address */ - mmu.dma_address = 0x0000; + /* reset */ + mmu.dma_next = 1; + } - /* reset */ - mmu.dma_next = 1; - } + /* update GPU state */ + if (gpu.next == cycles.cnt) + gpu_step(); - /* update GPU state */ - if (gpu.next == cycles.cnt) - gpu_step(); + /* fs clock */ + if (sound.fs_cycles_next == cycles.cnt) + sound_step_fs(); - /* fs clock */ - if (sound.fs_cycles_next == cycles.cnt) - sound_step_fs(); - - /* channel one */ - if (sound.channel_one.duty_cycles_next == cycles.cnt) - sound_step_ch1(); + /* channel one */ + if (sound.channel_one.duty_cycles_next == cycles.cnt) + sound_step_ch1(); - /* channel two */ - if (sound.channel_two.duty_cycles_next == cycles.cnt) - sound_step_ch2(); - - /* channel three */ - if (sound.channel_three.cycles_next <= cycles.cnt) - sound_step_ch3(); - - /* channel four */ - if (sound.channel_four.cycles_next == cycles.cnt) - sound_step_ch4(); + /* channel two */ + if (sound.channel_two.duty_cycles_next == cycles.cnt) + sound_step_ch2(); - /* update timer state */ - if (cycles.cnt == timer.next) - { - timer.next += 256; - timer.div++; - } + /* channel three */ + if (sound.channel_three.cycles_next <= cycles.cnt) + sound_step_ch3(); - /* timer is on? */ - if (timer.sub_next == cycles.cnt) - { - timer.sub_next += timer.threshold; - timer.cnt++; - - /* cnt value > 255? trigger an interrupt */ - if (timer.cnt > 255) - { - timer.cnt = timer.mod; + /* channel four */ + if (sound.channel_four.cycles_next == cycles.cnt) + sound_step_ch4(); - /* trigger timer interrupt */ - cycles_if->timer = 1; - } - } + /* update timer state */ + if (cycles.cnt == timer.next) + { + timer.next += 256; + timer.div++; + } - /* update serial state */ - if (serial.next == cycles.cnt) - { - /* nullize serial next */ - serial.next -= 1; + /* timer is on? */ + if (timer.sub_next == cycles.cnt) + { + timer.sub_next += timer.threshold; + timer.cnt++; - /* reset counter */ - serial.bits_sent = 0; + /* cnt value > 255? trigger an interrupt */ + if (timer.cnt > 255) + { + timer.cnt = timer.mod; - /* gotta reply with 0xff when asking for ff01 */ - serial.data = 0xFF; + /* trigger timer interrupt */ + cycles_if->timer = 1; + } + } - /* reset transfer_start flag to yell I'M DONE */ - serial.transfer_start = 0; - - /* if not connected, trig the fucking interrupt */ - cycles_if->serial_io = 1; - } + /* update serial state */ + if (serial.next == cycles.cnt) + { + /* nullize serial next */ + serial.next -= 1; + + /* reset counter */ + serial.bits_sent = 0; + + /* gotta reply with 0xff when asking for ff01 */ + serial.data = 0xFF; + + /* reset transfer_start flag to yell I'M DONE */ + serial.transfer_start = 0; + + /* if not connected, trig the fucking interrupt */ + cycles_if->serial_io = 1; + } } /* things to do when vsync kicks in */ void cycles_vblank() { - return; - + return; } /* stuff tied to entering into hblank state */ void cycles_hdma() { - /* HDMA (only CGB) */ - if (mmu.hdma_to_transfer) - { - /* hblank transfer */ - if (mmu.hdma_transfer_mode) - { - /* transfer when line is changed and we're into HBLANK phase */ - if (mmu.memory[0xFF44] < 143 && - mmu.hdma_current_line != mmu.memory[0xFF44] && - (mmu.memory[0xFF41] & 0x03) == 0x00) - { - /* update current line */ - mmu.hdma_current_line = mmu.memory[0xFF44]; + /* HDMA (only CGB) */ + if (mmu.hdma_to_transfer) + { + /* hblank transfer */ + if (mmu.hdma_transfer_mode) + { + /* transfer when line is changed and we're into HBLANK phase */ + if (mmu.memory[0xFF44] < 143 && + mmu.hdma_current_line != mmu.memory[0xFF44] && + (mmu.memory[0xFF41] & 0x03) == 0x00) + { + /* update current line */ + mmu.hdma_current_line = mmu.memory[0xFF44]; - /* copy 0x10 bytes */ - if (mmu.vram_idx) - memcpy(mmu_addr_vram1() + mmu.hdma_dst_address - 0x8000, - &mmu.memory[mmu.hdma_src_address], 0x10); - else - memcpy(mmu_addr_vram0() + mmu.hdma_dst_address - 0x8000, - &mmu.memory[mmu.hdma_src_address], 0x10); + /* copy 0x10 bytes */ + if (mmu.vram_idx) + memcpy(mmu_addr_vram1() + mmu.hdma_dst_address - 0x8000, + &mmu.memory[mmu.hdma_src_address], 0x10); + else + memcpy(mmu_addr_vram0() + mmu.hdma_dst_address - 0x8000, + &mmu.memory[mmu.hdma_src_address], 0x10); - /* decrease bytes to transfer */ - mmu.hdma_to_transfer -= 0x10; + /* decrease bytes to transfer */ + mmu.hdma_to_transfer -= 0x10; - /* increase pointers */ - mmu.hdma_dst_address += 0x10; - mmu.hdma_src_address += 0x10; - } - } - } + /* increase pointers */ + mmu.hdma_dst_address += 0x10; + mmu.hdma_src_address += 0x10; + } + } + } } char cycles_init() { - cycles.inited = 1; + cycles.inited = 1; - /* interrupt registers */ - cycles_if = mmu_addr(0xFF0F); + /* interrupt registers */ + cycles_if = mmu_addr(0xFF0F); - /* init clock and counter */ - cycles.clock = 4194304; - cycles.cnt = 0; - cycles.hs_next = 70224; + /* init clock and counter */ + cycles.clock = 4194304; + cycles.cnt = 0; + cycles.hs_next = 70224; - /* mask for pauses cycles fast calc */ - cycles.step = 4194304 / CYCLES_PAUSES; - cycles.next = 4194304 / CYCLES_PAUSES; + /* mask for pauses cycles fast calc */ + cycles.step = 4194304 / CYCLES_PAUSES; + cycles.next = 4194304 / CYCLES_PAUSES; - return 0; + return 0; } diff --git a/waterbox/pizza/lib/cycles.h b/waterbox/pizza/lib/cycles.h index 39cf216552..58c7c2bb4c 100644 --- a/waterbox/pizza/lib/cycles.h +++ b/waterbox/pizza/lib/cycles.h @@ -25,26 +25,23 @@ typedef struct cycles_s { - /* am i init'ed? */ - uint_fast32_t inited; - - /* ticks counter */ - uint64_t cnt; + /* am i init'ed? */ + uint_fast32_t inited; - // CPU clock. advances at 4MHz or 8MHz depending on current cgb setting - uint_fast32_t clock; + /* ticks counter */ + uint64_t cnt; - /* handy for calculation */ - uint64_t next; + // CPU clock. advances at 4MHz or 8MHz depending on current cgb setting + uint_fast32_t clock; - /* step varying on cpu and emulation speed */ - uint_fast32_t step; + /* handy for calculation */ + uint64_t next; - /* total running seconds */ - uint_fast32_t seconds; + /* step varying on cpu and emulation speed */ + uint_fast32_t step; - /* 2 spares */ - uint64_t hs_next; + /* 2 spares */ + uint64_t hs_next; // reference clock. advances at 2MHz always uint64_t sampleclock; @@ -56,7 +53,7 @@ extern cycles_t cycles; // extern uint8_t cycles_hs_peer_cnt; /* callback function */ -typedef void (*cycles_send_cb_t) (uint32_t v); +typedef void (*cycles_send_cb_t)(uint32_t v); /* prototypes */ void cycles_change_emulation_speed(); diff --git a/waterbox/pizza/lib/gameboy.c b/waterbox/pizza/lib/gameboy.c index 6fd8fc7977..be64e6436d 100644 --- a/waterbox/pizza/lib/gameboy.c +++ b/waterbox/pizza/lib/gameboy.c @@ -19,8 +19,6 @@ #include #include -#include -#include #include "cartridge.h" #include "sound.h" #include "mmu.h" @@ -36,206 +34,202 @@ char gameboy_inited = 0; - void gameboy_init() { - /* init z80 */ - z80_init(); + /* init z80 */ + z80_init(); - /* init cycles syncronizer */ - cycles_init(); + /* init cycles syncronizer */ + cycles_init(); - /* init timer */ - timer_init(); + /* init timer */ + timer_init(); - /* init serial */ - serial_init(); + /* init serial */ + serial_init(); - /* init sound (this will start audio thread) */ - sound_init(); + /* init sound (this will start audio thread) */ + sound_init(); - /* reset GPU counters */ - gpu_reset(); + /* reset GPU counters */ + gpu_reset(); - /* reset to default values */ - mmu_write_no_cyc(0xFF05, 0x00); - mmu_write_no_cyc(0xFF06, 0x00); - mmu_write_no_cyc(0xFF07, 0x00); - mmu_write_no_cyc(0xFF10, 0x80); - mmu_write_no_cyc(0xFF11, 0xBF); - mmu_write_no_cyc(0xFF12, 0xF3); - mmu_write_no_cyc(0xFF14, 0xBF); - mmu_write_no_cyc(0xFF16, 0x3F); - mmu_write_no_cyc(0xFF17, 0x00); - mmu_write_no_cyc(0xFF19, 0xBF); - mmu_write_no_cyc(0xFF1A, 0x7F); - mmu_write_no_cyc(0xFF1B, 0xFF); - mmu_write_no_cyc(0xFF1C, 0x9F); - mmu_write_no_cyc(0xFF1E, 0xBF); - mmu_write_no_cyc(0xFF20, 0xFF); - mmu_write_no_cyc(0xFF21, 0x00); - mmu_write_no_cyc(0xFF22, 0x00); - mmu_write_no_cyc(0xFF23, 0xBF); - mmu_write_no_cyc(0xFF24, 0x77); - mmu_write_no_cyc(0xFF25, 0xF3); - mmu_write_no_cyc(0xFF26, 0xF1); - mmu_write_no_cyc(0xFF40, 0x91); - mmu_write_no_cyc(0xFF41, 0x80); - mmu_write_no_cyc(0xFF42, 0x00); - mmu_write_no_cyc(0xFF43, 0x00); - mmu_write_no_cyc(0xFF44, 0x00); - mmu_write_no_cyc(0xFF45, 0x00); - mmu_write_no_cyc(0xFF47, 0xFC); - mmu_write_no_cyc(0xFF48, 0xFF); - mmu_write_no_cyc(0xFF49, 0xFF); - mmu_write_no_cyc(0xFF4A, 0x00); - mmu_write_no_cyc(0xFF4B, 0x00); - mmu_write_no_cyc(0xFF98, 0xDC); - mmu_write_no_cyc(0xFFFF, 0x00); - mmu_write_no_cyc(0xC000, 0x08); - mmu_write_no_cyc(0xFFFE, 0x69); + /* reset to default values */ + mmu_write_no_cyc(0xFF05, 0x00); + mmu_write_no_cyc(0xFF06, 0x00); + mmu_write_no_cyc(0xFF07, 0x00); + mmu_write_no_cyc(0xFF10, 0x80); + mmu_write_no_cyc(0xFF11, 0xBF); + mmu_write_no_cyc(0xFF12, 0xF3); + mmu_write_no_cyc(0xFF14, 0xBF); + mmu_write_no_cyc(0xFF16, 0x3F); + mmu_write_no_cyc(0xFF17, 0x00); + mmu_write_no_cyc(0xFF19, 0xBF); + mmu_write_no_cyc(0xFF1A, 0x7F); + mmu_write_no_cyc(0xFF1B, 0xFF); + mmu_write_no_cyc(0xFF1C, 0x9F); + mmu_write_no_cyc(0xFF1E, 0xBF); + mmu_write_no_cyc(0xFF20, 0xFF); + mmu_write_no_cyc(0xFF21, 0x00); + mmu_write_no_cyc(0xFF22, 0x00); + mmu_write_no_cyc(0xFF23, 0xBF); + mmu_write_no_cyc(0xFF24, 0x77); + mmu_write_no_cyc(0xFF25, 0xF3); + mmu_write_no_cyc(0xFF26, 0xF1); + mmu_write_no_cyc(0xFF40, 0x91); + mmu_write_no_cyc(0xFF41, 0x80); + mmu_write_no_cyc(0xFF42, 0x00); + mmu_write_no_cyc(0xFF43, 0x00); + mmu_write_no_cyc(0xFF44, 0x00); + mmu_write_no_cyc(0xFF45, 0x00); + mmu_write_no_cyc(0xFF47, 0xFC); + mmu_write_no_cyc(0xFF48, 0xFF); + mmu_write_no_cyc(0xFF49, 0xFF); + mmu_write_no_cyc(0xFF4A, 0x00); + mmu_write_no_cyc(0xFF4B, 0x00); + mmu_write_no_cyc(0xFF98, 0xDC); + mmu_write_no_cyc(0xFFFF, 0x00); + mmu_write_no_cyc(0xC000, 0x08); + mmu_write_no_cyc(0xFFFE, 0x69); - if (global_cgb) - state.a = 0x11; - else - state.a = 0x00; + if (global_cgb) + state.a = 0x11; + else + state.a = 0x00; - state.b = 0x00; - state.c = 0x13; - state.d = 0x00; - state.e = 0xd8; - state.h = 0x01; - state.l = 0x4d; - state.pc = 0x0100; - state.sp = 0xFFFE; - *state.f = 0xB0; + state.b = 0x00; + state.c = 0x13; + state.d = 0x00; + state.e = 0xd8; + state.h = 0x01; + state.l = 0x4d; + state.pc = 0x0100; + state.sp = 0xFFFE; + *state.f = 0xB0; - /* reset counter */ - cycles.cnt = 0; - /* start at normal speed */ - global_cpu_double_speed = 0; + /* reset counter */ + cycles.cnt = 0; + /* start at normal speed */ + global_cpu_double_speed = 0; - /* mark as inited */ - gameboy_inited = 1; + /* mark as inited */ + gameboy_inited = 1; - return; + return; } void gameboy_run(uint64_t target) { - uint8_t op; + uint8_t op; - /* get interrupt flags and interrupt enables */ - uint8_t *int_e; - uint8_t *int_f; + /* get interrupt flags and interrupt enables */ + uint8_t *int_e; + uint8_t *int_f; - /* pointers to memory location of interrupt enables/flags */ - int_e = mmu_addr(0xFFFF); - int_f = mmu_addr(0xFF0F); + /* pointers to memory location of interrupt enables/flags */ + int_e = mmu_addr(0xFFFF); + int_f = mmu_addr(0xFF0F); - /* run stuff! */ - /* mechanism is simple. */ - /* 1) execute instruction 2) update cycles counter 3) check interrupts */ - /* and repeat forever */ - while (cycles.sampleclock < target) - { - /* get op */ - op = mmu_read(state.pc); + /* run stuff! */ + /* mechanism is simple. */ + /* 1) execute instruction 2) update cycles counter 3) check interrupts */ + /* and repeat forever */ + while (cycles.sampleclock < target) + { + /* get op */ + op = mmu_read(state.pc); - /* print out CPU state if enabled by debug flag */ - if (global_debug) - { - utils_log("OP: %02x F: %02x PC: %04x:%02x:%02x SP: %04x:%02x:%02x ", - op, *state.f & 0xd0, state.pc, - mmu_read_no_cyc(state.pc + 1), - mmu_read_no_cyc(state.pc + 2), state.sp, - mmu_read_no_cyc(state.sp), - mmu_read_no_cyc(state.sp + 1)); + /* print out CPU state if enabled by debug flag */ + if (global_debug) + { + utils_log("OP: %02x F: %02x PC: %04x:%02x:%02x SP: %04x:%02x:%02x ", + op, *state.f & 0xd0, state.pc, + mmu_read_no_cyc(state.pc + 1), + mmu_read_no_cyc(state.pc + 2), state.sp, + mmu_read_no_cyc(state.sp), + mmu_read_no_cyc(state.sp + 1)); + utils_log("A: %02x BC: %04x DE: %04x HL: %04x FF41: %02x " + "FF44: %02x ENAB: %02x INTE: %02x INTF: %02x\n", + state.a, *state.bc, + *state.de, *state.hl, + mmu_read_no_cyc(0xFF41), + mmu_read_no_cyc(0xFF44), + state.int_enable, + *int_e, *int_f); + } - utils_log("A: %02x BC: %04x DE: %04x HL: %04x FF41: %02x " - "FF44: %02x ENAB: %02x INTE: %02x INTF: %02x\n", - state.a, *state.bc, - *state.de, *state.hl, - mmu_read_no_cyc(0xFF41), - mmu_read_no_cyc(0xFF44), - state.int_enable, - *int_e, *int_f); - } + /* execute instruction by the GB Z80 version */ + z80_execute(op); - /* execute instruction by the GB Z80 version */ - z80_execute(op); + /* if last op was Interrupt Enable (0xFB) */ + /* we need to check for INTR on next cycle */ + if (op == 0xFB) + continue; - /* if last op was Interrupt Enable (0xFB) */ - /* we need to check for INTR on next cycle */ - if (op == 0xFB) - continue; + /* interrupts filtered by enable flags */ + uint8_t int_r = (*int_f & *int_e); - /* interrupts filtered by enable flags */ - uint8_t int_r = (*int_f & *int_e); + /* check for interrupts */ + if ((state.int_enable || op == 0x76) && (int_r != 0)) + { + /* discard useless bits */ + if ((int_r & 0x1F) == 0x00) + continue; - /* check for interrupts */ - if ((state.int_enable || op == 0x76) && (int_r != 0)) - { - /* discard useless bits */ - if ((int_r & 0x1F) == 0x00) - continue; + /* beware of instruction that doesn't move PC! */ + /* like HALT (0x76) */ + if (op == 0x76) + { + state.pc++; - /* beware of instruction that doesn't move PC! */ - /* like HALT (0x76) */ - if (op == 0x76) - { - state.pc++; + if (state.int_enable == 0) + continue; + } - if (state.int_enable == 0) - continue; - } + /* reset int-enable flag, it will be restored after a RETI op */ + state.int_enable = 0; - /* reset int-enable flag, it will be restored after a RETI op */ - state.int_enable = 0; + if ((int_r & 0x01) == 0x01) + { + /* vblank interrupt triggers RST 5 */ - if ((int_r & 0x01) == 0x01) - { - /* vblank interrupt triggers RST 5 */ + /* reset flag */ + *int_f &= 0xFE; - /* reset flag */ - *int_f &= 0xFE; + /* handle the interrupt */ + z80_intr(0x0040); + } + else if ((int_r & 0x02) == 0x02) + { + /* LCD Stat interrupt */ - /* handle the interrupt */ - z80_intr(0x0040); - } - else if ((int_r & 0x02) == 0x02) - { - /* LCD Stat interrupt */ + /* reset flag */ + *int_f &= 0xFD; - /* reset flag */ - *int_f &= 0xFD; + /* handle the interrupt! */ + z80_intr(0x0048); + } + else if ((int_r & 0x04) == 0x04) + { + /* timer interrupt */ - /* handle the interrupt! */ - z80_intr(0x0048); - } - else if ((int_r & 0x04) == 0x04) - { - /* timer interrupt */ + /* reset flag */ + *int_f &= 0xFB; - /* reset flag */ - *int_f &= 0xFB; + /* handle the interrupt! */ + z80_intr(0x0050); + } + else if ((int_r & 0x08) == 0x08) + { + /* serial interrupt */ - /* handle the interrupt! */ - z80_intr(0x0050); - } - else if ((int_r & 0x08) == 0x08) - { - /* serial interrupt */ + /* reset flag */ + *int_f &= 0xF7; - /* reset flag */ - *int_f &= 0xF7; - - /* handle the interrupt! */ - z80_intr(0x0058); - } - } - } - - return; + /* handle the interrupt! */ + z80_intr(0x0058); + } + } + } } diff --git a/waterbox/pizza/lib/global.c b/waterbox/pizza/lib/global.c index 8f0818dd94..e14d158dc3 100644 --- a/waterbox/pizza/lib/global.c +++ b/waterbox/pizza/lib/global.c @@ -31,6 +31,7 @@ char global_rumble; char global_window; // if true, show window int global_lagged; void (*global_input_callback)(void); +int64_t global_currenttime; void global_init() { diff --git a/waterbox/pizza/lib/global.h b/waterbox/pizza/lib/global.h index dbc477bcc6..06e3cff320 100644 --- a/waterbox/pizza/lib/global.h +++ b/waterbox/pizza/lib/global.h @@ -20,6 +20,8 @@ #ifndef __GLOBAL__ #define __GLOBAL__ +#include + extern char global_window; extern char global_debug; extern char global_cgb; @@ -30,6 +32,7 @@ extern char global_rumble; extern char global_cart_name[256]; extern int global_lagged; extern void (*global_input_callback)(void); +extern int64_t global_currenttime; /* prototypes */ void global_init(); diff --git a/waterbox/pizza/lib/gpu.c b/waterbox/pizza/lib/gpu.c index 8f4ee2c848..44859f824d 100644 --- a/waterbox/pizza/lib/gpu.c +++ b/waterbox/pizza/lib/gpu.c @@ -17,10 +17,8 @@ */ -#include #include #include -#include #include "cycles.h" #include "gameboy.h" diff --git a/waterbox/pizza/lib/mmu.c b/waterbox/pizza/lib/mmu.c index 4fe931f3f2..8a8bc9b30b 100644 --- a/waterbox/pizza/lib/mmu.c +++ b/waterbox/pizza/lib/mmu.c @@ -32,7 +32,6 @@ #include #include #include -#include #include "sgb.h" #include @@ -140,7 +139,6 @@ void mmu_init(uint8_t c, uint8_t rn) mmu.dma_cycles = 0; mmu.dma_address = 0; mmu.rtc_mode = 0; - time(&mmu.rtc_time); /* reset memory */ bzero(mmu.memory, 65536); @@ -207,7 +205,7 @@ uint8_t mmu_read(uint16_t a) { if (mmu.rtc_mode != 0x00) { - time_t diff = mmu.rtc_latch_time - mmu.rtc_time; + int64_t diff = mmu.rtc_latch_time - mmu.rtc_time; switch (mmu.rtc_mode) { @@ -358,47 +356,6 @@ void mmu_save_saveram(uint8_t* dest, int sz) } } -void mmu_restore_rtc(char *fn) -{ - /* save only if cartridge got a battery */ - if (mmu.carttype == 0x10 || - mmu.carttype == 0x13) - { - FILE *fp = fopen(fn, "r+"); - - /* it could be not present */ - if (fp == NULL) - { - /* just pick current time */ - time(&mmu.rtc_time); - return; - } - - /* read last saved time */ - fscanf(fp, "%ld", &mmu.rtc_time); - - fclose(fp); - } -} - -void mmu_save_rtc(char *fn) -{ - /* save only if cartridge got a battery */ - if (mmu.carttype == 0x10 || - mmu.carttype == 0x13) - { - FILE *fp = fopen(fn, "w+"); - - if (fp == NULL) - { - printf("Error saving RTC\n"); - return; - } - - fprintf(fp, "%ld", mmu.rtc_time); - } -} - void mmu_set_rumble_cb(mmu_rumble_cb_t cb) { mmu_rumble_cb = cb; @@ -428,10 +385,9 @@ void mmu_write(uint16_t a, uint8_t v) /* wanna access to RTC register? */ if (a >= 0xA000 && a <= 0xBFFF && mmu.rtc_mode != 0x00) { - time_t t,s1,s2,m1,m2,h1,h2,d1,d2,days; + int64_t t,s1,s2,m1,m2,h1,h2,d1,d2,days; - /* get current time */ - time(&t); + t = global_currenttime; /* extract parts in seconds from current and ref times */ s1 = t % 60; @@ -727,7 +683,7 @@ void mmu_write(uint16_t a, uint8_t v) else if (a >= 0x6000 && a <= 0x7FFF) { /* latch clock data. move clock data to RTC registers */ - time(&mmu.rtc_latch_time); + mmu.rtc_latch_time = global_currenttime; } diff --git a/waterbox/pizza/lib/mmu.h b/waterbox/pizza/lib/mmu.h index 4fda013058..cc36b8e0cc 100644 --- a/waterbox/pizza/lib/mmu.h +++ b/waterbox/pizza/lib/mmu.h @@ -22,93 +22,91 @@ #include #include -#include -typedef struct mmu_s { - /* main 64K of memory */ - uint8_t memory[65536]; +typedef struct mmu_s +{ + /* main 64K of memory */ + uint8_t memory[65536]; - /* vram in standby */ - uint8_t vram0[0x2000]; - uint8_t vram1[0x2000]; + /* vram in standby */ + uint8_t vram0[0x2000]; + uint8_t vram1[0x2000]; - /* vram current idx */ - uint8_t vram_idx; - uint8_t spare; - uint16_t spare2; + /* vram current idx */ + uint8_t vram_idx; + uint8_t spare; + uint16_t spare2; - // cartridge RAM - uint8_t ram_external_enabled; - uint8_t ram_current_bank; + // cartridge RAM + uint8_t ram_external_enabled; + uint8_t ram_current_bank; - /* cartridge type */ - uint8_t carttype; + /* cartridge type */ + uint8_t carttype; - /* number of switchable roms */ - uint8_t roms; + /* number of switchable roms */ + uint8_t roms; - /* current ROM bank */ - uint8_t rom_current_bank; + /* current ROM bank */ + uint8_t rom_current_bank; - /* type of banking */ - uint8_t banking; + /* type of banking */ + uint8_t banking; - /* working RAM (only CGB) */ - uint8_t wram[0x8000]; + /* working RAM (only CGB) */ + uint8_t wram[0x8000]; - /* current WRAM bank (only CGB) */ - uint8_t wram_current_bank; - uint8_t spare3; - uint16_t spare4; + /* current WRAM bank (only CGB) */ + uint8_t wram_current_bank; + uint8_t spare3; + uint16_t spare4; - /* DMA transfer stuff */ - uint_fast16_t dma_address; - uint_fast16_t dma_cycles; + /* DMA transfer stuff */ + uint_fast16_t dma_address; + uint_fast16_t dma_cycles; - /* HDMA transfer stuff */ - uint16_t hdma_src_address; - uint16_t hdma_dst_address; - uint16_t hdma_to_transfer; - uint8_t hdma_transfer_mode; - uint8_t hdma_current_line; + /* HDMA transfer stuff */ + uint16_t hdma_src_address; + uint16_t hdma_dst_address; + uint16_t hdma_to_transfer; + uint8_t hdma_transfer_mode; + uint8_t hdma_current_line; - /* RTC stuff */ - uint8_t rtc_mode; - uint8_t spare5; - uint16_t spare6; - time_t rtc_time; - time_t rtc_latch_time; + /* RTC stuff */ + uint8_t rtc_mode; + int64_t rtc_time; + int64_t rtc_latch_time; - uint64_t dma_next; + uint64_t dma_next; } mmu_t; extern mmu_t mmu; /* callback function */ -typedef void (*mmu_rumble_cb_t) (uint8_t onoff); +typedef void (*mmu_rumble_cb_t)(uint8_t onoff); /* functions prototypes */ -void *mmu_addr(uint16_t a); -void *mmu_addr_vram0(); -void *mmu_addr_vram1(); -void mmu_dump_all(); -void mmu_init(uint8_t c, uint8_t rn); -void mmu_init_ram(uint32_t c); -void mmu_load(uint8_t *data, size_t sz, uint16_t a); -void mmu_load_cartridge(const uint8_t *data, size_t sz); -void mmu_move(uint16_t d, uint16_t s); -uint8_t mmu_read_no_cyc(uint16_t a); -uint8_t mmu_read(uint16_t a); -unsigned int mmu_read_16(uint16_t a); +void *mmu_addr(uint16_t a); +void *mmu_addr_vram0(); +void *mmu_addr_vram1(); +void mmu_dump_all(); +void mmu_init(uint8_t c, uint8_t rn); +void mmu_init_ram(uint32_t c); +void mmu_load(uint8_t *data, size_t sz, uint16_t a); +void mmu_load_cartridge(const uint8_t *data, size_t sz); +void mmu_move(uint16_t d, uint16_t s); +uint8_t mmu_read_no_cyc(uint16_t a); +uint8_t mmu_read(uint16_t a); +unsigned int mmu_read_16(uint16_t a); int mmu_saveram_size(void); -void mmu_restore_saveram(const uint8_t* data, int sz); -void mmu_save_saveram(uint8_t* dest, int sz); -void mmu_restore_rtc(char *fn); -void mmu_save_rtc(char *fn); -void mmu_set_rumble_cb(mmu_rumble_cb_t cb); -void mmu_step(); -void mmu_write_no_cyc(uint16_t a, uint8_t v); -void mmu_write(uint16_t a, uint8_t v); -void mmu_write_16(uint16_t a, uint16_t v); +void mmu_restore_saveram(const uint8_t *data, int sz); +void mmu_save_saveram(uint8_t *dest, int sz); +void mmu_restore_rtc(char *fn); +void mmu_save_rtc(char *fn); +void mmu_set_rumble_cb(mmu_rumble_cb_t cb); +void mmu_step(); +void mmu_write_no_cyc(uint16_t a, uint8_t v); +void mmu_write(uint16_t a, uint8_t v); +void mmu_write_16(uint16_t a, uint16_t v); #endif diff --git a/waterbox/pizza/pizza.c b/waterbox/pizza/pizza.c index 0736f7ef89..70f6083146 100644 --- a/waterbox/pizza/pizza.c +++ b/waterbox/pizza/pizza.c @@ -93,6 +93,7 @@ typedef struct int32_t Height; int32_t Samples; int32_t Lagged; + int64_t Time; uint32_t Keys; } MyFrameInfo; @@ -107,6 +108,7 @@ EXPORT void FrameAdvance(MyFrameInfo *frame) input_set_keys(frame->Keys); current_vbuff = frame->VideoBuffer; global_lagged = 1; + global_currenttime = frame->Time; uint64_t current = cycles.sampleclock; uint64_t target = current + 35112 - overflow;