hook up RTC support for new BSNES, resolves #3577

This commit is contained in:
CasualPokePlayer 2023-04-01 01:23:16 -07:00
parent 116bc26556
commit 22e35c45fc
14 changed files with 121 additions and 24 deletions

Binary file not shown.

View File

@ -64,13 +64,16 @@
this.lblRegion = new BizHawk.WinForms.Controls.LocLabelEx();
this.lblEntropy = new BizHawk.WinForms.Controls.LocLabelEx();
this.lblDoubleSize = new BizHawk.WinForms.Controls.LocLabelEx();
this.cbUseRealTime = new System.Windows.Forms.CheckBox();
this.dtpInitialTime = new System.Windows.Forms.DateTimePicker();
this.lblInitialTime = new BizHawk.WinForms.Controls.LocLabelEx();
this.groupBox1.SuspendLayout();
this.SuspendLayout();
//
// btnOk
//
this.btnOk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnOk.Location = new System.Drawing.Point(136, 405);
this.btnOk.Location = new System.Drawing.Point(136, 439);
this.btnOk.Name = "btnOk";
this.btnOk.Size = new System.Drawing.Size(75, 23);
this.btnOk.TabIndex = 26;
@ -82,7 +85,7 @@
//
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btnCancel.Location = new System.Drawing.Point(217, 405);
this.btnCancel.Location = new System.Drawing.Point(217, 439);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(75, 23);
this.btnCancel.TabIndex = 0;
@ -118,7 +121,7 @@
this.groupBox1.Controls.Add(this.Obj3Checkbox);
this.groupBox1.Controls.Add(this.Obj2Checkbox);
this.groupBox1.Controls.Add(this.Obj1Checkbox);
this.groupBox1.Location = new System.Drawing.Point(18, 282);
this.groupBox1.Location = new System.Drawing.Point(18, 316);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(274, 115);
this.groupBox1.TabIndex = 13;
@ -264,7 +267,7 @@
//
this.EntropyBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.EntropyBox.FormattingEnabled = true;
this.EntropyBox.Location = new System.Drawing.Point(16, 215);
this.EntropyBox.Location = new System.Drawing.Point(16, 249);
this.EntropyBox.Name = "EntropyBox";
this.EntropyBox.Size = new System.Drawing.Size(128, 21);
this.EntropyBox.TabIndex = 10;
@ -273,7 +276,7 @@
//
this.RegionBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.RegionBox.FormattingEnabled = true;
this.RegionBox.Location = new System.Drawing.Point(162, 255);
this.RegionBox.Location = new System.Drawing.Point(161, 289);
this.RegionBox.Name = "RegionBox";
this.RegionBox.Size = new System.Drawing.Size(128, 21);
this.RegionBox.TabIndex = 13;
@ -353,7 +356,7 @@
//
this.AspectRatioCorrectionBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.AspectRatioCorrectionBox.FormattingEnabled = true;
this.AspectRatioCorrectionBox.Location = new System.Drawing.Point(161, 215);
this.AspectRatioCorrectionBox.Location = new System.Drawing.Point(161, 249);
this.AspectRatioCorrectionBox.Name = "AspectRatioCorrectionBox";
this.AspectRatioCorrectionBox.Size = new System.Drawing.Size(128, 21);
this.AspectRatioCorrectionBox.TabIndex = 11;
@ -382,32 +385,32 @@
//
this.SatellaviewCartridgeBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.SatellaviewCartridgeBox.FormattingEnabled = true;
this.SatellaviewCartridgeBox.Location = new System.Drawing.Point(16, 255);
this.SatellaviewCartridgeBox.Location = new System.Drawing.Point(16, 289);
this.SatellaviewCartridgeBox.Name = "SatellaviewCartridgeBox";
this.SatellaviewCartridgeBox.Size = new System.Drawing.Size(128, 21);
this.SatellaviewCartridgeBox.TabIndex = 12;
//
// lblSatellaviewCartridge
//
this.lblSatellaviewCartridge.Location = new System.Drawing.Point(14, 239);
this.lblSatellaviewCartridge.Location = new System.Drawing.Point(16, 273);
this.lblSatellaviewCartridge.Name = "lblSatellaviewCartridge";
this.lblSatellaviewCartridge.Text = "Satellaview cartridge";
//
// lblAspectRatioCorrection
//
this.lblAspectRatioCorrection.Location = new System.Drawing.Point(159, 198);
this.lblAspectRatioCorrection.Location = new System.Drawing.Point(159, 233);
this.lblAspectRatioCorrection.Name = "lblAspectRatioCorrection";
this.lblAspectRatioCorrection.Text = "Aspect Ratio Correction";
//
// lblRegion
//
this.lblRegion.Location = new System.Drawing.Point(159, 239);
this.lblRegion.Location = new System.Drawing.Point(159, 273);
this.lblRegion.Name = "lblRegion";
this.lblRegion.Text = "Region";
//
// lblEntropy
//
this.lblEntropy.Location = new System.Drawing.Point(13, 198);
this.lblEntropy.Location = new System.Drawing.Point(13, 233);
this.lblEntropy.Name = "lblEntropy";
this.lblEntropy.Text = "Entropy";
//
@ -418,6 +421,34 @@
this.lblDoubleSize.Name = "lblDoubleSize";
this.lblDoubleSize.Text = "Some games are changing the resolution constantly (e.g. SD3) so this option can f" +
"orce the SNES output to stay double-size always.";
//
// cbUseRealTime
//
this.cbUseRealTime.AutoSize = true;
this.cbUseRealTime.Location = new System.Drawing.Point(161, 176);
this.cbUseRealTime.Name = "cbUseRealTime";
this.cbUseRealTime.Size = new System.Drawing.Size(96, 17);
this.cbUseRealTime.TabIndex = 27;
this.cbUseRealTime.Text = "Use Real Time";
this.cbUseRealTime.UseVisualStyleBackColor = true;
//
// dtpInitialTime
//
this.dtpInitialTime.CustomFormat = "yyyy-MM-dd HH:mm:ss";
this.dtpInitialTime.Format = System.Windows.Forms.DateTimePickerFormat.Custom;
this.dtpInitialTime.Location = new System.Drawing.Point(79, 203);
this.dtpInitialTime.MinDate = new System.DateTime(1970, 1, 1, 0, 0, 0, 0);
this.dtpInitialTime.Name = "dtpInitialTime";
this.dtpInitialTime.Size = new System.Drawing.Size(206, 20);
this.dtpInitialTime.TabIndex = 27;
//
// lblInitialTime
//
this.lblInitialTime.Location = new System.Drawing.Point(15, 202);
this.lblInitialTime.MaximumSize = new System.Drawing.Size(260, 0);
this.lblInitialTime.Name = "lblInitialTime";
this.lblInitialTime.Padding = new System.Windows.Forms.Padding(0, 4, 0, 4);
this.lblInitialTime.Text = "Initial Time";
//
// BSNESOptions
//
@ -425,7 +456,8 @@
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.btnCancel;
this.ClientSize = new System.Drawing.Size(304, 436);
this.ClientSize = new System.Drawing.Size(304, 470);
this.Controls.Add(this.lblInitialTime);
this.Controls.Add(this.SatellaviewCartridgeBox);
this.Controls.Add(this.lblSatellaviewCartridge);
this.Controls.Add(this.cbShowCursor);
@ -446,6 +478,8 @@
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.lblDoubleSize);
this.Controls.Add(this.cbDoubleSize);
this.Controls.Add(this.cbUseRealTime);
this.Controls.Add(this.dtpInitialTime);
this.Controls.Add(this.btnCancel);
this.Controls.Add(this.btnOk);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
@ -501,5 +535,8 @@
private System.Windows.Forms.CheckBox cbShowCursor;
private WinForms.Controls.LocLabelEx lblSatellaviewCartridge;
private System.Windows.Forms.ComboBox SatellaviewCartridgeBox;
private System.Windows.Forms.CheckBox cbUseRealTime;
private System.Windows.Forms.DateTimePicker dtpInitialTime;
private WinForms.Controls.LocLabelEx lblInitialTime;
}
}

