pizza: RTC, maybe
This commit is contained in:
parent
537b2a1616
commit
7c5c3482e7
|
@ -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)]
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -17,10 +17,8 @@
|
|||
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "cycles.h"
|
||||
#include "gameboy.h"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue