diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Abstraction/IBeeperDevice.cs b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Abstraction/IBeeperDevice.cs
deleted file mode 100644
index de19bfe9a2..0000000000
--- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Abstraction/IBeeperDevice.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using BizHawk.Common;
-
-namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
-{
- ///
- /// Represents a beeper/buzzer device
- ///
- public interface IBeeperDevice
- {
- ///
- /// Initialization
- ///
- void Init(int sampleRate, int tStatesPerFrame);
-
- ///
- /// Processes an incoming pulse value and adds it to the blipbuffer
- ///
- void ProcessPulseValue(bool pulse);
-
- ///
- /// State serialization
- ///
- void SyncState(Serializer ser);
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Datacorder/DatacorderDevice.cs b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Datacorder/DatacorderDevice.cs
index 450fa39c46..1fde14b52c 100644
--- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Datacorder/DatacorderDevice.cs
+++ b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Datacorder/DatacorderDevice.cs
@@ -5,6 +5,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
+
namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
{
///
diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/CHRN.cs b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/CHRN.cs
deleted file mode 100644
index 76d7ae23be..0000000000
--- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/CHRN.cs
+++ /dev/null
@@ -1,180 +0,0 @@
-
-namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
-{
- ///
- /// Used for the sector CHRN structure
- ///
- public class CHRN
- {
- ///
- /// Track
- ///
- public byte C { get; set; }
-
- ///
- /// Side
- ///
- public byte H { get; set; }
-
- ///
- /// Sector ID
- ///
- public byte R { get; set; }
-
- ///
- /// Sector Size
- ///
- public byte N { get; set; }
-
- ///
- /// Status register 1
- ///
- private byte _flag1;
- public byte Flag1
- {
- get => _flag1;
- set => _flag1 = value;
- }
-
- ///
- /// Status register 2
- ///
- private byte _flag2;
- public byte Flag2
- {
- get => _flag2;
- set => _flag2 = value;
- }
-
- ///
- /// Used to store the last transmitted/received data bytes
- ///
- public byte[] DataBytes { get; set; }
-
- ///
- /// ID for the read/write data command
- ///
- public int DataID { get; set; }
-
- #region Helper Methods
-
- ///
- /// Missing Address Mark (Sector_ID or DAM not found)
- ///
- public bool ST1MA
- {
- get => NECUPD765.GetBit(0, _flag1);
- set
- {
- if (value) { NECUPD765.SetBit(0, ref _flag1); }
- else { NECUPD765.UnSetBit(0, ref _flag1); }
- }
- }
-
- ///
- /// No Data (Sector_ID not found, CRC fail in ID_field)
- ///
- public bool ST1ND
- {
- get => NECUPD765.GetBit(2, _flag1);
- set
- {
- if (value) { NECUPD765.SetBit(2, ref _flag1); }
- else { NECUPD765.UnSetBit(2, ref _flag1); }
- }
- }
-
- ///
- /// Data Error (CRC-fail in ID- or Data-Field)
- ///
- public bool ST1DE
- {
- get => NECUPD765.GetBit(5, _flag1);
- set
- {
- if (value) { NECUPD765.SetBit(5, ref _flag1); }
- else { NECUPD765.UnSetBit(5, ref _flag1); }
- }
- }
-
- ///
- /// End of Track (set past most read/write commands) (see IC)
- ///
- public bool ST1EN
- {
- get => NECUPD765.GetBit(7, _flag1);
- set
- {
- if (value) { NECUPD765.SetBit(7, ref _flag1); }
- else { NECUPD765.UnSetBit(7, ref _flag1); }
- }
- }
-
- ///
- /// Missing Address Mark in Data Field (DAM not found)
- ///
- public bool ST2MD
- {
- get => NECUPD765.GetBit(0, _flag2);
- set
- {
- if (value) { NECUPD765.SetBit(0, ref _flag2); }
- else { NECUPD765.UnSetBit(0, ref _flag2); }
- }
- }
-
- ///
- /// Bad Cylinder (read/programmed track-ID different and read-ID = FF)
- ///
- public bool ST2BC
- {
- get => NECUPD765.GetBit(1, _flag2);
- set
- {
- if (value) { NECUPD765.SetBit(1, ref _flag2); }
- else { NECUPD765.UnSetBit(1, ref _flag2); }
- }
- }
-
- ///
- /// Wrong Cylinder (read/programmed track-ID different) (see b1)
- ///
- public bool ST2WC
- {
- get => NECUPD765.GetBit(4, _flag2);
- set
- {
- if (value) { NECUPD765.SetBit(4, ref _flag2); }
- else { NECUPD765.UnSetBit(4, ref _flag2); }
- }
- }
-
- ///
- /// Data Error in Data Field (CRC-fail in data-field)
- ///
- public bool ST2DD
- {
- get => NECUPD765.GetBit(5, _flag2);
- set
- {
- if (value) { NECUPD765.SetBit(5, ref _flag2); }
- else { NECUPD765.UnSetBit(5, ref _flag2); }
- }
- }
-
- ///
- /// Control Mark (read/scan command found sector with deleted DAM)
- ///
- public bool ST2CM
- {
- get => NECUPD765.GetBit(6, _flag2);
- set
- {
- if (value) { NECUPD765.SetBit(6, ref _flag2); }
- else { NECUPD765.UnSetBit(6, ref _flag2); }
- }
- }
-
- #endregion
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/NECUPD765.FDD.cs b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/NECUPD765.FDD.cs
deleted file mode 100644
index a1ec95fdba..0000000000
--- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/NECUPD765.FDD.cs
+++ /dev/null
@@ -1,875 +0,0 @@
-using BizHawk.Common;
-using BizHawk.Common.NumberExtensions;
-using System;
-using System.Linq;
-
-namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
-{
- ///
- /// Floppy drive related stuff
- ///
- #region Attribution
- /*
- Implementation based on the information contained here:
- http://www.cpcwiki.eu/index.php/765_FDC
- and here:
- http://www.cpcwiki.eu/imgs/f/f3/UPD765_Datasheet_OCRed.pdf
- */
- #endregion
- public partial class NECUPD765 : IFDDHost
- {
- #region Drive State
-
- ///
- /// FDD Flag - motor on/off
- ///
- public bool FDD_FLAG_MOTOR;
-
- ///
- /// The index of the currently active disk drive
- ///
- public int DiskDriveIndex
- {
- get => _diskDriveIndex;
- set
- {
- // when index is changed update the ActiveDrive
- _diskDriveIndex = value;
- ActiveDrive = DriveStates[_diskDriveIndex];
- }
- }
- private int _diskDriveIndex = 0;
-
- ///
- /// The currently active drive
- ///
- private DriveState ActiveDrive;
-
- ///
- /// Array that holds state information for each possible drive
- ///
- private DriveState[] DriveStates = new DriveState[4];
-
- #endregion
-
- #region FDD Methods
-
- ///
- /// Initialization / reset of the floppy drive subsystem
- ///
- private void FDD_Init()
- {
- for (int i = 0; i < 4; i++)
- {
- DriveState ds = new DriveState(i, this);
- DriveStates[i] = ds;
- }
- }
-
- ///
- /// Searches for the requested sector
- ///
- private FloppyDisk.Sector GetSector()
- {
- FloppyDisk.Sector sector = null;
-
- // get the current track
- var trk = ActiveDrive.Disk.DiskTracks[ActiveDrive.TrackIndex];
-
- // get the current sector index
- int index = ActiveDrive.SectorIndex;
-
- // make sure this index exists
- if (index > trk.Sectors.Length)
- {
- index = 0;
- }
-
- // index hole count
- int iHole = 0;
-
- // loop through the sectors in a track
- // the loop ends with either the sector being found
- // or the index hole being passed twice
- while (iHole <= 2)
- {
- // does the requested sector match the current sector
- if (trk.Sectors[index].SectorIDInfo.C == ActiveCommandParams.Cylinder &&
- trk.Sectors[index].SectorIDInfo.H == ActiveCommandParams.Head &&
- trk.Sectors[index].SectorIDInfo.R == ActiveCommandParams.Sector &&
- trk.Sectors[index].SectorIDInfo.N == ActiveCommandParams.SectorSize)
- {
- // sector has been found
- sector = trk.Sectors[index];
-
- UnSetBit(SR2_BC, ref Status2);
- UnSetBit(SR2_WC, ref Status2);
- break;
- }
-
- // check for bad cylinder
- if (trk.Sectors[index].SectorIDInfo.C == 255)
- {
- SetBit(SR2_BC, ref Status2);
- }
- // check for no cylinder
- else if (trk.Sectors[index].SectorIDInfo.C != ActiveCommandParams.Cylinder)
- {
- SetBit(SR2_WC, ref Status2);
- }
-
- // incrememnt sector index
- index++;
-
- // have we reached the index hole?
- if (trk.Sectors.Length <= index)
- {
- // wrap around
- index = 0;
- iHole++;
- }
- }
-
- // search loop has completed and the sector may or may not have been found
-
- // bad cylinder detected?
- if (Status2.Bit(SR2_BC))
- {
- // remove WC
- UnSetBit(SR2_WC, ref Status2);
- }
-
- // update sectorindex on drive
- ActiveDrive.SectorIndex = index;
-
- return sector;
- }
-
- #endregion
-
- #region IFDDHost
-
- // IFDDHost methods that fall through to the currently active drive
-
- ///
- /// Parses a new disk image and loads it into this floppy drive
- ///
- public void FDD_LoadDisk(byte[] diskData)
- {
- // we are only going to load into the first drive
- DriveStates[0].FDD_LoadDisk(diskData);
- }
-
- ///
- /// Ejects the current disk
- ///
- public void FDD_EjectDisk()
- {
- DriveStates[0].FDD_EjectDisk();
- }
-
- ///
- /// Signs whether the current active drive has a disk inserted
- ///
- public bool FDD_IsDiskLoaded => DriveStates[DiskDriveIndex].FDD_IsDiskLoaded;
-
- ///
- /// Returns the disk object from drive 0
- ///
- public FloppyDisk DiskPointer => DriveStates[0].Disk;
-
- public FloppyDisk Disk { get; set; }
-
- #endregion
-
- #region Drive Status Class
-
- ///
- /// Holds specfic state information about a drive
- ///
- private class DriveState : IFDDHost
- {
- #region State
-
- ///
- /// The drive ID from an FDC perspective
- ///
- public int ID;
-
- ///
- /// Signs whether this drive ready
- /// TRUE if both drive exists and has a disk inserted
- ///
- public bool FLAG_READY
- {
- get
- {
- if (!FDD_IsDiskLoaded || Disk.GetTrackCount() == 0 || !FDC.FDD_FLAG_MOTOR)
- return false;
- else
- return true;
- }
- }
-
- ///
- /// Disk is write protected (TRUE BY DEFAULT)
- ///
- public bool FLAG_WRITEPROTECT = false;
-
- ///
- /// Storage for seek steps
- /// One step for each indexpulse (track index) until seeked track
- ///
- public int SeekCounter;
-
- ///
- /// Seek status
- ///
- public int SeekStatus;
-
- ///
- /// Age counter
- ///
- public int SeekAge;
-
- ///
- /// The current side
- ///
- public byte CurrentSide;
-
- ///
- /// The current track index in the DiskTracks array
- ///
- public byte TrackIndex;
-
- ///
- /// The track ID of the current cylinder
- ///
- public byte CurrentTrackID
- {
- get
- {
- // default invalid track
- int id = 0xff;
-
- if (Disk == null)
- return (byte)id;
-
- if (Disk.DiskTracks.Count() == 0)
- return (byte)id;
-
- if (TrackIndex >= Disk.GetTrackCount())
- TrackIndex = 0;
- else if (TrackIndex < 0)
- TrackIndex = 0;
-
- var track = Disk.DiskTracks[TrackIndex];
-
- id = track.TrackNumber;
-
- return (byte)id;
- }
- set
- {
- for (int i = 0; i < Disk.GetTrackCount(); i++)
- {
- if (Disk.DiskTracks[i].TrackNumber == value)
- {
- TrackIndex = (byte)i;
- break;
- }
- }
- }
- }
-
-
- ///
- /// The new track that the drive is seeking to
- /// (used in seek operations)
- ///
- public int SeekingTrack;
-
- ///
- /// The current sector index in the Sectors array
- ///
- public int SectorIndex;
-
- ///
- /// The currently loaded floppy disk
- ///
- public FloppyDisk Disk { get; set; }
-
- ///
- /// The parent controller
- ///
- private NECUPD765 FDC;
-
- #endregion
-
- #region Lookups
-
- ///
- /// TRUE if we are on track 0
- ///
- public bool FLAG_TRACK0
- {
- get
- {
- if (TrackIndex == 0) { return true; }
- else { return false; }
- }
- }
-
- #endregion
-
- #region Public Methods
- /*
- ///
- /// Moves the head across the disk cylinders
- ///
- public void MoveHead(SkipDirection direction, int cylinderCount)
- {
- // get total tracks
- int trackCount = Disk.DiskTracks.Count();
-
- int trk = 0;
-
- switch (direction)
- {
- case SkipDirection.Increment:
- trk = (int)CurrentTrack + cylinderCount;
- if (trk >= trackCount)
- {
- // past the last track
- trk = trackCount - 1;
- }
- else if (trk < 0)
- trk = 0;
- break;
- case SkipDirection.Decrement:
- trk = (int)CurrentTrack - cylinderCount;
- if (trk < 0)
- {
- // before the first track
- trk = 0;
- }
- else if (trk >= trackCount)
- trk = trackCount - 1;
- break;
- }
-
- // move the head
- CurrentTrack = (byte)trk;
- }
- */
-
- /*
-
- ///
- /// Finds a supplied sector
- ///
- public FloppyDisk.Sector FindSector(ref byte[] resBuffer, CommandParameters prms)
- {
- int index =CurrentSector;
- int lc = 0;
- FloppyDisk.Sector sector = null;
-
- bool found = false;
-
- do
- {
- sector = Disk.DiskTracks[CurrentTrack].Sectors[index];
- if (sector != null && sector.SectorID == prms.Sector)
- {
- // sector found
- // check for data errors
- if ((sector.Status1 & 0x20) != 0 || (sector.Status2 & 0x20) != 0)
- {
- // data errors found
- }
- found = true;
- break;
- }
-
- // sector doesnt match
- var c = Disk.DiskTracks[CurrentTrack].Sectors[index].TrackNumber;
- if (c == 255)
- {
- // bad cylinder
- resBuffer[RS_ST2] |= 0x02;
- }
- else if (prms.Cylinder != c)
- {
- // cylinder mismatch
- resBuffer[RS_ST2] |= 0x10;
- }
-
- // increment index
- index++;
-
- if (index >= Disk.DiskTracks[CurrentTrack].NumberOfSectors)
- {
- // out of bounds
- index = 0;
- lc++;
- }
-
- } while (lc < 2);
-
- if ((resBuffer[RS_ST2] & 0x02) != 0)
- {
- // bad cylinder set - remove no cylinder
- UnSetBit(SR2_WC, ref resBuffer[RS_ST2]);
- }
-
- // update current sector
- CurrentSector = index;
-
- if (found)
- return sector;
- else
- return null;
- }
-
-
- ///
- /// Populates a result buffer
- ///
- public void FillResult(ref byte[] resBuffer, CHRN chrn)
- {
- // clear results
- resBuffer[RS_ST0] = 0;
- resBuffer[RS_ST1] = 0;
- resBuffer[RS_ST2] = 0;
- resBuffer[RS_C] = 0;
- resBuffer[RS_H] = 0;
- resBuffer[RS_R] = 0;
- resBuffer[RS_N] = 0;
-
- if (chrn == null)
- {
- // no chrn supplied
- resBuffer[RS_ST0] = ST0;
- resBuffer[RS_ST1] = 0;
- resBuffer[RS_ST2] = 0;
- resBuffer[RS_C] = 0;
- resBuffer[RS_H] = 0;
- resBuffer[RS_R] = 0;
- resBuffer[RS_N] = 0;
- }
- }
-
-
-
- ///
- /// Populates the result buffer with ReadID data
- ///
- public void ReadID(ref byte[] resBuffer)
- {
- if (CheckDriveStatus() == false)
- {
- // drive not ready
- resBuffer[RS_ST0] = ST0;
- return;
- }
-
- var track = Disk.DiskTracks.Where(a => a.TrackNumber == CurrentTrack).FirstOrDefault();
-
- if (track != null && track.NumberOfSectors > 0)
- {
- // formatted track
-
- // get the current sector
- int index = CurrentSector;
-
- // is the index out of bounds?
- if (index >= track.NumberOfSectors)
- {
- // reset the index
- index = 0;
- }
-
- // read the sector data
- var data = track.Sectors[index];
- resBuffer[RS_C] = data.TrackNumber;
- resBuffer[RS_H] = data.SideNumber;
- resBuffer[RS_R] = data.SectorID;
- resBuffer[RS_N] = data.SectorSize;
-
- resBuffer[RS_ST0] = ST0;
-
- // increment the current sector
- CurrentSector = index + 1;
- return;
- }
- else
- {
- // unformatted track?
- resBuffer[RS_C] = FDC.CommBuffer[CM_C];
- resBuffer[RS_H] = FDC.CommBuffer[CM_H];
- resBuffer[RS_R] = FDC.CommBuffer[CM_R];
- resBuffer[RS_N] = FDC.CommBuffer[CM_N];
-
- SetBit(SR0_IC0, ref ST0);
- resBuffer[RS_ST0] = ST0;
- resBuffer[RS_ST1] = 0x01;
- return;
- }
- }
- */
-
- /*
-
- ///
- /// The drive performs a seek operation if necessary
- /// Return value TRUE indicates seek complete
- ///
- public void DoSeek()
- {
- if (CurrentState != DriveMainState.Recalibrate &&
- CurrentState != DriveMainState.Seek)
- {
- // no seek/recalibrate has been asked for
- return;
- }
-
- if (GetBit(ID, FDC.StatusMain))
- {
- // drive is already seeking
- return;
- }
-
- RunSeekCycle();
- }
-
- ///
- /// Runs a seek cycle
- ///
- public void RunSeekCycle()
- {
- for (;;)
- {
- switch (SeekState)
- {
- // seek or recalibrate has been requested
- case SeekSubState.Idle:
-
- if (CurrentState == DriveMainState.Recalibrate)
- {
- // recalibrate always seeks to track 0
- SeekingTrack = 0;
- }
- SeekState = SeekSubState.MoveInit;
-
- // mark drive as busy
- // this should be cleared by SIS command
- SetBit(ID, ref FDC.StatusMain);
-
- break;
-
- // setup for the head move
- case SeekSubState.MoveInit:
-
- if (CurrentTrack == SeekingTrack)
- {
- // we are already at the required track
- if (CurrentState == DriveMainState.Recalibrate &&
- !FLAG_TRACK0)
- {
- // recalibration fail
- SeekIntState = SeekIntStatus.Abnormal;
-
- // raise seek interrupt
- FDC.ActiveInterrupt = InterruptState.Seek;
-
- // unset DB bit
- UnSetBit(ID, ref FDC.StatusMain);
-
- // equipment check
- SetBit(SR0_EC, ref FDC.Status0);
-
- SeekState = SeekSubState.PerformCompletion;
- break;
- }
-
- if (CurrentState == DriveMainState.Recalibrate &&
- FLAG_TRACK0)
- {
- // recalibration success
- SeekIntState = SeekIntStatus.Normal;
-
- // raise seek interrupt
- FDC.ActiveInterrupt = InterruptState.Seek;
-
- // unset DB bit
- UnSetBit(ID, ref FDC.StatusMain);
-
- SeekState = SeekSubState.PerformCompletion;
- break;
- }
- }
-
- // check for error
- if (IntStatus >= IC_ABORTED_DISCREMOVED || Disk == null)
- {
- // drive not ready
- FLAG_READY = false;
-
- // drive not ready
- SeekIntState = SeekIntStatus.DriveNotReady;
-
- // cancel any interrupt
- FDC.ActiveInterrupt = InterruptState.None;
-
- // unset DB bit
- UnSetBit(ID, ref FDC.StatusMain);
-
- SeekState = SeekSubState.PerformCompletion;
- break;
- }
-
- if (SeekCounter > 1)
- {
- // not ready to seek yet
- SeekCounter--;
- return;
- }
-
- if (FDC.SRT < 1 && CurrentTrack != SeekingTrack)
- {
- SeekState = SeekSubState.MoveImmediate;
- break;
- }
-
- // head move
- SeekState = SeekSubState.HeadMove;
-
- break;
-
- case SeekSubState.HeadMove:
-
- // do the seek
- SeekCounter = FDC.SRT;
-
- if (CurrentTrack < SeekingTrack)
- {
- // we are seeking forward
- var delta = SeekingTrack - CurrentTrack;
- MoveHead(SkipDirection.Increment, 1);
- }
- else if (CurrentTrack > SeekingTrack)
- {
- // we are seeking backward
- var delta = CurrentTrack - SeekingTrack;
- MoveHead(SkipDirection.Decrement, 1);
- }
-
- // should the seek be completed now?
- if (CurrentTrack == SeekingTrack)
- {
- SeekState = SeekSubState.PerformCompletion;
- break;
- }
-
- // seek not finished yet
- return;
-
- // seek emulation processed immediately
- case SeekSubState.MoveImmediate:
-
- if (CurrentTrack < SeekingTrack)
- {
- // we are seeking forward
- var delta = SeekingTrack - CurrentTrack;
- MoveHead(SkipDirection.Increment, delta);
-
- }
- else if (CurrentTrack > SeekingTrack)
- {
- // we are seeking backward
- var delta = CurrentTrack - SeekingTrack;
- MoveHead(SkipDirection.Decrement, delta);
- }
-
- SeekState = SeekSubState.PerformCompletion;
- break;
-
- case SeekSubState.PerformCompletion:
- SeekDone();
- SeekState = SeekSubState.SeekCompleted;
- break;
-
- case SeekSubState.SeekCompleted:
- // seek has already completed
- return;
- }
- }
- }
-
- ///
- /// Called when a seek operation has completed
- ///
- public void SeekDone()
- {
- SeekCounter = 0;
- SeekingTrack = CurrentTrack;
-
- // generate ST0 register data
-
- // get only the IC bits
- IntStatus &= IC_ABORTED_DISCREMOVED;
-
- // drive ready?
- if (!FLAG_READY)
- {
- SetBit(SR0_NR, ref IntStatus);
- SetBit(SR0_EC, ref IntStatus);
-
- // are we recalibrating?
- if (CurrentState == DriveMainState.Recalibrate)
- {
- SetBit(SR0_EC, ref IntStatus);
- }
- }
-
- // set seek end
- SetBit(SR0_SE, ref IntStatus);
- /*
- // head address
- if (CurrentSide > 0)
- {
- SetBit(SR0_HD, ref IntStatus);
-
- // drive only supports 1 head
- // set the EC bit
- SetBit(SR0_EC, ref IntStatus);
- }
- */
- /*
- // UnitSelect
- SetUnitSelect(ID, ref IntStatus);
-
- // move to none state
- //CurrentState = DriveMainState.None;
-
- //SeekState = SeekSubState.SeekCompleted;
-
- // set the seek interrupt flag for this drive
- // this will be cleared at the next successful senseint
- FLAG_SEEK_INTERRUPT = true;
-
- //CurrentState = DriveMainState.None;
-
- }
- */
-
- #endregion
-
- #region Construction
-
- public DriveState(int driveID, NECUPD765 fdc)
- {
- ID = driveID;
- FDC = fdc;
- }
-
- #endregion
-
- #region IFDDHost
-
- ///
- /// Parses a new disk image and loads it into this floppy drive
- ///
- public void FDD_LoadDisk(byte[] diskData)
- {
- // try dsk first
- FloppyDisk fdd = null;
- bool found = false;
-
- foreach (DiskType type in Enum.GetValues(typeof(DiskType)))
- {
- switch (type)
- {
- case DiskType.CPCExtended:
- fdd = new CPCExtendedFloppyDisk();
- found = fdd.ParseDisk(diskData);
- break;
- case DiskType.CPC:
- fdd = new CPCFloppyDisk();
- found = fdd.ParseDisk(diskData);
- break;
- }
-
- if (found)
- {
- Disk = fdd;
- break;
- }
- }
-
- if (!found)
- {
- throw new Exception(this.GetType().ToString() +
- "\n\nDisk image file could not be parsed. Potentially an unknown format.");
- }
- }
-
- ///
- /// Ejects the current disk
- ///
- public void FDD_EjectDisk()
- {
- Disk = null;
- //FLAG_READY = false;
- }
-
- ///
- /// Signs whether the current active drive has a disk inserted
- ///
- public bool FDD_IsDiskLoaded
- {
- get
- {
- if (Disk != null)
- return true;
- else
- return false;
- }
- }
-
- #endregion
-
- #region StateSerialization
-
- public void SyncState(Serializer ser)
- {
- ser.Sync(nameof(ID), ref ID);
- ser.Sync(nameof(FLAG_WRITEPROTECT), ref FLAG_WRITEPROTECT);
- //ser.Sync(nameof(FLAG_DISKCHANGED), ref FLAG_DISKCHANGED);
- //ser.Sync(nameof(FLAG_RECALIBRATING), ref FLAG_RECALIBRATING);
- //ser.Sync(nameof(FLAG_SEEK_INTERRUPT), ref FLAG_SEEK_INTERRUPT);
- //ser.Sync(nameof(IntStatus), ref IntStatus);
- //ser.Sync(nameof(ST0), ref ST0);
- //ser.Sync(nameof(RecalibrationCounter), ref RecalibrationCounter);
- ser.Sync(nameof(SeekCounter), ref SeekCounter);
- ser.Sync(nameof(SeekStatus), ref SeekStatus);
- ser.Sync(nameof(SeekAge), ref SeekAge);
- ser.Sync(nameof(CurrentSide), ref CurrentSide);
- //ser.Sync(nameof(CurrentTrack), ref CurrentTrack);
- ser.Sync(nameof(TrackIndex), ref TrackIndex);
- ser.Sync(nameof(SeekingTrack), ref SeekingTrack);
- //ser.Sync(nameof(CurrentSector), ref CurrentSector);
- ser.Sync(nameof(SectorIndex), ref SectorIndex);
- //ser.Sync(nameof(RAngles), ref RAngles);
- //ser.Sync(nameof(DataPointer), ref DataPointer);
- //ser.SyncEnum(nameof(CurrentState), ref CurrentState);
- //ser.SyncEnum(nameof(SeekState), ref SeekState);
- //ser.SyncEnum(nameof(SeekIntState), ref SeekIntState);
- }
-
- #endregion
- }
-
- #endregion
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/NECUPD765CPC.cs b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/NECUPD765CPC.cs
new file mode 100644
index 0000000000..012ecf99ef
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/NECUPD765CPC.cs
@@ -0,0 +1,68 @@
+using System;
+
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
+
+namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
+{
+ public class NECUPD765CPC : NECUPD765
+ {
+ protected override CPCDriveState ConstructDriveState(int driveID, NECUPD765 fdc) => new CPCDriveState(driveID, fdc);
+
+ protected override void TimingInit()
+ {
+ // z80 timing
+ double frameSize = _machine.GateArray.FrameLength;
+ double rRate = _machine.GateArray.Z80ClockSpeed / frameSize;
+ long tPerSecond = (long)(frameSize * rRate);
+ CPUCyclesPerMs = tPerSecond / 1000;
+
+ // drive timing
+ double dRate = DriveClock / frameSize;
+ long dPerSecond = (long)(frameSize * dRate);
+ DriveCyclesPerMs = dPerSecond / 1000;
+
+ long TStatesPerDriveCycle = (long)((double)_machine.GateArray.Z80ClockSpeed / DriveClock);
+ StatesPerDriveTick = TStatesPerDriveCycle;
+
+ }
+
+ public class CPCDriveState : NECUPD765DriveState
+ {
+ public CPCDriveState(int driveID, NECUPD765 fdc) : base(driveID, fdc) {}
+
+ public override void FDD_LoadDisk(byte[] diskData)
+ {
+ // try dsk first
+ FloppyDisk fdd = null;
+ bool found = false;
+
+ foreach (DiskType type in Enum.GetValues(typeof(DiskType)))
+ {
+ switch (type)
+ {
+ case DiskType.CPCExtended:
+ fdd = new CPCExtendedFloppyDisk();
+ found = fdd.ParseDisk(diskData);
+ break;
+ case DiskType.CPC:
+ fdd = new CPCFloppyDisk();
+ found = fdd.ParseDisk(diskData);
+ break;
+ }
+
+ if (found)
+ {
+ Disk = fdd;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ throw new Exception(this.GetType().ToString() +
+ "\n\nDisk image file could not be parsed. Potentially an unknown format.");
+ }
+ }
+ }
+ }
+}
diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Display/AmstradGateArray.cs b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Display/AmstradGateArray.cs
index f12028334b..05bb4be727 100644
--- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Display/AmstradGateArray.cs
+++ b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Display/AmstradGateArray.cs
@@ -7,6 +7,8 @@ using System.Collections;
using System.Collections.Generic;
using System.Linq;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
+
namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
{
///
@@ -23,7 +25,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
private CRCT_6845 CRCT => _machine.CRCT;
//private CRTDevice CRT => _machine.CRT;
private IPSG PSG => _machine.AYDevice;
- private NECUPD765 FDC => _machine.UPDDiskDevice;
+ private NECUPD765CPC FDC => _machine.UPDDiskDevice;
private DatacorderDevice DATACORDER => _machine.TapeDevice;
private ushort BUSRQ => CPU.MEMRQ[CPU.bus_pntr];
public const ushort PCh = 1;
diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Display/CRCT_6845.cs b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Display/CRCT_6845.cs
index 3b6b17370e..bd71f9ab77 100644
--- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Display/CRCT_6845.cs
+++ b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Display/CRCT_6845.cs
@@ -1,5 +1,6 @@
using BizHawk.Common;
using BizHawk.Common.NumberExtensions;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
{
diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/PPI/PPI_8255.cs b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/PPI/PPI_8255.cs
index 7570ce10c8..e0dc66dbe2 100644
--- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/PPI/PPI_8255.cs
+++ b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/PPI/PPI_8255.cs
@@ -1,6 +1,7 @@
using System.Collections;
using BizHawk.Common;
using BizHawk.Common.NumberExtensions;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
{
diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/SoundOutput/Beeper.cs b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/SoundOutput/Beeper.cs
index db6dbda9f0..5db18834e1 100644
--- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/SoundOutput/Beeper.cs
+++ b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/SoundOutput/Beeper.cs
@@ -2,6 +2,8 @@
using BizHawk.Emulation.Common;
using System;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
+
namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
{
///
diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Machine/CPC6128/CPC6128.cs b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Machine/CPC6128/CPC6128.cs
index 2128e34ca6..de6990be21 100644
--- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Machine/CPC6128/CPC6128.cs
+++ b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Machine/CPC6128/CPC6128.cs
@@ -37,7 +37,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
TapeDevice = new DatacorderDevice(autoTape);
TapeDevice.Init(this);
- UPDDiskDevice = new NECUPD765();
+ UPDDiskDevice = new NECUPD765CPC();
UPDDiskDevice.Init(this);
InitializeMedia(files);
diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Machine/CPCBase.Media.cs b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Machine/CPCBase.Media.cs
index 60520e64f6..1cb34dc16b 100644
--- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Machine/CPCBase.Media.cs
+++ b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Machine/CPCBase.Media.cs
@@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
+
namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
{
///
diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Machine/CPCBase.cs b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Machine/CPCBase.cs
index 0e9d9427d9..c412969b49 100644
--- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Machine/CPCBase.cs
+++ b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Machine/CPCBase.cs
@@ -1,5 +1,6 @@
using BizHawk.Common;
using BizHawk.Emulation.Cores.Components.Z80A;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
{
@@ -7,7 +8,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
/// The abstract class that all emulated models will inherit from
/// * Main properties / fields / contruction*
///
- public abstract partial class CPCBase
+ public abstract partial class CPCBase : CPCSpectrumBase.CPCSpectrumBase
{
#region Devices
@@ -50,7 +51,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
///
/// The Amstrad disk drive
///
- public virtual NECUPD765 UPDDiskDevice { get; set; }
+ public virtual NECUPD765CPC UPDDiskDevice { get; set; }
///
/// The Cathode Ray Tube Controller chip
diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Disk/CPCExtendedFloppyDisk.cs b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Disk/CPCExtendedFloppyDisk.cs
index f045be5df5..f93e17a7b6 100644
--- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Disk/CPCExtendedFloppyDisk.cs
+++ b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Disk/CPCExtendedFloppyDisk.cs
@@ -3,6 +3,8 @@ using BizHawk.Common;
using System;
using System.Collections.Generic;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
+
namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
{
///
diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Disk/CPCFloppyDisk.cs b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Disk/CPCFloppyDisk.cs
index 214c0fced0..07eff55776 100644
--- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Disk/CPCFloppyDisk.cs
+++ b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Disk/CPCFloppyDisk.cs
@@ -3,6 +3,8 @@ using BizHawk.Common;
using System.Collections.Generic;
using System;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
+
namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
{
///
diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Disk/DiskType.cs b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Disk/DiskType.cs
deleted file mode 100644
index df211b4e55..0000000000
--- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Disk/DiskType.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-
-namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
-{
- ///
- /// The different disk formats ZXHawk currently supports
- ///
- public enum DiskType
- {
- ///
- /// Standard CPCEMU disk format (used in the built-in +3 disk drive)
- ///
- CPC,
-
- ///
- /// Extended CPCEMU disk format (used in the built-in +3 disk drive)
- ///
- CPCExtended
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Tape/CDT/CdtConverter.cs b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Tape/CDT/CdtConverter.cs
index 401e97ff56..7192292d44 100644
--- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Tape/CDT/CdtConverter.cs
+++ b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Tape/CDT/CdtConverter.cs
@@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
+
namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
{
///
diff --git a/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/CPCSpectrumBase.cs b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/CPCSpectrumBase.cs
new file mode 100644
index 0000000000..3fce366f34
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/CPCSpectrumBase.cs
@@ -0,0 +1,9 @@
+using BizHawk.Emulation.Cores.Components.Z80A;
+
+namespace BizHawk.Emulation.Cores.Computers.CPCSpectrumBase
+{
+ public interface CPCSpectrumBase
+ {
+ Z80A CPU { get; set; }
+ }
+}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Abstraction/IBeeperDevice.cs b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Abstraction/IBeeperDevice.cs
similarity index 88%
rename from BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Abstraction/IBeeperDevice.cs
rename to BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Abstraction/IBeeperDevice.cs
index 8d40ce166c..02f9c3c622 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Abstraction/IBeeperDevice.cs
+++ b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Abstraction/IBeeperDevice.cs
@@ -1,6 +1,6 @@
using BizHawk.Common;
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
+namespace BizHawk.Emulation.Cores.Computers.CPCSpectrumBase
{
///
/// Represents a beeper/buzzer device
diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Abstraction/IFDDHost.cs b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Abstraction/IFDDHost.cs
similarity index 90%
rename from BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Abstraction/IFDDHost.cs
rename to BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Abstraction/IFDDHost.cs
index 7ae645b750..eb7cddeaac 100644
--- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Abstraction/IFDDHost.cs
+++ b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Abstraction/IFDDHost.cs
@@ -1,5 +1,5 @@
-namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
+namespace BizHawk.Emulation.Cores.Computers.CPCSpectrumBase
{
///
/// Defines an object that can load a floppy disk image
diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Abstraction/IJoystick.cs b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Abstraction/IJoystick.cs
similarity index 82%
rename from BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Abstraction/IJoystick.cs
rename to BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Abstraction/IJoystick.cs
index 50088cceae..41e5546f82 100644
--- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Abstraction/IJoystick.cs
+++ b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Abstraction/IJoystick.cs
@@ -1,15 +1,17 @@
-namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
+using System;
+
+namespace BizHawk.Emulation.Cores.Computers.CPCSpectrumBase
{
///
/// Represents a spectrum joystick
///
- public interface IJoystick
+ public interface IJoystick where T : Enum
{
///
/// The type of joystick
///
- JoystickType JoyType { get; }
+ T JoyType { get; }
///
/// Array of all the possibly button press names
diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Abstraction/IPortIODevice.cs b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Abstraction/IPortIODevice.cs
similarity index 86%
rename from BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Abstraction/IPortIODevice.cs
rename to BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Abstraction/IPortIODevice.cs
index b71e08ee08..6515a55e27 100644
--- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Abstraction/IPortIODevice.cs
+++ b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Abstraction/IPortIODevice.cs
@@ -1,5 +1,5 @@
-namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
+namespace BizHawk.Emulation.Cores.Computers.CPCSpectrumBase
{
///
/// Represents a device that utilizes port IN & OUT
diff --git a/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/CHRN.cs b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/CHRN.cs
new file mode 100644
index 0000000000..b1970aa4a3
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/CHRN.cs
@@ -0,0 +1,179 @@
+namespace BizHawk.Emulation.Cores.Computers.CPCSpectrumBase
+{
+ ///
+ /// Used for the sector CHRN structure
+ ///
+ public class CHRN
+ {
+ ///
+ /// Track
+ ///
+ public byte C { get; set; }
+
+ ///
+ /// Side
+ ///
+ public byte H { get; set; }
+
+ ///
+ /// Sector ID
+ ///
+ public byte R { get; set; }
+
+ ///
+ /// Sector Size
+ ///
+ public byte N { get; set; }
+
+ ///
+ /// Status register 1
+ ///
+ private byte _flag1;
+ public byte Flag1
+ {
+ get => _flag1;
+ set => _flag1 = value;
+ }
+
+ ///
+ /// Status register 2
+ ///
+ private byte _flag2;
+ public byte Flag2
+ {
+ get => _flag2;
+ set => _flag2 = value;
+ }
+
+ ///
+ /// Used to store the last transmitted/received data bytes
+ ///
+ public byte[] DataBytes { get; set; }
+
+ ///
+ /// ID for the read/write data command
+ ///
+ public int DataID { get; set; }
+
+ #region Helper Methods
+
+ ///
+ /// Missing Address Mark (Sector_ID or DAM not found)
+ ///
+ public bool ST1MA
+ {
+ get => NECUPD765.GetBit(0, _flag1);
+ set
+ {
+ if (value) { NECUPD765.SetBit(0, ref _flag1); }
+ else { NECUPD765.UnSetBit(0, ref _flag1); }
+ }
+ }
+
+ ///
+ /// No Data (Sector_ID not found, CRC fail in ID_field)
+ ///
+ public bool ST1ND
+ {
+ get => NECUPD765.GetBit(2, _flag1);
+ set
+ {
+ if (value) { NECUPD765.SetBit(2, ref _flag1); }
+ else { NECUPD765.UnSetBit(2, ref _flag1); }
+ }
+ }
+
+ ///
+ /// Data Error (CRC-fail in ID- or Data-Field)
+ ///
+ public bool ST1DE
+ {
+ get => NECUPD765.GetBit(5, _flag1);
+ set
+ {
+ if (value) { NECUPD765.SetBit(5, ref _flag1); }
+ else { NECUPD765.UnSetBit(5, ref _flag1); }
+ }
+ }
+
+ ///
+ /// End of Track (set past most read/write commands) (see IC)
+ ///
+ public bool ST1EN
+ {
+ get => NECUPD765.GetBit(7, _flag1);
+ set
+ {
+ if (value) { NECUPD765.SetBit(7, ref _flag1); }
+ else { NECUPD765.UnSetBit(7, ref _flag1); }
+ }
+ }
+
+ ///
+ /// Missing Address Mark in Data Field (DAM not found)
+ ///
+ public bool ST2MD
+ {
+ get => NECUPD765.GetBit(0, _flag2);
+ set
+ {
+ if (value) { NECUPD765.SetBit(0, ref _flag2); }
+ else { NECUPD765.UnSetBit(0, ref _flag2); }
+ }
+ }
+
+ ///
+ /// Bad Cylinder (read/programmed track-ID different and read-ID = FF)
+ ///
+ public bool ST2BC
+ {
+ get => NECUPD765.GetBit(1, _flag2);
+ set
+ {
+ if (value) { NECUPD765.SetBit(1, ref _flag2); }
+ else { NECUPD765.UnSetBit(1, ref _flag2); }
+ }
+ }
+
+ ///
+ /// Wrong Cylinder (read/programmed track-ID different) (see b1)
+ ///
+ public bool ST2WC
+ {
+ get => NECUPD765.GetBit(4, _flag2);
+ set
+ {
+ if (value) { NECUPD765.SetBit(4, ref _flag2); }
+ else { NECUPD765.UnSetBit(4, ref _flag2); }
+ }
+ }
+
+ ///
+ /// Data Error in Data Field (CRC-fail in data-field)
+ ///
+ public bool ST2DD
+ {
+ get => NECUPD765.GetBit(5, _flag2);
+ set
+ {
+ if (value) { NECUPD765.SetBit(5, ref _flag2); }
+ else { NECUPD765.UnSetBit(5, ref _flag2); }
+ }
+ }
+
+ ///
+ /// Control Mark (read/scan command found sector with deleted DAM)
+ ///
+ public bool ST2CM
+ {
+ get => NECUPD765.GetBit(6, _flag2);
+ set
+ {
+ if (value) { NECUPD765.SetBit(6, ref _flag2); }
+ else { NECUPD765.UnSetBit(6, ref _flag2); }
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/INECUPD765.cs b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/INECUPD765.cs
new file mode 100644
index 0000000000..444aa99cfc
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/INECUPD765.cs
@@ -0,0 +1,7 @@
+namespace BizHawk.Emulation.Cores.Computers.CPCSpectrumBase
+{
+ public interface INECUPD765
+ {
+ bool FDD_FLAG_MOTOR { get; }
+ }
+}
diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/NECUPD765.Definitions.cs b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/NECUPD765.Definitions.cs
similarity index 97%
rename from BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/NECUPD765.Definitions.cs
rename to BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/NECUPD765.Definitions.cs
index a560164411..85825ab2e5 100644
--- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/NECUPD765.Definitions.cs
+++ b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/NECUPD765.Definitions.cs
@@ -1,20 +1,20 @@
using BizHawk.Common;
using System;
-namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
+namespace BizHawk.Emulation.Cores.Computers.CPCSpectrumBase
{
///
/// Definitions
///
#region Attribution
/*
- Implementation based on the information contained here:
- http://www.cpcwiki.eu/index.php/765_FDC
- and here:
- http://www.cpcwiki.eu/imgs/f/f3/UPD765_Datasheet_OCRed.pdf
- */
+ Implementation based on the information contained here:
+ http://www.cpcwiki.eu/index.php/765_FDC
+ and here:
+ http://www.cpcwiki.eu/imgs/f/f3/UPD765_Datasheet_OCRed.pdf
+ */
#endregion
- public partial class NECUPD765
+ public abstract partial class NECUPD765
{
#region Enums
@@ -692,10 +692,10 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
///
private class Command
{
- // ///
- // /// Mask to remove potential parameter bits (5,6, and or 7) in order to identify the command
- // ///
- // public int BitMask { get; set; }
+// ///
+// /// Mask to remove potential parameter bits (5,6, and or 7) in order to identify the command
+// ///
+// public int BitMask { get; set; }
///
/// The command code after bitmask has been applied
///
diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/NECUPD765.FDC.cs b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/NECUPD765.FDC.cs
similarity index 94%
rename from BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/NECUPD765.FDC.cs
rename to BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/NECUPD765.FDC.cs
index a68d84dec6..c88ff82bef 100644
--- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/NECUPD765.FDC.cs
+++ b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/NECUPD765.FDC.cs
@@ -3,20 +3,20 @@ using System.Collections;
using System.Collections.Generic;
using System.Linq;
-namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
+namespace BizHawk.Emulation.Cores.Computers.CPCSpectrumBase
{
///
/// FDC State and Methods
///
#region Attribution
/*
- Implementation based on the information contained here:
- http://www.cpcwiki.eu/index.php/765_FDC
- and here:
- http://www.cpcwiki.eu/imgs/f/f3/UPD765_Datasheet_OCRed.pdf
- */
+ Implementation based on the information contained here:
+ http://www.cpcwiki.eu/index.php/765_FDC
+ and here:
+ http://www.cpcwiki.eu/imgs/f/f3/UPD765_Datasheet_OCRed.pdf
+ */
#endregion
- public partial class NECUPD765
+ public abstract partial class NECUPD765
{
#region Controller State
@@ -210,69 +210,69 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
/// Main status register (accessed via reads to port 0x2ffd)
///
/*
- b0..3 DB FDD0..3 Busy (seek/recalib active, until succesful sense intstat)
- b4 CB FDC Busy (still in command-, execution- or result-phase)
- b5 EXM Execution Mode (still in execution-phase, non_DMA_only)
- b6 DIO Data Input/Output (0=CPU->FDC, 1=FDC->CPU) (see b7)
- b7 RQM Request For Master (1=ready for next byte) (see b6 for direction)
- */
+ b0..3 DB FDD0..3 Busy (seek/recalib active, until succesful sense intstat)
+ b4 CB FDC Busy (still in command-, execution- or result-phase)
+ b5 EXM Execution Mode (still in execution-phase, non_DMA_only)
+ b6 DIO Data Input/Output (0=CPU->FDC, 1=FDC->CPU) (see b7)
+ b7 RQM Request For Master (1=ready for next byte) (see b6 for direction)
+ */
private byte StatusMain;
///
/// Status Register 0
///
/*
- b0,1 US Unit Select (driveno during interrupt)
- b2 HD Head Address (head during interrupt)
- b3 NR Not Ready (drive not ready or non-existing 2nd head selected)
- b4 EC Equipment Check (drive failure or recalibrate failed (retry))
- b5 SE Seek End (Set if seek-command completed)
- b6,7 IC Interrupt Code (0=OK, 1=aborted:readfail/OK if EN, 2=unknown cmd
- or senseint with no int occured, 3=aborted:disc removed etc.)
- */
+ b0,1 US Unit Select (driveno during interrupt)
+ b2 HD Head Address (head during interrupt)
+ b3 NR Not Ready (drive not ready or non-existing 2nd head selected)
+ b4 EC Equipment Check (drive failure or recalibrate failed (retry))
+ b5 SE Seek End (Set if seek-command completed)
+ b6,7 IC Interrupt Code (0=OK, 1=aborted:readfail/OK if EN, 2=unknown cmd
+ or senseint with no int occured, 3=aborted:disc removed etc.)
+ */
private byte Status0;
///
/// Status Register 1
///
/*
- b0 MA Missing Address Mark (Sector_ID or DAM not found)
- b1 NW Not Writeable (tried to write/format disc with wprot_tab=on)
- b2 ND No Data (Sector_ID not found, CRC fail in ID_field)
- b3,6 0 Not used
- b4 OR Over Run (CPU too slow in execution-phase (ca. 26us/Byte))
- b5 DE Data Error (CRC-fail in ID- or Data-Field)
- b7 EN End of Track (set past most read/write commands) (see IC)
- */
+ b0 MA Missing Address Mark (Sector_ID or DAM not found)
+ b1 NW Not Writeable (tried to write/format disc with wprot_tab=on)
+ b2 ND No Data (Sector_ID not found, CRC fail in ID_field)
+ b3,6 0 Not used
+ b4 OR Over Run (CPU too slow in execution-phase (ca. 26us/Byte))
+ b5 DE Data Error (CRC-fail in ID- or Data-Field)
+ b7 EN End of Track (set past most read/write commands) (see IC)
+ */
private byte Status1;
///
/// Status Register 2
///
/*
- b0 MD Missing Address Mark in Data Field (DAM not found)
- b1 BC Bad Cylinder (read/programmed track-ID different and read-ID = FF)
- b2 SN Scan Not Satisfied (no fitting sector found)
- b3 SH Scan Equal Hit (equal)
- b4 WC Wrong Cylinder (read/programmed track-ID different) (see b1)
- b5 DD Data Error in Data Field (CRC-fail in data-field)
- b6 CM Control Mark (read/scan command found sector with deleted DAM)
- b7 0 Not Used
- */
+ b0 MD Missing Address Mark in Data Field (DAM not found)
+ b1 BC Bad Cylinder (read/programmed track-ID different and read-ID = FF)
+ b2 SN Scan Not Satisfied (no fitting sector found)
+ b3 SH Scan Equal Hit (equal)
+ b4 WC Wrong Cylinder (read/programmed track-ID different) (see b1)
+ b5 DD Data Error in Data Field (CRC-fail in data-field)
+ b6 CM Control Mark (read/scan command found sector with deleted DAM)
+ b7 0 Not Used
+ */
private byte Status2;
///
/// Status Register 3
///
/*
- b0,1 US Unit Select (pin 28,29 of FDC)
- b2 HD Head Address (pin 27 of FDC)
- b3 TS Two Side (0=yes, 1=no (!))
- b4 T0 Track 0 (on track 0 we are)
- b5 RY Ready (drive ready signal)
- b6 WP Write Protected (write protected)
- b7 FT Fault (if supported: 1=Drive failure)
- */
+ b0,1 US Unit Select (pin 28,29 of FDC)
+ b2 HD Head Address (pin 27 of FDC)
+ b3 TS Two Side (0=yes, 1=no (!))
+ b4 T0 Track 0 (on track 0 we are)
+ b5 RY Ready (drive ready signal)
+ b6 WP Write Protected (write protected)
+ b7 FT Fault (if supported: 1=Drive failure)
+ */
private byte Status3;
#endregion
@@ -385,8 +385,6 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
sectorSize = 0x80 << ActiveCommandParams.SectorSize;
}
- var mtc = maxTransferCap;
-
// get the current track
var track = ActiveDrive.Disk.DiskTracks.FirstOrDefault(a => a.TrackNumber == ActiveDrive.CurrentTrackID);
@@ -672,22 +670,13 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
switch (ActiveCommandParams.SectorSize)
{
case 1:
- if (CMD_FLAG_MF)
- maxTransferCap = 6656;
- else
- maxTransferCap = 3840;
+ maxTransferCap = CMD_FLAG_MF ? 6656 : 3840;
break;
case 2:
- if (CMD_FLAG_MF)
- maxTransferCap = 7680;
- else
- maxTransferCap = 4096;
+ maxTransferCap = CMD_FLAG_MF ? 7680 : 4096;
break;
case 3:
- if (CMD_FLAG_MF)
- maxTransferCap = 8192;
- else
- maxTransferCap = 4096;
+ maxTransferCap = CMD_FLAG_MF ? 8192 : 4096;
break;
}
@@ -2148,17 +2137,17 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
// second byte is the current track id
ResBuffer[1] = ActiveDrive.CurrentTrackID;
}
- /*
- else if (ActiveDrive.SeekStatus == SEEK_INTACKNOWLEDGED)
- {
- // DriveA interrupt has already been acknowledged
- ActiveDrive.SeekStatus = SEEK_IDLE;
+#if false
+ else if (ActiveDrive.SeekStatus == SEEK_INTACKNOWLEDGED)
+ {
+ // DriveA interrupt has already been acknowledged
+ ActiveDrive.SeekStatus = SEEK_IDLE;
- ResLength = 1;
- Status0 = 192;
- ResBuffer[0] = Status0;
- }
- */
+ ResLength = 1;
+ Status0 = 192;
+ ResBuffer[0] = Status0;
+ }
+#endif
else if (ActiveDrive.SeekStatus == SEEK_IDLE)
{
// SIS with no interrupt
@@ -2363,7 +2352,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
SetBit(MSR_EXM, ref StatusMain);
SetBit(MSR_CB, ref StatusMain);
- // overrun detection
+ // overrun detection
OverrunCounter++;
if (OverrunCounter >= 64)
{
@@ -2383,6 +2372,8 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
break;
}
+// if (!CheckTiming()) UnSetBit(MSR_EXM, ref StatusMain);
+
return StatusMain;
}
@@ -2474,7 +2465,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
//// we are in command phase
case Phase.Command:
// attempt to process this parameter byte
- //ProcessCommand(data);
+ //ProcessCommand(data);
ActiveCommand.CommandDelegate();
break;
//// we are in execution phase
@@ -2553,15 +2544,15 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
CMDIndex = CommandList.Count() - 1;
}
- /*
- if ((CMD_FLAG_MF && !ActiveCommand.MF) ||
- (CMD_FLAG_MT && !ActiveCommand.MT) ||
- (CMD_FLAG_SK && !ActiveCommand.SK))
- {
- // command byte included spurious bit 5,6 or 7 flags
- CMDIndex = CommandList.Count() - 1;
- }
- */
+#if false
+ if ((CMD_FLAG_MF && !ActiveCommand.MF) ||
+ (CMD_FLAG_MT && !ActiveCommand.MT) ||
+ (CMD_FLAG_SK && !ActiveCommand.SK))
+ {
+ // command byte included spurious bit 5,6 or 7 flags
+ CMDIndex = CommandList.Count() - 1;
+ }
+#endif
}
CommCounter = 0;
@@ -2571,14 +2562,14 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
// move to command phase
ActivePhase = Phase.Command;
- /*
- // check for invalid SIS
- if (ActiveInterrupt == InterruptState.None && CMDIndex == CC_SENSE_INTSTATUS)
- {
- CMDIndex = CC_INVALID;
- //ActiveCommand.CommandDelegate(InstructionState.StartResult);
- }
- */
+#if false
+ // check for invalid SIS
+ if (ActiveInterrupt == InterruptState.None && CMDIndex == CC_SENSE_INTSTATUS)
+ {
+ CMDIndex = CC_INVALID;
+ //ActiveCommand.CommandDelegate(InstructionState.StartResult);
+ }
+#endif
// set reslength
ResLength = ActiveCommand.ResultByteCount;
diff --git a/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/NECUPD765.FDD.cs b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/NECUPD765.FDD.cs
new file mode 100644
index 0000000000..5c2cd776a5
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/NECUPD765.FDD.cs
@@ -0,0 +1,189 @@
+using BizHawk.Common;
+using BizHawk.Common.NumberExtensions;
+using System;
+using System.Linq;
+
+namespace BizHawk.Emulation.Cores.Computers.CPCSpectrumBase
+{
+ ///
+ /// Floppy drive related stuff
+ ///
+ #region Attribution
+ /*
+ Implementation based on the information contained here:
+ http://www.cpcwiki.eu/index.php/765_FDC
+ and here:
+ http://www.cpcwiki.eu/imgs/f/f3/UPD765_Datasheet_OCRed.pdf
+ */
+ #endregion
+ public abstract partial class NECUPD765 : IFDDHost, INECUPD765
+ {
+ #region Drive State
+
+ ///
+ /// FDD Flag - motor on/off
+ ///
+ public bool FDD_FLAG_MOTOR;
+
+ bool INECUPD765.FDD_FLAG_MOTOR => FDD_FLAG_MOTOR;
+
+ ///
+ /// The index of the currently active disk drive
+ ///
+ public int DiskDriveIndex
+ {
+ get => _diskDriveIndex;
+ set
+ {
+ // when index is changed update the ActiveDrive
+ _diskDriveIndex = value;
+ ActiveDrive = DriveStates[_diskDriveIndex];
+ }
+ }
+ private int _diskDriveIndex = 0;
+
+ ///
+ /// The currently active drive
+ ///
+ private NECUPD765DriveState ActiveDrive;
+
+ ///
+ /// Array that holds state information for each possible drive
+ ///
+ private NECUPD765DriveState[] DriveStates = new NECUPD765DriveState[4];
+
+ #endregion
+
+ #region FDD Methods
+
+ protected abstract TDriveState ConstructDriveState(int driveID, NECUPD765 fdc);
+
+ ///
+ /// Initialization / reset of the floppy drive subsystem
+ ///
+ private void FDD_Init()
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ NECUPD765DriveState ds = ConstructDriveState(i, this);
+ DriveStates[i] = ds;
+ }
+ }
+
+ ///
+ /// Searches for the requested sector
+ ///
+ private FloppyDisk.Sector GetSector()
+ {
+ FloppyDisk.Sector sector = null;
+
+ // get the current track
+ var trk = ActiveDrive.Disk.DiskTracks[ActiveDrive.TrackIndex];
+
+ // get the current sector index
+ int index = ActiveDrive.SectorIndex;
+
+ // make sure this index exists
+ if (index > trk.Sectors.Length)
+ {
+ index = 0;
+ }
+
+ // index hole count
+ int iHole = 0;
+
+ // loop through the sectors in a track
+ // the loop ends with either the sector being found
+ // or the index hole being passed twice
+ while (iHole <= 2)
+ {
+ // does the requested sector match the current sector
+ if (trk.Sectors[index].SectorIDInfo.C == ActiveCommandParams.Cylinder &&
+ trk.Sectors[index].SectorIDInfo.H == ActiveCommandParams.Head &&
+ trk.Sectors[index].SectorIDInfo.R == ActiveCommandParams.Sector &&
+ trk.Sectors[index].SectorIDInfo.N == ActiveCommandParams.SectorSize)
+ {
+ // sector has been found
+ sector = trk.Sectors[index];
+
+ UnSetBit(SR2_BC, ref Status2);
+ UnSetBit(SR2_WC, ref Status2);
+ break;
+ }
+
+ // check for bad cylinder
+ if (trk.Sectors[index].SectorIDInfo.C == 255)
+ {
+ SetBit(SR2_BC, ref Status2);
+ }
+ // check for no cylinder
+ else if (trk.Sectors[index].SectorIDInfo.C != ActiveCommandParams.Cylinder)
+ {
+ SetBit(SR2_WC, ref Status2);
+ }
+
+ // incrememnt sector index
+ index++;
+
+ // have we reached the index hole?
+ if (trk.Sectors.Length <= index)
+ {
+ // wrap around
+ index = 0;
+ iHole++;
+ }
+ }
+
+ // search loop has completed and the sector may or may not have been found
+
+ // bad cylinder detected?
+ if (Status2.Bit(SR2_BC))
+ {
+ // remove WC
+ UnSetBit(SR2_WC, ref Status2);
+ }
+
+ // update sectorindex on drive
+ ActiveDrive.SectorIndex = index;
+
+ return sector;
+ }
+
+ #endregion
+
+ #region IFDDHost
+
+ // IFDDHost methods that fall through to the currently active drive
+
+ ///
+ /// Parses a new disk image and loads it into this floppy drive
+ ///
+ public void FDD_LoadDisk(byte[] diskData)
+ {
+ // we are only going to load into the first drive
+ DriveStates[0].FDD_LoadDisk(diskData);
+ }
+
+ ///
+ /// Ejects the current disk
+ ///
+ public void FDD_EjectDisk()
+ {
+ DriveStates[0].FDD_EjectDisk();
+ }
+
+ ///
+ /// Signs whether the current active drive has a disk inserted
+ ///
+ public bool FDD_IsDiskLoaded => DriveStates[DiskDriveIndex].FDD_IsDiskLoaded;
+
+ ///
+ /// Returns the disk object from drive 0
+ ///
+ public FloppyDisk DiskPointer => DriveStates[0].Disk;
+
+ public FloppyDisk Disk { get; set; }
+
+ #endregion
+ }
+}
diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/NECUPD765.IPortIODevice.cs b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/NECUPD765.IPortIODevice.cs
similarity index 89%
rename from BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/NECUPD765.IPortIODevice.cs
rename to BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/NECUPD765.IPortIODevice.cs
index 5f6e87f99a..ed50adff38 100644
--- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/NECUPD765.IPortIODevice.cs
+++ b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/NECUPD765.IPortIODevice.cs
@@ -3,20 +3,20 @@ using System.Collections;
using System.Collections.Generic;
using System.Text;
-namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
+namespace BizHawk.Emulation.Cores.Computers.CPCSpectrumBase
{
///
/// IPortIODevice
///
#region Attribution
/*
- Implementation based on the information contained here:
- http://www.cpcwiki.eu/index.php/765_FDC
- and here:
- http://www.cpcwiki.eu/imgs/f/f3/UPD765_Datasheet_OCRed.pdf
- */
+ Implementation based on the information contained here:
+ http://www.cpcwiki.eu/index.php/765_FDC
+ and here:
+ http://www.cpcwiki.eu/imgs/f/f3/UPD765_Datasheet_OCRed.pdf
+ */
#endregion
- public partial class NECUPD765 : IPortIODevice
+ public abstract partial class NECUPD765 : IPortIODevice
{
#region Dev Logging
@@ -31,15 +31,15 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
/*
- * Status read
- * Data write
- * Data read
- * CMD code
- * CMD string
- * MT flag
- * MK flag
- * SK flag
- * */
+ Status read
+ Data write
+ Data read
+ CMD code
+ CMD string
+ MT flag
+ MK flag
+ SK flag
+ */
private string[] workingArr = new string[3];
private void BuildCSVLine()
diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/NECUPS765.Static.cs b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/NECUPD765.Static.cs
similarity index 86%
rename from BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/NECUPS765.Static.cs
rename to BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/NECUPD765.Static.cs
index 9abd27e6a5..1dff759e22 100644
--- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/NECUPS765.Static.cs
+++ b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/NECUPD765.Static.cs
@@ -1,19 +1,19 @@
using System.Collections;
-namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
+namespace BizHawk.Emulation.Cores.Computers.CPCSpectrumBase
{
///
/// Static helper methods
///
#region Attribution
/*
- Implementation based on the information contained here:
- http://www.cpcwiki.eu/index.php/765_FDC
- and here:
- http://www.cpcwiki.eu/imgs/f/f3/UPD765_Datasheet_OCRed.pdf
- */
+ Implementation based on the information contained here:
+ http://www.cpcwiki.eu/index.php/765_FDC
+ and here:
+ http://www.cpcwiki.eu/imgs/f/f3/UPD765_Datasheet_OCRed.pdf
+ */
#endregion
- public partial class NECUPD765
+ public abstract partial class NECUPD765
{
///
/// Returns the specified bit value from supplied byte
diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/NECUPD765.Timing.cs b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/NECUPD765.Timing.cs
similarity index 69%
rename from BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/NECUPD765.Timing.cs
rename to BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/NECUPD765.Timing.cs
index c6fb76300b..f80e422288 100644
--- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/NECUPD765.Timing.cs
+++ b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/NECUPD765.Timing.cs
@@ -1,18 +1,18 @@
-namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
+namespace BizHawk.Emulation.Cores.Computers.CPCSpectrumBase
{
///
/// Timimng
///
#region Attribution
/*
- Implementation based on the information contained here:
- http://www.cpcwiki.eu/index.php/765_FDC
- and here:
- http://www.cpcwiki.eu/imgs/f/f3/UPD765_Datasheet_OCRed.pdf
- */
+ Implementation based on the information contained here:
+ http://www.cpcwiki.eu/index.php/765_FDC
+ and here:
+ http://www.cpcwiki.eu/imgs/f/f3/UPD765_Datasheet_OCRed.pdf
+ */
#endregion
- public partial class NECUPD765
+ public abstract partial class NECUPD765
{
///
/// The current Z80 cycle
@@ -43,7 +43,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
///
/// Defines the numbers of Z80 cycles per MS
///
- private long CPUCyclesPerMs;
+ protected long CPUCyclesPerMs;
///
/// The floppy drive emulated clock speed
@@ -73,23 +73,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
///
/// Initializes the timing routines
///
- private void TimingInit()
- {
- // z80 timing
- double frameSize = _machine.GateArray.FrameLength;
- double rRate = _machine.GateArray.Z80ClockSpeed / frameSize;
- long tPerSecond = (long)(frameSize * rRate);
- CPUCyclesPerMs = tPerSecond / 1000;
-
- // drive timing
- double dRate = DriveClock / frameSize;
- long dPerSecond = (long)(frameSize * dRate);
- DriveCyclesPerMs = dPerSecond / 1000;
-
- long TStatesPerDriveCycle = (long)((double)_machine.GateArray.Z80ClockSpeed / DriveClock);
- StatesPerDriveTick = TStatesPerDriveCycle;
-
- }
+ protected abstract void TimingInit();
///
/// Called by reads to the main status register
diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/NECUPD765.cs b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/NECUPD765.cs
similarity index 68%
rename from BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/NECUPD765.cs
rename to BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/NECUPD765.cs
index b876db870c..d4fcbfd24c 100644
--- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/NECUPD765.cs
+++ b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/NECUPD765.cs
@@ -1,27 +1,29 @@
using BizHawk.Common;
using System.Collections.Generic;
-namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
+namespace BizHawk.Emulation.Cores.Computers.CPCSpectrumBase
{
///
/// The NEC floppy disk controller (and floppy drive) found in the +3
///
#region Attribution
/*
- Implementation based on the information contained here:
- http://www.cpcwiki.eu/index.php/765_FDC
- and here:
- http://www.cpcwiki.eu/imgs/f/f3/UPD765_Datasheet_OCRed.pdf
- */
+ Implementation based on the information contained here:
+ http://www.cpcwiki.eu/index.php/765_FDC
+ and here:
+ http://www.cpcwiki.eu/imgs/f/f3/UPD765_Datasheet_OCRed.pdf
+ */
#endregion
- public partial class NECUPD765
+ public abstract partial class NECUPD765
+ where TMachine : CPCSpectrumBase
+ where TDriveState : NECUPD765DriveState
{
#region Devices
///
- /// The emulated spectrum machine
+ /// The emulated CPC or Spectrum machine
///
- private CPCBase _machine;
+ protected TMachine _machine;
#endregion
@@ -38,7 +40,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
///
/// Initialization routine
///
- public void Init(CPCBase machine)
+ public void Init(TMachine machine)
{
_machine = machine;
FDD_Init();
@@ -94,56 +96,56 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
{
CommandList = new List
{
- // read data
- new Command { CommandDelegate = UPD_ReadData, CommandCode = 0x06, MT = true, MF = true, SK = true, IsRead = true,
+ // read data
+ new Command { CommandDelegate = UPD_ReadData, CommandCode = 0x06, MT = true, MF = true, SK = true, IsRead = true,
Direction = CommandDirection.OUT, ParameterByteCount = 8, ResultByteCount = 7 },
- // read id
- new Command { CommandDelegate = UPD_ReadID, CommandCode = 0x0a, MF = true, IsRead = true,
+ // read id
+ new Command { CommandDelegate = UPD_ReadID, CommandCode = 0x0a, MF = true, IsRead = true,
Direction = CommandDirection.OUT, ParameterByteCount = 1, ResultByteCount = 7 },
- // specify
- new Command { CommandDelegate = UPD_Specify, CommandCode = 0x03,
+ // specify
+ new Command { CommandDelegate = UPD_Specify, CommandCode = 0x03,
Direction = CommandDirection.OUT, ParameterByteCount = 2, ResultByteCount = 0 },
- // read diagnostic
- new Command { CommandDelegate = UPD_ReadDiagnostic, CommandCode = 0x02, MF = true, SK = true, IsRead = true,
+ // read diagnostic
+ new Command { CommandDelegate = UPD_ReadDiagnostic, CommandCode = 0x02, MF = true, SK = true, IsRead = true,
Direction = CommandDirection.OUT, ParameterByteCount = 8, ResultByteCount = 7 },
- // scan equal
- new Command { CommandDelegate = UPD_ScanEqual, CommandCode = 0x11, MT = true, MF = true, SK = true, IsRead = true,
+ // scan equal
+ new Command { CommandDelegate = UPD_ScanEqual, CommandCode = 0x11, MT = true, MF = true, SK = true, IsRead = true,
Direction = CommandDirection.IN, ParameterByteCount = 8, ResultByteCount = 7 },
- // scan high or equal
- new Command { CommandDelegate = UPD_ScanHighOrEqual, CommandCode = 0x1d, MT = true, MF = true, SK = true, IsRead = true,
+ // scan high or equal
+ new Command { CommandDelegate = UPD_ScanHighOrEqual, CommandCode = 0x1d, MT = true, MF = true, SK = true, IsRead = true,
Direction = CommandDirection.IN, ParameterByteCount = 8, ResultByteCount = 7 },
- // scan low or equal
- new Command { CommandDelegate = UPD_ScanLowOrEqual, CommandCode = 0x19, MT = true, MF = true, SK = true, IsRead = true,
+ // scan low or equal
+ new Command { CommandDelegate = UPD_ScanLowOrEqual, CommandCode = 0x19, MT = true, MF = true, SK = true, IsRead = true,
Direction = CommandDirection.IN, ParameterByteCount = 8, ResultByteCount = 7 },
- // read deleted data
- new Command { CommandDelegate = UPD_ReadDeletedData, CommandCode = 0x0c, MT = true, MF = true, SK = true, IsRead = true,
+ // read deleted data
+ new Command { CommandDelegate = UPD_ReadDeletedData, CommandCode = 0x0c, MT = true, MF = true, SK = true, IsRead = true,
Direction = CommandDirection.OUT, ParameterByteCount = 8, ResultByteCount = 7 },
- // write data
- new Command { CommandDelegate = UPD_WriteData, CommandCode = 0x05, MT = true, MF = true, IsWrite = true,
+ // write data
+ new Command { CommandDelegate = UPD_WriteData, CommandCode = 0x05, MT = true, MF = true, IsWrite = true,
Direction = CommandDirection.IN, ParameterByteCount = 8, ResultByteCount = 7 },
- // write id
- new Command { CommandDelegate = UPD_WriteID, CommandCode = 0x0d, MF = true, IsWrite = true,
+ // write id
+ new Command { CommandDelegate = UPD_WriteID, CommandCode = 0x0d, MF = true, IsWrite = true,
Direction = CommandDirection.IN, ParameterByteCount = 5, ResultByteCount = 7 },
- // write deleted data
- new Command { CommandDelegate = UPD_WriteDeletedData, CommandCode = 0x09, MT = true, MF = true, IsWrite = true,
+ // write deleted data
+ new Command { CommandDelegate = UPD_WriteDeletedData, CommandCode = 0x09, MT = true, MF = true, IsWrite = true,
Direction = CommandDirection.IN, ParameterByteCount = 8, ResultByteCount = 7 },
- // seek
- new Command { CommandDelegate = UPD_Seek, CommandCode = 0x0f,
+ // seek
+ new Command { CommandDelegate = UPD_Seek, CommandCode = 0x0f,
Direction = CommandDirection.OUT, ParameterByteCount = 2, ResultByteCount = 0 },
- // recalibrate (seek track00)
- new Command { CommandDelegate = UPD_Recalibrate, CommandCode = 0x07,
+ // recalibrate (seek track00)
+ new Command { CommandDelegate = UPD_Recalibrate, CommandCode = 0x07,
Direction = CommandDirection.OUT, ParameterByteCount = 1, ResultByteCount = 0 },
- // sense interrupt status
- new Command { CommandDelegate = UPD_SenseInterruptStatus, CommandCode = 0x08,
+ // sense interrupt status
+ new Command { CommandDelegate = UPD_SenseInterruptStatus, CommandCode = 0x08,
Direction = CommandDirection.OUT, ParameterByteCount = 0, ResultByteCount = 2 },
- // sense drive status
- new Command { CommandDelegate = UPD_SenseDriveStatus, CommandCode = 0x04,
+ // sense drive status
+ new Command { CommandDelegate = UPD_SenseDriveStatus, CommandCode = 0x04,
Direction = CommandDirection.OUT, ParameterByteCount = 1, ResultByteCount = 1 },
- // version
- new Command { CommandDelegate = UPD_Version, CommandCode = 0x10,
+ // version
+ new Command { CommandDelegate = UPD_Version, CommandCode = 0x10,
Direction = CommandDirection.OUT, ParameterByteCount = 0, ResultByteCount = 1 },
- // invalid
- new Command { CommandDelegate = UPD_Invalid, CommandCode = 0x00,
+ // invalid
+ new Command { CommandDelegate = UPD_Invalid, CommandCode = 0x00,
Direction = CommandDirection.OUT, ParameterByteCount = 0, ResultByteCount = 1 },
};
}
diff --git a/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/NECUPD765DriveState.cs b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/NECUPD765DriveState.cs
new file mode 100644
index 0000000000..9d51d6da1b
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Hardware/Disk/NECUPD765DriveState.cs
@@ -0,0 +1,651 @@
+using System.Linq;
+
+using BizHawk.Common;
+
+namespace BizHawk.Emulation.Cores.Computers.CPCSpectrumBase
+{
+ ///
+ /// Holds specfic state information about a drive
+ ///
+ public abstract class NECUPD765DriveState : IFDDHost
+ {
+ #region State
+
+ ///
+ /// The drive ID from an FDC perspective
+ ///
+ public int ID;
+
+ ///
+ /// Signs whether this drive ready
+ /// TRUE if both drive exists and has a disk inserted
+ ///
+ public bool FLAG_READY
+ {
+ get
+ {
+ if (!FDD_IsDiskLoaded || Disk.GetTrackCount() == 0 || !FDC.FDD_FLAG_MOTOR)
+ return false;
+ else
+ return true;
+ }
+ }
+
+ ///
+ /// Disk is write protected (TRUE BY DEFAULT)
+ ///
+ public bool FLAG_WRITEPROTECT = false;
+
+ ///
+ /// Storage for seek steps
+ /// One step for each indexpulse (track index) until seeked track
+ ///
+ public int SeekCounter;
+
+ ///
+ /// Seek status
+ ///
+ public int SeekStatus;
+
+ ///
+ /// Age counter
+ ///
+ public int SeekAge;
+
+ ///
+ /// The current side
+ ///
+ public byte CurrentSide;
+
+ ///
+ /// The current track index in the DiskTracks array
+ ///
+ public byte TrackIndex;
+
+ ///
+ /// The track ID of the current cylinder
+ ///
+ public byte CurrentTrackID
+ {
+ get
+ {
+ // default invalid track
+ int id = 0xff;
+
+ if (Disk == null)
+ return (byte)id;
+
+ if (Disk.DiskTracks.Count() == 0)
+ return (byte)id;
+
+ if (TrackIndex >= Disk.GetTrackCount())
+ TrackIndex = 0;
+ else if (TrackIndex < 0)
+ TrackIndex = 0;
+
+ var track = Disk.DiskTracks[TrackIndex];
+
+ id = track.TrackNumber;
+
+ return (byte)id;
+ }
+ set
+ {
+ for (int i = 0; i < Disk.GetTrackCount(); i++)
+ {
+ if (Disk.DiskTracks[i].TrackNumber == value)
+ {
+ TrackIndex = (byte)i;
+ break;
+ }
+ }
+ }
+ }
+
+
+ ///
+ /// The new track that the drive is seeking to
+ /// (used in seek operations)
+ ///
+ public int SeekingTrack;
+
+ ///
+ /// The current sector index in the Sectors array
+ ///
+ public int SectorIndex;
+
+ ///
+ /// The currently loaded floppy disk
+ ///
+ public FloppyDisk Disk { get; set; }
+
+ ///
+ /// The parent controller
+ ///
+ private INECUPD765 FDC;
+
+ #endregion
+
+ #region Lookups
+
+ ///
+ /// TRUE if we are on track 0
+ ///
+ public bool FLAG_TRACK0 => TrackIndex == 0;
+
+ #endregion
+
+ #region Public Methods
+
+#if false
+ ///
+ /// Moves the head across the disk cylinders
+ ///
+ public void MoveHead(SkipDirection direction, int cylinderCount)
+ {
+ // get total tracks
+ int trackCount = Disk.DiskTracks.Count();
+
+ int trk = 0;
+
+ switch (direction)
+ {
+ case SkipDirection.Increment:
+ trk = (int)CurrentTrack + cylinderCount;
+ if (trk >= trackCount)
+ {
+ // past the last track
+ trk = trackCount - 1;
+ }
+ else if (trk < 0)
+ trk = 0;
+ break;
+ case SkipDirection.Decrement:
+ trk = (int)CurrentTrack - cylinderCount;
+ if (trk < 0)
+ {
+ // before the first track
+ trk = 0;
+ }
+ else if (trk >= trackCount)
+ trk = trackCount - 1;
+ break;
+ }
+
+ // move the head
+ CurrentTrack = (byte)trk;
+ }
+#endif
+
+#if false
+ ///
+ /// Finds a supplied sector
+ ///
+ public FloppyDisk.Sector FindSector(ref byte[] resBuffer, CommandParameters prms)
+ {
+ int index =CurrentSector;
+ int lc = 0;
+ FloppyDisk.Sector sector = null;
+
+ bool found = false;
+
+ do
+ {
+ sector = Disk.DiskTracks[CurrentTrack].Sectors[index];
+ if (sector != null && sector.SectorID == prms.Sector)
+ {
+ // sector found
+ // check for data errors
+ if ((sector.Status1 & 0x20) != 0 || (sector.Status2 & 0x20) != 0)
+ {
+ // data errors found
+ }
+ found = true;
+ break;
+ }
+
+ // sector doesnt match
+ var c = Disk.DiskTracks[CurrentTrack].Sectors[index].TrackNumber;
+ if (c == 255)
+ {
+ // bad cylinder
+ resBuffer[RS_ST2] |= 0x02;
+ }
+ else if (prms.Cylinder != c)
+ {
+ // cylinder mismatch
+ resBuffer[RS_ST2] |= 0x10;
+ }
+
+ // increment index
+ index++;
+
+ if (index >= Disk.DiskTracks[CurrentTrack].NumberOfSectors)
+ {
+ // out of bounds
+ index = 0;
+ lc++;
+ }
+
+ } while (lc < 2);
+
+ if ((resBuffer[RS_ST2] & 0x02) != 0)
+ {
+ // bad cylinder set - remove no cylinder
+ UnSetBit(SR2_WC, ref resBuffer[RS_ST2]);
+ }
+
+ // update current sector
+ CurrentSector = index;
+
+ if (found)
+ return sector;
+ else
+ return null;
+ }
+
+
+ ///
+ /// Populates a result buffer
+ ///
+ public void FillResult(ref byte[] resBuffer, CHRN chrn)
+ {
+ // clear results
+ resBuffer[RS_ST0] = 0;
+ resBuffer[RS_ST1] = 0;
+ resBuffer[RS_ST2] = 0;
+ resBuffer[RS_C] = 0;
+ resBuffer[RS_H] = 0;
+ resBuffer[RS_R] = 0;
+ resBuffer[RS_N] = 0;
+
+ if (chrn == null)
+ {
+ // no chrn supplied
+ resBuffer[RS_ST0] = ST0;
+ resBuffer[RS_ST1] = 0;
+ resBuffer[RS_ST2] = 0;
+ resBuffer[RS_C] = 0;
+ resBuffer[RS_H] = 0;
+ resBuffer[RS_R] = 0;
+ resBuffer[RS_N] = 0;
+ }
+ }
+
+
+
+ ///
+ /// Populates the result buffer with ReadID data
+ ///
+ public void ReadID(ref byte[] resBuffer)
+ {
+ if (CheckDriveStatus() == false)
+ {
+ // drive not ready
+ resBuffer[RS_ST0] = ST0;
+ return;
+ }
+
+ var track = Disk.DiskTracks.Where(a => a.TrackNumber == CurrentTrack).FirstOrDefault();
+
+ if (track != null && track.NumberOfSectors > 0)
+ {
+ // formatted track
+
+ // get the current sector
+ int index = CurrentSector;
+
+ // is the index out of bounds?
+ if (index >= track.NumberOfSectors)
+ {
+ // reset the index
+ index = 0;
+ }
+
+ // read the sector data
+ var data = track.Sectors[index];
+ resBuffer[RS_C] = data.TrackNumber;
+ resBuffer[RS_H] = data.SideNumber;
+ resBuffer[RS_R] = data.SectorID;
+ resBuffer[RS_N] = data.SectorSize;
+
+ resBuffer[RS_ST0] = ST0;
+
+ // increment the current sector
+ CurrentSector = index + 1;
+ return;
+ }
+ else
+ {
+ // unformatted track?
+ resBuffer[RS_C] = FDC.CommBuffer[CM_C];
+ resBuffer[RS_H] = FDC.CommBuffer[CM_H];
+ resBuffer[RS_R] = FDC.CommBuffer[CM_R];
+ resBuffer[RS_N] = FDC.CommBuffer[CM_N];
+
+ SetBit(SR0_IC0, ref ST0);
+ resBuffer[RS_ST0] = ST0;
+ resBuffer[RS_ST1] = 0x01;
+ return;
+ }
+ }
+#endif
+
+#if false
+ ///
+ /// The drive performs a seek operation if necessary
+ /// Return value TRUE indicates seek complete
+ ///
+ public void DoSeek()
+ {
+ if (CurrentState != DriveMainState.Recalibrate &&
+ CurrentState != DriveMainState.Seek)
+ {
+ // no seek/recalibrate has been asked for
+ return;
+ }
+
+ if (GetBit(ID, FDC.StatusMain))
+ {
+ // drive is already seeking
+ return;
+ }
+
+ RunSeekCycle();
+ }
+
+ ///
+ /// Runs a seek cycle
+ ///
+ public void RunSeekCycle()
+ {
+ for (;;)
+ {
+ switch (SeekState)
+ {
+ // seek or recalibrate has been requested
+ case SeekSubState.Idle:
+
+ if (CurrentState == DriveMainState.Recalibrate)
+ {
+ // recalibrate always seeks to track 0
+ SeekingTrack = 0;
+ }
+ SeekState = SeekSubState.MoveInit;
+
+ // mark drive as busy
+ // this should be cleared by SIS command
+ SetBit(ID, ref FDC.StatusMain);
+
+ break;
+
+ // setup for the head move
+ case SeekSubState.MoveInit:
+
+ if (CurrentTrack == SeekingTrack)
+ {
+ // we are already at the required track
+ if (CurrentState == DriveMainState.Recalibrate &&
+ !FLAG_TRACK0)
+ {
+ // recalibration fail
+ SeekIntState = SeekIntStatus.Abnormal;
+
+ // raise seek interrupt
+ FDC.ActiveInterrupt = InterruptState.Seek;
+
+ // unset DB bit
+ UnSetBit(ID, ref FDC.StatusMain);
+
+ // equipment check
+ SetBit(SR0_EC, ref FDC.Status0);
+
+ SeekState = SeekSubState.PerformCompletion;
+ break;
+ }
+
+ if (CurrentState == DriveMainState.Recalibrate &&
+ FLAG_TRACK0)
+ {
+ // recalibration success
+ SeekIntState = SeekIntStatus.Normal;
+
+ // raise seek interrupt
+ FDC.ActiveInterrupt = InterruptState.Seek;
+
+ // unset DB bit
+ UnSetBit(ID, ref FDC.StatusMain);
+
+ SeekState = SeekSubState.PerformCompletion;
+ break;
+ }
+ }
+
+ // check for error
+ if (IntStatus >= IC_ABORTED_DISCREMOVED || Disk == null)
+ {
+ // drive not ready
+ FLAG_READY = false;
+
+ // drive not ready
+ SeekIntState = SeekIntStatus.DriveNotReady;
+
+ // cancel any interrupt
+ FDC.ActiveInterrupt = InterruptState.None;
+
+ // unset DB bit
+ UnSetBit(ID, ref FDC.StatusMain);
+
+ SeekState = SeekSubState.PerformCompletion;
+ break;
+ }
+
+ if (SeekCounter > 1)
+ {
+ // not ready to seek yet
+ SeekCounter--;
+ return;
+ }
+
+ if (FDC.SRT < 1 && CurrentTrack != SeekingTrack)
+ {
+ SeekState = SeekSubState.MoveImmediate;
+ break;
+ }
+
+ // head move
+ SeekState = SeekSubState.HeadMove;
+
+ break;
+
+ case SeekSubState.HeadMove:
+
+ // do the seek
+ SeekCounter = FDC.SRT;
+
+ if (CurrentTrack < SeekingTrack)
+ {
+ // we are seeking forward
+ var delta = SeekingTrack - CurrentTrack;
+ MoveHead(SkipDirection.Increment, 1);
+ }
+ else if (CurrentTrack > SeekingTrack)
+ {
+ // we are seeking backward
+ var delta = CurrentTrack - SeekingTrack;
+ MoveHead(SkipDirection.Decrement, 1);
+ }
+
+ // should the seek be completed now?
+ if (CurrentTrack == SeekingTrack)
+ {
+ SeekState = SeekSubState.PerformCompletion;
+ break;
+ }
+
+ // seek not finished yet
+ return;
+
+ // seek emulation processed immediately
+ case SeekSubState.MoveImmediate:
+
+ if (CurrentTrack < SeekingTrack)
+ {
+ // we are seeking forward
+ var delta = SeekingTrack - CurrentTrack;
+ MoveHead(SkipDirection.Increment, delta);
+
+ }
+ else if (CurrentTrack > SeekingTrack)
+ {
+ // we are seeking backward
+ var delta = CurrentTrack - SeekingTrack;
+ MoveHead(SkipDirection.Decrement, delta);
+ }
+
+ SeekState = SeekSubState.PerformCompletion;
+ break;
+
+ case SeekSubState.PerformCompletion:
+ SeekDone();
+ SeekState = SeekSubState.SeekCompleted;
+ break;
+
+ case SeekSubState.SeekCompleted:
+ // seek has already completed
+ return;
+ }
+ }
+ }
+
+ ///
+ /// Called when a seek operation has completed
+ ///
+ public void SeekDone()
+ {
+ SeekCounter = 0;
+ SeekingTrack = CurrentTrack;
+
+ // generate ST0 register data
+
+ // get only the IC bits
+ IntStatus &= IC_ABORTED_DISCREMOVED;
+
+ // drive ready?
+ if (!FLAG_READY)
+ {
+ SetBit(SR0_NR, ref IntStatus);
+ SetBit(SR0_EC, ref IntStatus);
+
+ // are we recalibrating?
+ if (CurrentState == DriveMainState.Recalibrate)
+ {
+ SetBit(SR0_EC, ref IntStatus);
+ }
+ }
+
+ // set seek end
+ SetBit(SR0_SE, ref IntStatus);
+ /*
+ // head address
+ if (CurrentSide > 0)
+ {
+ SetBit(SR0_HD, ref IntStatus);
+
+ // drive only supports 1 head
+ // set the EC bit
+ SetBit(SR0_EC, ref IntStatus);
+ }
+ */
+ // UnitSelect
+ SetUnitSelect(ID, ref IntStatus);
+
+ // move to none state
+ //CurrentState = DriveMainState.None;
+
+ //SeekState = SeekSubState.SeekCompleted;
+
+ // set the seek interrupt flag for this drive
+ // this will be cleared at the next successful senseint
+ FLAG_SEEK_INTERRUPT = true;
+
+ //CurrentState = DriveMainState.None;
+
+ }
+#endif
+
+ #endregion
+
+ #region Construction
+
+ public NECUPD765DriveState(int driveID, INECUPD765 fdc)
+ {
+ ID = driveID;
+ FDC = fdc;
+ }
+
+ #endregion
+
+ #region IFDDHost
+
+ ///
+ /// Parses a new disk image and loads it into this floppy drive
+ ///
+ public abstract void FDD_LoadDisk(byte[] diskData);
+
+ ///
+ /// Ejects the current disk
+ ///
+ public void FDD_EjectDisk()
+ {
+ Disk = null;
+ //FLAG_READY = false;
+ }
+
+ ///
+ /// Signs whether the current active drive has a disk inserted
+ ///
+ public bool FDD_IsDiskLoaded
+ {
+ get
+ {
+ if (Disk != null)
+ return true;
+ else
+ return false;
+ }
+ }
+
+ #endregion
+
+ #region StateSerialization
+
+ public void SyncState(Serializer ser)
+ {
+ ser.Sync(nameof(ID), ref ID);
+ ser.Sync(nameof(FLAG_WRITEPROTECT), ref FLAG_WRITEPROTECT);
+ //ser.Sync(nameof(FLAG_DISKCHANGED), ref FLAG_DISKCHANGED);
+ //ser.Sync(nameof(FLAG_RECALIBRATING), ref FLAG_RECALIBRATING);
+ //ser.Sync(nameof(FLAG_SEEK_INTERRUPT), ref FLAG_SEEK_INTERRUPT);
+ //ser.Sync(nameof(IntStatus), ref IntStatus);
+ //ser.Sync(nameof(ST0), ref ST0);
+ //ser.Sync(nameof(RecalibrationCounter), ref RecalibrationCounter);
+ ser.Sync(nameof(SeekCounter), ref SeekCounter);
+ ser.Sync(nameof(SeekStatus), ref SeekStatus);
+ ser.Sync(nameof(SeekAge), ref SeekAge);
+ ser.Sync(nameof(CurrentSide), ref CurrentSide);
+ //ser.Sync(nameof(CurrentTrack), ref CurrentTrack);
+ ser.Sync(nameof(TrackIndex), ref TrackIndex);
+ ser.Sync(nameof(SeekingTrack), ref SeekingTrack);
+ //ser.Sync(nameof(CurrentSector), ref CurrentSector);
+ ser.Sync(nameof(SectorIndex), ref SectorIndex);
+ //ser.Sync(nameof(RAngles), ref RAngles);
+ //ser.Sync(nameof(DataPointer), ref DataPointer);
+ //ser.SyncEnum(nameof(CurrentState), ref CurrentState);
+ //ser.SyncEnum(nameof(SeekState), ref SeekState);
+ //ser.SyncEnum(nameof(SeekIntState), ref SeekIntState);
+ }
+
+ #endregion
+ }
+}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/DiskType.cs b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Media/Disk/DiskType.cs
similarity index 90%
rename from BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/DiskType.cs
rename to BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Media/Disk/DiskType.cs
index d403ec6ffa..76691f17a9 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/DiskType.cs
+++ b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Media/Disk/DiskType.cs
@@ -1,5 +1,5 @@
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
+namespace BizHawk.Emulation.Cores.Computers.CPCSpectrumBase
{
///
/// The different disk formats ZXHawk currently supports
diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Disk/FloppyDisk.cs b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Media/Disk/FloppyDisk.cs
similarity index 80%
rename from BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Disk/FloppyDisk.cs
rename to BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Media/Disk/FloppyDisk.cs
index bbafc189bc..295d80ed6b 100644
--- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Disk/FloppyDisk.cs
+++ b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Media/Disk/FloppyDisk.cs
@@ -4,7 +4,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
-namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
+namespace BizHawk.Emulation.Cores.Computers.CPCSpectrumBase
{
///
/// This abstract class defines a logical floppy disk
@@ -307,7 +307,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
// TrackID is consistent between the sectors although is usually high (233, 237 etc)
// SideID is fairly random looking but with all IDs being even
// SectorID is also fairly random looking but contains both odd and even numbers
- //
+ //
// There doesnt appear to be any CRC errors in this track, but the sector size is always 1 (256 bytes)
// Each sector contains different filler byte
// Once track 0 is loaded the CPU completely reads all the sectors in this track one-by-one.
@@ -402,104 +402,104 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
return false;
}
- /*
- ///
- /// Should be run at the end of the ParseDisk process
- /// If speedlock is detected the flag is set in the disk image
- ///
- protected virtual void SpeedlockDetection()
- {
+#if false
+ ///
+ /// Should be run at the end of the ParseDisk process
+ /// If speedlock is detected the flag is set in the disk image
+ ///
+ protected virtual void SpeedlockDetection()
+ {
- if (DiskTracks.Length == 0)
- return;
+ if (DiskTracks.Length == 0)
+ return;
- // check for speedlock copyright notice
- string ident = Encoding.ASCII.GetString(DiskData, 0x100, 0x1400);
- if (!ident.ToUpper().Contains("SPEEDLOCK"))
- {
- // speedlock not found
- return;
- }
+ // check for speedlock copyright notice
+ string ident = Encoding.ASCII.GetString(DiskData, 0x100, 0x1400);
+ if (!ident.ToUpper().Contains("SPEEDLOCK"))
+ {
+ // speedlock not found
+ return;
+ }
- // get cylinder 0
- var cyl = DiskTracks[0];
+ // get cylinder 0
+ var cyl = DiskTracks[0];
- // get sector with ID=2
- var sec = cyl.Sectors.Where(a => a.SectorID == 2).FirstOrDefault();
+ // get sector with ID=2
+ var sec = cyl.Sectors.Where(a => a.SectorID == 2).FirstOrDefault();
- if (sec == null)
- return;
+ if (sec == null)
+ return;
- // check for already multiple weak copies
- if (sec.ContainsMultipleWeakSectors || sec.SectorData.Length != 0x80 << sec.SectorSize)
- return;
+ // check for already multiple weak copies
+ if (sec.ContainsMultipleWeakSectors || sec.SectorData.Length != 0x80 << sec.SectorSize)
+ return;
- // check for invalid crcs in sector 2
- if (sec.Status1.Bit(5) || sec.Status2.Bit(5))
- {
- Protection = ProtectionType.Speedlock;
- }
- else
- {
- return;
- }
+ // check for invalid crcs in sector 2
+ if (sec.Status1.Bit(5) || sec.Status2.Bit(5))
+ {
+ Protection = ProtectionType.Speedlock;
+ }
+ else
+ {
+ return;
+ }
- // we are going to create a total of 5 weak sector copies
- // keeping the original copy
- byte[] origData = sec.SectorData.ToArray();
- List data = new List();
- //Random rnd = new Random();
+ // we are going to create a total of 5 weak sector copies
+ // keeping the original copy
+ byte[] origData = sec.SectorData.ToArray();
+ List data = new List();
+ //Random rnd = new Random();
- for (int i = 0; i < 6; i++)
- {
- for (int s = 0; s < origData.Length; s++)
- {
- if (i == 0)
- {
- data.Add(origData[s]);
- continue;
- }
+ for (int i = 0; i < 6; i++)
+ {
+ for (int s = 0; s < origData.Length; s++)
+ {
+ if (i == 0)
+ {
+ data.Add(origData[s]);
+ continue;
+ }
- // deterministic 'random' implementation
- int n = origData[s] + i + 1;
- if (n > 0xff)
- n = n - 0xff;
- else if (n < 0)
- n = 0xff + n;
+ // deterministic 'random' implementation
+ int n = origData[s] + i + 1;
+ if (n > 0xff)
+ n = n - 0xff;
+ else if (n < 0)
+ n = 0xff + n;
- byte nByte = (byte)n;
+ byte nByte = (byte)n;
- if (s < 336)
- {
- // non weak data
- data.Add(origData[s]);
- }
- else if (s < 511)
- {
- // weak data
- data.Add(nByte);
- }
- else if (s == 511)
- {
- // final sector byte
- data.Add(nByte);
- }
- else
- {
- // speedlock sector should not be more than 512 bytes
- // but in case it is just do non weak
- data.Add(origData[i]);
- }
- }
- }
+ if (s < 336)
+ {
+ // non weak data
+ data.Add(origData[s]);
+ }
+ else if (s < 511)
+ {
+ // weak data
+ data.Add(nByte);
+ }
+ else if (s == 511)
+ {
+ // final sector byte
+ data.Add(nByte);
+ }
+ else
+ {
+ // speedlock sector should not be more than 512 bytes
+ // but in case it is just do non weak
+ data.Add(origData[i]);
+ }
+ }
+ }
- // commit the sector data
- sec.SectorData = data.ToArray();
- sec.ContainsMultipleWeakSectors = true;
- sec.ActualDataByteLength = data.Count();
+ // commit the sector data
+ sec.SectorData = data.ToArray();
+ sec.ContainsMultipleWeakSectors = true;
+ sec.ActualDataByteLength = data.Count();
- }
- */
+ }
+#endif
///
/// Returns the track count for the disk
@@ -587,8 +587,18 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
public byte NumberOfSectors { get; set; }
public byte GAP3Length { get; set; }
public byte FillerByte { get; set; }
- public Sector[] Sectors { get; set; }
+ public virtual Sector[] Sectors { get; set; }
+ #region UDI
+
+ public byte TrackType { get; set; }
+ public int TLEN { get; set; }
+ public int CLEN => TLEN / 8 + (TLEN % 8 / 7) / 8;
+ public byte[] TrackData { get; set; }
+
+ #endregion
+
+#if false
///
/// Presents a contiguous byte array of all sector data for this track
/// (including any multiple weak/random data)
@@ -607,6 +617,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
return list.ToArray();
}
}
+#endif
}
public class Sector
@@ -637,10 +648,8 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
{
return ActualDataByteLength;
}
- else
- {
- return ActualDataByteLength / (ActualDataByteLength / (0x80 << SectorSize));
- }
+
+ return ActualDataByteLength / (ActualDataByteLength / (0x80 << SectorSize));
}
}
@@ -667,10 +676,8 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
return l.ToArray();
}
- else
- {
- return SectorData;
- }
+
+ return SectorData;
}
else
{
@@ -688,14 +695,14 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
return res;
/*
- int copies = ActualDataByteLength / (0x80 << SectorSize);
- Random rnd = new Random();
- int r = rnd.Next(0, copies - 1);
- int step = r * (0x80 << SectorSize);
- byte[] res = new byte[(0x80 << SectorSize)];
- Array.Copy(SectorData, step, res, 0, 0x80 << SectorSize);
- return res;
- */
+ int copies = ActualDataByteLength / (0x80 << SectorSize);
+ Random rnd = new Random();
+ int r = rnd.Next(0, copies - 1);
+ int step = r * (0x80 << SectorSize);
+ byte[] res = new byte[(0x80 << SectorSize)];
+ Array.Copy(SectorData, step, res, 0, 0x80 << SectorSize);
+ return res;
+ */
}
}
}
diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Tape/TapeCommand.cs b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Media/Tape/TapeCommand.cs
similarity index 79%
rename from BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Tape/TapeCommand.cs
rename to BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Media/Tape/TapeCommand.cs
index 5af5c32109..d9891206cd 100644
--- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Tape/TapeCommand.cs
+++ b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Media/Tape/TapeCommand.cs
@@ -1,5 +1,5 @@
-namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
+namespace BizHawk.Emulation.Cores.Computers.CPCSpectrumBase
{
///
/// Represents the possible commands that can be raised from each tape block
diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Tape/TapeDataBlock.cs b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Media/Tape/TapeDataBlock.cs
similarity index 86%
rename from BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Tape/TapeDataBlock.cs
rename to BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Media/Tape/TapeDataBlock.cs
index 75dcc3995c..aea7c494a3 100644
--- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Tape/TapeDataBlock.cs
+++ b/BizHawk.Emulation.Cores/Computers/CPCSpectrumBase/Media/Tape/TapeDataBlock.cs
@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Linq;
-namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
+namespace BizHawk.Emulation.Cores.Computers.CPCSpectrumBase
{
///
/// Represents a tape block
@@ -52,31 +52,31 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
set => _blockData = value;
}
- /*
- ///
- /// An array of bytearray encoded strings (stored in this format for easy Bizhawk serialization)
- /// Its basically tape information
- ///
- private byte[][] _tapeDescriptionData;
+#if false
+ ///
+ /// An array of bytearray encoded strings (stored in this format for easy Bizhawk serialization)
+ /// Its basically tape information
+ ///
+ private byte[][] _tapeDescriptionData;
- ///
- /// Returns the Tape Description Data in a human readable format
- ///
- public List TapeDescriptionData
- {
- get
- {
- List data = new List();
+ ///
+ /// Returns the Tape Description Data in a human readable format
+ ///
+ public List TapeDescriptionData
+ {
+ get
+ {
+ List data = new List();
- foreach (byte[] b in _tapeDescriptionData)
- {
- data.Add(Encoding.ASCII.GetString(b));
- }
+ foreach (byte[] b in _tapeDescriptionData)
+ {
+ data.Add(Encoding.ASCII.GetString(b));
+ }
- return data;
- }
- }
- */
+ return data;
+ }
+ }
+#endif
#region Block Meta Data
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Abstraction/IFDDHost.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Abstraction/IFDDHost.cs
deleted file mode 100644
index 2586d05d61..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Abstraction/IFDDHost.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// Defines an object that can load a floppy disk image
- ///
- public interface IFDDHost
- {
- ///
- /// The currently inserted diskimage
- ///
- FloppyDisk Disk { get; set; }
-
- ///
- /// Parses a new disk image and loads it into this floppy drive
- ///
- void FDD_LoadDisk(byte[] diskData);
-
- ///
- /// Ejects the current disk
- ///
- void FDD_EjectDisk();
-
- ///
- /// Signs whether the current active drive has a disk inserted
- ///
- bool FDD_IsDiskLoaded { get; }
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Abstraction/IJoystick.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Abstraction/IJoystick.cs
deleted file mode 100644
index 6ea7acd897..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Abstraction/IJoystick.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// Represents a spectrum joystick
- ///
- public interface IJoystick
- {
- ///
- /// The type of joystick
- ///
- JoystickType JoyType { get; }
-
- ///
- /// Array of all the possibly button press names
- ///
- string[] ButtonCollection { get; set; }
-
- ///
- /// The player number that this controller is currently assigned to
- ///
- int PlayerNumber { get; set; }
-
- ///
- /// Sets the joystick line based on key pressed
- ///
- void SetJoyInput(string key, bool isPressed);
-
- ///
- /// Gets the state of a particular joystick binding
- ///
- bool GetJoyInput(string key);
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Abstraction/IKeyboard.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Abstraction/IKeyboard.cs
index ad1cc4acc2..df93be37a4 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Abstraction/IKeyboard.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Abstraction/IKeyboard.cs
@@ -1,4 +1,5 @@
using BizHawk.Common;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Abstraction/IPSG.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Abstraction/IPSG.cs
index cd50120130..bb27454976 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Abstraction/IPSG.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Abstraction/IPSG.cs
@@ -1,5 +1,6 @@
using BizHawk.Common;
using BizHawk.Emulation.Common;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Abstraction/IPortIODevice.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Abstraction/IPortIODevice.cs
deleted file mode 100644
index 7a24c2d1ba..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Abstraction/IPortIODevice.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// Represents a device that utilizes port IN & OUT
- ///
- public interface IPortIODevice
- {
- ///
- /// Device responds to an IN instruction
- ///
- bool ReadPort(ushort port, ref int result);
-
- ///
- /// Device responds to an OUT instruction
- ///
- bool WritePort(ushort port, int result);
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Datacorder/DatacorderDevice.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Datacorder/DatacorderDevice.cs
index 909df491aa..a85c6c6a43 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Datacorder/DatacorderDevice.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Datacorder/DatacorderDevice.cs
@@ -4,6 +4,8 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
+
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
using BizHawk.Emulation.Cores.Sound;
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/CHRN.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/CHRN.cs
deleted file mode 100644
index a3f7bf3fd4..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/CHRN.cs
+++ /dev/null
@@ -1,180 +0,0 @@
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// Used for the sector CHRN structure
- ///
- public class CHRN
- {
- ///
- /// Track
- ///
- public byte C { get; set; }
-
- ///
- /// Side
- ///
- public byte H { get; set; }
-
- ///
- /// Sector ID
- ///
- public byte R { get; set; }
-
- ///
- /// Sector Size
- ///
- public byte N { get; set; }
-
- ///
- /// Status register 1
- ///
- private byte _flag1;
- public byte Flag1
- {
- get => _flag1;
- set => _flag1 = value;
- }
-
- ///
- /// Status register 2
- ///
- private byte _flag2;
- public byte Flag2
- {
- get => _flag2;
- set => _flag2 = value;
- }
-
- ///
- /// Used to store the last transmitted/received data bytes
- ///
- public byte[] DataBytes { get; set; }
-
- ///
- /// ID for the read/write data command
- ///
- public int DataID { get; set; }
-
- #region Helper Methods
-
- ///
- /// Missing Address Mark (Sector_ID or DAM not found)
- ///
- public bool ST1MA
- {
- get => NECUPD765.GetBit(0, _flag1);
- set
- {
- if (value) { NECUPD765.SetBit(0, ref _flag1); }
- else { NECUPD765.UnSetBit(0, ref _flag1); }
- }
- }
-
- ///
- /// No Data (Sector_ID not found, CRC fail in ID_field)
- ///
- public bool ST1ND
- {
- get => NECUPD765.GetBit(2, _flag1);
- set
- {
- if (value) { NECUPD765.SetBit(2, ref _flag1); }
- else { NECUPD765.UnSetBit(2, ref _flag1); }
- }
- }
-
- ///
- /// Data Error (CRC-fail in ID- or Data-Field)
- ///
- public bool ST1DE
- {
- get => NECUPD765.GetBit(5, _flag1);
- set
- {
- if (value) { NECUPD765.SetBit(5, ref _flag1); }
- else { NECUPD765.UnSetBit(5, ref _flag1); }
- }
- }
-
- ///
- /// End of Track (set past most read/write commands) (see IC)
- ///
- public bool ST1EN
- {
- get => NECUPD765.GetBit(7, _flag1);
- set
- {
- if (value) { NECUPD765.SetBit(7, ref _flag1); }
- else { NECUPD765.UnSetBit(7, ref _flag1); }
- }
- }
-
- ///
- /// Missing Address Mark in Data Field (DAM not found)
- ///
- public bool ST2MD
- {
- get => NECUPD765.GetBit(0, _flag2);
- set
- {
- if (value) { NECUPD765.SetBit(0, ref _flag2); }
- else { NECUPD765.UnSetBit(0, ref _flag2); }
- }
- }
-
- ///
- /// Bad Cylinder (read/programmed track-ID different and read-ID = FF)
- ///
- public bool ST2BC
- {
- get => NECUPD765.GetBit(1, _flag2);
- set
- {
- if (value) { NECUPD765.SetBit(1, ref _flag2); }
- else { NECUPD765.UnSetBit(1, ref _flag2); }
- }
- }
-
- ///
- /// Wrong Cylinder (read/programmed track-ID different) (see b1)
- ///
- public bool ST2WC
- {
- get => NECUPD765.GetBit(4, _flag2);
- set
- {
- if (value) { NECUPD765.SetBit(4, ref _flag2); }
- else { NECUPD765.UnSetBit(4, ref _flag2); }
- }
- }
-
- ///
- /// Data Error in Data Field (CRC-fail in data-field)
- ///
- public bool ST2DD
- {
- get => NECUPD765.GetBit(5, _flag2);
- set
- {
- if (value) { NECUPD765.SetBit(5, ref _flag2); }
- else { NECUPD765.UnSetBit(5, ref _flag2); }
- }
- }
-
- ///
- /// Control Mark (read/scan command found sector with deleted DAM)
- ///
- public bool ST2CM
- {
- get => NECUPD765.GetBit(6, _flag2);
- set
- {
- if (value) { NECUPD765.SetBit(6, ref _flag2); }
- else { NECUPD765.UnSetBit(6, ref _flag2); }
- }
- }
-
- #endregion
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/NECUPD765.Definitions.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/NECUPD765.Definitions.cs
deleted file mode 100644
index 351e993631..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/NECUPD765.Definitions.cs
+++ /dev/null
@@ -1,826 +0,0 @@
-using BizHawk.Common;
-using System;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// Definitions
- ///
- #region Attribution
- /*
- Implementation based on the information contained here:
- http://www.cpcwiki.eu/index.php/765_FDC
- and here:
- http://www.cpcwiki.eu/imgs/f/f3/UPD765_Datasheet_OCRed.pdf
- */
- #endregion
- public partial class NECUPD765
- {
- #region Enums
-
- ///
- /// Defines the current phase of the controller
- ///
- private enum Phase
- {
- ///
- /// FDC is in an idle state, awaiting the next initial command byte
- ///
- Idle,
-
- ///
- /// FDC is in a state waiting for the next command instruction
- /// A command consists of a command byte (eventually including the MF, MK, SK bits), and up to eight parameter bytes
- ///
- Command,
-
- ///
- /// During this phase, the actual data is transferred (if any). Usually that are the data bytes for the read/written sector(s), except for the Format Track Command,
- /// in that case four bytes for each sector are transferred
- ///
- Execution,
-
- ///
- /// Returns up to seven result bytes (depending on the command) that are containing status information. The Recalibrate and Seek Track commands do not return result bytes directly,
- /// instead the program must wait until the Main Status Register signalizes that the command has been completed, and then it must (!) send a
- /// Sense Interrupt State command to 'terminate' the Seek/Recalibrate command.
- ///
- Result
- }
-
- ///
- /// The lifecycle of an instruction
- /// Similar to phase, this describes the current 'sub-phase' we are in when dealing with an instruction
- ///
- private enum InstructionState
- {
- ///
- /// FDC has received a command byte and is currently reading parameter bytes from the data bus
- ///
- ReceivingParameters,
-
- ///
- /// All parameter bytes have been received. This phase allows any neccessary setup before instruction execution starts
- ///
- PreExecution,
-
- ///
- /// The start of instruction execution. This may end up with the FDC moving into result phase,
- /// but also may also prepare the way for further processing to occur later in execution phase
- ///
- StartExecute,
-
- ///
- /// Data is read or written in execution phase
- ///
- ExecutionReadWrite,
-
- ///
- /// Execution phase is well under way. This state primarily deals with data transfer between CPU and FDC
- ///
- ExecutionWrite,
-
- ///
- /// Execution phase is well under way. This state primarily deals with data transfer between FDC and CPU
- ///
- ExecutionRead,
-
- ///
- /// Execution has finished and results bytes are ready to be read by the CPU
- /// Initial result setup
- ///
- StartResult,
-
- ///
- /// Result processing
- ///
- ProcessResult,
-
- ///
- /// Results are being sent
- ///
- SendingResults,
-
- ///
- /// Final cleanup tasks when the instruction has fully completed
- ///
- Completed
-
- }
-
- ///
- /// Represents internal interrupt state of the FDC
- ///
- public enum InterruptState
- {
- ///
- /// There is no interrupt
- ///
- None,
- ///
- /// Execution interrupt
- ///
- Execution,
- ///
- /// Result interrupt
- ///
- Result,
- ///
- /// Ready interrupt
- ///
- Ready,
- ///
- /// Seek interrupt
- ///
- Seek
- }
-
- ///
- /// Possible main states that each drive can be in
- ///
- public enum DriveMainState
- {
- ///
- /// Drive is not doing anything
- ///
- None,
- ///
- /// Seek operation is in progress
- ///
- Seek,
- ///
- /// Recalibrate operation is in progress
- ///
- Recalibrate,
- ///
- /// A scan data operation is in progress
- ///
- Scan,
- ///
- /// A read ID operation is in progress
- ///
- ReadID,
- ///
- /// A read data operation is in progress
- ///
- ReadData,
- ///
- /// A read diagnostic (read track) operation is in progress
- ///
- ReadDiagnostic,
- ///
- /// A write id (format track) operation is in progress
- ///
- WriteID,
- ///
- /// A write data operation is in progress
- ///
- WriteData,
- }
-
- ///
- /// State information during a seek/recalibration operation
- ///
- public enum SeekSubState
- {
- ///
- /// Seek hasnt started yet
- ///
- Idle,
- ///
- /// Delayed
- ///
- Wait,
- ///
- /// Setup for head move
- ///
- MoveInit,
- ///
- /// Seek is currently happening
- ///
- HeadMove,
- ///
- /// Head move with no delay
- ///
- MoveImmediate,
- ///
- /// Ready to complete
- ///
- PerformCompletion,
- ///
- /// Seek operation has completed
- ///
- SeekCompleted
- }
-
- ///
- /// Seek int code
- ///
- public enum SeekIntStatus
- {
- Normal,
- Abnormal,
- DriveNotReady,
- }
-
- ///
- /// The direction of a specific command
- ///
- private enum CommandDirection
- {
- ///
- /// Data flows from UPD765A to Z80
- ///
- OUT,
- ///
- /// Data flows from Z80 to UPD765A
- ///
- IN
- }
-
- ///
- /// Enum defining the different types of result that can be returned
- ///
- private enum ResultType
- {
- ///
- /// Standard 7 result bytes are returned
- ///
- Standard,
- ///
- /// 1 byte returned - ST3
- /// (used for SenseDriveStatus)
- ///
- ST3,
- ///
- /// 1 byte returned - ST0
- /// (used for version & invalid)
- ///
- ST0,
- ///
- /// 2 bytes returned for sense interrupt status command
- /// ST0
- /// CurrentCylinder
- ///
- Interrupt
- }
-
- ///
- /// Possible list of encountered drive status errors
- ///
- public enum Status
- {
- ///
- /// No error detected
- ///
- None,
- ///
- /// An undefined error has been detected
- ///
- Undefined,
- ///
- /// Drive is not ready
- ///
- DriveNotReady,
- ///
- /// Invalid command received
- ///
- Invalid,
- ///
- /// The disk has its write protection tab enabled
- ///
- WriteProtected,
- ///
- /// The requested sector has not been found
- ///
- SectorNotFound
- }
-
- ///
- /// Represents the direction that the head is moving over the cylinders
- /// Increment: Track number increasing (head moving from outside of disk inwards)
- /// Decrement: Track number decreasing (head moving from inside of disk outwards)
- ///
- public enum SkipDirection
- {
- Increment,
- Decrement
- }
-
- #endregion
-
- #region Constants
-
- // Command Instruction Constants
- // Designates the default postitions within the cmdbuffer array
-
- public const int CM_HEAD = 0;
- ///
- /// C - Track
- ///
- public const int CM_C = 1;
- ///
- /// H - Side
- ///
- public const int CM_H = 2;
- ///
- /// R - Sector ID
- ///
- public const int CM_R = 3;
- ///
- /// N - Sector size
- ///
- public const int CM_N = 4;
- ///
- /// EOT - End of track
- ///
- public const int CM_EOT = 5;
- ///
- /// GPL - Gap length
- ///
- public const int CM_GPL = 6;
- ///
- /// DTL - Data length
- ///
- public const int CM_DTL = 7;
- ///
- /// STP - Step
- ///
- public const int CM_STP = 7;
-
- // Result Instruction Constants
- // Designates the default postitions within the cmdbuffer array
-
- ///
- /// Status register 0
- ///
- public const int RS_ST0 = 0;
- ///
- /// Status register 1
- ///
- public const int RS_ST1 = 1;
- ///
- /// Status register 2
- ///
- public const int RS_ST2 = 2;
- ///
- /// C - Track
- ///
- public const int RS_C = 3;
- ///
- /// H - Side
- ///
- public const int RS_H = 4;
- ///
- /// R - Sector ID
- ///
- public const int RS_R = 5;
- ///
- /// N - Sector size
- ///
- public const int RS_N = 6;
-
- // Main Status Register Constants
- // Designates the bit positions within the Main status register
-
- ///
- /// FDD0 Busy (seek/recalib active, until succesful sense intstat)
- /// FDD number 0 is in the seek mode. If any of the DnB bits IS set FDC will not accept read or write command.
- ///
- public const int MSR_D0B = 0;
- ///
- /// FDD1 Busy (seek/recalib active, until succesful sense intstat)
- /// FDD number 1 is in the seek mode. If any of the DnB bits IS set FDC will not accept read or write command.
- ///
- public const int MSR_D1B = 1;
- ///
- /// FDD2 Busy (seek/recalib active, until succesful sense intstat)
- /// FDD number 2 is in the seek mode. If any of the DnB bits IS set FDC will not accept read or write command.
- ///
- public const int MSR_D2B = 2;
- ///
- /// FDD3 Busy (seek/recalib active, until succesful sense intstat)
- /// FDD number 3 is in the seek mode. If any of the DnB bits IS set FDC will not accept read or write command.
- ///
- public const int MSR_D3B = 3;
- ///
- /// FDC Busy (still in command-, execution- or result-phase)
- /// A Read or Write command is in orocess. (FDC Busy) FDC will not accept any other command
- ///
- public const int MSR_CB = 4;
- ///
- /// Execution Mode (still in execution-phase, non_DMA_only)
- /// This bit is set only during execution ohase (Execution Mode) in non-DMA mode When DB5 goes low, execution phase has ended and result phase has started.It operates only during
- /// non-DMA mode of operation
- ///
- public const int MSR_EXM = 5;
- ///
- /// Data Input/Output (0=CPU->FDC, 1=FDC->CPU) (see b7)
- /// Indicates direction of data transfer between FDC and data regrster If DIO = 1, then transfer is from data register to the
- /// processor.If DIO = 0, then transfer is from the processor to data register
- ///
- public const int MSR_DIO = 6;
- ///
- /// Request For Master (1=ready for next byte) (see b6 for direction)
- /// ndicates data register IS ready to send or receive data to or from the processor Both bits DIO and RQM should be
- /// used to perform the hand-shaking functions of “ready” and “directron” to the processor
- ///
- public const int MSR_RQM = 7;
-
- // Status Register 0 Constants
- // Designates the bit positions within the status register 0
-
- ///
- /// Unit Select (driveno during interrupt)
- /// This flag IS used to indicate a drive unit number at interrupt
- ///
- public const int SR0_US0 = 0;
-
- ///
- /// Unit Select (driveno during interrupt)
- /// This flag IS used to indicate a drive unit number at interrupt
- ///
- public const int SR0_US1 = 1;
-
- ///
- /// Head Address (head during interrupt)
- /// State of the head at interrupt
- ///
- public const int SR0_HD = 2;
-
- ///
- /// Not Ready (drive not ready or non-existing 2nd head selected)
- /// Not Ready - When the FDD IS in the not-ready state and a Read or Write command IS Issued, this
- /// flag IS set If a Read or Write command is issued to side 1 of a single-sided drive, then this flag IS set
- ///
- public const int SR0_NR = 3;
-
- ///
- /// Equipment Check (drive failure or recalibrate failed (retry))
- /// Equipment check - If a fault srgnal IS received from the FDD, or if the track 0 srgnal fails to occur after 77
- /// step pulses(Recalibrate Command) then this flag is set
- ///
- public const int SR0_EC = 4;
-
- ///
- /// Seek End (Set if seek-command completed)
- /// Seek end - When the FDC completes the Seek command, this flag IS set lo 1 (high)
- ///
- public const int SR0_SE = 5;
-
- ///
- /// Interrupt Code (low byte)
- /// Interrupt Code (0=OK, 1=aborted:readfail/OK if EN, 2=unknown cmd
- /// or senseint with no int occured, 3=aborted:disc removed etc.)
- ///
- public const int SR0_IC0 = 6;
-
- ///
- /// Interrupt Code (high byte)
- /// Interrupt Code (0=OK, 1=aborted:readfail/OK if EN, 2=unknown cmd
- /// or senseint with no int occured, 3=aborted:disc removed etc.)
- ///
- public const int SR0_IC1 = 7;
-
- // Status Register 1 Constants
- // Designates the bit positions within the status register 1
-
- ///
- /// Missing Address Mark (Sector_ID or DAM not found)
- /// Missing address mark - This bit is set i f the FDC does not detect the IDAM before 2 index pulses It is also set if
- /// the FDC cannot find the DAM or DDAM after the IDAM i s found.MD bit of ST2 is also set at this time
- ///
- public const int SR1_MA = 0;
-
- ///
- /// Not Writeable (tried to write/format disc with wprot_tab=on)
- /// Not writable (write protect) - During execution of Write Data, Write Deleted Data or Write ID command. if the FDC
- /// detect: a write protect srgnal from the FDD.then this flag is Set
- ///
- public const int SR1_NW = 1;
-
- ///
- /// No Data
- /// No Data (Sector_ID not found, CRC fail in ID_field)
- ///
- /// During execution of Read Data. Read Deleted Data Write Data.Write Deleted Data or Scan command, if the FDC cannot find
- /// the sector specified in the IDR(2)Register, this flag i s set.
- ///
- /// During execution of the Read ID command. if the FDC cannot read the ID field without an error, then this flag IS set
- ///
- /// During execution of the Read Diagnostic command. if the starting sector cannot be found, then this flag is set
- ///
- public const int SR1_ND = 2;
-
- ///
- /// Over Run (CPU too slow in execution-phase (ca. 26us/Byte))
- /// Overrun - If the FDC i s not serviced by the host system during data transfers within a certain time interval.this flaa i s set
- ///
- public const int SR1_OR = 4;
-
- ///
- /// Data Error (CRC-fail in ID- or Data-Field)
- /// Data error - When the FDC detects a CRC(1) error in either the ID field or the data field, this flag is set
- ///
- public const int SR1_DE = 5;
-
- ///
- /// End of Track (set past most read/write commands) (see IC)
- /// End of cylinder - When the FDC tries to access a sector beyond the final sector of a cylinder, this flag I S set
- ///
- public const int SR1_EN = 7;
-
- // Status Register 2 Constants
- // Designates the bit positions within the status register 2
-
- ///
- /// Missing Address Mark in Data Field (DAM not found)
- /// Missing address mark - When data IS read from the medium, i f the FDC cannot find a data address mark or deleted
- /// data address mark, then this flag is set
- ///
- public const int SR2_MD = 0;
-
- ///
- /// Bad Cylinder (read/programmed track-ID different and read-ID = FF)
- /// Bad cylinder - This bit i s related to the ND bit. and when the contents of C on the medium is different
- /// from that stored i n the IDR and the contents of C IS FFH.then this flag IS set
- ///
- public const int SR2_BC = 1;
-
- ///
- /// Scan Not Satisfied (no fitting sector found)
- /// Scan not satisfied - During execution of the Scan command, i f the F D cannot find a sector on the cylinder
- /// which meets the condition.then this flag i s set
- ///
- public const int SR2_SN = 2;
-
- ///
- /// Scan Equal Hit (equal)
- /// Scan equal hit - During execution of the Scan command. i f the condition of “equal” is satisfied, this flag i s set
- ///
- public const int SR2_SH = 3;
-
- ///
- /// Wrong Cylinder (read/programmed track-ID different) (see b1)
- /// Wrong cylinder - This bit IS related to the ND bit, and when the contents of C(3) on the medium is different
- /// from that stored i n the IDR.this flag is set
- ///
- public const int SR2_WC = 4;
-
- ///
- /// Data Error in Data Field (CRC-fail in data-field)
- /// Data error in data field - If the FDC detects a CRC error i n the data field then this flag is set
- ///
- public const int SR2_DD = 5;
-
- ///
- /// Control Mark (read/scan command found sector with deleted DAM)
- /// Control mark - During execution of the Read Data or Scan command, if the FDC encounters a sector
- /// which contains a deleted data address mark, this flag is set Also set if DAM is
- /// found during Read Deleted Data
- ///
- public const int SR2_CM = 6;
-
- // Status Register 3 Constants
- // Designates the bit positions within the status register 3
-
- ///
- /// Unit select 0
- /// Unit Select (pin 28,29 of FDC)
- ///
- public const int SR3_US0 = 0;
-
- ///
- /// Unit select 1
- /// Unit Select (pin 28,29 of FDC)
- ///
- public const int SR3_US1 = 1;
-
- ///
- /// Head address (side select)
- /// Head Address (pin 27 of FDC)
- ///
- public const int SR3_HD = 2;
-
- ///
- /// Two Side (0=yes, 1=no (!))
- /// Two-side - This bit IS used to indicate the status of the two-side signal from the FDD
- ///
- public const int SR3_TS = 3;
-
- ///
- /// Track 0 (on track 0 we are)
- /// Track 0 - This bit IS used to indicate the status of the track 0 signal from the FDD
- ///
- public const int SR3_T0 = 4;
-
- ///
- /// Ready - status of the ready signal from the fdd
- /// Ready (drive ready signal)
- ///
- public const int SR3_RY = 5;
-
- ///
- /// Write Protected (write protected)
- /// Write protect - status of the wp signal from the fdd
- ///
- public const int SR3_WP = 6;
-
- ///
- /// Fault - This bit is used to indicate the status of the fault signal from the FDD
- /// Fault (if supported: 1=Drive failure)
- ///
- public const int SR3_FT = 7;
-
- // Interrupt Code Masks
-
- ///
- /// 1 = aborted:readfail / OK if EN (end of track)
- ///
- public const byte IC_OK = 0x00;
-
- ///
- /// 1 = aborted:readfail / OK if EN (end of track)
- ///
- public const byte IC_ABORTED_RF_OKEN = 0x40;
-
- ///
- /// 2 = unknown cmd or senseint with no int occured
- ///
- public const byte IC_NO_INT_OCCURED = 0x80;
-
- ///
- /// 3 = aborted:disc removed etc
- ///
- public const byte IC_ABORTED_DISCREMOVED = 0xC0;
-
- // command code constants
- public const int CC_READ_DATA = 0x06;
- public const int CC_READ_ID = 0x0a;
- public const int CC_SPECIFY = 0x03;
- public const int CC_READ_DIAGNOSTIC = 0x02;
- public const int CC_SCAN_EQUAL = 0x11;
- public const int CC_SCAN_HIGHOREQUAL = 0x1d;
- public const int CC_SCAN_LOWOREQUAL = 0x19;
- public const int CC_READ_DELETEDDATA = 0x0c;
- public const int CC_WRITE_DATA = 0x05;
- public const int CC_WRITE_ID = 0x0d;
- public const int CC_WRITE_DELETEDDATA = 0x09;
- public const int CC_SEEK = 0x0f;
- public const int CC_RECALIBRATE = 0x07;
- public const int CC_SENSE_INTSTATUS = 0x08;
- public const int CC_SENSE_DRIVESTATUS = 0x04;
- public const int CC_VERSION = 0x10;
- public const int CC_INVALID = 0x00;
-
- // drive seek state constants
- public const int SEEK_IDLE = 0;
- public const int SEEK_SEEK = 1;
- public const int SEEK_RECALIBRATE = 2;
- // seek interrupt
- public const int SEEK_INTACKNOWLEDGED = 3;
- public const int SEEK_NORMALTERM = 4;
- public const int SEEK_ABNORMALTERM = 5;
- public const int SEEK_DRIVENOTREADY = 6;
-
- #endregion
-
- #region Classes & Structs
-
- ///
- /// Class that holds information about a specific command
- ///
- private class Command
- {
-// ///
-// /// Mask to remove potential parameter bits (5,6, and or 7) in order to identify the command
-// ///
-// public int BitMask { get; set; }
- ///
- /// The command code after bitmask has been applied
- ///
- public int CommandCode { get; set; }
- ///
- /// The number of bytes that make up the full command
- ///
- public int ParameterByteCount { get; set; }
- ///
- /// The number of result bytes that will be generated from the command
- ///
- public int ResultByteCount { get; set; }
- ///
- /// The command direction
- /// IN - Z80 to UPD765A
- /// OUT - UPD765A to Z80
- ///
- public CommandDirection Direction { get; set; }
- ///
- /// Command makes use of the MT bit
- ///
- public bool MT;
- ///
- /// Command makes use of the MF bit
- ///
- public bool MF;
- ///
- /// Command makes use of the SK bit
- ///
- public bool SK;
- ///
- /// Read/Write command that is READ
- ///
- public bool IsRead;
- ///
- /// Read/Write command that is WRITE
- ///
- public bool IsWrite;
-
- ///
- /// Delegate function that is called by this command
- /// bool 1: EXECUTE - if TRUE the command will be executed. if FALSE the method will instead parse commmand parameter bytes
- /// bool 2: RESULT - if TRUE
- ///
- public Action CommandDelegate { get; set; }
- }
-
- ///
- /// Storage for command parameters
- ///
- public class CommandParameters
- {
- ///
- /// The requested drive
- ///
- public byte UnitSelect;
- ///
- /// The requested physical side
- ///
- public byte Side;
- ///
- /// The requested track (C)
- ///
- public byte Cylinder;
- ///
- /// The requested head (H)
- ///
- public byte Head;
- ///
- /// The requested sector (R)
- ///
- public byte Sector;
- ///
- /// The specified sector size (N)
- ///
- public byte SectorSize;
- ///
- /// The end of track or last sector value (EOT)
- ///
- public byte EOT;
- ///
- /// Gap3 length (GPL)
- ///
- public byte Gap3Length;
- ///
- /// Data length (DTL) - When N is defined as 00, DTL stands for the data length
- /// which users are going to read out or write into the sector
- ///
- public byte DTL;
-
- ///
- /// Clear down
- ///
- public void Reset()
- {
- UnitSelect = 0;
- Side = 0;
- Cylinder = 0;
- Head = 0;
- Sector = 0;
- SectorSize = 0;
- EOT = 0;
- Gap3Length = 0;
- DTL = 0;
- }
-
- public void SyncState(Serializer ser)
- {
- ser.BeginSection("ActiveCmdParams");
-
- ser.Sync(nameof(UnitSelect), ref UnitSelect);
- ser.Sync(nameof(Side), ref Side);
- ser.Sync(nameof(Cylinder), ref Cylinder);
- ser.Sync(nameof(Head), ref Head);
- ser.Sync(nameof(Sector), ref Sector);
- ser.Sync(nameof(SectorSize), ref SectorSize);
- ser.Sync(nameof(EOT), ref EOT);
- ser.Sync(nameof(Gap3Length), ref Gap3Length);
- ser.Sync(nameof(DTL), ref DTL);
-
- ser.EndSection();
- }
- }
-
-
- #endregion
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/NECUPD765.FDC.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/NECUPD765.FDC.cs
deleted file mode 100644
index 094e3eab19..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/NECUPD765.FDC.cs
+++ /dev/null
@@ -1,2840 +0,0 @@
-using BizHawk.Common.NumberExtensions;
-using System.Collections;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// FDC State and Methods
- ///
- #region Attribution
- /*
- Implementation based on the information contained here:
- http://www.cpcwiki.eu/index.php/765_FDC
- and here:
- http://www.cpcwiki.eu/imgs/f/f3/UPD765_Datasheet_OCRed.pdf
- */
- #endregion
- public partial class NECUPD765
- {
- #region Controller State
-
- ///
- /// Signs whether the drive is active
- ///
- public bool DriveLight;
-
- ///
- /// Collection of possible commands
- ///
- private List CommandList;
-
- ///
- /// State parameters relating to the Active command
- ///
- public CommandParameters ActiveCommandParams = new CommandParameters();
-
- ///
- /// The current active phase of the controller
- ///
- private Phase ActivePhase = Phase.Command;
-
- ///
- /// The currently active interrupt
- ///
- private InterruptState ActiveInterrupt = InterruptState.None;
- ///
- /// Command buffer
- /// This does not contain the initial command byte (only parameter bytes)
- ///
- private byte[] CommBuffer = new byte[9];
-
- ///
- /// Current index within the command buffer
- ///
- private int CommCounter = 0;
-
- ///
- /// Initial command byte flag
- /// Bit7 Multi Track (continue multi-sector-function on other head)
- ///
- private bool CMD_FLAG_MT;
-
- ///
- /// Initial command byte flag
- /// Bit6 MFM-Mode-Bit (Default 1=Double Density)
- ///
- private bool CMD_FLAG_MF;
-
- ///
- /// Initial command byte flag
- /// Bit5 Skip-Bit (set if secs with deleted DAM shall be skipped)
- ///
- private bool CMD_FLAG_SK;
-
- ///
- /// Step Rate Time (supplied via the specify command)
- /// SRT stands for the steooino rate for the FDD ( 1 to 16 ms in 1 ms increments).
- /// Stepping rate applies to all drives(FH= 1ms, EH= 2ms, etc.).
- ///
- private int SRT;
-
- ///
- /// Keeps track of the current SRT state
- ///
- private int SRT_Counter;
-
- ///
- /// Head Unload Time (supplied via the specify command)
- /// HUT stands for the head unload time after a Read or Write operation has occurred
- /// (16 to 240 ms in 16 ms Increments)
- ///
- private int HUT;
-
- ///
- /// Keeps track of the current HUT state
- ///
- private int HUT_Counter;
-
- ///
- /// Head load Time (supplied via the specify command)
- /// HLT stands for the head load time in the FDD (2 to 254 ms in 2 ms Increments)
- ///
- private int HLT;
-
- ///
- /// Keeps track of the current HLT state
- ///
- private int HLT_Counter;
-
- ///
- /// Non-DMA Mode (supplied via the specify command)
- /// ND stands for operation in the non-DMA mode
- ///
- private bool ND;
-
- ///
- /// In lieu of actual timing, this will count status reads in execution phase
- /// where the CPU hasnt actually read any bytes
- ///
- private int OverrunCounter;
-
- ///
- /// Contains result bytes in result phase
- ///
- private byte[] ResBuffer = new byte[7];
-
- ///
- /// Contains sector data to be written/read in execution phase
- ///
- private byte[] ExecBuffer = new byte[0x8000];
-
- ///
- /// Interrupt result buffer
- /// Persists (and returns when needed) the last result data when a sense interrupt status command happens
- ///
- private byte[] InterruptResultBuffer = new byte[2];
-
- ///
- /// Current index within the result buffer
- ///
- private int ResCounter = 0;
-
- ///
- /// The byte length of the currently active command
- /// This may or may not be the same as the actual command resultbytes value
- ///
- private int ResLength = 0;
-
- ///
- /// Index for sector data within the result buffer
- ///
- private int ExecCounter = 0;
-
- ///
- /// The length of the current exec command
- ///
- private int ExecLength = 0;
-
- ///
- /// The last write byte that was received during execution phase
- ///
- private byte LastSectorDataWriteByte = 0;
-
- ///
- /// The last read byte to be sent during execution phase
- ///
- private byte LastSectorDataReadByte = 0;
-
- ///
- /// The last parameter byte that was written to the FDC
- ///
- private byte LastByteReceived = 0;
-
- ///
- /// Delay for reading sector
- ///
- private int SectorDelayCounter = 0;
-
- ///
- /// The phyical sector ID
- ///
- private int SectorID = 0;
-
- ///
- /// Counter for index pulses
- ///
- private int IndexPulseCounter;
-
- ///
- /// Specifies the index of the currently selected command (in the CommandList)
- ///
- public int CMDIndex
- {
- get => _cmdIndex;
- set
- {
- _cmdIndex = value;
- ActiveCommand = CommandList[_cmdIndex];
- }
- }
- private int _cmdIndex;
-
- ///
- /// The currently active command
- ///
- private Command ActiveCommand;
-
- ///
- /// Main status register (accessed via reads to port 0x2ffd)
- ///
- /*
- b0..3 DB FDD0..3 Busy (seek/recalib active, until succesful sense intstat)
- b4 CB FDC Busy (still in command-, execution- or result-phase)
- b5 EXM Execution Mode (still in execution-phase, non_DMA_only)
- b6 DIO Data Input/Output (0=CPU->FDC, 1=FDC->CPU) (see b7)
- b7 RQM Request For Master (1=ready for next byte) (see b6 for direction)
- */
- private byte StatusMain;
-
- ///
- /// Status Register 0
- ///
- /*
- b0,1 US Unit Select (driveno during interrupt)
- b2 HD Head Address (head during interrupt)
- b3 NR Not Ready (drive not ready or non-existing 2nd head selected)
- b4 EC Equipment Check (drive failure or recalibrate failed (retry))
- b5 SE Seek End (Set if seek-command completed)
- b6,7 IC Interrupt Code (0=OK, 1=aborted:readfail/OK if EN, 2=unknown cmd
- or senseint with no int occured, 3=aborted:disc removed etc.)
- */
- private byte Status0;
-
- ///
- /// Status Register 1
- ///
- /*
- b0 MA Missing Address Mark (Sector_ID or DAM not found)
- b1 NW Not Writeable (tried to write/format disc with wprot_tab=on)
- b2 ND No Data (Sector_ID not found, CRC fail in ID_field)
- b3,6 0 Not used
- b4 OR Over Run (CPU too slow in execution-phase (ca. 26us/Byte))
- b5 DE Data Error (CRC-fail in ID- or Data-Field)
- b7 EN End of Track (set past most read/write commands) (see IC)
- */
- private byte Status1;
-
- ///
- /// Status Register 2
- ///
- /*
- b0 MD Missing Address Mark in Data Field (DAM not found)
- b1 BC Bad Cylinder (read/programmed track-ID different and read-ID = FF)
- b2 SN Scan Not Satisfied (no fitting sector found)
- b3 SH Scan Equal Hit (equal)
- b4 WC Wrong Cylinder (read/programmed track-ID different) (see b1)
- b5 DD Data Error in Data Field (CRC-fail in data-field)
- b6 CM Control Mark (read/scan command found sector with deleted DAM)
- b7 0 Not Used
- */
- private byte Status2;
-
- ///
- /// Status Register 3
- ///
- /*
- b0,1 US Unit Select (pin 28,29 of FDC)
- b2 HD Head Address (pin 27 of FDC)
- b3 TS Two Side (0=yes, 1=no (!))
- b4 T0 Track 0 (on track 0 we are)
- b5 RY Ready (drive ready signal)
- b6 WP Write Protected (write protected)
- b7 FT Fault (if supported: 1=Drive failure)
- */
- private byte Status3;
-
- #endregion
-
- #region UPD Internal Functions
-
- #region READ Commands
-
- ///
- /// Read Data
- /// COMMAND: 8 parameter bytes
- /// EXECUTION: Data transfer between FDD and FDC
- /// RESULT: 7 result bytes
- ///
- private void UPD_ReadData()
- {
- switch (ActivePhase)
- {
- //----------------------------------------
- // FDC is waiting for a command byte
- //----------------------------------------
- case Phase.Idle:
- break;
-
- //----------------------------------------
- // Receiving command parameter bytes
- //----------------------------------------
- case Phase.Command:
-
- // store the parameter in the command buffer
- CommBuffer[CommCounter] = LastByteReceived;
-
- // process parameter byte
- ParseParamByteStandard(CommCounter);
-
- // increment command parameter counter
- CommCounter++;
-
- // was that the last parameter byte?
- if (CommCounter == ActiveCommand.ParameterByteCount)
- {
- // all parameter bytes received - setup for execution phase
-
- // clear exec buffer and status registers
- ClearExecBuffer();
- Status0 = 0;
- Status1 = 0;
- Status2 = 0;
- Status3 = 0;
-
- // temp sector index
- byte secIdx = ActiveCommandParams.Sector;
-
- // hack for when another drive (non-existent) is being called
- if (ActiveDrive.ID != 0)
- DiskDriveIndex = 0;
-
- // do we have a valid disk inserted?
- if (!ActiveDrive.FLAG_READY)
- {
- // no disk, no tracks or motor is not on
- SetBit(SR0_IC0, ref Status0);
- SetBit(SR0_NR, ref Status0);
-
- CommitResultCHRN();
- CommitResultStatus();
- //ResBuffer[RS_ST0] = Status0;
-
- // move to result phase
- ActivePhase = Phase.Result;
- break;
- }
-
- int buffPos = 0;
- int sectorSize = 0;
- int maxTransferCap = 0;
-
- // calculate requested size of data required
- if (ActiveCommandParams.SectorSize == 0)
- {
- // When N=0, then DTL defines the data length which the FDC must treat as a sector. If DTL is smaller than the actual
- // data length in a sector, the data beyond DTL in the sector is not sent to the Data Bus. The FDC reads (internally)
- // the complete sector performing the CRC check and, depending upon the manner of command termination, may perform
- // a Multi-Sector Read Operation.
- sectorSize = ActiveCommandParams.DTL;
-
- // calculate maximum transfer capacity
- if (!CMD_FLAG_MF)
- maxTransferCap = 3328;
-
- if (maxTransferCap == 0) { }
- }
- else
- {
- // When N is non - zero, then DTL has no meaning and should be set to ffh
- ActiveCommandParams.DTL = 0xFF;
-
- // calculate maximum transfer capacity
- switch (ActiveCommandParams.SectorSize)
- {
- case 1:
- if (CMD_FLAG_MF)
- maxTransferCap = 6656;
- else
- maxTransferCap = 3840;
- break;
- case 2:
- if (CMD_FLAG_MF)
- maxTransferCap = 7680;
- else
- maxTransferCap = 4096;
- break;
- case 3:
- if (CMD_FLAG_MF)
- maxTransferCap = 8192;
- else
- maxTransferCap = 4096;
- break;
- }
-
- sectorSize = 0x80 << ActiveCommandParams.SectorSize;
- }
-
- // get the current track
- var track = ActiveDrive.Disk.DiskTracks.FirstOrDefault(a => a.TrackNumber == ActiveDrive.CurrentTrackID);
-
- if (track == null || track.NumberOfSectors <= 0)
- {
- // track could not be found
- SetBit(SR0_IC0, ref Status0);
- SetBit(SR0_NR, ref Status0);
-
- CommitResultCHRN();
- CommitResultStatus();
-
- //ResBuffer[RS_ST0] = Status0;
-
- // move to result phase
- ActivePhase = Phase.Result;
- break;
- }
-
- FloppyDisk.Sector sector = null;
-
- // sector read loop
- for (; ; )
- {
- bool terminate = false;
-
- // lookup the sector
- sector = GetSector();
-
- if (sector == null)
- {
- // sector was not found after two passes of the disk index hole
- SetBit(SR1_ND, ref Status1);
- SetBit(SR0_IC0, ref Status0);
- UnSetBit(SR0_IC1, ref Status0);
-
- // result requires the actual track id, rather than the sector track id
- ActiveCommandParams.Cylinder = track.TrackNumber;
-
- CommitResultCHRN();
- CommitResultStatus();
- ActivePhase = Phase.Result;
- break;
- }
-
- // sector ID was found on this track
-
- // get status regs from sector
- Status1 = sector.Status1;
- Status2 = sector.Status2;
-
- // we don't need EN
- UnSetBit(SR1_EN, ref Status1);
-
- // If SK=1, the FDC skips the sector with the Deleted Data Address Mark and reads the next sector.
- // The CRC bits in the deleted data field are not checked when SK=1
- if (CMD_FLAG_SK && Status2.Bit(SR2_CM))
- {
- if (ActiveCommandParams.Sector != ActiveCommandParams.EOT)
- {
- // increment the sector ID and search again
- ActiveCommandParams.Sector++;
- continue;
- }
- else
- {
- // no execution phase
- SetBit(SR0_IC0, ref Status0);
- UnSetBit(SR0_IC1, ref Status0);
-
- // result requires the actual track id, rather than the sector track id
- ActiveCommandParams.Cylinder = track.TrackNumber;
-
- CommitResultCHRN();
- CommitResultStatus();
- ActivePhase = Phase.Result;
- break;
- }
- }
-
- // read the sector
- for (int i = 0; i < sector.DataLen; i++)
- {
- ExecBuffer[buffPos++] = sector.ActualData[i];
- }
-
- // mark the sector read
- sector.SectorReadCompleted();
-
- // any CRC errors?
- if (Status1.Bit(SR1_DE) || Status2.Bit(SR2_DD))
- {
- SetBit(SR0_IC0, ref Status0);
- UnSetBit(SR0_IC1, ref Status0);
- terminate = true;
- }
-
- if (!CMD_FLAG_SK && Status2.Bit(SR2_CM))
- {
- // deleted address mark was detected with NO skip flag set
- ActiveCommandParams.EOT = ActiveCommandParams.Sector;
- SetBit(SR2_CM, ref Status2);
- SetBit(SR0_IC0, ref Status0);
- UnSetBit(SR0_IC1, ref Status0);
- terminate = true;
- }
-
- if (sector.SectorID == ActiveCommandParams.EOT || terminate)
- {
- // this was the last sector to read
- // or termination requested
-
- SetBit(SR1_EN, ref Status1);
-
- int keyIndex = 0;
- for (int i = 0; i < track.Sectors.Length; i++)
- {
- if (track.Sectors[i].SectorID == sector.SectorID)
- {
- keyIndex = i;
- break;
- }
- }
-
- if (keyIndex == track.Sectors.Length - 1)
- {
- // last sector on the cylinder, set EN
- SetBit(SR1_EN, ref Status1);
-
- // increment cylinder
- ActiveCommandParams.Cylinder++;
-
- // reset sector
- ActiveCommandParams.Sector = sector.SectorID; // 1;
- ActiveDrive.SectorIndex = 0;
- }
- else
- {
- ActiveDrive.SectorIndex++;
- }
-
- UnSetBit(SR0_IC1, ref Status0);
- if (terminate)
- SetBit(SR0_IC0, ref Status0);
- else
- UnSetBit(SR0_IC0, ref Status0);
-
- SetBit(SR0_IC0, ref Status0);
-
- // result requires the actual track id, rather than the sector track id
- ActiveCommandParams.Cylinder = track.TrackNumber;
-
- CommitResultCHRN();
- CommitResultStatus();
- ActivePhase = Phase.Execution;
- break;
- }
- else
- {
- // continue with multi-sector read operation
- ActiveCommandParams.Sector++;
- //ActiveDrive.SectorIndex++;
- }
- }
-
- if (ActivePhase == Phase.Execution)
- {
- ExecLength = buffPos;
- ExecCounter = buffPos;
-
- DriveLight = true;
- }
- }
-
- break;
-
- //----------------------------------------
- // FDC in execution phase reading/writing bytes
- //----------------------------------------
- case Phase.Execution:
-
- var index = ExecLength - ExecCounter;
-
- LastSectorDataReadByte = ExecBuffer[index];
-
- OverrunCounter--;
- ExecCounter--;
-
- break;
-
- //----------------------------------------
- // Result bytes being sent to CPU
- //----------------------------------------
- case Phase.Result:
- break;
- }
- }
-
- ///
- /// Read Deleted Data
- /// COMMAND: 8 parameter bytes
- /// EXECUTION: Data transfer between the FDD and FDC
- /// RESULT: 7 result bytes
- ///
- private void UPD_ReadDeletedData()
- {
- switch (ActivePhase)
- {
- //----------------------------------------
- // FDC is waiting for a command byte
- //----------------------------------------
- case Phase.Idle:
- break;
-
- //----------------------------------------
- // Receiving command parameter bytes
- //----------------------------------------
- case Phase.Command:
- // store the parameter in the command buffer
- CommBuffer[CommCounter] = LastByteReceived;
-
- // process parameter byte
- ParseParamByteStandard(CommCounter);
-
- // increment command parameter counter
- CommCounter++;
-
- // was that the last parameter byte?
- if (CommCounter == ActiveCommand.ParameterByteCount)
- {
- // all parameter bytes received - setup for execution phase
-
- // clear exec buffer and status registers
- ClearExecBuffer();
- Status0 = 0;
- Status1 = 0;
- Status2 = 0;
- Status3 = 0;
-
- // temp sector index
- byte secIdx = ActiveCommandParams.Sector;
-
- // do we have a valid disk inserted?
- if (!ActiveDrive.FLAG_READY)
- {
- // no disk, no tracks or motor is not on
- SetBit(SR0_IC0, ref Status0);
- SetBit(SR0_NR, ref Status0);
-
- CommitResultCHRN();
- CommitResultStatus();
- //ResBuffer[RS_ST0] = Status0;
-
- // move to result phase
- ActivePhase = Phase.Result;
- break;
- }
-
- int buffPos = 0;
- int sectorSize = 0;
- int maxTransferCap = 0;
- if (maxTransferCap > 0) { }
-
- // calculate requested size of data required
- if (ActiveCommandParams.SectorSize == 0)
- {
- // When N=0, then DTL defines the data length which the FDC must treat as a sector. If DTL is smaller than the actual
- // data length in a sector, the data beyond DTL in the sector is not sent to the Data Bus. The FDC reads (internally)
- // the complete sector performing the CRC check and, depending upon the manner of command termination, may perform
- // a Multi-Sector Read Operation.
- sectorSize = ActiveCommandParams.DTL;
-
- // calculate maximum transfer capacity
- if (!CMD_FLAG_MF)
- maxTransferCap = 3328;
- }
- else
- {
- // When N is non - zero, then DTL has no meaning and should be set to ffh
- ActiveCommandParams.DTL = 0xFF;
-
- // calculate maximum transfer capacity
- switch (ActiveCommandParams.SectorSize)
- {
- case 1:
- if (CMD_FLAG_MF)
- maxTransferCap = 6656;
- else
- maxTransferCap = 3840;
- break;
- case 2:
- if (CMD_FLAG_MF)
- maxTransferCap = 7680;
- else
- maxTransferCap = 4096;
- break;
- case 3:
- if (CMD_FLAG_MF)
- maxTransferCap = 8192;
- else
- maxTransferCap = 4096;
- break;
- }
-
- sectorSize = 0x80 << ActiveCommandParams.SectorSize;
- }
-
- // get the current track
- var track = ActiveDrive.Disk.DiskTracks.FirstOrDefault(a => a.TrackNumber == ActiveDrive.CurrentTrackID);
-
- if (track == null || track.NumberOfSectors <= 0)
- {
- // track could not be found
- SetBit(SR0_IC0, ref Status0);
- SetBit(SR0_NR, ref Status0);
-
- CommitResultCHRN();
- CommitResultStatus();
-
- //ResBuffer[RS_ST0] = Status0;
-
- // move to result phase
- ActivePhase = Phase.Result;
- break;
- }
-
- FloppyDisk.Sector sector = null;
-
- // sector read loop
- for (; ; )
- {
- bool terminate = false;
-
- // lookup the sector
- sector = GetSector();
-
- if (sector == null)
- {
- // sector was not found after two passes of the disk index hole
- SetBit(SR1_ND, ref Status1);
- SetBit(SR0_IC0, ref Status0);
- UnSetBit(SR0_IC1, ref Status0);
-
- // result requires the actual track id, rather than the sector track id
- ActiveCommandParams.Cylinder = track.TrackNumber;
-
- CommitResultCHRN();
- CommitResultStatus();
- ActivePhase = Phase.Result;
- break;
- }
-
- // sector ID was found on this track
-
- // get status regs from sector
- Status1 = sector.Status1;
- Status2 = sector.Status2;
-
- // we don't need EN
- UnSetBit(SR1_EN, ref Status1);
-
- // invert CM for read deleted data command
- if (Status2.Bit(SR2_CM))
- UnSetBit(SR2_CM, ref Status2);
- else
- SetBit(SR2_CM, ref Status2);
-
- // skip flag is set and no DAM found
- if (CMD_FLAG_SK && Status2.Bit(SR2_CM))
- {
- if (ActiveCommandParams.Sector != ActiveCommandParams.EOT)
- {
- // increment the sector ID and search again
- ActiveCommandParams.Sector++;
- continue;
- }
- else
- {
- // no execution phase
- SetBit(SR0_IC0, ref Status0);
- UnSetBit(SR0_IC1, ref Status0);
-
- // result requires the actual track id, rather than the sector track id
- ActiveCommandParams.Cylinder = track.TrackNumber;
-
- CommitResultCHRN();
- CommitResultStatus();
- ActivePhase = Phase.Result;
- break;
- }
- }
- // we can read this sector
- else
- {
- // if DAM is not set this will be the last sector to read
- if (Status2.Bit(SR2_CM))
- {
- ActiveCommandParams.EOT = ActiveCommandParams.Sector;
- }
-
- if (!CMD_FLAG_SK && !Status2.Bit(SR2_CM) &&
- ActiveDrive.Disk.Protection == ProtectionType.PaulOwens)
- {
- ActiveCommandParams.EOT = ActiveCommandParams.Sector;
- SetBit(SR2_CM, ref Status2);
- SetBit(SR0_IC0, ref Status0);
- UnSetBit(SR0_IC1, ref Status0);
- terminate = true;
- }
-
- // read the sector
- for (int i = 0; i < sectorSize; i++)
- {
- ExecBuffer[buffPos++] = sector.ActualData[i];
- }
-
- // mark the sector read
- sector.SectorReadCompleted();
-
- if (sector.SectorID == ActiveCommandParams.EOT)
- {
- // this was the last sector to read
-
- SetBit(SR1_EN, ref Status1);
-
- int keyIndex = 0;
- for (int i = 0; i < track.Sectors.Length; i++)
- {
- if (track.Sectors[i].SectorID == sector.SectorID)
- {
- keyIndex = i;
- break;
- }
- }
-
- if (keyIndex == track.Sectors.Length - 1)
- {
- // last sector on the cylinder, set EN
- SetBit(SR1_EN, ref Status1);
-
- // increment cylinder
- ActiveCommandParams.Cylinder++;
-
- // reset sector
- ActiveCommandParams.Sector = 1;
- ActiveDrive.SectorIndex = 0;
- }
- else
- {
- ActiveDrive.SectorIndex++;
- }
-
- UnSetBit(SR0_IC1, ref Status0);
- if (terminate)
- SetBit(SR0_IC0, ref Status0);
- else
- UnSetBit(SR0_IC0, ref Status0);
-
- SetBit(SR0_IC0, ref Status0);
-
- // result requires the actual track id, rather than the sector track id
- ActiveCommandParams.Cylinder = track.TrackNumber;
-
- // remove CM (appears to be required to defeat Alkatraz copy protection)
- UnSetBit(SR2_CM, ref Status2);
-
- CommitResultCHRN();
- CommitResultStatus();
- ActivePhase = Phase.Execution;
- break;
- }
- else
- {
- // continue with multi-sector read operation
- ActiveCommandParams.Sector++;
- //ActiveDrive.SectorIndex++;
- }
- }
- }
-
- if (ActivePhase == Phase.Execution)
- {
- ExecLength = buffPos;
- ExecCounter = buffPos;
- DriveLight = true;
- }
- }
- break;
-
- //----------------------------------------
- // FDC in execution phase reading/writing bytes
- //----------------------------------------
- case Phase.Execution:
- var index = ExecLength - ExecCounter;
-
- LastSectorDataReadByte = ExecBuffer[index];
-
- OverrunCounter--;
- ExecCounter--;
-
- break;
-
- //----------------------------------------
- // Result bytes being sent to CPU
- //----------------------------------------
- case Phase.Result:
- break;
- }
- }
-
- ///
- /// Read Diagnostic (read track)
- /// COMMAND: 8 parameter bytes
- /// EXECUTION: Data transfer between FDD and FDC. FDC reads all data fields from index hole to EDT
- /// RESULT: 7 result bytes
- ///
- private void UPD_ReadDiagnostic()
- {
- switch (ActivePhase)
- {
- //----------------------------------------
- // FDC is waiting for a command byte
- //----------------------------------------
- case Phase.Idle:
- break;
-
- //----------------------------------------
- // Receiving command parameter bytes
- //----------------------------------------
- case Phase.Command:
-
- // store the parameter in the command buffer
- CommBuffer[CommCounter] = LastByteReceived;
-
- // process parameter byte
- ParseParamByteStandard(CommCounter);
-
- // increment command parameter counter
- CommCounter++;
-
- // was that the last parameter byte?
- if (CommCounter == ActiveCommand.ParameterByteCount)
- {
- // all parameter bytes received - setup for execution phase
-
- // clear exec buffer and status registers
- ClearExecBuffer();
- Status0 = 0;
- Status1 = 0;
- Status2 = 0;
- Status3 = 0;
-
- // temp sector index
- byte secIdx = ActiveCommandParams.Sector;
-
- // do we have a valid disk inserted?
- if (!ActiveDrive.FLAG_READY)
- {
- // no disk, no tracks or motor is not on
- SetBit(SR0_IC0, ref Status0);
- SetBit(SR0_NR, ref Status0);
-
- CommitResultCHRN();
- CommitResultStatus();
- //ResBuffer[RS_ST0] = Status0;
-
- // move to result phase
- ActivePhase = Phase.Result;
- break;
- }
-
- int buffPos = 0;
- int sectorSize = 0;
- int maxTransferCap = 0;
- if (maxTransferCap > 0) { }
-
- // calculate requested size of data required
- if (ActiveCommandParams.SectorSize == 0)
- {
- // When N=0, then DTL defines the data length which the FDC must treat as a sector. If DTL is smaller than the actual
- // data length in a sector, the data beyond DTL in the sector is not sent to the Data Bus. The FDC reads (internally)
- // the complete sector performing the CRC check and, depending upon the manner of command termination, may perform
- // a Multi-Sector Read Operation.
- sectorSize = ActiveCommandParams.DTL;
-
- // calculate maximum transfer capacity
- if (!CMD_FLAG_MF)
- maxTransferCap = 3328;
- }
- else
- {
- // When N is non - zero, then DTL has no meaning and should be set to ffh
- ActiveCommandParams.DTL = 0xFF;
-
- // calculate maximum transfer capacity
- switch (ActiveCommandParams.SectorSize)
- {
- case 1:
- if (CMD_FLAG_MF)
- maxTransferCap = 6656;
- else
- maxTransferCap = 3840;
- break;
- case 2:
- if (CMD_FLAG_MF)
- maxTransferCap = 7680;
- else
- maxTransferCap = 4096;
- break;
- case 3:
- if (CMD_FLAG_MF)
- maxTransferCap = 8192;
- else
- maxTransferCap = 4096;
- break;
- }
-
- sectorSize = 0x80 << ActiveCommandParams.SectorSize;
- }
-
- // get the current track
- var track = ActiveDrive.Disk.DiskTracks.FirstOrDefault(a => a.TrackNumber == ActiveDrive.CurrentTrackID);
-
- if (track == null || track.NumberOfSectors <= 0)
- {
- // track could not be found
- SetBit(SR0_IC0, ref Status0);
- SetBit(SR0_NR, ref Status0);
-
- CommitResultCHRN();
- CommitResultStatus();
-
- //ResBuffer[RS_ST0] = Status0;
-
- // move to result phase
- ActivePhase = Phase.Result;
- break;
- }
-
- //FloppyDisk.Sector sector = null;
- ActiveDrive.SectorIndex = 0;
-
- int secCount = 0;
-
- // read the whole track
- for (int i = 0; i < track.Sectors.Length; i++)
- {
- if (secCount >= ActiveCommandParams.EOT)
- {
- break;
- }
-
- var sec = track.Sectors[i];
- for (int b = 0; b < sec.ActualData.Length; b++)
- {
- ExecBuffer[buffPos++] = sec.ActualData[b];
- }
-
- // mark the sector read
- sec.SectorReadCompleted();
-
- // end of sector - compare IDs
- if (sec.TrackNumber != ActiveCommandParams.Cylinder ||
- sec.SideNumber != ActiveCommandParams.Head ||
- sec.SectorID != ActiveCommandParams.Sector ||
- sec.SectorSize != ActiveCommandParams.SectorSize)
- {
- SetBit(SR1_ND, ref Status1);
- }
-
- secCount++;
- ActiveDrive.SectorIndex = i;
- }
-
- if (secCount == ActiveCommandParams.EOT)
- {
- // this was the last sector to read
- // or termination requested
-
- int keyIndex = 0;
- for (int i = 0; i < track.Sectors.Length; i++)
- {
- if (track.Sectors[i].SectorID == track.Sectors[ActiveDrive.SectorIndex].SectorID)
- {
- keyIndex = i;
- break;
- }
- }
-
- if (keyIndex == track.Sectors.Length - 1)
- {
- // last sector on the cylinder, set EN
- SetBit(SR1_EN, ref Status1);
-
- // increment cylinder
- ActiveCommandParams.Cylinder++;
-
- // reset sector
- ActiveCommandParams.Sector = 1;
- ActiveDrive.SectorIndex = 0;
- }
- else
- {
- ActiveDrive.SectorIndex++;
- }
-
- UnSetBit(SR0_IC1, ref Status0);
- UnSetBit(SR0_IC0, ref Status0);
-
- CommitResultCHRN();
- CommitResultStatus();
- ActivePhase = Phase.Execution;
- }
-
- if (ActivePhase == Phase.Execution)
- {
- ExecLength = buffPos;
- ExecCounter = buffPos;
-
- DriveLight = true;
- }
- }
-
- break;
-
- //----------------------------------------
- // FDC in execution phase reading/writing bytes
- //----------------------------------------
- case Phase.Execution:
-
- var index = ExecLength - ExecCounter;
-
- LastSectorDataReadByte = ExecBuffer[index];
-
- OverrunCounter--;
- ExecCounter--;
-
- break;
-
- //----------------------------------------
- // Result bytes being sent to CPU
- //----------------------------------------
- case Phase.Result:
- break;
- }
- }
-
- ///
- /// Read ID
- /// COMMAND: 1 parameter byte
- /// EXECUTION: The first correct ID information on the cylinder is stored in the data register
- /// RESULT: 7 result bytes
- ///
- private void UPD_ReadID()
- {
- switch (ActivePhase)
- {
- //----------------------------------------
- // FDC is waiting for a command byte
- //----------------------------------------
- case Phase.Idle:
- break;
-
- //----------------------------------------
- // Receiving command parameter bytes
- //----------------------------------------
- case Phase.Command:
-
- // store the parameter in the command buffer
- CommBuffer[CommCounter] = LastByteReceived;
-
- // process parameter byte
- ParseParamByteStandard(CommCounter);
-
- // increment command parameter counter
- CommCounter++;
-
- // was that the last parameter byte?
- if (CommCounter == ActiveCommand.ParameterByteCount)
- {
- DriveLight = true;
-
- // all parameter bytes received
- ClearResultBuffer();
- Status0 = 0;
- Status1 = 0;
- Status2 = 0;
- Status3 = 0;
-
- // set unit select
- //SetUnitSelect(ActiveDrive.ID, ref Status0);
-
- // HD should always be 0
- UnSetBit(SR0_HD, ref Status0);
-
- if (!ActiveDrive.FLAG_READY)
- {
- // no disk, no tracks or motor is not on
- // it is at this point the +3 detects whether a disk is present
- // if not (and after another readid and SIS) it will eventually proceed to loading from tape
- SetBit(SR0_IC0, ref Status0);
- SetBit(SR0_NR, ref Status0);
-
- // setup the result buffer
- ResBuffer[RS_ST0] = Status0;
- for (int i = 1; i < 7; i++)
- ResBuffer[i] = 0;
-
- // move to result phase
- ActivePhase = Phase.Result;
- break;
- }
-
- var track = ActiveDrive.Disk.DiskTracks.FirstOrDefault(a => a.TrackNumber == ActiveDrive.CurrentTrackID);
-
- if (track != null && track.NumberOfSectors > 0 && track.TrackNumber != 0xff)
- {
- // formatted track
-
- // is the index out of bounds?
- if (ActiveDrive.SectorIndex >= track.NumberOfSectors)
- {
- // reset the index
- ActiveDrive.SectorIndex = 0;
- }
-
- if (ActiveDrive.SectorIndex == 0 && ActiveDrive.Disk.DiskTracks[ActiveDrive.CurrentTrackID].Sectors.Length > 1)
- {
- // looks like readid always skips the first sector on a track
- ActiveDrive.SectorIndex++;
- }
-
- // read the sector data
- var data = track.Sectors[ActiveDrive.SectorIndex]; //.GetCHRN();
- ResBuffer[RS_C] = data.TrackNumber;
- ResBuffer[RS_H] = data.SideNumber;
- ResBuffer[RS_R] = data.SectorID;
- ResBuffer[RS_N] = data.SectorSize;
-
- ResBuffer[RS_ST0] = Status0;
-
- // check for DAM & CRC
- //if (data.Status2.Bit(SR2_CM))
- //SetBit(SR2_CM, ref ResBuffer[RS_ST2]);
-
-
- // increment the current sector
- ActiveDrive.SectorIndex++;
-
- // is the index out of bounds?
- if (ActiveDrive.SectorIndex >= track.NumberOfSectors)
- {
- // reset the index
- ActiveDrive.SectorIndex = 0;
- }
- }
- else
- {
- // unformatted track?
- CommitResultCHRN();
-
- SetBit(SR0_IC0, ref Status0);
- ResBuffer[RS_ST0] = Status0;
- ResBuffer[RS_ST1] = 0x01;
- }
-
- ActivePhase = Phase.Result;
- }
-
- break;
-
- //----------------------------------------
- // FDC in execution phase reading/writing bytes
- //----------------------------------------
- case Phase.Execution:
- break;
-
- //----------------------------------------
- // Result bytes being sent to CPU
- //----------------------------------------
- case Phase.Result:
- break;
- }
- }
-
- #endregion
-
- #region WRITE Commands
-
- ///
- /// Write Data
- /// COMMAND: 8 parameter bytes
- /// EXECUTION: Data transfer between FDC and FDD
- /// RESULT: 7 result bytes
- ///
- private void UPD_WriteData()
- {
- switch (ActivePhase)
- {
- //----------------------------------------
- // FDC is waiting for a command byte
- //----------------------------------------
- case Phase.Idle:
- break;
-
- //----------------------------------------
- // Receiving command parameter bytes
- //----------------------------------------
- case Phase.Command:
-
- // store the parameter in the command buffer
- CommBuffer[CommCounter] = LastByteReceived;
-
- // process parameter byte
- ParseParamByteStandard(CommCounter);
-
- // increment command parameter counter
- CommCounter++;
-
- // was that the last parameter byte?
- if (CommCounter == ActiveCommand.ParameterByteCount)
- {
- // all parameter bytes received - setup for execution phase
-
- // clear exec buffer and status registers
- ClearExecBuffer();
- Status0 = 0;
- Status1 = 0;
- Status2 = 0;
- Status3 = 0;
-
- // temp sector index
- byte secIdx = ActiveCommandParams.Sector;
-
- // hack for when another drive (non-existent) is being called
- if (ActiveDrive.ID != 0)
- DiskDriveIndex = 0;
-
- // do we have a valid disk inserted?
- if (!ActiveDrive.FLAG_READY)
- {
- // no disk, no tracks or motor is not on
- SetBit(SR0_IC0, ref Status0);
- SetBit(SR0_NR, ref Status0);
-
- CommitResultCHRN();
- CommitResultStatus();
- //ResBuffer[RS_ST0] = Status0;
-
- // move to result phase
- ActivePhase = Phase.Result;
- break;
- }
-
- // check write protect tab
- if (ActiveDrive.FLAG_WRITEPROTECT)
- {
- SetBit(SR0_IC0, ref Status0);
- SetBit(SR1_NW, ref Status1);
-
- CommitResultCHRN();
- CommitResultStatus();
- //ResBuffer[RS_ST0] = Status0;
-
- // move to result phase
- ActivePhase = Phase.Result;
- break;
- }
- else
- {
-
- // calculate the number of bytes to write
- int byteCounter = 0;
- byte startSecID = ActiveCommandParams.Sector;
- byte endSecID = ActiveCommandParams.EOT;
- bool lastSec = false;
-
- // get the first sector
- var track = ActiveDrive.Disk.DiskTracks[ActiveCommandParams.Cylinder];
- //int secIndex = 0;
- for (int s = 0; s < track.Sectors.Length; s++)
- {
- if (track.Sectors[s].SectorID == endSecID)
- lastSec = true;
-
- for (int i = 0; i < 0x80 << ActiveCommandParams.SectorSize; i++)
- {
- byteCounter++;
-
- if (i == (0x80 << ActiveCommandParams.SectorSize) - 1 && lastSec)
- {
- break;
- }
- }
-
- if (lastSec)
- break;
- }
-
- ExecCounter = byteCounter;
- ExecLength = byteCounter;
- ActivePhase = Phase.Execution;
- DriveLight = true;
- break;
- }
- }
-
- break;
-
- //----------------------------------------
- // FDC in execution phase reading/writing bytes
- //----------------------------------------
- case Phase.Execution:
-
- var index = ExecLength - ExecCounter;
-
- ExecBuffer[index] = LastSectorDataWriteByte;
-
- OverrunCounter--;
- ExecCounter--;
-
- if (ExecCounter <= 0)
- {
- int cnt = 0;
-
- // all data received
- byte startSecID = ActiveCommandParams.Sector;
- byte endSecID = ActiveCommandParams.EOT;
- bool lastSec = false;
- var track = ActiveDrive.Disk.DiskTracks[ActiveCommandParams.Cylinder];
- //int secIndex = 0;
-
- for (int s = 0; s < track.Sectors.Length; s++)
- {
- if (cnt == ExecLength)
- break;
-
- ActiveCommandParams.Sector = track.Sectors[s].SectorID;
-
- if (track.Sectors[s].SectorID == endSecID)
- lastSec = true;
-
- int size = 0x80 << track.Sectors[s].SectorSize;
-
- for (int d = 0; d < size; d++)
- {
- track.Sectors[s].SectorData[d] = ExecBuffer[cnt++];
- }
-
- if (lastSec)
- break;
- }
-
- SetBit(SR0_IC0, ref Status0);
- SetBit(SR1_EN, ref Status1);
-
- CommitResultCHRN();
- CommitResultStatus();
- }
-
- break;
-
- //----------------------------------------
- // Result bytes being sent to CPU
- //----------------------------------------
- case Phase.Result:
- break;
- }
- }
-
- ///
- /// Write ID (format write)
- /// COMMAND: 5 parameter bytes
- /// EXECUTION: Entire track is formatted
- /// RESULT: 7 result bytes
- ///
- private void UPD_WriteID()
- {
- switch (ActivePhase)
- {
- //----------------------------------------
- // FDC is waiting for a command byte
- //----------------------------------------
- case Phase.Idle:
- break;
-
- //----------------------------------------
- // Receiving command parameter bytes
- //----------------------------------------
- case Phase.Command:
-
- // store the parameter in the command buffer
- CommBuffer[CommCounter] = LastByteReceived;
-
- // process parameter byte
- ParseParamByteStandard(CommCounter);
-
- // increment command parameter counter
- CommCounter++;
-
- // was that the last parameter byte?
- if (CommCounter == ActiveCommand.ParameterByteCount)
- {
- // all parameter bytes received - setup for execution phase
- DriveLight = true;
-
- // clear exec buffer and status registers
- ClearExecBuffer();
- Status0 = 0;
- Status1 = 0;
- Status2 = 0;
- Status3 = 0;
-
- // temp sector index
- byte secIdx = ActiveCommandParams.Sector;
-
- // hack for when another drive (non-existent) is being called
- if (ActiveDrive.ID != 0)
- DiskDriveIndex = 0;
-
- // do we have a valid disk inserted?
- if (!ActiveDrive.FLAG_READY)
- {
- // no disk, no tracks or motor is not on
- SetBit(SR0_IC0, ref Status0);
- SetBit(SR0_NR, ref Status0);
-
- CommitResultCHRN();
- CommitResultStatus();
- //ResBuffer[RS_ST0] = Status0;
-
- // move to result phase
- ActivePhase = Phase.Result;
- break;
- }
-
- // check write protect tab
- if (ActiveDrive.FLAG_WRITEPROTECT)
- {
- SetBit(SR0_IC0, ref Status0);
- SetBit(SR1_NW, ref Status1);
-
- CommitResultCHRN();
- CommitResultStatus();
- //ResBuffer[RS_ST0] = Status0;
-
- // move to result phase
- ActivePhase = Phase.Result;
- break;
- }
- else
- {
- // not implemented yet
- SetBit(SR0_IC0, ref Status0);
- SetBit(SR1_NW, ref Status1);
-
- CommitResultCHRN();
- CommitResultStatus();
- //ResBuffer[RS_ST0] = Status0;
-
- // move to result phase
- ActivePhase = Phase.Result;
- break;
- }
- }
-
- break;
-
- //----------------------------------------
- // FDC in execution phase reading/writing bytes
- //----------------------------------------
- case Phase.Execution:
- break;
-
- //----------------------------------------
- // Result bytes being sent to CPU
- //----------------------------------------
- case Phase.Result:
- break;
- }
- }
-
- ///
- /// Write Deleted Data
- /// COMMAND: 8 parameter bytes
- /// EXECUTION: Data transfer between FDC and FDD
- /// RESULT: 7 result bytes
- ///
- private void UPD_WriteDeletedData()
- {
- switch (ActivePhase)
- {
- //----------------------------------------
- // FDC is waiting for a command byte
- //----------------------------------------
- case Phase.Idle:
- break;
-
- //----------------------------------------
- // Receiving command parameter bytes
- //----------------------------------------
- case Phase.Command:
-
- // store the parameter in the command buffer
- CommBuffer[CommCounter] = LastByteReceived;
-
- // process parameter byte
- ParseParamByteStandard(CommCounter);
-
- // increment command parameter counter
- CommCounter++;
-
- // was that the last parameter byte?
- if (CommCounter == ActiveCommand.ParameterByteCount)
- {
- // all parameter bytes received - setup for execution phase
-
- // clear exec buffer and status registers
- ClearExecBuffer();
- Status0 = 0;
- Status1 = 0;
- Status2 = 0;
- Status3 = 0;
-
- // temp sector index
- byte secIdx = ActiveCommandParams.Sector;
-
- // hack for when another drive (non-existent) is being called
- if (ActiveDrive.ID != 0)
- DiskDriveIndex = 0;
-
- // do we have a valid disk inserted?
- if (!ActiveDrive.FLAG_READY)
- {
- // no disk, no tracks or motor is not on
- SetBit(SR0_IC0, ref Status0);
- SetBit(SR0_NR, ref Status0);
-
- CommitResultCHRN();
- CommitResultStatus();
- //ResBuffer[RS_ST0] = Status0;
-
- // move to result phase
- ActivePhase = Phase.Result;
- break;
- }
-
- // check write protect tab
- if (ActiveDrive.FLAG_WRITEPROTECT)
- {
- SetBit(SR0_IC0, ref Status0);
- SetBit(SR1_NW, ref Status1);
-
- CommitResultCHRN();
- CommitResultStatus();
- //ResBuffer[RS_ST0] = Status0;
-
- // move to result phase
- ActivePhase = Phase.Result;
- break;
- }
- else
- {
-
- // calculate the number of bytes to write
- int byteCounter = 0;
- byte startSecID = ActiveCommandParams.Sector;
- byte endSecID = ActiveCommandParams.EOT;
- bool lastSec = false;
-
- // get the first sector
- var track = ActiveDrive.Disk.DiskTracks[ActiveCommandParams.Cylinder];
- //int secIndex = 0;
- for (int s = 0; s < track.Sectors.Length; s++)
- {
- if (track.Sectors[s].SectorID == endSecID)
- lastSec = true;
-
- for (int i = 0; i < 0x80 << ActiveCommandParams.SectorSize; i++)
- {
- byteCounter++;
-
- if (i == (0x80 << ActiveCommandParams.SectorSize) - 1 && lastSec)
- {
- break;
- }
- }
-
- if (lastSec)
- break;
- }
-
- ExecCounter = byteCounter;
- ExecLength = byteCounter;
- ActivePhase = Phase.Execution;
- DriveLight = true;
- break;
- }
- }
-
- break;
-
- //----------------------------------------
- // FDC in execution phase reading/writing bytes
- //----------------------------------------
- case Phase.Execution:
-
- var index = ExecLength - ExecCounter;
-
- ExecBuffer[index] = LastSectorDataWriteByte;
-
- OverrunCounter--;
- ExecCounter--;
-
- if (ExecCounter <= 0)
- {
- int cnt = 0;
-
- // all data received
- byte startSecID = ActiveCommandParams.Sector;
- byte endSecID = ActiveCommandParams.EOT;
- bool lastSec = false;
- var track = ActiveDrive.Disk.DiskTracks[ActiveCommandParams.Cylinder];
- //int secIndex = 0;
-
- for (int s = 0; s < track.Sectors.Length; s++)
- {
- if (cnt == ExecLength)
- break;
-
- ActiveCommandParams.Sector = track.Sectors[s].SectorID;
-
- if (track.Sectors[s].SectorID == endSecID)
- lastSec = true;
-
- int size = 0x80 << track.Sectors[s].SectorSize;
-
- for (int d = 0; d < size; d++)
- {
- track.Sectors[s].SectorData[d] = ExecBuffer[cnt++];
- }
-
- if (lastSec)
- break;
- }
-
- SetBit(SR0_IC0, ref Status0);
- SetBit(SR1_EN, ref Status1);
-
- CommitResultCHRN();
- CommitResultStatus();
- }
-
- break;
-
- //----------------------------------------
- // Result bytes being sent to CPU
- //----------------------------------------
- case Phase.Result:
- break;
- }
- }
-
- #endregion
-
- #region SCAN Commands
-
- ///
- /// Scan Equal
- /// COMMAND: 8 parameter bytes
- /// EXECUTION: Data compared between the FDD and FDC
- /// RESULT: 7 result bytes
- ///
- private void UPD_ScanEqual()
- {
- switch (ActivePhase)
- {
- //----------------------------------------
- // FDC is waiting for a command byte
- //----------------------------------------
- case Phase.Idle:
- break;
-
- //----------------------------------------
- // Receiving command parameter bytes
- //----------------------------------------
- case Phase.Command:
- break;
-
- //----------------------------------------
- // FDC in execution phase reading/writing bytes
- //----------------------------------------
- case Phase.Execution:
- break;
-
- //----------------------------------------
- // Result bytes being sent to CPU
- //----------------------------------------
- case Phase.Result:
- break;
- }
- }
-
- ///
- /// Scan Low or Equal
- /// COMMAND: 8 parameter bytes
- /// EXECUTION: Data compared between the FDD and FDC
- /// RESULT: 7 result bytes
- ///
- private void UPD_ScanLowOrEqual()
- {
- switch (ActivePhase)
- {
- //----------------------------------------
- // FDC is waiting for a command byte
- //----------------------------------------
- case Phase.Idle:
- break;
-
- //----------------------------------------
- // Receiving command parameter bytes
- //----------------------------------------
- case Phase.Command:
- break;
-
- //----------------------------------------
- // FDC in execution phase reading/writing bytes
- //----------------------------------------
- case Phase.Execution:
- break;
-
- //----------------------------------------
- // Result bytes being sent to CPU
- //----------------------------------------
- case Phase.Result:
- break;
- }
- }
-
- ///
- /// Scan High or Equal
- /// COMMAND: 8 parameter bytes
- /// EXECUTION: Data compared between the FDD and FDC
- /// RESULT: 7 result bytes
- ///
- private void UPD_ScanHighOrEqual()
- {
- switch (ActivePhase)
- {
- //----------------------------------------
- // FDC is waiting for a command byte
- //----------------------------------------
- case Phase.Idle:
- break;
-
- //----------------------------------------
- // Receiving command parameter bytes
- //----------------------------------------
- case Phase.Command:
- break;
-
- //----------------------------------------
- // FDC in execution phase reading/writing bytes
- //----------------------------------------
- case Phase.Execution:
- break;
-
- //----------------------------------------
- // Result bytes being sent to CPU
- //----------------------------------------
- case Phase.Result:
- break;
- }
- }
-
- #endregion
-
- #region OTHER Commands
-
- ///
- /// Specify
- /// COMMAND: 2 parameter bytes
- /// EXECUTION: NO execution phase
- /// RESULT: NO result phase
- ///
- /// Looks like specify command returns status 0x80 throughout its lifecycle
- /// so CB is NOT set
- ///
- private void UPD_Specify()
- {
- switch (ActivePhase)
- {
- //----------------------------------------
- // FDC is waiting for a command byte
- //----------------------------------------
- case Phase.Idle:
- break;
-
- //----------------------------------------
- // Receiving command parameter bytes
- //----------------------------------------
- case Phase.Command:
-
- // store the parameter in the command buffer
- CommBuffer[CommCounter] = LastByteReceived;
-
- // process parameter byte
- byte currByte = CommBuffer[CommCounter];
- BitArray bi = new BitArray(new byte[] { currByte });
-
- switch (CommCounter)
- {
- // SRT & HUT
- case 0:
- SRT = 16 - (currByte >> 4) & 0x0f;
- HUT = (currByte & 0x0f) << 4;
- if (HUT == 0)
- {
- HUT = 255;
- }
- break;
- // HLT & ND
- case 1:
- if (bi[0])
- ND = true;
- else
- ND = false;
-
- HLT = currByte & 0xfe;
- if (HLT == 0)
- {
- HLT = 255;
- }
- break;
- }
-
- // increment command parameter counter
- CommCounter++;
-
- // was that the last parameter byte?
- if (CommCounter == ActiveCommand.ParameterByteCount)
- {
- // all parameter bytes received
- ActivePhase = Phase.Idle;
- }
-
- break;
-
- //----------------------------------------
- // FDC in execution phase reading/writing bytes
- //----------------------------------------
- case Phase.Execution:
- break;
-
- //----------------------------------------
- // Result bytes being sent to CPU
- //----------------------------------------
- case Phase.Result:
- break;
- }
- }
-
- ///
- /// Seek
- /// COMMAND: 2 parameter bytes
- /// EXECUTION: Head is positioned over proper cylinder on disk
- /// RESULT: NO result phase
- ///
- private void UPD_Seek()
- {
- switch (ActivePhase)
- {
- //----------------------------------------
- // FDC is waiting for a command byte
- //----------------------------------------
- case Phase.Idle:
- break;
-
- //----------------------------------------
- // Receiving command parameter bytes
- //----------------------------------------
- case Phase.Command:
- // store the parameter in the command buffer
- CommBuffer[CommCounter] = LastByteReceived;
-
- // process parameter byte
- byte currByte = CommBuffer[CommCounter];
- switch (CommCounter)
- {
- case 0:
- ParseParamByteStandard(CommCounter);
- break;
- case 1:
- ActiveDrive.SeekingTrack = currByte;
- break;
- }
-
- // increment command parameter counter
- CommCounter++;
-
- // was that the last parameter byte?
- if (CommCounter == ActiveCommand.ParameterByteCount)
- {
- // all parameter bytes received
- DriveLight = true;
- ActivePhase = Phase.Execution;
- ActiveCommand.CommandDelegate();
- }
- break;
-
- //----------------------------------------
- // FDC in execution phase reading/writing bytes
- //----------------------------------------
- case Phase.Execution:
- // set seek flag
- ActiveDrive.SeekStatus = SEEK_SEEK;
-
- if (ActiveDrive.CurrentTrackID == CommBuffer[CM_C])
- {
- // we are already on the correct track
- ActiveDrive.SectorIndex = 0;
- }
- else
- {
- // immediate seek
- ActiveDrive.CurrentTrackID = CommBuffer[CM_C];
-
- ActiveDrive.SectorIndex = 0;
-
- if (ActiveDrive.Disk.DiskTracks[ActiveDrive.CurrentTrackID].Sectors.Length > 1)
- {
- // always read the first sector
- //ActiveDrive.SectorIndex++;
- }
- }
-
- // skip execution mode and go directly to idle
- // result is determined by SIS command
- ActivePhase = Phase.Idle;
- break;
-
- //----------------------------------------
- // Result bytes being sent to CPU
- //----------------------------------------
- case Phase.Result:
- break;
- }
- }
-
- ///
- /// Recalibrate (seek track 0)
- /// COMMAND: 1 parameter byte
- /// EXECUTION: Head retracted to track 0
- /// RESULT: NO result phase
- ///
- private void UPD_Recalibrate()
- {
- switch (ActivePhase)
- {
- //----------------------------------------
- // FDC is waiting for a command byte
- //----------------------------------------
- case Phase.Idle:
- break;
-
- //----------------------------------------
- // Receiving command parameter bytes
- //----------------------------------------
- case Phase.Command:
- // store the parameter in the command buffer
- CommBuffer[CommCounter] = LastByteReceived;
-
- // process parameter byte
- ParseParamByteStandard(CommCounter);
-
- // increment command parameter counter
- CommCounter++;
-
- // was that the last parameter byte?
- if (CommCounter == ActiveCommand.ParameterByteCount)
- {
- // all parameter bytes received
- DriveLight = true;
- ActivePhase = Phase.Execution;
- ActiveCommand.CommandDelegate();
- }
- break;
-
- //----------------------------------------
- // FDC in execution phase reading/writing bytes
- //----------------------------------------
- case Phase.Execution:
-
- // immediate recalibration
- ActiveDrive.TrackIndex = 0;
- ActiveDrive.SectorIndex = 0;
-
- // recalibrate appears to always skip the first sector
- //if (ActiveDrive.Disk.DiskTracks[ActiveDrive.TrackIndex].Sectors.Length > 1)
- //ActiveDrive.SectorIndex++;
-
- // set seek flag
- ActiveDrive.SeekStatus = SEEK_RECALIBRATE;
-
- // skip execution mode and go directly to idle
- // result is determined by SIS command
- ActivePhase = Phase.Idle;
- break;
-
- //----------------------------------------
- // Result bytes being sent to CPU
- //----------------------------------------
- case Phase.Result:
- break;
- }
- }
-
- ///
- /// Sense Interrupt Status
- /// COMMAND: NO parameter bytes
- /// EXECUTION: NO execution phase
- /// RESULT: 2 result bytes
- ///
- private void UPD_SenseInterruptStatus()
- {
- switch (ActivePhase)
- {
- //----------------------------------------
- // FDC is waiting for a command byte
- //----------------------------------------
- case Phase.Idle:
- break;
-
- //----------------------------------------
- // Receiving command parameter bytes
- //----------------------------------------
- case Phase.Command:
- break;
-
- //----------------------------------------
- // FDC in execution phase reading/writing bytes
- //----------------------------------------
- case Phase.Execution:
- // SIS should return 2 bytes if sucessfully sensed an interrupt
- // 1 byte otherwise
-
- // it seems like the +3 ROM makes 3 SIS calls for each seek/recalibrate call for some reason
- // possibly one for each drive???
- // 1 - the interrupt is acknowleged with ST0 = 32 and track number
- // 2 - second sis returns 1 ST0 byte with 192
- // 3 - third SIS call returns standard 1 byte 0x80 (unknown cmd or SIS with no interrupt occured)
- // for now I will assume that the first call is aimed at DriveA, the second at DriveB (which we are NOT implementing)
-
- // check active drive first
- if (ActiveDrive.SeekStatus == SEEK_RECALIBRATE ||
- ActiveDrive.SeekStatus == SEEK_SEEK)
- {
- // interrupt has been raised for this drive
- // acknowledge
- ActiveDrive.SeekStatus = SEEK_IDLE;// SEEK_INTACKNOWLEDGED;
-
- // result length 2
- ResLength = 2;
-
- // first byte ST0 0x20
- Status0 = 0x20;
- ResBuffer[0] = Status0;
- // second byte is the current track id
- ResBuffer[1] = ActiveDrive.CurrentTrackID;
- }
- /*
- else if (ActiveDrive.SeekStatus == SEEK_INTACKNOWLEDGED)
- {
- // DriveA interrupt has already been acknowledged
- ActiveDrive.SeekStatus = SEEK_IDLE;
-
- ResLength = 1;
- Status0 = 192;
- ResBuffer[0] = Status0;
- }
- */
- else if (ActiveDrive.SeekStatus == SEEK_IDLE)
- {
- // SIS with no interrupt
- ResLength = 1;
- Status0 = 0x80;
- ResBuffer[0] = Status0;
- }
-
- ActivePhase = Phase.Result;
-
- break;
-
- //----------------------------------------
- // Result bytes being sent to CPU
- //----------------------------------------
- case Phase.Result:
- break;
- }
- }
-
- ///
- /// Sense Drive Status
- /// COMMAND: 1 parameter byte
- /// EXECUTION: NO execution phase
- /// RESULT: 1 result byte
- ///
- /// The ZX spectrum appears to only specify drive 1 as the parameter byte, NOT drive 0
- /// After the final param byte is received main status changes to 0xd0
- /// Data register (ST3) result is 0x51 if drive/disk not available
- /// 0x71 if disk is present in 2nd drive
- ///
- private void UPD_SenseDriveStatus()
- {
- switch (ActivePhase)
- {
- //----------------------------------------
- // FDC is waiting for a command byte
- //----------------------------------------
- case Phase.Idle:
- break;
-
- //----------------------------------------
- // Receiving command parameter bytes
- //----------------------------------------
- case Phase.Command:
- // store the parameter in the command buffer
- CommBuffer[CommCounter] = LastByteReceived;
-
- // process parameter byte
- ParseParamByteStandard(CommCounter);
-
- // increment command parameter counter
- CommCounter++;
-
- // was that the last parameter byte?
- if (CommCounter == ActiveCommand.ParameterByteCount)
- {
- // all parameter bytes received
- ActivePhase = Phase.Execution;
- UPD_SenseDriveStatus();
- }
- break;
-
- //----------------------------------------
- // FDC in execution phase reading/writing bytes
- //----------------------------------------
- case Phase.Execution:
- // one ST3 byte required
-
- // set US
- Status3 = (byte)ActiveDrive.ID;
-
- if (Status3 != 0)
- {
- // we only support 1 drive
- SetBit(SR3_FT, ref Status3);
- }
- else
- {
- // HD - only one side
- UnSetBit(SR3_HD, ref Status3);
-
- // write protect
- if (ActiveDrive.FLAG_WRITEPROTECT)
- SetBit(SR3_WP, ref Status3);
-
- // track 0
- if (ActiveDrive.FLAG_TRACK0)
- SetBit(SR3_T0, ref Status3);
-
- // rdy
- if (ActiveDrive.Disk != null)
- SetBit(SR3_RY, ref Status3);
- }
-
- ResBuffer[0] = Status3;
- ActivePhase = Phase.Result;
-
- break;
-
- //----------------------------------------
- // Result bytes being sent to CPU
- //----------------------------------------
- case Phase.Result:
- break;
- }
- }
-
- ///
- /// Version
- /// COMMAND: NO parameter bytes
- /// EXECUTION: NO execution phase
- /// RESULT: 1 result byte
- ///
- private void UPD_Version()
- {
- switch (ActivePhase)
- {
- case Phase.Idle:
- case Phase.Command:
- case Phase.Execution:
- case Phase.Result:
- UPD_Invalid();
- break;
- }
- }
-
- ///
- /// Invalid
- /// COMMAND: NO parameter bytes
- /// EXECUTION: NO execution phase
- /// RESULT: 1 result byte
- ///
- private void UPD_Invalid()
- {
- switch (ActivePhase)
- {
- //----------------------------------------
- // FDC is waiting for a command byte
- //----------------------------------------
- case Phase.Idle:
- break;
-
- //----------------------------------------
- // Receiving command parameter bytes
- //----------------------------------------
- case Phase.Command:
- break;
-
- //----------------------------------------
- // FDC in execution phase reading/writing bytes
- //----------------------------------------
- case Phase.Execution:
- // no execution phase
- ActivePhase = Phase.Result;
- UPD_Invalid();
- break;
-
- //----------------------------------------
- // Result bytes being sent to CPU
- //----------------------------------------
- case Phase.Result:
- ResBuffer[0] = 0x80;
- break;
- }
- }
-
- #endregion
-
- #endregion
-
- #region Controller Methods
-
- ///
- /// Called when a status register read is required
- /// This can be called at any time
- /// The main status register appears to be queried nearly all the time
- /// so needs to be kept updated. It keeps the CPU informed of the current state
- ///
- private byte ReadMainStatus()
- {
- SetBit(MSR_RQM, ref StatusMain);
-
- switch (ActivePhase)
- {
- case Phase.Idle:
- UnSetBit(MSR_DIO, ref StatusMain);
- UnSetBit(MSR_CB, ref StatusMain);
- UnSetBit(MSR_EXM, ref StatusMain);
- break;
- case Phase.Command:
- UnSetBit(MSR_DIO, ref StatusMain);
- SetBit(MSR_CB, ref StatusMain);
- UnSetBit(MSR_EXM, ref StatusMain);
- break;
- case Phase.Execution:
- if (ActiveCommand.Direction == CommandDirection.OUT)
- SetBit(MSR_DIO, ref StatusMain);
- else
- UnSetBit(MSR_DIO, ref StatusMain);
-
- SetBit(MSR_EXM, ref StatusMain);
- SetBit(MSR_CB, ref StatusMain);
-
- // overrun detection
- OverrunCounter++;
- if (OverrunCounter >= 64)
- {
- // CPU has read the status register 64 times without reading the data register
- // switch the current command into result phase
- ActivePhase = Phase.Result;
-
- // reset the overun counter
- OverrunCounter = 0;
- }
-
- break;
- case Phase.Result:
- SetBit(MSR_DIO, ref StatusMain);
- SetBit(MSR_CB, ref StatusMain);
- UnSetBit(MSR_EXM, ref StatusMain);
- break;
- }
-
- //if (!CheckTiming())
- //{
- // UnSetBit(MSR_EXM, ref StatusMain);
- //}
-
- return StatusMain;
- }
-
- //private int testCount = 0;
- ///
- /// Handles CPU reading from the data register
- ///
- private byte ReadDataRegister()
- {
- // default return value
- byte res = 0xff;
-
- // check RQM flag status
- if (!GetBit(MSR_RQM, StatusMain))
- {
- // FDC is not ready to return data
- return res;
- }
-
- // check active direction
- if (!GetBit(MSR_DIO, StatusMain))
- {
- // FDC is expecting to receive, not send data
- return res;
- }
-
- switch (ActivePhase)
- {
- case Phase.Execution:
- // reset overrun counter
- OverrunCounter = 0;
-
- // execute read
- ActiveCommand.CommandDelegate();
-
- res = LastSectorDataReadByte;
-
- if (ExecCounter <= 0)
- {
- // end of execution phase
- ActivePhase = Phase.Result;
- }
-
- return res;
-
- case Phase.Result:
-
- DriveLight = false;
-
- ActiveCommand.CommandDelegate();
-
- // result byte reading
- res = ResBuffer[ResCounter];
-
- // increment result counter
- ResCounter++;
-
- if (ResCounter >= ResLength)
- {
- ActivePhase = Phase.Idle;
- }
-
- break;
- }
-
- return res;
- }
-
- ///
- /// Handles CPU writing to the data register
- ///
- private void WriteDataRegister(byte data)
- {
- if (!GetBit(MSR_RQM, StatusMain) || GetBit(MSR_DIO, StatusMain))
- {
- // FDC will not receive and process any bytes
- return;
- }
-
- // store the incoming byte
- LastByteReceived = data;
-
- // process incoming bytes
- switch (ActivePhase)
- {
- //// controller is idle awaiting the first command byte of a new instruction
- case Phase.Idle:
- ParseCommandByte(data);
- break;
- //// we are in command phase
- case Phase.Command:
- // attempt to process this parameter byte
- //ProcessCommand(data);
- ActiveCommand.CommandDelegate();
- break;
- //// we are in execution phase
- case Phase.Execution:
- // CPU is going to be sending data bytes to the FDC to be written to disk
-
- // store the byte
- LastSectorDataWriteByte = data;
- ActiveCommand.CommandDelegate();
-
- if (ExecCounter <= 0)
- {
- // end of execution phase
- ActivePhase = Phase.Result;
- }
-
- break;
- //// result phase
- case Phase.Result:
- // data register will not receive bytes during result phase
- break;
- }
- }
-
- ///
- /// Processes the first command byte (within a command instruction)
- /// Returns TRUE if successful. FALSE if otherwise
- /// Called only in idle phase
- ///
- private bool ParseCommandByte(byte cmdByte)
- {
- // clear counters
- CommCounter = 0;
- ResCounter = 0;
-
- // get the first 4 bytes
- byte cByte = (byte)(cmdByte & 0x0f);
-
- // get MT, MD and SK states
- CMD_FLAG_MT = cmdByte.Bit(7);
- CMD_FLAG_MF = cmdByte.Bit(6);
- CMD_FLAG_SK = cmdByte.Bit(5);
-
- cmdByte = cByte;
-
- // lookup the command
- var cmd = CommandList.FirstOrDefault(a => a.CommandCode == cmdByte);
-
- if (cmd == null)
- {
- // no command found - use invalid
- CMDIndex = CommandList.Count() - 1;
- }
- else
- {
- // valid command found
- CMDIndex = CommandList.FindIndex(a => a.CommandCode == cmdByte);
-
- // check validity of command byte flags
- // if a flag is set but not valid for this command then it is invalid
- bool invalid = false;
-
- if (!ActiveCommand.MT)
- if (CMD_FLAG_MT)
- invalid = true;
- if (!ActiveCommand.MF)
- if (CMD_FLAG_MF)
- invalid = true;
- if (!ActiveCommand.SK)
- if (CMD_FLAG_SK)
- invalid = true;
-
- if (invalid)
- {
- // command byte included spurious bit 5,6 or 7 flags
- CMDIndex = CommandList.Count() - 1;
- }
-
- /*
- if ((CMD_FLAG_MF && !ActiveCommand.MF) ||
- (CMD_FLAG_MT && !ActiveCommand.MT) ||
- (CMD_FLAG_SK && !ActiveCommand.SK))
- {
- // command byte included spurious bit 5,6 or 7 flags
- CMDIndex = CommandList.Count() - 1;
- }
- */
- }
-
- CommCounter = 0;
- ResCounter = 0;
-
- // there will now be an active command set
- // move to command phase
- ActivePhase = Phase.Command;
-
- /*
- // check for invalid SIS
- if (ActiveInterrupt == InterruptState.None && CMDIndex == CC_SENSE_INTSTATUS)
- {
- CMDIndex = CC_INVALID;
- //ActiveCommand.CommandDelegate(InstructionState.StartResult);
- }
- */
-
- // set reslength
- ResLength = ActiveCommand.ResultByteCount;
-
- // if there are no expected param bytes to receive - go ahead and run the command
- if (ActiveCommand.ParameterByteCount == 0)
- {
- ActivePhase = Phase.Execution;
- ActiveCommand.CommandDelegate();
- }
-
- return true;
- }
-
- ///
- /// Parses the first 5 command argument bytes that are of the standard format
- ///
- private void ParseParamByteStandard(int index)
- {
- byte currByte = CommBuffer[index];
- BitArray bi = new BitArray(new byte[] { currByte });
-
- switch (index)
- {
- // HD & US
- case CM_HEAD:
- if (bi[2])
- ActiveCommandParams.Side = 1;
- else
- ActiveCommandParams.Side = 0;
-
- ActiveCommandParams.UnitSelect = (byte)(GetUnitSelect(currByte));
- DiskDriveIndex = ActiveCommandParams.UnitSelect;
- break;
-
- // C
- case CM_C:
- ActiveCommandParams.Cylinder = currByte;
- break;
-
- // H
- case CM_H:
- ActiveCommandParams.Head = currByte;
- break;
-
- // R
- case CM_R:
- ActiveCommandParams.Sector = currByte;
- break;
-
- // N
- case CM_N:
- ActiveCommandParams.SectorSize = currByte;
- break;
-
- // EOT
- case CM_EOT:
- ActiveCommandParams.EOT = currByte;
- break;
-
- // GPL
- case CM_GPL:
- ActiveCommandParams.Gap3Length = currByte;
- break;
-
- // DTL
- case CM_DTL:
- ActiveCommandParams.DTL = currByte;
- break;
-
- default:
- break;
- }
- }
-
- ///
- /// Clears the result buffer
- ///
- public void ClearResultBuffer()
- {
- for (int i = 0; i < ResBuffer.Length; i++)
- {
- ResBuffer[i] = 0;
- }
- }
-
- ///
- /// Clears the result buffer
- ///
- public void ClearExecBuffer()
- {
- for (int i = 0; i < ExecBuffer.Length; i++)
- {
- ExecBuffer[i] = 0;
- }
- }
-
- ///
- /// Populates the result status registers
- ///
- private void CommitResultStatus()
- {
- // check for read diag
- if (ActiveCommand.CommandCode == 0x02)
- {
- // commit to result buffer
- ResBuffer[RS_ST0] = Status0;
- ResBuffer[RS_ST1] = Status1;
- return;
- }
-
- // check for error bits
- if (GetBit(SR1_DE, Status1) ||
- GetBit(SR1_MA, Status1) ||
- GetBit(SR1_ND, Status1) ||
- GetBit(SR1_NW, Status1) ||
- GetBit(SR1_OR, Status1) ||
- GetBit(SR2_BC, Status2) ||
- GetBit(SR2_CM, Status2) ||
- GetBit(SR2_DD, Status2) ||
- GetBit(SR2_MD, Status2) ||
- GetBit(SR2_SN, Status2) ||
- GetBit(SR2_WC, Status2))
- {
- // error bits set - unset end of track
- UnSetBit(SR1_EN, ref Status1);
- }
-
- // check for data errors
- if (GetBit(SR1_DE, Status1) ||
- GetBit(SR2_DD, Status2))
- {
- // unset control mark
- UnSetBit(SR2_CM, ref Status2);
- }
- else if (GetBit(SR2_CM, Status2))
- {
- // DAM found - unset IC and US0
- UnSetBit(SR0_IC0, ref Status0);
- UnSetBit(SR0_US0, ref Status0);
- }
-
- // commit to result buffer
- ResBuffer[RS_ST0] = Status0;
- ResBuffer[RS_ST1] = Status1;
- ResBuffer[RS_ST2] = Status2;
-
- }
-
- ///
- /// Populates the result CHRN values
- ///
- private void CommitResultCHRN()
- {
- ResBuffer[RS_C] = ActiveCommandParams.Cylinder;
- ResBuffer[RS_H] = ActiveCommandParams.Head;
- ResBuffer[RS_R] = ActiveCommandParams.Sector;
- ResBuffer[RS_N] = ActiveCommandParams.SectorSize;
- }
-
- ///
- /// Moves active phase into idle
- ///
- public void SetPhase_Idle()
- {
- ActivePhase = Phase.Idle;
-
- // active direction
- UnSetBit(MSR_DIO, ref StatusMain);
- // CB
- UnSetBit(MSR_CB, ref StatusMain);
- // RQM
- SetBit(MSR_RQM, ref StatusMain);
-
- CommCounter = 0;
- ResCounter = 0;
- }
-
- ///
- /// Moves to result phase
- ///
- public void SetPhase_Result()
- {
- ActivePhase = Phase.Result;
-
- // active direction
- SetBit(MSR_DIO, ref StatusMain);
- // CB
- SetBit(MSR_CB, ref StatusMain);
- // RQM
- SetBit(MSR_RQM, ref StatusMain);
- // EXM
- UnSetBit(MSR_EXM, ref StatusMain);
-
- CommCounter = 0;
- ResCounter = 0;
- }
-
- ///
- /// Moves to command phase
- ///
- public void SetPhase_Command()
- {
- ActivePhase = Phase.Command;
-
- // default 0x80 - just RQM
- SetBit(MSR_RQM, ref StatusMain);
- UnSetBit(MSR_DIO, ref StatusMain);
- UnSetBit(MSR_CB, ref StatusMain);
- UnSetBit(MSR_EXM, ref StatusMain);
- CommCounter = 0;
- ResCounter = 0;
- }
-
- ///
- /// Moves to execution phase
- ///
- public void SetPhase_Execution()
- {
- ActivePhase = Phase.Execution;
-
- // EXM
- SetBit(MSR_EXM, ref StatusMain);
- // CB
- SetBit(MSR_CB, ref StatusMain);
- // RQM
- UnSetBit(MSR_RQM, ref StatusMain);
-
- CommCounter = 0;
- ResCounter = 0;
- }
-
- #endregion
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/NECUPD765.FDD.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/NECUPD765.FDD.cs
deleted file mode 100644
index 5ea4b182a4..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/NECUPD765.FDD.cs
+++ /dev/null
@@ -1,876 +0,0 @@
-using BizHawk.Common;
-using BizHawk.Common.NumberExtensions;
-using System;
-using System.Linq;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// Floppy drive related stuff
- ///
- #region Attribution
- /*
- Implementation based on the information contained here:
- http://www.cpcwiki.eu/index.php/765_FDC
- and here:
- http://www.cpcwiki.eu/imgs/f/f3/UPD765_Datasheet_OCRed.pdf
- */
- #endregion
- public partial class NECUPD765 : IFDDHost
- {
- #region Drive State
-
- ///
- /// FDD Flag - motor on/off
- ///
- public bool FDD_FLAG_MOTOR;
-
- ///
- /// The index of the currently active disk drive
- ///
- public int DiskDriveIndex
- {
- get => _diskDriveIndex;
- set
- {
- // when index is changed update the ActiveDrive
- _diskDriveIndex = value;
- ActiveDrive = DriveStates[_diskDriveIndex];
- }
- }
- private int _diskDriveIndex = 0;
-
- ///
- /// The currently active drive
- ///
- private DriveState ActiveDrive;
-
- ///
- /// Array that holds state information for each possible drive
- ///
- private DriveState[] DriveStates = new DriveState[4];
-
- #endregion
-
- #region FDD Methods
-
- ///
- /// Initialization / reset of the floppy drive subsystem
- ///
- private void FDD_Init()
- {
- for (int i = 0; i < 4; i++)
- {
- DriveState ds = new DriveState(i, this);
- DriveStates[i] = ds;
- }
- }
-
- ///
- /// Searches for the requested sector
- ///
- private FloppyDisk.Sector GetSector()
- {
- FloppyDisk.Sector sector = null;
-
- // get the current track
- var trk = ActiveDrive.Disk.DiskTracks[ActiveDrive.TrackIndex];
-
- // get the current sector index
- int index = ActiveDrive.SectorIndex;
-
- // make sure this index exists
- if (index > trk.Sectors.Length)
- {
- index = 0;
- }
-
- // index hole count
- int iHole = 0;
-
- // loop through the sectors in a track
- // the loop ends with either the sector being found
- // or the index hole being passed twice
- while (iHole <= 2)
- {
- // does the requested sector match the current sector
- if (trk.Sectors[index].SectorIDInfo.C == ActiveCommandParams.Cylinder &&
- trk.Sectors[index].SectorIDInfo.H == ActiveCommandParams.Head &&
- trk.Sectors[index].SectorIDInfo.R == ActiveCommandParams.Sector &&
- trk.Sectors[index].SectorIDInfo.N == ActiveCommandParams.SectorSize)
- {
- // sector has been found
- sector = trk.Sectors[index];
-
- UnSetBit(SR2_BC, ref Status2);
- UnSetBit(SR2_WC, ref Status2);
- break;
- }
-
- // check for bad cylinder
- if (trk.Sectors[index].SectorIDInfo.C == 255)
- {
- SetBit(SR2_BC, ref Status2);
- }
- // check for no cylinder
- else if (trk.Sectors[index].SectorIDInfo.C != ActiveCommandParams.Cylinder)
- {
- SetBit(SR2_WC, ref Status2);
- }
-
- // incrememnt sector index
- index++;
-
- // have we reached the index hole?
- if (trk.Sectors.Length <= index)
- {
- // wrap around
- index = 0;
- iHole++;
- }
- }
-
- // search loop has completed and the sector may or may not have been found
-
- // bad cylinder detected?
- if (Status2.Bit(SR2_BC))
- {
- // remove WC
- UnSetBit(SR2_WC, ref Status2);
- }
-
- // update sectorindex on drive
- ActiveDrive.SectorIndex = index;
-
- return sector;
- }
-
- #endregion
-
- #region IFDDHost
-
- // IFDDHost methods that fall through to the currently active drive
-
- ///
- /// Parses a new disk image and loads it into this floppy drive
- ///
- public void FDD_LoadDisk(byte[] diskData)
- {
- // we are only going to load into the first drive
- DriveStates[0].FDD_LoadDisk(diskData);
- }
-
- ///
- /// Ejects the current disk
- ///
- public void FDD_EjectDisk()
- {
- DriveStates[0].FDD_EjectDisk();
- }
-
- ///
- /// Signs whether the current active drive has a disk inserted
- ///
- public bool FDD_IsDiskLoaded => DriveStates[DiskDriveIndex].FDD_IsDiskLoaded;
-
- ///
- /// Returns the disk object from drive 0
- ///
- public FloppyDisk DiskPointer => DriveStates[0].Disk;
-
- public FloppyDisk Disk { get; set; }
-
- #endregion
-
- #region Drive Status Class
-
- ///
- /// Holds specfic state information about a drive
- ///
- private class DriveState : IFDDHost
- {
- #region State
-
- ///
- /// The drive ID from an FDC perspective
- ///
- public int ID;
-
- ///
- /// Signs whether this drive ready
- /// TRUE if both drive exists and has a disk inserted
- ///
- public bool FLAG_READY
- {
- get
- {
- if (!FDD_IsDiskLoaded || Disk.GetTrackCount() == 0 || !FDC.FDD_FLAG_MOTOR)
- return false;
- else
- return true;
- }
- }
-
- ///
- /// Disk is write protected (TRUE BY DEFAULT)
- ///
- public bool FLAG_WRITEPROTECT = false;
-
- ///
- /// Storage for seek steps
- /// One step for each indexpulse (track index) until seeked track
- ///
- public int SeekCounter;
-
- ///
- /// Seek status
- ///
- public int SeekStatus;
-
- ///
- /// Age counter
- ///
- public int SeekAge;
-
- ///
- /// The current side
- ///
- public byte CurrentSide;
-
- ///
- /// The current track index in the DiskTracks array
- ///
- public byte TrackIndex;
-
- ///
- /// The track ID of the current cylinder
- ///
- public byte CurrentTrackID
- {
- get
- {
- // default invalid track
- int id = 0xff;
-
- if (Disk == null)
- return (byte)id;
-
- if (Disk.DiskTracks.Count() == 0)
- return (byte)id;
-
- if (TrackIndex >= Disk.GetTrackCount())
- TrackIndex = 0;
- else if (TrackIndex < 0)
- TrackIndex = 0;
-
- var track = Disk.DiskTracks[TrackIndex];
-
- id = track.TrackNumber;
-
- return (byte)id;
- }
- set
- {
- for (int i = 0; i < Disk.GetTrackCount(); i++)
- {
- if (Disk.DiskTracks[i].TrackNumber == value)
- {
- TrackIndex = (byte)i;
- break;
- }
- }
- }
- }
-
-
- ///
- /// The new track that the drive is seeking to
- /// (used in seek operations)
- ///
- public int SeekingTrack;
-
- ///
- /// The current sector index in the Sectors array
- ///
- public int SectorIndex;
-
- ///
- /// The currently loaded floppy disk
- ///
- public FloppyDisk Disk { get; set; }
-
- ///
- /// The parent controller
- ///
- private NECUPD765 FDC;
-
- #endregion
-
- #region Lookups
-
- ///
- /// TRUE if we are on track 0
- ///
- public bool FLAG_TRACK0 => TrackIndex == 0;
-
- #endregion
-
- #region Public Methods
- /*
- ///
- /// Moves the head across the disk cylinders
- ///
- public void MoveHead(SkipDirection direction, int cylinderCount)
- {
- // get total tracks
- int trackCount = Disk.DiskTracks.Count();
-
- int trk = 0;
-
- switch (direction)
- {
- case SkipDirection.Increment:
- trk = (int)CurrentTrack + cylinderCount;
- if (trk >= trackCount)
- {
- // past the last track
- trk = trackCount - 1;
- }
- else if (trk < 0)
- trk = 0;
- break;
- case SkipDirection.Decrement:
- trk = (int)CurrentTrack - cylinderCount;
- if (trk < 0)
- {
- // before the first track
- trk = 0;
- }
- else if (trk >= trackCount)
- trk = trackCount - 1;
- break;
- }
-
- // move the head
- CurrentTrack = (byte)trk;
- }
- */
-
- /*
-
- ///
- /// Finds a supplied sector
- ///
- public FloppyDisk.Sector FindSector(ref byte[] resBuffer, CommandParameters prms)
- {
- int index =CurrentSector;
- int lc = 0;
- FloppyDisk.Sector sector = null;
-
- bool found = false;
-
- do
- {
- sector = Disk.DiskTracks[CurrentTrack].Sectors[index];
- if (sector != null && sector.SectorID == prms.Sector)
- {
- // sector found
- // check for data errors
- if ((sector.Status1 & 0x20) != 0 || (sector.Status2 & 0x20) != 0)
- {
- // data errors found
- }
- found = true;
- break;
- }
-
- // sector doesnt match
- var c = Disk.DiskTracks[CurrentTrack].Sectors[index].TrackNumber;
- if (c == 255)
- {
- // bad cylinder
- resBuffer[RS_ST2] |= 0x02;
- }
- else if (prms.Cylinder != c)
- {
- // cylinder mismatch
- resBuffer[RS_ST2] |= 0x10;
- }
-
- // increment index
- index++;
-
- if (index >= Disk.DiskTracks[CurrentTrack].NumberOfSectors)
- {
- // out of bounds
- index = 0;
- lc++;
- }
-
- } while (lc < 2);
-
- if ((resBuffer[RS_ST2] & 0x02) != 0)
- {
- // bad cylinder set - remove no cylinder
- UnSetBit(SR2_WC, ref resBuffer[RS_ST2]);
- }
-
- // update current sector
- CurrentSector = index;
-
- if (found)
- return sector;
- else
- return null;
- }
-
-
- ///
- /// Populates a result buffer
- ///
- public void FillResult(ref byte[] resBuffer, CHRN chrn)
- {
- // clear results
- resBuffer[RS_ST0] = 0;
- resBuffer[RS_ST1] = 0;
- resBuffer[RS_ST2] = 0;
- resBuffer[RS_C] = 0;
- resBuffer[RS_H] = 0;
- resBuffer[RS_R] = 0;
- resBuffer[RS_N] = 0;
-
- if (chrn == null)
- {
- // no chrn supplied
- resBuffer[RS_ST0] = ST0;
- resBuffer[RS_ST1] = 0;
- resBuffer[RS_ST2] = 0;
- resBuffer[RS_C] = 0;
- resBuffer[RS_H] = 0;
- resBuffer[RS_R] = 0;
- resBuffer[RS_N] = 0;
- }
- }
-
-
-
- ///
- /// Populates the result buffer with ReadID data
- ///
- public void ReadID(ref byte[] resBuffer)
- {
- if (CheckDriveStatus() == false)
- {
- // drive not ready
- resBuffer[RS_ST0] = ST0;
- return;
- }
-
- var track = Disk.DiskTracks.Where(a => a.TrackNumber == CurrentTrack).FirstOrDefault();
-
- if (track != null && track.NumberOfSectors > 0)
- {
- // formatted track
-
- // get the current sector
- int index = CurrentSector;
-
- // is the index out of bounds?
- if (index >= track.NumberOfSectors)
- {
- // reset the index
- index = 0;
- }
-
- // read the sector data
- var data = track.Sectors[index];
- resBuffer[RS_C] = data.TrackNumber;
- resBuffer[RS_H] = data.SideNumber;
- resBuffer[RS_R] = data.SectorID;
- resBuffer[RS_N] = data.SectorSize;
-
- resBuffer[RS_ST0] = ST0;
-
- // increment the current sector
- CurrentSector = index + 1;
- return;
- }
- else
- {
- // unformatted track?
- resBuffer[RS_C] = FDC.CommBuffer[CM_C];
- resBuffer[RS_H] = FDC.CommBuffer[CM_H];
- resBuffer[RS_R] = FDC.CommBuffer[CM_R];
- resBuffer[RS_N] = FDC.CommBuffer[CM_N];
-
- SetBit(SR0_IC0, ref ST0);
- resBuffer[RS_ST0] = ST0;
- resBuffer[RS_ST1] = 0x01;
- return;
- }
- }
- */
-
- /*
-
- ///
- /// The drive performs a seek operation if necessary
- /// Return value TRUE indicates seek complete
- ///
- public void DoSeek()
- {
- if (CurrentState != DriveMainState.Recalibrate &&
- CurrentState != DriveMainState.Seek)
- {
- // no seek/recalibrate has been asked for
- return;
- }
-
- if (GetBit(ID, FDC.StatusMain))
- {
- // drive is already seeking
- return;
- }
-
- RunSeekCycle();
- }
-
- ///
- /// Runs a seek cycle
- ///
- public void RunSeekCycle()
- {
- for (;;)
- {
- switch (SeekState)
- {
- // seek or recalibrate has been requested
- case SeekSubState.Idle:
-
- if (CurrentState == DriveMainState.Recalibrate)
- {
- // recalibrate always seeks to track 0
- SeekingTrack = 0;
- }
- SeekState = SeekSubState.MoveInit;
-
- // mark drive as busy
- // this should be cleared by SIS command
- SetBit(ID, ref FDC.StatusMain);
-
- break;
-
- // setup for the head move
- case SeekSubState.MoveInit:
-
- if (CurrentTrack == SeekingTrack)
- {
- // we are already at the required track
- if (CurrentState == DriveMainState.Recalibrate &&
- !FLAG_TRACK0)
- {
- // recalibration fail
- SeekIntState = SeekIntStatus.Abnormal;
-
- // raise seek interrupt
- FDC.ActiveInterrupt = InterruptState.Seek;
-
- // unset DB bit
- UnSetBit(ID, ref FDC.StatusMain);
-
- // equipment check
- SetBit(SR0_EC, ref FDC.Status0);
-
- SeekState = SeekSubState.PerformCompletion;
- break;
- }
-
- if (CurrentState == DriveMainState.Recalibrate &&
- FLAG_TRACK0)
- {
- // recalibration success
- SeekIntState = SeekIntStatus.Normal;
-
- // raise seek interrupt
- FDC.ActiveInterrupt = InterruptState.Seek;
-
- // unset DB bit
- UnSetBit(ID, ref FDC.StatusMain);
-
- SeekState = SeekSubState.PerformCompletion;
- break;
- }
- }
-
- // check for error
- if (IntStatus >= IC_ABORTED_DISCREMOVED || Disk == null)
- {
- // drive not ready
- FLAG_READY = false;
-
- // drive not ready
- SeekIntState = SeekIntStatus.DriveNotReady;
-
- // cancel any interrupt
- FDC.ActiveInterrupt = InterruptState.None;
-
- // unset DB bit
- UnSetBit(ID, ref FDC.StatusMain);
-
- SeekState = SeekSubState.PerformCompletion;
- break;
- }
-
- if (SeekCounter > 1)
- {
- // not ready to seek yet
- SeekCounter--;
- return;
- }
-
- if (FDC.SRT < 1 && CurrentTrack != SeekingTrack)
- {
- SeekState = SeekSubState.MoveImmediate;
- break;
- }
-
- // head move
- SeekState = SeekSubState.HeadMove;
-
- break;
-
- case SeekSubState.HeadMove:
-
- // do the seek
- SeekCounter = FDC.SRT;
-
- if (CurrentTrack < SeekingTrack)
- {
- // we are seeking forward
- var delta = SeekingTrack - CurrentTrack;
- MoveHead(SkipDirection.Increment, 1);
- }
- else if (CurrentTrack > SeekingTrack)
- {
- // we are seeking backward
- var delta = CurrentTrack - SeekingTrack;
- MoveHead(SkipDirection.Decrement, 1);
- }
-
- // should the seek be completed now?
- if (CurrentTrack == SeekingTrack)
- {
- SeekState = SeekSubState.PerformCompletion;
- break;
- }
-
- // seek not finished yet
- return;
-
- // seek emulation processed immediately
- case SeekSubState.MoveImmediate:
-
- if (CurrentTrack < SeekingTrack)
- {
- // we are seeking forward
- var delta = SeekingTrack - CurrentTrack;
- MoveHead(SkipDirection.Increment, delta);
-
- }
- else if (CurrentTrack > SeekingTrack)
- {
- // we are seeking backward
- var delta = CurrentTrack - SeekingTrack;
- MoveHead(SkipDirection.Decrement, delta);
- }
-
- SeekState = SeekSubState.PerformCompletion;
- break;
-
- case SeekSubState.PerformCompletion:
- SeekDone();
- SeekState = SeekSubState.SeekCompleted;
- break;
-
- case SeekSubState.SeekCompleted:
- // seek has already completed
- return;
- }
- }
- }
-
- ///
- /// Called when a seek operation has completed
- ///
- public void SeekDone()
- {
- SeekCounter = 0;
- SeekingTrack = CurrentTrack;
-
- // generate ST0 register data
-
- // get only the IC bits
- IntStatus &= IC_ABORTED_DISCREMOVED;
-
- // drive ready?
- if (!FLAG_READY)
- {
- SetBit(SR0_NR, ref IntStatus);
- SetBit(SR0_EC, ref IntStatus);
-
- // are we recalibrating?
- if (CurrentState == DriveMainState.Recalibrate)
- {
- SetBit(SR0_EC, ref IntStatus);
- }
- }
-
- // set seek end
- SetBit(SR0_SE, ref IntStatus);
- /*
- // head address
- if (CurrentSide > 0)
- {
- SetBit(SR0_HD, ref IntStatus);
-
- // drive only supports 1 head
- // set the EC bit
- SetBit(SR0_EC, ref IntStatus);
- }
- */
- /*
- // UnitSelect
- SetUnitSelect(ID, ref IntStatus);
-
- // move to none state
- //CurrentState = DriveMainState.None;
-
- //SeekState = SeekSubState.SeekCompleted;
-
- // set the seek interrupt flag for this drive
- // this will be cleared at the next successful senseint
- FLAG_SEEK_INTERRUPT = true;
-
- //CurrentState = DriveMainState.None;
-
- }
- */
-
- #endregion
-
- #region Construction
-
- public DriveState(int driveID, NECUPD765 fdc)
- {
- ID = driveID;
- FDC = fdc;
- }
-
- #endregion
-
- #region IFDDHost
-
- ///
- /// Parses a new disk image and loads it into this floppy drive
- ///
- public void FDD_LoadDisk(byte[] diskData)
- {
- // try dsk first
- FloppyDisk fdd = null;
- bool found = false;
-
- foreach (DiskType type in Enum.GetValues(typeof(DiskType)))
- {
- switch (type)
- {
- case DiskType.CPCExtended:
- fdd = new CPCExtendedFloppyDisk();
- found = fdd.ParseDisk(diskData);
- break;
- case DiskType.CPC:
- fdd = new CPCFloppyDisk();
- found = fdd.ParseDisk(diskData);
- break;
- case DiskType.IPF:
- fdd = new IPFFloppyDisk();
- found = fdd.ParseDisk(diskData);
- break;
- case DiskType.UDI:
- fdd = new UDI1_0FloppyDisk();
- found = fdd.ParseDisk(diskData);
- break;
- }
-
- if (found)
- {
- Disk = fdd;
- break;
- }
- }
-
- if (!found)
- {
- throw new Exception(this.GetType().ToString() +
- "\n\nDisk image file could not be parsed. Potentially an unknown format.");
- }
- }
-
- ///
- /// Ejects the current disk
- ///
- public void FDD_EjectDisk()
- {
- Disk = null;
- //FLAG_READY = false;
- }
-
- ///
- /// Signs whether the current active drive has a disk inserted
- ///
- public bool FDD_IsDiskLoaded
- {
- get
- {
- if (Disk != null)
- return true;
- else
- return false;
- }
- }
-
- #endregion
-
- #region StateSerialization
-
- public void SyncState(Serializer ser)
- {
- ser.Sync(nameof(ID), ref ID);
- ser.Sync(nameof(FLAG_WRITEPROTECT), ref FLAG_WRITEPROTECT);
- //ser.Sync(nameof(FLAG_DISKCHANGED), ref FLAG_DISKCHANGED);
- //ser.Sync(nameof(FLAG_RECALIBRATING), ref FLAG_RECALIBRATING);
- //ser.Sync(nameof(FLAG_SEEK_INTERRUPT), ref FLAG_SEEK_INTERRUPT);
- //ser.Sync(nameof(IntStatus), ref IntStatus);
- //ser.Sync(nameof(ST0), ref ST0);
- //ser.Sync(nameof(RecalibrationCounter), ref RecalibrationCounter);
- ser.Sync(nameof(SeekCounter), ref SeekCounter);
- ser.Sync(nameof(SeekStatus), ref SeekStatus);
- ser.Sync(nameof(SeekAge), ref SeekAge);
- ser.Sync(nameof(CurrentSide), ref CurrentSide);
- //ser.Sync(nameof(CurrentTrack), ref CurrentTrack);
- ser.Sync(nameof(TrackIndex), ref TrackIndex);
- ser.Sync(nameof(SeekingTrack), ref SeekingTrack);
- //ser.Sync(nameof(CurrentSector), ref CurrentSector);
- ser.Sync(nameof(SectorIndex), ref SectorIndex);
- //ser.Sync(nameof(RAngles), ref RAngles);
- //ser.Sync(nameof(DataPointer), ref DataPointer);
- //ser.SyncEnum(nameof(CurrentState), ref CurrentState);
- //ser.SyncEnum(nameof(SeekState), ref SeekState);
- //ser.SyncEnum(nameof(SeekIntState), ref SeekIntState);
- }
-
- #endregion
- }
-
- #endregion
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/NECUPD765.IPortIODevice.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/NECUPD765.IPortIODevice.cs
deleted file mode 100644
index 7964653bab..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/NECUPD765.IPortIODevice.cs
+++ /dev/null
@@ -1,145 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Text;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// IPortIODevice
- ///
- #region Attribution
- /*
- Implementation based on the information contained here:
- http://www.cpcwiki.eu/index.php/765_FDC
- and here:
- http://www.cpcwiki.eu/imgs/f/f3/UPD765_Datasheet_OCRed.pdf
- */
- #endregion
- public partial class NECUPD765 : IPortIODevice
- {
- #region Dev Logging
-
- public string outputfile = @"D:\Dropbox\Dropbox\_Programming\TASVideos\BizHawk\output\zxhawkio-" + DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".csv";
- public string outputString = "STATUS,WRITE,READ,CODE,MT,MF,SK,CMDCNT,RESCNT,EXECCNT,EXECLEN\r\n";
- public bool writeDebug = false;
-
- public List dLog = new List
- {
- "STATUS,WRITE,READ,CODE,MT,MF,SK,CMDCNT,RESCNT,EXECCNT,EXECLEN"
- };
-
-
- /*
- * Status read
- * Data write
- * Data read
- * CMD code
- * CMD string
- * MT flag
- * MK flag
- * SK flag
- * */
- private string[] workingArr = new string[3];
-
- private void BuildCSVLine()
- {
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < 3; i++)
- {
- sb.Append(workingArr[i]);
- sb.Append(",");
- workingArr[i] = "";
- }
-
- sb.Append(ActiveCommand.CommandCode).Append(",");
-
- sb.Append(CMD_FLAG_MT).Append(",");
- sb.Append(CMD_FLAG_MF).Append(",");
- sb.Append(CMD_FLAG_SK).Append(",");
-
- sb.Append(CommCounter).Append(",");
- sb.Append(ResCounter).Append(",");
- sb.Append(ExecCounter).Append(",");
- sb.Append(ExecLength);
-
- //sb.Append("\r\n");
-
- //outputString += sb.ToString();
- dLog.Add(sb.ToString());
- }
-
- #endregion
-
- ///
- /// Device responds to an IN instruction
- ///
- public bool ReadPort(ushort port, ref int data)
- {
- BitArray bits = new BitArray(new byte[] { (byte)data });
-
- if (port == 0x3ffd)
- {
- // Z80 is trying to read from the data register
- data = ReadDataRegister();
- if (writeDebug)
- {
- workingArr[2] = data.ToString();
- //outputString += ",," + data + "," + ActiveCommand.CommandCode + "\r\n";
- BuildCSVLine();
- }
-
- return true;
- }
-
- if (port == 0x2ffd)
- {
- // read main status register
- // this can happen at any time
- data = ReadMainStatus();
- if (writeDebug)
- {
- //outputString += data + ",,," + ActiveCommand.CommandCode + "\r\n";
- workingArr[0] = data.ToString();
- BuildCSVLine();
- //System.IO.File.WriteAllText(outputfile, outputString);
- }
-
- return true;
- }
-
- return false;
- }
-
- ///
- /// Device responds to an OUT instruction
- ///
- public bool WritePort(ushort port, int data)
- {
- BitArray bits = new BitArray(new byte[] { (byte)data });
-
- if (port == 0x3ffd)
- {
- // Z80 is attempting to write to the data register
- WriteDataRegister((byte)data);
- if (writeDebug)
- {
- //outputString += "," + data + ",," + ActiveCommand.CommandCode + "\r\n";
- workingArr[1] = data.ToString();
- BuildCSVLine();
- //System.IO.File.WriteAllText(outputfile, outputString);
- }
-
- return true;
- }
-
- if (port == 0x1ffd)
- {
- // set disk motor on/off
- FDD_FLAG_MOTOR = bits[3];
- return true;
- }
- return false;
- }
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/NECUPD765.Timing.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/NECUPD765.Timing.cs
deleted file mode 100644
index 2ef6f4080d..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/NECUPD765.Timing.cs
+++ /dev/null
@@ -1,120 +0,0 @@
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// Timimng
- ///
- #region Attribution
- /*
- Implementation based on the information contained here:
- http://www.cpcwiki.eu/index.php/765_FDC
- and here:
- http://www.cpcwiki.eu/imgs/f/f3/UPD765_Datasheet_OCRed.pdf
- */
- #endregion
- public partial class NECUPD765
- {
- ///
- /// The current Z80 cycle
- ///
- private long CurrentCPUCycle
- {
- get
- {
- if (_machine == null)
- return 0;
- else
- return _machine.CPU.TotalExecutedCycles;
- }
- }
-
- ///
- /// The last CPU cycle when the FDC accepted an IO read/write
- ///
- private long LastCPUCycle;
-
- ///
- /// The current delay figure (in Z80 t-states)
- /// This implementation only introduces delay upon main status register reads
- /// All timing calculations should be done during the other read/write operations
- ///
- private long StatusDelay;
-
- ///
- /// Defines the numbers of Z80 cycles per MS
- ///
- private long CPUCyclesPerMs;
-
- ///
- /// The floppy drive emulated clock speed
- ///
- public const double DriveClock = 31250;
-
- ///
- /// The number of floppy drive cycles per MS
- ///
- public long DriveCyclesPerMs;
-
- ///
- /// The number of T-States in one floppy drive clock tick
- ///
- public long StatesPerDriveTick;
-
- ///
- /// Responsible for measuring when the floppy drive is ready to run a cycle
- ///
- private long TickCounter;
-
- ///
- /// Internal drive cycle counter
- ///
- private int DriveCycleCounter = 1;
-
- ///
- /// Initializes the timing routines
- ///
- private void TimingInit()
- {
- // z80 timing
- double frameSize = _machine.ULADevice.FrameLength;
- double rRate = _machine.ULADevice.ClockSpeed / frameSize;
- long tPerSecond = (long)(frameSize * rRate);
- CPUCyclesPerMs = tPerSecond / 1000;
-
- // drive timing
- double dRate = DriveClock / frameSize;
- long dPerSecond = (long)(frameSize * dRate);
- DriveCyclesPerMs = dPerSecond / 1000;
-
- long TStatesPerDriveCycle = (long)((double)_machine.ULADevice.ClockSpeed / DriveClock);
- StatesPerDriveTick = TStatesPerDriveCycle;
-
- }
-
- ///
- /// Called by reads to the main status register
- /// Returns true if there is no delay
- /// Returns false if read is to be deferred
- ///
- private bool CheckTiming()
- {
- // get delta
- long delta = CurrentCPUCycle - LastCPUCycle;
-
- if (StatusDelay >= delta)
- {
- // there is still delay remaining
- StatusDelay -= delta;
- LastCPUCycle = CurrentCPUCycle;
- return false;
- }
- else
- {
- // no delay remaining
- StatusDelay = 0;
- LastCPUCycle = CurrentCPUCycle;
- return true;
- }
- }
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/NECUPD765.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/NECUPD765.cs
deleted file mode 100644
index a248f6fd76..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/NECUPD765.cs
+++ /dev/null
@@ -1,248 +0,0 @@
-using BizHawk.Common;
-using System.Collections.Generic;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// The NEC floppy disk controller (and floppy drive) found in the +3
- ///
- #region Attribution
- /*
- Implementation based on the information contained here:
- http://www.cpcwiki.eu/index.php/765_FDC
- and here:
- http://www.cpcwiki.eu/imgs/f/f3/UPD765_Datasheet_OCRed.pdf
- */
- #endregion
- public partial class NECUPD765
- {
- #region Devices
-
- ///
- /// The emulated spectrum machine
- ///
- private SpectrumBase _machine;
-
- #endregion
-
- #region Construction & Initialization
-
- ///
- /// Main constructor
- ///
- public NECUPD765()
- {
- InitCommandList();
- }
-
- ///
- /// Initialization routine
- ///
- public void Init(SpectrumBase machine)
- {
- _machine = machine;
- FDD_Init();
- TimingInit();
- Reset();
- }
-
- ///
- /// Resets the FDC
- ///
- public void Reset()
- {
- // setup main status
- StatusMain = 0;
-
- Status0 = 0;
- Status1 = 0;
- Status2 = 0;
- Status3 = 0;
-
- SetBit(MSR_RQM, ref StatusMain);
-
- SetPhase_Idle();
-
- //FDC_FLAG_RQM = true;
- //ActiveDirection = CommandDirection.IN;
- SRT = 6;
- HUT = 16;
- HLT = 2;
- HLT_Counter = 0;
- HUT_Counter = 0;
- IndexPulseCounter = 0;
- CMD_FLAG_MF = false;
-
- foreach (var d in DriveStates)
- {
- //d.SeekingTrack = d.CurrentTrack;
- ////d.SeekCounter = 0;
- //d.FLAG_SEEK_INTERRUPT = false;
- //d.IntStatus = 0;
- //d.SeekState = SeekSubState.Idle;
- //d.SeekIntState = SeekIntStatus.Normal;
-
- }
-
- }
-
- ///
- /// Setup the command structure
- /// Each command represents one of the internal UPD765 commands
- ///
- private void InitCommandList()
- {
- CommandList = new List
- {
- // read data
- new Command { CommandDelegate = UPD_ReadData, CommandCode = 0x06, MT = true, MF = true, SK = true, IsRead = true,
- Direction = CommandDirection.OUT, ParameterByteCount = 8, ResultByteCount = 7 },
- // read id
- new Command { CommandDelegate = UPD_ReadID, CommandCode = 0x0a, MF = true, IsRead = true,
- Direction = CommandDirection.OUT, ParameterByteCount = 1, ResultByteCount = 7 },
- // specify
- new Command { CommandDelegate = UPD_Specify, CommandCode = 0x03,
- Direction = CommandDirection.OUT, ParameterByteCount = 2, ResultByteCount = 0 },
- // read diagnostic
- new Command { CommandDelegate = UPD_ReadDiagnostic, CommandCode = 0x02, MF = true, SK = true, IsRead = true,
- Direction = CommandDirection.OUT, ParameterByteCount = 8, ResultByteCount = 7 },
- // scan equal
- new Command { CommandDelegate = UPD_ScanEqual, CommandCode = 0x11, MT = true, MF = true, SK = true, IsRead = true,
- Direction = CommandDirection.IN, ParameterByteCount = 8, ResultByteCount = 7 },
- // scan high or equal
- new Command { CommandDelegate = UPD_ScanHighOrEqual, CommandCode = 0x1d, MT = true, MF = true, SK = true, IsRead = true,
- Direction = CommandDirection.IN, ParameterByteCount = 8, ResultByteCount = 7 },
- // scan low or equal
- new Command { CommandDelegate = UPD_ScanLowOrEqual, CommandCode = 0x19, MT = true, MF = true, SK = true, IsRead = true,
- Direction = CommandDirection.IN, ParameterByteCount = 8, ResultByteCount = 7 },
- // read deleted data
- new Command { CommandDelegate = UPD_ReadDeletedData, CommandCode = 0x0c, MT = true, MF = true, SK = true, IsRead = true,
- Direction = CommandDirection.OUT, ParameterByteCount = 8, ResultByteCount = 7 },
- // write data
- new Command { CommandDelegate = UPD_WriteData, CommandCode = 0x05, MT = true, MF = true, IsWrite = true,
- Direction = CommandDirection.IN, ParameterByteCount = 8, ResultByteCount = 7 },
- // write id
- new Command { CommandDelegate = UPD_WriteID, CommandCode = 0x0d, MF = true, IsWrite = true,
- Direction = CommandDirection.IN, ParameterByteCount = 5, ResultByteCount = 7 },
- // write deleted data
- new Command { CommandDelegate = UPD_WriteDeletedData, CommandCode = 0x09, MT = true, MF = true, IsWrite = true,
- Direction = CommandDirection.IN, ParameterByteCount = 8, ResultByteCount = 7 },
- // seek
- new Command { CommandDelegate = UPD_Seek, CommandCode = 0x0f,
- Direction = CommandDirection.OUT, ParameterByteCount = 2, ResultByteCount = 0 },
- // recalibrate (seek track00)
- new Command { CommandDelegate = UPD_Recalibrate, CommandCode = 0x07,
- Direction = CommandDirection.OUT, ParameterByteCount = 1, ResultByteCount = 0 },
- // sense interrupt status
- new Command { CommandDelegate = UPD_SenseInterruptStatus, CommandCode = 0x08,
- Direction = CommandDirection.OUT, ParameterByteCount = 0, ResultByteCount = 2 },
- // sense drive status
- new Command { CommandDelegate = UPD_SenseDriveStatus, CommandCode = 0x04,
- Direction = CommandDirection.OUT, ParameterByteCount = 1, ResultByteCount = 1 },
- // version
- new Command { CommandDelegate = UPD_Version, CommandCode = 0x10,
- Direction = CommandDirection.OUT, ParameterByteCount = 0, ResultByteCount = 1 },
- // invalid
- new Command { CommandDelegate = UPD_Invalid, CommandCode = 0x00,
- Direction = CommandDirection.OUT, ParameterByteCount = 0, ResultByteCount = 1 },
- };
- }
-
- #endregion
-
- #region State Serialization
-
- public void SyncState(Serializer ser)
- {
- void SyncFDDState(Serializer ser1)
- {
- ser1.Sync(nameof(FDD_FLAG_MOTOR), ref FDD_FLAG_MOTOR);
-
- for (int i = 0; i < 4; i++)
- {
- ser1.BeginSection("HITDrive_" + i);
- DriveStates[i].SyncState(ser1);
- ser1.EndSection();
- }
-
- ser1.Sync(nameof(DiskDriveIndex), ref _diskDriveIndex);
- // set active drive
- DiskDriveIndex = _diskDriveIndex;
- }
-
- void SyncRegisterState(Serializer ser1)
- {
- ser1.Sync("_RegMain", ref StatusMain);
- ser1.Sync("_Reg0", ref Status0);
- ser1.Sync("_Reg1", ref Status1);
- ser1.Sync("_Reg2", ref Status2);
- ser1.Sync("_Reg3", ref Status3);
- }
-
- void SyncControllerState(Serializer ser1)
- {
- ser1.Sync(nameof(DriveLight), ref DriveLight);
- ser1.SyncEnum(nameof(ActivePhase), ref ActivePhase);
-#if false
- ser1.SyncEnum(nameof(ActiveDirection), ref ActiveDirection);
-#endif
- ser1.SyncEnum(nameof(ActiveInterrupt), ref ActiveInterrupt);
- ser1.Sync(nameof(CommBuffer), ref CommBuffer, false);
- ser1.Sync(nameof(CommCounter), ref CommCounter);
- ser1.Sync(nameof(ResBuffer), ref ResBuffer, false);
- ser1.Sync(nameof(ExecBuffer), ref ExecBuffer, false);
- ser1.Sync(nameof(ExecCounter), ref ExecCounter);
- ser1.Sync(nameof(ExecLength), ref ExecLength);
- ser1.Sync(nameof(InterruptResultBuffer), ref InterruptResultBuffer, false);
- ser1.Sync(nameof(ResCounter), ref ResCounter);
- ser1.Sync(nameof(ResLength), ref ResLength);
- ser1.Sync(nameof(LastSectorDataWriteByte), ref LastSectorDataWriteByte);
- ser1.Sync(nameof(LastSectorDataReadByte), ref LastSectorDataReadByte);
- ser1.Sync(nameof(LastByteReceived), ref LastByteReceived);
-
- ser1.Sync(nameof(_cmdIndex), ref _cmdIndex);
- // resync the ActiveCommand
- CMDIndex = _cmdIndex;
-
- ActiveCommandParams.SyncState(ser1);
-
- ser1.Sync(nameof(IndexPulseCounter), ref IndexPulseCounter);
-#if false
- ser1.SyncEnum(nameof(_activeStatus), ref _activeStatus);
- ser1.SyncEnum(nameof(_statusRaised), ref _statusRaised);
-#endif
-
- ser1.Sync(nameof(CMD_FLAG_MT), ref CMD_FLAG_MT);
- ser1.Sync(nameof(CMD_FLAG_MF), ref CMD_FLAG_MF);
- ser1.Sync(nameof(CMD_FLAG_SK), ref CMD_FLAG_SK);
- ser1.Sync(nameof(SRT), ref SRT);
- ser1.Sync(nameof(HUT), ref HUT);
- ser1.Sync(nameof(HLT), ref HLT);
- ser1.Sync(nameof(ND), ref ND);
- ser1.Sync(nameof(SRT_Counter), ref SRT_Counter);
- ser1.Sync(nameof(HUT_Counter), ref HUT_Counter);
- ser1.Sync(nameof(HLT_Counter), ref HLT_Counter);
-
- ser1.Sync(nameof(SectorDelayCounter), ref SectorDelayCounter);
- ser1.Sync(nameof(SectorID), ref SectorID);
- }
-
- void SyncTimingState(Serializer ser1)
- {
- ser1.Sync(nameof(LastCPUCycle), ref LastCPUCycle);
- ser1.Sync(nameof(StatusDelay), ref StatusDelay);
- ser1.Sync(nameof(TickCounter), ref TickCounter);
- ser1.Sync(nameof(DriveCycleCounter), ref DriveCycleCounter);
- }
-
- ser.BeginSection("NEC-UPD765");
- SyncFDDState(ser);
- SyncRegisterState(ser);
- SyncControllerState(ser);
- SyncTimingState(ser);
- ser.EndSection();
- }
-
- #endregion
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/NECUPD765Spectrum.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/NECUPD765Spectrum.cs
new file mode 100644
index 0000000000..ef4f76538c
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/NECUPD765Spectrum.cs
@@ -0,0 +1,75 @@
+using System;
+
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
+
+namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
+{
+ public class NECUPD765Spectrum : NECUPD765
+ {
+ protected override ZXDriveState ConstructDriveState(int driveID, NECUPD765 fdc) => new ZXDriveState(driveID, fdc);
+
+ protected override void TimingInit()
+ {
+ // z80 timing
+ double frameSize = _machine.ULADevice.FrameLength;
+ double rRate = _machine.ULADevice.ClockSpeed / frameSize;
+ long tPerSecond = (long)(frameSize * rRate);
+ CPUCyclesPerMs = tPerSecond / 1000;
+
+ // drive timing
+ double dRate = DriveClock / frameSize;
+ long dPerSecond = (long)(frameSize * dRate);
+ DriveCyclesPerMs = dPerSecond / 1000;
+
+ long TStatesPerDriveCycle = (long)((double)_machine.ULADevice.ClockSpeed / DriveClock);
+ StatesPerDriveTick = TStatesPerDriveCycle;
+ }
+
+ public class ZXDriveState : NECUPD765DriveState
+ {
+ public ZXDriveState(int driveID, NECUPD765 fdc) : base(driveID, fdc) {}
+
+ public override void FDD_LoadDisk(byte[] diskData)
+ {
+ // try dsk first
+ FloppyDisk fdd = null;
+ bool found = false;
+
+ foreach (DiskType type in Enum.GetValues(typeof(DiskType)))
+ {
+ switch (type)
+ {
+ case DiskType.CPCExtended:
+ fdd = new CPCExtendedFloppyDisk();
+ found = fdd.ParseDisk(diskData);
+ break;
+ case DiskType.CPC:
+ fdd = new CPCFloppyDisk();
+ found = fdd.ParseDisk(diskData);
+ break;
+ case DiskType.IPF:
+ fdd = new IPFFloppyDisk();
+ found = fdd.ParseDisk(diskData);
+ break;
+ case DiskType.UDI:
+ fdd = new UDI1_0FloppyDisk();
+ found = fdd.ParseDisk(diskData);
+ break;
+ }
+
+ if (found)
+ {
+ Disk = fdd;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ throw new Exception(this.GetType().ToString() +
+ "\n\nDisk image file could not be parsed. Potentially an unknown format.");
+ }
+ }
+ }
+ }
+}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/NECUPS765.Static.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/NECUPS765.Static.cs
deleted file mode 100644
index 276bd41ccd..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/NECUPS765.Static.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-using System.Collections;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// Static helper methods
- ///
- #region Attribution
- /*
- Implementation based on the information contained here:
- http://www.cpcwiki.eu/index.php/765_FDC
- and here:
- http://www.cpcwiki.eu/imgs/f/f3/UPD765_Datasheet_OCRed.pdf
- */
- #endregion
- public partial class NECUPD765
- {
- ///
- /// Returns the specified bit value from supplied byte
- ///
- public static bool GetBit(int bitNumber, byte dataByte)
- {
- if (bitNumber < 0 || bitNumber > 7)
- return false;
-
- BitArray bi = new BitArray(new byte[] { dataByte });
-
- return bi[bitNumber];
- }
-
- ///
- /// Sets the specified bit of the supplied byte to 1
- ///
- public static void SetBit(int bitNumber, ref byte dataByte)
- {
- if (bitNumber < 0 || bitNumber > 7)
- return;
-
- int db = (int)dataByte;
-
- db |= 1 << bitNumber;
-
- dataByte = (byte)db;
- }
-
- ///
- /// Sets the specified bit of the supplied byte to 0
- ///
- public static void UnSetBit(int bitNumber, ref byte dataByte)
- {
- if (bitNumber < 0 || bitNumber > 7)
- return;
-
- int db = (int)dataByte;
-
- db &= ~(1 << bitNumber);
-
- dataByte = (byte)db;
- }
-
- ///
- /// Returns a drive number (0-3) based on the first two bits of the supplied byte
- ///
- public static int GetUnitSelect(byte dataByte)
- {
- int driveNumber = dataByte & 0x03;
- return driveNumber;
- }
-
- ///
- /// Sets the first two bits of a byte based on the supplied drive number (0-3)
- ///
- public static void SetUnitSelect(int driveNumber, ref byte dataByte)
- {
- switch (driveNumber)
- {
- case 0:
- UnSetBit(SR0_US0, ref dataByte);
- UnSetBit(SR0_US1, ref dataByte);
- break;
- case 1:
- SetBit(SR0_US0, ref dataByte);
- UnSetBit(SR0_US1, ref dataByte);
- break;
- case 2:
- SetBit(SR0_US1, ref dataByte);
- UnSetBit(SR0_US0, ref dataByte);
- break;
- case 3:
- SetBit(SR0_US0, ref dataByte);
- SetBit(SR0_US1, ref dataByte);
- break;
- }
- }
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/CursorJoystick.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/CursorJoystick.cs
index 57fc3c867b..a32427aa19 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/CursorJoystick.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/CursorJoystick.cs
@@ -1,13 +1,15 @@
using System;
using System.Collections.Generic;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
+
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
///
/// Cursor joystick
/// Maps to a combination of 0xf7fe and 0xeffe
///
- public class CursorJoystick : IJoystick
+ public class CursorJoystick : IJoystick
{
//private int _joyLine;
private SpectrumBase _machine;
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/KempstonJoystick.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/KempstonJoystick.cs
index 3a1040d045..9c8813e0c9 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/KempstonJoystick.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/KempstonJoystick.cs
@@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
+
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
- public class KempstonJoystick : IJoystick
+ public class KempstonJoystick : IJoystick
{
private int _joyLine;
private SpectrumBase _machine;
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/NullJoystick.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/NullJoystick.cs
index 95bbb879a9..2185bca85d 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/NullJoystick.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/NullJoystick.cs
@@ -1,12 +1,14 @@
using System;
using System.Collections.Generic;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
+
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
///
/// A null joystick object
///
- public class NullJoystick : IJoystick
+ public class NullJoystick : IJoystick
{
private int _joyLine;
private SpectrumBase _machine;
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/SinclairJoystick1.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/SinclairJoystick1.cs
index 9908f344de..8004a2a4dc 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/SinclairJoystick1.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/SinclairJoystick1.cs
@@ -1,13 +1,15 @@
using System;
using System.Collections.Generic;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
+
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
///
/// Sinclair Joystick LEFT
/// Just maps to the standard keyboard and is read the same (from port 0xf7fe)
///
- public class SinclairJoystick1 : IJoystick
+ public class SinclairJoystick1 : IJoystick
{
//private int _joyLine;
private SpectrumBase _machine;
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/SinclairJoystick2.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/SinclairJoystick2.cs
index a01c4435d9..9c28d65ff1 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/SinclairJoystick2.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/SinclairJoystick2.cs
@@ -1,13 +1,15 @@
using System;
using System.Collections.Generic;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
+
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
///
/// Sinclair Joystick RIGHT
/// Just maps to the standard keyboard and is read the same (from port 0xeffe)
///
- public class SinclairJoystick2 : IJoystick
+ public class SinclairJoystick2 : IJoystick
{
//private int _joyLine;
private SpectrumBase _machine;
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Input.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Input.cs
index bac2ae50c5..466bd0dcc7 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Input.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Input.cs
@@ -1,6 +1,8 @@
using System.Collections.Generic;
using System.Linq;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
+
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
///
@@ -280,7 +282,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
///
protected void InitJoysticks(List joys)
{
- var jCollection = new List();
+ var jCollection = new List>();
for (int i = 0; i < joys.Count(); i++)
{
@@ -298,7 +300,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
///
/// Instantiates a new IJoystick object
///
- public IJoystick InstantiateJoystick(JoystickType type, int playerNumber)
+ public IJoystick InstantiateJoystick(JoystickType type, int playerNumber)
{
switch (type)
{
@@ -320,7 +322,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
///
/// Returns a IJoystick object depending on the type (or null if not found)
///
- protected IJoystick LocateUniqueJoystick(JoystickType type)
+ protected IJoystick LocateUniqueJoystick(JoystickType type)
{
return JoystickCollection.FirstOrDefault(a => a.JoyType == type);
}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Media.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Media.cs
index 2f4fc56688..5090eda0dd 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Media.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Media.cs
@@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
+
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
///
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs
index c218adbca6..ed7db3469e 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs
@@ -1,5 +1,6 @@
using BizHawk.Common;
using BizHawk.Emulation.Cores.Components.Z80A;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
using BizHawk.Emulation.Cores.Sound;
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
@@ -8,7 +9,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
/// The abstract class that all emulated models will inherit from
/// * Main properties / fields / contruction*
///
- public abstract partial class SpectrumBase
+ public abstract partial class SpectrumBase : CPCSpectrumBase.CPCSpectrumBase
{
#region Devices
@@ -66,12 +67,12 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
///
/// The +3 built-in disk drive
///
- public virtual NECUPD765 UPDDiskDevice { get; set; }
+ public virtual NECUPD765Spectrum UPDDiskDevice { get; set; }
///
/// Holds the currently selected joysticks
///
- public virtual IJoystick[] JoystickCollection { get; set; }
+ public virtual IJoystick[] JoystickCollection { get; set; }
///
/// +3/2a printer port strobe
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.cs
index cb3bb54eab..cc8bbc565e 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.cs
@@ -42,7 +42,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
TapeDevice = new DatacorderDevice(spectrum.SyncSettings.AutoLoadTape);
TapeDevice.Init(this);
- UPDDiskDevice = new NECUPD765();
+ UPDDiskDevice = new NECUPD765Spectrum();
UPDDiskDevice.Init(this);
InitializeMedia(files);
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/CPCFormat/CPCExtendedFloppyDisk.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/CPCFormat/CPCExtendedFloppyDisk.cs
index 3407d88e16..caa61f03c9 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/CPCFormat/CPCExtendedFloppyDisk.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/CPCFormat/CPCExtendedFloppyDisk.cs
@@ -3,6 +3,8 @@ using BizHawk.Common;
using System;
using System.Collections.Generic;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
+
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
///
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/CPCFormat/CPCFloppyDisk.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/CPCFormat/CPCFloppyDisk.cs
index 351229d774..8e3e09c02b 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/CPCFormat/CPCFloppyDisk.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/CPCFormat/CPCFloppyDisk.cs
@@ -3,6 +3,8 @@ using BizHawk.Common;
using System;
using System.Collections.Generic;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
+
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
///
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/FloppyDisk.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/FloppyDisk.cs
deleted file mode 100644
index 1058f98b4a..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/FloppyDisk.cs
+++ /dev/null
@@ -1,735 +0,0 @@
-using BizHawk.Common;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// This abstract class defines a logical floppy disk
- ///
- public abstract class FloppyDisk
- {
- ///
- /// The disk format type
- ///
- public abstract DiskType DiskFormatType { get; }
-
- ///
- /// Disk information header
- ///
- public Header DiskHeader = new Header();
-
- ///
- /// Track array
- ///
- public Track[] DiskTracks = null;
-
- ///
- /// No. of tracks per side
- ///
- public int CylinderCount;
-
- ///
- /// The number of physical sides
- ///
- public int SideCount;
-
- ///
- /// The number of bytes per track
- ///
- public int BytesPerTrack;
-
- ///
- /// The write-protect tab on the disk
- ///
- public bool WriteProtected;
-
- ///
- /// The detected protection scheme (if any)
- ///
- public ProtectionType Protection;
-
- ///
- /// The actual disk image data
- ///
- public byte[] DiskData;
-
- ///
- /// If TRUE then data on the disk has changed (been written to)
- /// This will be used to determine whether the disk data needs to be included
- /// in any SyncState operations
- ///
- protected bool DirtyData = false;
-
- ///
- /// Used to deterministically choose a 'random' sector when dealing with weak reads
- ///
- public int RandomCounter
- {
- get => _randomCounter;
- set
- {
- _randomCounter = value;
-
- foreach (var trk in DiskTracks)
- {
- foreach (var sec in trk.Sectors)
- {
- sec.RandSecCounter = _randomCounter;
- }
- }
- }
- }
- protected int _randomCounter;
-
-
- ///
- /// Attempts to parse incoming disk data
- ///
- ///
- /// TRUE: disk parsed
- /// FALSE: unable to parse disk
- ///
- public virtual bool ParseDisk(byte[] diskData)
- {
- // default result
- // override in inheriting class
- return false;
- }
-
- ///
- /// Examines the floppydisk data to work out what protection (if any) is present
- /// If possible it will also fix the disk data for this protection
- /// This should be run at the end of the ParseDisk() method
- ///
- public virtual void ParseProtection()
- {
- int[] weakArr = new int[2];
-
- // speedlock
- if (DetectSpeedlock(ref weakArr))
- {
- Protection = ProtectionType.Speedlock;
-
- Sector sec = DiskTracks[0].Sectors[1];
- if (!sec.ContainsMultipleWeakSectors)
- {
- byte[] origData = sec.SectorData.ToArray();
- List data = new List();
- for (int m = 0; m < 3; m++)
- {
- for (int i = 0; i < 512; i++)
- {
- // deterministic 'random' implementation
- int n = origData[i] + m + 1;
- if (n > 0xff)
- n = n - 0xff;
- else if (n < 0)
- n = 0xff + n;
-
- byte nByte = (byte)n;
-
- if (m == 0)
- {
- data.Add(origData[i]);
- continue;
- }
-
- if (i < weakArr[0])
- {
- data.Add(origData[i]);
- }
-
- else if (weakArr[1] > 0)
- {
- data.Add(nByte);
- weakArr[1]--;
- }
-
- else
- {
- data.Add(origData[i]);
- }
- }
- }
-
- sec.SectorData = data.ToArray();
- sec.ActualDataByteLength = data.Count();
- sec.ContainsMultipleWeakSectors = true;
- }
- }
- else if (DetectAlkatraz(ref weakArr))
- {
- Protection = ProtectionType.Alkatraz;
- }
- else if (DetectPaulOwens(ref weakArr))
- {
- Protection = ProtectionType.PaulOwens;
- }
- else if (DetectHexagon(ref weakArr))
- {
- Protection = ProtectionType.Hexagon;
- }
- else if (DetectShadowOfTheBeast())
- {
- Protection = ProtectionType.ShadowOfTheBeast;
- }
- }
-
- ///
- /// Detection routine for shadow of the beast game
- /// Still cannot get this to work, but at least the game is detected
- ///
- public bool DetectShadowOfTheBeast()
- {
- if (DiskTracks[0].Sectors.Length != 9)
- return false;
-
- var zeroSecs = DiskTracks[0].Sectors;
- if (zeroSecs[0].SectorID != 65 ||
- zeroSecs[1].SectorID != 66 ||
- zeroSecs[2].SectorID != 67 ||
- zeroSecs[3].SectorID != 68 ||
- zeroSecs[4].SectorID != 69 ||
- zeroSecs[5].SectorID != 70 ||
- zeroSecs[6].SectorID != 71 ||
- zeroSecs[7].SectorID != 72 ||
- zeroSecs[8].SectorID != 73)
- return false;
-
- var oneSecs = DiskTracks[1].Sectors;
-
- if (oneSecs.Length != 8)
- return false;
-
- if (oneSecs[0].SectorID != 17 ||
- oneSecs[1].SectorID != 18 ||
- oneSecs[2].SectorID != 19 ||
- oneSecs[3].SectorID != 20 ||
- oneSecs[4].SectorID != 21 ||
- oneSecs[5].SectorID != 22 ||
- oneSecs[6].SectorID != 23 ||
- oneSecs[7].SectorID != 24)
- return false;
-
- return true;
- }
-
- ///
- /// Detect speedlock weak sector
- ///
- public bool DetectSpeedlock(ref int[] weak)
- {
- // SPEEDLOCK NOTES (-asni 2018-05-01)
- // ---------------------------------
- // Speedlock is one of the more common +3 disk protections and there are a few different versions
- // Usually, track 0 sector 1 (ID 2) has data CRC errors that result in certain bytes returning a different value every time they are read
- // Speedlock will generally read this track a number of times during the load process
- // and if the correct bytes are not different between reads, the load fails
-
- // always must have track 0 containing 9 sectors
- if (DiskTracks[0].Sectors.Length != 9)
- return false;
-
- // check for SPEEDLOCK ident in sector 0
- string ident = Encoding.ASCII.GetString(DiskTracks[0].Sectors[0].SectorData, 0, DiskTracks[0].Sectors[0].SectorData.Length);
- if (!ident.ToUpper().Contains("SPEEDLOCK"))
- return false;
-
- // check for correct sector 0 lengths
- if (DiskTracks[0].Sectors[0].SectorSize != 2 ||
- DiskTracks[0].Sectors[0].SectorData.Length < 0x200)
- return false;
-
- // sector[1] (SectorID 2) contains the weak sectors
- Sector sec = DiskTracks[0].Sectors[1];
-
- // check for correct sector 1 lengths
- if (sec.SectorSize != 2 ||
- sec.SectorData.Length < 0x200)
- return false;
-
- // secID 2 needs a CRC error
- //if (!(sec.Status1.Bit(5) || sec.Status2.Bit(5)))
- //return false;
-
- // check for filler
- bool startFillerFound = true;
- for (int i = 0; i < 250; i++)
- {
- if (sec.SectorData[i] != sec.SectorData[i + 1])
- {
- startFillerFound = false;
- break;
- }
- }
-
- if (!startFillerFound)
- {
- weak[0] = 0;
- weak[1] = 0x200;
- }
- else
- {
- weak[0] = 0x150;
- weak[1] = 0x20;
- }
-
- return true;
- }
-
- ///
- /// Detect Alkatraz
- ///
- public bool DetectAlkatraz(ref int[] weak)
- {
- try
- {
- var data1 = DiskTracks[0].Sectors[0].SectorData;
- var data2 = DiskTracks[0].Sectors[0].SectorData.Length;
- }
- catch (Exception)
- {
- return false;
- }
-
- // check for ALKATRAZ ident in sector 0
- string ident = Encoding.ASCII.GetString(DiskTracks[0].Sectors[0].SectorData, 0, DiskTracks[0].Sectors[0].SectorData.Length);
- if (!ident.ToUpper().Contains("ALKATRAZ PROTECTION SYSTEM"))
- return false;
-
- // ALKATRAZ NOTES (-asni 2018-05-01)
- // ---------------------------------
- // Alkatraz protection appears to revolve around a track on the disk with 18 sectors,
- // (track position is not consistent) with the sector ID info being incorrect:
- // TrackID is consistent between the sectors although is usually high (233, 237 etc)
- // SideID is fairly random looking but with all IDs being even
- // SectorID is also fairly random looking but contains both odd and even numbers
- //
- // There doesnt appear to be any CRC errors in this track, but the sector size is always 1 (256 bytes)
- // Each sector contains different filler byte
- // Once track 0 is loaded the CPU completely reads all the sectors in this track one-by-one.
- // Data transferred during execution must be correct, also result ST0, ST1 and ST2 must be 64, 128 and 0 respectively
-
- // Immediately following this track are a number of tracks and sectors with a DAM set.
- // These are all read in sector by sector
- // Again, Alkatraz appears to require that ST0, ST1, and ST2 result bytes are set to 64, 128 and 0 respectively
- // (so the CM in ST2 needs to be reset)
-
- return true;
- }
-
- ///
- /// Detect Paul Owens
- ///
- public bool DetectPaulOwens(ref int[] weak)
- {
- try
- {
- var data1 = DiskTracks[0].Sectors[2].SectorData;
- var data2 = DiskTracks[0].Sectors[2].SectorData.Length;
- }
- catch (Exception)
- {
- return false;
- }
-
- // check for PAUL OWENS ident in sector 2
- string ident = Encoding.ASCII.GetString(DiskTracks[0].Sectors[2].SectorData, 0, DiskTracks[0].Sectors[2].SectorData.Length);
- if (!ident.ToUpper().Contains("PAUL OWENS"))
- return false;
-
- // Paul Owens Disk Protection Notes (-asni 2018-05-01)
- // ---------------------------------------------------
- //
- // This scheme looks a little similar to Alkatraz with incorrect sector ID info in many places
- // and deleted address marks (although these do not seem to show the strict relience on removing the CM mark from ST2 result that Alkatraz does)
- // There are also data CRC errors but these don't look to be read more than once/checked for changes during load
- // Main identifiers:
- //
- // * There are more than 10 cylinders
- // * Cylinder 1 has no sector data
- // * The sector ID infomation in most cases contains incorrect track IDs
- // * Tracks 0 (boot) and 5 appear to be pretty much the only tracks that do not have incorrect sector ID marks
-
- return true;
- }
-
- ///
- /// Detect Hexagon copy protection
- ///
- public bool DetectHexagon(ref int[] weak)
- {
- try
- {
- var data1 = DiskTracks[0].Sectors.Length;
- var data2 = DiskTracks[0].Sectors[8].ActualDataByteLength;
- var data3 = DiskTracks[0].Sectors[8].SectorData;
- var data4 = DiskTracks[0].Sectors[8].SectorData.Length;
- var data5 = DiskTracks[1].Sectors[0];
- }
- catch (Exception)
- {
- return false;
- }
-
- if (DiskTracks[0].Sectors.Length != 10 || DiskTracks[0].Sectors[8].ActualDataByteLength != 512)
- return false;
-
- // check for Hexagon ident in sector 8
- string ident = Encoding.ASCII.GetString(DiskTracks[0].Sectors[8].SectorData, 0, DiskTracks[0].Sectors[8].SectorData.Length);
- if (ident.ToUpper().Contains("GON DISK PROT"))
- return true;
-
- // hexagon protection may not be labelled as such
- var track = DiskTracks[1];
- var sector = track.Sectors[0];
-
- if (sector.SectorSize == 6 && sector.Status1 == 0x20 && sector.Status2 == 0x60)
- {
- if (track.Sectors.Length == 1)
- return true;
- }
-
-
- // Hexagon Copy Protection Notes (-asni 2018-05-01)
- // ---------------------------------------------------
- //
- //
-
- return false;
- }
-
- /*
- ///
- /// Should be run at the end of the ParseDisk process
- /// If speedlock is detected the flag is set in the disk image
- ///
- protected virtual void SpeedlockDetection()
- {
-
- if (DiskTracks.Length == 0)
- return;
-
- // check for speedlock copyright notice
- string ident = Encoding.ASCII.GetString(DiskData, 0x100, 0x1400);
- if (!ident.ToUpper().Contains("SPEEDLOCK"))
- {
- // speedlock not found
- return;
- }
-
- // get cylinder 0
- var cyl = DiskTracks[0];
-
- // get sector with ID=2
- var sec = cyl.Sectors.Where(a => a.SectorID == 2).FirstOrDefault();
-
- if (sec == null)
- return;
-
- // check for already multiple weak copies
- if (sec.ContainsMultipleWeakSectors || sec.SectorData.Length != 0x80 << sec.SectorSize)
- return;
-
- // check for invalid crcs in sector 2
- if (sec.Status1.Bit(5) || sec.Status2.Bit(5))
- {
- Protection = ProtectionType.Speedlock;
- }
- else
- {
- return;
- }
-
- // we are going to create a total of 5 weak sector copies
- // keeping the original copy
- byte[] origData = sec.SectorData.ToArray();
- List data = new List();
- //Random rnd = new Random();
-
- for (int i = 0; i < 6; i++)
- {
- for (int s = 0; s < origData.Length; s++)
- {
- if (i == 0)
- {
- data.Add(origData[s]);
- continue;
- }
-
- // deterministic 'random' implementation
- int n = origData[s] + i + 1;
- if (n > 0xff)
- n = n - 0xff;
- else if (n < 0)
- n = 0xff + n;
-
- byte nByte = (byte)n;
-
- if (s < 336)
- {
- // non weak data
- data.Add(origData[s]);
- }
- else if (s < 511)
- {
- // weak data
- data.Add(nByte);
- }
- else if (s == 511)
- {
- // final sector byte
- data.Add(nByte);
- }
- else
- {
- // speedlock sector should not be more than 512 bytes
- // but in case it is just do non weak
- data.Add(origData[i]);
- }
- }
- }
-
- // commit the sector data
- sec.SectorData = data.ToArray();
- sec.ContainsMultipleWeakSectors = true;
- sec.ActualDataByteLength = data.Count();
-
- }
- */
-
- ///
- /// Returns the track count for the disk
- ///
- public virtual int GetTrackCount()
- {
- return DiskHeader.NumberOfTracks * DiskHeader.NumberOfSides;
- }
-
- ///
- /// Reads the current sector ID info
- ///
- public virtual CHRN ReadID(byte trackIndex, byte side, int sectorIndex)
- {
- if (side != 0)
- return null;
-
- if (DiskTracks.Length <= trackIndex || trackIndex < 0)
- {
- // invalid track - wrap around
- trackIndex = 0;
- }
-
- var track = DiskTracks[trackIndex];
-
- if (track.NumberOfSectors <= sectorIndex)
- {
- // invalid sector - wrap around
- sectorIndex = 0;
- }
-
- var sector = track.Sectors[sectorIndex];
-
- CHRN chrn = new CHRN();
-
- chrn.C = sector.TrackNumber;
- chrn.H = sector.SideNumber;
- chrn.R = sector.SectorID;
-
- // wrap around for N > 7
- if (sector.SectorSize > 7)
- {
- chrn.N = (byte)(sector.SectorSize - 7);
- }
- else if (sector.SectorSize < 0)
- {
- chrn.N = 0;
- }
- else
- {
- chrn.N = sector.SectorSize;
- }
-
- chrn.Flag1 = (byte)(sector.Status1 & 0x25);
- chrn.Flag2 = (byte)(sector.Status2 & 0x61);
-
- chrn.DataBytes = sector.ActualData;
-
- return chrn;
- }
-
- ///
- /// State serialization routines
- ///
- public abstract void SyncState(Serializer ser);
-
-
- public class Header
- {
- public string DiskIdent { get; set; }
- public string DiskCreatorString { get; set; }
- public byte NumberOfTracks { get; set; }
- public byte NumberOfSides { get; set; }
- public int[] TrackSizes { get; set; }
- }
-
- public class Track
- {
- public string TrackIdent { get; set; }
- public byte TrackNumber { get; set; }
- public byte SideNumber { get; set; }
- public byte DataRate { get; set; }
- public byte RecordingMode { get; set; }
- public byte SectorSize { get; set; }
- public byte NumberOfSectors { get; set; }
- public byte GAP3Length { get; set; }
- public byte FillerByte { get; set; }
- public virtual Sector[] Sectors { get; set; }
-
- #region UDI
-
- public virtual byte TrackType { get; set; }
- public virtual int TLEN { get; set; }
- public virtual int CLEN => TLEN / 8 + (TLEN % 8 / 7) / 8;
- public virtual byte[] TrackData { get; set; }
-
- #endregion
-
- ///
- /// Presents a contiguous byte array of all sector data for this track
- /// (including any multiple weak/random data)
- ///
- public virtual byte[] TrackSectorData
- {
- get
- {
- List list = new List();
-
- foreach (var sec in Sectors)
- {
- list.AddRange(sec.ActualData);
- }
-
- return list.ToArray();
- }
- }
- }
-
- public class Sector
- {
- public virtual byte TrackNumber { get; set; }
- public virtual byte SideNumber { get; set; }
- public virtual byte SectorID { get; set; }
- public virtual byte SectorSize { get; set; }
- public virtual byte Status1 { get; set; }
- public virtual byte Status2 { get; set; }
- public virtual int ActualDataByteLength { get; set; }
- public virtual byte[] SectorData { get; set; }
- public virtual bool ContainsMultipleWeakSectors { get; set; }
-
- public int WeakReadIndex = 0;
-
- public void SectorReadCompleted()
- {
- if (ContainsMultipleWeakSectors)
- WeakReadIndex++;
- }
-
- public int DataLen
- {
- get
- {
- if (!ContainsMultipleWeakSectors)
- {
- return ActualDataByteLength;
- }
-
- return ActualDataByteLength / (ActualDataByteLength / (0x80 << SectorSize));
- }
- }
-
-
- public int RandSecCounter = 0;
-
- public byte[] ActualData
- {
- get
- {
- if (!ContainsMultipleWeakSectors)
- {
- // check whether filler bytes are needed
- int size = 0x80 << SectorSize;
- if (size > ActualDataByteLength)
- {
- List l = new List();
- l.AddRange(SectorData);
- for (int i = 0; i < size - ActualDataByteLength; i++)
- {
- //l.Add(SectorData[i]);
- l.Add(SectorData.Last());
- }
-
- return l.ToArray();
- }
-
- return SectorData;
- }
- else
- {
- // weak read neccessary
- int copies = ActualDataByteLength / (0x80 << SectorSize);
-
- // handle index wrap-around
- if (WeakReadIndex > copies - 1)
- WeakReadIndex = copies - 1;
-
- // get the sector data based on the current weakreadindex
- int step = WeakReadIndex * (0x80 << SectorSize);
- byte[] res = new byte[(0x80 << SectorSize)];
- Array.Copy(SectorData, step, res, 0, 0x80 << SectorSize);
- return res;
-
- /*
- int copies = ActualDataByteLength / (0x80 << SectorSize);
- Random rnd = new Random();
- int r = rnd.Next(0, copies - 1);
- int step = r * (0x80 << SectorSize);
- byte[] res = new byte[(0x80 << SectorSize)];
- Array.Copy(SectorData, step, res, 0, 0x80 << SectorSize);
- return res;
- */
- }
- }
- }
-
- public CHRN SectorIDInfo =>
- new CHRN
- {
- C = TrackNumber,
- H = SideNumber,
- R = SectorID,
- N = SectorSize,
- Flag1 = Status1,
- Flag2 = Status2,
- };
- }
- }
-
- ///
- /// Defines the type of speedlock detection found
- ///
- public enum ProtectionType
- {
- None,
- Speedlock,
- Alkatraz,
- Hexagon,
- Frontier,
- PaulOwens,
- ShadowOfTheBeast
- }
-
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/IPFFormat/IPFFloppyDisk.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/IPFFormat/IPFFloppyDisk.cs
index 96e446c2c2..85489454bf 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/IPFFormat/IPFFloppyDisk.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/IPFFormat/IPFFloppyDisk.cs
@@ -5,6 +5,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
+
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
public class IPFFloppyDisk : FloppyDisk
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/UDIFormat/UDI1_0FloppyDisk.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/UDIFormat/UDI1_0FloppyDisk.cs
index 95cd1ea1d0..5b565f289f 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/UDIFormat/UDI1_0FloppyDisk.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/UDIFormat/UDI1_0FloppyDisk.cs
@@ -5,6 +5,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
+
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
public class UDI1_0FloppyDisk : FloppyDisk
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/CSW/CswConverter.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/CSW/CswConverter.cs
index 479571ebc4..2be656af72 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/CSW/CswConverter.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/CSW/CswConverter.cs
@@ -3,6 +3,8 @@ using System;
using System.Collections.Generic;
using System.Text;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
+
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
///
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/PZX/PzxConverter.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/PZX/PzxConverter.cs
index 7f1b1b29dc..5d10ee4c1f 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/PZX/PzxConverter.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/PZX/PzxConverter.cs
@@ -3,6 +3,8 @@ using System;
using System.Collections.Generic;
using System.Text;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
+
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
///
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TAP/TapConverter.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TAP/TapConverter.cs
index 3016b7aba0..7e072ffc44 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TAP/TapConverter.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TAP/TapConverter.cs
@@ -4,6 +4,8 @@ using System.IO;
using System.Linq;
using System.Text;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
+
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
///
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/TzxConverter.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/TzxConverter.cs
index 94a5f21f97..862ec85708 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/TzxConverter.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/TzxConverter.cs
@@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
+
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
///
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TapeCommand.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TapeCommand.cs
deleted file mode 100644
index 28383dd838..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TapeCommand.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// Represents the possible commands that can be raised from each tape block
- ///
- public enum TapeCommand
- {
- NONE,
- STOP_THE_TAPE,
- STOP_THE_TAPE_48K,
- BEGIN_GROUP,
- END_GROUP,
- SHOW_MESSAGE,
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TapeDataBlock.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TapeDataBlock.cs
deleted file mode 100644
index b05036d7ef..0000000000
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TapeDataBlock.cs
+++ /dev/null
@@ -1,282 +0,0 @@
-using BizHawk.Common;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
-{
- ///
- /// Represents a tape block
- ///
- public class TapeDataBlock
- {
- ///
- /// Either the TZX block ID, or -1 in the case of non-tzx blocks
- ///
- private int _blockID = -1;
- public int BlockID
- {
- get => _blockID;
- set
- {
- _blockID = value;
-
- if (MetaData == null)
- MetaData = new Dictionary();
-
- AddMetaData(BlockDescriptorTitle.Block_ID, value.ToString());
- }
- }
-
- ///
- /// The block type
- ///
- private BlockType _blockType;
- public BlockType BlockDescription
- {
- get => _blockType;
- set
- {
- _blockType = value;
- if (MetaData == null)
- MetaData = new Dictionary();
- }
- }
-
- ///
- /// Byte array containing the raw block data
- ///
- private byte[] _blockData;
- public byte[] BlockData
- {
- get => _blockData;
- set => _blockData = value;
- }
-
- /*
-
- ///
- /// An array of bytearray encoded strings (stored in this format for easy Bizhawk serialization)
- /// Its basically tape information
- ///
- private byte[][] _tapeDescriptionData;
-
- ///
- /// Returns the Tape Description Data in a human readable format
- ///
- public List TapeDescriptionData
- {
- get
- {
- List data = new List();
-
- foreach (byte[] b in _tapeDescriptionData)
- {
- data.Add(Encoding.ASCII.GetString(b));
- }
-
- return data;
- }
- }
- */
-
-
- #region Block Meta Data
-
- ///
- /// Dictionary of block related data
- ///
- public Dictionary MetaData { get; set; }
-
- ///
- /// Adds a single metadata item to the Dictionary
- ///
- public void AddMetaData(BlockDescriptorTitle descriptor, string data)
- {
- // check whether entry already exists
- bool check = MetaData.ContainsKey(descriptor);
- if (check)
- {
- // already exists - update
- MetaData[descriptor] = data;
- }
- else
- {
- // create new
- MetaData.Add(descriptor, data);
- }
- }
-
- #endregion
-
-
-
- ///
- /// List containing the pulse timing values
- ///
- public List DataPeriods = new List();
-
- public bool InitialPulseLevel;
-
- ///
- /// Command that is raised by this data block
- /// (that may or may not need to be acted on)
- ///
- private TapeCommand _command = TapeCommand.NONE;
- public TapeCommand Command
- {
- get => _command;
- set => _command = value;
- }
-
- ///
- /// The defined post-block pause
- ///
- private int _pauseInMS;
- public int PauseInMS
- {
- get => _pauseInMS;
- set => _pauseInMS = value;
- }
-
-
- ///
- /// Returns the data periods as an array
- /// (primarily to aid in bizhawk state serialization)
- ///
- public int[] GetDataPeriodsArray()
- {
- return DataPeriods.ToArray();
- }
-
- ///
- /// Accepts an array of data periods and updates the DataPeriods list accordingly
- /// (primarily to aid in bizhawk state serialization)
- ///
- public void SetDataPeriodsArray(int[] periodArray)
- {
- DataPeriods = periodArray?.ToList() ?? new List();
- }
-
- ///
- /// Bizhawk state serialization
- ///
- public void SyncState(Serializer ser, int blockPosition)
- {
- ser.BeginSection("DataBlock" + blockPosition);
-
- ser.Sync(nameof(_blockID), ref _blockID);
- //ser.SyncFixedString(nameof(_blockDescription), ref _blockDescription, 200);
- ser.SyncEnum(nameof(_blockType), ref _blockType);
- ser.Sync(nameof(_blockData), ref _blockData, true);
- ser.SyncEnum(nameof(_command), ref _command);
-
- int[] tempArray = null;
-
- if (ser.IsWriter)
- {
- tempArray = GetDataPeriodsArray();
- ser.Sync("_periods", ref tempArray, true);
- }
- else
- {
- ser.Sync("_periods", ref tempArray, true);
- SetDataPeriodsArray(tempArray);
- }
-
- ser.EndSection();
- }
- }
-
- ///
- /// The types of TZX blocks
- ///
- public enum BlockType
- {
- Standard_Speed_Data_Block = 0x10,
- Turbo_Speed_Data_Block = 0x11,
- Pure_Tone = 0x12,
- Pulse_Sequence = 0x13,
- Pure_Data_Block = 0x14,
- Direct_Recording = 0x15,
- CSW_Recording = 0x18,
- Generalized_Data_Block = 0x19,
- Pause_or_Stop_the_Tape = 0x20,
- Group_Start = 0x21,
- Group_End = 0x22,
- Jump_to_Block = 0x23,
- Loop_Start = 0x24,
- Loop_End = 0x25,
- Call_Sequence = 0x26,
- Return_From_Sequence = 0x27,
- Select_Block = 0x28,
- Stop_the_Tape_48K = 0x2A,
- Set_Signal_Level = 0x2B,
- Text_Description = 0x30,
- Message_Block = 0x31,
- Archive_Info = 0x32,
- Hardware_Type = 0x33,
- Custom_Info_Block = 0x35,
- Glue_Block = 0x5A,
-
- // depreciated blocks
- C64_ROM_Type_Data_Block = 0x16,
- C64_Turbo_Tape_Data_Block = 0x17,
- Emulation_Info = 0x34,
- Snapshot_Block = 0x40,
-
- // unsupported / undetected
- Unsupported,
-
- // PZX blocks
- PZXT,
- PULS,
- DATA,
- BRWS,
- PAUS,
-
- // zxhawk proprietry
- PAUSE_BLOCK,
-
- WAV_Recording
- }
-
-
- ///
- /// Different title possibilities
- ///
- public enum BlockDescriptorTitle
- {
- Undefined,
- Block_ID,
- Program,
- Data_Bytes,
- Bytes,
-
- Pilot_Pulse_Length,
- Pilot_Pulse_Count,
- First_Sync_Length,
- Second_Sync_Length,
- Zero_Bit_Length,
- One_Bit_Length,
- Data_Length,
- Bits_In_Last_Byte,
- Pause_After_Data,
-
- Pulse_Length,
- Pulse_Count,
-
- Text_Description,
- Title,
- Publisher,
- Author,
- Year,
- Language,
- Type,
- Price,
- Protection,
- Origin,
- Comments,
-
- Needs_Parsing
- }
-}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/WAV/WavConverter.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/WAV/WavConverter.cs
index 8d1780c193..c0a3a156b8 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/WAV/WavConverter.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/WAV/WavConverter.cs
@@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.IO;
using System.Text;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
+
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
///
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Messaging.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Messaging.cs
index c5be96f6b6..9bd459a7c4 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Messaging.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Messaging.cs
@@ -2,6 +2,8 @@
using System.Linq;
using System.Text;
+using BizHawk.Emulation.Cores.Computers.CPCSpectrumBase;
+
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
///