View File

@ -43,6 +43,8 @@ namespace BizHawk.Client.EmuHawk
FastDSP = ss.FastDSP,
FastCoprocessors = ss.FastCoprocessors,
UseSGB2 = ss.UseSGB2,
UseRealTime = ss.UseRealTime,
InitialTime = ss.InitialTime,
ShowObj1 = s.ShowOBJ_0,
ShowObj2 = s.ShowOBJ_1,
ShowObj3 = s.ShowOBJ_2,
@ -74,6 +76,8 @@ namespace BizHawk.Client.EmuHawk
ss.FastCoprocessors = dlg.FastCoprocessors;
ss.UseSGB2 = dlg.UseSGB2;
ss.SatellaviewCartridge = dlg.SatellaviewCartridge;
ss.UseRealTime = dlg.UseRealTime;
ss.InitialTime = dlg.InitialTime;
s.ShowOBJ_0 = dlg.ShowObj1;
s.ShowOBJ_1 = dlg.ShowObj2;
s.ShowOBJ_2 = dlg.ShowObj3;
@ -113,8 +117,8 @@ namespace BizHawk.Client.EmuHawk
{
get => cbShowOverscan.Checked;
init => cbShowOverscan.Checked = value;
}
}
private bool ShowCursor
{
get => cbShowCursor.Checked;
@ -153,6 +157,18 @@ namespace BizHawk.Client.EmuHawk
init => cbUseSGB2.Checked = value;
}
private bool UseRealTime
{
get => cbUseRealTime.Checked;
init => cbUseRealTime.Checked = value;
}
private DateTime InitialTime
{
get => dtpInitialTime.Value;
init => dtpInitialTime.Value = value;
}
private BsnesApi.ENTROPY Entropy => (BsnesApi.ENTROPY) EntropyBox.SelectedIndex;
private BsnesApi.REGION_OVERRIDE RegionOverride => (BsnesApi.REGION_OVERRIDE)RegionBox.SelectedIndex;

