From a2c0d1b57b54600f4317c630161cf8692f94ee04 Mon Sep 17 00:00:00 2001 From: goyuken Date: Sun, 28 Oct 2012 15:13:56 +0000 Subject: [PATCH] FDS: cleanup and savestates --- .../Consoles/Nintendo/NES/FDS/FDS.cs | 106 ++++++++++----- .../Consoles/Nintendo/NES/FDS/FDSAudio.cs | 47 +++++++ .../Consoles/Nintendo/NES/FDS/RamAdapter.cs | 122 +++++++++++------- 3 files changed, 192 insertions(+), 83 deletions(-) diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/FDS/FDS.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/FDS/FDS.cs index a37c230a4b..c66a58d0b6 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/FDS/FDS.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/FDS/FDS.cs @@ -15,15 +15,73 @@ namespace BizHawk.Emulation.Consoles.Nintendo [NES.INESBoardImplCancel] public class FDS : NES.NESBoardBase { - /// - /// fds bios image; should be 8192 bytes - /// + #region configuration + /// FDS bios image; should be 8192 bytes public byte[] biosrom; - - /// - /// .fds disk image - /// + /// .FDS disk image byte[] diskimage; + #endregion + + #region state + RamAdapter diskdrive; + FDSAudio audio; + /// 0-2, how many ppu cycles since audio was last triggered + int audioclock; + /// currently loaded side of the .FDS image, 0 based + int? currentside = null; + /// collection of diffs (as provided by the RamAdapter) for each side in the .FDS image + byte[][] diskdiffs; + + bool _diskirq; + bool _timerirq; + + /// disk io ports enabled; see 4023.0 + bool diskenable = false; + /// sound io ports enabled; see 4023.1 + bool soundenable = false; + /// read on 4033, write on 4026 + byte reg4026; + + /// timer reload + int timerlatch; + /// timer current value + int timervalue; + /// 4022.0,1 + 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(); + } + /// /// 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; } diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/FDS/FDSAudio.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/FDS/FDSAudio.cs index f823bd25d2..2ca361c585 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/FDS/FDSAudio.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/FDS/FDSAudio.cs @@ -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; diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/FDS/RamAdapter.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/FDS/RamAdapter.cs index 4f423b1723..83d0296df6 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/FDS/RamAdapter.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/FDS/RamAdapter.cs @@ -11,6 +11,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo /// 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 + /// /// advance a 16 bit CRC register with 1 new input bit. x.25 standard /// @@ -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 /// the original contents of this disk when it was loaded. for virtual saveram diff byte[] originaldisk = null; /// currently loaded disk side (ca 65k bytes) @@ -129,6 +170,38 @@ namespace BizHawk.Emulation.Consoles.Nintendo /// true if current disk is writeprotected bool writeprotect = true; + /// ppu cycles until next action + int cycleswaiting = 0; + /// physical state of the drive + RamAdapterState state = RamAdapterState.IDLE; + + /// cached 4025 write; can be modified internally by some things + byte cached4025; + /// can be raised on byte transfer complete + public bool irq; + /// true if 4025.1 is set to true + bool transferreset = false; + + /// + /// 16 bit CRC register. in normal operation, will become all 0 on finishing a read (see x.25 spec for more details) + /// + ushort crc = 0; + /// true if data being written to disk is currently being computed in CRC + 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 + /// /// eject the loaded disk /// @@ -221,11 +294,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo } // all timings are in terms of PPU cycles (@5.37mhz) - /// - /// ppu cycles until next action - /// - int cycleswaiting = 0; - enum RamAdapterState { /// moving over the disk @@ -239,10 +307,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo /// nothing happening IDLE, }; - /// - /// physical state of the drive - /// - RamAdapterState state = RamAdapterState.IDLE; /// /// set cycleswaiting param after a state change @@ -285,23 +349,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo //Console.WriteLine("!!4024:{0:x2}", value); } - /// - /// cached 4025 write; can be modified internally by some things - /// - byte cached4025; - - /// - /// can be raised on byte transfer complete - /// - public bool irq; - - /// true if 4025.1 is set to true - bool transferreset = false; - - /// - /// 16 bit CRC register. in normal operation, will become all 0 on finishing a read (see x.25 spec for more details) - /// - ushort crc = 0; /// /// control reg @@ -374,11 +421,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo return ret; } - /// - /// DEBUG ONLY - /// - int lastreaddiskpos; - /// /// more status stuff /// @@ -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; - - /// - /// true if data being written to disk is currently being computed in CRC - /// - 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;