[NES] mapper cleanup and savestates

This commit is contained in:
zeromus 2011-03-01 09:32:12 +00:00
parent d225c23cc1
commit 0d5cff7408
18 changed files with 559 additions and 62 deletions

View File

@ -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 ====
/// <summary>Carry Flag</summary>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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<MemoryDomain> MemoryDomains { get { return new List<MemoryDomain>(); } }
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);
}
}
}

View File

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

View File

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

View File

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

View File

@ -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
/// <summary>
/// conerts bytes to an uppercase string of hex numbers in upper case without any spacing or anything
/// //could be extension method
/// </summary>
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))

View File

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

View File

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

View File

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

View File

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