View File

@ -198,6 +198,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
public delegate void snes_read_hook_t(uint address);
public delegate void snes_write_hook_t(uint address, byte value);
public delegate void snes_exec_hook_t(uint address);
public delegate long snes_time_t();
public delegate void snes_msu_open_t(ushort track_id);
public delegate void snes_msu_seek_t(long offset, bool relative);
public delegate byte snes_msu_read_t();
@ -248,6 +249,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
public snes_read_hook_t readHookCb;
public snes_write_hook_t writeHookCb;
public snes_exec_hook_t execHookCb;
public snes_time_t timeCb;
public snes_msu_open_t msuOpenCb;
public snes_msu_seek_t msuSeekCb;
public snes_msu_read_t msuReadCb;

View File

@ -55,6 +55,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
int numSamples = UpdateAudioBuffer();
_soundProvider.PutSamples(_audioBuffer, numSamples / 2);
Frame++;
AdvanceRtc();
if (IsLagFrame)
{
@ -77,7 +78,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
public string SystemId { get; }
public bool DeterministicEmulation => true;
public bool DeterministicEmulation { get; }
public void ResetCounters()
{

View File

@ -1,4 +1,5 @@
using BizHawk.Emulation.Common;
using System;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Nintendo.BSNES
{
@ -120,6 +121,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
public bool UseSGB2 { get; set; } = true;
public SATELLAVIEW_CARTRIDGE SatellaviewCartridge { get; set; } = SATELLAVIEW_CARTRIDGE.Autodetect;
public bool UseRealTime { get; set; } = true;
public DateTime InitialTime { get; set; } = new(2010, 1, 1);
}
}
}

View File

@ -11,6 +11,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
writer.Write(IsLagFrame);
writer.Write(LagCount);
writer.Write(Frame);
writer.Write(_clockTime);
writer.Write(_clockRemainder);
}
public void LoadStateBinary(BinaryReader reader)
@ -19,6 +21,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
IsLagFrame = reader.ReadBoolean();
LagCount = reader.ReadInt32();
Frame = reader.ReadInt32();
_clockTime = reader.ReadInt64();
_clockRemainder = reader.ReadInt32();
}
}
}

View File

@ -56,6 +56,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
readHookCb = ReadHook,
writeHookCb = WriteHook,
execHookCb = ExecHook,
timeCb = snes_time,
msuOpenCb = msu_open,
msuSeekCb = msu_seek,
msuReadCb = msu_read,
@ -66,6 +67,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
_controllers = new BsnesControllers(_syncSettings, subframe);
DeterministicEmulation = !_syncSettings.UseRealTime || loadParameters.DeterministicEmulationRequested;
InitializeRtc(_syncSettings.InitialTime);
generate_palette();
BsnesApi.SnesInitData snesInitData = new()
{
@ -340,6 +344,26 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
}
}
private static readonly DateTime _epoch = new(1970, 1, 1, 0, 0, 0);
private long _clockTime;
private int _clockRemainder;
protected void InitializeRtc(DateTime start)
=> _clockTime = (long)(start - _epoch).TotalSeconds;
private void AdvanceRtc()
{
_clockRemainder += VsyncDenominator;
if (_clockRemainder >= VsyncNumerator)
{
_clockRemainder -= VsyncNumerator;
_clockTime++;
}
}
private long snes_time()
=> DeterministicEmulation ? _clockTime : (long)(DateTime.Now - _epoch).TotalSeconds;
private FileStream _currentMsuTrack;
private void msu_seek(long offset, bool relative)

View File

