C64: Allow writing to disk.
This commit is contained in:
parent
0cdb28fc8f
commit
4e1892d094
|
@ -129,15 +129,15 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
_acrSrControl = 0;
|
||||
_acrT1Control = 0;
|
||||
_acrT2Control = 0;
|
||||
_ca1L = false;
|
||||
_cb1L = false;
|
||||
Ca1 = false;
|
||||
Ca2 = false;
|
||||
Cb1 = false;
|
||||
Cb2 = false;
|
||||
_ca1L = true;
|
||||
_cb1L = true;
|
||||
Ca1 = true;
|
||||
Ca2 = true;
|
||||
Cb1 = true;
|
||||
Cb2 = true;
|
||||
|
||||
_pb6L = false;
|
||||
_pb6 = false;
|
||||
_pb6L = true;
|
||||
_pb6 = true;
|
||||
_resetCa2NextClock = false;
|
||||
_resetCb2NextClock = false;
|
||||
_handshakeCa2NextClock = false;
|
||||
|
@ -222,9 +222,6 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
switch (_acrT1Control)
|
||||
{
|
||||
case ACR_T1_CONTROL_CONTINUOUS_INTERRUPTS:
|
||||
_t1C = _t1L;
|
||||
_t1CLoaded = true;
|
||||
break;
|
||||
case ACR_T1_CONTROL_CONTINUOUS_INTERRUPTS_AND_OUTPUT_ON_PB7:
|
||||
_t1C = _t1L;
|
||||
_t1CLoaded = true;
|
||||
|
@ -261,11 +258,11 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
if (!_pb6 && _pb6L)
|
||||
{
|
||||
_t2C--;
|
||||
if (_t2C < 0)
|
||||
if (_t2C == 0)
|
||||
{
|
||||
_ifr |= 0x20;
|
||||
_t2C = 0xFFFF;
|
||||
}
|
||||
_t2C &= 0xFFFF;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -331,26 +328,45 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
break;
|
||||
}
|
||||
|
||||
// interrupt generation
|
||||
if ((_pcrCb1IntControl == PCR_INT_CONTROL_POSITIVE_EDGE && Cb1 && !_cb1L) ||
|
||||
(_pcrCb1IntControl == PCR_INT_CONTROL_NEGATIVE_EDGE && !Cb1 && _cb1L))
|
||||
{
|
||||
_ifr |= 0x10;
|
||||
if (_acrPbLatchEnable)
|
||||
{
|
||||
_pbLatch = _port.ReadExternalPrb();
|
||||
}
|
||||
}
|
||||
// interrupt generation
|
||||
|
||||
if ((_pcrCa1IntControl == PCR_INT_CONTROL_POSITIVE_EDGE && Ca1 && !_ca1L) ||
|
||||
(_pcrCa1IntControl == PCR_INT_CONTROL_NEGATIVE_EDGE && !Ca1 && _ca1L))
|
||||
{
|
||||
_ifr |= 0x02;
|
||||
if (_acrPaLatchEnable)
|
||||
{
|
||||
_paLatch = _port.ReadExternalPra();
|
||||
}
|
||||
}
|
||||
/*
|
||||
As long as the CA1 interrupt flag is set, the data on the peripheral pins can change
|
||||
without affecting the data in the latches. This input latching can be used with any of the CA2
|
||||
input or output modes.
|
||||
It is important to note that on the PA port, the processor always reads the data on the
|
||||
peripheral pins (as reflected in the latches). For output pins, the processor still reads the
|
||||
latches. This may or may not reflect the data currently in the ORA. Proper system operation
|
||||
requires careful planning on the part of the system designer if input latching is combined
|
||||
with output pins on the peripheral ports.
|
||||
*/
|
||||
|
||||
if ((_pcrCa1IntControl == PCR_INT_CONTROL_POSITIVE_EDGE && Ca1 && !_ca1L) ||
|
||||
(_pcrCa1IntControl == PCR_INT_CONTROL_NEGATIVE_EDGE && !Ca1 && _ca1L))
|
||||
{
|
||||
if (_acrPaLatchEnable && (_ifr & 0x02) == 0)
|
||||
{
|
||||
_paLatch = _port.ReadExternalPra();
|
||||
}
|
||||
_ifr |= 0x02;
|
||||
}
|
||||
|
||||
/*
|
||||
Input latching on the PB port is controlled in the same manner as that described for the PA port.
|
||||
However, with the peripheral B port the input latch will store either the voltage on the pin or the contents
|
||||
of the Output Register (ORB) depending on whether the pin is programmed to act as an input or an
|
||||
output. As with the PA port, the processor always reads the input latches.
|
||||
*/
|
||||
|
||||
if ((_pcrCb1IntControl == PCR_INT_CONTROL_POSITIVE_EDGE && Cb1 && !_cb1L) ||
|
||||
(_pcrCb1IntControl == PCR_INT_CONTROL_NEGATIVE_EDGE && !Cb1 && _cb1L))
|
||||
{
|
||||
if (_acrPbLatchEnable && (_ifr & 0x10) == 0)
|
||||
{
|
||||
_pbLatch = _port.ReadPrb(_prb, _ddrb);
|
||||
}
|
||||
_ifr |= 0x10;
|
||||
}
|
||||
|
||||
switch (_acrSrControl)
|
||||
{
|
||||
|
|
|
@ -9,6 +9,22 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media
|
|||
{
|
||||
const int D64_DISK_ID_OFFSET = 0x165A2; // track 18, sector 0, 0xA2
|
||||
|
||||
private enum ErrorType
|
||||
{
|
||||
NoError = 0x01,
|
||||
HeaderNotFound = 0x02,
|
||||
NoSyncSequence = 0x03,
|
||||
DataNotFound = 0x04,
|
||||
DataChecksumError = 0x05,
|
||||
WriteVerifyFormatError = 0x06,
|
||||
WriteVerifyError = 0x07,
|
||||
WriteProtectOn = 0x08,
|
||||
HeaderChecksumError = 0x09,
|
||||
WriteError = 0x0A,
|
||||
IdMismatch = 0x0B,
|
||||
DriveNotReady = 0x0F
|
||||
}
|
||||
|
||||
private static readonly int[] DensityTable =
|
||||
{
|
||||
3, 3, 3, 3, 3,
|
||||
|
@ -84,25 +100,34 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media
|
|||
return result;
|
||||
}
|
||||
|
||||
private static byte[] ConvertSectorToGcr(byte[] source, byte sectorNo, byte trackNo, byte formatA, byte formatB, int gapLength, out int bitsWritten)
|
||||
private static byte[] ConvertSectorToGcr(byte[] source, byte sectorNo, byte trackNo, byte formatA, byte formatB, int gapLength, ErrorType errorType, out int bitsWritten)
|
||||
{
|
||||
using (var mem = new MemoryStream())
|
||||
{
|
||||
var writer = new BinaryWriter(mem);
|
||||
var headerChecksum = (byte)(sectorNo ^ trackNo ^ formatA ^ formatB);
|
||||
|
||||
if (errorType == ErrorType.IdMismatch)
|
||||
{
|
||||
formatA ^= 0xFF;
|
||||
formatB ^= 0xFF;
|
||||
}
|
||||
|
||||
var headerChecksum = (byte)(sectorNo ^ trackNo ^ formatA ^ formatB ^ (errorType == ErrorType.HeaderChecksumError ? 0xFF : 0x00));
|
||||
|
||||
// assemble written data for GCR encoding
|
||||
var writtenData = new byte[260];
|
||||
var syncBytes40 = Enumerable.Repeat((byte) (errorType == ErrorType.NoSyncSequence ? 0x00 : 0xFF), 5).ToArray();
|
||||
|
||||
Array.Copy(source, 0, writtenData, 1, 256);
|
||||
writtenData[0] = 0x07;
|
||||
writtenData[0x101] = Checksum(source);
|
||||
writtenData[0] = (byte)(errorType == ErrorType.HeaderNotFound ? 0x00 : 0x07);
|
||||
writtenData[0x101] = (byte)(Checksum(source) ^ (errorType == ErrorType.DataChecksumError ? 0xFF : 0x00));
|
||||
writtenData[0x102] = 0x00;
|
||||
writtenData[0x103] = 0x00;
|
||||
|
||||
writer.Write(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); // sync
|
||||
writer.Write(EncodeGcr(new byte[] { 0x08, headerChecksum, sectorNo, trackNo, formatA, formatB, 0x0F, 0x0F })); // header
|
||||
writer.Write(syncBytes40); // sync
|
||||
writer.Write(EncodeGcr(new byte[] { (byte)(errorType == ErrorType.DataNotFound ? 0x00 : 0x08), headerChecksum, sectorNo, trackNo, formatA, formatB, 0x0F, 0x0F })); // header
|
||||
writer.Write(new byte[] { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 }); // gap
|
||||
writer.Write(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); // sync
|
||||
writer.Write(syncBytes40); // sync
|
||||
writer.Write(EncodeGcr(writtenData)); // data
|
||||
writer.Write(Enumerable.Repeat((byte)0x55, gapLength).ToArray()); // gap
|
||||
|
||||
|
@ -156,67 +181,76 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media
|
|||
|
||||
public static Disk Read(byte[] source)
|
||||
{
|
||||
var formatB = source[D64_DISK_ID_OFFSET + 0x00];
|
||||
var formatA = source[D64_DISK_ID_OFFSET + 0x01];
|
||||
var formatB = source[D64_DISK_ID_OFFSET + 0x00];
|
||||
var formatA = source[D64_DISK_ID_OFFSET + 0x01];
|
||||
|
||||
using (var mem = new MemoryStream(source))
|
||||
{
|
||||
var reader = new BinaryReader(mem);
|
||||
var trackDatas = new List<byte[]>();
|
||||
var trackLengths = new List<int>();
|
||||
var trackNumbers = new List<int>();
|
||||
var trackDensities = new List<int>();
|
||||
int trackCount;
|
||||
using (var mem = new MemoryStream(source))
|
||||
{
|
||||
var reader = new BinaryReader(mem);
|
||||
var trackDatas = new List<byte[]>();
|
||||
var trackLengths = new List<int>();
|
||||
var trackNumbers = new List<int>();
|
||||
var trackDensities = new List<int>();
|
||||
var errorType = ErrorType.NoError;
|
||||
int trackCount;
|
||||
int errorOffset = -1;
|
||||
|
||||
switch (source.Length)
|
||||
{
|
||||
case 174848: // 35 tracks no errors
|
||||
trackCount = 35;
|
||||
break;
|
||||
case 175531: // 35 tracks with errors
|
||||
trackCount = 35;
|
||||
break;
|
||||
case 196608: // 40 tracks no errors
|
||||
trackCount = 40;
|
||||
break;
|
||||
case 197376: // 40 tracks with errors
|
||||
trackCount = 40;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Not able to identify capacity of the D64 file.");
|
||||
}
|
||||
switch (source.Length)
|
||||
{
|
||||
case 174848: // 35 tracks no errors
|
||||
trackCount = 35;
|
||||
break;
|
||||
case 175531: // 35 tracks with errors
|
||||
trackCount = 35;
|
||||
errorOffset = 174848;
|
||||
break;
|
||||
case 196608: // 40 tracks no errors
|
||||
trackCount = 40;
|
||||
break;
|
||||
case 197376: // 40 tracks with errors
|
||||
trackCount = 40;
|
||||
errorOffset = 196608;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Not able to identify capacity of the D64 file.");
|
||||
}
|
||||
|
||||
for (var i = 0; i < trackCount; i++)
|
||||
{
|
||||
var sectors = SectorsPerTrack[i];
|
||||
var trackLengthBits = 0;
|
||||
using (var trackMem = new MemoryStream())
|
||||
{
|
||||
for (var j = 0; j < sectors; j++)
|
||||
{
|
||||
int bitsWritten;
|
||||
var sectorData = reader.ReadBytes(256);
|
||||
var diskData = ConvertSectorToGcr(sectorData, (byte)j, (byte)(i + 1), formatA, formatB, StandardSectorGapLength[DensityTable[i]], out bitsWritten);
|
||||
trackMem.Write(diskData, 0, diskData.Length);
|
||||
trackLengthBits += bitsWritten;
|
||||
}
|
||||
var density = DensityTable[i];
|
||||
for (var i = 0; i < trackCount; i++)
|
||||
{
|
||||
if (errorOffset >= 0)
|
||||
{
|
||||
errorType = (ErrorType) source[errorOffset];
|
||||
errorOffset++;
|
||||
}
|
||||
var sectors = SectorsPerTrack[i];
|
||||
var trackLengthBits = 0;
|
||||
using (var trackMem = new MemoryStream())
|
||||
{
|
||||
for (var j = 0; j < sectors; j++)
|
||||
{
|
||||
int bitsWritten;
|
||||
var sectorData = reader.ReadBytes(256);
|
||||
var diskData = ConvertSectorToGcr(sectorData, (byte)j, (byte)(i + 1), formatA, formatB, StandardSectorGapLength[DensityTable[i]], errorType, out bitsWritten);
|
||||
trackMem.Write(diskData, 0, diskData.Length);
|
||||
trackLengthBits += bitsWritten;
|
||||
}
|
||||
var density = DensityTable[i];
|
||||
|
||||
// we pad the tracks with extra gap bytes to meet MNIB standards
|
||||
while (trackMem.Length < StandardTrackLengthBytes[density])
|
||||
{
|
||||
trackMem.WriteByte(0x55);
|
||||
}
|
||||
// we pad the tracks with extra gap bytes to meet MNIB standards
|
||||
while (trackMem.Length < StandardTrackLengthBytes[density])
|
||||
{
|
||||
trackMem.WriteByte(0x55);
|
||||
}
|
||||
|
||||
trackDatas.Add(trackMem.ToArray());
|
||||
trackLengths.Add(trackLengthBits);
|
||||
trackNumbers.Add(i * 2);
|
||||
trackDensities.Add(DensityTable[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return new Disk(trackDatas, trackNumbers, trackDensities, 84);
|
||||
}
|
||||
}
|
||||
trackDatas.Add(trackMem.ToArray());
|
||||
trackLengths.Add(trackLengthBits);
|
||||
trackNumbers.Add(i * 2);
|
||||
trackDensities.Add(DensityTable[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return new Disk(trackDatas, trackNumbers, trackDensities, 84);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,11 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
|
|||
private int _rngCurrent;
|
||||
private int _clocks;
|
||||
private int _cpuClocks;
|
||||
private int _diskWriteBitsRemaining;
|
||||
private bool _diskWriteEnabled;
|
||||
private int _diskWriteLatch;
|
||||
private int _diskOutputBits;
|
||||
private bool _diskWriteProtected;
|
||||
|
||||
// Lehmer RNG
|
||||
private void AdvanceRng()
|
||||
|
@ -31,127 +36,167 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
|
|||
_rngCurrent = (int)(_rngCurrent * LEHMER_RNG_PRIME % int.MaxValue);
|
||||
}
|
||||
|
||||
private void ExecuteFlux()
|
||||
{
|
||||
// This actually executes the main 16mhz clock
|
||||
while (_clocks > 0)
|
||||
{
|
||||
_clocks--;
|
||||
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;
|
||||
}
|
||||
// rotate disk
|
||||
if (_motorEnabled)
|
||||
{
|
||||
if (_disk == null)
|
||||
{
|
||||
_diskBitsLeft = 1;
|
||||
_diskBits = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_diskBitsLeft <= 0)
|
||||
{
|
||||
if (_diskWriteEnabled)
|
||||
_trackImageData[_diskByteOffset] = _diskOutputBits;
|
||||
|
||||
_diskBits = _trackImageData[_diskByteOffset];
|
||||
_diskBitsLeft = Disk.FluxBitsPerEntry;
|
||||
}
|
||||
}
|
||||
_diskByteOffset++;
|
||||
|
||||
if ((_diskBits & 1) != 0)
|
||||
{
|
||||
_countsBeforeRandomTransition = 0;
|
||||
_diskFluxReversalDetected = true;
|
||||
}
|
||||
if (_diskByteOffset == Disk.FluxEntriesPerTrack)
|
||||
_diskByteOffset = 0;
|
||||
|
||||
_diskBits >>= 1;
|
||||
_diskBitsLeft--;
|
||||
}
|
||||
if (!_diskWriteEnabled)
|
||||
_diskBits = _trackImageData[_diskByteOffset];
|
||||
|
||||
// random flux transition readings for unformatted data
|
||||
if (_countsBeforeRandomTransition > 0)
|
||||
{
|
||||
_countsBeforeRandomTransition--;
|
||||
if (_countsBeforeRandomTransition == 0)
|
||||
{
|
||||
_diskFluxReversalDetected = true;
|
||||
AdvanceRng();
|
||||
_diskOutputBits = 0;
|
||||
_diskBitsLeft = Disk.FluxBitsPerEntry;
|
||||
}
|
||||
}
|
||||
_diskOutputBits >>= 1;
|
||||
|
||||
// This constant is what VICE uses. TODO: Determine accuracy.
|
||||
_countsBeforeRandomTransition = (_rngCurrent % 367) + 33;
|
||||
}
|
||||
}
|
||||
if (_diskWriteEnabled)
|
||||
_countsBeforeRandomTransition = 0;
|
||||
|
||||
// flux transition circuitry
|
||||
if (_diskFluxReversalDetected)
|
||||
{
|
||||
_diskDensityCounter = _diskDensity;
|
||||
_diskSupplementaryCounter = 0;
|
||||
_diskFluxReversalDetected = false;
|
||||
if (_countsBeforeRandomTransition == 0)
|
||||
{
|
||||
AdvanceRng();
|
||||
if ((_diskBits & 1) != 0)
|
||||
{
|
||||
_countsBeforeRandomTransition = 0;
|
||||
_diskFluxReversalDetected = true;
|
||||
_diskOutputBits |= int.MinValue; // set bit 31
|
||||
}
|
||||
else
|
||||
{
|
||||
_diskOutputBits &= int.MaxValue; // clear bit 31
|
||||
}
|
||||
|
||||
// This constant is what VICE uses. TODO: Determine accuracy.
|
||||
_countsBeforeRandomTransition = (_rngCurrent & 0x1F) + 289;
|
||||
}
|
||||
}
|
||||
_diskBits >>= 1;
|
||||
_diskBitsLeft--;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
if (_bitsRemainingInLatchedByte <= 0)
|
||||
{
|
||||
_bitsRemainingInLatchedByte = 8;
|
||||
// flux transition circuitry
|
||||
if (_diskFluxReversalDetected)
|
||||
{
|
||||
if (!_diskWriteEnabled)
|
||||
{
|
||||
_diskDensityCounter = _diskDensity;
|
||||
_diskSupplementaryCounter = 0;
|
||||
}
|
||||
_diskFluxReversalDetected = false;
|
||||
if (_countsBeforeRandomTransition == 0)
|
||||
{
|
||||
AdvanceRng();
|
||||
// This constant is what VICE uses. TODO: Determine accuracy.
|
||||
_countsBeforeRandomTransition = (_rngCurrent & 0x1F) + 289;
|
||||
}
|
||||
}
|
||||
|
||||
// SOE (sync output enabled)
|
||||
_byteReady = Via1.Ca2;
|
||||
}
|
||||
// counter circuitry
|
||||
if (_diskDensityCounter >= 16)
|
||||
{
|
||||
_diskDensityCounter = _diskDensity;
|
||||
_diskSupplementaryCounter++;
|
||||
|
||||
// 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 & 0x3) == 0x2)
|
||||
{
|
||||
if (!_diskWriteEnabled)
|
||||
_diskWriteBitsRemaining = 0;
|
||||
_diskWriteEnabled = !Via1.Cb2;
|
||||
|
||||
if (_diskSupplementaryCounter >= 16)
|
||||
{
|
||||
_diskSupplementaryCounter = 0;
|
||||
}
|
||||
_diskWriteBitsRemaining--;
|
||||
if (_diskWriteEnabled)
|
||||
{
|
||||
_countsBeforeRandomTransition = 0;
|
||||
_byteReady = false;
|
||||
if (_diskWriteBitsRemaining <= 0)
|
||||
{
|
||||
_diskWriteLatch = Via1.EffectivePrA;
|
||||
_diskWriteBitsRemaining = 8;
|
||||
_byteReady = Via1.Ca2;
|
||||
}
|
||||
if ((_diskWriteLatch & 0x80) != 0)
|
||||
{
|
||||
_diskOutputBits |= int.MinValue; // set bit 31
|
||||
}
|
||||
_diskWriteLatch <<= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
_bitsRemainingInLatchedByte--;
|
||||
_byteReady = false;
|
||||
_bitHistory = (_bitHistory << 1) | ((_diskSupplementaryCounter & 0xC) == 0x0 ? 1 : 0);
|
||||
_sync = false;
|
||||
if (!_diskWriteEnabled && (_bitHistory & 0x3FF) == 0x3FF)
|
||||
{
|
||||
_sync = true;
|
||||
_bitsRemainingInLatchedByte = 8;
|
||||
_byteReady = false;
|
||||
}
|
||||
|
||||
_cpuClocks--;
|
||||
if (_cpuClocks <= 0)
|
||||
{
|
||||
ExecuteSystem();
|
||||
_cpuClocks = 16;
|
||||
}
|
||||
if (_bitsRemainingInLatchedByte <= 0)
|
||||
{
|
||||
_bitsRemainingInLatchedByte = 8;
|
||||
|
||||
_diskDensityCounter++;
|
||||
_diskCycle = (_diskCycle + 1) & 0xF;
|
||||
}
|
||||
}
|
||||
// SOE (SO/Byte Ready 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
|
||||
private int ReadVia1PrB()
|
||||
{
|
||||
return (_motorStep & 0x03) | (_motorEnabled ? 0x04 : 0x00) | (_sync ? 0x00 : 0x80);
|
||||
return (_motorStep & 0x03) | (_motorEnabled ? 0x04 : 0x00) | (_sync ? 0x00 : 0x80) | (_diskWriteProtected ? 0x00 : 0x10);
|
||||
}
|
||||
|
||||
public int Peek(int addr)
|
||||
|
|
|
@ -117,6 +117,11 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
|
|||
ser.Sync("Clocks", ref _clocks);
|
||||
ser.Sync("CpuClocks", ref _cpuClocks);
|
||||
ser.Sync("OverflowFlagDelayShiftRegister", ref _overflowFlagDelaySr);
|
||||
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);
|
||||
}
|
||||
|
||||
public override void ExecutePhase()
|
||||
|
|
Loading…
Reference in New Issue