Merge pull request #1106 from TASVideos/master
Bring ZXSpectrum branch up to date with master
This commit is contained in:
commit
7c82d6d526
|
@ -273,6 +273,9 @@ sha1:3C72706AF5998133EC6BE703994C10466A094EAB Xing Ji Zheng Ba (China) (Unl) NE
|
|||
sha1:18DF013DB350787D0F3D83ADE33EA92B097BD54B Mahjan Samit Kabukicho Hen (Asia) (Unl) NES board=MAPPER146;PRG=64;CHR=64;WRAM=0;VRAM=0;PAD_V=1;PAD_H=0
|
||||
sha1:6AAA5521F91F101448E77C996C9802015578400C Dooly_Bravo_Land NES board=MAPPER002;PRG=256;CHR=0;WRAM=0;VRAM=8;PAD_V=0;PAD_H=1
|
||||
sha1:4EBC1ED9665C36913D0F05129E6A54787BAD3165 Dragon Ball 3 - Gokuu Den (Japan) (Rev 1) NES board=BANDAI-FCG-2;PRG=128;CHR=256;WRAM=0;VRAM=0;PAD_V=0;PAD_H=1
|
||||
sha1:5A6DFDD8A2D62EBE313A6FDB986C3585077BB348 Final Combat (Asia) (NTSC) (Unl) NES board=MAPPER139
|
||||
sha1:DFAF6D81280ADBEB2ADF3DAB38E536B0F2FDFC76 Final Combat (Asia) (PAL) (Unl) NES board=MAPPER139;system=NES-PAL
|
||||
sha1:433CEC30E71DCA31E32B8A44A0D534DBFE7039CA BoogerMan II (RexSoft) [!] NES board=UNIF_UNL-KOF97
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;-----------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -336,6 +336,12 @@ namespace BizHawk.Client.Common
|
|||
name += "." + Global.Emulator.Attributes().CoreName;
|
||||
}
|
||||
|
||||
// Gambatte and GBHawk have incompatible savestates, store the name to keep them separate
|
||||
if (Global.Emulator.SystemId == "GB")
|
||||
{
|
||||
name += "." + Global.Emulator.Attributes().CoreName;
|
||||
}
|
||||
|
||||
if (Global.Emulator is Snes9x) // Keep snes9x savestate away from libsnes, we want to not be too tedious so bsnes names will just have the profile name not the core name
|
||||
{
|
||||
name += "." + Global.Emulator.Attributes().CoreName;
|
||||
|
|
|
@ -155,6 +155,8 @@ namespace BizHawk.Client.Common
|
|||
|
||||
public string MoviesPathFragment => Global.Config.PathEntries["Global", "Movies"].Path;
|
||||
|
||||
public string MoviesBackupsPathFragment => Global.Config.PathEntries["Global", "Movie backups"].Path;
|
||||
|
||||
public string LuaPathFragment => Global.Config.PathEntries["Global", "Lua"].Path;
|
||||
|
||||
public string FirmwaresPathFragment => Global.Config.PathEntries["Global", "Firmware"].Path;
|
||||
|
|
|
@ -177,7 +177,7 @@ namespace BizHawk.Client.Common
|
|||
var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)];
|
||||
var lastAddr = length + addr;
|
||||
var table = Lua.NewTable();
|
||||
if (lastAddr < d.Size)
|
||||
if (lastAddr <= d.Size)
|
||||
{
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
|
|
|
@ -20,9 +20,10 @@ namespace BizHawk.Client.Common
|
|||
return;
|
||||
}
|
||||
|
||||
var backupDir = PathManager.MakeAbsolutePath(Global.Config.PathEntries.MoviesBackupsPathFragment, null);
|
||||
var backupName = Filename;
|
||||
backupName = backupName.Insert(Filename.LastIndexOf("."), $".{DateTime.Now:yyyy-MM-dd HH.mm.ss}");
|
||||
backupName = Path.Combine(Global.Config.PathEntries["Global", "Movie backups"].Path, Path.GetFileName(backupName));
|
||||
backupName = Path.Combine(backupDir, Path.GetFileName(backupName));
|
||||
|
||||
var directoryInfo = new FileInfo(backupName).Directory;
|
||||
if (directoryInfo != null)
|
||||
|
|
|
@ -50,11 +50,11 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
if (arg.StartsWith("--load-state="))
|
||||
{
|
||||
cmdLoadState = arg.Substring(arg.IndexOf('=') + 1);
|
||||
cmdLoadState = args[i].Substring(args[i].IndexOf('=') + 1);
|
||||
}
|
||||
else if (arg.StartsWith("--movie="))
|
||||
{
|
||||
cmdMovie = arg.Substring(arg.IndexOf('=') + 1);
|
||||
cmdMovie = args[i].Substring(args[i].IndexOf('=') + 1);
|
||||
}
|
||||
else if (arg.StartsWith("--dump-type="))
|
||||
{
|
||||
|
@ -75,7 +75,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
else if (arg.StartsWith("--dump-name="))
|
||||
{
|
||||
cmdDumpName = arg.Substring(arg.IndexOf('=') + 1);
|
||||
cmdDumpName = args[i].Substring(args[i].IndexOf('=') + 1);
|
||||
}
|
||||
else if (arg.StartsWith("--dump-length="))
|
||||
{
|
||||
|
@ -95,7 +95,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
else if (arg.StartsWith("--lua="))
|
||||
{
|
||||
luaScript = arg.Substring(arg.IndexOf('=') + 1);
|
||||
luaScript = args[i].Substring(args[i].IndexOf('=') + 1);
|
||||
luaConsole = true;
|
||||
}
|
||||
else if (arg.StartsWith("--luaconsole"))
|
||||
|
|
|
@ -609,7 +609,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
private bool IsTurboSeeking => PauseOnFrame.HasValue && Global.Config.TurboSeek;
|
||||
|
||||
private bool IsTurboing => Global.ClientControls["Turbo"] || IsTurboSeeking;
|
||||
public bool IsTurboing => Global.ClientControls["Turbo"] || IsTurboSeeking;
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -2974,11 +2974,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
Global.CheatList.Pulse();
|
||||
|
||||
if (!PauseAvi)
|
||||
{
|
||||
AvFrameAdvance();
|
||||
}
|
||||
|
||||
if (IsLagFrame && Global.Config.AutofireLagFrames)
|
||||
{
|
||||
Global.AutoFireController.IncrementStarts();
|
||||
|
@ -3002,6 +2997,11 @@ namespace BizHawk.Client.EmuHawk
|
|||
UpdateToolsAfter(SuppressLua);
|
||||
}
|
||||
|
||||
if (!PauseAvi)
|
||||
{
|
||||
AvFrameAdvance();
|
||||
}
|
||||
|
||||
if (GlobalWin.Tools.IsLoaded<TAStudio>() &&
|
||||
GlobalWin.Tools.TAStudio.LastPositionFrame == Emulator.Frame)
|
||||
{
|
||||
|
|
|
@ -150,6 +150,18 @@ namespace BizHawk.Client.EmuHawk
|
|||
return GlobalWin.MainForm.EmulatorPaused;
|
||||
}
|
||||
|
||||
[LuaMethod("isturbo", "Returns true if emulator is in turbo mode, otherwise, false")]
|
||||
public static bool IsTurbo()
|
||||
{
|
||||
return GlobalWin.MainForm.IsTurboing;
|
||||
}
|
||||
|
||||
[LuaMethod("isseeking", "Returns true if emulator is seeking, otherwise, false")]
|
||||
public static bool IsSeeking()
|
||||
{
|
||||
return GlobalWin.MainForm.IsSeeking;
|
||||
}
|
||||
|
||||
[LuaMethod("opencheats", "opens the Cheats dialog")]
|
||||
public static void OpenCheats()
|
||||
{
|
||||
|
|
|
@ -135,6 +135,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
Movie.AddBranch(branch);
|
||||
BranchView.RowCount = Movie.BranchCount;
|
||||
Movie.CurrentBranch = Movie.BranchCount - 1;
|
||||
BranchView.ScrollToIndex(Movie.CurrentBranch);
|
||||
BranchView.Refresh();
|
||||
Tastudio.RefreshDialog();
|
||||
}
|
||||
|
|
|
@ -180,7 +180,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
this.DiskCapacityNumeric.Enabled = false;
|
||||
this.DiskCapacityNumeric.Location = new System.Drawing.Point(24, 241);
|
||||
this.DiskCapacityNumeric.Maximum = new decimal(new int[] {
|
||||
1,
|
||||
16384,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Windows.Forms;
|
|||
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Client.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
|
@ -34,8 +35,8 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
MemStateGapDividerNumeric.Maximum = Statable.SaveStateBinary().Length / 1024 / 2 + 1;
|
||||
MemStateGapDividerNumeric.Minimum = Statable.SaveStateBinary().Length / 1024 / 16;
|
||||
MemStateGapDividerNumeric.Value = _settings.MemStateGapDivider < MemStateGapDividerNumeric.Minimum ?
|
||||
MemStateGapDividerNumeric.Minimum : _settings.MemStateGapDivider;
|
||||
MemStateGapDividerNumeric.Value = NumberExtensions.Clamp(_settings.MemStateGapDivider,
|
||||
MemStateGapDividerNumeric.Minimum, MemStateGapDividerNumeric.Maximum);
|
||||
|
||||
FileStateGapNumeric.Value = _settings.FileStateGap;
|
||||
SavestateSizeLabel.Text = Math.Round(_stateSizeMb, 2).ToString() + " MB";
|
||||
|
|
|
@ -150,12 +150,28 @@ namespace BizHawk.Client.EmuHawk
|
|||
if (MarkerView.AnyRowsSelected)
|
||||
{
|
||||
SelectedMarkers.ForEach(i => Markers.Remove(i));
|
||||
MarkerInputRoll.DeselectAll();
|
||||
ShrinkSelection();
|
||||
Tastudio.RefreshDialog();
|
||||
MarkerView_SelectedIndexChanged(null, null);
|
||||
}
|
||||
}
|
||||
|
||||
// feos: not the same as InputRoll.TruncateSelection(), since multiple selection of markers is forbidden
|
||||
// moreover, when the last marker is removed, we need its selection to move to the previous marker
|
||||
// still iterate, so things don't break if multiple selection is allowed someday
|
||||
public void ShrinkSelection()
|
||||
{
|
||||
if (MarkerView.AnyRowsSelected)
|
||||
{
|
||||
while (MarkerView.SelectedRows.Last() > Markers.Count() - 1)
|
||||
{
|
||||
MarkerView.SelectRow(Markers.Count(), false);
|
||||
MarkerView.SelectRow(Markers.Count() - 1, true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void AddMarker(bool editText = false, int? frame = null)
|
||||
{
|
||||
// feos: we specify the selected frame if we call this from TasView, otherwise marker should be added to the emulated frame
|
||||
|
@ -190,6 +206,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
UpdateValues();
|
||||
}
|
||||
|
||||
MarkerView.ScrollToIndex(Markers.Count() - 1);
|
||||
Tastudio.RefreshDialog();
|
||||
}
|
||||
|
||||
|
@ -252,7 +269,8 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
get
|
||||
{
|
||||
return MarkerView.SelectedRows
|
||||
return MarkerView
|
||||
.SelectedRows
|
||||
.Select(index => Markers[index])
|
||||
.ToList();
|
||||
}
|
||||
|
|
|
@ -742,7 +742,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
CurrentTasMovie.Markers.Remove(m);
|
||||
}
|
||||
|
||||
MarkerControl.ShrinkSelection();
|
||||
RefreshDialog();
|
||||
}
|
||||
|
||||
|
|
|
@ -111,6 +111,9 @@ namespace BizHawk.Client.EmuHawk
|
|||
/// </summary>
|
||||
public void SetVisibleIndex(int? indexThatMustBeVisible = null)
|
||||
{
|
||||
if (TasView.AlwaysScroll && _leftButtonHeld)
|
||||
return;
|
||||
|
||||
if (!indexThatMustBeVisible.HasValue)
|
||||
{
|
||||
indexThatMustBeVisible = Emulator.Frame;
|
||||
|
|
|
@ -132,13 +132,16 @@ namespace BizHawk.Emulation.Common
|
|||
var sms_jp_21 = File("A8C1B39A2E41137835EDA6A5DE6D46DD9FADBAF2", 8192, "sms_jp_2.1.sms", "SMS BIOS 2.1 (Japan)");
|
||||
var sms_us_1b = File("29091FF60EF4C22B1EE17AA21E0E75BAC6B36474", 8192, "sms_us_1.0b.sms", "SMS BIOS 1.0 (USA) (Proto)"); // ?? is this size correct?
|
||||
var sms_m404 = File("4A06C8E66261611DCE0305217C42138B71331701", 8192, "sms_m404.sms", "SMS BIOS (USA) (M404) (Proto)"); // ?? is this size correct?
|
||||
var sms_kr = File("2FEAFD8F1C40FDF1BD5668F8C5C02E5560945B17", 131072, "sms_kr.sms", "SMS BIOS (Kr)"); // ?? is this size correct?
|
||||
|
||||
Firmware("SMS", "Export", "SMS Bios (USA/Export)");
|
||||
Firmware("SMS", "Japan", "SMS Bios (Japan)");
|
||||
Firmware("SMS", "Korea", "SMS Bios (Korea)");
|
||||
Option("SMS", "Export", sms_us_13);
|
||||
Option("SMS", "Export", sms_us_1b);
|
||||
Option("SMS", "Export", sms_m404);
|
||||
Option("SMS", "Japan", sms_jp_21);
|
||||
Option("SMS", "Korea", sms_kr);
|
||||
|
||||
// PSX
|
||||
// http://forum.fobby.net/index.php?t=msg&goto=2763 [f]
|
||||
|
|
|
@ -722,6 +722,8 @@
|
|||
<Compile Include="Consoles\Nintendo\NES\Boards\BxROM.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\Camerica.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\CamericaGoldenFive.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\Mapper063.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\Mapper043.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\Cony.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\CoolBoy.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\DatachBarcode.cs" />
|
||||
|
@ -917,6 +919,7 @@
|
|||
<Compile Include="Consoles\Nintendo\NES\Boards\Taito_X1_017.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\TENGEN-800032.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\TENGEN_800008.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\UNIF\UNIF_UNL_SMB2J.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\UNIF\UNIF-DREAMTECH01.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\UNIF\UNIF_BMC-12-IN-1.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\UNIF\UNIF_BMC-190in1.cs" />
|
||||
|
|
|
@ -137,17 +137,6 @@ namespace BizHawk.Emulation.Common.Components.LR35902
|
|||
|
||||
// call interrupt processor
|
||||
// lowest bit set is highest priority
|
||||
|
||||
if (interrupt_src.Bit(0) && interrupt_enable.Bit(0)) { int_src = 0; }
|
||||
else if (interrupt_src.Bit(1) && interrupt_enable.Bit(1)) { int_src = 1; }
|
||||
else if (interrupt_src.Bit(2) && interrupt_enable.Bit(2)) { int_src = 2; }
|
||||
else if (interrupt_src.Bit(3) && interrupt_enable.Bit(3)) { int_src = 3; }
|
||||
else if (interrupt_src.Bit(4) && interrupt_enable.Bit(4)) { int_src = 4; }
|
||||
else { /*Console.WriteLine("No source"); }*/ throw new Exception("Interrupt without Source"); }
|
||||
|
||||
|
||||
if ((interrupt_src & interrupt_enable) == 0) { FlagI = false; }
|
||||
|
||||
INTERRUPT_();
|
||||
}
|
||||
else
|
||||
|
@ -252,7 +241,7 @@ namespace BizHawk.Emulation.Common.Components.LR35902
|
|||
SET_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case EI:
|
||||
EI_pending = 2;
|
||||
if (EI_pending == 0) { EI_pending = 2; }
|
||||
break;
|
||||
case DI:
|
||||
interrupts_enabled = false;
|
||||
|
@ -286,18 +275,6 @@ namespace BizHawk.Emulation.Common.Components.LR35902
|
|||
}
|
||||
halted = false;
|
||||
// call interrupt processor
|
||||
instr_pntr = 0;
|
||||
// lowest bit set is highest priority
|
||||
|
||||
if (interrupt_src.Bit(0) && interrupt_enable.Bit(0)) { int_src = 0; }
|
||||
else if (interrupt_src.Bit(1) && interrupt_enable.Bit(1)) { int_src = 1; }
|
||||
else if (interrupt_src.Bit(2) && interrupt_enable.Bit(2)) { int_src = 2; }
|
||||
else if (interrupt_src.Bit(3) && interrupt_enable.Bit(3)) { int_src = 3; }
|
||||
else if (interrupt_src.Bit(4) && interrupt_enable.Bit(4)) { int_src = 4; }
|
||||
else { /*Console.WriteLine("No source"); } */throw new Exception("Interrupt without Source"); }
|
||||
|
||||
if ((interrupt_src & interrupt_enable) == 0) { FlagI = false; }
|
||||
|
||||
INTERRUPT_();
|
||||
}
|
||||
else if (FlagI)
|
||||
|
@ -315,17 +292,16 @@ namespace BizHawk.Emulation.Common.Components.LR35902
|
|||
if (OnExecFetch != null) OnExecFetch(RegPC);
|
||||
if (TraceCallback != null && !CB_prefix) TraceCallback(State());
|
||||
FetchInstruction(ReadMemory(RegPC++));
|
||||
instr_pntr = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
instr_pntr = 0;
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
HALT };
|
||||
}
|
||||
instr_pntr = 0;
|
||||
break;
|
||||
case STOP:
|
||||
stopped = true;
|
||||
|
@ -387,43 +363,14 @@ namespace BizHawk.Emulation.Common.Components.LR35902
|
|||
case INT_GET:
|
||||
// check if any interrupts got cancelled along the way
|
||||
// interrupt src = 5 sets the PC to zero as observed
|
||||
if (int_src == 0)
|
||||
{
|
||||
if (interrupt_enable.Bit(0)) { interrupt_src -= 1; }
|
||||
else { int_src = 5; }
|
||||
}
|
||||
if (int_src == 1)
|
||||
{
|
||||
if (interrupt_enable.Bit(1)) { interrupt_src -= 2; }
|
||||
else { int_src = 5; }
|
||||
}
|
||||
if (int_src == 2)
|
||||
{
|
||||
if (interrupt_enable.Bit(2)) { interrupt_src -= 4; }
|
||||
else { int_src = 5; }
|
||||
}
|
||||
if (int_src == 3)
|
||||
{
|
||||
if (interrupt_enable.Bit(3)) { interrupt_src -= 8; }
|
||||
else { int_src = 5; }
|
||||
}
|
||||
if (int_src == 4)
|
||||
{
|
||||
if (interrupt_enable.Bit(4)) { interrupt_src -= 16; }
|
||||
else { int_src = 5; }
|
||||
}
|
||||
|
||||
// if we lost the interrupt, find the next highest interrupt, if any
|
||||
if (int_src == 5)
|
||||
{
|
||||
if (interrupt_src.Bit(0) && interrupt_enable.Bit(0)) { int_src = 0; interrupt_src -= 1; }
|
||||
else if (interrupt_src.Bit(1) && interrupt_enable.Bit(1)) { int_src = 1; interrupt_src -= 2; }
|
||||
else if (interrupt_src.Bit(2) && interrupt_enable.Bit(2)) { int_src = 2; interrupt_src -= 4; }
|
||||
else if (interrupt_src.Bit(3) && interrupt_enable.Bit(3)) { int_src = 3; interrupt_src -= 8; }
|
||||
else if (interrupt_src.Bit(4) && interrupt_enable.Bit(4)) { int_src = 4; interrupt_src -= 16; }
|
||||
else { int_src = 5; }
|
||||
}
|
||||
|
||||
if (interrupt_src.Bit(0) && interrupt_enable.Bit(0)) { int_src = 0; interrupt_src -= 1; }
|
||||
else if (interrupt_src.Bit(1) && interrupt_enable.Bit(1)) { int_src = 1; interrupt_src -= 2; }
|
||||
else if (interrupt_src.Bit(2) && interrupt_enable.Bit(2)) { int_src = 2; interrupt_src -= 4; }
|
||||
else if (interrupt_src.Bit(3) && interrupt_enable.Bit(3)) { int_src = 3; interrupt_src -= 8; }
|
||||
else if (interrupt_src.Bit(4) && interrupt_enable.Bit(4)) { int_src = 4; interrupt_src -= 16; }
|
||||
else { int_src = 5; }
|
||||
|
||||
if ((interrupt_src & interrupt_enable) == 0) { FlagI = false; }
|
||||
|
||||
Regs[cur_instr[instr_pntr++]] = INT_vectors[int_src];
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
});
|
||||
}
|
||||
|
||||
if (tapeDriveEnabled)
|
||||
if (tapeDriveEnabled && (_board.TapeDrive.TapeDataDomain != null))
|
||||
{
|
||||
domains.AddRange(new[]
|
||||
{
|
||||
|
|
|
@ -32,7 +32,8 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cassette
|
|||
|
||||
public override void SyncState(Serializer ser)
|
||||
{
|
||||
_tape.SyncState(ser);
|
||||
|
||||
if (_tape != null) { _tape.SyncState(ser); }
|
||||
}
|
||||
|
||||
public void Insert(Tape tape)
|
||||
|
@ -46,6 +47,19 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cassette
|
|||
}
|
||||
|
||||
// Exposed for memory domains, should not be used for actual emulation implementation
|
||||
public override byte[] TapeDataDomain => _tape.TapeDataDomain;
|
||||
public override byte[] TapeDataDomain
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_tape != null)
|
||||
{
|
||||
return _tape.TapeDataDomain;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,8 +111,15 @@
|
|||
break;
|
||||
case 0x19: result = _potX; break;
|
||||
case 0x1A: result = _potY; break;
|
||||
case 0x1B: result = _voiceOutput2 >> 4; break;
|
||||
case 0x1C: result = _envelopeOutput2; break;
|
||||
// these two registers are reading the sound output in real time, so we need to flush the output here
|
||||
case 0x1B:
|
||||
Flush(false);
|
||||
result = _voiceOutput2 >> 4;
|
||||
break;
|
||||
case 0x1C:
|
||||
Flush(false);
|
||||
result = _envelopeOutput2;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -138,12 +145,13 @@
|
|||
|
||||
// we want to only flush the filter when the filter is actually changed, that way
|
||||
// the FFT will not be impacted by small sample sizes from other changes
|
||||
if (addr == 15 || addr == 16 || addr==17)
|
||||
if ((addr == 0x15) || (addr == 0x16) || (addr == 0x17))
|
||||
{
|
||||
Flush(true);
|
||||
}
|
||||
else if (addr==18)
|
||||
else if (addr == 0x18)
|
||||
{
|
||||
|
||||
// note: we only want to flush the filter here if the filter components are changing
|
||||
bool temp1 = (val & 0x10) != 0;
|
||||
bool temp2 = (val & 0x20) != 0;
|
||||
|
|
|
@ -49,8 +49,8 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
{
|
||||
_mixer = _outputBuffer_not_filtered[i] + _outputBuffer_filtered[i];
|
||||
_mixer = _mixer >> 7;
|
||||
_mixer = (_mixer * _volume) >> 4;
|
||||
_mixer -= _volume << 8;
|
||||
_mixer = (_mixer * _volume_at_sample_time[i]) >> 4;
|
||||
_mixer -= _volume_at_sample_time[i] << 8;
|
||||
|
||||
if (_mixer > 0x7FFF)
|
||||
{
|
||||
|
|
|
@ -41,6 +41,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
private short[] _outputBuffer;
|
||||
private int[] _outputBuffer_filtered;
|
||||
private int[] _outputBuffer_not_filtered;
|
||||
private int[] _volume_at_sample_time;
|
||||
private int _outputBufferIndex;
|
||||
private int filter_index;
|
||||
private int last_filtered_value;
|
||||
|
@ -93,6 +94,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
|
||||
_outputBuffer_filtered = new int[sampleRate];
|
||||
_outputBuffer_not_filtered = new int[sampleRate];
|
||||
_volume_at_sample_time = new int[sampleRate];
|
||||
}
|
||||
|
||||
// ------------------------------------
|
||||
|
@ -190,6 +192,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
{
|
||||
_outputBuffer_not_filtered[_outputBufferIndex] = temp_not_filtered;
|
||||
_outputBuffer_filtered[_outputBufferIndex] = temp_filtered;
|
||||
_volume_at_sample_time[_outputBufferIndex] = _volume;
|
||||
_outputBufferIndex++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,7 +99,7 @@
|
|||
return 0x01 | ((_pointerVm & 0x3C00) >> 6) |
|
||||
((_pointerCb & 0x7) << 1);
|
||||
case 0x19:
|
||||
return 0x70 | (_intRaster ? 0x01 : 0x00) |
|
||||
return 0x70 | (_rasterInterruptTriggered ? 0x01 : 0x00) |
|
||||
(_intSpriteDataCollision ? 0x02 : 0x00) |
|
||||
(_intSpriteCollision ? 0x04 : 0x00) |
|
||||
(_intLightPen ? 0x08 : 0x00) |
|
||||
|
@ -207,7 +207,11 @@
|
|||
case 0x19:
|
||||
// interrupts are cleared by writing a 1
|
||||
if ((val & 0x01) != 0)
|
||||
{
|
||||
_intRaster = false;
|
||||
_rasterInterruptTriggered = false;
|
||||
}
|
||||
|
||||
if ((val & 0x02) != 0)
|
||||
_intSpriteDataCollision = false;
|
||||
if ((val & 0x04) != 0)
|
||||
|
|
|
@ -25,20 +25,20 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
{
|
||||
Colors.ARGB(0x00, 0x00, 0x00),
|
||||
Colors.ARGB(0xFF, 0xFF, 0xFF),
|
||||
Colors.ARGB(0x68, 0x37, 0x2B),
|
||||
Colors.ARGB(0x70, 0xA4, 0xB2),
|
||||
Colors.ARGB(0x6F, 0x3D, 0x86),
|
||||
Colors.ARGB(0x58, 0x8D, 0x43),
|
||||
Colors.ARGB(0x35, 0x28, 0x79),
|
||||
Colors.ARGB(0xB8, 0xC7, 0x6F),
|
||||
Colors.ARGB(0x6F, 0x4F, 0x25),
|
||||
Colors.ARGB(0x43, 0x39, 0x00),
|
||||
Colors.ARGB(0x9A, 0x67, 0x59),
|
||||
Colors.ARGB(0x44, 0x44, 0x44),
|
||||
Colors.ARGB(0x6C, 0x6C, 0x6C),
|
||||
Colors.ARGB(0x9A, 0xD2, 0x84),
|
||||
Colors.ARGB(0x6C, 0x5E, 0xB5),
|
||||
Colors.ARGB(0x95, 0x95, 0x95)
|
||||
Colors.ARGB(0x96, 0x28, 0x2E),
|
||||
Colors.ARGB(0x5B, 0xD6, 0xCE),
|
||||
Colors.ARGB(0x9F, 0x2D, 0xAD),
|
||||
Colors.ARGB(0x41, 0xB9, 0x36),
|
||||
Colors.ARGB(0x27, 0x24, 0xC4),
|
||||
Colors.ARGB(0xEF, 0xF3, 0x47),
|
||||
Colors.ARGB(0x9F, 0x48, 0x15),
|
||||
Colors.ARGB(0x5E, 0x35, 0x00),
|
||||
Colors.ARGB(0xDA, 0x5F, 0x66),
|
||||
Colors.ARGB(0x47, 0x47, 0x47),
|
||||
Colors.ARGB(0x78, 0x78, 0x78),
|
||||
Colors.ARGB(0x91, 0xFF, 0x84),
|
||||
Colors.ARGB(0x68, 0x64, 0xFF),
|
||||
Colors.ARGB(0xAE, 0xAE, 0xAE)
|
||||
};
|
||||
|
||||
public int BackgroundColor => BgColor;
|
||||
|
|
|
@ -242,23 +242,16 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
// start of rasterline
|
||||
if ((_cycle == RasterIrqLineXCycle && _rasterLine > 0) || (_cycle == RasterIrqLine0Cycle && _rasterLine == 0))
|
||||
{
|
||||
_rasterInterruptTriggered = false;
|
||||
//_rasterInterruptTriggered = false;
|
||||
|
||||
if (_rasterLine == LastDmaLine)
|
||||
_badlineEnable = false;
|
||||
}
|
||||
|
||||
// rasterline IRQ compare
|
||||
if (_rasterLine != _rasterInterruptLine)
|
||||
{
|
||||
_rasterInterruptTriggered = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_rasterInterruptTriggered)
|
||||
// IRQ compares are done here
|
||||
if (_rasterLine == _rasterInterruptLine)
|
||||
{
|
||||
_rasterInterruptTriggered = true;
|
||||
|
||||
|
||||
// interrupt needs to be enabled to be set to true
|
||||
if (_enableIntRaster)
|
||||
{
|
||||
|
|
|
@ -54,7 +54,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
|
|||
public override void SyncState(Serializer ser)
|
||||
{
|
||||
ser.BeginSection("Disk");
|
||||
_disk.SyncState(ser);
|
||||
if (_disk != null) { _disk.SyncState(ser); }
|
||||
ser.EndSection();
|
||||
|
||||
ser.Sync("BitHistory", ref _bitHistory);
|
||||
|
|
|
@ -188,11 +188,20 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
SQ1_len_cntr = SQ1_length;
|
||||
break;
|
||||
case 0xFF12: // NR12 (envelope)
|
||||
Audio_Regs[NR12] = value;
|
||||
SQ1_st_vol = (byte)((value & 0xF0) >> 4);
|
||||
SQ1_env_add = (value & 8) > 0;
|
||||
SQ1_per = (byte)(value & 7);
|
||||
|
||||
// several glitchy effects happen when writing to NRx2 during audio playing
|
||||
if (((Audio_Regs[NR12] & 7) == 0) && !SQ1_vol_done) { SQ1_vol_state++; }
|
||||
else if ((Audio_Regs[NR12] & 8) == 0) { SQ1_vol_state += 2; }
|
||||
|
||||
if (((Audio_Regs[NR12] ^ value) & 8) > 0) { SQ1_vol_state = (byte)(0x10 - SQ1_vol_state); }
|
||||
|
||||
SQ1_vol_state &= 0xF;
|
||||
|
||||
if ((value & 0xF8) == 0) { SQ1_enable = SQ1_swp_enable = false; SQ1_output = 0; }
|
||||
Audio_Regs[NR12] = value;
|
||||
break;
|
||||
case 0xFF13: // NR13 (freq low)
|
||||
Audio_Regs[NR13] = value;
|
||||
|
@ -269,11 +278,19 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
SQ2_len_cntr = SQ2_length;
|
||||
break;
|
||||
case 0xFF17: // NR22 (envelope)
|
||||
Audio_Regs[NR22] = value;
|
||||
SQ2_st_vol = (byte)((value & 0xF0) >> 4);
|
||||
SQ2_env_add = (value & 8) > 0;
|
||||
SQ2_per = (byte)(value & 7);
|
||||
|
||||
// several glitchy effects happen when writing to NRx2 during audio playing
|
||||
if (((Audio_Regs[NR22] & 7) == 0) && !SQ2_vol_done) { SQ2_vol_state++; }
|
||||
else if ((Audio_Regs[NR22] & 8) == 0) { SQ2_vol_state += 2; }
|
||||
|
||||
if (((Audio_Regs[NR22] ^ value) & 8) > 0) { SQ2_vol_state = (byte)(0x10 - SQ2_vol_state); }
|
||||
|
||||
SQ2_vol_state &= 0xF;
|
||||
if ((value & 0xF8) == 0) { SQ2_enable = false; SQ2_output = 0; }
|
||||
Audio_Regs[NR22] = value;
|
||||
break;
|
||||
case 0xFF18: // NR23 (freq low)
|
||||
Audio_Regs[NR23] = value;
|
||||
|
@ -388,11 +405,19 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
NOISE_len_cntr = NOISE_length;
|
||||
break;
|
||||
case 0xFF21: // NR42 (envelope)
|
||||
Audio_Regs[NR42] = value;
|
||||
NOISE_st_vol = (byte)((value & 0xF0) >> 4);
|
||||
NOISE_env_add = (value & 8) > 0;
|
||||
NOISE_per = (byte)(value & 7);
|
||||
|
||||
// several glitchy effects happen when writing to NRx2 during audio playing
|
||||
if (((Audio_Regs[NR42] & 7) == 0) && !NOISE_vol_done) { NOISE_vol_state++; }
|
||||
else if ((Audio_Regs[NR42] & 8) == 0) { NOISE_vol_state += 2; }
|
||||
|
||||
if (((Audio_Regs[NR42] ^ value) & 8) > 0) { NOISE_vol_state = (byte)(0x10 - NOISE_vol_state); }
|
||||
|
||||
NOISE_vol_state &= 0xF;
|
||||
if ((value & 0xF8) == 0) { NOISE_enable = false; NOISE_output = 0; }
|
||||
Audio_Regs[NR42] = value;
|
||||
break;
|
||||
case 0xFF22: // NR43 (shift)
|
||||
Audio_Regs[NR43] = value;
|
||||
|
@ -961,7 +986,21 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
ser.Sync("sequencer_tick", ref sequencer_tick);
|
||||
|
||||
ser.Sync("master_audio_clock", ref master_audio_clock);
|
||||
}
|
||||
|
||||
ser.Sync("AUD_CTRL_vin_L_en", ref AUD_CTRL_vin_L_en);
|
||||
ser.Sync("AUD_CTRL_vin_R_en", ref AUD_CTRL_vin_R_en);
|
||||
ser.Sync("AUD_CTRL_sq1_L_en", ref AUD_CTRL_sq1_L_en);
|
||||
ser.Sync("AUD_CTRL_sq2_L_en", ref AUD_CTRL_sq2_L_en);
|
||||
ser.Sync("AUD_CTRL_wave_L_en", ref AUD_CTRL_wave_L_en);
|
||||
ser.Sync("AUD_CTRL_noise_L_en", ref AUD_CTRL_noise_L_en);
|
||||
ser.Sync("AUD_CTRL_sq1_R_en", ref AUD_CTRL_sq1_R_en);
|
||||
ser.Sync("AUD_CTRL_sq2_R_en", ref AUD_CTRL_sq2_R_en);
|
||||
ser.Sync("AUD_CTRL_wave_R_en", ref AUD_CTRL_wave_R_en);
|
||||
ser.Sync("AUD_CTRL_noise_R_en", ref AUD_CTRL_noise_R_en);
|
||||
ser.Sync("AUD_CTRL_power", ref AUD_CTRL_power);
|
||||
ser.Sync("AUD_CTRL_vol_L", ref AUD_CTRL_vol_L);
|
||||
ser.Sync("AUD_CTRL_vol_R", ref AUD_CTRL_vol_R);
|
||||
}
|
||||
|
||||
public byte Read_NR52()
|
||||
{
|
||||
|
|
|
@ -37,7 +37,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
color_palette[3] = color_palette_Gr[3];
|
||||
}
|
||||
|
||||
|
||||
if (_tracer.Enabled)
|
||||
{
|
||||
cpu.TraceCallback = s => _tracer.Put(s);
|
||||
|
@ -103,9 +102,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
input_register |= 0xF;
|
||||
}
|
||||
|
||||
// check for interrupts
|
||||
|
||||
|
||||
// check for interrupts
|
||||
if (((contr_prev & 8) > 0) && ((input_register & 8) == 0) ||
|
||||
((contr_prev & 4) > 0) && ((input_register & 4) == 0) ||
|
||||
((contr_prev & 2) > 0) && ((input_register & 2) == 0) ||
|
||||
|
@ -115,8 +112,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
REG_FF0F |= 0x10;
|
||||
}
|
||||
|
||||
|
||||
while (!vblank_rise && (ticker < 100000))
|
||||
while (!vblank_rise)
|
||||
{
|
||||
audio.tick();
|
||||
timer.tick_1();
|
||||
|
@ -133,7 +129,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
{
|
||||
vblank_rise = true;
|
||||
}
|
||||
|
||||
ticker++;
|
||||
if (ticker > 10000000) { throw new Exception("ERROR: Unable to Resolve Frame"); }
|
||||
|
||||
in_vblank_old = in_vblank;
|
||||
}
|
||||
|
||||
|
@ -174,7 +173,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
Marshal.FreeHGlobal(iptr3);
|
||||
}
|
||||
|
||||
|
||||
#region Video provider
|
||||
|
||||
public int _frameHz = 60;
|
||||
|
@ -183,7 +181,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
public int[] GetVideoBuffer()
|
||||
{
|
||||
return _vidbuffer;
|
||||
if (ppu.blank_frame)
|
||||
{
|
||||
for (int i = 0; i < _vidbuffer.Length; i++)
|
||||
{
|
||||
_vidbuffer[i] = (int)color_palette[0];
|
||||
}
|
||||
ppu.blank_frame = false;
|
||||
}
|
||||
return _vidbuffer;
|
||||
}
|
||||
|
||||
public int VirtualWidth => 160;
|
||||
|
|
|
@ -44,8 +44,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
Gr
|
||||
}
|
||||
|
||||
[DisplayName("Console Mode")]
|
||||
[Description("Pick which console to run, 'Auto' chooses from ROM header, 'GB' and 'GBC' chooses the respective system")]
|
||||
[DisplayName("Color Mode")]
|
||||
[Description("Pick Between Green scale and Grey scale colors")]
|
||||
[DefaultValue(PaletteType.BW)]
|
||||
public PaletteType Palette { get; set; }
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
_syncSettings = (GBSyncSettings)syncSettings ?? new GBSyncSettings();
|
||||
_controllerDeck = new GBHawkControllerDeck(_syncSettings.Port1);
|
||||
|
||||
byte[] Bios = comm.CoreFileProvider.GetFirmware("GB", "World", false, "BIOS Not Found, Cannot Load");
|
||||
byte[] Bios = comm.CoreFileProvider.GetFirmware("GB", "World", true, "BIOS Not Found, Cannot Load");
|
||||
|
||||
if (Bios == null)
|
||||
{
|
||||
|
|
|
@ -44,12 +44,38 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
public byte Read(IController c)
|
||||
{
|
||||
byte result = 0xFF;
|
||||
for (int i = 0; i < 8; i++)
|
||||
|
||||
if (c.IsPressed(Definition.BoolButtons[0]))
|
||||
{
|
||||
if (c.IsPressed(Definition.BoolButtons[i]))
|
||||
{
|
||||
result -= (byte)(1 << i);
|
||||
}
|
||||
result -= 4;
|
||||
}
|
||||
if (c.IsPressed(Definition.BoolButtons[1]))
|
||||
{
|
||||
result -= 8;
|
||||
}
|
||||
if (c.IsPressed(Definition.BoolButtons[2]))
|
||||
{
|
||||
result -= 2;
|
||||
}
|
||||
if (c.IsPressed(Definition.BoolButtons[3]))
|
||||
{
|
||||
result -= 1;
|
||||
}
|
||||
if (c.IsPressed(Definition.BoolButtons[4]))
|
||||
{
|
||||
result -= 128;
|
||||
}
|
||||
if (c.IsPressed(Definition.BoolButtons[5]))
|
||||
{
|
||||
result -= 64;
|
||||
}
|
||||
if (c.IsPressed(Definition.BoolButtons[6]))
|
||||
{
|
||||
result -= 32;
|
||||
}
|
||||
if (c.IsPressed(Definition.BoolButtons[7]))
|
||||
{
|
||||
result -= 16;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -57,7 +83,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
private static readonly string[] BaseDefinition =
|
||||
{
|
||||
"Right", "Left", "Up", "Down", "A", "B", "Select", "Start", "Power"
|
||||
"Up", "Down", "Left", "Right", "Start", "Select", "B", "A", "Power"
|
||||
};
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
|
|
|
@ -83,7 +83,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
{
|
||||
if (addr < 0x2000)
|
||||
{
|
||||
RAM_enable = (value & 0xA) == 0xA;
|
||||
RAM_enable = (value & 0xF) == 0xA;
|
||||
}
|
||||
else if (addr < 0x4000)
|
||||
{
|
||||
|
|
|
@ -59,6 +59,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
public int tile_byte;
|
||||
public int sprite_fetch_cycles;
|
||||
public bool fetch_sprite;
|
||||
public bool fetch_sprite_01;
|
||||
public bool fetch_sprite_4;
|
||||
public bool going_to_fetch;
|
||||
public int sprite_fetch_counter;
|
||||
public byte[] sprite_attr_list = new byte[160];
|
||||
public byte[] sprite_pixel_list = new byte[160];
|
||||
public byte[] sprite_present_list = new byte[160];
|
||||
public int temp_fetch;
|
||||
public int tile_inc;
|
||||
public bool pre_render;
|
||||
|
@ -74,11 +81,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
public byte[] sprite_sel = new byte[2];
|
||||
public int sl_use_index;
|
||||
public bool no_sprites;
|
||||
public int sprite_fetch_index;
|
||||
public int[] SL_sprites_ordered = new int[40]; // (x_end, data_low, data_high, attr)
|
||||
public int index_used;
|
||||
public int evaled_sprites;
|
||||
public int sprite_ordered_index;
|
||||
public int bottom_index;
|
||||
public bool blank_frame;
|
||||
|
||||
// windowing state
|
||||
public int window_counter;
|
||||
|
@ -88,6 +94,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
public int window_y_tile;
|
||||
public int window_x_tile;
|
||||
public int window_y_tile_inc;
|
||||
public int window_x_latch;
|
||||
|
||||
public byte ReadReg(int addr)
|
||||
{
|
||||
|
@ -125,6 +132,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
OAM_access_write = true;
|
||||
}
|
||||
|
||||
if (!LCDC.Bit(7) && value.Bit(7))
|
||||
{
|
||||
// don't draw for one frame after turning on
|
||||
blank_frame = true;
|
||||
}
|
||||
|
||||
LCDC = value;
|
||||
break;
|
||||
case 0xFF41: // STAT
|
||||
|
@ -175,13 +188,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
case 0xFF4B: // WX
|
||||
window_x = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void tick()
|
||||
{
|
||||
// tick DMA
|
||||
if (DMA_start)
|
||||
// tick DMA, note that DMA is halted when the CPU is halted
|
||||
if (DMA_start && !Core.cpu.halted)
|
||||
{
|
||||
if (DMA_clock >= 4)
|
||||
{
|
||||
|
@ -195,14 +208,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
else if ((DMA_clock % 4) == 3)
|
||||
{
|
||||
if ((DMA_inc % 4) == 3)
|
||||
{
|
||||
Core.OAM[DMA_inc] = DMA_byte;
|
||||
}
|
||||
else
|
||||
{
|
||||
Core.OAM[DMA_inc] = DMA_byte;
|
||||
}
|
||||
Core.OAM[DMA_inc] = DMA_byte;
|
||||
|
||||
if (DMA_inc < (0xA0 - 1)) { DMA_inc++; }
|
||||
}
|
||||
|
@ -213,6 +219,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
if (DMA_clock == 648)
|
||||
{
|
||||
DMA_start = false;
|
||||
DMA_OAM_access = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -232,10 +239,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
cycle = 0;
|
||||
LY += LY_inc;
|
||||
//Console.WriteLine(Core.cpu.TotalExecutedCycles);
|
||||
no_scan = false;
|
||||
|
||||
// here is where LY = LYC gets cleared (but only if LY isnt 0 as that's a special case
|
||||
|
@ -387,7 +392,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
{
|
||||
if (cycle == 4)
|
||||
{
|
||||
// apparently, writes can make it to OAm one cycle longer then reads
|
||||
// apparently, writes can make it to OAM one cycle longer then reads
|
||||
OAM_access_write = false;
|
||||
|
||||
// here mode 2 will be set to true and interrupts fired if enabled
|
||||
|
@ -416,11 +421,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
// render the screen and handle hblank
|
||||
render(cycle - 80);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ((LY_inc == 0))
|
||||
{
|
||||
if (cycle == 12)
|
||||
|
@ -458,10 +461,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
else
|
||||
{
|
||||
// screen disable sets STAT as though it were vblank, but there is no Stat IRQ asserted
|
||||
//STAT &= 0xFC;
|
||||
//STAT |= 0x01;
|
||||
|
||||
STAT &= 0xF8;
|
||||
|
||||
VBL_INT = LYC_INT = HBL_INT = OAM_INT = false;
|
||||
|
@ -489,7 +488,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
// process latch delays
|
||||
//latch_delay();
|
||||
|
||||
}
|
||||
|
||||
// might be needed, not sure yet
|
||||
|
@ -527,14 +525,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
{
|
||||
if (OAM_scan_index < 40)
|
||||
{
|
||||
ushort temp = DMA_OAM_access ? Core.OAM[OAM_scan_index * 4] : (ushort)0xFF;
|
||||
// (sprite Y - 16) equals LY, we have a sprite
|
||||
if ((Core.OAM[OAM_scan_index * 4] - 16) <= LY &&
|
||||
((Core.OAM[OAM_scan_index * 4] - 16) + 8 + (LCDC.Bit(2) ? 8 : 0)) > LY)
|
||||
if ((temp - 16) <= LY &&
|
||||
((temp - 16) + 8 + (LCDC.Bit(2) ? 8 : 0)) > LY)
|
||||
{
|
||||
// always pick the first 10 in range sprites
|
||||
if (SL_sprites_index < 10)
|
||||
{
|
||||
SL_sprites[SL_sprites_index * 4] = Core.OAM[OAM_scan_index * 4];
|
||||
SL_sprites[SL_sprites_index * 4] = temp;
|
||||
|
||||
write_sprite = 1;
|
||||
}
|
||||
|
@ -552,7 +551,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
else
|
||||
{
|
||||
SL_sprites[SL_sprites_index * 4 + write_sprite] = Core.OAM[OAM_scan_index * 4 + write_sprite];
|
||||
ushort temp2 = DMA_OAM_access ? Core.OAM[OAM_scan_index * 4 + write_sprite] : (ushort)0xFF;
|
||||
SL_sprites[SL_sprites_index * 4 + write_sprite] = temp2;
|
||||
write_sprite++;
|
||||
|
||||
if (write_sprite == 4)
|
||||
|
@ -576,18 +576,22 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
OAM_access_write = true;
|
||||
VRAM_access_read = false;
|
||||
|
||||
// window X is latched for the scanline, mid-line changes have no effect
|
||||
window_x_latch = window_x;
|
||||
|
||||
OAM_scan_index = 0;
|
||||
read_case = 0;
|
||||
internal_cycle = 0;
|
||||
pre_render = true;
|
||||
tile_inc = 0;
|
||||
pixel_counter = 0;
|
||||
pixel_counter = -8;
|
||||
sl_use_index = 0;
|
||||
index_used = 0;
|
||||
bottom_index = 0;
|
||||
sprite_ordered_index = 0;
|
||||
fetch_sprite = false;
|
||||
fetch_sprite_01 = false;
|
||||
fetch_sprite_4 = false;
|
||||
going_to_fetch = false;
|
||||
no_sprites = false;
|
||||
evaled_sprites = 0;
|
||||
|
||||
window_pre_render = false;
|
||||
if (window_started && LCDC.Bit(5))
|
||||
|
@ -602,28 +606,27 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
window_started = false;
|
||||
|
||||
// calculate the row number of the tiles to be fetched
|
||||
y_tile = ((int)Math.Floor((float)(scroll_y + LY) / 8)) % 32;
|
||||
if (SL_sprites_index == 0) { no_sprites = true; }
|
||||
// it is much easier to process sprites if we order them according to the rules of sprite priority first
|
||||
if (!no_sprites) { reorder_and_assemble_sprites(); }
|
||||
|
||||
if (SL_sprites_index == 0)
|
||||
{
|
||||
no_sprites = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// before anything else, we have to check if windowing is in effect
|
||||
if (LCDC.Bit(5) && !window_started && (LY >= window_y) && (pixel_counter >= (window_x - 7)))
|
||||
if (LCDC.Bit(5) && !window_started && (LY >= window_y) && (pixel_counter >= (window_x_latch - 7)) && (window_x_latch < 167))
|
||||
{
|
||||
/*
|
||||
Console.Write(LY);
|
||||
Console.Write(" ");
|
||||
Console.Write(window_y);
|
||||
Console.Write(cycle);
|
||||
Console.Write(" ");
|
||||
Console.Write(window_y_tile_inc);
|
||||
Console.Write(" ");
|
||||
Console.WriteLine(scroll_y);
|
||||
Console.Write(window_x_latch);
|
||||
Console.Write(" ");
|
||||
Console.WriteLine(pixel_counter);
|
||||
*/
|
||||
if (pixel_counter == 0 && window_x <= 7)
|
||||
if (pixel_counter == 0 && window_x_latch <= 7)
|
||||
{
|
||||
// if the window starts at zero, we still do the first access to the BG
|
||||
// but then restart all over again at the window
|
||||
|
@ -637,7 +640,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
window_counter = 0;
|
||||
|
||||
window_x_tile = (int)Math.Floor((float)(pixel_counter - (window_x - 7)) / 8);
|
||||
window_x_tile = (int)Math.Floor((float)(pixel_counter - (window_x_latch - 7)) / 8);
|
||||
|
||||
window_tile_inc = 0;
|
||||
window_started = true;
|
||||
|
@ -645,132 +648,117 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
if (!pre_render && !fetch_sprite && !window_pre_render)
|
||||
{
|
||||
// start by fetching all the sprites that need to be fetched
|
||||
if (!no_sprites)
|
||||
// start shifting data into the LCD
|
||||
if (render_counter >= (render_offset + 8))
|
||||
{
|
||||
for (int i = 0; i < SL_sprites_index; i++)
|
||||
pixel = tile_data_latch[0].Bit(7 - (render_counter % 8)) ? 1 : 0;
|
||||
pixel |= tile_data_latch[1].Bit(7 - (render_counter % 8)) ? 2 : 0;
|
||||
|
||||
int ref_pixel = pixel;
|
||||
if (LCDC.Bit(0))
|
||||
{
|
||||
if ((pixel_counter >= (SL_sprites[i * 4 + 1] - 8)) &&
|
||||
(pixel_counter < SL_sprites[i * 4 + 1]) &&
|
||||
!index_used.Bit(i))
|
||||
{
|
||||
fetch_sprite = true;
|
||||
sprite_fetch_index = 0;
|
||||
}
|
||||
pixel = (BGP >> (pixel * 2)) & 3;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fetch_sprite)
|
||||
{
|
||||
// start shifting data into the LCD
|
||||
if (render_counter >= (render_offset + 8))
|
||||
else
|
||||
{
|
||||
pixel = tile_data_latch[0].Bit(7 - (render_counter % 8)) ? 1 : 0;
|
||||
pixel |= tile_data_latch[1].Bit(7 - (render_counter % 8)) ? 2 : 0;
|
||||
|
||||
int ref_pixel = pixel;
|
||||
if (LCDC.Bit(0))
|
||||
{
|
||||
pixel = (BGP >> (pixel * 2)) & 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
pixel = 0;
|
||||
}
|
||||
pixel = 0;
|
||||
}
|
||||
|
||||
// now we have the BG pixel, we next need the sprite pixel
|
||||
if (!no_sprites)
|
||||
{
|
||||
bool have_sprite = false;
|
||||
int s_pixel = 0;
|
||||
int sprite_attr = 0;
|
||||
|
||||
// now we have the BG pixel, we next need the sprite pixel
|
||||
if (!no_sprites)
|
||||
if (sprite_present_list[pixel_counter] == 1)
|
||||
{
|
||||
bool have_sprite = false;
|
||||
int i = bottom_index;
|
||||
int s_pixel = 0;
|
||||
int sprite_attr = 0;
|
||||
|
||||
while (i < sprite_ordered_index)
|
||||
{
|
||||
if (SL_sprites_ordered[i * 4] == pixel_counter)
|
||||
{
|
||||
bottom_index++;
|
||||
if (bottom_index == SL_sprites_index) { no_sprites = true; }
|
||||
}
|
||||
else if (!have_sprite)
|
||||
{
|
||||
// we can use the current sprite, so pick out a pixel for it
|
||||
int t_index = pixel_counter - (SL_sprites_ordered[i * 4] - 8);
|
||||
|
||||
t_index = 7 - t_index;
|
||||
|
||||
sprite_data[0] = (byte)((SL_sprites_ordered[i * 4 + 1] >> t_index) & 1);
|
||||
sprite_data[1] = (byte)(((SL_sprites_ordered[i * 4 + 2] >> t_index) & 1) << 1);
|
||||
|
||||
s_pixel = sprite_data[0] + sprite_data[1];
|
||||
sprite_attr = SL_sprites_ordered[i * 4 + 3];
|
||||
|
||||
// pixel color of 0 is transparent, so if this is the case we dont have a pixel
|
||||
if (s_pixel != 0)
|
||||
{
|
||||
have_sprite = true;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (have_sprite)
|
||||
{
|
||||
bool use_sprite = false;
|
||||
if (LCDC.Bit(1))
|
||||
{
|
||||
if (!sprite_attr.Bit(7))
|
||||
{
|
||||
use_sprite = true;
|
||||
}
|
||||
else if (ref_pixel == 0)
|
||||
{
|
||||
use_sprite = true;
|
||||
}
|
||||
|
||||
if (!LCDC.Bit(0))
|
||||
{
|
||||
use_sprite = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_sprite)
|
||||
{
|
||||
if (sprite_attr.Bit(4))
|
||||
{
|
||||
pixel = (obj_pal_1 >> (s_pixel * 2)) & 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
pixel = (obj_pal_0 >> (s_pixel * 2)) & 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
have_sprite = true;
|
||||
s_pixel = sprite_pixel_list[pixel_counter];
|
||||
sprite_attr = sprite_attr_list[pixel_counter];
|
||||
}
|
||||
|
||||
// based on sprite priority and pixel values, pick a final pixel color
|
||||
Core._vidbuffer[LY * 160 + pixel_counter] = (int)Core.color_palette[pixel];
|
||||
pixel_counter++;
|
||||
|
||||
if (pixel_counter == 160)
|
||||
if (have_sprite)
|
||||
{
|
||||
read_case = 8;
|
||||
hbl_countdown = 4;
|
||||
bool use_sprite = false;
|
||||
if (LCDC.Bit(1))
|
||||
{
|
||||
if (!sprite_attr.Bit(7))
|
||||
{
|
||||
use_sprite = true;
|
||||
}
|
||||
else if (ref_pixel == 0)
|
||||
{
|
||||
use_sprite = true;
|
||||
}
|
||||
|
||||
if (!LCDC.Bit(0))
|
||||
{
|
||||
use_sprite = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_sprite)
|
||||
{
|
||||
if (sprite_attr.Bit(4))
|
||||
{
|
||||
pixel = (obj_pal_1 >> (s_pixel * 2)) & 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
pixel = (obj_pal_0 >> (s_pixel * 2)) & 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
render_counter++;
|
||||
|
||||
// based on sprite priority and pixel values, pick a final pixel color
|
||||
Core._vidbuffer[LY * 160 + pixel_counter] = (int)Core.color_palette[pixel];
|
||||
pixel_counter++;
|
||||
|
||||
if (pixel_counter == 160)
|
||||
{
|
||||
read_case = 8;
|
||||
hbl_countdown = 7;
|
||||
}
|
||||
}
|
||||
else if ((render_counter >= render_offset) && (pixel_counter < 0))
|
||||
{
|
||||
pixel_counter++;
|
||||
}
|
||||
render_counter++;
|
||||
}
|
||||
|
||||
if (!fetch_sprite)
|
||||
{
|
||||
if (latch_new_data)
|
||||
if (!pre_render)
|
||||
{
|
||||
latch_new_data = false;
|
||||
tile_data_latch[0] = tile_data[0];
|
||||
tile_data_latch[1] = tile_data[1];
|
||||
// before we go on to read case 3, we need to know if we stall there or not
|
||||
// Gekkio's tests show that if sprites are at position 0 or 1 (mod 8)
|
||||
// then it takes an extra cycle (1 or 2 more t-states) to process them
|
||||
|
||||
if (!no_sprites && (pixel_counter < 160))
|
||||
{
|
||||
for (int i = 0; i < SL_sprites_index; i++)
|
||||
{
|
||||
if ((pixel_counter >= (SL_sprites[i * 4 + 1] - 8)) &&
|
||||
(pixel_counter < (SL_sprites[i * 4 + 1])) &&
|
||||
!evaled_sprites.Bit(i))
|
||||
{
|
||||
going_to_fetch = true;
|
||||
fetch_sprite = true;
|
||||
|
||||
if ((SL_sprites[i * 4 + 1] % 8) < 2)
|
||||
{
|
||||
fetch_sprite_01 = true;
|
||||
}
|
||||
if ((SL_sprites[i * 4 + 1] % 8) > 3)
|
||||
{
|
||||
fetch_sprite_4 = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (read_case)
|
||||
|
@ -778,10 +766,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
case 0: // read a background tile
|
||||
if ((internal_cycle % 2) == 0)
|
||||
{
|
||||
// calculate the row number of the tiles to be fetched
|
||||
y_tile = ((int)Math.Floor((float)(scroll_y + LY) / 8)) % 32;
|
||||
|
||||
temp_fetch = y_tile * 32 + (x_tile + tile_inc) % 32;
|
||||
tile_byte = LCDC.Bit(3) ? Core.BG_map_2[temp_fetch] : Core.BG_map_1[temp_fetch];
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -857,7 +846,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
// here we set up rendering
|
||||
pre_render = false;
|
||||
render_offset = scroll_x % 8;
|
||||
render_counter = -1;
|
||||
render_counter = 0;
|
||||
latch_counter = 0;
|
||||
read_case = 0;
|
||||
}
|
||||
|
@ -865,7 +854,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
{
|
||||
read_case = 3;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -960,13 +948,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
// here we set up rendering
|
||||
window_pre_render = false;
|
||||
render_offset = 0;
|
||||
render_counter = -1;
|
||||
render_counter = 0;
|
||||
latch_counter = 0;
|
||||
read_case = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 7;
|
||||
|
||||
}
|
||||
}
|
||||
window_counter++;
|
||||
|
@ -1010,54 +999,71 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
break;
|
||||
}
|
||||
internal_cycle++;
|
||||
|
||||
if (latch_new_data)
|
||||
{
|
||||
latch_new_data = false;
|
||||
tile_data_latch[0] = tile_data[0];
|
||||
tile_data_latch[1] = tile_data[1];
|
||||
}
|
||||
}
|
||||
|
||||
// every in range sprite takes 6 cycles to process
|
||||
// sprites located at x=0 still take 6 cycles to process even though they don't appear on screen
|
||||
// sprites above x=168 do not take any cycles to process however
|
||||
if (fetch_sprite)
|
||||
{
|
||||
if (sprite_fetch_index < SL_sprites_index)
|
||||
if (going_to_fetch)
|
||||
{
|
||||
if (pixel_counter != 0) {
|
||||
if ((pixel_counter == (SL_sprites[sprite_fetch_index * 4 + 1] - 8)) &&
|
||||
//(pixel_counter < SL_sprites[sprite_fetch_index * 4 + 1]) &&
|
||||
!index_used.Bit(sprite_fetch_index))
|
||||
{
|
||||
sl_use_index = sprite_fetch_index;
|
||||
process_sprite();
|
||||
SL_sprites_ordered[sprite_ordered_index * 4] = SL_sprites[sprite_fetch_index * 4 + 1];
|
||||
SL_sprites_ordered[sprite_ordered_index * 4 + 1] = sprite_sel[0];
|
||||
SL_sprites_ordered[sprite_ordered_index * 4 + 2] = sprite_sel[1];
|
||||
SL_sprites_ordered[sprite_ordered_index * 4 + 3] = SL_sprites[sprite_fetch_index * 4 + 3];
|
||||
sprite_ordered_index++;
|
||||
index_used |= (1 << sl_use_index);
|
||||
}
|
||||
sprite_fetch_index++;
|
||||
if (sprite_fetch_index == SL_sprites_index) { fetch_sprite = false; }
|
||||
}
|
||||
else
|
||||
going_to_fetch = false;
|
||||
sprite_fetch_counter = 0;
|
||||
|
||||
if (fetch_sprite_01)
|
||||
{
|
||||
// whan pixel counter is 0, we want to scan all the points before 0 as well
|
||||
// certainly non-physical but good enough for now
|
||||
for (int j = -7; j < 1; j++)
|
||||
sprite_fetch_counter += 2;
|
||||
fetch_sprite_01 = false;
|
||||
}
|
||||
|
||||
if (fetch_sprite_4)
|
||||
{
|
||||
sprite_fetch_counter -= 2;
|
||||
fetch_sprite_4 = false;
|
||||
}
|
||||
|
||||
int last_eval = 0;
|
||||
|
||||
// at this time it is unknown what each cycle does, but we only need to accurately keep track of cycles
|
||||
for (int i = 0; i < SL_sprites_index; i++)
|
||||
{
|
||||
if ((pixel_counter >= (SL_sprites[i * 4 + 1] - 8)) &&
|
||||
(pixel_counter < (SL_sprites[i * 4 + 1])) &&
|
||||
!evaled_sprites.Bit(i))
|
||||
{
|
||||
for (int i = 0; i < SL_sprites_index; i++)
|
||||
{
|
||||
if ((j == (SL_sprites[i * 4 + 1] - 8)) &&
|
||||
!index_used.Bit(i))
|
||||
{
|
||||
sl_use_index = i;
|
||||
process_sprite();
|
||||
SL_sprites_ordered[sprite_ordered_index * 4] = SL_sprites[i * 4 + 1];
|
||||
SL_sprites_ordered[sprite_ordered_index * 4 + 1] = sprite_sel[0];
|
||||
SL_sprites_ordered[sprite_ordered_index * 4 + 2] = sprite_sel[1];
|
||||
SL_sprites_ordered[sprite_ordered_index * 4 + 3] = SL_sprites[i * 4 + 3];
|
||||
sprite_ordered_index++;
|
||||
index_used |= (1 << sl_use_index);
|
||||
}
|
||||
}
|
||||
sprite_fetch_counter += 6;
|
||||
evaled_sprites |= (1 << i);
|
||||
last_eval = SL_sprites[i * 4 + 1];
|
||||
}
|
||||
fetch_sprite = false;
|
||||
}
|
||||
|
||||
// if we didn't evaluate all the sprites immediately, 2 more cycles are added to restart it
|
||||
if (evaled_sprites != (Math.Pow(2,SL_sprites_index) - 1))
|
||||
{
|
||||
if ((last_eval % 8) == 0) { sprite_fetch_counter += 3; }
|
||||
else if ((last_eval % 8) == 1) { sprite_fetch_counter += 2; }
|
||||
else if ((last_eval % 8) == 2) { sprite_fetch_counter += 3; }
|
||||
else if ((last_eval % 8) == 3) { sprite_fetch_counter += 2; }
|
||||
else if ((last_eval % 8) == 4) { sprite_fetch_counter += 3; }
|
||||
else { sprite_fetch_counter += 2; }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sprite_fetch_counter--;
|
||||
if (sprite_fetch_counter == 0)
|
||||
{
|
||||
fetch_sprite = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1075,12 +1081,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
obj_pal_1 = 0xFF;
|
||||
window_y = 0x0;
|
||||
window_x = 0x0;
|
||||
window_x_latch = 0xFF;
|
||||
LY_inc = 1;
|
||||
no_scan = false;
|
||||
OAM_access_read = true;
|
||||
VRAM_access_read = true;
|
||||
OAM_access_write = true;
|
||||
VRAM_access_write = true;
|
||||
DMA_OAM_access = true;
|
||||
|
||||
cycle = 0;
|
||||
LYC_INT = false;
|
||||
|
@ -1156,6 +1164,74 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
}
|
||||
|
||||
// order sprites according to x coordinate
|
||||
// note that for sprites of equal x coordinate, priority goes to first on the list
|
||||
public void reorder_and_assemble_sprites()
|
||||
{
|
||||
sprite_ordered_index = 0;
|
||||
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
for (int j = 0; j < SL_sprites_index; j++)
|
||||
{
|
||||
if (SL_sprites[j * 4 + 1] == i)
|
||||
{
|
||||
sl_use_index = j;
|
||||
process_sprite();
|
||||
SL_sprites_ordered[sprite_ordered_index * 4] = SL_sprites[j * 4 + 1];
|
||||
SL_sprites_ordered[sprite_ordered_index * 4 + 1] = sprite_sel[0];
|
||||
SL_sprites_ordered[sprite_ordered_index * 4 + 2] = sprite_sel[1];
|
||||
SL_sprites_ordered[sprite_ordered_index * 4 + 3] = SL_sprites[j * 4 + 3];
|
||||
sprite_ordered_index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool have_pixel = false;
|
||||
byte s_pixel = 0;
|
||||
byte sprite_attr = 0;
|
||||
|
||||
for (int i = 0; i < 160; i++)
|
||||
{
|
||||
have_pixel = false;
|
||||
for (int j = 0; j < SL_sprites_index; j++)
|
||||
{
|
||||
if ((i >= (SL_sprites_ordered[j * 4] - 8)) &&
|
||||
(i < SL_sprites_ordered[j * 4]) &&
|
||||
!have_pixel)
|
||||
{
|
||||
// we can use the current sprite, so pick out a pixel for it
|
||||
int t_index = i - (SL_sprites_ordered[j * 4] - 8);
|
||||
|
||||
t_index = 7 - t_index;
|
||||
|
||||
sprite_data[0] = (byte)((SL_sprites_ordered[j * 4 + 1] >> t_index) & 1);
|
||||
sprite_data[1] = (byte)(((SL_sprites_ordered[j * 4 + 2] >> t_index) & 1) << 1);
|
||||
|
||||
s_pixel = (byte)(sprite_data[0] + sprite_data[1]);
|
||||
sprite_attr = (byte)SL_sprites_ordered[j * 4 + 3];
|
||||
|
||||
// pixel color of 0 is transparent, so if this is the case we dont have a pixel
|
||||
if (s_pixel != 0)
|
||||
{
|
||||
have_pixel = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (have_pixel)
|
||||
{
|
||||
sprite_present_list[i] = 1;
|
||||
sprite_pixel_list[i] = s_pixel;
|
||||
sprite_attr_list[i] = sprite_attr;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprite_present_list[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.Sync("LCDC", ref LCDC);
|
||||
|
@ -1206,6 +1282,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
ser.Sync("tile_byte", ref tile_byte);
|
||||
ser.Sync("sprite_fetch_cycles", ref sprite_fetch_cycles);
|
||||
ser.Sync("fetch_sprite", ref fetch_sprite);
|
||||
ser.Sync("fetch_sprite_01", ref fetch_sprite_01);
|
||||
ser.Sync("fetch_sprite_4", ref fetch_sprite_4);
|
||||
ser.Sync("going_to_fetch", ref going_to_fetch);
|
||||
ser.Sync("sprite_fetch_counter", ref sprite_fetch_counter);
|
||||
ser.Sync("sprite_attr_list", ref sprite_attr_list, false);
|
||||
ser.Sync("sprite_pixel_list", ref sprite_pixel_list, false);
|
||||
ser.Sync("sprite_present_list", ref sprite_present_list, false);
|
||||
ser.Sync("temp_fetch", ref temp_fetch);
|
||||
ser.Sync("tile_inc", ref tile_inc);
|
||||
ser.Sync("pre_render", ref pre_render);
|
||||
|
@ -1221,11 +1304,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
ser.Sync("sl_use_index", ref sl_use_index);
|
||||
ser.Sync("sprite_sel", ref sprite_sel, false);
|
||||
ser.Sync("no_sprites", ref no_sprites);
|
||||
ser.Sync("sprite_fetch_index", ref sprite_fetch_index);
|
||||
ser.Sync("evaled_sprites", ref evaled_sprites);
|
||||
ser.Sync("SL_sprites_ordered", ref SL_sprites_ordered, false);
|
||||
ser.Sync("index_used", ref index_used);
|
||||
ser.Sync("sprite_ordered_index", ref sprite_ordered_index);
|
||||
ser.Sync("bottom_index", ref bottom_index);
|
||||
ser.Sync("blank_frame", ref blank_frame);
|
||||
|
||||
ser.Sync("window_counter", ref window_counter);
|
||||
ser.Sync("window_pre_render", ref window_pre_render);
|
||||
|
@ -1234,6 +1316,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
ser.Sync("window_y_tile", ref window_y_tile);
|
||||
ser.Sync("window_x_tile", ref window_x_tile);
|
||||
ser.Sync("window_y_tile_inc", ref window_y_tile_inc);
|
||||
ser.Sync("window_x_latch", ref window_x_latch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
writer.Write(Frame);
|
||||
writer.Write(frameOverflow);
|
||||
writer.Write(_cycleCount);
|
||||
writer.Write(IsCgb);
|
||||
}
|
||||
|
||||
public void LoadStateBinary(BinaryReader reader)
|
||||
|
@ -61,6 +62,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
Frame = reader.ReadInt32();
|
||||
frameOverflow = reader.ReadUInt32();
|
||||
_cycleCount = reader.ReadUInt64();
|
||||
IsCgb = reader.ReadBoolean();
|
||||
}
|
||||
|
||||
public byte[] SaveStateBinary()
|
||||
|
@ -84,7 +86,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
private void NewSaveCoreSetBuff()
|
||||
{
|
||||
_savebuff = new byte[LibGambatte.gambatte_newstatelen(GambatteState)];
|
||||
_savebuff2 = new byte[_savebuff.Length + 4 + 21];
|
||||
_savebuff2 = new byte[_savebuff.Length + 4 + 21 + 1];
|
||||
}
|
||||
|
||||
private readonly JsonSerializer ser = new JsonSerializer { Formatting = Formatting.Indented };
|
||||
|
@ -97,6 +99,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
public bool IsLagFrame;
|
||||
public ulong _cycleCount;
|
||||
public uint frameOverflow;
|
||||
public bool IsCgb;
|
||||
}
|
||||
|
||||
internal TextState<TextStateData> SaveState()
|
||||
|
@ -110,6 +113,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
s.ExtraData.Frame = Frame;
|
||||
s.ExtraData.frameOverflow = frameOverflow;
|
||||
s.ExtraData._cycleCount = _cycleCount;
|
||||
s.ExtraData.IsCgb = IsCgb;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -123,6 +127,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
Frame = s.ExtraData.Frame;
|
||||
frameOverflow = s.ExtraData.frameOverflow;
|
||||
_cycleCount = s.ExtraData._cycleCount;
|
||||
IsCgb = s.ExtraData.IsCgb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,6 +93,29 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
throw new InvalidOperationException("gambatte_load() returned non-zero (is this not a gb or gbc rom?)");
|
||||
}
|
||||
|
||||
if ((flags & LibGambatte.LoadFlags.FORCE_DMG) == LibGambatte.LoadFlags.FORCE_DMG)
|
||||
{
|
||||
byte[] Bios = comm.CoreFileProvider.GetFirmware("GB", "World", true, "BIOS Not Found, Cannot Load");
|
||||
|
||||
IsCgb = false;
|
||||
|
||||
if (LibGambatte.gambatte_loaddmgbios(GambatteState, Bios) != 0)
|
||||
{
|
||||
throw new InvalidOperationException("gambatte_loaddmgbios() returned non-zero (bios error)");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] Bios = comm.CoreFileProvider.GetFirmware("GBC", "World", true, "BIOS Not Found, Cannot Load");
|
||||
|
||||
IsCgb = true;
|
||||
|
||||
if (LibGambatte.gambatte_loadgbcbios(GambatteState, Bios) != 0)
|
||||
{
|
||||
throw new InvalidOperationException("gambatte_loadgbcbios() returned non-zero (bios error)");
|
||||
}
|
||||
}
|
||||
|
||||
// set real default colors (before anyone mucks with them at all)
|
||||
PutSettings((GambatteSettings)settings ?? new GambatteSettings());
|
||||
|
||||
|
@ -209,6 +232,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
|
||||
public int LagCount { get; set; }
|
||||
public bool IsLagFrame { get; set; }
|
||||
public bool IsCgb { get; set; }
|
||||
|
||||
// all cycle counts are relative to a 2*1024*1024 mhz refclock
|
||||
|
||||
|
@ -251,7 +275,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
/// </summary>
|
||||
public bool IsCGBMode()
|
||||
{
|
||||
return LibGambatte.gambatte_iscgb(GambatteState);
|
||||
//return LibGambatte.gambatte_iscgb(GambatteState);
|
||||
return IsCgb;
|
||||
}
|
||||
|
||||
private InputCallbackSystem _inputCallbacks = new InputCallbackSystem();
|
||||
|
|
|
@ -59,6 +59,24 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int gambatte_load(IntPtr core, byte[] romdata, uint length, long now, LoadFlags flags);
|
||||
|
||||
/// <summary>
|
||||
/// Load GB BIOS image.
|
||||
/// </summary>
|
||||
/// <param name="core">opaque state pointer</param>
|
||||
/// <param name="biosdata">the bios data, can be disposed of once this function returns</param>
|
||||
/// <returns>0 on success, negative value on failure.</returns>
|
||||
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int gambatte_loaddmgbios(IntPtr core, byte[] biosdata);
|
||||
|
||||
/// <summary>
|
||||
/// Load GBC BIOS image.
|
||||
/// </summary>
|
||||
/// <param name="core">opaque state pointer</param>
|
||||
/// <param name="biosdata">the bios data, can be disposed of once this function returns</param>
|
||||
/// <returns>0 on success, negative value on failure.</returns>
|
||||
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int gambatte_loadgbcbios(IntPtr core, byte[] biosdata);
|
||||
|
||||
/// <summary>
|
||||
/// Emulates until at least 'samples' stereo sound samples are produced in the supplied buffer,
|
||||
/// or until a video frame has been drawn.
|
||||
|
|
|
@ -1328,6 +1328,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
}
|
||||
|
||||
SyncIRQ();
|
||||
nes._irq_apu = irq_pending;
|
||||
|
||||
// since the units run concurrently, the APU frame sequencer is ran last because
|
||||
// it can change the ouput values of the pulse/triangle channels
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
using System;
|
||||
using BizHawk.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||
{
|
||||
public sealed class Mapper043 : NES.NESBoardBase
|
||||
{
|
||||
int prg = 0;
|
||||
int irqcnt = 0;
|
||||
bool irqenable = false;
|
||||
bool swap;
|
||||
|
||||
|
||||
private static int[] lut = { 4, 3, 5, 3, 6, 3, 7, 3 };
|
||||
|
||||
public override bool Configure(NES.EDetectionOrigin origin)
|
||||
{
|
||||
switch (Cart.board_type)
|
||||
{
|
||||
case "MAPPER043":
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
Cart.wram_size = 0;
|
||||
// not sure on initial mirroring
|
||||
SetMirrorType(EMirrorType.Vertical);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void WriteEXP(int addr, byte value)
|
||||
{
|
||||
addr += 0x4000;
|
||||
|
||||
switch (addr & 0xF1FF)
|
||||
{
|
||||
case 0x4022:
|
||||
prg = lut[value & 0x7];
|
||||
break;
|
||||
|
||||
case 0x4120:
|
||||
swap = (value & 1) == 1;
|
||||
break;
|
||||
|
||||
case 0x4122:
|
||||
irqenable = (value & 1) == 1;
|
||||
IRQSignal = false;
|
||||
irqcnt = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void WritePRG(int addr, byte value)
|
||||
{
|
||||
addr += 0x8000;
|
||||
switch (addr & 0xF1FF)
|
||||
{
|
||||
case 0x8122:
|
||||
irqenable = (value & 1) == 1;
|
||||
IRQSignal = false;
|
||||
irqcnt = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override byte ReadEXP(int addr)
|
||||
{
|
||||
if (addr > 0x1000)
|
||||
{
|
||||
return ROM[(addr - 0x1000) + 8 * 0x2000];
|
||||
}
|
||||
else return base.ReadEXP(addr);
|
||||
}
|
||||
|
||||
public override byte ReadWRAM(int addr)
|
||||
{
|
||||
if (swap)
|
||||
{
|
||||
return ROM[addr];
|
||||
}
|
||||
else
|
||||
{
|
||||
return ROM[addr + 0x4000];
|
||||
}
|
||||
}
|
||||
|
||||
public override byte ReadPRG(int addr)
|
||||
{
|
||||
if (addr < 0x2000)
|
||||
{
|
||||
return ROM[addr + 0x2000];
|
||||
}
|
||||
else if (addr < 0x4000)
|
||||
{
|
||||
return ROM[addr - 0x2000];
|
||||
}
|
||||
else if (addr < 0x6000)
|
||||
{
|
||||
return ROM[(addr - 0x4000) + prg * 0x2000];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (swap)
|
||||
{
|
||||
return ROM[(addr - 0x6000) + 8 * 0x2000];
|
||||
}
|
||||
else
|
||||
{
|
||||
return ROM[(addr - 0x6000) + 9 * 0x2000];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void ClockCPU()
|
||||
{
|
||||
if (irqenable)
|
||||
{
|
||||
irqcnt++;
|
||||
|
||||
if (irqcnt >= 4096)
|
||||
{
|
||||
irqenable = false;
|
||||
IRQSignal = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void SyncState(Serializer ser)
|
||||
{
|
||||
base.SyncState(ser);
|
||||
ser.Sync("prg", ref prg);
|
||||
ser.Sync("irqenable", ref irqenable);
|
||||
ser.Sync("irqcnt", ref irqcnt);
|
||||
ser.Sync("swap", ref swap);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
using System;
|
||||
using BizHawk.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||
{
|
||||
public sealed class Mapper063 : NES.NESBoardBase
|
||||
{
|
||||
int prg0, prg1, prg2, prg3;
|
||||
bool open_bus;
|
||||
|
||||
public override bool Configure(NES.EDetectionOrigin origin)
|
||||
{
|
||||
switch (Cart.board_type)
|
||||
{
|
||||
case "MAPPER063":
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
Cart.wram_size = 0;
|
||||
// not sure on initial mirroring
|
||||
SetMirrorType(EMirrorType.Vertical);
|
||||
|
||||
WritePRG(0, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void WritePRG(int addr, byte value)
|
||||
{
|
||||
open_bus = ((addr & 0x0300) == 0x0300);
|
||||
|
||||
prg0 = (addr >> 1 & 0x1FC) | ((addr & 0x2) > 0 ? 0x0 : (addr >> 1 & 0x2) | 0x0);
|
||||
prg1 = (addr >> 1 & 0x1FC) | ((addr & 0x2) > 0 ? 0x1 : (addr >> 1 & 0x2) | 0x1);
|
||||
prg2 = (addr >> 1 & 0x1FC) | ((addr & 0x2) > 0 ? 0x2 : (addr >> 1 & 0x2) | 0x0);
|
||||
prg3 = (addr & 0x800) > 0 ? ((addr & 0x07C) | ((addr & 0x06) > 0 ? 0x03 : 0x01)) : ((addr >> 1 & 0x01FC) | ((addr & 0x02) > 0 ? 0x03 : ((addr >> 1 & 0x02) | 0x01)));
|
||||
|
||||
SetMirrorType((addr & 0x01) > 0 ? EMirrorType.Horizontal : EMirrorType.Vertical);
|
||||
}
|
||||
|
||||
public override byte ReadPRG(int addr)
|
||||
{
|
||||
if (addr < 0x2000)
|
||||
{
|
||||
if (open_bus)
|
||||
{
|
||||
return this.NES.DB;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ROM[addr + prg0 * 0x2000];
|
||||
}
|
||||
}
|
||||
else if (addr < 0x4000)
|
||||
{
|
||||
if (open_bus)
|
||||
{
|
||||
return this.NES.DB;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ROM[(addr - 0x2000) + prg1 * 0x2000];
|
||||
}
|
||||
}
|
||||
else if (addr < 0x6000)
|
||||
{
|
||||
return ROM[(addr - 0x4000) + prg2 * 0x2000];
|
||||
}
|
||||
else
|
||||
{
|
||||
return ROM[(addr - 0x6000) + prg3 * 0x2000];
|
||||
}
|
||||
}
|
||||
|
||||
public override void SyncState(Serializer ser)
|
||||
{
|
||||
base.SyncState(ser);
|
||||
ser.Sync("prg0", ref prg0);
|
||||
ser.Sync("prg1", ref prg1);
|
||||
ser.Sync("prg2", ref prg2);
|
||||
ser.Sync("prg3", ref prg3);
|
||||
ser.Sync("open_bus", ref open_bus);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -33,36 +33,20 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
|
||||
public override void WritePRG(int addr, byte value)
|
||||
{
|
||||
if (addr < 0x1000) // 0x8000 - 0x8FFF
|
||||
{
|
||||
base.WritePRG(addr & 1, Unscramble(value));
|
||||
}
|
||||
value = Unscramble(value);
|
||||
|
||||
else if (addr == 0x1000) // 9000 = 8001
|
||||
if (addr == 0x1000) // 9000 = 8001
|
||||
{
|
||||
base.WritePRG(1, Unscramble(value));
|
||||
base.WritePRG(1, value);
|
||||
}
|
||||
|
||||
else if (addr == 0x2000) // A000 = 8000)
|
||||
{
|
||||
base.WritePRG(0, Unscramble(value));
|
||||
}
|
||||
|
||||
else if (addr == 0x5000) // D000 = C001
|
||||
{
|
||||
base.WritePRG(0x4001, Unscramble(value));
|
||||
base.WritePRG(0x4001, value);
|
||||
}
|
||||
|
||||
else if (addr >= 0x6000 && addr < 0x7000) // 0xE0000 - 0xEFFF
|
||||
else if (addr == 0x7000) // F000 = E001
|
||||
{
|
||||
base.WritePRG(addr & 1, Unscramble(value));
|
||||
base.WritePRG(0x6001, value);
|
||||
}
|
||||
|
||||
else if (addr == 0x7000) // F000
|
||||
{
|
||||
base.WritePRG(0x6001, Unscramble(value));
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
base.WritePRG(addr, value);
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
using System;
|
||||
using BizHawk.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||
{
|
||||
public sealed class UNIF_UNL_SMB2J : NES.NESBoardBase
|
||||
{
|
||||
int prg = 0;
|
||||
int prg_count;
|
||||
int irqcnt = 0;
|
||||
bool irqenable = false;
|
||||
bool swap;
|
||||
|
||||
public override bool Configure(NES.EDetectionOrigin origin)
|
||||
{
|
||||
switch (Cart.board_type)
|
||||
{
|
||||
case "UNIF_UNL-SMB2J":
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
prg_count = Cart.prg_size/4;
|
||||
|
||||
Cart.wram_size = 0;
|
||||
// not sure on initial mirroring
|
||||
SetMirrorType(EMirrorType.Vertical);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void WriteEXP(int addr, byte value)
|
||||
{
|
||||
addr += 0x4000;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0x4022:
|
||||
if (ROM.Length > 0x10000) { prg = (value & 0x01) << 2; }
|
||||
break;
|
||||
|
||||
case 0x4122:
|
||||
irqenable = (value & 3) > 0;
|
||||
IRQSignal = false;
|
||||
irqcnt = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override byte ReadEXP(int addr)
|
||||
{
|
||||
if (addr > 0x1000)
|
||||
{
|
||||
return ROM[(addr - 0x1000) + (prg_count - 3) * 0x1000];
|
||||
}
|
||||
else return base.ReadEXP(addr);
|
||||
}
|
||||
|
||||
public override byte ReadWRAM(int addr)
|
||||
{
|
||||
return ROM[addr + (prg_count - 2) * 0x1000];
|
||||
}
|
||||
|
||||
public override byte ReadPRG(int addr)
|
||||
{
|
||||
return ROM[(addr + prg * 01000)];
|
||||
}
|
||||
|
||||
public override void ClockCPU()
|
||||
{
|
||||
if (irqenable)
|
||||
{
|
||||
irqcnt++;
|
||||
|
||||
if (irqcnt >= 4096)
|
||||
{
|
||||
irqenable = false;
|
||||
IRQSignal = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void SyncState(Serializer ser)
|
||||
{
|
||||
base.SyncState(ser);
|
||||
ser.Sync("prg", ref prg);
|
||||
ser.Sync("irqenable", ref irqenable);
|
||||
ser.Sync("irqcnt", ref irqcnt);
|
||||
ser.Sync("swap", ref swap);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -69,6 +69,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
for (int i = 0; i < NumSides; i++)
|
||||
ser.Sync("diskdiffs" + i, ref diskdiffs[i], true);
|
||||
ser.Sync("_timerirq", ref _timerirq);
|
||||
ser.Sync("timer_irq_active", ref timer_irq_active);
|
||||
ser.Sync("timerirq_cd", ref timerirq_cd);
|
||||
ser.Sync("_diskirq", ref _diskirq);
|
||||
ser.Sync("diskenable", ref diskenable);
|
||||
ser.Sync("soundenable", ref soundenable);
|
||||
|
@ -237,7 +239,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
}
|
||||
bool diskirq { get { return _diskirq; } set { _diskirq = value; SetIRQ(); } }
|
||||
bool timerirq { get { return _timerirq; } set { _timerirq = value; SetIRQ(); } }
|
||||
|
||||
int timerirq_cd;
|
||||
bool timer_irq_active;
|
||||
|
||||
public override void WriteEXP(int addr, byte value)
|
||||
{
|
||||
|
@ -270,14 +273,19 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
}
|
||||
else
|
||||
{
|
||||
_timerirq = false;
|
||||
timerirq = false;
|
||||
timer_irq_active = false;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case 0x0023:
|
||||
diskenable = (value & 1) != 0;
|
||||
if (!diskenable) { _timerirq = false; }
|
||||
if (!diskenable)
|
||||
{
|
||||
timerirq = false;
|
||||
timer_irq_active = false;
|
||||
}
|
||||
soundenable = (value & 2) != 0;
|
||||
break;
|
||||
case 0x0024:
|
||||
|
@ -315,6 +323,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
ret |= 1;
|
||||
ret |= (byte)tmp;
|
||||
timerirq = false;
|
||||
timer_irq_active = false;
|
||||
}
|
||||
break;
|
||||
case 0x0031:
|
||||
|
@ -360,16 +369,34 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
{
|
||||
timervalue--;
|
||||
}
|
||||
if (timervalue == 0)
|
||||
else
|
||||
{
|
||||
timervalue = timerlatch;
|
||||
timerirq = true;
|
||||
//timerirq = true;
|
||||
if ((timerreg & 1) == 0)
|
||||
{
|
||||
timerreg -= 2;
|
||||
}
|
||||
|
||||
if (!timer_irq_active)
|
||||
{
|
||||
timer_irq_active = true;
|
||||
timerirq_cd = 3;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (timerirq_cd > 0)
|
||||
{
|
||||
timerirq_cd--;
|
||||
}
|
||||
|
||||
if ((timerirq_cd == 0) && (timer_irq_active))
|
||||
{
|
||||
timerirq = true;
|
||||
}
|
||||
|
||||
audio.Clock();
|
||||
}
|
||||
|
||||
|
|
|
@ -214,7 +214,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
disk = null;
|
||||
state = RamAdapterState.IDLE;
|
||||
SetCycles();
|
||||
Console.WriteLine("FDS: Disk ejected");
|
||||
//Console.WriteLine("FDS: Disk ejected");
|
||||
DriveLightCallback?.Invoke(false);
|
||||
}
|
||||
|
||||
|
@ -234,7 +234,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
this.writeprotect = writeprotect;
|
||||
state = RamAdapterState.INSERTING;
|
||||
SetCycles();
|
||||
Console.WriteLine("FDS: Disk Inserted");
|
||||
//Console.WriteLine("FDS: Disk Inserted");
|
||||
originaldisk = (byte[])disk.Clone();
|
||||
DriveLightCallback?.Invoke(false);
|
||||
}
|
||||
|
@ -388,7 +388,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
}
|
||||
}
|
||||
if ((value & 2) != 0)
|
||||
{
|
||||
transferreset = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
transferreset = false;
|
||||
}
|
||||
|
||||
if ((cached4025 & 0x40) == 0 && (value & 0x40) != 0)
|
||||
{
|
||||
lookingforendofgap = true;
|
||||
|
@ -469,6 +476,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
if (disk != null && state != RamAdapterState.INSERTING && !writeprotect)
|
||||
ret &= unchecked((byte)~0x04);
|
||||
|
||||
//Console.Write(state);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -491,9 +500,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
Write();
|
||||
if (diskpos >= disksize)
|
||||
{
|
||||
// Console.WriteLine("FDS: End of Disk");
|
||||
//Console.WriteLine("FDS: End of Disk");
|
||||
state = RamAdapterState.RESET;
|
||||
transferreset = false;
|
||||
//transferreset = false;
|
||||
//numcrc = 0;
|
||||
DriveLightCallback?.Invoke(false);
|
||||
}
|
||||
|
@ -505,9 +514,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
state = RamAdapterState.IDLE;
|
||||
diskpos = 0;
|
||||
SetCycles();
|
||||
transferreset = false;
|
||||
//transferreset = false;
|
||||
//numcrc = 0;
|
||||
// Console.WriteLine("FDS: Return or Insert Complete");
|
||||
//Console.WriteLine("FDS: Return or Insert Complete");
|
||||
DriveLightCallback?.Invoke(false);
|
||||
break;
|
||||
case RamAdapterState.SPINUP:
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
EDetectionOrigin origin = EDetectionOrigin.None;
|
||||
int sprdma_countdown;
|
||||
|
||||
bool _irq_apu; //various irq signals that get merged to the cpu irq pin
|
||||
public bool _irq_apu; //various irq signals that get merged to the cpu irq pin
|
||||
|
||||
/// <summary>clock speed of the main cpu in hz</summary>
|
||||
public int cpuclockrate { get; private set; }
|
||||
|
@ -288,6 +288,17 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
ram[0xEC] = 0;
|
||||
ram[0xED] = 0;
|
||||
}
|
||||
|
||||
if (cart.DB_GameInfo.Hash == "00C50062A2DECE99580063777590F26A253AAB6B") // Silva Saga
|
||||
{
|
||||
for (int i = 0; i < Board.WRAM.Length; i++)
|
||||
{
|
||||
Board.WRAM[i] = 0xFF;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -34,9 +34,10 @@ namespace BizHawk.Emulation.Cores.PCEngine
|
|||
if (MultiResHack > 0 && render)
|
||||
Array.Clear(FrameBuffer, 0, FrameBuffer.Length);
|
||||
|
||||
int ActiveDisplayStartLine = DisplayStartLine;
|
||||
|
||||
while (true)
|
||||
{
|
||||
int ActiveDisplayStartLine = DisplayStartLine;
|
||||
int VBlankLine = ActiveDisplayStartLine + Registers[VDW] + 1;
|
||||
if (VBlankLine > 261)
|
||||
VBlankLine = 261;
|
||||
|
@ -106,7 +107,7 @@ namespace BizHawk.Emulation.Cores.PCEngine
|
|||
|
||||
public void RenderScanLine()
|
||||
{
|
||||
if (ActiveLine >= FrameHeight)
|
||||
if ((ActiveLine + ViewStartLine) >= 262)
|
||||
return;
|
||||
|
||||
RenderBackgroundScanline(pce.Settings.ShowBG1);
|
||||
|
@ -124,7 +125,7 @@ namespace BizHawk.Emulation.Cores.PCEngine
|
|||
int p = vce.Palette[256];
|
||||
fixed (int* FBptr = FrameBuffer)
|
||||
{
|
||||
int* dst = FBptr + ActiveLine * FramePitch;
|
||||
int* dst = FBptr + (ActiveLine + ViewStartLine) * FramePitch;
|
||||
for (int i = 0; i < FrameWidth; i++)
|
||||
*dst++ = p;
|
||||
}
|
||||
|
@ -148,7 +149,7 @@ namespace BizHawk.Emulation.Cores.PCEngine
|
|||
{
|
||||
// pointer to the BAT and the framebuffer for this line
|
||||
ushort* BatRow = VRAMptr + yTile * BatWidth;
|
||||
int* dst = FBptr + ActiveLine * FramePitch;
|
||||
int* dst = FBptr + (ActiveLine + ViewStartLine) * FramePitch;
|
||||
|
||||
// parameters that change per tile
|
||||
ushort BatEnt;
|
||||
|
@ -202,7 +203,7 @@ namespace BizHawk.Emulation.Cores.PCEngine
|
|||
if (BackgroundEnabled == false)
|
||||
{
|
||||
for (int i = 0; i < FrameWidth; i++)
|
||||
FrameBuffer[(ActiveLine * FramePitch) + i] = vce.Palette[256];
|
||||
FrameBuffer[((ActiveLine + ViewStartLine) * FramePitch) + i] = vce.Palette[256];
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -226,10 +227,10 @@ namespace BizHawk.Emulation.Cores.PCEngine
|
|||
|
||||
byte c = PatternBuffer[(tileNo * 64) + (yOfs * 8) + xOfs];
|
||||
if (c == 0)
|
||||
FrameBuffer[(ActiveLine * FramePitch) + x] = vce.Palette[0];
|
||||
FrameBuffer[((ActiveLine + ViewStartLine) * FramePitch) + x] = vce.Palette[0];
|
||||
else
|
||||
{
|
||||
FrameBuffer[(ActiveLine * FramePitch) + x] = show ? vce.Palette[paletteBase + c] : vce.Palette[0];
|
||||
FrameBuffer[((ActiveLine + ViewStartLine) * FramePitch) + x] = show ? vce.Palette[paletteBase + c] : vce.Palette[0];
|
||||
PriorityBuffer[x] = 1;
|
||||
}
|
||||
}
|
||||
|
@ -361,7 +362,7 @@ namespace BizHawk.Emulation.Cores.PCEngine
|
|||
{
|
||||
InterSpritePriorityBuffer[xs] = 1;
|
||||
if ((priority || PriorityBuffer[xs] == 0) && show)
|
||||
FrameBuffer[(ActiveLine * FramePitch) + xs] = vce.Palette[paletteBase + pixel];
|
||||
FrameBuffer[((ActiveLine + ViewStartLine) * FramePitch) + xs] = vce.Palette[paletteBase + pixel];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -378,7 +379,7 @@ namespace BizHawk.Emulation.Cores.PCEngine
|
|||
{
|
||||
InterSpritePriorityBuffer[xs] = 1;
|
||||
if ((priority || PriorityBuffer[xs] == 0) && show)
|
||||
FrameBuffer[(ActiveLine * FramePitch) + xs] = vce.Palette[paletteBase + pixel];
|
||||
FrameBuffer[((ActiveLine + ViewStartLine) * FramePitch) + xs] = vce.Palette[paletteBase + pixel];
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -399,7 +400,7 @@ namespace BizHawk.Emulation.Cores.PCEngine
|
|||
{
|
||||
InterSpritePriorityBuffer[xs] = 1;
|
||||
if ((priority || PriorityBuffer[xs] == 0) && show)
|
||||
FrameBuffer[(ActiveLine * FramePitch) + xs] = vce.Palette[paletteBase + pixel];
|
||||
FrameBuffer[((ActiveLine + ViewStartLine) * FramePitch) + xs] = vce.Palette[paletteBase + pixel];
|
||||
}
|
||||
}
|
||||
if (width == 32)
|
||||
|
@ -415,7 +416,7 @@ namespace BizHawk.Emulation.Cores.PCEngine
|
|||
{
|
||||
InterSpritePriorityBuffer[xs] = 1;
|
||||
if ((priority || PriorityBuffer[xs] == 0) && show)
|
||||
FrameBuffer[(ActiveLine * FramePitch) + xs] = vce.Palette[paletteBase + pixel];
|
||||
FrameBuffer[((ActiveLine + ViewStartLine) * FramePitch) + xs] = vce.Palette[paletteBase + pixel];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -426,8 +427,8 @@ namespace BizHawk.Emulation.Cores.PCEngine
|
|||
|
||||
private int FramePitch = 256;
|
||||
private int FrameWidth = 256;
|
||||
private int FrameHeight = 240;
|
||||
private int[] FrameBuffer = new int[256 * 240];
|
||||
private int FrameHeight = 262;
|
||||
private int[] FrameBuffer = new int[256 * 262];
|
||||
|
||||
// IVideoProvider implementation
|
||||
public int[] GetVideoBuffer()
|
||||
|
|
|
@ -49,6 +49,7 @@ namespace BizHawk.Emulation.Cores.PCEngine
|
|||
public int RequestedFrameWidth => ((Registers[HDR] & 0x3F) + 1) * 8;
|
||||
public int RequestedFrameHeight => (Registers[VDW] & 0x1FF) + 1;
|
||||
public int DisplayStartLine => (Registers[VPR] >> 8) + (Registers[VPR] & 0x1F);
|
||||
public int ViewStartLine => (Registers[VPR] >> 8) + 2;
|
||||
|
||||
private const int MAWR = 0; // Memory Address Write Register
|
||||
private const int MARR = 1; // Memory Address Read Register
|
||||
|
@ -158,18 +159,20 @@ namespace BizHawk.Emulation.Cores.PCEngine
|
|||
case HDR: // Horizontal Display Register - update framebuffer size
|
||||
FrameWidth = RequestedFrameWidth;
|
||||
FramePitch = MultiResHack == 0 ? FrameWidth : MultiResHack;
|
||||
if (FrameBuffer.Length != FramePitch * FrameHeight)
|
||||
FrameBuffer = new int[FramePitch * FrameHeight];
|
||||
//if (FrameBuffer.Length != FramePitch * FrameHeight)
|
||||
//FrameBuffer = new int[FramePitch * FrameHeight];
|
||||
FrameBuffer = new int[256 * 262];
|
||||
break;
|
||||
case VDW: // Vertical Display Word? - update framebuffer size
|
||||
FrameHeight = RequestedFrameHeight;
|
||||
//FrameHeight = RequestedFrameHeight;
|
||||
FrameWidth = RequestedFrameWidth;
|
||||
if (FrameHeight > 242)
|
||||
FrameHeight = 242;
|
||||
//if (FrameHeight > 242)
|
||||
//FrameHeight = 242;
|
||||
if (MultiResHack != 0)
|
||||
FramePitch = MultiResHack;
|
||||
if (FrameBuffer.Length != FramePitch * FrameHeight)
|
||||
FrameBuffer = new int[FramePitch * FrameHeight];
|
||||
//if (FrameBuffer.Length != FramePitch * FrameHeight)
|
||||
//FrameBuffer = new int[FramePitch * FrameHeight];
|
||||
FrameBuffer = new int[256 * 262];
|
||||
break;
|
||||
case LENR: // Initiate DMA transfer
|
||||
if (!msbComplete) break;
|
||||
|
|
|
@ -128,12 +128,13 @@ namespace BizHawk.Emulation.Cores.PCEngine
|
|||
FrameBuffer = VDC1.GetVideoBuffer();
|
||||
|
||||
int ScanLine = 0;
|
||||
int ActiveDisplayStartLine = VDC1.DisplayStartLine;
|
||||
|
||||
while (true)
|
||||
{
|
||||
VDC1.ScanLine = ScanLine;
|
||||
VDC2.ScanLine = ScanLine;
|
||||
|
||||
int ActiveDisplayStartLine = VDC1.DisplayStartLine;
|
||||
|
||||
int VBlankLine = ActiveDisplayStartLine + VDC1.Registers[VDW] + 1;
|
||||
if (VBlankLine > 261)
|
||||
VBlankLine = 261;
|
||||
|
@ -291,7 +292,7 @@ namespace BizHawk.Emulation.Cores.PCEngine
|
|||
{
|
||||
// pointer to the BAT and the framebuffer for this line
|
||||
ushort* BatRow = VRAMptr + yTile * vdc.BatWidth;
|
||||
int* dst = FBptr + vdc.ActiveLine * FrameWidth;
|
||||
int* dst = FBptr + (vdc.ActiveLine + vdc.ViewStartLine) * FrameWidth;
|
||||
|
||||
// parameters that change per tile
|
||||
ushort BatEnt;
|
||||
|
@ -447,7 +448,7 @@ namespace BizHawk.Emulation.Cores.PCEngine
|
|||
byte myPriority = priority ? highPriority : lowPriority;
|
||||
if (PriorityBuffer[xs] < myPriority)
|
||||
{
|
||||
if (show) FrameBuffer[(vdc.ActiveLine * FrameWidth) + xs] = VCE.Palette[paletteBase + pixel];
|
||||
if (show) FrameBuffer[((vdc.ActiveLine + vdc.ViewStartLine) * FrameWidth) + xs] = VCE.Palette[paletteBase + pixel];
|
||||
PriorityBuffer[xs] = myPriority;
|
||||
}
|
||||
}
|
||||
|
@ -466,7 +467,7 @@ namespace BizHawk.Emulation.Cores.PCEngine
|
|||
byte myPriority = priority ? highPriority : lowPriority;
|
||||
if (PriorityBuffer[xs] < myPriority)
|
||||
{
|
||||
if (show) FrameBuffer[(vdc.ActiveLine * FrameWidth) + xs] = VCE.Palette[paletteBase + pixel];
|
||||
if (show) FrameBuffer[((vdc.ActiveLine + vdc.ViewStartLine) * FrameWidth) + xs] = VCE.Palette[paletteBase + pixel];
|
||||
PriorityBuffer[xs] = myPriority;
|
||||
}
|
||||
}
|
||||
|
@ -488,7 +489,7 @@ namespace BizHawk.Emulation.Cores.PCEngine
|
|||
byte myPriority = priority ? highPriority : lowPriority;
|
||||
if (PriorityBuffer[xs] < myPriority)
|
||||
{
|
||||
if (show) FrameBuffer[(vdc.ActiveLine * FrameWidth) + xs] = VCE.Palette[paletteBase + pixel];
|
||||
if (show) FrameBuffer[((vdc.ActiveLine + vdc.ViewStartLine) * FrameWidth) + xs] = VCE.Palette[paletteBase + pixel];
|
||||
PriorityBuffer[xs] = myPriority;
|
||||
}
|
||||
}
|
||||
|
@ -506,7 +507,7 @@ namespace BizHawk.Emulation.Cores.PCEngine
|
|||
byte myPriority = priority ? highPriority : lowPriority;
|
||||
if (PriorityBuffer[xs] < myPriority)
|
||||
{
|
||||
if (show) FrameBuffer[(vdc.ActiveLine * FrameWidth) + xs] = VCE.Palette[paletteBase + pixel];
|
||||
if (show) FrameBuffer[((vdc.ActiveLine + vdc.ViewStartLine) * FrameWidth) + xs] = VCE.Palette[paletteBase + pixel];
|
||||
PriorityBuffer[xs] = myPriority;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
||||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
||||
{
|
||||
public partial class SMS
|
||||
{
|
||||
|
@ -8,9 +10,32 @@
|
|||
|
||||
byte ReadMemoryKR(ushort address)
|
||||
{
|
||||
if (address < 0x8000) return RomData[address & 0x7FFF];
|
||||
if (address < 0xC000) return RomData[(RomBank2 * BankSize) + (address & BankSizeMask)];
|
||||
return SystemRam[address & RamSizeMask];
|
||||
if (address < 0xC000)
|
||||
{
|
||||
if ((Port3E & 0x48) == 0x48) // cart and bios disabled, return empty bus
|
||||
return 0xFF;
|
||||
if (BiosMapped && BiosRom != null)
|
||||
{
|
||||
// korean BIOS (and a couple of rarer BIOses) use memory slot 2 mechanics as needed
|
||||
if (address < 0x8000)
|
||||
{
|
||||
return BiosRom[address];
|
||||
}
|
||||
else
|
||||
{
|
||||
return BiosRom[(Bios_bank * BankSize) + (address & BankSizeMask)];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (address < 0x8000) return RomData[address & 0x7FFF];
|
||||
else return RomData[(RomBank2 * BankSize) + (address & BankSizeMask)];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return SystemRam[address & RamSizeMask];
|
||||
}
|
||||
}
|
||||
|
||||
CDLog_MapResults MapMemoryKR(ushort address, bool write)
|
||||
|
@ -26,6 +51,11 @@
|
|||
SystemRam[address & RamSizeMask] = value;
|
||||
else if (address == 0xA000)
|
||||
RomBank2 = (byte)(value % RomBanks);
|
||||
|
||||
if ((address == 0xFFFF) && BiosMapped)
|
||||
{
|
||||
Bios_bank = value;
|
||||
}
|
||||
}
|
||||
|
||||
void InitKoreaMapper()
|
||||
|
@ -36,6 +66,7 @@
|
|||
RomBank0 = 0;
|
||||
RomBank1 = 1;
|
||||
RomBank2 = 2;
|
||||
Bios_bank = 2;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
|
|
@ -30,7 +30,32 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
|||
if ((Port3E & 0x48) == 0x48) // cart and bios disabled, return empty bus
|
||||
ret = 0xFF;
|
||||
else if (BiosMapped && BiosRom != null)
|
||||
ret = BiosRom[address & 0x1FFF];
|
||||
{
|
||||
if (BiosRom.Length == 0x2000)
|
||||
{
|
||||
ret = BiosRom[address & 0x1FFF];
|
||||
}
|
||||
else
|
||||
{
|
||||
// korean BIOS (and a couple of rarer BIOses) use memory slot 2 mechanics as needed
|
||||
if (address < 0x8000)
|
||||
{
|
||||
return BiosRom[address];
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (SaveRamBank)
|
||||
{
|
||||
case 0: ret = BiosRom[(Bios_bank * BankSize) + (address & BankSizeMask)]; break;
|
||||
case 1: if (SaveRAM != null) ret = SaveRAM[(address & BankSizeMask) % SaveRAM.Length]; break;
|
||||
case 2: if (SaveRAM != null) ret = SaveRAM[(BankSize + (address & BankSizeMask)) % SaveRAM.Length]; break;
|
||||
default:
|
||||
ret = SystemRam[address & RamSizeMask];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (address < 1024)
|
||||
ret = RomData[address];
|
||||
else if (address < 0x4000)
|
||||
|
@ -125,7 +150,17 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
|||
}
|
||||
else if (address == 0xFFFD) RomBank0 = (byte)(value % RomBanks);
|
||||
else if (address == 0xFFFE) RomBank1 = (byte)(value % RomBanks);
|
||||
else if (address == 0xFFFF) RomBank2 = (byte)(value % RomBanks);
|
||||
else if (address == 0xFFFF)
|
||||
{
|
||||
if (BiosMapped)
|
||||
{
|
||||
Bios_bank = (byte)value;
|
||||
}
|
||||
else
|
||||
{
|
||||
RomBank2 = (byte)(value % RomBanks);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -139,6 +174,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
|||
WriteMemorySega(0xFFFD, 0);
|
||||
WriteMemorySega(0xFFFE, 1);
|
||||
WriteMemorySega(0xFFFF, 2);
|
||||
Bios_bank = 2;
|
||||
}
|
||||
|
||||
// Mapper when loading a BIOS as a ROM (simulating no cart loaded)
|
||||
|
|
|
@ -61,6 +61,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
|||
ser.Sync("RomBank1", ref RomBank1);
|
||||
ser.Sync("RomBank2", ref RomBank2);
|
||||
ser.Sync("RomBank3", ref RomBank3);
|
||||
ser.Sync("Bios_bank", ref Bios_bank);
|
||||
ser.Sync("Port01", ref Port01);
|
||||
ser.Sync("Port02", ref Port02);
|
||||
ser.Sync("Port3E", ref Port3E);
|
||||
|
@ -72,9 +73,10 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
|||
if (SaveRAM != null)
|
||||
{
|
||||
ser.Sync("SaveRAM", ref SaveRAM, false);
|
||||
ser.Sync("SaveRamBank", ref SaveRamBank);
|
||||
}
|
||||
|
||||
ser.Sync("SaveRamBank", ref SaveRamBank);
|
||||
|
||||
if (ExtRam != null)
|
||||
{
|
||||
ser.Sync("ExtRAM", ref ExtRam, true);
|
||||
|
|
|
@ -195,6 +195,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
|||
// ROM
|
||||
private byte[] RomData;
|
||||
private byte RomBank0, RomBank1, RomBank2, RomBank3;
|
||||
private byte Bios_bank;
|
||||
private byte RomBanks;
|
||||
private byte[] BiosRom;
|
||||
|
||||
|
@ -241,6 +242,8 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
|||
return "Export";
|
||||
if (gameRegion.IndexOf("Australia") >= 0)
|
||||
return "Export";
|
||||
if (gameRegion.IndexOf("Korea") >= 0)
|
||||
return "Korea";
|
||||
return "Japan";
|
||||
}
|
||||
|
||||
|
@ -382,6 +385,6 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
|||
}
|
||||
}
|
||||
|
||||
private readonly string[] validRegions = { "Export", "Japan", "Auto" };
|
||||
private readonly string[] validRegions = { "Export", "Japan", "Auto" , "Korea" };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
private readonly MemoryCallbackSystem _memoryCallbacks = new MemoryCallbackSystem(new[] { "M68K BUS" });
|
||||
private readonly MemoryCallbackSystem _memoryCallbacks = new MemoryCallbackSystem(new[] { "M68K BUS", "" });
|
||||
|
||||
private LibGPGX.mem_cb ExecCallback;
|
||||
private LibGPGX.mem_cb ReadCallback;
|
||||
|
|
|
@ -32,34 +32,66 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
public sd.SizeF Measure(string str)
|
||||
{
|
||||
float x = 0;
|
||||
float y = FontInfo.LineHeight;
|
||||
float ox = x;
|
||||
int len = str.Length;
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
Cyotek.Drawing.BitmapFont.Character c;
|
||||
if (!FontInfo.Characters.TryGetValue(str[i], out c))
|
||||
c = FontInfo.Characters[unchecked((char)-1)];
|
||||
int c = str[i];
|
||||
|
||||
x += c.XAdvance;
|
||||
if (c == '\r')
|
||||
{
|
||||
if (i != len - 1 && str[i + 1] == '\n')
|
||||
i++;
|
||||
}
|
||||
|
||||
if (c == '\r')
|
||||
{
|
||||
c = '\n';
|
||||
}
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
if (x > ox)
|
||||
ox = x;
|
||||
x = 0;
|
||||
y += FontInfo.LineHeight;
|
||||
continue;
|
||||
}
|
||||
|
||||
Cyotek.Drawing.BitmapFont.Character bfc;
|
||||
if (!FontInfo.Characters.TryGetValue((char)c, out bfc))
|
||||
bfc = FontInfo.Characters[unchecked((char)-1)];
|
||||
|
||||
x += bfc.XAdvance;
|
||||
}
|
||||
|
||||
return new sd.SizeF(x, FontInfo.LineHeight);
|
||||
return new sd.SizeF(Math.Max(x, ox), y);
|
||||
}
|
||||
|
||||
public void RenderString(IGuiRenderer renderer, float x, float y, string str)
|
||||
{
|
||||
float ox = x;
|
||||
int len = str.Length;
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
int c = str[i];
|
||||
|
||||
if (c == '\r')
|
||||
{
|
||||
if (i != len - 1 && str[i + 1] == '\n')
|
||||
i++;
|
||||
}
|
||||
if (c == '\r') c = '\n';
|
||||
|
||||
if(c == '\n') {
|
||||
if (c == '\r')
|
||||
{
|
||||
c = '\n';
|
||||
}
|
||||
|
||||
if(c == '\n')
|
||||
{
|
||||
x = ox;
|
||||
y += FontInfo.LineHeight;
|
||||
continue;
|
||||
|
|
|
@ -18,6 +18,7 @@ namespace BizHawk.Build.Tool
|
|||
case "GIT_REV": SVN_REV(false,cmdArgs); break;
|
||||
case "NXCOMPAT": NXCOMPAT(cmdArgs); break;
|
||||
case "LARGEADDRESS": LARGEADDRESS(cmdArgs); break;
|
||||
case "TIMESTAMP": TIMESTAMP(cmdArgs); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,6 +114,15 @@ namespace BizHawk.Build.Tool
|
|||
}
|
||||
}
|
||||
|
||||
//clears the timestamp in PE header (for deterministic builds)
|
||||
static void TIMESTAMP(string[] args)
|
||||
{
|
||||
using (var fs = new FileStream(args[0], FileMode.Open, FileAccess.ReadWrite, FileShare.Read))
|
||||
{
|
||||
fs.Position = 0x88;
|
||||
fs.WriteByte(0); fs.WriteByte(0); fs.WriteByte(0); fs.WriteByte(0);
|
||||
}
|
||||
}
|
||||
|
||||
//sets NXCOMPAT bit in PE header
|
||||
static void NXCOMPAT(string[] args)
|
||||
|
|
Binary file not shown.
|
@ -162,7 +162,7 @@
|
|||
<CodeAnalysisFailOnMissingRules>false</CodeAnalysisFailOnMissingRules>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release-LUAPERKS|x64'">
|
||||
<OutputPath>..\..\references\x64\</OutputPath>
|
||||
<OutputPath>..\..\output\dll\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
|
|
|
@ -51,7 +51,7 @@ public:
|
|||
enum LoadFlag {
|
||||
FORCE_DMG = 1, /**< Treat the ROM as not having CGB support regardless of what its header advertises. */
|
||||
GBA_CGB = 2, /**< Use GBA intial CPU register values when in CGB mode. */
|
||||
MULTICART_COMPAT = 4 /**< Use heuristics to detect and support some multicart MBCs disguised as MBC1. */
|
||||
MULTICART_COMPAT = 4, /**< Use heuristics to detect and support some multicart MBCs disguised as MBC1. */
|
||||
};
|
||||
|
||||
/** Load ROM image.
|
||||
|
@ -62,6 +62,9 @@ public:
|
|||
*/
|
||||
int load(const char *romfiledata, unsigned romfilelength, std::uint32_t now, unsigned flags = 0);
|
||||
|
||||
int loadGBCBios(const char* biosfiledata);
|
||||
int loadDMGBios(const char* biosfiledata);
|
||||
|
||||
/** Emulates until at least 'samples' stereo sound samples are produced in the supplied buffer,
|
||||
* or until a video frame has been drawn.
|
||||
*
|
||||
|
@ -109,7 +112,7 @@ public:
|
|||
void setTraceCallback(void (*callback)(void *));
|
||||
void setScanlineCallback(void (*callback)(), int sl);
|
||||
void setRTCCallback(std::uint32_t (*callback)());
|
||||
void setLinkCallback(void (*callback)());
|
||||
void setLinkCallback(void(*callback)());
|
||||
|
||||
/** Returns true if the currently loaded ROM image is treated as having CGB support. */
|
||||
bool isCgb() const;
|
||||
|
@ -135,6 +138,9 @@ public:
|
|||
|
||||
void GetRegs(int *dest);
|
||||
|
||||
void SetInterruptAddresses(int *addrs, int numAddrs);
|
||||
int GetHitInterruptAddress();
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
|
||||
private:
|
||||
|
|
|
@ -1,231 +1,222 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{5D630682-7BDA-474D-B387-0EB420DDC199}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>libgambatte</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</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 Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<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 Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<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>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBGAMBATTE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>include;src;src\common</AdditionalIncludeDirectories>
|
||||
<DisableSpecificWarnings>4244;4373;4800;4804</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>copy /y $(TargetDir)$(TargetFileName) $(ProjectDir)..\output\dll\$(TargetFileName)</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBGAMBATTE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>include;src;src\common</AdditionalIncludeDirectories>
|
||||
<DisableSpecificWarnings>4244;4373;4800;4804</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>copy /y $(TargetDir)$(TargetFileName) $(ProjectDir)..\output\dll\$(TargetFileName)</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBGAMBATTE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>include;src;src\common</AdditionalIncludeDirectories>
|
||||
<DisableSpecificWarnings>4244;4373;4800;4804</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>copy /y $(TargetDir)$(TargetFileName) $(ProjectDir)..\output\dll\$(TargetFileName)</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBGAMBATTE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>include;src;src\common</AdditionalIncludeDirectories>
|
||||
<DisableSpecificWarnings>4244;4373;4800;4804</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>copy /y $(TargetDir)$(TargetFileName) $(ProjectDir)..\output\dll\$(TargetFileName)</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\gambatte.h" />
|
||||
<ClInclude Include="include\gbint.h" />
|
||||
<ClInclude Include="src\cinterface.h" />
|
||||
<ClInclude Include="src\common\array.h" />
|
||||
<ClInclude Include="src\common\uncopyable.h" />
|
||||
<ClInclude Include="src\counterdef.h" />
|
||||
<ClInclude Include="src\cpu.h" />
|
||||
<ClInclude Include="src\file\stdfile.h" />
|
||||
<ClInclude Include="src\initstate.h" />
|
||||
<ClInclude Include="src\insertion_sort.h" />
|
||||
<ClInclude Include="src\interrupter.h" />
|
||||
<ClInclude Include="src\interruptrequester.h" />
|
||||
<ClInclude Include="src\memory.h" />
|
||||
<ClInclude Include="src\mem\cartridge.h" />
|
||||
<ClInclude Include="src\mem\memptrs.h" />
|
||||
<ClInclude Include="src\mem\rtc.h" />
|
||||
<ClInclude Include="src\minkeeper.h" />
|
||||
<ClInclude Include="src\newstate.h" />
|
||||
<ClInclude Include="src\savestate.h" />
|
||||
<ClInclude Include="src\sound.h" />
|
||||
<ClInclude Include="src\sound\channel1.h" />
|
||||
<ClInclude Include="src\sound\channel2.h" />
|
||||
<ClInclude Include="src\sound\channel3.h" />
|
||||
<ClInclude Include="src\sound\channel4.h" />
|
||||
<ClInclude Include="src\sound\duty_unit.h" />
|
||||
<ClInclude Include="src\sound\envelope_unit.h" />
|
||||
<ClInclude Include="src\sound\length_counter.h" />
|
||||
<ClInclude Include="src\sound\master_disabler.h" />
|
||||
<ClInclude Include="src\sound\sound_unit.h" />
|
||||
<ClInclude Include="src\sound\static_output_tester.h" />
|
||||
<ClInclude Include="src\tima.h" />
|
||||
<ClInclude Include="src\video.h" />
|
||||
<ClInclude Include="src\video\lyc_irq.h" />
|
||||
<ClInclude Include="src\video\ly_counter.h" />
|
||||
<ClInclude Include="src\video\next_m0_time.h" />
|
||||
<ClInclude Include="src\video\ppu.h" />
|
||||
<ClInclude Include="src\video\sprite_mapper.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\cinterface.cpp" />
|
||||
<ClCompile Include="src\cpu.cpp" />
|
||||
<ClCompile Include="src\gambatte.cpp" />
|
||||
<ClCompile Include="src\initstate.cpp" />
|
||||
<ClCompile Include="src\interrupter.cpp" />
|
||||
<ClCompile Include="src\interruptrequester.cpp" />
|
||||
<ClCompile Include="src\memory.cpp" />
|
||||
<ClCompile Include="src\mem\cartridge.cpp" />
|
||||
<ClCompile Include="src\mem\memptrs.cpp" />
|
||||
<ClCompile Include="src\mem\rtc.cpp" />
|
||||
<ClCompile Include="src\newstate.cpp" />
|
||||
<ClCompile Include="src\sound.cpp" />
|
||||
<ClCompile Include="src\sound\channel1.cpp" />
|
||||
<ClCompile Include="src\sound\channel2.cpp" />
|
||||
<ClCompile Include="src\sound\channel3.cpp" />
|
||||
<ClCompile Include="src\sound\channel4.cpp" />
|
||||
<ClCompile Include="src\sound\duty_unit.cpp" />
|
||||
<ClCompile Include="src\sound\envelope_unit.cpp" />
|
||||
<ClCompile Include="src\sound\length_counter.cpp" />
|
||||
<ClCompile Include="src\tima.cpp" />
|
||||
<ClCompile Include="src\video.cpp" />
|
||||
<ClCompile Include="src\video\lyc_irq.cpp" />
|
||||
<ClCompile Include="src\video\ly_counter.cpp" />
|
||||
<ClCompile Include="src\video\next_m0_time.cpp" />
|
||||
<ClCompile Include="src\video\ppu.cpp" />
|
||||
<ClCompile Include="src\video\sprite_mapper.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" 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">
|
||||
<ProjectGuid>{5D630682-7BDA-474D-B387-0EB420DDC199}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>libgambatte</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</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>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBGAMBATTE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>include;src;src\common</AdditionalIncludeDirectories>
|
||||
<DisableSpecificWarnings>4244;4373;4800;4804</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBGAMBATTE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>include;src;src\common</AdditionalIncludeDirectories>
|
||||
<DisableSpecificWarnings>4244;4373;4800;4804</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBGAMBATTE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>include;src;src\common</AdditionalIncludeDirectories>
|
||||
<DisableSpecificWarnings>4244;4373;4800;4804</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBGAMBATTE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>include;src;src\common</AdditionalIncludeDirectories>
|
||||
<DisableSpecificWarnings>4244;4373;4800;4804</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\gambatte.h" />
|
||||
<ClInclude Include="include\gbint.h" />
|
||||
<ClInclude Include="src\cinterface.h" />
|
||||
<ClInclude Include="src\common\array.h" />
|
||||
<ClInclude Include="src\common\uncopyable.h" />
|
||||
<ClInclude Include="src\counterdef.h" />
|
||||
<ClInclude Include="src\cpu.h" />
|
||||
<ClInclude Include="src\file\stdfile.h" />
|
||||
<ClInclude Include="src\initstate.h" />
|
||||
<ClInclude Include="src\insertion_sort.h" />
|
||||
<ClInclude Include="src\interrupter.h" />
|
||||
<ClInclude Include="src\interruptrequester.h" />
|
||||
<ClInclude Include="src\memory.h" />
|
||||
<ClInclude Include="src\mem\cartridge.h" />
|
||||
<ClInclude Include="src\mem\memptrs.h" />
|
||||
<ClInclude Include="src\mem\rtc.h" />
|
||||
<ClInclude Include="src\minkeeper.h" />
|
||||
<ClInclude Include="src\newstate.h" />
|
||||
<ClInclude Include="src\savestate.h" />
|
||||
<ClInclude Include="src\sound.h" />
|
||||
<ClInclude Include="src\sound\channel1.h" />
|
||||
<ClInclude Include="src\sound\channel2.h" />
|
||||
<ClInclude Include="src\sound\channel3.h" />
|
||||
<ClInclude Include="src\sound\channel4.h" />
|
||||
<ClInclude Include="src\sound\duty_unit.h" />
|
||||
<ClInclude Include="src\sound\envelope_unit.h" />
|
||||
<ClInclude Include="src\sound\length_counter.h" />
|
||||
<ClInclude Include="src\sound\master_disabler.h" />
|
||||
<ClInclude Include="src\sound\sound_unit.h" />
|
||||
<ClInclude Include="src\sound\static_output_tester.h" />
|
||||
<ClInclude Include="src\tima.h" />
|
||||
<ClInclude Include="src\video.h" />
|
||||
<ClInclude Include="src\video\lyc_irq.h" />
|
||||
<ClInclude Include="src\video\ly_counter.h" />
|
||||
<ClInclude Include="src\video\next_m0_time.h" />
|
||||
<ClInclude Include="src\video\ppu.h" />
|
||||
<ClInclude Include="src\video\sprite_mapper.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\cinterface.cpp" />
|
||||
<ClCompile Include="src\cpu.cpp" />
|
||||
<ClCompile Include="src\gambatte.cpp" />
|
||||
<ClCompile Include="src\initstate.cpp" />
|
||||
<ClCompile Include="src\interrupter.cpp" />
|
||||
<ClCompile Include="src\interruptrequester.cpp" />
|
||||
<ClCompile Include="src\memory.cpp" />
|
||||
<ClCompile Include="src\mem\cartridge.cpp" />
|
||||
<ClCompile Include="src\mem\memptrs.cpp" />
|
||||
<ClCompile Include="src\mem\rtc.cpp" />
|
||||
<ClCompile Include="src\newstate.cpp" />
|
||||
<ClCompile Include="src\sound.cpp" />
|
||||
<ClCompile Include="src\sound\channel1.cpp" />
|
||||
<ClCompile Include="src\sound\channel2.cpp" />
|
||||
<ClCompile Include="src\sound\channel3.cpp" />
|
||||
<ClCompile Include="src\sound\channel4.cpp" />
|
||||
<ClCompile Include="src\sound\duty_unit.cpp" />
|
||||
<ClCompile Include="src\sound\envelope_unit.cpp" />
|
||||
<ClCompile Include="src\sound\length_counter.cpp" />
|
||||
<ClCompile Include="src\tima.cpp" />
|
||||
<ClCompile Include="src\video.cpp" />
|
||||
<ClCompile Include="src\video\lyc_irq.cpp" />
|
||||
<ClCompile Include="src\video\ly_counter.cpp" />
|
||||
<ClCompile Include="src\video\next_m0_time.cpp" />
|
||||
<ClCompile Include="src\video\ppu.cpp" />
|
||||
<ClCompile Include="src\video\sprite_mapper.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -1,203 +1,225 @@
|
|||
#include "cinterface.h"
|
||||
#include "gambatte.h"
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include "newstate.h"
|
||||
|
||||
using namespace gambatte;
|
||||
|
||||
// new is actually called in a few different places, so replace all of them for determinism guarantees
|
||||
void *operator new(std::size_t n)
|
||||
{
|
||||
void *p = std::malloc(n);
|
||||
std::memset(p, 0, n);
|
||||
return p;
|
||||
}
|
||||
|
||||
void operator delete(void *p)
|
||||
{
|
||||
std::free(p);
|
||||
}
|
||||
|
||||
GBEXPORT GB *gambatte_create()
|
||||
{
|
||||
return new GB();
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_destroy(GB *g)
|
||||
{
|
||||
delete g;
|
||||
}
|
||||
|
||||
GBEXPORT int gambatte_load(GB *g, const char *romfiledata, unsigned romfilelength, long long now, unsigned flags)
|
||||
{
|
||||
int ret = g->load(romfiledata, romfilelength, now, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
GBEXPORT int gambatte_runfor(GB *g, short *soundbuf, unsigned *samples)
|
||||
{
|
||||
unsigned sampv = *samples;
|
||||
int ret = g->runFor((unsigned int *) soundbuf, sampv);
|
||||
*samples = sampv;
|
||||
return ret;
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_blitto(GB *g, unsigned int *videobuf, int pitch)
|
||||
{
|
||||
g->blitTo((unsigned int *)videobuf, pitch);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_setlayers(GB *g, unsigned mask)
|
||||
{
|
||||
g->setLayers(mask);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_reset(GB *g, long long now)
|
||||
{
|
||||
g->reset(now);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_setdmgpalettecolor(GB *g, unsigned palnum, unsigned colornum, unsigned rgb32)
|
||||
{
|
||||
g->setDmgPaletteColor(palnum, colornum, rgb32);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_setcgbpalette(GB *g, unsigned *lut)
|
||||
{
|
||||
g->setCgbPalette(lut);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_setinputgetter(GB *g, unsigned (*getinput)(void))
|
||||
{
|
||||
g->setInputGetter(getinput);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_setreadcallback(GB *g, void (*callback)(unsigned))
|
||||
{
|
||||
g->setReadCallback(callback);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_setwritecallback(GB *g, void (*callback)(unsigned))
|
||||
{
|
||||
g->setWriteCallback(callback);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_setexeccallback(GB *g, void (*callback)(unsigned))
|
||||
{
|
||||
g->setExecCallback(callback);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_setcdcallback(GB *g, CDCallback cdc)
|
||||
{
|
||||
g->setCDCallback(cdc);
|
||||
}
|
||||
|
||||
|
||||
GBEXPORT void gambatte_settracecallback(GB *g, void (*callback)(void *))
|
||||
{
|
||||
g->setTraceCallback(callback);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_setscanlinecallback(GB *g, void (*callback)(), int sl)
|
||||
{
|
||||
g->setScanlineCallback(callback, sl);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_setrtccallback(GB *g, unsigned int (*callback)())
|
||||
{
|
||||
g->setRTCCallback(callback);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_setlinkcallback(GB *g, void (*callback)())
|
||||
{
|
||||
g->setLinkCallback(callback);
|
||||
}
|
||||
|
||||
GBEXPORT int gambatte_iscgb(GB *g)
|
||||
{
|
||||
return g->isCgb();
|
||||
}
|
||||
|
||||
GBEXPORT int gambatte_isloaded(GB *g)
|
||||
{
|
||||
return g->isLoaded();
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_savesavedata(GB *g, char *dest)
|
||||
{
|
||||
g->saveSavedata(dest);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_loadsavedata(GB *g, const char *data)
|
||||
{
|
||||
g->loadSavedata(data);
|
||||
}
|
||||
|
||||
GBEXPORT int gambatte_savesavedatalength(GB *g)
|
||||
{
|
||||
return g->saveSavedataLength();
|
||||
}
|
||||
|
||||
GBEXPORT int gambatte_newstatelen(GB *g)
|
||||
{
|
||||
NewStateDummy dummy;
|
||||
g->SyncState<false>(&dummy);
|
||||
return dummy.GetLength();
|
||||
}
|
||||
|
||||
GBEXPORT int gambatte_newstatesave(GB *g, char *data, int len)
|
||||
{
|
||||
NewStateExternalBuffer saver(data, len);
|
||||
g->SyncState<false>(&saver);
|
||||
return !saver.Overflow() && saver.GetLength() == len;
|
||||
}
|
||||
|
||||
GBEXPORT int gambatte_newstateload(GB *g, const char *data, int len)
|
||||
{
|
||||
NewStateExternalBuffer loader((char *)data, len);
|
||||
g->SyncState<true>(&loader);
|
||||
return !loader.Overflow() && loader.GetLength() == len;
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_newstatesave_ex(GB *g, FPtrs *ff)
|
||||
{
|
||||
NewStateExternalFunctions saver(ff);
|
||||
g->SyncState<false>(&saver);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_newstateload_ex(GB *g, FPtrs *ff)
|
||||
{
|
||||
NewStateExternalFunctions loader(ff);
|
||||
g->SyncState<true>(&loader);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_romtitle(GB *g, char *dest)
|
||||
{
|
||||
std::strcpy(dest, g->romTitle().c_str());
|
||||
}
|
||||
|
||||
GBEXPORT int gambatte_getmemoryarea(GB *g, int which, unsigned char **data, int *length)
|
||||
{
|
||||
return g->getMemoryArea(which, data, length);
|
||||
}
|
||||
|
||||
GBEXPORT unsigned char gambatte_cpuread(GB *g, unsigned short addr)
|
||||
{
|
||||
return g->ExternalRead(addr);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_cpuwrite(GB *g, unsigned short addr, unsigned char val)
|
||||
{
|
||||
g->ExternalWrite(addr, val);
|
||||
}
|
||||
|
||||
GBEXPORT int gambatte_linkstatus(GB *g, int which)
|
||||
{
|
||||
return g->LinkStatus(which);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_getregs(GB *g, int *dest)
|
||||
{
|
||||
g->GetRegs(dest);
|
||||
}
|
||||
#include "cinterface.h"
|
||||
#include "gambatte.h"
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include "newstate.h"
|
||||
|
||||
using namespace gambatte;
|
||||
|
||||
// new is actually called in a few different places, so replace all of them for determinism guarantees
|
||||
void *operator new(std::size_t n)
|
||||
{
|
||||
void *p = std::malloc(n);
|
||||
std::memset(p, 0, n);
|
||||
return p;
|
||||
}
|
||||
|
||||
void operator delete(void *p)
|
||||
{
|
||||
std::free(p);
|
||||
}
|
||||
|
||||
GBEXPORT GB *gambatte_create()
|
||||
{
|
||||
return new GB();
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_destroy(GB *g)
|
||||
{
|
||||
delete g;
|
||||
}
|
||||
|
||||
GBEXPORT int gambatte_load(GB *g, const char *romfiledata, unsigned romfilelength, long long now, unsigned flags)
|
||||
{
|
||||
int ret = g->load(romfiledata, romfilelength, now, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
GBEXPORT int gambatte_loadgbcbios(GB* g, const char* biosfiledata)
|
||||
{
|
||||
int ret = g->loadGBCBios(biosfiledata);
|
||||
return ret;
|
||||
}
|
||||
|
||||
GBEXPORT int gambatte_loaddmgbios(GB* g, const char* biosfiledata)
|
||||
{
|
||||
int ret = g->loadDMGBios(biosfiledata);
|
||||
return ret;
|
||||
}
|
||||
|
||||
GBEXPORT int gambatte_runfor(GB *g, short *soundbuf, unsigned *samples)
|
||||
{
|
||||
unsigned sampv = *samples;
|
||||
int ret = g->runFor((unsigned int *) soundbuf, sampv);
|
||||
*samples = sampv;
|
||||
return ret;
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_blitto(GB *g, unsigned int *videobuf, int pitch)
|
||||
{
|
||||
g->blitTo((unsigned int *)videobuf, pitch);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_setlayers(GB *g, unsigned mask)
|
||||
{
|
||||
g->setLayers(mask);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_reset(GB *g, long long now)
|
||||
{
|
||||
g->reset(now);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_setdmgpalettecolor(GB *g, unsigned palnum, unsigned colornum, unsigned rgb32)
|
||||
{
|
||||
g->setDmgPaletteColor(palnum, colornum, rgb32);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_setcgbpalette(GB *g, unsigned *lut)
|
||||
{
|
||||
g->setCgbPalette(lut);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_setinputgetter(GB *g, unsigned (*getinput)(void))
|
||||
{
|
||||
g->setInputGetter(getinput);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_setreadcallback(GB *g, void (*callback)(unsigned))
|
||||
{
|
||||
g->setReadCallback(callback);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_setwritecallback(GB *g, void (*callback)(unsigned))
|
||||
{
|
||||
g->setWriteCallback(callback);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_setexeccallback(GB *g, void (*callback)(unsigned))
|
||||
{
|
||||
g->setExecCallback(callback);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_setcdcallback(GB *g, CDCallback cdc)
|
||||
{
|
||||
g->setCDCallback(cdc);
|
||||
}
|
||||
|
||||
|
||||
GBEXPORT void gambatte_settracecallback(GB *g, void (*callback)(void *))
|
||||
{
|
||||
g->setTraceCallback(callback);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_setscanlinecallback(GB *g, void (*callback)(), int sl)
|
||||
{
|
||||
g->setScanlineCallback(callback, sl);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_setrtccallback(GB *g, unsigned int (*callback)())
|
||||
{
|
||||
g->setRTCCallback(callback);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_setlinkcallback(GB *g, void(*callback)())
|
||||
{
|
||||
g->setLinkCallback(callback);
|
||||
}
|
||||
|
||||
GBEXPORT int gambatte_iscgb(GB *g)
|
||||
{
|
||||
return g->isCgb();
|
||||
}
|
||||
|
||||
GBEXPORT int gambatte_isloaded(GB *g)
|
||||
{
|
||||
return g->isLoaded();
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_savesavedata(GB *g, char *dest)
|
||||
{
|
||||
g->saveSavedata(dest);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_loadsavedata(GB *g, const char *data)
|
||||
{
|
||||
g->loadSavedata(data);
|
||||
}
|
||||
|
||||
GBEXPORT int gambatte_savesavedatalength(GB *g)
|
||||
{
|
||||
return g->saveSavedataLength();
|
||||
}
|
||||
|
||||
GBEXPORT int gambatte_newstatelen(GB *g)
|
||||
{
|
||||
NewStateDummy dummy;
|
||||
g->SyncState<false>(&dummy);
|
||||
return dummy.GetLength();
|
||||
}
|
||||
|
||||
GBEXPORT int gambatte_newstatesave(GB *g, char *data, int len)
|
||||
{
|
||||
NewStateExternalBuffer saver(data, len);
|
||||
g->SyncState<false>(&saver);
|
||||
return !saver.Overflow() && saver.GetLength() == len;
|
||||
}
|
||||
|
||||
GBEXPORT int gambatte_newstateload(GB *g, const char *data, int len)
|
||||
{
|
||||
NewStateExternalBuffer loader((char *)data, len);
|
||||
g->SyncState<true>(&loader);
|
||||
return !loader.Overflow() && loader.GetLength() == len;
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_newstatesave_ex(GB *g, FPtrs *ff)
|
||||
{
|
||||
NewStateExternalFunctions saver(ff);
|
||||
g->SyncState<false>(&saver);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_newstateload_ex(GB *g, FPtrs *ff)
|
||||
{
|
||||
NewStateExternalFunctions loader(ff);
|
||||
g->SyncState<true>(&loader);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_romtitle(GB *g, char *dest)
|
||||
{
|
||||
std::strcpy(dest, g->romTitle().c_str());
|
||||
}
|
||||
|
||||
GBEXPORT int gambatte_getmemoryarea(GB *g, int which, unsigned char **data, int *length)
|
||||
{
|
||||
return g->getMemoryArea(which, data, length);
|
||||
}
|
||||
|
||||
GBEXPORT unsigned char gambatte_cpuread(GB *g, unsigned short addr)
|
||||
{
|
||||
return g->ExternalRead(addr);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_cpuwrite(GB *g, unsigned short addr, unsigned char val)
|
||||
{
|
||||
g->ExternalWrite(addr, val);
|
||||
}
|
||||
|
||||
GBEXPORT int gambatte_linkstatus(GB *g, int which)
|
||||
{
|
||||
return g->LinkStatus(which);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_getregs(GB *g, int *dest)
|
||||
{
|
||||
g->GetRegs(dest);
|
||||
}
|
||||
|
||||
GBEXPORT void gambatte_setinterruptaddresses(GB *g, int *addrs, int numAddrs)
|
||||
{
|
||||
g->SetInterruptAddresses(addrs, numAddrs);
|
||||
}
|
||||
|
||||
GBEXPORT int gambatte_gethitinterruptaddress(GB *g)
|
||||
{
|
||||
return g->GetHitInterruptAddress();
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#ifndef CINTERFACE_H
|
||||
#define CINTERFACE_H
|
||||
|
||||
// these are all documented on the C# side
|
||||
|
||||
#define GBEXPORT extern "C" __declspec(dllexport)
|
||||
|
||||
#endif
|
||||
#ifndef CINTERFACE_H
|
||||
#define CINTERFACE_H
|
||||
|
||||
// these are all documented on the C# side
|
||||
|
||||
#define GBEXPORT extern "C" __declspec(dllexport)
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,136 +1,147 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef CPU_H
|
||||
#define CPU_H
|
||||
|
||||
#include "memory.h"
|
||||
#include "newstate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
class CPU {
|
||||
Memory memory;
|
||||
|
||||
unsigned long cycleCounter_;
|
||||
|
||||
unsigned short PC;
|
||||
unsigned short SP;
|
||||
|
||||
unsigned HF1, HF2, ZF, CF;
|
||||
|
||||
unsigned char A, B, C, D, E, /*F,*/ H, L;
|
||||
|
||||
bool skip;
|
||||
|
||||
void process(unsigned long cycles);
|
||||
|
||||
void (*tracecallback)(void *);
|
||||
|
||||
public:
|
||||
|
||||
CPU();
|
||||
// void halt();
|
||||
|
||||
// unsigned interrupt(unsigned address, unsigned cycleCounter);
|
||||
|
||||
long runFor(unsigned long cycles);
|
||||
void setStatePtrs(SaveState &state);
|
||||
void loadState(const SaveState &state);
|
||||
void setLayers(unsigned mask) { memory.setLayers(mask); }
|
||||
|
||||
void loadSavedata(const char *data) { memory.loadSavedata(data); }
|
||||
int saveSavedataLength() {return memory.saveSavedataLength(); }
|
||||
void saveSavedata(char *dest) { memory.saveSavedata(dest); }
|
||||
|
||||
bool getMemoryArea(int which, unsigned char **data, int *length) { return memory.getMemoryArea(which, data, length); }
|
||||
|
||||
void setVideoBuffer(uint_least32_t *const videoBuf, const int pitch) {
|
||||
memory.setVideoBuffer(videoBuf, pitch);
|
||||
}
|
||||
|
||||
void setInputGetter(unsigned (*getInput)()) {
|
||||
memory.setInputGetter(getInput);
|
||||
}
|
||||
|
||||
void setReadCallback(void (*callback)(unsigned)) {
|
||||
memory.setReadCallback(callback);
|
||||
}
|
||||
|
||||
void setWriteCallback(void (*callback)(unsigned)) {
|
||||
memory.setWriteCallback(callback);
|
||||
}
|
||||
|
||||
void setExecCallback(void (*callback)(unsigned)) {
|
||||
memory.setExecCallback(callback);
|
||||
}
|
||||
|
||||
void setCDCallback(CDCallback cdc) {
|
||||
memory.setCDCallback(cdc);
|
||||
}
|
||||
|
||||
void setTraceCallback(void (*callback)(void *)) {
|
||||
tracecallback = callback;
|
||||
}
|
||||
|
||||
void setScanlineCallback(void (*callback)(), int sl) {
|
||||
memory.setScanlineCallback(callback, sl);
|
||||
}
|
||||
|
||||
void setRTCCallback(std::uint32_t (*callback)()) {
|
||||
memory.setRTCCallback(callback);
|
||||
}
|
||||
|
||||
void setLinkCallback(void (*callback)()) {
|
||||
memory.setLinkCallback(callback);
|
||||
}
|
||||
|
||||
int load(const char *romfiledata, unsigned romfilelength, bool forceDmg, bool multicartCompat) {
|
||||
return memory.loadROM(romfiledata, romfilelength, forceDmg, multicartCompat);
|
||||
}
|
||||
|
||||
bool loaded() const { return memory.loaded(); }
|
||||
const char * romTitle() const { return memory.romTitle(); }
|
||||
|
||||
void setSoundBuffer(uint_least32_t *const buf) { memory.setSoundBuffer(buf); }
|
||||
unsigned fillSoundBuffer() { return memory.fillSoundBuffer(cycleCounter_); }
|
||||
|
||||
bool isCgb() const { return memory.isCgb(); }
|
||||
|
||||
void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned rgb32) {
|
||||
memory.setDmgPaletteColor(palNum, colorNum, rgb32);
|
||||
}
|
||||
|
||||
void setCgbPalette(unsigned *lut) {
|
||||
memory.setCgbPalette(lut);
|
||||
}
|
||||
|
||||
//unsigned char ExternalRead(unsigned short addr) { return memory.read(addr, cycleCounter_); }
|
||||
unsigned char ExternalRead(unsigned short addr) { return memory.peek(addr); }
|
||||
void ExternalWrite(unsigned short addr, unsigned char val) { memory.write_nocb(addr, val, cycleCounter_); }
|
||||
|
||||
int LinkStatus(int which) { return memory.LinkStatus(which); }
|
||||
|
||||
void GetRegs(int *dest);
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef CPU_H
|
||||
#define CPU_H
|
||||
|
||||
#include "memory.h"
|
||||
#include "newstate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
class CPU {
|
||||
Memory memory;
|
||||
|
||||
unsigned long cycleCounter_;
|
||||
|
||||
unsigned short PC;
|
||||
unsigned short SP;
|
||||
|
||||
unsigned HF1, HF2, ZF, CF;
|
||||
|
||||
unsigned char A, B, C, D, E, /*F,*/ H, L;
|
||||
|
||||
bool skip;
|
||||
|
||||
int *interruptAddresses;
|
||||
int numInterruptAddresses;
|
||||
int hitInterruptAddress;
|
||||
|
||||
void process(unsigned long cycles);
|
||||
|
||||
void (*tracecallback)(void *);
|
||||
|
||||
public:
|
||||
|
||||
CPU();
|
||||
// void halt();
|
||||
|
||||
// unsigned interrupt(unsigned address, unsigned cycleCounter);
|
||||
|
||||
long runFor(unsigned long cycles);
|
||||
void setStatePtrs(SaveState &state);
|
||||
void loadState(const SaveState &state);
|
||||
void setLayers(unsigned mask) { memory.setLayers(mask); }
|
||||
|
||||
void loadSavedata(const char *data) { memory.loadSavedata(data); }
|
||||
int saveSavedataLength() {return memory.saveSavedataLength(); }
|
||||
void saveSavedata(char *dest) { memory.saveSavedata(dest); }
|
||||
|
||||
bool getMemoryArea(int which, unsigned char **data, int *length) { return memory.getMemoryArea(which, data, length); }
|
||||
|
||||
void setVideoBuffer(uint_least32_t *const videoBuf, const int pitch) {
|
||||
memory.setVideoBuffer(videoBuf, pitch);
|
||||
}
|
||||
|
||||
void setInputGetter(unsigned (*getInput)()) {
|
||||
memory.setInputGetter(getInput);
|
||||
}
|
||||
|
||||
void setReadCallback(void (*callback)(unsigned)) {
|
||||
memory.setReadCallback(callback);
|
||||
}
|
||||
|
||||
void setWriteCallback(void (*callback)(unsigned)) {
|
||||
memory.setWriteCallback(callback);
|
||||
}
|
||||
|
||||
void setExecCallback(void (*callback)(unsigned)) {
|
||||
memory.setExecCallback(callback);
|
||||
}
|
||||
|
||||
void setCDCallback(CDCallback cdc) {
|
||||
memory.setCDCallback(cdc);
|
||||
}
|
||||
|
||||
void setTraceCallback(void (*callback)(void *)) {
|
||||
tracecallback = callback;
|
||||
}
|
||||
|
||||
void setScanlineCallback(void (*callback)(), int sl) {
|
||||
memory.setScanlineCallback(callback, sl);
|
||||
}
|
||||
|
||||
void setRTCCallback(std::uint32_t (*callback)()) {
|
||||
memory.setRTCCallback(callback);
|
||||
}
|
||||
|
||||
void setLinkCallback(void(*callback)()) {
|
||||
memory.setLinkCallback(callback);
|
||||
}
|
||||
|
||||
int load(const char *romfiledata, unsigned romfilelength, bool forceDmg, bool multicartCompat) {
|
||||
return memory.loadROM(romfiledata, romfilelength, forceDmg, multicartCompat);
|
||||
}
|
||||
|
||||
bool loaded() const { return memory.loaded(); }
|
||||
const char * romTitle() const { return memory.romTitle(); }
|
||||
|
||||
void setSoundBuffer(uint_least32_t *const buf) { memory.setSoundBuffer(buf); }
|
||||
unsigned fillSoundBuffer() { return memory.fillSoundBuffer(cycleCounter_); }
|
||||
|
||||
bool isCgb() const { return memory.isCgb(); }
|
||||
|
||||
void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned rgb32) {
|
||||
memory.setDmgPaletteColor(palNum, colorNum, rgb32);
|
||||
}
|
||||
|
||||
void setCgbPalette(unsigned *lut) {
|
||||
memory.setCgbPalette(lut);
|
||||
}
|
||||
|
||||
unsigned char* cgbBiosBuffer() { return memory.cgbBiosBuffer(); }
|
||||
unsigned char* dmgBiosBuffer() { return memory.dmgBiosBuffer(); }
|
||||
bool gbIsCgb() { return memory.gbIsCgb(); }
|
||||
|
||||
//unsigned char ExternalRead(unsigned short addr) { return memory.read(addr, cycleCounter_); }
|
||||
unsigned char ExternalRead(unsigned short addr) { return memory.peek(addr); }
|
||||
void ExternalWrite(unsigned short addr, unsigned char val) { memory.write_nocb(addr, val, cycleCounter_); }
|
||||
|
||||
int LinkStatus(int which) { return memory.LinkStatus(which); }
|
||||
|
||||
void GetRegs(int *dest);
|
||||
|
||||
void SetInterruptAddresses(int *addrs, int numAddrs);
|
||||
int GetHitInterruptAddress();
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -26,12 +26,12 @@
|
|||
namespace gambatte {
|
||||
struct GB::Priv {
|
||||
CPU cpu;
|
||||
bool gbaCgbMode;
|
||||
unsigned loadflags;
|
||||
unsigned layersMask;
|
||||
|
||||
uint_least32_t vbuff[160*144];
|
||||
|
||||
Priv() : gbaCgbMode(false), layersMask(LAYER_MASK_BG | LAYER_MASK_OBJ)
|
||||
Priv() : loadflags(0), layersMask(LAYER_MASK_BG | LAYER_MASK_OBJ)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -94,8 +94,7 @@ void GB::reset(const std::uint32_t now) {
|
|||
|
||||
SaveState state;
|
||||
p_->cpu.setStatePtrs(state);
|
||||
|
||||
setInitState(state, p_->cpu.isCgb(), p_->gbaCgbMode, now);
|
||||
setInitState(state, !(p_->loadflags & FORCE_DMG), p_->loadflags & GBA_CGB, now);
|
||||
p_->cpu.loadState(state);
|
||||
if (length > 0)
|
||||
{
|
||||
|
@ -146,11 +145,12 @@ int GB::load(const char *romfiledata, unsigned romfilelength, const std::uint32_
|
|||
// p_->cpu.saveSavedata();
|
||||
|
||||
const int failed = p_->cpu.load(romfiledata, romfilelength, flags & FORCE_DMG, flags & MULTICART_COMPAT);
|
||||
|
||||
|
||||
if (!failed) {
|
||||
SaveState state;
|
||||
p_->cpu.setStatePtrs(state);
|
||||
setInitState(state, p_->cpu.isCgb(), p_->gbaCgbMode = flags & GBA_CGB, now);
|
||||
p_->loadflags = flags;
|
||||
setInitState(state, !(flags & FORCE_DMG), flags & GBA_CGB, now);
|
||||
p_->cpu.loadState(state);
|
||||
//p_->cpu.loadSavedata();
|
||||
}
|
||||
|
@ -158,6 +158,16 @@ int GB::load(const char *romfiledata, unsigned romfilelength, const std::uint32_
|
|||
return failed;
|
||||
}
|
||||
|
||||
int GB::loadGBCBios(const char* biosfiledata) {
|
||||
memcpy(p_->cpu.cgbBiosBuffer(), biosfiledata, 0x900);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GB::loadDMGBios(const char* biosfiledata) {
|
||||
memcpy(p_->cpu.dmgBiosBuffer(), biosfiledata, 0x100);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool GB::isCgb() const {
|
||||
return p_->cpu.isCgb();
|
||||
}
|
||||
|
@ -228,10 +238,20 @@ void GB::GetRegs(int *dest) {
|
|||
p_->cpu.GetRegs(dest);
|
||||
}
|
||||
|
||||
void GB::SetInterruptAddresses(int *addrs, int numAddrs)
|
||||
{
|
||||
p_->cpu.SetInterruptAddresses(addrs, numAddrs);
|
||||
}
|
||||
|
||||
int GB::GetHitInterruptAddress()
|
||||
{
|
||||
return p_->cpu.GetHitInterruptAddress();
|
||||
}
|
||||
|
||||
SYNCFUNC(GB)
|
||||
{
|
||||
SSS(p_->cpu);
|
||||
NSS(p_->gbaCgbMode);
|
||||
NSS(p_->loadflags);
|
||||
NSS(p_->vbuff);
|
||||
}
|
||||
|
||||
|
|
|
@ -1041,11 +1041,11 @@ static void setInitialCgbIoamhram(unsigned char *const ioamhram) {
|
|||
};
|
||||
|
||||
static const unsigned char ffxxDump[0x100] = {
|
||||
0xCF, 0x00, 0x7C, 0xFF, 0x44, 0x00, 0x00, 0xF8,
|
||||
0xCF, 0x00, 0x7C, 0xFF, 0x00, 0x00, 0x00, 0xF8,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE1,
|
||||
0x80, 0xBF, 0xF3, 0xFF, 0xBF, 0xFF, 0x3F, 0x00,
|
||||
0x80, 0x3F, 0x00, 0xFF, 0xBF, 0xFF, 0x3F, 0x00,
|
||||
0xFF, 0xBF, 0x7F, 0xFF, 0x9F, 0xFF, 0xBF, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0xBF, 0x77, 0xF3, 0xF1, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0xBF, 0x00, 0x00, 0x70, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
|
@ -1148,59 +1148,56 @@ static void setInitialDmgIoamhram(unsigned char *const ioamhram) {
|
|||
|
||||
void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbMode, const std::uint32_t now) {
|
||||
static const unsigned char cgbObjpDump[0x40] = {
|
||||
0x00, 0x00, 0xF2, 0xAB,
|
||||
0x61, 0xC2, 0xD9, 0xBA,
|
||||
0x88, 0x6E, 0xDD, 0x63,
|
||||
0x28, 0x27, 0xFB, 0x9F,
|
||||
0x35, 0x42, 0xD6, 0xD4,
|
||||
0x50, 0x48, 0x57, 0x5E,
|
||||
0x23, 0x3E, 0x3D, 0xCA,
|
||||
0x71, 0x21, 0x37, 0xC0,
|
||||
0xC6, 0xB3, 0xFB, 0xF9,
|
||||
0x08, 0x00, 0x8D, 0x29,
|
||||
0xA3, 0x20, 0xDB, 0x87,
|
||||
0x62, 0x05, 0x5D, 0xD4,
|
||||
0x0E, 0x08, 0xFE, 0xAF,
|
||||
0x20, 0x02, 0xD7, 0xFF,
|
||||
0x07, 0x6A, 0x55, 0xEC,
|
||||
0x00, 0x00, 0xF2, 0xAB,
|
||||
0x61, 0xC2, 0xD9, 0xBA,
|
||||
0x88, 0x6E, 0xDD, 0x63,
|
||||
0x28, 0x27, 0xFB, 0x9F,
|
||||
0x35, 0x42, 0xD6, 0xD4,
|
||||
0x50, 0x48, 0x57, 0x5E,
|
||||
0x23, 0x3E, 0x3D, 0xCA,
|
||||
0x71, 0x21, 0x37, 0xC0,
|
||||
0xC6, 0xB3, 0xFB, 0xF9,
|
||||
0x08, 0x00, 0x8D, 0x29,
|
||||
0xA3, 0x20, 0xDB, 0x87,
|
||||
0x62, 0x05, 0x5D, 0xD4,
|
||||
0x0E, 0x08, 0xFE, 0xAF,
|
||||
0x20, 0x02, 0xD7, 0xFF,
|
||||
0x07, 0x6A, 0x55, 0xEC,
|
||||
0x83, 0x40, 0x0B, 0x77
|
||||
};
|
||||
|
||||
state.cpu.PC = 0x100;
|
||||
state.cpu.SP = 0xFFFE;
|
||||
state.cpu.A = cgb * 0x10 | 0x01;
|
||||
state.cpu.B = cgb & gbaCgbMode;
|
||||
state.cpu.C = 0x13;
|
||||
state.cpu.D = 0x00;
|
||||
state.cpu.E = 0xD8;
|
||||
state.cpu.F = 0xB0;
|
||||
state.cpu.H = 0x01;
|
||||
state.cpu.L = 0x4D;
|
||||
state.cpu.skip = false;
|
||||
setInitialVram(state.mem.vram.ptr, cgb);
|
||||
state.cpu.cycleCounter = cgb ? 0x102A0 : 0x102A0 + 0x8D2C;
|
||||
|
||||
state.cpu.cycleCounter = 8;
|
||||
state.cpu.PC = 0;
|
||||
state.cpu.SP = 0;
|
||||
state.cpu.A = 0;
|
||||
state.cpu.B = 0;
|
||||
state.cpu.C = 0;
|
||||
state.cpu.D = 0;
|
||||
state.cpu.E = 0;
|
||||
state.cpu.F = 0;
|
||||
state.cpu.H = 0;
|
||||
state.cpu.L = 0;
|
||||
state.cpu.skip = false;
|
||||
state.mem.biosMode = true;
|
||||
state.mem.cgbSwitching = false;
|
||||
state.mem.agbMode = gbaCgbMode;
|
||||
|
||||
std::memset(state.mem.sram.ptr, 0xFF, state.mem.sram.getSz());
|
||||
|
||||
setInitialVram(state.mem.vram.ptr, cgb);
|
||||
|
||||
if (cgb) {
|
||||
setInitialCgbWram(state.mem.wram.ptr);
|
||||
}
|
||||
else {
|
||||
setInitialDmgWram(state.mem.wram.ptr);
|
||||
}
|
||||
|
||||
if (cgb) {
|
||||
setInitialCgbIoamhram(state.mem.ioamhram.ptr);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
setInitialDmgWram(state.mem.wram.ptr);
|
||||
setInitialDmgIoamhram(state.mem.ioamhram.ptr);
|
||||
}
|
||||
|
||||
state.mem.ioamhram.ptr[0x140] = 0x91;
|
||||
state.mem.ioamhram.ptr[0x104] = 0x1C;
|
||||
|
||||
state.mem.ioamhram.ptr[0x104] = 0;
|
||||
state.mem.ioamhram.ptr[0x140] = 0;
|
||||
state.mem.ioamhram.ptr[0x144] = 0x00;
|
||||
|
||||
|
||||
state.mem.divLastUpdate = 0;
|
||||
state.mem.timaLastUpdate = 0;
|
||||
state.mem.tmatime = DISABLED_TIME;
|
||||
|
@ -1218,29 +1215,30 @@ void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbM
|
|||
state.mem.enableRam = false;
|
||||
state.mem.rambankMode = false;
|
||||
state.mem.hdmaTransfer = false;
|
||||
state.mem.gbIsCgb = cgb;
|
||||
|
||||
|
||||
|
||||
for (unsigned i = 0x00; i < 0x40; i += 0x02) {
|
||||
state.ppu.bgpData.ptr[i] = 0xFF;
|
||||
state.ppu.bgpData.ptr[i ] = 0xFF;
|
||||
state.ppu.bgpData.ptr[i + 1] = 0x7F;
|
||||
}
|
||||
|
||||
|
||||
std::memcpy(state.ppu.objpData.ptr, cgbObjpDump, sizeof(cgbObjpDump));
|
||||
|
||||
|
||||
if (!cgb) {
|
||||
state.ppu.bgpData.ptr[0] = state.mem.ioamhram.get()[0x147];
|
||||
state.ppu.objpData.ptr[0] = state.mem.ioamhram.get()[0x148];
|
||||
state.ppu.objpData.ptr[1] = state.mem.ioamhram.get()[0x149];
|
||||
}
|
||||
|
||||
|
||||
for (unsigned pos = 0; pos < 80; ++pos)
|
||||
state.ppu.oamReaderBuf.ptr[pos] = state.mem.ioamhram.ptr[(pos * 2 & ~3) | (pos & 1)];
|
||||
|
||||
|
||||
std::fill_n(state.ppu.oamReaderSzbuf.ptr, 40, false);
|
||||
std::memset(state.ppu.spAttribList, 0, sizeof(state.ppu.spAttribList));
|
||||
std::memset(state.ppu.spByte0List, 0, sizeof(state.ppu.spByte0List));
|
||||
std::memset(state.ppu.spByte1List, 0, sizeof(state.ppu.spByte1List));
|
||||
state.ppu.videoCycles = cgb ? 144 * 456ul + 164 : 153 * 456ul + 396;
|
||||
state.ppu.videoCycles = 0;
|
||||
state.ppu.enableDisplayM0Time = state.cpu.cycleCounter;
|
||||
state.ppu.winYPos = 0xFF;
|
||||
state.ppu.xpos = 0;
|
||||
|
@ -1254,7 +1252,7 @@ void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbM
|
|||
state.ppu.state = 0;
|
||||
state.ppu.nextSprite = 0;
|
||||
state.ppu.currentSprite = 0;
|
||||
state.ppu.lyc = state.mem.ioamhram.get()[0x145];
|
||||
state.ppu.lyc = state.mem.ioamhram.get()[0x145];
|
||||
state.ppu.m0lyc = state.mem.ioamhram.get()[0x145];
|
||||
state.ppu.weMaster = false;
|
||||
state.ppu.winDrawState = 0;
|
||||
|
@ -1263,36 +1261,38 @@ void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbM
|
|||
state.ppu.nextM0Irq = 0;
|
||||
state.ppu.oldWy = state.mem.ioamhram.get()[0x14A];
|
||||
state.ppu.pendingLcdstatIrq = false;
|
||||
state.ppu.isCgb = cgb;
|
||||
|
||||
state.spu.cycleCounter = 0x1000 | (state.cpu.cycleCounter >> 1 & 0xFFF); // spu.cycleCounter >> 12 & 7 represents the frame sequencer position.
|
||||
|
||||
|
||||
state.spu.cycleCounter = 0; // spu.cycleCounter >> 12 & 7 represents the frame sequencer position.
|
||||
|
||||
state.spu.ch1.sweep.counter = SoundUnit::COUNTER_DISABLED;
|
||||
state.spu.ch1.sweep.shadow = 0;
|
||||
state.spu.ch1.sweep.nr0 = 0;
|
||||
state.spu.ch1.sweep.negging = false;
|
||||
state.spu.ch1.duty.nextPosUpdate = (state.spu.cycleCounter & ~1) + 2048 * 2;
|
||||
state.spu.ch1.duty.nextPosUpdate = (state.spu.cycleCounter & ~1ul) + 37 * 2;
|
||||
state.spu.ch1.duty.nr3 = 0;
|
||||
state.spu.ch1.duty.pos = 0;
|
||||
state.spu.ch1.env.counter = SoundUnit::COUNTER_DISABLED;
|
||||
state.spu.ch1.env.volume = 0;
|
||||
state.spu.ch1.lcounter.counter = SoundUnit::COUNTER_DISABLED;
|
||||
state.spu.ch1.lcounter.lengthCounter = 0x40;
|
||||
state.spu.ch1.lcounter.lengthCounter = 0;
|
||||
state.spu.ch1.nr4 = 0;
|
||||
state.spu.ch1.master = true;
|
||||
|
||||
state.spu.ch2.duty.nextPosUpdate = (state.spu.cycleCounter & ~1) + 2048 * 2;
|
||||
|
||||
state.spu.ch2.duty.nextPosUpdate = SoundUnit::COUNTER_DISABLED;
|
||||
state.spu.ch2.duty.nr3 = 0;
|
||||
state.spu.ch2.duty.pos = 0;
|
||||
state.spu.ch2.env.counter = state.spu.cycleCounter - ((state.spu.cycleCounter - 0x1000) & 0x7FFF) + 8ul * 0x8000;
|
||||
state.spu.ch2.env.counter = SoundUnit::COUNTER_DISABLED;
|
||||
state.spu.ch2.env.volume = 0;
|
||||
state.spu.ch2.lcounter.counter = SoundUnit::COUNTER_DISABLED;
|
||||
state.spu.ch2.lcounter.lengthCounter = 0x40;
|
||||
state.spu.ch2.lcounter.lengthCounter = 0;
|
||||
state.spu.ch2.nr4 = 0;
|
||||
state.spu.ch2.master = false;
|
||||
|
||||
|
||||
for (unsigned i = 0; i < 0x10; ++i)
|
||||
state.spu.ch3.waveRam.ptr[i] = state.mem.ioamhram.get()[0x130 + i];
|
||||
|
||||
|
||||
state.spu.ch3.lcounter.counter = SoundUnit::COUNTER_DISABLED;
|
||||
state.spu.ch3.lcounter.lengthCounter = 0x100;
|
||||
state.spu.ch3.waveCounter = SoundUnit::COUNTER_DISABLED;
|
||||
|
@ -1302,16 +1302,16 @@ void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbM
|
|||
state.spu.ch3.wavePos = 0;
|
||||
state.spu.ch3.sampleBuf = 0;
|
||||
state.spu.ch3.master = false;
|
||||
|
||||
|
||||
state.spu.ch4.lfsr.counter = state.spu.cycleCounter + 4;
|
||||
state.spu.ch4.lfsr.reg = 0xFF;
|
||||
state.spu.ch4.env.counter = state.spu.cycleCounter - ((state.spu.cycleCounter - 0x1000) & 0x7FFF) + 8ul * 0x8000;
|
||||
state.spu.ch4.env.counter = SoundUnit::COUNTER_DISABLED;
|
||||
state.spu.ch4.env.volume = 0;
|
||||
state.spu.ch4.lcounter.counter = SoundUnit::COUNTER_DISABLED;
|
||||
state.spu.ch4.lcounter.lengthCounter = 0x40;
|
||||
state.spu.ch4.lcounter.lengthCounter = 0;
|
||||
state.spu.ch4.nr4 = 0;
|
||||
state.spu.ch4.master = false;
|
||||
|
||||
|
||||
state.rtc.baseTime = now;
|
||||
state.rtc.haltTime = state.rtc.baseTime;
|
||||
state.rtc.dataDh = 0;
|
||||
|
|
|
@ -1,51 +1,51 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef INSERTION_SORT_H
|
||||
#define INSERTION_SORT_H
|
||||
|
||||
#include <functional>
|
||||
|
||||
template<typename T, class Less>
|
||||
void insertionSort(T *const start, T *const end, Less less) {
|
||||
if (start >= end)
|
||||
return;
|
||||
|
||||
T *a = start;
|
||||
|
||||
while (++a < end) {
|
||||
const T e = *a;
|
||||
|
||||
T *b = a;
|
||||
|
||||
while (b != start && less(e, *(b - 1))) {
|
||||
*b = *(b - 1);
|
||||
b = b - 1;
|
||||
}
|
||||
|
||||
*b = e;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void insertionSort(T *const start, T *const end) {
|
||||
insertionSort(start, end, std::less<T>());
|
||||
}
|
||||
|
||||
#endif /*INSERTION_SORT_H*/
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef INSERTION_SORT_H
|
||||
#define INSERTION_SORT_H
|
||||
|
||||
#include <functional>
|
||||
|
||||
template<typename T, class Less>
|
||||
void insertionSort(T *const start, T *const end, Less less) {
|
||||
if (start >= end)
|
||||
return;
|
||||
|
||||
T *a = start;
|
||||
|
||||
while (++a < end) {
|
||||
const T e = *a;
|
||||
|
||||
T *b = a;
|
||||
|
||||
while (b != start && less(e, *(b - 1))) {
|
||||
*b = *(b - 1);
|
||||
b = b - 1;
|
||||
}
|
||||
|
||||
*b = e;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void insertionSort(T *const start, T *const end) {
|
||||
insertionSort(start, end, std::less<T>());
|
||||
}
|
||||
|
||||
#endif /*INSERTION_SORT_H*/
|
||||
|
|
|
@ -94,13 +94,13 @@ void InterruptRequester::setIfreg(const unsigned ifreg) {
|
|||
eventTimes.setValue<INTERRUPTS>(pendingIrqs() ? minIntTime : static_cast<unsigned long>(DISABLED_TIME));
|
||||
}
|
||||
|
||||
SYNCFUNC(InterruptRequester)
|
||||
{
|
||||
SSS(eventTimes);
|
||||
NSS(minIntTime);
|
||||
NSS(ifreg_);
|
||||
NSS(iereg_);
|
||||
NSS(intFlags.flags_);
|
||||
}
|
||||
SYNCFUNC(InterruptRequester)
|
||||
{
|
||||
SSS(eventTimes);
|
||||
NSS(minIntTime);
|
||||
NSS(ifreg_);
|
||||
NSS(iereg_);
|
||||
NSS(intFlags.flags_);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include "counterdef.h"
|
||||
#include "minkeeper.h"
|
||||
#include "newstate.h"
|
||||
#include "newstate.h"
|
||||
|
||||
namespace gambatte {
|
||||
struct SaveState;
|
||||
|
@ -62,6 +62,7 @@ public:
|
|||
void resetCc(unsigned long oldCc, unsigned long newCc);
|
||||
|
||||
unsigned ifreg() const { return ifreg_; }
|
||||
unsigned iereg() const { return iereg_; }
|
||||
unsigned pendingIrqs() const { return ifreg_ & iereg_; }
|
||||
bool ime() const { return intFlags.ime(); }
|
||||
bool halted() const { return intFlags.halted(); }
|
||||
|
@ -81,7 +82,7 @@ public:
|
|||
void setEventTime(const MemEventId id, unsigned long value) { eventTimes.setValue(id, value); }
|
||||
unsigned long eventTime(MemEventId id) const { return eventTimes.value(id); }
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
inline void flagHdmaReq(InterruptRequester *const intreq) { intreq->setEventTime<DMA>(0); }
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,112 +1,113 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2007-2010 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef CARTRIDGE_H
|
||||
#define CARTRIDGE_H
|
||||
|
||||
#include "memptrs.h"
|
||||
#include "rtc.h"
|
||||
#include "savestate.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "newstate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
//DOOM
|
||||
//enum eAddressMappingType
|
||||
//{
|
||||
// eAddressMappingType_ROM,
|
||||
// eAddressMappingType_RAM
|
||||
//};
|
||||
//
|
||||
//struct AddressMapping
|
||||
//{
|
||||
// int32_t address;
|
||||
// eAddressMappingType type;
|
||||
//};
|
||||
|
||||
class Mbc {
|
||||
public:
|
||||
virtual ~Mbc() {}
|
||||
virtual void romWrite(unsigned P, unsigned data) = 0;
|
||||
virtual void loadState(const SaveState::Mem &ss) = 0;
|
||||
virtual bool isAddressWithinAreaRombankCanBeMappedTo(unsigned address, unsigned rombank) const = 0;
|
||||
//virtual void mapAddress(AddressMapping* mapping, unsigned address) const = 0; //DOOM
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns)
|
||||
{
|
||||
// can't have virtual templates, so..
|
||||
SyncState(ns, isReader);
|
||||
}
|
||||
virtual void SyncState(NewState *ns, bool isReader) = 0;
|
||||
};
|
||||
|
||||
class Cartridge {
|
||||
MemPtrs memptrs;
|
||||
Rtc rtc;
|
||||
std::auto_ptr<Mbc> mbc;
|
||||
|
||||
public:
|
||||
void setStatePtrs(SaveState &);
|
||||
void loadState(const SaveState &);
|
||||
|
||||
bool loaded() const { return mbc.get(); }
|
||||
|
||||
const unsigned char * rmem(unsigned area) const { return memptrs.rmem(area); }
|
||||
unsigned char * wmem(unsigned area) const { return memptrs.wmem(area); }
|
||||
unsigned char * vramdata() const { return memptrs.vramdata(); }
|
||||
unsigned char * romdata(unsigned area) const { return memptrs.romdata(area); }
|
||||
unsigned char * wramdata(unsigned area) const { return memptrs.wramdata(area); }
|
||||
const unsigned char * rdisabledRam() const { return memptrs.rdisabledRam(); }
|
||||
const unsigned char * rsrambankptr() const { return memptrs.rsrambankptr(); }
|
||||
unsigned char * wsrambankptr() const { return memptrs.wsrambankptr(); }
|
||||
unsigned char * vrambankptr() const { return memptrs.vrambankptr(); }
|
||||
OamDmaSrc oamDmaSrc() const { return memptrs.oamDmaSrc(); }
|
||||
|
||||
void setVrambank(unsigned bank) { memptrs.setVrambank(bank); }
|
||||
void setWrambank(unsigned bank) { memptrs.setWrambank(bank); }
|
||||
void setOamDmaSrc(OamDmaSrc oamDmaSrc) { memptrs.setOamDmaSrc(oamDmaSrc); }
|
||||
|
||||
void mbcWrite(unsigned addr, unsigned data) { mbc->romWrite(addr, data); }
|
||||
|
||||
bool isCgb() const { return gambatte::isCgb(memptrs); }
|
||||
|
||||
void rtcWrite(unsigned data) { rtc.write(data); }
|
||||
unsigned char rtcRead() const { return *rtc.getActive(); }
|
||||
|
||||
void loadSavedata(const char *data);
|
||||
int saveSavedataLength();
|
||||
void saveSavedata(char *dest);
|
||||
|
||||
bool getMemoryArea(int which, unsigned char **data, int *length) const;
|
||||
|
||||
int loadROM(const char *romfiledata, unsigned romfilelength, bool forceDmg, bool multicartCompat);
|
||||
const char * romTitle() const { return reinterpret_cast<const char *>(memptrs.romdata() + 0x134); }
|
||||
|
||||
void setRTCCallback(std::uint32_t (*callback)()) {
|
||||
rtc.setRTCCallback(callback);
|
||||
}
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007-2010 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef CARTRIDGE_H
|
||||
#define CARTRIDGE_H
|
||||
|
||||
#include "memptrs.h"
|
||||
#include "rtc.h"
|
||||
#include "savestate.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "newstate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
//DOOM
|
||||
//enum eAddressMappingType
|
||||
//{
|
||||
// eAddressMappingType_ROM,
|
||||
// eAddressMappingType_RAM
|
||||
//};
|
||||
//
|
||||
//struct AddressMapping
|
||||
//{
|
||||
// int32_t address;
|
||||
// eAddressMappingType type;
|
||||
//};
|
||||
|
||||
class Mbc {
|
||||
public:
|
||||
virtual ~Mbc() {}
|
||||
virtual void romWrite(unsigned P, unsigned data) = 0;
|
||||
virtual void loadState(const SaveState::Mem &ss) = 0;
|
||||
virtual bool isAddressWithinAreaRombankCanBeMappedTo(unsigned address, unsigned rombank) const = 0;
|
||||
//virtual void mapAddress(AddressMapping* mapping, unsigned address) const = 0; //DOOM
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns)
|
||||
{
|
||||
// can't have virtual templates, so..
|
||||
SyncState(ns, isReader);
|
||||
}
|
||||
virtual void SyncState(NewState *ns, bool isReader) = 0;
|
||||
};
|
||||
|
||||
class Cartridge {
|
||||
MemPtrs memptrs;
|
||||
Rtc rtc;
|
||||
std::auto_ptr<Mbc> mbc;
|
||||
|
||||
public:
|
||||
void setStatePtrs(SaveState &);
|
||||
void loadState(const SaveState &);
|
||||
|
||||
bool loaded() const { return mbc.get(); }
|
||||
|
||||
const unsigned char * rmem(unsigned area) const { return memptrs.rmem(area); }
|
||||
unsigned char * wmem(unsigned area) const { return memptrs.wmem(area); }
|
||||
unsigned char * vramdata() const { return memptrs.vramdata(); }
|
||||
unsigned char * romdata(unsigned area) const { return memptrs.romdata(area); }
|
||||
unsigned char * wramdata(unsigned area) const { return memptrs.wramdata(area); }
|
||||
const unsigned char * rdisabledRam() const { return memptrs.rdisabledRam(); }
|
||||
const unsigned char * rsrambankptr() const { return memptrs.rsrambankptr(); }
|
||||
unsigned char * wsrambankptr() const { return memptrs.wsrambankptr(); }
|
||||
unsigned char * vrambankptr() const { return memptrs.vrambankptr(); }
|
||||
OamDmaSrc oamDmaSrc() const { return memptrs.oamDmaSrc(); }
|
||||
unsigned curRomBank() const { return memptrs.curRomBank(); }
|
||||
|
||||
void setVrambank(unsigned bank) { memptrs.setVrambank(bank); }
|
||||
void setWrambank(unsigned bank) { memptrs.setWrambank(bank); }
|
||||
void setOamDmaSrc(OamDmaSrc oamDmaSrc) { memptrs.setOamDmaSrc(oamDmaSrc); }
|
||||
|
||||
void mbcWrite(unsigned addr, unsigned data) { mbc->romWrite(addr, data); }
|
||||
|
||||
bool isCgb() const { return gambatte::isCgb(memptrs); }
|
||||
|
||||
void rtcWrite(unsigned data) { rtc.write(data); }
|
||||
unsigned char rtcRead() const { return *rtc.getActive(); }
|
||||
|
||||
void loadSavedata(const char *data);
|
||||
int saveSavedataLength();
|
||||
void saveSavedata(char *dest);
|
||||
|
||||
bool getMemoryArea(int which, unsigned char **data, int *length) const;
|
||||
|
||||
int loadROM(const char *romfiledata, unsigned romfilelength, bool forceDmg, bool multicartCompat);
|
||||
const char * romTitle() const { return reinterpret_cast<const char *>(memptrs.romdata() + 0x134); }
|
||||
|
||||
void setRTCCallback(std::uint32_t (*callback)()) {
|
||||
rtc.setRTCCallback(callback);
|
||||
}
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,226 +1,223 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2007-2010 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "memptrs.h"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
MemPtrs::MemPtrs()
|
||||
: rmem_(), wmem_(), romdata_(), wramdata_(), vrambankptr_(0), rsrambankptr_(0),
|
||||
wsrambankptr_(0), memchunk_(0), rambankdata_(0), wramdataend_(0), oamDmaSrc_(OAM_DMA_SRC_OFF),
|
||||
memchunk_len(0)
|
||||
{
|
||||
}
|
||||
|
||||
MemPtrs::~MemPtrs() {
|
||||
delete []memchunk_;
|
||||
}
|
||||
|
||||
void MemPtrs::reset(const unsigned rombanks, const unsigned rambanks, const unsigned wrambanks) {
|
||||
delete []memchunk_;
|
||||
|
||||
memchunk_len = 0x4000 + rombanks * 0x4000ul + 0x4000 + rambanks * 0x2000ul + wrambanks * 0x1000ul + 0x4000;
|
||||
memchunk_ = new unsigned char[memchunk_len];
|
||||
|
||||
romdata_[0] = romdata();
|
||||
|
||||
rambankdata_ = romdata_[0] + rombanks * 0x4000ul + 0x4000;
|
||||
wramdata_[0] = rambankdata_ + rambanks * 0x2000ul;
|
||||
wramdataend_ = wramdata_[0] + wrambanks * 0x1000ul;
|
||||
|
||||
std::memset(rdisabledRamw(), 0xFF, 0x2000);
|
||||
|
||||
oamDmaSrc_ = OAM_DMA_SRC_OFF;
|
||||
rmem_[0x3] = rmem_[0x2] = rmem_[0x1] = rmem_[0x0] = romdata_[0];
|
||||
rmem_[0xC] = wmem_[0xC] = wramdata_[0] - 0xC000;
|
||||
rmem_[0xE] = wmem_[0xE] = wramdata_[0] - 0xE000;
|
||||
setRombank(1);
|
||||
setRambank(0, 0);
|
||||
setVrambank(0);
|
||||
setWrambank(1);
|
||||
|
||||
// we save only the ram areas
|
||||
memchunk_saveoffs = vramdata() - memchunk_;
|
||||
memchunk_savelen = wramdataend() - memchunk_ - memchunk_saveoffs;
|
||||
}
|
||||
|
||||
void MemPtrs::setRombank0(const unsigned bank) {
|
||||
|
||||
romdata_[0] = romdata() + bank * 0x4000ul;
|
||||
|
||||
rmem_[0x3] = rmem_[0x2] = rmem_[0x1] = rmem_[0x0] = romdata_[0];
|
||||
disconnectOamDmaAreas();
|
||||
}
|
||||
|
||||
void MemPtrs::setRombank(const unsigned bank) {
|
||||
|
||||
romdata_[1] = romdata() + bank * 0x4000ul - 0x4000;
|
||||
|
||||
rmem_[0x7] = rmem_[0x6] = rmem_[0x5] = rmem_[0x4] = romdata_[1];
|
||||
disconnectOamDmaAreas();
|
||||
}
|
||||
|
||||
void MemPtrs::setRambank(const unsigned flags, const unsigned rambank) {
|
||||
unsigned char *const srambankptr = flags & RTC_EN
|
||||
? 0
|
||||
: (rambankdata() != rambankdataend()
|
||||
? rambankdata_ + rambank * 0x2000ul - 0xA000 : wdisabledRam() - 0xA000);
|
||||
|
||||
rsrambankptr_ = (flags & READ_EN) && srambankptr != wdisabledRam() - 0xA000 ? srambankptr : rdisabledRamw() - 0xA000;
|
||||
wsrambankptr_ = flags & WRITE_EN ? srambankptr : wdisabledRam() - 0xA000;
|
||||
rmem_[0xB] = rmem_[0xA] = rsrambankptr_;
|
||||
wmem_[0xB] = wmem_[0xA] = wsrambankptr_;
|
||||
disconnectOamDmaAreas();
|
||||
}
|
||||
|
||||
void MemPtrs::setWrambank(const unsigned bank) {
|
||||
wramdata_[1] = wramdata_[0] + ((bank & 0x07) ? (bank & 0x07) : 1) * 0x1000;
|
||||
rmem_[0xD] = wmem_[0xD] = wramdata_[1] - 0xD000;
|
||||
disconnectOamDmaAreas();
|
||||
}
|
||||
|
||||
void MemPtrs::setOamDmaSrc(const OamDmaSrc oamDmaSrc) {
|
||||
rmem_[0x3] = rmem_[0x2] = rmem_[0x1] = rmem_[0x0] = romdata_[0];
|
||||
rmem_[0x7] = rmem_[0x6] = rmem_[0x5] = rmem_[0x4] = romdata_[1];
|
||||
rmem_[0xB] = rmem_[0xA] = rsrambankptr_;
|
||||
wmem_[0xB] = wmem_[0xA] = wsrambankptr_;
|
||||
rmem_[0xC] = wmem_[0xC] = wramdata_[0] - 0xC000;
|
||||
rmem_[0xD] = wmem_[0xD] = wramdata_[1] - 0xD000;
|
||||
rmem_[0xE] = wmem_[0xE] = wramdata_[0] - 0xE000;
|
||||
|
||||
oamDmaSrc_ = oamDmaSrc;
|
||||
disconnectOamDmaAreas();
|
||||
}
|
||||
|
||||
void MemPtrs::disconnectOamDmaAreas() {
|
||||
if (isCgb(*this)) {
|
||||
switch (oamDmaSrc_) {
|
||||
case OAM_DMA_SRC_ROM: // fall through
|
||||
case OAM_DMA_SRC_SRAM:
|
||||
case OAM_DMA_SRC_INVALID:
|
||||
std::fill(rmem_, rmem_ + 8, static_cast<unsigned char *>(0));
|
||||
rmem_[0xB] = rmem_[0xA] = 0;
|
||||
wmem_[0xB] = wmem_[0xA] = 0;
|
||||
break;
|
||||
case OAM_DMA_SRC_VRAM:
|
||||
break;
|
||||
case OAM_DMA_SRC_WRAM:
|
||||
rmem_[0xE] = rmem_[0xD] = rmem_[0xC] = 0;
|
||||
wmem_[0xE] = wmem_[0xD] = wmem_[0xC] = 0;
|
||||
break;
|
||||
case OAM_DMA_SRC_OFF:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (oamDmaSrc_) {
|
||||
case OAM_DMA_SRC_ROM: // fall through
|
||||
case OAM_DMA_SRC_SRAM:
|
||||
case OAM_DMA_SRC_WRAM:
|
||||
case OAM_DMA_SRC_INVALID:
|
||||
std::fill(rmem_, rmem_ + 8, static_cast<unsigned char *>(0));
|
||||
rmem_[0xB] = rmem_[0xA] = 0;
|
||||
wmem_[0xB] = wmem_[0xA] = 0;
|
||||
rmem_[0xE] = rmem_[0xD] = rmem_[0xC] = 0;
|
||||
wmem_[0xE] = wmem_[0xD] = wmem_[0xC] = 0;
|
||||
break;
|
||||
case OAM_DMA_SRC_VRAM:
|
||||
break;
|
||||
case OAM_DMA_SRC_OFF:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// all pointers here are relative to memchunk_
|
||||
#define MSS(a) RSS(a,memchunk_)
|
||||
#define MSL(a) RSL(a,memchunk_)
|
||||
|
||||
SYNCFUNC(MemPtrs)
|
||||
{
|
||||
/*
|
||||
int memchunk_len_old = memchunk_len;
|
||||
int memchunk_saveoffs_old = memchunk_saveoffs;
|
||||
int memchunk_savelen_old = memchunk_savelen;
|
||||
*/
|
||||
|
||||
NSS(memchunk_len);
|
||||
NSS(memchunk_saveoffs);
|
||||
NSS(memchunk_savelen);
|
||||
|
||||
/*
|
||||
if (isReader)
|
||||
{
|
||||
if (memchunk_len != memchunk_len_old || memchunk_saveoffs != memchunk_saveoffs_old || memchunk_savelen != memchunk_savelen_old)
|
||||
__debugbreak();
|
||||
}
|
||||
*/
|
||||
|
||||
PSS(memchunk_ + memchunk_saveoffs, memchunk_savelen);
|
||||
|
||||
MSS(rmem_[0x0]);
|
||||
MSS(wmem_[0x0]);
|
||||
MSS(rmem_[0x1]);
|
||||
MSS(wmem_[0x1]);
|
||||
MSS(rmem_[0x2]);
|
||||
MSS(wmem_[0x2]);
|
||||
MSS(rmem_[0x3]);
|
||||
MSS(wmem_[0x3]);
|
||||
MSS(rmem_[0x4]);
|
||||
MSS(wmem_[0x4]);
|
||||
MSS(rmem_[0x5]);
|
||||
MSS(wmem_[0x5]);
|
||||
MSS(rmem_[0x6]);
|
||||
MSS(wmem_[0x6]);
|
||||
MSS(rmem_[0x7]);
|
||||
MSS(wmem_[0x7]);
|
||||
MSS(rmem_[0x8]);
|
||||
MSS(wmem_[0x8]);
|
||||
MSS(rmem_[0x9]);
|
||||
MSS(wmem_[0x9]);
|
||||
MSS(rmem_[0xa]);
|
||||
MSS(wmem_[0xa]);
|
||||
MSS(rmem_[0xb]);
|
||||
MSS(wmem_[0xb]);
|
||||
MSS(rmem_[0xc]);
|
||||
MSS(wmem_[0xc]);
|
||||
MSS(rmem_[0xd]);
|
||||
MSS(wmem_[0xd]);
|
||||
MSS(rmem_[0xe]);
|
||||
MSS(wmem_[0xe]);
|
||||
MSS(rmem_[0xf]);
|
||||
MSS(wmem_[0xf]);
|
||||
//for (int i = 0; i < 0x10; i++)
|
||||
//{
|
||||
// MSS(rmem_[i]);
|
||||
// MSS(wmem_[i]);
|
||||
//}
|
||||
MSS(romdata_[0]);
|
||||
MSS(romdata_[1]);
|
||||
MSS(wramdata_[0]);
|
||||
MSS(wramdata_[1]);
|
||||
MSS(vrambankptr_);
|
||||
MSS(rsrambankptr_);
|
||||
MSS(wsrambankptr_);
|
||||
MSS(rambankdata_);
|
||||
MSS(wramdataend_);
|
||||
NSS(oamDmaSrc_);
|
||||
}
|
||||
|
||||
}
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007-2010 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "memptrs.h"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
MemPtrs::MemPtrs()
|
||||
: rmem_(), wmem_(), romdata_(), wramdata_(), vrambankptr_(0), rsrambankptr_(0),
|
||||
wsrambankptr_(0), memchunk_(0), rambankdata_(0), wramdataend_(0), oamDmaSrc_(OAM_DMA_SRC_OFF),
|
||||
curRomBank_(1),
|
||||
memchunk_len(0)
|
||||
{
|
||||
}
|
||||
|
||||
MemPtrs::~MemPtrs() {
|
||||
delete []memchunk_;
|
||||
}
|
||||
|
||||
void MemPtrs::reset(const unsigned rombanks, const unsigned rambanks, const unsigned wrambanks) {
|
||||
delete []memchunk_;
|
||||
memchunk_len = 0x4000 + rombanks * 0x4000ul + 0x4000 + rambanks * 0x2000ul + wrambanks * 0x1000ul + 0x4000;
|
||||
memchunk_ = new unsigned char[memchunk_len];
|
||||
|
||||
romdata_[0] = romdata();
|
||||
rambankdata_ = romdata_[0] + rombanks * 0x4000ul + 0x4000;
|
||||
wramdata_[0] = rambankdata_ + rambanks * 0x2000ul;
|
||||
wramdataend_ = wramdata_[0] + wrambanks * 0x1000ul;
|
||||
|
||||
std::memset(rdisabledRamw(), 0xFF, 0x2000);
|
||||
|
||||
oamDmaSrc_ = OAM_DMA_SRC_OFF;
|
||||
rmem_[0x3] = rmem_[0x2] = rmem_[0x1] = rmem_[0x0] = romdata_[0];
|
||||
rmem_[0xC] = wmem_[0xC] = wramdata_[0] - 0xC000;
|
||||
rmem_[0xE] = wmem_[0xE] = wramdata_[0] - 0xE000;
|
||||
setRombank(1);
|
||||
setRambank(0, 0);
|
||||
setVrambank(0);
|
||||
setWrambank(1);
|
||||
|
||||
// we save only the ram areas
|
||||
memchunk_saveoffs = vramdata() - memchunk_;
|
||||
memchunk_savelen = wramdataend() - memchunk_ - memchunk_saveoffs;
|
||||
}
|
||||
|
||||
void MemPtrs::setRombank0(const unsigned bank) {
|
||||
romdata_[0] = romdata() + bank * 0x4000ul;
|
||||
rmem_[0x3] = rmem_[0x2] = rmem_[0x1] = rmem_[0x0] = romdata_[0];
|
||||
disconnectOamDmaAreas();
|
||||
}
|
||||
|
||||
void MemPtrs::setRombank(const unsigned bank) {
|
||||
curRomBank_ = bank;
|
||||
romdata_[1] = romdata() + bank * 0x4000ul - 0x4000;
|
||||
rmem_[0x7] = rmem_[0x6] = rmem_[0x5] = rmem_[0x4] = romdata_[1];
|
||||
disconnectOamDmaAreas();
|
||||
}
|
||||
|
||||
void MemPtrs::setRambank(const unsigned flags, const unsigned rambank) {
|
||||
unsigned char *const srambankptr = flags & RTC_EN
|
||||
? 0
|
||||
: (rambankdata() != rambankdataend()
|
||||
? rambankdata_ + rambank * 0x2000ul - 0xA000 : wdisabledRam() - 0xA000);
|
||||
|
||||
rsrambankptr_ = (flags & READ_EN) && srambankptr != wdisabledRam() - 0xA000 ? srambankptr : rdisabledRamw() - 0xA000;
|
||||
wsrambankptr_ = flags & WRITE_EN ? srambankptr : wdisabledRam() - 0xA000;
|
||||
rmem_[0xB] = rmem_[0xA] = rsrambankptr_;
|
||||
wmem_[0xB] = wmem_[0xA] = wsrambankptr_;
|
||||
disconnectOamDmaAreas();
|
||||
}
|
||||
|
||||
void MemPtrs::setWrambank(const unsigned bank) {
|
||||
wramdata_[1] = wramdata_[0] + ((bank & 0x07) ? (bank & 0x07) : 1) * 0x1000;
|
||||
rmem_[0xD] = wmem_[0xD] = wramdata_[1] - 0xD000;
|
||||
disconnectOamDmaAreas();
|
||||
}
|
||||
|
||||
void MemPtrs::setOamDmaSrc(const OamDmaSrc oamDmaSrc) {
|
||||
rmem_[0x3] = rmem_[0x2] = rmem_[0x1] = rmem_[0x0] = romdata_[0];
|
||||
rmem_[0x7] = rmem_[0x6] = rmem_[0x5] = rmem_[0x4] = romdata_[1];
|
||||
rmem_[0xB] = rmem_[0xA] = rsrambankptr_;
|
||||
wmem_[0xB] = wmem_[0xA] = wsrambankptr_;
|
||||
rmem_[0xC] = wmem_[0xC] = wramdata_[0] - 0xC000;
|
||||
rmem_[0xD] = wmem_[0xD] = wramdata_[1] - 0xD000;
|
||||
rmem_[0xE] = wmem_[0xE] = wramdata_[0] - 0xE000;
|
||||
|
||||
oamDmaSrc_ = oamDmaSrc;
|
||||
disconnectOamDmaAreas();
|
||||
}
|
||||
|
||||
void MemPtrs::disconnectOamDmaAreas() {
|
||||
if (isCgb(*this)) {
|
||||
switch (oamDmaSrc_) {
|
||||
case OAM_DMA_SRC_ROM: // fall through
|
||||
case OAM_DMA_SRC_SRAM:
|
||||
case OAM_DMA_SRC_INVALID:
|
||||
std::fill(rmem_, rmem_ + 8, static_cast<unsigned char *>(0));
|
||||
rmem_[0xB] = rmem_[0xA] = 0;
|
||||
wmem_[0xB] = wmem_[0xA] = 0;
|
||||
break;
|
||||
case OAM_DMA_SRC_VRAM:
|
||||
break;
|
||||
case OAM_DMA_SRC_WRAM:
|
||||
rmem_[0xE] = rmem_[0xD] = rmem_[0xC] = 0;
|
||||
wmem_[0xE] = wmem_[0xD] = wmem_[0xC] = 0;
|
||||
break;
|
||||
case OAM_DMA_SRC_OFF:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (oamDmaSrc_) {
|
||||
case OAM_DMA_SRC_ROM: // fall through
|
||||
case OAM_DMA_SRC_SRAM:
|
||||
case OAM_DMA_SRC_WRAM:
|
||||
case OAM_DMA_SRC_INVALID:
|
||||
std::fill(rmem_, rmem_ + 8, static_cast<unsigned char *>(0));
|
||||
rmem_[0xB] = rmem_[0xA] = 0;
|
||||
wmem_[0xB] = wmem_[0xA] = 0;
|
||||
rmem_[0xE] = rmem_[0xD] = rmem_[0xC] = 0;
|
||||
wmem_[0xE] = wmem_[0xD] = wmem_[0xC] = 0;
|
||||
break;
|
||||
case OAM_DMA_SRC_VRAM:
|
||||
break;
|
||||
case OAM_DMA_SRC_OFF:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// all pointers here are relative to memchunk_
|
||||
#define MSS(a) RSS(a,memchunk_)
|
||||
#define MSL(a) RSL(a,memchunk_)
|
||||
|
||||
SYNCFUNC(MemPtrs)
|
||||
{
|
||||
/*
|
||||
int memchunk_len_old = memchunk_len;
|
||||
int memchunk_saveoffs_old = memchunk_saveoffs;
|
||||
int memchunk_savelen_old = memchunk_savelen;
|
||||
*/
|
||||
|
||||
NSS(memchunk_len);
|
||||
NSS(memchunk_saveoffs);
|
||||
NSS(memchunk_savelen);
|
||||
|
||||
/*
|
||||
if (isReader)
|
||||
{
|
||||
if (memchunk_len != memchunk_len_old || memchunk_saveoffs != memchunk_saveoffs_old || memchunk_savelen != memchunk_savelen_old)
|
||||
__debugbreak();
|
||||
}
|
||||
*/
|
||||
|
||||
PSS(memchunk_ + memchunk_saveoffs, memchunk_savelen);
|
||||
|
||||
MSS(rmem_[0x0]);
|
||||
MSS(wmem_[0x0]);
|
||||
MSS(rmem_[0x1]);
|
||||
MSS(wmem_[0x1]);
|
||||
MSS(rmem_[0x2]);
|
||||
MSS(wmem_[0x2]);
|
||||
MSS(rmem_[0x3]);
|
||||
MSS(wmem_[0x3]);
|
||||
MSS(rmem_[0x4]);
|
||||
MSS(wmem_[0x4]);
|
||||
MSS(rmem_[0x5]);
|
||||
MSS(wmem_[0x5]);
|
||||
MSS(rmem_[0x6]);
|
||||
MSS(wmem_[0x6]);
|
||||
MSS(rmem_[0x7]);
|
||||
MSS(wmem_[0x7]);
|
||||
MSS(rmem_[0x8]);
|
||||
MSS(wmem_[0x8]);
|
||||
MSS(rmem_[0x9]);
|
||||
MSS(wmem_[0x9]);
|
||||
MSS(rmem_[0xa]);
|
||||
MSS(wmem_[0xa]);
|
||||
MSS(rmem_[0xb]);
|
||||
MSS(wmem_[0xb]);
|
||||
MSS(rmem_[0xc]);
|
||||
MSS(wmem_[0xc]);
|
||||
MSS(rmem_[0xd]);
|
||||
MSS(wmem_[0xd]);
|
||||
MSS(rmem_[0xe]);
|
||||
MSS(wmem_[0xe]);
|
||||
MSS(rmem_[0xf]);
|
||||
MSS(wmem_[0xf]);
|
||||
//for (int i = 0; i < 0x10; i++)
|
||||
//{
|
||||
// MSS(rmem_[i]);
|
||||
// MSS(wmem_[i]);
|
||||
//}
|
||||
MSS(romdata_[0]);
|
||||
MSS(romdata_[1]);
|
||||
MSS(wramdata_[0]);
|
||||
MSS(wramdata_[1]);
|
||||
MSS(vrambankptr_);
|
||||
MSS(rsrambankptr_);
|
||||
MSS(wsrambankptr_);
|
||||
MSS(rambankdata_);
|
||||
MSS(wramdataend_);
|
||||
NSS(oamDmaSrc_);
|
||||
NSS(curRomBank_);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,93 +1,96 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2007-2010 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef MEMPTRS_H
|
||||
#define MEMPTRS_H
|
||||
|
||||
#include "newstate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
enum OamDmaSrc { OAM_DMA_SRC_ROM, OAM_DMA_SRC_SRAM, OAM_DMA_SRC_VRAM,
|
||||
OAM_DMA_SRC_WRAM, OAM_DMA_SRC_INVALID, OAM_DMA_SRC_OFF };
|
||||
|
||||
class MemPtrs {
|
||||
const unsigned char *rmem_[0x10];
|
||||
unsigned char *wmem_[0x10];
|
||||
|
||||
unsigned char *romdata_[2];
|
||||
unsigned char *wramdata_[2];
|
||||
unsigned char *vrambankptr_;
|
||||
unsigned char *rsrambankptr_;
|
||||
unsigned char *wsrambankptr_;
|
||||
unsigned char *memchunk_;
|
||||
unsigned char *rambankdata_;
|
||||
unsigned char *wramdataend_;
|
||||
|
||||
OamDmaSrc oamDmaSrc_;
|
||||
|
||||
int memchunk_len;
|
||||
int memchunk_saveoffs;
|
||||
int memchunk_savelen;
|
||||
|
||||
MemPtrs(const MemPtrs &);
|
||||
MemPtrs & operator=(const MemPtrs &);
|
||||
void disconnectOamDmaAreas();
|
||||
unsigned char * rdisabledRamw() const { return wramdataend_ ; }
|
||||
unsigned char * wdisabledRam() const { return wramdataend_ + 0x2000; }
|
||||
public:
|
||||
enum RamFlag { READ_EN = 1, WRITE_EN = 2, RTC_EN = 4 };
|
||||
|
||||
MemPtrs();
|
||||
~MemPtrs();
|
||||
void reset(unsigned rombanks, unsigned rambanks, unsigned wrambanks);
|
||||
|
||||
const unsigned char * rmem(unsigned area) const { return rmem_[area]; }
|
||||
unsigned char * wmem(unsigned area) const { return wmem_[area]; }
|
||||
unsigned char * vramdata() const { return rambankdata_ - 0x4000; }
|
||||
unsigned char * vramdataend() const { return rambankdata_; }
|
||||
unsigned char * romdata() const { return memchunk_ + 0x4000;}
|
||||
unsigned char * romdata(unsigned area) const { return romdata_[area]; }
|
||||
unsigned char * romdataend() const { return rambankdata_ - 0x4000; }
|
||||
unsigned char * wramdata(unsigned area) const { return wramdata_[area]; }
|
||||
unsigned char * wramdataend() const { return wramdataend_; }
|
||||
unsigned char * rambankdata() const { return rambankdata_; }
|
||||
unsigned char * rambankdataend() const { return wramdata_[0]; }
|
||||
const unsigned char * rdisabledRam() const { return rdisabledRamw(); }
|
||||
const unsigned char * rsrambankptr() const { return rsrambankptr_; }
|
||||
unsigned char * wsrambankptr() const { return wsrambankptr_; }
|
||||
unsigned char * vrambankptr() const { return vrambankptr_; }
|
||||
OamDmaSrc oamDmaSrc() const { return oamDmaSrc_; }
|
||||
|
||||
void setRombank0(unsigned bank);
|
||||
void setRombank(unsigned bank);
|
||||
void setRambank(unsigned ramFlags, unsigned rambank);
|
||||
void setVrambank(unsigned bank) { vrambankptr_ = vramdata() + bank * 0x2000ul - 0x8000; }
|
||||
void setWrambank(unsigned bank);
|
||||
void setOamDmaSrc(OamDmaSrc oamDmaSrc);
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
inline bool isCgb(const MemPtrs &memptrs) {
|
||||
return memptrs.wramdataend() - memptrs.wramdata(0) == 0x8000;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007-2010 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef MEMPTRS_H
|
||||
#define MEMPTRS_H
|
||||
|
||||
#include "newstate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
enum OamDmaSrc { OAM_DMA_SRC_ROM, OAM_DMA_SRC_SRAM, OAM_DMA_SRC_VRAM,
|
||||
OAM_DMA_SRC_WRAM, OAM_DMA_SRC_INVALID, OAM_DMA_SRC_OFF };
|
||||
|
||||
class MemPtrs {
|
||||
const unsigned char *rmem_[0x10];
|
||||
unsigned char *wmem_[0x10];
|
||||
|
||||
unsigned char *romdata_[2];
|
||||
unsigned char *wramdata_[2];
|
||||
unsigned char *vrambankptr_;
|
||||
unsigned char *rsrambankptr_;
|
||||
unsigned char *wsrambankptr_;
|
||||
unsigned char *memchunk_;
|
||||
unsigned char *rambankdata_;
|
||||
unsigned char *wramdataend_;
|
||||
|
||||
OamDmaSrc oamDmaSrc_;
|
||||
|
||||
unsigned curRomBank_;
|
||||
|
||||
int memchunk_len;
|
||||
int memchunk_saveoffs;
|
||||
int memchunk_savelen;
|
||||
|
||||
MemPtrs(const MemPtrs &);
|
||||
MemPtrs & operator=(const MemPtrs &);
|
||||
void disconnectOamDmaAreas();
|
||||
unsigned char * rdisabledRamw() const { return wramdataend_ ; }
|
||||
unsigned char * wdisabledRam() const { return wramdataend_ + 0x2000; }
|
||||
public:
|
||||
enum RamFlag { READ_EN = 1, WRITE_EN = 2, RTC_EN = 4 };
|
||||
|
||||
MemPtrs();
|
||||
~MemPtrs();
|
||||
void reset(unsigned rombanks, unsigned rambanks, unsigned wrambanks);
|
||||
|
||||
const unsigned char * rmem(unsigned area) const { return rmem_[area]; }
|
||||
unsigned char * wmem(unsigned area) const { return wmem_[area]; }
|
||||
unsigned char * vramdata() const { return rambankdata_ - 0x4000; }
|
||||
unsigned char * vramdataend() const { return rambankdata_; }
|
||||
unsigned char * romdata() const { return memchunk_ + 0x4000; }
|
||||
unsigned char * romdata(unsigned area) const { return romdata_[area]; }
|
||||
unsigned char * romdataend() const { return rambankdata_ - 0x4000; }
|
||||
unsigned char * wramdata(unsigned area) const { return wramdata_[area]; }
|
||||
unsigned char * wramdataend() const { return wramdataend_; }
|
||||
unsigned char * rambankdata() const { return rambankdata_; }
|
||||
unsigned char * rambankdataend() const { return wramdata_[0]; }
|
||||
const unsigned char * rdisabledRam() const { return rdisabledRamw(); }
|
||||
const unsigned char * rsrambankptr() const { return rsrambankptr_; }
|
||||
unsigned char * wsrambankptr() const { return wsrambankptr_; }
|
||||
unsigned char * vrambankptr() const { return vrambankptr_; }
|
||||
OamDmaSrc oamDmaSrc() const { return oamDmaSrc_; }
|
||||
unsigned curRomBank() const { return curRomBank_; }
|
||||
|
||||
void setRombank0(unsigned bank);
|
||||
void setRombank(unsigned bank);
|
||||
void setRambank(unsigned ramFlags, unsigned rambank);
|
||||
void setVrambank(unsigned bank) { vrambankptr_ = vramdata() + bank * 0x2000ul - 0x8000; }
|
||||
void setWrambank(unsigned bank);
|
||||
void setOamDmaSrc(OamDmaSrc oamDmaSrc);
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
inline bool isCgb(const MemPtrs &memptrs) {
|
||||
return memptrs.wramdataend() - memptrs.wramdata(0) == 0x8000;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,177 +1,177 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "rtc.h"
|
||||
#include "../savestate.h"
|
||||
#include <cstdlib>
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
Rtc::Rtc()
|
||||
: activeData(NULL),
|
||||
activeSet(NULL),
|
||||
baseTime(0),
|
||||
haltTime(0),
|
||||
index(5),
|
||||
dataDh(0),
|
||||
dataDl(0),
|
||||
dataH(0),
|
||||
dataM(0),
|
||||
dataS(0),
|
||||
enabled(false),
|
||||
lastLatchData(false),
|
||||
timeCB(0)
|
||||
{
|
||||
}
|
||||
|
||||
void Rtc::doLatch() {
|
||||
std::uint32_t tmp = ((dataDh & 0x40) ? haltTime : timeCB()) - baseTime;
|
||||
|
||||
while (tmp > 0x1FF * 86400) {
|
||||
baseTime += 0x1FF * 86400;
|
||||
tmp -= 0x1FF * 86400;
|
||||
dataDh |= 0x80;
|
||||
}
|
||||
|
||||
dataDl = (tmp / 86400) & 0xFF;
|
||||
dataDh &= 0xFE;
|
||||
dataDh |= ((tmp / 86400) & 0x100) >> 8;
|
||||
tmp %= 86400;
|
||||
|
||||
dataH = tmp / 3600;
|
||||
tmp %= 3600;
|
||||
|
||||
dataM = tmp / 60;
|
||||
tmp %= 60;
|
||||
|
||||
dataS = tmp;
|
||||
}
|
||||
|
||||
void Rtc::doSwapActive() {
|
||||
if (!enabled || index > 4) {
|
||||
activeData = NULL;
|
||||
activeSet = NULL;
|
||||
} else switch (index) {
|
||||
case 0x00:
|
||||
activeData = &dataS;
|
||||
activeSet = &Rtc::setS;
|
||||
break;
|
||||
case 0x01:
|
||||
activeData = &dataM;
|
||||
activeSet = &Rtc::setM;
|
||||
break;
|
||||
case 0x02:
|
||||
activeData = &dataH;
|
||||
activeSet = &Rtc::setH;
|
||||
break;
|
||||
case 0x03:
|
||||
activeData = &dataDl;
|
||||
activeSet = &Rtc::setDl;
|
||||
break;
|
||||
case 0x04:
|
||||
activeData = &dataDh;
|
||||
activeSet = &Rtc::setDh;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Rtc::loadState(const SaveState &state) {
|
||||
baseTime = state.rtc.baseTime;
|
||||
haltTime = state.rtc.haltTime;
|
||||
dataDh = state.rtc.dataDh;
|
||||
dataDl = state.rtc.dataDl;
|
||||
dataH = state.rtc.dataH;
|
||||
dataM = state.rtc.dataM;
|
||||
dataS = state.rtc.dataS;
|
||||
lastLatchData = state.rtc.lastLatchData;
|
||||
|
||||
doSwapActive();
|
||||
}
|
||||
|
||||
void Rtc::setDh(const unsigned new_dh) {
|
||||
const std::uint32_t unixtime = (dataDh & 0x40) ? haltTime : timeCB();
|
||||
const std::uint32_t old_highdays = ((unixtime - baseTime) / 86400) & 0x100;
|
||||
baseTime += old_highdays * 86400;
|
||||
baseTime -= ((new_dh & 0x1) << 8) * 86400;
|
||||
|
||||
if ((dataDh ^ new_dh) & 0x40) {
|
||||
if (new_dh & 0x40)
|
||||
haltTime = timeCB();
|
||||
else
|
||||
baseTime += timeCB() - haltTime;
|
||||
}
|
||||
}
|
||||
|
||||
void Rtc::setDl(const unsigned new_lowdays) {
|
||||
const std::uint32_t unixtime = (dataDh & 0x40) ? haltTime : timeCB();
|
||||
const std::uint32_t old_lowdays = ((unixtime - baseTime) / 86400) & 0xFF;
|
||||
baseTime += old_lowdays * 86400;
|
||||
baseTime -= new_lowdays * 86400;
|
||||
}
|
||||
|
||||
void Rtc::setH(const unsigned new_hours) {
|
||||
const std::uint32_t unixtime = (dataDh & 0x40) ? haltTime : timeCB();
|
||||
const std::uint32_t old_hours = ((unixtime - baseTime) / 3600) % 24;
|
||||
baseTime += old_hours * 3600;
|
||||
baseTime -= new_hours * 3600;
|
||||
}
|
||||
|
||||
void Rtc::setM(const unsigned new_minutes) {
|
||||
const std::uint32_t unixtime = (dataDh & 0x40) ? haltTime : timeCB();
|
||||
const std::uint32_t old_minutes = ((unixtime - baseTime) / 60) % 60;
|
||||
baseTime += old_minutes * 60;
|
||||
baseTime -= new_minutes * 60;
|
||||
}
|
||||
|
||||
void Rtc::setS(const unsigned new_seconds) {
|
||||
const std::uint32_t unixtime = (dataDh & 0x40) ? haltTime : timeCB();
|
||||
baseTime += (unixtime - baseTime) % 60;
|
||||
baseTime -= new_seconds;
|
||||
}
|
||||
|
||||
SYNCFUNC(Rtc)
|
||||
{
|
||||
EBS(activeData, 0);
|
||||
EVS(activeData, &dataS, 1);
|
||||
EVS(activeData, &dataM, 2);
|
||||
EVS(activeData, &dataH, 3);
|
||||
EVS(activeData, &dataDl, 4);
|
||||
EVS(activeData, &dataDh, 5);
|
||||
EES(activeData, NULL);
|
||||
|
||||
EBS(activeSet, 0);
|
||||
EVS(activeSet, &Rtc::setS, 1);
|
||||
EVS(activeSet, &Rtc::setM, 2);
|
||||
EVS(activeSet, &Rtc::setH, 3);
|
||||
EVS(activeSet, &Rtc::setDl, 4);
|
||||
EVS(activeSet, &Rtc::setDh, 5);
|
||||
EES(activeSet, NULL);
|
||||
|
||||
NSS(baseTime);
|
||||
NSS(haltTime);
|
||||
NSS(index);
|
||||
NSS(dataDh);
|
||||
NSS(dataDl);
|
||||
NSS(dataH);
|
||||
NSS(dataM);
|
||||
NSS(dataS);
|
||||
NSS(enabled);
|
||||
NSS(lastLatchData);
|
||||
}
|
||||
|
||||
}
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "rtc.h"
|
||||
#include "../savestate.h"
|
||||
#include <cstdlib>
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
Rtc::Rtc()
|
||||
: activeData(NULL),
|
||||
activeSet(NULL),
|
||||
baseTime(0),
|
||||
haltTime(0),
|
||||
index(5),
|
||||
dataDh(0),
|
||||
dataDl(0),
|
||||
dataH(0),
|
||||
dataM(0),
|
||||
dataS(0),
|
||||
enabled(false),
|
||||
lastLatchData(false),
|
||||
timeCB(0)
|
||||
{
|
||||
}
|
||||
|
||||
void Rtc::doLatch() {
|
||||
std::uint32_t tmp = ((dataDh & 0x40) ? haltTime : timeCB()) - baseTime;
|
||||
|
||||
while (tmp > 0x1FF * 86400) {
|
||||
baseTime += 0x1FF * 86400;
|
||||
tmp -= 0x1FF * 86400;
|
||||
dataDh |= 0x80;
|
||||
}
|
||||
|
||||
dataDl = (tmp / 86400) & 0xFF;
|
||||
dataDh &= 0xFE;
|
||||
dataDh |= ((tmp / 86400) & 0x100) >> 8;
|
||||
tmp %= 86400;
|
||||
|
||||
dataH = tmp / 3600;
|
||||
tmp %= 3600;
|
||||
|
||||
dataM = tmp / 60;
|
||||
tmp %= 60;
|
||||
|
||||
dataS = tmp;
|
||||
}
|
||||
|
||||
void Rtc::doSwapActive() {
|
||||
if (!enabled || index > 4) {
|
||||
activeData = NULL;
|
||||
activeSet = NULL;
|
||||
} else switch (index) {
|
||||
case 0x00:
|
||||
activeData = &dataS;
|
||||
activeSet = &Rtc::setS;
|
||||
break;
|
||||
case 0x01:
|
||||
activeData = &dataM;
|
||||
activeSet = &Rtc::setM;
|
||||
break;
|
||||
case 0x02:
|
||||
activeData = &dataH;
|
||||
activeSet = &Rtc::setH;
|
||||
break;
|
||||
case 0x03:
|
||||
activeData = &dataDl;
|
||||
activeSet = &Rtc::setDl;
|
||||
break;
|
||||
case 0x04:
|
||||
activeData = &dataDh;
|
||||
activeSet = &Rtc::setDh;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Rtc::loadState(const SaveState &state) {
|
||||
baseTime = state.rtc.baseTime;
|
||||
haltTime = state.rtc.haltTime;
|
||||
dataDh = state.rtc.dataDh;
|
||||
dataDl = state.rtc.dataDl;
|
||||
dataH = state.rtc.dataH;
|
||||
dataM = state.rtc.dataM;
|
||||
dataS = state.rtc.dataS;
|
||||
lastLatchData = state.rtc.lastLatchData;
|
||||
|
||||
doSwapActive();
|
||||
}
|
||||
|
||||
void Rtc::setDh(const unsigned new_dh) {
|
||||
const std::uint32_t unixtime = (dataDh & 0x40) ? haltTime : timeCB();
|
||||
const std::uint32_t old_highdays = ((unixtime - baseTime) / 86400) & 0x100;
|
||||
baseTime += old_highdays * 86400;
|
||||
baseTime -= ((new_dh & 0x1) << 8) * 86400;
|
||||
|
||||
if ((dataDh ^ new_dh) & 0x40) {
|
||||
if (new_dh & 0x40)
|
||||
haltTime = timeCB();
|
||||
else
|
||||
baseTime += timeCB() - haltTime;
|
||||
}
|
||||
}
|
||||
|
||||
void Rtc::setDl(const unsigned new_lowdays) {
|
||||
const std::uint32_t unixtime = (dataDh & 0x40) ? haltTime : timeCB();
|
||||
const std::uint32_t old_lowdays = ((unixtime - baseTime) / 86400) & 0xFF;
|
||||
baseTime += old_lowdays * 86400;
|
||||
baseTime -= new_lowdays * 86400;
|
||||
}
|
||||
|
||||
void Rtc::setH(const unsigned new_hours) {
|
||||
const std::uint32_t unixtime = (dataDh & 0x40) ? haltTime : timeCB();
|
||||
const std::uint32_t old_hours = ((unixtime - baseTime) / 3600) % 24;
|
||||
baseTime += old_hours * 3600;
|
||||
baseTime -= new_hours * 3600;
|
||||
}
|
||||
|
||||
void Rtc::setM(const unsigned new_minutes) {
|
||||
const std::uint32_t unixtime = (dataDh & 0x40) ? haltTime : timeCB();
|
||||
const std::uint32_t old_minutes = ((unixtime - baseTime) / 60) % 60;
|
||||
baseTime += old_minutes * 60;
|
||||
baseTime -= new_minutes * 60;
|
||||
}
|
||||
|
||||
void Rtc::setS(const unsigned new_seconds) {
|
||||
const std::uint32_t unixtime = (dataDh & 0x40) ? haltTime : timeCB();
|
||||
baseTime += (unixtime - baseTime) % 60;
|
||||
baseTime -= new_seconds;
|
||||
}
|
||||
|
||||
SYNCFUNC(Rtc)
|
||||
{
|
||||
EBS(activeData, 0);
|
||||
EVS(activeData, &dataS, 1);
|
||||
EVS(activeData, &dataM, 2);
|
||||
EVS(activeData, &dataH, 3);
|
||||
EVS(activeData, &dataDl, 4);
|
||||
EVS(activeData, &dataDh, 5);
|
||||
EES(activeData, NULL);
|
||||
|
||||
EBS(activeSet, 0);
|
||||
EVS(activeSet, &Rtc::setS, 1);
|
||||
EVS(activeSet, &Rtc::setM, 2);
|
||||
EVS(activeSet, &Rtc::setH, 3);
|
||||
EVS(activeSet, &Rtc::setDl, 4);
|
||||
EVS(activeSet, &Rtc::setDh, 5);
|
||||
EES(activeSet, NULL);
|
||||
|
||||
NSS(baseTime);
|
||||
NSS(haltTime);
|
||||
NSS(index);
|
||||
NSS(dataDh);
|
||||
NSS(dataDl);
|
||||
NSS(dataH);
|
||||
NSS(dataM);
|
||||
NSS(dataS);
|
||||
NSS(enabled);
|
||||
NSS(lastLatchData);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,98 +1,98 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef RTC_H
|
||||
#define RTC_H
|
||||
|
||||
#include <cstdint>
|
||||
#include "newstate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
struct SaveState;
|
||||
|
||||
class Rtc {
|
||||
private:
|
||||
unsigned char *activeData;
|
||||
void (Rtc::*activeSet)(unsigned);
|
||||
std::uint32_t baseTime;
|
||||
std::uint32_t haltTime;
|
||||
unsigned char index;
|
||||
unsigned char dataDh;
|
||||
unsigned char dataDl;
|
||||
unsigned char dataH;
|
||||
unsigned char dataM;
|
||||
unsigned char dataS;
|
||||
bool enabled;
|
||||
bool lastLatchData;
|
||||
std::uint32_t (*timeCB)();
|
||||
|
||||
void doLatch();
|
||||
void doSwapActive();
|
||||
void setDh(unsigned new_dh);
|
||||
void setDl(unsigned new_lowdays);
|
||||
void setH(unsigned new_hours);
|
||||
void setM(unsigned new_minutes);
|
||||
void setS(unsigned new_seconds);
|
||||
|
||||
public:
|
||||
Rtc();
|
||||
|
||||
const unsigned char* getActive() const { return activeData; }
|
||||
std::uint32_t getBaseTime() const { return baseTime; }
|
||||
|
||||
void setBaseTime(const std::uint32_t baseTime) {
|
||||
this->baseTime = baseTime;
|
||||
// doLatch();
|
||||
}
|
||||
|
||||
void latch(const unsigned data) {
|
||||
if (!lastLatchData && data == 1)
|
||||
doLatch();
|
||||
|
||||
lastLatchData = data;
|
||||
}
|
||||
|
||||
void loadState(const SaveState &state);
|
||||
|
||||
void set(const bool enabled, unsigned bank) {
|
||||
bank &= 0xF;
|
||||
bank -= 8;
|
||||
|
||||
this->enabled = enabled;
|
||||
this->index = bank;
|
||||
|
||||
doSwapActive();
|
||||
}
|
||||
|
||||
void write(const unsigned data) {
|
||||
// if (activeSet)
|
||||
(this->*activeSet)(data);
|
||||
*activeData = data;
|
||||
}
|
||||
|
||||
void setRTCCallback(std::uint32_t (*callback)()) {
|
||||
timeCB = callback;
|
||||
}
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef RTC_H
|
||||
#define RTC_H
|
||||
|
||||
#include <cstdint>
|
||||
#include "newstate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
struct SaveState;
|
||||
|
||||
class Rtc {
|
||||
private:
|
||||
unsigned char *activeData;
|
||||
void (Rtc::*activeSet)(unsigned);
|
||||
std::uint32_t baseTime;
|
||||
std::uint32_t haltTime;
|
||||
unsigned char index;
|
||||
unsigned char dataDh;
|
||||
unsigned char dataDl;
|
||||
unsigned char dataH;
|
||||
unsigned char dataM;
|
||||
unsigned char dataS;
|
||||
bool enabled;
|
||||
bool lastLatchData;
|
||||
std::uint32_t (*timeCB)();
|
||||
|
||||
void doLatch();
|
||||
void doSwapActive();
|
||||
void setDh(unsigned new_dh);
|
||||
void setDl(unsigned new_lowdays);
|
||||
void setH(unsigned new_hours);
|
||||
void setM(unsigned new_minutes);
|
||||
void setS(unsigned new_seconds);
|
||||
|
||||
public:
|
||||
Rtc();
|
||||
|
||||
const unsigned char* getActive() const { return activeData; }
|
||||
std::uint32_t getBaseTime() const { return baseTime; }
|
||||
|
||||
void setBaseTime(const std::uint32_t baseTime) {
|
||||
this->baseTime = baseTime;
|
||||
// doLatch();
|
||||
}
|
||||
|
||||
void latch(const unsigned data) {
|
||||
if (!lastLatchData && data == 1)
|
||||
doLatch();
|
||||
|
||||
lastLatchData = data;
|
||||
}
|
||||
|
||||
void loadState(const SaveState &state);
|
||||
|
||||
void set(const bool enabled, unsigned bank) {
|
||||
bank &= 0xF;
|
||||
bank -= 8;
|
||||
|
||||
this->enabled = enabled;
|
||||
this->index = bank;
|
||||
|
||||
doSwapActive();
|
||||
}
|
||||
|
||||
void write(const unsigned data) {
|
||||
// if (activeSet)
|
||||
(this->*activeSet)(data);
|
||||
*activeData = data;
|
||||
}
|
||||
|
||||
void setRTCCallback(std::uint32_t (*callback)()) {
|
||||
timeCB = callback;
|
||||
}
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,298 +1,336 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef MEMORY_H
|
||||
#define MEMORY_H
|
||||
|
||||
#include "mem/cartridge.h"
|
||||
#include "video.h"
|
||||
#include "sound.h"
|
||||
#include "interrupter.h"
|
||||
#include "tima.h"
|
||||
#include "newstate.h"
|
||||
#include "gambatte.h"
|
||||
|
||||
namespace gambatte {
|
||||
class InputGetter;
|
||||
class FilterInfo;
|
||||
|
||||
class Memory {
|
||||
Cartridge cart;
|
||||
unsigned char ioamhram[0x200];
|
||||
|
||||
void (*readCallback)(unsigned);
|
||||
void (*writeCallback)(unsigned);
|
||||
void (*execCallback)(unsigned);
|
||||
CDCallback cdCallback;
|
||||
void (*linkCallback)();
|
||||
|
||||
unsigned (*getInput)();
|
||||
unsigned long divLastUpdate;
|
||||
unsigned long lastOamDmaUpdate;
|
||||
|
||||
InterruptRequester intreq;
|
||||
Tima tima;
|
||||
LCD display;
|
||||
PSG sound;
|
||||
Interrupter interrupter;
|
||||
|
||||
unsigned short dmaSource;
|
||||
unsigned short dmaDestination;
|
||||
unsigned char oamDmaPos;
|
||||
unsigned char serialCnt;
|
||||
bool blanklcd;
|
||||
|
||||
bool LINKCABLE;
|
||||
bool linkClockTrigger;
|
||||
|
||||
void decEventCycles(MemEventId eventId, unsigned long dec);
|
||||
|
||||
void oamDmaInitSetup();
|
||||
void updateOamDma(unsigned long cycleCounter);
|
||||
void startOamDma(unsigned long cycleCounter);
|
||||
void endOamDma(unsigned long cycleCounter);
|
||||
const unsigned char * oamDmaSrcPtr() const;
|
||||
|
||||
unsigned nontrivial_ff_read(unsigned P, unsigned long cycleCounter);
|
||||
unsigned nontrivial_read(unsigned P, unsigned long cycleCounter);
|
||||
void nontrivial_ff_write(unsigned P, unsigned data, unsigned long cycleCounter);
|
||||
void nontrivial_write(unsigned P, unsigned data, unsigned long cycleCounter);
|
||||
|
||||
unsigned nontrivial_peek(unsigned P);
|
||||
unsigned nontrivial_ff_peek(unsigned P);
|
||||
|
||||
void updateSerial(unsigned long cc);
|
||||
void updateTimaIrq(unsigned long cc);
|
||||
void updateIrqs(unsigned long cc);
|
||||
|
||||
bool isDoubleSpeed() const { return display.isDoubleSpeed(); }
|
||||
|
||||
public:
|
||||
explicit Memory(const Interrupter &interrupter);
|
||||
|
||||
bool loaded() const { return cart.loaded(); }
|
||||
const char * romTitle() const { return cart.romTitle(); }
|
||||
|
||||
int debugGetLY() const { return display.debugGetLY(); }
|
||||
|
||||
void setStatePtrs(SaveState &state);
|
||||
void loadState(const SaveState &state/*, unsigned long oldCc*/);
|
||||
void loadSavedata(const char *data) { cart.loadSavedata(data); }
|
||||
int saveSavedataLength() {return cart.saveSavedataLength(); }
|
||||
void saveSavedata(char *dest) { cart.saveSavedata(dest); }
|
||||
void updateInput();
|
||||
|
||||
bool getMemoryArea(int which, unsigned char **data, int *length); // { return cart.getMemoryArea(which, data, length); }
|
||||
|
||||
unsigned long stop(unsigned long cycleCounter);
|
||||
bool isCgb() const { return display.isCgb(); }
|
||||
bool ime() const { return intreq.ime(); }
|
||||
bool halted() const { return intreq.halted(); }
|
||||
unsigned long nextEventTime() const { return intreq.minEventTime(); }
|
||||
|
||||
void setLayers(unsigned mask) { display.setLayers(mask); }
|
||||
|
||||
bool isActive() const { return intreq.eventTime(END) != DISABLED_TIME; }
|
||||
|
||||
long cyclesSinceBlit(const unsigned long cc) const {
|
||||
return cc < intreq.eventTime(BLIT) ? -1 : static_cast<long>((cc - intreq.eventTime(BLIT)) >> isDoubleSpeed());
|
||||
}
|
||||
|
||||
void halt() { intreq.halt(); }
|
||||
void ei(unsigned long cycleCounter) { if (!ime()) { intreq.ei(cycleCounter); } }
|
||||
|
||||
void di() { intreq.di(); }
|
||||
|
||||
unsigned ff_read(const unsigned P, const unsigned long cycleCounter) {
|
||||
return P < 0xFF80 ? nontrivial_ff_read(P, cycleCounter) : ioamhram[P - 0xFE00];
|
||||
}
|
||||
|
||||
struct CDMapResult
|
||||
{
|
||||
eCDLog_AddrType type;
|
||||
unsigned addr;
|
||||
};
|
||||
|
||||
CDMapResult CDMap(const unsigned P) const
|
||||
{
|
||||
if(P<0x4000)
|
||||
{
|
||||
CDMapResult ret = { eCDLog_AddrType_ROM, P };
|
||||
return ret;
|
||||
}
|
||||
else if(P<0x8000)
|
||||
{
|
||||
unsigned bank = cart.rmem(P>>12) - cart.rmem(0);
|
||||
unsigned addr = P+bank;
|
||||
CDMapResult ret = { eCDLog_AddrType_ROM, addr };
|
||||
return ret;
|
||||
}
|
||||
else if(P<0xA000) {}
|
||||
else if(P<0xC000)
|
||||
{
|
||||
if(cart.wsrambankptr())
|
||||
{
|
||||
//not bankable. but. we're not sure how much might be here
|
||||
unsigned char *data;
|
||||
int length;
|
||||
bool has = cart.getMemoryArea(3,&data,&length);
|
||||
unsigned addr = P&(length-1);
|
||||
if(has && length!=0)
|
||||
{
|
||||
CDMapResult ret = { eCDLog_AddrType_CartRAM, addr };
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(P<0xE000)
|
||||
{
|
||||
unsigned bank = cart.wramdata(P >> 12 & 1) - cart.wramdata(0);
|
||||
unsigned addr = (P&0xFFF)+bank;
|
||||
CDMapResult ret = { eCDLog_AddrType_WRAM, addr };
|
||||
return ret;
|
||||
}
|
||||
else if(P<0xFF80) {}
|
||||
else
|
||||
{
|
||||
////this is just for debugging, really, it's pretty useless
|
||||
//CDMapResult ret = { eCDLog_AddrType_HRAM, (P-0xFF80) };
|
||||
//return ret;
|
||||
}
|
||||
|
||||
CDMapResult ret = { eCDLog_AddrType_None };
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
unsigned read(const unsigned P, const unsigned long cycleCounter) {
|
||||
if (readCallback)
|
||||
readCallback(P);
|
||||
if(cdCallback)
|
||||
{
|
||||
CDMapResult map = CDMap(P);
|
||||
if(map.type != eCDLog_AddrType_None)
|
||||
cdCallback(map.addr,map.type,eCDLog_Flags_Data);
|
||||
}
|
||||
return cart.rmem(P >> 12) ? cart.rmem(P >> 12)[P] : nontrivial_read(P, cycleCounter);
|
||||
}
|
||||
|
||||
unsigned read_excb(const unsigned P, const unsigned long cycleCounter, bool first) {
|
||||
if (execCallback)
|
||||
execCallback(P);
|
||||
if(cdCallback)
|
||||
{
|
||||
CDMapResult map = CDMap(P);
|
||||
if(map.type != eCDLog_AddrType_None)
|
||||
cdCallback(map.addr,map.type,first?eCDLog_Flags_ExecFirst : eCDLog_Flags_ExecOperand);
|
||||
}
|
||||
return cart.rmem(P >> 12) ? cart.rmem(P >> 12)[P] : nontrivial_read(P, cycleCounter);
|
||||
}
|
||||
|
||||
unsigned peek(const unsigned P) {
|
||||
return cart.rmem(P >> 12) ? cart.rmem(P >> 12)[P] : nontrivial_peek(P);
|
||||
}
|
||||
|
||||
void write_nocb(const unsigned P, const unsigned data, const unsigned long cycleCounter) {
|
||||
if (cart.wmem(P >> 12)) {
|
||||
cart.wmem(P >> 12)[P] = data;
|
||||
} else
|
||||
nontrivial_write(P, data, cycleCounter);
|
||||
}
|
||||
|
||||
void write(const unsigned P, const unsigned data, const unsigned long cycleCounter) {
|
||||
if (cart.wmem(P >> 12)) {
|
||||
cart.wmem(P >> 12)[P] = data;
|
||||
} else
|
||||
nontrivial_write(P, data, cycleCounter);
|
||||
if (writeCallback)
|
||||
writeCallback(P);
|
||||
if(cdCallback)
|
||||
{
|
||||
CDMapResult map = CDMap(P);
|
||||
if(map.type != eCDLog_AddrType_None)
|
||||
cdCallback(map.addr,map.type,eCDLog_Flags_Data);
|
||||
}
|
||||
}
|
||||
|
||||
void ff_write(const unsigned P, const unsigned data, const unsigned long cycleCounter) {
|
||||
if (P - 0xFF80u < 0x7Fu) {
|
||||
ioamhram[P - 0xFE00] = data;
|
||||
} else
|
||||
nontrivial_ff_write(P, data, cycleCounter);
|
||||
if(cdCallback)
|
||||
{
|
||||
CDMapResult map = CDMap(P);
|
||||
if(map.type != eCDLog_AddrType_None)
|
||||
cdCallback(map.addr,map.type,eCDLog_Flags_Data);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long event(unsigned long cycleCounter);
|
||||
unsigned long resetCounters(unsigned long cycleCounter);
|
||||
|
||||
int loadROM(const char *romfiledata, unsigned romfilelength, bool forceDmg, bool multicartCompat);
|
||||
|
||||
void setInputGetter(unsigned (*getInput)()) {
|
||||
this->getInput = getInput;
|
||||
}
|
||||
|
||||
void setReadCallback(void (*callback)(unsigned)) {
|
||||
this->readCallback = callback;
|
||||
}
|
||||
void setWriteCallback(void (*callback)(unsigned)) {
|
||||
this->writeCallback = callback;
|
||||
}
|
||||
void setExecCallback(void (*callback)(unsigned)) {
|
||||
this->execCallback = callback;
|
||||
}
|
||||
void setCDCallback(CDCallback cdc) {
|
||||
this->cdCallback = cdc;
|
||||
}
|
||||
|
||||
void setScanlineCallback(void (*callback)(), int sl) {
|
||||
display.setScanlineCallback(callback, sl);
|
||||
}
|
||||
|
||||
void setRTCCallback(std::uint32_t (*callback)()) {
|
||||
cart.setRTCCallback(callback);
|
||||
}
|
||||
|
||||
void setLinkCallback(void (*callback)()) {
|
||||
this->linkCallback = callback;
|
||||
}
|
||||
|
||||
void setEndtime(unsigned long cc, unsigned long inc);
|
||||
|
||||
void setSoundBuffer(uint_least32_t *const buf) { sound.setBuffer(buf); }
|
||||
unsigned fillSoundBuffer(unsigned long cc);
|
||||
|
||||
void setVideoBuffer(uint_least32_t *const videoBuf, const int pitch) {
|
||||
display.setVideoBuffer(videoBuf, pitch);
|
||||
}
|
||||
|
||||
void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned long rgb32);
|
||||
void setCgbPalette(unsigned *lut);
|
||||
|
||||
int LinkStatus(int which);
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef MEMORY_H
|
||||
#define MEMORY_H
|
||||
|
||||
static unsigned char const agbOverride[0xD] = { 0xFF, 0x00, 0xCD, 0x03, 0x35, 0xAA, 0x31, 0x90, 0x94, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
#include "mem/cartridge.h"
|
||||
#include "video.h"
|
||||
#include "sound.h"
|
||||
#include "interrupter.h"
|
||||
#include "tima.h"
|
||||
#include "newstate.h"
|
||||
#include "gambatte.h"
|
||||
|
||||
namespace gambatte {
|
||||
class InputGetter;
|
||||
class FilterInfo;
|
||||
|
||||
class Memory {
|
||||
Cartridge cart;
|
||||
unsigned char ioamhram[0x200];
|
||||
unsigned char cgbBios[0x900];
|
||||
unsigned char dmgBios[0x100];
|
||||
bool biosMode;
|
||||
bool cgbSwitching;
|
||||
bool agbMode;
|
||||
bool gbIsCgb_;
|
||||
unsigned short &SP;
|
||||
unsigned short &PC;
|
||||
|
||||
void (*readCallback)(unsigned);
|
||||
void (*writeCallback)(unsigned);
|
||||
void (*execCallback)(unsigned);
|
||||
CDCallback cdCallback;
|
||||
void(*linkCallback)();
|
||||
|
||||
unsigned (*getInput)();
|
||||
unsigned long divLastUpdate;
|
||||
unsigned long lastOamDmaUpdate;
|
||||
|
||||
InterruptRequester intreq;
|
||||
Tima tima;
|
||||
LCD display;
|
||||
PSG sound;
|
||||
Interrupter interrupter;
|
||||
|
||||
unsigned short dmaSource;
|
||||
unsigned short dmaDestination;
|
||||
unsigned char oamDmaPos;
|
||||
unsigned char serialCnt;
|
||||
bool blanklcd;
|
||||
|
||||
bool LINKCABLE;
|
||||
bool linkClockTrigger;
|
||||
|
||||
void decEventCycles(MemEventId eventId, unsigned long dec);
|
||||
|
||||
void oamDmaInitSetup();
|
||||
void updateOamDma(unsigned long cycleCounter);
|
||||
void startOamDma(unsigned long cycleCounter);
|
||||
void endOamDma(unsigned long cycleCounter);
|
||||
const unsigned char * oamDmaSrcPtr() const;
|
||||
|
||||
unsigned nontrivial_ff_read(unsigned P, unsigned long cycleCounter);
|
||||
unsigned nontrivial_read(unsigned P, unsigned long cycleCounter);
|
||||
void nontrivial_ff_write(unsigned P, unsigned data, unsigned long cycleCounter);
|
||||
void nontrivial_write(unsigned P, unsigned data, unsigned long cycleCounter);
|
||||
|
||||
unsigned nontrivial_peek(unsigned P);
|
||||
unsigned nontrivial_ff_peek(unsigned P);
|
||||
|
||||
void updateSerial(unsigned long cc);
|
||||
void updateTimaIrq(unsigned long cc);
|
||||
void updateIrqs(unsigned long cc);
|
||||
|
||||
bool isDoubleSpeed() const { return display.isDoubleSpeed(); }
|
||||
|
||||
public:
|
||||
explicit Memory(const Interrupter &interrupter, unsigned short &sp, unsigned short &pc);
|
||||
|
||||
bool loaded() const { return cart.loaded(); }
|
||||
unsigned curRomBank() const { return cart.curRomBank(); }
|
||||
const char * romTitle() const { return cart.romTitle(); }
|
||||
|
||||
int debugGetLY() const { return display.debugGetLY(); }
|
||||
|
||||
void setStatePtrs(SaveState &state);
|
||||
void loadState(const SaveState &state/*, unsigned long oldCc*/);
|
||||
void loadSavedata(const char *data) { cart.loadSavedata(data); }
|
||||
int saveSavedataLength() {return cart.saveSavedataLength(); }
|
||||
void saveSavedata(char *dest) { cart.saveSavedata(dest); }
|
||||
void updateInput();
|
||||
|
||||
unsigned char* cgbBiosBuffer() { return (unsigned char*)cgbBios; }
|
||||
unsigned char* dmgBiosBuffer() { return (unsigned char*)dmgBios; }
|
||||
bool gbIsCgb() { return gbIsCgb_; }
|
||||
|
||||
bool getMemoryArea(int which, unsigned char **data, int *length); // { return cart.getMemoryArea(which, data, length); }
|
||||
|
||||
unsigned long stop(unsigned long cycleCounter);
|
||||
bool isCgb() const { return display.isCgb(); }
|
||||
bool ime() const { return intreq.ime(); }
|
||||
bool halted() const { return intreq.halted(); }
|
||||
unsigned long nextEventTime() const { return intreq.minEventTime(); }
|
||||
|
||||
void setLayers(unsigned mask) { display.setLayers(mask); }
|
||||
|
||||
bool isActive() const { return intreq.eventTime(END) != DISABLED_TIME; }
|
||||
|
||||
long cyclesSinceBlit(const unsigned long cc) const {
|
||||
return cc < intreq.eventTime(BLIT) ? -1 : static_cast<long>((cc - intreq.eventTime(BLIT)) >> isDoubleSpeed());
|
||||
}
|
||||
|
||||
void halt() { intreq.halt(); }
|
||||
void ei(unsigned long cycleCounter) { if (!ime()) { intreq.ei(cycleCounter); } }
|
||||
|
||||
void di() { intreq.di(); }
|
||||
|
||||
unsigned ff_read(const unsigned P, const unsigned long cycleCounter) {
|
||||
return P < 0xFF80 ? nontrivial_ff_read(P, cycleCounter) : ioamhram[P - 0xFE00];
|
||||
}
|
||||
|
||||
struct CDMapResult
|
||||
{
|
||||
eCDLog_AddrType type;
|
||||
unsigned addr;
|
||||
};
|
||||
|
||||
CDMapResult CDMap(const unsigned P) const
|
||||
{
|
||||
if(P<0x4000)
|
||||
{
|
||||
CDMapResult ret = { eCDLog_AddrType_ROM, P };
|
||||
return ret;
|
||||
}
|
||||
else if(P<0x8000)
|
||||
{
|
||||
unsigned bank = cart.rmem(P>>12) - cart.rmem(0);
|
||||
unsigned addr = P+bank;
|
||||
CDMapResult ret = { eCDLog_AddrType_ROM, addr };
|
||||
return ret;
|
||||
}
|
||||
else if(P<0xA000) {}
|
||||
else if(P<0xC000)
|
||||
{
|
||||
if(cart.wsrambankptr())
|
||||
{
|
||||
//not bankable. but. we're not sure how much might be here
|
||||
unsigned char *data;
|
||||
int length;
|
||||
bool has = cart.getMemoryArea(3,&data,&length);
|
||||
unsigned addr = P&(length-1);
|
||||
if(has && length!=0)
|
||||
{
|
||||
CDMapResult ret = { eCDLog_AddrType_CartRAM, addr };
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(P<0xE000)
|
||||
{
|
||||
unsigned bank = cart.wramdata(P >> 12 & 1) - cart.wramdata(0);
|
||||
unsigned addr = (P&0xFFF)+bank;
|
||||
CDMapResult ret = { eCDLog_AddrType_WRAM, addr };
|
||||
return ret;
|
||||
}
|
||||
else if(P<0xFF80) {}
|
||||
else
|
||||
{
|
||||
////this is just for debugging, really, it's pretty useless
|
||||
//CDMapResult ret = { eCDLog_AddrType_HRAM, (P-0xFF80) };
|
||||
//return ret;
|
||||
}
|
||||
|
||||
CDMapResult ret = { eCDLog_AddrType_None };
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
unsigned readBios(const unsigned P) {
|
||||
if (gbIsCgb_) {
|
||||
if (agbMode && P >= 0xF3 && P < 0x100) {
|
||||
return (agbOverride[P - 0xF3] + cgbBios[P]) & 0xFF;
|
||||
}
|
||||
return cgbBios[P];
|
||||
}
|
||||
return dmgBios[P];
|
||||
}
|
||||
|
||||
unsigned read(const unsigned P, const unsigned long cycleCounter) {
|
||||
if (readCallback)
|
||||
readCallback(P);
|
||||
if(cdCallback)
|
||||
{
|
||||
CDMapResult map = CDMap(P);
|
||||
if(map.type != eCDLog_AddrType_None)
|
||||
cdCallback(map.addr,map.type,eCDLog_Flags_Data);
|
||||
}
|
||||
if (biosMode && ((!gbIsCgb_ && P < 0x100) || (gbIsCgb_ && P < 0x900 && (P < 0x100 || P >= 0x200)))) {
|
||||
return readBios(P);
|
||||
}
|
||||
return cart.rmem(P >> 12) ? cart.rmem(P >> 12)[P] : nontrivial_read(P, cycleCounter);
|
||||
}
|
||||
|
||||
unsigned read_excb(const unsigned P, const unsigned long cycleCounter, bool first) {
|
||||
if (execCallback)
|
||||
execCallback(P);
|
||||
if(cdCallback)
|
||||
{
|
||||
CDMapResult map = CDMap(P);
|
||||
if(map.type != eCDLog_AddrType_None)
|
||||
cdCallback(map.addr,map.type,first?eCDLog_Flags_ExecFirst : eCDLog_Flags_ExecOperand);
|
||||
}
|
||||
if (biosMode && ((!gbIsCgb_ && P < 0x100) || (gbIsCgb_ && P < 0x900 && (P < 0x100 || P >= 0x200)))) {
|
||||
return readBios(P);
|
||||
}
|
||||
return cart.rmem(P >> 12) ? cart.rmem(P >> 12)[P] : nontrivial_read(P, cycleCounter);
|
||||
}
|
||||
|
||||
unsigned peek(const unsigned P) {
|
||||
if (biosMode && ((!gbIsCgb_ && P < 0x100) || (gbIsCgb_ && P < 0x900 && (P < 0x100 || P >= 0x200)))) {
|
||||
return readBios(P);
|
||||
}
|
||||
return cart.rmem(P >> 12) ? cart.rmem(P >> 12)[P] : nontrivial_peek(P);
|
||||
}
|
||||
|
||||
void write_nocb(const unsigned P, const unsigned data, const unsigned long cycleCounter) {
|
||||
if (cart.wmem(P >> 12)) {
|
||||
cart.wmem(P >> 12)[P] = data;
|
||||
} else
|
||||
nontrivial_write(P, data, cycleCounter);
|
||||
}
|
||||
|
||||
void write(const unsigned P, const unsigned data, const unsigned long cycleCounter) {
|
||||
if (cart.wmem(P >> 12)) {
|
||||
cart.wmem(P >> 12)[P] = data;
|
||||
} else
|
||||
nontrivial_write(P, data, cycleCounter);
|
||||
if (writeCallback)
|
||||
writeCallback(P);
|
||||
if(cdCallback)
|
||||
{
|
||||
CDMapResult map = CDMap(P);
|
||||
if(map.type != eCDLog_AddrType_None)
|
||||
cdCallback(map.addr,map.type,eCDLog_Flags_Data);
|
||||
}
|
||||
}
|
||||
|
||||
void ff_write(const unsigned P, const unsigned data, const unsigned long cycleCounter) {
|
||||
if (P - 0xFF80u < 0x7Fu) {
|
||||
ioamhram[P - 0xFE00] = data;
|
||||
} else
|
||||
nontrivial_ff_write(P, data, cycleCounter);
|
||||
if(cdCallback)
|
||||
{
|
||||
CDMapResult map = CDMap(P);
|
||||
if(map.type != eCDLog_AddrType_None)
|
||||
cdCallback(map.addr,map.type,eCDLog_Flags_Data);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long event(unsigned long cycleCounter);
|
||||
unsigned long resetCounters(unsigned long cycleCounter);
|
||||
|
||||
int loadROM(const char *romfiledata, unsigned romfilelength, bool forceDmg, bool multicartCompat);
|
||||
|
||||
void setInputGetter(unsigned (*getInput)()) {
|
||||
this->getInput = getInput;
|
||||
}
|
||||
|
||||
void setReadCallback(void (*callback)(unsigned)) {
|
||||
this->readCallback = callback;
|
||||
}
|
||||
void setWriteCallback(void (*callback)(unsigned)) {
|
||||
this->writeCallback = callback;
|
||||
}
|
||||
void setExecCallback(void (*callback)(unsigned)) {
|
||||
this->execCallback = callback;
|
||||
}
|
||||
void setCDCallback(CDCallback cdc) {
|
||||
this->cdCallback = cdc;
|
||||
}
|
||||
|
||||
void setScanlineCallback(void (*callback)(), int sl) {
|
||||
display.setScanlineCallback(callback, sl);
|
||||
}
|
||||
|
||||
void setRTCCallback(std::uint32_t (*callback)()) {
|
||||
cart.setRTCCallback(callback);
|
||||
}
|
||||
|
||||
void setLinkCallback(void(*callback)()) {
|
||||
this->linkCallback = callback;
|
||||
}
|
||||
|
||||
void setEndtime(unsigned long cc, unsigned long inc);
|
||||
|
||||
void setSoundBuffer(uint_least32_t *const buf) { sound.setBuffer(buf); }
|
||||
unsigned fillSoundBuffer(unsigned long cc);
|
||||
|
||||
void setVideoBuffer(uint_least32_t *const videoBuf, const int pitch) {
|
||||
display.setVideoBuffer(videoBuf, pitch);
|
||||
}
|
||||
|
||||
void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned long rgb32);
|
||||
void setCgbPalette(unsigned *lut);
|
||||
|
||||
void blackScreen() {
|
||||
display.blackScreen();
|
||||
}
|
||||
|
||||
int LinkStatus(int which);
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#define MINKEEPER_H
|
||||
|
||||
#include <algorithm>
|
||||
#include "newstate.h"
|
||||
#include "newstate.h"
|
||||
|
||||
namespace MinKeeperUtil {
|
||||
template<int n> struct CeiledLog2 { enum { R = 1 + CeiledLog2<(n + 1) / 2>::R }; };
|
||||
|
@ -108,12 +108,12 @@ public:
|
|||
unsigned long value(const int id) const { return values[id]; }
|
||||
|
||||
// not sure if i understood everything in minkeeper correctly, so something might be missing here?
|
||||
template<bool isReader>
|
||||
void SyncState(gambatte::NewState *ns)
|
||||
{
|
||||
NSS(values);
|
||||
NSS(minValue_);
|
||||
NSS(a);
|
||||
template<bool isReader>
|
||||
void SyncState(gambatte::NewState *ns)
|
||||
{
|
||||
NSS(values);
|
||||
NSS(minValue_);
|
||||
NSS(a);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,69 +1,69 @@
|
|||
#include "newstate.h"
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
NewStateDummy::NewStateDummy()
|
||||
:length(0)
|
||||
{
|
||||
}
|
||||
void NewStateDummy::Save(const void *ptr, size_t size, const char *name)
|
||||
{
|
||||
length += size;
|
||||
}
|
||||
void NewStateDummy::Load(void *ptr, size_t size, const char *name)
|
||||
{
|
||||
}
|
||||
|
||||
NewStateExternalBuffer::NewStateExternalBuffer(char *buffer, long maxlength)
|
||||
:buffer(buffer), length(0), maxlength(maxlength)
|
||||
{
|
||||
}
|
||||
|
||||
void NewStateExternalBuffer::Save(const void *ptr, size_t size, const char *name)
|
||||
{
|
||||
if (maxlength - length >= (long)size)
|
||||
{
|
||||
std::memcpy(buffer + length, ptr, size);
|
||||
}
|
||||
length += size;
|
||||
}
|
||||
|
||||
void NewStateExternalBuffer::Load(void *ptr, size_t size, const char *name)
|
||||
{
|
||||
char *dst = static_cast<char *>(ptr);
|
||||
if (maxlength - length >= (long)size)
|
||||
{
|
||||
std::memcpy(dst, buffer + length, size);
|
||||
}
|
||||
length += size;
|
||||
}
|
||||
|
||||
NewStateExternalFunctions::NewStateExternalFunctions(const FPtrs *ff)
|
||||
:Save_(ff->Save_),
|
||||
Load_(ff->Load_),
|
||||
EnterSection_(ff->EnterSection_),
|
||||
ExitSection_(ff->ExitSection_)
|
||||
{
|
||||
}
|
||||
|
||||
void NewStateExternalFunctions::Save(const void *ptr, size_t size, const char *name)
|
||||
{
|
||||
Save_(ptr, size, name);
|
||||
}
|
||||
void NewStateExternalFunctions::Load(void *ptr, size_t size, const char *name)
|
||||
{
|
||||
Load_(ptr, size, name);
|
||||
}
|
||||
void NewStateExternalFunctions::EnterSection(const char *name)
|
||||
{
|
||||
EnterSection_(name);
|
||||
}
|
||||
void NewStateExternalFunctions::ExitSection(const char *name)
|
||||
{
|
||||
ExitSection_(name);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#include "newstate.h"
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
NewStateDummy::NewStateDummy()
|
||||
:length(0)
|
||||
{
|
||||
}
|
||||
void NewStateDummy::Save(const void *ptr, size_t size, const char *name)
|
||||
{
|
||||
length += size;
|
||||
}
|
||||
void NewStateDummy::Load(void *ptr, size_t size, const char *name)
|
||||
{
|
||||
}
|
||||
|
||||
NewStateExternalBuffer::NewStateExternalBuffer(char *buffer, long maxlength)
|
||||
:buffer(buffer), length(0), maxlength(maxlength)
|
||||
{
|
||||
}
|
||||
|
||||
void NewStateExternalBuffer::Save(const void *ptr, size_t size, const char *name)
|
||||
{
|
||||
if (maxlength - length >= (long)size)
|
||||
{
|
||||
std::memcpy(buffer + length, ptr, size);
|
||||
}
|
||||
length += size;
|
||||
}
|
||||
|
||||
void NewStateExternalBuffer::Load(void *ptr, size_t size, const char *name)
|
||||
{
|
||||
char *dst = static_cast<char *>(ptr);
|
||||
if (maxlength - length >= (long)size)
|
||||
{
|
||||
std::memcpy(dst, buffer + length, size);
|
||||
}
|
||||
length += size;
|
||||
}
|
||||
|
||||
NewStateExternalFunctions::NewStateExternalFunctions(const FPtrs *ff)
|
||||
:Save_(ff->Save_),
|
||||
Load_(ff->Load_),
|
||||
EnterSection_(ff->EnterSection_),
|
||||
ExitSection_(ff->ExitSection_)
|
||||
{
|
||||
}
|
||||
|
||||
void NewStateExternalFunctions::Save(const void *ptr, size_t size, const char *name)
|
||||
{
|
||||
Save_(ptr, size, name);
|
||||
}
|
||||
void NewStateExternalFunctions::Load(void *ptr, size_t size, const char *name)
|
||||
{
|
||||
Load_(ptr, size, name);
|
||||
}
|
||||
void NewStateExternalFunctions::EnterSection(const char *name)
|
||||
{
|
||||
EnterSection_(name);
|
||||
}
|
||||
void NewStateExternalFunctions::ExitSection(const char *name)
|
||||
{
|
||||
ExitSection_(name);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,102 +1,102 @@
|
|||
#ifndef NEWSTATE_H
|
||||
#define NEWSTATE_H
|
||||
|
||||
#include <cstring>
|
||||
#include <cstddef>
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
class NewState
|
||||
{
|
||||
public:
|
||||
virtual void Save(const void *ptr, size_t size, const char *name) = 0;
|
||||
virtual void Load(void *ptr, size_t size, const char *name) = 0;
|
||||
virtual void EnterSection(const char *name) { }
|
||||
virtual void ExitSection(const char *name) { }
|
||||
};
|
||||
|
||||
class NewStateDummy : public NewState
|
||||
{
|
||||
private:
|
||||
long length;
|
||||
public:
|
||||
NewStateDummy();
|
||||
long GetLength() { return length; }
|
||||
void Rewind() { length = 0; }
|
||||
virtual void Save(const void *ptr, size_t size, const char *name);
|
||||
virtual void Load(void *ptr, size_t size, const char *name);
|
||||
};
|
||||
|
||||
class NewStateExternalBuffer : public NewState
|
||||
{
|
||||
private:
|
||||
char *const buffer;
|
||||
long length;
|
||||
const long maxlength;
|
||||
public:
|
||||
NewStateExternalBuffer(char *buffer, long maxlength);
|
||||
long GetLength() { return length; }
|
||||
void Rewind() { length = 0; }
|
||||
bool Overflow() { return length > maxlength; }
|
||||
virtual void Save(const void *ptr, size_t size, const char *name);
|
||||
virtual void Load(void *ptr, size_t size, const char *name);
|
||||
};
|
||||
|
||||
struct FPtrs
|
||||
{
|
||||
void (*Save_)(const void *ptr, size_t size, const char *name);
|
||||
void (*Load_)(void *ptr, size_t size, const char *name);
|
||||
void (*EnterSection_)(const char *name);
|
||||
void (*ExitSection_)(const char *name);
|
||||
};
|
||||
|
||||
class NewStateExternalFunctions : public NewState
|
||||
{
|
||||
private:
|
||||
void (*Save_)(const void *ptr, size_t size, const char *name);
|
||||
void (*Load_)(void *ptr, size_t size, const char *name);
|
||||
void (*EnterSection_)(const char *name);
|
||||
void (*ExitSection_)(const char *name);
|
||||
public:
|
||||
NewStateExternalFunctions(const FPtrs *ff);
|
||||
virtual void Save(const void *ptr, size_t size, const char *name);
|
||||
virtual void Load(void *ptr, size_t size, const char *name);
|
||||
virtual void EnterSection(const char *name);
|
||||
virtual void ExitSection(const char *name);
|
||||
};
|
||||
|
||||
// defines and explicitly instantiates
|
||||
#define SYNCFUNC(x)\
|
||||
template void x::SyncState<false>(NewState *ns);\
|
||||
template void x::SyncState<true>(NewState *ns);\
|
||||
template<bool isReader>void x::SyncState(NewState *ns)
|
||||
|
||||
// N = normal variable
|
||||
// P = pointer to fixed size data
|
||||
// S = "sub object"
|
||||
// T = "ptr to sub object"
|
||||
// R = pointer, store its offset from some other pointer
|
||||
// E = general purpose cased value "enum"
|
||||
|
||||
|
||||
// first line is default value in converted enum; last line is default value in argument x
|
||||
#define EBS(x,d) do { int _ttmp = (d); if (isReader) ns->Load(&_ttmp, sizeof(_ttmp), #x); if (0)
|
||||
#define EVS(x,v,n) else if (!isReader && (x) == (v)) _ttmp = (n); else if (isReader && _ttmp == (n)) (x) = (v)
|
||||
#define EES(x,d) else if (isReader) (x) = (d); if (!isReader) ns->Save(&_ttmp, sizeof(_ttmp), #x); } while (0)
|
||||
|
||||
#define RSS(x,b) do { if (isReader)\
|
||||
{ ptrdiff_t _ttmp; ns->Load(&_ttmp, sizeof(_ttmp), #x); (x) = (_ttmp == (ptrdiff_t)0xdeadbeef ? 0 : (b) + _ttmp); }\
|
||||
else\
|
||||
{ ptrdiff_t _ttmp = (x) == 0 ? 0xdeadbeef : (x) - (b); ns->Save(&_ttmp, sizeof(_ttmp), #x); } } while (0)
|
||||
|
||||
#define PSS(x,s) do { if (isReader) ns->Load((x), (s), #x); else ns->Save((x), (s), #x); } while (0)
|
||||
|
||||
#define NSS(x) do { if (isReader) ns->Load(&(x), sizeof(x), #x); else ns->Save(&(x), sizeof(x), #x); } while (0)
|
||||
|
||||
#define SSS(x) do { ns->EnterSection(#x); (x).SyncState<isReader>(ns); ns->ExitSection(#x); } while (0)
|
||||
|
||||
#define TSS(x) do { ns->EnterSection(#x); (x)->SyncState<isReader>(ns); ns->ExitSection(#x); } while (0)
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifndef NEWSTATE_H
|
||||
#define NEWSTATE_H
|
||||
|
||||
#include <cstring>
|
||||
#include <cstddef>
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
class NewState
|
||||
{
|
||||
public:
|
||||
virtual void Save(const void *ptr, size_t size, const char *name) = 0;
|
||||
virtual void Load(void *ptr, size_t size, const char *name) = 0;
|
||||
virtual void EnterSection(const char *name) { }
|
||||
virtual void ExitSection(const char *name) { }
|
||||
};
|
||||
|
||||
class NewStateDummy : public NewState
|
||||
{
|
||||
private:
|
||||
long length;
|
||||
public:
|
||||
NewStateDummy();
|
||||
long GetLength() { return length; }
|
||||
void Rewind() { length = 0; }
|
||||
virtual void Save(const void *ptr, size_t size, const char *name);
|
||||
virtual void Load(void *ptr, size_t size, const char *name);
|
||||
};
|
||||
|
||||
class NewStateExternalBuffer : public NewState
|
||||
{
|
||||
private:
|
||||
char *const buffer;
|
||||
long length;
|
||||
const long maxlength;
|
||||
public:
|
||||
NewStateExternalBuffer(char *buffer, long maxlength);
|
||||
long GetLength() { return length; }
|
||||
void Rewind() { length = 0; }
|
||||
bool Overflow() { return length > maxlength; }
|
||||
virtual void Save(const void *ptr, size_t size, const char *name);
|
||||
virtual void Load(void *ptr, size_t size, const char *name);
|
||||
};
|
||||
|
||||
struct FPtrs
|
||||
{
|
||||
void (*Save_)(const void *ptr, size_t size, const char *name);
|
||||
void (*Load_)(void *ptr, size_t size, const char *name);
|
||||
void (*EnterSection_)(const char *name);
|
||||
void (*ExitSection_)(const char *name);
|
||||
};
|
||||
|
||||
class NewStateExternalFunctions : public NewState
|
||||
{
|
||||
private:
|
||||
void (*Save_)(const void *ptr, size_t size, const char *name);
|
||||
void (*Load_)(void *ptr, size_t size, const char *name);
|
||||
void (*EnterSection_)(const char *name);
|
||||
void (*ExitSection_)(const char *name);
|
||||
public:
|
||||
NewStateExternalFunctions(const FPtrs *ff);
|
||||
virtual void Save(const void *ptr, size_t size, const char *name);
|
||||
virtual void Load(void *ptr, size_t size, const char *name);
|
||||
virtual void EnterSection(const char *name);
|
||||
virtual void ExitSection(const char *name);
|
||||
};
|
||||
|
||||
// defines and explicitly instantiates
|
||||
#define SYNCFUNC(x)\
|
||||
template void x::SyncState<false>(NewState *ns);\
|
||||
template void x::SyncState<true>(NewState *ns);\
|
||||
template<bool isReader>void x::SyncState(NewState *ns)
|
||||
|
||||
// N = normal variable
|
||||
// P = pointer to fixed size data
|
||||
// S = "sub object"
|
||||
// T = "ptr to sub object"
|
||||
// R = pointer, store its offset from some other pointer
|
||||
// E = general purpose cased value "enum"
|
||||
|
||||
|
||||
// first line is default value in converted enum; last line is default value in argument x
|
||||
#define EBS(x,d) do { int _ttmp = (d); if (isReader) ns->Load(&_ttmp, sizeof(_ttmp), #x); if (0)
|
||||
#define EVS(x,v,n) else if (!isReader && (x) == (v)) _ttmp = (n); else if (isReader && _ttmp == (n)) (x) = (v)
|
||||
#define EES(x,d) else if (isReader) (x) = (d); if (!isReader) ns->Save(&_ttmp, sizeof(_ttmp), #x); } while (0)
|
||||
|
||||
#define RSS(x,b) do { if (isReader)\
|
||||
{ ptrdiff_t _ttmp; ns->Load(&_ttmp, sizeof(_ttmp), #x); (x) = (_ttmp == (ptrdiff_t)0xdeadbeef ? 0 : (b) + _ttmp); }\
|
||||
else\
|
||||
{ ptrdiff_t _ttmp = (x) == 0 ? 0xdeadbeef : (x) - (b); ns->Save(&_ttmp, sizeof(_ttmp), #x); } } while (0)
|
||||
|
||||
#define PSS(x,s) do { if (isReader) ns->Load((x), (s), #x); else ns->Save((x), (s), #x); } while (0)
|
||||
|
||||
#define NSS(x) do { if (isReader) ns->Load(&(x), sizeof(x), #x); else ns->Save(&(x), sizeof(x), #x); } while (0)
|
||||
|
||||
#define SSS(x) do { ns->EnterSection(#x); (x).SyncState<isReader>(ns); ns->ExitSection(#x); } while (0)
|
||||
|
||||
#define TSS(x) do { ns->EnterSection(#x); (x)->SyncState<isReader>(ns); ns->ExitSection(#x); } while (0)
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -78,6 +78,10 @@ struct SaveState {
|
|||
bool enableRam;
|
||||
bool rambankMode;
|
||||
bool hdmaTransfer;
|
||||
bool biosMode;
|
||||
bool cgbSwitching;
|
||||
bool agbMode;
|
||||
bool gbIsCgb;
|
||||
} mem;
|
||||
|
||||
struct PPU {
|
||||
|
@ -113,6 +117,7 @@ struct SaveState {
|
|||
unsigned char wscx;
|
||||
bool weMaster;
|
||||
bool pendingLcdstatIrq;
|
||||
bool isCgb;
|
||||
} ppu;
|
||||
|
||||
struct SPU {
|
||||
|
|
|
@ -173,16 +173,16 @@ unsigned PSG::getStatus() const {
|
|||
}
|
||||
|
||||
// the buffer and position are not saved, as they're set and flushed on each runfor() call
|
||||
SYNCFUNC(PSG)
|
||||
{
|
||||
SSS(ch1);
|
||||
SSS(ch2);
|
||||
SSS(ch3);
|
||||
SSS(ch4);
|
||||
NSS(lastUpdate);
|
||||
NSS(soVol);
|
||||
NSS(rsum);
|
||||
NSS(enabled);
|
||||
}
|
||||
SYNCFUNC(PSG)
|
||||
{
|
||||
SSS(ch1);
|
||||
SSS(ch2);
|
||||
SSS(ch3);
|
||||
SSS(ch4);
|
||||
NSS(lastUpdate);
|
||||
NSS(soVol);
|
||||
NSS(rsum);
|
||||
NSS(enabled);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include "sound/channel2.h"
|
||||
#include "sound/channel3.h"
|
||||
#include "sound/channel4.h"
|
||||
#include "newstate.h"
|
||||
#include "newstate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
|
@ -89,7 +89,7 @@ public:
|
|||
void map_so(unsigned nr51);
|
||||
unsigned getStatus() const;
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -97,14 +97,14 @@ void Channel1::SweepUnit::loadState(const SaveState &state) {
|
|||
negging = state.spu.ch1.sweep.negging;
|
||||
}
|
||||
|
||||
template<bool isReader>
|
||||
void Channel1::SweepUnit::SyncState(NewState *ns)
|
||||
{
|
||||
NSS(counter);
|
||||
NSS(shadow);
|
||||
NSS(nr0);
|
||||
NSS(negging);
|
||||
}
|
||||
template<bool isReader>
|
||||
void Channel1::SweepUnit::SyncState(NewState *ns)
|
||||
{
|
||||
NSS(counter);
|
||||
NSS(shadow);
|
||||
NSS(nr0);
|
||||
NSS(negging);
|
||||
}
|
||||
|
||||
Channel1::Channel1() :
|
||||
staticOutputTest(*this, dutyUnit),
|
||||
|
@ -250,26 +250,26 @@ void Channel1::update(uint_least32_t *buf, const unsigned long soBaseVol, unsign
|
|||
}
|
||||
}
|
||||
|
||||
SYNCFUNC(Channel1)
|
||||
{
|
||||
SSS(lengthCounter);
|
||||
SSS(dutyUnit);
|
||||
SSS(envelopeUnit);
|
||||
SSS(sweepUnit);
|
||||
|
||||
EBS(nextEventUnit, 0);
|
||||
EVS(nextEventUnit, &dutyUnit, 1);
|
||||
EVS(nextEventUnit, &sweepUnit, 2);
|
||||
EVS(nextEventUnit, &envelopeUnit, 3);
|
||||
EVS(nextEventUnit, &lengthCounter, 4);
|
||||
EES(nextEventUnit, NULL);
|
||||
|
||||
NSS(cycleCounter);
|
||||
NSS(soMask);
|
||||
NSS(prevOut);
|
||||
|
||||
NSS(nr4);
|
||||
NSS(master);
|
||||
}
|
||||
SYNCFUNC(Channel1)
|
||||
{
|
||||
SSS(lengthCounter);
|
||||
SSS(dutyUnit);
|
||||
SSS(envelopeUnit);
|
||||
SSS(sweepUnit);
|
||||
|
||||
EBS(nextEventUnit, 0);
|
||||
EVS(nextEventUnit, &dutyUnit, 1);
|
||||
EVS(nextEventUnit, &sweepUnit, 2);
|
||||
EVS(nextEventUnit, &envelopeUnit, 3);
|
||||
EVS(nextEventUnit, &lengthCounter, 4);
|
||||
EES(nextEventUnit, NULL);
|
||||
|
||||
NSS(cycleCounter);
|
||||
NSS(soMask);
|
||||
NSS(prevOut);
|
||||
|
||||
NSS(nr4);
|
||||
NSS(master);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,97 +1,97 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef SOUND_CHANNEL1_H
|
||||
#define SOUND_CHANNEL1_H
|
||||
|
||||
#include "gbint.h"
|
||||
#include "master_disabler.h"
|
||||
#include "length_counter.h"
|
||||
#include "duty_unit.h"
|
||||
#include "envelope_unit.h"
|
||||
#include "static_output_tester.h"
|
||||
#include "newstate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
struct SaveState;
|
||||
|
||||
class Channel1 {
|
||||
class SweepUnit : public SoundUnit {
|
||||
MasterDisabler &disableMaster;
|
||||
DutyUnit &dutyUnit;
|
||||
unsigned short shadow;
|
||||
unsigned char nr0;
|
||||
bool negging;
|
||||
|
||||
unsigned calcFreq();
|
||||
|
||||
public:
|
||||
SweepUnit(MasterDisabler &disabler, DutyUnit &dutyUnit);
|
||||
void event();
|
||||
void nr0Change(unsigned newNr0);
|
||||
void nr4Init(unsigned long cycleCounter);
|
||||
void reset();
|
||||
void loadState(const SaveState &state);
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
friend class StaticOutputTester<Channel1,DutyUnit>;
|
||||
|
||||
StaticOutputTester<Channel1,DutyUnit> staticOutputTest;
|
||||
DutyMasterDisabler disableMaster;
|
||||
LengthCounter lengthCounter;
|
||||
DutyUnit dutyUnit;
|
||||
EnvelopeUnit envelopeUnit;
|
||||
SweepUnit sweepUnit;
|
||||
|
||||
SoundUnit *nextEventUnit;
|
||||
|
||||
unsigned long cycleCounter;
|
||||
unsigned long soMask;
|
||||
unsigned long prevOut;
|
||||
|
||||
unsigned char nr4;
|
||||
bool master;
|
||||
|
||||
void setEvent();
|
||||
|
||||
public:
|
||||
Channel1();
|
||||
void setNr0(unsigned data);
|
||||
void setNr1(unsigned data);
|
||||
void setNr2(unsigned data);
|
||||
void setNr3(unsigned data);
|
||||
void setNr4(unsigned data);
|
||||
|
||||
void setSo(unsigned long soMask);
|
||||
bool isActive() const { return master; }
|
||||
|
||||
void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles);
|
||||
|
||||
void reset();
|
||||
void init(bool cgb);
|
||||
void loadState(const SaveState &state);
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef SOUND_CHANNEL1_H
|
||||
#define SOUND_CHANNEL1_H
|
||||
|
||||
#include "gbint.h"
|
||||
#include "master_disabler.h"
|
||||
#include "length_counter.h"
|
||||
#include "duty_unit.h"
|
||||
#include "envelope_unit.h"
|
||||
#include "static_output_tester.h"
|
||||
#include "newstate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
struct SaveState;
|
||||
|
||||
class Channel1 {
|
||||
class SweepUnit : public SoundUnit {
|
||||
MasterDisabler &disableMaster;
|
||||
DutyUnit &dutyUnit;
|
||||
unsigned short shadow;
|
||||
unsigned char nr0;
|
||||
bool negging;
|
||||
|
||||
unsigned calcFreq();
|
||||
|
||||
public:
|
||||
SweepUnit(MasterDisabler &disabler, DutyUnit &dutyUnit);
|
||||
void event();
|
||||
void nr0Change(unsigned newNr0);
|
||||
void nr4Init(unsigned long cycleCounter);
|
||||
void reset();
|
||||
void loadState(const SaveState &state);
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
friend class StaticOutputTester<Channel1,DutyUnit>;
|
||||
|
||||
StaticOutputTester<Channel1,DutyUnit> staticOutputTest;
|
||||
DutyMasterDisabler disableMaster;
|
||||
LengthCounter lengthCounter;
|
||||
DutyUnit dutyUnit;
|
||||
EnvelopeUnit envelopeUnit;
|
||||
SweepUnit sweepUnit;
|
||||
|
||||
SoundUnit *nextEventUnit;
|
||||
|
||||
unsigned long cycleCounter;
|
||||
unsigned long soMask;
|
||||
unsigned long prevOut;
|
||||
|
||||
unsigned char nr4;
|
||||
bool master;
|
||||
|
||||
void setEvent();
|
||||
|
||||
public:
|
||||
Channel1();
|
||||
void setNr0(unsigned data);
|
||||
void setNr1(unsigned data);
|
||||
void setNr2(unsigned data);
|
||||
void setNr3(unsigned data);
|
||||
void setNr4(unsigned data);
|
||||
|
||||
void setSo(unsigned long soMask);
|
||||
bool isActive() const { return master; }
|
||||
|
||||
void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles);
|
||||
|
||||
void reset();
|
||||
void init(bool cgb);
|
||||
void loadState(const SaveState &state);
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -153,24 +153,24 @@ void Channel2::update(uint_least32_t *buf, const unsigned long soBaseVol, unsign
|
|||
}
|
||||
}
|
||||
|
||||
SYNCFUNC(Channel2)
|
||||
{
|
||||
SSS(lengthCounter);
|
||||
SSS(dutyUnit);
|
||||
SSS(envelopeUnit);
|
||||
|
||||
EBS(nextEventUnit, 0);
|
||||
EVS(nextEventUnit, &dutyUnit, 1);
|
||||
EVS(nextEventUnit, &envelopeUnit, 2);
|
||||
EVS(nextEventUnit, &lengthCounter, 3);
|
||||
EES(nextEventUnit, NULL);
|
||||
|
||||
NSS(cycleCounter);
|
||||
NSS(soMask);
|
||||
NSS(prevOut);
|
||||
|
||||
NSS(nr4);
|
||||
NSS(master);
|
||||
}
|
||||
SYNCFUNC(Channel2)
|
||||
{
|
||||
SSS(lengthCounter);
|
||||
SSS(dutyUnit);
|
||||
SSS(envelopeUnit);
|
||||
|
||||
EBS(nextEventUnit, 0);
|
||||
EVS(nextEventUnit, &dutyUnit, 1);
|
||||
EVS(nextEventUnit, &envelopeUnit, 2);
|
||||
EVS(nextEventUnit, &lengthCounter, 3);
|
||||
EES(nextEventUnit, NULL);
|
||||
|
||||
NSS(cycleCounter);
|
||||
NSS(soMask);
|
||||
NSS(prevOut);
|
||||
|
||||
NSS(nr4);
|
||||
NSS(master);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,75 +1,75 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef SOUND_CHANNEL2_H
|
||||
#define SOUND_CHANNEL2_H
|
||||
|
||||
#include "gbint.h"
|
||||
#include "length_counter.h"
|
||||
#include "duty_unit.h"
|
||||
#include "envelope_unit.h"
|
||||
#include "static_output_tester.h"
|
||||
#include "newstate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
struct SaveState;
|
||||
|
||||
class Channel2 {
|
||||
friend class StaticOutputTester<Channel2,DutyUnit>;
|
||||
|
||||
StaticOutputTester<Channel2,DutyUnit> staticOutputTest;
|
||||
DutyMasterDisabler disableMaster;
|
||||
LengthCounter lengthCounter;
|
||||
DutyUnit dutyUnit;
|
||||
EnvelopeUnit envelopeUnit;
|
||||
|
||||
SoundUnit *nextEventUnit;
|
||||
|
||||
unsigned long cycleCounter;
|
||||
unsigned long soMask;
|
||||
unsigned long prevOut;
|
||||
|
||||
unsigned char nr4;
|
||||
bool master;
|
||||
|
||||
void setEvent();
|
||||
|
||||
public:
|
||||
Channel2();
|
||||
void setNr1(unsigned data);
|
||||
void setNr2(unsigned data);
|
||||
void setNr3(unsigned data);
|
||||
void setNr4(unsigned data);
|
||||
|
||||
void setSo(unsigned long soMask);
|
||||
// void deactivate() { disableMaster(); setEvent(); }
|
||||
bool isActive() const { return master; }
|
||||
|
||||
void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles);
|
||||
|
||||
void reset();
|
||||
void init(bool cgb);
|
||||
void loadState(const SaveState &state);
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef SOUND_CHANNEL2_H
|
||||
#define SOUND_CHANNEL2_H
|
||||
|
||||
#include "gbint.h"
|
||||
#include "length_counter.h"
|
||||
#include "duty_unit.h"
|
||||
#include "envelope_unit.h"
|
||||
#include "static_output_tester.h"
|
||||
#include "newstate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
struct SaveState;
|
||||
|
||||
class Channel2 {
|
||||
friend class StaticOutputTester<Channel2,DutyUnit>;
|
||||
|
||||
StaticOutputTester<Channel2,DutyUnit> staticOutputTest;
|
||||
DutyMasterDisabler disableMaster;
|
||||
LengthCounter lengthCounter;
|
||||
DutyUnit dutyUnit;
|
||||
EnvelopeUnit envelopeUnit;
|
||||
|
||||
SoundUnit *nextEventUnit;
|
||||
|
||||
unsigned long cycleCounter;
|
||||
unsigned long soMask;
|
||||
unsigned long prevOut;
|
||||
|
||||
unsigned char nr4;
|
||||
bool master;
|
||||
|
||||
void setEvent();
|
||||
|
||||
public:
|
||||
Channel2();
|
||||
void setNr1(unsigned data);
|
||||
void setNr2(unsigned data);
|
||||
void setNr3(unsigned data);
|
||||
void setNr4(unsigned data);
|
||||
|
||||
void setSo(unsigned long soMask);
|
||||
// void deactivate() { disableMaster(); setEvent(); }
|
||||
bool isActive() const { return master; }
|
||||
|
||||
void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles);
|
||||
|
||||
void reset();
|
||||
void init(bool cgb);
|
||||
void loadState(const SaveState &state);
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -196,27 +196,27 @@ void Channel3::update(uint_least32_t *buf, const unsigned long soBaseVol, unsign
|
|||
}
|
||||
}
|
||||
|
||||
SYNCFUNC(Channel3)
|
||||
{
|
||||
NSS(waveRam);
|
||||
|
||||
SSS(lengthCounter);
|
||||
|
||||
NSS(cycleCounter);
|
||||
NSS(soMask);
|
||||
NSS(prevOut);
|
||||
NSS(waveCounter);
|
||||
NSS(lastReadTime);
|
||||
|
||||
NSS(nr0);
|
||||
NSS(nr3);
|
||||
NSS(nr4);
|
||||
NSS(wavePos);
|
||||
NSS(rShift);
|
||||
NSS(sampleBuf);
|
||||
|
||||
NSS(master);
|
||||
NSS(cgb);
|
||||
}
|
||||
SYNCFUNC(Channel3)
|
||||
{
|
||||
NSS(waveRam);
|
||||
|
||||
SSS(lengthCounter);
|
||||
|
||||
NSS(cycleCounter);
|
||||
NSS(soMask);
|
||||
NSS(prevOut);
|
||||
NSS(waveCounter);
|
||||
NSS(lastReadTime);
|
||||
|
||||
NSS(nr0);
|
||||
NSS(nr3);
|
||||
NSS(nr4);
|
||||
NSS(wavePos);
|
||||
NSS(rShift);
|
||||
NSS(sampleBuf);
|
||||
|
||||
NSS(master);
|
||||
NSS(cgb);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,105 +1,105 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef SOUND_CHANNEL3_H
|
||||
#define SOUND_CHANNEL3_H
|
||||
|
||||
#include "gbint.h"
|
||||
#include "master_disabler.h"
|
||||
#include "length_counter.h"
|
||||
#include "newstate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
struct SaveState;
|
||||
|
||||
class Channel3 {
|
||||
class Ch3MasterDisabler : public MasterDisabler {
|
||||
unsigned long &waveCounter;
|
||||
|
||||
public:
|
||||
Ch3MasterDisabler(bool &m, unsigned long &wC) : MasterDisabler(m), waveCounter(wC) {}
|
||||
void operator()() { MasterDisabler::operator()(); waveCounter = SoundUnit::COUNTER_DISABLED; }
|
||||
};
|
||||
|
||||
unsigned char waveRam[0x10];
|
||||
|
||||
Ch3MasterDisabler disableMaster;
|
||||
LengthCounter lengthCounter;
|
||||
|
||||
unsigned long cycleCounter;
|
||||
unsigned long soMask;
|
||||
unsigned long prevOut;
|
||||
unsigned long waveCounter;
|
||||
unsigned long lastReadTime;
|
||||
|
||||
unsigned char nr0;
|
||||
unsigned char nr3;
|
||||
unsigned char nr4;
|
||||
unsigned char wavePos;
|
||||
unsigned char rShift;
|
||||
unsigned char sampleBuf;
|
||||
|
||||
bool master;
|
||||
bool cgb;
|
||||
|
||||
void updateWaveCounter(unsigned long cc);
|
||||
|
||||
public:
|
||||
Channel3();
|
||||
bool isActive() const { return master; }
|
||||
void reset();
|
||||
void init(bool cgb);
|
||||
void setStatePtrs(SaveState &state);
|
||||
void loadState(const SaveState &state);
|
||||
void setNr0(unsigned data);
|
||||
void setNr1(unsigned data) { lengthCounter.nr1Change(data, nr4, cycleCounter); }
|
||||
void setNr2(unsigned data);
|
||||
void setNr3(unsigned data) { nr3 = data; }
|
||||
void setNr4(unsigned data);
|
||||
void setSo(unsigned long soMask);
|
||||
void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles);
|
||||
|
||||
unsigned waveRamRead(unsigned index) const {
|
||||
if (master) {
|
||||
if (!cgb && cycleCounter != lastReadTime)
|
||||
return 0xFF;
|
||||
|
||||
index = wavePos >> 1;
|
||||
}
|
||||
|
||||
return waveRam[index];
|
||||
}
|
||||
|
||||
void waveRamWrite(unsigned index, unsigned data) {
|
||||
if (master) {
|
||||
if (!cgb && cycleCounter != lastReadTime)
|
||||
return;
|
||||
|
||||
index = wavePos >> 1;
|
||||
}
|
||||
|
||||
waveRam[index] = data;
|
||||
}
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef SOUND_CHANNEL3_H
|
||||
#define SOUND_CHANNEL3_H
|
||||
|
||||
#include "gbint.h"
|
||||
#include "master_disabler.h"
|
||||
#include "length_counter.h"
|
||||
#include "newstate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
struct SaveState;
|
||||
|
||||
class Channel3 {
|
||||
class Ch3MasterDisabler : public MasterDisabler {
|
||||
unsigned long &waveCounter;
|
||||
|
||||
public:
|
||||
Ch3MasterDisabler(bool &m, unsigned long &wC) : MasterDisabler(m), waveCounter(wC) {}
|
||||
void operator()() { MasterDisabler::operator()(); waveCounter = SoundUnit::COUNTER_DISABLED; }
|
||||
};
|
||||
|
||||
unsigned char waveRam[0x10];
|
||||
|
||||
Ch3MasterDisabler disableMaster;
|
||||
LengthCounter lengthCounter;
|
||||
|
||||
unsigned long cycleCounter;
|
||||
unsigned long soMask;
|
||||
unsigned long prevOut;
|
||||
unsigned long waveCounter;
|
||||
unsigned long lastReadTime;
|
||||
|
||||
unsigned char nr0;
|
||||
unsigned char nr3;
|
||||
unsigned char nr4;
|
||||
unsigned char wavePos;
|
||||
unsigned char rShift;
|
||||
unsigned char sampleBuf;
|
||||
|
||||
bool master;
|
||||
bool cgb;
|
||||
|
||||
void updateWaveCounter(unsigned long cc);
|
||||
|
||||
public:
|
||||
Channel3();
|
||||
bool isActive() const { return master; }
|
||||
void reset();
|
||||
void init(bool cgb);
|
||||
void setStatePtrs(SaveState &state);
|
||||
void loadState(const SaveState &state);
|
||||
void setNr0(unsigned data);
|
||||
void setNr1(unsigned data) { lengthCounter.nr1Change(data, nr4, cycleCounter); }
|
||||
void setNr2(unsigned data);
|
||||
void setNr3(unsigned data) { nr3 = data; }
|
||||
void setNr4(unsigned data);
|
||||
void setSo(unsigned long soMask);
|
||||
void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles);
|
||||
|
||||
unsigned waveRamRead(unsigned index) const {
|
||||
if (master) {
|
||||
if (!cgb && cycleCounter != lastReadTime)
|
||||
return 0xFF;
|
||||
|
||||
index = wavePos >> 1;
|
||||
}
|
||||
|
||||
return waveRam[index];
|
||||
}
|
||||
|
||||
void waveRamWrite(unsigned index, unsigned data) {
|
||||
if (master) {
|
||||
if (!cgb && cycleCounter != lastReadTime)
|
||||
return;
|
||||
|
||||
index = wavePos >> 1;
|
||||
}
|
||||
|
||||
waveRam[index] = data;
|
||||
}
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -157,15 +157,15 @@ void Channel4::Lfsr::loadState(const SaveState &state) {
|
|||
nr3 = state.mem.ioamhram.get()[0x122];
|
||||
}
|
||||
|
||||
template<bool isReader>
|
||||
void Channel4::Lfsr::SyncState(NewState *ns)
|
||||
{
|
||||
NSS(counter);
|
||||
NSS(backupCounter);
|
||||
NSS(reg);
|
||||
NSS(nr3);
|
||||
NSS(master);
|
||||
}
|
||||
template<bool isReader>
|
||||
void Channel4::Lfsr::SyncState(NewState *ns)
|
||||
{
|
||||
NSS(counter);
|
||||
NSS(backupCounter);
|
||||
NSS(reg);
|
||||
NSS(nr3);
|
||||
NSS(master);
|
||||
}
|
||||
|
||||
Channel4::Channel4() :
|
||||
staticOutputTest(*this, lfsr),
|
||||
|
@ -295,25 +295,25 @@ void Channel4::update(uint_least32_t *buf, const unsigned long soBaseVol, unsign
|
|||
cycleCounter -= SoundUnit::COUNTER_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
SYNCFUNC(Channel4)
|
||||
{
|
||||
SSS(lengthCounter);
|
||||
SSS(envelopeUnit);
|
||||
SSS(lfsr);
|
||||
|
||||
EBS(nextEventUnit, 0);
|
||||
EVS(nextEventUnit, &lfsr, 1);
|
||||
EVS(nextEventUnit, &envelopeUnit, 2);
|
||||
EVS(nextEventUnit, &lengthCounter, 3);
|
||||
EES(nextEventUnit, NULL);
|
||||
|
||||
NSS(cycleCounter);
|
||||
NSS(soMask);
|
||||
NSS(prevOut);
|
||||
|
||||
NSS(nr4);
|
||||
NSS(master);
|
||||
}
|
||||
|
||||
SYNCFUNC(Channel4)
|
||||
{
|
||||
SSS(lengthCounter);
|
||||
SSS(envelopeUnit);
|
||||
SSS(lfsr);
|
||||
|
||||
EBS(nextEventUnit, 0);
|
||||
EVS(nextEventUnit, &lfsr, 1);
|
||||
EVS(nextEventUnit, &envelopeUnit, 2);
|
||||
EVS(nextEventUnit, &lengthCounter, 3);
|
||||
EES(nextEventUnit, NULL);
|
||||
|
||||
NSS(cycleCounter);
|
||||
NSS(soMask);
|
||||
NSS(prevOut);
|
||||
|
||||
NSS(nr4);
|
||||
NSS(master);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include "length_counter.h"
|
||||
#include "envelope_unit.h"
|
||||
#include "static_output_tester.h"
|
||||
#include "newstate.h"
|
||||
#include "newstate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
|
@ -52,7 +52,7 @@ class Channel4 {
|
|||
void killCounter() { counter = COUNTER_DISABLED; }
|
||||
void reviveCounter(unsigned long cc);
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
class Ch4MasterDisabler : public MasterDisabler {
|
||||
|
@ -97,7 +97,7 @@ public:
|
|||
void init(bool cgb);
|
||||
void loadState(const SaveState &state);
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -142,15 +142,15 @@ void DutyUnit::reviveCounter(const unsigned long cc) {
|
|||
setCounter();
|
||||
}
|
||||
|
||||
SYNCFUNC(DutyUnit)
|
||||
{
|
||||
NSS(counter);
|
||||
NSS(nextPosUpdate);
|
||||
NSS(period);
|
||||
NSS(pos);
|
||||
NSS(duty);
|
||||
NSS(high);
|
||||
NSS(enableEvents);
|
||||
}
|
||||
SYNCFUNC(DutyUnit)
|
||||
{
|
||||
NSS(counter);
|
||||
NSS(nextPosUpdate);
|
||||
NSS(period);
|
||||
NSS(pos);
|
||||
NSS(duty);
|
||||
NSS(high);
|
||||
NSS(enableEvents);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "sound_unit.h"
|
||||
#include "master_disabler.h"
|
||||
#include "../savestate.h"
|
||||
#include "newstate.h"
|
||||
#include "newstate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
|
@ -55,7 +55,7 @@ public:
|
|||
unsigned getFreq() const { return 2048 - (period >> 1); }
|
||||
void setFreq(unsigned newFreq, unsigned long cc);
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
class DutyMasterDisabler : public MasterDisabler {
|
||||
|
|
|
@ -98,11 +98,11 @@ void EnvelopeUnit::loadState(const SaveState::SPU::Env &estate, const unsigned n
|
|||
this->nr2 = nr2;
|
||||
}
|
||||
|
||||
SYNCFUNC(EnvelopeUnit)
|
||||
{
|
||||
NSS(counter);
|
||||
NSS(nr2);
|
||||
NSS(volume);
|
||||
}
|
||||
SYNCFUNC(EnvelopeUnit)
|
||||
{
|
||||
NSS(counter);
|
||||
NSS(nr2);
|
||||
NSS(volume);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include "sound_unit.h"
|
||||
#include "../savestate.h"
|
||||
#include "newstate.h"
|
||||
#include "newstate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
|
@ -48,7 +48,7 @@ public:
|
|||
void reset();
|
||||
void loadState(const SaveState::SPU::Env &estate, unsigned nr2, unsigned long cc);
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -83,11 +83,11 @@ void LengthCounter::loadState(const SaveState::SPU::LCounter &lstate, const unsi
|
|||
lengthCounter = lstate.lengthCounter;
|
||||
}
|
||||
|
||||
SYNCFUNC(LengthCounter)
|
||||
{
|
||||
NSS(counter);
|
||||
NSS(lengthCounter);
|
||||
NSS(cgb);
|
||||
}
|
||||
SYNCFUNC(LengthCounter)
|
||||
{
|
||||
NSS(counter);
|
||||
NSS(lengthCounter);
|
||||
NSS(cgb);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include "sound_unit.h"
|
||||
#include "../savestate.h"
|
||||
#include "newstate.h"
|
||||
#include "newstate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
|
@ -42,7 +42,7 @@ public:
|
|||
void init(bool cgb);
|
||||
void loadState(const SaveState::SPU::LCounter &lstate, unsigned long cc);
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -163,13 +163,13 @@ void Tima::doIrqEvent(const TimaInterruptRequester timaIrq) {
|
|||
timaIrq.setNextIrqEventTime(timaIrq.nextIrqEventTime() + ((256u - tma_) << timaClock[tac_ & 3]));
|
||||
}
|
||||
|
||||
SYNCFUNC(Tima)
|
||||
{
|
||||
NSS(lastUpdate_);
|
||||
NSS(tmatime_);
|
||||
NSS(tima_);
|
||||
NSS(tma_);
|
||||
NSS(tac_);
|
||||
}
|
||||
SYNCFUNC(Tima)
|
||||
{
|
||||
NSS(lastUpdate_);
|
||||
NSS(tmatime_);
|
||||
NSS(tima_);
|
||||
NSS(tma_);
|
||||
NSS(tac_);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ public:
|
|||
|
||||
void doIrqEvent(TimaInterruptRequester timaIrq);
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -37,6 +37,10 @@ void LCD::setCgbPalette(unsigned *lut) {
|
|||
}
|
||||
|
||||
unsigned long LCD::gbcToRgb32(const unsigned bgr15) {
|
||||
unsigned long const r = bgr15 & 0x1F;
|
||||
unsigned long const g = bgr15 >> 5 & 0x1F;
|
||||
unsigned long const b = bgr15 >> 10 & 0x1F;
|
||||
|
||||
return cgbColorsRgb32[bgr15 & 0x7FFF];
|
||||
}
|
||||
|
||||
|
@ -66,6 +70,10 @@ void LCD::reset(const unsigned char *const oamram, const unsigned char *vram, co
|
|||
refreshPalettes();
|
||||
}
|
||||
|
||||
void LCD::setCgb(bool cgb) {
|
||||
ppu.setCgb(cgb);
|
||||
}
|
||||
|
||||
static unsigned long mode2IrqSchedule(const unsigned statReg, const LyCounter &lyCounter, const unsigned long cycleCounter) {
|
||||
if (!(statReg & 0x20))
|
||||
return DISABLED_TIME;
|
||||
|
@ -150,6 +158,32 @@ void LCD::refreshPalettes() {
|
|||
}
|
||||
}
|
||||
|
||||
void LCD::copyCgbPalettesToDmg() {
|
||||
for (unsigned i = 0; i < 4; i++) {
|
||||
dmgColorsRgb32[i] = gbcToRgb32(bgpData[i * 2] | bgpData[i * 2 + 1] << 8);
|
||||
}
|
||||
for (unsigned i = 0; i < 8; i++) {
|
||||
dmgColorsRgb32[i + 4] = gbcToRgb32(objpData[i * 2] | objpData[i * 2 + 1] << 8);
|
||||
}
|
||||
}
|
||||
|
||||
void LCD::blackScreen() {
|
||||
if (ppu.cgb()) {
|
||||
for (unsigned i = 0; i < 8 * 8; i += 2) {
|
||||
ppu.bgPalette()[i >> 1] = 0;
|
||||
ppu.spPalette()[i >> 1] = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (unsigned i = 0; i < 4; i++) {
|
||||
dmgColorsRgb32[i] = 0;
|
||||
}
|
||||
for (unsigned i = 0; i < 8; i++) {
|
||||
dmgColorsRgb32[i + 4] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
template<typename T>
|
||||
|
@ -734,19 +768,19 @@ void LCD::setDmgPaletteColor(const unsigned palNum, const unsigned colorNum, con
|
|||
|
||||
// don't need to save or load rgb32 color data
|
||||
|
||||
SYNCFUNC(LCD)
|
||||
{
|
||||
SSS(ppu);
|
||||
NSS(bgpData);
|
||||
NSS(objpData);
|
||||
SSS(eventTimes_);
|
||||
SSS(m0Irq_);
|
||||
SSS(lycIrq);
|
||||
SSS(nextM0Time_);
|
||||
|
||||
NSS(statReg);
|
||||
NSS(m2IrqStatReg_);
|
||||
NSS(m1IrqStatReg_);
|
||||
}
|
||||
SYNCFUNC(LCD)
|
||||
{
|
||||
SSS(ppu);
|
||||
NSS(bgpData);
|
||||
NSS(objpData);
|
||||
SSS(eventTimes_);
|
||||
SSS(m0Irq_);
|
||||
SSS(lycIrq);
|
||||
SSS(nextM0Time_);
|
||||
|
||||
NSS(statReg);
|
||||
NSS(m2IrqStatReg_);
|
||||
NSS(m1IrqStatReg_);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include "interruptrequester.h"
|
||||
#include "minkeeper.h"
|
||||
#include <memory>
|
||||
#include "newstate.h"
|
||||
#include "newstate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
|
@ -79,10 +79,10 @@ public:
|
|||
unsigned statReg() const { return statReg_; }
|
||||
|
||||
template<bool isReader>
|
||||
void SyncState(NewState *ns)
|
||||
{
|
||||
NSS(statReg_);
|
||||
NSS(lycReg_);
|
||||
void SyncState(NewState *ns)
|
||||
{
|
||||
NSS(statReg_);
|
||||
NSS(lycReg_);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -120,12 +120,12 @@ class LCD {
|
|||
void flagIrq(const unsigned bit) { memEventRequester_.flagIrq(bit); }
|
||||
void flagHdmaReq() { memEventRequester_.flagHdmaReq(); }
|
||||
|
||||
template<bool isReader>
|
||||
void SyncState(NewState *ns)
|
||||
{
|
||||
SSS(eventMin_);
|
||||
SSS(memEventMin_);
|
||||
//SSS(memEventRequester_); // not needed
|
||||
template<bool isReader>
|
||||
void SyncState(NewState *ns)
|
||||
{
|
||||
SSS(eventMin_);
|
||||
SSS(memEventMin_);
|
||||
//SSS(memEventRequester_); // not needed
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -175,6 +175,9 @@ public:
|
|||
void setCgbPalette(unsigned *lut);
|
||||
void setVideoBuffer(uint_least32_t *videoBuf, int pitch);
|
||||
void setLayers(unsigned mask) { ppu.setLayers(mask); }
|
||||
void setCgb(bool cgb);
|
||||
void copyCgbPalettesToDmg();
|
||||
void blackScreen();
|
||||
|
||||
int debugGetLY() const { return ppu.lyCounter().ly(); }
|
||||
|
||||
|
@ -273,7 +276,7 @@ public:
|
|||
|
||||
void setScanlineCallback(void (*callback)(), int sl) { scanlinecallback = callback; scanlinecallbacksl = sl; }
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -64,13 +64,13 @@ void LyCounter::setDoubleSpeed(const bool ds_in) {
|
|||
ds = ds_in;
|
||||
lineTime_ = 456U << ds_in;
|
||||
}
|
||||
|
||||
SYNCFUNC(LyCounter)
|
||||
{
|
||||
NSS(time_);
|
||||
NSS(lineTime_);
|
||||
NSS(ly_);
|
||||
NSS(ds);
|
||||
}
|
||||
|
||||
SYNCFUNC(LyCounter)
|
||||
{
|
||||
NSS(time_);
|
||||
NSS(lineTime_);
|
||||
NSS(ly_);
|
||||
NSS(ds);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue