Merge branch 'master' of https://github.com/TASVideos/BizHawk
This commit is contained in:
commit
7aec03d788
|
@ -44,7 +44,9 @@ namespace BizHawk.Client.Common
|
|||
|
||||
public void Set(Dictionary<string, bool> buttons, int? controller = null)
|
||||
{
|
||||
foreach (var button in Global.InputManager.ActiveController.Definition.BoolButtons)
|
||||
// If a controller is specified, we need to iterate over unique button names. If not, we iterate over
|
||||
// ALL button names with P{controller} prefixes
|
||||
foreach (var button in Global.InputManager.ActiveController.ToBoolButtonNameList(controller))
|
||||
{
|
||||
Set(button, buttons.TryGetValue(button, out var state) ? state : (bool?) null, controller);
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace BizHawk.Client.Common
|
|||
public void Set(LuaTable buttons, int? controller = null)
|
||||
{
|
||||
var dict = new Dictionary<string, bool>();
|
||||
foreach (var k in buttons.Keys) dict[k.ToString()] = (bool) buttons[k];
|
||||
foreach (var k in buttons.Keys) dict[k.ToString()] = Convert.ToBoolean(buttons[k]); // Accepts 1/0 or true/false
|
||||
APIs.Joypad.Set(dict, controller);
|
||||
}
|
||||
|
||||
|
|
|
@ -424,6 +424,15 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
["Lid"] = 'P',
|
||||
["Touch"] = 'T'
|
||||
},
|
||||
["O2"] = new Dictionary<string, char>
|
||||
{
|
||||
["PERIOD"] = '.',
|
||||
["SPC"] = 's',
|
||||
["YES"] = 'y',
|
||||
["NO"] = 'n',
|
||||
["CLR"] = 'c',
|
||||
["ENT"] = 'e'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -51,6 +51,12 @@ namespace BizHawk.Client.EmuHawk
|
|||
Size = UIHelper.Scale(_schema.Size);
|
||||
MaximumSize = UIHelper.Scale(_schema.Size);
|
||||
PadBox.Text = _schema.DisplayName;
|
||||
|
||||
if (_schema.IsConsole)
|
||||
{
|
||||
this.PadBox.ForeColor = SystemColors.HotTrack;
|
||||
}
|
||||
|
||||
foreach (var button in _schema.Buttons)
|
||||
{
|
||||
switch (button.Type)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using BizHawk.Client.EmuHawk.Properties;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
|
@ -52,50 +52,50 @@ namespace BizHawk.Client.EmuHawk
|
|||
public static ButtonSchema Up(int x, int y, string name = null)
|
||||
=> new ButtonSchema(x, y, name ?? "Up")
|
||||
{
|
||||
Icon = Properties.Resources.BlueUp
|
||||
Icon = Resources.BlueUp
|
||||
};
|
||||
|
||||
public static ButtonSchema Up(int x, int y, int controller)
|
||||
=> new ButtonSchema(x, y, controller, "Up")
|
||||
{
|
||||
Icon = Properties.Resources.BlueUp
|
||||
Icon = Resources.BlueUp
|
||||
};
|
||||
|
||||
|
||||
public static ButtonSchema Down(int x, int y, string name = null)
|
||||
=> new ButtonSchema(x, y, name ?? "Down")
|
||||
{
|
||||
Icon = Properties.Resources.BlueDown
|
||||
Icon = Resources.BlueDown
|
||||
};
|
||||
|
||||
public static ButtonSchema Down(int x, int y, int controller)
|
||||
=> new ButtonSchema(x, y, controller, "Down")
|
||||
{
|
||||
Icon = Properties.Resources.BlueDown
|
||||
Icon = Resources.BlueDown
|
||||
};
|
||||
|
||||
public static ButtonSchema Left(int x, int y, string name = null)
|
||||
=> new ButtonSchema(x, y, name ?? "Left")
|
||||
{
|
||||
Icon = Properties.Resources.Back
|
||||
Icon = Resources.Back
|
||||
};
|
||||
|
||||
public static ButtonSchema Left(int x, int y, int controller)
|
||||
=> new ButtonSchema(x, y, controller, "Left")
|
||||
{
|
||||
Icon = Properties.Resources.Back
|
||||
Icon = Resources.Back
|
||||
};
|
||||
|
||||
public static ButtonSchema Right(int x, int y, string name = null)
|
||||
=> new ButtonSchema(x, y, name ?? "Right")
|
||||
{
|
||||
Icon = Properties.Resources.Forward
|
||||
Icon = Resources.Forward
|
||||
};
|
||||
|
||||
public static ButtonSchema Right(int x, int y, int controller)
|
||||
=> new ButtonSchema(x, y, controller, "Right")
|
||||
{
|
||||
Icon = Properties.Resources.Forward
|
||||
Icon = Resources.Forward
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using BizHawk.Client.EmuHawk.Properties;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Consoles.Sega.gpgx;
|
||||
|
||||
|
@ -175,6 +176,8 @@ namespace BizHawk.Client.EmuHawk
|
|||
};
|
||||
}
|
||||
|
||||
// TODO: don't know what L/U is, couldn't find documentation, went with U
|
||||
// Also, which number corresponds to which direction?
|
||||
private static PadSchema Activator(int controller)
|
||||
{
|
||||
return new PadSchema
|
||||
|
@ -182,15 +185,14 @@ namespace BizHawk.Client.EmuHawk
|
|||
Size = new Size(110, 110),
|
||||
Buttons = new[]
|
||||
{
|
||||
ButtonSchema.Up(47, 10, controller),
|
||||
ButtonSchema.Down(47, 73, controller),
|
||||
ButtonSchema.Left(15, 43, controller),
|
||||
ButtonSchema.Right(80, 43, controller),
|
||||
new ButtonSchema(70, 65, controller, "A"),
|
||||
new ButtonSchema(70, 20, controller, "B"),
|
||||
new ButtonSchema(22, 20, controller, "C"),
|
||||
new ButtonSchema(22, 65, controller, "A"),
|
||||
new ButtonSchema(47, 43, controller, "Start") { DisplayName = "S" }
|
||||
new ButtonSchema(15, 43, controller, "1U") { Icon = Resources.Back },
|
||||
new ButtonSchema(22, 20, controller, "2U") { Icon = Resources.NW },
|
||||
new ButtonSchema(47, 10, controller, "3U") { Icon = Resources.BlueUp },
|
||||
new ButtonSchema(70, 20, controller, "4U") { Icon = Resources.NE },
|
||||
new ButtonSchema(80, 43, controller, "5U") { Icon = Resources.Forward },
|
||||
new ButtonSchema(70, 65, controller, "6U") { Icon = Resources.SE },
|
||||
new ButtonSchema(47, 73, controller, "7U") { Icon = Resources.BlueDown },
|
||||
new ButtonSchema(22, 65, controller, "8U") { Icon = Resources.SW }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using BizHawk.Client.EmuHawk.Properties;
|
||||
using BizHawk.Common.ReflectionExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Intellivision;
|
||||
|
@ -47,70 +48,22 @@ namespace BizHawk.Client.EmuHawk
|
|||
Size = new Size(148, 332),
|
||||
Buttons = StandardButtons(controller).Concat(new[]
|
||||
{
|
||||
new ButtonSchema(51, 124, controller, "N")
|
||||
{
|
||||
Icon = Properties.Resources.BlueUp
|
||||
},
|
||||
new ButtonSchema(63, 145, controller, "NNE")
|
||||
{
|
||||
Icon = Properties.Resources.NNE
|
||||
},
|
||||
new ButtonSchema(39, 145, controller, "NNW")
|
||||
{
|
||||
Icon = Properties.Resources.NNW
|
||||
},
|
||||
new ButtonSchema(75, 166, controller, "NE")
|
||||
{
|
||||
Icon = Properties.Resources.NE
|
||||
},
|
||||
new ButtonSchema(27, 166, controller, "NW")
|
||||
{
|
||||
Icon = Properties.Resources.NW
|
||||
},
|
||||
new ButtonSchema(87, 187, controller, "ENE")
|
||||
{
|
||||
Icon = Properties.Resources.ENE
|
||||
},
|
||||
new ButtonSchema(15, 187, controller, "WNW")
|
||||
{
|
||||
Icon = Properties.Resources.WNW
|
||||
},
|
||||
new ButtonSchema(99, 208, controller, "E")
|
||||
{
|
||||
Icon = Properties.Resources.Forward
|
||||
},
|
||||
new ButtonSchema(3, 208, controller, "W")
|
||||
{
|
||||
Icon = Properties.Resources.Back
|
||||
},
|
||||
new ButtonSchema(87, 229, controller, "ESE")
|
||||
{
|
||||
Icon = Properties.Resources.ESE
|
||||
},
|
||||
new ButtonSchema(15, 229, controller, "WSW")
|
||||
{
|
||||
Icon = Properties.Resources.WSW
|
||||
},
|
||||
new ButtonSchema(75, 250, controller, "SE")
|
||||
{
|
||||
Icon = Properties.Resources.SE
|
||||
},
|
||||
new ButtonSchema(27, 250, controller, "SW")
|
||||
{
|
||||
Icon = Properties.Resources.SW
|
||||
},
|
||||
new ButtonSchema(63, 271, controller, "SSE")
|
||||
{
|
||||
Icon = Properties.Resources.SSE
|
||||
},
|
||||
new ButtonSchema(39, 271, controller, "SSW")
|
||||
{
|
||||
Icon = Properties.Resources.SSW
|
||||
},
|
||||
new ButtonSchema(51, 292, controller, "S")
|
||||
{
|
||||
Icon = Properties.Resources.BlueDown
|
||||
}
|
||||
new ButtonSchema(51, 124, controller, "N") { Icon = Resources.BlueUp },
|
||||
new ButtonSchema(63, 145, controller, "NNE") { Icon = Resources.NNE },
|
||||
new ButtonSchema(39, 145, controller, "NNW") { Icon = Resources.NNW },
|
||||
new ButtonSchema(75, 166, controller, "NE") { Icon = Resources.NE },
|
||||
new ButtonSchema(27, 166, controller, "NW") { Icon = Resources.NW },
|
||||
new ButtonSchema(87, 187, controller, "ENE") { Icon = Resources.ENE },
|
||||
new ButtonSchema(15, 187, controller, "WNW") { Icon = Resources.WNW },
|
||||
new ButtonSchema(99, 208, controller, "E") { Icon = Resources.Forward },
|
||||
new ButtonSchema(3, 208, controller, "W") { Icon = Resources.Back },
|
||||
new ButtonSchema(87, 229, controller, "ESE") { Icon = Resources.ESE },
|
||||
new ButtonSchema(15, 229, controller, "WSW") { Icon = Resources.WSW },
|
||||
new ButtonSchema(75, 250, controller, "SE") { Icon = Resources.SE },
|
||||
new ButtonSchema(27, 250, controller, "SW") { Icon = Resources.SW },
|
||||
new ButtonSchema(63, 271, controller, "SSE") { Icon = Resources.SSE },
|
||||
new ButtonSchema(39, 271, controller, "SSW") { Icon = Resources.SSW },
|
||||
new ButtonSchema(51, 292, controller, "S") { Icon = Resources.BlueDown }
|
||||
})
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Consoles.O2Hawk;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
|
@ -12,19 +10,10 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
public IEnumerable<PadSchema> GetPadSchemas(IEmulator core)
|
||||
{
|
||||
var O2SyncSettings = ((O2Hawk)core).GetSyncSettings().Clone();
|
||||
// var port1 = O2SyncSettings.Port1;
|
||||
// var port2 = O2SyncSettings.Port2;
|
||||
|
||||
// if (port1 == "O2 Controller")
|
||||
// {
|
||||
yield return StandardController(1);
|
||||
// }
|
||||
|
||||
// if (port2 == "O2 Controller")
|
||||
// {
|
||||
yield return StandardController(2);
|
||||
// }
|
||||
yield return StandardController(1);
|
||||
yield return StandardController(2);
|
||||
yield return KeyboardButtons();
|
||||
yield return ConsoleButtons();
|
||||
}
|
||||
|
||||
private static PadSchema StandardController(int controller)
|
||||
|
@ -42,5 +31,82 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static PadSchema KeyboardButtons()
|
||||
{
|
||||
return new PadSchema
|
||||
{
|
||||
Size = new Size(275, 200),
|
||||
Buttons = new[]
|
||||
{
|
||||
new ButtonSchema(8, 14, "0"),
|
||||
new ButtonSchema(33, 14, "1"),
|
||||
new ButtonSchema(58, 14, "2"),
|
||||
new ButtonSchema(83, 14, "3"),
|
||||
new ButtonSchema(108, 14, "4"),
|
||||
new ButtonSchema(133, 14, "5"),
|
||||
new ButtonSchema(158, 14, "6"),
|
||||
new ButtonSchema(183, 14, "7"),
|
||||
new ButtonSchema(208, 14, "8"),
|
||||
new ButtonSchema(233, 14, "9"),
|
||||
|
||||
new ButtonSchema(8, 44, "+"),
|
||||
new ButtonSchema(33, 44, "-"),
|
||||
new ButtonSchema(58, 44, "*") { DisplayName = "x"},
|
||||
new ButtonSchema(83, 44, "/") { DisplayName = "÷" },
|
||||
new ButtonSchema(108, 44, "="),
|
||||
new ButtonSchema(133, 44, "YES") { DisplayName = "y" },
|
||||
new ButtonSchema(158, 44, "NO") { DisplayName = "n" },
|
||||
new ButtonSchema(183, 44, "CLR") { DisplayName = "cl" },
|
||||
new ButtonSchema(216, 44, "ENT") { DisplayName = "enter" },
|
||||
|
||||
new ButtonSchema(8, 74, "Q"),
|
||||
new ButtonSchema(33, 74, "W"),
|
||||
new ButtonSchema(58, 74, "E"),
|
||||
new ButtonSchema(83, 74, "R"),
|
||||
new ButtonSchema(108, 74, "T"),
|
||||
new ButtonSchema(133, 74, "YES") { DisplayName = "Y" },
|
||||
new ButtonSchema(158, 74, "U"),
|
||||
new ButtonSchema(183, 74, "I"),
|
||||
new ButtonSchema(208, 74, "O"),
|
||||
new ButtonSchema(233, 74, "P"),
|
||||
|
||||
new ButtonSchema(20, 104, "A"),
|
||||
new ButtonSchema(45, 104, "S"),
|
||||
new ButtonSchema(70, 104, "D"),
|
||||
new ButtonSchema(95, 104, "F"),
|
||||
new ButtonSchema(120, 104, "G"),
|
||||
new ButtonSchema(145, 104, "H"),
|
||||
new ButtonSchema(170, 104, "J"),
|
||||
new ButtonSchema(195, 104, "K"),
|
||||
new ButtonSchema(220, 104, "L"),
|
||||
|
||||
|
||||
new ButtonSchema(33, 134, "Z"),
|
||||
new ButtonSchema(58, 134, "X"),
|
||||
new ButtonSchema(83, 134, "C"),
|
||||
new ButtonSchema(108, 134, "V"),
|
||||
new ButtonSchema(133, 134, "B"),
|
||||
new ButtonSchema(158, 134, "NO") { DisplayName = "N" },
|
||||
new ButtonSchema(183, 134, "M"),
|
||||
new ButtonSchema(208, 134, "PERIOD") { DisplayName = "." },
|
||||
new ButtonSchema(233, 134, "?"),
|
||||
|
||||
new ButtonSchema(95, 164, "SPC") { DisplayName = " SPACE " }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static PadSchema ConsoleButtons()
|
||||
{
|
||||
return new ConsoleSchema
|
||||
{
|
||||
Size = new Size(75, 50),
|
||||
Buttons = new[]
|
||||
{
|
||||
new ButtonSchema(10, 15, "Power")
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,7 +113,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
SecondaryNames = new[] { $"P{controller} Stick Vertical" },
|
||||
AxisRange = axisRanges[0],
|
||||
SecondaryAxisRange = axisRanges[1],
|
||||
SecondaryAxisRange = axisRanges[1]
|
||||
},
|
||||
new SingleFloatSchema(8, 12, controller, "Left Shoulder")
|
||||
{
|
||||
|
|
|
@ -16,25 +16,27 @@ namespace BizHawk.Client.EmuHawk
|
|||
var port1 = vecSyncSettings.Port1;
|
||||
var port2 = vecSyncSettings.Port2;
|
||||
|
||||
if (port1 == "Vectrex Digital Controller")
|
||||
switch (port1)
|
||||
{
|
||||
yield return StandardController(1);
|
||||
case "Vectrex Digital Controller":
|
||||
yield return StandardController(1);
|
||||
break;
|
||||
case "Vectrex Analog Controller":
|
||||
yield return AnalogController(1);
|
||||
break;
|
||||
}
|
||||
|
||||
if (port2 == "Vectrex Digital Controller")
|
||||
switch (port2)
|
||||
{
|
||||
yield return StandardController(2);
|
||||
case "Vectrex Digital Controller":
|
||||
yield return StandardController(2);
|
||||
break;
|
||||
case "Vectrex Analog Controller":
|
||||
yield return AnalogController(2);
|
||||
break;
|
||||
}
|
||||
|
||||
if (port1 == "Vectrex Analog Controller")
|
||||
{
|
||||
yield return AnalogController(1);
|
||||
}
|
||||
|
||||
if (port2 == "Vectrex Analog Controller")
|
||||
{
|
||||
yield return AnalogController(2);
|
||||
}
|
||||
yield return ConsoleButtons();
|
||||
}
|
||||
|
||||
private static PadSchema StandardController(int controller)
|
||||
|
@ -48,22 +50,10 @@ namespace BizHawk.Client.EmuHawk
|
|||
ButtonSchema.Down(14, 56, controller),
|
||||
ButtonSchema.Left(2, 34, controller),
|
||||
ButtonSchema.Right(24, 34, controller),
|
||||
new ButtonSchema(74, 34, controller, "Button 1")
|
||||
{
|
||||
DisplayName = "1"
|
||||
},
|
||||
new ButtonSchema(98, 34, controller, "Button 2")
|
||||
{
|
||||
DisplayName = "2"
|
||||
},
|
||||
new ButtonSchema(122, 34, controller, "Button 3")
|
||||
{
|
||||
DisplayName = "3"
|
||||
},
|
||||
new ButtonSchema(146, 34, controller, "Button 4")
|
||||
{
|
||||
DisplayName = "4"
|
||||
}
|
||||
Button(74, 34, controller, 1),
|
||||
Button(98, 34, controller, 2),
|
||||
Button(122, 34, controller, 3),
|
||||
Button(146, 34, controller, 4)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -73,25 +63,13 @@ namespace BizHawk.Client.EmuHawk
|
|||
var controllerDefRanges = new AnalogControls(controller).Definition.FloatRanges;
|
||||
return new PadSchema
|
||||
{
|
||||
Size = new Size(280, 380),
|
||||
Size = new Size(280, 300),
|
||||
Buttons = new[]
|
||||
{
|
||||
new ButtonSchema(74, 34, controller, "Button 1")
|
||||
{
|
||||
DisplayName = "1"
|
||||
},
|
||||
new ButtonSchema(98, 34, controller, "Button 2")
|
||||
{
|
||||
DisplayName = "2"
|
||||
},
|
||||
new ButtonSchema(122, 34, controller, "Button 3")
|
||||
{
|
||||
DisplayName = "3"
|
||||
},
|
||||
new ButtonSchema(146, 34, controller, "Button 4")
|
||||
{
|
||||
DisplayName = "4"
|
||||
},
|
||||
Button(74, 34, controller, 1),
|
||||
Button(98, 34, controller, 2),
|
||||
Button(122, 34, controller, 3),
|
||||
Button(146, 34, controller, 4),
|
||||
new AnalogSchema(2, 80, $"P{controller} Stick X")
|
||||
{
|
||||
AxisRange = controllerDefRanges[0],
|
||||
|
@ -100,5 +78,26 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static ButtonSchema Button(int x, int y, int controller, int button)
|
||||
{
|
||||
return new ButtonSchema(x, y, controller, $"Button {button}")
|
||||
{
|
||||
DisplayName = button.ToString()
|
||||
};
|
||||
}
|
||||
|
||||
private static PadSchema ConsoleButtons()
|
||||
{
|
||||
return new ConsoleSchema
|
||||
{
|
||||
Size = new Size(150, 50),
|
||||
Buttons = new[]
|
||||
{
|
||||
new ButtonSchema(10, 15, "Reset"),
|
||||
new ButtonSchema(58, 15, "Power")
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="System.ComponentModel.Annotations" Version="4.7.0" />
|
||||
<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.7.0" PrivateAssets="All" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.113"
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8"
|
||||
Condition=" '$(MachineRunAnalyzersDuringBuild)' != '' " />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.164"
|
||||
Condition=" '$(MachineRunAnalyzersDuringBuild)' != '' " />
|
||||
<Compile Include="$(SolutionDir)Version/svnrev.cs" />
|
||||
<Compile Include="$(SolutionDir)Version/VersionInfo.cs" />
|
||||
|
|
|
@ -314,6 +314,47 @@ namespace BizHawk.Emulation.Common
|
|||
return !info.GetCustomAttributes(false).Any(a => a is FeatureNotImplementedAttribute);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of boolean button names. If a controller number is specified, only returns button names
|
||||
/// (without the "P" prefix) that match that controller number. If a controller number is NOT specified,
|
||||
/// then all button names are returned.
|
||||
///
|
||||
/// For example, consider example "P1 A", "P1 B", "P2 A", "P2 B". See below for sample outputs:
|
||||
/// - ToBoolButtonNameList(controller, 1) -> [A, B]
|
||||
/// - ToBoolButtonNameList(controller, 2) -> [A, B]
|
||||
/// - ToBoolButtonNameList(controller, null) -> [P1 A, P1 B, P2 A, P2 B]
|
||||
/// </summary>
|
||||
public static List<string> ToBoolButtonNameList(this IController controller, int? controllerNum = null)
|
||||
{
|
||||
return ToControlNameList(controller.Definition.BoolButtons, controllerNum);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// See ToBoolButtonNameList(). Works the same except with float controls
|
||||
/// </summary>
|
||||
public static List<string> ToFloatControlNameList(this IController controller, int? controllerNum = null)
|
||||
{
|
||||
return ToControlNameList(controller.Definition.FloatControls, controllerNum);
|
||||
}
|
||||
|
||||
private static List<string> ToControlNameList(List<string> buttonList, int? controllerNum = null)
|
||||
{
|
||||
var buttons = new List<string>();
|
||||
foreach (var button in buttonList)
|
||||
{
|
||||
if (controllerNum != null && button.Length > 2 && button.Substring(0, 2) == $"P{controllerNum}")
|
||||
{
|
||||
var sub = button.Substring(3);
|
||||
buttons.Add(sub);
|
||||
}
|
||||
else if (controllerNum == null)
|
||||
{
|
||||
buttons.Add(button);
|
||||
}
|
||||
}
|
||||
return buttons;
|
||||
}
|
||||
|
||||
public static IDictionary<string, dynamic> ToDictionary(this IController controller, int? controllerNum = null)
|
||||
{
|
||||
var buttons = new Dictionary<string, dynamic>();
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
public bool in_vblank_old;
|
||||
public bool in_vblank;
|
||||
public bool vblank_rise;
|
||||
public uint ticker;
|
||||
|
||||
public bool FrameAdvance(IController controller, bool render, bool rendersound)
|
||||
{
|
||||
|
@ -59,8 +60,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
{
|
||||
// PAL timing is: 17.7 / 5 ppu
|
||||
// and 17.7 / 9 for cpu (divide by 3 externally then by 3 again internally)
|
||||
int ticker = 0;
|
||||
|
||||
while (frame_chk)
|
||||
{
|
||||
ticker++;
|
||||
|
@ -68,7 +67,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
if ((ticker % 5) == 0)
|
||||
{
|
||||
ppu.tick();
|
||||
|
||||
if ((ticker % 10) == 0)
|
||||
{
|
||||
ppu.Audio_tick();
|
||||
|
@ -77,7 +75,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
|
||||
if ((ticker % 9) == 0)
|
||||
{
|
||||
serialport.serial_transfer_tick();
|
||||
cpu.ExecuteOne();
|
||||
}
|
||||
|
||||
|
@ -96,7 +93,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
{
|
||||
ppu.tick();
|
||||
ppu.tick();
|
||||
serialport.serial_transfer_tick();
|
||||
ppu.Audio_tick();
|
||||
cpu.ExecuteOne();
|
||||
|
||||
|
@ -114,7 +110,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
{
|
||||
ppu.tick();
|
||||
ppu.tick();
|
||||
serialport.serial_transfer_tick();
|
||||
ppu.Audio_tick();
|
||||
cpu.ExecuteOne();
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
cpu.SyncState(ser);
|
||||
mapper.SyncState(ser);
|
||||
ppu.SyncState(ser);
|
||||
serialport.SyncState(ser);
|
||||
|
||||
ser.Sync(nameof(core), ref core, false);
|
||||
ser.Sync("Lag", ref _lagcount);
|
||||
|
@ -32,6 +31,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
ser.Sync(nameof(in_vblank), ref in_vblank);
|
||||
ser.Sync(nameof(in_vblank_old), ref in_vblank_old);
|
||||
ser.Sync(nameof(vblank_rise), ref vblank_rise);
|
||||
ser.Sync(nameof(ticker), ref ticker);
|
||||
|
||||
ser.Sync(nameof(RAM_en), ref RAM_en);
|
||||
ser.Sync(nameof(ppu_en), ref ppu_en);
|
||||
|
|
|
@ -37,7 +37,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
|
||||
public I8048 cpu;
|
||||
public PPU ppu;
|
||||
public SerialPort serialport;
|
||||
|
||||
public bool is_pal;
|
||||
|
||||
|
@ -56,8 +55,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
WritePort = WritePort,
|
||||
OnExecFetch = ExecFetch,
|
||||
};
|
||||
|
||||
serialport = new SerialPort();
|
||||
|
||||
_settings = (O2Settings)settings ?? new O2Settings();
|
||||
_syncSettings = (O2SyncSettings)syncSettings ?? new O2SyncSettings();
|
||||
|
@ -86,7 +83,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
|
||||
ppu.Core = this;
|
||||
cpu.Core = this;
|
||||
serialport.Core = this;
|
||||
|
||||
ser.Register<IVideoProvider>(this);
|
||||
ser.Register<ISoundProvider>(ppu);
|
||||
|
@ -134,7 +130,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
WritePort(2, 0xFF);
|
||||
|
||||
ppu.Reset();
|
||||
serialport.Reset();
|
||||
|
||||
cpu.SetCallbacks(ReadMemory, PeekMemory, PeekMemory, WriteMemory);
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
"8", "9", "SPC", "?", "L", "P",
|
||||
"+", "W", "E", "R", "T", "U", "I", "O",
|
||||
"Q", "S", "D", "F", "G", "H", "J", "K",
|
||||
"A", "Z", "X", "C", "V", "B", "M", ".",
|
||||
"A", "Z", "X", "C", "V", "B", "M", "PERIOD",
|
||||
"-", "*", "/", "=", "YES", "NO", "CLR", "ENT",
|
||||
"Power"
|
||||
})
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
TODO:
|
|
@ -1,147 +0,0 @@
|
|||
using BizHawk.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
||||
{
|
||||
public class SerialPort
|
||||
{
|
||||
public O2Hawk Core { get; set; }
|
||||
|
||||
public byte serial_control;
|
||||
public byte serial_data;
|
||||
public bool serial_start;
|
||||
public bool can_pulse;
|
||||
public int serial_clock;
|
||||
public int serial_bits;
|
||||
public int clk_rate;
|
||||
public byte going_out;
|
||||
public byte coming_in;
|
||||
|
||||
public byte ReadReg(int addr)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0xFF01:
|
||||
return serial_data;
|
||||
case 0xFF02:
|
||||
return serial_control;
|
||||
}
|
||||
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
public void WriteReg(int addr, byte value)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0xFF01:
|
||||
serial_data = value;
|
||||
break;
|
||||
|
||||
case 0xFF02:
|
||||
if (((value & 0x80) > 0) && !serial_start)
|
||||
{
|
||||
serial_start = true;
|
||||
serial_bits = 8;
|
||||
if ((value & 1) > 0)
|
||||
{
|
||||
if (((value & 2) > 0))
|
||||
{
|
||||
clk_rate = 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
clk_rate = 512;
|
||||
}
|
||||
serial_clock = clk_rate;
|
||||
can_pulse = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
clk_rate = -1;
|
||||
serial_clock = clk_rate;
|
||||
can_pulse = false;
|
||||
}
|
||||
}
|
||||
else if (serial_start)
|
||||
{
|
||||
if ((value & 1) > 0)
|
||||
{
|
||||
if (((value & 2) > 0))
|
||||
{
|
||||
clk_rate = 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
clk_rate = 512;
|
||||
}
|
||||
serial_clock = clk_rate;
|
||||
can_pulse = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
clk_rate = -1;
|
||||
serial_clock = clk_rate;
|
||||
can_pulse = false;
|
||||
}
|
||||
}
|
||||
|
||||
serial_control = (byte)(0x7E | (value & 0x81)); // middle six bits always 1
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void serial_transfer_tick()
|
||||
{
|
||||
if (serial_start)
|
||||
{
|
||||
if (serial_clock > 0) { serial_clock--; }
|
||||
|
||||
if (serial_clock == 0)
|
||||
{
|
||||
if (serial_bits > 0)
|
||||
{
|
||||
byte temp = coming_in;
|
||||
serial_data = (byte)((serial_data << 1) | temp);
|
||||
|
||||
serial_bits--;
|
||||
|
||||
if (serial_bits == 0)
|
||||
{
|
||||
serial_control &= 0x7F;
|
||||
serial_start = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
serial_clock = clk_rate;
|
||||
if (clk_rate > 0) { can_pulse = true; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
serial_control = 0x7E;
|
||||
serial_start = false;
|
||||
serial_data = 0x00;
|
||||
going_out = 0;
|
||||
coming_in = 1;
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.Sync(nameof(serial_control), ref serial_control);
|
||||
ser.Sync(nameof(serial_data), ref serial_data);
|
||||
ser.Sync(nameof(serial_start), ref serial_start);
|
||||
ser.Sync(nameof(serial_clock), ref serial_clock);
|
||||
ser.Sync(nameof(serial_bits), ref serial_bits);
|
||||
ser.Sync(nameof(clk_rate), ref clk_rate);
|
||||
ser.Sync(nameof(going_out), ref going_out);
|
||||
ser.Sync(nameof(coming_in), ref coming_in);
|
||||
ser.Sync(nameof(can_pulse), ref can_pulse);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ using BizHawk.Emulation.Common;
|
|||
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
||||
{
|
||||
[Core("MelonDS", "Arisotura", false, false, null, null, true)]
|
||||
unsafe public partial class MelonDS : IEmulator
|
||||
public unsafe partial class MelonDS : IEmulator
|
||||
{
|
||||
private BasicServiceProvider _serviceProvider;
|
||||
public IEmulatorServiceProvider ServiceProvider => _serviceProvider;
|
||||
|
|
218
Common.ruleset
218
Common.ruleset
|
@ -1,5 +1,223 @@
|
|||
<?xml version="1.0"?>
|
||||
<RuleSet Name="BizHawk Rules" Description="Applies to all projects in the solution -- or, it will eventually." ToolsVersion="14.0">
|
||||
<Rules AnalyzerId="Microsoft.CodeAnalysis.FxCopAnalyzers" RuleNamespace="Microsoft.CodeAnalysis.FxCopAnalyzers">
|
||||
<!-- Types that own disposable fields should be disposable -->
|
||||
<Rule Id="CA1001" Action="Hidden" />
|
||||
|
||||
<!-- Collections should implement generic interface -->
|
||||
<Rule Id="CA1010" Action="Hidden" />
|
||||
|
||||
<!-- Mark assemblies with assembly version -->
|
||||
<Rule Id="CA1016" Action="Hidden" />
|
||||
|
||||
<!-- Mark attributes with AttributeUsageAttribute -->
|
||||
<Rule Id="CA1018" Action="Hidden" />
|
||||
|
||||
<!-- Enum Storage should be Int32 -->
|
||||
<Rule Id="CA1028" Action="Hidden" />
|
||||
|
||||
<!-- Do not catch general exception types -->
|
||||
<Rule Id="CA1031" Action="Hidden" />
|
||||
|
||||
<!-- Implement standard exception constructors -->
|
||||
<Rule Id="CA1032" Action="Hidden" />
|
||||
|
||||
<!-- Nested types should not be visible -->
|
||||
<Rule Id="CA1034" Action="Hidden" />
|
||||
|
||||
<!-- Override methods on comparable types -->
|
||||
<Rule Id="CA1036" Action="Hidden" />
|
||||
|
||||
<!-- Avoid empty interfaces -->
|
||||
<Rule Id="CA1040" Action="Hidden" />
|
||||
|
||||
<!-- Provide ObsoleteAttribute message -->
|
||||
<Rule Id="CA1041" Action="Hidden" />
|
||||
|
||||
<!-- Use Integral Or String Argument For Indexers -->
|
||||
<Rule Id="CA1043" Action="Hidden" />
|
||||
|
||||
<!-- Properties should not be write only -->
|
||||
<Rule Id="CA1044" Action="Hidden" />
|
||||
|
||||
<!-- Do not declare visible instance fields -->
|
||||
<Rule Id="CA1051" Action="Hidden" />
|
||||
|
||||
<!-- Static holder types should be Static or NotInheritable -->
|
||||
<Rule Id="CA1052" Action="Hidden" />
|
||||
|
||||
<!-- Uri parameters should not be strings -->
|
||||
<Rule Id="CA1054" Action="Hidden" />
|
||||
|
||||
<!-- Uri return values should not be strings -->
|
||||
<Rule Id="CA1055" Action="Hidden" />
|
||||
|
||||
<!-- Validate arguments of public methods -->
|
||||
<Rule Id="CA1062" Action="Hidden" />
|
||||
|
||||
<!-- Implement IDisposable Correctly -->
|
||||
<Rule Id="CA1063" Action="Hidden" />
|
||||
|
||||
<!-- Exceptions should be public -->
|
||||
<Rule Id="CA1064" Action="Hidden" />
|
||||
|
||||
<!-- Do not raise exceptions in unexpected locations -->
|
||||
<Rule Id="CA1065" Action="Hidden" />
|
||||
|
||||
<!-- Type {0} should implement IEquatable<T> because it overrides Equals -->
|
||||
<Rule Id="CA1066" Action="Hidden" />
|
||||
|
||||
<!-- Do not pass literals as localized parameters -->
|
||||
<Rule Id="CA1303" Action="Hidden" />
|
||||
|
||||
<!-- Specify CultureInfo -->
|
||||
<Rule Id="CA1304" Action="Hidden" />
|
||||
|
||||
<!-- Specify IFormatProvider -->
|
||||
<Rule Id="CA1305" Action="Hidden" />
|
||||
|
||||
<!-- Specify StringComparison -->
|
||||
<Rule Id="CA1307" Action="Hidden" />
|
||||
|
||||
<!-- Normalize strings to uppercase -->
|
||||
<Rule Id="CA1308" Action="Hidden" />
|
||||
|
||||
<!-- P/Invokes should not be visible -->
|
||||
<Rule Id="CA1401" Action="Hidden" />
|
||||
|
||||
<!-- Use nameof to express symbol names -->
|
||||
<Rule Id="CA1507" Action="Hidden" />
|
||||
|
||||
<!-- Identifiers should not contain underscores -->
|
||||
<Rule Id="CA1707" Action="Hidden" />
|
||||
|
||||
<!-- Identifiers should have correct suffix -->
|
||||
<Rule Id="CA1710" Action="Hidden" />
|
||||
|
||||
<!-- Do not prefix enum values with type name -->
|
||||
<Rule Id="CA1712" Action="Hidden" />
|
||||
|
||||
<!-- Flags enums should have plural names -->
|
||||
<Rule Id="CA1714" Action="Hidden" />
|
||||
|
||||
<!-- Identifiers should have correct prefix -->
|
||||
<Rule Id="CA1715" Action="Hidden" />
|
||||
|
||||
<!-- Identifiers should not match keywords -->
|
||||
<Rule Id="CA1716" Action="Hidden" />
|
||||
|
||||
<!-- Only FlagsAttribute enums should have plural names -->
|
||||
<Rule Id="CA1717" Action="Hidden" />
|
||||
|
||||
<!-- Identifier contains type name -->
|
||||
<Rule Id="CA1720" Action="Hidden" />
|
||||
|
||||
<!-- Property names should not match get methods -->
|
||||
<Rule Id="CA1721" Action="Hidden" />
|
||||
|
||||
<!-- Type names should not match namespaces -->
|
||||
<Rule Id="CA1724" Action="Hidden" />
|
||||
|
||||
<!-- Review unused parameters -->
|
||||
<Rule Id="CA1801" Action="Hidden" />
|
||||
|
||||
<!-- Use literals where appropriate -->
|
||||
<Rule Id="CA1802" Action="Hidden" />
|
||||
|
||||
<!-- Do not ignore method results -->
|
||||
<Rule Id="CA1806" Action="Hidden" />
|
||||
|
||||
<!-- Initialize reference type static fields inline -->
|
||||
<Rule Id="CA1810" Action="Hidden" />
|
||||
|
||||
<!-- Avoid uninstantiated internal classes -->
|
||||
<Rule Id="CA1812" Action="Hidden" />
|
||||
|
||||
<!-- Prefer jagged arrays over multidimensional -->
|
||||
<Rule Id="CA1814" Action="Hidden" />
|
||||
|
||||
<!-- Override equals and operator equals on value types -->
|
||||
<Rule Id="CA1815" Action="Hidden" />
|
||||
|
||||
<!-- Dispose methods should call SuppressFinalize -->
|
||||
<Rule Id="CA1816" Action="Hidden" />
|
||||
|
||||
<!-- Properties should not return arrays -->
|
||||
<Rule Id="CA1819" Action="Hidden" />
|
||||
|
||||
<!-- Test for empty strings using string length -->
|
||||
<Rule Id="CA1820" Action="Hidden" />
|
||||
|
||||
<!-- Mark members as static -->
|
||||
<Rule Id="CA1822" Action="Hidden" />
|
||||
|
||||
<!-- Avoid unused private fields -->
|
||||
<Rule Id="CA1823" Action="Hidden" />
|
||||
|
||||
<!-- Avoid zero-length array allocations. -->
|
||||
<Rule Id="CA1825" Action="Hidden" />
|
||||
|
||||
<!-- Do not use Count() or LongCount() when Any() can be used -->
|
||||
<Rule Id="CA1827" Action="Hidden" />
|
||||
|
||||
<!-- Use Length/Count property instead of Count() when available -->
|
||||
<Rule Id="CA1829" Action="Hidden" />
|
||||
|
||||
<!-- Dispose objects before losing scope -->
|
||||
<Rule Id="CA2000" Action="Hidden" />
|
||||
|
||||
<!-- Do not lock on objects with weak identity -->
|
||||
<Rule Id="CA2002" Action="Hidden" />
|
||||
|
||||
<!-- Review SQL queries for security vulnerabilities -->
|
||||
<Rule Id="CA2100" Action="Hidden" />
|
||||
|
||||
<!-- Specify marshaling for P/Invoke string arguments -->
|
||||
<Rule Id="CA2101" Action="Hidden" />
|
||||
|
||||
<!-- Instantiate argument exceptions correctly -->
|
||||
<Rule Id="CA2208" Action="Hidden" />
|
||||
|
||||
<!-- Non-constant fields should not be visible -->
|
||||
<Rule Id="CA2211" Action="Hidden" />
|
||||
|
||||
<!-- Disposable fields should be disposed -->
|
||||
<Rule Id="CA2213" Action="Hidden" />
|
||||
|
||||
<!-- Do not call overridable methods in constructors -->
|
||||
<Rule Id="CA2214" Action="Hidden" />
|
||||
|
||||
<!-- Disposable types should declare finalizer -->
|
||||
<Rule Id="CA2216" Action="Hidden" />
|
||||
|
||||
<!-- Operator overloads have named alternates -->
|
||||
<Rule Id="CA2225" Action="Hidden" />
|
||||
|
||||
<!-- Collection properties should be read only -->
|
||||
<Rule Id="CA2227" Action="Hidden" />
|
||||
|
||||
<!-- Implement serialization constructors -->
|
||||
<Rule Id="CA2229" Action="Hidden" />
|
||||
|
||||
<!-- Mark ISerializable types with serializable -->
|
||||
<Rule Id="CA2237" Action="Hidden" />
|
||||
|
||||
<!-- Provide correct arguments to formatting methods -->
|
||||
<Rule Id="CA2241" Action="Hidden" />
|
||||
|
||||
<!-- Attribute string literals should parse correctly -->
|
||||
<Rule Id="CA2243" Action="Hidden" />
|
||||
|
||||
<!-- Insecure DTD processing in XML -->
|
||||
<Rule Id="CA3075" Action="Hidden" />
|
||||
|
||||
<!-- Do Not Use Weak Cryptographic Algorithms -->
|
||||
<Rule Id="CA5350" Action="Hidden" />
|
||||
|
||||
<!-- Do Not Use Broken Cryptographic Algorithms -->
|
||||
<Rule Id="CA5351" Action="Hidden" />
|
||||
</Rules>
|
||||
|
||||
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.SpecialRules">
|
||||
<!-- XML comment analysis disabled -->
|
||||
<Rule Id="SA0001" Action="Hidden" />
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Include="$(SolutionDir).stylecop.json" />
|
||||
<Analyzer Include="$(SolutionDir)packages/StyleCop.Analyzers.Unstable.1.2.0.113/analyzers/dotnet/cs/*.dll" /><!-- already restored by first transitive dep (BizHawk.Common) -->
|
||||
<Analyzer Include="$(SolutionDir)packages/StyleCop.Analyzers.Unstable.1.2.0.164/analyzers/dotnet/cs/*.dll" /><!-- already restored by first transitive dep (BizHawk.Common) -->
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29709.97
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GBHawk", "GBHawk\GBHawk.vcxproj", "{FA59603F-32AB-429A-9186-B46114851290}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{FA59603F-32AB-429A-9186-B46114851290}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{FA59603F-32AB-429A-9186-B46114851290}.Debug|x64.Build.0 = Debug|x64
|
||||
{FA59603F-32AB-429A-9186-B46114851290}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{FA59603F-32AB-429A-9186-B46114851290}.Debug|x86.Build.0 = Debug|Win32
|
||||
{FA59603F-32AB-429A-9186-B46114851290}.Release|x64.ActiveCfg = Release|x64
|
||||
{FA59603F-32AB-429A-9186-B46114851290}.Release|x64.Build.0 = Release|x64
|
||||
{FA59603F-32AB-429A-9186-B46114851290}.Release|x86.ActiveCfg = Release|Win32
|
||||
{FA59603F-32AB-429A-9186-B46114851290}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {ED770D9B-8735-46CA-B51E-F85B00A9C744}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,191 @@
|
|||
#include <iostream>
|
||||
#include <cstdint>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
|
||||
#include "LR35902.h"
|
||||
#include "GBAudio.h"
|
||||
#include "TMS9918A.h"
|
||||
#include "Memory.h"
|
||||
|
||||
namespace GBHawk
|
||||
{
|
||||
class GBCore
|
||||
{
|
||||
public:
|
||||
GBCore()
|
||||
{
|
||||
MemMap.cpu_pntr = &cpu;
|
||||
MemMap.vdp_pntr = &vdp;
|
||||
MemMap.psg_pntr = &psg;
|
||||
cpu.mem_ctrl = &MemMap;
|
||||
vdp.IRQ_PTR = &cpu.FlagI;
|
||||
vdp.SHOW_BG = vdp.SHOW_SPRITES = true;
|
||||
sl_case = 0;
|
||||
};
|
||||
|
||||
TMS9918A vdp;
|
||||
LR35902 cpu;
|
||||
GBAudio psg;
|
||||
MemoryManager MemMap;
|
||||
|
||||
uint8_t sl_case = 0;
|
||||
|
||||
void Load_BIOS(uint8_t* bios, uint8_t* basic)
|
||||
{
|
||||
MemMap.Load_BIOS(bios, basic);
|
||||
}
|
||||
|
||||
void Load_ROM(uint8_t* ext_rom_1, uint32_t ext_rom_size_1, uint32_t ext_rom_mapper_1, uint8_t* ext_rom_2, uint32_t ext_rom_size_2, uint32_t ext_rom_mapper_2)
|
||||
{
|
||||
MemMap.Load_ROM(ext_rom_1, ext_rom_size_1, ext_rom_mapper_1, ext_rom_2, ext_rom_size_2, ext_rom_mapper_2);
|
||||
}
|
||||
|
||||
bool FrameAdvance(uint8_t controller_1, uint8_t controller_2, uint8_t* kb_rows_ptr, bool render, bool rendersound)
|
||||
{
|
||||
|
||||
MemMap.controller_byte_1 = controller_1;
|
||||
MemMap.controller_byte_2 = controller_2;
|
||||
MemMap.kb_rows = kb_rows_ptr;
|
||||
MemMap.start_pressed = (controller_1 & 0x80) > 0;
|
||||
MemMap.lagged = true;
|
||||
|
||||
uint32_t scanlinesPerFrame = 262;
|
||||
vdp.SpriteLimit = true;
|
||||
|
||||
return MemMap.lagged;
|
||||
}
|
||||
|
||||
void GetVideo(uint32_t* dest)
|
||||
{
|
||||
uint32_t* src = vdp.FrameBuffer;
|
||||
uint32_t* dst = dest;
|
||||
|
||||
std::memcpy(dst, src, sizeof uint32_t * 256 * 192);
|
||||
}
|
||||
|
||||
uint32_t GetAudio(int32_t* dest_L, int32_t* n_samp_L, int32_t* dest_R, int32_t* n_samp_R)
|
||||
{
|
||||
int32_t* src = psg.samples_L;
|
||||
int32_t* dst = dest_L;
|
||||
|
||||
std::memcpy(dst, src, sizeof int32_t * psg.num_samples_L * 2);
|
||||
n_samp_L[0] = psg.num_samples_L;
|
||||
|
||||
src = psg.samples_R;
|
||||
dst = dest_R;
|
||||
|
||||
std::memcpy(dst, src, sizeof int32_t * psg.num_samples_R * 2);
|
||||
n_samp_R[0] = psg.num_samples_R;
|
||||
|
||||
return psg.master_audio_clock;
|
||||
}
|
||||
|
||||
#pragma region State Save / Load
|
||||
|
||||
void SaveState(uint8_t* saver)
|
||||
{
|
||||
saver = vdp.SaveState(saver);
|
||||
saver = cpu.SaveState(saver);
|
||||
saver = psg.SaveState(saver);
|
||||
saver = MemMap.SaveState(saver);
|
||||
|
||||
*saver = sl_case; saver++;
|
||||
}
|
||||
|
||||
void LoadState(uint8_t* loader)
|
||||
{
|
||||
loader = vdp.LoadState(loader);
|
||||
loader = cpu.LoadState(loader);
|
||||
loader = psg.LoadState(loader);
|
||||
loader = MemMap.LoadState(loader);
|
||||
|
||||
sl_case = *loader; loader++;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Memory Domain Functions
|
||||
|
||||
uint8_t GetSysBus(uint32_t addr)
|
||||
{
|
||||
return cpu.PeekMemory(addr);
|
||||
}
|
||||
|
||||
uint8_t GetVRAM(uint32_t addr)
|
||||
{
|
||||
return vdp.VRAM[addr & 0x3FFF];
|
||||
}
|
||||
|
||||
uint8_t GetRAM(uint32_t addr)
|
||||
{
|
||||
return MemMap.ram[addr & 0xFFFF];
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Tracer
|
||||
|
||||
void SetTraceCallback(void (*callback)(int))
|
||||
{
|
||||
cpu.TraceCallback = callback;
|
||||
}
|
||||
|
||||
int GetHeaderLength()
|
||||
{
|
||||
return 105 + 1;
|
||||
}
|
||||
|
||||
int GetDisasmLength()
|
||||
{
|
||||
return 48 + 1;
|
||||
}
|
||||
|
||||
int GetRegStringLength()
|
||||
{
|
||||
return 86 + 1;
|
||||
}
|
||||
|
||||
void GetHeader(char* h, int l)
|
||||
{
|
||||
memcpy(h, cpu.TraceHeader, l);
|
||||
}
|
||||
|
||||
// the copy length l must be supplied ahead of time from GetRegStrngLength
|
||||
void GetRegisterState(char* r, int t, int l)
|
||||
{
|
||||
if (t == 0)
|
||||
{
|
||||
memcpy(r, cpu.CPURegisterState().c_str(), l);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(r, cpu.No_Reg, l);
|
||||
}
|
||||
}
|
||||
|
||||
// the copy length l must be supplied ahead of time from GetDisasmLength
|
||||
void GetDisassembly(char* d, int t, int l)
|
||||
{
|
||||
if (t == 0)
|
||||
{
|
||||
memcpy(d, cpu.CPUDisassembly().c_str(), l);
|
||||
}
|
||||
else if (t == 1)
|
||||
{
|
||||
memcpy(d, cpu.Un_halt_event, l);
|
||||
}
|
||||
else if (t == 2)
|
||||
{
|
||||
memcpy(d, cpu.IRQ_event, l);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(d, cpu.Un_halt_event, l);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
};
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,131 @@
|
|||
// GBHawk.cpp : Defines the exported functions for the DLL.
|
||||
//
|
||||
|
||||
#include "GBHawk.h"
|
||||
#include "Core.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdint>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
|
||||
using namespace GBHawk;
|
||||
|
||||
#pragma region Core
|
||||
// Create pointer to a core instance
|
||||
GBHawk_EXPORT GBCore* GB_create()
|
||||
{
|
||||
return new GBCore();
|
||||
}
|
||||
|
||||
// free the memory from the core pointer
|
||||
GBHawk_EXPORT void GB_destroy(GBCore* p)
|
||||
{
|
||||
delete p->MemMap.bios_rom;
|
||||
delete p->MemMap.basic_rom;
|
||||
delete p->MemMap.rom_1;
|
||||
delete p->MemMap.rom_2;
|
||||
std::free(p);
|
||||
}
|
||||
|
||||
// load bios and basic into the core
|
||||
GBHawk_EXPORT void GB_load_bios(GBCore* p, uint8_t* bios, uint8_t* basic)
|
||||
{
|
||||
p->Load_BIOS(bios, basic);
|
||||
}
|
||||
|
||||
// load a rom into the core
|
||||
GBHawk_EXPORT void GB_load(GBCore* p, uint8_t* rom_1, uint32_t size_1, uint32_t mapper_1, uint8_t* rom_2, uint32_t size_2, uint8_t mapper_2)
|
||||
{
|
||||
p->Load_ROM(rom_1, size_1, mapper_1, rom_2, size_2, mapper_2);
|
||||
}
|
||||
|
||||
// advance a frame
|
||||
GBHawk_EXPORT bool GB_frame_advance(GBCore* p, uint8_t ctrl1, uint8_t ctrl2, uint8_t* kbrows, bool render, bool sound)
|
||||
{
|
||||
return p->FrameAdvance(ctrl1, ctrl2, kbrows, render, sound);
|
||||
}
|
||||
|
||||
// send video data to external video provider
|
||||
GBHawk_EXPORT void GB_get_video(GBCore* p, uint32_t* dest)
|
||||
{
|
||||
p->GetVideo(dest);
|
||||
}
|
||||
|
||||
// send audio data to external audio provider
|
||||
GBHawk_EXPORT uint32_t GB_get_audio(GBCore* p, int32_t* dest_L, int32_t* n_samp_L, int32_t* dest_R, int32_t* n_samp_R)
|
||||
{
|
||||
return p->GetAudio(dest_L, n_samp_L, dest_R, n_samp_R);
|
||||
}
|
||||
|
||||
#pragma region State Save / Load
|
||||
|
||||
// save state
|
||||
GBHawk_EXPORT void GB_save_state(GBCore* p, uint8_t* saver)
|
||||
{
|
||||
p->SaveState(saver);
|
||||
}
|
||||
|
||||
// load state
|
||||
GBHawk_EXPORT void GB_load_state(GBCore* p, uint8_t* loader)
|
||||
{
|
||||
p->LoadState(loader);
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Memory Domain Functions
|
||||
|
||||
GBHawk_EXPORT uint8_t GB_getsysbus(GBCore* p, uint32_t addr) {
|
||||
return p->GetSysBus(addr);
|
||||
}
|
||||
|
||||
GBHawk_EXPORT uint8_t GB_getvram(GBCore* p, uint32_t addr) {
|
||||
return p->GetVRAM(addr);
|
||||
}
|
||||
|
||||
GBHawk_EXPORT uint8_t GB_getram(GBCore* p, uint32_t addr) {
|
||||
return p->GetRAM(addr);
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
|
||||
#pragma region Tracer
|
||||
|
||||
// set tracer callback
|
||||
GBHawk_EXPORT void GB_settracecallback(GBCore* p, void (*callback)(int)) {
|
||||
p->SetTraceCallback(callback);
|
||||
}
|
||||
|
||||
// return the cpu trace header length
|
||||
GBHawk_EXPORT int GB_getheaderlength(GBCore* p) {
|
||||
return p->GetHeaderLength();
|
||||
}
|
||||
|
||||
// return the cpu disassembly length
|
||||
GBHawk_EXPORT int GB_getdisasmlength(GBCore* p) {
|
||||
return p->GetDisasmLength();
|
||||
}
|
||||
|
||||
// return the cpu register string length
|
||||
GBHawk_EXPORT int GB_getregstringlength(GBCore* p) {
|
||||
return p->GetRegStringLength();
|
||||
}
|
||||
|
||||
// return the cpu trace header
|
||||
GBHawk_EXPORT void GB_getheader(GBCore* p, char* h, int l) {
|
||||
p->GetHeader(h, l);
|
||||
}
|
||||
|
||||
// return the cpu register state
|
||||
GBHawk_EXPORT void GB_getregisterstate(GBCore* p, char* r, int t, int l) {
|
||||
p->GetRegisterState(r, t, l);
|
||||
}
|
||||
|
||||
// return the cpu disassembly
|
||||
GBHawk_EXPORT void GB_getdisassembly(GBCore* p, char* d, int t, int l) {
|
||||
p->GetDisassembly(d, t, l);
|
||||
}
|
||||
|
||||
#pragma endregion
|
|
@ -0,0 +1,5 @@
|
|||
#ifdef _WIN32
|
||||
#define GBHawk_EXPORT extern "C" __declspec(dllexport)
|
||||
#elif __linux__
|
||||
#define GBHawk_EXPORT extern "C"
|
||||
#endif
|
|
@ -0,0 +1,172 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<ProjectGuid>{FA59603F-32AB-429A-9186-B46114851290}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>GBHawk</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;GBHAWK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;GBHAWK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;GBHAWK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;GBHAWK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="GBAudio.h" />
|
||||
<ClInclude Include="Core.h" />
|
||||
<ClInclude Include="GBHawk.h" />
|
||||
<ClInclude Include="Memory.h" />
|
||||
<ClInclude Include="TMS9918A.h" />
|
||||
<ClInclude Include="LR35902.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="GBHawk.cpp" />
|
||||
<ClCompile Include="Memory.cpp" />
|
||||
<ClCompile Include="LR35902.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="cpp.hint" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -0,0 +1,31 @@
|
|||
#include <cstdint>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
|
||||
#include "Memory.h"
|
||||
#include "LR35902.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace GBHawk
|
||||
{
|
||||
void LR35902::WriteMemory(uint32_t addr, uint8_t value)
|
||||
{
|
||||
mem_ctrl->MemoryWrite(addr, value);
|
||||
}
|
||||
|
||||
uint8_t LR35902::ReadMemory(uint32_t addr)
|
||||
{
|
||||
return mem_ctrl->HardwareRead(addr);
|
||||
}
|
||||
|
||||
uint8_t LR35902::PeekMemory(uint32_t addr)
|
||||
{
|
||||
return mem_ctrl->HardwareRead(addr);
|
||||
}
|
||||
|
||||
uint8_t LR35902::SpeedFunc(uint32_t addr)
|
||||
{
|
||||
return mem_ctrl->HardwareRead(addr);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,25 @@
|
|||
#include <iostream>
|
||||
#include <cstdint>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
|
||||
#include "Memory.h"
|
||||
#include "LR35902.h"
|
||||
#include "TMS9918A.h"
|
||||
#include "GBAudio.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace GBHawk
|
||||
{
|
||||
uint8_t MemoryManager::HardwareRead(uint32_t port)
|
||||
{
|
||||
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
void MemoryManager::HardwareWrite(uint32_t port, uint8_t value)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
#include <iostream>
|
||||
#include <cstdint>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace GBHawk
|
||||
{
|
||||
class LR35902;
|
||||
class TMS9918A;
|
||||
class GBAudio;
|
||||
|
||||
class MemoryManager
|
||||
{
|
||||
public:
|
||||
|
||||
TMS9918A* vdp_pntr = nullptr;
|
||||
GBAudio* psg_pntr = nullptr;
|
||||
LR35902* cpu_pntr = nullptr;
|
||||
uint8_t* rom_1 = nullptr;
|
||||
uint8_t* rom_2 = nullptr;
|
||||
uint8_t* bios_rom = nullptr;
|
||||
uint8_t* basic_rom = nullptr;
|
||||
|
||||
// initialized by core loading, not savestated
|
||||
uint32_t rom_size_1;
|
||||
uint32_t rom_mapper_1;
|
||||
uint32_t rom_size_2;
|
||||
uint32_t rom_mapper_2;
|
||||
|
||||
// controls are not stated
|
||||
uint8_t controller_byte_1, controller_byte_2;
|
||||
uint8_t* kb_rows;
|
||||
|
||||
// State
|
||||
bool PortDEEnabled = false;
|
||||
bool lagged;
|
||||
bool start_pressed;
|
||||
|
||||
uint8_t kb_rows_sel;
|
||||
uint8_t PortA8 = 0x00;
|
||||
uint8_t reg_FFFC, reg_FFFD, reg_FFFE, reg_FFFF;
|
||||
uint8_t ram[0x10000] = {};
|
||||
uint8_t cart_ram[0x8000] = {};
|
||||
uint8_t unmapped[0x400] = {};
|
||||
|
||||
MemoryManager()
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
uint8_t HardwareRead(uint32_t value);
|
||||
|
||||
void HardwareWrite(uint32_t addr, uint8_t value);
|
||||
|
||||
// NOTE: only called from source when both are available and of correct size (0x4000)
|
||||
void Load_BIOS(uint8_t* bios, uint8_t* basic)
|
||||
{
|
||||
bios_rom = new uint8_t[0x4000];
|
||||
basic_rom = new uint8_t[0x4000];
|
||||
|
||||
memcpy(bios_rom, bios, 0x4000);
|
||||
memcpy(basic_rom, basic, 0x4000);
|
||||
}
|
||||
|
||||
void Load_ROM(uint8_t* ext_rom_1, uint32_t ext_rom_size_1, uint32_t ext_rom_mapper_1, uint8_t* ext_rom_2, uint32_t ext_rom_size_2, uint32_t ext_rom_mapper_2)
|
||||
{
|
||||
rom_1 = new uint8_t[ext_rom_size_1];
|
||||
rom_2 = new uint8_t[ext_rom_size_2];
|
||||
|
||||
memcpy(rom_1, ext_rom_1, ext_rom_size_1);
|
||||
memcpy(rom_2, ext_rom_2, ext_rom_size_2);
|
||||
|
||||
rom_size_1 = ext_rom_size_1 / 0x4000;
|
||||
rom_mapper_1 = ext_rom_mapper_1;
|
||||
|
||||
rom_size_2 = ext_rom_size_2 / 0x4000;
|
||||
rom_mapper_2 = ext_rom_mapper_2;
|
||||
|
||||
// default memory map setup
|
||||
PortA8 = 0;
|
||||
}
|
||||
|
||||
void MemoryWrite(uint32_t addr, uint8_t value)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#pragma region State Save / Load
|
||||
|
||||
uint8_t* SaveState(uint8_t* saver)
|
||||
{
|
||||
*saver = (uint8_t)(PortDEEnabled ? 1 : 0); saver++;
|
||||
*saver = (uint8_t)(lagged ? 1 : 0); saver++;
|
||||
*saver = (uint8_t)(start_pressed ? 1 : 0); saver++;
|
||||
|
||||
*saver = kb_rows_sel; saver++;
|
||||
*saver = PortA8; saver++;
|
||||
*saver = reg_FFFC; saver++;
|
||||
*saver = reg_FFFD; saver++;
|
||||
*saver = reg_FFFE; saver++;
|
||||
*saver = reg_FFFF; saver++;
|
||||
|
||||
std::memcpy(saver, &ram, 0x10000); saver += 0x10000;
|
||||
std::memcpy(saver, &cart_ram, 0x8000); saver += 0x8000;
|
||||
|
||||
return saver;
|
||||
}
|
||||
|
||||
uint8_t* LoadState(uint8_t* loader)
|
||||
{
|
||||
PortDEEnabled = *loader == 1; loader++;
|
||||
lagged = *loader == 1; loader++;
|
||||
start_pressed = *loader == 1; loader++;
|
||||
|
||||
kb_rows_sel = *loader; loader++;
|
||||
PortA8 = *loader; loader++;
|
||||
reg_FFFC = *loader; loader++;
|
||||
reg_FFFD = *loader; loader++;
|
||||
reg_FFFE = *loader; loader++;
|
||||
reg_FFFF = *loader; loader++;
|
||||
|
||||
std::memcpy(&ram, loader, 0x10000); loader += 0x10000;
|
||||
std::memcpy(&cart_ram, loader, 0x8000); loader += 0x8000;
|
||||
|
||||
return loader;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
};
|
||||
}
|
|
@ -0,0 +1,610 @@
|
|||
#include <iostream>
|
||||
#include <cstdint>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace GBHawk
|
||||
{
|
||||
class TMS9918A
|
||||
{
|
||||
public:
|
||||
#pragma region VDP
|
||||
|
||||
TMS9918A()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool* IRQ_PTR = nullptr;
|
||||
|
||||
// external flags to display background or sprites
|
||||
bool SHOW_BG, SHOW_SPRITES;
|
||||
bool SpriteLimit;
|
||||
|
||||
// VDP State
|
||||
bool VdpWaitingForLatchInt = true;
|
||||
bool VdpWaitingForLatchByte = true;
|
||||
bool VIntPending;
|
||||
bool HIntPending;
|
||||
|
||||
uint8_t StatusByte;
|
||||
uint8_t VdpLatch;
|
||||
uint8_t VdpBuffer;
|
||||
uint8_t TmsMode;
|
||||
uint8_t Registers[8] = {};
|
||||
uint8_t VRAM[0x4000]; //16kb video RAM
|
||||
|
||||
int32_t ScanLine;
|
||||
uint32_t VdpAddress;
|
||||
uint32_t ColorTableBase;
|
||||
uint32_t PatternGeneratorBase;
|
||||
uint32_t SpritePatternGeneratorBase;
|
||||
uint32_t TmsPatternNameTableBase;
|
||||
uint32_t TmsSpriteAttributeBase;
|
||||
|
||||
uint32_t FrameBuffer[192 * 256] = {};
|
||||
uint8_t ScanlinePriorityBuffer[256] = {};
|
||||
uint8_t SpriteCollisionBuffer[256] = {};
|
||||
|
||||
// constants after load, not stated
|
||||
uint32_t BackgroundColor = 0;
|
||||
uint32_t IPeriod = 228;
|
||||
|
||||
// temporary variables not stated if on frame boundary
|
||||
bool is_top;
|
||||
uint32_t yc;
|
||||
uint32_t yofs;
|
||||
uint32_t FrameBufferOffset;
|
||||
uint32_t PatternNameOffset;
|
||||
uint32_t ScreenBGColor;
|
||||
uint32_t yrow;
|
||||
uint32_t PatternGeneratorOffset;
|
||||
uint32_t ColorOffset;
|
||||
uint32_t pn;
|
||||
uint32_t pv;
|
||||
uint32_t colorEntry;
|
||||
uint32_t fgIndex;
|
||||
uint32_t bgIndex;
|
||||
uint32_t fgColor;
|
||||
uint32_t bgColor;
|
||||
uint32_t lColorIndex;
|
||||
uint32_t rColorIndex;
|
||||
uint32_t lColor;
|
||||
uint32_t rColor;
|
||||
|
||||
uint32_t PaletteTMS9918[16] =
|
||||
{
|
||||
0xFF000000,
|
||||
0xFF000000,
|
||||
0xFF47B73B,
|
||||
0xFF7CCF6F,
|
||||
0xFF5D4EFF,
|
||||
0xFF8072FF,
|
||||
0xFFB66247,
|
||||
0xFF5DC8ED,
|
||||
0xFFD76B48,
|
||||
0xFFFB8F6C,
|
||||
0xFFC3CD41,
|
||||
0xFFD3DA76,
|
||||
0xFF3E9F2F,
|
||||
0xFFB664C7,
|
||||
0xFFCCCCCC,
|
||||
0xFFFFFFFF
|
||||
};
|
||||
|
||||
bool Mode1Bit() { return (Registers[1] & 16) > 0; }
|
||||
bool Mode2Bit() { return (Registers[0] & 2) > 0; }
|
||||
bool Mode3Bit() { return (Registers[1] & 8) > 0; }
|
||||
bool EnableDoubledSprites() { return (Registers[1] & 1) > 0; }
|
||||
bool EnableLargeSprites() { return (Registers[1] & 2) > 0; }
|
||||
bool EnableInterrupts() { return (Registers[1] & 32) > 0; }
|
||||
bool DisplayOn() { return (Registers[1] & 64) > 0; }
|
||||
bool Mode16k() { return (Registers[1] & 128) > 0; }
|
||||
|
||||
bool InterruptPendingGet() { return (StatusByte & 0x80) != 0; }
|
||||
void InterruptPendingSet(bool value) { StatusByte = (uint8_t)((StatusByte & ~0x02) | (value ? 0x80 : 0x00)); }
|
||||
|
||||
void WriteVdpControl(uint8_t value)
|
||||
{
|
||||
if (VdpWaitingForLatchByte)
|
||||
{
|
||||
VdpLatch = value;
|
||||
VdpWaitingForLatchByte = false;
|
||||
VdpAddress = (uint32_t)((VdpAddress & 0x3F00) | value);
|
||||
return;
|
||||
}
|
||||
|
||||
VdpWaitingForLatchByte = true;
|
||||
VdpAddress = (uint32_t)(((value & 63) << 8) | VdpLatch);
|
||||
VdpAddress &= 0x3FFF;
|
||||
switch (value & 0xC0)
|
||||
{
|
||||
case 0x00: // read VRAM
|
||||
VdpBuffer = VRAM[VdpAddress];
|
||||
VdpAddress++;
|
||||
VdpAddress &= 0x3FFF;
|
||||
break;
|
||||
case 0x40: // write VRAM
|
||||
break;
|
||||
case 0x80: // VDP register write
|
||||
WriteRegister(value & 0x0F, VdpLatch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void WriteVdpData(uint8_t value)
|
||||
{
|
||||
VdpWaitingForLatchByte = true;
|
||||
VdpBuffer = value;
|
||||
|
||||
VRAM[VdpAddress] = value;
|
||||
//if (!Mode16k)
|
||||
// Console.WriteLine("VRAM written while not in 16k addressing mode!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
||||
VdpAddress++;
|
||||
VdpAddress &= 0x3FFF;
|
||||
}
|
||||
|
||||
void WriteRegister(uint32_t reg, uint8_t data)
|
||||
{
|
||||
if (reg >= 8) return;
|
||||
|
||||
Registers[reg] = data;
|
||||
switch (reg)
|
||||
{
|
||||
case 0: // Mode Control Register 1
|
||||
CheckVideoMode();
|
||||
break;
|
||||
case 1: // Mode Control Register 2
|
||||
CheckVideoMode();
|
||||
IRQ_PTR[0] = (EnableInterrupts() && InterruptPendingGet());
|
||||
break;
|
||||
case 2: // Name Table Base Address
|
||||
TmsPatternNameTableBase = (Registers[2] << 10) & 0x3C00;
|
||||
break;
|
||||
case 3: // Color Table Base Address
|
||||
ColorTableBase = (Registers[3] << 6) & 0x3FC0;
|
||||
break;
|
||||
case 4: // Pattern Generator Base Address
|
||||
PatternGeneratorBase = (Registers[4] << 11) & 0x3800;
|
||||
break;
|
||||
case 5: // Sprite Attribute Table Base Address
|
||||
TmsSpriteAttributeBase = (Registers[5] << 7) & 0x3F80;
|
||||
break;
|
||||
case 6: // Sprite Pattern Generator Base Adderss
|
||||
SpritePatternGeneratorBase = (Registers[6] << 11) & 0x3800;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t ReadVdpStatus()
|
||||
{
|
||||
VdpWaitingForLatchByte = true;
|
||||
uint8_t returnValue = StatusByte;
|
||||
StatusByte &= 0x1F;
|
||||
IRQ_PTR[0] = false;
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
uint8_t ReadData()
|
||||
{
|
||||
VdpWaitingForLatchByte = true;
|
||||
uint8_t value = VdpBuffer;
|
||||
VdpBuffer = VRAM[VdpAddress];
|
||||
VdpAddress++;
|
||||
VdpAddress &= 0x3FFF;
|
||||
return value;
|
||||
}
|
||||
|
||||
void CheckVideoMode()
|
||||
{
|
||||
if (Mode1Bit()) TmsMode = 1;
|
||||
else if (Mode2Bit()) TmsMode = 2;
|
||||
else if (Mode3Bit()) TmsMode = 3;
|
||||
else TmsMode = 0;
|
||||
}
|
||||
|
||||
void RenderScanline(int32_t scanLine)
|
||||
{
|
||||
if (scanLine >= 192)
|
||||
return;
|
||||
|
||||
if (TmsMode == 2)
|
||||
{
|
||||
RenderBackgroundM2(scanLine);
|
||||
RenderTmsSprites(scanLine);
|
||||
}
|
||||
else if (TmsMode == 0)
|
||||
{
|
||||
RenderBackgroundM0(scanLine);
|
||||
RenderTmsSprites(scanLine);
|
||||
}
|
||||
else if (TmsMode == 3)
|
||||
{
|
||||
RenderBackgroundM3(scanLine);
|
||||
RenderTmsSprites(scanLine);
|
||||
}
|
||||
else if (TmsMode == 1)
|
||||
{
|
||||
RenderBackgroundM1(scanLine);
|
||||
// no sprites (text mode)
|
||||
}
|
||||
}
|
||||
|
||||
void RenderBackgroundM0(uint32_t scanLine)
|
||||
{
|
||||
if (DisplayOn() == false)
|
||||
{
|
||||
for (int i = 0; i < 256; i++) { FrameBuffer[scanLine * 256 + i] = 0; };
|
||||
return;
|
||||
}
|
||||
|
||||
yc = scanLine / 8;
|
||||
yofs = scanLine % 8;
|
||||
FrameBufferOffset = scanLine * 256;
|
||||
PatternNameOffset = TmsPatternNameTableBase + (yc * 32);
|
||||
ScreenBGColor = PaletteTMS9918[Registers[7] & 0x0F];
|
||||
|
||||
for (uint32_t xc = 0; xc < 32; xc++)
|
||||
{
|
||||
pn = VRAM[PatternNameOffset++];
|
||||
pv = VRAM[PatternGeneratorBase + (pn * 8) + yofs];
|
||||
colorEntry = VRAM[ColorTableBase + (pn / 8)];
|
||||
fgIndex = (colorEntry >> 4) & 0x0F;
|
||||
bgIndex = colorEntry & 0x0F;
|
||||
fgColor = fgIndex == 0 ? ScreenBGColor : PaletteTMS9918[fgIndex];
|
||||
bgColor = bgIndex == 0 ? ScreenBGColor : PaletteTMS9918[bgIndex];
|
||||
|
||||
FrameBuffer[FrameBufferOffset++] = ((pv & 0x80) > 0) ? fgColor : bgColor;
|
||||
FrameBuffer[FrameBufferOffset++] = ((pv & 0x40) > 0) ? fgColor : bgColor;
|
||||
FrameBuffer[FrameBufferOffset++] = ((pv & 0x20) > 0) ? fgColor : bgColor;
|
||||
FrameBuffer[FrameBufferOffset++] = ((pv & 0x10) > 0) ? fgColor : bgColor;
|
||||
FrameBuffer[FrameBufferOffset++] = ((pv & 0x08) > 0) ? fgColor : bgColor;
|
||||
FrameBuffer[FrameBufferOffset++] = ((pv & 0x04) > 0) ? fgColor : bgColor;
|
||||
FrameBuffer[FrameBufferOffset++] = ((pv & 0x02) > 0) ? fgColor : bgColor;
|
||||
FrameBuffer[FrameBufferOffset++] = ((pv & 0x01) > 0) ? fgColor : bgColor;
|
||||
}
|
||||
}
|
||||
|
||||
void RenderBackgroundM1(uint32_t scanLine)
|
||||
{
|
||||
if (DisplayOn() == false)
|
||||
{
|
||||
for (int i = 0; i < 256; i++) { FrameBuffer[scanLine * 256 + i] = 0; };
|
||||
return;
|
||||
}
|
||||
|
||||
yc = scanLine / 8;
|
||||
yofs = scanLine % 8;
|
||||
FrameBufferOffset = scanLine * 256;
|
||||
PatternNameOffset = TmsPatternNameTableBase + (yc * 40);
|
||||
ScreenBGColor = PaletteTMS9918[Registers[7] & 0x0F];
|
||||
|
||||
for (uint32_t xc = 0; xc < 40; xc++)
|
||||
{
|
||||
pn = VRAM[PatternNameOffset++];
|
||||
pv = VRAM[PatternGeneratorBase + (pn * 8) + yofs];
|
||||
colorEntry = Registers[7];
|
||||
fgIndex = (colorEntry >> 4) & 0x0F;
|
||||
bgIndex = colorEntry & 0x0F;
|
||||
fgColor = fgIndex == 0 ? ScreenBGColor : PaletteTMS9918[fgIndex];
|
||||
bgColor = bgIndex == 0 ? ScreenBGColor : PaletteTMS9918[bgIndex];
|
||||
|
||||
FrameBuffer[FrameBufferOffset++] = ((pv & 0x80) > 0) ? fgColor : bgColor;
|
||||
FrameBuffer[FrameBufferOffset++] = ((pv & 0x40) > 0) ? fgColor : bgColor;
|
||||
FrameBuffer[FrameBufferOffset++] = ((pv & 0x20) > 0) ? fgColor : bgColor;
|
||||
FrameBuffer[FrameBufferOffset++] = ((pv & 0x10) > 0) ? fgColor : bgColor;
|
||||
FrameBuffer[FrameBufferOffset++] = ((pv & 0x08) > 0) ? fgColor : bgColor;
|
||||
FrameBuffer[FrameBufferOffset++] = ((pv & 0x04) > 0) ? fgColor : bgColor;
|
||||
}
|
||||
}
|
||||
|
||||
void RenderBackgroundM2(uint32_t scanLine)
|
||||
{
|
||||
if (DisplayOn() == false)
|
||||
{
|
||||
for (int i = 0; i < 256; i++) { FrameBuffer[scanLine * 256 + i] = 0; };
|
||||
return;
|
||||
}
|
||||
|
||||
yrow = scanLine / 8;
|
||||
yofs = scanLine % 8;
|
||||
FrameBufferOffset = scanLine * 256;
|
||||
PatternNameOffset = TmsPatternNameTableBase + (yrow * 32);
|
||||
PatternGeneratorOffset = (((Registers[4] & 4) << 11) & 0x2000);
|
||||
ColorOffset = (ColorTableBase & 0x2000);
|
||||
ScreenBGColor = PaletteTMS9918[Registers[7] & 0x0F];
|
||||
|
||||
for (uint32_t xc = 0; xc < 32; xc++)
|
||||
{
|
||||
pn = VRAM[PatternNameOffset++] + ((yrow / 8) * 0x100);
|
||||
pv = VRAM[PatternGeneratorOffset + (pn * 8) + yofs];
|
||||
colorEntry = VRAM[ColorOffset + (pn * 8) + yofs];
|
||||
fgIndex = (colorEntry >> 4) & 0x0F;
|
||||
bgIndex = colorEntry & 0x0F;
|
||||
fgColor = fgIndex == 0 ? ScreenBGColor : PaletteTMS9918[fgIndex];
|
||||
bgColor = bgIndex == 0 ? ScreenBGColor : PaletteTMS9918[bgIndex];
|
||||
|
||||
FrameBuffer[FrameBufferOffset++] = ((pv & 0x80) > 0) ? fgColor : bgColor;
|
||||
FrameBuffer[FrameBufferOffset++] = ((pv & 0x40) > 0) ? fgColor : bgColor;
|
||||
FrameBuffer[FrameBufferOffset++] = ((pv & 0x20) > 0) ? fgColor : bgColor;
|
||||
FrameBuffer[FrameBufferOffset++] = ((pv & 0x10) > 0) ? fgColor : bgColor;
|
||||
FrameBuffer[FrameBufferOffset++] = ((pv & 0x08) > 0) ? fgColor : bgColor;
|
||||
FrameBuffer[FrameBufferOffset++] = ((pv & 0x04) > 0) ? fgColor : bgColor;
|
||||
FrameBuffer[FrameBufferOffset++] = ((pv & 0x02) > 0) ? fgColor : bgColor;
|
||||
FrameBuffer[FrameBufferOffset++] = ((pv & 0x01) > 0) ? fgColor : bgColor;
|
||||
}
|
||||
}
|
||||
|
||||
void RenderBackgroundM3(uint32_t scanLine)
|
||||
{
|
||||
if (DisplayOn() == false)
|
||||
{
|
||||
for (int i = 0; i < 256; i++) { FrameBuffer[scanLine * 256 + i] = 0; };
|
||||
return;
|
||||
}
|
||||
|
||||
yc = scanLine / 8;
|
||||
is_top = (scanLine & 4) == 0; // am I in the top 4 pixels of an 8-pixel character?
|
||||
FrameBufferOffset = scanLine * 256;
|
||||
PatternNameOffset = TmsPatternNameTableBase + (yc * 32);
|
||||
ScreenBGColor = PaletteTMS9918[Registers[7] & 0x0F];
|
||||
|
||||
for (uint32_t xc = 0; xc < 32; xc++)
|
||||
{
|
||||
pn = VRAM[PatternNameOffset++];
|
||||
pv = VRAM[PatternGeneratorBase + (pn * 8) + ((yc & 3) * 2) + (is_top ? 0 : 1)];
|
||||
|
||||
lColorIndex = pv & 0xF;
|
||||
rColorIndex = pv >> 4;
|
||||
lColor = lColorIndex == 0 ? ScreenBGColor : PaletteTMS9918[lColorIndex];
|
||||
rColor = rColorIndex == 0 ? ScreenBGColor : PaletteTMS9918[rColorIndex];
|
||||
|
||||
FrameBuffer[FrameBufferOffset++] = lColor;
|
||||
FrameBuffer[FrameBufferOffset++] = lColor;
|
||||
FrameBuffer[FrameBufferOffset++] = lColor;
|
||||
FrameBuffer[FrameBufferOffset++] = lColor;
|
||||
FrameBuffer[FrameBufferOffset++] = rColor;
|
||||
FrameBuffer[FrameBufferOffset++] = rColor;
|
||||
FrameBuffer[FrameBufferOffset++] = rColor;
|
||||
FrameBuffer[FrameBufferOffset] = rColor;
|
||||
}
|
||||
}
|
||||
|
||||
inline void RenderTmsSprites(int32_t scanLine)
|
||||
{
|
||||
if (EnableDoubledSprites() == false)
|
||||
{
|
||||
RenderTmsSpritesStandard(scanLine);
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderTmsSpritesDouble(scanLine);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderTmsSpritesStandard(int32_t scanLine)
|
||||
{
|
||||
if (DisplayOn() == false) return;
|
||||
|
||||
for (uint32_t i = 0; i < 256; i++)
|
||||
{
|
||||
ScanlinePriorityBuffer[i] = 0;
|
||||
SpriteCollisionBuffer[i] = 0;
|
||||
};
|
||||
|
||||
bool LargeSprites = EnableLargeSprites();
|
||||
|
||||
int32_t SpriteSize = 8;
|
||||
if (LargeSprites) SpriteSize *= 2;
|
||||
const int32_t OneCellSize = 8;
|
||||
|
||||
int32_t NumSpritesOnScanline = 0;
|
||||
for (int32_t i = 0; i < 32; i++)
|
||||
{
|
||||
int32_t SpriteBase = TmsSpriteAttributeBase + (i * 4);
|
||||
int32_t y = VRAM[SpriteBase++];
|
||||
int32_t x = VRAM[SpriteBase++];
|
||||
int32_t Pattern = VRAM[SpriteBase++];
|
||||
int32_t Color = VRAM[SpriteBase];
|
||||
|
||||
if (y == 208) break; // terminator sprite
|
||||
if (y > 224) y -= 256; // sprite Y wrap
|
||||
y++; // inexplicably, sprites start on Y+1
|
||||
if (y > scanLine || y + SpriteSize <= scanLine) continue; // sprite is not on this scanline
|
||||
if ((Color & 0x80) > 0) x -= 32; // Early Clock adjustment
|
||||
|
||||
if (++NumSpritesOnScanline == 5)
|
||||
{
|
||||
StatusByte &= 0xE0; // Clear FS0-FS4 bits
|
||||
StatusByte |= (uint8_t)i; // set 5th sprite index
|
||||
StatusByte |= 0x40; // set overflow bit
|
||||
break;
|
||||
}
|
||||
|
||||
if (LargeSprites) Pattern &= 0xFC; // 16x16 sprites forced to 4-uint8_t alignment
|
||||
int32_t SpriteLine = scanLine - y;
|
||||
|
||||
// pv contains the VRAM uint8_t holding the pattern data for this character at this scanline.
|
||||
// each uint8_t contains the pattern data for each the 8 pixels on this line.
|
||||
// the bit-shift further down on PV pulls out the relevant horizontal pixel.
|
||||
|
||||
int8_t pv = VRAM[SpritePatternGeneratorBase + (Pattern * 8) + SpriteLine];
|
||||
|
||||
for (int32_t xp = 0; xp < SpriteSize && x + xp < 256; xp++)
|
||||
{
|
||||
if (x + xp < 0) continue;
|
||||
if (LargeSprites && xp == OneCellSize)
|
||||
pv = VRAM[SpritePatternGeneratorBase + (Pattern * 8) + SpriteLine + 16];
|
||||
|
||||
if (Color != 0 && (pv & (1 << (7 - (xp & 7)))) > 0)
|
||||
{
|
||||
if (SpriteCollisionBuffer[x + xp] != 0)
|
||||
StatusByte |= 0x20; // Set sprite collision flag
|
||||
|
||||
if (ScanlinePriorityBuffer[x + xp] == 0)
|
||||
{
|
||||
ScanlinePriorityBuffer[x + xp] = 1;
|
||||
SpriteCollisionBuffer[x + xp] = 1;
|
||||
FrameBuffer[(scanLine * 256) + x + xp] = PaletteTMS9918[Color & 0x0F];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderTmsSpritesDouble(int32_t scanLine)
|
||||
{
|
||||
if (DisplayOn() == false) return;
|
||||
|
||||
for (uint32_t i = 0; i < 256; i++)
|
||||
{
|
||||
ScanlinePriorityBuffer[i] = 0;
|
||||
SpriteCollisionBuffer[i] = 0;
|
||||
};
|
||||
|
||||
bool LargeSprites = EnableLargeSprites();
|
||||
|
||||
int32_t SpriteSize = 8;
|
||||
if (LargeSprites) SpriteSize *= 2;
|
||||
SpriteSize *= 2; // because sprite magnification
|
||||
const int32_t OneCellSize = 16; // once 8-pixel cell, doubled, will take 16 pixels
|
||||
|
||||
int32_t NumSpritesOnScanline = 0;
|
||||
for (int32_t i = 0; i < 32; i++)
|
||||
{
|
||||
int32_t SpriteBase = TmsSpriteAttributeBase + (i * 4);
|
||||
int32_t y = VRAM[SpriteBase++];
|
||||
int32_t x = VRAM[SpriteBase++];
|
||||
int32_t Pattern = VRAM[SpriteBase++];
|
||||
int32_t Color = VRAM[SpriteBase];
|
||||
|
||||
if (y == 208) break; // terminator sprite
|
||||
if (y > 224) y -= 256; // sprite Y wrap
|
||||
y++; // inexplicably, sprites start on Y+1
|
||||
if (y > scanLine || y + SpriteSize <= scanLine) continue; // sprite is not on this scanline
|
||||
if ((Color & 0x80) > 0) x -= 32; // Early Clock adjustment
|
||||
|
||||
if (++NumSpritesOnScanline == 5)
|
||||
{
|
||||
StatusByte &= 0xE0; // Clear FS0-FS4 bits
|
||||
StatusByte |= (uint8_t)i; // set 5th sprite index
|
||||
StatusByte |= 0x40; // set overflow bit
|
||||
break;
|
||||
}
|
||||
|
||||
if (LargeSprites) Pattern &= 0xFC; // 16x16 sprites forced to 4-byte alignment
|
||||
int32_t SpriteLine = scanLine - y;
|
||||
SpriteLine /= 2; // because of sprite magnification
|
||||
|
||||
int8_t pv = VRAM[SpritePatternGeneratorBase + (Pattern * 8) + SpriteLine];
|
||||
|
||||
for (int32_t xp = 0; xp < SpriteSize && x + xp < 256; xp++)
|
||||
{
|
||||
if (x + xp < 0) continue;
|
||||
if (LargeSprites && xp == OneCellSize)
|
||||
pv = VRAM[SpritePatternGeneratorBase + (Pattern * 8) + SpriteLine + 16];
|
||||
|
||||
if (Color != 0 && (pv & (1 << (7 - ((xp / 2) & 7)))) > 0) // xp/2 is due to sprite magnification
|
||||
{
|
||||
if (SpriteCollisionBuffer[x + xp] != 0)
|
||||
StatusByte |= 0x20; // Set sprite collision flag
|
||||
|
||||
if (ScanlinePriorityBuffer[x + xp] == 0)
|
||||
{
|
||||
ScanlinePriorityBuffer[x + xp] = 1;
|
||||
SpriteCollisionBuffer[x + xp] = 1;
|
||||
FrameBuffer[(scanLine * 256) + x + xp] = PaletteTMS9918[Color & 0x0F];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region State Save / Load
|
||||
|
||||
uint8_t* SaveState(uint8_t* saver)
|
||||
{
|
||||
*saver = (uint8_t)(VdpWaitingForLatchInt ? 1 : 0); saver++;
|
||||
*saver = (uint8_t)(VdpWaitingForLatchByte ? 1 : 0); saver++;
|
||||
*saver = (uint8_t)(VIntPending ? 1 : 0); saver++;
|
||||
*saver = (uint8_t)(HIntPending ? 1 : 0); saver++;
|
||||
|
||||
*saver = StatusByte; saver++;
|
||||
*saver = VdpLatch; saver++;
|
||||
*saver = VdpBuffer; saver++;
|
||||
*saver = TmsMode; saver++;
|
||||
|
||||
std::memcpy(saver, &Registers, 8); saver += 8;
|
||||
std::memcpy(saver, &VRAM, 0x4000); saver += 0x4000;
|
||||
|
||||
*saver = (uint8_t)(ScanLine & 0xFF); saver++; *saver = (uint8_t)((ScanLine >> 8) & 0xFF); saver++;
|
||||
*saver = (uint8_t)((ScanLine >> 16) & 0xFF); saver++; *saver = (uint8_t)((ScanLine >> 24) & 0xFF); saver++;
|
||||
|
||||
*saver = (uint8_t)(VdpAddress & 0xFF); saver++; *saver = (uint8_t)((VdpAddress >> 8) & 0xFF); saver++;
|
||||
*saver = (uint8_t)((VdpAddress >> 16) & 0xFF); saver++; *saver = (uint8_t)((VdpAddress >> 24) & 0xFF); saver++;
|
||||
|
||||
*saver = (uint8_t)(ColorTableBase & 0xFF); saver++; *saver = (uint8_t)((ColorTableBase >> 8) & 0xFF); saver++;
|
||||
*saver = (uint8_t)((ColorTableBase >> 16) & 0xFF); saver++; *saver = (uint8_t)((ColorTableBase >> 24) & 0xFF); saver++;
|
||||
|
||||
*saver = (uint8_t)(PatternGeneratorBase & 0xFF); saver++; *saver = (uint8_t)((PatternGeneratorBase >> 8) & 0xFF); saver++;
|
||||
*saver = (uint8_t)((PatternGeneratorBase >> 16) & 0xFF); saver++; *saver = (uint8_t)((PatternGeneratorBase >> 24) & 0xFF); saver++;
|
||||
|
||||
*saver = (uint8_t)(SpritePatternGeneratorBase & 0xFF); saver++; *saver = (uint8_t)((SpritePatternGeneratorBase >> 8) & 0xFF); saver++;
|
||||
*saver = (uint8_t)((SpritePatternGeneratorBase >> 16) & 0xFF); saver++; *saver = (uint8_t)((SpritePatternGeneratorBase >> 24) & 0xFF); saver++;
|
||||
|
||||
*saver = (uint8_t)(TmsPatternNameTableBase & 0xFF); saver++; *saver = (uint8_t)((TmsPatternNameTableBase >> 8) & 0xFF); saver++;
|
||||
*saver = (uint8_t)((TmsPatternNameTableBase >> 16) & 0xFF); saver++; *saver = (uint8_t)((TmsPatternNameTableBase >> 24) & 0xFF); saver++;
|
||||
|
||||
*saver = (uint8_t)(TmsSpriteAttributeBase & 0xFF); saver++; *saver = (uint8_t)((TmsSpriteAttributeBase >> 8) & 0xFF); saver++;
|
||||
*saver = (uint8_t)((TmsSpriteAttributeBase >> 16) & 0xFF); saver++; *saver = (uint8_t)((TmsSpriteAttributeBase >> 24) & 0xFF); saver++;
|
||||
|
||||
return saver;
|
||||
}
|
||||
|
||||
uint8_t* LoadState(uint8_t* loader)
|
||||
{
|
||||
VdpWaitingForLatchInt = *loader == 1; loader++;
|
||||
VdpWaitingForLatchByte = *loader == 1; loader++;
|
||||
VIntPending = *loader == 1; loader++;
|
||||
HIntPending = *loader == 1; loader++;
|
||||
|
||||
StatusByte = *loader; loader++;
|
||||
VdpLatch = *loader; loader++;
|
||||
VdpBuffer = *loader; loader++;
|
||||
TmsMode = *loader; loader++;
|
||||
|
||||
std::memcpy(&Registers, loader, 8); loader += 8;
|
||||
std::memcpy(&VRAM, loader, 0x4000); loader += 0x4000;
|
||||
|
||||
ScanLine = *loader; loader++; ScanLine |= (*loader << 8); loader++;
|
||||
ScanLine |= (*loader << 16); loader++; ScanLine |= (*loader << 24); loader++;
|
||||
|
||||
VdpAddress = *loader; loader++; VdpAddress |= (*loader << 8); loader++;
|
||||
VdpAddress |= (*loader << 16); loader++; VdpAddress |= (*loader << 24); loader++;
|
||||
|
||||
ColorTableBase = *loader; loader++; ColorTableBase |= (*loader << 8); loader++;
|
||||
ColorTableBase |= (*loader << 16); loader++; ColorTableBase |= (*loader << 24); loader++;
|
||||
|
||||
PatternGeneratorBase = *loader; loader++; PatternGeneratorBase |= (*loader << 8); loader++;
|
||||
PatternGeneratorBase |= (*loader << 16); loader++; PatternGeneratorBase |= (*loader << 24); loader++;
|
||||
|
||||
SpritePatternGeneratorBase = *loader; loader++; SpritePatternGeneratorBase |= (*loader << 8); loader++;
|
||||
SpritePatternGeneratorBase |= (*loader << 16); loader++; SpritePatternGeneratorBase |= (*loader << 24); loader++;
|
||||
|
||||
TmsPatternNameTableBase = *loader; loader++; TmsPatternNameTableBase |= (*loader << 8); loader++;
|
||||
TmsPatternNameTableBase |= (*loader << 16); loader++; TmsPatternNameTableBase |= (*loader << 24); loader++;
|
||||
|
||||
TmsSpriteAttributeBase = *loader; loader++; TmsSpriteAttributeBase |= (*loader << 8); loader++;
|
||||
TmsSpriteAttributeBase |= (*loader << 16); loader++; TmsSpriteAttributeBase |= (*loader << 24); loader++;
|
||||
|
||||
return loader;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
};
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
#define GBHawk_API __declspec(dllexport)
|
||||
#define GBHawk_API __declspec(dllimport)
|
Loading…
Reference in New Issue