diff --git a/BizHawk.Emulation/BizHawk.Emulation.csproj b/BizHawk.Emulation/BizHawk.Emulation.csproj index 91449aee1d..3fd1541b69 100644 --- a/BizHawk.Emulation/BizHawk.Emulation.csproj +++ b/BizHawk.Emulation/BizHawk.Emulation.csproj @@ -86,6 +86,7 @@ + diff --git a/BizHawk.Emulation/Computers/Commodore64/C64.core.cs b/BizHawk.Emulation/Computers/Commodore64/C64.core.cs index 3a2a21b9fe..5efc2d8c1e 100644 --- a/BizHawk.Emulation/Computers/Commodore64/C64.core.cs +++ b/BizHawk.Emulation/Computers/Commodore64/C64.core.cs @@ -76,11 +76,12 @@ namespace BizHawk.Emulation.Computers.Commodore64 switch (extension.ToUpper()) { case @".G64": - diskDrive = new Drive1541(File.ReadAllBytes(Path.Combine(romPath, @"1541dos")), Region.NTSC); + diskDrive = new Drive1541(File.ReadAllBytes(Path.Combine(romPath, @"dos1541")), Region.NTSC); diskDrive.Insert(G64.Read(inputFile)); break; case @".D64": - diskDrive = new Drive1541(File.ReadAllBytes(Path.Combine(romPath, @"1541dos")), Region.NTSC); + diskDrive = new Drive1541(File.ReadAllBytes(Path.Combine(romPath, @"dos1541")), Region.NTSC); + diskDrive.Insert(D64.Read(inputFile)); break; case @".PRG": if (inputFile.Length > 2) diff --git a/BizHawk.Emulation/Computers/Commodore64/D64.cs b/BizHawk.Emulation/Computers/Commodore64/D64.cs new file mode 100644 index 0000000000..70710df23e --- /dev/null +++ b/BizHawk.Emulation/Computers/Commodore64/D64.cs @@ -0,0 +1,241 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace BizHawk.Emulation.Computers.Commodore64 +{ + public static class D64 + { + private static int[] densityTable = + { + 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, + 3, 3, 2, 2, 2, + 2, 2, 2, 2, 1, + 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0 + }; + + private static int[] gcrDecodeTable = + { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, //00xxx + 0xFF, 0x08, 0x00, 0x01, 0xFF, 0x0C, 0x04, 0x05, //01xxx + 0xFF, 0xFF, 0x02, 0x03, 0xFF, 0x0F, 0x06, 0x07, //10xxx + 0xFF, 0x09, 0x0A, 0x0B, 0xFF, 0x0D, 0x0E, 0xFF //11xxx + }; + + private static int[] gcrEncodeTable = + { + Convert.ToByte("01010", 2), // 0 + Convert.ToByte("01011", 2), // 1 + Convert.ToByte("10010", 2), // 2 + Convert.ToByte("10011", 2), // 3 + Convert.ToByte("01110", 2), // 4 + Convert.ToByte("01111", 2), // 5 + Convert.ToByte("10110", 2), // 6 + Convert.ToByte("10111", 2), // 7 + Convert.ToByte("01001", 2), // 8 + Convert.ToByte("11001", 2), // 9 + Convert.ToByte("11010", 2), // A + Convert.ToByte("11011", 2), // B + Convert.ToByte("01101", 2), // C + Convert.ToByte("11101", 2), // D + Convert.ToByte("11110", 2), // E + Convert.ToByte("10101", 2) // F + }; + + private static int[] sectorsPerTrack = + { + 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, + 21, 21, 19, 19, 19, + 19, 19, 19, 19, 18, + 18, 18, 18, 18, 18, + 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17 + }; + + private static byte Checksum(byte[] source) + { + int count = source.Length; + byte result = 0; + + for (int i = 0; i < count; i++) + result ^= source[i]; + + return result; + } + + private static byte[] ConvertSectorFromGCR(byte[] source, out int bitsWritten) + { + bitsWritten = 0; + return new byte[] { }; + } + + private static byte[] ConvertSectorToGCR(byte[] source, byte sectorNo, byte trackNo, byte formatA, byte formatB, out int bitsWritten) + { + MemoryStream mem = new MemoryStream(); + BinaryWriter writer = new BinaryWriter(mem); + byte[] writtenData; + byte headerChecksum = (byte)(sectorNo ^ trackNo ^ formatA ^ formatB); + + // assemble written data for GCR encoding + writtenData = new byte[260]; + Array.Copy(source, 0, writtenData, 1, 256); + writtenData[0] = 0x07; + writtenData[0x101] = Checksum(source); + writtenData[0x102] = 0x00; + writtenData[0x103] = 0x00; + + bitsWritten = 0; + 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; + + writer.Flush(); + return mem.ToArray(); + } + + private static byte[] DecodeGCR(byte[] source) + { + // 5 GCR encoded bytes -> 4 bytes + int[] gcr = new int[8]; + byte[] data = new byte[4]; + int count = source.Length; + int outputValue; + MemoryStream mem = new MemoryStream(); + BinaryWriter writer = new BinaryWriter(mem); + + for (int i = 0; i < count; i += 5) + { + Array.Copy(source, i, data, 0, 5); + + // -------- -------- -------- -------- -------- + // 11100000 32222211 44443333 66555554 77777666 + + gcr[0] = ((data[0])) & 0x1F; + gcr[1] = ((data[0] >> 5) | data[1] << 3) & 0x1F; + gcr[2] = ((data[1] >> 2)) & 0x1F; + gcr[3] = ((data[1] >> 7) | data[2] << 1) & 0x1F; + gcr[4] = ((data[2] >> 4) | data[3] << 4) & 0x1F; + gcr[5] = ((data[3] >> 1)) & 0x1F; + gcr[6] = ((data[3] >> 6) | data[4] << 2) & 0x1F; + gcr[7] = ((data[4] >> 3)) & 0x1F; + + outputValue = gcrDecodeTable[gcr[0]] | (gcrDecodeTable[gcr[1]] << 4); + writer.Write((byte)(outputValue & 0xFF)); + outputValue = gcrDecodeTable[gcr[2]] | (gcrDecodeTable[gcr[3]] << 4); + writer.Write((byte)(outputValue & 0xFF)); + outputValue = gcrDecodeTable[gcr[4]] | (gcrDecodeTable[gcr[5]] << 4); + writer.Write((byte)(outputValue & 0xFF)); + outputValue = gcrDecodeTable[gcr[6]] | (gcrDecodeTable[gcr[7]] << 4); + writer.Write((byte)(outputValue & 0xFF)); + } + writer.Flush(); + return mem.ToArray(); + } + + private static byte[] EncodeGCR(byte[] source) + { + // 4 bytes -> 5 GCR encoded bytes + int[] gcr = new int[8]; + byte[] data = new byte[4]; + int count = source.Length; + int outputValue; + MemoryStream mem = new MemoryStream(); + BinaryWriter writer = new BinaryWriter(mem); + + for (int i = 0; i < count; i += 4) + { + Array.Copy(source, i, data, 0, 4); + gcr[0] = gcrEncodeTable[data[0] & 0xF]; + gcr[1] = gcrEncodeTable[data[0] >> 4]; + gcr[2] = gcrEncodeTable[data[1] & 0xF]; + gcr[3] = gcrEncodeTable[data[1] >> 4]; + gcr[4] = gcrEncodeTable[data[2] & 0xF]; + gcr[5] = gcrEncodeTable[data[2] >> 4]; + gcr[6] = gcrEncodeTable[data[3] & 0xF]; + gcr[7] = gcrEncodeTable[data[3] >> 4]; + + // -------- -------- -------- -------- -------- + // 11100000 32222211 44443333 66555554 77777666 + + 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)); + } + writer.Flush(); + return mem.ToArray(); + } + + public static Disk Read(byte[] source) + { + MemoryStream mem = new MemoryStream(source); + BinaryReader reader = new BinaryReader(mem); + Disk result = new Disk(); + int trackCount = 0; + + 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; + } + + for (int i = 0; i < trackCount; i++) + { + Track track = new Track(); + int sectors = sectorsPerTrack[i]; + MemoryStream trackMem = new MemoryStream(); + + for (int j = 0; j < sectors; j++) + { + int bitsWritten; + byte[] sectorData = reader.ReadBytes(256); + byte[] diskData = ConvertSectorToGCR(sectorData, (byte)j, (byte)i, (byte)0x00, (byte)0x00, out bitsWritten); + trackMem.Write(diskData, 0, diskData.Length); + } + track.data = trackMem.ToArray(); + track.bits = (int)trackMem.Length; + track.density = densityTable[i]; + track.index = i; + result.tracks.Add(track); + trackMem.Dispose(); + } + + result.valid = (result.tracks.Count > 0); + return result; + } + + public static byte[] Write(Disk source) + { + return null; + } + } +} diff --git a/BizHawk.Emulation/Computers/Commodore64/Disk.cs b/BizHawk.Emulation/Computers/Commodore64/Disk.cs index 41feeff34a..65df7f3517 100644 --- a/BizHawk.Emulation/Computers/Commodore64/Disk.cs +++ b/BizHawk.Emulation/Computers/Commodore64/Disk.cs @@ -5,15 +5,16 @@ using System.Text; namespace BizHawk.Emulation.Computers.Commodore64 { + public class Track + { + public int bits; + public byte[] data; + public int density; + public int index; + } + public class Disk { - public class Track - { - public int bits; - public byte[] data; - public int density; - public int index; - } public List tracks = new List(); public bool valid; diff --git a/BizHawk.Emulation/Computers/Commodore64/G64.cs b/BizHawk.Emulation/Computers/Commodore64/G64.cs index 8b449f8133..746517ed29 100644 --- a/BizHawk.Emulation/Computers/Commodore64/G64.cs +++ b/BizHawk.Emulation/Computers/Commodore64/G64.cs @@ -37,7 +37,7 @@ namespace BizHawk.Emulation.Computers.Commodore64 { int trackLength; byte[] trackData; - Disk.Track track = new Disk.Track(); + Track track = new Track(); mem.Position = trackOffsetTable[i]; trackLength = reader.ReadInt16(); @@ -55,8 +55,9 @@ namespace BizHawk.Emulation.Computers.Commodore64 return result; } - public static void Write(Disk source) + public static byte[] Write(Disk source) { + return null; } } }