pizza: RTC, maybe

This commit is contained in:
nattthebear 2017-06-25 09:19:32 -04:00
parent 537b2a1616
commit 7c5c3482e7
14 changed files with 451 additions and 499 deletions

View File

@ -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)]

View File

@ -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)
};
}

View File

@ -23,8 +23,6 @@ namespace BizHawk.Emulation.Cores.Consoles.SNK
ISettable<object, NeoGeoPort.SyncSettings>
{
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)

View File

@ -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);
}

Binary file not shown.

View File

@ -18,8 +18,6 @@
*/
#include <string.h>
#include <time.h>
#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;
}

View File

@ -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();

View File

@ -19,8 +19,6 @@
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <time.h>
#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);
}
}
}
}

View File

@ -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()
{

View File

@ -20,6 +20,8 @@
#ifndef __GLOBAL__
#define __GLOBAL__
#include <stdint.h>
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();

View File

@ -17,10 +17,8 @@
*/
#include <signal.h>
#include <string.h>
#include <strings.h>
#include <time.h>
#include "cycles.h"
#include "gameboy.h"

View File

@ -32,7 +32,6 @@
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <time.h>
#include "sgb.h"
#include <emulibc.h>
@ -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;
}

View File

@ -22,93 +22,91 @@
#include <stdio.h>
#include <stdint.h>
#include <sys/time.h>
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

View File

@ -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;