158 lines
3.7 KiB
C#
158 lines
3.7 KiB
C#
using BizHawk.Emulation.Cores.Computers.Commodore64.Media;
|
|
|
|
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
|
|
{
|
|
public sealed partial class Drive1541
|
|
{
|
|
private const long LEHMER_RNG_PRIME = 48271;
|
|
|
|
private int _diskDensityCounter; // density .. 16
|
|
private int _diskSupplementaryCounter; // 0 .. 16
|
|
private bool _diskFluxReversalDetected;
|
|
private int _diskBitsLeft;
|
|
private int _diskByteOffset;
|
|
private int _diskBits;
|
|
private int _diskCycle;
|
|
private int _diskDensity;
|
|
private bool _previousCa1;
|
|
private int _countsBeforeRandomTransition;
|
|
private int _rngCurrent;
|
|
private int _clocks;
|
|
private int _cpuClocks;
|
|
|
|
// Lehmer RNG
|
|
private void AdvanceRng()
|
|
{
|
|
if (_rngCurrent == 0)
|
|
{
|
|
_rngCurrent = 1;
|
|
}
|
|
|
|
_rngCurrent = (int)(_rngCurrent * LEHMER_RNG_PRIME % int.MaxValue);
|
|
}
|
|
|
|
private void ExecuteFlux()
|
|
{
|
|
// This actually executes the main 16mhz clock
|
|
while (_clocks > 0)
|
|
{
|
|
_clocks--;
|
|
|
|
// rotate disk
|
|
if (_motorEnabled)
|
|
{
|
|
if (_disk == null)
|
|
{
|
|
_diskBitsLeft = 1;
|
|
_diskBits = 0;
|
|
}
|
|
else
|
|
{
|
|
if (_diskBitsLeft <= 0)
|
|
{
|
|
_diskByteOffset++;
|
|
if (_diskByteOffset == Disk.FluxEntriesPerTrack)
|
|
{
|
|
_diskByteOffset = 0;
|
|
}
|
|
|
|
_diskBits = _trackImageData[_diskByteOffset];
|
|
_diskBitsLeft = Disk.FluxBitsPerEntry;
|
|
}
|
|
}
|
|
|
|
if ((_diskBits & 1) != 0)
|
|
{
|
|
_countsBeforeRandomTransition = 0;
|
|
_diskFluxReversalDetected = true;
|
|
}
|
|
|
|
_diskBits >>= 1;
|
|
_diskBitsLeft--;
|
|
}
|
|
|
|
// random flux transition readings for unformatted data
|
|
if (_countsBeforeRandomTransition > 0)
|
|
{
|
|
_countsBeforeRandomTransition--;
|
|
if (_countsBeforeRandomTransition == 0)
|
|
{
|
|
_diskFluxReversalDetected = true;
|
|
AdvanceRng();
|
|
|
|
// This constant is what VICE uses. TODO: Determine accuracy.
|
|
_countsBeforeRandomTransition = (_rngCurrent % 367) + 33;
|
|
}
|
|
}
|
|
|
|
// flux transition circuitry
|
|
if (_diskFluxReversalDetected)
|
|
{
|
|
_diskDensityCounter = _diskDensity;
|
|
_diskSupplementaryCounter = 0;
|
|
_diskFluxReversalDetected = false;
|
|
if (_countsBeforeRandomTransition == 0)
|
|
{
|
|
AdvanceRng();
|
|
|
|
// This constant is what VICE uses. TODO: Determine accuracy.
|
|
_countsBeforeRandomTransition = (_rngCurrent & 0x1F) + 289;
|
|
}
|
|
}
|
|
|
|
// counter circuitry
|
|
if (_diskDensityCounter >= 16)
|
|
{
|
|
_diskDensityCounter = _diskDensity;
|
|
_diskSupplementaryCounter++;
|
|
if ((_diskSupplementaryCounter & 0x3) == 0x2)
|
|
{
|
|
_bitsRemainingInLatchedByte--;
|
|
_byteReady = false;
|
|
_bitHistory = (_bitHistory << 1) | ((_diskSupplementaryCounter & 0xC) == 0x0 ? 1 : 0);
|
|
_sync = false;
|
|
if (Via1.Cb2 && (_bitHistory & 0x3FF) == 0x3FF)
|
|
{
|
|
_sync = true;
|
|
_bitsRemainingInLatchedByte = 8;
|
|
_byteReady = false;
|
|
}
|
|
|
|
if (_bitsRemainingInLatchedByte <= 0)
|
|
{
|
|
_bitsRemainingInLatchedByte = 8;
|
|
|
|
// SOE (sync output enabled)
|
|
_byteReady = Via1.Ca2;
|
|
}
|
|
|
|
// negative transition activates SO pin on CPU
|
|
_previousCa1 = Via1.Ca1;
|
|
Via1.Ca1 = !_byteReady;
|
|
if (_previousCa1 && !Via1.Ca1)
|
|
{
|
|
// cycle 6 is roughly 400ns
|
|
_overflowFlagDelaySr |= _diskCycle > 6 ? 4 : 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (_diskSupplementaryCounter >= 16)
|
|
{
|
|
_diskSupplementaryCounter = 0;
|
|
}
|
|
|
|
_cpuClocks--;
|
|
if (_cpuClocks <= 0)
|
|
{
|
|
ExecuteSystem();
|
|
_cpuClocks = 16;
|
|
}
|
|
|
|
_diskDensityCounter++;
|
|
_diskCycle = (_diskCycle + 1) & 0xF;
|
|
}
|
|
}
|
|
}
|
|
}
|