FDS: cleanup and savestates
This commit is contained in:
parent
77794dae50
commit
a2c0d1b57b
|
@ -15,15 +15,73 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
[NES.INESBoardImplCancel]
|
||||
public class FDS : NES.NESBoardBase
|
||||
{
|
||||
/// <summary>
|
||||
/// fds bios image; should be 8192 bytes
|
||||
/// </summary>
|
||||
#region configuration
|
||||
/// <summary>FDS bios image; should be 8192 bytes</summary>
|
||||
public byte[] biosrom;
|
||||
|
||||
/// <summary>
|
||||
/// .fds disk image
|
||||
/// </summary>
|
||||
/// <summary>.FDS disk image</summary>
|
||||
byte[] diskimage;
|
||||
#endregion
|
||||
|
||||
#region state
|
||||
RamAdapter diskdrive;
|
||||
FDSAudio audio;
|
||||
/// <summary>0-2, how many ppu cycles since audio was last triggered</summary>
|
||||
int audioclock;
|
||||
/// <summary>currently loaded side of the .FDS image, 0 based</summary>
|
||||
int? currentside = null;
|
||||
/// <summary>collection of diffs (as provided by the RamAdapter) for each side in the .FDS image</summary>
|
||||
byte[][] diskdiffs;
|
||||
|
||||
bool _diskirq;
|
||||
bool _timerirq;
|
||||
|
||||
/// <summary>disk io ports enabled; see 4023.0</summary>
|
||||
bool diskenable = false;
|
||||
/// <summary>sound io ports enabled; see 4023.1</summary>
|
||||
bool soundenable = false;
|
||||
/// <summary>read on 4033, write on 4026</summary>
|
||||
byte reg4026;
|
||||
|
||||
/// <summary>timer reload</summary>
|
||||
int timerlatch;
|
||||
/// <summary>timer current value</summary>
|
||||
int timervalue;
|
||||
/// <summary>4022.0,1</summary>
|
||||
byte timerreg;
|
||||
#endregion
|
||||
|
||||
public override void SyncState(Serializer ser)
|
||||
{
|
||||
base.SyncState(ser);
|
||||
ser.BeginSection("FDS");
|
||||
ser.BeginSection("RamAdapter");
|
||||
diskdrive.SyncState(ser);
|
||||
ser.EndSection();
|
||||
ser.BeginSection("audio");
|
||||
audio.SyncState(ser);
|
||||
ser.EndSection();
|
||||
ser.Sync("audioclock", ref audioclock);
|
||||
{
|
||||
// silly little hack
|
||||
int tmp = currentside != null ? (int)currentside : 1234567;
|
||||
ser.Sync("currentside", ref tmp);
|
||||
currentside = tmp == 1234567 ? null : (int?)tmp;
|
||||
}
|
||||
for (int i = 0; i < NumSides; i++)
|
||||
ser.Sync("diskdiffs" + i, ref diskdiffs[i], false);
|
||||
ser.Sync("_timerirq", ref _timerirq);
|
||||
ser.Sync("_diskirq", ref _diskirq);
|
||||
ser.Sync("diskenable", ref diskenable);
|
||||
ser.Sync("soundenable", ref soundenable);
|
||||
ser.Sync("reg4026", ref reg4026);
|
||||
ser.Sync("timerlatch", ref timerlatch);
|
||||
ser.Sync("timervalue", ref timervalue);
|
||||
ser.Sync("timerreg", ref timerreg);
|
||||
ser.EndSection();
|
||||
|
||||
SetIRQ();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// should only be called once, before emulation begins
|
||||
|
@ -35,11 +93,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
diskdiffs = new byte[NumSides][];
|
||||
}
|
||||
|
||||
|
||||
RamAdapter diskdrive;
|
||||
FDSAudio audio;
|
||||
int audioclock;
|
||||
|
||||
// as we have [INESBoardImplCancel], this will only be called with an fds disk image
|
||||
public override bool Configure(NES.EDetectionOrigin origin)
|
||||
{
|
||||
|
@ -56,21 +109,13 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
audio = new FDSAudio();
|
||||
|
||||
InsertSide(0);
|
||||
|
||||
// set mirroring
|
||||
|
||||
// set mirroring??
|
||||
return true;
|
||||
}
|
||||
|
||||
// with a bit of change, these methods could work with a better disk format
|
||||
|
||||
public int NumSides
|
||||
{
|
||||
get
|
||||
{
|
||||
return diskimage[4];
|
||||
}
|
||||
}
|
||||
public int NumSides { get { return diskimage[4]; } }
|
||||
|
||||
public void Eject()
|
||||
{
|
||||
|
@ -84,6 +129,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
|
||||
public void InsertSide(int side)
|
||||
{
|
||||
if (side >= NumSides)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
byte[] buf = new byte[65500];
|
||||
Buffer.BlockCopy(diskimage, 16 + side * 65500, buf, 0, 65500);
|
||||
diskdrive.InsertBrokenImage(buf, false /*true*/);
|
||||
|
@ -92,10 +139,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
currentside = side;
|
||||
}
|
||||
|
||||
int? currentside = null;
|
||||
|
||||
byte[][] diskdiffs;
|
||||
|
||||
public byte[] ReadSaveRam()
|
||||
{
|
||||
// update diff for currently loaded disk first!
|
||||
|
@ -169,20 +212,12 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
{
|
||||
IRQSignal = _diskirq || _timerirq;
|
||||
}
|
||||
bool _diskirq;
|
||||
bool _timerirq;
|
||||
bool diskirq { get { return _diskirq; } set { _diskirq = value; SetIRQ(); } }
|
||||
bool timerirq { get { return _timerirq; } set { _timerirq = value; SetIRQ(); } }
|
||||
|
||||
bool diskenable = false;
|
||||
bool soundenable = false;
|
||||
|
||||
|
||||
int timerlatch;
|
||||
int timervalue;
|
||||
byte timerreg;
|
||||
|
||||
byte reg4026;
|
||||
|
||||
public override void WriteEXP(int addr, byte value)
|
||||
{
|
||||
|
@ -268,7 +303,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
if (diskenable)
|
||||
{
|
||||
ret = reg4026;
|
||||
ret &= 0x80; // set battery flag
|
||||
// uncomment to set low battery flag
|
||||
// ret &= 0x7f;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,53 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
// http://wiki.nesdev.com/w/index.php/FDS_audio
|
||||
public class FDSAudio
|
||||
{
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
// no need to sync the DCFilter or the samplebuff
|
||||
ser.Sync("waveram", ref waveram, false);
|
||||
ser.Sync("waverampos", ref waverampos);
|
||||
|
||||
ser.Sync("volumespd", ref volumespd);
|
||||
ser.Sync("r4080_6", ref r4080_6);
|
||||
ser.Sync("r4080_7", ref r4080_7);
|
||||
|
||||
ser.Sync("frequency", ref frequency);
|
||||
ser.Sync("r4083_6", ref r4083_6);
|
||||
ser.Sync("r4083_7", ref r4083_7);
|
||||
|
||||
ser.Sync("sweepspd", ref sweepspd);
|
||||
ser.Sync("r4084_6", ref r4084_6);
|
||||
ser.Sync("r4084_7", ref r4084_7);
|
||||
|
||||
ser.Sync("sweepbias", ref sweepbias);
|
||||
|
||||
ser.Sync("modfreq", ref modfreq);
|
||||
ser.Sync("r4087_7", ref r4087_7);
|
||||
|
||||
ser.Sync("modtable", ref modtable, false);
|
||||
ser.Sync("modtablepos", ref modtablepos);
|
||||
|
||||
ser.Sync("mastervol_num", ref mastervol_num);
|
||||
ser.Sync("mastervol_den", ref mastervol_den);
|
||||
ser.Sync("waveram_writeenable", ref waveram_writeenable);
|
||||
|
||||
ser.Sync("envspeed", ref envspeed);
|
||||
|
||||
ser.Sync("volumeclock", ref volumeclock);
|
||||
ser.Sync("sweepclock", ref sweepclock);
|
||||
ser.Sync("modclock", ref modclock);
|
||||
ser.Sync("mainclock", ref mainclock);
|
||||
|
||||
ser.Sync("modoutput", ref modoutput);
|
||||
|
||||
ser.Sync("volumegain", ref volumegain);
|
||||
ser.Sync("sweepgain", ref sweepgain);
|
||||
|
||||
ser.Sync("waveramoutput", ref waveramoutput);
|
||||
|
||||
ser.Sync("latchedoutput", ref latchedoutput);
|
||||
}
|
||||
|
||||
//4040:407f
|
||||
byte[] waveram = new byte[64];
|
||||
int waverampos;
|
||||
|
|
|
@ -11,6 +11,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
/// </summary>
|
||||
public class RamAdapter
|
||||
{
|
||||
#region fix broken images
|
||||
|
||||
static void WriteBlock(Stream dest, byte[] data, int pregap)
|
||||
{
|
||||
for (int i = 0; i < pregap - 1; i++)
|
||||
|
@ -87,6 +89,10 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
return tmp;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region crc
|
||||
|
||||
/// <summary>
|
||||
/// advance a 16 bit CRC register with 1 new input bit. x.25 standard
|
||||
/// </summary>
|
||||
|
@ -118,6 +124,41 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
return crc;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.Sync("originaldisk", ref originaldisk, false);
|
||||
ser.Sync("disk", ref disk, false);
|
||||
ser.Sync("diskpos", ref diskpos);
|
||||
ser.Sync("disksize", ref disksize);
|
||||
ser.Sync("writeprotect", ref writeprotect);
|
||||
|
||||
ser.Sync("cycleswaiting", ref cycleswaiting);
|
||||
{
|
||||
int tmp = (int)state;
|
||||
ser.Sync("state", ref tmp);
|
||||
state = (RamAdapterState)tmp;
|
||||
}
|
||||
ser.Sync("cached4025", ref cached4025);
|
||||
ser.Sync("irq", ref irq);
|
||||
ser.Sync("transferreset", ref transferreset);
|
||||
|
||||
ser.Sync("crc", ref crc);
|
||||
ser.Sync("writecomputecrc", ref writecomputecrc);
|
||||
|
||||
ser.Sync("readreg", ref readreg);
|
||||
ser.Sync("writereg", ref writereg);
|
||||
ser.Sync("readregpos", ref readregpos);
|
||||
ser.Sync("writeregpos", ref writeregpos);
|
||||
ser.Sync("readreglatch", ref readreglatch);
|
||||
ser.Sync("writereglatch", ref writereglatch);
|
||||
|
||||
ser.Sync("bytetransferflag", ref bytetransferflag);
|
||||
ser.Sync("lookingforendofgap", ref lookingforendofgap);
|
||||
}
|
||||
|
||||
#region state
|
||||
/// <summary>the original contents of this disk when it was loaded. for virtual saveram diff</summary>
|
||||
byte[] originaldisk = null;
|
||||
/// <summary>currently loaded disk side (ca 65k bytes)</summary>
|
||||
|
@ -129,6 +170,38 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
/// <summary>true if current disk is writeprotected</summary>
|
||||
bool writeprotect = true;
|
||||
|
||||
/// <summary>ppu cycles until next action</summary>
|
||||
int cycleswaiting = 0;
|
||||
/// <summary>physical state of the drive</summary>
|
||||
RamAdapterState state = RamAdapterState.IDLE;
|
||||
|
||||
/// <summary>cached 4025 write; can be modified internally by some things</summary>
|
||||
byte cached4025;
|
||||
/// <summary>can be raised on byte transfer complete</summary>
|
||||
public bool irq;
|
||||
/// <summary>true if 4025.1 is set to true</summary>
|
||||
bool transferreset = false;
|
||||
|
||||
/// <summary>
|
||||
/// 16 bit CRC register. in normal operation, will become all 0 on finishing a read (see x.25 spec for more details)
|
||||
/// </summary>
|
||||
ushort crc = 0;
|
||||
/// <summary>true if data being written to disk is currently being computed in CRC</summary>
|
||||
bool writecomputecrc; // this has to be latched because the "flush CRC" call comes in the middle of a byte, of course
|
||||
|
||||
// read and write shift regs, with bit positions and latched values for reload
|
||||
byte readreg;
|
||||
byte writereg;
|
||||
int readregpos;
|
||||
int writeregpos;
|
||||
byte readreglatch;
|
||||
byte writereglatch;
|
||||
|
||||
bool bytetransferflag;
|
||||
bool lookingforendofgap = false;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// eject the loaded disk
|
||||
/// </summary>
|
||||
|
@ -221,11 +294,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
}
|
||||
|
||||
// all timings are in terms of PPU cycles (@5.37mhz)
|
||||
/// <summary>
|
||||
/// ppu cycles until next action
|
||||
/// </summary>
|
||||
int cycleswaiting = 0;
|
||||
|
||||
enum RamAdapterState
|
||||
{
|
||||
/// <summary>moving over the disk</summary>
|
||||
|
@ -239,10 +307,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
/// <summary>nothing happening</summary>
|
||||
IDLE,
|
||||
};
|
||||
/// <summary>
|
||||
/// physical state of the drive
|
||||
/// </summary>
|
||||
RamAdapterState state = RamAdapterState.IDLE;
|
||||
|
||||
/// <summary>
|
||||
/// set cycleswaiting param after a state change
|
||||
|
@ -285,23 +349,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
//Console.WriteLine("!!4024:{0:x2}", value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// cached 4025 write; can be modified internally by some things
|
||||
/// </summary>
|
||||
byte cached4025;
|
||||
|
||||
/// <summary>
|
||||
/// can be raised on byte transfer complete
|
||||
/// </summary>
|
||||
public bool irq;
|
||||
|
||||
/// <summary>true if 4025.1 is set to true</summary>
|
||||
bool transferreset = false;
|
||||
|
||||
/// <summary>
|
||||
/// 16 bit CRC register. in normal operation, will become all 0 on finishing a read (see x.25 spec for more details)
|
||||
/// </summary>
|
||||
ushort crc = 0;
|
||||
|
||||
/// <summary>
|
||||
/// control reg
|
||||
|
@ -374,11 +421,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DEBUG ONLY
|
||||
/// </summary>
|
||||
int lastreaddiskpos;
|
||||
|
||||
/// <summary>
|
||||
/// more status stuff
|
||||
/// </summary>
|
||||
|
@ -463,22 +505,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
}
|
||||
}
|
||||
|
||||
// read and write shift regs, with bit positions and latched values for reload
|
||||
byte readreg;
|
||||
byte writereg;
|
||||
int readregpos;
|
||||
int writeregpos;
|
||||
byte readreglatch;
|
||||
byte writereglatch;
|
||||
|
||||
bool bytetransferflag;
|
||||
|
||||
bool lookingforendofgap = false;
|
||||
|
||||
/// <summary>
|
||||
/// true if data being written to disk is currently being computed in CRC
|
||||
/// </summary>
|
||||
bool writecomputecrc; // this has to be latched because the "flush CRC" call comes in the middle of a byte, of course
|
||||
|
||||
void Read()
|
||||
{
|
||||
|
@ -516,7 +542,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
bytetransferflag = true;
|
||||
if ((cached4025 & 0x80) != 0)
|
||||
irq = true;
|
||||
lastreaddiskpos = diskpos;
|
||||
//lastreaddiskpos = diskpos;
|
||||
//Console.WriteLine("{0:x2} {1} @{2}", readreg, (cached4025 & 0x80) != 0 ? "RAISE" : " ", diskpos);
|
||||
readreglatch = readreg;
|
||||
|
||||
|
|
Loading…
Reference in New Issue