C64: Improved disk support.
This commit is contained in:
parent
aaa0da85fd
commit
9557a25301
|
@ -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<C64.C64Settings, C64.C64SyncSettings>
|
||||
{
|
||||
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<C64.C64Settings, C64.C64SyncSettings>
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<DiskBuilder.Entry>
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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")]
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<byte> 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<bool> 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<Entry> Entries { get; set; }
|
||||
public int VersionType { get; set; }
|
||||
public string Title { get; set; }
|
||||
|
||||
public DiskBuilder()
|
||||
{
|
||||
Entries = new List<Entry>();
|
||||
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<LocatedEntry>();
|
||||
|
||||
Func<int, int, int> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,49 +1,49 @@
|
|||
using System;
|
||||
using BizHawk.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.User
|
||||
{
|
||||
public abstract class UserPortDevice
|
||||
{
|
||||
public Func<bool> ReadCounter1;
|
||||
public Func<bool> ReadCounter2;
|
||||
public Func<bool> ReadHandshake;
|
||||
public Func<bool> ReadSerial1;
|
||||
public Func<bool> 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<bool> ReadCounter1;
|
||||
public Func<bool> ReadCounter2;
|
||||
public Func<bool> ReadHandshake;
|
||||
public Func<bool> ReadSerial1;
|
||||
public Func<bool> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue