From 0d5cff74080e67602031cd6b035fccfdf670d8db Mon Sep 17 00:00:00 2001 From: zeromus Date: Tue, 1 Mar 2011 09:32:12 +0000 Subject: [PATCH] [NES] mapper cleanup and savestates --- BizHawk.Emulation/CPUs/MOS 6502/MOS6502.cs | 78 +++++++++-- .../Consoles/Nintendo/NES/Boards/AxROM.cs | 26 +++- .../Consoles/Nintendo/NES/Boards/CPROM.cs | 21 ++- .../Consoles/Nintendo/NES/Boards/CxROM.cs | 27 +++- .../Consoles/Nintendo/NES/Boards/GxROM.cs | 26 +++- .../Consoles/Nintendo/NES/Boards/IC_74x377.cs | 23 +++- .../Consoles/Nintendo/NES/Boards/NROM.cs | 8 +- .../Consoles/Nintendo/NES/Boards/SxROM.cs | 51 ++++++- .../Consoles/Nintendo/NES/Boards/UxROM.cs | 33 ++++- .../Consoles/Nintendo/NES/NES.cs | 100 ++++++++++---- .../Consoles/Nintendo/NES/PPU.cs | 41 ++++++ .../Consoles/Nintendo/NES/PPU.regs.cs | 41 ++++++ .../Consoles/Nintendo/NES/PPU.run.cs | 6 +- BizHawk.Emulation/Util.cs | 129 +++++++++++++++++- BizHawk.MultiClient/Config.cs | 1 + BizHawk.MultiClient/MainForm.cs | 4 +- BizHawk.MultiClient/Rewind.cs | 4 + BizHawk.MultiClient/output/gamedb.txt | 2 +- 18 files changed, 559 insertions(+), 62 deletions(-) diff --git a/BizHawk.Emulation/CPUs/MOS 6502/MOS6502.cs b/BizHawk.Emulation/CPUs/MOS 6502/MOS6502.cs index b69231c4aa..ffe5319495 100644 --- a/BizHawk.Emulation/CPUs/MOS 6502/MOS6502.cs +++ b/BizHawk.Emulation/CPUs/MOS 6502/MOS6502.cs @@ -1,4 +1,6 @@ using System; +using System.Globalization; +using System.IO; namespace BizHawk.Emulation.CPUs.M6502 { @@ -59,19 +61,6 @@ namespace BizHawk.Emulation.CPUs.M6502 return val; } - // ==== CPU State ==== - - public byte A; - public byte X; - public byte Y; - public byte P; - public ushort PC; - public byte S; - - // TODO IRQ, NMI functions - public bool Interrupt; - public bool NMI; - private const ushort NMIVector = 0xFFFA; private const ushort ResetVector = 0xFFFC; private const ushort BRKVector = 0xFFFE; @@ -91,13 +80,74 @@ namespace BizHawk.Emulation.CPUs.M6502 WriteMemory((ushort)(S-- + 0x100), P); P = oldP; FlagI = true; - if(type == ExceptionType.NMI) + if (type == ExceptionType.NMI) PC = ReadWord(NMIVector); else PC = ReadWord(BRKVector); PendingCycles -= 7; } + // ==== CPU State ==== + + public byte A; + public byte X; + public byte Y; + public byte P; + public ushort PC; + public byte S; + + // TODO IRQ, NMI functions + public bool Interrupt; + public bool NMI; + + public void SaveStateText(TextWriter writer) + { + writer.WriteLine("[MOS6502]"); + writer.WriteLine("A {0:X2}", A); + writer.WriteLine("X {0:X2}", X); + writer.WriteLine("Y {0:X2}", Y); + writer.WriteLine("P {0:X2}", P); + writer.WriteLine("PC {0:X4}", PC); + writer.WriteLine("S {0:X2}", S); + writer.WriteLine("NMI {0}", NMI); + writer.WriteLine("Interrupt {0}", Interrupt); + writer.WriteLine("TotalExecutedCycles {0}", TotalExecutedCycles); + writer.WriteLine("PendingCycles {0}", PendingCycles); + writer.WriteLine("[/MOS6502]\n"); + } + + public void LoadStateText(TextReader reader) + { + while (true) + { + string[] args = reader.ReadLine().Split(' '); + if (args[0].Trim() == "") continue; + if (args[0] == "[/MOS6502]") break; + if (args[0] == "A") + A = byte.Parse(args[1], NumberStyles.HexNumber); + else if (args[0] == "X") + X = byte.Parse(args[1], NumberStyles.HexNumber); + else if (args[0] == "Y") + Y = byte.Parse(args[1], NumberStyles.HexNumber); + else if (args[0] == "P") + P = byte.Parse(args[1], NumberStyles.HexNumber); + else if (args[0] == "PC") + PC = ushort.Parse(args[1], NumberStyles.HexNumber); + else if (args[0] == "S") + S = byte.Parse(args[1], NumberStyles.HexNumber); + else if (args[0] == "NMI") + NMI = bool.Parse(args[1]); + else if (args[0] == "Interrupt") + Interrupt = bool.Parse(args[1]); + else if (args[0] == "TotalExecutedCycles") + TotalExecutedCycles = int.Parse(args[1]); + else if (args[0] == "PendingCycles") + PendingCycles = int.Parse(args[1]); + else + Console.WriteLine("Skipping unrecognized identifier " + args[0]); + } + } + // ==== End State ==== /// Carry Flag diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/AxROM.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/AxROM.cs index 4786ae45ef..59d938490a 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/AxROM.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/AxROM.cs @@ -1,17 +1,27 @@ using System; +using System.IO; using System.Diagnostics; namespace BizHawk.Emulation.Consoles.Nintendo.Boards { + //TODO - hardcode CRAM size and assert + //generally mapper7 + //Battletoads + //Time Lord + //Marble Madness + public class AxROM : NES.NESBoardBase { + //configuration string type; bool bus_conflict; - byte[] cram; int cram_mask; int prg_mask; + + //state + byte[] cram; int prg; public AxROM(string type) @@ -81,5 +91,19 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards else base.WritePPU(addr,value); } + public override void SaveStateBinary(BinaryWriter bw) + { + base.SaveStateBinary(bw); + bw.Write(prg); + Util.WriteByteBuffer(bw, cram); + } + + public override void LoadStateBinary(BinaryReader br) + { + base.LoadStateBinary(br); + prg = br.ReadInt32(); + cram = Util.ReadByteBuffer(br, false); + } + } } \ No newline at end of file diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/CPROM.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/CPROM.cs index e54b1e6d17..69bc3a392e 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/CPROM.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/CPROM.cs @@ -1,12 +1,17 @@ using System; +using System.IO; using System.Diagnostics; namespace BizHawk.Emulation.Consoles.Nintendo.Boards { - //generally mapper3 public class CPROM : NES.NESBoardBase { + //generally mapper 13 + + //Videomation + + //state byte[] cram; int chr; @@ -42,5 +47,19 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards cram[addr - 0x1000 + (chr << 12)] = value; else base.WritePPU(addr,value); } + + public override void SaveStateBinary(BinaryWriter bw) + { + base.SaveStateBinary(bw); + bw.Write(chr); + Util.WriteByteBuffer(bw, cram); + } + + public override void LoadStateBinary(BinaryReader br) + { + base.LoadStateBinary(br); + chr = br.ReadInt32(); + cram = Util.ReadByteBuffer(br, false); + } } } \ No newline at end of file diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/CxROM.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/CxROM.cs index bac6e6c335..f7f589bca1 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/CxROM.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/CxROM.cs @@ -1,13 +1,27 @@ using System; +using System.IO; using System.Diagnostics; namespace BizHawk.Emulation.Consoles.Nintendo.Boards { //generally mapper3 + //Solomon's Key + //Arkanoid + //Arkista's Ring + //Bump 'n' Jump + //Cybernoid + public class CxROM : NES.NESBoardBase { + //configuration string type; + int chr_mask; + bool bus_conflict; + + //state + int chr; + public CxROM(string type) { this.type = type; @@ -36,9 +50,16 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards else return base.ReadPPU(addr); } - int chr; - int chr_mask; - bool bus_conflict; + public override void SaveStateBinary(BinaryWriter bw) + { + base.SaveStateBinary(bw); + bw.Write(chr); + } + public override void LoadStateBinary(BinaryReader br) + { + base.LoadStateBinary(br); + chr = br.ReadInt32(); + } } } \ No newline at end of file diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/GxROM.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/GxROM.cs index fb50d311d3..d5396a386e 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/GxROM.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/GxROM.cs @@ -1,13 +1,25 @@ using System; +using System.IO; using System.Diagnostics; namespace BizHawk.Emulation.Consoles.Nintendo.Boards { + //generally mapper66 + + //Doraemon + //Dragon Power + //Gumshoe + //Thunder & Lightning + //Super Mario Bros. + Duck Hunt + //should this be called GNROM? there is no other Gx anything AFAIK.. public class GxROM : NES.NESBoardBase { + //configuraton int prg_mask, chr_mask; + + //state int prg, chr; public override void Initialize(NES.RomInfo romInfo, NES nes) @@ -40,6 +52,18 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards prg = (((value>>4) & 3) & prg_mask); } - int mask; + public override void SaveStateBinary(BinaryWriter bw) + { + base.SaveStateBinary(bw); + bw.Write(chr); + bw.Write(prg); + } + + public override void LoadStateBinary(BinaryReader br) + { + base.LoadStateBinary(br); + chr = br.ReadInt32(); + prg = br.ReadInt32(); + } } } \ No newline at end of file diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/IC_74x377.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/IC_74x377.cs index de30bc1f37..f1ce05858f 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/IC_74x377.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/IC_74x377.cs @@ -1,16 +1,23 @@ using System; +using System.IO; using System.Diagnostics; namespace BizHawk.Emulation.Consoles.Nintendo.Boards { //mapper 11 + //Crystal Mines + //Metal Fighter + public class Discrete_74x377 : NES.NESBoardBase { + //configuration int prg_mask, chr_mask; - int prg, chr; bool bus_conflict = true; + //state + int prg, chr; + public override void Initialize(NES.RomInfo romInfo, NES nes) { base.Initialize(romInfo, nes); @@ -47,5 +54,19 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards prg = (value & 3) & prg_mask; chr = (value >> 4) & chr_mask; } + + public override void SaveStateBinary(BinaryWriter bw) + { + base.SaveStateBinary(bw); + bw.Write(chr); + bw.Write(prg); + } + + public override void LoadStateBinary(BinaryReader br) + { + base.LoadStateBinary(br); + chr = br.ReadInt32(); + prg = br.ReadInt32(); + } } } \ No newline at end of file diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/NROM.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/NROM.cs index ec9c26e4d7..50f2444c83 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/NROM.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/NROM.cs @@ -5,6 +5,12 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards { public class NROM : NES.NESBoardBase { + //configuration + int mask; + + //state + //(none) + public override void Initialize(NES.RomInfo romInfo, NES nes) { base.Initialize(romInfo, nes); @@ -16,7 +22,5 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards addr &= mask; return RomInfo.ROM[addr]; } - - int mask; } } \ No newline at end of file diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/SxROM.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/SxROM.cs index b7e7b99f7c..447b54cb09 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/SxROM.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/SxROM.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using System.Diagnostics; namespace BizHawk.Emulation.Consoles.Nintendo.Boards @@ -26,6 +27,33 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards //well, lets leave it. } + public void SaveStateBinary(BinaryWriter bw) + { + bw.Write(shift_count); + bw.Write(shift_val); + bw.Write(chr_mode); + bw.Write(prg_mode); + bw.Write(prg_slot); + bw.Write((int)mirror); + bw.Write(chr_0); + bw.Write(chr_1); + bw.Write(wram_disable); + bw.Write(prg); + } + public void LoadStateBinary(BinaryReader br) + { + shift_count = br.ReadInt32(); + shift_val = br.ReadInt32(); + chr_mode = br.ReadInt32(); + prg_mode = br.ReadInt32(); + prg_slot = br.ReadInt32(); + mirror = (NES.EMirrorType)br.ReadInt32(); + chr_0 = br.ReadInt32(); + chr_1 = br.ReadInt32(); + wram_disable = br.ReadInt32(); + prg = br.ReadInt32(); + } + public enum Rev { A, B1, B2, B3 @@ -137,12 +165,14 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards public class SxROM : NES.NESBoardBase { + //configuration string type; - MMC1 mmc1; int prg_mask, chr_mask; - byte[] cram, pram; int cram_mask, pram_mask; + //state + byte[] cram, pram; + MMC1 mmc1; public SxROM(string type) { @@ -184,6 +214,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards cram = new byte[RomInfo.CRAM_Size * 1024]; cram_mask = cram.Length - 1; } + else cram = new byte[0]; Debug.Assert(RomInfo.PRAM_Size == 0 || RomInfo.PRAM_Size == 8); if (RomInfo.PRAM_Size != 0) @@ -191,6 +222,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards pram = new byte[RomInfo.CRAM_Size * 1024]; pram_mask = pram.Length - 1; } + else pram = new byte[0]; if (RomInfo.CHR_Size != 0) { @@ -264,6 +296,21 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards } } + public override void SaveStateBinary(BinaryWriter bw) + { + base.SaveStateBinary(bw); + mmc1.SaveStateBinary(bw); + Util.WriteByteBuffer(bw, pram); + Util.WriteByteBuffer(bw, cram); + } + public override void LoadStateBinary(BinaryReader br) + { + base.LoadStateBinary(br); + mmc1.LoadStateBinary(br); + pram = Util.ReadByteBuffer(br, false); + cram = Util.ReadByteBuffer(br, false); + } + } } diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/UxROM.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/UxROM.cs index 551cb5e0bd..003af1ba6d 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/UxROM.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/UxROM.cs @@ -1,15 +1,30 @@ using System; +using System.IO; using System.Diagnostics; namespace BizHawk.Emulation.Consoles.Nintendo.Boards { //generally mapper2 + //Mega Man + //Castlevania + //Contra + //Duck Tales + //Metal Gear + //TODO - simplify logic and handle fewer (known) cases (e.g. no IsPowerOfTwo, but rather hardcoded cases) public class UxROM : NES.NESBoardBase { + //configuration string type; + int pagemask; + int cram_mask; + + //state + int prg; + byte[] cram; + public UxROM(string type) { this.type = type; @@ -24,6 +39,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards else throw new InvalidOperationException("Invalid UxROM type"); //guess CRAM size (this is a very confident guess!) + //(should these guesses be here?) (is this a guess? maybe all these boards have cram) if (RomInfo.CRAM_Size == -1) RomInfo.CRAM_Size = 8; cram = new byte[RomInfo.CRAM_Size * 1024]; @@ -59,9 +75,18 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards else base.WritePPU(addr,value); } - int pagemask; - int prg; - byte[] cram; - int cram_mask; + public override void SaveStateBinary(BinaryWriter bw) + { + base.SaveStateBinary(bw); + bw.Write(prg); + Util.WriteByteBuffer(bw, cram); + } + + public override void LoadStateBinary(BinaryReader br) + { + base.LoadStateBinary(br); + prg = br.ReadInt32(); + cram = Util.ReadByteBuffer(br, false); + } } } \ No newline at end of file diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs index cb419c4730..a47e496df9 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs @@ -49,6 +49,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo void WritePRAM(int addr, byte value); void Initialize(RomInfo romInfo, NES nes); byte[] SaveRam { get; } + void SaveStateBinary(BinaryWriter bw); + void LoadStateBinary(BinaryReader br); }; public abstract class NESBoardBase : INESBoard @@ -62,6 +64,15 @@ namespace BizHawk.Emulation.Consoles.Nintendo public RomInfo RomInfo { get; set; } public NES NES { get; set; } + public virtual void SaveStateBinary(BinaryWriter bw) + { + for (int i = 0; i < 4; i++) bw.Write(mirroring[i]); + } + public virtual void LoadStateBinary(BinaryReader br) + { + for (int i = 0; i < 4; i++) mirroring[i] = br.ReadInt32(); + } + int[] mirroring = new int[4]; protected void SetMirroring(int a, int b, int c, int d) { @@ -132,17 +143,17 @@ namespace BizHawk.Emulation.Consoles.Nintendo public virtual byte[] SaveRam { get { return null; } } } - //hardware + //hardware/state protected MOS6502 cpu; INESBoard board; public PPU ppu; - RomInfo romInfo; byte[] ram; - - IPortDevice[] ports; + int cpu_accumulate; //user configuration int[,] palette; //TBD!! + IPortDevice[] ports; + RomInfo romInfo; public byte ReadPPUReg(int addr) { @@ -299,7 +310,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo ppu.FrameAdvance(); } - int cpu_accumulate; protected void RunCpu(int cycles) { if (ppu.PAL) @@ -415,27 +425,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo set { } } - public void SaveStateText(TextWriter writer) - { - } - - public void LoadStateText(TextReader reader) - { - } - - public void SaveStateBinary(BinaryWriter writer) - { - } - - public void LoadStateBinary(BinaryReader reader) - { - } - - public byte[] SaveStateBinary() - { - return new byte[0]; - } - public string SystemId { get { return "NES"; } } public IList MemoryDomains { get { return new List(); } } public MemoryDomain MainMemory @@ -684,6 +673,65 @@ namespace BizHawk.Emulation.Consoles.Nintendo HardReset(); } + + public void SaveStateText(TextWriter writer) + { + writer.WriteLine("[NES]"); + byte[] lol = SaveStateBinary(); + writer.WriteLine("blob {0}", Util.BytesToHexString(lol)); + writer.WriteLine("[/NES]"); + } + + public void LoadStateText(TextReader reader) + { + byte[] blob = null; + while (true) + { + string[] args = reader.ReadLine().Split(' '); + if (args[0] == "blob") + blob = Util.HexStringToBytes(args[1]); + else if (args[0] == "[/NES]") break; + } + if (blob == null) throw new ArgumentException(); + LoadStateBinary(new BinaryReader(new MemoryStream(blob))); + } + + + public byte[] SaveStateBinary() + { + MemoryStream ms = new MemoryStream(); + BinaryWriter bw = new BinaryWriter(ms); + SaveStateBinary(bw); + bw.Flush(); + return ms.ToArray(); + } + + public void SaveStateBinary(BinaryWriter bw) + { + using (var sw = new StringWriter()) + { + cpu.SaveStateText(sw); + sw.Flush(); + Util.WriteByteBuffer(bw, System.Text.Encoding.ASCII.GetBytes(sw.ToString())); + } + Util.WriteByteBuffer(bw,ram); + bw.Write(cpu_accumulate); + board.SaveStateBinary(bw); + ppu.SaveStateBinary(bw); + bw.Flush(); + } + + public void LoadStateBinary(BinaryReader br) + { + using (var sr = new StringReader(System.Text.Encoding.ASCII.GetString(Util.ReadByteBuffer(br, false)))) + cpu.LoadStateText(sr); + ram = Util.ReadByteBuffer(br, false); + cpu_accumulate = br.ReadInt32(); + board.LoadStateBinary(br); + ppu.LoadStateBinary(br); + } + + } } diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.cs index 988b0d4914..0087b9466d 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.cs @@ -51,9 +51,50 @@ namespace BizHawk.Emulation.Consoles.Nintendo Reset(); } + //state int ppudead; //measured in frames bool idleSynch; + public void SaveStateBinary(BinaryWriter bw) + { + bw.Write(ppudead); + bw.Write(idleSynch); + bw.Write((bool)Reg2002_objoverflow); + bw.Write((bool)Reg2002_objhit); + bw.Write((bool)Reg2002_vblank_active); + bw.Write(PPUGenLatch); + bw.Write(reg_2000.Value); + bw.Write(reg_2001.Value); + bw.Write(reg_2003); + Util.WriteByteBuffer(bw, OAM); + Util.WriteByteBuffer(bw, PALRAM); + Util.WriteByteBuffer(bw, NTARAM); + bw.Write(vtoggle); + bw.Write(VRAMBuffer); + ppur.SaveStateBinary(bw); + bw.Write(xbuf); + } + + public void LoadStateBinary(BinaryReader br) + { + ppudead = br.ReadInt32(); + idleSynch = br.ReadBoolean(); + Reg2002_objoverflow = br.ReadBit(); + Reg2002_objhit = br.ReadBit(); + Reg2002_vblank_active = br.ReadBit(); + PPUGenLatch = br.ReadByte(); + reg_2000.Value = br.ReadByte(); + reg_2001.Value = br.ReadByte(); + reg_2003 = br.ReadByte(); + OAM = Util.ReadByteBuffer(br,false); + PALRAM = Util.ReadByteBuffer(br, false); + NTARAM = Util.ReadByteBuffer(br, false); + vtoggle = br.ReadBoolean(); + VRAMBuffer = br.ReadByte(); + ppur.LoadStateBinary(br); + xbuf = br.ReadShorts(xbuf.Length); + } + public void Reset() { regs_reset(); diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.regs.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.regs.cs index c093431661..ec607b8197 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.regs.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.regs.cs @@ -71,6 +71,42 @@ namespace BizHawk.Emulation.Consoles.Nintendo reset(); } + public void SaveStateBinary(BinaryWriter bw) + { + bw.Write(fv); + bw.Write(v); + bw.Write(h); + bw.Write(vt); + bw.Write(ht); + bw.Write(_fv); + bw.Write(_v); + bw.Write(_h); + bw.Write(_vt); + bw.Write(_ht); + bw.Write(fh); + bw.Write(status.cycle); + bw.Write(status.end_cycle); + bw.Write(status.sl); + } + + public void LoadStateBinary(BinaryReader br) + { + fv = br.ReadInt32(); + v = br.ReadInt32(); + h = br.ReadInt32(); + vt = br.ReadInt32(); + ht = br.ReadInt32(); + _fv = br.ReadInt32(); + _v = br.ReadInt32(); + _h = br.ReadInt32(); + _vt = br.ReadInt32(); + _ht = br.ReadInt32(); + fh = br.ReadInt32(); + status.cycle = br.ReadInt32(); + status.end_cycle = br.ReadInt32(); + status.sl = br.ReadInt32(); + } + //normal clocked regs. as the game can interfere with these at any time, they need to be savestated public int fv;//3 public int v;//1 @@ -221,8 +257,13 @@ namespace BizHawk.Emulation.Consoles.Nintendo public Bit ppu_layer; //PPU layer select (should always be 0 in the NES; some Nintendo arcade boards presumably had two PPUs) public Bit vblank_nmi_gen; //Vertical blank NMI generation (0: off; 1: on) + public byte Value { + get + { + return (byte)(ppu.ppur._h | (ppu.ppur._v << 1) | (vram_incr32 << 2) | (obj_pattern_hi << 3) | (bg_pattern_hi << 4) | (obj_size_16 << 5) | (ppu_layer << 6) | (vblank_nmi_gen << 7)); + } set { ppu.ppur._h = value & 1; diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.run.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.run.cs index ab1f0053dd..e35895fcae 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.run.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.run.cs @@ -21,7 +21,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo public byte pt_0, pt_1; }; - public int[] xbuf = new int[256*256]; + public short[] xbuf = new short[256*256]; void Read_bgdata(ref BGDataRecord bgdata) { int addr = ppur.get_ntread(); @@ -68,11 +68,11 @@ namespace BizHawk.Emulation.Consoles.Nintendo } //TODO - check flashing sirens in werewolf - int PaletteAdjustPixel(int pixel) + short PaletteAdjustPixel(int pixel) { //tack on the deemph bits pixel |= (reg_2001.intense_red<<8)|(reg_2001.intense_green<<9)|(reg_2001.intense_blue<<10); - return pixel; + return (short)pixel; } const int kLineTime = 341; diff --git a/BizHawk.Emulation/Util.cs b/BizHawk.Emulation/Util.cs index 89be102a48..d5fba37bd3 100644 --- a/BizHawk.Emulation/Util.cs +++ b/BizHawk.Emulation/Util.cs @@ -200,6 +200,65 @@ namespace BizHawk writer.WriteLine(); } + public static void SaveAsHex(this int[] buffer, TextWriter writer) + { + for (int i = 0; i < buffer.Length; i++) + { + writer.Write("{0:X8}", buffer[i]); + } + writer.WriteLine(); + } + + public static void SaveAsHex(this uint[] buffer, TextWriter writer) + { + for (int i = 0; i < buffer.Length; i++) + { + writer.Write("{0:X8}", buffer[i]); + } + writer.WriteLine(); + } + + public static void Write(this BinaryWriter bw, int[] buffer) + { + for (int i = 0; i < buffer.Length; i++) + bw.Write(buffer[i]); + } + + public static void Write(this BinaryWriter bw, uint[] buffer) + { + for (int i = 0; i < buffer.Length; i++) + bw.Write(buffer[i]); + } + + public static void Write(this BinaryWriter bw, short[] buffer) + { + for (int i = 0; i < buffer.Length; i++) + bw.Write(buffer[i]); + } + + public static void Write(this BinaryWriter bw, ushort[] buffer) + { + for (int i = 0; i < buffer.Length; i++) + bw.Write(buffer[i]); + } + + public static int[] ReadInts(this BinaryReader br, int num) + { + int[] ret = new int[num]; + for (int i = 0; i < num; i++) + ret[i] = br.ReadInt32(); + return ret; + } + + public static short[] ReadShorts(this BinaryReader br, int num) + { + short[] ret = new short[num]; + for (int i = 0; i < num; i++) + ret[i] = br.ReadInt16(); + return ret; + } + + public static void ReadFromHex(this byte[] buffer, string hex) { if (hex.Length % 2 != 0) @@ -232,6 +291,22 @@ namespace BizHawk buffer[i] = ushort.Parse(ushorthex, NumberStyles.HexNumber); } } + + public static void ReadFromHex(this int[] buffer, BinaryWriter bw) + { + for (int i = 0; i < buffer.Length; i++) + bw.Write(buffer[i]); + } + + public static void SaveAsHex(this uint[] buffer, BinaryWriter bw) + { + for (int i = 0; i < buffer.Length; i++) + bw.Write(buffer[i]); + } + + //these don't work??? they dont get chosen by compiler + public static void Write(this BinaryWriter bw, Bit bit) { bw.Write((bool)bit); } + public static Bit ReadBit(this BinaryReader br) { return br.ReadBoolean(); } } public static class Colors @@ -255,7 +330,7 @@ namespace BizHawk //I think this is a little faster with uint than with byte - struct Bit + public struct Bit { Bit(uint val) { this.val = val; } uint val; @@ -299,6 +374,7 @@ namespace BizHawk /// /// conerts bytes to an uppercase string of hex numbers in upper case without any spacing or anything + /// //could be extension method /// public static string BytesToHexString(byte[] bytes) { @@ -308,6 +384,57 @@ namespace BizHawk return sb.ToString(); } + //could be extension method + public static byte[] HexStringToBytes(string str) + { + MemoryStream ms = new MemoryStream(); + if (str.Length % 2 != 0) throw new ArgumentException(); + int len = str.Length/2; + for (int i = 0; i < len; i++) + { + int d = 0; + for (int j = 0; j < 2; j++) + { + char c = char.ToLower(str[i * 2 + j]); + if (c >= '0' && c <= '9') + d += (c - '0'); + else if (c >= 'a' && c <= 'f') + d += (c - 'a') + 10; + else throw new ArgumentException(); + if (j == 0) d <<= 4; + } + ms.WriteByte((byte)d); + } + return ms.ToArray(); + } + + //could be extension method + public static void WriteByteBuffer(BinaryWriter bw, byte[] data) + { + if (data == null) bw.Write(0); + else + { + bw.Write(data.Length); + bw.Write(data); + } + } + + //could be extension method + public static byte[] ReadByteBuffer(BinaryReader br, bool return_null) + { + int len = br.ReadInt32(); + if (len == 0 && return_null) return null; + byte[] ret = new byte[len]; + int ofs = 0; + while (len > 0) + { + int done = br.Read(ret, ofs, len); + ofs += done; + len -= done; + } + return ret; + } + public static unsafe int memcmp(void* a, string b, int len) { fixed (byte* bp = System.Text.Encoding.ASCII.GetBytes(b)) diff --git a/BizHawk.MultiClient/Config.cs b/BizHawk.MultiClient/Config.cs index 6fec656066..3a4eda5b35 100644 --- a/BizHawk.MultiClient/Config.cs +++ b/BizHawk.MultiClient/Config.cs @@ -35,6 +35,7 @@ public bool LimitFramerate = true; public bool AutoMinimizeSkipping = true; public bool DisplayVSync = false; + public bool RewindEnabled = true; // Display options public bool DisplayFPS = false; diff --git a/BizHawk.MultiClient/MainForm.cs b/BizHawk.MultiClient/MainForm.cs index 93f227f475..6def637169 100644 --- a/BizHawk.MultiClient/MainForm.cs +++ b/BizHawk.MultiClient/MainForm.cs @@ -610,7 +610,7 @@ namespace BizHawk.MultiClient runFrame = true; } - if (/*Global.Config.RewindEnabled && */Global.ClientControls["Rewind"]) + if (Global.Config.RewindEnabled && Global.ClientControls["Rewind"]) { rewindCredits += Global.Config.SpeedPercent; int rewindTodo = rewindCredits / 100; @@ -629,7 +629,7 @@ namespace BizHawk.MultiClient bool genSound = false; if (runFrame) { - if(!suppressCaptureRewind) CaptureRewindState(); + if(!suppressCaptureRewind && Global.Config.RewindEnabled) CaptureRewindState(); if (!runloop_frameadvance) genSound = true; else if (!Global.Config.MuteFrameAdvance) genSound = true; diff --git a/BizHawk.MultiClient/Rewind.cs b/BizHawk.MultiClient/Rewind.cs index e9dd1b3606..785ef4bcb7 100644 --- a/BizHawk.MultiClient/Rewind.cs +++ b/BizHawk.MultiClient/Rewind.cs @@ -38,6 +38,8 @@ namespace BizHawk.MultiClient { if (inChangeSequence == false) { + if (i >= LastState.Length) + continue; if (CurrentState[i] == LastState[i]) continue; @@ -82,6 +84,8 @@ namespace BizHawk.MultiClient { if (inChangeSequence == false) { + if (i >= LastState.Length) + continue; if (CurrentState[i] == LastState[i]) continue; diff --git a/BizHawk.MultiClient/output/gamedb.txt b/BizHawk.MultiClient/output/gamedb.txt index 0955d251e3..8ec551f891 100644 --- a/BizHawk.MultiClient/output/gamedb.txt +++ b/BizHawk.MultiClient/output/gamedb.txt @@ -2386,7 +2386,7 @@ D821FB982CE47299FDB08A027EC0B8BE Super Mario Bros - Duck Hunt (U) NES board=Gx ;GxROM 8,4 (mapper 66) ;these frequently needs to be corrected to V ADD4E9F5ED4391A6B3FDFC5F0E300E71 Doraemon (J) NES board=GxROM;mirror=V;PRG=8;CHR=4 4E9D128C63A41C8CC20FF1114A67A2DD Dragon Power (U) NES board=GxROM;mirror=V;PRG=8;CHR=4 -8F43E7D7BD3DBDF6D8ADF3E046DE3562 Gumshoe (UE) NES board=GxROM;mirror=H;PRG=8;CHR=4 +8F43E7D7BD3DBDF6D8ADF3E046DE3562 Gumshoe (UE) NES board=GxROM;mirror=V;PRG=8;CHR=4 ;GxROM 8,16 (mapper 66) BE40E77C5532AF8E2C1EA7B96831CCEA Thunder & Lightning (U).nes NES board=GxROM;mirror=H;PRG=8;CHR=16 \ No newline at end of file