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