@ -22,8 +22,8 @@ struct Platform {
virtual auto inputRumble(uint port, uint device, uint input, bool enable) -> void {}
virtual auto dipSettings(Markup::Node node) -> uint { return 0; }
virtual auto notify(string text) -> void {}
// 03-may-2021 manual addition. unused currently but let's hope for the best
virtual auto getBackdropColor() -> uint16 { return 0; }
// 03-may-2021 manual addition. unused currently but let's hope for the best
virtual auto getBackdropColor() -> uint16 { return 0; }
bool traceEnabled = false;
bool readHookEnabled = false;
@ -33,6 +33,7 @@ struct Platform {
virtual auto readHook(uint address) -> void {}
virtual auto writeHook(uint address, uint8 value) -> void {}
virtual auto execHook(uint address) -> void {}
virtual auto time() -> int64 { return ::time(0); }
};
extern Platform* platform;

View File

@ -155,7 +155,7 @@ auto EpsonRTC::load(const uint8* data) -> void {
timestamp |= data[8 + byte] << (byte * 8);
}
uint64 diff = (uint64)time(0) - timestamp;
uint64 diff = (uint64)platform->time() - timestamp;
while(diff >= 60 * 60 * 24) { tickDay(); diff -= 60 * 60 * 24; }
while(diff >= 60 * 60) { tickHour(); diff -= 60 * 60; }
while(diff >= 60) { tickMinute(); diff -= 60; }
@ -172,7 +172,7 @@ auto EpsonRTC::save(uint8* data) -> void {
data[6] = weekday << 0 | resync << 3 | hold << 4 | calendar << 5 | irqflag << 6 | roundseconds << 7;
data[7] = irqmask << 0 | irqduty << 1 | irqperiod << 2 | pause << 4 | stop << 5 | atime << 6 | test << 7;
uint64 timestamp = (uint64)time(0);
uint64 timestamp = (uint64)platform->time();
for(auto byte : range(8)) {
data[8 + byte] = timestamp;
timestamp >>= 8;

View File

@ -46,7 +46,7 @@ auto SharpRTC::load(const uint8* data) -> void {
timestamp |= data[8 + byte] << (byte * 8);
}
uint64 diff = (uint64)time(0) - timestamp;
uint64 diff = (uint64)platform->time() - timestamp;
while(diff >= 60 * 60 * 24) { tickDay(); diff -= 60 * 60 * 24; }
while(diff >= 60 * 60) { tickHour(); diff -= 60 * 60; }
while(diff >= 60) { tickMinute(); diff -= 60; }
@ -59,7 +59,7 @@ auto SharpRTC::save(uint8* data) -> void {
data[byte] |= rtcRead(byte * 2 + 1) << 4;
}
uint64 timestamp = (uint64)time(nullptr);
uint64 timestamp = (uint64)platform->time();
for(auto byte : range(8)) {
data[8 + byte] = timestamp;
timestamp >>= 8;

View File

@ -26,8 +26,7 @@ auto Satellaview::read(uint addr, uint8 data) -> uint8 {
if(regs.rtcCounter >= 18) regs.rtcCounter = 0;
if(counter == 0) {
time_t rawtime;
time(&rawtime);
time_t rawtime = platform->time();
tm* t = localtime(&rawtime);
regs.rtcHour = t->tm_hour;

View File

@ -12,6 +12,7 @@ typedef void (*snes_trace_t)(const char* disassembly, const char* register_info)
typedef void (*snes_read_hook_t)(uint32_t address);
typedef void (*snes_write_hook_t)(uint32_t address, uint8_t value);
typedef void (*snes_exec_hook_t)(uint32_t address);
typedef int64_t (*snes_time_t)(void);
typedef void (*snes_msu_open_t)(uint16_t track_id);
typedef void (*snes_msu_seek_t)(long offset, bool relative);
typedef uint8_t (*snes_msu_read_t)(void);
@ -27,6 +28,7 @@ struct SnesCallbacks {
snes_read_hook_t snes_read_hook;
snes_write_hook_t snes_write_hook;
snes_exec_hook_t snes_exec_hook;
snes_time_t snes_time;
snes_msu_open_t snes_msu_open;
snes_msu_seek_t snes_msu_seek;
snes_msu_read_t snes_msu_read;

View File

@ -29,6 +29,7 @@ struct Program : Emulator::Platform
auto readHook(uint address) -> void override;
auto writeHook(uint address, uint8 value) -> void override;
auto execHook(uint address) -> void override;
auto time() -> int64 override;
auto load() -> void;
auto loadSuperFamicom() -> bool;
@ -494,6 +495,11 @@ auto Program::execHook(uint address) -> void
snesCallbacks.snes_exec_hook(address);
}
auto Program::time() -> int64
{
return snesCallbacks.snes_time();
}
auto Program::getBackdropColor() -> uint16
{
return backdropColor;