BizHawk/BizHawk.Emulation.Cores/Computers/Commodore64/Serial/Drive1541.cs

233 lines
6.2 KiB
C#
Raw Normal View History

2016-02-22 23:50:11 +00:00
using System;
2017-05-30 17:09:46 +00:00
using BizHawk.Common;
2016-02-22 23:50:11 +00:00
using BizHawk.Emulation.Cores.Components.M6502;
using BizHawk.Emulation.Cores.Computers.Commodore64.Media;
using BizHawk.Emulation.Cores.Computers.Commodore64.MOS;
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
{
2017-04-24 13:35:05 +00:00
public sealed partial class Drive1541 : SerialPortDevice
{
private Disk _disk;
private int _bitHistory;
private int _bitsRemainingInLatchedByte;
private bool _sync;
private bool _byteReady;
private int _driveCpuClockNum;
2017-04-24 13:35:05 +00:00
private int _trackNumber;
private bool _motorEnabled;
private bool _ledEnabled;
private int _motorStep;
private readonly MOS6502X<CpuLink> _cpu;
private int[] _ram;
2017-04-24 13:35:05 +00:00
public readonly Via Via0;
public readonly Via Via1;
private int _cpuClockNum;
2017-04-24 13:35:05 +00:00
private int _ratioDifference;
private int _driveLightOffTime;
private int[] _trackImageData = new int[1];
public Func<int> ReadIec = () => 0xFF;
public Action DebuggerStep;
public readonly Chip23128 DriveRom;
private struct CpuLink : IMOS6502XLink
{
private readonly Drive1541 _drive;
public CpuLink(Drive1541 drive)
{
_drive = drive;
}
public byte DummyReadMemory(ushort address) => unchecked((byte)_drive.Read(address));
public void OnExecFetch(ushort address) { }
public byte PeekMemory(ushort address) => unchecked((byte)_drive.Peek(address));
public byte ReadMemory(ushort address) => unchecked((byte)_drive.Read(address));
public void WriteMemory(ushort address, byte value) => _drive.Write(address, value);
}
2017-04-24 13:35:05 +00:00
public Drive1541(int clockNum, int clockDen)
{
DriveRom = new Chip23128();
_cpu = new MOS6502X<CpuLink>(new CpuLink(this))
2017-04-24 13:35:05 +00:00
{
NMI = false
};
_ram = new int[0x800];
Via0 = Chip6522.Create(ViaReadClock, ViaReadData, ViaReadAtn, 8);
Via1 = Chip6522.Create(ReadVia1PrA, ReadVia1PrB);
_cpuClockNum = clockNum;
_driveCpuClockNum = clockDen * 16000000; // 16mhz
}
public override void SyncState(Serializer ser)
{
ser.BeginSection("Disk");
2017-12-31 16:11:24 +00:00
if (_disk != null) { _disk.SyncState(ser); }
ser.EndSection();
ser.Sync("BitHistory", ref _bitHistory);
ser.Sync("BitsRemainingInLatchedByte", ref _bitsRemainingInLatchedByte);
ser.Sync("Sync", ref _sync);
ser.Sync("ByteReady", ref _byteReady);
ser.Sync("DriveCpuClockNumerator", ref _driveCpuClockNum);
ser.Sync("TrackNumber", ref _trackNumber);
ser.Sync("MotorEnabled", ref _motorEnabled);
ser.Sync("LedEnabled", ref _ledEnabled);
ser.Sync("MotorStep", ref _motorStep);
ser.BeginSection("Disk6502");
_cpu.SyncState(ser);
ser.EndSection();
ser.Sync("RAM", ref _ram, useNull: false);
ser.BeginSection("VIA0");
Via0.SyncState(ser);
ser.EndSection();
ser.BeginSection("VIA1");
Via1.SyncState(ser);
ser.EndSection();
ser.Sync("SystemCpuClockNumerator", ref _cpuClockNum);
ser.Sync("SystemDriveCpuRatioDifference", ref _ratioDifference);
ser.Sync("DriveLightOffTime", ref _driveLightOffTime);
2018-09-08 21:20:05 +00:00
// feos: drop 400KB of ROM data from savestates
//ser.Sync("TrackImageData", ref _trackImageData, useNull: false);
ser.Sync("DiskDensityCounter", ref _diskDensityCounter);
ser.Sync("DiskSupplementaryCounter", ref _diskSupplementaryCounter);
ser.Sync("DiskFluxReversalDetected", ref _diskFluxReversalDetected);
ser.Sync("DiskBitsRemainingInDataEntry", ref _diskBitsLeft);
ser.Sync("DiskDataEntryIndex", ref _diskByteOffset);
ser.Sync("DiskDataEntry", ref _diskBits);
ser.Sync("DiskCurrentCycle", ref _diskCycle);
ser.Sync("DiskDensityConfig", ref _diskDensity);
ser.Sync("PreviousCA1", ref _previousCa1);
ser.Sync("CountsBeforeRandomTransition", ref _countsBeforeRandomTransition);
ser.Sync("CurrentRNG", ref _rngCurrent);
ser.Sync("Clocks", ref _clocks);
ser.Sync("CpuClocks", ref _cpuClocks);
ser.Sync("OverflowFlagDelayShiftRegister", ref _overflowFlagDelaySr);
2019-07-04 05:11:03 +00:00
ser.Sync("DiskWriteBitsRemaining", ref _diskWriteBitsRemaining);
ser.Sync("DiskWriteEnabled", ref _diskWriteEnabled);
ser.Sync("DiskWriteLatch", ref _diskWriteLatch);
ser.Sync("DiskOutputBits", ref _diskOutputBits);
ser.Sync("DiskWriteProtected", ref _diskWriteProtected);
}
2017-04-24 13:35:05 +00:00
public override void ExecutePhase()
{
_ratioDifference += _driveCpuClockNum;
while (_ratioDifference > _cpuClockNum)
{
_ratioDifference -= _cpuClockNum;
_clocks++;
}
2017-05-30 17:09:46 +00:00
2017-04-24 13:35:05 +00:00
ExecutePhaseInternal();
}
private void ExecutePhaseInternal()
{
// clock output from 325572-01 drives CPU clock (phi0)
ExecuteMotor();
ExecuteFlux();
}
private void ExecuteSystem()
{
Via0.Ca1 = ViaReadAtn();
Via0.ExecutePhase();
Via1.ExecutePhase();
// SO pin pipeline
if ((_overflowFlagDelaySr & 0x01) != 0)
{
_cpu.SetOverflow();
}
2017-05-30 17:09:46 +00:00
2017-04-24 13:35:05 +00:00
_overflowFlagDelaySr >>= 1;
_cpu.IRQ = !(Via0.Irq && Via1.Irq); // active low IRQ line
_cpu.ExecuteOne();
if (_ledEnabled)
{
_driveLightOffTime = 25000;
}
else if (_driveLightOffTime > 0)
{
_driveLightOffTime--;
}
}
public override void HardReset()
{
Via0.HardReset();
Via1.HardReset();
_trackNumber = 34;
for (var i = 0; i < _ram.Length; i++)
{
_ram[i] = 0x00;
}
_diskDensity = 0;
_diskFluxReversalDetected = false;
_diskByteOffset = 0;
_diskBitsLeft = 0;
_diskBits = 0;
_driveLightOffTime = 0;
_diskDensityCounter = 0;
_diskSupplementaryCounter = 0;
_diskCycle = 0;
_previousCa1 = false;
_countsBeforeRandomTransition = 0;
SoftReset();
UpdateMediaData();
}
public void SoftReset()
{
_cpu.NESSoftReset();
_overflowFlagDelaySr = 0;
}
public void InsertMedia(Disk disk)
{
_disk = disk;
UpdateMediaData();
}
private void UpdateMediaData()
{
if (_disk != null)
{
_trackImageData = _disk.GetDataForTrack(_trackNumber);
_diskBits = _trackImageData[_diskByteOffset] >> (Disk.FluxBitsPerEntry - _diskBitsLeft);
_diskWriteProtected = _disk.WriteProtected;
}
else
{
_diskWriteProtected = true;
2017-04-24 13:35:05 +00:00
}
}
public void RemoveMedia()
{
_disk = null;
_trackImageData = null;
_diskBits = 0;
}
}
2016-02-22 23:50:11 +00:00
}