diff --git a/BizHawk.Emulation.Cores/Computers/Commodore64/C64.ISettable.cs b/BizHawk.Emulation.Cores/Computers/Commodore64/C64.ISettable.cs index a34ff6f602..d68e1f8503 100644 --- a/BizHawk.Emulation.Cores/Computers/Commodore64/C64.ISettable.cs +++ b/BizHawk.Emulation.Cores/Computers/Commodore64/C64.ISettable.cs @@ -1,121 +1,121 @@ -using BizHawk.Emulation.Common; - -using Newtonsoft.Json; - -using System; -using System.ComponentModel; -using System.Drawing; - - -namespace BizHawk.Emulation.Cores.Computers.Commodore64 -{ - // adelikat: changing settings to default object until there are actually settings, as the ui depends on it to know if there are any settings avaialable - public partial class C64 : ISettable - { - public C64Settings GetSettings() - { - return Settings.Clone(); - } - - public C64SyncSettings GetSyncSettings() - { - return SyncSettings.Clone(); - } - - public bool PutSettings(C64Settings o) - { - Settings = o; - return false; - } - - public bool PutSyncSettings(C64SyncSettings o) - { - SyncSettings = o; - return false; - } - - internal C64Settings Settings { get; private set; } - internal C64SyncSettings SyncSettings { get; private set; } - - public class C64Settings - { - [DisplayName("Border type")] - [Description("Select how to show the border area")] - [DefaultValue(BorderType.SmallProportional)] - public BorderType BorderType { get; set; } - - public C64Settings Clone() - { - return (C64Settings)MemberwiseClone(); - } - - public C64Settings() - { - BizHawk.Common.SettingsUtil.SetDefaultValues(this); - } - } - - public class C64SyncSettings - { - [DisplayName("VIC type")] - [Description("Set the type of video chip to use")] - [DefaultValue(VicType.Pal)] - public VicType VicType { get; set; } - - [DisplayName("SID type")] - [Description("Set the type of sound chip to use")] - [DefaultValue(SidType.OldR2)] - public SidType SidType { get; set; } - - [DisplayName("Tape drive type")] - [Description("Set the type of tape drive attached")] - [DefaultValue(TapeDriveType.None)] - public TapeDriveType TapeDriveType { get; set; } - - [DisplayName("Disk drive type")] - [Description("Set the type of disk drive attached")] - [DefaultValue(DiskDriveType.None)] - public DiskDriveType DiskDriveType { get; set; } - - public C64SyncSettings Clone() - { - return (C64SyncSettings)MemberwiseClone(); - } - - public C64SyncSettings() - { - BizHawk.Common.SettingsUtil.SetDefaultValues(this); - } - } - - public enum VicType - { - Pal, Ntsc, NtscOld, Drean - } - - public enum CiaType - { - Pal, Ntsc, PalRevA, NtscRevA - } - - public enum BorderType - { - SmallProportional, SmallFixed, Normal, Full - } - - public enum SidType - { - OldR2, OldR3, OldR4AR, NewR5 - } - - public enum TapeDriveType - { - None, Commodore1530 - } - - public enum DiskDriveType - { - None, Commodore1541, Commodore1541II, Commodore1571 - } - } +using BizHawk.Emulation.Common; + +using Newtonsoft.Json; + +using System; +using System.ComponentModel; +using System.Drawing; + + +namespace BizHawk.Emulation.Cores.Computers.Commodore64 +{ + // adelikat: changing settings to default object until there are actually settings, as the ui depends on it to know if there are any settings avaialable + public partial class C64 : ISettable + { + public C64Settings GetSettings() + { + return Settings.Clone(); + } + + public C64SyncSettings GetSyncSettings() + { + return SyncSettings.Clone(); + } + + public bool PutSettings(C64Settings o) + { + Settings = o; + return false; + } + + public bool PutSyncSettings(C64SyncSettings o) + { + SyncSettings = o; + return false; + } + + internal C64Settings Settings { get; private set; } + internal C64SyncSettings SyncSettings { get; private set; } + + public class C64Settings + { + [DisplayName("Border type")] + [Description("Select how to show the border area")] + [DefaultValue(BorderType.SmallProportional)] + public BorderType BorderType { get; set; } + + public C64Settings Clone() + { + return (C64Settings)MemberwiseClone(); + } + + public C64Settings() + { + BizHawk.Common.SettingsUtil.SetDefaultValues(this); + } + } + + public class C64SyncSettings + { + [DisplayName("VIC type")] + [Description("Set the type of video chip to use")] + [DefaultValue(VicType.Pal)] + public VicType VicType { get; set; } + + [DisplayName("SID type")] + [Description("Set the type of sound chip to use")] + [DefaultValue(SidType.OldR2)] + public SidType SidType { get; set; } + + [DisplayName("Tape drive type")] + [Description("Set the type of tape drive attached")] + [DefaultValue(TapeDriveType.None)] + public TapeDriveType TapeDriveType { get; set; } + + [DisplayName("Disk drive type")] + [Description("Set the type of disk drive attached")] + [DefaultValue(DiskDriveType.None)] + public DiskDriveType DiskDriveType { get; set; } + + public C64SyncSettings Clone() + { + return (C64SyncSettings)MemberwiseClone(); + } + + public C64SyncSettings() + { + BizHawk.Common.SettingsUtil.SetDefaultValues(this); + } + } + + public enum VicType + { + Pal, Ntsc, NtscOld, Drean + } + + public enum CiaType + { + Pal, Ntsc, PalRevA, NtscRevA + } + + public enum BorderType + { + SmallProportional, SmallFixed, Normal, Full + } + + public enum SidType + { + OldR2, OldR3, OldR4AR, NewR5 + } + + public enum TapeDriveType + { + None, Commodore1530 + } + + public enum DiskDriveType + { + None, Commodore1541, Commodore1541II + } + } } \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Computers/Commodore64/C64.cs b/BizHawk.Emulation.Cores/Computers/Commodore64/C64.cs index 6c4a061b85..6276a45612 100644 --- a/BizHawk.Emulation.Cores/Computers/Commodore64/C64.cs +++ b/BizHawk.Emulation.Cores/Computers/Commodore64/C64.cs @@ -156,17 +156,6 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64 _board.Execute(); _frameCycles++; - // load PRG file if needed - if (_loadPrg) - { - // check to see if cpu PC is at the BASIC warm start vector - if (_board.Cpu.Pc != 0 && _board.Cpu.Pc == ((_board.Ram.Peek(0x0303) << 8) | _board.Ram.Peek(0x0302))) - { - Prg.Load(_board.Pla, _prgFile); - _loadPrg = false; - } - } - if (_frameCycles != _cyclesPerFrame) { return; @@ -188,8 +177,6 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64 } private Motherboard _board; - private bool _loadPrg; - [SaveState.DoNotSave] private byte[] _prgFile; private byte[] GetFirmware(int length, params string[] names) { @@ -212,10 +199,6 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64 if (diskDriveType == DiskDriveType.None) diskDriveType = DiskDriveType.Commodore1541; break; - case C64Format.D71: - if (diskDriveType == DiskDriveType.None) - diskDriveType = DiskDriveType.Commodore1571; - break; case C64Format.T64: case C64Format.TAP: if (tapeDriveType == TapeDriveType.None) @@ -223,6 +206,19 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64 tapeDriveType = TapeDriveType.Commodore1530; } break; + case C64Format.CRT: + // Nothing required. + break; + case C64Format.Unknown: + if (rom.Length >= 0xFE00) + { + throw new Exception("The image format is not known, and too large to be used as a PRG."); + } + if (diskDriveType == DiskDriveType.None) + diskDriveType = DiskDriveType.Commodore1541; + break; + default: + throw new Exception("The image format is not yet supported by the Commodore 64 core."); } } @@ -269,11 +265,25 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64 _board.TapeDrive.Insert(tape); } break; - default: - if (rom.Length > 2) + case C64Format.Unknown: + var prgDisk = new DiskBuilder { - _loadPrg = true; - _prgFile = rom; + Entries = new List + { + new DiskBuilder.Entry + { + Closed = true, + Data = rom, + Locked = false, + Name = "PRG", + RecordLength = 0, + Type = DiskBuilder.FileType.Program + } + } + }.Build(); + if (prgDisk != null) + { + _board.DiskDrive.InsertMedia(prgDisk); } break; } @@ -294,9 +304,6 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64 case DiskDriveType.Commodore1541II: _board.DiskDrive.DriveRom.Flash(GetFirmware(0x4000, "Drive1541II")); break; - case DiskDriveType.Commodore1571: - _board.DiskDrive.DriveRom.Flash(GetFirmware(0x8000, "Drive1571")); - break; } } diff --git a/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Cia.Registers.cs b/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Cia.Registers.cs index 6f7061cbea..ae08655914 100644 --- a/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Cia.Registers.cs +++ b/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Cia.Registers.cs @@ -173,6 +173,22 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS _icr |= 0x80; } break; + case 0xE: + var oldCra = _cra; + WriteRegister(addr, val); + + // Toggle output begins high when timer starts. + if ((_cra & 0x05) == 0x05 && (oldCra & 0x01) == 0) + _prb |= 0x40; + break; + case 0xF: + var oldCrb = _crb; + WriteRegister(addr, val); + + // Toggle output begins high when timer starts. + if ((_crb & 0x05) == 0x05 && (oldCrb & 0x01) == 0) + _prb |= 0x80; + break; default: WriteRegister(addr, val); break; diff --git a/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Cia.Tod.cs b/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Cia.Tod.cs index f0512eddc2..e06b1c1ab2 100644 --- a/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Cia.Tod.cs +++ b/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Cia.Tod.cs @@ -1,69 +1,69 @@ -namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS -{ - public sealed partial class Cia - { - private void CountTod() - { - if (_todCounter > 0) - { - _todCounter -= _todDen; - return; - } - - _todCounter += _todNum * ((_cra & 0x80) != 0 ? 6 : 5); - _tod10Ths++; - if (_tod10Ths > 9) - { - _tod10Ths = 0; - _todlo = (_todSec & 0x0F) + 1; - _todhi = (_todSec >> 4); - if (_todlo > 9) - { - _todlo = 0; - _todhi++; - } - if (_todhi > 5) - { - _todSec = 0; - _todlo = (_todMin & 0x0F) + 1; - _todhi = (_todMin >> 4); - if (_todlo > 9) - { - _todlo = 0; - _todhi++; - } - if (_todhi > 5) - { - _todMin = 0; - _todlo = (_todHr & 0x0F) + 1; - _todhi = (_todHr >> 4); - _todHr &= 0x80; - if (_todlo > 9) - { - _todlo = 0; - _todhi++; - } - _todHr |= (_todhi << 4) | _todlo; - if ((_todHr & 0x1F) > 0x11) - { - _todHr &= 0x80 ^ 0x80; - } - } - else - { - _todMin = (_todhi << 4) | _todlo; - } - } - else - { - _todSec = (_todhi << 4) | _todlo; - } - } - - if (_tod10Ths == _alm10Ths && _todSec == _almSec && _todMin == _almMin && _todHr == _almHr) - { - TriggerInterrupt(4); - } - } - } -} +namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS +{ + public sealed partial class Cia + { + private void CountTod() + { + if (_todCounter > 0) + { + _todCounter -= _todDen; + return; + } + + _todCounter += _todNum * ((_cra & 0x80) != 0 ? 6 : 5); + _tod10Ths++; + if (_tod10Ths > 9) + { + _tod10Ths = 0; + _todlo = (_todSec & 0x0F) + 1; + _todhi = (_todSec >> 4); + if (_todlo > 9) + { + _todlo = 0; + _todhi++; + } + if (_todhi > 5) + { + _todSec = 0; + _todlo = (_todMin & 0x0F) + 1; + _todhi = (_todMin >> 4); + if (_todlo > 9) + { + _todlo = 0; + _todhi++; + } + if (_todhi > 5) + { + _todMin = 0; + _todlo = (_todHr & 0x0F) + 1; + _todhi = (_todHr >> 4); + _todHr &= 0x80; + if (_todlo > 9) + { + _todlo = 0; + _todhi++; + } + _todHr |= (_todhi << 4) | _todlo; + if ((_todHr & 0x1F) > 0x11) + { + _todHr &= 0x80 ^ 0x80; + } + } + else + { + _todMin = (_todhi << 4) | _todlo; + } + } + else + { + _todSec = (_todhi << 4) | _todlo; + } + } + + if (_tod10Ths == _alm10Ths && _todSec == _almSec && _todMin == _almMin && _todHr == _almHr) + { + TriggerInterrupt(4); + } + } + } +} diff --git a/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Cia.cs b/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Cia.cs index 9d54a8fbea..3606d6424f 100644 --- a/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Cia.cs +++ b/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Cia.cs @@ -164,7 +164,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS _prb &= 0x7F; _tbPrb7NegativeNextCycle = false; } - + switch (_taState) { @@ -268,6 +268,11 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS { CheckIrqs(); } + + if ((_cra & 0x02) != 0) + _ddra |= 0x40; + if ((_crb & 0x02) != 0) + _ddrb |= 0x80; } private void Ta_Count() @@ -412,9 +417,9 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS _tbState = TimerState.LoadThenCount; } - if ((_cra & 0x02) != 0) + if ((_crb & 0x02) != 0) { - if ((_cra & 0x04) != 0) + if ((_crb & 0x04) != 0) { _tbPrb7NegativeNextCycle = true; _prb |= 0x80; @@ -423,7 +428,6 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS { _prb ^= 0x80; } - _ddrb |= 0x80; } } diff --git a/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/LatchedPort.cs b/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/LatchedPort.cs index 2fd7e3bd3c..d4931fe541 100644 --- a/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/LatchedPort.cs +++ b/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/LatchedPort.cs @@ -1,85 +1,85 @@ -using System; -using BizHawk.Common; - -namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS -{ - public sealed class LatchedPort - { - public int Direction; - public int Latch; - - public LatchedPort() - { - Direction = 0x00; - Latch = 0x00; - } - - // data works like this in these types of systems: - // - // directionA directionB result - // 0 0 1 - // 1 0 latchA - // 0 1 latchB - // 1 1 latchA && latchB - // - // however because this uses transistor logic, there are cases where wired-ands - // cause the pull-up resistors not to be enough to keep the bus bit set to 1 when - // both the direction and latch are 1 (the keyboard and joystick port 2 can do this.) - // the class does not handle this case as it must be handled differently in every occurrence. - - public int ReadInput(int bus) - { - return (Latch & Direction) | ((Direction ^ 0xFF) & bus); - } - - public int ReadOutput() - { - return (Latch & Direction) | (Direction ^ 0xFF); - } - - public void SyncState(Serializer ser) - { - SaveState.SyncObject(ser, this); - } - } - - public sealed class LatchedBooleanPort - { - public bool Direction; - public bool Latch; - - public LatchedBooleanPort() - { - Direction = false; - Latch = false; - } - - // data dir bus out - // 0 0 0 0 - // 0 0 1 1 - - // 0 1 0 0 - // 0 1 1 0 - - // 1 0 0 0 - // 1 0 1 1 - - // 1 1 0 1 - // 1 1 1 1 - - public bool ReadInput(bool bus) - { - return (Direction && Latch) || (!Direction && bus); - } - - public bool ReadOutput() - { - return (Latch || !Direction); - } - - public void SyncState(Serializer ser) - { - SaveState.SyncObject(ser, this); - } - } -} +using System; +using BizHawk.Common; + +namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS +{ + public sealed class LatchedPort + { + public int Direction; + public int Latch; + + public LatchedPort() + { + Direction = 0x00; + Latch = 0x00; + } + + // data works like this in these types of systems: + // + // directionA directionB result + // 0 0 1 + // 1 0 latchA + // 0 1 latchB + // 1 1 latchA && latchB + // + // however because this uses transistor logic, there are cases where wired-ands + // cause the pull-up resistors not to be enough to keep the bus bit set to 1 when + // both the direction and latch are 1 (the keyboard and joystick port 2 can do this.) + // the class does not handle this case as it must be handled differently in every occurrence. + + public int ReadInput(int bus) + { + return (Latch & Direction) | ((Direction ^ 0xFF) & bus); + } + + public int ReadOutput() + { + return (Latch & Direction) | (Direction ^ 0xFF); + } + + public void SyncState(Serializer ser) + { + SaveState.SyncObject(ser, this); + } + } + + public sealed class LatchedBooleanPort + { + public bool Direction; + public bool Latch; + + public LatchedBooleanPort() + { + Direction = false; + Latch = false; + } + + // data dir bus out + // 0 0 0 0 + // 0 0 1 1 + + // 0 1 0 0 + // 0 1 1 0 + + // 1 0 0 0 + // 1 0 1 1 + + // 1 1 0 1 + // 1 1 1 1 + + public bool ReadInput(bool bus) + { + return (Direction && Latch) || (!Direction && bus); + } + + public bool ReadOutput() + { + return (Latch || !Direction); + } + + public void SyncState(Serializer ser) + { + SaveState.SyncObject(ser, this); + } + } +} diff --git a/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Via.cs b/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Via.cs index ad60babc6b..39be668838 100644 --- a/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Via.cs +++ b/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Via.cs @@ -108,9 +108,6 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS [SaveState.SaveWithName("HandshakeCb2NextClock")] private bool _handshakeCb2NextClock; - [SaveState.SaveWithName("ShiftRegisterCounter")] - private int _shiftCount; - [SaveState.SaveWithName("CA1")] public bool Ca1; [SaveState.SaveWithName("CA2")] diff --git a/BizHawk.Emulation.Cores/Computers/Commodore64/Media/D64.cs b/BizHawk.Emulation.Cores/Computers/Commodore64/Media/D64.cs index e1f27c3ed0..dc46956c18 100644 --- a/BizHawk.Emulation.Cores/Computers/Commodore64/Media/D64.cs +++ b/BizHawk.Emulation.Cores/Computers/Commodore64/Media/D64.cs @@ -6,7 +6,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media { public static class D64 { - private static readonly int[] densityTable = + private static readonly int[] DensityTable = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, @@ -18,7 +18,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media 0, 0, 0, 0, 0 }; - private static readonly int[] gcrDecodeTable = + private static readonly int[] GcrDecodeTable = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, //00xxx 0xFF, 0x08, 0x00, 0x01, 0xFF, 0x0C, 0x04, 0x05, //01xxx @@ -26,7 +26,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media 0xFF, 0x09, 0x0A, 0x0B, 0xFF, 0x0D, 0x0E, 0xFF //11xxx }; - private static readonly int[] gcrEncodeTable = + private static readonly int[] GcrEncodeTable = { Convert.ToByte("01010", 2), // 0 Convert.ToByte("01011", 2), // 1 @@ -46,7 +46,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media Convert.ToByte("10101", 2) // F }; - private static readonly int[] sectorsPerTrack = + private static readonly int[] SectorsPerTrack = { 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, @@ -58,7 +58,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media 17, 17, 17, 17, 17 }; - private static readonly int[] standardTrackLengthBytes = + private static readonly int[] StandardTrackLengthBytes = { 6250, 6666, 7142, 7692 }; @@ -116,14 +116,14 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media 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]; + 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 @@ -175,7 +175,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media for (var i = 0; i < trackCount; i++) { - var sectors = sectorsPerTrack[i]; + var sectors = SectorsPerTrack[i]; var trackLengthBits = 0; using (var trackMem = new MemoryStream()) { @@ -187,10 +187,10 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media trackMem.Write(diskData, 0, diskData.Length); trackLengthBits += bitsWritten; } - var density = densityTable[i]; + var density = DensityTable[i]; // we pad the tracks with extra gap bytes to meet MNIB standards - while (trackMem.Length < standardTrackLengthBytes[density]) + while (trackMem.Length < StandardTrackLengthBytes[density]) { trackMem.WriteByte(0x55); } @@ -198,7 +198,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media trackDatas.Add(trackMem.ToArray()); trackLengths.Add(trackLengthBits); trackNumbers.Add(i * 2); - trackDensities.Add(densityTable[i]); + trackDensities.Add(DensityTable[i]); } } diff --git a/BizHawk.Emulation.Cores/Computers/Commodore64/Media/DiskBuilder.cs b/BizHawk.Emulation.Cores/Computers/Commodore64/Media/DiskBuilder.cs new file mode 100644 index 0000000000..cd0f5d2a62 --- /dev/null +++ b/BizHawk.Emulation.Cores/Computers/Commodore64/Media/DiskBuilder.cs @@ -0,0 +1,307 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Linq.Expressions; +using System.Text; + +namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media +{ + public class DiskBuilder + { + public enum FileType + { + Deleted = 0, + Sequential = 1, + Program = 2, + User = 3, + Relative = 4 + } + + protected class BamEntry + { + public int Data { get; private set; } + public int Sectors { get; private set; } + + public BamEntry(int sectors) + { + Data = 0; + for (var i = 0; i < sectors; i++) + { + Data >>= 1; + Data |= 0x800000; + } + Data |= (sectors << 24); + Sectors = sectors; + } + + private int GetBit(int sector) + { + if (sector < 0 || sector >= Sectors) + { + return 0; + } + return 0x800000 >> sector; + } + + public void Allocate(int sector) + { + var bit = GetBit(sector); + if (bit != 0 && (Data & bit) != 0) + { + Data &= ~bit; + Data -= 0x1000000; + } + } + + public void Free(int sector) + { + var bit = GetBit(sector); + if (bit != 0 && (Data & bit) == 0) + { + Data |= bit; + Data += 0x1000000; + } + } + + public int SectorsRemaining + { + get { return (Data >> 24) & 0xFF; } + } + + public bool this[int sector] + { + get { return (Data & (1 << sector)) != 0; } + set + { + if (value) + Free(sector); + else + Allocate(sector); + } + } + + public byte[] GetBytes() + { + return GetBytesEnumerable().ToArray(); + } + + private IEnumerable GetBytesEnumerable() + { + yield return unchecked((byte)(Data >> 24)); + yield return unchecked((byte)(Data >> 16)); + yield return unchecked((byte)(Data >> 8)); + yield return unchecked((byte)Data); + } + + public IEnumerable Entries + { + get + { + var d = Data; + for (var i = 0; i < Sectors; i++) + { + d <<= 1; + yield return (d & 0x1000000) != 0; + } + } + } + } + + protected class LocatedEntry + { + public Entry Entry { get; set; } + public int DirectoryTrack { get; set; } + public int DirectorySector { get; set; } + public int Track { get; set; } + public int Sector { get; set; } + public int SideTrack { get; set; } + public int SideSector { get; set; } + public int LengthInSectors { get; set; } + } + + public class Entry + { + public FileType Type { get; set; } + public bool Locked { get; set; } + public bool Closed { get; set; } + public string Name { get; set; } + public int RecordLength { get; set; } + public byte[] Data { get; set; } + } + + private static readonly 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 + }; + + public List Entries { get; set; } + public int VersionType { get; set; } + public string Title { get; set; } + + public DiskBuilder() + { + Entries = new List(); + VersionType = 0x41; + } + + public Disk Build() + { + const int tracks = 35; + var trackByteOffsets = new int[tracks]; + var bam = new BamEntry[tracks]; + var diskFull = false; + + for (var i = 0; i < tracks; i++) + { + bam[i] = new BamEntry(SectorsPerTrack[i]); + if (i > 0) + { + trackByteOffsets[i] = trackByteOffsets[i - 1] + (SectorsPerTrack[i - 1] * 256); + } + } + var bytes = new byte[trackByteOffsets[tracks - 1] + (SectorsPerTrack[tracks - 1] *256)]; + + var currentTrack = 16; + var currentSector = 0; + var interleaveStart = 0; + var sectorInterleave = 3; + var directory = new List(); + + Func GetOutputOffset = (t, s) => trackByteOffsets[t] + (s*256); + + foreach (var entry in Entries) + { + var sourceOffset = 0; + var dataLength = entry.Data == null ? 0 : entry.Data.Length; + var lengthInSectors = dataLength / 254; + var dataRemaining = dataLength; + var directoryEntry = new LocatedEntry + { + Entry = entry, + LengthInSectors = lengthInSectors + 1, + Track = currentTrack, + Sector = currentSector + }; + directory.Add(directoryEntry); + + while (!diskFull) + { + var outputOffset = GetOutputOffset(currentTrack, currentSector); + + if (dataRemaining > 254) + { + Array.Copy(entry.Data, sourceOffset, bytes, outputOffset + 2, 254); + dataRemaining -= 254; + } + else + { + if (dataRemaining > 0) + { + Array.Copy(entry.Data, sourceOffset, bytes, outputOffset + 2, dataRemaining); + bytes[outputOffset + 0] = 0; + bytes[outputOffset + 1] = (byte) dataRemaining; + dataRemaining = 0; + } + } + + bam[currentTrack].Allocate(currentSector); + currentSector += sectorInterleave; + if (currentSector >= SectorsPerTrack[currentTrack]) + { + interleaveStart++; + if (interleaveStart >= sectorInterleave) + { + interleaveStart = 0; + if (currentTrack >= 17) + { + currentTrack++; + if (currentTrack >= 35) + { + diskFull = true; + break; + } + } + else + { + currentTrack--; + if (currentTrack < 0) + currentTrack = 18; + } + } + currentSector = interleaveStart; + } + + if (dataRemaining <= 0) + break; + + bytes[outputOffset + 0] = (byte)(currentTrack + 1); + bytes[outputOffset + 1] = (byte) currentSector; + } + + if (diskFull) + break; + } + + // write Directory + var directoryOffset = -(0x20); + currentTrack = 17; + currentSector = 1; + var directoryOutputOffset = GetOutputOffset(currentTrack, currentSector); + var fileIndex = 0; + bam[currentTrack].Allocate(currentSector); + foreach (var entry in directory) + { + directoryOffset += 0x20; + if (directoryOffset == 0x100) + { + directoryOffset = 0; + currentSector += 3; + bytes[directoryOutputOffset] = (byte) currentTrack; + bytes[directoryOutputOffset + 1] = (byte) currentSector; + directoryOutputOffset = GetOutputOffset(currentTrack, currentSector); + bam[currentTrack].Allocate(currentSector); + } + bytes[directoryOutputOffset + directoryOffset + 0x00] = 0x00; + bytes[directoryOutputOffset + directoryOffset + 0x01] = 0x00; + bytes[directoryOutputOffset + directoryOffset + 0x02] = (byte)((int)entry.Entry.Type | (entry.Entry.Locked ? 0x40 : 0x00) | (entry.Entry.Closed ? 0x80 : 0x00)); + bytes[directoryOutputOffset + directoryOffset + 0x03] = (byte)(entry.Track + 1); + bytes[directoryOutputOffset + directoryOffset + 0x04] = (byte)entry.Sector; + for (var i = 0x05; i <= 0x14; i++) + bytes[directoryOutputOffset + directoryOffset + i] = 0xA0; + var fileNameBytes = Encoding.ASCII.GetBytes(entry.Entry.Name ?? string.Format("FILE{0:D3}", fileIndex)); + Array.Copy(fileNameBytes, 0, bytes, directoryOutputOffset + directoryOffset + 0x05, Math.Min(fileNameBytes.Length, 0x10)); + bytes[directoryOutputOffset + directoryOffset + 0x1E] = (byte)(entry.LengthInSectors & 0xFF); + bytes[directoryOutputOffset + directoryOffset + 0x1F] = (byte)((entry.LengthInSectors >> 8) & 0xFF); + fileIndex++; + } + bytes[directoryOutputOffset + 0x00] = 0x00; + bytes[directoryOutputOffset + 0x01] = 0xFF; + + // write BAM + var bamOutputOffset = GetOutputOffset(17, 0); + bytes[bamOutputOffset + 0x00] = 18; + bytes[bamOutputOffset + 0x01] = 1; + bytes[bamOutputOffset + 0x02] = (byte)VersionType; + for (var i = 0; i < 35; i++) + { + Array.Copy(bam[i].GetBytes(), 0, bytes, bamOutputOffset + 4 + (i * 4), 4); + } + for (var i = 0x90; i <= 0xAA; i++) + { + bytes[bamOutputOffset + i] = 0xA0; + } + var titleBytes = Encoding.ASCII.GetBytes(Title ?? "UNTITLED"); + Array.Copy(titleBytes, 0, bytes, bamOutputOffset + 0x90, Math.Min(titleBytes.Length, 0x10)); + + return D64.Read(bytes); + } + } +} diff --git a/BizHawk.Emulation.Cores/Computers/Commodore64/User/UserPortDevice.cs b/BizHawk.Emulation.Cores/Computers/Commodore64/User/UserPortDevice.cs index b4e215f3bc..108e4d2674 100644 --- a/BizHawk.Emulation.Cores/Computers/Commodore64/User/UserPortDevice.cs +++ b/BizHawk.Emulation.Cores/Computers/Commodore64/User/UserPortDevice.cs @@ -1,49 +1,49 @@ -using System; -using BizHawk.Common; - -namespace BizHawk.Emulation.Cores.Computers.Commodore64.User -{ - public abstract class UserPortDevice - { - public Func ReadCounter1; - public Func ReadCounter2; - public Func ReadHandshake; - public Func ReadSerial1; - public Func ReadSerial2; - - public virtual void HardReset() - { - // note: this will not disconnect any attached media - } - - public virtual bool ReadAtn() - { - return true; - } - - public virtual int ReadData() - { - return 0xFF; - } - - public virtual bool ReadFlag2() - { - return true; - } - - public virtual bool ReadPa2() - { - return true; - } - - public virtual bool ReadReset() - { - return true; - } - - public void SyncState(Serializer ser) - { - SaveState.SyncObject(ser, this); - } - } -} +using System; +using BizHawk.Common; + +namespace BizHawk.Emulation.Cores.Computers.Commodore64.User +{ + public abstract class UserPortDevice + { + public Func ReadCounter1; + public Func ReadCounter2; + public Func ReadHandshake; + public Func ReadSerial1; + public Func ReadSerial2; + + public virtual void HardReset() + { + // note: this will not disconnect any attached media + } + + public virtual bool ReadAtn() + { + return true; + } + + public virtual int ReadData() + { + return 0xFF; + } + + public virtual bool ReadFlag2() + { + return true; + } + + public virtual bool ReadPa2() + { + return true; + } + + public virtual bool ReadReset() + { + return true; + } + + public void SyncState(Serializer ser) + { + SaveState.SyncObject(ser, this); + } + } +}