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[] { CoreNames.Faust, CoreNames.Snes9X, CoreNames.Bsnes, CoreNames.Bsnes115 }),
|
||||
(new[] { "SGB" },
|
||||
new[] { CoreNames.SameBoy, CoreNames.Bsnes, CoreNames.Bsnes115}),
|
||||
new[] { CoreNames.Gambatte, CoreNames.SameBoy, CoreNames.Bsnes, CoreNames.Bsnes115}),
|
||||
(new[] { "GB", "GBC" },
|
||||
new[] { CoreNames.Gambatte, CoreNames.GbHawk, CoreNames.SubGbHawk }),
|
||||
(new[] { "DGB" },
|
||||
|
|
|
@ -2004,6 +2004,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
case "GB":
|
||||
case "GBC":
|
||||
case "SGB" when Emulator is Sameboy:
|
||||
case "SGB" when Emulator is Gameboy:
|
||||
GBSubMenu.Visible = true;
|
||||
break;
|
||||
case "SNES" when Emulator is LibsnesCore { IsSGB: true }: // doesn't use "SGB" sysID
|
||||
|
|
|
@ -28,84 +28,98 @@
|
|||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.propertyGrid1 = new System.Windows.Forms.PropertyGrid();
|
||||
this.buttonDefaults = new System.Windows.Forms.Button();
|
||||
this.buttonPalette = new System.Windows.Forms.Button();
|
||||
this.cbRgbdsSyntax = new System.Windows.Forms.CheckBox();
|
||||
this.checkBoxMuted = new System.Windows.Forms.CheckBox();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// propertyGrid1
|
||||
//
|
||||
this.propertyGrid1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
this.propertyGrid1 = new System.Windows.Forms.PropertyGrid();
|
||||
this.buttonDefaults = new System.Windows.Forms.Button();
|
||||
this.buttonPalette = new System.Windows.Forms.Button();
|
||||
this.cbRgbdsSyntax = new System.Windows.Forms.CheckBox();
|
||||
this.checkBoxMuted = new System.Windows.Forms.CheckBox();
|
||||
this.cbShowBorder = new System.Windows.Forms.CheckBox();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// propertyGrid1
|
||||
//
|
||||
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.Right)));
|
||||
this.propertyGrid1.Location = new System.Drawing.Point(3, 3);
|
||||
this.propertyGrid1.Name = "propertyGrid1";
|
||||
this.propertyGrid1.PropertySort = System.Windows.Forms.PropertySort.NoSort;
|
||||
this.propertyGrid1.Size = new System.Drawing.Size(338, 279);
|
||||
this.propertyGrid1.TabIndex = 0;
|
||||
this.propertyGrid1.ToolbarVisible = false;
|
||||
this.propertyGrid1.PropertyValueChanged += new System.Windows.Forms.PropertyValueChangedEventHandler(this.PropertyGrid1_PropertyValueChanged);
|
||||
//
|
||||
// buttonDefaults
|
||||
//
|
||||
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.Name = "buttonDefaults";
|
||||
this.buttonDefaults.Size = new System.Drawing.Size(75, 23);
|
||||
this.buttonDefaults.TabIndex = 1;
|
||||
this.buttonDefaults.Text = "Defaults";
|
||||
this.buttonDefaults.UseVisualStyleBackColor = true;
|
||||
this.buttonDefaults.Click += new System.EventHandler(this.ButtonDefaults_Click);
|
||||
//
|
||||
// buttonPalette
|
||||
//
|
||||
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.Name = "buttonPalette";
|
||||
this.buttonPalette.Size = new System.Drawing.Size(75, 23);
|
||||
this.buttonPalette.TabIndex = 2;
|
||||
this.buttonPalette.Text = "Palette...";
|
||||
this.buttonPalette.UseVisualStyleBackColor = true;
|
||||
this.buttonPalette.Click += new System.EventHandler(this.ButtonPalette_Click);
|
||||
//
|
||||
// checkBoxMuted
|
||||
//
|
||||
this.checkBoxMuted.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.checkBoxMuted.AutoSize = true;
|
||||
this.checkBoxMuted.Location = new System.Drawing.Point(82, 292);
|
||||
this.checkBoxMuted.Name = "checkBoxMuted";
|
||||
this.checkBoxMuted.Size = new System.Drawing.Size(50, 17);
|
||||
this.checkBoxMuted.TabIndex = 3;
|
||||
this.checkBoxMuted.Text = "Mute";
|
||||
this.checkBoxMuted.UseVisualStyleBackColor = true;
|
||||
this.checkBoxMuted.CheckedChanged += new System.EventHandler(this.CheckBoxMuted_CheckedChanged);
|
||||
//
|
||||
// cbRgbdsSyntax
|
||||
//
|
||||
this.cbRgbdsSyntax.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.cbRgbdsSyntax.AutoSize = true;
|
||||
this.cbRgbdsSyntax.Location = new System.Drawing.Point(130, 292);
|
||||
this.cbRgbdsSyntax.Name = "cbRgbdsSyntax";
|
||||
this.cbRgbdsSyntax.Size = new System.Drawing.Size(150, 17);
|
||||
this.cbRgbdsSyntax.TabIndex = 7;
|
||||
this.cbRgbdsSyntax.Text = "RGBDS Syntax";
|
||||
this.cbRgbdsSyntax.UseVisualStyleBackColor = true;
|
||||
this.cbRgbdsSyntax.CheckedChanged += new System.EventHandler(this.CbRgbdsSyntax_CheckedChanged);
|
||||
//
|
||||
// GBPrefControl
|
||||
//
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
|
||||
this.Controls.Add(this.cbRgbdsSyntax);
|
||||
this.Controls.Add(this.checkBoxMuted);
|
||||
this.Controls.Add(this.buttonPalette);
|
||||
this.Controls.Add(this.buttonDefaults);
|
||||
this.Controls.Add(this.propertyGrid1);
|
||||
this.Name = "GBPrefControl";
|
||||
this.Size = new System.Drawing.Size(344, 314);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
this.propertyGrid1.Location = new System.Drawing.Point(3, 3);
|
||||
this.propertyGrid1.Name = "propertyGrid1";
|
||||
this.propertyGrid1.PropertySort = System.Windows.Forms.PropertySort.NoSort;
|
||||
this.propertyGrid1.Size = new System.Drawing.Size(402, 368);
|
||||
this.propertyGrid1.TabIndex = 0;
|
||||
this.propertyGrid1.ToolbarVisible = false;
|
||||
this.propertyGrid1.PropertyValueChanged += new System.Windows.Forms.PropertyValueChangedEventHandler(this.PropertyGrid1_PropertyValueChanged);
|
||||
//
|
||||
// buttonDefaults
|
||||
//
|
||||
this.buttonDefaults.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.buttonDefaults.Location = new System.Drawing.Point(330, 377);
|
||||
this.buttonDefaults.Name = "buttonDefaults";
|
||||
this.buttonDefaults.Size = new System.Drawing.Size(75, 23);
|
||||
this.buttonDefaults.TabIndex = 1;
|
||||
this.buttonDefaults.Text = "Defaults";
|
||||
this.buttonDefaults.UseVisualStyleBackColor = true;
|
||||
this.buttonDefaults.Click += new System.EventHandler(this.ButtonDefaults_Click);
|
||||
//
|
||||
// buttonPalette
|
||||
//
|
||||
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, 377);
|
||||
this.buttonPalette.Name = "buttonPalette";
|
||||
this.buttonPalette.Size = new System.Drawing.Size(75, 23);
|
||||
this.buttonPalette.TabIndex = 2;
|
||||
this.buttonPalette.Text = "Palette...";
|
||||
this.buttonPalette.UseVisualStyleBackColor = true;
|
||||
this.buttonPalette.Click += new System.EventHandler(this.ButtonPalette_Click);
|
||||
//
|
||||
// cbRgbdsSyntax
|
||||
//
|
||||
this.cbRgbdsSyntax.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.cbRgbdsSyntax.AutoSize = true;
|
||||
this.cbRgbdsSyntax.Location = new System.Drawing.Point(138, 381);
|
||||
this.cbRgbdsSyntax.Name = "cbRgbdsSyntax";
|
||||
this.cbRgbdsSyntax.Size = new System.Drawing.Size(99, 17);
|
||||
this.cbRgbdsSyntax.TabIndex = 3;
|
||||
this.cbRgbdsSyntax.Text = "RGBDS Syntax";
|
||||
this.cbRgbdsSyntax.UseVisualStyleBackColor = true;
|
||||
this.cbRgbdsSyntax.CheckedChanged += new System.EventHandler(this.CbRgbdsSyntax_CheckedChanged);
|
||||
//
|
||||
// checkBoxMuted
|
||||
//
|
||||
this.checkBoxMuted.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.checkBoxMuted.AutoSize = true;
|
||||
this.checkBoxMuted.Location = new System.Drawing.Point(82, 381);
|
||||
this.checkBoxMuted.Name = "checkBoxMuted";
|
||||
this.checkBoxMuted.Size = new System.Drawing.Size(50, 17);
|
||||
this.checkBoxMuted.TabIndex = 4;
|
||||
this.checkBoxMuted.Text = "Mute";
|
||||
this.checkBoxMuted.UseVisualStyleBackColor = true;
|
||||
this.checkBoxMuted.CheckedChanged += new System.EventHandler(this.CheckBoxMuted_CheckedChanged);
|
||||
//
|
||||
// cbShowBorder
|
||||
//
|
||||
this.cbShowBorder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.cbShowBorder.AutoSize = true;
|
||||
this.cbShowBorder.Location = new System.Drawing.Point(243, 381);
|
||||
this.cbShowBorder.Name = "cbShowBorder";
|
||||
this.cbShowBorder.Size = new System.Drawing.Size(87, 17);
|
||||
this.cbShowBorder.TabIndex = 5;
|
||||
this.cbShowBorder.Text = "Show Border";
|
||||
this.cbShowBorder.UseVisualStyleBackColor = true;
|
||||
this.cbShowBorder.CheckedChanged += new System.EventHandler(this.CbShowBorder_CheckedChanged);
|
||||
//
|
||||
// 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.CheckBox cbRgbdsSyntax;
|
||||
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();
|
||||
checkBoxMuted.Checked = _s.Muted;
|
||||
cbRgbdsSyntax.Checked = _s.RgbdsSyntax;
|
||||
cbShowBorder.Checked = _s.ShowBorder;
|
||||
}
|
||||
|
||||
public void GetSettings(out Gameboy.GambatteSettings s, out Gameboy.GambatteSyncSettings ss)
|
||||
|
@ -86,5 +87,10 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
_s.RgbdsSyntax = ((CheckBox)sender).Checked;
|
||||
}
|
||||
|
||||
private void CbShowBorder_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
_s.ShowBorder = ((CheckBox)sender).Checked;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,58 +28,58 @@
|
|||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.buttonOK = new System.Windows.Forms.Button();
|
||||
this.buttonCancel = new System.Windows.Forms.Button();
|
||||
this.gbPrefControl1 = new GBPrefControl();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// buttonOK
|
||||
//
|
||||
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.Location = new System.Drawing.Point(280, 363);
|
||||
this.buttonOK.Name = "buttonOK";
|
||||
this.buttonOK.Size = new System.Drawing.Size(75, 23);
|
||||
this.buttonOK.TabIndex = 1;
|
||||
this.buttonOK.Text = "OK";
|
||||
this.buttonOK.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// buttonCancel
|
||||
//
|
||||
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.Location = new System.Drawing.Point(361, 363);
|
||||
this.buttonCancel.Name = "buttonCancel";
|
||||
this.buttonCancel.Size = new System.Drawing.Size(75, 23);
|
||||
this.buttonCancel.TabIndex = 2;
|
||||
this.buttonCancel.Text = "Cancel";
|
||||
this.buttonCancel.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// gbPrefControl1
|
||||
//
|
||||
this.gbPrefControl1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
this.buttonOK = new System.Windows.Forms.Button();
|
||||
this.buttonCancel = new System.Windows.Forms.Button();
|
||||
this.gbPrefControl1 = new BizHawk.Client.EmuHawk.GBPrefControl();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// buttonOK
|
||||
//
|
||||
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.Location = new System.Drawing.Point(280, 363);
|
||||
this.buttonOK.Name = "buttonOK";
|
||||
this.buttonOK.Size = new System.Drawing.Size(75, 23);
|
||||
this.buttonOK.TabIndex = 1;
|
||||
this.buttonOK.Text = "OK";
|
||||
this.buttonOK.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// buttonCancel
|
||||
//
|
||||
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.Location = new System.Drawing.Point(361, 363);
|
||||
this.buttonCancel.Name = "buttonCancel";
|
||||
this.buttonCancel.Size = new System.Drawing.Size(75, 23);
|
||||
this.buttonCancel.TabIndex = 2;
|
||||
this.buttonCancel.Text = "Cancel";
|
||||
this.buttonCancel.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// gbPrefControl1
|
||||
//
|
||||
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.Right)));
|
||||
this.gbPrefControl1.ColorGameBoy = false;
|
||||
this.gbPrefControl1.Location = new System.Drawing.Point(12, 12);
|
||||
this.gbPrefControl1.Name = "gbPrefControl1";
|
||||
this.gbPrefControl1.Size = new System.Drawing.Size(424, 345);
|
||||
this.gbPrefControl1.TabIndex = 0;
|
||||
//
|
||||
// GBPrefs
|
||||
//
|
||||
this.AcceptButton = this.buttonOK;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.buttonCancel;
|
||||
this.ClientSize = new System.Drawing.Size(448, 398);
|
||||
this.Controls.Add(this.buttonCancel);
|
||||
this.Controls.Add(this.buttonOK);
|
||||
this.Controls.Add(this.gbPrefControl1);
|
||||
this.Name = "GBPrefs";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Game Boy Settings";
|
||||
this.ResumeLayout(false);
|
||||
this.gbPrefControl1.ColorGameBoy = false;
|
||||
this.gbPrefControl1.Location = new System.Drawing.Point(12, 12);
|
||||
this.gbPrefControl1.Name = "gbPrefControl1";
|
||||
this.gbPrefControl1.Size = new System.Drawing.Size(424, 345);
|
||||
this.gbPrefControl1.TabIndex = 0;
|
||||
//
|
||||
// GBPrefs
|
||||
//
|
||||
this.AcceptButton = this.buttonOK;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.buttonCancel;
|
||||
this.ClientSize = new System.Drawing.Size(448, 398);
|
||||
this.Controls.Add(this.buttonCancel);
|
||||
this.Controls.Add(this.buttonOK);
|
||||
this.Controls.Add(this.gbPrefControl1);
|
||||
this.Name = "GBPrefs";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Game Boy Settings";
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
using var dlg = new GBPrefs(mainForm.DialogController);
|
||||
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())
|
||||
{
|
||||
dlg.gbPrefControl1.GetSettings(out s, out ss);
|
||||
|
|
|
@ -9,12 +9,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
{
|
||||
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)
|
||||
{
|
||||
FrameAdvancePrep(controller);
|
||||
uint samplesEmitted;
|
||||
uint samplesEmittedInFrame = 0; // for sgb
|
||||
switch (_syncSettings.FrameLength)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
samplesEmittedInFrame += samplesEmitted;
|
||||
frameOverflow = 0;
|
||||
|
||||
if (rendersound && !Muted)
|
||||
{
|
||||
ProcessSound((int)samplesEmitted);
|
||||
|
@ -43,10 +53,18 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
if (LibGambatte.gambatte_runfor(GambatteState, FrameBuffer, 160, _soundbuff, ref samplesEmitted) > 0)
|
||||
{
|
||||
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
|
||||
_cycleCount += samplesEmitted;
|
||||
samplesEmittedInFrame += samplesEmitted;
|
||||
frameOverflow += samplesEmitted;
|
||||
|
||||
if (rendersound && !Muted)
|
||||
|
@ -76,10 +94,18 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
if (LibGambatte.gambatte_runfor(GambatteState, FrameBuffer, 160, _soundbuff, ref samplesEmitted) > 0)
|
||||
{
|
||||
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
|
||||
_cycleCount += samplesEmitted;
|
||||
samplesEmittedInFrame += samplesEmitted;
|
||||
frameOverflow += samplesEmitted;
|
||||
|
||||
if (rendersound && !Muted)
|
||||
|
@ -96,6 +122,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
break;
|
||||
}
|
||||
|
||||
if (IsSgb)
|
||||
{
|
||||
ProcessSgbSound((int)samplesEmittedInFrame, (rendersound && !Muted));
|
||||
}
|
||||
|
||||
if (rendersound && !Muted)
|
||||
{
|
||||
ProcessSoundEnd();
|
||||
|
@ -108,7 +139,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
|
||||
public int Frame { get; private set; }
|
||||
|
||||
public string SystemId => "GB";
|
||||
public string SystemId => IsSgb ? "SGB" : "GB";
|
||||
|
||||
public string BoardName { get; }
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
{
|
||||
_settings = o;
|
||||
_disassembler.UseRGBDSSyntax = _settings.RgbdsSyntax;
|
||||
if (IsCGBMode())
|
||||
if (IsCGBMode() || IsSgb)
|
||||
{
|
||||
SetCGBColors(_settings.CGBColors);
|
||||
}
|
||||
|
@ -77,11 +77,17 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
/// </summary>
|
||||
public bool RgbdsSyntax;
|
||||
|
||||
/// <summary>
|
||||
/// true to show sgb border (sgb mode only)
|
||||
/// </summary>
|
||||
public bool ShowBorder;
|
||||
|
||||
public GambatteSettings()
|
||||
{
|
||||
GBPalette = (int[])DefaultPalette.Clone();
|
||||
CGBColors = GBColors.ColorType.gambatte;
|
||||
RgbdsSyntax = true;
|
||||
ShowBorder = true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
|
||||
// sample pairs before resampling
|
||||
private readonly short[] _soundbuff = new short[(35112 + 2064) * 2];
|
||||
private readonly short[] _sgbsoundbuff = new short[2048 * 2];
|
||||
|
||||
private int _soundoutbuffcontains = 0;
|
||||
|
||||
|
@ -45,6 +46,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
private int _latchL = 0;
|
||||
private int _latchR = 0;
|
||||
|
||||
private int _sgbLatchL = 0;
|
||||
private int _sgbLatchR = 0;
|
||||
|
||||
private BlipBuffer _blipL, _blipR;
|
||||
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()
|
||||
{
|
||||
_blipL.EndFrame(_blipAccumulate);
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using System;
|
||||
//#define USE_UPSTREAM_STATES
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
@ -22,13 +24,21 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
|
||||
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");
|
||||
}
|
||||
#endif
|
||||
|
||||
writer.Write(_savebuff.Length);
|
||||
writer.Write(_savebuff);
|
||||
writer.Write(_stateBuf.Length);
|
||||
writer.Write(_stateBuf);
|
||||
|
||||
// other variables
|
||||
writer.Write(IsLagFrame);
|
||||
|
@ -37,22 +47,30 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
writer.Write(frameOverflow);
|
||||
writer.Write(_cycleCount);
|
||||
writer.Write(IsCgb);
|
||||
writer.Write(IsSgb);
|
||||
}
|
||||
|
||||
public void LoadStateBinary(BinaryReader reader)
|
||||
{
|
||||
int length = reader.ReadInt32();
|
||||
if (length != _savebuff.Length)
|
||||
if (length != _stateBuf.Length)
|
||||
{
|
||||
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");
|
||||
}
|
||||
#endif
|
||||
|
||||
// other variables
|
||||
IsLagFrame = reader.ReadBoolean();
|
||||
|
@ -61,13 +79,18 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
frameOverflow = reader.ReadUInt32();
|
||||
_cycleCount = reader.ReadUInt64();
|
||||
IsCgb = reader.ReadBoolean();
|
||||
IsSgb = reader.ReadBoolean();
|
||||
}
|
||||
|
||||
private byte[] _savebuff;
|
||||
private byte[] _stateBuf;
|
||||
|
||||
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 };
|
||||
|
@ -81,6 +104,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
public ulong _cycleCount;
|
||||
public uint frameOverflow;
|
||||
public bool IsCgb;
|
||||
public bool IsSgb;
|
||||
}
|
||||
|
||||
internal TextState<TextStateData> SaveState()
|
||||
|
@ -95,6 +119,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
s.ExtraData.frameOverflow = frameOverflow;
|
||||
s.ExtraData._cycleCount = _cycleCount;
|
||||
s.ExtraData.IsCgb = IsCgb;
|
||||
s.ExtraData.IsSgb = IsSgb;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -109,6 +134,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
frameOverflow = s.ExtraData.frameOverflow;
|
||||
_cycleCount = s.ExtraData._cycleCount;
|
||||
IsCgb = s.ExtraData.IsCgb;
|
||||
IsSgb = s.ExtraData.IsSgb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,12 @@
|
|||
/// stored image of most recent frame
|
||||
/// </summary>
|
||||
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()
|
||||
{
|
||||
var b = new int[160 * 144];
|
||||
|
@ -24,16 +29,16 @@
|
|||
|
||||
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;
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Common.BufferExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
@ -20,6 +21,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
{
|
||||
[CoreConstructor("GB")]
|
||||
[CoreConstructor("GBC")]
|
||||
[CoreConstructor("SGB")]
|
||||
public Gameboy(CoreComm comm, GameInfo game, byte[] file, Gameboy.GambatteSettings settings, Gameboy.GambatteSyncSettings syncSettings, bool deterministic)
|
||||
{
|
||||
var ser = new BasicServiceProvider(this);
|
||||
|
@ -66,6 +68,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
break;
|
||||
}
|
||||
|
||||
if (game.System == "SGB")
|
||||
{
|
||||
flags &= ~(LibGambatte.LoadFlags.CGB_MODE | LibGambatte.LoadFlags.GBA_FLAG);
|
||||
flags |= LibGambatte.LoadFlags.SGB_MODE;
|
||||
IsSgb = true;
|
||||
}
|
||||
|
||||
if (_syncSettings.MulticartCompat)
|
||||
{
|
||||
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;
|
||||
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)
|
||||
{
|
||||
|
@ -86,15 +100,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
{
|
||||
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)
|
||||
{
|
||||
// patch from cgb->agb re
|
||||
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;
|
||||
}
|
||||
|
@ -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?)");
|
||||
}
|
||||
|
||||
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)
|
||||
PutSettings((GambatteSettings)settings ?? new GambatteSettings());
|
||||
|
||||
|
@ -196,6 +223,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
|
||||
_cdCallback = new LibGambatte.CDCallback(CDCallbackProc);
|
||||
|
||||
ControllerDefinition = CreateControllerDefinition(IsSgb, _syncSettings.FrameLength is GambatteSyncSettings.FrameLengthType.UserDefinedFrames);
|
||||
|
||||
NewSaveCoreSetBuff();
|
||||
}
|
||||
catch
|
||||
|
@ -219,6 +248,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
/// </summary>
|
||||
private const uint TICKSPERSECOND = 2097152;
|
||||
|
||||
/// <summary>
|
||||
/// number of reset stall ticks
|
||||
/// </summary>
|
||||
private uint ResetStallTicks { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// keep a copy of the input callback delegate so it doesn't get GCed
|
||||
/// </summary>
|
||||
|
@ -237,8 +271,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
public int LagCount { get; set; }
|
||||
public bool IsLagFrame { 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>
|
||||
/// total cycles actually executed
|
||||
|
@ -253,29 +288,52 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
public long CycleCount => (long)_cycleCount;
|
||||
public double ClockRate => TICKSPERSECOND;
|
||||
|
||||
public static readonly ControllerDefinition GbController = new ControllerDefinition
|
||||
public static ControllerDefinition CreateControllerDefinition(bool sgb, bool sub)
|
||||
{
|
||||
Name = "Gameboy Controller",
|
||||
BoolButtons =
|
||||
var ret = sub
|
||||
? 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");
|
||||
}
|
||||
};
|
||||
|
||||
public static readonly ControllerDefinition SubGbController = new ControllerDefinition
|
||||
{
|
||||
Name = "Subframe Gameboy Controller",
|
||||
BoolButtons =
|
||||
else
|
||||
{
|
||||
"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()
|
||||
{
|
||||
InputCallbacks.Call();
|
||||
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>
|
||||
|
@ -310,16 +368,34 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
// update our local copy of the controller data
|
||||
byte b = 0;
|
||||
for (var i = 0; i < 8; i++)
|
||||
uint b = 0;
|
||||
if (IsSgb)
|
||||
{
|
||||
b <<= 1;
|
||||
if (controller.IsPressed(BUTTON_ORDER_IN_BITMASK[i])) b |= 1;
|
||||
for (var i = 0; i < 32; i++)
|
||||
{
|
||||
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;
|
||||
|
||||
|
@ -328,8 +404,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
|
||||
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, stall ? 485808u : 0u);
|
||||
LibGambatte.gambatte_reset(GambatteState, ResetStallTicks);
|
||||
}
|
||||
|
||||
if (Tracer.IsEnabled())
|
||||
|
@ -779,8 +854,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
else
|
||||
{
|
||||
LinkConnected = false;
|
||||
printer.Disconnect();
|
||||
printer = null;
|
||||
if (printer != null) // have no idea how this is ever null???
|
||||
{
|
||||
printer.Disconnect();
|
||||
printer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -71,8 +71,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
|
||||
private const int SampPerFrame = 35112;
|
||||
|
||||
private readonly SaveController LCont = new SaveController(Gameboy.GbController);
|
||||
private readonly SaveController RCont = new SaveController(Gameboy.GbController);
|
||||
private readonly SaveController LCont = new SaveController(Gameboy.CreateControllerDefinition(false, false));
|
||||
private readonly SaveController RCont = new SaveController(Gameboy.CreateControllerDefinition(false, false));
|
||||
|
||||
public bool IsCGBMode(bool right)
|
||||
{
|
||||
|
|
|
@ -93,6 +93,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
[DllImport("libgambatte", CallingConvention = CallingConvention.Cdecl)]
|
||||
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>
|
||||
/// Reset to initial state.
|
||||
/// 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)]
|
||||
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>
|
||||
/// type of the read\write memory callbacks
|
||||
/// </summary>
|
||||
|
@ -405,6 +418,27 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
[DllImport("libgambatte", CallingConvention = CallingConvention.Cdecl)]
|
||||
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>
|
||||
/// 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.
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit c3e44f8fde85317219f233d0f2876e2a2fb354ee
|
||||
Subproject commit dc09a5882c962c426b5c56f4dec541e5fd22335e
|
Loading…
Reference in New Issue