C64: Better lifecycle management and 1541-II support.
This commit is contained in:
parent
87200593b6
commit
f4f45f73a8
|
@ -261,6 +261,7 @@
|
|||
<Compile Include="Computers\Commodore64\Serial\Drive1541.IDebuggable.cs" />
|
||||
<Compile Include="Computers\Commodore64\Serial\Drive1541.IDisassemblable.cs" />
|
||||
<Compile Include="Computers\Commodore64\Serial\Drive1541.Motor.cs" />
|
||||
<Compile Include="Computers\Commodore64\Serial\Drive1541.Registers.cs" />
|
||||
<Compile Include="Computers\Commodore64\Serial\SerialPort.cs" />
|
||||
<Compile Include="Computers\Commodore64\Serial\SerialPortDevice.cs" />
|
||||
<Compile Include="Computers\Commodore64\User\UserPort.cs" />
|
||||
|
|
|
@ -115,7 +115,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
|
||||
public enum DiskDriveType
|
||||
{
|
||||
None, Commodore1541
|
||||
None, Commodore1541, Commodore1541II
|
||||
}
|
||||
}
|
||||
}
|
|
@ -130,6 +130,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
switch (diskDriveType)
|
||||
{
|
||||
case C64.DiskDriveType.Commodore1541:
|
||||
case C64.DiskDriveType.Commodore1541II:
|
||||
DiskDrive = new Drive1541(ClockNumerator, ClockDenominator);
|
||||
Serial.Connect(DiskDrive);
|
||||
break;
|
||||
|
|
|
@ -117,7 +117,19 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
if (_board != null)
|
||||
{
|
||||
if (_board.TapeDrive != null)
|
||||
{
|
||||
_board.TapeDrive.RemoveMedia();
|
||||
}
|
||||
if (_board.DiskDrive != null)
|
||||
{
|
||||
_board.DiskDrive.RemoveMedia();
|
||||
}
|
||||
_board = null;
|
||||
}
|
||||
}
|
||||
|
||||
private int _frameCycles;
|
||||
|
||||
|
@ -266,19 +278,19 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
|
||||
private void InitRoms(DiskDriveType diskDriveType)
|
||||
{
|
||||
var basicRom = GetFirmware(0x2000, "Basic");
|
||||
var charRom = GetFirmware(0x1000, "Chargen");
|
||||
var kernalRom = GetFirmware(0x2000, "Kernal");
|
||||
_board.BasicRom.Flash(GetFirmware(0x2000, "Basic"));
|
||||
_board.KernalRom.Flash(GetFirmware(0x1000, "Chargen"));
|
||||
_board.CharRom.Flash(GetFirmware(0x2000, "Kernal"));
|
||||
|
||||
_board.BasicRom.Flash(basicRom);
|
||||
_board.KernalRom.Flash(kernalRom);
|
||||
_board.CharRom.Flash(charRom);
|
||||
|
||||
if (diskDriveType == DiskDriveType.Commodore1541)
|
||||
switch (diskDriveType)
|
||||
{
|
||||
var diskRom = GetFirmware(0x4000, "Drive1541", "Drive1541II");
|
||||
_board.DiskDrive.DriveRom.Flash(diskRom);
|
||||
}
|
||||
case DiskDriveType.Commodore1541:
|
||||
_board.DiskDrive.DriveRom.Flash(GetFirmware(0x4000, "Drive1541"));
|
||||
break;
|
||||
case DiskDriveType.Commodore1541II:
|
||||
_board.DiskDrive.DriveRom.Flash(GetFirmware(0x4000, "Drive1541II"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------
|
||||
|
|
|
@ -37,5 +37,10 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cassette
|
|||
{
|
||||
_tape = tape;
|
||||
}
|
||||
|
||||
public void RemoveMedia()
|
||||
{
|
||||
_tape = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,30 +76,32 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media
|
|||
|
||||
private static byte[] ConvertSectorToGcr(byte[] source, byte sectorNo, byte trackNo, byte formatA, byte formatB, out int bitsWritten)
|
||||
{
|
||||
var mem = new MemoryStream();
|
||||
var writer = new BinaryWriter(mem);
|
||||
var headerChecksum = (byte)(sectorNo ^ trackNo ^ formatA ^ formatB);
|
||||
using (var mem = new MemoryStream())
|
||||
{
|
||||
var writer = new BinaryWriter(mem);
|
||||
var headerChecksum = (byte)(sectorNo ^ trackNo ^ formatA ^ formatB);
|
||||
|
||||
// assemble written data for GCR encoding
|
||||
var writtenData = new byte[260];
|
||||
Array.Copy(source, 0, writtenData, 1, 256);
|
||||
writtenData[0] = 0x07;
|
||||
writtenData[0x101] = Checksum(source);
|
||||
writtenData[0x102] = 0x00;
|
||||
writtenData[0x103] = 0x00;
|
||||
// assemble written data for GCR encoding
|
||||
var writtenData = new byte[260];
|
||||
Array.Copy(source, 0, writtenData, 1, 256);
|
||||
writtenData[0] = 0x07;
|
||||
writtenData[0x101] = Checksum(source);
|
||||
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(new byte[] { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 }); // gap
|
||||
writer.Write(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); // sync
|
||||
writer.Write(EncodeGcr(writtenData)); // data
|
||||
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(EncodeGcr(new byte[] { 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(EncodeGcr(writtenData)); // data
|
||||
writer.Write(new byte[] { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 }); // gap
|
||||
|
||||
bitsWritten = (int)mem.Length * 8;
|
||||
bitsWritten = (int)mem.Length * 8;
|
||||
|
||||
writer.Flush();
|
||||
return mem.ToArray();
|
||||
}
|
||||
writer.Flush();
|
||||
return mem.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] EncodeGcr(byte[] source)
|
||||
{
|
||||
|
@ -107,113 +109,101 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media
|
|||
var gcr = new int[8];
|
||||
var data = new byte[4];
|
||||
var count = source.Length;
|
||||
var mem = new MemoryStream();
|
||||
var writer = new BinaryWriter(mem);
|
||||
using (var mem = new MemoryStream())
|
||||
{
|
||||
var writer = new BinaryWriter(mem);
|
||||
|
||||
for (var i = 0; i < count; i += 4)
|
||||
{
|
||||
Array.Copy(source, i, data, 0, 4);
|
||||
gcr[0] = gcrEncodeTable[data[0] >> 4];
|
||||
gcr[1] = gcrEncodeTable[data[0] & 0xF];
|
||||
gcr[2] = gcrEncodeTable[data[1] >> 4];
|
||||
gcr[3] = gcrEncodeTable[data[1] & 0xF];
|
||||
gcr[4] = gcrEncodeTable[data[2] >> 4];
|
||||
gcr[5] = gcrEncodeTable[data[2] & 0xF];
|
||||
gcr[6] = gcrEncodeTable[data[3] >> 4];
|
||||
gcr[7] = gcrEncodeTable[data[3] & 0xF];
|
||||
for (var i = 0; i < count; i += 4)
|
||||
{
|
||||
Array.Copy(source, i, data, 0, 4);
|
||||
gcr[0] = gcrEncodeTable[data[0] >> 4];
|
||||
gcr[1] = gcrEncodeTable[data[0] & 0xF];
|
||||
gcr[2] = gcrEncodeTable[data[1] >> 4];
|
||||
gcr[3] = gcrEncodeTable[data[1] & 0xF];
|
||||
gcr[4] = gcrEncodeTable[data[2] >> 4];
|
||||
gcr[5] = gcrEncodeTable[data[2] & 0xF];
|
||||
gcr[6] = gcrEncodeTable[data[3] >> 4];
|
||||
gcr[7] = gcrEncodeTable[data[3] & 0xF];
|
||||
|
||||
// -------- -------- -------- -------- --------
|
||||
// 00000111 11222223 33334444 45555566 66677777
|
||||
// -------- -------- -------- -------- --------
|
||||
// 00000111 11222223 33334444 45555566 66677777
|
||||
|
||||
var outputValue = (gcr[0] << 3) | (gcr[1] >> 2);
|
||||
writer.Write((byte)(outputValue & 0xFF));
|
||||
outputValue = (gcr[1] << 6) | (gcr[2] << 1) | (gcr[3] >> 4);
|
||||
writer.Write((byte)(outputValue & 0xFF));
|
||||
outputValue = (gcr[3] << 4) | (gcr[4] >> 1);
|
||||
writer.Write((byte)(outputValue & 0xFF));
|
||||
outputValue = (gcr[4] << 7) | (gcr[5] << 2) | (gcr[6] >> 3);
|
||||
writer.Write((byte)(outputValue & 0xFF));
|
||||
outputValue = (gcr[6] << 5) | (gcr[7]);
|
||||
writer.Write((byte)(outputValue & 0xFF));
|
||||
|
||||
/*
|
||||
// -------- -------- -------- -------- --------
|
||||
// 11100000 32222211 44443333 66555554 77777666
|
||||
|
||||
var outputValue = (gcr[0]) | (gcr[1] << 5);
|
||||
writer.Write((byte)(outputValue & 0xFF));
|
||||
outputValue = (gcr[1] >> 3) | (gcr[2] << 2) | (gcr[3] << 7);
|
||||
writer.Write((byte)(outputValue & 0xFF));
|
||||
outputValue = (gcr[3] >> 1) | (gcr[4] << 4);
|
||||
writer.Write((byte)(outputValue & 0xFF));
|
||||
outputValue = (gcr[4] >> 4) | (gcr[5] << 1) | (gcr[6] << 6);
|
||||
writer.Write((byte)(outputValue & 0xFF));
|
||||
outputValue = (gcr[6] >> 2) | (gcr[7] << 3);
|
||||
writer.Write((byte)(outputValue & 0xFF));
|
||||
*/
|
||||
var outputValue = (gcr[0] << 3) | (gcr[1] >> 2);
|
||||
writer.Write((byte)(outputValue & 0xFF));
|
||||
outputValue = (gcr[1] << 6) | (gcr[2] << 1) | (gcr[3] >> 4);
|
||||
writer.Write((byte)(outputValue & 0xFF));
|
||||
outputValue = (gcr[3] << 4) | (gcr[4] >> 1);
|
||||
writer.Write((byte)(outputValue & 0xFF));
|
||||
outputValue = (gcr[4] << 7) | (gcr[5] << 2) | (gcr[6] >> 3);
|
||||
writer.Write((byte)(outputValue & 0xFF));
|
||||
outputValue = (gcr[6] << 5) | (gcr[7]);
|
||||
writer.Write((byte)(outputValue & 0xFF));
|
||||
}
|
||||
writer.Flush();
|
||||
return mem.ToArray();
|
||||
}
|
||||
writer.Flush();
|
||||
return mem.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static Disk Read(byte[] source)
|
||||
{
|
||||
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>();
|
||||
int trackCount;
|
||||
|
||||
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.");
|
||||
}
|
||||
|
||||
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), 0xA0, 0xA0, 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);
|
||||
}
|
||||
|
||||
trackDatas.Add(trackMem.ToArray());
|
||||
trackLengths.Add(trackLengthBits);
|
||||
trackNumbers.Add(i * 2);
|
||||
trackDensities.Add(densityTable[i]);
|
||||
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.");
|
||||
}
|
||||
}
|
||||
|
||||
return new Disk(trackDatas, trackNumbers, trackDensities, trackLengths, 84);
|
||||
}
|
||||
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), 0xA0, 0xA0, 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);
|
||||
}
|
||||
|
||||
trackDatas.Add(trackMem.ToArray());
|
||||
trackLengths.Add(trackLengthBits);
|
||||
trackNumbers.Add(i * 2);
|
||||
trackDensities.Add(densityTable[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return new Disk(trackDatas, trackNumbers, trackDensities, trackLengths, 84);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media
|
|||
FillMissingTracks();
|
||||
_originalMedia = SerializeTracks(_tracks);
|
||||
Valid = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an expanded representation of a magnetic disk.
|
||||
|
|
|
@ -9,54 +9,56 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media
|
|||
{
|
||||
public static Disk Read(byte[] source)
|
||||
{
|
||||
var mem = new MemoryStream(source);
|
||||
var reader = new BinaryReader(mem);
|
||||
var id = new string(reader.ReadChars(8));
|
||||
var trackDatas = new List<byte[]>();
|
||||
var trackLengths = new List<int>();
|
||||
var trackNumbers = new List<int>();
|
||||
var trackDensities = new List<int>();
|
||||
using (var mem = new MemoryStream(source))
|
||||
{
|
||||
var reader = new BinaryReader(mem);
|
||||
var id = new string(reader.ReadChars(8));
|
||||
var trackDatas = new List<byte[]>();
|
||||
var trackLengths = new List<int>();
|
||||
var trackNumbers = new List<int>();
|
||||
var trackDensities = new List<int>();
|
||||
|
||||
if (id == @"GCR-1541")
|
||||
{
|
||||
if (id == @"GCR-1541")
|
||||
{
|
||||
|
||||
reader.ReadByte(); //version
|
||||
int trackCount = reader.ReadByte();
|
||||
reader.ReadInt16(); //max track size in bytes
|
||||
reader.ReadByte(); //version
|
||||
int trackCount = reader.ReadByte();
|
||||
reader.ReadInt16(); //max track size in bytes
|
||||
|
||||
var trackOffsetTable = new int[trackCount];
|
||||
var trackSpeedTable = new int[trackCount];
|
||||
var trackOffsetTable = new int[trackCount];
|
||||
var trackSpeedTable = new int[trackCount];
|
||||
|
||||
for (var i = 0; i < trackCount; i++)
|
||||
trackOffsetTable[i] = reader.ReadInt32();
|
||||
for (var i = 0; i < trackCount; i++)
|
||||
trackOffsetTable[i] = reader.ReadInt32();
|
||||
|
||||
for (var i = 0; i < trackCount; i++)
|
||||
trackSpeedTable[i] = reader.ReadInt32();
|
||||
for (var i = 0; i < trackCount; i++)
|
||||
trackSpeedTable[i] = reader.ReadInt32();
|
||||
|
||||
for (var i = 0; i < trackCount; i++)
|
||||
{
|
||||
if (trackOffsetTable[i] > 0)
|
||||
{
|
||||
mem.Position = trackOffsetTable[i];
|
||||
int trackLength = reader.ReadInt16();
|
||||
var trackData = reader.ReadBytes(trackLength);
|
||||
for (var i = 0; i < trackCount; i++)
|
||||
{
|
||||
if (trackOffsetTable[i] > 0)
|
||||
{
|
||||
mem.Position = trackOffsetTable[i];
|
||||
int trackLength = reader.ReadInt16();
|
||||
var trackData = reader.ReadBytes(trackLength);
|
||||
|
||||
trackDatas.Add(trackData);
|
||||
trackLengths.Add(trackLength * 8);
|
||||
trackDensities.Add(trackSpeedTable[i]);
|
||||
trackNumbers.Add(i);
|
||||
}
|
||||
}
|
||||
trackDatas.Add(trackData);
|
||||
trackLengths.Add(trackLength * 8);
|
||||
trackDensities.Add(trackSpeedTable[i]);
|
||||
trackNumbers.Add(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (trackSpeedTable.Any(ts => ts > 3 || ts < 0))
|
||||
{
|
||||
throw new Exception("Byte-level speeds are not yet supported in the G64 loader.");
|
||||
}
|
||||
if (trackSpeedTable.Any(ts => ts > 3 || ts < 0))
|
||||
{
|
||||
throw new Exception("Byte-level speeds are not yet supported in the G64 loader.");
|
||||
}
|
||||
|
||||
return new Disk(trackDatas, trackNumbers, trackDensities, trackLengths, 84);
|
||||
}
|
||||
return new Disk(trackDatas, trackNumbers, trackDensities, trackLengths, 84);
|
||||
}
|
||||
|
||||
return new Disk(84);
|
||||
}
|
||||
return new Disk(84);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,10 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
|
|||
private int _countsBeforeRandomTransition;
|
||||
[SaveState.SaveWithName("CurrentRNG")]
|
||||
private int _rngCurrent;
|
||||
[SaveState.SaveWithName("Clocks")]
|
||||
private int _clocks;
|
||||
[SaveState.SaveWithName("CpuClocks")]
|
||||
private int _cpuClocks;
|
||||
|
||||
// Lehmer RNG
|
||||
private void AdvanceRng()
|
||||
|
@ -43,8 +47,11 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
|
|||
|
||||
private void ExecuteFlux()
|
||||
{
|
||||
for (_diskCycle = 0; _diskCycle < 16; _diskCycle++)
|
||||
// This actually executes the main 16mhz clock
|
||||
while (_clocks > 0)
|
||||
{
|
||||
_clocks--;
|
||||
|
||||
// rotate disk
|
||||
if (_motorEnabled)
|
||||
{
|
||||
|
@ -144,7 +151,15 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
|
|||
_diskSupplementaryCounter = 0;
|
||||
}
|
||||
|
||||
_cpuClocks--;
|
||||
if (_cpuClocks <= 0)
|
||||
{
|
||||
ExecuteSystem();
|
||||
_cpuClocks = 16;
|
||||
}
|
||||
|
||||
_diskDensityCounter++;
|
||||
_diskCycle = (_diskCycle + 1) & 0xF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,18 +11,6 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
|
|||
[SaveState.DoNotSave] private int _tempStep;
|
||||
[SaveState.DoNotSave] private int _tempPrB1;
|
||||
|
||||
private int _overflowFlagDelaySr;
|
||||
|
||||
private int ReadVia1PrA()
|
||||
{
|
||||
return _bitHistory & 0xFF;
|
||||
}
|
||||
|
||||
private int ReadVia1PrB()
|
||||
{
|
||||
return (_motorStep & 0x03) | (_motorEnabled ? 0x04 : 0x00) | (_sync ? 0x00 : 0x80);
|
||||
}
|
||||
|
||||
private void ExecuteMotor()
|
||||
{
|
||||
_tempPrB1 = Via1.EffectivePrB;
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
|
||||
{
|
||||
public sealed partial class Drive1541
|
||||
{
|
||||
[SaveState.SaveWithName("OverflowFlagDelayShiftRegister")]
|
||||
private int _overflowFlagDelaySr;
|
||||
|
||||
private byte CpuPeek(ushort addr)
|
||||
{
|
||||
return unchecked((byte)Peek(addr));
|
||||
}
|
||||
|
||||
private byte CpuRead(ushort addr)
|
||||
{
|
||||
return unchecked((byte)Read(addr));
|
||||
}
|
||||
|
||||
private void CpuWrite(ushort addr, byte val)
|
||||
{
|
||||
Write(addr, val);
|
||||
}
|
||||
|
||||
private bool ViaReadClock()
|
||||
{
|
||||
var inputClock = ReadMasterClk();
|
||||
var outputClock = ReadDeviceClk();
|
||||
return !(inputClock && outputClock);
|
||||
}
|
||||
|
||||
private bool ViaReadData()
|
||||
{
|
||||
var inputData = ReadMasterData();
|
||||
var outputData = ReadDeviceData();
|
||||
return !(inputData && outputData);
|
||||
}
|
||||
|
||||
private bool ViaReadAtn()
|
||||
{
|
||||
var inputAtn = ReadMasterAtn();
|
||||
return !inputAtn;
|
||||
}
|
||||
|
||||
private int ReadVia1PrA()
|
||||
{
|
||||
return _bitHistory & 0xFF;
|
||||
}
|
||||
|
||||
private int ReadVia1PrB()
|
||||
{
|
||||
return (_motorStep & 0x03) | (_motorEnabled ? 0x04 : 0x00) | (_sync ? 0x00 : 0x80);
|
||||
}
|
||||
|
||||
public int Peek(int addr)
|
||||
{
|
||||
switch (addr & 0xFC00)
|
||||
{
|
||||
case 0x1800:
|
||||
return Via0.Peek(addr);
|
||||
case 0x1C00:
|
||||
return Via1.Peek(addr);
|
||||
}
|
||||
if ((addr & 0x8000) != 0)
|
||||
return DriveRom.Peek(addr & 0x3FFF);
|
||||
if ((addr & 0x1F00) < 0x800)
|
||||
return _ram[addr & 0x7FF];
|
||||
return (addr >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
public int PeekVia0(int addr)
|
||||
{
|
||||
return Via0.Peek(addr);
|
||||
}
|
||||
|
||||
public int PeekVia1(int addr)
|
||||
{
|
||||
return Via1.Peek(addr);
|
||||
}
|
||||
|
||||
public void Poke(int addr, int val)
|
||||
{
|
||||
switch (addr & 0xFC00)
|
||||
{
|
||||
case 0x1800:
|
||||
Via0.Poke(addr, val);
|
||||
break;
|
||||
case 0x1C00:
|
||||
Via1.Poke(addr, val);
|
||||
break;
|
||||
default:
|
||||
if ((addr & 0x8000) == 0 && (addr & 0x1F00) < 0x800)
|
||||
_ram[addr & 0x7FF] = val & 0xFF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void PokeVia0(int addr, int val)
|
||||
{
|
||||
Via0.Poke(addr, val);
|
||||
}
|
||||
|
||||
public void PokeVia1(int addr, int val)
|
||||
{
|
||||
Via1.Poke(addr, val);
|
||||
}
|
||||
|
||||
public int Read(int addr)
|
||||
{
|
||||
switch (addr & 0xFC00)
|
||||
{
|
||||
case 0x1800:
|
||||
return Via0.Read(addr);
|
||||
case 0x1C00:
|
||||
return Via1.Read(addr);
|
||||
}
|
||||
if ((addr & 0x8000) != 0)
|
||||
return DriveRom.Read(addr & 0x3FFF);
|
||||
if ((addr & 0x1F00) < 0x800)
|
||||
return _ram[addr & 0x7FF];
|
||||
return (addr >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
public void Write(int addr, int val)
|
||||
{
|
||||
switch (addr & 0xFC00)
|
||||
{
|
||||
case 0x1800:
|
||||
Via0.Write(addr, val);
|
||||
break;
|
||||
case 0x1C00:
|
||||
Via1.Write(addr, val);
|
||||
break;
|
||||
default:
|
||||
if ((addr & 0x8000) == 0 && (addr & 0x1F00) < 0x800)
|
||||
_ram[addr & 0x7FF] = val & 0xFF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool ReadDeviceClk()
|
||||
{
|
||||
var viaOutputClock = (Via0.DdrB & 0x08) != 0 && (Via0.PrB & 0x08) != 0;
|
||||
return !viaOutputClock;
|
||||
}
|
||||
|
||||
public override bool ReadDeviceData()
|
||||
{
|
||||
var viaOutputData = (Via0.DdrB & 0x02) != 0 && (Via0.PrB & 0x02) != 0;
|
||||
var viaInputAtn = ViaReadAtn();
|
||||
var viaOutputAtna = (Via0.DdrB & 0x10) != 0 && (Via0.PrB & 0x10) != 0;
|
||||
|
||||
return !(viaOutputAtna ^ viaInputAtn) && !viaOutputData;
|
||||
}
|
||||
|
||||
public override bool ReadDeviceLight()
|
||||
{
|
||||
return _driveLightOffTime > 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,6 +25,8 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
|
|||
private bool _byteReady;
|
||||
[SaveState.SaveWithName("DriveCpuClockNumerator")]
|
||||
private readonly int _driveCpuClockNum;
|
||||
[SaveState.SaveWithName("DriveCpuClockDenominator")]
|
||||
private readonly int _driveCpuClockDen;
|
||||
[SaveState.SaveWithName("TrackNumber")]
|
||||
private int _trackNumber;
|
||||
[SaveState.SaveWithName("MotorEnabled")]
|
||||
|
@ -75,74 +77,30 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
|
|||
Via1 = Chip6522.Create(ReadVia1PrA, ReadVia1PrB);
|
||||
|
||||
_cpuClockNum = clockNum;
|
||||
_driveCpuClockNum = clockDen*1000000; // 1mhz
|
||||
}
|
||||
|
||||
private byte CpuPeek(ushort addr)
|
||||
{
|
||||
return unchecked((byte)Peek(addr));
|
||||
}
|
||||
|
||||
private byte CpuRead(ushort addr)
|
||||
{
|
||||
return unchecked((byte) Read(addr));
|
||||
}
|
||||
|
||||
private void CpuWrite(ushort addr, byte val)
|
||||
{
|
||||
Write(addr, val);
|
||||
}
|
||||
|
||||
private bool ViaReadClock()
|
||||
{
|
||||
var inputClock = ReadMasterClk();
|
||||
var outputClock = ReadDeviceClk();
|
||||
return !(inputClock && outputClock);
|
||||
}
|
||||
|
||||
private bool ViaReadData()
|
||||
{
|
||||
var inputData = ReadMasterData();
|
||||
var outputData = ReadDeviceData();
|
||||
return !(inputData && outputData);
|
||||
}
|
||||
|
||||
private bool ViaReadAtn()
|
||||
{
|
||||
var inputAtn = ReadMasterAtn();
|
||||
return !inputAtn;
|
||||
_driveCpuClockNum = clockDen*16000000; // 16mhz
|
||||
}
|
||||
|
||||
public override void ExecutePhase()
|
||||
{
|
||||
if (_cpuClockNum > _driveCpuClockNum)
|
||||
_ratioDifference += _driveCpuClockNum;
|
||||
while (_ratioDifference > _cpuClockNum)
|
||||
{
|
||||
_ratioDifference += _cpuClockNum - _driveCpuClockNum;
|
||||
if (_ratioDifference > _cpuClockNum)
|
||||
{
|
||||
_ratioDifference -= _cpuClockNum;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (_cpuClockNum <= _driveCpuClockNum)
|
||||
{
|
||||
_ratioDifference += _driveCpuClockNum - _cpuClockNum;
|
||||
while (_ratioDifference > _driveCpuClockNum)
|
||||
{
|
||||
_ratioDifference -= _driveCpuClockNum;
|
||||
ExecutePhaseInternal();
|
||||
}
|
||||
_ratioDifference -= _cpuClockNum;
|
||||
_clocks++;
|
||||
}
|
||||
ExecutePhaseInternal();
|
||||
}
|
||||
|
||||
private void ExecutePhaseInternal()
|
||||
{
|
||||
Via0.Ca1 = ViaReadAtn();
|
||||
|
||||
// clock output from 325572-01 drives CPU clock (phi0)
|
||||
ExecuteMotor();
|
||||
ExecuteFlux();
|
||||
}
|
||||
|
||||
private void ExecuteSystem()
|
||||
{
|
||||
Via0.Ca1 = ViaReadAtn();
|
||||
Via0.ExecutePhase();
|
||||
Via1.ExecutePhase();
|
||||
|
||||
|
@ -220,111 +178,5 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
|
|||
{
|
||||
_disk = null;
|
||||
}
|
||||
|
||||
public int Peek(int addr)
|
||||
{
|
||||
switch (addr & 0xFC00)
|
||||
{
|
||||
case 0x1800:
|
||||
return Via0.Peek(addr);
|
||||
case 0x1C00:
|
||||
return Via1.Peek(addr);
|
||||
}
|
||||
if ((addr & 0x8000) != 0)
|
||||
return DriveRom.Peek(addr & 0x3FFF);
|
||||
if ((addr & 0x1F00) < 0x800)
|
||||
return _ram[addr & 0x7FF];
|
||||
return (addr >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
public int PeekVia0(int addr)
|
||||
{
|
||||
return Via0.Peek(addr);
|
||||
}
|
||||
|
||||
public int PeekVia1(int addr)
|
||||
{
|
||||
return Via1.Peek(addr);
|
||||
}
|
||||
|
||||
public void Poke(int addr, int val)
|
||||
{
|
||||
switch (addr & 0xFC00)
|
||||
{
|
||||
case 0x1800:
|
||||
Via0.Poke(addr, val);
|
||||
break;
|
||||
case 0x1C00:
|
||||
Via1.Poke(addr, val);
|
||||
break;
|
||||
default:
|
||||
if ((addr & 0x8000) == 0 && (addr & 0x1F00) < 0x800)
|
||||
_ram[addr & 0x7FF] = val & 0xFF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void PokeVia0(int addr, int val)
|
||||
{
|
||||
Via0.Poke(addr, val);
|
||||
}
|
||||
|
||||
public void PokeVia1(int addr, int val)
|
||||
{
|
||||
Via1.Poke(addr, val);
|
||||
}
|
||||
|
||||
public int Read(int addr)
|
||||
{
|
||||
switch (addr & 0xFC00)
|
||||
{
|
||||
case 0x1800:
|
||||
return Via0.Read(addr);
|
||||
case 0x1C00:
|
||||
return Via1.Read(addr);
|
||||
}
|
||||
if ((addr & 0x8000) != 0)
|
||||
return DriveRom.Read(addr & 0x3FFF);
|
||||
if ((addr & 0x1F00) < 0x800)
|
||||
return _ram[addr & 0x7FF];
|
||||
return (addr >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
public void Write(int addr, int val)
|
||||
{
|
||||
switch (addr & 0xFC00)
|
||||
{
|
||||
case 0x1800:
|
||||
Via0.Write(addr, val);
|
||||
break;
|
||||
case 0x1C00:
|
||||
Via1.Write(addr, val);
|
||||
break;
|
||||
default:
|
||||
if ((addr & 0x8000) == 0 && (addr & 0x1F00) < 0x800)
|
||||
_ram[addr & 0x7FF] = val & 0xFF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool ReadDeviceClk()
|
||||
{
|
||||
var viaOutputClock = (Via0.DdrB & 0x08) != 0 && (Via0.PrB & 0x08) != 0;
|
||||
return !viaOutputClock;
|
||||
}
|
||||
|
||||
public override bool ReadDeviceData()
|
||||
{
|
||||
var viaOutputData = (Via0.DdrB & 0x02) != 0 && (Via0.PrB & 0x02) != 0;
|
||||
var viaInputAtn = ViaReadAtn();
|
||||
var viaOutputAtna = (Via0.DdrB & 0x10) != 0 && (Via0.PrB & 0x10) != 0;
|
||||
|
||||
return !(viaOutputAtna ^ viaInputAtn) && !viaOutputData;
|
||||
}
|
||||
|
||||
public override bool ReadDeviceLight()
|
||||
{
|
||||
return _driveLightOffTime > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue