FDS: cleanup and savestates

This commit is contained in:
goyuken 2012-10-28 15:13:56 +00:00
parent 77794dae50
commit a2c0d1b57b
3 changed files with 192 additions and 83 deletions

View File

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

View File

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

View File

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