Implement HLE SGB Emulation in Gambatte (squashed PR #2917)
* sgb meme * various sgb fixes, add hard reset support for spc, make frontend provide spc file * sgb border support, mostly copied from sameboy * add support for disabling sgb border, also fix dumb when disabling border * state work, states seem to be broken tho * fix dumb state issue * multiplayer * fix dumb in spc stating * misc * pass SGB tests * oh right I have to fix this too * and this dumb too * attempt to fix weird crashes * or maybe this will fix it? * wtf is spc doing? * rebase * misc state + debugging stuff * finally fix weird assertion failure * factor out loading in spc file, also factor out the ipl * oops * init special sgb colors for certain games * slight sgb audio refactor * this should work better? * oops * switch back to master * super penguin
This commit is contained in:
parent
fc0ebf372f
commit
fbab7f6291
Binary file not shown.
Binary file not shown.
|
@ -24,7 +24,7 @@ namespace BizHawk.Client.Common
|
||||||
(new[] { "SNES" },
|
(new[] { "SNES" },
|
||||||
new[] { CoreNames.Faust, CoreNames.Snes9X, CoreNames.Bsnes, CoreNames.Bsnes115 }),
|
new[] { CoreNames.Faust, CoreNames.Snes9X, CoreNames.Bsnes, CoreNames.Bsnes115 }),
|
||||||
(new[] { "SGB" },
|
(new[] { "SGB" },
|
||||||
new[] { CoreNames.SameBoy, CoreNames.Bsnes, CoreNames.Bsnes115}),
|
new[] { CoreNames.Gambatte, CoreNames.SameBoy, CoreNames.Bsnes, CoreNames.Bsnes115}),
|
||||||
(new[] { "GB", "GBC" },
|
(new[] { "GB", "GBC" },
|
||||||
new[] { CoreNames.Gambatte, CoreNames.GbHawk, CoreNames.SubGbHawk }),
|
new[] { CoreNames.Gambatte, CoreNames.GbHawk, CoreNames.SubGbHawk }),
|
||||||
(new[] { "DGB" },
|
(new[] { "DGB" },
|
||||||
|
|
|
@ -2004,6 +2004,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
case "GB":
|
case "GB":
|
||||||
case "GBC":
|
case "GBC":
|
||||||
case "SGB" when Emulator is Sameboy:
|
case "SGB" when Emulator is Sameboy:
|
||||||
|
case "SGB" when Emulator is Gameboy:
|
||||||
GBSubMenu.Visible = true;
|
GBSubMenu.Visible = true;
|
||||||
break;
|
break;
|
||||||
case "SNES" when Emulator is LibsnesCore { IsSGB: true }: // doesn't use "SGB" sysID
|
case "SNES" when Emulator is LibsnesCore { IsSGB: true }: // doesn't use "SGB" sysID
|
||||||
|
|
|
@ -28,84 +28,98 @@
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void InitializeComponent()
|
private void InitializeComponent()
|
||||||
{
|
{
|
||||||
this.propertyGrid1 = new System.Windows.Forms.PropertyGrid();
|
this.propertyGrid1 = new System.Windows.Forms.PropertyGrid();
|
||||||
this.buttonDefaults = new System.Windows.Forms.Button();
|
this.buttonDefaults = new System.Windows.Forms.Button();
|
||||||
this.buttonPalette = new System.Windows.Forms.Button();
|
this.buttonPalette = new System.Windows.Forms.Button();
|
||||||
this.cbRgbdsSyntax = new System.Windows.Forms.CheckBox();
|
this.cbRgbdsSyntax = new System.Windows.Forms.CheckBox();
|
||||||
this.checkBoxMuted = new System.Windows.Forms.CheckBox();
|
this.checkBoxMuted = new System.Windows.Forms.CheckBox();
|
||||||
this.SuspendLayout();
|
this.cbShowBorder = new System.Windows.Forms.CheckBox();
|
||||||
//
|
this.SuspendLayout();
|
||||||
// propertyGrid1
|
//
|
||||||
//
|
// propertyGrid1
|
||||||
this.propertyGrid1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
//
|
||||||
|
this.propertyGrid1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||||
| System.Windows.Forms.AnchorStyles.Left)
|
| System.Windows.Forms.AnchorStyles.Left)
|
||||||
| System.Windows.Forms.AnchorStyles.Right)));
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
this.propertyGrid1.Location = new System.Drawing.Point(3, 3);
|
this.propertyGrid1.Location = new System.Drawing.Point(3, 3);
|
||||||
this.propertyGrid1.Name = "propertyGrid1";
|
this.propertyGrid1.Name = "propertyGrid1";
|
||||||
this.propertyGrid1.PropertySort = System.Windows.Forms.PropertySort.NoSort;
|
this.propertyGrid1.PropertySort = System.Windows.Forms.PropertySort.NoSort;
|
||||||
this.propertyGrid1.Size = new System.Drawing.Size(338, 279);
|
this.propertyGrid1.Size = new System.Drawing.Size(402, 368);
|
||||||
this.propertyGrid1.TabIndex = 0;
|
this.propertyGrid1.TabIndex = 0;
|
||||||
this.propertyGrid1.ToolbarVisible = false;
|
this.propertyGrid1.ToolbarVisible = false;
|
||||||
this.propertyGrid1.PropertyValueChanged += new System.Windows.Forms.PropertyValueChangedEventHandler(this.PropertyGrid1_PropertyValueChanged);
|
this.propertyGrid1.PropertyValueChanged += new System.Windows.Forms.PropertyValueChangedEventHandler(this.PropertyGrid1_PropertyValueChanged);
|
||||||
//
|
//
|
||||||
// buttonDefaults
|
// buttonDefaults
|
||||||
//
|
//
|
||||||
this.buttonDefaults.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
this.buttonDefaults.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
this.buttonDefaults.Location = new System.Drawing.Point(266, 288);
|
this.buttonDefaults.Location = new System.Drawing.Point(330, 377);
|
||||||
this.buttonDefaults.Name = "buttonDefaults";
|
this.buttonDefaults.Name = "buttonDefaults";
|
||||||
this.buttonDefaults.Size = new System.Drawing.Size(75, 23);
|
this.buttonDefaults.Size = new System.Drawing.Size(75, 23);
|
||||||
this.buttonDefaults.TabIndex = 1;
|
this.buttonDefaults.TabIndex = 1;
|
||||||
this.buttonDefaults.Text = "Defaults";
|
this.buttonDefaults.Text = "Defaults";
|
||||||
this.buttonDefaults.UseVisualStyleBackColor = true;
|
this.buttonDefaults.UseVisualStyleBackColor = true;
|
||||||
this.buttonDefaults.Click += new System.EventHandler(this.ButtonDefaults_Click);
|
this.buttonDefaults.Click += new System.EventHandler(this.ButtonDefaults_Click);
|
||||||
//
|
//
|
||||||
// buttonPalette
|
// buttonPalette
|
||||||
//
|
//
|
||||||
this.buttonPalette.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
this.buttonPalette.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||||
this.buttonPalette.Location = new System.Drawing.Point(3, 288);
|
this.buttonPalette.Location = new System.Drawing.Point(3, 377);
|
||||||
this.buttonPalette.Name = "buttonPalette";
|
this.buttonPalette.Name = "buttonPalette";
|
||||||
this.buttonPalette.Size = new System.Drawing.Size(75, 23);
|
this.buttonPalette.Size = new System.Drawing.Size(75, 23);
|
||||||
this.buttonPalette.TabIndex = 2;
|
this.buttonPalette.TabIndex = 2;
|
||||||
this.buttonPalette.Text = "Palette...";
|
this.buttonPalette.Text = "Palette...";
|
||||||
this.buttonPalette.UseVisualStyleBackColor = true;
|
this.buttonPalette.UseVisualStyleBackColor = true;
|
||||||
this.buttonPalette.Click += new System.EventHandler(this.ButtonPalette_Click);
|
this.buttonPalette.Click += new System.EventHandler(this.ButtonPalette_Click);
|
||||||
//
|
//
|
||||||
// checkBoxMuted
|
// cbRgbdsSyntax
|
||||||
//
|
//
|
||||||
this.checkBoxMuted.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
this.cbRgbdsSyntax.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||||
this.checkBoxMuted.AutoSize = true;
|
this.cbRgbdsSyntax.AutoSize = true;
|
||||||
this.checkBoxMuted.Location = new System.Drawing.Point(82, 292);
|
this.cbRgbdsSyntax.Location = new System.Drawing.Point(138, 381);
|
||||||
this.checkBoxMuted.Name = "checkBoxMuted";
|
this.cbRgbdsSyntax.Name = "cbRgbdsSyntax";
|
||||||
this.checkBoxMuted.Size = new System.Drawing.Size(50, 17);
|
this.cbRgbdsSyntax.Size = new System.Drawing.Size(99, 17);
|
||||||
this.checkBoxMuted.TabIndex = 3;
|
this.cbRgbdsSyntax.TabIndex = 3;
|
||||||
this.checkBoxMuted.Text = "Mute";
|
this.cbRgbdsSyntax.Text = "RGBDS Syntax";
|
||||||
this.checkBoxMuted.UseVisualStyleBackColor = true;
|
this.cbRgbdsSyntax.UseVisualStyleBackColor = true;
|
||||||
this.checkBoxMuted.CheckedChanged += new System.EventHandler(this.CheckBoxMuted_CheckedChanged);
|
this.cbRgbdsSyntax.CheckedChanged += new System.EventHandler(this.CbRgbdsSyntax_CheckedChanged);
|
||||||
//
|
//
|
||||||
// cbRgbdsSyntax
|
// checkBoxMuted
|
||||||
//
|
//
|
||||||
this.cbRgbdsSyntax.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
this.checkBoxMuted.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||||
this.cbRgbdsSyntax.AutoSize = true;
|
this.checkBoxMuted.AutoSize = true;
|
||||||
this.cbRgbdsSyntax.Location = new System.Drawing.Point(130, 292);
|
this.checkBoxMuted.Location = new System.Drawing.Point(82, 381);
|
||||||
this.cbRgbdsSyntax.Name = "cbRgbdsSyntax";
|
this.checkBoxMuted.Name = "checkBoxMuted";
|
||||||
this.cbRgbdsSyntax.Size = new System.Drawing.Size(150, 17);
|
this.checkBoxMuted.Size = new System.Drawing.Size(50, 17);
|
||||||
this.cbRgbdsSyntax.TabIndex = 7;
|
this.checkBoxMuted.TabIndex = 4;
|
||||||
this.cbRgbdsSyntax.Text = "RGBDS Syntax";
|
this.checkBoxMuted.Text = "Mute";
|
||||||
this.cbRgbdsSyntax.UseVisualStyleBackColor = true;
|
this.checkBoxMuted.UseVisualStyleBackColor = true;
|
||||||
this.cbRgbdsSyntax.CheckedChanged += new System.EventHandler(this.CbRgbdsSyntax_CheckedChanged);
|
this.checkBoxMuted.CheckedChanged += new System.EventHandler(this.CheckBoxMuted_CheckedChanged);
|
||||||
//
|
//
|
||||||
// GBPrefControl
|
// cbShowBorder
|
||||||
//
|
//
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
|
this.cbShowBorder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||||
this.Controls.Add(this.cbRgbdsSyntax);
|
this.cbShowBorder.AutoSize = true;
|
||||||
this.Controls.Add(this.checkBoxMuted);
|
this.cbShowBorder.Location = new System.Drawing.Point(243, 381);
|
||||||
this.Controls.Add(this.buttonPalette);
|
this.cbShowBorder.Name = "cbShowBorder";
|
||||||
this.Controls.Add(this.buttonDefaults);
|
this.cbShowBorder.Size = new System.Drawing.Size(87, 17);
|
||||||
this.Controls.Add(this.propertyGrid1);
|
this.cbShowBorder.TabIndex = 5;
|
||||||
this.Name = "GBPrefControl";
|
this.cbShowBorder.Text = "Show Border";
|
||||||
this.Size = new System.Drawing.Size(344, 314);
|
this.cbShowBorder.UseVisualStyleBackColor = true;
|
||||||
this.ResumeLayout(false);
|
this.cbShowBorder.CheckedChanged += new System.EventHandler(this.CbShowBorder_CheckedChanged);
|
||||||
this.PerformLayout();
|
//
|
||||||
|
// GBPrefControl
|
||||||
|
//
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
|
||||||
|
this.Controls.Add(this.cbRgbdsSyntax);
|
||||||
|
this.Controls.Add(this.checkBoxMuted);
|
||||||
|
this.Controls.Add(this.cbShowBorder);
|
||||||
|
this.Controls.Add(this.buttonPalette);
|
||||||
|
this.Controls.Add(this.buttonDefaults);
|
||||||
|
this.Controls.Add(this.propertyGrid1);
|
||||||
|
this.Name = "GBPrefControl";
|
||||||
|
this.Size = new System.Drawing.Size(408, 403);
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
this.PerformLayout();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,5 +130,6 @@
|
||||||
private System.Windows.Forms.Button buttonPalette;
|
private System.Windows.Forms.Button buttonPalette;
|
||||||
private System.Windows.Forms.CheckBox cbRgbdsSyntax;
|
private System.Windows.Forms.CheckBox cbRgbdsSyntax;
|
||||||
private System.Windows.Forms.CheckBox checkBoxMuted;
|
private System.Windows.Forms.CheckBox checkBoxMuted;
|
||||||
|
private System.Windows.Forms.CheckBox cbShowBorder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
propertyGrid1.Enabled = movieSession.Movie.NotActive();
|
propertyGrid1.Enabled = movieSession.Movie.NotActive();
|
||||||
checkBoxMuted.Checked = _s.Muted;
|
checkBoxMuted.Checked = _s.Muted;
|
||||||
cbRgbdsSyntax.Checked = _s.RgbdsSyntax;
|
cbRgbdsSyntax.Checked = _s.RgbdsSyntax;
|
||||||
|
cbShowBorder.Checked = _s.ShowBorder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GetSettings(out Gameboy.GambatteSettings s, out Gameboy.GambatteSyncSettings ss)
|
public void GetSettings(out Gameboy.GambatteSettings s, out Gameboy.GambatteSyncSettings ss)
|
||||||
|
@ -86,5 +87,10 @@ namespace BizHawk.Client.EmuHawk
|
||||||
{
|
{
|
||||||
_s.RgbdsSyntax = ((CheckBox)sender).Checked;
|
_s.RgbdsSyntax = ((CheckBox)sender).Checked;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CbShowBorder_CheckedChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
_s.ShowBorder = ((CheckBox)sender).Checked;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,58 +28,58 @@
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void InitializeComponent()
|
private void InitializeComponent()
|
||||||
{
|
{
|
||||||
this.buttonOK = new System.Windows.Forms.Button();
|
this.buttonOK = new System.Windows.Forms.Button();
|
||||||
this.buttonCancel = new System.Windows.Forms.Button();
|
this.buttonCancel = new System.Windows.Forms.Button();
|
||||||
this.gbPrefControl1 = new GBPrefControl();
|
this.gbPrefControl1 = new BizHawk.Client.EmuHawk.GBPrefControl();
|
||||||
this.SuspendLayout();
|
this.SuspendLayout();
|
||||||
//
|
//
|
||||||
// buttonOK
|
// buttonOK
|
||||||
//
|
//
|
||||||
this.buttonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
this.buttonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
this.buttonOK.DialogResult = System.Windows.Forms.DialogResult.OK;
|
this.buttonOK.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||||
this.buttonOK.Location = new System.Drawing.Point(280, 363);
|
this.buttonOK.Location = new System.Drawing.Point(280, 363);
|
||||||
this.buttonOK.Name = "buttonOK";
|
this.buttonOK.Name = "buttonOK";
|
||||||
this.buttonOK.Size = new System.Drawing.Size(75, 23);
|
this.buttonOK.Size = new System.Drawing.Size(75, 23);
|
||||||
this.buttonOK.TabIndex = 1;
|
this.buttonOK.TabIndex = 1;
|
||||||
this.buttonOK.Text = "OK";
|
this.buttonOK.Text = "OK";
|
||||||
this.buttonOK.UseVisualStyleBackColor = true;
|
this.buttonOK.UseVisualStyleBackColor = true;
|
||||||
//
|
//
|
||||||
// buttonCancel
|
// buttonCancel
|
||||||
//
|
//
|
||||||
this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||||
this.buttonCancel.Location = new System.Drawing.Point(361, 363);
|
this.buttonCancel.Location = new System.Drawing.Point(361, 363);
|
||||||
this.buttonCancel.Name = "buttonCancel";
|
this.buttonCancel.Name = "buttonCancel";
|
||||||
this.buttonCancel.Size = new System.Drawing.Size(75, 23);
|
this.buttonCancel.Size = new System.Drawing.Size(75, 23);
|
||||||
this.buttonCancel.TabIndex = 2;
|
this.buttonCancel.TabIndex = 2;
|
||||||
this.buttonCancel.Text = "Cancel";
|
this.buttonCancel.Text = "Cancel";
|
||||||
this.buttonCancel.UseVisualStyleBackColor = true;
|
this.buttonCancel.UseVisualStyleBackColor = true;
|
||||||
//
|
//
|
||||||
// gbPrefControl1
|
// gbPrefControl1
|
||||||
//
|
//
|
||||||
this.gbPrefControl1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
this.gbPrefControl1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||||
| System.Windows.Forms.AnchorStyles.Left)
|
| System.Windows.Forms.AnchorStyles.Left)
|
||||||
| System.Windows.Forms.AnchorStyles.Right)));
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
this.gbPrefControl1.ColorGameBoy = false;
|
this.gbPrefControl1.ColorGameBoy = false;
|
||||||
this.gbPrefControl1.Location = new System.Drawing.Point(12, 12);
|
this.gbPrefControl1.Location = new System.Drawing.Point(12, 12);
|
||||||
this.gbPrefControl1.Name = "gbPrefControl1";
|
this.gbPrefControl1.Name = "gbPrefControl1";
|
||||||
this.gbPrefControl1.Size = new System.Drawing.Size(424, 345);
|
this.gbPrefControl1.Size = new System.Drawing.Size(424, 345);
|
||||||
this.gbPrefControl1.TabIndex = 0;
|
this.gbPrefControl1.TabIndex = 0;
|
||||||
//
|
//
|
||||||
// GBPrefs
|
// GBPrefs
|
||||||
//
|
//
|
||||||
this.AcceptButton = this.buttonOK;
|
this.AcceptButton = this.buttonOK;
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
this.CancelButton = this.buttonCancel;
|
this.CancelButton = this.buttonCancel;
|
||||||
this.ClientSize = new System.Drawing.Size(448, 398);
|
this.ClientSize = new System.Drawing.Size(448, 398);
|
||||||
this.Controls.Add(this.buttonCancel);
|
this.Controls.Add(this.buttonCancel);
|
||||||
this.Controls.Add(this.buttonOK);
|
this.Controls.Add(this.buttonOK);
|
||||||
this.Controls.Add(this.gbPrefControl1);
|
this.Controls.Add(this.gbPrefControl1);
|
||||||
this.Name = "GBPrefs";
|
this.Name = "GBPrefs";
|
||||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||||
this.Text = "Game Boy Settings";
|
this.Text = "Game Boy Settings";
|
||||||
this.ResumeLayout(false);
|
this.ResumeLayout(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
using var dlg = new GBPrefs(mainForm.DialogController);
|
using var dlg = new GBPrefs(mainForm.DialogController);
|
||||||
dlg.gbPrefControl1.PutSettings(config, game, movieSession, s, ss);
|
dlg.gbPrefControl1.PutSettings(config, game, movieSession, s, ss);
|
||||||
dlg.gbPrefControl1.ColorGameBoy = gb.IsCGBMode();
|
dlg.gbPrefControl1.ColorGameBoy = gb.IsCGBMode() || gb.IsSgb;
|
||||||
if (mainForm.ShowDialogAsChild(dlg).IsOk())
|
if (mainForm.ShowDialogAsChild(dlg).IsOk())
|
||||||
{
|
{
|
||||||
dlg.gbPrefControl1.GetSettings(out s, out ss);
|
dlg.gbPrefControl1.GetSettings(out s, out ss);
|
||||||
|
|
|
@ -9,12 +9,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
{
|
{
|
||||||
public IEmulatorServiceProvider ServiceProvider { get; }
|
public IEmulatorServiceProvider ServiceProvider { get; }
|
||||||
|
|
||||||
public ControllerDefinition ControllerDefinition => (_syncSettings.FrameLength == GambatteSyncSettings.FrameLengthType.UserDefinedFrames) ? SubGbController : GbController;
|
public ControllerDefinition ControllerDefinition { get; set; }
|
||||||
|
|
||||||
public bool FrameAdvance(IController controller, bool render, bool rendersound)
|
public bool FrameAdvance(IController controller, bool render, bool rendersound)
|
||||||
{
|
{
|
||||||
FrameAdvancePrep(controller);
|
FrameAdvancePrep(controller);
|
||||||
uint samplesEmitted;
|
uint samplesEmitted;
|
||||||
|
uint samplesEmittedInFrame = 0; // for sgb
|
||||||
switch (_syncSettings.FrameLength)
|
switch (_syncSettings.FrameLength)
|
||||||
{
|
{
|
||||||
case GambatteSyncSettings.FrameLengthType.VBlankDrivenFrames:
|
case GambatteSyncSettings.FrameLengthType.VBlankDrivenFrames:
|
||||||
|
@ -25,10 +26,19 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
if (LibGambatte.gambatte_runfor(GambatteState, FrameBuffer, 160, _soundbuff, ref samplesEmitted) > 0)
|
if (LibGambatte.gambatte_runfor(GambatteState, FrameBuffer, 160, _soundbuff, ref samplesEmitted) > 0)
|
||||||
{
|
{
|
||||||
Array.Copy(FrameBuffer, VideoBuffer, FrameBuffer.Length);
|
Array.Copy(FrameBuffer, VideoBuffer, FrameBuffer.Length);
|
||||||
|
if (IsSgb)
|
||||||
|
{
|
||||||
|
if (LibGambatte.gambatte_updatescreenborder(GambatteState, SgbVideoBuffer, 256) != 0)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"{nameof(LibGambatte.gambatte_updatescreenborder)}() returned non-zero (border error???)");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_cycleCount += samplesEmitted;
|
_cycleCount += samplesEmitted;
|
||||||
|
samplesEmittedInFrame += samplesEmitted;
|
||||||
frameOverflow = 0;
|
frameOverflow = 0;
|
||||||
|
|
||||||
if (rendersound && !Muted)
|
if (rendersound && !Muted)
|
||||||
{
|
{
|
||||||
ProcessSound((int)samplesEmitted);
|
ProcessSound((int)samplesEmitted);
|
||||||
|
@ -43,10 +53,18 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
if (LibGambatte.gambatte_runfor(GambatteState, FrameBuffer, 160, _soundbuff, ref samplesEmitted) > 0)
|
if (LibGambatte.gambatte_runfor(GambatteState, FrameBuffer, 160, _soundbuff, ref samplesEmitted) > 0)
|
||||||
{
|
{
|
||||||
Array.Copy(FrameBuffer, VideoBuffer, FrameBuffer.Length);
|
Array.Copy(FrameBuffer, VideoBuffer, FrameBuffer.Length);
|
||||||
|
if (IsSgb)
|
||||||
|
{
|
||||||
|
if (LibGambatte.gambatte_updatescreenborder(GambatteState, SgbVideoBuffer, 256) != 0)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"{nameof(LibGambatte.gambatte_updatescreenborder)}() returned non-zero (border error???)");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// account for actual number of samples emitted
|
// account for actual number of samples emitted
|
||||||
_cycleCount += samplesEmitted;
|
_cycleCount += samplesEmitted;
|
||||||
|
samplesEmittedInFrame += samplesEmitted;
|
||||||
frameOverflow += samplesEmitted;
|
frameOverflow += samplesEmitted;
|
||||||
|
|
||||||
if (rendersound && !Muted)
|
if (rendersound && !Muted)
|
||||||
|
@ -76,10 +94,18 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
if (LibGambatte.gambatte_runfor(GambatteState, FrameBuffer, 160, _soundbuff, ref samplesEmitted) > 0)
|
if (LibGambatte.gambatte_runfor(GambatteState, FrameBuffer, 160, _soundbuff, ref samplesEmitted) > 0)
|
||||||
{
|
{
|
||||||
Array.Copy(FrameBuffer, VideoBuffer, FrameBuffer.Length);
|
Array.Copy(FrameBuffer, VideoBuffer, FrameBuffer.Length);
|
||||||
|
if (IsSgb)
|
||||||
|
{
|
||||||
|
if (LibGambatte.gambatte_updatescreenborder(GambatteState, SgbVideoBuffer, 256) != 0)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"{nameof(LibGambatte.gambatte_updatescreenborder)}() returned non-zero (border error???)");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// account for actual number of samples emitted
|
// account for actual number of samples emitted
|
||||||
_cycleCount += samplesEmitted;
|
_cycleCount += samplesEmitted;
|
||||||
|
samplesEmittedInFrame += samplesEmitted;
|
||||||
frameOverflow += samplesEmitted;
|
frameOverflow += samplesEmitted;
|
||||||
|
|
||||||
if (rendersound && !Muted)
|
if (rendersound && !Muted)
|
||||||
|
@ -96,6 +122,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsSgb)
|
||||||
|
{
|
||||||
|
ProcessSgbSound((int)samplesEmittedInFrame, (rendersound && !Muted));
|
||||||
|
}
|
||||||
|
|
||||||
if (rendersound && !Muted)
|
if (rendersound && !Muted)
|
||||||
{
|
{
|
||||||
ProcessSoundEnd();
|
ProcessSoundEnd();
|
||||||
|
@ -108,7 +139,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
|
|
||||||
public int Frame { get; private set; }
|
public int Frame { get; private set; }
|
||||||
|
|
||||||
public string SystemId => "GB";
|
public string SystemId => IsSgb ? "SGB" : "GB";
|
||||||
|
|
||||||
public string BoardName { get; }
|
public string BoardName { get; }
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
{
|
{
|
||||||
_settings = o;
|
_settings = o;
|
||||||
_disassembler.UseRGBDSSyntax = _settings.RgbdsSyntax;
|
_disassembler.UseRGBDSSyntax = _settings.RgbdsSyntax;
|
||||||
if (IsCGBMode())
|
if (IsCGBMode() || IsSgb)
|
||||||
{
|
{
|
||||||
SetCGBColors(_settings.CGBColors);
|
SetCGBColors(_settings.CGBColors);
|
||||||
}
|
}
|
||||||
|
@ -77,11 +77,17 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool RgbdsSyntax;
|
public bool RgbdsSyntax;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// true to show sgb border (sgb mode only)
|
||||||
|
/// </summary>
|
||||||
|
public bool ShowBorder;
|
||||||
|
|
||||||
public GambatteSettings()
|
public GambatteSettings()
|
||||||
{
|
{
|
||||||
GBPalette = (int[])DefaultPalette.Clone();
|
GBPalette = (int[])DefaultPalette.Clone();
|
||||||
CGBColors = GBColors.ColorType.gambatte;
|
CGBColors = GBColors.ColorType.gambatte;
|
||||||
RgbdsSyntax = true;
|
RgbdsSyntax = true;
|
||||||
|
ShowBorder = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
|
|
||||||
// sample pairs before resampling
|
// sample pairs before resampling
|
||||||
private readonly short[] _soundbuff = new short[(35112 + 2064) * 2];
|
private readonly short[] _soundbuff = new short[(35112 + 2064) * 2];
|
||||||
|
private readonly short[] _sgbsoundbuff = new short[2048 * 2];
|
||||||
|
|
||||||
private int _soundoutbuffcontains = 0;
|
private int _soundoutbuffcontains = 0;
|
||||||
|
|
||||||
|
@ -45,6 +46,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
private int _latchL = 0;
|
private int _latchL = 0;
|
||||||
private int _latchR = 0;
|
private int _latchR = 0;
|
||||||
|
|
||||||
|
private int _sgbLatchL = 0;
|
||||||
|
private int _sgbLatchR = 0;
|
||||||
|
|
||||||
private BlipBuffer _blipL, _blipR;
|
private BlipBuffer _blipL, _blipR;
|
||||||
private uint _blipAccumulate;
|
private uint _blipAccumulate;
|
||||||
|
|
||||||
|
@ -74,6 +78,31 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ProcessSgbSound(int nsamp, bool processSound)
|
||||||
|
{
|
||||||
|
int remainder = LibGambatte.gambatte_generatesgbsamples(GambatteState, _sgbsoundbuff, out uint samples);
|
||||||
|
if (remainder < 0)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"{nameof(LibGambatte.gambatte_generatesgbsamples)}() returned negative (spc error???)");
|
||||||
|
}
|
||||||
|
uint t = 65 - (uint)remainder;
|
||||||
|
for (int i = 0; i < samples; i++, t += 65)
|
||||||
|
{
|
||||||
|
int ls = _sgbsoundbuff[i * 2] - _sgbLatchL;
|
||||||
|
int rs = _sgbsoundbuff[(i * 2) + 1] - _sgbLatchR;
|
||||||
|
if (ls != 0 && processSound)
|
||||||
|
{
|
||||||
|
_blipL.AddDelta(t, ls);
|
||||||
|
}
|
||||||
|
if (rs != 0 && processSound)
|
||||||
|
{
|
||||||
|
_blipR.AddDelta(t, rs);
|
||||||
|
}
|
||||||
|
_sgbLatchL = _sgbsoundbuff[i * 2];
|
||||||
|
_sgbLatchR = _sgbsoundbuff[(i * 2) + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void ProcessSoundEnd()
|
private void ProcessSoundEnd()
|
||||||
{
|
{
|
||||||
_blipL.EndFrame(_blipAccumulate);
|
_blipL.EndFrame(_blipAccumulate);
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
using System;
|
//#define USE_UPSTREAM_STATES
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
@ -22,13 +24,21 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
|
|
||||||
public void SaveStateBinary(BinaryWriter writer)
|
public void SaveStateBinary(BinaryWriter writer)
|
||||||
{
|
{
|
||||||
if (!LibGambatte.gambatte_newstatesave(GambatteState, _savebuff, _savebuff.Length))
|
#if USE_UPSTREAM_STATES
|
||||||
|
int size = LibGambatte.gambatte_savestate(GambatteState, null, 160, _stateBuf);
|
||||||
|
if (size != _stateBuf.Length)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Savestate buffer size mismatch!");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (!LibGambatte.gambatte_newstatesave(GambatteState, _stateBuf, _stateBuf.Length))
|
||||||
{
|
{
|
||||||
throw new Exception($"{nameof(LibGambatte.gambatte_newstatesave)}() returned false");
|
throw new Exception($"{nameof(LibGambatte.gambatte_newstatesave)}() returned false");
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
writer.Write(_savebuff.Length);
|
writer.Write(_stateBuf.Length);
|
||||||
writer.Write(_savebuff);
|
writer.Write(_stateBuf);
|
||||||
|
|
||||||
// other variables
|
// other variables
|
||||||
writer.Write(IsLagFrame);
|
writer.Write(IsLagFrame);
|
||||||
|
@ -37,22 +47,30 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
writer.Write(frameOverflow);
|
writer.Write(frameOverflow);
|
||||||
writer.Write(_cycleCount);
|
writer.Write(_cycleCount);
|
||||||
writer.Write(IsCgb);
|
writer.Write(IsCgb);
|
||||||
|
writer.Write(IsSgb);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadStateBinary(BinaryReader reader)
|
public void LoadStateBinary(BinaryReader reader)
|
||||||
{
|
{
|
||||||
int length = reader.ReadInt32();
|
int length = reader.ReadInt32();
|
||||||
if (length != _savebuff.Length)
|
if (length != _stateBuf.Length)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Savestate buffer size mismatch!");
|
throw new InvalidOperationException("Savestate buffer size mismatch!");
|
||||||
}
|
}
|
||||||
|
|
||||||
reader.Read(_savebuff, 0, _savebuff.Length);
|
reader.Read(_stateBuf, 0, _stateBuf.Length);
|
||||||
|
|
||||||
if (!LibGambatte.gambatte_newstateload(GambatteState, _savebuff, _savebuff.Length))
|
#if USE_UPSTREAM_STATES
|
||||||
|
if (!LibGambatte.gambatte_loadstate(GambatteState, _stateBuf, _stateBuf.Length))
|
||||||
|
{
|
||||||
|
throw new Exception($"{nameof(LibGambatte.gambatte_loadstate)}() returned false");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (!LibGambatte.gambatte_newstateload(GambatteState, _stateBuf, _stateBuf.Length))
|
||||||
{
|
{
|
||||||
throw new Exception($"{nameof(LibGambatte.gambatte_newstateload)}() returned false");
|
throw new Exception($"{nameof(LibGambatte.gambatte_newstateload)}() returned false");
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// other variables
|
// other variables
|
||||||
IsLagFrame = reader.ReadBoolean();
|
IsLagFrame = reader.ReadBoolean();
|
||||||
|
@ -61,13 +79,18 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
frameOverflow = reader.ReadUInt32();
|
frameOverflow = reader.ReadUInt32();
|
||||||
_cycleCount = reader.ReadUInt64();
|
_cycleCount = reader.ReadUInt64();
|
||||||
IsCgb = reader.ReadBoolean();
|
IsCgb = reader.ReadBoolean();
|
||||||
|
IsSgb = reader.ReadBoolean();
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] _savebuff;
|
private byte[] _stateBuf;
|
||||||
|
|
||||||
private void NewSaveCoreSetBuff()
|
private void NewSaveCoreSetBuff()
|
||||||
{
|
{
|
||||||
_savebuff = new byte[LibGambatte.gambatte_newstatelen(GambatteState)];
|
#if USE_UPSTREAM_STATES
|
||||||
|
_stateBuf = new byte[LibGambatte.gambatte_savestate(GambatteState, null, 160, null)];
|
||||||
|
#else
|
||||||
|
_stateBuf = new byte[LibGambatte.gambatte_newstatelen(GambatteState)];
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly JsonSerializer ser = new JsonSerializer { Formatting = Formatting.Indented };
|
private readonly JsonSerializer ser = new JsonSerializer { Formatting = Formatting.Indented };
|
||||||
|
@ -81,6 +104,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
public ulong _cycleCount;
|
public ulong _cycleCount;
|
||||||
public uint frameOverflow;
|
public uint frameOverflow;
|
||||||
public bool IsCgb;
|
public bool IsCgb;
|
||||||
|
public bool IsSgb;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal TextState<TextStateData> SaveState()
|
internal TextState<TextStateData> SaveState()
|
||||||
|
@ -95,6 +119,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
s.ExtraData.frameOverflow = frameOverflow;
|
s.ExtraData.frameOverflow = frameOverflow;
|
||||||
s.ExtraData._cycleCount = _cycleCount;
|
s.ExtraData._cycleCount = _cycleCount;
|
||||||
s.ExtraData.IsCgb = IsCgb;
|
s.ExtraData.IsCgb = IsCgb;
|
||||||
|
s.ExtraData.IsSgb = IsSgb;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,6 +134,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
frameOverflow = s.ExtraData.frameOverflow;
|
frameOverflow = s.ExtraData.frameOverflow;
|
||||||
_cycleCount = s.ExtraData._cycleCount;
|
_cycleCount = s.ExtraData._cycleCount;
|
||||||
IsCgb = s.ExtraData.IsCgb;
|
IsCgb = s.ExtraData.IsCgb;
|
||||||
|
IsSgb = s.ExtraData.IsSgb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,12 @@
|
||||||
/// stored image of most recent frame
|
/// stored image of most recent frame
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly int[] VideoBuffer = CreateVideoBuffer();
|
private readonly int[] VideoBuffer = CreateVideoBuffer();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// stored image of most recent sgb frame
|
||||||
|
/// </summary>
|
||||||
|
private readonly int[] SgbVideoBuffer = new int[256 * 244];
|
||||||
|
|
||||||
private static int[] CreateVideoBuffer()
|
private static int[] CreateVideoBuffer()
|
||||||
{
|
{
|
||||||
var b = new int[160 * 144];
|
var b = new int[160 * 144];
|
||||||
|
@ -24,16 +29,16 @@
|
||||||
|
|
||||||
public int[] GetVideoBuffer()
|
public int[] GetVideoBuffer()
|
||||||
{
|
{
|
||||||
return VideoBuffer;
|
return (IsSgb && _settings.ShowBorder) ? SgbVideoBuffer : VideoBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int VirtualWidth => 160; // only sgb changes this, which we don't emulate here
|
public int VirtualWidth => (IsSgb && _settings.ShowBorder) ? 256 : 160;
|
||||||
|
|
||||||
public int VirtualHeight => 144;
|
public int VirtualHeight => (IsSgb && _settings.ShowBorder) ? 224 : 144;
|
||||||
|
|
||||||
public int BufferWidth => 160;
|
public int BufferWidth => (IsSgb && _settings.ShowBorder) ? 256 : 160;
|
||||||
|
|
||||||
public int BufferHeight => 144;
|
public int BufferHeight => (IsSgb && _settings.ShowBorder) ? 224 : 144;
|
||||||
|
|
||||||
public int BackgroundColor => 0;
|
public int BackgroundColor => 0;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using BizHawk.Common;
|
using BizHawk.Common;
|
||||||
using BizHawk.Common.BufferExtensions;
|
using BizHawk.Common.BufferExtensions;
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
|
@ -20,6 +21,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
{
|
{
|
||||||
[CoreConstructor("GB")]
|
[CoreConstructor("GB")]
|
||||||
[CoreConstructor("GBC")]
|
[CoreConstructor("GBC")]
|
||||||
|
[CoreConstructor("SGB")]
|
||||||
public Gameboy(CoreComm comm, GameInfo game, byte[] file, Gameboy.GambatteSettings settings, Gameboy.GambatteSyncSettings syncSettings, bool deterministic)
|
public Gameboy(CoreComm comm, GameInfo game, byte[] file, Gameboy.GambatteSettings settings, Gameboy.GambatteSyncSettings syncSettings, bool deterministic)
|
||||||
{
|
{
|
||||||
var ser = new BasicServiceProvider(this);
|
var ser = new BasicServiceProvider(this);
|
||||||
|
@ -66,6 +68,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (game.System == "SGB")
|
||||||
|
{
|
||||||
|
flags &= ~(LibGambatte.LoadFlags.CGB_MODE | LibGambatte.LoadFlags.GBA_FLAG);
|
||||||
|
flags |= LibGambatte.LoadFlags.SGB_MODE;
|
||||||
|
IsSgb = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (_syncSettings.MulticartCompat)
|
if (_syncSettings.MulticartCompat)
|
||||||
{
|
{
|
||||||
flags |= LibGambatte.LoadFlags.MULTICART_COMPAT;
|
flags |= LibGambatte.LoadFlags.MULTICART_COMPAT;
|
||||||
|
@ -77,7 +86,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
|
|
||||||
IsCgb = (flags & LibGambatte.LoadFlags.CGB_MODE) == LibGambatte.LoadFlags.CGB_MODE;
|
IsCgb = (flags & LibGambatte.LoadFlags.CGB_MODE) == LibGambatte.LoadFlags.CGB_MODE;
|
||||||
biosSystemId = IsCgb ? "GBC" : "GB";
|
biosSystemId = IsCgb ? "GBC" : "GB";
|
||||||
biosId = ((_syncSettings.ConsoleMode == GambatteSyncSettings.ConsoleModeType.GBA) && !_syncSettings.PatchBIOS) ? "AGB" : "World";
|
biosId = (_syncSettings.ConsoleMode == GambatteSyncSettings.ConsoleModeType.GBA) && !_syncSettings.PatchBIOS ? "AGB" : "World";
|
||||||
|
|
||||||
|
if (IsSgb)
|
||||||
|
{
|
||||||
|
biosId = "SGB2";
|
||||||
|
}
|
||||||
|
|
||||||
if (_syncSettings.EnableBIOS)
|
if (_syncSettings.EnableBIOS)
|
||||||
{
|
{
|
||||||
|
@ -86,15 +100,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
{
|
{
|
||||||
if (!IsCgb)
|
if (!IsCgb)
|
||||||
{
|
{
|
||||||
bios[0xFD] ^= 0xFE; // patch from dmg<->mgb
|
bios[0xFD] ^= 0xFE; // patch from dmg<->mgb, or sgb1<->sgb2
|
||||||
}
|
}
|
||||||
else if (_syncSettings.ConsoleMode == GambatteSyncSettings.ConsoleModeType.GBA)
|
else if (_syncSettings.ConsoleMode == GambatteSyncSettings.ConsoleModeType.GBA)
|
||||||
{
|
{
|
||||||
// patch from cgb->agb re
|
// patch from cgb->agb re
|
||||||
bios[0xF3] ^= 0x03;
|
bios[0xF3] ^= 0x03;
|
||||||
for (var i = 0xF5; i < 0xFB;)
|
for (var i = 0xF5; i < 0xFB; i++)
|
||||||
{
|
{
|
||||||
bios[i] = bios[++i];
|
bios[i] = bios[i + 1];
|
||||||
}
|
}
|
||||||
bios[0xFB] ^= 0x74;
|
bios[0xFB] ^= 0x74;
|
||||||
}
|
}
|
||||||
|
@ -118,6 +132,19 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
throw new InvalidOperationException($"{nameof(LibGambatte.gambatte_loadbuf)}() returned non-zero (is this not a gb or gbc rom?)");
|
throw new InvalidOperationException($"{nameof(LibGambatte.gambatte_loadbuf)}() returned non-zero (is this not a gb or gbc rom?)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsSgb)
|
||||||
|
{
|
||||||
|
ResetStallTicks = 128 * (2 << 14);
|
||||||
|
}
|
||||||
|
else if (_syncSettings.EnableBIOS && (_syncSettings.ConsoleMode is GambatteSyncSettings.ConsoleModeType.GBA))
|
||||||
|
{
|
||||||
|
ResetStallTicks = 485808; // GBA takes 971616 cycles to switch to CGB mode; CGB CPU is inactive during this time.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ResetStallTicks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// set real default colors (before anyone mucks with them at all)
|
// set real default colors (before anyone mucks with them at all)
|
||||||
PutSettings((GambatteSettings)settings ?? new GambatteSettings());
|
PutSettings((GambatteSettings)settings ?? new GambatteSettings());
|
||||||
|
|
||||||
|
@ -196,6 +223,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
|
|
||||||
_cdCallback = new LibGambatte.CDCallback(CDCallbackProc);
|
_cdCallback = new LibGambatte.CDCallback(CDCallbackProc);
|
||||||
|
|
||||||
|
ControllerDefinition = CreateControllerDefinition(IsSgb, _syncSettings.FrameLength is GambatteSyncSettings.FrameLengthType.UserDefinedFrames);
|
||||||
|
|
||||||
NewSaveCoreSetBuff();
|
NewSaveCoreSetBuff();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
@ -219,6 +248,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const uint TICKSPERSECOND = 2097152;
|
private const uint TICKSPERSECOND = 2097152;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// number of reset stall ticks
|
||||||
|
/// </summary>
|
||||||
|
private uint ResetStallTicks { get; set; } = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// keep a copy of the input callback delegate so it doesn't get GCed
|
/// keep a copy of the input callback delegate so it doesn't get GCed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -237,8 +271,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
public int LagCount { get; set; }
|
public int LagCount { get; set; }
|
||||||
public bool IsLagFrame { get; set; }
|
public bool IsLagFrame { get; set; }
|
||||||
public bool IsCgb { get; set; }
|
public bool IsCgb { get; set; }
|
||||||
|
public bool IsSgb { get; set; }
|
||||||
|
|
||||||
// all cycle counts are relative to a 2*1024*1024 mhz refclock
|
// all cycle counts are relative to a 2*1024*1024 hz refclock
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// total cycles actually executed
|
/// total cycles actually executed
|
||||||
|
@ -253,29 +288,52 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
public long CycleCount => (long)_cycleCount;
|
public long CycleCount => (long)_cycleCount;
|
||||||
public double ClockRate => TICKSPERSECOND;
|
public double ClockRate => TICKSPERSECOND;
|
||||||
|
|
||||||
public static readonly ControllerDefinition GbController = new ControllerDefinition
|
public static ControllerDefinition CreateControllerDefinition(bool sgb, bool sub)
|
||||||
{
|
{
|
||||||
Name = "Gameboy Controller",
|
var ret = sub
|
||||||
BoolButtons =
|
? new ControllerDefinition { Name = "Subframe Gameboy Controller" }.AddAxis("Input Length", 0.RangeTo(35112), 35112)
|
||||||
|
: new ControllerDefinition { Name = "Gameboy Controller" };
|
||||||
|
if (sgb)
|
||||||
{
|
{
|
||||||
"Up", "Down", "Left", "Right", "Start", "Select", "B", "A", "Power"
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
ret.BoolButtons.AddRange(
|
||||||
|
new[] { "Up", "Down", "Left", "Right", "Start", "Select", "B", "A" }
|
||||||
|
.Select(s => $"P{i + 1} {s}"));
|
||||||
|
}
|
||||||
|
ret.BoolButtons.Add("Power");
|
||||||
}
|
}
|
||||||
};
|
else
|
||||||
|
|
||||||
public static readonly ControllerDefinition SubGbController = new ControllerDefinition
|
|
||||||
{
|
|
||||||
Name = "Subframe Gameboy Controller",
|
|
||||||
BoolButtons =
|
|
||||||
{
|
{
|
||||||
"Up", "Down", "Left", "Right", "Start", "Select", "B", "A", "Power"
|
ret.BoolButtons.AddRange(new[] { "Up", "Down", "Left", "Right", "Start", "Select", "B", "A", "Power" });
|
||||||
}
|
}
|
||||||
}.AddAxis("Input Length", 0.RangeTo(35112), 35112);
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
private LibGambatte.Buttons ControllerCallback()
|
private LibGambatte.Buttons ControllerCallback()
|
||||||
{
|
{
|
||||||
InputCallbacks.Call();
|
InputCallbacks.Call();
|
||||||
IsLagFrame = false;
|
IsLagFrame = false;
|
||||||
return CurrentButtons;
|
if (IsSgb)
|
||||||
|
{
|
||||||
|
int index = LibGambatte.gambatte_getjoypadindex(GambatteState);
|
||||||
|
uint b = (uint)CurrentButtons;
|
||||||
|
b >>= index * 8;
|
||||||
|
b &= 0xFF;
|
||||||
|
if ((b & 0x30) == 0x30) // snes software side blocks l+r
|
||||||
|
{
|
||||||
|
b &= ~0x30u;
|
||||||
|
}
|
||||||
|
if ((b & 0xC0) == 0xC0) // same for u+d
|
||||||
|
{
|
||||||
|
b &= ~0xC0u;
|
||||||
|
}
|
||||||
|
return (LibGambatte.Buttons)b;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return CurrentButtons;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -310,16 +368,34 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
}
|
}
|
||||||
|
|
||||||
// needs to match the reverse order of Libgambatte's button enum
|
// needs to match the reverse order of Libgambatte's button enum
|
||||||
private static readonly IReadOnlyList<string> BUTTON_ORDER_IN_BITMASK = new[] { "Down", "Up", "Left", "Right", "Start", "Select", "B", "A" };
|
private static readonly IReadOnlyList<string> GB_BUTTON_ORDER_IN_BITMASK = new[] { "Down", "Up", "Left", "Right", "Start", "Select", "B", "A" };
|
||||||
|
|
||||||
|
// input callback assumes buttons are ordered from first player in lsbs to last player in msbs
|
||||||
|
private static readonly IReadOnlyList<string> SGB_BUTTON_ORDER_IN_BITMASK = new[] {
|
||||||
|
"P4 Down", "P4 Up", "P4 Left", "P4 Right", "P4 Start", "P4 Select", "P4 B", "P4 A",
|
||||||
|
"P3 Down", "P3 Up", "P3 Left", "P3 Right", "P3 Start", "P3 Select", "P3 B", "P3 A",
|
||||||
|
"P2 Down", "P2 Up", "P2 Left", "P2 Right", "P2 Start", "P2 Select", "P2 B", "P2 A",
|
||||||
|
"P1 Down", "P1 Up", "P1 Left", "P1 Right", "P1 Start", "P1 Select", "P1 B", "P1 A" };
|
||||||
|
|
||||||
internal void FrameAdvancePrep(IController controller)
|
internal void FrameAdvancePrep(IController controller)
|
||||||
{
|
{
|
||||||
// update our local copy of the controller data
|
// update our local copy of the controller data
|
||||||
byte b = 0;
|
uint b = 0;
|
||||||
for (var i = 0; i < 8; i++)
|
if (IsSgb)
|
||||||
{
|
{
|
||||||
b <<= 1;
|
for (var i = 0; i < 32; i++)
|
||||||
if (controller.IsPressed(BUTTON_ORDER_IN_BITMASK[i])) b |= 1;
|
{
|
||||||
|
b <<= 1;
|
||||||
|
if (controller.IsPressed(SGB_BUTTON_ORDER_IN_BITMASK[i])) b |= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (var i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
b <<= 1;
|
||||||
|
if (controller.IsPressed(GB_BUTTON_ORDER_IN_BITMASK[i])) b |= 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
CurrentButtons = (LibGambatte.Buttons)b;
|
CurrentButtons = (LibGambatte.Buttons)b;
|
||||||
|
|
||||||
|
@ -328,8 +404,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
|
|
||||||
if (controller.IsPressed("Power"))
|
if (controller.IsPressed("Power"))
|
||||||
{
|
{
|
||||||
bool stall = _syncSettings.EnableBIOS && (_syncSettings.ConsoleMode is GambatteSyncSettings.ConsoleModeType.GBA); // GBA takes 971616 cycles to switch to CGB mode; CGB CPU is inactive during this time.
|
LibGambatte.gambatte_reset(GambatteState, ResetStallTicks);
|
||||||
LibGambatte.gambatte_reset(GambatteState, stall ? 485808u : 0u);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Tracer.IsEnabled())
|
if (Tracer.IsEnabled())
|
||||||
|
@ -779,8 +854,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LinkConnected = false;
|
LinkConnected = false;
|
||||||
printer.Disconnect();
|
if (printer != null) // have no idea how this is ever null???
|
||||||
printer = null;
|
{
|
||||||
|
printer.Disconnect();
|
||||||
|
printer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,8 +71,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
|
|
||||||
private const int SampPerFrame = 35112;
|
private const int SampPerFrame = 35112;
|
||||||
|
|
||||||
private readonly SaveController LCont = new SaveController(Gameboy.GbController);
|
private readonly SaveController LCont = new SaveController(Gameboy.CreateControllerDefinition(false, false));
|
||||||
private readonly SaveController RCont = new SaveController(Gameboy.GbController);
|
private readonly SaveController RCont = new SaveController(Gameboy.CreateControllerDefinition(false, false));
|
||||||
|
|
||||||
public bool IsCGBMode(bool right)
|
public bool IsCGBMode(bool right)
|
||||||
{
|
{
|
||||||
|
|
|
@ -93,6 +93,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
[DllImport("libgambatte", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("libgambatte", CallingConvention = CallingConvention.Cdecl)]
|
||||||
public static extern unsafe int gambatte_runfor(IntPtr core, int* videobuf, int pitch, short* soundbuf, ref uint samples);
|
public static extern unsafe int gambatte_runfor(IntPtr core, int* videobuf, int pitch, short* soundbuf, ref uint samples);
|
||||||
|
|
||||||
|
[DllImport("libgambatte", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int gambatte_updatescreenborder(IntPtr core, int[] videobuf, int pitch);
|
||||||
|
|
||||||
|
[DllImport("libgambatte", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int gambatte_generatesgbsamples(IntPtr core, short[] soundbuf, out uint samples);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reset to initial state.
|
/// Reset to initial state.
|
||||||
/// Equivalent to reloading a ROM image, or turning a Game Boy Color off and on again.
|
/// Equivalent to reloading a ROM image, or turning a Game Boy Color off and on again.
|
||||||
|
@ -156,6 +162,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
[DllImport("libgambatte", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("libgambatte", CallingConvention = CallingConvention.Cdecl)]
|
||||||
public static extern void gambatte_setinputgetter(IntPtr core, InputGetter getinput);
|
public static extern void gambatte_setinputgetter(IntPtr core, InputGetter getinput);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets which SGB controller is in use, 0 indexed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="core">opaque state pointer</param>
|
||||||
|
[DllImport("libgambatte", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int gambatte_getjoypadindex(IntPtr core);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// type of the read\write memory callbacks
|
/// type of the read\write memory callbacks
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -405,6 +418,27 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
[DllImport("libgambatte", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("libgambatte", CallingConvention = CallingConvention.Cdecl)]
|
||||||
public static extern bool gambatte_getmemoryarea(IntPtr core, MemoryAreas which, ref IntPtr data, ref int length);
|
public static extern bool gambatte_getmemoryarea(IntPtr core, MemoryAreas which, ref IntPtr data, ref int length);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Saves emulator state to the buffer given by 'stateBuf'.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="core">opaque state pointer</param>
|
||||||
|
/// <param name="videoBuf">160x144 RGB32 (native endian) video frame buffer or 0. Used for saving a thumbnail.</param>
|
||||||
|
/// <param name="pitch">pitch distance in number of pixels (not bytes) from the start of one line to the next in videoBuf.</param>
|
||||||
|
/// <param name="stateBuf">buffer for savestate</param>
|
||||||
|
/// <returns>size</returns>
|
||||||
|
[DllImport("libgambatte", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int gambatte_savestate(IntPtr core, int[] videoBuf, int pitch, byte[] stateBuf);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads emulator state from the buffer given by 'stateBuf' of size 'size'.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="core">opaque state pointer</param>
|
||||||
|
/// <param name="stateBuf">buffer for savestate</param>
|
||||||
|
/// <param name="size">size of savestate buffer</param>
|
||||||
|
/// <returns>success</returns>
|
||||||
|
[DllImport("libgambatte", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern bool gambatte_loadstate(IntPtr core, byte[] stateBuf, int size);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// read a single byte from the cpu bus. this includes all ram, rom, mmio, etc, as it is visible to the cpu (including mappers).
|
/// read a single byte from the cpu bus. this includes all ram, rom, mmio, etc, as it is visible to the cpu (including mappers).
|
||||||
/// while there is no cycle cost to these reads, there may be other side effects! use at your own risk.
|
/// while there is no cycle cost to these reads, there may be other side effects! use at your own risk.
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit c3e44f8fde85317219f233d0f2876e2a2fb354ee
|
Subproject commit dc09a5882c962c426b5c56f4dec541e5fd22335e
|
Loading…
Reference in New Issue