This commit is contained in:
SuuperW 2020-03-25 14:11:16 -05:00
commit 7aec03d788
33 changed files with 6126 additions and 310 deletions

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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'
}
};
}

View File

@ -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)

View File

@ -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
};
}

View File

@ -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 }
}
};
}

View File

@ -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 }
})
};
}

View File

@ -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")
}
};
}
}
}

View File

@ -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")
{

View File

@ -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")
}
};
}
}
}

View File

@ -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" />

View File

@ -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>();

View File

@ -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();

View File

@ -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);

View File

@ -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);
}

View File

@ -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"
})

View File

@ -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);
}
}
}

View File

@ -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;

View File

@ -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" />

View File

@ -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>

31
libHawk/GBHawk/GBHawk.sln Normal file
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,5 @@
#ifdef _WIN32
#define GBHawk_EXPORT extern "C" __declspec(dllexport)
#elif __linux__
#define GBHawk_EXPORT extern "C"
#endif

View File

@ -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>

View File

@ -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

View File

@ -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)
{
}
}

View File

@ -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
};
}

View File

@ -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
};
}

View File

@ -0,0 +1,2 @@
#define GBHawk_API __declspec(dllexport)
#define GBHawk_API __declspec(dllimport)