spaces to tabs in C64 files
This commit is contained in:
parent
5247e1d357
commit
3dd5478efd
|
@ -7,57 +7,57 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
{
|
||||
public partial class C64 : IDebuggable
|
||||
{
|
||||
[SaveState.DoNotSave] private IDebuggable _selectedDebuggable;
|
||||
[SaveState.DoNotSave] private IDebuggable _selectedDebuggable;
|
||||
|
||||
private IEnumerable<IDebuggable> GetAvailableDebuggables()
|
||||
{
|
||||
yield return _board.Cpu;
|
||||
if (_board.DiskDrive != null)
|
||||
{
|
||||
yield return _board.DiskDrive;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetDefaultDebuggable()
|
||||
{
|
||||
_selectedDebuggable = GetAvailableDebuggables().First();
|
||||
}
|
||||
|
||||
IDictionary<string, RegisterValue> IDebuggable.GetCpuFlagsAndRegisters()
|
||||
private IEnumerable<IDebuggable> GetAvailableDebuggables()
|
||||
{
|
||||
if (_selectedDebuggable == null)
|
||||
{
|
||||
SetDefaultDebuggable();
|
||||
}
|
||||
return _selectedDebuggable.GetCpuFlagsAndRegisters();
|
||||
yield return _board.Cpu;
|
||||
if (_board.DiskDrive != null)
|
||||
{
|
||||
yield return _board.DiskDrive;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetDefaultDebuggable()
|
||||
{
|
||||
_selectedDebuggable = GetAvailableDebuggables().First();
|
||||
}
|
||||
|
||||
IDictionary<string, RegisterValue> IDebuggable.GetCpuFlagsAndRegisters()
|
||||
{
|
||||
if (_selectedDebuggable == null)
|
||||
{
|
||||
SetDefaultDebuggable();
|
||||
}
|
||||
return _selectedDebuggable.GetCpuFlagsAndRegisters();
|
||||
}
|
||||
|
||||
void IDebuggable.SetCpuRegister(string register, int value)
|
||||
{
|
||||
if (_selectedDebuggable == null)
|
||||
{
|
||||
SetDefaultDebuggable();
|
||||
}
|
||||
_selectedDebuggable.SetCpuRegister(register, value);
|
||||
if (_selectedDebuggable == null)
|
||||
{
|
||||
SetDefaultDebuggable();
|
||||
}
|
||||
_selectedDebuggable.SetCpuRegister(register, value);
|
||||
}
|
||||
|
||||
bool IDebuggable.CanStep(StepType type)
|
||||
{
|
||||
if (_selectedDebuggable == null)
|
||||
{
|
||||
SetDefaultDebuggable();
|
||||
}
|
||||
return _selectedDebuggable.CanStep(type);
|
||||
if (_selectedDebuggable == null)
|
||||
{
|
||||
SetDefaultDebuggable();
|
||||
}
|
||||
return _selectedDebuggable.CanStep(type);
|
||||
}
|
||||
|
||||
|
||||
void IDebuggable.Step(StepType type)
|
||||
void IDebuggable.Step(StepType type)
|
||||
{
|
||||
if (_selectedDebuggable == null)
|
||||
{
|
||||
SetDefaultDebuggable();
|
||||
}
|
||||
_selectedDebuggable.Step(type);
|
||||
if (_selectedDebuggable == null)
|
||||
{
|
||||
SetDefaultDebuggable();
|
||||
}
|
||||
_selectedDebuggable.Step(type);
|
||||
}
|
||||
|
||||
[FeatureNotImplemented]
|
||||
|
@ -66,10 +66,10 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
get { return _selectedDebuggable.TotalExecutedCycles; }
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
private readonly IMemoryCallbackSystem _memoryCallbacks;
|
||||
[SaveState.DoNotSave]
|
||||
private readonly IMemoryCallbackSystem _memoryCallbacks;
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
IMemoryCallbackSystem IDebuggable.MemoryCallbacks { get { return _memoryCallbacks; } }
|
||||
[SaveState.DoNotSave]
|
||||
IMemoryCallbackSystem IDebuggable.MemoryCallbacks { get { return _memoryCallbacks; } }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,70 +7,70 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
{
|
||||
public partial class C64 : IDisassemblable
|
||||
{
|
||||
[SaveState.DoNotSave] private IDisassemblable _selectedDisassemblable;
|
||||
[SaveState.DoNotSave] private IDisassemblable _selectedDisassemblable;
|
||||
|
||||
private IEnumerable<IDisassemblable> GetAvailableDisassemblables()
|
||||
{
|
||||
yield return _board.Cpu;
|
||||
if (_board.DiskDrive != null)
|
||||
{
|
||||
yield return _board.DiskDrive;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetDefaultDisassemblable()
|
||||
{
|
||||
_selectedDisassemblable = GetAvailableDisassemblables().First();
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public string Cpu
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_selectedDisassemblable == null)
|
||||
{
|
||||
SetDefaultDisassemblable();
|
||||
}
|
||||
return _selectedDisassemblable.Cpu;
|
||||
}
|
||||
set
|
||||
{
|
||||
var currentSelectedDisassemblable = _selectedDisassemblable;
|
||||
_selectedDisassemblable = GetAvailableDisassemblables().FirstOrDefault(d => d.Cpu == value) ?? currentSelectedDisassemblable;
|
||||
if (_selectedDisassemblable is IDebuggable)
|
||||
{
|
||||
_selectedDebuggable = _selectedDisassemblable as IDebuggable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public string PCRegisterName
|
||||
private IEnumerable<IDisassemblable> GetAvailableDisassemblables()
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_selectedDisassemblable == null)
|
||||
{
|
||||
SetDefaultDisassemblable();
|
||||
}
|
||||
return _selectedDisassemblable.PCRegisterName;
|
||||
}
|
||||
yield return _board.Cpu;
|
||||
if (_board.DiskDrive != null)
|
||||
{
|
||||
yield return _board.DiskDrive;
|
||||
}
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public IEnumerable<string> AvailableCpus
|
||||
private void SetDefaultDisassemblable()
|
||||
{
|
||||
get { return GetAvailableDisassemblables().SelectMany(d => d.AvailableCpus); }
|
||||
_selectedDisassemblable = GetAvailableDisassemblables().First();
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public string Cpu
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_selectedDisassemblable == null)
|
||||
{
|
||||
SetDefaultDisassemblable();
|
||||
}
|
||||
return _selectedDisassemblable.Cpu;
|
||||
}
|
||||
set
|
||||
{
|
||||
var currentSelectedDisassemblable = _selectedDisassemblable;
|
||||
_selectedDisassemblable = GetAvailableDisassemblables().FirstOrDefault(d => d.Cpu == value) ?? currentSelectedDisassemblable;
|
||||
if (_selectedDisassemblable is IDebuggable)
|
||||
{
|
||||
_selectedDebuggable = _selectedDisassemblable as IDebuggable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public string PCRegisterName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_selectedDisassemblable == null)
|
||||
{
|
||||
SetDefaultDisassemblable();
|
||||
}
|
||||
return _selectedDisassemblable.PCRegisterName;
|
||||
}
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public IEnumerable<string> AvailableCpus
|
||||
{
|
||||
get { return GetAvailableDisassemblables().SelectMany(d => d.AvailableCpus); }
|
||||
}
|
||||
|
||||
public string Disassemble(MemoryDomain m, uint addr, out int length)
|
||||
{
|
||||
if (_selectedDisassemblable == null)
|
||||
{
|
||||
SetDefaultDisassemblable();
|
||||
}
|
||||
return _selectedDisassemblable.Disassemble(m, addr, out length);
|
||||
if (_selectedDisassemblable == null)
|
||||
{
|
||||
SetDefaultDisassemblable();
|
||||
}
|
||||
return _selectedDisassemblable.Disassemble(m, addr, out length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,6 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
public partial class C64 : IDriveLight
|
||||
{
|
||||
public bool DriveLightEnabled { get { return _board != null && (_board.CartPort.DriveLightEnabled || _board.Serial.DriveLightEnabled); } }
|
||||
public bool DriveLightOn { get { return _board != null && (_board.CartPort.DriveLightOn || _board.Serial.DriveLightOn);} }
|
||||
public bool DriveLightOn { get { return _board != null && (_board.CartPort.DriveLightOn || _board.Serial.DriveLightOn); } }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
public partial class C64 : IInputPollable
|
||||
{
|
||||
public bool IsLagFrame { get; set; }
|
||||
public int LagCount { get; set; }
|
||||
public int LagCount { get; set; }
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public IInputCallbackSystem InputCallbacks { get; private set; }
|
||||
[SaveState.DoNotSave]
|
||||
public IInputCallbackSystem InputCallbacks { get; private set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,36 +10,36 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
|
||||
private void SetupMemoryDomains(bool diskDriveEnabled)
|
||||
{
|
||||
var domains = new List<MemoryDomain>
|
||||
{
|
||||
C64MemoryDomainFactory.Create("System Bus", 0x10000, a => _board.Cpu.Peek(a), (a, v) => _board.Cpu.Poke(a, v)),
|
||||
C64MemoryDomainFactory.Create("RAM", 0x10000, a => _board.Ram.Peek(a), (a, v) => _board.Ram.Poke(a, v)),
|
||||
C64MemoryDomainFactory.Create("CIA0", 0x10, a => _board.Cia0.Peek(a), (a, v) => _board.Cia0.Poke(a, v)),
|
||||
C64MemoryDomainFactory.Create("CIA1", 0x10, a => _board.Cia1.Peek(a), (a, v) => _board.Cia1.Poke(a, v)),
|
||||
C64MemoryDomainFactory.Create("VIC", 0x40, a => _board.Vic.Peek(a), (a, v) => _board.Vic.Poke(a, v)),
|
||||
C64MemoryDomainFactory.Create("SID", 0x20, a => _board.Sid.Peek(a), (a, v) => _board.Sid.Poke(a, v)),
|
||||
};
|
||||
var domains = new List<MemoryDomain>
|
||||
{
|
||||
C64MemoryDomainFactory.Create("System Bus", 0x10000, a => _board.Cpu.Peek(a), (a, v) => _board.Cpu.Poke(a, v)),
|
||||
C64MemoryDomainFactory.Create("RAM", 0x10000, a => _board.Ram.Peek(a), (a, v) => _board.Ram.Poke(a, v)),
|
||||
C64MemoryDomainFactory.Create("CIA0", 0x10, a => _board.Cia0.Peek(a), (a, v) => _board.Cia0.Poke(a, v)),
|
||||
C64MemoryDomainFactory.Create("CIA1", 0x10, a => _board.Cia1.Peek(a), (a, v) => _board.Cia1.Poke(a, v)),
|
||||
C64MemoryDomainFactory.Create("VIC", 0x40, a => _board.Vic.Peek(a), (a, v) => _board.Vic.Poke(a, v)),
|
||||
C64MemoryDomainFactory.Create("SID", 0x20, a => _board.Sid.Peek(a), (a, v) => _board.Sid.Poke(a, v)),
|
||||
};
|
||||
|
||||
if (diskDriveEnabled)
|
||||
{
|
||||
domains.AddRange(new[]
|
||||
{
|
||||
C64MemoryDomainFactory.Create("1541 Bus", 0x10000, a => _board.DiskDrive.Peek(a), (a, v) => _board.DiskDrive.Poke(a, v)),
|
||||
C64MemoryDomainFactory.Create("1541 RAM", 0x800, a => _board.DiskDrive.Peek(a), (a, v) => _board.DiskDrive.Poke(a, v)),
|
||||
C64MemoryDomainFactory.Create("1541 VIA0", 0x10, a => _board.DiskDrive.PeekVia0(a), (a, v) => _board.DiskDrive.PokeVia0(a, v)),
|
||||
C64MemoryDomainFactory.Create("1541 VIA1", 0x10, a => _board.DiskDrive.PeekVia1(a), (a, v) => _board.DiskDrive.PokeVia1(a, v))
|
||||
});
|
||||
}
|
||||
if (diskDriveEnabled)
|
||||
{
|
||||
domains.AddRange(new[]
|
||||
{
|
||||
C64MemoryDomainFactory.Create("1541 Bus", 0x10000, a => _board.DiskDrive.Peek(a), (a, v) => _board.DiskDrive.Poke(a, v)),
|
||||
C64MemoryDomainFactory.Create("1541 RAM", 0x800, a => _board.DiskDrive.Peek(a), (a, v) => _board.DiskDrive.Poke(a, v)),
|
||||
C64MemoryDomainFactory.Create("1541 VIA0", 0x10, a => _board.DiskDrive.PeekVia0(a), (a, v) => _board.DiskDrive.PokeVia0(a, v)),
|
||||
C64MemoryDomainFactory.Create("1541 VIA1", 0x10, a => _board.DiskDrive.PeekVia1(a), (a, v) => _board.DiskDrive.PokeVia1(a, v))
|
||||
});
|
||||
}
|
||||
_memoryDomains = new MemoryDomainList(domains);
|
||||
((BasicServiceProvider) ServiceProvider).Register(_memoryDomains);
|
||||
((BasicServiceProvider)ServiceProvider).Register(_memoryDomains);
|
||||
}
|
||||
|
||||
private static class C64MemoryDomainFactory
|
||||
{
|
||||
public static MemoryDomain Create(string name, int size, Func<int, int> peekByte, Action<int, int> pokeByte)
|
||||
{
|
||||
return new MemoryDomainDelegate(name, size, MemoryDomain.Endian.Little, addr => unchecked((byte)peekByte((int)addr)), (addr, val) => pokeByte(unchecked((int)addr), val), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
private static class C64MemoryDomainFactory
|
||||
{
|
||||
public static MemoryDomain Create(string name, int size, Func<int, int> peekByte, Action<int, int> pokeByte)
|
||||
{
|
||||
return new MemoryDomainDelegate(name, size, MemoryDomain.Endian.Little, addr => unchecked((byte)peekByte((int)addr)), (addr, val) => pokeByte(unchecked((int)addr), val), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,10 +39,10 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
|
||||
public class C64Settings
|
||||
{
|
||||
[DisplayName("Border type")]
|
||||
[Description("Select how to show the border area")]
|
||||
[DefaultValue(BorderType.SmallProportional)]
|
||||
public BorderType BorderType { get; set; }
|
||||
[DisplayName("Border type")]
|
||||
[Description("Select how to show the border area")]
|
||||
[DefaultValue(BorderType.SmallProportional)]
|
||||
public BorderType BorderType { get; set; }
|
||||
|
||||
public C64Settings Clone()
|
||||
{
|
||||
|
@ -62,22 +62,22 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
[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("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("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; }
|
||||
[DisplayName("Disk drive type")]
|
||||
[Description("Set the type of disk drive attached")]
|
||||
[DefaultValue(DiskDriveType.None)]
|
||||
public DiskDriveType DiskDriveType { get; set; }
|
||||
|
||||
public C64SyncSettings Clone()
|
||||
public C64SyncSettings Clone()
|
||||
{
|
||||
return (C64SyncSettings)MemberwiseClone();
|
||||
}
|
||||
|
@ -93,29 +93,29 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
Pal, Ntsc, NtscOld, Drean
|
||||
}
|
||||
|
||||
public enum CiaType
|
||||
{
|
||||
Pal, Ntsc, PalRevA, NtscRevA
|
||||
}
|
||||
public enum CiaType
|
||||
{
|
||||
Pal, Ntsc, PalRevA, NtscRevA
|
||||
}
|
||||
|
||||
public enum BorderType
|
||||
{
|
||||
SmallProportional, SmallFixed, Normal, Full
|
||||
}
|
||||
public enum BorderType
|
||||
{
|
||||
SmallProportional, SmallFixed, Normal, Full
|
||||
}
|
||||
|
||||
public enum SidType
|
||||
{
|
||||
OldR2, OldR3, OldR4AR, NewR5
|
||||
}
|
||||
public enum SidType
|
||||
{
|
||||
OldR2, OldR3, OldR4AR, NewR5
|
||||
}
|
||||
|
||||
public enum TapeDriveType
|
||||
{
|
||||
None, Commodore1530
|
||||
}
|
||||
public enum TapeDriveType
|
||||
{
|
||||
None, Commodore1530
|
||||
}
|
||||
|
||||
public enum DiskDriveType
|
||||
{
|
||||
None, Commodore1541, Commodore1541II
|
||||
}
|
||||
public enum DiskDriveType
|
||||
{
|
||||
None, Commodore1541, Commodore1541II
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,36 +15,36 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
/// </summary>
|
||||
public sealed partial class Motherboard
|
||||
{
|
||||
// chips
|
||||
public readonly Chip23128 BasicRom;
|
||||
public readonly Chip23128 CharRom;
|
||||
public readonly Cia Cia0;
|
||||
public readonly Cia Cia1;
|
||||
public readonly Chip2114 ColorRam;
|
||||
public readonly Chip6510 Cpu;
|
||||
public readonly Chip23128 KernalRom;
|
||||
public readonly Chip90611401 Pla;
|
||||
public readonly Chip4864 Ram;
|
||||
public readonly Sid Sid;
|
||||
public readonly Vic Vic;
|
||||
// chips
|
||||
public readonly Chip23128 BasicRom;
|
||||
public readonly Chip23128 CharRom;
|
||||
public readonly Cia Cia0;
|
||||
public readonly Cia Cia1;
|
||||
public readonly Chip2114 ColorRam;
|
||||
public readonly Chip6510 Cpu;
|
||||
public readonly Chip23128 KernalRom;
|
||||
public readonly Chip90611401 Pla;
|
||||
public readonly Chip4864 Ram;
|
||||
public readonly Sid Sid;
|
||||
public readonly Vic Vic;
|
||||
|
||||
// ports
|
||||
public readonly CartridgePort CartPort;
|
||||
public readonly CassettePort Cassette;
|
||||
public IController Controller;
|
||||
public readonly SerialPort Serial;
|
||||
public readonly TapeDrive TapeDrive;
|
||||
public readonly UserPort User;
|
||||
// ports
|
||||
public readonly CartridgePort CartPort;
|
||||
public readonly CassettePort Cassette;
|
||||
public IController Controller;
|
||||
public readonly SerialPort Serial;
|
||||
public readonly TapeDrive TapeDrive;
|
||||
public readonly UserPort User;
|
||||
|
||||
// devices
|
||||
public readonly Drive1541 DiskDrive;
|
||||
// devices
|
||||
public readonly Drive1541 DiskDrive;
|
||||
|
||||
// state
|
||||
//public int address;
|
||||
public int Bus;
|
||||
public bool InputRead;
|
||||
public bool Irq;
|
||||
public bool Nmi;
|
||||
// state
|
||||
//public int address;
|
||||
public int Bus;
|
||||
public bool InputRead;
|
||||
public bool Irq;
|
||||
public bool Nmi;
|
||||
|
||||
private readonly C64 _c64;
|
||||
|
||||
|
@ -58,115 +58,115 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
case C64.VicType.Pal:
|
||||
clockNum = 17734475;
|
||||
clockDen = 18;
|
||||
break;
|
||||
break;
|
||||
case C64.VicType.Ntsc:
|
||||
clockNum = 14318181;
|
||||
clockDen = 14;
|
||||
break;
|
||||
clockNum = 14318181;
|
||||
clockDen = 14;
|
||||
break;
|
||||
case C64.VicType.NtscOld:
|
||||
clockNum = 11250000;
|
||||
clockDen = 11;
|
||||
break;
|
||||
break;
|
||||
case C64.VicType.Drean:
|
||||
clockNum = 14328225;
|
||||
clockDen = 14;
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
throw new System.Exception();
|
||||
}
|
||||
CartPort = new CartridgePort();
|
||||
Cassette = new CassettePort();
|
||||
ColorRam = new Chip2114();
|
||||
ColorRam = new Chip2114();
|
||||
Cpu = new Chip6510();
|
||||
Pla = new Chip90611401();
|
||||
Ram = new Chip4864();
|
||||
Serial = new SerialPort();
|
||||
|
||||
switch (sidType)
|
||||
{
|
||||
case C64.SidType.OldR2:
|
||||
Sid = Chip6581R2.Create(44100, clockNum, clockDen);
|
||||
break;
|
||||
case C64.SidType.OldR3:
|
||||
Sid = Chip6581R3.Create(44100, clockNum, clockDen);
|
||||
break;
|
||||
case C64.SidType.OldR4AR:
|
||||
Sid = Chip6581R4AR.Create(44100, clockNum, clockDen);
|
||||
break;
|
||||
case C64.SidType.NewR5:
|
||||
Sid = Chip8580R5.Create(44100, clockNum, clockDen);
|
||||
break;
|
||||
}
|
||||
switch (sidType)
|
||||
{
|
||||
case C64.SidType.OldR2:
|
||||
Sid = Chip6581R2.Create(44100, clockNum, clockDen);
|
||||
break;
|
||||
case C64.SidType.OldR3:
|
||||
Sid = Chip6581R3.Create(44100, clockNum, clockDen);
|
||||
break;
|
||||
case C64.SidType.OldR4AR:
|
||||
Sid = Chip6581R4AR.Create(44100, clockNum, clockDen);
|
||||
break;
|
||||
case C64.SidType.NewR5:
|
||||
Sid = Chip8580R5.Create(44100, clockNum, clockDen);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (initRegion)
|
||||
{
|
||||
case C64.VicType.Ntsc:
|
||||
Vic = Chip6567R8.Create(borderType);
|
||||
Cia0 = Chip6526.Create(C64.CiaType.Ntsc, Input_ReadKeyboard, Input_ReadJoysticks);
|
||||
Cia1 = Chip6526.Create(C64.CiaType.Ntsc, Cia1_ReadPortA);
|
||||
break;
|
||||
Vic = Chip6567R8.Create(borderType);
|
||||
Cia0 = Chip6526.Create(C64.CiaType.Ntsc, Input_ReadKeyboard, Input_ReadJoysticks);
|
||||
Cia1 = Chip6526.Create(C64.CiaType.Ntsc, Cia1_ReadPortA);
|
||||
break;
|
||||
case C64.VicType.Pal:
|
||||
Vic = Chip6569.Create(borderType);
|
||||
Cia0 = Chip6526.Create(C64.CiaType.Pal, Input_ReadKeyboard, Input_ReadJoysticks);
|
||||
Cia1 = Chip6526.Create(C64.CiaType.Pal, Cia1_ReadPortA);
|
||||
break;
|
||||
case C64.VicType.NtscOld:
|
||||
Vic = Chip6567R56A.Create(borderType);
|
||||
Cia0 = Chip6526.Create(C64.CiaType.NtscRevA, Input_ReadKeyboard, Input_ReadJoysticks);
|
||||
Cia1 = Chip6526.Create(C64.CiaType.NtscRevA, Cia1_ReadPortA);
|
||||
break;
|
||||
case C64.VicType.Drean:
|
||||
Vic = Chip6572.Create(borderType);
|
||||
Cia0 = Chip6526.Create(C64.CiaType.Pal, Input_ReadKeyboard, Input_ReadJoysticks);
|
||||
Cia1 = Chip6526.Create(C64.CiaType.Pal, Cia1_ReadPortA);
|
||||
break;
|
||||
Vic = Chip6569.Create(borderType);
|
||||
Cia0 = Chip6526.Create(C64.CiaType.Pal, Input_ReadKeyboard, Input_ReadJoysticks);
|
||||
Cia1 = Chip6526.Create(C64.CiaType.Pal, Cia1_ReadPortA);
|
||||
break;
|
||||
case C64.VicType.NtscOld:
|
||||
Vic = Chip6567R56A.Create(borderType);
|
||||
Cia0 = Chip6526.Create(C64.CiaType.NtscRevA, Input_ReadKeyboard, Input_ReadJoysticks);
|
||||
Cia1 = Chip6526.Create(C64.CiaType.NtscRevA, Cia1_ReadPortA);
|
||||
break;
|
||||
case C64.VicType.Drean:
|
||||
Vic = Chip6572.Create(borderType);
|
||||
Cia0 = Chip6526.Create(C64.CiaType.Pal, Input_ReadKeyboard, Input_ReadJoysticks);
|
||||
Cia1 = Chip6526.Create(C64.CiaType.Pal, Cia1_ReadPortA);
|
||||
break;
|
||||
}
|
||||
User = new UserPort();
|
||||
|
||||
ClockNumerator = clockNum;
|
||||
ClockDenominator = clockDen;
|
||||
ClockNumerator = clockNum;
|
||||
ClockDenominator = clockDen;
|
||||
|
||||
// Initialize disk drive
|
||||
switch (diskDriveType)
|
||||
{
|
||||
case C64.DiskDriveType.Commodore1541:
|
||||
case C64.DiskDriveType.Commodore1541II:
|
||||
DiskDrive = new Drive1541(ClockNumerator, ClockDenominator);
|
||||
Serial.Connect(DiskDrive);
|
||||
break;
|
||||
}
|
||||
// Initialize disk drive
|
||||
switch (diskDriveType)
|
||||
{
|
||||
case C64.DiskDriveType.Commodore1541:
|
||||
case C64.DiskDriveType.Commodore1541II:
|
||||
DiskDrive = new Drive1541(ClockNumerator, ClockDenominator);
|
||||
Serial.Connect(DiskDrive);
|
||||
break;
|
||||
}
|
||||
|
||||
// Initialize tape drive
|
||||
switch (tapeDriveType)
|
||||
{
|
||||
case C64.TapeDriveType.Commodore1530:
|
||||
TapeDrive = new TapeDrive();
|
||||
Cassette.Connect(TapeDrive);
|
||||
break;
|
||||
}
|
||||
// Initialize tape drive
|
||||
switch (tapeDriveType)
|
||||
{
|
||||
case C64.TapeDriveType.Commodore1530:
|
||||
TapeDrive = new TapeDrive();
|
||||
Cassette.Connect(TapeDrive);
|
||||
break;
|
||||
}
|
||||
|
||||
BasicRom = new Chip23128();
|
||||
CharRom = new Chip23128();
|
||||
KernalRom = new Chip23128();
|
||||
BasicRom = new Chip23128();
|
||||
CharRom = new Chip23128();
|
||||
KernalRom = new Chip23128();
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave] public int ClockNumerator { get; private set; }
|
||||
[SaveState.DoNotSave] public int ClockDenominator { get; private set; }
|
||||
[SaveState.DoNotSave] public int ClockNumerator { get; private set; }
|
||||
[SaveState.DoNotSave] public int ClockDenominator { get; private set; }
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
_vicBank = (0x3 - ((Cia1.PrA | ~Cia1.DdrA) & 0x3)) << 14;
|
||||
_vicBank = (0x3 - ((Cia1.PrA | ~Cia1.DdrA) & 0x3)) << 14;
|
||||
|
||||
Vic.ExecutePhase();
|
||||
CartPort.ExecutePhase();
|
||||
Cassette.ExecutePhase();
|
||||
Serial.ExecutePhase();
|
||||
Sid.ExecutePhase();
|
||||
Cia0.ExecutePhase();
|
||||
Cia1.ExecutePhase();
|
||||
Cpu.ExecutePhase();
|
||||
Vic.ExecutePhase();
|
||||
CartPort.ExecutePhase();
|
||||
Cassette.ExecutePhase();
|
||||
Serial.ExecutePhase();
|
||||
Sid.ExecutePhase();
|
||||
Cia0.ExecutePhase();
|
||||
Cia1.ExecutePhase();
|
||||
Cpu.ExecutePhase();
|
||||
}
|
||||
|
||||
public void Flush()
|
||||
|
@ -190,19 +190,19 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
Vic.HardReset();
|
||||
User.HardReset();
|
||||
Cassette.HardReset();
|
||||
Serial.HardReset();
|
||||
Cpu.HardReset();
|
||||
CartPort.HardReset();
|
||||
}
|
||||
Serial.HardReset();
|
||||
Cpu.HardReset();
|
||||
CartPort.HardReset();
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
CartPort.ReadOpenBus = ReadOpenBus;
|
||||
public void Init()
|
||||
{
|
||||
CartPort.ReadOpenBus = ReadOpenBus;
|
||||
|
||||
Cassette.ReadDataOutput = CassPort_ReadDataOutput;
|
||||
Cassette.ReadMotor = CassPort_ReadMotor;
|
||||
Cassette.ReadDataOutput = CassPort_ReadDataOutput;
|
||||
Cassette.ReadMotor = CassPort_ReadMotor;
|
||||
|
||||
Cia0.ReadFlag = Cassette.ReadDataInputBuffer;
|
||||
Cia0.ReadFlag = Cassette.ReadDataInputBuffer;
|
||||
|
||||
Cpu.PeekMemory = Pla.Peek;
|
||||
Cpu.PokeMemory = Pla.Poke;
|
||||
|
@ -215,7 +215,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
Cpu.WriteMemory = Pla.Write;
|
||||
Cpu.WriteMemoryPort = Cpu_WriteMemoryPort;
|
||||
|
||||
Pla.PeekBasicRom = BasicRom.Peek;
|
||||
Pla.PeekBasicRom = BasicRom.Peek;
|
||||
Pla.PeekCartridgeHi = CartPort.PeekHiRom;
|
||||
Pla.PeekCartridgeLo = CartPort.PeekLoRom;
|
||||
Pla.PeekCharRom = CharRom.Peek;
|
||||
|
@ -276,13 +276,13 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
Sid.ReadPotX = Sid_ReadPotX;
|
||||
Sid.ReadPotY = Sid_ReadPotY;
|
||||
|
||||
Vic.ReadMemory = Vic_ReadMemory;
|
||||
Vic.ReadMemory = Vic_ReadMemory;
|
||||
Vic.ReadColorRam = ColorRam.Read;
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
}
|
||||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,27 +7,27 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
{
|
||||
public sealed partial class Motherboard
|
||||
{
|
||||
private int _lastReadVicAddress = 0x3FFF;
|
||||
private int _lastReadVicData = 0xFF;
|
||||
private int _vicBank = 0xC000;
|
||||
private int _lastReadVicAddress = 0x3FFF;
|
||||
private int _lastReadVicData = 0xFF;
|
||||
private int _vicBank = 0xC000;
|
||||
|
||||
private bool CassPort_ReadDataOutput()
|
||||
private bool CassPort_ReadDataOutput()
|
||||
{
|
||||
return (Cpu.PortData & 0x08) != 0;
|
||||
}
|
||||
|
||||
private bool CassPort_ReadMotor()
|
||||
private bool CassPort_ReadMotor()
|
||||
{
|
||||
return (Cpu.PortData & 0x20) != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
private bool Cia0_ReadCnt()
|
||||
/*
|
||||
private bool Cia0_ReadCnt()
|
||||
{
|
||||
return User.ReadCounter1() && Cia0.ReadCntBuffer();
|
||||
}
|
||||
|
||||
private int Cia0_ReadPortA()
|
||||
private int Cia0_ReadPortA()
|
||||
{
|
||||
return cia0InputLatchA;
|
||||
}
|
||||
|
@ -37,12 +37,12 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
return cia0InputLatchB;
|
||||
}
|
||||
|
||||
private bool Cia0_ReadSP()
|
||||
private bool Cia0_ReadSP()
|
||||
{
|
||||
return User.ReadSerial1() && Cia0.ReadSpBuffer();
|
||||
}
|
||||
|
||||
private bool Cia1_ReadSP()
|
||||
private bool Cia1_ReadSP()
|
||||
{
|
||||
return User.ReadSerial2() && Cia1.ReadSpBuffer();
|
||||
}
|
||||
|
@ -51,21 +51,21 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
{
|
||||
return User.ReadCounter2() && Cia1.ReadCntBuffer();
|
||||
}
|
||||
*/
|
||||
*/
|
||||
|
||||
private int Cia1_ReadPortA()
|
||||
private int Cia1_ReadPortA()
|
||||
{
|
||||
// the low bits are actually the VIC memory address.
|
||||
return (SerPort_ReadDataOut() && Serial.ReadDeviceData() ? 0x80 : 0x00) |
|
||||
(SerPort_ReadClockOut() && Serial.ReadDeviceClock() ? 0x40 : 0x00);
|
||||
// the low bits are actually the VIC memory address.
|
||||
return (SerPort_ReadDataOut() && Serial.ReadDeviceData() ? 0x80 : 0x00) |
|
||||
(SerPort_ReadClockOut() && Serial.ReadDeviceClock() ? 0x40 : 0x00);
|
||||
}
|
||||
|
||||
private int Cia1_ReadPortB()
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
private int Cia1_ReadPortB()
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
private int Cpu_ReadPort()
|
||||
private int Cpu_ReadPort()
|
||||
{
|
||||
var data = 0x1F;
|
||||
if (!Cassette.ReadSenseBuffer())
|
||||
|
@ -73,37 +73,37 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
return data;
|
||||
}
|
||||
|
||||
private void Cpu_WriteMemoryPort(int addr, int val)
|
||||
private void Cpu_WriteMemoryPort(int addr, int val)
|
||||
{
|
||||
Pla.WriteMemory(addr, Bus);
|
||||
}
|
||||
|
||||
private bool Glue_ReadIRQ()
|
||||
private bool Glue_ReadIRQ()
|
||||
{
|
||||
return Cia0.ReadIrq() && Vic.ReadIrq() && CartPort.ReadIrq();
|
||||
}
|
||||
|
||||
private bool Glue_ReadNMI()
|
||||
{
|
||||
return !_restorePressed && Cia1.ReadIrq() && CartPort.ReadNmi();
|
||||
}
|
||||
private bool Glue_ReadNMI()
|
||||
{
|
||||
return !_restorePressed && Cia1.ReadIrq() && CartPort.ReadNmi();
|
||||
}
|
||||
|
||||
private bool[] Input_ReadJoysticks()
|
||||
{
|
||||
return _joystickPressed;
|
||||
}
|
||||
private bool[] Input_ReadJoysticks()
|
||||
{
|
||||
return _joystickPressed;
|
||||
}
|
||||
|
||||
private bool[] Input_ReadKeyboard()
|
||||
{
|
||||
return _keyboardPressed;
|
||||
}
|
||||
private bool[] Input_ReadKeyboard()
|
||||
{
|
||||
return _keyboardPressed;
|
||||
}
|
||||
|
||||
private bool Pla_ReadCharen()
|
||||
private bool Pla_ReadCharen()
|
||||
{
|
||||
return (Cpu.PortData & 0x04) != 0;
|
||||
}
|
||||
|
||||
private int Pla_ReadCia0(int addr)
|
||||
private int Pla_ReadCia0(int addr)
|
||||
{
|
||||
if (addr == 0xDC00 || addr == 0xDC01)
|
||||
{
|
||||
|
@ -112,70 +112,70 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
return Cia0.Read(addr);
|
||||
}
|
||||
|
||||
private int Pla_ReadColorRam(int addr)
|
||||
private int Pla_ReadColorRam(int addr)
|
||||
{
|
||||
var result = Bus;
|
||||
var result = Bus;
|
||||
result &= 0xF0;
|
||||
result |= ColorRam.Read(addr);
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool Pla_ReadHiRam()
|
||||
private bool Pla_ReadHiRam()
|
||||
{
|
||||
return (Cpu.PortData & 0x02) != 0;
|
||||
}
|
||||
|
||||
private bool Pla_ReadLoRam()
|
||||
private bool Pla_ReadLoRam()
|
||||
{
|
||||
return (Cpu.PortData & 0x01) != 0;
|
||||
}
|
||||
|
||||
private int Pla_ReadExpansion0(int addr)
|
||||
{
|
||||
return CartPort.IsConnected ? CartPort.ReadLoExp(addr) : _lastReadVicData;
|
||||
}
|
||||
private int Pla_ReadExpansion0(int addr)
|
||||
{
|
||||
return CartPort.IsConnected ? CartPort.ReadLoExp(addr) : _lastReadVicData;
|
||||
}
|
||||
|
||||
private int Pla_ReadExpansion1(int addr)
|
||||
{
|
||||
return CartPort.IsConnected ? CartPort.ReadHiExp(addr) : _lastReadVicData;
|
||||
}
|
||||
private int Pla_ReadExpansion1(int addr)
|
||||
{
|
||||
return CartPort.IsConnected ? CartPort.ReadHiExp(addr) : _lastReadVicData;
|
||||
}
|
||||
|
||||
private bool SerPort_ReadAtnOut()
|
||||
private bool SerPort_ReadAtnOut()
|
||||
{
|
||||
return !((Cia1.DdrA & 0x08) != 0 && (Cia1.PrA & 0x08) != 0);
|
||||
}
|
||||
|
||||
private bool SerPort_ReadClockOut()
|
||||
{
|
||||
return !((Cia1.DdrA & 0x10) != 0 && (Cia1.PrA & 0x10) != 0);
|
||||
private bool SerPort_ReadClockOut()
|
||||
{
|
||||
return !((Cia1.DdrA & 0x10) != 0 && (Cia1.PrA & 0x10) != 0);
|
||||
}
|
||||
|
||||
private bool SerPort_ReadDataOut()
|
||||
private bool SerPort_ReadDataOut()
|
||||
{
|
||||
return !((Cia1.DdrA & 0x20) != 0 && (Cia1.PrA & 0x20) != 0);
|
||||
}
|
||||
return !((Cia1.DdrA & 0x20) != 0 && (Cia1.PrA & 0x20) != 0);
|
||||
}
|
||||
|
||||
private int Sid_ReadPotX()
|
||||
private int Sid_ReadPotX()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int Sid_ReadPotY()
|
||||
private int Sid_ReadPotY()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int Vic_ReadMemory(int addr)
|
||||
private int Vic_ReadMemory(int addr)
|
||||
{
|
||||
// the system sees (cia1.PortAData & 0x3) but we use a shortcut
|
||||
_lastReadVicAddress = addr | _vicBank;
|
||||
// the system sees (cia1.PortAData & 0x3) but we use a shortcut
|
||||
_lastReadVicAddress = addr | _vicBank;
|
||||
_lastReadVicData = Pla.VicRead(_lastReadVicAddress);
|
||||
return _lastReadVicData;
|
||||
return _lastReadVicData;
|
||||
}
|
||||
|
||||
private int ReadOpenBus()
|
||||
{
|
||||
return _lastReadVicData;
|
||||
}
|
||||
private int ReadOpenBus()
|
||||
{
|
||||
return _lastReadVicData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,45 +15,45 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
)]
|
||||
[ServiceNotApplicable(typeof(ISettable<,>))]
|
||||
public sealed partial class C64 : IEmulator, IRegionable
|
||||
{
|
||||
#region Internals
|
||||
{
|
||||
#region Internals
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int _cyclesPerFrame;
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int _cyclesPerFrame;
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public GameInfo Game;
|
||||
[SaveState.DoNotSave]
|
||||
public GameInfo Game;
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public IEnumerable<byte[]> Roms { get; private set; }
|
||||
[SaveState.DoNotSave]
|
||||
public IEnumerable<byte[]> Roms { get; private set; }
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
private static readonly ControllerDefinition C64ControllerDefinition = new ControllerDefinition
|
||||
{
|
||||
Name = "Commodore 64 Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
"P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 Button",
|
||||
"P2 Up", "P2 Down", "P2 Left", "P2 Right", "P2 Button",
|
||||
"Key Left Arrow", "Key 1", "Key 2", "Key 3", "Key 4", "Key 5", "Key 6", "Key 7", "Key 8", "Key 9", "Key 0", "Key Plus", "Key Minus", "Key Pound", "Key Clear/Home", "Key Insert/Delete",
|
||||
"Key Control", "Key Q", "Key W", "Key E", "Key R", "Key T", "Key Y", "Key U", "Key I", "Key O", "Key P", "Key At", "Key Asterisk", "Key Up Arrow", "Key Restore",
|
||||
"Key Run/Stop", "Key Lck", "Key A", "Key S", "Key D", "Key F", "Key G", "Key H", "Key J", "Key K", "Key L", "Key Colon", "Key Semicolon", "Key Equal", "Key Return",
|
||||
"Key Commodore", "Key Left Shift", "Key Z", "Key X", "Key C", "Key V", "Key B", "Key N", "Key M", "Key Comma", "Key Period", "Key Slash", "Key Right Shift", "Key Cursor Up/Down", "Key Cursor Left/Right",
|
||||
"Key Space",
|
||||
"Key F1", "Key F3", "Key F5", "Key F7"
|
||||
}
|
||||
};
|
||||
[SaveState.DoNotSave]
|
||||
private static readonly ControllerDefinition C64ControllerDefinition = new ControllerDefinition
|
||||
{
|
||||
Name = "Commodore 64 Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
"P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 Button",
|
||||
"P2 Up", "P2 Down", "P2 Left", "P2 Right", "P2 Button",
|
||||
"Key Left Arrow", "Key 1", "Key 2", "Key 3", "Key 4", "Key 5", "Key 6", "Key 7", "Key 8", "Key 9", "Key 0", "Key Plus", "Key Minus", "Key Pound", "Key Clear/Home", "Key Insert/Delete",
|
||||
"Key Control", "Key Q", "Key W", "Key E", "Key R", "Key T", "Key Y", "Key U", "Key I", "Key O", "Key P", "Key At", "Key Asterisk", "Key Up Arrow", "Key Restore",
|
||||
"Key Run/Stop", "Key Lck", "Key A", "Key S", "Key D", "Key F", "Key G", "Key H", "Key J", "Key K", "Key L", "Key Colon", "Key Semicolon", "Key Equal", "Key Return",
|
||||
"Key Commodore", "Key Left Shift", "Key Z", "Key X", "Key C", "Key V", "Key B", "Key N", "Key M", "Key Comma", "Key Period", "Key Slash", "Key Right Shift", "Key Cursor Up/Down", "Key Cursor Left/Right",
|
||||
"Key Space",
|
||||
"Key F1", "Key F3", "Key F5", "Key F7"
|
||||
}
|
||||
};
|
||||
|
||||
[SaveState.SaveWithName("Board")]
|
||||
private Motherboard _board;
|
||||
[SaveState.SaveWithName("Board")]
|
||||
private Motherboard _board;
|
||||
|
||||
private int _frameCycles;
|
||||
private int _frameCycles;
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Ctor
|
||||
#region Ctor
|
||||
|
||||
public C64(CoreComm comm, IEnumerable<byte[]> roms, object settings, object syncSettings)
|
||||
public C64(CoreComm comm, IEnumerable<byte[]> roms, object settings, object syncSettings)
|
||||
{
|
||||
PutSyncSettings((C64SyncSettings)syncSettings ?? new C64SyncSettings());
|
||||
PutSettings((C64Settings)settings ?? new C64Settings());
|
||||
|
@ -61,108 +61,108 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
ServiceProvider = new BasicServiceProvider(this);
|
||||
InputCallbacks = new InputCallbackSystem();
|
||||
|
||||
CoreComm = comm;
|
||||
Roms = roms;
|
||||
Init(SyncSettings.VicType, Settings.BorderType, SyncSettings.SidType, SyncSettings.TapeDriveType, SyncSettings.DiskDriveType);
|
||||
CoreComm = comm;
|
||||
Roms = roms;
|
||||
Init(SyncSettings.VicType, Settings.BorderType, SyncSettings.SidType, SyncSettings.TapeDriveType, SyncSettings.DiskDriveType);
|
||||
_cyclesPerFrame = _board.Vic.CyclesPerFrame;
|
||||
SetupMemoryDomains(_board.DiskDrive != null);
|
||||
_memoryCallbacks = new MemoryCallbackSystem();
|
||||
_memoryCallbacks = new MemoryCallbackSystem();
|
||||
HardReset();
|
||||
|
||||
switch (SyncSettings.VicType)
|
||||
{
|
||||
case VicType.Ntsc:
|
||||
case VicType.Drean:
|
||||
case VicType.NtscOld:
|
||||
Region = DisplayType.NTSC;
|
||||
break;
|
||||
case VicType.Pal:
|
||||
Region = DisplayType.PAL;
|
||||
break;
|
||||
}
|
||||
switch (SyncSettings.VicType)
|
||||
{
|
||||
case VicType.Ntsc:
|
||||
case VicType.Drean:
|
||||
case VicType.NtscOld:
|
||||
Region = DisplayType.NTSC;
|
||||
break;
|
||||
case VicType.Pal:
|
||||
Region = DisplayType.PAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (_board.Sid != null)
|
||||
{
|
||||
if (_board.Sid != null)
|
||||
{
|
||||
_soundProvider = new DCFilter(_board.Sid, 512);
|
||||
((BasicServiceProvider)ServiceProvider).Register<ISoundProvider>(_soundProvider);
|
||||
}
|
||||
|
||||
DeterministicEmulation = true;
|
||||
DeterministicEmulation = true;
|
||||
|
||||
((BasicServiceProvider) ServiceProvider).Register<IVideoProvider>(_board.Vic);
|
||||
((BasicServiceProvider) ServiceProvider).Register<IDriveLight>(this);
|
||||
}
|
||||
((BasicServiceProvider)ServiceProvider).Register<IVideoProvider>(_board.Vic);
|
||||
((BasicServiceProvider)ServiceProvider).Register<IDriveLight>(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region IDisposable
|
||||
#region IDisposable
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_board != null)
|
||||
{
|
||||
if (_board.TapeDrive != null)
|
||||
{
|
||||
_board.TapeDrive.RemoveMedia();
|
||||
}
|
||||
if (_board.DiskDrive != null)
|
||||
{
|
||||
_board.DiskDrive.RemoveMedia();
|
||||
}
|
||||
_board = null;
|
||||
}
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
if (_board != null)
|
||||
{
|
||||
if (_board.TapeDrive != null)
|
||||
{
|
||||
_board.TapeDrive.RemoveMedia();
|
||||
}
|
||||
if (_board.DiskDrive != null)
|
||||
{
|
||||
_board.DiskDrive.RemoveMedia();
|
||||
}
|
||||
_board = null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region IRegionable
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public DisplayType Region
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IEmulator
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public CoreComm CoreComm { get; private set; }
|
||||
[SaveState.DoNotSave]
|
||||
public string SystemId { get { return "C64"; } }
|
||||
[SaveState.DoNotSave]
|
||||
public string BoardName { get { return null; } }
|
||||
[SaveState.SaveWithName("DeterministicEmulation")]
|
||||
public bool DeterministicEmulation { get; set; }
|
||||
[SaveState.SaveWithName("Frame")]
|
||||
public int Frame { get; set; }
|
||||
#region IRegionable
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public ControllerDefinition ControllerDefinition { get { return C64ControllerDefinition; } }
|
||||
[SaveState.DoNotSave]
|
||||
public IController Controller { get { return _board.Controller; } set { _board.Controller = value; } }
|
||||
[SaveState.DoNotSave]
|
||||
public IEmulatorServiceProvider ServiceProvider { get; private set; }
|
||||
public DisplayType Region
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public void ResetCounters()
|
||||
{
|
||||
Frame = 0;
|
||||
LagCount = 0;
|
||||
IsLagFrame = false;
|
||||
_frameCycles = 0;
|
||||
}
|
||||
#endregion
|
||||
|
||||
// process frame
|
||||
public void FrameAdvance(bool render, bool rendersound)
|
||||
{
|
||||
do
|
||||
{
|
||||
DoCycle();
|
||||
}
|
||||
while (_frameCycles != 0);
|
||||
}
|
||||
#region IEmulator
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public CoreComm CoreComm { get; private set; }
|
||||
[SaveState.DoNotSave]
|
||||
public string SystemId { get { return "C64"; } }
|
||||
[SaveState.DoNotSave]
|
||||
public string BoardName { get { return null; } }
|
||||
[SaveState.SaveWithName("DeterministicEmulation")]
|
||||
public bool DeterministicEmulation { get; set; }
|
||||
[SaveState.SaveWithName("Frame")]
|
||||
public int Frame { get; set; }
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public ControllerDefinition ControllerDefinition { get { return C64ControllerDefinition; } }
|
||||
[SaveState.DoNotSave]
|
||||
public IController Controller { get { return _board.Controller; } set { _board.Controller = value; } }
|
||||
[SaveState.DoNotSave]
|
||||
public IEmulatorServiceProvider ServiceProvider { get; private set; }
|
||||
|
||||
public void ResetCounters()
|
||||
{
|
||||
Frame = 0;
|
||||
LagCount = 0;
|
||||
IsLagFrame = false;
|
||||
_frameCycles = 0;
|
||||
}
|
||||
|
||||
// process frame
|
||||
public void FrameAdvance(bool render, bool rendersound)
|
||||
{
|
||||
do
|
||||
{
|
||||
DoCycle();
|
||||
}
|
||||
while (_frameCycles != 0);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -175,32 +175,33 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
|
||||
private void DoCycle()
|
||||
{
|
||||
if (_frameCycles == 0) {
|
||||
if (_frameCycles == 0)
|
||||
{
|
||||
_board.InputRead = false;
|
||||
_board.PollInput();
|
||||
_board.Cpu.LagCycles = 0;
|
||||
}
|
||||
|
||||
_board.Execute();
|
||||
_board.Execute();
|
||||
_frameCycles++;
|
||||
|
||||
if (_frameCycles != _cyclesPerFrame)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_frameCycles != _cyclesPerFrame)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_board.Flush();
|
||||
IsLagFrame = !_board.InputRead;
|
||||
_board.Flush();
|
||||
IsLagFrame = !_board.InputRead;
|
||||
|
||||
if (IsLagFrame)
|
||||
LagCount++;
|
||||
_frameCycles -= _cyclesPerFrame;
|
||||
Frame++;
|
||||
if (IsLagFrame)
|
||||
LagCount++;
|
||||
_frameCycles -= _cyclesPerFrame;
|
||||
Frame++;
|
||||
}
|
||||
|
||||
private byte[] GetFirmware(int length, params string[] names)
|
||||
{
|
||||
var result = names.Select(n => CoreComm.CoreFileProvider.GetFirmware("C64", n, false)).FirstOrDefault(b => b != null && b.Length == length);
|
||||
var result = names.Select(n => CoreComm.CoreFileProvider.GetFirmware("C64", n, false)).FirstOrDefault(b => b != null && b.Length == length);
|
||||
if (result == null)
|
||||
throw new MissingFirmwareException(string.Format("At least one of these firmwares is required: {0}", string.Join(", ", names)));
|
||||
return result;
|
||||
|
@ -208,129 +209,129 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
|
||||
private void Init(VicType initRegion, BorderType borderType, SidType sidType, TapeDriveType tapeDriveType, DiskDriveType diskDriveType)
|
||||
{
|
||||
// Force certain drive types to be available depending on ROM type
|
||||
foreach (var rom in Roms)
|
||||
{
|
||||
switch (C64FormatFinder.GetFormat(rom))
|
||||
{
|
||||
case C64Format.D64:
|
||||
case C64Format.G64:
|
||||
case C64Format.X64:
|
||||
if (diskDriveType == DiskDriveType.None)
|
||||
diskDriveType = DiskDriveType.Commodore1541;
|
||||
break;
|
||||
case C64Format.T64:
|
||||
case C64Format.TAP:
|
||||
if (tapeDriveType == TapeDriveType.None)
|
||||
{
|
||||
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.");
|
||||
}
|
||||
}
|
||||
// Force certain drive types to be available depending on ROM type
|
||||
foreach (var rom in Roms)
|
||||
{
|
||||
switch (C64FormatFinder.GetFormat(rom))
|
||||
{
|
||||
case C64Format.D64:
|
||||
case C64Format.G64:
|
||||
case C64Format.X64:
|
||||
if (diskDriveType == DiskDriveType.None)
|
||||
diskDriveType = DiskDriveType.Commodore1541;
|
||||
break;
|
||||
case C64Format.T64:
|
||||
case C64Format.TAP:
|
||||
if (tapeDriveType == TapeDriveType.None)
|
||||
{
|
||||
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.");
|
||||
}
|
||||
}
|
||||
|
||||
_board = new Motherboard(this, initRegion, borderType, sidType, tapeDriveType, diskDriveType);
|
||||
_board = new Motherboard(this, initRegion, borderType, sidType, tapeDriveType, diskDriveType);
|
||||
InitRoms(diskDriveType);
|
||||
_board.Init();
|
||||
|
||||
// configure video
|
||||
CoreComm.VsyncDen = _board.Vic.CyclesPerFrame;
|
||||
// configure video
|
||||
CoreComm.VsyncDen = _board.Vic.CyclesPerFrame;
|
||||
CoreComm.VsyncNum = _board.Vic.CyclesPerSecond;
|
||||
}
|
||||
}
|
||||
|
||||
private void InitMedia()
|
||||
{
|
||||
foreach (var rom in Roms)
|
||||
{
|
||||
switch (C64FormatFinder.GetFormat(rom))
|
||||
{
|
||||
case C64Format.D64:
|
||||
var d64 = D64.Read(rom);
|
||||
if (d64 != null)
|
||||
{
|
||||
_board.DiskDrive.InsertMedia(d64);
|
||||
}
|
||||
break;
|
||||
case C64Format.G64:
|
||||
var g64 = G64.Read(rom);
|
||||
if (g64 != null)
|
||||
{
|
||||
_board.DiskDrive.InsertMedia(g64);
|
||||
}
|
||||
break;
|
||||
case C64Format.CRT:
|
||||
var cart = CartridgeDevice.Load(rom);
|
||||
if (cart != null)
|
||||
{
|
||||
_board.CartPort.Connect(cart);
|
||||
}
|
||||
break;
|
||||
case C64Format.TAP:
|
||||
var tape = Tape.Load(rom);
|
||||
if (tape != null)
|
||||
{
|
||||
_board.TapeDrive.Insert(tape);
|
||||
}
|
||||
break;
|
||||
case C64Format.Unknown:
|
||||
var prgDisk = new DiskBuilder
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (var rom in Roms)
|
||||
{
|
||||
switch (C64FormatFinder.GetFormat(rom))
|
||||
{
|
||||
case C64Format.D64:
|
||||
var d64 = D64.Read(rom);
|
||||
if (d64 != null)
|
||||
{
|
||||
_board.DiskDrive.InsertMedia(d64);
|
||||
}
|
||||
break;
|
||||
case C64Format.G64:
|
||||
var g64 = G64.Read(rom);
|
||||
if (g64 != null)
|
||||
{
|
||||
_board.DiskDrive.InsertMedia(g64);
|
||||
}
|
||||
break;
|
||||
case C64Format.CRT:
|
||||
var cart = CartridgeDevice.Load(rom);
|
||||
if (cart != null)
|
||||
{
|
||||
_board.CartPort.Connect(cart);
|
||||
}
|
||||
break;
|
||||
case C64Format.TAP:
|
||||
var tape = Tape.Load(rom);
|
||||
if (tape != null)
|
||||
{
|
||||
_board.TapeDrive.Insert(tape);
|
||||
}
|
||||
break;
|
||||
case C64Format.Unknown:
|
||||
var prgDisk = new DiskBuilder
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void InitRoms(DiskDriveType diskDriveType)
|
||||
{
|
||||
_board.BasicRom.Flash(GetFirmware(0x2000, "Basic"));
|
||||
_board.KernalRom.Flash(GetFirmware(0x2000, "Kernal"));
|
||||
_board.CharRom.Flash(GetFirmware(0x1000, "Chargen"));
|
||||
_board.BasicRom.Flash(GetFirmware(0x2000, "Basic"));
|
||||
_board.KernalRom.Flash(GetFirmware(0x2000, "Kernal"));
|
||||
_board.CharRom.Flash(GetFirmware(0x1000, "Chargen"));
|
||||
|
||||
switch (diskDriveType)
|
||||
{
|
||||
case DiskDriveType.Commodore1541:
|
||||
_board.DiskDrive.DriveRom.Flash(GetFirmware(0x4000, "Drive1541"));
|
||||
break;
|
||||
case DiskDriveType.Commodore1541II:
|
||||
_board.DiskDrive.DriveRom.Flash(GetFirmware(0x4000, "Drive1541II"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (diskDriveType)
|
||||
{
|
||||
case DiskDriveType.Commodore1541:
|
||||
_board.DiskDrive.DriveRom.Flash(GetFirmware(0x4000, "Drive1541"));
|
||||
break;
|
||||
case DiskDriveType.Commodore1541II:
|
||||
_board.DiskDrive.DriveRom.Flash(GetFirmware(0x4000, "Drive1541II"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void HardReset()
|
||||
{
|
||||
InitMedia();
|
||||
_board.HardReset();
|
||||
InitMedia();
|
||||
_board.HardReset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,20 +5,20 @@ using System.Text;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
||||
{
|
||||
public enum C64Format
|
||||
{
|
||||
Unknown,
|
||||
D64,
|
||||
D71,
|
||||
D81,
|
||||
X64,
|
||||
G64,
|
||||
T64,
|
||||
TAP,
|
||||
CRT,
|
||||
P64,
|
||||
P00,
|
||||
D82,
|
||||
D80,
|
||||
}
|
||||
public enum C64Format
|
||||
{
|
||||
Unknown,
|
||||
D64,
|
||||
D71,
|
||||
D81,
|
||||
X64,
|
||||
G64,
|
||||
T64,
|
||||
TAP,
|
||||
CRT,
|
||||
P64,
|
||||
P00,
|
||||
D82,
|
||||
D80,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,42 +6,42 @@ using System.Text;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
||||
{
|
||||
public static class C64FormatFinder
|
||||
{
|
||||
public static C64Format GetFormat(byte[] data)
|
||||
{
|
||||
if (data == null || data.Length < 0x10)
|
||||
return C64Format.Unknown;
|
||||
using (var mem = new MemoryStream(data))
|
||||
{
|
||||
var reader = new BinaryReader(mem);
|
||||
var header = Encoding.GetEncoding(437).GetString(reader.ReadBytes(0x10));
|
||||
if (header.StartsWith("C64 CARTRIDGE "))
|
||||
return C64Format.CRT;
|
||||
if (header.StartsWith("GCR-1541"))
|
||||
return C64Format.G64;
|
||||
if (header.StartsWith("C64S tape image "))
|
||||
return C64Format.T64;
|
||||
if (header.StartsWith("C64-TAPE-RAW"))
|
||||
return C64Format.TAP;
|
||||
if (header.StartsWith("C64File"))
|
||||
return C64Format.P00;
|
||||
if (header.StartsWith("P64-1541"))
|
||||
return C64Format.P64;
|
||||
if (data[0] == 0x43 && data[1] == 0x15 && data[2] == 0x41 && data[3] == 0x64)
|
||||
return C64Format.X64;
|
||||
if (data.Length == 174848 || data.Length == 175531 || data.Length == 196608 || data.Length == 197376)
|
||||
return C64Format.D64;
|
||||
if (data.Length == 349696 || data.Length == 351062)
|
||||
return C64Format.D71;
|
||||
if (data.Length == 533248)
|
||||
return C64Format.D80;
|
||||
if (data.Length == 819200 || data.Length == 822400)
|
||||
return C64Format.D81;
|
||||
if (data.Length == 1066496)
|
||||
return C64Format.D82;
|
||||
}
|
||||
return C64Format.Unknown;
|
||||
}
|
||||
}
|
||||
public static class C64FormatFinder
|
||||
{
|
||||
public static C64Format GetFormat(byte[] data)
|
||||
{
|
||||
if (data == null || data.Length < 0x10)
|
||||
return C64Format.Unknown;
|
||||
using (var mem = new MemoryStream(data))
|
||||
{
|
||||
var reader = new BinaryReader(mem);
|
||||
var header = Encoding.GetEncoding(437).GetString(reader.ReadBytes(0x10));
|
||||
if (header.StartsWith("C64 CARTRIDGE "))
|
||||
return C64Format.CRT;
|
||||
if (header.StartsWith("GCR-1541"))
|
||||
return C64Format.G64;
|
||||
if (header.StartsWith("C64S tape image "))
|
||||
return C64Format.T64;
|
||||
if (header.StartsWith("C64-TAPE-RAW"))
|
||||
return C64Format.TAP;
|
||||
if (header.StartsWith("C64File"))
|
||||
return C64Format.P00;
|
||||
if (header.StartsWith("P64-1541"))
|
||||
return C64Format.P64;
|
||||
if (data[0] == 0x43 && data[1] == 0x15 && data[2] == 0x41 && data[3] == 0x64)
|
||||
return C64Format.X64;
|
||||
if (data.Length == 174848 || data.Length == 175531 || data.Length == 196608 || data.Length == 197376)
|
||||
return C64Format.D64;
|
||||
if (data.Length == 349696 || data.Length == 351062)
|
||||
return C64Format.D71;
|
||||
if (data.Length == 533248)
|
||||
return C64Format.D80;
|
||||
if (data.Length == 819200 || data.Length == 822400)
|
||||
return C64Format.D81;
|
||||
if (data.Length == 1066496)
|
||||
return C64Format.D82;
|
||||
}
|
||||
return C64Format.Unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,11 +21,11 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
|
||||
public static string ToHex(int n, int charsmin)
|
||||
{
|
||||
var result = new StringBuilder(string.Empty);
|
||||
var result = new StringBuilder(string.Empty);
|
||||
|
||||
while (n > 0 || charsmin > 0)
|
||||
while (n > 0 || charsmin > 0)
|
||||
{
|
||||
result.Insert(0, "0123456789ABCDEF".Substring(n & 0xF, 1));
|
||||
result.Insert(0, "0123456789ABCDEF".Substring(n & 0xF, 1));
|
||||
n >>= 4;
|
||||
if (charsmin > 0)
|
||||
charsmin--;
|
||||
|
|
|
@ -9,143 +9,143 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
|
|||
{
|
||||
public abstract partial class CartridgeDevice : IDriveLight
|
||||
{
|
||||
public Func<int> ReadOpenBus;
|
||||
public Func<int> ReadOpenBus;
|
||||
|
||||
public static CartridgeDevice Load(byte[] crtFile)
|
||||
{
|
||||
using (var mem = new MemoryStream(crtFile))
|
||||
{
|
||||
var reader = new BinaryReader(mem);
|
||||
using (var mem = new MemoryStream(crtFile))
|
||||
{
|
||||
var reader = new BinaryReader(mem);
|
||||
|
||||
if (new string(reader.ReadChars(16)) != "C64 CARTRIDGE ")
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (new string(reader.ReadChars(16)) != "C64 CARTRIDGE ")
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var chipAddress = new List<int>();
|
||||
var chipBank = new List<int>();
|
||||
var chipData = new List<int[]>();
|
||||
var chipType = new List<int>();
|
||||
var chipAddress = new List<int>();
|
||||
var chipBank = new List<int>();
|
||||
var chipData = new List<int[]>();
|
||||
var chipType = new List<int>();
|
||||
|
||||
var headerLength = ReadCRTInt(reader);
|
||||
var version = ReadCRTShort(reader);
|
||||
var mapper = ReadCRTShort(reader);
|
||||
var exrom = reader.ReadByte() != 0;
|
||||
var game = reader.ReadByte() != 0;
|
||||
var headerLength = ReadCRTInt(reader);
|
||||
var version = ReadCRTShort(reader);
|
||||
var mapper = ReadCRTShort(reader);
|
||||
var exrom = reader.ReadByte() != 0;
|
||||
var game = reader.ReadByte() != 0;
|
||||
|
||||
// reserved
|
||||
reader.ReadBytes(6);
|
||||
// reserved
|
||||
reader.ReadBytes(6);
|
||||
|
||||
// cartridge name
|
||||
reader.ReadBytes(0x20);
|
||||
// cartridge name
|
||||
reader.ReadBytes(0x20);
|
||||
|
||||
// skip extra header bytes
|
||||
if (headerLength > 0x40)
|
||||
{
|
||||
reader.ReadBytes(headerLength - 0x40);
|
||||
}
|
||||
// skip extra header bytes
|
||||
if (headerLength > 0x40)
|
||||
{
|
||||
reader.ReadBytes(headerLength - 0x40);
|
||||
}
|
||||
|
||||
// read chips
|
||||
while (reader.PeekChar() >= 0)
|
||||
{
|
||||
if (new string(reader.ReadChars(4)) != "CHIP")
|
||||
{
|
||||
break;
|
||||
}
|
||||
// read chips
|
||||
while (reader.PeekChar() >= 0)
|
||||
{
|
||||
if (new string(reader.ReadChars(4)) != "CHIP")
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
var chipLength = ReadCRTInt(reader);
|
||||
chipType.Add(ReadCRTShort(reader));
|
||||
chipBank.Add(ReadCRTShort(reader));
|
||||
chipAddress.Add(ReadCRTShort(reader));
|
||||
var chipDataLength = ReadCRTShort(reader);
|
||||
chipData.Add(reader.ReadBytes(chipDataLength).Select(x => (int)x).ToArray());
|
||||
chipLength -= chipDataLength + 0x10;
|
||||
if (chipLength > 0)
|
||||
reader.ReadBytes(chipLength);
|
||||
}
|
||||
var chipLength = ReadCRTInt(reader);
|
||||
chipType.Add(ReadCRTShort(reader));
|
||||
chipBank.Add(ReadCRTShort(reader));
|
||||
chipAddress.Add(ReadCRTShort(reader));
|
||||
var chipDataLength = ReadCRTShort(reader);
|
||||
chipData.Add(reader.ReadBytes(chipDataLength).Select(x => (int)x).ToArray());
|
||||
chipLength -= chipDataLength + 0x10;
|
||||
if (chipLength > 0)
|
||||
reader.ReadBytes(chipLength);
|
||||
}
|
||||
|
||||
if (chipData.Count <= 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (chipData.Count <= 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
CartridgeDevice result;
|
||||
switch (mapper)
|
||||
{
|
||||
case 0x0000: // Standard Cartridge
|
||||
result = new Mapper0000(chipAddress, chipData, game, exrom);
|
||||
break;
|
||||
case 0x0001: // Action Replay (4.2 and up)
|
||||
result = new Mapper0001(chipAddress, chipBank, chipData);
|
||||
break;
|
||||
case 0x0005: // Ocean
|
||||
result = new Mapper0005(chipAddress, chipBank, chipData);
|
||||
break;
|
||||
case 0x000A: // Epyx FastLoad
|
||||
result = new Mapper000A(chipData);
|
||||
break;
|
||||
case 0x000B: // Westermann Learning
|
||||
result = new Mapper000B(chipAddress, chipData);
|
||||
break;
|
||||
case 0x000F: // C64 Game System / System 3
|
||||
result = new Mapper000F(chipAddress, chipBank, chipData);
|
||||
break;
|
||||
case 0x0011: // Dinamic
|
||||
result = new Mapper0011(chipAddress, chipBank, chipData);
|
||||
break;
|
||||
case 0x0012: // Zaxxon / Super Zaxxon
|
||||
result = new Mapper0012(chipAddress, chipBank, chipData);
|
||||
break;
|
||||
case 0x0013: // Domark
|
||||
result = new Mapper0013(chipAddress, chipBank, chipData);
|
||||
break;
|
||||
case 0x0020: // EasyFlash
|
||||
result = new Mapper0020(chipAddress, chipBank, chipData);
|
||||
break;
|
||||
case 0x002B: // Prophet 64
|
||||
result = new Mapper002B(chipAddress, chipBank, chipData);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("This cartridge file uses an unrecognized mapper: " + mapper);
|
||||
}
|
||||
result.HardReset();
|
||||
CartridgeDevice result;
|
||||
switch (mapper)
|
||||
{
|
||||
case 0x0000: // Standard Cartridge
|
||||
result = new Mapper0000(chipAddress, chipData, game, exrom);
|
||||
break;
|
||||
case 0x0001: // Action Replay (4.2 and up)
|
||||
result = new Mapper0001(chipAddress, chipBank, chipData);
|
||||
break;
|
||||
case 0x0005: // Ocean
|
||||
result = new Mapper0005(chipAddress, chipBank, chipData);
|
||||
break;
|
||||
case 0x000A: // Epyx FastLoad
|
||||
result = new Mapper000A(chipData);
|
||||
break;
|
||||
case 0x000B: // Westermann Learning
|
||||
result = new Mapper000B(chipAddress, chipData);
|
||||
break;
|
||||
case 0x000F: // C64 Game System / System 3
|
||||
result = new Mapper000F(chipAddress, chipBank, chipData);
|
||||
break;
|
||||
case 0x0011: // Dinamic
|
||||
result = new Mapper0011(chipAddress, chipBank, chipData);
|
||||
break;
|
||||
case 0x0012: // Zaxxon / Super Zaxxon
|
||||
result = new Mapper0012(chipAddress, chipBank, chipData);
|
||||
break;
|
||||
case 0x0013: // Domark
|
||||
result = new Mapper0013(chipAddress, chipBank, chipData);
|
||||
break;
|
||||
case 0x0020: // EasyFlash
|
||||
result = new Mapper0020(chipAddress, chipBank, chipData);
|
||||
break;
|
||||
case 0x002B: // Prophet 64
|
||||
result = new Mapper002B(chipAddress, chipBank, chipData);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("This cartridge file uses an unrecognized mapper: " + mapper);
|
||||
}
|
||||
result.HardReset();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private static int ReadCRTShort(BinaryReader reader)
|
||||
{
|
||||
return (reader.ReadByte() << 8) |
|
||||
reader.ReadByte();
|
||||
return (reader.ReadByte() << 8) |
|
||||
reader.ReadByte();
|
||||
}
|
||||
|
||||
private static int ReadCRTInt(BinaryReader reader)
|
||||
{
|
||||
return (reader.ReadByte() << 24) |
|
||||
(reader.ReadByte() << 16) |
|
||||
(reader.ReadByte() << 8) |
|
||||
reader.ReadByte();
|
||||
(reader.ReadByte() << 16) |
|
||||
(reader.ReadByte() << 8) |
|
||||
reader.ReadByte();
|
||||
}
|
||||
|
||||
[SaveState.SaveWithName("ExRom")]
|
||||
[SaveState.SaveWithName("ExRom")]
|
||||
protected bool pinExRom;
|
||||
[SaveState.SaveWithName("Game")]
|
||||
protected bool pinGame;
|
||||
[SaveState.SaveWithName("IRQ")]
|
||||
protected bool pinIRQ;
|
||||
[SaveState.SaveWithName("NMI")]
|
||||
protected bool pinNMI;
|
||||
[SaveState.SaveWithName("Reset")]
|
||||
protected bool pinReset;
|
||||
[SaveState.DoNotSave]
|
||||
protected bool validCartridge;
|
||||
[SaveState.SaveWithName("Game")]
|
||||
protected bool pinGame;
|
||||
[SaveState.SaveWithName("IRQ")]
|
||||
protected bool pinIRQ;
|
||||
[SaveState.SaveWithName("NMI")]
|
||||
protected bool pinNMI;
|
||||
[SaveState.SaveWithName("Reset")]
|
||||
protected bool pinReset;
|
||||
[SaveState.DoNotSave]
|
||||
protected bool validCartridge;
|
||||
|
||||
public virtual void ExecutePhase()
|
||||
{
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
[SaveState.DoNotSave]
|
||||
public bool ExRom
|
||||
{
|
||||
get
|
||||
|
@ -154,8 +154,8 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
|
|||
}
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public bool Game
|
||||
[SaveState.DoNotSave]
|
||||
public bool Game
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -170,8 +170,8 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
|
|||
pinReset = true;
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public bool IRQ
|
||||
[SaveState.DoNotSave]
|
||||
public bool IRQ
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -179,8 +179,8 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
|
|||
}
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public bool NMI
|
||||
[SaveState.DoNotSave]
|
||||
public bool NMI
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -244,8 +244,8 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
|
|||
return ReadOpenBus();
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public bool Reset
|
||||
[SaveState.DoNotSave]
|
||||
public bool Reset
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -258,8 +258,8 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
|
|||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public bool Valid
|
||||
[SaveState.DoNotSave]
|
||||
public bool Valid
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -283,7 +283,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
|
|||
{
|
||||
}
|
||||
|
||||
public bool DriveLightEnabled { get; protected set; }
|
||||
public bool DriveLightOn { get; protected set; }
|
||||
public bool DriveLightEnabled { get; protected set; }
|
||||
public bool DriveLightOn { get; protected set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,108 +5,108 @@ using BizHawk.Emulation.Common;
|
|||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
|
||||
{
|
||||
public sealed class CartridgePort : IDriveLight
|
||||
{
|
||||
public Func<int> ReadOpenBus;
|
||||
|
||||
private CartridgeDevice _cartridgeDevice;
|
||||
private bool _connected;
|
||||
{
|
||||
public Func<int> ReadOpenBus;
|
||||
|
||||
private CartridgeDevice _cartridgeDevice;
|
||||
private bool _connected;
|
||||
|
||||
public CartridgePort()
|
||||
{
|
||||
// start up with no media connected
|
||||
{
|
||||
// start up with no media connected
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
// ------------------------------------------
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------
|
||||
|
||||
public int PeekHiExp(int addr)
|
||||
{
|
||||
return _connected ? _cartridgeDevice.PeekDF00(addr & 0x00FF) : 0xFF;
|
||||
}
|
||||
|
||||
public int PeekHiRom(int addr)
|
||||
{
|
||||
return _connected ? _cartridgeDevice.PeekA000(addr & 0x1FFF) : 0xFF;
|
||||
}
|
||||
|
||||
public int PeekLoExp(int addr)
|
||||
{
|
||||
return _connected ? _cartridgeDevice.PeekDE00(addr & 0x00FF) : 0xFF;
|
||||
}
|
||||
|
||||
public int PeekLoRom(int addr)
|
||||
{
|
||||
return _connected ? _cartridgeDevice.Peek8000(addr & 0x1FFF) : 0xFF;
|
||||
}
|
||||
|
||||
public void PokeHiExp(int addr, int val) { if (_connected) { _cartridgeDevice.PokeDF00(addr & 0x00FF, val); } }
|
||||
{
|
||||
return _connected ? _cartridgeDevice.PeekDF00(addr & 0x00FF) : 0xFF;
|
||||
}
|
||||
|
||||
public int PeekHiRom(int addr)
|
||||
{
|
||||
return _connected ? _cartridgeDevice.PeekA000(addr & 0x1FFF) : 0xFF;
|
||||
}
|
||||
|
||||
public int PeekLoExp(int addr)
|
||||
{
|
||||
return _connected ? _cartridgeDevice.PeekDE00(addr & 0x00FF) : 0xFF;
|
||||
}
|
||||
|
||||
public int PeekLoRom(int addr)
|
||||
{
|
||||
return _connected ? _cartridgeDevice.Peek8000(addr & 0x1FFF) : 0xFF;
|
||||
}
|
||||
|
||||
public void PokeHiExp(int addr, int val) { if (_connected) { _cartridgeDevice.PokeDF00(addr & 0x00FF, val); } }
|
||||
public void PokeHiRom(int addr, int val) { if (_connected) { _cartridgeDevice.PokeA000(addr & 0x1FFF, val); } }
|
||||
public void PokeLoExp(int addr, int val) { if (_connected) { _cartridgeDevice.PokeDE00(addr & 0x00FF, val); } }
|
||||
public void PokeLoRom(int addr, int val) { if (_connected) { _cartridgeDevice.Poke8000(addr & 0x1FFF, val); } }
|
||||
|
||||
public bool ReadExRom()
|
||||
{
|
||||
return !_connected || _cartridgeDevice.ExRom;
|
||||
}
|
||||
|
||||
public bool ReadGame()
|
||||
{
|
||||
return !_connected || _cartridgeDevice.Game;
|
||||
}
|
||||
|
||||
public int ReadHiExp(int addr)
|
||||
{
|
||||
return _connected ? _cartridgeDevice.ReadDF00(addr & 0x00FF) : 0xFF;
|
||||
}
|
||||
|
||||
public int ReadHiRom(int addr)
|
||||
{
|
||||
return _connected ? _cartridgeDevice.ReadA000(addr & 0x1FFF) : 0xFF;
|
||||
}
|
||||
|
||||
public int ReadLoExp(int addr)
|
||||
{
|
||||
return _connected ? _cartridgeDevice.ReadDE00(addr & 0x00FF) : 0xFF;
|
||||
}
|
||||
|
||||
public int ReadLoRom(int addr)
|
||||
{
|
||||
return _connected ? _cartridgeDevice.Read8000(addr & 0x1FFF) : 0xFF;
|
||||
}
|
||||
|
||||
public void WriteHiExp(int addr, int val) { if (_connected) { _cartridgeDevice.WriteDF00(addr & 0x00FF, val); } }
|
||||
{
|
||||
return !_connected || _cartridgeDevice.ExRom;
|
||||
}
|
||||
|
||||
public bool ReadGame()
|
||||
{
|
||||
return !_connected || _cartridgeDevice.Game;
|
||||
}
|
||||
|
||||
public int ReadHiExp(int addr)
|
||||
{
|
||||
return _connected ? _cartridgeDevice.ReadDF00(addr & 0x00FF) : 0xFF;
|
||||
}
|
||||
|
||||
public int ReadHiRom(int addr)
|
||||
{
|
||||
return _connected ? _cartridgeDevice.ReadA000(addr & 0x1FFF) : 0xFF;
|
||||
}
|
||||
|
||||
public int ReadLoExp(int addr)
|
||||
{
|
||||
return _connected ? _cartridgeDevice.ReadDE00(addr & 0x00FF) : 0xFF;
|
||||
}
|
||||
|
||||
public int ReadLoRom(int addr)
|
||||
{
|
||||
return _connected ? _cartridgeDevice.Read8000(addr & 0x1FFF) : 0xFF;
|
||||
}
|
||||
|
||||
public void WriteHiExp(int addr, int val) { if (_connected) { _cartridgeDevice.WriteDF00(addr & 0x00FF, val); } }
|
||||
public void WriteHiRom(int addr, int val) { if (_connected) { _cartridgeDevice.WriteA000(addr & 0x1FFF, val); } }
|
||||
public void WriteLoExp(int addr, int val) { if (_connected) { _cartridgeDevice.WriteDE00(addr & 0x00FF, val); } }
|
||||
public void WriteLoRom(int addr, int val) { if (_connected) { _cartridgeDevice.Write8000(addr & 0x1FFF, val); } }
|
||||
|
||||
// ------------------------------------------
|
||||
|
||||
public void WriteLoRom(int addr, int val) { if (_connected) { _cartridgeDevice.Write8000(addr & 0x1FFF, val); } }
|
||||
|
||||
// ------------------------------------------
|
||||
|
||||
public void Connect(CartridgeDevice newCartridgeDevice)
|
||||
{
|
||||
_connected = true;
|
||||
_cartridgeDevice = newCartridgeDevice;
|
||||
newCartridgeDevice.ReadOpenBus = ReadOpenBus;
|
||||
{
|
||||
_connected = true;
|
||||
_cartridgeDevice = newCartridgeDevice;
|
||||
newCartridgeDevice.ReadOpenBus = ReadOpenBus;
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
_cartridgeDevice = null;
|
||||
_connected = false;
|
||||
}
|
||||
|
||||
public void ExecutePhase()
|
||||
{
|
||||
if (_connected)
|
||||
_cartridgeDevice.ExecutePhase();
|
||||
}
|
||||
|
||||
public void ExecutePhase()
|
||||
{
|
||||
if (_connected)
|
||||
_cartridgeDevice.ExecutePhase();
|
||||
}
|
||||
|
||||
public void HardReset()
|
||||
{
|
||||
// note: this will not disconnect any attached media
|
||||
if (_connected)
|
||||
{
|
||||
_cartridgeDevice.HardReset();
|
||||
}
|
||||
{
|
||||
// note: this will not disconnect any attached media
|
||||
if (_connected)
|
||||
{
|
||||
_cartridgeDevice.HardReset();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsConnected
|
||||
|
@ -123,16 +123,16 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
|
|||
}
|
||||
|
||||
public bool ReadNmi()
|
||||
{
|
||||
return !_connected || _cartridgeDevice.NMI;
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
return !_connected || _cartridgeDevice.NMI;
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
|
||||
public bool DriveLightEnabled { get { return _connected && _cartridgeDevice.DriveLightEnabled; } }
|
||||
public bool DriveLightOn { get { return _connected && _cartridgeDevice.DriveLightOn; } }
|
||||
}
|
||||
|
||||
public bool DriveLightEnabled { get { return _connected && _cartridgeDevice.DriveLightEnabled; } }
|
||||
public bool DriveLightOn { get { return _connected && _cartridgeDevice.DriveLightOn; } }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,101 +4,101 @@ using System.Linq;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
|
||||
{
|
||||
public abstract partial class CartridgeDevice
|
||||
{
|
||||
private sealed class Mapper0000 : CartridgeDevice
|
||||
{
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int[] _romA;
|
||||
[SaveState.SaveWithName("RomMaskA")]
|
||||
private readonly int _romAMask;
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int[] _romB;
|
||||
[SaveState.SaveWithName("RomMaskB")]
|
||||
private readonly int _romBMask;
|
||||
public abstract partial class CartridgeDevice
|
||||
{
|
||||
private sealed class Mapper0000 : CartridgeDevice
|
||||
{
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int[] _romA;
|
||||
[SaveState.SaveWithName("RomMaskA")]
|
||||
private readonly int _romAMask;
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int[] _romB;
|
||||
[SaveState.SaveWithName("RomMaskB")]
|
||||
private readonly int _romBMask;
|
||||
|
||||
// standard cartridge mapper (Commodore)
|
||||
// note that this format also covers Ultimax carts
|
||||
// standard cartridge mapper (Commodore)
|
||||
// note that this format also covers Ultimax carts
|
||||
|
||||
public Mapper0000(IList<int> newAddresses, IList<int[]> newData, bool game, bool exrom)
|
||||
{
|
||||
pinGame = game;
|
||||
pinExRom = exrom;
|
||||
public Mapper0000(IList<int> newAddresses, IList<int[]> newData, bool game, bool exrom)
|
||||
{
|
||||
pinGame = game;
|
||||
pinExRom = exrom;
|
||||
|
||||
validCartridge = true;
|
||||
validCartridge = true;
|
||||
|
||||
// default to empty banks
|
||||
_romA = new int[1];
|
||||
_romB = new int[1];
|
||||
_romA[0] = 0xFF;
|
||||
_romB[0] = 0xFF;
|
||||
// default to empty banks
|
||||
_romA = new int[1];
|
||||
_romB = new int[1];
|
||||
_romA[0] = 0xFF;
|
||||
_romB[0] = 0xFF;
|
||||
|
||||
for (var i = 0; i < newAddresses.Count; i++)
|
||||
{
|
||||
if (newAddresses[i] == 0x8000)
|
||||
{
|
||||
switch (newData[i].Length)
|
||||
{
|
||||
case 0x1000:
|
||||
_romAMask = 0x0FFF;
|
||||
_romA = newData[i];
|
||||
break;
|
||||
case 0x2000:
|
||||
_romAMask = 0x1FFF;
|
||||
_romA = newData[i];
|
||||
break;
|
||||
case 0x4000:
|
||||
_romAMask = 0x1FFF;
|
||||
_romBMask = 0x1FFF;
|
||||
// split the rom into two banks
|
||||
_romA = new int[0x2000];
|
||||
_romB = new int[0x2000];
|
||||
Array.Copy(newData[i], 0x0000, _romA, 0x0000, 0x2000);
|
||||
Array.Copy(newData[i], 0x2000, _romB, 0x0000, 0x2000);
|
||||
break;
|
||||
default:
|
||||
validCartridge = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (newAddresses[i] == 0xA000 || newAddresses[i] == 0xE000)
|
||||
{
|
||||
switch (newData[i].Length)
|
||||
{
|
||||
case 0x1000:
|
||||
_romBMask = 0x0FFF;
|
||||
break;
|
||||
case 0x2000:
|
||||
_romBMask = 0x1FFF;
|
||||
break;
|
||||
default:
|
||||
validCartridge = false;
|
||||
return;
|
||||
}
|
||||
_romB = newData[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < newAddresses.Count; i++)
|
||||
{
|
||||
if (newAddresses[i] == 0x8000)
|
||||
{
|
||||
switch (newData[i].Length)
|
||||
{
|
||||
case 0x1000:
|
||||
_romAMask = 0x0FFF;
|
||||
_romA = newData[i];
|
||||
break;
|
||||
case 0x2000:
|
||||
_romAMask = 0x1FFF;
|
||||
_romA = newData[i];
|
||||
break;
|
||||
case 0x4000:
|
||||
_romAMask = 0x1FFF;
|
||||
_romBMask = 0x1FFF;
|
||||
// split the rom into two banks
|
||||
_romA = new int[0x2000];
|
||||
_romB = new int[0x2000];
|
||||
Array.Copy(newData[i], 0x0000, _romA, 0x0000, 0x2000);
|
||||
Array.Copy(newData[i], 0x2000, _romB, 0x0000, 0x2000);
|
||||
break;
|
||||
default:
|
||||
validCartridge = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (newAddresses[i] == 0xA000 || newAddresses[i] == 0xE000)
|
||||
{
|
||||
switch (newData[i].Length)
|
||||
{
|
||||
case 0x1000:
|
||||
_romBMask = 0x0FFF;
|
||||
break;
|
||||
case 0x2000:
|
||||
_romBMask = 0x1FFF;
|
||||
break;
|
||||
default:
|
||||
validCartridge = false;
|
||||
return;
|
||||
}
|
||||
_romB = newData[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override int Peek8000(int addr)
|
||||
{
|
||||
return _romA[addr & _romAMask];
|
||||
}
|
||||
public override int Peek8000(int addr)
|
||||
{
|
||||
return _romA[addr & _romAMask];
|
||||
}
|
||||
|
||||
public override int PeekA000(int addr)
|
||||
{
|
||||
return _romB[addr & _romBMask];
|
||||
}
|
||||
public override int PeekA000(int addr)
|
||||
{
|
||||
return _romB[addr & _romBMask];
|
||||
}
|
||||
|
||||
public override int Read8000(int addr)
|
||||
{
|
||||
return _romA[addr & _romAMask];
|
||||
}
|
||||
public override int Read8000(int addr)
|
||||
{
|
||||
return _romA[addr & _romAMask];
|
||||
}
|
||||
|
||||
public override int ReadA000(int addr)
|
||||
{
|
||||
return _romB[addr & _romBMask];
|
||||
}
|
||||
}
|
||||
}
|
||||
public override int ReadA000(int addr)
|
||||
{
|
||||
return _romB[addr & _romBMask];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,150 +5,150 @@ using System.Text;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
|
||||
{
|
||||
public abstract partial class CartridgeDevice
|
||||
{
|
||||
private sealed class Mapper0001 : CartridgeDevice
|
||||
{
|
||||
[SaveState.SaveWithName("RAM")] private readonly int[] _ram = new int[0x2000];
|
||||
[SaveState.SaveWithName("RAMEnabled")] private bool _ramEnabled;
|
||||
[SaveState.DoNotSave] private readonly int[] _rom = new int[0x8000];
|
||||
[SaveState.SaveWithName("ROMOffset")] private int _romOffset;
|
||||
[SaveState.SaveWithName("CartEnabled")] private bool _cartEnabled;
|
||||
public abstract partial class CartridgeDevice
|
||||
{
|
||||
private sealed class Mapper0001 : CartridgeDevice
|
||||
{
|
||||
[SaveState.SaveWithName("RAM")] private readonly int[] _ram = new int[0x2000];
|
||||
[SaveState.SaveWithName("RAMEnabled")] private bool _ramEnabled;
|
||||
[SaveState.DoNotSave] private readonly int[] _rom = new int[0x8000];
|
||||
[SaveState.SaveWithName("ROMOffset")] private int _romOffset;
|
||||
[SaveState.SaveWithName("CartEnabled")] private bool _cartEnabled;
|
||||
|
||||
public Mapper0001(IList<int> newAddresses, IList<int> newBanks, IList<int[]> newData)
|
||||
{
|
||||
pinExRom = false;
|
||||
pinGame = false;
|
||||
for (var i = 0; i < newData.Count; i++)
|
||||
{
|
||||
if (newAddresses[i] == 0x8000)
|
||||
Array.Copy(newData[i], 0, _rom, 0x2000 * newBanks[i], 0x2000);
|
||||
}
|
||||
_romOffset = 0;
|
||||
_cartEnabled = true;
|
||||
}
|
||||
public Mapper0001(IList<int> newAddresses, IList<int> newBanks, IList<int[]> newData)
|
||||
{
|
||||
pinExRom = false;
|
||||
pinGame = false;
|
||||
for (var i = 0; i < newData.Count; i++)
|
||||
{
|
||||
if (newAddresses[i] == 0x8000)
|
||||
Array.Copy(newData[i], 0, _rom, 0x2000 * newBanks[i], 0x2000);
|
||||
}
|
||||
_romOffset = 0;
|
||||
_cartEnabled = true;
|
||||
}
|
||||
|
||||
public override void HardReset()
|
||||
{
|
||||
base.HardReset();
|
||||
pinExRom = false;
|
||||
pinGame = false;
|
||||
for (var i = 0; i < 0x2000; i++)
|
||||
_ram[i] = 0x00;
|
||||
_romOffset = 0;
|
||||
_cartEnabled = true;
|
||||
}
|
||||
public override void HardReset()
|
||||
{
|
||||
base.HardReset();
|
||||
pinExRom = false;
|
||||
pinGame = false;
|
||||
for (var i = 0; i < 0x2000; i++)
|
||||
_ram[i] = 0x00;
|
||||
_romOffset = 0;
|
||||
_cartEnabled = true;
|
||||
}
|
||||
|
||||
public override int Peek8000(int addr)
|
||||
{
|
||||
return GetLoRom(addr);
|
||||
}
|
||||
public override int Peek8000(int addr)
|
||||
{
|
||||
return GetLoRom(addr);
|
||||
}
|
||||
|
||||
public override int PeekA000(int addr)
|
||||
{
|
||||
return Peek8000(addr);
|
||||
}
|
||||
public override int PeekA000(int addr)
|
||||
{
|
||||
return Peek8000(addr);
|
||||
}
|
||||
|
||||
public override int PeekDF00(int addr)
|
||||
{
|
||||
return GetIo2(addr);
|
||||
}
|
||||
public override int PeekDF00(int addr)
|
||||
{
|
||||
return GetIo2(addr);
|
||||
}
|
||||
|
||||
public override void Poke8000(int addr, int val)
|
||||
{
|
||||
SetLoRom(addr, val);
|
||||
}
|
||||
public override void Poke8000(int addr, int val)
|
||||
{
|
||||
SetLoRom(addr, val);
|
||||
}
|
||||
|
||||
public override void PokeA000(int addr, int val)
|
||||
{
|
||||
Poke8000(addr, val);
|
||||
}
|
||||
public override void PokeA000(int addr, int val)
|
||||
{
|
||||
Poke8000(addr, val);
|
||||
}
|
||||
|
||||
public override void PokeDE00(int addr, int val)
|
||||
{
|
||||
SetState(val);
|
||||
}
|
||||
public override void PokeDE00(int addr, int val)
|
||||
{
|
||||
SetState(val);
|
||||
}
|
||||
|
||||
public override void PokeDF00(int addr, int val)
|
||||
{
|
||||
SetIo2(addr, val);
|
||||
}
|
||||
public override void PokeDF00(int addr, int val)
|
||||
{
|
||||
SetIo2(addr, val);
|
||||
}
|
||||
|
||||
public override int Read8000(int addr)
|
||||
{
|
||||
return GetLoRom(addr);
|
||||
}
|
||||
public override int Read8000(int addr)
|
||||
{
|
||||
return GetLoRom(addr);
|
||||
}
|
||||
|
||||
public override int ReadA000(int addr)
|
||||
{
|
||||
return GetHiRom(addr);
|
||||
}
|
||||
public override int ReadA000(int addr)
|
||||
{
|
||||
return GetHiRom(addr);
|
||||
}
|
||||
|
||||
public override int ReadDF00(int addr)
|
||||
{
|
||||
return GetIo2(addr);
|
||||
}
|
||||
public override int ReadDF00(int addr)
|
||||
{
|
||||
return GetIo2(addr);
|
||||
}
|
||||
|
||||
public override void Write8000(int addr, int val)
|
||||
{
|
||||
SetLoRom(addr, val);
|
||||
}
|
||||
public override void Write8000(int addr, int val)
|
||||
{
|
||||
SetLoRom(addr, val);
|
||||
}
|
||||
|
||||
public override void WriteA000(int addr, int val)
|
||||
{
|
||||
SetLoRom(addr, val);
|
||||
}
|
||||
public override void WriteA000(int addr, int val)
|
||||
{
|
||||
SetLoRom(addr, val);
|
||||
}
|
||||
|
||||
public override void WriteDE00(int addr, int val)
|
||||
{
|
||||
SetState(val);
|
||||
}
|
||||
public override void WriteDE00(int addr, int val)
|
||||
{
|
||||
SetState(val);
|
||||
}
|
||||
|
||||
public override void WriteDF00(int addr, int val)
|
||||
{
|
||||
SetIo2(addr, val);
|
||||
}
|
||||
public override void WriteDF00(int addr, int val)
|
||||
{
|
||||
SetIo2(addr, val);
|
||||
}
|
||||
|
||||
private void SetState(int val)
|
||||
{
|
||||
pinGame = (val & 0x01) == 0;
|
||||
pinExRom = (val & 0x02) != 0;
|
||||
_cartEnabled = (val & 0x04) == 0;
|
||||
_romOffset = (val & 0x18) << 10;
|
||||
_ramEnabled = (val & 0x20) == 0;
|
||||
}
|
||||
private void SetState(int val)
|
||||
{
|
||||
pinGame = (val & 0x01) == 0;
|
||||
pinExRom = (val & 0x02) != 0;
|
||||
_cartEnabled = (val & 0x04) == 0;
|
||||
_romOffset = (val & 0x18) << 10;
|
||||
_ramEnabled = (val & 0x20) == 0;
|
||||
}
|
||||
|
||||
private int GetLoRom(int addr)
|
||||
{
|
||||
return _ramEnabled
|
||||
? _ram[addr & 0x1FFF]
|
||||
: _rom[(addr & 0x1FFF) | _romOffset];
|
||||
}
|
||||
private int GetLoRom(int addr)
|
||||
{
|
||||
return _ramEnabled
|
||||
? _ram[addr & 0x1FFF]
|
||||
: _rom[(addr & 0x1FFF) | _romOffset];
|
||||
}
|
||||
|
||||
private int GetHiRom(int addr)
|
||||
{
|
||||
return _rom[(addr & 0x1FFF) | _romOffset];
|
||||
}
|
||||
private int GetHiRom(int addr)
|
||||
{
|
||||
return _rom[(addr & 0x1FFF) | _romOffset];
|
||||
}
|
||||
|
||||
private void SetLoRom(int addr, int val)
|
||||
{
|
||||
_ram[addr & 0x1FFF] = val;
|
||||
}
|
||||
private void SetLoRom(int addr, int val)
|
||||
{
|
||||
_ram[addr & 0x1FFF] = val;
|
||||
}
|
||||
|
||||
private int GetIo2(int addr)
|
||||
{
|
||||
if (!_cartEnabled)
|
||||
return ReadOpenBus();
|
||||
private int GetIo2(int addr)
|
||||
{
|
||||
if (!_cartEnabled)
|
||||
return ReadOpenBus();
|
||||
|
||||
return _ramEnabled
|
||||
? _ram[(addr & 0xFF) | 0x1F00]
|
||||
: _rom[(addr & 0xFF) | _romOffset | 0x1F00];
|
||||
}
|
||||
return _ramEnabled
|
||||
? _ram[(addr & 0xFF) | 0x1F00]
|
||||
: _rom[(addr & 0xFF) | _romOffset | 0x1F00];
|
||||
}
|
||||
|
||||
private void SetIo2(int addr, int val)
|
||||
{
|
||||
_ram[addr & 0x1FFF] = val & 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void SetIo2(int addr, int val)
|
||||
{
|
||||
_ram[addr & 0x1FFF] = val & 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,153 +5,153 @@ using BizHawk.Common;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
|
||||
{
|
||||
public abstract partial class CartridgeDevice
|
||||
{
|
||||
private sealed class Mapper0005 : CartridgeDevice
|
||||
{
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int[][] _banksA; //8000
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int[][] _banksB = new int[0][]; //A000
|
||||
[SaveState.SaveWithName("BankMask")]
|
||||
private readonly int _bankMask;
|
||||
[SaveState.SaveWithName("BankNumber")]
|
||||
private int _bankNumber;
|
||||
[SaveState.DoNotSave]
|
||||
private int[] _currentBankA;
|
||||
[SaveState.DoNotSave]
|
||||
private int[] _currentBankB;
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int[] _dummyBank;
|
||||
public abstract partial class CartridgeDevice
|
||||
{
|
||||
private sealed class Mapper0005 : CartridgeDevice
|
||||
{
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int[][] _banksA; //8000
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int[][] _banksB = new int[0][]; //A000
|
||||
[SaveState.SaveWithName("BankMask")]
|
||||
private readonly int _bankMask;
|
||||
[SaveState.SaveWithName("BankNumber")]
|
||||
private int _bankNumber;
|
||||
[SaveState.DoNotSave]
|
||||
private int[] _currentBankA;
|
||||
[SaveState.DoNotSave]
|
||||
private int[] _currentBankB;
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int[] _dummyBank;
|
||||
|
||||
public Mapper0005(IList<int> newAddresses, IList<int> newBanks, IList<int[]> newData)
|
||||
{
|
||||
var count = newAddresses.Count;
|
||||
public Mapper0005(IList<int> newAddresses, IList<int> newBanks, IList<int[]> newData)
|
||||
{
|
||||
var count = newAddresses.Count;
|
||||
|
||||
// build dummy bank
|
||||
_dummyBank = new int[0x2000];
|
||||
for (var i = 0; i < 0x2000; i++)
|
||||
_dummyBank[i] = 0xFF; // todo: determine if this is correct
|
||||
// build dummy bank
|
||||
_dummyBank = new int[0x2000];
|
||||
for (var i = 0; i < 0x2000; i++)
|
||||
_dummyBank[i] = 0xFF; // todo: determine if this is correct
|
||||
|
||||
switch (count)
|
||||
{
|
||||
case 64:
|
||||
pinGame = true;
|
||||
pinExRom = false;
|
||||
_bankMask = 0x3F;
|
||||
_banksA = new int[64][];
|
||||
break;
|
||||
case 32:
|
||||
// this specific config is a weird exception
|
||||
pinGame = false;
|
||||
pinExRom = false;
|
||||
_bankMask = 0x0F;
|
||||
_banksA = new int[16][];
|
||||
_banksB = new int[16][];
|
||||
break;
|
||||
case 16:
|
||||
pinGame = true;
|
||||
pinExRom = false;
|
||||
_bankMask = 0x0F;
|
||||
_banksA = new int[16][];
|
||||
break;
|
||||
case 8:
|
||||
pinGame = true;
|
||||
pinExRom = false;
|
||||
_bankMask = 0x07;
|
||||
_banksA = new int[8][];
|
||||
break;
|
||||
case 4:
|
||||
pinGame = true;
|
||||
pinExRom = false;
|
||||
_bankMask = 0x03;
|
||||
_banksA = new int[4][];
|
||||
break;
|
||||
case 2:
|
||||
pinGame = true;
|
||||
pinExRom = false;
|
||||
_bankMask = 0x01;
|
||||
_banksA = new int[2][];
|
||||
break;
|
||||
case 1:
|
||||
pinGame = true;
|
||||
pinExRom = false;
|
||||
_bankMask = 0x00;
|
||||
_banksA = new int[1][];
|
||||
break;
|
||||
default:
|
||||
throw new Exception("This looks like an Ocean cartridge but cannot be loaded...");
|
||||
}
|
||||
switch (count)
|
||||
{
|
||||
case 64:
|
||||
pinGame = true;
|
||||
pinExRom = false;
|
||||
_bankMask = 0x3F;
|
||||
_banksA = new int[64][];
|
||||
break;
|
||||
case 32:
|
||||
// this specific config is a weird exception
|
||||
pinGame = false;
|
||||
pinExRom = false;
|
||||
_bankMask = 0x0F;
|
||||
_banksA = new int[16][];
|
||||
_banksB = new int[16][];
|
||||
break;
|
||||
case 16:
|
||||
pinGame = true;
|
||||
pinExRom = false;
|
||||
_bankMask = 0x0F;
|
||||
_banksA = new int[16][];
|
||||
break;
|
||||
case 8:
|
||||
pinGame = true;
|
||||
pinExRom = false;
|
||||
_bankMask = 0x07;
|
||||
_banksA = new int[8][];
|
||||
break;
|
||||
case 4:
|
||||
pinGame = true;
|
||||
pinExRom = false;
|
||||
_bankMask = 0x03;
|
||||
_banksA = new int[4][];
|
||||
break;
|
||||
case 2:
|
||||
pinGame = true;
|
||||
pinExRom = false;
|
||||
_bankMask = 0x01;
|
||||
_banksA = new int[2][];
|
||||
break;
|
||||
case 1:
|
||||
pinGame = true;
|
||||
pinExRom = false;
|
||||
_bankMask = 0x00;
|
||||
_banksA = new int[1][];
|
||||
break;
|
||||
default:
|
||||
throw new Exception("This looks like an Ocean cartridge but cannot be loaded...");
|
||||
}
|
||||
|
||||
// for safety, initialize all banks to dummy
|
||||
for (var i = 0; i < _banksA.Length; i++)
|
||||
_banksA[i] = _dummyBank;
|
||||
for (var i = 0; i < _banksB.Length; i++)
|
||||
_banksB[i] = _dummyBank;
|
||||
// for safety, initialize all banks to dummy
|
||||
for (var i = 0; i < _banksA.Length; i++)
|
||||
_banksA[i] = _dummyBank;
|
||||
for (var i = 0; i < _banksB.Length; i++)
|
||||
_banksB[i] = _dummyBank;
|
||||
|
||||
// now load in the banks
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
switch (newAddresses[i])
|
||||
{
|
||||
case 0x8000:
|
||||
_banksA[newBanks[i] & _bankMask] = newData[i];
|
||||
break;
|
||||
case 0xA000:
|
||||
case 0xE000:
|
||||
_banksB[newBanks[i] & _bankMask] = newData[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
// now load in the banks
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
switch (newAddresses[i])
|
||||
{
|
||||
case 0x8000:
|
||||
_banksA[newBanks[i] & _bankMask] = newData[i];
|
||||
break;
|
||||
case 0xA000:
|
||||
case 0xE000:
|
||||
_banksB[newBanks[i] & _bankMask] = newData[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BankSet(0);
|
||||
}
|
||||
BankSet(0);
|
||||
}
|
||||
|
||||
private void BankSet(int index)
|
||||
{
|
||||
_bankNumber = index & _bankMask;
|
||||
_currentBankA = !pinExRom ? _banksA[_bankNumber] : _dummyBank;
|
||||
_currentBankB = !pinGame ? _banksB[_bankNumber] : _dummyBank;
|
||||
}
|
||||
private void BankSet(int index)
|
||||
{
|
||||
_bankNumber = index & _bankMask;
|
||||
_currentBankA = !pinExRom ? _banksA[_bankNumber] : _dummyBank;
|
||||
_currentBankB = !pinGame ? _banksB[_bankNumber] : _dummyBank;
|
||||
}
|
||||
|
||||
public override int Peek8000(int addr)
|
||||
{
|
||||
return _currentBankA[addr];
|
||||
}
|
||||
public override int Peek8000(int addr)
|
||||
{
|
||||
return _currentBankA[addr];
|
||||
}
|
||||
|
||||
public override int PeekA000(int addr)
|
||||
{
|
||||
return _currentBankB[addr];
|
||||
}
|
||||
public override int PeekA000(int addr)
|
||||
{
|
||||
return _currentBankB[addr];
|
||||
}
|
||||
|
||||
public override void PokeDE00(int addr, int val)
|
||||
{
|
||||
if (addr == 0x00)
|
||||
BankSet(val);
|
||||
}
|
||||
public override void PokeDE00(int addr, int val)
|
||||
{
|
||||
if (addr == 0x00)
|
||||
BankSet(val);
|
||||
}
|
||||
|
||||
public override int Read8000(int addr)
|
||||
{
|
||||
return _currentBankA[addr];
|
||||
}
|
||||
public override int Read8000(int addr)
|
||||
{
|
||||
return _currentBankA[addr];
|
||||
}
|
||||
|
||||
public override int ReadA000(int addr)
|
||||
{
|
||||
return _currentBankB[addr];
|
||||
}
|
||||
public override int ReadA000(int addr)
|
||||
{
|
||||
return _currentBankB[addr];
|
||||
}
|
||||
|
||||
public override void WriteDE00(int addr, int val)
|
||||
{
|
||||
if (addr == 0x00)
|
||||
BankSet(val);
|
||||
}
|
||||
public override void WriteDE00(int addr, int val)
|
||||
{
|
||||
if (addr == 0x00)
|
||||
BankSet(val);
|
||||
}
|
||||
|
||||
public override void SyncState(Serializer ser)
|
||||
{
|
||||
base.SyncState(ser);
|
||||
if (ser.IsReader)
|
||||
BankSet(_bankNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
public override void SyncState(Serializer ser)
|
||||
{
|
||||
base.SyncState(ser);
|
||||
if (ser.IsReader)
|
||||
BankSet(_bankNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,79 +5,79 @@ using System.Text;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
|
||||
{
|
||||
// Epyx Fastload. Uppermost page is always visible at DFxx.
|
||||
// They use a capacitor that is discharged by accesses to DExx
|
||||
// to pull down EXROM. Also, accesses to LOROM while it is active
|
||||
// discharge the capacitor.
|
||||
// Thanks to VICE team for the info: http://vice-emu.sourceforge.net/vice_15.html
|
||||
// Epyx Fastload. Uppermost page is always visible at DFxx.
|
||||
// They use a capacitor that is discharged by accesses to DExx
|
||||
// to pull down EXROM. Also, accesses to LOROM while it is active
|
||||
// discharge the capacitor.
|
||||
// Thanks to VICE team for the info: http://vice-emu.sourceforge.net/vice_15.html
|
||||
|
||||
public abstract partial class CartridgeDevice
|
||||
{
|
||||
private class Mapper000A : CartridgeDevice
|
||||
{
|
||||
// This constant differs depending on whose research you reference. TODO: Verify.
|
||||
[SaveState.DoNotSave]
|
||||
private const int RESET_CAPACITOR_CYCLES = 512;
|
||||
public abstract partial class CartridgeDevice
|
||||
{
|
||||
private class Mapper000A : CartridgeDevice
|
||||
{
|
||||
// This constant differs depending on whose research you reference. TODO: Verify.
|
||||
[SaveState.DoNotSave]
|
||||
private const int RESET_CAPACITOR_CYCLES = 512;
|
||||
|
||||
[SaveState.SaveWithName("CapacitorCycles")]
|
||||
private int _capacitorCycles;
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int[] _rom;
|
||||
[SaveState.SaveWithName("CapacitorCycles")]
|
||||
private int _capacitorCycles;
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int[] _rom;
|
||||
|
||||
public Mapper000A(IList<int[]> newData)
|
||||
{
|
||||
_rom = new int[0x2000];
|
||||
Array.Copy(newData.First(), _rom, 0x2000);
|
||||
pinGame = true;
|
||||
}
|
||||
public Mapper000A(IList<int[]> newData)
|
||||
{
|
||||
_rom = new int[0x2000];
|
||||
Array.Copy(newData.First(), _rom, 0x2000);
|
||||
pinGame = true;
|
||||
}
|
||||
|
||||
public override void ExecutePhase()
|
||||
{
|
||||
pinExRom = !(_capacitorCycles > 0);
|
||||
if (!pinExRom)
|
||||
{
|
||||
_capacitorCycles--;
|
||||
}
|
||||
}
|
||||
public override void ExecutePhase()
|
||||
{
|
||||
pinExRom = !(_capacitorCycles > 0);
|
||||
if (!pinExRom)
|
||||
{
|
||||
_capacitorCycles--;
|
||||
}
|
||||
}
|
||||
|
||||
public override void HardReset()
|
||||
{
|
||||
_capacitorCycles = RESET_CAPACITOR_CYCLES;
|
||||
base.HardReset();
|
||||
}
|
||||
public override void HardReset()
|
||||
{
|
||||
_capacitorCycles = RESET_CAPACITOR_CYCLES;
|
||||
base.HardReset();
|
||||
}
|
||||
|
||||
public override int Peek8000(int addr)
|
||||
{
|
||||
return _rom[addr & 0x1FFF];
|
||||
}
|
||||
public override int Peek8000(int addr)
|
||||
{
|
||||
return _rom[addr & 0x1FFF];
|
||||
}
|
||||
|
||||
public override int PeekDE00(int addr)
|
||||
{
|
||||
return 0x00;
|
||||
}
|
||||
public override int PeekDE00(int addr)
|
||||
{
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
public override int PeekDF00(int addr)
|
||||
{
|
||||
return _rom[(addr & 0xFF) | 0x1F00];
|
||||
}
|
||||
public override int PeekDF00(int addr)
|
||||
{
|
||||
return _rom[(addr & 0xFF) | 0x1F00];
|
||||
}
|
||||
|
||||
public override int Read8000(int addr)
|
||||
{
|
||||
_capacitorCycles = RESET_CAPACITOR_CYCLES;
|
||||
return _rom[addr & 0x1FFF];
|
||||
}
|
||||
public override int Read8000(int addr)
|
||||
{
|
||||
_capacitorCycles = RESET_CAPACITOR_CYCLES;
|
||||
return _rom[addr & 0x1FFF];
|
||||
}
|
||||
|
||||
public override int ReadDE00(int addr)
|
||||
{
|
||||
_capacitorCycles = RESET_CAPACITOR_CYCLES;
|
||||
return 0x00;
|
||||
}
|
||||
public override int ReadDE00(int addr)
|
||||
{
|
||||
_capacitorCycles = RESET_CAPACITOR_CYCLES;
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
public override int ReadDF00(int addr)
|
||||
{
|
||||
return _rom[(addr & 0xFF) | 0x1F00];
|
||||
}
|
||||
}
|
||||
}
|
||||
public override int ReadDF00(int addr)
|
||||
{
|
||||
return _rom[(addr & 0xFF) | 0x1F00];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,62 +3,62 @@ using System.Collections.Generic;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
|
||||
{
|
||||
// Westermann Learning mapper.
|
||||
// Starts up with both banks enabled, any read to DFxx
|
||||
// turns off the high bank by bringing GAME high.
|
||||
// I suspect that the game loads by copying all hirom to
|
||||
// the RAM underneath (BASIC variable values probably)
|
||||
// and then disables once loaded.
|
||||
// Westermann Learning mapper.
|
||||
// Starts up with both banks enabled, any read to DFxx
|
||||
// turns off the high bank by bringing GAME high.
|
||||
// I suspect that the game loads by copying all hirom to
|
||||
// the RAM underneath (BASIC variable values probably)
|
||||
// and then disables once loaded.
|
||||
|
||||
public abstract partial class CartridgeDevice
|
||||
{
|
||||
private sealed class Mapper000B : CartridgeDevice
|
||||
{
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int[] _rom = new int[0x4000];
|
||||
public abstract partial class CartridgeDevice
|
||||
{
|
||||
private sealed class Mapper000B : CartridgeDevice
|
||||
{
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int[] _rom = new int[0x4000];
|
||||
|
||||
public Mapper000B(IList<int> newAddresses, IList<int[]> newData)
|
||||
{
|
||||
validCartridge = false;
|
||||
public Mapper000B(IList<int> newAddresses, IList<int[]> newData)
|
||||
{
|
||||
validCartridge = false;
|
||||
|
||||
for (var i = 0; i < 0x4000; i++)
|
||||
_rom[i] = 0xFF;
|
||||
for (var i = 0; i < 0x4000; i++)
|
||||
_rom[i] = 0xFF;
|
||||
|
||||
if (newAddresses[0] != 0x8000)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (newAddresses[0] != 0x8000)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Array.Copy(newData[0], _rom, Math.Min(newData[0].Length, 0x4000));
|
||||
validCartridge = true;
|
||||
}
|
||||
Array.Copy(newData[0], _rom, Math.Min(newData[0].Length, 0x4000));
|
||||
validCartridge = true;
|
||||
}
|
||||
|
||||
public override int Peek8000(int addr)
|
||||
{
|
||||
return _rom[addr];
|
||||
}
|
||||
public override int Peek8000(int addr)
|
||||
{
|
||||
return _rom[addr];
|
||||
}
|
||||
|
||||
public override int PeekA000(int addr)
|
||||
{
|
||||
return _rom[addr | 0x2000];
|
||||
}
|
||||
public override int PeekA000(int addr)
|
||||
{
|
||||
return _rom[addr | 0x2000];
|
||||
}
|
||||
|
||||
public override int Read8000(int addr)
|
||||
{
|
||||
return _rom[addr];
|
||||
}
|
||||
public override int Read8000(int addr)
|
||||
{
|
||||
return _rom[addr];
|
||||
}
|
||||
|
||||
public override int ReadA000(int addr)
|
||||
{
|
||||
return _rom[addr | 0x2000];
|
||||
}
|
||||
public override int ReadA000(int addr)
|
||||
{
|
||||
return _rom[addr | 0x2000];
|
||||
}
|
||||
|
||||
public override int ReadDF00(int addr)
|
||||
{
|
||||
pinGame = true;
|
||||
return base.ReadDF00(addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
public override int ReadDF00(int addr)
|
||||
{
|
||||
pinGame = true;
|
||||
return base.ReadDF00(addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,125 +5,125 @@ using BizHawk.Common;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
|
||||
{
|
||||
// This is a mapper used commonly by System 3. It is
|
||||
// also utilized by the short-lived C64 Game System.
|
||||
// This is a mapper used commonly by System 3. It is
|
||||
// also utilized by the short-lived C64 Game System.
|
||||
|
||||
// Bank select is DExx. You select them by writing to the
|
||||
// register DE00+BankNr. For example, bank 01 is a write
|
||||
// to DE01.
|
||||
// Bank select is DExx. You select them by writing to the
|
||||
// register DE00+BankNr. For example, bank 01 is a write
|
||||
// to DE01.
|
||||
|
||||
public abstract partial class CartridgeDevice
|
||||
{
|
||||
private class Mapper000F : CartridgeDevice
|
||||
{
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int[][] _banks; //8000
|
||||
[SaveState.SaveWithName("BankMask")]
|
||||
private readonly int _bankMask;
|
||||
[SaveState.SaveWithName("BankNumber")]
|
||||
private int _bankNumber;
|
||||
[SaveState.SaveWithName("CurrentBank")]
|
||||
private int[] _currentBank;
|
||||
public abstract partial class CartridgeDevice
|
||||
{
|
||||
private class Mapper000F : CartridgeDevice
|
||||
{
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int[][] _banks; //8000
|
||||
[SaveState.SaveWithName("BankMask")]
|
||||
private readonly int _bankMask;
|
||||
[SaveState.SaveWithName("BankNumber")]
|
||||
private int _bankNumber;
|
||||
[SaveState.SaveWithName("CurrentBank")]
|
||||
private int[] _currentBank;
|
||||
|
||||
public Mapper000F(IList<int> newAddresses, IList<int> newBanks, IList<int[]> newData)
|
||||
{
|
||||
var count = newAddresses.Count;
|
||||
public Mapper000F(IList<int> newAddresses, IList<int> newBanks, IList<int[]> newData)
|
||||
{
|
||||
var count = newAddresses.Count;
|
||||
|
||||
pinGame = true;
|
||||
pinExRom = false;
|
||||
pinGame = true;
|
||||
pinExRom = false;
|
||||
|
||||
// build dummy bank
|
||||
var dummyBank = new int[0x2000];
|
||||
for (var i = 0; i < 0x2000; i++)
|
||||
dummyBank[i] = 0xFF; // todo: determine if this is correct
|
||||
// build dummy bank
|
||||
var dummyBank = new int[0x2000];
|
||||
for (var i = 0; i < 0x2000; i++)
|
||||
dummyBank[i] = 0xFF; // todo: determine if this is correct
|
||||
|
||||
switch (count)
|
||||
{
|
||||
case 64:
|
||||
_bankMask = 0x3F;
|
||||
_banks = new int[64][];
|
||||
break;
|
||||
case 32:
|
||||
_bankMask = 0x1F;
|
||||
_banks = new int[32][];
|
||||
break;
|
||||
case 16:
|
||||
_bankMask = 0x0F;
|
||||
_banks = new int[16][];
|
||||
break;
|
||||
case 8:
|
||||
_bankMask = 0x07;
|
||||
_banks = new int[8][];
|
||||
break;
|
||||
case 4:
|
||||
_bankMask = 0x03;
|
||||
_banks = new int[4][];
|
||||
break;
|
||||
case 2:
|
||||
_bankMask = 0x01;
|
||||
_banks = new int[2][];
|
||||
break;
|
||||
case 1:
|
||||
_bankMask = 0x00;
|
||||
_banks = new int[1][];
|
||||
break;
|
||||
default:
|
||||
throw new Exception("This looks like a System 3/C64GS cartridge but cannot be loaded...");
|
||||
}
|
||||
switch (count)
|
||||
{
|
||||
case 64:
|
||||
_bankMask = 0x3F;
|
||||
_banks = new int[64][];
|
||||
break;
|
||||
case 32:
|
||||
_bankMask = 0x1F;
|
||||
_banks = new int[32][];
|
||||
break;
|
||||
case 16:
|
||||
_bankMask = 0x0F;
|
||||
_banks = new int[16][];
|
||||
break;
|
||||
case 8:
|
||||
_bankMask = 0x07;
|
||||
_banks = new int[8][];
|
||||
break;
|
||||
case 4:
|
||||
_bankMask = 0x03;
|
||||
_banks = new int[4][];
|
||||
break;
|
||||
case 2:
|
||||
_bankMask = 0x01;
|
||||
_banks = new int[2][];
|
||||
break;
|
||||
case 1:
|
||||
_bankMask = 0x00;
|
||||
_banks = new int[1][];
|
||||
break;
|
||||
default:
|
||||
throw new Exception("This looks like a System 3/C64GS cartridge but cannot be loaded...");
|
||||
}
|
||||
|
||||
// for safety, initialize all banks to dummy
|
||||
for (var i = 0; i < _banks.Length; i++)
|
||||
_banks[i] = dummyBank;
|
||||
// for safety, initialize all banks to dummy
|
||||
for (var i = 0; i < _banks.Length; i++)
|
||||
_banks[i] = dummyBank;
|
||||
|
||||
// now load in the banks
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
if (newAddresses[i] == 0x8000)
|
||||
{
|
||||
_banks[newBanks[i] & _bankMask] = newData[i];
|
||||
}
|
||||
}
|
||||
// now load in the banks
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
if (newAddresses[i] == 0x8000)
|
||||
{
|
||||
_banks[newBanks[i] & _bankMask] = newData[i];
|
||||
}
|
||||
}
|
||||
|
||||
BankSet(0);
|
||||
}
|
||||
BankSet(0);
|
||||
}
|
||||
|
||||
protected void BankSet(int index)
|
||||
{
|
||||
_bankNumber = index & _bankMask;
|
||||
UpdateState();
|
||||
}
|
||||
protected void BankSet(int index)
|
||||
{
|
||||
_bankNumber = index & _bankMask;
|
||||
UpdateState();
|
||||
}
|
||||
|
||||
public override int Peek8000(int addr)
|
||||
{
|
||||
return _currentBank[addr];
|
||||
}
|
||||
public override int Peek8000(int addr)
|
||||
{
|
||||
return _currentBank[addr];
|
||||
}
|
||||
|
||||
public override void PokeDE00(int addr, int val)
|
||||
{
|
||||
BankSet(addr);
|
||||
}
|
||||
public override void PokeDE00(int addr, int val)
|
||||
{
|
||||
BankSet(addr);
|
||||
}
|
||||
|
||||
public override int Read8000(int addr)
|
||||
{
|
||||
return _currentBank[addr];
|
||||
}
|
||||
public override int Read8000(int addr)
|
||||
{
|
||||
return _currentBank[addr];
|
||||
}
|
||||
|
||||
private void UpdateState()
|
||||
{
|
||||
_currentBank = _banks[_bankNumber];
|
||||
}
|
||||
private void UpdateState()
|
||||
{
|
||||
_currentBank = _banks[_bankNumber];
|
||||
}
|
||||
|
||||
public override void WriteDE00(int addr, int val)
|
||||
{
|
||||
BankSet(addr);
|
||||
}
|
||||
public override void WriteDE00(int addr, int val)
|
||||
{
|
||||
BankSet(addr);
|
||||
}
|
||||
|
||||
public override void SyncState(Serializer ser)
|
||||
{
|
||||
base.SyncState(ser);
|
||||
if (ser.IsReader)
|
||||
BankSet(_bankNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
public override void SyncState(Serializer ser)
|
||||
{
|
||||
base.SyncState(ser);
|
||||
if (ser.IsReader)
|
||||
BankSet(_bankNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,36 +2,36 @@
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
|
||||
{
|
||||
// This mapper comes from Dinamic. It is in fact identical
|
||||
// to the System 3 mapper (000F) except that bank switching is
|
||||
// done by reads to the DExx region instead of writes.
|
||||
// This is why mapper 0011 inherits directly from 000F.
|
||||
// This mapper comes from Dinamic. It is in fact identical
|
||||
// to the System 3 mapper (000F) except that bank switching is
|
||||
// done by reads to the DExx region instead of writes.
|
||||
// This is why mapper 0011 inherits directly from 000F.
|
||||
|
||||
public abstract partial class CartridgeDevice
|
||||
{
|
||||
private class Mapper0011 : Mapper000F
|
||||
{
|
||||
public Mapper0011(IList<int> newAddresses, IList<int> newBanks, IList<int[]> newData)
|
||||
: base(newAddresses, newBanks, newData)
|
||||
{
|
||||
// required to pass information to base class
|
||||
}
|
||||
public abstract partial class CartridgeDevice
|
||||
{
|
||||
private class Mapper0011 : Mapper000F
|
||||
{
|
||||
public Mapper0011(IList<int> newAddresses, IList<int> newBanks, IList<int[]> newData)
|
||||
: base(newAddresses, newBanks, newData)
|
||||
{
|
||||
// required to pass information to base class
|
||||
}
|
||||
|
||||
public override void PokeDE00(int addr, int val)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
public override void PokeDE00(int addr, int val)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public override int ReadDE00(int addr)
|
||||
{
|
||||
BankSet(addr);
|
||||
return base.ReadDE00(addr);
|
||||
}
|
||||
public override int ReadDE00(int addr)
|
||||
{
|
||||
BankSet(addr);
|
||||
return base.ReadDE00(addr);
|
||||
}
|
||||
|
||||
public override void WriteDE00(int addr, int val)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
public override void WriteDE00(int addr, int val)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,83 +4,83 @@ using BizHawk.Common;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
|
||||
{
|
||||
public abstract partial class CartridgeDevice
|
||||
{
|
||||
private sealed class Mapper0012 : CartridgeDevice
|
||||
{
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int[] _bankMain;
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int[][] _bankHigh;
|
||||
[SaveState.SaveWithName("BankHighSelected")]
|
||||
private int[] _bankHighSelected;
|
||||
[SaveState.SaveWithName("BankIndex")]
|
||||
private int _bankIndex;
|
||||
public abstract partial class CartridgeDevice
|
||||
{
|
||||
private sealed class Mapper0012 : CartridgeDevice
|
||||
{
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int[] _bankMain;
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int[][] _bankHigh;
|
||||
[SaveState.SaveWithName("BankHighSelected")]
|
||||
private int[] _bankHighSelected;
|
||||
[SaveState.SaveWithName("BankIndex")]
|
||||
private int _bankIndex;
|
||||
|
||||
// Zaxxon and Super Zaxxon cartridges
|
||||
// - read to 8xxx selects bank 0 in A000-BFFF
|
||||
// - read to 9xxx selects bank 1 in A000-BFFF
|
||||
// Zaxxon and Super Zaxxon cartridges
|
||||
// - read to 8xxx selects bank 0 in A000-BFFF
|
||||
// - read to 9xxx selects bank 1 in A000-BFFF
|
||||
|
||||
public Mapper0012(IList<int> newAddresses, IList<int> newBanks, IList<int[]> newData)
|
||||
{
|
||||
_bankMain = new int[0x2000];
|
||||
_bankHigh = new int[2][];
|
||||
var dummyBank = new int[0x2000];
|
||||
public Mapper0012(IList<int> newAddresses, IList<int> newBanks, IList<int[]> newData)
|
||||
{
|
||||
_bankMain = new int[0x2000];
|
||||
_bankHigh = new int[2][];
|
||||
var dummyBank = new int[0x2000];
|
||||
|
||||
// create dummy bank just in case
|
||||
for (var i = 0; i < 0x2000; i++)
|
||||
dummyBank[i] = 0xFF;
|
||||
// create dummy bank just in case
|
||||
for (var i = 0; i < 0x2000; i++)
|
||||
dummyBank[i] = 0xFF;
|
||||
|
||||
_bankHigh[0] = dummyBank;
|
||||
_bankHigh[1] = dummyBank;
|
||||
_bankHigh[0] = dummyBank;
|
||||
_bankHigh[1] = dummyBank;
|
||||
|
||||
// load in the banks
|
||||
for (var i = 0; i < newAddresses.Count; i++)
|
||||
{
|
||||
if (newAddresses[i] == 0x8000)
|
||||
Array.Copy(newData[i], _bankMain, 0x1000);
|
||||
else if ((newAddresses[i] == 0xA000 || newAddresses[i] == 0xE000) && newBanks[i] < 2)
|
||||
_bankHigh[newBanks[i]] = newData[i];
|
||||
}
|
||||
// load in the banks
|
||||
for (var i = 0; i < newAddresses.Count; i++)
|
||||
{
|
||||
if (newAddresses[i] == 0x8000)
|
||||
Array.Copy(newData[i], _bankMain, 0x1000);
|
||||
else if ((newAddresses[i] == 0xA000 || newAddresses[i] == 0xE000) && newBanks[i] < 2)
|
||||
_bankHigh[newBanks[i]] = newData[i];
|
||||
}
|
||||
|
||||
// mirror the main rom from 8000 to 9000
|
||||
Array.Copy(_bankMain, 0x0000, _bankMain, 0x1000, 0x1000);
|
||||
// mirror the main rom from 8000 to 9000
|
||||
Array.Copy(_bankMain, 0x0000, _bankMain, 0x1000, 0x1000);
|
||||
|
||||
// set both pins low for 16k rom config
|
||||
pinExRom = false;
|
||||
pinGame = false;
|
||||
// set both pins low for 16k rom config
|
||||
pinExRom = false;
|
||||
pinGame = false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public override int Peek8000(int addr)
|
||||
{
|
||||
return _bankMain[addr];
|
||||
}
|
||||
public override int Peek8000(int addr)
|
||||
{
|
||||
return _bankMain[addr];
|
||||
}
|
||||
|
||||
public override int PeekA000(int addr)
|
||||
{
|
||||
return _bankHighSelected[addr];
|
||||
}
|
||||
public override int PeekA000(int addr)
|
||||
{
|
||||
return _bankHighSelected[addr];
|
||||
}
|
||||
|
||||
public override int Read8000(int addr)
|
||||
{
|
||||
_bankIndex = (addr & 0x1000) >> 12;
|
||||
_bankHighSelected = _bankHigh[_bankIndex];
|
||||
return _bankMain[addr];
|
||||
}
|
||||
public override int Read8000(int addr)
|
||||
{
|
||||
_bankIndex = (addr & 0x1000) >> 12;
|
||||
_bankHighSelected = _bankHigh[_bankIndex];
|
||||
return _bankMain[addr];
|
||||
}
|
||||
|
||||
public override int ReadA000(int addr)
|
||||
{
|
||||
return _bankHighSelected[addr];
|
||||
}
|
||||
public override int ReadA000(int addr)
|
||||
{
|
||||
return _bankHighSelected[addr];
|
||||
}
|
||||
|
||||
public override void SyncState(Serializer ser)
|
||||
{
|
||||
base.SyncState(ser);
|
||||
if (ser.IsReader)
|
||||
_bankHighSelected = _bankHigh[_bankIndex];
|
||||
}
|
||||
}
|
||||
public override void SyncState(Serializer ser)
|
||||
{
|
||||
base.SyncState(ser);
|
||||
if (ser.IsReader)
|
||||
_bankHighSelected = _bankHigh[_bankIndex];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,126 +4,126 @@ using BizHawk.Common;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
|
||||
{
|
||||
// Mapper for a few Domark and HES Australia games.
|
||||
// It seems a lot of people dumping these have remapped
|
||||
// them to the Ocean mapper (0005) but this is still here
|
||||
// for compatibility.
|
||||
//
|
||||
// Bank select is DE00, bit 7 enabled means to disable
|
||||
// ROM in 8000-9FFF.
|
||||
// Mapper for a few Domark and HES Australia games.
|
||||
// It seems a lot of people dumping these have remapped
|
||||
// them to the Ocean mapper (0005) but this is still here
|
||||
// for compatibility.
|
||||
//
|
||||
// Bank select is DE00, bit 7 enabled means to disable
|
||||
// ROM in 8000-9FFF.
|
||||
|
||||
public abstract partial class CartridgeDevice
|
||||
{
|
||||
private sealed class Mapper0013 : CartridgeDevice
|
||||
{
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int[][] _banks; //8000
|
||||
[SaveState.SaveWithName("BankMask")]
|
||||
private readonly int _bankMask;
|
||||
[SaveState.SaveWithName("BankNumber")]
|
||||
private int _bankNumber;
|
||||
[SaveState.DoNotSave]
|
||||
private int[] _currentBank;
|
||||
[SaveState.SaveWithName("ROMEnable")]
|
||||
private bool _romEnable;
|
||||
public abstract partial class CartridgeDevice
|
||||
{
|
||||
private sealed class Mapper0013 : CartridgeDevice
|
||||
{
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int[][] _banks; //8000
|
||||
[SaveState.SaveWithName("BankMask")]
|
||||
private readonly int _bankMask;
|
||||
[SaveState.SaveWithName("BankNumber")]
|
||||
private int _bankNumber;
|
||||
[SaveState.DoNotSave]
|
||||
private int[] _currentBank;
|
||||
[SaveState.SaveWithName("ROMEnable")]
|
||||
private bool _romEnable;
|
||||
|
||||
public Mapper0013(IList<int> newAddresses, IList<int> newBanks, IList<int[]> newData)
|
||||
{
|
||||
var count = newAddresses.Count;
|
||||
public Mapper0013(IList<int> newAddresses, IList<int> newBanks, IList<int[]> newData)
|
||||
{
|
||||
var count = newAddresses.Count;
|
||||
|
||||
pinGame = true;
|
||||
pinExRom = false;
|
||||
_romEnable = true;
|
||||
pinGame = true;
|
||||
pinExRom = false;
|
||||
_romEnable = true;
|
||||
|
||||
// build dummy bank
|
||||
var dummyBank = new int[0x2000];
|
||||
for (var i = 0; i < 0x2000; i++)
|
||||
dummyBank[i] = 0xFF; // todo: determine if this is correct
|
||||
// build dummy bank
|
||||
var dummyBank = new int[0x2000];
|
||||
for (var i = 0; i < 0x2000; i++)
|
||||
dummyBank[i] = 0xFF; // todo: determine if this is correct
|
||||
|
||||
switch (count)
|
||||
{
|
||||
case 16:
|
||||
_bankMask = 0x0F;
|
||||
_banks = new int[16][];
|
||||
break;
|
||||
case 8:
|
||||
_bankMask = 0x07;
|
||||
_banks = new int[8][];
|
||||
break;
|
||||
case 4:
|
||||
_bankMask = 0x03;
|
||||
_banks = new int[4][];
|
||||
break;
|
||||
default:
|
||||
throw new Exception("This looks like a Domark/HES cartridge but cannot be loaded...");
|
||||
}
|
||||
switch (count)
|
||||
{
|
||||
case 16:
|
||||
_bankMask = 0x0F;
|
||||
_banks = new int[16][];
|
||||
break;
|
||||
case 8:
|
||||
_bankMask = 0x07;
|
||||
_banks = new int[8][];
|
||||
break;
|
||||
case 4:
|
||||
_bankMask = 0x03;
|
||||
_banks = new int[4][];
|
||||
break;
|
||||
default:
|
||||
throw new Exception("This looks like a Domark/HES cartridge but cannot be loaded...");
|
||||
}
|
||||
|
||||
// for safety, initialize all banks to dummy
|
||||
for (var i = 0; i < _banks.Length; i++)
|
||||
_banks[i] = dummyBank;
|
||||
// for safety, initialize all banks to dummy
|
||||
for (var i = 0; i < _banks.Length; i++)
|
||||
_banks[i] = dummyBank;
|
||||
|
||||
// now load in the banks
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
if (newAddresses[i] == 0x8000)
|
||||
{
|
||||
_banks[newBanks[i] & _bankMask] = newData[i];
|
||||
}
|
||||
}
|
||||
// now load in the banks
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
if (newAddresses[i] == 0x8000)
|
||||
{
|
||||
_banks[newBanks[i] & _bankMask] = newData[i];
|
||||
}
|
||||
}
|
||||
|
||||
BankSet(0);
|
||||
}
|
||||
BankSet(0);
|
||||
}
|
||||
|
||||
private void BankSet(int index)
|
||||
{
|
||||
_bankNumber = index & _bankMask;
|
||||
_romEnable = (index & 0x80) == 0;
|
||||
UpdateState();
|
||||
}
|
||||
private void BankSet(int index)
|
||||
{
|
||||
_bankNumber = index & _bankMask;
|
||||
_romEnable = (index & 0x80) == 0;
|
||||
UpdateState();
|
||||
}
|
||||
|
||||
public override int Peek8000(int addr)
|
||||
{
|
||||
return _currentBank[addr];
|
||||
}
|
||||
public override int Peek8000(int addr)
|
||||
{
|
||||
return _currentBank[addr];
|
||||
}
|
||||
|
||||
public override void PokeDE00(int addr, int val)
|
||||
{
|
||||
if (addr == 0x00)
|
||||
BankSet(val);
|
||||
}
|
||||
public override void PokeDE00(int addr, int val)
|
||||
{
|
||||
if (addr == 0x00)
|
||||
BankSet(val);
|
||||
}
|
||||
|
||||
public override int Read8000(int addr)
|
||||
{
|
||||
return _currentBank[addr];
|
||||
}
|
||||
public override int Read8000(int addr)
|
||||
{
|
||||
return _currentBank[addr];
|
||||
}
|
||||
|
||||
private void UpdateState()
|
||||
{
|
||||
_currentBank = _banks[_bankNumber];
|
||||
if (_romEnable)
|
||||
{
|
||||
pinExRom = false;
|
||||
pinGame = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
pinExRom = true;
|
||||
pinGame = true;
|
||||
}
|
||||
}
|
||||
private void UpdateState()
|
||||
{
|
||||
_currentBank = _banks[_bankNumber];
|
||||
if (_romEnable)
|
||||
{
|
||||
pinExRom = false;
|
||||
pinGame = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
pinExRom = true;
|
||||
pinGame = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteDE00(int addr, int val)
|
||||
{
|
||||
if (addr == 0x00)
|
||||
BankSet(val);
|
||||
}
|
||||
public override void WriteDE00(int addr, int val)
|
||||
{
|
||||
if (addr == 0x00)
|
||||
BankSet(val);
|
||||
}
|
||||
|
||||
public override void SyncState(Serializer ser)
|
||||
{
|
||||
base.SyncState(ser);
|
||||
if (ser.IsReader)
|
||||
BankSet(_bankNumber | (_romEnable ? 0x00 : 0x80));
|
||||
}
|
||||
}
|
||||
}
|
||||
public override void SyncState(Serializer ser)
|
||||
{
|
||||
base.SyncState(ser);
|
||||
if (ser.IsReader)
|
||||
BankSet(_bankNumber | (_romEnable ? 0x00 : 0x80));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,294 +5,294 @@ using BizHawk.Common;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
|
||||
{
|
||||
// EasyFlash cartridge
|
||||
// No official games came on one of these but there
|
||||
// are a few dumps from GameBase64 that use this mapper
|
||||
// EasyFlash cartridge
|
||||
// No official games came on one of these but there
|
||||
// are a few dumps from GameBase64 that use this mapper
|
||||
|
||||
// There are 64 banks total, DE00 is bank select.
|
||||
// Selecing a bank will select both Lo and Hi ROM.
|
||||
// DE02 will switch exrom/game bits: bit 0=game,
|
||||
// bit 1=exrom, bit 2=for our cases, always set true.
|
||||
// These two registers are write only.
|
||||
// There are 64 banks total, DE00 is bank select.
|
||||
// Selecing a bank will select both Lo and Hi ROM.
|
||||
// DE02 will switch exrom/game bits: bit 0=game,
|
||||
// bit 1=exrom, bit 2=for our cases, always set true.
|
||||
// These two registers are write only.
|
||||
|
||||
// This cartridge always starts up in Ultimax mode,
|
||||
// with Game set high and ExRom set low.
|
||||
// This cartridge always starts up in Ultimax mode,
|
||||
// with Game set high and ExRom set low.
|
||||
|
||||
// There is also 256 bytes RAM at DF00-DFFF.
|
||||
// There is also 256 bytes RAM at DF00-DFFF.
|
||||
|
||||
// We emulate having the AM29F040 chip.
|
||||
// We emulate having the AM29F040 chip.
|
||||
|
||||
public abstract partial class CartridgeDevice
|
||||
{
|
||||
private sealed class Mapper0020 : CartridgeDevice
|
||||
{
|
||||
[SaveState.SaveWithName("BankOffset")]
|
||||
private int _bankOffset = 63 << 13;
|
||||
[SaveState.DoNotSave]
|
||||
private int[] _banksA = new int[64 << 13]; //8000
|
||||
[SaveState.DoNotSave]
|
||||
private int[] _banksB = new int[64 << 13]; //A000
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int[] _originalMediaA; //8000
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int[] _originalMediaB; //A000
|
||||
[SaveState.SaveWithName("BoardLed")]
|
||||
private bool _boardLed;
|
||||
[SaveState.SaveWithName("Jumper")]
|
||||
private bool _jumper = false;
|
||||
[SaveState.SaveWithName("StateBits")]
|
||||
private int _stateBits;
|
||||
[SaveState.SaveWithName("RAM")]
|
||||
private readonly int[] _ram = new int[256];
|
||||
[SaveState.SaveWithName("CommandLatch55")]
|
||||
private bool _commandLatch55;
|
||||
[SaveState.SaveWithName("CommandLatchAA")]
|
||||
private bool _commandLatchAa;
|
||||
[SaveState.SaveWithName("InternalROMState")]
|
||||
private int _internalRomState;
|
||||
public abstract partial class CartridgeDevice
|
||||
{
|
||||
private sealed class Mapper0020 : CartridgeDevice
|
||||
{
|
||||
[SaveState.SaveWithName("BankOffset")]
|
||||
private int _bankOffset = 63 << 13;
|
||||
[SaveState.DoNotSave]
|
||||
private int[] _banksA = new int[64 << 13]; //8000
|
||||
[SaveState.DoNotSave]
|
||||
private int[] _banksB = new int[64 << 13]; //A000
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int[] _originalMediaA; //8000
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int[] _originalMediaB; //A000
|
||||
[SaveState.SaveWithName("BoardLed")]
|
||||
private bool _boardLed;
|
||||
[SaveState.SaveWithName("Jumper")]
|
||||
private bool _jumper = false;
|
||||
[SaveState.SaveWithName("StateBits")]
|
||||
private int _stateBits;
|
||||
[SaveState.SaveWithName("RAM")]
|
||||
private readonly int[] _ram = new int[256];
|
||||
[SaveState.SaveWithName("CommandLatch55")]
|
||||
private bool _commandLatch55;
|
||||
[SaveState.SaveWithName("CommandLatchAA")]
|
||||
private bool _commandLatchAa;
|
||||
[SaveState.SaveWithName("InternalROMState")]
|
||||
private int _internalRomState;
|
||||
|
||||
public Mapper0020(IList<int> newAddresses, IList<int> newBanks, IList<int[]> newData)
|
||||
{
|
||||
DriveLightEnabled = true;
|
||||
var count = newAddresses.Count;
|
||||
public Mapper0020(IList<int> newAddresses, IList<int> newBanks, IList<int[]> newData)
|
||||
{
|
||||
DriveLightEnabled = true;
|
||||
var count = newAddresses.Count;
|
||||
|
||||
// force ultimax mode (the cart SHOULD set this
|
||||
// otherwise on load, according to the docs)
|
||||
pinGame = false;
|
||||
pinExRom = true;
|
||||
// force ultimax mode (the cart SHOULD set this
|
||||
// otherwise on load, according to the docs)
|
||||
pinGame = false;
|
||||
pinExRom = true;
|
||||
|
||||
// for safety, initialize all banks to dummy
|
||||
for (var i = 0; i < 64*0x2000; i++)
|
||||
{
|
||||
_banksA[i] = 0xFF;
|
||||
_banksB[i] = 0xFF;
|
||||
}
|
||||
// for safety, initialize all banks to dummy
|
||||
for (var i = 0; i < 64 * 0x2000; i++)
|
||||
{
|
||||
_banksA[i] = 0xFF;
|
||||
_banksB[i] = 0xFF;
|
||||
}
|
||||
|
||||
// load in all banks
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
switch (newAddresses[i])
|
||||
{
|
||||
case 0x8000:
|
||||
Array.Copy(newData[i], 0, _banksA, newBanks[i] * 0x2000, 0x2000);
|
||||
break;
|
||||
case 0xA000:
|
||||
case 0xE000:
|
||||
Array.Copy(newData[i], 0, _banksB, newBanks[i] * 0x2000, 0x2000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// load in all banks
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
switch (newAddresses[i])
|
||||
{
|
||||
case 0x8000:
|
||||
Array.Copy(newData[i], 0, _banksA, newBanks[i] * 0x2000, 0x2000);
|
||||
break;
|
||||
case 0xA000:
|
||||
case 0xE000:
|
||||
Array.Copy(newData[i], 0, _banksB, newBanks[i] * 0x2000, 0x2000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// default to bank 0
|
||||
BankSet(0);
|
||||
// default to bank 0
|
||||
BankSet(0);
|
||||
|
||||
// internal operation settings
|
||||
_commandLatch55 = false;
|
||||
_commandLatchAa = false;
|
||||
_internalRomState = 0;
|
||||
// internal operation settings
|
||||
_commandLatch55 = false;
|
||||
_commandLatchAa = false;
|
||||
_internalRomState = 0;
|
||||
|
||||
// back up original media
|
||||
_originalMediaA = _banksA.Select(d => d).ToArray();
|
||||
_originalMediaB = _banksB.Select(d => d).ToArray();
|
||||
}
|
||||
// back up original media
|
||||
_originalMediaA = _banksA.Select(d => d).ToArray();
|
||||
_originalMediaB = _banksB.Select(d => d).ToArray();
|
||||
}
|
||||
|
||||
private void BankSet(int index)
|
||||
{
|
||||
_bankOffset = (index & 0x3F) << 13;
|
||||
}
|
||||
private void BankSet(int index)
|
||||
{
|
||||
_bankOffset = (index & 0x3F) << 13;
|
||||
}
|
||||
|
||||
public override int Peek8000(int addr)
|
||||
{
|
||||
addr &= 0x1FFF;
|
||||
return _banksA[addr | _bankOffset];
|
||||
}
|
||||
public override int Peek8000(int addr)
|
||||
{
|
||||
addr &= 0x1FFF;
|
||||
return _banksA[addr | _bankOffset];
|
||||
}
|
||||
|
||||
public override int PeekA000(int addr)
|
||||
{
|
||||
addr &= 0x1FFF;
|
||||
return _banksB[addr | _bankOffset];
|
||||
}
|
||||
public override int PeekA000(int addr)
|
||||
{
|
||||
addr &= 0x1FFF;
|
||||
return _banksB[addr | _bankOffset];
|
||||
}
|
||||
|
||||
public override int PeekDE00(int addr)
|
||||
{
|
||||
// normally you can't read these regs
|
||||
// but Peek is provided here for debug reasons
|
||||
// and may not stay around
|
||||
addr &= 0x02;
|
||||
return addr == 0x00 ? _bankOffset >> 13 : _stateBits;
|
||||
}
|
||||
public override int PeekDE00(int addr)
|
||||
{
|
||||
// normally you can't read these regs
|
||||
// but Peek is provided here for debug reasons
|
||||
// and may not stay around
|
||||
addr &= 0x02;
|
||||
return addr == 0x00 ? _bankOffset >> 13 : _stateBits;
|
||||
}
|
||||
|
||||
public override int PeekDF00(int addr)
|
||||
{
|
||||
addr &= 0xFF;
|
||||
return _ram[addr];
|
||||
}
|
||||
public override int PeekDF00(int addr)
|
||||
{
|
||||
addr &= 0xFF;
|
||||
return _ram[addr];
|
||||
}
|
||||
|
||||
public override void PokeDE00(int addr, int val)
|
||||
{
|
||||
addr &= 0x02;
|
||||
if (addr == 0x00)
|
||||
BankSet(val);
|
||||
else
|
||||
StateSet(val);
|
||||
}
|
||||
public override void PokeDE00(int addr, int val)
|
||||
{
|
||||
addr &= 0x02;
|
||||
if (addr == 0x00)
|
||||
BankSet(val);
|
||||
else
|
||||
StateSet(val);
|
||||
}
|
||||
|
||||
public override void PokeDF00(int addr, int val)
|
||||
{
|
||||
addr &= 0xFF;
|
||||
_ram[addr] = val & 0xFF;
|
||||
}
|
||||
public override void PokeDF00(int addr, int val)
|
||||
{
|
||||
addr &= 0xFF;
|
||||
_ram[addr] = val & 0xFF;
|
||||
}
|
||||
|
||||
public override int Read8000(int addr)
|
||||
{
|
||||
return ReadInternal(addr & 0x1FFF, _banksA);
|
||||
}
|
||||
public override int Read8000(int addr)
|
||||
{
|
||||
return ReadInternal(addr & 0x1FFF, _banksA);
|
||||
}
|
||||
|
||||
public override int ReadA000(int addr)
|
||||
{
|
||||
return ReadInternal(addr & 0x1FFF, _banksB);
|
||||
}
|
||||
public override int ReadA000(int addr)
|
||||
{
|
||||
return ReadInternal(addr & 0x1FFF, _banksB);
|
||||
}
|
||||
|
||||
public override int ReadDF00(int addr)
|
||||
{
|
||||
addr &= 0xFF;
|
||||
return _ram[addr];
|
||||
}
|
||||
public override int ReadDF00(int addr)
|
||||
{
|
||||
addr &= 0xFF;
|
||||
return _ram[addr];
|
||||
}
|
||||
|
||||
private int ReadInternal(int addr, int[] bank)
|
||||
{
|
||||
switch (_internalRomState)
|
||||
{
|
||||
case 0x80:
|
||||
break;
|
||||
case 0x90:
|
||||
switch (addr & 0x1FFF)
|
||||
{
|
||||
case 0x0000:
|
||||
return 0x01;
|
||||
case 0x0001:
|
||||
return 0xA4;
|
||||
case 0x0002:
|
||||
return 0x00;
|
||||
}
|
||||
break;
|
||||
case 0xA0:
|
||||
break;
|
||||
case 0xF0:
|
||||
break;
|
||||
}
|
||||
private int ReadInternal(int addr, int[] bank)
|
||||
{
|
||||
switch (_internalRomState)
|
||||
{
|
||||
case 0x80:
|
||||
break;
|
||||
case 0x90:
|
||||
switch (addr & 0x1FFF)
|
||||
{
|
||||
case 0x0000:
|
||||
return 0x01;
|
||||
case 0x0001:
|
||||
return 0xA4;
|
||||
case 0x0002:
|
||||
return 0x00;
|
||||
}
|
||||
break;
|
||||
case 0xA0:
|
||||
break;
|
||||
case 0xF0:
|
||||
break;
|
||||
}
|
||||
|
||||
return bank[addr | _bankOffset];
|
||||
}
|
||||
return bank[addr | _bankOffset];
|
||||
}
|
||||
|
||||
private void StateSet(int val)
|
||||
{
|
||||
_stateBits = val &= 0x87;
|
||||
if ((val & 0x04) != 0)
|
||||
pinGame = (val & 0x01) == 0;
|
||||
else
|
||||
pinGame = _jumper;
|
||||
pinExRom = (val & 0x02) == 0;
|
||||
_boardLed = (val & 0x80) != 0;
|
||||
_internalRomState = 0;
|
||||
DriveLightOn = _boardLed;
|
||||
}
|
||||
private void StateSet(int val)
|
||||
{
|
||||
_stateBits = val &= 0x87;
|
||||
if ((val & 0x04) != 0)
|
||||
pinGame = (val & 0x01) == 0;
|
||||
else
|
||||
pinGame = _jumper;
|
||||
pinExRom = (val & 0x02) == 0;
|
||||
_boardLed = (val & 0x80) != 0;
|
||||
_internalRomState = 0;
|
||||
DriveLightOn = _boardLed;
|
||||
}
|
||||
|
||||
public override void Write8000(int addr, int val)
|
||||
{
|
||||
WriteInternal(addr, val);
|
||||
}
|
||||
public override void Write8000(int addr, int val)
|
||||
{
|
||||
WriteInternal(addr, val);
|
||||
}
|
||||
|
||||
public override void WriteA000(int addr, int val)
|
||||
{
|
||||
WriteInternal(addr | 0x2000, val);
|
||||
}
|
||||
public override void WriteA000(int addr, int val)
|
||||
{
|
||||
WriteInternal(addr | 0x2000, val);
|
||||
}
|
||||
|
||||
private void WriteInternal(int addr, int val)
|
||||
{
|
||||
if (pinGame || !pinExRom)
|
||||
{
|
||||
return;
|
||||
}
|
||||
private void WriteInternal(int addr, int val)
|
||||
{
|
||||
if (pinGame || !pinExRom)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (val == 0xF0) // any address, resets flash
|
||||
{
|
||||
_internalRomState = 0;
|
||||
_commandLatch55 = false;
|
||||
_commandLatchAa = false;
|
||||
}
|
||||
else if (_internalRomState != 0x00 && _internalRomState != 0xF0)
|
||||
{
|
||||
switch (_internalRomState)
|
||||
{
|
||||
case 0xA0:
|
||||
if ((addr & 0x2000) == 0)
|
||||
{
|
||||
addr &= 0x1FFF;
|
||||
_banksA[addr | _bankOffset] = val & 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
addr &= 0x1FFF;
|
||||
_banksB[addr | _bankOffset] = val & 0xFF;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (addr == 0x0555) // $8555
|
||||
{
|
||||
if (!_commandLatchAa)
|
||||
{
|
||||
if (val == 0xAA)
|
||||
{
|
||||
_commandLatch55 = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// process EZF command
|
||||
_internalRomState = val;
|
||||
}
|
||||
}
|
||||
else if (addr == 0x02AA) // $82AA
|
||||
{
|
||||
if (_commandLatch55 && val == 0x55)
|
||||
{
|
||||
_commandLatchAa = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_commandLatch55 = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_commandLatch55 = false;
|
||||
_commandLatchAa = false;
|
||||
}
|
||||
}
|
||||
if (val == 0xF0) // any address, resets flash
|
||||
{
|
||||
_internalRomState = 0;
|
||||
_commandLatch55 = false;
|
||||
_commandLatchAa = false;
|
||||
}
|
||||
else if (_internalRomState != 0x00 && _internalRomState != 0xF0)
|
||||
{
|
||||
switch (_internalRomState)
|
||||
{
|
||||
case 0xA0:
|
||||
if ((addr & 0x2000) == 0)
|
||||
{
|
||||
addr &= 0x1FFF;
|
||||
_banksA[addr | _bankOffset] = val & 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
addr &= 0x1FFF;
|
||||
_banksB[addr | _bankOffset] = val & 0xFF;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (addr == 0x0555) // $8555
|
||||
{
|
||||
if (!_commandLatchAa)
|
||||
{
|
||||
if (val == 0xAA)
|
||||
{
|
||||
_commandLatch55 = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// process EZF command
|
||||
_internalRomState = val;
|
||||
}
|
||||
}
|
||||
else if (addr == 0x02AA) // $82AA
|
||||
{
|
||||
if (_commandLatch55 && val == 0x55)
|
||||
{
|
||||
_commandLatchAa = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_commandLatch55 = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_commandLatch55 = false;
|
||||
_commandLatchAa = false;
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteDE00(int addr, int val)
|
||||
{
|
||||
addr &= 0x02;
|
||||
if (addr == 0x00)
|
||||
BankSet(val);
|
||||
else
|
||||
StateSet(val);
|
||||
}
|
||||
public override void WriteDE00(int addr, int val)
|
||||
{
|
||||
addr &= 0x02;
|
||||
if (addr == 0x00)
|
||||
BankSet(val);
|
||||
else
|
||||
StateSet(val);
|
||||
}
|
||||
|
||||
public override void WriteDF00(int addr, int val)
|
||||
{
|
||||
_ram[addr] = val & 0xFF;
|
||||
}
|
||||
public override void WriteDF00(int addr, int val)
|
||||
{
|
||||
_ram[addr] = val & 0xFF;
|
||||
}
|
||||
|
||||
public override void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncDelta("MediaStateA", ser, _originalMediaA, ref _banksA);
|
||||
SaveState.SyncDelta("MediaStateB", ser, _originalMediaB, ref _banksB);
|
||||
base.SyncState(ser);
|
||||
DriveLightOn = _boardLed;
|
||||
}
|
||||
}
|
||||
}
|
||||
public override void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncDelta("MediaStateA", ser, _originalMediaA, ref _banksA);
|
||||
SaveState.SyncDelta("MediaStateB", ser, _originalMediaB, ref _banksB);
|
||||
base.SyncState(ser);
|
||||
DriveLightOn = _boardLed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,76 +5,76 @@ using System.Text;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
|
||||
{
|
||||
// Prophet 64 cartridge. Because we can.
|
||||
// 32 banks of 8KB.
|
||||
// DFxx = status register, xxABBBBB. A=enable cart, B=bank
|
||||
// Thanks to VICE team for the info: http://vice-emu.sourceforge.net/vice_15.html
|
||||
// Prophet 64 cartridge. Because we can.
|
||||
// 32 banks of 8KB.
|
||||
// DFxx = status register, xxABBBBB. A=enable cart, B=bank
|
||||
// Thanks to VICE team for the info: http://vice-emu.sourceforge.net/vice_15.html
|
||||
|
||||
public abstract partial class CartridgeDevice
|
||||
{
|
||||
private class Mapper002B : CartridgeDevice
|
||||
{
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int[] _rom;
|
||||
[SaveState.SaveWithName("RomOffset")]
|
||||
private int _romOffset;
|
||||
[SaveState.SaveWithName("RomEnabled")]
|
||||
private bool _romEnabled;
|
||||
public abstract partial class CartridgeDevice
|
||||
{
|
||||
private class Mapper002B : CartridgeDevice
|
||||
{
|
||||
[SaveState.DoNotSave]
|
||||
private readonly int[] _rom;
|
||||
[SaveState.SaveWithName("RomOffset")]
|
||||
private int _romOffset;
|
||||
[SaveState.SaveWithName("RomEnabled")]
|
||||
private bool _romEnabled;
|
||||
|
||||
public Mapper002B(IList<int> newAddresses, IList<int> newBanks, IList<int[]> newData)
|
||||
{
|
||||
pinExRom = false;
|
||||
pinGame = true;
|
||||
_rom = new int[0x40000];
|
||||
Array.Copy(newData.First(), _rom, 0x2000);
|
||||
pinGame = true;
|
||||
for (var i = 0; i < newData.Count; i++)
|
||||
{
|
||||
if (newAddresses[i] == 0x8000)
|
||||
{
|
||||
Array.Copy(newData[i], 0, _rom, newBanks[i] * 0x2000, 0x2000);
|
||||
}
|
||||
}
|
||||
}
|
||||
public Mapper002B(IList<int> newAddresses, IList<int> newBanks, IList<int[]> newData)
|
||||
{
|
||||
pinExRom = false;
|
||||
pinGame = true;
|
||||
_rom = new int[0x40000];
|
||||
Array.Copy(newData.First(), _rom, 0x2000);
|
||||
pinGame = true;
|
||||
for (var i = 0; i < newData.Count; i++)
|
||||
{
|
||||
if (newAddresses[i] == 0x8000)
|
||||
{
|
||||
Array.Copy(newData[i], 0, _rom, newBanks[i] * 0x2000, 0x2000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void HardReset()
|
||||
{
|
||||
_romEnabled = true;
|
||||
_romOffset = 0;
|
||||
}
|
||||
public override void HardReset()
|
||||
{
|
||||
_romEnabled = true;
|
||||
_romOffset = 0;
|
||||
}
|
||||
|
||||
public override int Peek8000(int addr)
|
||||
{
|
||||
return _romOffset | (addr & 0x1FFF);
|
||||
}
|
||||
public override int Peek8000(int addr)
|
||||
{
|
||||
return _romOffset | (addr & 0x1FFF);
|
||||
}
|
||||
|
||||
public override int PeekDF00(int addr)
|
||||
{
|
||||
// For debugging only. The processor does not see this.
|
||||
return ((_romOffset >> 13) & 0x1F) | (_romEnabled ? 0x20 : 0x00);
|
||||
}
|
||||
public override int PeekDF00(int addr)
|
||||
{
|
||||
// For debugging only. The processor does not see this.
|
||||
return ((_romOffset >> 13) & 0x1F) | (_romEnabled ? 0x20 : 0x00);
|
||||
}
|
||||
|
||||
public override void PokeDF00(int addr, int val)
|
||||
{
|
||||
_romOffset = (val & 0x1F) << 13;
|
||||
_romEnabled = (val & 0x20) != 0;
|
||||
}
|
||||
public override void PokeDF00(int addr, int val)
|
||||
{
|
||||
_romOffset = (val & 0x1F) << 13;
|
||||
_romEnabled = (val & 0x20) != 0;
|
||||
}
|
||||
|
||||
public override int Read8000(int addr)
|
||||
{
|
||||
return _romOffset | (addr & 0x1FFF);
|
||||
}
|
||||
public override int Read8000(int addr)
|
||||
{
|
||||
return _romOffset | (addr & 0x1FFF);
|
||||
}
|
||||
|
||||
public override int ReadDF00(int addr)
|
||||
{
|
||||
return 0x00;
|
||||
}
|
||||
public override int ReadDF00(int addr)
|
||||
{
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
public override void WriteDF00(int addr, int val)
|
||||
{
|
||||
_romOffset = (val & 0x1F) << 13;
|
||||
_romEnabled = (val & 0x20) != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
public override void WriteDF00(int addr, int val)
|
||||
{
|
||||
_romOffset = (val & 0x1F) << 13;
|
||||
_romEnabled = (val & 0x20) != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,60 +3,60 @@ using BizHawk.Common;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cassette
|
||||
{
|
||||
public sealed class CassettePort
|
||||
{
|
||||
[SaveState.DoNotSave]
|
||||
public Func<bool> ReadDataOutput = () => true;
|
||||
[SaveState.DoNotSave]
|
||||
public Func<bool> ReadMotor = () => true;
|
||||
public sealed class CassettePort
|
||||
{
|
||||
[SaveState.DoNotSave]
|
||||
public Func<bool> ReadDataOutput = () => true;
|
||||
[SaveState.DoNotSave]
|
||||
public Func<bool> ReadMotor = () => true;
|
||||
|
||||
[SaveState.SaveWithName("Device")]
|
||||
private CassettePortDevice _device;
|
||||
[SaveState.SaveWithName("Connected")]
|
||||
private bool _connected;
|
||||
[SaveState.SaveWithName("Device")]
|
||||
private CassettePortDevice _device;
|
||||
[SaveState.SaveWithName("Connected")]
|
||||
private bool _connected;
|
||||
|
||||
public void HardReset()
|
||||
{
|
||||
if (_connected)
|
||||
{
|
||||
_device.HardReset();
|
||||
}
|
||||
}
|
||||
public void HardReset()
|
||||
{
|
||||
if (_connected)
|
||||
{
|
||||
_device.HardReset();
|
||||
}
|
||||
}
|
||||
|
||||
public void ExecutePhase()
|
||||
{
|
||||
if (_connected)
|
||||
{
|
||||
_device.ExecutePhase2();
|
||||
}
|
||||
}
|
||||
public void ExecutePhase()
|
||||
{
|
||||
if (_connected)
|
||||
{
|
||||
_device.ExecutePhase2();
|
||||
}
|
||||
}
|
||||
|
||||
public bool ReadDataInputBuffer()
|
||||
{
|
||||
return !_connected || _device.ReadDataInputBuffer();
|
||||
}
|
||||
public bool ReadDataInputBuffer()
|
||||
{
|
||||
return !_connected || _device.ReadDataInputBuffer();
|
||||
}
|
||||
|
||||
public bool ReadSenseBuffer()
|
||||
{
|
||||
return !_connected || _device.ReadSenseBuffer();
|
||||
}
|
||||
public bool ReadSenseBuffer()
|
||||
{
|
||||
return !_connected || _device.ReadSenseBuffer();
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
|
||||
public void Connect(CassettePortDevice device)
|
||||
{
|
||||
_connected = device != null;
|
||||
_device = device;
|
||||
if (_device == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
public void Connect(CassettePortDevice device)
|
||||
{
|
||||
_connected = device != null;
|
||||
_device = device;
|
||||
if (_device == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_device.ReadDataOutput = () => ReadDataOutput();
|
||||
_device.ReadMotor = () => ReadMotor();
|
||||
}
|
||||
}
|
||||
_device.ReadDataOutput = () => ReadDataOutput();
|
||||
_device.ReadMotor = () => ReadMotor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,34 +3,34 @@ using BizHawk.Common;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cassette
|
||||
{
|
||||
public abstract class CassettePortDevice
|
||||
{
|
||||
[SaveState.DoNotSave]
|
||||
public Func<bool> ReadDataOutput;
|
||||
[SaveState.DoNotSave]
|
||||
public Func<bool> ReadMotor;
|
||||
public abstract class CassettePortDevice
|
||||
{
|
||||
[SaveState.DoNotSave]
|
||||
public Func<bool> ReadDataOutput;
|
||||
[SaveState.DoNotSave]
|
||||
public Func<bool> ReadMotor;
|
||||
|
||||
public virtual void ExecutePhase2()
|
||||
{
|
||||
}
|
||||
public virtual void ExecutePhase2()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void HardReset()
|
||||
{
|
||||
}
|
||||
public virtual void HardReset()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual bool ReadDataInputBuffer()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
public virtual bool ReadDataInputBuffer()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool ReadSenseBuffer()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
public virtual bool ReadSenseBuffer()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
}
|
||||
public virtual void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,44 +3,44 @@ using BizHawk.Emulation.Cores.Computers.Commodore64.Media;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cassette
|
||||
{
|
||||
public class TapeDrive : CassettePortDevice
|
||||
{
|
||||
[SaveState.SaveWithName("Tape")]
|
||||
private Tape _tape;
|
||||
public class TapeDrive : CassettePortDevice
|
||||
{
|
||||
[SaveState.SaveWithName("Tape")]
|
||||
private Tape _tape;
|
||||
|
||||
public override void ExecutePhase2()
|
||||
{
|
||||
if (_tape != null && !ReadMotor()) _tape.ExecuteCycle();
|
||||
}
|
||||
public override void ExecutePhase2()
|
||||
{
|
||||
if (_tape != null && !ReadMotor()) _tape.ExecuteCycle();
|
||||
}
|
||||
|
||||
public override void HardReset()
|
||||
{
|
||||
if (_tape != null) _tape.Rewind();
|
||||
}
|
||||
public override void HardReset()
|
||||
{
|
||||
if (_tape != null) _tape.Rewind();
|
||||
}
|
||||
|
||||
public override bool ReadDataInputBuffer()
|
||||
{
|
||||
return _tape == null || _tape.Read();
|
||||
}
|
||||
public override bool ReadDataInputBuffer()
|
||||
{
|
||||
return _tape == null || _tape.Read();
|
||||
}
|
||||
|
||||
public override bool ReadSenseBuffer()
|
||||
{
|
||||
return _tape == null;
|
||||
}
|
||||
public override bool ReadSenseBuffer()
|
||||
{
|
||||
return _tape == null;
|
||||
}
|
||||
|
||||
public override void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
public override void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
|
||||
public void Insert(Tape tape)
|
||||
{
|
||||
_tape = tape;
|
||||
}
|
||||
public void Insert(Tape tape)
|
||||
{
|
||||
_tape = tape;
|
||||
}
|
||||
|
||||
public void RemoveMedia()
|
||||
{
|
||||
_tape = null;
|
||||
}
|
||||
}
|
||||
public void RemoveMedia()
|
||||
{
|
||||
_tape = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
|
||||
public sealed class Chip2114
|
||||
{
|
||||
private int[] _ram = new int[0x400];
|
||||
private int[] _ram = new int[0x400];
|
||||
|
||||
public Chip2114()
|
||||
{
|
||||
|
@ -15,10 +15,10 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
|
||||
public void HardReset()
|
||||
{
|
||||
for (var i = 0; i < 0x400; i++)
|
||||
{
|
||||
_ram[i] = 0x0;
|
||||
}
|
||||
for (var i = 0; i < 0x400; i++)
|
||||
{
|
||||
_ram[i] = 0x0;
|
||||
}
|
||||
}
|
||||
|
||||
public int Peek(int addr)
|
||||
|
|
|
@ -6,28 +6,28 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
// ROM chips
|
||||
public sealed class Chip23128
|
||||
{
|
||||
[SaveState.DoNotSave] private readonly int[] _rom;
|
||||
[SaveState.DoNotSave] private readonly int[] _rom;
|
||||
|
||||
public Chip23128()
|
||||
{
|
||||
_rom = new int[0x4000];
|
||||
}
|
||||
|
||||
public Chip23128(byte[] data) : this()
|
||||
public Chip23128()
|
||||
{
|
||||
Flash(data);
|
||||
}
|
||||
_rom = new int[0x4000];
|
||||
}
|
||||
|
||||
public void Flash(byte[] data)
|
||||
{
|
||||
// ensures ROM is mirrored
|
||||
for (var i = 0; i < _rom.Length; i += data.Length)
|
||||
{
|
||||
Array.Copy(data, 0, _rom, i, data.Length);
|
||||
}
|
||||
}
|
||||
public Chip23128(byte[] data) : this()
|
||||
{
|
||||
Flash(data);
|
||||
}
|
||||
|
||||
public int Peek(int addr)
|
||||
public void Flash(byte[] data)
|
||||
{
|
||||
// ensures ROM is mirrored
|
||||
for (var i = 0; i < _rom.Length; i += data.Length)
|
||||
{
|
||||
Array.Copy(data, 0, _rom, i, data.Length);
|
||||
}
|
||||
}
|
||||
|
||||
public int Peek(int addr)
|
||||
{
|
||||
return _rom[addr & 0x3FFF];
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
|
||||
public sealed class Chip4864
|
||||
{
|
||||
private int[] _ram;
|
||||
private int[] _ram;
|
||||
|
||||
public Chip4864()
|
||||
{
|
||||
|
|
|
@ -6,159 +6,159 @@ using BizHawk.Emulation.Common;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
||||
{
|
||||
public sealed partial class Chip6510 : IDebuggable
|
||||
{
|
||||
IDictionary<string, RegisterValue> IDebuggable.GetCpuFlagsAndRegisters()
|
||||
{
|
||||
return new Dictionary<string, RegisterValue>
|
||||
{
|
||||
{ "A", _cpu.A },
|
||||
{ "X", _cpu.X },
|
||||
{ "Y", _cpu.Y },
|
||||
{ "S", _cpu.S },
|
||||
{ "PC", _cpu.PC },
|
||||
{ "Flag C", _cpu.FlagC },
|
||||
{ "Flag Z", _cpu.FlagZ },
|
||||
{ "Flag I", _cpu.FlagI },
|
||||
{ "Flag D", _cpu.FlagD },
|
||||
{ "Flag B", _cpu.FlagB },
|
||||
{ "Flag V", _cpu.FlagV },
|
||||
{ "Flag N", _cpu.FlagN },
|
||||
{ "Flag T", _cpu.FlagT }
|
||||
};
|
||||
}
|
||||
public sealed partial class Chip6510 : IDebuggable
|
||||
{
|
||||
IDictionary<string, RegisterValue> IDebuggable.GetCpuFlagsAndRegisters()
|
||||
{
|
||||
return new Dictionary<string, RegisterValue>
|
||||
{
|
||||
{ "A", _cpu.A },
|
||||
{ "X", _cpu.X },
|
||||
{ "Y", _cpu.Y },
|
||||
{ "S", _cpu.S },
|
||||
{ "PC", _cpu.PC },
|
||||
{ "Flag C", _cpu.FlagC },
|
||||
{ "Flag Z", _cpu.FlagZ },
|
||||
{ "Flag I", _cpu.FlagI },
|
||||
{ "Flag D", _cpu.FlagD },
|
||||
{ "Flag B", _cpu.FlagB },
|
||||
{ "Flag V", _cpu.FlagV },
|
||||
{ "Flag N", _cpu.FlagN },
|
||||
{ "Flag T", _cpu.FlagT }
|
||||
};
|
||||
}
|
||||
|
||||
void IDebuggable.SetCpuRegister(string register, int value)
|
||||
{
|
||||
switch (register)
|
||||
{
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
case "A":
|
||||
_cpu.A = (byte)value;
|
||||
break;
|
||||
case "X":
|
||||
_cpu.X = (byte)value;
|
||||
break;
|
||||
case "Y":
|
||||
_cpu.Y = (byte)value;
|
||||
break;
|
||||
case "S":
|
||||
_cpu.S = (byte)value;
|
||||
break;
|
||||
case "PC":
|
||||
_cpu.PC = (ushort)value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
void IDebuggable.SetCpuRegister(string register, int value)
|
||||
{
|
||||
switch (register)
|
||||
{
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
case "A":
|
||||
_cpu.A = (byte)value;
|
||||
break;
|
||||
case "X":
|
||||
_cpu.X = (byte)value;
|
||||
break;
|
||||
case "Y":
|
||||
_cpu.Y = (byte)value;
|
||||
break;
|
||||
case "S":
|
||||
_cpu.S = (byte)value;
|
||||
break;
|
||||
case "PC":
|
||||
_cpu.PC = (ushort)value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool IDebuggable.CanStep(StepType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case StepType.Into:
|
||||
case StepType.Over:
|
||||
case StepType.Out:
|
||||
return DebuggerStep != null;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool IDebuggable.CanStep(StepType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case StepType.Into:
|
||||
case StepType.Over:
|
||||
case StepType.Out:
|
||||
return DebuggerStep != null;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void IDebuggable.Step(StepType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case StepType.Into:
|
||||
StepInto();
|
||||
break;
|
||||
case StepType.Out:
|
||||
StepOut();
|
||||
break;
|
||||
case StepType.Over:
|
||||
StepOver();
|
||||
break;
|
||||
}
|
||||
}
|
||||
void IDebuggable.Step(StepType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case StepType.Into:
|
||||
StepInto();
|
||||
break;
|
||||
case StepType.Out:
|
||||
StepOut();
|
||||
break;
|
||||
case StepType.Over:
|
||||
StepOver();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int IDebuggable.TotalExecutedCycles
|
||||
{
|
||||
get { return _cpu.TotalExecutedCycles; }
|
||||
}
|
||||
|
||||
private void StepInto()
|
||||
{
|
||||
while (_cpu.AtInstructionStart())
|
||||
{
|
||||
DebuggerStep();
|
||||
}
|
||||
while (!_cpu.AtInstructionStart())
|
||||
{
|
||||
DebuggerStep();
|
||||
}
|
||||
}
|
||||
private void StepInto()
|
||||
{
|
||||
while (_cpu.AtInstructionStart())
|
||||
{
|
||||
DebuggerStep();
|
||||
}
|
||||
while (!_cpu.AtInstructionStart())
|
||||
{
|
||||
DebuggerStep();
|
||||
}
|
||||
}
|
||||
|
||||
private void StepOver()
|
||||
{
|
||||
var instruction = CpuPeek(_cpu.PC);
|
||||
private void StepOver()
|
||||
{
|
||||
var instruction = CpuPeek(_cpu.PC);
|
||||
|
||||
if (instruction == Jsr)
|
||||
{
|
||||
var destination = _cpu.PC + JsrSize;
|
||||
while (_cpu.PC != destination)
|
||||
{
|
||||
StepInto();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
StepInto();
|
||||
}
|
||||
}
|
||||
if (instruction == Jsr)
|
||||
{
|
||||
var destination = _cpu.PC + JsrSize;
|
||||
while (_cpu.PC != destination)
|
||||
{
|
||||
StepInto();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
StepInto();
|
||||
}
|
||||
}
|
||||
|
||||
private void StepOut()
|
||||
{
|
||||
var instructionsBeforeBailout = 1000000;
|
||||
var instr = CpuPeek(_cpu.PC);
|
||||
_jsrCount = instr == Jsr ? 1 : 0;
|
||||
private void StepOut()
|
||||
{
|
||||
var instructionsBeforeBailout = 1000000;
|
||||
var instr = CpuPeek(_cpu.PC);
|
||||
_jsrCount = instr == Jsr ? 1 : 0;
|
||||
|
||||
while (--instructionsBeforeBailout > 0)
|
||||
{
|
||||
StepInto();
|
||||
instr = CpuPeek(_cpu.PC);
|
||||
if (instr == Jsr)
|
||||
{
|
||||
_jsrCount++;
|
||||
}
|
||||
else if ((instr == Rts || instr == Rti) && _jsrCount <= 0)
|
||||
{
|
||||
StepInto();
|
||||
_jsrCount = 0;
|
||||
break;
|
||||
}
|
||||
else if (instr == Rts || instr == Rti)
|
||||
{
|
||||
_jsrCount--;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (--instructionsBeforeBailout > 0)
|
||||
{
|
||||
StepInto();
|
||||
instr = CpuPeek(_cpu.PC);
|
||||
if (instr == Jsr)
|
||||
{
|
||||
_jsrCount++;
|
||||
}
|
||||
else if ((instr == Rts || instr == Rti) && _jsrCount <= 0)
|
||||
{
|
||||
StepInto();
|
||||
_jsrCount = 0;
|
||||
break;
|
||||
}
|
||||
else if (instr == Rts || instr == Rti)
|
||||
{
|
||||
_jsrCount--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
private int _jsrCount;
|
||||
[SaveState.DoNotSave]
|
||||
private const byte Jsr = 0x20;
|
||||
[SaveState.DoNotSave]
|
||||
private const byte Rti = 0x40;
|
||||
[SaveState.DoNotSave]
|
||||
private const byte Rts = 0x60;
|
||||
[SaveState.DoNotSave]
|
||||
private int _jsrCount;
|
||||
[SaveState.DoNotSave]
|
||||
private const byte Jsr = 0x20;
|
||||
[SaveState.DoNotSave]
|
||||
private const byte Rti = 0x40;
|
||||
[SaveState.DoNotSave]
|
||||
private const byte Rts = 0x60;
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
private const byte JsrSize = 3;
|
||||
[SaveState.DoNotSave]
|
||||
private const byte JsrSize = 3;
|
||||
|
||||
[SaveState.DoNotSave] private IMemoryCallbackSystem _memoryCallbacks = new MemoryCallbackSystem();
|
||||
[SaveState.DoNotSave] private IMemoryCallbackSystem _memoryCallbacks = new MemoryCallbackSystem();
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
IMemoryCallbackSystem IDebuggable.MemoryCallbacks { get { return _memoryCallbacks; } }
|
||||
}
|
||||
[SaveState.DoNotSave]
|
||||
IMemoryCallbackSystem IDebuggable.MemoryCallbacks { get { return _memoryCallbacks; } }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,29 +6,29 @@ using BizHawk.Emulation.Common;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
||||
{
|
||||
public sealed partial class Chip6510 : IDisassemblable
|
||||
{
|
||||
public IEnumerable<string> AvailableCpus
|
||||
{
|
||||
get { yield return "6510"; }
|
||||
}
|
||||
public sealed partial class Chip6510 : IDisassemblable
|
||||
{
|
||||
public IEnumerable<string> AvailableCpus
|
||||
{
|
||||
get { yield return "6510"; }
|
||||
}
|
||||
|
||||
public string Cpu
|
||||
{
|
||||
get { return "6510"; }
|
||||
set
|
||||
{
|
||||
}
|
||||
}
|
||||
public string Cpu
|
||||
{
|
||||
get { return "6510"; }
|
||||
set
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public string PCRegisterName
|
||||
{
|
||||
get { return "PC"; }
|
||||
}
|
||||
public string PCRegisterName
|
||||
{
|
||||
get { return "PC"; }
|
||||
}
|
||||
|
||||
public string Disassemble(MemoryDomain m, uint addr, out int length)
|
||||
{
|
||||
return Components.M6502.MOS6502X.Disassemble((ushort)addr, out length, CpuPeek);
|
||||
}
|
||||
}
|
||||
public string Disassemble(MemoryDomain m, uint addr, out int length)
|
||||
{
|
||||
return Components.M6502.MOS6502X.Disassemble((ushort)addr, out length, CpuPeek);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,10 +13,10 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
{
|
||||
// ------------------------------------
|
||||
|
||||
private MOS6502X _cpu;
|
||||
private bool _pinNmiLast;
|
||||
private LatchedPort _port;
|
||||
private bool _thisNmi;
|
||||
private MOS6502X _cpu;
|
||||
private bool _pinNmiLast;
|
||||
private LatchedPort _port;
|
||||
private bool _thisNmi;
|
||||
|
||||
public Func<int, int> PeekMemory;
|
||||
public Action<int, int> PokeMemory;
|
||||
|
@ -29,52 +29,52 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
public Action<int, int> WriteMemory;
|
||||
public Action<int, int> WriteMemoryPort;
|
||||
|
||||
public Action DebuggerStep;
|
||||
public Action DebuggerStep;
|
||||
|
||||
// ------------------------------------
|
||||
|
||||
public Chip6510()
|
||||
{
|
||||
// configure cpu r/w
|
||||
_cpu = new MOS6502X
|
||||
{
|
||||
DummyReadMemory = CpuRead,
|
||||
ReadMemory = CpuRead,
|
||||
WriteMemory = CpuWrite,
|
||||
PeekMemory = CpuPeek
|
||||
};
|
||||
// configure cpu r/w
|
||||
_cpu = new MOS6502X
|
||||
{
|
||||
DummyReadMemory = CpuRead,
|
||||
ReadMemory = CpuRead,
|
||||
WriteMemory = CpuWrite,
|
||||
PeekMemory = CpuPeek
|
||||
};
|
||||
|
||||
// perform hard reset
|
||||
// perform hard reset
|
||||
HardReset();
|
||||
}
|
||||
|
||||
public void SetOverflow()
|
||||
{
|
||||
}
|
||||
public void SetOverflow()
|
||||
{
|
||||
}
|
||||
|
||||
private byte CpuPeek(ushort addr)
|
||||
{
|
||||
return unchecked((byte)Peek(addr));
|
||||
}
|
||||
private byte CpuPeek(ushort addr)
|
||||
{
|
||||
return unchecked((byte)Peek(addr));
|
||||
}
|
||||
|
||||
private byte CpuRead(ushort addr)
|
||||
{
|
||||
return unchecked((byte) Read(addr));
|
||||
}
|
||||
private byte CpuRead(ushort addr)
|
||||
{
|
||||
return unchecked((byte)Read(addr));
|
||||
}
|
||||
|
||||
private void CpuWrite(ushort addr, byte val)
|
||||
{
|
||||
Write(addr, val);
|
||||
}
|
||||
private void CpuWrite(ushort addr, byte val)
|
||||
{
|
||||
Write(addr, val);
|
||||
}
|
||||
|
||||
public void HardReset()
|
||||
{
|
||||
_cpu.NESSoftReset();
|
||||
_port = new LatchedPort
|
||||
{
|
||||
Direction = 0x00,
|
||||
Latch = 0xFF
|
||||
};
|
||||
_port = new LatchedPort
|
||||
{
|
||||
Direction = 0x00,
|
||||
Latch = 0xFF
|
||||
};
|
||||
_pinNmiLast = true;
|
||||
}
|
||||
|
||||
|
@ -82,33 +82,33 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
|
||||
public void ExecutePhase()
|
||||
{
|
||||
_cpu.RDY = ReadRdy();
|
||||
_cpu.RDY = ReadRdy();
|
||||
|
||||
if (ReadAec())
|
||||
{
|
||||
_cpu.IRQ = !ReadIrq();
|
||||
_pinNmiLast = _thisNmi;
|
||||
_thisNmi = ReadNmi();
|
||||
_cpu.NMI |= _pinNmiLast && !_thisNmi;
|
||||
_cpu.ExecuteOne();
|
||||
}
|
||||
else
|
||||
{
|
||||
LagCycles++;
|
||||
}
|
||||
if (ReadAec())
|
||||
{
|
||||
_cpu.IRQ = !ReadIrq();
|
||||
_pinNmiLast = _thisNmi;
|
||||
_thisNmi = ReadNmi();
|
||||
_cpu.NMI |= _pinNmiLast && !_thisNmi;
|
||||
_cpu.ExecuteOne();
|
||||
}
|
||||
else
|
||||
{
|
||||
LagCycles++;
|
||||
}
|
||||
}
|
||||
|
||||
public int LagCycles;
|
||||
public int LagCycles;
|
||||
|
||||
internal bool AtInstructionStart()
|
||||
internal bool AtInstructionStart()
|
||||
{
|
||||
return _cpu.AtInstructionStart();
|
||||
}
|
||||
|
||||
// ------------------------------------
|
||||
// ------------------------------------
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public ushort Pc
|
||||
[SaveState.DoNotSave]
|
||||
public ushort Pc
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -120,78 +120,82 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
}
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public int A
|
||||
[SaveState.DoNotSave]
|
||||
public int A
|
||||
{
|
||||
get { return _cpu.A; } set { _cpu.A = unchecked((byte)value); }
|
||||
get { return _cpu.A; }
|
||||
set { _cpu.A = unchecked((byte)value); }
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public int X
|
||||
[SaveState.DoNotSave]
|
||||
public int X
|
||||
{
|
||||
get { return _cpu.X; } set { _cpu.X = unchecked((byte)value); }
|
||||
get { return _cpu.X; }
|
||||
set { _cpu.X = unchecked((byte)value); }
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public int Y
|
||||
[SaveState.DoNotSave]
|
||||
public int Y
|
||||
{
|
||||
get { return _cpu.Y; } set { _cpu.Y = unchecked((byte)value); }
|
||||
get { return _cpu.Y; }
|
||||
set { _cpu.Y = unchecked((byte)value); }
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public int S
|
||||
[SaveState.DoNotSave]
|
||||
public int S
|
||||
{
|
||||
get { return _cpu.S; } set { _cpu.S = unchecked((byte)value); }
|
||||
get { return _cpu.S; }
|
||||
set { _cpu.S = unchecked((byte)value); }
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public bool FlagC { get { return _cpu.FlagC; } }
|
||||
[SaveState.DoNotSave]
|
||||
public bool FlagZ { get { return _cpu.FlagZ; } }
|
||||
[SaveState.DoNotSave]
|
||||
public bool FlagI { get { return _cpu.FlagI; } }
|
||||
[SaveState.DoNotSave]
|
||||
public bool FlagD { get { return _cpu.FlagD; } }
|
||||
[SaveState.DoNotSave]
|
||||
public bool FlagB { get { return _cpu.FlagB; } }
|
||||
[SaveState.DoNotSave]
|
||||
public bool FlagV { get { return _cpu.FlagV; } }
|
||||
[SaveState.DoNotSave]
|
||||
public bool FlagN { get { return _cpu.FlagN; } }
|
||||
[SaveState.DoNotSave]
|
||||
public bool FlagT { get { return _cpu.FlagT; } }
|
||||
[SaveState.DoNotSave]
|
||||
public bool FlagC { get { return _cpu.FlagC; } }
|
||||
[SaveState.DoNotSave]
|
||||
public bool FlagZ { get { return _cpu.FlagZ; } }
|
||||
[SaveState.DoNotSave]
|
||||
public bool FlagI { get { return _cpu.FlagI; } }
|
||||
[SaveState.DoNotSave]
|
||||
public bool FlagD { get { return _cpu.FlagD; } }
|
||||
[SaveState.DoNotSave]
|
||||
public bool FlagB { get { return _cpu.FlagB; } }
|
||||
[SaveState.DoNotSave]
|
||||
public bool FlagV { get { return _cpu.FlagV; } }
|
||||
[SaveState.DoNotSave]
|
||||
public bool FlagN { get { return _cpu.FlagN; } }
|
||||
[SaveState.DoNotSave]
|
||||
public bool FlagT { get { return _cpu.FlagT; } }
|
||||
|
||||
public int Peek(int addr)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0x0000:
|
||||
return _port.Direction;
|
||||
case 0x0001:
|
||||
return PortData;
|
||||
default:
|
||||
return PeekMemory(addr);
|
||||
}
|
||||
switch (addr)
|
||||
{
|
||||
case 0x0000:
|
||||
return _port.Direction;
|
||||
case 0x0001:
|
||||
return PortData;
|
||||
default:
|
||||
return PeekMemory(addr);
|
||||
}
|
||||
}
|
||||
|
||||
public void Poke(int addr, int val)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0x0000:
|
||||
_port.Direction = val;
|
||||
break;
|
||||
case 0x0001:
|
||||
_port.Latch = val;
|
||||
break;
|
||||
default:
|
||||
PokeMemory(addr, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
public void Poke(int addr, int val)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0x0000:
|
||||
_port.Direction = val;
|
||||
break;
|
||||
case 0x0001:
|
||||
_port.Latch = val;
|
||||
break;
|
||||
default:
|
||||
PokeMemory(addr, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public int PortData
|
||||
[SaveState.DoNotSave]
|
||||
public int PortData
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -205,38 +209,38 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
|
||||
public int Read(int addr)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0x0000:
|
||||
return _port.Direction;
|
||||
case 0x0001:
|
||||
return PortData;
|
||||
default:
|
||||
return ReadMemory(addr);
|
||||
}
|
||||
switch (addr)
|
||||
{
|
||||
case 0x0000:
|
||||
return _port.Direction;
|
||||
case 0x0001:
|
||||
return PortData;
|
||||
default:
|
||||
return ReadMemory(addr);
|
||||
}
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
|
||||
public void Write(int addr, int val)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0x0000:
|
||||
_port.Direction = val;
|
||||
WriteMemoryPort(addr, val);
|
||||
break;
|
||||
case 0x0001:
|
||||
_port.Latch = val;
|
||||
WriteMemoryPort(addr, val);
|
||||
break;
|
||||
default:
|
||||
WriteMemory(addr, val);
|
||||
break;
|
||||
}
|
||||
switch (addr)
|
||||
{
|
||||
case 0x0000:
|
||||
_port.Direction = val;
|
||||
WriteMemoryPort(addr, val);
|
||||
break;
|
||||
case 0x0001:
|
||||
_port.Latch = val;
|
||||
WriteMemoryPort(addr, val);
|
||||
break;
|
||||
default:
|
||||
WriteMemory(addr, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,16 +5,16 @@ using System.Text;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
||||
{
|
||||
public static class Chip6522
|
||||
{
|
||||
public static Via Create(Func<int> readPrA, Func<int> readPrB)
|
||||
{
|
||||
return new Via(readPrA, readPrB);
|
||||
}
|
||||
public static class Chip6522
|
||||
{
|
||||
public static Via Create(Func<int> readPrA, Func<int> readPrB)
|
||||
{
|
||||
return new Via(readPrA, readPrB);
|
||||
}
|
||||
|
||||
public static Via Create(Func<bool> readClock, Func<bool> readData, Func<bool> readAtn, int driveNumber)
|
||||
{
|
||||
return new Via(readClock, readData, readAtn, driveNumber);
|
||||
}
|
||||
}
|
||||
public static Via Create(Func<bool> readClock, Func<bool> readData, Func<bool> readAtn, int driveNumber)
|
||||
{
|
||||
return new Via(readClock, readData, readAtn, driveNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,62 +11,62 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
|
||||
public static class Chip6526
|
||||
{
|
||||
public static Cia Create(C64.CiaType type, Func<int> readIec)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case C64.CiaType.Ntsc:
|
||||
return new Cia(14318181, 14*60, readIec)
|
||||
{
|
||||
DelayedInterrupts = true
|
||||
};
|
||||
case C64.CiaType.NtscRevA:
|
||||
return new Cia(14318181, 14 * 60, readIec)
|
||||
{
|
||||
DelayedInterrupts = false
|
||||
};
|
||||
case C64.CiaType.Pal:
|
||||
return new Cia(17734472, 18 * 50, readIec)
|
||||
{
|
||||
DelayedInterrupts = true
|
||||
};
|
||||
case C64.CiaType.PalRevA:
|
||||
return new Cia(17734472, 18 * 50, readIec)
|
||||
{
|
||||
DelayedInterrupts = false
|
||||
};
|
||||
default:
|
||||
throw new Exception("Unrecognized CIA timer type.");
|
||||
}
|
||||
}
|
||||
public static Cia Create(C64.CiaType type, Func<int> readIec)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case C64.CiaType.Ntsc:
|
||||
return new Cia(14318181, 14 * 60, readIec)
|
||||
{
|
||||
DelayedInterrupts = true
|
||||
};
|
||||
case C64.CiaType.NtscRevA:
|
||||
return new Cia(14318181, 14 * 60, readIec)
|
||||
{
|
||||
DelayedInterrupts = false
|
||||
};
|
||||
case C64.CiaType.Pal:
|
||||
return new Cia(17734472, 18 * 50, readIec)
|
||||
{
|
||||
DelayedInterrupts = true
|
||||
};
|
||||
case C64.CiaType.PalRevA:
|
||||
return new Cia(17734472, 18 * 50, readIec)
|
||||
{
|
||||
DelayedInterrupts = false
|
||||
};
|
||||
default:
|
||||
throw new Exception("Unrecognized CIA timer type.");
|
||||
}
|
||||
}
|
||||
|
||||
public static Cia Create(C64.CiaType type, Func<bool[]> keyboard, Func<bool[]> joysticks)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case C64.CiaType.Ntsc:
|
||||
return new Cia(14318181, 14 * 60, keyboard, joysticks)
|
||||
{
|
||||
DelayedInterrupts = true
|
||||
};
|
||||
case C64.CiaType.NtscRevA:
|
||||
return new Cia(14318181, 14 * 60, keyboard, joysticks)
|
||||
{
|
||||
DelayedInterrupts = false
|
||||
};
|
||||
case C64.CiaType.Pal:
|
||||
return new Cia(17734472, 18 * 50, keyboard, joysticks)
|
||||
{
|
||||
DelayedInterrupts = true
|
||||
};
|
||||
case C64.CiaType.PalRevA:
|
||||
return new Cia(17734472, 18 * 50, keyboard, joysticks)
|
||||
{
|
||||
DelayedInterrupts = false
|
||||
};
|
||||
default:
|
||||
throw new Exception("Unrecognized CIA timer type.");
|
||||
}
|
||||
}
|
||||
}
|
||||
public static Cia Create(C64.CiaType type, Func<bool[]> keyboard, Func<bool[]> joysticks)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case C64.CiaType.Ntsc:
|
||||
return new Cia(14318181, 14 * 60, keyboard, joysticks)
|
||||
{
|
||||
DelayedInterrupts = true
|
||||
};
|
||||
case C64.CiaType.NtscRevA:
|
||||
return new Cia(14318181, 14 * 60, keyboard, joysticks)
|
||||
{
|
||||
DelayedInterrupts = false
|
||||
};
|
||||
case C64.CiaType.Pal:
|
||||
return new Cia(17734472, 18 * 50, keyboard, joysticks)
|
||||
{
|
||||
DelayedInterrupts = true
|
||||
};
|
||||
case C64.CiaType.PalRevA:
|
||||
return new Cia(17734472, 18 * 50, keyboard, joysticks)
|
||||
{
|
||||
DelayedInterrupts = false
|
||||
};
|
||||
default:
|
||||
throw new Exception("Unrecognized CIA timer type.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,21 +3,21 @@
|
|||
// vic ntsc old
|
||||
public static class Chip6567R56A
|
||||
{
|
||||
private static readonly int Cycles = 64;
|
||||
private static readonly int ScanWidth = Cycles * 8;
|
||||
private static readonly int Lines = 262;
|
||||
private static readonly int Vblankstart = 0x00D % Lines;
|
||||
private static readonly int VblankEnd = 0x018 % Lines;
|
||||
private static readonly int HblankOffset = 24;
|
||||
private static readonly int HblankStart = (0x18C + HblankOffset) % ScanWidth;
|
||||
private static readonly int HblankEnd = (0x1F0 + HblankOffset) % ScanWidth;
|
||||
private static readonly int Cycles = 64;
|
||||
private static readonly int ScanWidth = Cycles * 8;
|
||||
private static readonly int Lines = 262;
|
||||
private static readonly int Vblankstart = 0x00D % Lines;
|
||||
private static readonly int VblankEnd = 0x018 % Lines;
|
||||
private static readonly int HblankOffset = 24;
|
||||
private static readonly int HblankStart = (0x18C + HblankOffset) % ScanWidth;
|
||||
private static readonly int HblankEnd = (0x1F0 + HblankOffset) % ScanWidth;
|
||||
|
||||
private static readonly int[] Timing = Vic.TimingBuilder_XRaster(0x19C, 0x200, ScanWidth, -1, -1);
|
||||
private static readonly int[] Fetch = Vic.TimingBuilder_Fetch(Timing, 0x16C);
|
||||
private static readonly int[] Ba = Vic.TimingBuilder_BA(Fetch);
|
||||
private static readonly int[] Act = Vic.TimingBuilder_Act(Timing, 0x004, 0x154, 0x164);
|
||||
private static readonly int[] Timing = Vic.TimingBuilder_XRaster(0x19C, 0x200, ScanWidth, -1, -1);
|
||||
private static readonly int[] Fetch = Vic.TimingBuilder_Fetch(Timing, 0x16C);
|
||||
private static readonly int[] Ba = Vic.TimingBuilder_BA(Fetch);
|
||||
private static readonly int[] Act = Vic.TimingBuilder_Act(Timing, 0x004, 0x154, 0x164);
|
||||
|
||||
private static readonly int[][] Pipeline = {
|
||||
private static readonly int[][] Pipeline = {
|
||||
Timing,
|
||||
Fetch,
|
||||
Ba,
|
||||
|
@ -32,8 +32,8 @@
|
|||
14318181 / 14,
|
||||
HblankStart, HblankEnd,
|
||||
Vblankstart, VblankEnd,
|
||||
borderType,
|
||||
762, 1000
|
||||
borderType,
|
||||
762, 1000
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,25 +3,25 @@
|
|||
// vic ntsc
|
||||
public static class Chip6567R8
|
||||
{
|
||||
private static readonly int Cycles = 65;
|
||||
private static readonly int ScanWidth = Cycles * 8;
|
||||
private static readonly int Lines = 263;
|
||||
private static readonly int VblankStart = 0x00D % Lines;
|
||||
private static readonly int VblankEnd = 0x018 % Lines;
|
||||
private static readonly int HblankOffset = 24;
|
||||
private static readonly int HblankStart = (0x18C + HblankOffset) % ScanWidth;
|
||||
private static readonly int HblankEnd = (0x1F0 + HblankOffset) % ScanWidth;
|
||||
private static readonly int Cycles = 65;
|
||||
private static readonly int ScanWidth = Cycles * 8;
|
||||
private static readonly int Lines = 263;
|
||||
private static readonly int VblankStart = 0x00D % Lines;
|
||||
private static readonly int VblankEnd = 0x018 % Lines;
|
||||
private static readonly int HblankOffset = 24;
|
||||
private static readonly int HblankStart = (0x18C + HblankOffset) % ScanWidth;
|
||||
private static readonly int HblankEnd = (0x1F0 + HblankOffset) % ScanWidth;
|
||||
|
||||
private static readonly int[] Timing = Vic.TimingBuilder_XRaster(0x19C, 0x200, ScanWidth, 0x184, 8);
|
||||
private static readonly int[] Fetch = Vic.TimingBuilder_Fetch(Timing, 0x174);
|
||||
private static readonly int[] Ba = Vic.TimingBuilder_BA(Fetch);
|
||||
private static readonly int[] Act = Vic.TimingBuilder_Act(Timing, 0x004, 0x154, 0x16C);
|
||||
private static readonly int[] Timing = Vic.TimingBuilder_XRaster(0x19C, 0x200, ScanWidth, 0x184, 8);
|
||||
private static readonly int[] Fetch = Vic.TimingBuilder_Fetch(Timing, 0x174);
|
||||
private static readonly int[] Ba = Vic.TimingBuilder_BA(Fetch);
|
||||
private static readonly int[] Act = Vic.TimingBuilder_Act(Timing, 0x004, 0x154, 0x16C);
|
||||
|
||||
private static readonly int[][] Pipeline = {
|
||||
private static readonly int[][] Pipeline = {
|
||||
Timing,
|
||||
Fetch,
|
||||
Ba,
|
||||
Act
|
||||
Act
|
||||
};
|
||||
|
||||
public static Vic Create(C64.BorderType borderType)
|
||||
|
@ -33,8 +33,8 @@
|
|||
HblankStart, HblankEnd,
|
||||
VblankStart, VblankEnd,
|
||||
borderType,
|
||||
6136, 8182
|
||||
);
|
||||
6136, 8182
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,21 +3,21 @@
|
|||
// vic pal
|
||||
public static class Chip6569
|
||||
{
|
||||
private static readonly int Cycles = 63;
|
||||
private static readonly int ScanWidth = Cycles * 8;
|
||||
private static readonly int Lines = 312;
|
||||
private static readonly int VblankStart = 0x120 % Lines;
|
||||
private static readonly int VblankEnd = 0x00F % Lines;
|
||||
private static readonly int HblankOffset = 24;
|
||||
private static readonly int HblankStart = (0x178 + HblankOffset) % ScanWidth;
|
||||
private static readonly int HblankEnd = (0x1F0 + HblankOffset) % ScanWidth;
|
||||
private static readonly int Cycles = 63;
|
||||
private static readonly int ScanWidth = Cycles * 8;
|
||||
private static readonly int Lines = 312;
|
||||
private static readonly int VblankStart = 0x120 % Lines;
|
||||
private static readonly int VblankEnd = 0x00F % Lines;
|
||||
private static readonly int HblankOffset = 24;
|
||||
private static readonly int HblankStart = (0x178 + HblankOffset) % ScanWidth;
|
||||
private static readonly int HblankEnd = (0x1F0 + HblankOffset) % ScanWidth;
|
||||
|
||||
private static readonly int[] Timing = Vic.TimingBuilder_XRaster(0x194, 0x1F8, ScanWidth, -1, -1);
|
||||
private static readonly int[] Fetch = Vic.TimingBuilder_Fetch(Timing, 0x164);
|
||||
private static readonly int[] Ba = Vic.TimingBuilder_BA(Fetch);
|
||||
private static readonly int[] Act = Vic.TimingBuilder_Act(Timing, 0x004, 0x14C, 0x164);
|
||||
private static readonly int[] Timing = Vic.TimingBuilder_XRaster(0x194, 0x1F8, ScanWidth, -1, -1);
|
||||
private static readonly int[] Fetch = Vic.TimingBuilder_Fetch(Timing, 0x164);
|
||||
private static readonly int[] Ba = Vic.TimingBuilder_BA(Fetch);
|
||||
private static readonly int[] Act = Vic.TimingBuilder_Act(Timing, 0x004, 0x14C, 0x164);
|
||||
|
||||
private static readonly int[][] Pipeline = {
|
||||
private static readonly int[][] Pipeline = {
|
||||
Timing,
|
||||
Fetch,
|
||||
Ba,
|
||||
|
@ -32,8 +32,8 @@
|
|||
17734472 / 18,
|
||||
HblankStart, HblankEnd,
|
||||
VblankStart, VblankEnd,
|
||||
borderType,
|
||||
7375, 7882
|
||||
borderType,
|
||||
7375, 7882
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,21 +3,21 @@
|
|||
// pal n / drean - TODO correct?
|
||||
public static class Chip6572
|
||||
{
|
||||
private static readonly int Cycles = 65;
|
||||
private static readonly int ScanWidth = Cycles * 8;
|
||||
private static readonly int Lines = 312;
|
||||
private static readonly int VblankStart = 0x12C % Lines;
|
||||
private static readonly int VblankEnd = 0x00F % Lines;
|
||||
private static readonly int HblankOffset = 24;
|
||||
private static readonly int HblankStart = (0x18C + HblankOffset) % ScanWidth;
|
||||
private static readonly int HblankEnd = (0x1F0 + HblankOffset) % ScanWidth;
|
||||
private static readonly int Cycles = 65;
|
||||
private static readonly int ScanWidth = Cycles * 8;
|
||||
private static readonly int Lines = 312;
|
||||
private static readonly int VblankStart = 0x12C % Lines;
|
||||
private static readonly int VblankEnd = 0x00F % Lines;
|
||||
private static readonly int HblankOffset = 24;
|
||||
private static readonly int HblankStart = (0x18C + HblankOffset) % ScanWidth;
|
||||
private static readonly int HblankEnd = (0x1F0 + HblankOffset) % ScanWidth;
|
||||
|
||||
private static readonly int[] Timing = Vic.TimingBuilder_XRaster(0x19C, 0x200, ScanWidth, 0x18C, 8);
|
||||
private static readonly int[] Fetch = Vic.TimingBuilder_Fetch(Timing, 0x174);
|
||||
private static readonly int[] Ba = Vic.TimingBuilder_BA(Fetch);
|
||||
private static readonly int[] Act = Vic.TimingBuilder_Act(Timing, 0x004, 0x154, 0x16C);
|
||||
private static readonly int[] Timing = Vic.TimingBuilder_XRaster(0x19C, 0x200, ScanWidth, 0x18C, 8);
|
||||
private static readonly int[] Fetch = Vic.TimingBuilder_Fetch(Timing, 0x174);
|
||||
private static readonly int[] Ba = Vic.TimingBuilder_BA(Fetch);
|
||||
private static readonly int[] Act = Vic.TimingBuilder_Act(Timing, 0x004, 0x154, 0x16C);
|
||||
|
||||
private static readonly int[][] Pipeline = {
|
||||
private static readonly int[][] Pipeline = {
|
||||
Timing,
|
||||
Fetch,
|
||||
Ba,
|
||||
|
@ -32,8 +32,8 @@
|
|||
14328225 / 14,
|
||||
HblankStart, HblankEnd,
|
||||
VblankStart, VblankEnd,
|
||||
borderType,
|
||||
908, 1000
|
||||
borderType,
|
||||
908, 1000
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -33,8 +33,8 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
public Action<int, int> PokeMemory;
|
||||
public Action<int, int> PokeSid;
|
||||
public Action<int, int> PokeVic;
|
||||
public Func<bool> ReadAec;
|
||||
public Func<bool> ReadBa;
|
||||
public Func<bool> ReadAec;
|
||||
public Func<bool> ReadBa;
|
||||
public Func<int, int> ReadBasicRom;
|
||||
public Func<int, int> ReadCartridgeLo;
|
||||
public Func<int, int> ReadCartridgeHi;
|
||||
|
@ -63,10 +63,10 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
public Action<int, int> WriteMemory;
|
||||
public Action<int, int> WriteSid;
|
||||
public Action<int, int> WriteVic;
|
||||
|
||||
|
||||
// ------------------------------------
|
||||
|
||||
private enum PlaBank
|
||||
private enum PlaBank
|
||||
{
|
||||
None,
|
||||
Ram,
|
||||
|
@ -86,94 +86,94 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
|
||||
// ------------------------------------
|
||||
|
||||
private bool _p24;
|
||||
private bool _p25;
|
||||
private bool _p26;
|
||||
private bool _p27;
|
||||
private bool _p28;
|
||||
private bool _loram;
|
||||
private bool _hiram;
|
||||
private bool _game;
|
||||
private bool _exrom;
|
||||
private bool _charen;
|
||||
private bool _a15;
|
||||
private bool _a14;
|
||||
private bool _a13;
|
||||
private bool _a12;
|
||||
private bool _p24;
|
||||
private bool _p25;
|
||||
private bool _p26;
|
||||
private bool _p27;
|
||||
private bool _p28;
|
||||
private bool _loram;
|
||||
private bool _hiram;
|
||||
private bool _game;
|
||||
private bool _exrom;
|
||||
private bool _charen;
|
||||
private bool _a15;
|
||||
private bool _a14;
|
||||
private bool _a13;
|
||||
private bool _a12;
|
||||
|
||||
private PlaBank Bank(int addr, bool read)
|
||||
{
|
||||
_loram = ReadLoRam();
|
||||
_hiram = ReadHiRam();
|
||||
_game = ReadGame();
|
||||
_loram = ReadLoRam();
|
||||
_hiram = ReadHiRam();
|
||||
_game = ReadGame();
|
||||
|
||||
_a15 = (addr & 0x08000) != 0;
|
||||
_a14 = (addr & 0x04000) != 0;
|
||||
_a13 = (addr & 0x02000) != 0;
|
||||
_a12 = (addr & 0x01000) != 0;
|
||||
_a15 = (addr & 0x08000) != 0;
|
||||
_a14 = (addr & 0x04000) != 0;
|
||||
_a13 = (addr & 0x02000) != 0;
|
||||
_a12 = (addr & 0x01000) != 0;
|
||||
|
||||
// upper memory regions 8000-FFFF
|
||||
_exrom = ReadExRom();
|
||||
if (_a15)
|
||||
{
|
||||
// io/character access
|
||||
if (_a14 && !_a13 && _a12)
|
||||
{
|
||||
// character rom, banked in at D000-DFFF
|
||||
_charen = ReadCharen();
|
||||
if (read && !_charen && (((_hiram || _loram) && _game) || (_hiram && !_exrom && !_game)))
|
||||
return PlaBank.CharRom;
|
||||
// upper memory regions 8000-FFFF
|
||||
_exrom = ReadExRom();
|
||||
if (_a15)
|
||||
{
|
||||
// io/character access
|
||||
if (_a14 && !_a13 && _a12)
|
||||
{
|
||||
// character rom, banked in at D000-DFFF
|
||||
_charen = ReadCharen();
|
||||
if (read && !_charen && (((_hiram || _loram) && _game) || (_hiram && !_exrom && !_game)))
|
||||
return PlaBank.CharRom;
|
||||
|
||||
// io block, banked in at D000-DFFF
|
||||
if ((_charen && (_hiram || _loram)) || (_exrom && !_game))
|
||||
{
|
||||
if (addr < 0xD400)
|
||||
return PlaBank.Vic;
|
||||
if (addr < 0xD800)
|
||||
return PlaBank.Sid;
|
||||
if (addr < 0xDC00)
|
||||
return PlaBank.ColorRam;
|
||||
if (addr < 0xDD00)
|
||||
return PlaBank.Cia0;
|
||||
if (addr < 0xDE00)
|
||||
return PlaBank.Cia1;
|
||||
return addr < 0xDF00
|
||||
? PlaBank.Expansion0
|
||||
: PlaBank.Expansion1;
|
||||
}
|
||||
}
|
||||
// io block, banked in at D000-DFFF
|
||||
if ((_charen && (_hiram || _loram)) || (_exrom && !_game))
|
||||
{
|
||||
if (addr < 0xD400)
|
||||
return PlaBank.Vic;
|
||||
if (addr < 0xD800)
|
||||
return PlaBank.Sid;
|
||||
if (addr < 0xDC00)
|
||||
return PlaBank.ColorRam;
|
||||
if (addr < 0xDD00)
|
||||
return PlaBank.Cia0;
|
||||
if (addr < 0xDE00)
|
||||
return PlaBank.Cia1;
|
||||
return addr < 0xDF00
|
||||
? PlaBank.Expansion0
|
||||
: PlaBank.Expansion1;
|
||||
}
|
||||
}
|
||||
|
||||
// cartridge high, banked either at A000-BFFF or E000-FFFF depending
|
||||
if (_a13 && !_game && ((_hiram && !_a14 && read && !_exrom) || (_a14 && _exrom)))
|
||||
return PlaBank.CartridgeHi;
|
||||
// cartridge high, banked either at A000-BFFF or E000-FFFF depending
|
||||
if (_a13 && !_game && ((_hiram && !_a14 && read && !_exrom) || (_a14 && _exrom)))
|
||||
return PlaBank.CartridgeHi;
|
||||
|
||||
// cartridge low, banked at 8000-9FFF
|
||||
if (!_a14 && !_a13 && ((_loram && _hiram && read && !_exrom) || (_exrom && !_game)))
|
||||
return PlaBank.CartridgeLo;
|
||||
// cartridge low, banked at 8000-9FFF
|
||||
if (!_a14 && !_a13 && ((_loram && _hiram && read && !_exrom) || (_exrom && !_game)))
|
||||
return PlaBank.CartridgeLo;
|
||||
|
||||
// kernal rom, banked at E000-FFFF
|
||||
if (_hiram && _a14 && _a13 && read && (_game || (!_exrom && !_game)))
|
||||
return PlaBank.KernalRom;
|
||||
// kernal rom, banked at E000-FFFF
|
||||
if (_hiram && _a14 && _a13 && read && (_game || (!_exrom && !_game)))
|
||||
return PlaBank.KernalRom;
|
||||
|
||||
// basic rom, banked at A000-BFFF
|
||||
if (_loram && _hiram && !_a14 && _a13 && read && _game)
|
||||
return PlaBank.BasicRom;
|
||||
}
|
||||
// basic rom, banked at A000-BFFF
|
||||
if (_loram && _hiram && !_a14 && _a13 && read && _game)
|
||||
return PlaBank.BasicRom;
|
||||
}
|
||||
|
||||
// ultimax mode ram exclusion
|
||||
if (_exrom && !_game)
|
||||
{
|
||||
_p24 = !_a15 && !_a14 && _a12; //00x1 1000-1FFF, 3000-3FFF
|
||||
_p25 = !_a15 && !_a14 && _a13; //001x 2000-3FFF
|
||||
_p26 = !_a15 && _a14; //01xx 4000-7FFF
|
||||
_p27 = _a15 && !_a14 && _a13; //101x A000-BFFF
|
||||
_p28 = _a15 && _a14 && !_a13 && !_a12; //1100 C000-CFFF
|
||||
if (_p24 || _p25 || _p26 || _p27 || _p28)
|
||||
return PlaBank.None;
|
||||
}
|
||||
// ultimax mode ram exclusion
|
||||
if (_exrom && !_game)
|
||||
{
|
||||
_p24 = !_a15 && !_a14 && _a12; //00x1 1000-1FFF, 3000-3FFF
|
||||
_p25 = !_a15 && !_a14 && _a13; //001x 2000-3FFF
|
||||
_p26 = !_a15 && _a14; //01xx 4000-7FFF
|
||||
_p27 = _a15 && !_a14 && _a13; //101x A000-BFFF
|
||||
_p28 = _a15 && _a14 && !_a13 && !_a12; //1100 C000-CFFF
|
||||
if (_p24 || _p25 || _p26 || _p27 || _p28)
|
||||
return PlaBank.None;
|
||||
}
|
||||
|
||||
return PlaBank.Ram;
|
||||
}
|
||||
return PlaBank.Ram;
|
||||
}
|
||||
|
||||
public int Peek(int addr)
|
||||
{
|
||||
|
@ -280,47 +280,47 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
return 0xFF;
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
|
||||
public int VicRead(int addr)
|
||||
{
|
||||
_game = ReadGame();
|
||||
_exrom = ReadExRom();
|
||||
_a14 = (addr & 0x04000) == 0;
|
||||
_a13 = (addr & 0x02000) != 0;
|
||||
_a12 = (addr & 0x01000) != 0;
|
||||
public int VicRead(int addr)
|
||||
{
|
||||
_game = ReadGame();
|
||||
_exrom = ReadExRom();
|
||||
_a14 = (addr & 0x04000) == 0;
|
||||
_a13 = (addr & 0x02000) != 0;
|
||||
_a12 = (addr & 0x01000) != 0;
|
||||
|
||||
// read char rom at 1000-1FFF and 9000-9FFF
|
||||
if (_a14 && !_a13 && _a12 && (_game || !_exrom))
|
||||
return ReadCharRom(addr);
|
||||
// read char rom at 1000-1FFF and 9000-9FFF
|
||||
if (_a14 && !_a13 && _a12 && (_game || !_exrom))
|
||||
return ReadCharRom(addr);
|
||||
|
||||
// read cartridge rom in ultimax mode
|
||||
if (_a13 && _a12 && _exrom && !_game)
|
||||
return ReadCartridgeHi(addr);
|
||||
// read cartridge rom in ultimax mode
|
||||
if (_a13 && _a12 && _exrom && !_game)
|
||||
return ReadCartridgeHi(addr);
|
||||
|
||||
return ReadMemory(addr);
|
||||
}
|
||||
return ReadMemory(addr);
|
||||
}
|
||||
|
||||
public void Write(int addr, int val)
|
||||
public void Write(int addr, int val)
|
||||
{
|
||||
switch (Bank(addr, false))
|
||||
{
|
||||
case PlaBank.CartridgeHi:
|
||||
WriteCartridgeHi(addr, val);
|
||||
if (ReadGame() || !ReadExRom())
|
||||
{
|
||||
WriteMemory(addr, val);
|
||||
}
|
||||
if (ReadGame() || !ReadExRom())
|
||||
{
|
||||
WriteMemory(addr, val);
|
||||
}
|
||||
break;
|
||||
case PlaBank.CartridgeLo:
|
||||
WriteCartridgeLo(addr, val);
|
||||
if (ReadGame() || !ReadExRom())
|
||||
{
|
||||
WriteMemory(addr, val);
|
||||
}
|
||||
if (ReadGame() || !ReadExRom())
|
||||
{
|
||||
WriteMemory(addr, val);
|
||||
}
|
||||
break;
|
||||
case PlaBank.Cia0:
|
||||
WriteCia0(addr, val);
|
||||
|
@ -336,9 +336,9 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
return;
|
||||
case PlaBank.Expansion1:
|
||||
WriteExpansionHi(addr, val);
|
||||
return;
|
||||
return;
|
||||
case PlaBank.Ram:
|
||||
WriteMemory(addr, val);
|
||||
WriteMemory(addr, val);
|
||||
break;
|
||||
case PlaBank.Sid:
|
||||
WriteSid(addr, val);
|
||||
|
|
|
@ -6,147 +6,147 @@ using BizHawk.Common;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
||||
{
|
||||
public sealed partial class Cia
|
||||
{
|
||||
private abstract class Port
|
||||
{
|
||||
public abstract int ReadPra(int pra, int ddra, int prb, int ddrb);
|
||||
public abstract int ReadPrb(int pra, int ddra, int prb, int ddrb);
|
||||
public sealed partial class Cia
|
||||
{
|
||||
private abstract class Port
|
||||
{
|
||||
public abstract int ReadPra(int pra, int ddra, int prb, int ddrb);
|
||||
public abstract int ReadPrb(int pra, int ddra, int prb, int ddrb);
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
}
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class DisconnectedPort : Port
|
||||
{
|
||||
public override int ReadPra(int pra, int ddra, int prb, int ddrb)
|
||||
{
|
||||
return (pra | ~ddra) & 0xFF;
|
||||
}
|
||||
private sealed class DisconnectedPort : Port
|
||||
{
|
||||
public override int ReadPra(int pra, int ddra, int prb, int ddrb)
|
||||
{
|
||||
return (pra | ~ddra) & 0xFF;
|
||||
}
|
||||
|
||||
public override int ReadPrb(int pra, int ddra, int prb, int ddrb)
|
||||
{
|
||||
return (prb | ~ddrb) & 0xFF;
|
||||
}
|
||||
}
|
||||
public override int ReadPrb(int pra, int ddra, int prb, int ddrb)
|
||||
{
|
||||
return (prb | ~ddrb) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class JoystickKeyboardPort : Port
|
||||
{
|
||||
[SaveState.DoNotSave] private int _ret;
|
||||
[SaveState.DoNotSave] private int _tst;
|
||||
[SaveState.DoNotSave] private readonly Func<bool[]> _readJoyData;
|
||||
[SaveState.DoNotSave] private readonly Func<bool[]> _readKeyData;
|
||||
private sealed class JoystickKeyboardPort : Port
|
||||
{
|
||||
[SaveState.DoNotSave] private int _ret;
|
||||
[SaveState.DoNotSave] private int _tst;
|
||||
[SaveState.DoNotSave] private readonly Func<bool[]> _readJoyData;
|
||||
[SaveState.DoNotSave] private readonly Func<bool[]> _readKeyData;
|
||||
|
||||
public JoystickKeyboardPort(Func<bool[]> readJoyData, Func<bool[]> readKeyData)
|
||||
{
|
||||
_readJoyData = readJoyData;
|
||||
_readKeyData = readKeyData;
|
||||
}
|
||||
public JoystickKeyboardPort(Func<bool[]> readJoyData, Func<bool[]> readKeyData)
|
||||
{
|
||||
_readJoyData = readJoyData;
|
||||
_readKeyData = readKeyData;
|
||||
}
|
||||
|
||||
private int GetJoystick1()
|
||||
{
|
||||
var joyData = _readJoyData();
|
||||
return 0xE0 |
|
||||
(joyData[0] ? 0x00 : 0x01) |
|
||||
(joyData[1] ? 0x00 : 0x02) |
|
||||
(joyData[2] ? 0x00 : 0x04) |
|
||||
(joyData[3] ? 0x00 : 0x08) |
|
||||
(joyData[4] ? 0x00 : 0x10);
|
||||
}
|
||||
private int GetJoystick1()
|
||||
{
|
||||
var joyData = _readJoyData();
|
||||
return 0xE0 |
|
||||
(joyData[0] ? 0x00 : 0x01) |
|
||||
(joyData[1] ? 0x00 : 0x02) |
|
||||
(joyData[2] ? 0x00 : 0x04) |
|
||||
(joyData[3] ? 0x00 : 0x08) |
|
||||
(joyData[4] ? 0x00 : 0x10);
|
||||
}
|
||||
|
||||
private int GetJoystick2()
|
||||
{
|
||||
var joyData = _readJoyData();
|
||||
return 0xE0 |
|
||||
(joyData[5] ? 0x00 : 0x01) |
|
||||
(joyData[6] ? 0x00 : 0x02) |
|
||||
(joyData[7] ? 0x00 : 0x04) |
|
||||
(joyData[8] ? 0x00 : 0x08) |
|
||||
(joyData[9] ? 0x00 : 0x10);
|
||||
}
|
||||
private int GetJoystick2()
|
||||
{
|
||||
var joyData = _readJoyData();
|
||||
return 0xE0 |
|
||||
(joyData[5] ? 0x00 : 0x01) |
|
||||
(joyData[6] ? 0x00 : 0x02) |
|
||||
(joyData[7] ? 0x00 : 0x04) |
|
||||
(joyData[8] ? 0x00 : 0x08) |
|
||||
(joyData[9] ? 0x00 : 0x10);
|
||||
}
|
||||
|
||||
private int GetKeyboardRows(int activeColumns)
|
||||
{
|
||||
var keyData = _readKeyData();
|
||||
var result = 0xFF;
|
||||
for (var r = 0; r < 8; r++)
|
||||
{
|
||||
if ((activeColumns & 0x1) == 0)
|
||||
{
|
||||
var i = r << 3;
|
||||
for (var c = 0; c < 8; c++)
|
||||
{
|
||||
if (keyData[i++])
|
||||
{
|
||||
result &= ~(1 << c);
|
||||
}
|
||||
}
|
||||
}
|
||||
activeColumns >>= 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private int GetKeyboardRows(int activeColumns)
|
||||
{
|
||||
var keyData = _readKeyData();
|
||||
var result = 0xFF;
|
||||
for (var r = 0; r < 8; r++)
|
||||
{
|
||||
if ((activeColumns & 0x1) == 0)
|
||||
{
|
||||
var i = r << 3;
|
||||
for (var c = 0; c < 8; c++)
|
||||
{
|
||||
if (keyData[i++])
|
||||
{
|
||||
result &= ~(1 << c);
|
||||
}
|
||||
}
|
||||
}
|
||||
activeColumns >>= 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private int GetKeyboardColumns(int activeRows)
|
||||
{
|
||||
var keyData = _readKeyData();
|
||||
var result = 0xFF;
|
||||
for (var c = 0; c < 8; c++)
|
||||
{
|
||||
if ((activeRows & 0x1) == 0)
|
||||
{
|
||||
var i = c;
|
||||
for (var r = 0; r < 8; r++)
|
||||
{
|
||||
if (keyData[i])
|
||||
{
|
||||
result &= ~(1 << r);
|
||||
}
|
||||
i += 0x8;
|
||||
}
|
||||
}
|
||||
activeRows >>= 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private int GetKeyboardColumns(int activeRows)
|
||||
{
|
||||
var keyData = _readKeyData();
|
||||
var result = 0xFF;
|
||||
for (var c = 0; c < 8; c++)
|
||||
{
|
||||
if ((activeRows & 0x1) == 0)
|
||||
{
|
||||
var i = c;
|
||||
for (var r = 0; r < 8; r++)
|
||||
{
|
||||
if (keyData[i])
|
||||
{
|
||||
result &= ~(1 << r);
|
||||
}
|
||||
i += 0x8;
|
||||
}
|
||||
}
|
||||
activeRows >>= 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public override int ReadPra(int pra, int ddra, int prb, int ddrb)
|
||||
{
|
||||
_ret = (pra | ~ddra) & 0xFF;
|
||||
_tst = (prb | ~ddrb) & GetJoystick1();
|
||||
_ret &= GetKeyboardColumns(_tst);
|
||||
return _ret & GetJoystick2();
|
||||
}
|
||||
public override int ReadPra(int pra, int ddra, int prb, int ddrb)
|
||||
{
|
||||
_ret = (pra | ~ddra) & 0xFF;
|
||||
_tst = (prb | ~ddrb) & GetJoystick1();
|
||||
_ret &= GetKeyboardColumns(_tst);
|
||||
return _ret & GetJoystick2();
|
||||
}
|
||||
|
||||
public override int ReadPrb(int pra, int ddra, int prb, int ddrb)
|
||||
{
|
||||
_ret = ~ddrb & 0xFF;
|
||||
_tst = (pra | ~ddra) & GetJoystick2();
|
||||
_ret &= GetKeyboardRows(_tst);
|
||||
return (_ret | (prb & ddrb)) & GetJoystick1();
|
||||
}
|
||||
}
|
||||
public override int ReadPrb(int pra, int ddra, int prb, int ddrb)
|
||||
{
|
||||
_ret = ~ddrb & 0xFF;
|
||||
_tst = (pra | ~ddra) & GetJoystick2();
|
||||
_ret &= GetKeyboardRows(_tst);
|
||||
return (_ret | (prb & ddrb)) & GetJoystick1();
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class IecPort : Port
|
||||
{
|
||||
private readonly Func<int> _readIec;
|
||||
private sealed class IecPort : Port
|
||||
{
|
||||
private readonly Func<int> _readIec;
|
||||
|
||||
public IecPort(Func<int> readIec)
|
||||
{
|
||||
_readIec = readIec;
|
||||
}
|
||||
public IecPort(Func<int> readIec)
|
||||
{
|
||||
_readIec = readIec;
|
||||
}
|
||||
|
||||
public override int ReadPra(int pra, int ddra, int prb, int ddrb)
|
||||
{
|
||||
return (pra & ddra) | (~ddra & _readIec());
|
||||
}
|
||||
public override int ReadPra(int pra, int ddra, int prb, int ddrb)
|
||||
{
|
||||
return (pra & ddra) | (~ddra & _readIec());
|
||||
}
|
||||
|
||||
public override int ReadPrb(int pra, int ddra, int prb, int ddrb)
|
||||
{
|
||||
return (prb | ~ddrb) & 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
public override int ReadPrb(int pra, int ddra, int prb, int ddrb)
|
||||
{
|
||||
return (prb | ~ddrb) & 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,296 +5,296 @@ using System.Text;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
||||
{
|
||||
public sealed partial class Cia
|
||||
{
|
||||
public int Peek(int addr)
|
||||
{
|
||||
return ReadRegister(addr & 0xF);
|
||||
}
|
||||
public sealed partial class Cia
|
||||
{
|
||||
public int Peek(int addr)
|
||||
{
|
||||
return ReadRegister(addr & 0xF);
|
||||
}
|
||||
|
||||
public bool ReadIrq()
|
||||
{
|
||||
return (_icr & 0x80) == 0;
|
||||
}
|
||||
public bool ReadIrq()
|
||||
{
|
||||
return (_icr & 0x80) == 0;
|
||||
}
|
||||
|
||||
public int ReadPortA()
|
||||
{
|
||||
return (_pra | ~_ddra) & 0xFF;
|
||||
}
|
||||
public int ReadPortA()
|
||||
{
|
||||
return (_pra | ~_ddra) & 0xFF;
|
||||
}
|
||||
|
||||
public int Read(int addr)
|
||||
{
|
||||
addr &= 0xF;
|
||||
switch (addr)
|
||||
{
|
||||
case 0x8:
|
||||
_todLatch = false;
|
||||
return _latch10Ths;
|
||||
case 0x9:
|
||||
return _latchSec;
|
||||
case 0xA:
|
||||
return _latchMin;
|
||||
case 0xB:
|
||||
_todLatch = true;
|
||||
return _latchHr;
|
||||
case 0xD:
|
||||
var icrTemp = _icr;
|
||||
_icr = 0;
|
||||
return icrTemp;
|
||||
}
|
||||
return ReadRegister(addr);
|
||||
}
|
||||
public int Read(int addr)
|
||||
{
|
||||
addr &= 0xF;
|
||||
switch (addr)
|
||||
{
|
||||
case 0x8:
|
||||
_todLatch = false;
|
||||
return _latch10Ths;
|
||||
case 0x9:
|
||||
return _latchSec;
|
||||
case 0xA:
|
||||
return _latchMin;
|
||||
case 0xB:
|
||||
_todLatch = true;
|
||||
return _latchHr;
|
||||
case 0xD:
|
||||
var icrTemp = _icr;
|
||||
_icr = 0;
|
||||
return icrTemp;
|
||||
}
|
||||
return ReadRegister(addr);
|
||||
}
|
||||
|
||||
private int ReadRegister(int addr)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0x0:
|
||||
return _port.ReadPra(_pra, _ddra, _prb, _ddrb);
|
||||
case 0x1:
|
||||
return _port.ReadPrb(_pra, _ddra, _prb, _ddrb);
|
||||
case 0x2:
|
||||
return _ddra;
|
||||
case 0x3:
|
||||
return _ddrb;
|
||||
case 0x4:
|
||||
return _ta & 0xFF;
|
||||
case 0x5:
|
||||
return (_ta >> 8) & 0xFF;
|
||||
case 0x6:
|
||||
return _tb & 0xFF;
|
||||
case 0x7:
|
||||
return (_tb >> 8) & 0xFF;
|
||||
case 0x8:
|
||||
return _tod10Ths;
|
||||
case 0x9:
|
||||
return _todSec;
|
||||
case 0xA:
|
||||
return _todMin;
|
||||
case 0xB:
|
||||
return _todHr;
|
||||
case 0xC:
|
||||
return _sdr;
|
||||
case 0xD:
|
||||
return _icr;
|
||||
case 0xE:
|
||||
return _cra;
|
||||
case 0xF:
|
||||
return _crb;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
private int ReadRegister(int addr)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0x0:
|
||||
return _port.ReadPra(_pra, _ddra, _prb, _ddrb);
|
||||
case 0x1:
|
||||
return _port.ReadPrb(_pra, _ddra, _prb, _ddrb);
|
||||
case 0x2:
|
||||
return _ddra;
|
||||
case 0x3:
|
||||
return _ddrb;
|
||||
case 0x4:
|
||||
return _ta & 0xFF;
|
||||
case 0x5:
|
||||
return (_ta >> 8) & 0xFF;
|
||||
case 0x6:
|
||||
return _tb & 0xFF;
|
||||
case 0x7:
|
||||
return (_tb >> 8) & 0xFF;
|
||||
case 0x8:
|
||||
return _tod10Ths;
|
||||
case 0x9:
|
||||
return _todSec;
|
||||
case 0xA:
|
||||
return _todMin;
|
||||
case 0xB:
|
||||
return _todHr;
|
||||
case 0xC:
|
||||
return _sdr;
|
||||
case 0xD:
|
||||
return _icr;
|
||||
case 0xE:
|
||||
return _cra;
|
||||
case 0xF:
|
||||
return _crb;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void Poke(int addr, int val)
|
||||
{
|
||||
WriteRegister(addr, val);
|
||||
}
|
||||
public void Poke(int addr, int val)
|
||||
{
|
||||
WriteRegister(addr, val);
|
||||
}
|
||||
|
||||
public void Write(int addr, int val)
|
||||
{
|
||||
addr &= 0xF;
|
||||
switch (addr)
|
||||
{
|
||||
case 0x4:
|
||||
_latcha = (_latcha & 0xFF00) | val;
|
||||
break;
|
||||
case 0x5:
|
||||
_latcha = (_latcha & 0xFF) | (val << 8);
|
||||
if ((_cra & 0x01) == 0)
|
||||
{
|
||||
_ta = _latcha;
|
||||
}
|
||||
break;
|
||||
case 0x6:
|
||||
_latchb = (_latchb & 0xFF00) | val;
|
||||
break;
|
||||
case 0x7:
|
||||
_latchb = (_latchb & 0xFF) | (val << 8);
|
||||
if ((_crb & 0x01) == 0)
|
||||
{
|
||||
_tb = _latchb;
|
||||
}
|
||||
break;
|
||||
case 0x8:
|
||||
if ((_crb & 0x80) != 0)
|
||||
{
|
||||
_alm10Ths = val & 0xF;
|
||||
}
|
||||
else
|
||||
{
|
||||
_tod10Ths = val & 0xF;
|
||||
}
|
||||
break;
|
||||
case 0x9:
|
||||
if ((_crb & 0x80) != 0)
|
||||
{
|
||||
_almSec = val & 0x7F;
|
||||
}
|
||||
else
|
||||
{
|
||||
_todSec = val & 0x7F;
|
||||
}
|
||||
break;
|
||||
case 0xA:
|
||||
if ((_crb & 0x80) != 0)
|
||||
{
|
||||
_almMin = val & 0x7F;
|
||||
}
|
||||
else
|
||||
{
|
||||
_todMin = val & 0x7F;
|
||||
}
|
||||
break;
|
||||
case 0xB:
|
||||
if ((_crb & 0x80) != 0)
|
||||
{
|
||||
_almHr = val & 0x9F;
|
||||
}
|
||||
else
|
||||
{
|
||||
_todHr = val & 0x9F;
|
||||
}
|
||||
break;
|
||||
case 0xC:
|
||||
WriteRegister(addr, val);
|
||||
TriggerInterrupt(8);
|
||||
break;
|
||||
case 0xD:
|
||||
if ((val & 0x80) != 0)
|
||||
{
|
||||
_intMask |= (val & 0x7F);
|
||||
}
|
||||
else
|
||||
{
|
||||
_intMask &= ~val;
|
||||
}
|
||||
if ((_icr & _intMask & 0x1F) != 0)
|
||||
{
|
||||
_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);
|
||||
public void Write(int addr, int val)
|
||||
{
|
||||
addr &= 0xF;
|
||||
switch (addr)
|
||||
{
|
||||
case 0x4:
|
||||
_latcha = (_latcha & 0xFF00) | val;
|
||||
break;
|
||||
case 0x5:
|
||||
_latcha = (_latcha & 0xFF) | (val << 8);
|
||||
if ((_cra & 0x01) == 0)
|
||||
{
|
||||
_ta = _latcha;
|
||||
}
|
||||
break;
|
||||
case 0x6:
|
||||
_latchb = (_latchb & 0xFF00) | val;
|
||||
break;
|
||||
case 0x7:
|
||||
_latchb = (_latchb & 0xFF) | (val << 8);
|
||||
if ((_crb & 0x01) == 0)
|
||||
{
|
||||
_tb = _latchb;
|
||||
}
|
||||
break;
|
||||
case 0x8:
|
||||
if ((_crb & 0x80) != 0)
|
||||
{
|
||||
_alm10Ths = val & 0xF;
|
||||
}
|
||||
else
|
||||
{
|
||||
_tod10Ths = val & 0xF;
|
||||
}
|
||||
break;
|
||||
case 0x9:
|
||||
if ((_crb & 0x80) != 0)
|
||||
{
|
||||
_almSec = val & 0x7F;
|
||||
}
|
||||
else
|
||||
{
|
||||
_todSec = val & 0x7F;
|
||||
}
|
||||
break;
|
||||
case 0xA:
|
||||
if ((_crb & 0x80) != 0)
|
||||
{
|
||||
_almMin = val & 0x7F;
|
||||
}
|
||||
else
|
||||
{
|
||||
_todMin = val & 0x7F;
|
||||
}
|
||||
break;
|
||||
case 0xB:
|
||||
if ((_crb & 0x80) != 0)
|
||||
{
|
||||
_almHr = val & 0x9F;
|
||||
}
|
||||
else
|
||||
{
|
||||
_todHr = val & 0x9F;
|
||||
}
|
||||
break;
|
||||
case 0xC:
|
||||
WriteRegister(addr, val);
|
||||
TriggerInterrupt(8);
|
||||
break;
|
||||
case 0xD:
|
||||
if ((val & 0x80) != 0)
|
||||
{
|
||||
_intMask |= (val & 0x7F);
|
||||
}
|
||||
else
|
||||
{
|
||||
_intMask &= ~val;
|
||||
}
|
||||
if ((_icr & _intMask & 0x1F) != 0)
|
||||
{
|
||||
_icr |= 0x80;
|
||||
}
|
||||
break;
|
||||
case 0xE:
|
||||
var oldCra = _cra;
|
||||
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;
|
||||
}
|
||||
}
|
||||
// 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);
|
||||
|
||||
private void WriteRegister(int addr, int val)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0x0:
|
||||
_pra = val;
|
||||
break;
|
||||
case 0x1:
|
||||
_prb = val;
|
||||
break;
|
||||
case 0x2:
|
||||
_ddra = val;
|
||||
break;
|
||||
case 0x3:
|
||||
_ddrb = val;
|
||||
break;
|
||||
case 0x4:
|
||||
_latcha = (_latcha & 0xFF00) | val;
|
||||
_ta = _latcha;
|
||||
break;
|
||||
case 0x5:
|
||||
_latcha = (_latcha & 0xFF) | (val << 8);
|
||||
_ta = _latcha;
|
||||
break;
|
||||
case 0x6:
|
||||
_latchb = (_latchb & 0xFF00) | val;
|
||||
_tb = _latchb;
|
||||
break;
|
||||
case 0x7:
|
||||
_latchb = (_latchb & 0xFF) | (val << 8);
|
||||
_tb = _latchb;
|
||||
break;
|
||||
case 0x8:
|
||||
_tod10Ths = val & 0xF;
|
||||
break;
|
||||
case 0x9:
|
||||
_todSec = val & 0x7F;
|
||||
break;
|
||||
case 0xA:
|
||||
_todMin = val & 0x7F;
|
||||
break;
|
||||
case 0xB:
|
||||
_todHr = val & 0x9F;
|
||||
break;
|
||||
case 0xC:
|
||||
_sdr = val;
|
||||
break;
|
||||
case 0xD:
|
||||
_intMask = val;
|
||||
break;
|
||||
case 0xE:
|
||||
_hasNewCra = true;
|
||||
_newCra = val;
|
||||
_taCntPhi2 = ((val & 0x20) == 0);
|
||||
_taCntCnt = ((val & 0x20) == 0x20);
|
||||
break;
|
||||
case 0xF:
|
||||
_hasNewCrb = true;
|
||||
_newCrb = val;
|
||||
_tbCntPhi2 = ((val & 0x60) == 0);
|
||||
_tbCntTa = ((val & 0x40) == 0x40);
|
||||
_tbCntCnt = ((val & 0x20) == 0x20);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Toggle output begins high when timer starts.
|
||||
if ((_crb & 0x05) == 0x05 && (oldCrb & 0x01) == 0)
|
||||
_prb |= 0x80;
|
||||
break;
|
||||
default:
|
||||
WriteRegister(addr, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public int DdrA
|
||||
{
|
||||
get { return _ddra; }
|
||||
}
|
||||
private void WriteRegister(int addr, int val)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0x0:
|
||||
_pra = val;
|
||||
break;
|
||||
case 0x1:
|
||||
_prb = val;
|
||||
break;
|
||||
case 0x2:
|
||||
_ddra = val;
|
||||
break;
|
||||
case 0x3:
|
||||
_ddrb = val;
|
||||
break;
|
||||
case 0x4:
|
||||
_latcha = (_latcha & 0xFF00) | val;
|
||||
_ta = _latcha;
|
||||
break;
|
||||
case 0x5:
|
||||
_latcha = (_latcha & 0xFF) | (val << 8);
|
||||
_ta = _latcha;
|
||||
break;
|
||||
case 0x6:
|
||||
_latchb = (_latchb & 0xFF00) | val;
|
||||
_tb = _latchb;
|
||||
break;
|
||||
case 0x7:
|
||||
_latchb = (_latchb & 0xFF) | (val << 8);
|
||||
_tb = _latchb;
|
||||
break;
|
||||
case 0x8:
|
||||
_tod10Ths = val & 0xF;
|
||||
break;
|
||||
case 0x9:
|
||||
_todSec = val & 0x7F;
|
||||
break;
|
||||
case 0xA:
|
||||
_todMin = val & 0x7F;
|
||||
break;
|
||||
case 0xB:
|
||||
_todHr = val & 0x9F;
|
||||
break;
|
||||
case 0xC:
|
||||
_sdr = val;
|
||||
break;
|
||||
case 0xD:
|
||||
_intMask = val;
|
||||
break;
|
||||
case 0xE:
|
||||
_hasNewCra = true;
|
||||
_newCra = val;
|
||||
_taCntPhi2 = ((val & 0x20) == 0);
|
||||
_taCntCnt = ((val & 0x20) == 0x20);
|
||||
break;
|
||||
case 0xF:
|
||||
_hasNewCrb = true;
|
||||
_newCrb = val;
|
||||
_tbCntPhi2 = ((val & 0x60) == 0);
|
||||
_tbCntTa = ((val & 0x40) == 0x40);
|
||||
_tbCntCnt = ((val & 0x20) == 0x20);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public int DdrB
|
||||
{
|
||||
get { return _ddrb; }
|
||||
}
|
||||
[SaveState.DoNotSave]
|
||||
public int DdrA
|
||||
{
|
||||
get { return _ddra; }
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public int PrA
|
||||
{
|
||||
get { return _pra; }
|
||||
}
|
||||
[SaveState.DoNotSave]
|
||||
public int DdrB
|
||||
{
|
||||
get { return _ddrb; }
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public int PrB
|
||||
{
|
||||
get { return _prb; }
|
||||
}
|
||||
[SaveState.DoNotSave]
|
||||
public int PrA
|
||||
{
|
||||
get { return _pra; }
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public int EffectivePrA
|
||||
{
|
||||
get { return _pra | ~_ddra; }
|
||||
}
|
||||
[SaveState.DoNotSave]
|
||||
public int PrB
|
||||
{
|
||||
get { return _prb; }
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public int EffectivePrB
|
||||
{
|
||||
get { return _prb | ~_ddrb; }
|
||||
}
|
||||
}
|
||||
[SaveState.DoNotSave]
|
||||
public int EffectivePrA
|
||||
{
|
||||
get { return _pra | ~_ddra; }
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public int EffectivePrB
|
||||
{
|
||||
get { return _prb | ~_ddrb; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_tod10Ths == _alm10Ths && _todSec == _almSec && _todMin == _almMin && _todHr == _almHr)
|
||||
{
|
||||
TriggerInterrupt(4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,9 +3,9 @@ using System;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
||||
{
|
||||
public sealed partial class Cia
|
||||
{
|
||||
/*
|
||||
public sealed partial class Cia
|
||||
{
|
||||
/*
|
||||
Commodore CIA 6526 core.
|
||||
|
||||
Many thanks to:
|
||||
|
@ -15,494 +15,494 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
http://frodo.cebix.net/
|
||||
*/
|
||||
|
||||
private enum TimerState
|
||||
{
|
||||
Stop = 0,
|
||||
WaitThenCount = 1,
|
||||
LoadThenStop = 2,
|
||||
LoadThenCount = 3,
|
||||
LoadThenWaitThenCount = 4,
|
||||
Count = 5,
|
||||
CountThenStop = 6
|
||||
}
|
||||
private enum TimerState
|
||||
{
|
||||
Stop = 0,
|
||||
WaitThenCount = 1,
|
||||
LoadThenStop = 2,
|
||||
LoadThenCount = 3,
|
||||
LoadThenWaitThenCount = 4,
|
||||
Count = 5,
|
||||
CountThenStop = 6
|
||||
}
|
||||
|
||||
public Func<bool> ReadFlag = () => true;
|
||||
public bool DelayedInterrupts = true;
|
||||
public Func<bool> ReadFlag = () => true;
|
||||
public bool DelayedInterrupts = true;
|
||||
|
||||
private int _pra;
|
||||
private int _prb;
|
||||
private int _ddra;
|
||||
private int _ddrb;
|
||||
private int _ta;
|
||||
private int _tb;
|
||||
private int _latcha;
|
||||
private int _latchb;
|
||||
private int _tod10Ths;
|
||||
private int _todSec;
|
||||
private int _todMin;
|
||||
private int _todHr;
|
||||
private int _latch10Ths;
|
||||
private int _latchSec;
|
||||
private int _latchMin;
|
||||
private int _latchHr;
|
||||
private int _alm10Ths;
|
||||
private int _almSec;
|
||||
private int _almMin;
|
||||
private int _almHr;
|
||||
private int _sdr;
|
||||
private int _icr;
|
||||
private int _cra;
|
||||
private int _crb;
|
||||
private int _intMask;
|
||||
private bool _todLatch;
|
||||
private bool _taCntPhi2;
|
||||
private bool _taCntCnt;
|
||||
private bool _tbCntPhi2;
|
||||
private bool _tbCntTa;
|
||||
private bool _tbCntCnt;
|
||||
private bool _taIrqNextCycle;
|
||||
private bool _taPrb6NegativeNextCycle;
|
||||
private bool _tbIrqNextCycle;
|
||||
private bool _tbPrb7NegativeNextCycle;
|
||||
private bool _hasNewCra;
|
||||
private bool _hasNewCrb;
|
||||
private TimerState _taState;
|
||||
private TimerState _tbState;
|
||||
private int _newCra;
|
||||
private int _newCrb;
|
||||
private bool _flagLatch;
|
||||
[SaveState.DoNotSave] private bool _flagInput;
|
||||
[SaveState.DoNotSave] private bool _taUnderflow;
|
||||
private int _pra;
|
||||
private int _prb;
|
||||
private int _ddra;
|
||||
private int _ddrb;
|
||||
private int _ta;
|
||||
private int _tb;
|
||||
private int _latcha;
|
||||
private int _latchb;
|
||||
private int _tod10Ths;
|
||||
private int _todSec;
|
||||
private int _todMin;
|
||||
private int _todHr;
|
||||
private int _latch10Ths;
|
||||
private int _latchSec;
|
||||
private int _latchMin;
|
||||
private int _latchHr;
|
||||
private int _alm10Ths;
|
||||
private int _almSec;
|
||||
private int _almMin;
|
||||
private int _almHr;
|
||||
private int _sdr;
|
||||
private int _icr;
|
||||
private int _cra;
|
||||
private int _crb;
|
||||
private int _intMask;
|
||||
private bool _todLatch;
|
||||
private bool _taCntPhi2;
|
||||
private bool _taCntCnt;
|
||||
private bool _tbCntPhi2;
|
||||
private bool _tbCntTa;
|
||||
private bool _tbCntCnt;
|
||||
private bool _taIrqNextCycle;
|
||||
private bool _taPrb6NegativeNextCycle;
|
||||
private bool _tbIrqNextCycle;
|
||||
private bool _tbPrb7NegativeNextCycle;
|
||||
private bool _hasNewCra;
|
||||
private bool _hasNewCrb;
|
||||
private TimerState _taState;
|
||||
private TimerState _tbState;
|
||||
private int _newCra;
|
||||
private int _newCrb;
|
||||
private bool _flagLatch;
|
||||
[SaveState.DoNotSave] private bool _flagInput;
|
||||
[SaveState.DoNotSave] private bool _taUnderflow;
|
||||
|
||||
private readonly Port _port;
|
||||
[SaveState.DoNotSave] private int _todlo;
|
||||
[SaveState.DoNotSave] private int _todhi;
|
||||
[SaveState.DoNotSave] private readonly int _todNum;
|
||||
[SaveState.DoNotSave] private readonly int _todDen;
|
||||
private int _todCounter;
|
||||
private readonly Port _port;
|
||||
[SaveState.DoNotSave] private int _todlo;
|
||||
[SaveState.DoNotSave] private int _todhi;
|
||||
[SaveState.DoNotSave] private readonly int _todNum;
|
||||
[SaveState.DoNotSave] private readonly int _todDen;
|
||||
private int _todCounter;
|
||||
|
||||
private Cia(int todNum, int todDen)
|
||||
{
|
||||
_todNum = todNum;
|
||||
_todDen = todDen;
|
||||
}
|
||||
private Cia(int todNum, int todDen)
|
||||
{
|
||||
_todNum = todNum;
|
||||
_todDen = todDen;
|
||||
}
|
||||
|
||||
public Cia(int todNum, int todDen, Func<bool[]> keyboard, Func<bool[]> joysticks) : this(todNum, todDen)
|
||||
{
|
||||
_port = new JoystickKeyboardPort(joysticks, keyboard);
|
||||
}
|
||||
public Cia(int todNum, int todDen, Func<bool[]> keyboard, Func<bool[]> joysticks) : this(todNum, todDen)
|
||||
{
|
||||
_port = new JoystickKeyboardPort(joysticks, keyboard);
|
||||
}
|
||||
|
||||
public Cia(int todNum, int todDen, Func<int> readIec) : this(todNum, todDen)
|
||||
{
|
||||
_port = new IecPort(readIec);
|
||||
}
|
||||
public Cia(int todNum, int todDen, Func<int> readIec) : this(todNum, todDen)
|
||||
{
|
||||
_port = new IecPort(readIec);
|
||||
}
|
||||
|
||||
public void HardReset()
|
||||
{
|
||||
_pra = 0;
|
||||
_prb = 0;
|
||||
_ddra = 0;
|
||||
_ddrb = 0;
|
||||
_ta = 0xFFFF;
|
||||
_tb = 0xFFFF;
|
||||
_latcha = 1;
|
||||
_latchb = 1;
|
||||
_tod10Ths = 0;
|
||||
_todSec = 0;
|
||||
_todMin = 0;
|
||||
_todHr = 0;
|
||||
_alm10Ths = 0;
|
||||
_almSec = 0;
|
||||
_almMin = 0;
|
||||
_almHr = 0;
|
||||
_sdr = 0;
|
||||
_icr = 0;
|
||||
_cra = 0;
|
||||
_crb = 0;
|
||||
_intMask = 0;
|
||||
_todLatch = false;
|
||||
_taCntPhi2 = false;
|
||||
_taCntCnt = false;
|
||||
_tbCntPhi2 = false;
|
||||
_tbCntTa = false;
|
||||
_tbCntCnt = false;
|
||||
_taIrqNextCycle = false;
|
||||
_tbIrqNextCycle = false;
|
||||
_taState = TimerState.Stop;
|
||||
_tbState = TimerState.Stop;
|
||||
}
|
||||
public void HardReset()
|
||||
{
|
||||
_pra = 0;
|
||||
_prb = 0;
|
||||
_ddra = 0;
|
||||
_ddrb = 0;
|
||||
_ta = 0xFFFF;
|
||||
_tb = 0xFFFF;
|
||||
_latcha = 1;
|
||||
_latchb = 1;
|
||||
_tod10Ths = 0;
|
||||
_todSec = 0;
|
||||
_todMin = 0;
|
||||
_todHr = 0;
|
||||
_alm10Ths = 0;
|
||||
_almSec = 0;
|
||||
_almMin = 0;
|
||||
_almHr = 0;
|
||||
_sdr = 0;
|
||||
_icr = 0;
|
||||
_cra = 0;
|
||||
_crb = 0;
|
||||
_intMask = 0;
|
||||
_todLatch = false;
|
||||
_taCntPhi2 = false;
|
||||
_taCntCnt = false;
|
||||
_tbCntPhi2 = false;
|
||||
_tbCntTa = false;
|
||||
_tbCntCnt = false;
|
||||
_taIrqNextCycle = false;
|
||||
_tbIrqNextCycle = false;
|
||||
_taState = TimerState.Stop;
|
||||
_tbState = TimerState.Stop;
|
||||
}
|
||||
|
||||
private void CheckIrqs()
|
||||
{
|
||||
if (_taIrqNextCycle)
|
||||
{
|
||||
_taIrqNextCycle = false;
|
||||
TriggerInterrupt(1);
|
||||
}
|
||||
if (_tbIrqNextCycle)
|
||||
{
|
||||
_tbIrqNextCycle = false;
|
||||
TriggerInterrupt(2);
|
||||
}
|
||||
}
|
||||
private void CheckIrqs()
|
||||
{
|
||||
if (_taIrqNextCycle)
|
||||
{
|
||||
_taIrqNextCycle = false;
|
||||
TriggerInterrupt(1);
|
||||
}
|
||||
if (_tbIrqNextCycle)
|
||||
{
|
||||
_tbIrqNextCycle = false;
|
||||
TriggerInterrupt(2);
|
||||
}
|
||||
}
|
||||
|
||||
public void ExecutePhase()
|
||||
{
|
||||
_taUnderflow = false;
|
||||
if (DelayedInterrupts)
|
||||
{
|
||||
CheckIrqs();
|
||||
}
|
||||
public void ExecutePhase()
|
||||
{
|
||||
_taUnderflow = false;
|
||||
if (DelayedInterrupts)
|
||||
{
|
||||
CheckIrqs();
|
||||
}
|
||||
|
||||
if (_taPrb6NegativeNextCycle)
|
||||
{
|
||||
_prb &= 0xBF;
|
||||
_taPrb6NegativeNextCycle = false;
|
||||
}
|
||||
if (_tbPrb7NegativeNextCycle)
|
||||
{
|
||||
_prb &= 0x7F;
|
||||
_tbPrb7NegativeNextCycle = false;
|
||||
}
|
||||
if (_taPrb6NegativeNextCycle)
|
||||
{
|
||||
_prb &= 0xBF;
|
||||
_taPrb6NegativeNextCycle = false;
|
||||
}
|
||||
if (_tbPrb7NegativeNextCycle)
|
||||
{
|
||||
_prb &= 0x7F;
|
||||
_tbPrb7NegativeNextCycle = false;
|
||||
}
|
||||
|
||||
|
||||
switch (_taState)
|
||||
{
|
||||
case TimerState.WaitThenCount:
|
||||
_taState = TimerState.Count;
|
||||
Ta_Idle();
|
||||
break;
|
||||
case TimerState.Stop:
|
||||
Ta_Idle();
|
||||
break;
|
||||
case TimerState.LoadThenStop:
|
||||
_taState = TimerState.Stop;
|
||||
_ta = _latcha;
|
||||
Ta_Idle();
|
||||
break;
|
||||
case TimerState.LoadThenCount:
|
||||
_taState = TimerState.Count;
|
||||
_ta = _latcha;
|
||||
Ta_Idle();
|
||||
break;
|
||||
case TimerState.LoadThenWaitThenCount:
|
||||
_taState = TimerState.WaitThenCount;
|
||||
if (_ta == 1)
|
||||
{
|
||||
Ta_Interrupt();
|
||||
_taUnderflow = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_ta = _latcha;
|
||||
}
|
||||
Ta_Idle();
|
||||
break;
|
||||
case TimerState.Count:
|
||||
Ta_Count();
|
||||
break;
|
||||
case TimerState.CountThenStop:
|
||||
_taState = TimerState.Stop;
|
||||
Ta_Count();
|
||||
break;
|
||||
}
|
||||
switch (_taState)
|
||||
{
|
||||
case TimerState.WaitThenCount:
|
||||
_taState = TimerState.Count;
|
||||
Ta_Idle();
|
||||
break;
|
||||
case TimerState.Stop:
|
||||
Ta_Idle();
|
||||
break;
|
||||
case TimerState.LoadThenStop:
|
||||
_taState = TimerState.Stop;
|
||||
_ta = _latcha;
|
||||
Ta_Idle();
|
||||
break;
|
||||
case TimerState.LoadThenCount:
|
||||
_taState = TimerState.Count;
|
||||
_ta = _latcha;
|
||||
Ta_Idle();
|
||||
break;
|
||||
case TimerState.LoadThenWaitThenCount:
|
||||
_taState = TimerState.WaitThenCount;
|
||||
if (_ta == 1)
|
||||
{
|
||||
Ta_Interrupt();
|
||||
_taUnderflow = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_ta = _latcha;
|
||||
}
|
||||
Ta_Idle();
|
||||
break;
|
||||
case TimerState.Count:
|
||||
Ta_Count();
|
||||
break;
|
||||
case TimerState.CountThenStop:
|
||||
_taState = TimerState.Stop;
|
||||
Ta_Count();
|
||||
break;
|
||||
}
|
||||
|
||||
switch (_tbState)
|
||||
{
|
||||
case TimerState.WaitThenCount:
|
||||
_tbState = TimerState.Count;
|
||||
Tb_Idle();
|
||||
break;
|
||||
case TimerState.Stop:
|
||||
Tb_Idle();
|
||||
break;
|
||||
case TimerState.LoadThenStop:
|
||||
_tbState = TimerState.Stop;
|
||||
_tb = _latchb;
|
||||
Tb_Idle();
|
||||
break;
|
||||
case TimerState.LoadThenCount:
|
||||
_tbState = TimerState.Count;
|
||||
_tb = _latchb;
|
||||
Tb_Idle();
|
||||
break;
|
||||
case TimerState.LoadThenWaitThenCount:
|
||||
_tbState = TimerState.WaitThenCount;
|
||||
if (_tb == 1)
|
||||
{
|
||||
Tb_Interrupt();
|
||||
}
|
||||
else
|
||||
{
|
||||
_tb = _latchb;
|
||||
}
|
||||
Tb_Idle();
|
||||
break;
|
||||
case TimerState.Count:
|
||||
Tb_Count();
|
||||
break;
|
||||
case TimerState.CountThenStop:
|
||||
_tbState = TimerState.Stop;
|
||||
Tb_Count();
|
||||
break;
|
||||
}
|
||||
switch (_tbState)
|
||||
{
|
||||
case TimerState.WaitThenCount:
|
||||
_tbState = TimerState.Count;
|
||||
Tb_Idle();
|
||||
break;
|
||||
case TimerState.Stop:
|
||||
Tb_Idle();
|
||||
break;
|
||||
case TimerState.LoadThenStop:
|
||||
_tbState = TimerState.Stop;
|
||||
_tb = _latchb;
|
||||
Tb_Idle();
|
||||
break;
|
||||
case TimerState.LoadThenCount:
|
||||
_tbState = TimerState.Count;
|
||||
_tb = _latchb;
|
||||
Tb_Idle();
|
||||
break;
|
||||
case TimerState.LoadThenWaitThenCount:
|
||||
_tbState = TimerState.WaitThenCount;
|
||||
if (_tb == 1)
|
||||
{
|
||||
Tb_Interrupt();
|
||||
}
|
||||
else
|
||||
{
|
||||
_tb = _latchb;
|
||||
}
|
||||
Tb_Idle();
|
||||
break;
|
||||
case TimerState.Count:
|
||||
Tb_Count();
|
||||
break;
|
||||
case TimerState.CountThenStop:
|
||||
_tbState = TimerState.Stop;
|
||||
Tb_Count();
|
||||
break;
|
||||
}
|
||||
|
||||
CountTod();
|
||||
CountTod();
|
||||
|
||||
if (!_todLatch)
|
||||
{
|
||||
_latch10Ths = _tod10Ths;
|
||||
_latchSec = _todSec;
|
||||
_latchMin = _todMin;
|
||||
_latchHr = _todHr;
|
||||
}
|
||||
if (!_todLatch)
|
||||
{
|
||||
_latch10Ths = _tod10Ths;
|
||||
_latchSec = _todSec;
|
||||
_latchMin = _todMin;
|
||||
_latchHr = _todHr;
|
||||
}
|
||||
|
||||
_flagInput = ReadFlag();
|
||||
if (!_flagInput && _flagLatch)
|
||||
{
|
||||
TriggerInterrupt(16);
|
||||
}
|
||||
_flagLatch = _flagInput;
|
||||
_flagInput = ReadFlag();
|
||||
if (!_flagInput && _flagLatch)
|
||||
{
|
||||
TriggerInterrupt(16);
|
||||
}
|
||||
_flagLatch = _flagInput;
|
||||
|
||||
if (!DelayedInterrupts)
|
||||
{
|
||||
CheckIrqs();
|
||||
}
|
||||
if (!DelayedInterrupts)
|
||||
{
|
||||
CheckIrqs();
|
||||
}
|
||||
|
||||
if ((_cra & 0x02) != 0)
|
||||
_ddra |= 0x40;
|
||||
if ((_crb & 0x02) != 0)
|
||||
_ddrb |= 0x80;
|
||||
}
|
||||
if ((_cra & 0x02) != 0)
|
||||
_ddra |= 0x40;
|
||||
if ((_crb & 0x02) != 0)
|
||||
_ddrb |= 0x80;
|
||||
}
|
||||
|
||||
private void Ta_Count()
|
||||
{
|
||||
if (_taCntPhi2)
|
||||
{
|
||||
if (_ta <= 0 || --_ta == 0)
|
||||
{
|
||||
if (_taState != TimerState.Stop)
|
||||
{
|
||||
Ta_Interrupt();
|
||||
}
|
||||
_taUnderflow = true;
|
||||
}
|
||||
}
|
||||
Ta_Idle();
|
||||
}
|
||||
private void Ta_Count()
|
||||
{
|
||||
if (_taCntPhi2)
|
||||
{
|
||||
if (_ta <= 0 || --_ta == 0)
|
||||
{
|
||||
if (_taState != TimerState.Stop)
|
||||
{
|
||||
Ta_Interrupt();
|
||||
}
|
||||
_taUnderflow = true;
|
||||
}
|
||||
}
|
||||
Ta_Idle();
|
||||
}
|
||||
|
||||
private void Ta_Interrupt()
|
||||
{
|
||||
_ta = _latcha;
|
||||
_taIrqNextCycle = true;
|
||||
_icr |= 1;
|
||||
private void Ta_Interrupt()
|
||||
{
|
||||
_ta = _latcha;
|
||||
_taIrqNextCycle = true;
|
||||
_icr |= 1;
|
||||
|
||||
if ((_cra & 0x08) != 0)
|
||||
{
|
||||
_cra &= 0xFE;
|
||||
_newCra &= 0xFE;
|
||||
_taState = TimerState.LoadThenStop;
|
||||
}
|
||||
else
|
||||
{
|
||||
_taState = TimerState.LoadThenCount;
|
||||
}
|
||||
if ((_cra & 0x08) != 0)
|
||||
{
|
||||
_cra &= 0xFE;
|
||||
_newCra &= 0xFE;
|
||||
_taState = TimerState.LoadThenStop;
|
||||
}
|
||||
else
|
||||
{
|
||||
_taState = TimerState.LoadThenCount;
|
||||
}
|
||||
|
||||
if ((_cra & 0x02) != 0)
|
||||
{
|
||||
if ((_cra & 0x04) != 0)
|
||||
{
|
||||
_taPrb6NegativeNextCycle = true;
|
||||
_prb |= 0x40;
|
||||
}
|
||||
else
|
||||
{
|
||||
_prb ^= 0x40;
|
||||
}
|
||||
_ddrb |= 0x40;
|
||||
}
|
||||
}
|
||||
if ((_cra & 0x02) != 0)
|
||||
{
|
||||
if ((_cra & 0x04) != 0)
|
||||
{
|
||||
_taPrb6NegativeNextCycle = true;
|
||||
_prb |= 0x40;
|
||||
}
|
||||
else
|
||||
{
|
||||
_prb ^= 0x40;
|
||||
}
|
||||
_ddrb |= 0x40;
|
||||
}
|
||||
}
|
||||
|
||||
private void Ta_Idle()
|
||||
{
|
||||
if (_hasNewCra)
|
||||
{
|
||||
switch (_taState)
|
||||
{
|
||||
case TimerState.Stop:
|
||||
case TimerState.LoadThenStop:
|
||||
if ((_newCra & 0x01) != 0)
|
||||
{
|
||||
_taState = (_newCra & 0x10) != 0
|
||||
? TimerState.LoadThenWaitThenCount
|
||||
: TimerState.WaitThenCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((_newCra & 0x10) != 0)
|
||||
{
|
||||
_taState = TimerState.LoadThenStop;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TimerState.Count:
|
||||
if ((_newCra & 0x01) != 0)
|
||||
{
|
||||
if ((_newCra & 0x10) != 0)
|
||||
{
|
||||
_taState = TimerState.LoadThenWaitThenCount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_taState = (_newCra & 0x10) != 0
|
||||
? TimerState.LoadThenStop
|
||||
: TimerState.CountThenStop;
|
||||
}
|
||||
break;
|
||||
case TimerState.LoadThenCount:
|
||||
case TimerState.WaitThenCount:
|
||||
if ((_newCra & 0x01) != 0)
|
||||
{
|
||||
if ((_newCra & 0x08) != 0)
|
||||
{
|
||||
_newCra &= 0xFE;
|
||||
_taState = TimerState.Stop;
|
||||
}
|
||||
else if ((_newCra & 0x10) != 0)
|
||||
{
|
||||
_taState = TimerState.LoadThenWaitThenCount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_taState = TimerState.Stop;
|
||||
}
|
||||
break;
|
||||
}
|
||||
_cra = _newCra & 0xEF;
|
||||
_hasNewCra = false;
|
||||
}
|
||||
}
|
||||
private void Ta_Idle()
|
||||
{
|
||||
if (_hasNewCra)
|
||||
{
|
||||
switch (_taState)
|
||||
{
|
||||
case TimerState.Stop:
|
||||
case TimerState.LoadThenStop:
|
||||
if ((_newCra & 0x01) != 0)
|
||||
{
|
||||
_taState = (_newCra & 0x10) != 0
|
||||
? TimerState.LoadThenWaitThenCount
|
||||
: TimerState.WaitThenCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((_newCra & 0x10) != 0)
|
||||
{
|
||||
_taState = TimerState.LoadThenStop;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TimerState.Count:
|
||||
if ((_newCra & 0x01) != 0)
|
||||
{
|
||||
if ((_newCra & 0x10) != 0)
|
||||
{
|
||||
_taState = TimerState.LoadThenWaitThenCount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_taState = (_newCra & 0x10) != 0
|
||||
? TimerState.LoadThenStop
|
||||
: TimerState.CountThenStop;
|
||||
}
|
||||
break;
|
||||
case TimerState.LoadThenCount:
|
||||
case TimerState.WaitThenCount:
|
||||
if ((_newCra & 0x01) != 0)
|
||||
{
|
||||
if ((_newCra & 0x08) != 0)
|
||||
{
|
||||
_newCra &= 0xFE;
|
||||
_taState = TimerState.Stop;
|
||||
}
|
||||
else if ((_newCra & 0x10) != 0)
|
||||
{
|
||||
_taState = TimerState.LoadThenWaitThenCount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_taState = TimerState.Stop;
|
||||
}
|
||||
break;
|
||||
}
|
||||
_cra = _newCra & 0xEF;
|
||||
_hasNewCra = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void Tb_Count()
|
||||
{
|
||||
if (_tbCntPhi2 || (_tbCntTa && _taUnderflow))
|
||||
{
|
||||
if (_tb <= 0 || --_tb == 0)
|
||||
{
|
||||
if (_tbState != TimerState.Stop)
|
||||
{
|
||||
Tb_Interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
Tb_Idle();
|
||||
}
|
||||
private void Tb_Count()
|
||||
{
|
||||
if (_tbCntPhi2 || (_tbCntTa && _taUnderflow))
|
||||
{
|
||||
if (_tb <= 0 || --_tb == 0)
|
||||
{
|
||||
if (_tbState != TimerState.Stop)
|
||||
{
|
||||
Tb_Interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
Tb_Idle();
|
||||
}
|
||||
|
||||
private void Tb_Interrupt()
|
||||
{
|
||||
_tb = _latchb;
|
||||
_tbIrqNextCycle = true;
|
||||
_icr |= 2;
|
||||
private void Tb_Interrupt()
|
||||
{
|
||||
_tb = _latchb;
|
||||
_tbIrqNextCycle = true;
|
||||
_icr |= 2;
|
||||
|
||||
if ((_crb & 0x08) != 0)
|
||||
{
|
||||
_crb &= 0xFE;
|
||||
_newCrb &= 0xFE;
|
||||
_tbState = TimerState.LoadThenStop;
|
||||
}
|
||||
else
|
||||
{
|
||||
_tbState = TimerState.LoadThenCount;
|
||||
}
|
||||
if ((_crb & 0x08) != 0)
|
||||
{
|
||||
_crb &= 0xFE;
|
||||
_newCrb &= 0xFE;
|
||||
_tbState = TimerState.LoadThenStop;
|
||||
}
|
||||
else
|
||||
{
|
||||
_tbState = TimerState.LoadThenCount;
|
||||
}
|
||||
|
||||
if ((_crb & 0x02) != 0)
|
||||
{
|
||||
if ((_crb & 0x04) != 0)
|
||||
{
|
||||
_tbPrb7NegativeNextCycle = true;
|
||||
_prb |= 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
_prb ^= 0x80;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((_crb & 0x02) != 0)
|
||||
{
|
||||
if ((_crb & 0x04) != 0)
|
||||
{
|
||||
_tbPrb7NegativeNextCycle = true;
|
||||
_prb |= 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
_prb ^= 0x80;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Tb_Idle()
|
||||
{
|
||||
if (_hasNewCrb)
|
||||
{
|
||||
switch (_tbState)
|
||||
{
|
||||
case TimerState.Stop:
|
||||
case TimerState.LoadThenStop:
|
||||
if ((_newCrb & 0x01) != 0)
|
||||
{
|
||||
_tbState = (_newCrb & 0x10) != 0
|
||||
? TimerState.LoadThenWaitThenCount
|
||||
: TimerState.WaitThenCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((_newCrb & 0x10) != 0)
|
||||
{
|
||||
_tbState = TimerState.LoadThenStop;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TimerState.Count:
|
||||
if ((_newCrb & 0x01) != 0)
|
||||
{
|
||||
if ((_newCrb & 0x10) != 0)
|
||||
{
|
||||
_tbState = TimerState.LoadThenWaitThenCount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_tbState = (_newCrb & 0x10) != 0
|
||||
? TimerState.LoadThenStop
|
||||
: TimerState.CountThenStop;
|
||||
}
|
||||
break;
|
||||
case TimerState.LoadThenCount:
|
||||
case TimerState.WaitThenCount:
|
||||
if ((_newCrb & 0x01) != 0)
|
||||
{
|
||||
if ((_newCrb & 0x08) != 0)
|
||||
{
|
||||
_newCrb &= 0xFE;
|
||||
_tbState = TimerState.Stop;
|
||||
}
|
||||
else if ((_newCrb & 0x10) != 0)
|
||||
{
|
||||
_tbState = TimerState.LoadThenWaitThenCount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_tbState = TimerState.Stop;
|
||||
}
|
||||
break;
|
||||
}
|
||||
_crb = _newCrb & 0xEF;
|
||||
_hasNewCrb = false;
|
||||
}
|
||||
}
|
||||
private void Tb_Idle()
|
||||
{
|
||||
if (_hasNewCrb)
|
||||
{
|
||||
switch (_tbState)
|
||||
{
|
||||
case TimerState.Stop:
|
||||
case TimerState.LoadThenStop:
|
||||
if ((_newCrb & 0x01) != 0)
|
||||
{
|
||||
_tbState = (_newCrb & 0x10) != 0
|
||||
? TimerState.LoadThenWaitThenCount
|
||||
: TimerState.WaitThenCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((_newCrb & 0x10) != 0)
|
||||
{
|
||||
_tbState = TimerState.LoadThenStop;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TimerState.Count:
|
||||
if ((_newCrb & 0x01) != 0)
|
||||
{
|
||||
if ((_newCrb & 0x10) != 0)
|
||||
{
|
||||
_tbState = TimerState.LoadThenWaitThenCount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_tbState = (_newCrb & 0x10) != 0
|
||||
? TimerState.LoadThenStop
|
||||
: TimerState.CountThenStop;
|
||||
}
|
||||
break;
|
||||
case TimerState.LoadThenCount:
|
||||
case TimerState.WaitThenCount:
|
||||
if ((_newCrb & 0x01) != 0)
|
||||
{
|
||||
if ((_newCrb & 0x08) != 0)
|
||||
{
|
||||
_newCrb &= 0xFE;
|
||||
_tbState = TimerState.Stop;
|
||||
}
|
||||
else if ((_newCrb & 0x10) != 0)
|
||||
{
|
||||
_tbState = TimerState.LoadThenWaitThenCount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_tbState = TimerState.Stop;
|
||||
}
|
||||
break;
|
||||
}
|
||||
_crb = _newCrb & 0xEF;
|
||||
_hasNewCrb = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void TriggerInterrupt(int bit)
|
||||
{
|
||||
_icr |= bit;
|
||||
if ((_intMask & bit) == 0) return;
|
||||
_icr |= 0x80;
|
||||
}
|
||||
private void TriggerInterrupt(int bit)
|
||||
{
|
||||
_icr |= bit;
|
||||
if ((_intMask & bit) == 0) return;
|
||||
_icr |= 0x80;
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
}
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,42 +9,42 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
{
|
||||
public sealed partial class Sid
|
||||
{
|
||||
private sealed class Envelope
|
||||
private sealed class Envelope
|
||||
{
|
||||
[SaveState.DoNotSave] private const int StateAttack = 0;
|
||||
[SaveState.DoNotSave] private const int StateDecay = 1;
|
||||
[SaveState.DoNotSave] private const int StateRelease = 2;
|
||||
[SaveState.DoNotSave] private const int StateAttack = 0;
|
||||
[SaveState.DoNotSave] private const int StateDecay = 1;
|
||||
[SaveState.DoNotSave] private const int StateRelease = 2;
|
||||
|
||||
private int _attack;
|
||||
private int _decay;
|
||||
private bool _delay;
|
||||
private int _envCounter;
|
||||
private int _expCounter;
|
||||
private int _expPeriod;
|
||||
private bool _freeze;
|
||||
private int _lfsr;
|
||||
private bool _gate;
|
||||
private int _rate;
|
||||
private int _release;
|
||||
private int _state;
|
||||
private int _sustain;
|
||||
private int _attack;
|
||||
private int _decay;
|
||||
private bool _delay;
|
||||
private int _envCounter;
|
||||
private int _expCounter;
|
||||
private int _expPeriod;
|
||||
private bool _freeze;
|
||||
private int _lfsr;
|
||||
private bool _gate;
|
||||
private int _rate;
|
||||
private int _release;
|
||||
private int _state;
|
||||
private int _sustain;
|
||||
|
||||
private static readonly int[] AdsrTable = {
|
||||
private static readonly int[] AdsrTable = {
|
||||
0x7F00, 0x0006, 0x003C, 0x0330,
|
||||
0x20C0, 0x6755, 0x3800, 0x500E,
|
||||
0x1212, 0x0222, 0x1848, 0x59B8,
|
||||
0x3840, 0x77E2, 0x7625, 0x0A93
|
||||
};
|
||||
|
||||
private static readonly int[] ExpCounterTable = {
|
||||
private static readonly int[] ExpCounterTable = {
|
||||
0xFF, 0x5D, 0x36, 0x1A, 0x0E, 0x06, 0x00
|
||||
};
|
||||
|
||||
private static readonly int[] ExpPeriodTable = {
|
||||
private static readonly int[] ExpPeriodTable = {
|
||||
0x01, 0x02, 0x04, 0x08, 0x10, 0x1E, 0x01
|
||||
};
|
||||
|
||||
private static readonly int[] SustainTable = {
|
||||
private static readonly int[] SustainTable = {
|
||||
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
|
||||
};
|
||||
|
@ -73,43 +73,43 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
|
||||
if (_state != StateAttack && ++_expCounter != _expPeriod)
|
||||
{
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
_expCounter = 0;
|
||||
if (_freeze)
|
||||
return;
|
||||
return;
|
||||
|
||||
switch (_state)
|
||||
{
|
||||
case StateAttack:
|
||||
_envCounter++;
|
||||
if (_envCounter == 0xFF)
|
||||
{
|
||||
_state = StateDecay;
|
||||
_rate = AdsrTable[_decay];
|
||||
}
|
||||
break;
|
||||
case StateDecay:
|
||||
if (_envCounter == SustainTable[_sustain])
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_expPeriod != 1)
|
||||
{
|
||||
_delay = false;
|
||||
return;
|
||||
}
|
||||
_envCounter--;
|
||||
break;
|
||||
case StateRelease:
|
||||
if (_expPeriod != 1)
|
||||
{
|
||||
_delay = false;
|
||||
return;
|
||||
}
|
||||
_envCounter--;
|
||||
break;
|
||||
case StateAttack:
|
||||
_envCounter++;
|
||||
if (_envCounter == 0xFF)
|
||||
{
|
||||
_state = StateDecay;
|
||||
_rate = AdsrTable[_decay];
|
||||
}
|
||||
break;
|
||||
case StateDecay:
|
||||
if (_envCounter == SustainTable[_sustain])
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_expPeriod != 1)
|
||||
{
|
||||
_delay = false;
|
||||
return;
|
||||
}
|
||||
_envCounter--;
|
||||
break;
|
||||
case StateRelease:
|
||||
if (_expPeriod != 1)
|
||||
{
|
||||
_delay = false;
|
||||
return;
|
||||
}
|
||||
_envCounter--;
|
||||
break;
|
||||
}
|
||||
_envCounter &= 0xFF;
|
||||
UpdateExpCounter();
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
public int Read(int addr)
|
||||
{
|
||||
addr &= 0x1F;
|
||||
var result = 0x00;
|
||||
var result = 0x00;
|
||||
switch (addr)
|
||||
{
|
||||
case 0x19:
|
||||
|
@ -36,7 +36,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
|
||||
private int ReadRegister(int addr)
|
||||
{
|
||||
var result = 0x00;
|
||||
var result = 0x00;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
|
@ -46,18 +46,18 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
case 0x03: result = _voice0.PulseWidthHi; break;
|
||||
case 0x04:
|
||||
result = (_envelope0.Gate ? 0x01 : 0x00) |
|
||||
(_voice0.Sync ? 0x02 : 0x00) |
|
||||
(_voice0.RingMod ? 0x04 : 0x00) |
|
||||
(_voice0.Test ? 0x08 : 0x00) |
|
||||
(_voice0.Waveform << 4);
|
||||
(_voice0.Sync ? 0x02 : 0x00) |
|
||||
(_voice0.RingMod ? 0x04 : 0x00) |
|
||||
(_voice0.Test ? 0x08 : 0x00) |
|
||||
(_voice0.Waveform << 4);
|
||||
break;
|
||||
case 0x05:
|
||||
result = (_envelope0.Attack << 4) |
|
||||
_envelope0.Decay;
|
||||
_envelope0.Decay;
|
||||
break;
|
||||
case 0x06:
|
||||
result = (_envelope0.Sustain << 4) |
|
||||
_envelope0.Release;
|
||||
_envelope0.Release;
|
||||
break;
|
||||
case 0x07: result = _voice1.FrequencyLo; break;
|
||||
case 0x08: result = _voice1.FrequencyHi; break;
|
||||
|
@ -65,18 +65,18 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
case 0x0A: result = _voice1.PulseWidthHi; break;
|
||||
case 0x0B:
|
||||
result = (_envelope1.Gate ? 0x01 : 0x00) |
|
||||
(_voice1.Sync ? 0x02 : 0x00) |
|
||||
(_voice1.RingMod ? 0x04 : 0x00) |
|
||||
(_voice1.Test ? 0x08 : 0x00) |
|
||||
(_voice1.Waveform << 4);
|
||||
(_voice1.Sync ? 0x02 : 0x00) |
|
||||
(_voice1.RingMod ? 0x04 : 0x00) |
|
||||
(_voice1.Test ? 0x08 : 0x00) |
|
||||
(_voice1.Waveform << 4);
|
||||
break;
|
||||
case 0x0C:
|
||||
result = (_envelope1.Attack << 4) |
|
||||
_envelope1.Decay;
|
||||
_envelope1.Decay;
|
||||
break;
|
||||
case 0x0D:
|
||||
result = (_envelope1.Sustain << 4) |
|
||||
_envelope1.Release;
|
||||
_envelope1.Release;
|
||||
break;
|
||||
case 0x0E: result = _voice2.FrequencyLo; break;
|
||||
case 0x0F: result = _voice2.FrequencyHi; break;
|
||||
|
@ -84,33 +84,33 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
case 0x11: result = _voice2.PulseWidthHi; break;
|
||||
case 0x12:
|
||||
result = (_envelope2.Gate ? 0x01 : 0x00) |
|
||||
(_voice2.Sync ? 0x02 : 0x00) |
|
||||
(_voice2.RingMod ? 0x04 : 0x00) |
|
||||
(_voice2.Test ? 0x08 : 0x00) |
|
||||
(_voice2.Waveform << 4);
|
||||
(_voice2.Sync ? 0x02 : 0x00) |
|
||||
(_voice2.RingMod ? 0x04 : 0x00) |
|
||||
(_voice2.Test ? 0x08 : 0x00) |
|
||||
(_voice2.Waveform << 4);
|
||||
break;
|
||||
case 0x13:
|
||||
result = (_envelope2.Attack << 4) |
|
||||
_envelope2.Decay;
|
||||
_envelope2.Decay;
|
||||
break;
|
||||
case 0x14:
|
||||
result = (_envelope2.Sustain << 4) |
|
||||
_envelope2.Release;
|
||||
_envelope2.Release;
|
||||
break;
|
||||
case 0x15: result = _filterFrequency & 0x7; break;
|
||||
case 0x16: result = (_filterFrequency >> 3) & 0xFF; break;
|
||||
case 0x17:
|
||||
result = (_filterEnable[0] ? 0x01 : 0x00) |
|
||||
(_filterEnable[1] ? 0x02 : 0x00) |
|
||||
(_filterEnable[2] ? 0x04 : 0x00) |
|
||||
(_filterResonance << 4);
|
||||
(_filterEnable[1] ? 0x02 : 0x00) |
|
||||
(_filterEnable[2] ? 0x04 : 0x00) |
|
||||
(_filterResonance << 4);
|
||||
break;
|
||||
case 0x18:
|
||||
result = _volume |
|
||||
(_filterSelectLoPass ? 0x10 : 0x00) |
|
||||
(_filterSelectBandPass ? 0x20 : 0x00) |
|
||||
(_filterSelectHiPass ? 0x40 : 0x00) |
|
||||
(_disableVoice3 ? 0x80 : 0x00);
|
||||
(_filterSelectLoPass ? 0x10 : 0x00) |
|
||||
(_filterSelectBandPass ? 0x20 : 0x00) |
|
||||
(_filterSelectHiPass ? 0x40 : 0x00) |
|
||||
(_disableVoice3 ? 0x80 : 0x00);
|
||||
break;
|
||||
case 0x19: result = _potX; break;
|
||||
case 0x1A: result = _potY; break;
|
||||
|
|
|
@ -9,34 +9,34 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
{
|
||||
public sealed partial class Sid
|
||||
{
|
||||
private sealed class Voice
|
||||
private sealed class Voice
|
||||
{
|
||||
private int _accBits;
|
||||
private int _accNext;
|
||||
private int _accumulator;
|
||||
private bool _controlTestPrev;
|
||||
private int _controlWavePrev;
|
||||
private int _delay;
|
||||
private int _floatOutputTtl;
|
||||
private int _frequency;
|
||||
private bool _msbRising;
|
||||
private int _noise;
|
||||
private int _noNoise;
|
||||
private int _noNoiseOrNoise;
|
||||
private int _noPulse;
|
||||
private int _output;
|
||||
private int _pulse;
|
||||
private int _pulseWidth;
|
||||
private bool _ringMod;
|
||||
private int _ringMsbMask;
|
||||
private int _shiftRegister;
|
||||
private int _shiftRegisterReset;
|
||||
private bool _sync;
|
||||
private bool _test;
|
||||
[SaveState.DoNotSave] private int[] _wave;
|
||||
private int _waveform;
|
||||
private int _waveformIndex;
|
||||
[SaveState.DoNotSave] private readonly int[][] _waveTable;
|
||||
private int _accBits;
|
||||
private int _accNext;
|
||||
private int _accumulator;
|
||||
private bool _controlTestPrev;
|
||||
private int _controlWavePrev;
|
||||
private int _delay;
|
||||
private int _floatOutputTtl;
|
||||
private int _frequency;
|
||||
private bool _msbRising;
|
||||
private int _noise;
|
||||
private int _noNoise;
|
||||
private int _noNoiseOrNoise;
|
||||
private int _noPulse;
|
||||
private int _output;
|
||||
private int _pulse;
|
||||
private int _pulseWidth;
|
||||
private bool _ringMod;
|
||||
private int _ringMsbMask;
|
||||
private int _shiftRegister;
|
||||
private int _shiftRegisterReset;
|
||||
private bool _sync;
|
||||
private bool _test;
|
||||
[SaveState.DoNotSave] private int[] _wave;
|
||||
private int _waveform;
|
||||
private int _waveformIndex;
|
||||
[SaveState.DoNotSave] private readonly int[][] _waveTable;
|
||||
|
||||
public Voice(int[][] newWaveTable)
|
||||
{
|
||||
|
@ -304,8 +304,8 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
public void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncObject(ser, this);
|
||||
_wave = _waveTable[_waveform & 0x07];
|
||||
}
|
||||
_wave = _waveTable[_waveform & 0x07];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
{
|
||||
public sealed partial class Sid
|
||||
{
|
||||
/*
|
||||
/*
|
||||
Commodore SID 6581/8580 core.
|
||||
|
||||
Many thanks to:
|
||||
|
@ -21,72 +21,72 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
https://sourceforge.net/projects/sidplay-residfp/
|
||||
*/
|
||||
|
||||
// ------------------------------------
|
||||
// ------------------------------------
|
||||
|
||||
private int _cachedCycles;
|
||||
private bool _disableVoice3;
|
||||
private int _envelopeOutput0;
|
||||
private int _envelopeOutput1;
|
||||
private int _envelopeOutput2;
|
||||
private readonly Envelope[] _envelopes;
|
||||
[SaveState.DoNotSave] private readonly Envelope _envelope0;
|
||||
[SaveState.DoNotSave] private readonly Envelope _envelope1;
|
||||
[SaveState.DoNotSave] private readonly Envelope _envelope2;
|
||||
private readonly bool[] _filterEnable;
|
||||
private int _filterFrequency;
|
||||
private int _filterResonance;
|
||||
private bool _filterSelectBandPass;
|
||||
private bool _filterSelectLoPass;
|
||||
private bool _filterSelectHiPass;
|
||||
private int _mixer;
|
||||
[SaveState.DoNotSave] private readonly short[] _outputBuffer;
|
||||
[SaveState.DoNotSave] private int _outputBufferIndex;
|
||||
private int _potCounter;
|
||||
private int _potX;
|
||||
private int _potY;
|
||||
private short _sample;
|
||||
private int _voiceOutput0;
|
||||
private int _voiceOutput1;
|
||||
private int _voiceOutput2;
|
||||
private readonly Voice[] _voices;
|
||||
[SaveState.DoNotSave] private readonly Voice _voice0;
|
||||
[SaveState.DoNotSave] private readonly Voice _voice1;
|
||||
[SaveState.DoNotSave] private readonly Voice _voice2;
|
||||
private int _volume;
|
||||
private int _cachedCycles;
|
||||
private bool _disableVoice3;
|
||||
private int _envelopeOutput0;
|
||||
private int _envelopeOutput1;
|
||||
private int _envelopeOutput2;
|
||||
private readonly Envelope[] _envelopes;
|
||||
[SaveState.DoNotSave] private readonly Envelope _envelope0;
|
||||
[SaveState.DoNotSave] private readonly Envelope _envelope1;
|
||||
[SaveState.DoNotSave] private readonly Envelope _envelope2;
|
||||
private readonly bool[] _filterEnable;
|
||||
private int _filterFrequency;
|
||||
private int _filterResonance;
|
||||
private bool _filterSelectBandPass;
|
||||
private bool _filterSelectLoPass;
|
||||
private bool _filterSelectHiPass;
|
||||
private int _mixer;
|
||||
[SaveState.DoNotSave] private readonly short[] _outputBuffer;
|
||||
[SaveState.DoNotSave] private int _outputBufferIndex;
|
||||
private int _potCounter;
|
||||
private int _potX;
|
||||
private int _potY;
|
||||
private short _sample;
|
||||
private int _voiceOutput0;
|
||||
private int _voiceOutput1;
|
||||
private int _voiceOutput2;
|
||||
private readonly Voice[] _voices;
|
||||
[SaveState.DoNotSave] private readonly Voice _voice0;
|
||||
[SaveState.DoNotSave] private readonly Voice _voice1;
|
||||
[SaveState.DoNotSave] private readonly Voice _voice2;
|
||||
private int _volume;
|
||||
|
||||
public Func<int> ReadPotX;
|
||||
public Func<int> ReadPotX;
|
||||
public Func<int> ReadPotY;
|
||||
|
||||
[SaveState.DoNotSave] private readonly int _cpuCyclesNum;
|
||||
[SaveState.DoNotSave] private int _sampleCyclesNum;
|
||||
[SaveState.DoNotSave] private readonly int _sampleCyclesDen;
|
||||
[SaveState.DoNotSave] private readonly int _sampleRate;
|
||||
[SaveState.DoNotSave] private readonly int _cpuCyclesNum;
|
||||
[SaveState.DoNotSave] private int _sampleCyclesNum;
|
||||
[SaveState.DoNotSave] private readonly int _sampleCyclesDen;
|
||||
[SaveState.DoNotSave] private readonly int _sampleRate;
|
||||
|
||||
public Sid(int[][] newWaveformTable, int sampleRate, int cyclesNum, int cyclesDen)
|
||||
{
|
||||
_sampleRate = sampleRate;
|
||||
_cpuCyclesNum = cyclesNum;
|
||||
_sampleCyclesDen = cyclesDen*sampleRate;
|
||||
public Sid(int[][] newWaveformTable, int sampleRate, int cyclesNum, int cyclesDen)
|
||||
{
|
||||
_sampleRate = sampleRate;
|
||||
_cpuCyclesNum = cyclesNum;
|
||||
_sampleCyclesDen = cyclesDen * sampleRate;
|
||||
|
||||
_envelopes = new Envelope[3];
|
||||
_envelopes = new Envelope[3];
|
||||
for (var i = 0; i < 3; i++)
|
||||
_envelopes[i] = new Envelope();
|
||||
_envelope0 = _envelopes[0];
|
||||
_envelope1 = _envelopes[1];
|
||||
_envelope2 = _envelopes[2];
|
||||
_envelope0 = _envelopes[0];
|
||||
_envelope1 = _envelopes[1];
|
||||
_envelope2 = _envelopes[2];
|
||||
|
||||
_voices = new Voice[3];
|
||||
_voices = new Voice[3];
|
||||
for (var i = 0; i < 3; i++)
|
||||
_voices[i] = new Voice(newWaveformTable);
|
||||
_voice0 = _voices[0];
|
||||
_voice1 = _voices[1];
|
||||
_voice2 = _voices[2];
|
||||
_voice0 = _voices[0];
|
||||
_voice1 = _voices[1];
|
||||
_voice2 = _voices[2];
|
||||
|
||||
_filterEnable = new bool[3];
|
||||
_filterEnable = new bool[3];
|
||||
for (var i = 0; i < 3; i++)
|
||||
_filterEnable[i] = false;
|
||||
|
||||
_outputBuffer = new short[sampleRate];
|
||||
_outputBuffer = new short[sampleRate];
|
||||
}
|
||||
|
||||
// ------------------------------------
|
||||
|
@ -121,9 +121,9 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
|
||||
public void Flush()
|
||||
{
|
||||
while (_cachedCycles > 0)
|
||||
{
|
||||
_cachedCycles--;
|
||||
while (_cachedCycles > 0)
|
||||
{
|
||||
_cachedCycles--;
|
||||
|
||||
// process voices and envelopes
|
||||
_voice0.ExecutePhase2();
|
||||
|
@ -133,50 +133,50 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
_envelope1.ExecutePhase2();
|
||||
_envelope2.ExecutePhase2();
|
||||
|
||||
_voice0.Synchronize(_voice1, _voice2);
|
||||
_voice1.Synchronize(_voice2, _voice0);
|
||||
_voice2.Synchronize(_voice0, _voice1);
|
||||
_voice0.Synchronize(_voice1, _voice2);
|
||||
_voice1.Synchronize(_voice2, _voice0);
|
||||
_voice2.Synchronize(_voice0, _voice1);
|
||||
|
||||
// get output
|
||||
_voiceOutput0 = _voice0.Output(_voice2);
|
||||
// get output
|
||||
_voiceOutput0 = _voice0.Output(_voice2);
|
||||
_voiceOutput1 = _voice1.Output(_voice0);
|
||||
_voiceOutput2 = _voice2.Output(_voice1);
|
||||
_envelopeOutput0 = _envelope0.Level;
|
||||
_envelopeOutput1 = _envelope1.Level;
|
||||
_envelopeOutput2 = _envelope2.Level;
|
||||
|
||||
_sampleCyclesNum += _sampleCyclesDen;
|
||||
if (_sampleCyclesNum >= _cpuCyclesNum)
|
||||
{
|
||||
_sampleCyclesNum -= _cpuCyclesNum;
|
||||
_mixer = (_voiceOutput0 * _envelopeOutput0) >> 7;
|
||||
_mixer += (_voiceOutput1 * _envelopeOutput1) >> 7;
|
||||
_mixer += (_voiceOutput2 * _envelopeOutput2) >> 7;
|
||||
_mixer = (_mixer * _volume) >> 4;
|
||||
_mixer -= _volume << 8;
|
||||
_sampleCyclesNum += _sampleCyclesDen;
|
||||
if (_sampleCyclesNum >= _cpuCyclesNum)
|
||||
{
|
||||
_sampleCyclesNum -= _cpuCyclesNum;
|
||||
_mixer = (_voiceOutput0 * _envelopeOutput0) >> 7;
|
||||
_mixer += (_voiceOutput1 * _envelopeOutput1) >> 7;
|
||||
_mixer += (_voiceOutput2 * _envelopeOutput2) >> 7;
|
||||
_mixer = (_mixer * _volume) >> 4;
|
||||
_mixer -= _volume << 8;
|
||||
|
||||
if (_mixer > 0x7FFF)
|
||||
{
|
||||
_mixer = 0x7FFF;
|
||||
}
|
||||
if (_mixer < -0x8000)
|
||||
{
|
||||
_mixer = -0x8000;
|
||||
}
|
||||
if (_mixer > 0x7FFF)
|
||||
{
|
||||
_mixer = 0x7FFF;
|
||||
}
|
||||
if (_mixer < -0x8000)
|
||||
{
|
||||
_mixer = -0x8000;
|
||||
}
|
||||
|
||||
_sample = unchecked((short)_mixer);
|
||||
if (_outputBufferIndex < _sampleRate)
|
||||
{
|
||||
_outputBuffer[_outputBufferIndex++] = _sample;
|
||||
_outputBuffer[_outputBufferIndex++] = _sample;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_sample = unchecked((short)_mixer);
|
||||
if (_outputBufferIndex < _sampleRate)
|
||||
{
|
||||
_outputBuffer[_outputBufferIndex++] = _sample;
|
||||
_outputBuffer[_outputBufferIndex++] = _sample;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------
|
||||
// ----------------------------------
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
|
|
|
@ -7,120 +7,120 @@ using BizHawk.Emulation.Cores.Computers.Commodore64.Media;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
||||
{
|
||||
public sealed partial class Via
|
||||
{
|
||||
private abstract class Port
|
||||
{
|
||||
public abstract int ReadPra(int pra, int ddra);
|
||||
public abstract int ReadPrb(int prb, int ddrb);
|
||||
public abstract int ReadExternalPra();
|
||||
public abstract int ReadExternalPrb();
|
||||
public sealed partial class Via
|
||||
{
|
||||
private abstract class Port
|
||||
{
|
||||
public abstract int ReadPra(int pra, int ddra);
|
||||
public abstract int ReadPrb(int prb, int ddrb);
|
||||
public abstract int ReadExternalPra();
|
||||
public abstract int ReadExternalPrb();
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
}
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class DisconnectedPort : Port
|
||||
{
|
||||
public override int ReadPra(int pra, int ddra)
|
||||
{
|
||||
return (pra | ~ddra) & 0xFF;
|
||||
}
|
||||
private sealed class DisconnectedPort : Port
|
||||
{
|
||||
public override int ReadPra(int pra, int ddra)
|
||||
{
|
||||
return (pra | ~ddra) & 0xFF;
|
||||
}
|
||||
|
||||
public override int ReadPrb(int prb, int ddrb)
|
||||
{
|
||||
return (prb | ~ddrb) & 0xFF;
|
||||
}
|
||||
public override int ReadPrb(int prb, int ddrb)
|
||||
{
|
||||
return (prb | ~ddrb) & 0xFF;
|
||||
}
|
||||
|
||||
public override int ReadExternalPra()
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
public override int ReadExternalPra()
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
public override int ReadExternalPrb()
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
public override int ReadExternalPrb()
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class DriverPort : Port
|
||||
{
|
||||
private readonly Func<int> _readPrA;
|
||||
private readonly Func<int> _readPrB;
|
||||
private sealed class DriverPort : Port
|
||||
{
|
||||
private readonly Func<int> _readPrA;
|
||||
private readonly Func<int> _readPrB;
|
||||
|
||||
public DriverPort(Func<int> readPrA, Func<int> readPrB)
|
||||
{
|
||||
_readPrA = readPrA;
|
||||
_readPrB = readPrB;
|
||||
}
|
||||
public DriverPort(Func<int> readPrA, Func<int> readPrB)
|
||||
{
|
||||
_readPrA = readPrA;
|
||||
_readPrB = readPrB;
|
||||
}
|
||||
|
||||
public override int ReadPra(int pra, int ddra)
|
||||
{
|
||||
return _readPrA();
|
||||
}
|
||||
public override int ReadPra(int pra, int ddra)
|
||||
{
|
||||
return _readPrA();
|
||||
}
|
||||
|
||||
public override int ReadPrb(int prb, int ddrb)
|
||||
{
|
||||
return (prb & ddrb) | (_readPrB() & ~ddrb);
|
||||
}
|
||||
public override int ReadPrb(int prb, int ddrb)
|
||||
{
|
||||
return (prb & ddrb) | (_readPrB() & ~ddrb);
|
||||
}
|
||||
|
||||
public override int ReadExternalPra()
|
||||
{
|
||||
return _readPrA();
|
||||
}
|
||||
public override int ReadExternalPra()
|
||||
{
|
||||
return _readPrA();
|
||||
}
|
||||
|
||||
public override int ReadExternalPrb()
|
||||
{
|
||||
return _readPrB();
|
||||
}
|
||||
}
|
||||
public override int ReadExternalPrb()
|
||||
{
|
||||
return _readPrB();
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class IecPort : Port
|
||||
{
|
||||
private readonly Func<bool> _readClock;
|
||||
private readonly Func<bool> _readData;
|
||||
private readonly Func<bool> _readAtn;
|
||||
private readonly int _driveNumber;
|
||||
private sealed class IecPort : Port
|
||||
{
|
||||
private readonly Func<bool> _readClock;
|
||||
private readonly Func<bool> _readData;
|
||||
private readonly Func<bool> _readAtn;
|
||||
private readonly int _driveNumber;
|
||||
|
||||
public IecPort(Func<bool> readClock, Func<bool> readData, Func<bool> readAtn, int driveNumber)
|
||||
{
|
||||
_readClock = readClock;
|
||||
_readData = readData;
|
||||
_readAtn = readAtn;
|
||||
_driveNumber = (driveNumber & 0x3) << 5;
|
||||
}
|
||||
public IecPort(Func<bool> readClock, Func<bool> readData, Func<bool> readAtn, int driveNumber)
|
||||
{
|
||||
_readClock = readClock;
|
||||
_readData = readData;
|
||||
_readAtn = readAtn;
|
||||
_driveNumber = (driveNumber & 0x3) << 5;
|
||||
}
|
||||
|
||||
public override int ReadPra(int pra, int ddra)
|
||||
{
|
||||
return (pra | ~ddra) & 0xFF;
|
||||
}
|
||||
public override int ReadPra(int pra, int ddra)
|
||||
{
|
||||
return (pra | ~ddra) & 0xFF;
|
||||
}
|
||||
|
||||
public override int ReadPrb(int prb, int ddrb)
|
||||
{
|
||||
return (prb & ddrb) |
|
||||
(~ddrb & 0xE5 & (
|
||||
(_readClock() ? 0x04 : 0x00) |
|
||||
(_readData() ? 0x01 : 0x00) |
|
||||
(_readAtn() ? 0x80 : 0x00) |
|
||||
_driveNumber)
|
||||
);
|
||||
}
|
||||
public override int ReadPrb(int prb, int ddrb)
|
||||
{
|
||||
return (prb & ddrb) |
|
||||
(~ddrb & 0xE5 & (
|
||||
(_readClock() ? 0x04 : 0x00) |
|
||||
(_readData() ? 0x01 : 0x00) |
|
||||
(_readAtn() ? 0x80 : 0x00) |
|
||||
_driveNumber)
|
||||
);
|
||||
}
|
||||
|
||||
public override int ReadExternalPra()
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
public override int ReadExternalPra()
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
public override int ReadExternalPrb()
|
||||
{
|
||||
return
|
||||
(_readClock() ? 0x04 : 0x00) |
|
||||
(_readData() ? 0x01 : 0x00) |
|
||||
(_readAtn() ? 0x80 : 0x00) |
|
||||
_driveNumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
public override int ReadExternalPrb()
|
||||
{
|
||||
return
|
||||
(_readClock() ? 0x04 : 0x00) |
|
||||
(_readData() ? 0x01 : 0x00) |
|
||||
(_readAtn() ? 0x80 : 0x00) |
|
||||
_driveNumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,273 +5,273 @@ using System.Text;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
||||
{
|
||||
public sealed partial class Via
|
||||
{
|
||||
public int Peek(int addr)
|
||||
{
|
||||
return ReadRegister(addr & 0xF);
|
||||
}
|
||||
public sealed partial class Via
|
||||
{
|
||||
public int Peek(int addr)
|
||||
{
|
||||
return ReadRegister(addr & 0xF);
|
||||
}
|
||||
|
||||
public void Poke(int addr, int val)
|
||||
{
|
||||
WriteRegister(addr & 0xF, val);
|
||||
}
|
||||
public void Poke(int addr, int val)
|
||||
{
|
||||
WriteRegister(addr & 0xF, val);
|
||||
}
|
||||
|
||||
public int Read(int addr)
|
||||
{
|
||||
addr &= 0xF;
|
||||
switch (addr)
|
||||
{
|
||||
case 0x0:
|
||||
_ifr &= 0xE7;
|
||||
if (_acrPbLatchEnable)
|
||||
{
|
||||
return _pbLatch;
|
||||
}
|
||||
break;
|
||||
case 0x1:
|
||||
_ifr &= 0xFC;
|
||||
if (_acrPaLatchEnable)
|
||||
{
|
||||
return _paLatch;
|
||||
}
|
||||
break;
|
||||
case 0x4:
|
||||
_ifr &= 0xBF;
|
||||
break;
|
||||
case 0x8:
|
||||
_ifr &= 0xDF;
|
||||
break;
|
||||
case 0xA:
|
||||
_ifr &= 0xFB;
|
||||
break;
|
||||
case 0xF:
|
||||
if (_acrPaLatchEnable)
|
||||
{
|
||||
return _paLatch;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return ReadRegister(addr);
|
||||
}
|
||||
public int Read(int addr)
|
||||
{
|
||||
addr &= 0xF;
|
||||
switch (addr)
|
||||
{
|
||||
case 0x0:
|
||||
_ifr &= 0xE7;
|
||||
if (_acrPbLatchEnable)
|
||||
{
|
||||
return _pbLatch;
|
||||
}
|
||||
break;
|
||||
case 0x1:
|
||||
_ifr &= 0xFC;
|
||||
if (_acrPaLatchEnable)
|
||||
{
|
||||
return _paLatch;
|
||||
}
|
||||
break;
|
||||
case 0x4:
|
||||
_ifr &= 0xBF;
|
||||
break;
|
||||
case 0x8:
|
||||
_ifr &= 0xDF;
|
||||
break;
|
||||
case 0xA:
|
||||
_ifr &= 0xFB;
|
||||
break;
|
||||
case 0xF:
|
||||
if (_acrPaLatchEnable)
|
||||
{
|
||||
return _paLatch;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return ReadRegister(addr);
|
||||
}
|
||||
|
||||
private int ReadRegister(int addr)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0x0:
|
||||
return _port.ReadPrb(_prb, _ddrb);
|
||||
case 0x1:
|
||||
return _port.ReadPra(_pra, _ddra);
|
||||
case 0x2:
|
||||
return _ddrb;
|
||||
case 0x3:
|
||||
return _ddra;
|
||||
case 0x4:
|
||||
return _t1C & 0xFF;
|
||||
case 0x5:
|
||||
return (_t1C >> 8) & 0xFF;
|
||||
case 0x6:
|
||||
return _t1L & 0xFF;
|
||||
case 0x7:
|
||||
return (_t1L >> 8) & 0xFF;
|
||||
case 0x8:
|
||||
return _t2C & 0xFF;
|
||||
case 0x9:
|
||||
return (_t2C >> 8) & 0xFF;
|
||||
case 0xA:
|
||||
return _sr;
|
||||
case 0xB:
|
||||
return _acr;
|
||||
case 0xC:
|
||||
return _pcr;
|
||||
case 0xD:
|
||||
return _ifr;
|
||||
case 0xE:
|
||||
return _ier | 0x80;
|
||||
case 0xF:
|
||||
return _port.ReadPra(_pra, _ddra);
|
||||
}
|
||||
return 0xFF;
|
||||
}
|
||||
private int ReadRegister(int addr)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0x0:
|
||||
return _port.ReadPrb(_prb, _ddrb);
|
||||
case 0x1:
|
||||
return _port.ReadPra(_pra, _ddra);
|
||||
case 0x2:
|
||||
return _ddrb;
|
||||
case 0x3:
|
||||
return _ddra;
|
||||
case 0x4:
|
||||
return _t1C & 0xFF;
|
||||
case 0x5:
|
||||
return (_t1C >> 8) & 0xFF;
|
||||
case 0x6:
|
||||
return _t1L & 0xFF;
|
||||
case 0x7:
|
||||
return (_t1L >> 8) & 0xFF;
|
||||
case 0x8:
|
||||
return _t2C & 0xFF;
|
||||
case 0x9:
|
||||
return (_t2C >> 8) & 0xFF;
|
||||
case 0xA:
|
||||
return _sr;
|
||||
case 0xB:
|
||||
return _acr;
|
||||
case 0xC:
|
||||
return _pcr;
|
||||
case 0xD:
|
||||
return _ifr;
|
||||
case 0xE:
|
||||
return _ier | 0x80;
|
||||
case 0xF:
|
||||
return _port.ReadPra(_pra, _ddra);
|
||||
}
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
public void Write(int addr, int val)
|
||||
{
|
||||
addr &= 0xF;
|
||||
switch (addr)
|
||||
{
|
||||
case 0x0:
|
||||
_ifr &= 0xE7;
|
||||
if (_pcrCb2Control == PCR_CONTROL_HANDSHAKE_OUTPUT || _pcrCb2Control == PCR_CONTROL_PULSE_OUTPUT)
|
||||
{
|
||||
_handshakeCb2NextClock = true;
|
||||
}
|
||||
WriteRegister(addr, val);
|
||||
break;
|
||||
case 0x1:
|
||||
_ifr &= 0xFC;
|
||||
if (_pcrCa2Control == PCR_CONTROL_HANDSHAKE_OUTPUT || _pcrCa2Control == PCR_CONTROL_PULSE_OUTPUT)
|
||||
{
|
||||
_handshakeCa2NextClock = true;
|
||||
}
|
||||
WriteRegister(addr, val);
|
||||
break;
|
||||
case 0x4:
|
||||
case 0x6:
|
||||
_t1L = (_t1L & 0xFF00) | (val & 0xFF);
|
||||
break;
|
||||
case 0x5:
|
||||
_t1L = (_t1L & 0xFF) | ((val & 0xFF) << 8);
|
||||
_ifr &= 0xBF;
|
||||
_t1C = _t1L;
|
||||
_t1CLoaded = true;
|
||||
_t1Delayed = 1;
|
||||
break;
|
||||
case 0x7:
|
||||
_t1L = (_t1L & 0xFF) | ((val & 0xFF) << 8);
|
||||
_ifr &= 0xBF;
|
||||
break;
|
||||
case 0x8:
|
||||
_t2L = (_t2L & 0xFF00) | (val & 0xFF);
|
||||
break;
|
||||
case 0x9:
|
||||
_t2L = (_t2L & 0xFF) | ((val & 0xFF) << 8);
|
||||
_ifr &= 0xDF;
|
||||
if (_acrT2Control == ACR_T2_CONTROL_TIMED)
|
||||
{
|
||||
_t2C = _t2L;
|
||||
_t2CLoaded = true;
|
||||
}
|
||||
_t2Delayed = 1;
|
||||
break;
|
||||
case 0xA:
|
||||
_ifr &= 0xFB;
|
||||
WriteRegister(addr, val);
|
||||
break;
|
||||
case 0xD:
|
||||
_ifr &= ~val;
|
||||
break;
|
||||
case 0xE:
|
||||
if ((val & 0x80) != 0)
|
||||
_ier |= val & 0x7F;
|
||||
else
|
||||
_ier &= ~val;
|
||||
break;
|
||||
default:
|
||||
WriteRegister(addr, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
public void Write(int addr, int val)
|
||||
{
|
||||
addr &= 0xF;
|
||||
switch (addr)
|
||||
{
|
||||
case 0x0:
|
||||
_ifr &= 0xE7;
|
||||
if (_pcrCb2Control == PCR_CONTROL_HANDSHAKE_OUTPUT || _pcrCb2Control == PCR_CONTROL_PULSE_OUTPUT)
|
||||
{
|
||||
_handshakeCb2NextClock = true;
|
||||
}
|
||||
WriteRegister(addr, val);
|
||||
break;
|
||||
case 0x1:
|
||||
_ifr &= 0xFC;
|
||||
if (_pcrCa2Control == PCR_CONTROL_HANDSHAKE_OUTPUT || _pcrCa2Control == PCR_CONTROL_PULSE_OUTPUT)
|
||||
{
|
||||
_handshakeCa2NextClock = true;
|
||||
}
|
||||
WriteRegister(addr, val);
|
||||
break;
|
||||
case 0x4:
|
||||
case 0x6:
|
||||
_t1L = (_t1L & 0xFF00) | (val & 0xFF);
|
||||
break;
|
||||
case 0x5:
|
||||
_t1L = (_t1L & 0xFF) | ((val & 0xFF) << 8);
|
||||
_ifr &= 0xBF;
|
||||
_t1C = _t1L;
|
||||
_t1CLoaded = true;
|
||||
_t1Delayed = 1;
|
||||
break;
|
||||
case 0x7:
|
||||
_t1L = (_t1L & 0xFF) | ((val & 0xFF) << 8);
|
||||
_ifr &= 0xBF;
|
||||
break;
|
||||
case 0x8:
|
||||
_t2L = (_t2L & 0xFF00) | (val & 0xFF);
|
||||
break;
|
||||
case 0x9:
|
||||
_t2L = (_t2L & 0xFF) | ((val & 0xFF) << 8);
|
||||
_ifr &= 0xDF;
|
||||
if (_acrT2Control == ACR_T2_CONTROL_TIMED)
|
||||
{
|
||||
_t2C = _t2L;
|
||||
_t2CLoaded = true;
|
||||
}
|
||||
_t2Delayed = 1;
|
||||
break;
|
||||
case 0xA:
|
||||
_ifr &= 0xFB;
|
||||
WriteRegister(addr, val);
|
||||
break;
|
||||
case 0xD:
|
||||
_ifr &= ~val;
|
||||
break;
|
||||
case 0xE:
|
||||
if ((val & 0x80) != 0)
|
||||
_ier |= val & 0x7F;
|
||||
else
|
||||
_ier &= ~val;
|
||||
break;
|
||||
default:
|
||||
WriteRegister(addr, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteRegister(int addr, int val)
|
||||
{
|
||||
addr &= 0xF;
|
||||
switch (addr)
|
||||
{
|
||||
case 0x0:
|
||||
_prb = val & 0xFF;
|
||||
break;
|
||||
case 0x1:
|
||||
case 0xF:
|
||||
_pra = val & 0xFF;
|
||||
break;
|
||||
case 0x2:
|
||||
_ddrb = val & 0xFF;
|
||||
break;
|
||||
case 0x3:
|
||||
_ddra = val & 0xFF;
|
||||
break;
|
||||
case 0x4:
|
||||
_t1C = (_t1C & 0xFF00) | (val & 0xFF);
|
||||
break;
|
||||
case 0x5:
|
||||
_t1C = (_t1C & 0xFF) | ((val & 0xFF) << 8);
|
||||
break;
|
||||
case 0x6:
|
||||
_t1L = (_t1L & 0xFF00) | (val & 0xFF);
|
||||
break;
|
||||
case 0x7:
|
||||
_t1L = (_t1L & 0xFF) | ((val & 0xFF) << 8);
|
||||
break;
|
||||
case 0x8:
|
||||
_t2C = (_t2C & 0xFF00) | (val & 0xFF);
|
||||
break;
|
||||
case 0x9:
|
||||
_t2C = (_t2C & 0xFF) | ((val & 0xFF) << 8);
|
||||
break;
|
||||
case 0xA:
|
||||
_sr = val & 0xFF;
|
||||
break;
|
||||
case 0xB:
|
||||
_acr = val & 0xFF;
|
||||
_acrPaLatchEnable = (val & 0x01) != 0;
|
||||
_acrPbLatchEnable = (val & 0x02) != 0;
|
||||
_acrSrControl = (val & 0x1C);
|
||||
_acrT2Control = (val & 0x20);
|
||||
_acrT1Control = (val & 0xC0);
|
||||
break;
|
||||
case 0xC:
|
||||
_pcr = val & 0xFF;
|
||||
_pcrCa1IntControl = _pcr & 0x01;
|
||||
_pcrCa2Control = _pcr & 0x0E;
|
||||
_pcrCb1IntControl = (_pcr & 0x10) >> 4;
|
||||
_pcrCb2Control = (_pcr & 0xE0) >> 4;
|
||||
break;
|
||||
case 0xD:
|
||||
_ifr = val & 0xFF;
|
||||
break;
|
||||
case 0xE:
|
||||
_ier = val & 0xFF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
private void WriteRegister(int addr, int val)
|
||||
{
|
||||
addr &= 0xF;
|
||||
switch (addr)
|
||||
{
|
||||
case 0x0:
|
||||
_prb = val & 0xFF;
|
||||
break;
|
||||
case 0x1:
|
||||
case 0xF:
|
||||
_pra = val & 0xFF;
|
||||
break;
|
||||
case 0x2:
|
||||
_ddrb = val & 0xFF;
|
||||
break;
|
||||
case 0x3:
|
||||
_ddra = val & 0xFF;
|
||||
break;
|
||||
case 0x4:
|
||||
_t1C = (_t1C & 0xFF00) | (val & 0xFF);
|
||||
break;
|
||||
case 0x5:
|
||||
_t1C = (_t1C & 0xFF) | ((val & 0xFF) << 8);
|
||||
break;
|
||||
case 0x6:
|
||||
_t1L = (_t1L & 0xFF00) | (val & 0xFF);
|
||||
break;
|
||||
case 0x7:
|
||||
_t1L = (_t1L & 0xFF) | ((val & 0xFF) << 8);
|
||||
break;
|
||||
case 0x8:
|
||||
_t2C = (_t2C & 0xFF00) | (val & 0xFF);
|
||||
break;
|
||||
case 0x9:
|
||||
_t2C = (_t2C & 0xFF) | ((val & 0xFF) << 8);
|
||||
break;
|
||||
case 0xA:
|
||||
_sr = val & 0xFF;
|
||||
break;
|
||||
case 0xB:
|
||||
_acr = val & 0xFF;
|
||||
_acrPaLatchEnable = (val & 0x01) != 0;
|
||||
_acrPbLatchEnable = (val & 0x02) != 0;
|
||||
_acrSrControl = (val & 0x1C);
|
||||
_acrT2Control = (val & 0x20);
|
||||
_acrT1Control = (val & 0xC0);
|
||||
break;
|
||||
case 0xC:
|
||||
_pcr = val & 0xFF;
|
||||
_pcrCa1IntControl = _pcr & 0x01;
|
||||
_pcrCa2Control = _pcr & 0x0E;
|
||||
_pcrCb1IntControl = (_pcr & 0x10) >> 4;
|
||||
_pcrCb2Control = (_pcr & 0xE0) >> 4;
|
||||
break;
|
||||
case 0xD:
|
||||
_ifr = val & 0xFF;
|
||||
break;
|
||||
case 0xE:
|
||||
_ier = val & 0xFF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public int DdrA
|
||||
{
|
||||
get { return _ddra; }
|
||||
}
|
||||
[SaveState.DoNotSave]
|
||||
public int DdrA
|
||||
{
|
||||
get { return _ddra; }
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public int DdrB
|
||||
{
|
||||
get { return _ddrb; }
|
||||
}
|
||||
[SaveState.DoNotSave]
|
||||
public int DdrB
|
||||
{
|
||||
get { return _ddrb; }
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public int PrA
|
||||
{
|
||||
get { return _pra; }
|
||||
}
|
||||
[SaveState.DoNotSave]
|
||||
public int PrA
|
||||
{
|
||||
get { return _pra; }
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public int PrB
|
||||
{
|
||||
get { return _prb; }
|
||||
}
|
||||
[SaveState.DoNotSave]
|
||||
public int PrB
|
||||
{
|
||||
get { return _prb; }
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public int EffectivePrA
|
||||
{
|
||||
get { return _pra | ~_ddra; }
|
||||
}
|
||||
[SaveState.DoNotSave]
|
||||
public int EffectivePrA
|
||||
{
|
||||
get { return _pra | ~_ddra; }
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public int EffectivePrB
|
||||
{
|
||||
get { return _prb | ~_ddrb; }
|
||||
}
|
||||
[SaveState.DoNotSave]
|
||||
public int EffectivePrB
|
||||
{
|
||||
get { return _prb | ~_ddrb; }
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public int ActualPrA
|
||||
{
|
||||
get { return _acrPaLatchEnable ? _paLatch : _port.ReadPra(_pra, _ddra); }
|
||||
}
|
||||
[SaveState.DoNotSave]
|
||||
public int ActualPrA
|
||||
{
|
||||
get { return _acrPaLatchEnable ? _paLatch : _port.ReadPra(_pra, _ddra); }
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public int ActualPrB
|
||||
{
|
||||
get { return _acrPbLatchEnable ? _pbLatch : _port.ReadPrb(_prb, _ddrb); }
|
||||
}
|
||||
}
|
||||
[SaveState.DoNotSave]
|
||||
public int ActualPrB
|
||||
{
|
||||
get { return _acrPbLatchEnable ? _pbLatch : _port.ReadPrb(_prb, _ddrb); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,406 +7,406 @@ using BizHawk.Emulation.Cores.Computers.Commodore64.Media;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
||||
{
|
||||
public sealed partial class Via
|
||||
{
|
||||
[SaveState.DoNotSave] private const int PCR_INT_CONTROL_NEGATIVE_EDGE = 0x00;
|
||||
[SaveState.DoNotSave] private const int PCR_INT_CONTROL_POSITIVE_EDGE = 0x01;
|
||||
[SaveState.DoNotSave] private const int PCR_CONTROL_INPUT_NEGATIVE_ACTIVE_EDGE = 0x00;
|
||||
[SaveState.DoNotSave] private const int PCR_CONTROL_INDEPENDENT_INTERRUPT_INPUT_NEGATIVE_EDGE = 0x02;
|
||||
[SaveState.DoNotSave] private const int PCR_CONTROL_INPUT_POSITIVE_ACTIVE_EDGE = 0x04;
|
||||
[SaveState.DoNotSave] private const int PCR_CONTROL_INDEPENDENT_INTERRUPT_INPUT_POSITIVE_EDGE = 0x06;
|
||||
[SaveState.DoNotSave] private const int PCR_CONTROL_HANDSHAKE_OUTPUT = 0x08;
|
||||
[SaveState.DoNotSave] private const int PCR_CONTROL_PULSE_OUTPUT = 0x0A;
|
||||
[SaveState.DoNotSave] private const int PCR_CONTROL_LOW_OUTPUT = 0x0C;
|
||||
[SaveState.DoNotSave] private const int PCR_CONTROL_HIGH_OUTPUT = 0x0E;
|
||||
[SaveState.DoNotSave] private const int ACR_SR_CONTROL_DISABLED = 0x00;
|
||||
[SaveState.DoNotSave] private const int ACR_SR_CONTROL_SHIFT_IN_T2_ONCE = 0x04;
|
||||
[SaveState.DoNotSave] private const int ACR_SR_CONTROL_SHIFT_IN_PHI2 = 0x08;
|
||||
[SaveState.DoNotSave] private const int ACR_SR_CONTROL_SHIFT_IN_CLOCK = 0x0C;
|
||||
[SaveState.DoNotSave] private const int ACR_SR_CONTROL_SHIFT_OUT_T2 = 0x10;
|
||||
[SaveState.DoNotSave] private const int ACR_SR_CONTROL_SHIFT_OUT_T2_ONCE = 0x14;
|
||||
[SaveState.DoNotSave] private const int ACR_SR_CONTROL_SHIFT_OUT_PHI2 = 0x18;
|
||||
[SaveState.DoNotSave] private const int ACR_SR_CONTROL_SHIFT_OUT_CLOCK = 0x1C;
|
||||
[SaveState.DoNotSave] private const int ACR_T2_CONTROL_TIMED = 0x00;
|
||||
[SaveState.DoNotSave] private const int ACR_T2_CONTROL_COUNT_ON_PB6 = 0x20;
|
||||
[SaveState.DoNotSave] private const int ACR_T1_CONTROL_INTERRUPT_ON_LOAD = 0x00;
|
||||
[SaveState.DoNotSave] private const int ACR_T1_CONTROL_CONTINUOUS_INTERRUPTS = 0x40;
|
||||
[SaveState.DoNotSave] private const int ACR_T1_CONTROL_INTERRUPT_ON_LOAD_AND_ONESHOT_PB7 = 0x80;
|
||||
[SaveState.DoNotSave] private const int ACR_T1_CONTROL_CONTINUOUS_INTERRUPTS_AND_OUTPUT_ON_PB7 = 0xC0;
|
||||
public sealed partial class Via
|
||||
{
|
||||
[SaveState.DoNotSave] private const int PCR_INT_CONTROL_NEGATIVE_EDGE = 0x00;
|
||||
[SaveState.DoNotSave] private const int PCR_INT_CONTROL_POSITIVE_EDGE = 0x01;
|
||||
[SaveState.DoNotSave] private const int PCR_CONTROL_INPUT_NEGATIVE_ACTIVE_EDGE = 0x00;
|
||||
[SaveState.DoNotSave] private const int PCR_CONTROL_INDEPENDENT_INTERRUPT_INPUT_NEGATIVE_EDGE = 0x02;
|
||||
[SaveState.DoNotSave] private const int PCR_CONTROL_INPUT_POSITIVE_ACTIVE_EDGE = 0x04;
|
||||
[SaveState.DoNotSave] private const int PCR_CONTROL_INDEPENDENT_INTERRUPT_INPUT_POSITIVE_EDGE = 0x06;
|
||||
[SaveState.DoNotSave] private const int PCR_CONTROL_HANDSHAKE_OUTPUT = 0x08;
|
||||
[SaveState.DoNotSave] private const int PCR_CONTROL_PULSE_OUTPUT = 0x0A;
|
||||
[SaveState.DoNotSave] private const int PCR_CONTROL_LOW_OUTPUT = 0x0C;
|
||||
[SaveState.DoNotSave] private const int PCR_CONTROL_HIGH_OUTPUT = 0x0E;
|
||||
[SaveState.DoNotSave] private const int ACR_SR_CONTROL_DISABLED = 0x00;
|
||||
[SaveState.DoNotSave] private const int ACR_SR_CONTROL_SHIFT_IN_T2_ONCE = 0x04;
|
||||
[SaveState.DoNotSave] private const int ACR_SR_CONTROL_SHIFT_IN_PHI2 = 0x08;
|
||||
[SaveState.DoNotSave] private const int ACR_SR_CONTROL_SHIFT_IN_CLOCK = 0x0C;
|
||||
[SaveState.DoNotSave] private const int ACR_SR_CONTROL_SHIFT_OUT_T2 = 0x10;
|
||||
[SaveState.DoNotSave] private const int ACR_SR_CONTROL_SHIFT_OUT_T2_ONCE = 0x14;
|
||||
[SaveState.DoNotSave] private const int ACR_SR_CONTROL_SHIFT_OUT_PHI2 = 0x18;
|
||||
[SaveState.DoNotSave] private const int ACR_SR_CONTROL_SHIFT_OUT_CLOCK = 0x1C;
|
||||
[SaveState.DoNotSave] private const int ACR_T2_CONTROL_TIMED = 0x00;
|
||||
[SaveState.DoNotSave] private const int ACR_T2_CONTROL_COUNT_ON_PB6 = 0x20;
|
||||
[SaveState.DoNotSave] private const int ACR_T1_CONTROL_INTERRUPT_ON_LOAD = 0x00;
|
||||
[SaveState.DoNotSave] private const int ACR_T1_CONTROL_CONTINUOUS_INTERRUPTS = 0x40;
|
||||
[SaveState.DoNotSave] private const int ACR_T1_CONTROL_INTERRUPT_ON_LOAD_AND_ONESHOT_PB7 = 0x80;
|
||||
[SaveState.DoNotSave] private const int ACR_T1_CONTROL_CONTINUOUS_INTERRUPTS_AND_OUTPUT_ON_PB7 = 0xC0;
|
||||
|
||||
[SaveState.SaveWithName("PortOutputA")]
|
||||
private int _pra;
|
||||
[SaveState.SaveWithName("PortDirectionA")]
|
||||
private int _ddra;
|
||||
[SaveState.SaveWithName("PortOutputB")]
|
||||
private int _prb;
|
||||
[SaveState.SaveWithName("PortDirectionB")]
|
||||
private int _ddrb;
|
||||
[SaveState.SaveWithName("Timer1Counter")]
|
||||
private int _t1C;
|
||||
[SaveState.SaveWithName("Timer1Latch")]
|
||||
private int _t1L;
|
||||
[SaveState.SaveWithName("Timer2Counter")]
|
||||
private int _t2C;
|
||||
[SaveState.SaveWithName("Timer2Latch")]
|
||||
private int _t2L;
|
||||
[SaveState.SaveWithName("ShiftRegister")]
|
||||
private int _sr;
|
||||
[SaveState.SaveWithName("AuxiliaryControlRegister")]
|
||||
private int _acr;
|
||||
[SaveState.SaveWithName("PeripheralControlRegister")]
|
||||
private int _pcr;
|
||||
[SaveState.SaveWithName("InterruptFlagRegister")]
|
||||
private int _ifr;
|
||||
[SaveState.SaveWithName("InterruptEnableRegister")]
|
||||
private int _ier;
|
||||
[SaveState.SaveWithName("Port")]
|
||||
private readonly Port _port;
|
||||
[SaveState.SaveWithName("PortOutputA")]
|
||||
private int _pra;
|
||||
[SaveState.SaveWithName("PortDirectionA")]
|
||||
private int _ddra;
|
||||
[SaveState.SaveWithName("PortOutputB")]
|
||||
private int _prb;
|
||||
[SaveState.SaveWithName("PortDirectionB")]
|
||||
private int _ddrb;
|
||||
[SaveState.SaveWithName("Timer1Counter")]
|
||||
private int _t1C;
|
||||
[SaveState.SaveWithName("Timer1Latch")]
|
||||
private int _t1L;
|
||||
[SaveState.SaveWithName("Timer2Counter")]
|
||||
private int _t2C;
|
||||
[SaveState.SaveWithName("Timer2Latch")]
|
||||
private int _t2L;
|
||||
[SaveState.SaveWithName("ShiftRegister")]
|
||||
private int _sr;
|
||||
[SaveState.SaveWithName("AuxiliaryControlRegister")]
|
||||
private int _acr;
|
||||
[SaveState.SaveWithName("PeripheralControlRegister")]
|
||||
private int _pcr;
|
||||
[SaveState.SaveWithName("InterruptFlagRegister")]
|
||||
private int _ifr;
|
||||
[SaveState.SaveWithName("InterruptEnableRegister")]
|
||||
private int _ier;
|
||||
[SaveState.SaveWithName("Port")]
|
||||
private readonly Port _port;
|
||||
|
||||
[SaveState.SaveWithName("PortLatchA")]
|
||||
private int _paLatch;
|
||||
[SaveState.SaveWithName("PortLatchB")]
|
||||
private int _pbLatch;
|
||||
[SaveState.SaveWithName("PortLatchA")]
|
||||
private int _paLatch;
|
||||
[SaveState.SaveWithName("PortLatchB")]
|
||||
private int _pbLatch;
|
||||
|
||||
[SaveState.SaveWithName("CA1InterruptControl")]
|
||||
private int _pcrCa1IntControl;
|
||||
[SaveState.SaveWithName("CA2Control")]
|
||||
private int _pcrCa2Control;
|
||||
[SaveState.SaveWithName("CB1InterruptControl")]
|
||||
private int _pcrCb1IntControl;
|
||||
[SaveState.SaveWithName("CB2Control")]
|
||||
private int _pcrCb2Control;
|
||||
[SaveState.SaveWithName("PortLatchEnableA")]
|
||||
private bool _acrPaLatchEnable;
|
||||
[SaveState.SaveWithName("PortLatchEnableB")]
|
||||
private bool _acrPbLatchEnable;
|
||||
[SaveState.SaveWithName("ShiftRegisterControl")]
|
||||
private int _acrSrControl;
|
||||
[SaveState.SaveWithName("Timer1Control")]
|
||||
private int _acrT1Control;
|
||||
[SaveState.SaveWithName("Timer2Control")]
|
||||
private int _acrT2Control;
|
||||
[SaveState.SaveWithName("CA1InterruptControl")]
|
||||
private int _pcrCa1IntControl;
|
||||
[SaveState.SaveWithName("CA2Control")]
|
||||
private int _pcrCa2Control;
|
||||
[SaveState.SaveWithName("CB1InterruptControl")]
|
||||
private int _pcrCb1IntControl;
|
||||
[SaveState.SaveWithName("CB2Control")]
|
||||
private int _pcrCb2Control;
|
||||
[SaveState.SaveWithName("PortLatchEnableA")]
|
||||
private bool _acrPaLatchEnable;
|
||||
[SaveState.SaveWithName("PortLatchEnableB")]
|
||||
private bool _acrPbLatchEnable;
|
||||
[SaveState.SaveWithName("ShiftRegisterControl")]
|
||||
private int _acrSrControl;
|
||||
[SaveState.SaveWithName("Timer1Control")]
|
||||
private int _acrT1Control;
|
||||
[SaveState.SaveWithName("Timer2Control")]
|
||||
private int _acrT2Control;
|
||||
|
||||
[SaveState.SaveWithName("PreviousCA1")]
|
||||
private bool _ca1L;
|
||||
[SaveState.SaveWithName("PreviousCA2")]
|
||||
private bool _ca2L;
|
||||
[SaveState.SaveWithName("PreviousCB1")]
|
||||
private bool _cb1L;
|
||||
[SaveState.SaveWithName("PreviousCB2")]
|
||||
private bool _cb2L;
|
||||
[SaveState.SaveWithName("PreviousPB6")]
|
||||
private bool _pb6L;
|
||||
[SaveState.SaveWithName("PreviousCA1")]
|
||||
private bool _ca1L;
|
||||
[SaveState.SaveWithName("PreviousCA2")]
|
||||
private bool _ca2L;
|
||||
[SaveState.SaveWithName("PreviousCB1")]
|
||||
private bool _cb1L;
|
||||
[SaveState.SaveWithName("PreviousCB2")]
|
||||
private bool _cb2L;
|
||||
[SaveState.SaveWithName("PreviousPB6")]
|
||||
private bool _pb6L;
|
||||
|
||||
[SaveState.SaveWithName("ResetCa2NextClock")]
|
||||
private bool _resetCa2NextClock;
|
||||
[SaveState.SaveWithName("ResetCb2NextClock")]
|
||||
private bool _resetCb2NextClock;
|
||||
[SaveState.SaveWithName("ResetCa2NextClock")]
|
||||
private bool _resetCa2NextClock;
|
||||
[SaveState.SaveWithName("ResetCb2NextClock")]
|
||||
private bool _resetCb2NextClock;
|
||||
|
||||
[SaveState.SaveWithName("HandshakeCa2NextClock")]
|
||||
private bool _handshakeCa2NextClock;
|
||||
[SaveState.SaveWithName("HandshakeCb2NextClock")]
|
||||
private bool _handshakeCb2NextClock;
|
||||
[SaveState.SaveWithName("HandshakeCa2NextClock")]
|
||||
private bool _handshakeCa2NextClock;
|
||||
[SaveState.SaveWithName("HandshakeCb2NextClock")]
|
||||
private bool _handshakeCb2NextClock;
|
||||
|
||||
[SaveState.SaveWithName("CA1")]
|
||||
public bool Ca1;
|
||||
[SaveState.SaveWithName("CA2")]
|
||||
public bool Ca2;
|
||||
[SaveState.SaveWithName("CB1")]
|
||||
public bool Cb1;
|
||||
[SaveState.SaveWithName("CB2")]
|
||||
public bool Cb2;
|
||||
[SaveState.SaveWithName("PB6")]
|
||||
private bool _pb6;
|
||||
[SaveState.SaveWithName("CA1")]
|
||||
public bool Ca1;
|
||||
[SaveState.SaveWithName("CA2")]
|
||||
public bool Ca2;
|
||||
[SaveState.SaveWithName("CB1")]
|
||||
public bool Cb1;
|
||||
[SaveState.SaveWithName("CB2")]
|
||||
public bool Cb2;
|
||||
[SaveState.SaveWithName("PB6")]
|
||||
private bool _pb6;
|
||||
|
||||
[SaveState.SaveWithName("InterruptNextClock")]
|
||||
private int _interruptNextClock;
|
||||
[SaveState.SaveWithName("T1Loaded")]
|
||||
private bool _t1CLoaded;
|
||||
[SaveState.SaveWithName("T2Loaded")]
|
||||
private bool _t2CLoaded;
|
||||
[SaveState.SaveWithName("T1Delayed")]
|
||||
private int _t1Delayed;
|
||||
[SaveState.SaveWithName("T2Delayed")]
|
||||
private int _t2Delayed;
|
||||
[SaveState.SaveWithName("InterruptNextClock")]
|
||||
private int _interruptNextClock;
|
||||
[SaveState.SaveWithName("T1Loaded")]
|
||||
private bool _t1CLoaded;
|
||||
[SaveState.SaveWithName("T2Loaded")]
|
||||
private bool _t2CLoaded;
|
||||
[SaveState.SaveWithName("T1Delayed")]
|
||||
private int _t1Delayed;
|
||||
[SaveState.SaveWithName("T2Delayed")]
|
||||
private int _t2Delayed;
|
||||
|
||||
public Via()
|
||||
{
|
||||
_port = new DisconnectedPort();
|
||||
}
|
||||
public Via()
|
||||
{
|
||||
_port = new DisconnectedPort();
|
||||
}
|
||||
|
||||
public Via(Func<int> readPrA, Func<int> readPrB)
|
||||
{
|
||||
_port = new DriverPort(readPrA, readPrB);
|
||||
}
|
||||
public Via(Func<int> readPrA, Func<int> readPrB)
|
||||
{
|
||||
_port = new DriverPort(readPrA, readPrB);
|
||||
}
|
||||
|
||||
public Via(Func<bool> readClock, Func<bool> readData, Func<bool> readAtn, int driveNumber)
|
||||
{
|
||||
_port = new IecPort(readClock, readData, readAtn, driveNumber);
|
||||
_ca1L = true;
|
||||
}
|
||||
public Via(Func<bool> readClock, Func<bool> readData, Func<bool> readAtn, int driveNumber)
|
||||
{
|
||||
_port = new IecPort(readClock, readData, readAtn, driveNumber);
|
||||
_ca1L = true;
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public bool Irq
|
||||
{
|
||||
get { return (_ifr & 0x80) == 0; }
|
||||
}
|
||||
[SaveState.DoNotSave]
|
||||
public bool Irq
|
||||
{
|
||||
get { return (_ifr & 0x80) == 0; }
|
||||
}
|
||||
|
||||
public void HardReset()
|
||||
{
|
||||
_pra = 0;
|
||||
_prb = 0;
|
||||
_ddra = 0;
|
||||
_ddrb = 0;
|
||||
_t1C = 0;
|
||||
_t1L = 0;
|
||||
_t2C = 0;
|
||||
_t2L = 0;
|
||||
_sr = 0;
|
||||
_acr = 0;
|
||||
_pcr = 0;
|
||||
_ifr = 0;
|
||||
_ier = 0;
|
||||
_paLatch = 0;
|
||||
_pbLatch = 0;
|
||||
_pcrCa1IntControl = 0;
|
||||
_pcrCa2Control = 0;
|
||||
_pcrCb1IntControl = 0;
|
||||
_pcrCb2Control = 0;
|
||||
_acrPaLatchEnable = false;
|
||||
_acrPbLatchEnable = false;
|
||||
_acrSrControl = 0;
|
||||
_acrT1Control = 0;
|
||||
_acrT2Control = 0;
|
||||
_ca1L = false;
|
||||
_cb1L = false;
|
||||
Ca1 = false;
|
||||
Ca2 = false;
|
||||
Cb1 = false;
|
||||
Cb2 = false;
|
||||
public void HardReset()
|
||||
{
|
||||
_pra = 0;
|
||||
_prb = 0;
|
||||
_ddra = 0;
|
||||
_ddrb = 0;
|
||||
_t1C = 0;
|
||||
_t1L = 0;
|
||||
_t2C = 0;
|
||||
_t2L = 0;
|
||||
_sr = 0;
|
||||
_acr = 0;
|
||||
_pcr = 0;
|
||||
_ifr = 0;
|
||||
_ier = 0;
|
||||
_paLatch = 0;
|
||||
_pbLatch = 0;
|
||||
_pcrCa1IntControl = 0;
|
||||
_pcrCa2Control = 0;
|
||||
_pcrCb1IntControl = 0;
|
||||
_pcrCb2Control = 0;
|
||||
_acrPaLatchEnable = false;
|
||||
_acrPbLatchEnable = false;
|
||||
_acrSrControl = 0;
|
||||
_acrT1Control = 0;
|
||||
_acrT2Control = 0;
|
||||
_ca1L = false;
|
||||
_cb1L = false;
|
||||
Ca1 = false;
|
||||
Ca2 = false;
|
||||
Cb1 = false;
|
||||
Cb2 = false;
|
||||
|
||||
_pb6L = false;
|
||||
_pb6 = false;
|
||||
_resetCa2NextClock = false;
|
||||
_resetCb2NextClock = false;
|
||||
_handshakeCa2NextClock = false;
|
||||
_handshakeCb2NextClock = false;
|
||||
_interruptNextClock = 0;
|
||||
_t1CLoaded = false;
|
||||
_t2CLoaded = false;
|
||||
}
|
||||
_pb6L = false;
|
||||
_pb6 = false;
|
||||
_resetCa2NextClock = false;
|
||||
_resetCb2NextClock = false;
|
||||
_handshakeCa2NextClock = false;
|
||||
_handshakeCb2NextClock = false;
|
||||
_interruptNextClock = 0;
|
||||
_t1CLoaded = false;
|
||||
_t2CLoaded = false;
|
||||
}
|
||||
|
||||
public void ExecutePhase()
|
||||
{
|
||||
// Process delayed interrupts
|
||||
_ifr |= _interruptNextClock;
|
||||
_interruptNextClock = 0;
|
||||
public void ExecutePhase()
|
||||
{
|
||||
// Process delayed interrupts
|
||||
_ifr |= _interruptNextClock;
|
||||
_interruptNextClock = 0;
|
||||
|
||||
// Process 'pulse' and 'handshake' outputs on CA2 and CB2
|
||||
// Process 'pulse' and 'handshake' outputs on CA2 and CB2
|
||||
|
||||
if (_resetCa2NextClock)
|
||||
{
|
||||
Ca2 = true;
|
||||
_resetCa2NextClock = false;
|
||||
}
|
||||
else if (_handshakeCa2NextClock)
|
||||
{
|
||||
Ca2 = false;
|
||||
_resetCa2NextClock = _pcrCa2Control == PCR_CONTROL_PULSE_OUTPUT;
|
||||
_handshakeCa2NextClock = false;
|
||||
}
|
||||
if (_resetCa2NextClock)
|
||||
{
|
||||
Ca2 = true;
|
||||
_resetCa2NextClock = false;
|
||||
}
|
||||
else if (_handshakeCa2NextClock)
|
||||
{
|
||||
Ca2 = false;
|
||||
_resetCa2NextClock = _pcrCa2Control == PCR_CONTROL_PULSE_OUTPUT;
|
||||
_handshakeCa2NextClock = false;
|
||||
}
|
||||
|
||||
if (_resetCb2NextClock)
|
||||
{
|
||||
Cb2 = true;
|
||||
_resetCb2NextClock = false;
|
||||
}
|
||||
else if (_handshakeCb2NextClock)
|
||||
{
|
||||
Cb2 = false;
|
||||
_resetCb2NextClock = _pcrCb2Control == PCR_CONTROL_PULSE_OUTPUT;
|
||||
_handshakeCb2NextClock = false;
|
||||
}
|
||||
if (_resetCb2NextClock)
|
||||
{
|
||||
Cb2 = true;
|
||||
_resetCb2NextClock = false;
|
||||
}
|
||||
else if (_handshakeCb2NextClock)
|
||||
{
|
||||
Cb2 = false;
|
||||
_resetCb2NextClock = _pcrCb2Control == PCR_CONTROL_PULSE_OUTPUT;
|
||||
_handshakeCb2NextClock = false;
|
||||
}
|
||||
|
||||
// Count timers
|
||||
// Count timers
|
||||
|
||||
if (_t1Delayed > 0)
|
||||
{
|
||||
_t1Delayed--;
|
||||
}
|
||||
else
|
||||
{
|
||||
_t1C--;
|
||||
if (_t1C < 0)
|
||||
{
|
||||
if (_t1CLoaded)
|
||||
{
|
||||
_interruptNextClock |= 0x40;
|
||||
_t1CLoaded = false;
|
||||
}
|
||||
switch (_acrT1Control)
|
||||
{
|
||||
case ACR_T1_CONTROL_CONTINUOUS_INTERRUPTS:
|
||||
_t1C = _t1L;
|
||||
_t1CLoaded = true;
|
||||
break;
|
||||
case ACR_T1_CONTROL_CONTINUOUS_INTERRUPTS_AND_OUTPUT_ON_PB7:
|
||||
_t1C = _t1L;
|
||||
_prb ^= 0x80;
|
||||
_t1CLoaded = true;
|
||||
break;
|
||||
}
|
||||
_t1C &= 0xFFFF;
|
||||
}
|
||||
}
|
||||
if (_t1Delayed > 0)
|
||||
{
|
||||
_t1Delayed--;
|
||||
}
|
||||
else
|
||||
{
|
||||
_t1C--;
|
||||
if (_t1C < 0)
|
||||
{
|
||||
if (_t1CLoaded)
|
||||
{
|
||||
_interruptNextClock |= 0x40;
|
||||
_t1CLoaded = false;
|
||||
}
|
||||
switch (_acrT1Control)
|
||||
{
|
||||
case ACR_T1_CONTROL_CONTINUOUS_INTERRUPTS:
|
||||
_t1C = _t1L;
|
||||
_t1CLoaded = true;
|
||||
break;
|
||||
case ACR_T1_CONTROL_CONTINUOUS_INTERRUPTS_AND_OUTPUT_ON_PB7:
|
||||
_t1C = _t1L;
|
||||
_prb ^= 0x80;
|
||||
_t1CLoaded = true;
|
||||
break;
|
||||
}
|
||||
_t1C &= 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
if (_t2Delayed > 0)
|
||||
{
|
||||
_t2Delayed--;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (_acrT2Control)
|
||||
{
|
||||
case ACR_T2_CONTROL_TIMED:
|
||||
_t2C--;
|
||||
if (_t2C < 0)
|
||||
{
|
||||
if (_t2CLoaded)
|
||||
{
|
||||
_interruptNextClock |= 0x20;
|
||||
_t2CLoaded = false;
|
||||
}
|
||||
_t2C = _t2L;
|
||||
}
|
||||
break;
|
||||
case ACR_T2_CONTROL_COUNT_ON_PB6:
|
||||
_pb6L = _pb6;
|
||||
_pb6 = (_port.ReadExternalPrb() & 0x40) != 0;
|
||||
if (!_pb6 && _pb6L)
|
||||
{
|
||||
_t2C--;
|
||||
if (_t2C < 0)
|
||||
{
|
||||
_ifr |= 0x20;
|
||||
_t2C = 0xFFFF;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_t2Delayed > 0)
|
||||
{
|
||||
_t2Delayed--;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (_acrT2Control)
|
||||
{
|
||||
case ACR_T2_CONTROL_TIMED:
|
||||
_t2C--;
|
||||
if (_t2C < 0)
|
||||
{
|
||||
if (_t2CLoaded)
|
||||
{
|
||||
_interruptNextClock |= 0x20;
|
||||
_t2CLoaded = false;
|
||||
}
|
||||
_t2C = _t2L;
|
||||
}
|
||||
break;
|
||||
case ACR_T2_CONTROL_COUNT_ON_PB6:
|
||||
_pb6L = _pb6;
|
||||
_pb6 = (_port.ReadExternalPrb() & 0x40) != 0;
|
||||
if (!_pb6 && _pb6L)
|
||||
{
|
||||
_t2C--;
|
||||
if (_t2C < 0)
|
||||
{
|
||||
_ifr |= 0x20;
|
||||
_t2C = 0xFFFF;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Process CA2
|
||||
// Process CA2
|
||||
|
||||
switch (_pcrCa2Control)
|
||||
{
|
||||
case PCR_CONTROL_INPUT_NEGATIVE_ACTIVE_EDGE:
|
||||
case PCR_CONTROL_INDEPENDENT_INTERRUPT_INPUT_NEGATIVE_EDGE:
|
||||
if (_ca2L && !Ca2)
|
||||
_ifr |= 0x01;
|
||||
break;
|
||||
case PCR_CONTROL_INPUT_POSITIVE_ACTIVE_EDGE:
|
||||
case PCR_CONTROL_INDEPENDENT_INTERRUPT_INPUT_POSITIVE_EDGE:
|
||||
if (!_ca2L && Ca2)
|
||||
_ifr |= 0x01;
|
||||
break;
|
||||
case PCR_CONTROL_HANDSHAKE_OUTPUT:
|
||||
if (_ca1L && !Ca1)
|
||||
{
|
||||
Ca2 = true;
|
||||
_ifr |= 0x01;
|
||||
}
|
||||
break;
|
||||
case PCR_CONTROL_PULSE_OUTPUT:
|
||||
break;
|
||||
case PCR_CONTROL_LOW_OUTPUT:
|
||||
Ca2 = false;
|
||||
break;
|
||||
case PCR_CONTROL_HIGH_OUTPUT:
|
||||
Ca2 = true;
|
||||
break;
|
||||
}
|
||||
switch (_pcrCa2Control)
|
||||
{
|
||||
case PCR_CONTROL_INPUT_NEGATIVE_ACTIVE_EDGE:
|
||||
case PCR_CONTROL_INDEPENDENT_INTERRUPT_INPUT_NEGATIVE_EDGE:
|
||||
if (_ca2L && !Ca2)
|
||||
_ifr |= 0x01;
|
||||
break;
|
||||
case PCR_CONTROL_INPUT_POSITIVE_ACTIVE_EDGE:
|
||||
case PCR_CONTROL_INDEPENDENT_INTERRUPT_INPUT_POSITIVE_EDGE:
|
||||
if (!_ca2L && Ca2)
|
||||
_ifr |= 0x01;
|
||||
break;
|
||||
case PCR_CONTROL_HANDSHAKE_OUTPUT:
|
||||
if (_ca1L && !Ca1)
|
||||
{
|
||||
Ca2 = true;
|
||||
_ifr |= 0x01;
|
||||
}
|
||||
break;
|
||||
case PCR_CONTROL_PULSE_OUTPUT:
|
||||
break;
|
||||
case PCR_CONTROL_LOW_OUTPUT:
|
||||
Ca2 = false;
|
||||
break;
|
||||
case PCR_CONTROL_HIGH_OUTPUT:
|
||||
Ca2 = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Process CB2
|
||||
// Process CB2
|
||||
|
||||
switch (_pcrCb2Control)
|
||||
{
|
||||
case PCR_CONTROL_INPUT_NEGATIVE_ACTIVE_EDGE:
|
||||
case PCR_CONTROL_INDEPENDENT_INTERRUPT_INPUT_NEGATIVE_EDGE:
|
||||
if (_cb2L && !Cb2)
|
||||
_ifr |= 0x08;
|
||||
break;
|
||||
case PCR_CONTROL_INPUT_POSITIVE_ACTIVE_EDGE:
|
||||
case PCR_CONTROL_INDEPENDENT_INTERRUPT_INPUT_POSITIVE_EDGE:
|
||||
if (!_cb2L && Cb2)
|
||||
_ifr |= 0x08;
|
||||
break;
|
||||
case PCR_CONTROL_HANDSHAKE_OUTPUT:
|
||||
if (_cb1L && !Cb1)
|
||||
{
|
||||
Cb2 = true;
|
||||
_ifr |= 0x08;
|
||||
}
|
||||
break;
|
||||
case PCR_CONTROL_PULSE_OUTPUT:
|
||||
break;
|
||||
case PCR_CONTROL_LOW_OUTPUT:
|
||||
Cb2 = false;
|
||||
break;
|
||||
case PCR_CONTROL_HIGH_OUTPUT:
|
||||
Cb2 = true;
|
||||
break;
|
||||
}
|
||||
switch (_pcrCb2Control)
|
||||
{
|
||||
case PCR_CONTROL_INPUT_NEGATIVE_ACTIVE_EDGE:
|
||||
case PCR_CONTROL_INDEPENDENT_INTERRUPT_INPUT_NEGATIVE_EDGE:
|
||||
if (_cb2L && !Cb2)
|
||||
_ifr |= 0x08;
|
||||
break;
|
||||
case PCR_CONTROL_INPUT_POSITIVE_ACTIVE_EDGE:
|
||||
case PCR_CONTROL_INDEPENDENT_INTERRUPT_INPUT_POSITIVE_EDGE:
|
||||
if (!_cb2L && Cb2)
|
||||
_ifr |= 0x08;
|
||||
break;
|
||||
case PCR_CONTROL_HANDSHAKE_OUTPUT:
|
||||
if (_cb1L && !Cb1)
|
||||
{
|
||||
Cb2 = true;
|
||||
_ifr |= 0x08;
|
||||
}
|
||||
break;
|
||||
case PCR_CONTROL_PULSE_OUTPUT:
|
||||
break;
|
||||
case PCR_CONTROL_LOW_OUTPUT:
|
||||
Cb2 = false;
|
||||
break;
|
||||
case PCR_CONTROL_HIGH_OUTPUT:
|
||||
Cb2 = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// interrupt generation
|
||||
// interrupt generation
|
||||
|
||||
if ((_pcrCb1IntControl == PCR_INT_CONTROL_POSITIVE_EDGE && Cb1 && !_cb1L) ||
|
||||
(_pcrCb1IntControl == PCR_INT_CONTROL_NEGATIVE_EDGE && !Cb1 && _cb1L))
|
||||
{
|
||||
_ifr |= 0x10;
|
||||
if (_acrPbLatchEnable)
|
||||
{
|
||||
_pbLatch = _port.ReadExternalPrb();
|
||||
}
|
||||
}
|
||||
if ((_pcrCb1IntControl == PCR_INT_CONTROL_POSITIVE_EDGE && Cb1 && !_cb1L) ||
|
||||
(_pcrCb1IntControl == PCR_INT_CONTROL_NEGATIVE_EDGE && !Cb1 && _cb1L))
|
||||
{
|
||||
_ifr |= 0x10;
|
||||
if (_acrPbLatchEnable)
|
||||
{
|
||||
_pbLatch = _port.ReadExternalPrb();
|
||||
}
|
||||
}
|
||||
|
||||
if ((_pcrCa1IntControl == PCR_INT_CONTROL_POSITIVE_EDGE && Ca1 && !_ca1L) ||
|
||||
(_pcrCa1IntControl == PCR_INT_CONTROL_NEGATIVE_EDGE && !Ca1 && _ca1L))
|
||||
{
|
||||
_ifr |= 0x02;
|
||||
if (_acrPaLatchEnable)
|
||||
{
|
||||
_paLatch = _port.ReadExternalPra();
|
||||
}
|
||||
}
|
||||
if ((_pcrCa1IntControl == PCR_INT_CONTROL_POSITIVE_EDGE && Ca1 && !_ca1L) ||
|
||||
(_pcrCa1IntControl == PCR_INT_CONTROL_NEGATIVE_EDGE && !Ca1 && _ca1L))
|
||||
{
|
||||
_ifr |= 0x02;
|
||||
if (_acrPaLatchEnable)
|
||||
{
|
||||
_paLatch = _port.ReadExternalPra();
|
||||
}
|
||||
}
|
||||
|
||||
switch (_acrSrControl)
|
||||
{
|
||||
case ACR_SR_CONTROL_DISABLED:
|
||||
_ifr &= 0xFB;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (_acrSrControl)
|
||||
{
|
||||
case ACR_SR_CONTROL_DISABLED:
|
||||
_ifr &= 0xFB;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ((_ifr & _ier & 0x7F) != 0)
|
||||
{
|
||||
_ifr |= 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
_ifr &= 0x7F;
|
||||
}
|
||||
if ((_ifr & _ier & 0x7F) != 0)
|
||||
{
|
||||
_ifr |= 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
_ifr &= 0x7F;
|
||||
}
|
||||
|
||||
_ca1L = Ca1;
|
||||
_ca2L = Ca2;
|
||||
_cb1L = Cb1;
|
||||
_cb2L = Cb2;
|
||||
}
|
||||
_ca1L = Ca1;
|
||||
_ca2L = Ca2;
|
||||
_cb1L = Cb1;
|
||||
_cb2L = Cb2;
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
}
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,37 +2,37 @@
|
|||
{
|
||||
public sealed partial class Vic
|
||||
{
|
||||
private const int BaResetCounter = 4;
|
||||
private const int PipelineUpdateVc = 0x00000001; // vc/rc rule 2
|
||||
private const int PipelineSpriteCrunch = 0x00000002;
|
||||
private const int PipelineUpdateMcBase = 0x00000004;
|
||||
private const int PipelineBorderLeft1 = 0x00000008;
|
||||
private const int PipelineBorderLeft0 = 0x00000010;
|
||||
private const int PipelineSpriteDma = 0x00000020; // sprite rule 3
|
||||
private const int PipelineBorderRight0 = 0x00000040;
|
||||
private const int PipelineSpriteExpansion = 0x00000080; // sprite rule 2
|
||||
private const int PipelineBorderRight1 = 0x00000100;
|
||||
private const int PipelineSpriteDisplay = 0x00000200; // sprite rule 4
|
||||
private const int PipelineUpdateRc = 0x00000400; // vc/rc rule 5
|
||||
private const int PipelineHoldX = 0x40000000;
|
||||
private const int RasterIrqLine0Cycle = 2;
|
||||
private const int RasterIrqLineXCycle = 1;
|
||||
private const int FetchTypeSprite = 0x0000;
|
||||
private const int FetchTypeRefresh = 0x0100;
|
||||
private const int FetchTypeColor = 0x0200;
|
||||
private const int FetchTypeGraphics = 0x0300;
|
||||
private const int FetchTypeIdle = 0x0400;
|
||||
private const int FetchTypeNone = 0x0500;
|
||||
private const int BaTypeNone = 0x0888;
|
||||
private const int BaTypeCharacter = 0x1000;
|
||||
private const int BaTypeMaskSprite0 = 0x000F;
|
||||
private const int BaTypeMaskSprite1 = 0x00F0;
|
||||
private const int BaTypeMaskSprite2 = 0x0F00;
|
||||
private const int AddressMask = 0x3FFF;
|
||||
private const int AddressMaskEc = 0x39FF;
|
||||
private const int AddressMaskRefresh = 0x3F00;
|
||||
private const int BaResetCounter = 4;
|
||||
private const int PipelineUpdateVc = 0x00000001; // vc/rc rule 2
|
||||
private const int PipelineSpriteCrunch = 0x00000002;
|
||||
private const int PipelineUpdateMcBase = 0x00000004;
|
||||
private const int PipelineBorderLeft1 = 0x00000008;
|
||||
private const int PipelineBorderLeft0 = 0x00000010;
|
||||
private const int PipelineSpriteDma = 0x00000020; // sprite rule 3
|
||||
private const int PipelineBorderRight0 = 0x00000040;
|
||||
private const int PipelineSpriteExpansion = 0x00000080; // sprite rule 2
|
||||
private const int PipelineBorderRight1 = 0x00000100;
|
||||
private const int PipelineSpriteDisplay = 0x00000200; // sprite rule 4
|
||||
private const int PipelineUpdateRc = 0x00000400; // vc/rc rule 5
|
||||
private const int PipelineHoldX = 0x40000000;
|
||||
private const int RasterIrqLine0Cycle = 2;
|
||||
private const int RasterIrqLineXCycle = 1;
|
||||
private const int FetchTypeSprite = 0x0000;
|
||||
private const int FetchTypeRefresh = 0x0100;
|
||||
private const int FetchTypeColor = 0x0200;
|
||||
private const int FetchTypeGraphics = 0x0300;
|
||||
private const int FetchTypeIdle = 0x0400;
|
||||
private const int FetchTypeNone = 0x0500;
|
||||
private const int BaTypeNone = 0x0888;
|
||||
private const int BaTypeCharacter = 0x1000;
|
||||
private const int BaTypeMaskSprite0 = 0x000F;
|
||||
private const int BaTypeMaskSprite1 = 0x00F0;
|
||||
private const int BaTypeMaskSprite2 = 0x0F00;
|
||||
private const int AddressMask = 0x3FFF;
|
||||
private const int AddressMaskEc = 0x39FF;
|
||||
private const int AddressMaskRefresh = 0x3F00;
|
||||
|
||||
[SaveState.DoNotSave] private int _parseAddr;
|
||||
[SaveState.DoNotSave] private int _parseAddr;
|
||||
[SaveState.DoNotSave] private int _parseCycleBaSprite0;
|
||||
[SaveState.DoNotSave] private int _parseCycleBaSprite1;
|
||||
[SaveState.DoNotSave] private int _parseCycleBaSprite2;
|
||||
|
@ -41,11 +41,11 @@
|
|||
[SaveState.DoNotSave] private int _parseFetchType;
|
||||
[SaveState.DoNotSave] private int _parseBa;
|
||||
[SaveState.DoNotSave] private int _parseAct;
|
||||
private bool _parseIsSprCrunch;
|
||||
private bool _parseIsSprCrunch;
|
||||
|
||||
private void ParseCycle()
|
||||
{
|
||||
// initialization
|
||||
// initialization
|
||||
_parseAddr = AddressMask;
|
||||
_parseFetch = _fetchPipeline[_cycleIndex];
|
||||
_parseBa = _baPipeline[_cycleIndex];
|
||||
|
@ -59,89 +59,89 @@
|
|||
_parseFetchType = _parseFetch & 0xFF00;
|
||||
switch (_parseFetchType)
|
||||
{
|
||||
case FetchTypeColor:
|
||||
// fetch C
|
||||
if (!_idle)
|
||||
{
|
||||
if (_badline)
|
||||
{
|
||||
_parseAddr = _pointerVm | _vc;
|
||||
_dataC = ReadMemory(_parseAddr);
|
||||
_dataC |= (ReadColorRam(_parseAddr) & 0xF) << 8;
|
||||
_bufferC[_vmli] = _dataC;
|
||||
}
|
||||
else
|
||||
{
|
||||
_dataC = _bufferC[_vmli];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_dataC = 0;
|
||||
_bufferC[_vmli] = _dataC;
|
||||
}
|
||||
_srColorSync |= 0x01 << (7 - _xScroll);
|
||||
break;
|
||||
case FetchTypeGraphics:
|
||||
// fetch G
|
||||
if (!_idle)
|
||||
{
|
||||
if (_bitmapMode)
|
||||
_parseAddr = _rc | (_vc << 3) | ((_pointerCb & 0x4) << 11);
|
||||
else
|
||||
_parseAddr = _rc | ((_dataC & 0xFF) << 3) | (_pointerCb << 11);
|
||||
}
|
||||
if (_extraColorModeBuffer)
|
||||
_parseAddr &= AddressMaskEc;
|
||||
_dataG = ReadMemory(_parseAddr);
|
||||
_sr |= _dataG << (7 - _xScroll);
|
||||
_srSync |= 0xAA << (7 - _xScroll);
|
||||
if (!_idle)
|
||||
{
|
||||
_bufferG[_vmli] = _dataG;
|
||||
_vmli = (_vmli + 1) & 0x3F;
|
||||
_vc = (_vc + 1) & 0x3FF;
|
||||
}
|
||||
break;
|
||||
case FetchTypeNone:
|
||||
// fetch none
|
||||
break;
|
||||
case FetchTypeRefresh:
|
||||
// fetch R
|
||||
_refreshCounter = (_refreshCounter - 1) & 0xFF;
|
||||
_parseAddr = AddressMaskRefresh | _refreshCounter;
|
||||
ReadMemory(_parseAddr);
|
||||
break;
|
||||
case FetchTypeIdle:
|
||||
// fetch I
|
||||
ReadMemory(AddressMask);
|
||||
break;
|
||||
default:
|
||||
_parseCycleFetchSpriteIndex = _parseFetch & 0x7;
|
||||
if ((_parseFetch & 0xF0) == 0) // sprite rule 5
|
||||
{
|
||||
// fetch P
|
||||
_parseAddr = 0x3F8 | _pointerVm | _parseCycleFetchSpriteIndex;
|
||||
_sprites[_parseCycleFetchSpriteIndex].Pointer = ReadMemory(_parseAddr);
|
||||
_sprites[_parseCycleFetchSpriteIndex].ShiftEnable = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// fetch S
|
||||
var spr = _sprites[_parseCycleFetchSpriteIndex];
|
||||
if (spr.Dma)
|
||||
{
|
||||
_parseAddr = spr.Mc | (spr.Pointer << 6);
|
||||
spr.Sr |= ReadMemory(_parseAddr) << ((0x30 - (_parseFetch & 0x30)) >> 1);
|
||||
spr.Mc++;
|
||||
spr.Loaded |= 0x800000;
|
||||
}
|
||||
else if ((_parseFetch & 0xF0) == 0x20)
|
||||
{
|
||||
ReadMemory(AddressMask);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FetchTypeColor:
|
||||
// fetch C
|
||||
if (!_idle)
|
||||
{
|
||||
if (_badline)
|
||||
{
|
||||
_parseAddr = _pointerVm | _vc;
|
||||
_dataC = ReadMemory(_parseAddr);
|
||||
_dataC |= (ReadColorRam(_parseAddr) & 0xF) << 8;
|
||||
_bufferC[_vmli] = _dataC;
|
||||
}
|
||||
else
|
||||
{
|
||||
_dataC = _bufferC[_vmli];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_dataC = 0;
|
||||
_bufferC[_vmli] = _dataC;
|
||||
}
|
||||
_srColorSync |= 0x01 << (7 - _xScroll);
|
||||
break;
|
||||
case FetchTypeGraphics:
|
||||
// fetch G
|
||||
if (!_idle)
|
||||
{
|
||||
if (_bitmapMode)
|
||||
_parseAddr = _rc | (_vc << 3) | ((_pointerCb & 0x4) << 11);
|
||||
else
|
||||
_parseAddr = _rc | ((_dataC & 0xFF) << 3) | (_pointerCb << 11);
|
||||
}
|
||||
if (_extraColorModeBuffer)
|
||||
_parseAddr &= AddressMaskEc;
|
||||
_dataG = ReadMemory(_parseAddr);
|
||||
_sr |= _dataG << (7 - _xScroll);
|
||||
_srSync |= 0xAA << (7 - _xScroll);
|
||||
if (!_idle)
|
||||
{
|
||||
_bufferG[_vmli] = _dataG;
|
||||
_vmli = (_vmli + 1) & 0x3F;
|
||||
_vc = (_vc + 1) & 0x3FF;
|
||||
}
|
||||
break;
|
||||
case FetchTypeNone:
|
||||
// fetch none
|
||||
break;
|
||||
case FetchTypeRefresh:
|
||||
// fetch R
|
||||
_refreshCounter = (_refreshCounter - 1) & 0xFF;
|
||||
_parseAddr = AddressMaskRefresh | _refreshCounter;
|
||||
ReadMemory(_parseAddr);
|
||||
break;
|
||||
case FetchTypeIdle:
|
||||
// fetch I
|
||||
ReadMemory(AddressMask);
|
||||
break;
|
||||
default:
|
||||
_parseCycleFetchSpriteIndex = _parseFetch & 0x7;
|
||||
if ((_parseFetch & 0xF0) == 0) // sprite rule 5
|
||||
{
|
||||
// fetch P
|
||||
_parseAddr = 0x3F8 | _pointerVm | _parseCycleFetchSpriteIndex;
|
||||
_sprites[_parseCycleFetchSpriteIndex].Pointer = ReadMemory(_parseAddr);
|
||||
_sprites[_parseCycleFetchSpriteIndex].ShiftEnable = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// fetch S
|
||||
var spr = _sprites[_parseCycleFetchSpriteIndex];
|
||||
if (spr.Dma)
|
||||
{
|
||||
_parseAddr = spr.Mc | (spr.Pointer << 6);
|
||||
spr.Sr |= ReadMemory(_parseAddr) << ((0x30 - (_parseFetch & 0x30)) >> 1);
|
||||
spr.Mc++;
|
||||
spr.Loaded |= 0x800000;
|
||||
}
|
||||
else if ((_parseFetch & 0xF0) == 0x20)
|
||||
{
|
||||
ReadMemory(AddressMask);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// perform actions
|
||||
|
@ -154,22 +154,22 @@
|
|||
spr.YCrunch = true;
|
||||
}
|
||||
|
||||
if ((_parseAct & PipelineUpdateMcBase) != 0) // VIC addendum sprite rule 7
|
||||
{
|
||||
foreach (var spr in _sprites)
|
||||
{
|
||||
if (spr.YCrunch)
|
||||
{
|
||||
spr.Mcbase = spr.Mc;
|
||||
if (spr.Mcbase == 63)
|
||||
{
|
||||
spr.Dma = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((_parseAct & PipelineUpdateMcBase) != 0) // VIC addendum sprite rule 7
|
||||
{
|
||||
foreach (var spr in _sprites)
|
||||
{
|
||||
if (spr.YCrunch)
|
||||
{
|
||||
spr.Mcbase = spr.Mc;
|
||||
if (spr.Mcbase == 63)
|
||||
{
|
||||
spr.Dma = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((_parseAct & PipelineSpriteDma) != 0) // sprite rule 3
|
||||
if ((_parseAct & PipelineSpriteDma) != 0) // sprite rule 3
|
||||
{
|
||||
foreach (var spr in _sprites)
|
||||
{
|
||||
|
@ -182,24 +182,24 @@
|
|||
}
|
||||
}
|
||||
|
||||
if ((_parseAct & PipelineSpriteExpansion) != 0) // sprite rule 2
|
||||
{
|
||||
foreach (var spr in _sprites)
|
||||
{
|
||||
if (spr.Dma && spr.YExpand)
|
||||
spr.YCrunch ^= true;
|
||||
}
|
||||
}
|
||||
if ((_parseAct & PipelineSpriteExpansion) != 0) // sprite rule 2
|
||||
{
|
||||
foreach (var spr in _sprites)
|
||||
{
|
||||
if (spr.Dma && spr.YExpand)
|
||||
spr.YCrunch ^= true;
|
||||
}
|
||||
}
|
||||
|
||||
if ((_parseAct & PipelineSpriteDisplay) != 0) // VIC addendum on sprite rule 4
|
||||
if ((_parseAct & PipelineSpriteDisplay) != 0) // VIC addendum on sprite rule 4
|
||||
{
|
||||
foreach (var spr in _sprites)
|
||||
{
|
||||
spr.Mc = spr.Mcbase;
|
||||
if (spr.Dma)
|
||||
{
|
||||
if (spr.Enable && spr.Y == (_rasterLine & 0xFF))
|
||||
spr.Display = true;
|
||||
if (spr.Enable && spr.Y == (_rasterLine & 0xFF))
|
||||
spr.Display = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -208,52 +208,52 @@
|
|||
}
|
||||
}
|
||||
|
||||
_parseIsSprCrunch = (_parseAct & PipelineSpriteCrunch) != 0; // VIC addendum sprite rule 7
|
||||
_parseIsSprCrunch = (_parseAct & PipelineSpriteCrunch) != 0; // VIC addendum sprite rule 7
|
||||
|
||||
if ((_parseAct & PipelineUpdateVc) != 0) // VC/RC rule 2
|
||||
{
|
||||
_vc = _vcbase;
|
||||
_srColorIndexLatch = 0;
|
||||
_vmli = 0;
|
||||
if (_badline)
|
||||
_rc = 0;
|
||||
}
|
||||
if ((_parseAct & PipelineUpdateVc) != 0) // VC/RC rule 2
|
||||
{
|
||||
_vc = _vcbase;
|
||||
_srColorIndexLatch = 0;
|
||||
_vmli = 0;
|
||||
if (_badline)
|
||||
_rc = 0;
|
||||
}
|
||||
|
||||
if ((_parseAct & PipelineUpdateRc) != 0) // VC/RC rule 5
|
||||
if ((_parseAct & PipelineUpdateRc) != 0) // VC/RC rule 5
|
||||
{
|
||||
if (_rc == 7)
|
||||
{
|
||||
_idle = true;
|
||||
_vcbase = _vc;
|
||||
}
|
||||
if (!_idle || _badline)
|
||||
{
|
||||
_rc = (_rc + 1) & 0x7;
|
||||
_idle = false;
|
||||
}
|
||||
}
|
||||
if (!_idle || _badline)
|
||||
{
|
||||
_rc = (_rc + 1) & 0x7;
|
||||
_idle = false;
|
||||
}
|
||||
}
|
||||
|
||||
// perform BA flag manipulation
|
||||
_pinBa = true;
|
||||
switch (_parseBa)
|
||||
{
|
||||
case BaTypeNone:
|
||||
break;
|
||||
case BaTypeCharacter:
|
||||
_pinBa = !_badline;
|
||||
break;
|
||||
default:
|
||||
_parseCycleBaSprite0 = _parseBa & BaTypeMaskSprite0;
|
||||
_parseCycleBaSprite1 = (_parseBa & BaTypeMaskSprite1) >> 4;
|
||||
_parseCycleBaSprite2 = (_parseBa & BaTypeMaskSprite2) >> 8;
|
||||
if ((_parseCycleBaSprite0 < 8 && _sprites[_parseCycleBaSprite0].Dma) ||
|
||||
(_parseCycleBaSprite1 < 8 && _sprites[_parseCycleBaSprite1].Dma) ||
|
||||
(_parseCycleBaSprite2 < 8 && _sprites[_parseCycleBaSprite2].Dma))
|
||||
_pinBa = false;
|
||||
break;
|
||||
}
|
||||
// perform BA flag manipulation
|
||||
_pinBa = true;
|
||||
switch (_parseBa)
|
||||
{
|
||||
case BaTypeNone:
|
||||
break;
|
||||
case BaTypeCharacter:
|
||||
_pinBa = !_badline;
|
||||
break;
|
||||
default:
|
||||
_parseCycleBaSprite0 = _parseBa & BaTypeMaskSprite0;
|
||||
_parseCycleBaSprite1 = (_parseBa & BaTypeMaskSprite1) >> 4;
|
||||
_parseCycleBaSprite2 = (_parseBa & BaTypeMaskSprite2) >> 8;
|
||||
if ((_parseCycleBaSprite0 < 8 && _sprites[_parseCycleBaSprite0].Dma) ||
|
||||
(_parseCycleBaSprite1 < 8 && _sprites[_parseCycleBaSprite1].Dma) ||
|
||||
(_parseCycleBaSprite2 < 8 && _sprites[_parseCycleBaSprite2].Dma))
|
||||
_pinBa = false;
|
||||
break;
|
||||
}
|
||||
|
||||
_cycleIndex++;
|
||||
_cycleIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,10 +19,10 @@
|
|||
switch (addr)
|
||||
{
|
||||
case 0x1E:
|
||||
_spriteSpriteCollisionClearPending = true;
|
||||
return ReadRegister(addr);
|
||||
case 0x1F:
|
||||
_spriteBackgroundCollisionClearPending = true;
|
||||
_spriteSpriteCollisionClearPending = true;
|
||||
return ReadRegister(addr);
|
||||
case 0x1F:
|
||||
_spriteBackgroundCollisionClearPending = true;
|
||||
return ReadRegister(addr);
|
||||
default:
|
||||
return ReadRegister(addr);
|
||||
|
@ -53,20 +53,20 @@
|
|||
return _sprites[addr >> 1].Y & 0xFF;
|
||||
case 0x10:
|
||||
return ((_sprite0.X >> 8) & 0x01) |
|
||||
((_sprite1.X >> 7) & 0x02) |
|
||||
((_sprite2.X >> 6) & 0x04) |
|
||||
((_sprite3.X >> 5) & 0x08) |
|
||||
((_sprite4.X >> 4) & 0x10) |
|
||||
((_sprite5.X >> 3) & 0x20) |
|
||||
((_sprite6.X >> 2) & 0x40) |
|
||||
((_sprite7.X >> 1) & 0x80);
|
||||
((_sprite1.X >> 7) & 0x02) |
|
||||
((_sprite2.X >> 6) & 0x04) |
|
||||
((_sprite3.X >> 5) & 0x08) |
|
||||
((_sprite4.X >> 4) & 0x10) |
|
||||
((_sprite5.X >> 3) & 0x20) |
|
||||
((_sprite6.X >> 2) & 0x40) |
|
||||
((_sprite7.X >> 1) & 0x80);
|
||||
case 0x11:
|
||||
return (_yScroll & 0x7) |
|
||||
(_rowSelect ? 0x08 : 0x00) |
|
||||
(_displayEnable ? 0x10 : 0x00) |
|
||||
(_bitmapMode ? 0x20 : 0x00) |
|
||||
(_extraColorMode ? 0x40 : 0x00) |
|
||||
((_rasterLine & 0x100) >> 1);
|
||||
(_rowSelect ? 0x08 : 0x00) |
|
||||
(_displayEnable ? 0x10 : 0x00) |
|
||||
(_bitmapMode ? 0x20 : 0x00) |
|
||||
(_extraColorMode ? 0x40 : 0x00) |
|
||||
((_rasterLine & 0x100) >> 1);
|
||||
case 0x12:
|
||||
return _rasterLine & 0xFF;
|
||||
case 0x13:
|
||||
|
@ -75,99 +75,99 @@
|
|||
return _lightPenY & 0xFF;
|
||||
case 0x15:
|
||||
return (_sprite0.Enable ? 0x01 : 0x00) |
|
||||
(_sprite1.Enable ? 0x02 : 0x00) |
|
||||
(_sprite2.Enable ? 0x04 : 0x00) |
|
||||
(_sprite3.Enable ? 0x08 : 0x00) |
|
||||
(_sprite4.Enable ? 0x10 : 0x00) |
|
||||
(_sprite5.Enable ? 0x20 : 0x00) |
|
||||
(_sprite6.Enable ? 0x40 : 0x00) |
|
||||
(_sprite7.Enable ? 0x80 : 0x00);
|
||||
(_sprite1.Enable ? 0x02 : 0x00) |
|
||||
(_sprite2.Enable ? 0x04 : 0x00) |
|
||||
(_sprite3.Enable ? 0x08 : 0x00) |
|
||||
(_sprite4.Enable ? 0x10 : 0x00) |
|
||||
(_sprite5.Enable ? 0x20 : 0x00) |
|
||||
(_sprite6.Enable ? 0x40 : 0x00) |
|
||||
(_sprite7.Enable ? 0x80 : 0x00);
|
||||
case 0x16:
|
||||
return 0xC0 | (_xScroll & 0x7) |
|
||||
(_columnSelect ? 0x08 : 0x00) |
|
||||
(_multicolorMode ? 0x10 : 0x00);
|
||||
(_columnSelect ? 0x08 : 0x00) |
|
||||
(_multicolorMode ? 0x10 : 0x00);
|
||||
case 0x17:
|
||||
return (_sprite0.YExpand ? 0x01 : 0x00) |
|
||||
(_sprite1.YExpand ? 0x02 : 0x00) |
|
||||
(_sprite2.YExpand ? 0x04 : 0x00) |
|
||||
(_sprite3.YExpand ? 0x08 : 0x00) |
|
||||
(_sprite4.YExpand ? 0x10 : 0x00) |
|
||||
(_sprite5.YExpand ? 0x20 : 0x00) |
|
||||
(_sprite6.YExpand ? 0x40 : 0x00) |
|
||||
(_sprite7.YExpand ? 0x80 : 0x00);
|
||||
(_sprite1.YExpand ? 0x02 : 0x00) |
|
||||
(_sprite2.YExpand ? 0x04 : 0x00) |
|
||||
(_sprite3.YExpand ? 0x08 : 0x00) |
|
||||
(_sprite4.YExpand ? 0x10 : 0x00) |
|
||||
(_sprite5.YExpand ? 0x20 : 0x00) |
|
||||
(_sprite6.YExpand ? 0x40 : 0x00) |
|
||||
(_sprite7.YExpand ? 0x80 : 0x00);
|
||||
case 0x18:
|
||||
return 0x01 | ((_pointerVm & 0x3C00) >> 6) |
|
||||
((_pointerCb & 0x7) << 1);
|
||||
((_pointerCb & 0x7) << 1);
|
||||
case 0x19:
|
||||
return 0x70 | (_intRaster ? 0x01 : 0x00) |
|
||||
(_intSpriteDataCollision ? 0x02 : 0x00) |
|
||||
(_intSpriteCollision ? 0x04 : 0x00) |
|
||||
(_intLightPen ? 0x08 : 0x00) |
|
||||
(_pinIrq ? 0x00 : 0x80);
|
||||
(_intSpriteDataCollision ? 0x02 : 0x00) |
|
||||
(_intSpriteCollision ? 0x04 : 0x00) |
|
||||
(_intLightPen ? 0x08 : 0x00) |
|
||||
(_pinIrq ? 0x00 : 0x80);
|
||||
case 0x1A:
|
||||
return 0xF0 | (_enableIntRaster ? 0x01 : 0x00) |
|
||||
(_enableIntSpriteDataCollision ? 0x02 : 0x00) |
|
||||
(_enableIntSpriteCollision ? 0x04 : 0x00) |
|
||||
(_enableIntLightPen ? 0x08 : 0x00);
|
||||
(_enableIntSpriteDataCollision ? 0x02 : 0x00) |
|
||||
(_enableIntSpriteCollision ? 0x04 : 0x00) |
|
||||
(_enableIntLightPen ? 0x08 : 0x00);
|
||||
case 0x1B:
|
||||
return (_sprite0.Priority ? 0x01 : 0x00) |
|
||||
(_sprite1.Priority ? 0x02 : 0x00) |
|
||||
(_sprite2.Priority ? 0x04 : 0x00) |
|
||||
(_sprite3.Priority ? 0x08 : 0x00) |
|
||||
(_sprite4.Priority ? 0x10 : 0x00) |
|
||||
(_sprite5.Priority ? 0x20 : 0x00) |
|
||||
(_sprite6.Priority ? 0x40 : 0x00) |
|
||||
(_sprite7.Priority ? 0x80 : 0x00);
|
||||
(_sprite1.Priority ? 0x02 : 0x00) |
|
||||
(_sprite2.Priority ? 0x04 : 0x00) |
|
||||
(_sprite3.Priority ? 0x08 : 0x00) |
|
||||
(_sprite4.Priority ? 0x10 : 0x00) |
|
||||
(_sprite5.Priority ? 0x20 : 0x00) |
|
||||
(_sprite6.Priority ? 0x40 : 0x00) |
|
||||
(_sprite7.Priority ? 0x80 : 0x00);
|
||||
case 0x1C:
|
||||
return (_sprite0.Multicolor ? 0x01 : 0x00) |
|
||||
(_sprite1.Multicolor ? 0x02 : 0x00) |
|
||||
(_sprite2.Multicolor ? 0x04 : 0x00) |
|
||||
(_sprite3.Multicolor ? 0x08 : 0x00) |
|
||||
(_sprite4.Multicolor ? 0x10 : 0x00) |
|
||||
(_sprite5.Multicolor ? 0x20 : 0x00) |
|
||||
(_sprite6.Multicolor ? 0x40 : 0x00) |
|
||||
(_sprite7.Multicolor ? 0x80 : 0x00);
|
||||
(_sprite1.Multicolor ? 0x02 : 0x00) |
|
||||
(_sprite2.Multicolor ? 0x04 : 0x00) |
|
||||
(_sprite3.Multicolor ? 0x08 : 0x00) |
|
||||
(_sprite4.Multicolor ? 0x10 : 0x00) |
|
||||
(_sprite5.Multicolor ? 0x20 : 0x00) |
|
||||
(_sprite6.Multicolor ? 0x40 : 0x00) |
|
||||
(_sprite7.Multicolor ? 0x80 : 0x00);
|
||||
case 0x1D:
|
||||
return (_sprite0.XExpand ? 0x01 : 0x00) |
|
||||
(_sprite1.XExpand ? 0x02 : 0x00) |
|
||||
(_sprite2.XExpand ? 0x04 : 0x00) |
|
||||
(_sprite3.XExpand ? 0x08 : 0x00) |
|
||||
(_sprite4.XExpand ? 0x10 : 0x00) |
|
||||
(_sprite5.XExpand ? 0x20 : 0x00) |
|
||||
(_sprite6.XExpand ? 0x40 : 0x00) |
|
||||
(_sprite7.XExpand ? 0x80 : 0x00);
|
||||
(_sprite1.XExpand ? 0x02 : 0x00) |
|
||||
(_sprite2.XExpand ? 0x04 : 0x00) |
|
||||
(_sprite3.XExpand ? 0x08 : 0x00) |
|
||||
(_sprite4.XExpand ? 0x10 : 0x00) |
|
||||
(_sprite5.XExpand ? 0x20 : 0x00) |
|
||||
(_sprite6.XExpand ? 0x40 : 0x00) |
|
||||
(_sprite7.XExpand ? 0x80 : 0x00);
|
||||
case 0x1E:
|
||||
return (_sprite0.CollideSprite ? 0x01 : 0x00) |
|
||||
(_sprite1.CollideSprite ? 0x02 : 0x00) |
|
||||
(_sprite2.CollideSprite ? 0x04 : 0x00) |
|
||||
(_sprite3.CollideSprite ? 0x08 : 0x00) |
|
||||
(_sprite4.CollideSprite ? 0x10 : 0x00) |
|
||||
(_sprite5.CollideSprite ? 0x20 : 0x00) |
|
||||
(_sprite6.CollideSprite ? 0x40 : 0x00) |
|
||||
(_sprite7.CollideSprite ? 0x80 : 0x00);
|
||||
(_sprite1.CollideSprite ? 0x02 : 0x00) |
|
||||
(_sprite2.CollideSprite ? 0x04 : 0x00) |
|
||||
(_sprite3.CollideSprite ? 0x08 : 0x00) |
|
||||
(_sprite4.CollideSprite ? 0x10 : 0x00) |
|
||||
(_sprite5.CollideSprite ? 0x20 : 0x00) |
|
||||
(_sprite6.CollideSprite ? 0x40 : 0x00) |
|
||||
(_sprite7.CollideSprite ? 0x80 : 0x00);
|
||||
case 0x1F:
|
||||
return (_sprite0.CollideData ? 0x01 : 0x00) |
|
||||
(_sprite1.CollideData ? 0x02 : 0x00) |
|
||||
(_sprite2.CollideData ? 0x04 : 0x00) |
|
||||
(_sprite3.CollideData ? 0x08 : 0x00) |
|
||||
(_sprite4.CollideData ? 0x10 : 0x00) |
|
||||
(_sprite5.CollideData ? 0x20 : 0x00) |
|
||||
(_sprite6.CollideData ? 0x40 : 0x00) |
|
||||
(_sprite7.CollideData ? 0x80 : 0x00);
|
||||
(_sprite1.CollideData ? 0x02 : 0x00) |
|
||||
(_sprite2.CollideData ? 0x04 : 0x00) |
|
||||
(_sprite3.CollideData ? 0x08 : 0x00) |
|
||||
(_sprite4.CollideData ? 0x10 : 0x00) |
|
||||
(_sprite5.CollideData ? 0x20 : 0x00) |
|
||||
(_sprite6.CollideData ? 0x40 : 0x00) |
|
||||
(_sprite7.CollideData ? 0x80 : 0x00);
|
||||
case 0x20:
|
||||
return 0xF0 | _borderColor & 0x0F;
|
||||
case 0x21:
|
||||
return 0xF0 | _backgroundColor0 & 0x0F;
|
||||
return 0xF0 | _backgroundColor0 & 0x0F;
|
||||
case 0x22:
|
||||
return 0xF0 | _backgroundColor1 & 0x0F;
|
||||
return 0xF0 | _backgroundColor1 & 0x0F;
|
||||
case 0x23:
|
||||
return 0xF0 | _backgroundColor2 & 0x0F;
|
||||
return 0xF0 | _backgroundColor2 & 0x0F;
|
||||
case 0x24:
|
||||
return 0xF0 | _backgroundColor3 & 0x0F;
|
||||
return 0xF0 | _backgroundColor3 & 0x0F;
|
||||
case 0x25:
|
||||
return 0xF0 | _spriteMulticolor0 & 0x0F;
|
||||
return 0xF0 | _spriteMulticolor0 & 0x0F;
|
||||
case 0x26:
|
||||
return 0xF0 | _spriteMulticolor1 & 0x0F;
|
||||
return 0xF0 | _spriteMulticolor1 & 0x0F;
|
||||
case 0x27:
|
||||
case 0x28:
|
||||
case 0x29:
|
||||
|
@ -177,8 +177,8 @@
|
|||
case 0x2D:
|
||||
case 0x2E:
|
||||
return 0xF0 | _sprites[addr - 0x27].Color & 0xF;
|
||||
default:
|
||||
return 0xFF;
|
||||
default:
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -187,21 +187,21 @@
|
|||
addr &= 0x3F;
|
||||
switch (addr)
|
||||
{
|
||||
case 0x17:
|
||||
// vic-ii addendum rule 7
|
||||
foreach (var spr in _sprites)
|
||||
{
|
||||
if ((val & 1) == 0 && !spr.YCrunch)
|
||||
{
|
||||
if (_parseIsSprCrunch)
|
||||
{
|
||||
spr.Mc = (0x2a & spr.Mcbase & spr.Mc) | (0x15 & (spr.Mcbase | spr.Mc));
|
||||
}
|
||||
spr.YCrunch = true;
|
||||
}
|
||||
}
|
||||
WriteRegister(addr, val);
|
||||
break;
|
||||
case 0x17:
|
||||
// vic-ii addendum rule 7
|
||||
foreach (var spr in _sprites)
|
||||
{
|
||||
if ((val & 1) == 0 && !spr.YCrunch)
|
||||
{
|
||||
if (_parseIsSprCrunch)
|
||||
{
|
||||
spr.Mc = (0x2a & spr.Mcbase & spr.Mc) | (0x15 & (spr.Mcbase | spr.Mc));
|
||||
}
|
||||
spr.YCrunch = true;
|
||||
}
|
||||
}
|
||||
WriteRegister(addr, val);
|
||||
break;
|
||||
case 0x19:
|
||||
// interrupts are cleared by writing a 1
|
||||
if ((val & 0x01) != 0)
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
{
|
||||
public sealed partial class Vic
|
||||
{
|
||||
[SaveState.DoNotSave] private int _borderPixel;
|
||||
[SaveState.DoNotSave] private int _bufferPixel;
|
||||
[SaveState.DoNotSave] private int _ecmPixel;
|
||||
[SaveState.DoNotSave] private int _borderPixel;
|
||||
[SaveState.DoNotSave] private int _bufferPixel;
|
||||
[SaveState.DoNotSave] private int _ecmPixel;
|
||||
[SaveState.DoNotSave] private int _pixel;
|
||||
[SaveState.DoNotSave] private int _pixelCounter;
|
||||
[SaveState.DoNotSave] private int _pixelData;
|
||||
|
@ -12,51 +12,51 @@
|
|||
[SaveState.DoNotSave] private int _sprData;
|
||||
[SaveState.DoNotSave] private int _sprIndex;
|
||||
[SaveState.DoNotSave] private int _sprPixel;
|
||||
private int _srSync;
|
||||
private int _srColorSync;
|
||||
private int _srColorIndexLatch;
|
||||
private int _srSync;
|
||||
private int _srColorSync;
|
||||
private int _srColorIndexLatch;
|
||||
private int _videoMode;
|
||||
private int _borderOnShiftReg;
|
||||
private int _borderOnShiftReg;
|
||||
|
||||
[SaveState.DoNotSave] private const int VideoMode000 = 0;
|
||||
[SaveState.DoNotSave] private const int VideoMode001 = 1;
|
||||
[SaveState.DoNotSave] private const int VideoMode010 = 2;
|
||||
[SaveState.DoNotSave] private const int VideoMode011 = 3;
|
||||
[SaveState.DoNotSave] private const int VideoMode100 = 4;
|
||||
[SaveState.DoNotSave] private const int VideoModeInvalid = -1;
|
||||
[SaveState.DoNotSave] private const int VideoMode000 = 0;
|
||||
[SaveState.DoNotSave] private const int VideoMode001 = 1;
|
||||
[SaveState.DoNotSave] private const int VideoMode010 = 2;
|
||||
[SaveState.DoNotSave] private const int VideoMode011 = 3;
|
||||
[SaveState.DoNotSave] private const int VideoMode100 = 4;
|
||||
[SaveState.DoNotSave] private const int VideoModeInvalid = -1;
|
||||
|
||||
[SaveState.DoNotSave] private const int SrMask1 = 0x20000;
|
||||
[SaveState.DoNotSave] private const int SrMask1 = 0x20000;
|
||||
[SaveState.DoNotSave] private const int SrMask2 = SrMask1 << 1;
|
||||
[SaveState.DoNotSave] private const int SrMask3 = SrMask1 | SrMask2;
|
||||
[SaveState.DoNotSave] private const int SrColorMask = 0x8000;
|
||||
[SaveState.DoNotSave] private const int SrSpriteMask = SrSpriteMask2;
|
||||
[SaveState.DoNotSave] private const int SrSpriteMask1 = 0x400000;
|
||||
[SaveState.DoNotSave] private const int SrColorMask = 0x8000;
|
||||
[SaveState.DoNotSave] private const int SrSpriteMask = SrSpriteMask2;
|
||||
[SaveState.DoNotSave] private const int SrSpriteMask1 = 0x400000;
|
||||
[SaveState.DoNotSave] private const int SrSpriteMask2 = SrSpriteMask1 << 1;
|
||||
[SaveState.DoNotSave] private const int SrSpriteMask3 = SrSpriteMask1 | SrSpriteMask2;
|
||||
[SaveState.DoNotSave] private const int SrSpriteMaskMc = SrSpriteMask3;
|
||||
[SaveState.DoNotSave] private const int SrSpriteMaskMc = SrSpriteMask3;
|
||||
|
||||
private void Render()
|
||||
private void Render()
|
||||
{
|
||||
if (_rasterX == _hblankEndCheckXRaster)
|
||||
_hblank = false;
|
||||
if (_rasterX == _hblankStartCheckXRaster)
|
||||
_hblank = true;
|
||||
if (_rasterX == _hblankEndCheckXRaster)
|
||||
_hblank = false;
|
||||
if (_rasterX == _hblankStartCheckXRaster)
|
||||
_hblank = true;
|
||||
|
||||
_renderEnabled = !_hblank && !_vblank;
|
||||
_renderEnabled = !_hblank && !_vblank;
|
||||
_pixelCounter = -1;
|
||||
while (_pixelCounter++ < 3)
|
||||
{
|
||||
|
||||
if ((_srColorSync & SrColorMask) != 0)
|
||||
{
|
||||
_displayC = _bufferC[_srColorIndexLatch];
|
||||
_srColorIndexLatch = (_srColorIndexLatch + 1) & 0x3F;
|
||||
}
|
||||
if ((_srColorSync & SrColorMask) != 0)
|
||||
{
|
||||
_displayC = _bufferC[_srColorIndexLatch];
|
||||
_srColorIndexLatch = (_srColorIndexLatch + 1) & 0x3F;
|
||||
}
|
||||
|
||||
#region PRE-RENDER BORDER
|
||||
#region PRE-RENDER BORDER
|
||||
|
||||
// check left border
|
||||
if (_borderCheckLEnable && (_rasterX == _borderL))
|
||||
// check left border
|
||||
if (_borderCheckLEnable && (_rasterX == _borderL))
|
||||
{
|
||||
if (_rasterLine == _borderB)
|
||||
_borderOnVertical = true;
|
||||
|
@ -66,14 +66,14 @@
|
|||
_borderOnMain = false;
|
||||
}
|
||||
|
||||
// check right border
|
||||
if (_borderCheckREnable && (_rasterX == _borderR))
|
||||
_borderOnMain = true;
|
||||
// check right border
|
||||
if (_borderCheckREnable && (_rasterX == _borderR))
|
||||
_borderOnMain = true;
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region CHARACTER GRAPHICS
|
||||
switch (_videoMode)
|
||||
#region CHARACTER GRAPHICS
|
||||
switch (_videoMode)
|
||||
{
|
||||
case VideoMode000:
|
||||
_pixelData = _sr & SrMask2;
|
||||
|
@ -82,25 +82,25 @@
|
|||
case VideoMode001:
|
||||
if ((_displayC & 0x800) != 0)
|
||||
{
|
||||
// multicolor 001
|
||||
// multicolor 001
|
||||
if ((_srSync & SrMask2) != 0)
|
||||
_pixelData = _sr & SrMask3;
|
||||
|
||||
switch (_pixelData)
|
||||
{
|
||||
case 0:
|
||||
_pixel = _backgroundColor0;
|
||||
break;
|
||||
case SrMask1:
|
||||
_pixel = _backgroundColor1;
|
||||
break;
|
||||
case SrMask2:
|
||||
_pixel = _backgroundColor2;
|
||||
break;
|
||||
default:
|
||||
_pixel = (_displayC & 0x700) >> 8;
|
||||
break;
|
||||
}
|
||||
switch (_pixelData)
|
||||
{
|
||||
case 0:
|
||||
_pixel = _backgroundColor0;
|
||||
break;
|
||||
case SrMask1:
|
||||
_pixel = _backgroundColor1;
|
||||
break;
|
||||
case SrMask2:
|
||||
_pixel = _backgroundColor2;
|
||||
break;
|
||||
default:
|
||||
_pixel = (_displayC & 0x700) >> 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -119,18 +119,18 @@
|
|||
|
||||
switch (_pixelData)
|
||||
{
|
||||
case 0:
|
||||
_pixel = _backgroundColor0;
|
||||
break;
|
||||
case SrMask1:
|
||||
_pixel = _displayC >> 4;
|
||||
break;
|
||||
case SrMask2:
|
||||
_pixel = _displayC;
|
||||
break;
|
||||
default:
|
||||
_pixel = _displayC >> 8;
|
||||
break;
|
||||
case 0:
|
||||
_pixel = _backgroundColor0;
|
||||
break;
|
||||
case SrMask1:
|
||||
_pixel = _displayC >> 4;
|
||||
break;
|
||||
case SrMask2:
|
||||
_pixel = _displayC;
|
||||
break;
|
||||
default:
|
||||
_pixel = _displayC >> 8;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case VideoMode100:
|
||||
|
@ -141,24 +141,24 @@
|
|||
}
|
||||
else
|
||||
{
|
||||
_ecmPixel = (_displayC & 0xC0) >> 6;
|
||||
switch (_ecmPixel)
|
||||
{
|
||||
case 0:
|
||||
_pixel = _backgroundColor0;
|
||||
break;
|
||||
case 1:
|
||||
_pixel = _backgroundColor1;
|
||||
break;
|
||||
case 2:
|
||||
_pixel = _backgroundColor2;
|
||||
break;
|
||||
default:
|
||||
_pixel = _backgroundColor3;
|
||||
break;
|
||||
}
|
||||
_ecmPixel = (_displayC & 0xC0) >> 6;
|
||||
switch (_ecmPixel)
|
||||
{
|
||||
case 0:
|
||||
_pixel = _backgroundColor0;
|
||||
break;
|
||||
case 1:
|
||||
_pixel = _backgroundColor1;
|
||||
break;
|
||||
case 2:
|
||||
_pixel = _backgroundColor2;
|
||||
break;
|
||||
default:
|
||||
_pixel = _backgroundColor3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
_pixelData = 0;
|
||||
_pixel = 0;
|
||||
|
@ -167,12 +167,12 @@
|
|||
_pixel &= 0xF;
|
||||
_sr <<= 1;
|
||||
_srSync <<= 1;
|
||||
_srColorSync <<= 1;
|
||||
#endregion
|
||||
_srColorSync <<= 1;
|
||||
#endregion
|
||||
|
||||
#region SPRITES
|
||||
// render sprites
|
||||
_pixelOwner = -1;
|
||||
#region SPRITES
|
||||
// render sprites
|
||||
_pixelOwner = -1;
|
||||
_sprIndex = 0;
|
||||
foreach (var spr in _sprites)
|
||||
{
|
||||
|
@ -226,19 +226,19 @@
|
|||
// sprite-sprite collision
|
||||
if (_pixelOwner < 0)
|
||||
{
|
||||
switch (_sprData)
|
||||
{
|
||||
case SrSpriteMask1:
|
||||
_sprPixel = _spriteMulticolor0;
|
||||
break;
|
||||
case SrSpriteMask2:
|
||||
_sprPixel = spr.Color;
|
||||
break;
|
||||
case SrSpriteMask3:
|
||||
_sprPixel = _spriteMulticolor1;
|
||||
break;
|
||||
}
|
||||
_pixelOwner = _sprIndex;
|
||||
switch (_sprData)
|
||||
{
|
||||
case SrSpriteMask1:
|
||||
_sprPixel = _spriteMulticolor0;
|
||||
break;
|
||||
case SrSpriteMask2:
|
||||
_sprPixel = spr.Color;
|
||||
break;
|
||||
case SrSpriteMask3:
|
||||
_sprPixel = _spriteMulticolor1;
|
||||
break;
|
||||
}
|
||||
_pixelOwner = _sprIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -270,38 +270,38 @@
|
|||
_sprIndex++;
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region POST-RENDER BORDER
|
||||
#region POST-RENDER BORDER
|
||||
|
||||
// border doesn't work with the background buffer
|
||||
_borderPixel = _pixBorderBuffer[_pixBufferBorderIndex];
|
||||
_pixBorderBuffer[_pixBufferBorderIndex] = _borderColor;
|
||||
// border doesn't work with the background buffer
|
||||
_borderPixel = _pixBorderBuffer[_pixBufferBorderIndex];
|
||||
_pixBorderBuffer[_pixBufferBorderIndex] = _borderColor;
|
||||
#endregion
|
||||
|
||||
// plot pixel if within viewing area
|
||||
if (_renderEnabled)
|
||||
{
|
||||
_bufferPixel = (_borderOnShiftReg & 0x80000) != 0 ? _borderPixel : _pixBuffer[_pixBufferIndex];
|
||||
_buf[_bufOffset] = Palette[_bufferPixel];
|
||||
_bufferPixel = (_borderOnShiftReg & 0x80000) != 0 ? _borderPixel : _pixBuffer[_pixBufferIndex];
|
||||
_buf[_bufOffset] = Palette[_bufferPixel];
|
||||
_bufOffset++;
|
||||
if (_bufOffset == _bufLength)
|
||||
_bufOffset = 0;
|
||||
}
|
||||
|
||||
_borderOnShiftReg <<= 1;
|
||||
_borderOnShiftReg |= (_borderOnVertical || _borderOnMain) ? 1 : 0;
|
||||
_pixBuffer[_pixBufferIndex] = _pixel;
|
||||
_borderOnShiftReg <<= 1;
|
||||
_borderOnShiftReg |= (_borderOnVertical || _borderOnMain) ? 1 : 0;
|
||||
_pixBuffer[_pixBufferIndex] = _pixel;
|
||||
_pixBufferIndex++;
|
||||
_pixBufferBorderIndex++;
|
||||
_pixBufferBorderIndex++;
|
||||
|
||||
if (!_rasterXHold)
|
||||
if (!_rasterXHold)
|
||||
_rasterX++;
|
||||
}
|
||||
|
||||
if (_pixBufferBorderIndex >= PixBorderBufferSize)
|
||||
_pixBufferBorderIndex = 0;
|
||||
if (_pixBufferIndex >= PixBufferSize)
|
||||
if (_pixBufferBorderIndex >= PixBorderBufferSize)
|
||||
_pixBufferBorderIndex = 0;
|
||||
if (_pixBufferIndex >= PixBufferSize)
|
||||
_pixBufferIndex = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
private int _baCount;
|
||||
private bool _badline;
|
||||
private bool _badlineEnable;
|
||||
private bool _bitmapMode;
|
||||
private bool _bitmapMode;
|
||||
private int _borderB;
|
||||
private bool _borderCheckLEnable;
|
||||
private bool _borderCheckREnable;
|
||||
|
@ -36,19 +36,19 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
private int _dataG;
|
||||
private bool _displayEnable;
|
||||
private int _displayC;
|
||||
private bool _enableIntLightPen;
|
||||
private bool _enableIntLightPen;
|
||||
private bool _enableIntRaster;
|
||||
private bool _enableIntSpriteCollision;
|
||||
private bool _enableIntSpriteDataCollision;
|
||||
private bool _extraColorMode;
|
||||
private bool _extraColorModeBuffer;
|
||||
[SaveState.DoNotSave] private bool _hblank;
|
||||
private bool _extraColorModeBuffer;
|
||||
[SaveState.DoNotSave] private bool _hblank;
|
||||
private bool _idle;
|
||||
private bool _intLightPen;
|
||||
private bool _intRaster;
|
||||
private bool _intSpriteCollision;
|
||||
private bool _intSpriteDataCollision;
|
||||
private int _lightPenX;
|
||||
private int _lightPenX;
|
||||
private int _lightPenY;
|
||||
private bool _multicolorMode;
|
||||
private bool _pinAec = true;
|
||||
|
@ -57,7 +57,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
private int _pointerCb;
|
||||
private int _pointerVm;
|
||||
private int _rasterInterruptLine;
|
||||
private bool _rasterInterruptTriggered;
|
||||
private bool _rasterInterruptTriggered;
|
||||
private int _rasterLine;
|
||||
private int _rasterX;
|
||||
private bool _rasterXHold;
|
||||
|
@ -65,23 +65,23 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
private int _refreshCounter;
|
||||
private bool _renderEnabled;
|
||||
private bool _rowSelect;
|
||||
private bool _spriteBackgroundCollisionClearPending;
|
||||
private bool _spriteSpriteCollisionClearPending;
|
||||
private int _spriteMulticolor0;
|
||||
private int _spriteMulticolor1;
|
||||
[SaveState.DoNotSave] private readonly Sprite _sprite0;
|
||||
[SaveState.DoNotSave] private readonly Sprite _sprite1;
|
||||
[SaveState.DoNotSave] private readonly Sprite _sprite2;
|
||||
[SaveState.DoNotSave] private readonly Sprite _sprite3;
|
||||
[SaveState.DoNotSave] private readonly Sprite _sprite4;
|
||||
[SaveState.DoNotSave] private readonly Sprite _sprite5;
|
||||
[SaveState.DoNotSave] private readonly Sprite _sprite6;
|
||||
[SaveState.DoNotSave] private readonly Sprite _sprite7;
|
||||
private readonly Sprite[] _sprites;
|
||||
private bool _spriteBackgroundCollisionClearPending;
|
||||
private bool _spriteSpriteCollisionClearPending;
|
||||
private int _spriteMulticolor0;
|
||||
private int _spriteMulticolor1;
|
||||
[SaveState.DoNotSave] private readonly Sprite _sprite0;
|
||||
[SaveState.DoNotSave] private readonly Sprite _sprite1;
|
||||
[SaveState.DoNotSave] private readonly Sprite _sprite2;
|
||||
[SaveState.DoNotSave] private readonly Sprite _sprite3;
|
||||
[SaveState.DoNotSave] private readonly Sprite _sprite4;
|
||||
[SaveState.DoNotSave] private readonly Sprite _sprite5;
|
||||
[SaveState.DoNotSave] private readonly Sprite _sprite6;
|
||||
[SaveState.DoNotSave] private readonly Sprite _sprite7;
|
||||
private readonly Sprite[] _sprites;
|
||||
private int _sr;
|
||||
[SaveState.DoNotSave] private bool _vblank;
|
||||
[SaveState.DoNotSave] private int _vblankEnd;
|
||||
[SaveState.DoNotSave] private int _vblankStart;
|
||||
[SaveState.DoNotSave] private int _vblankStart;
|
||||
private int _vc;
|
||||
private int _vcbase;
|
||||
private int _vmli;
|
||||
|
@ -132,9 +132,9 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
_rc = 7;
|
||||
_refreshCounter = 0xFF;
|
||||
_rowSelect = false;
|
||||
_spriteBackgroundCollisionClearPending = false;
|
||||
_spriteSpriteCollisionClearPending = false;
|
||||
_spriteMulticolor0 = 0;
|
||||
_spriteBackgroundCollisionClearPending = false;
|
||||
_spriteSpriteCollisionClearPending = false;
|
||||
_spriteMulticolor0 = 0;
|
||||
_spriteMulticolor1 = 0;
|
||||
_sr = 0;
|
||||
_vc = 0;
|
||||
|
@ -142,7 +142,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
_vmli = 0;
|
||||
_xScroll = 0;
|
||||
_yScroll = 0;
|
||||
_cycle = 0;
|
||||
_cycle = 0;
|
||||
|
||||
// reset sprites
|
||||
for (var i = 0; i < 8; i++)
|
||||
|
@ -156,21 +156,21 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
}
|
||||
|
||||
_pixBuffer = new int[PixBufferSize];
|
||||
_pixBorderBuffer = new int[PixBorderBufferSize];
|
||||
_pixBufferIndex = 0;
|
||||
_pixBufferBorderIndex = 0;
|
||||
UpdateBorder();
|
||||
_pixBorderBuffer = new int[PixBorderBufferSize];
|
||||
_pixBufferIndex = 0;
|
||||
_pixBufferBorderIndex = 0;
|
||||
UpdateBorder();
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncObject(ser, this);
|
||||
if (ser.IsReader)
|
||||
{
|
||||
UpdateBorder();
|
||||
UpdatePins();
|
||||
UpdateVideoMode();
|
||||
}
|
||||
}
|
||||
if (ser.IsReader)
|
||||
{
|
||||
UpdateBorder();
|
||||
UpdatePins();
|
||||
UpdateVideoMode();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,24 +8,24 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
{
|
||||
public sealed partial class Vic
|
||||
{
|
||||
[SaveState.DoNotSave] private const int BorderLeft38 = 0x023;
|
||||
[SaveState.DoNotSave] private const int BorderLeft40 = 0x01C;
|
||||
[SaveState.DoNotSave] private const int BorderRight38 = 0x153;
|
||||
[SaveState.DoNotSave] private const int BorderRight40 = 0x15C;
|
||||
[SaveState.DoNotSave] private const int BorderTop25 = 0x033;
|
||||
[SaveState.DoNotSave] private const int BorderTop24 = 0x037;
|
||||
[SaveState.DoNotSave] private const int BorderBottom25 = 0x0FB;
|
||||
[SaveState.DoNotSave] private const int BorderBottom24 = 0x0F7;
|
||||
[SaveState.DoNotSave] private const int FirstDmaLine = 0x030;
|
||||
[SaveState.DoNotSave] private const int LastDmaLine = 0x0F7;
|
||||
[SaveState.DoNotSave] private const int BorderLeft38 = 0x023;
|
||||
[SaveState.DoNotSave] private const int BorderLeft40 = 0x01C;
|
||||
[SaveState.DoNotSave] private const int BorderRight38 = 0x153;
|
||||
[SaveState.DoNotSave] private const int BorderRight40 = 0x15C;
|
||||
[SaveState.DoNotSave] private const int BorderTop25 = 0x033;
|
||||
[SaveState.DoNotSave] private const int BorderTop24 = 0x037;
|
||||
[SaveState.DoNotSave] private const int BorderBottom25 = 0x0FB;
|
||||
[SaveState.DoNotSave] private const int BorderBottom24 = 0x0F7;
|
||||
[SaveState.DoNotSave] private const int FirstDmaLine = 0x030;
|
||||
[SaveState.DoNotSave] private const int LastDmaLine = 0x0F7;
|
||||
|
||||
// The special actions taken by the Vic are in the same order and interval on all chips, just different offsets.
|
||||
[SaveState.DoNotSave]
|
||||
private static readonly int[] TimingBuilderCycle14Act = {
|
||||
// The special actions taken by the Vic are in the same order and interval on all chips, just different offsets.
|
||||
[SaveState.DoNotSave]
|
||||
private static readonly int[] TimingBuilderCycle14Act = {
|
||||
PipelineUpdateVc, 0,
|
||||
PipelineSpriteCrunch, 0,
|
||||
PipelineUpdateMcBase, 0,
|
||||
};
|
||||
};
|
||||
|
||||
// This builds a table of special actions to take on each half-cycle. Cycle14 is the X-raster position where
|
||||
// pre-display operations happen, and Cycle55 is the X-raster position where post-display operations happen.
|
||||
|
@ -59,15 +59,15 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
if (timing[i] == (BorderRight40 & 0xFFC))
|
||||
result[i] |= PipelineBorderRight1;
|
||||
|
||||
// right side timing
|
||||
if (timing[i] == 0x0158)
|
||||
result[i] |= PipelineSpriteExpansion;
|
||||
if (timing[i] == 0x0168)
|
||||
result[i] |= PipelineUpdateRc;
|
||||
if (timing[i] == sprite0Ba || timing[i] == sprite0Ba + 8)
|
||||
result[i] |= PipelineSpriteDma;
|
||||
if (timing[i] == sprDisp)
|
||||
result[i] |= PipelineSpriteDisplay;
|
||||
// right side timing
|
||||
if (timing[i] == 0x0158)
|
||||
result[i] |= PipelineSpriteExpansion;
|
||||
if (timing[i] == 0x0168)
|
||||
result[i] |= PipelineUpdateRc;
|
||||
if (timing[i] == sprite0Ba || timing[i] == sprite0Ba + 8)
|
||||
result[i] |= PipelineSpriteDma;
|
||||
if (timing[i] == sprDisp)
|
||||
result[i] |= PipelineSpriteDisplay;
|
||||
|
||||
}
|
||||
|
||||
|
@ -151,7 +151,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
{
|
||||
var length = timing.Length;
|
||||
var result = new int[length];
|
||||
var index = -1;
|
||||
var index = -1;
|
||||
var refreshCounter = 0;
|
||||
var spriteActive = false;
|
||||
var spriteIndex = 0;
|
||||
|
@ -160,11 +160,11 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
result[i++] = FetchTypeIdle;
|
||||
result[i] = FetchTypeNone;
|
||||
}
|
||||
result[i++] = FetchTypeIdle;
|
||||
result[i] = FetchTypeNone;
|
||||
}
|
||||
|
||||
while (true)
|
||||
while (true)
|
||||
{
|
||||
index++;
|
||||
if (index >= length)
|
||||
|
@ -213,14 +213,14 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
}
|
||||
|
||||
// This uses the vBlank values to determine the height of the visible screen.
|
||||
private static int TimingBuilder_ScreenHeight(int vblankStart, int vblankEnd, int lines)
|
||||
private static int TimingBuilder_ScreenHeight(int vblankStart, int vblankEnd, int lines)
|
||||
{
|
||||
if (vblankStart < 0 || vblankEnd < 0)
|
||||
{
|
||||
return lines;
|
||||
}
|
||||
if (vblankStart < 0 || vblankEnd < 0)
|
||||
{
|
||||
return lines;
|
||||
}
|
||||
|
||||
var offset = vblankEnd;
|
||||
var offset = vblankEnd;
|
||||
var result = 0;
|
||||
while (true)
|
||||
{
|
||||
|
@ -234,12 +234,12 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
}
|
||||
|
||||
// This uses the hBlank values to determine the width of the visible screen.
|
||||
private static int TimingBuilder_ScreenWidth(IList<int> timing, int hblankStart, int hblankEnd)
|
||||
private static int TimingBuilder_ScreenWidth(IList<int> timing, int hblankStart, int hblankEnd)
|
||||
{
|
||||
if (hblankStart < 0 || hblankEnd < 0)
|
||||
{
|
||||
return timing.Count * 4;
|
||||
}
|
||||
if (hblankStart < 0 || hblankEnd < 0)
|
||||
{
|
||||
return timing.Count * 4;
|
||||
}
|
||||
|
||||
var length = timing.Count;
|
||||
var result = 0;
|
||||
|
|
|
@ -7,22 +7,22 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
{
|
||||
public sealed partial class Vic : IVideoProvider
|
||||
{
|
||||
[SaveState.DoNotSave] private static readonly int BgColor = Colors.ARGB(0, 0, 0);
|
||||
[SaveState.DoNotSave] private int[] _buf;
|
||||
[SaveState.DoNotSave] private static readonly int BgColor = Colors.ARGB(0, 0, 0);
|
||||
[SaveState.DoNotSave] private int[] _buf;
|
||||
[SaveState.DoNotSave] private int _bufHeight;
|
||||
[SaveState.DoNotSave] private int _bufLength;
|
||||
private int _bufOffset;
|
||||
[SaveState.DoNotSave] private int _bufWidth;
|
||||
[SaveState.DoNotSave] private const int PixBufferSize = 24;
|
||||
[SaveState.DoNotSave] private const int PixBorderBufferSize = 12;
|
||||
private int[] _pixBuffer;
|
||||
[SaveState.DoNotSave] private const int PixBufferSize = 24;
|
||||
[SaveState.DoNotSave] private const int PixBorderBufferSize = 12;
|
||||
private int[] _pixBuffer;
|
||||
private int _pixBufferIndex;
|
||||
private int[] _pixBorderBuffer;
|
||||
private int _pixBufferBorderIndex;
|
||||
private int[] _pixBorderBuffer;
|
||||
private int _pixBufferBorderIndex;
|
||||
|
||||
// palette
|
||||
[SaveState.DoNotSave]
|
||||
private static readonly int[] Palette =
|
||||
// palette
|
||||
[SaveState.DoNotSave]
|
||||
private static readonly int[] Palette =
|
||||
{
|
||||
Colors.ARGB(0x00, 0x00, 0x00),
|
||||
Colors.ARGB(0xFF, 0xFF, 0xFF),
|
||||
|
@ -42,20 +42,20 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
Colors.ARGB(0x95, 0x95, 0x95)
|
||||
};
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public int BackgroundColor
|
||||
[SaveState.DoNotSave]
|
||||
public int BackgroundColor
|
||||
{
|
||||
get { return BgColor; }
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public int BufferHeight
|
||||
[SaveState.DoNotSave]
|
||||
public int BufferHeight
|
||||
{
|
||||
get { return _bufHeight; }
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public int BufferWidth
|
||||
[SaveState.DoNotSave]
|
||||
public int BufferWidth
|
||||
{
|
||||
get { return _bufWidth; }
|
||||
}
|
||||
|
@ -65,10 +65,10 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
return _buf;
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public int VirtualWidth { get; private set; }
|
||||
[SaveState.DoNotSave]
|
||||
public int VirtualWidth { get; private set; }
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public int VirtualHeight { get; private set; }
|
||||
[SaveState.DoNotSave]
|
||||
public int VirtualHeight { get; private set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
{
|
||||
public sealed partial class Vic
|
||||
{
|
||||
/*
|
||||
/*
|
||||
Commodore VIC-II 6567/6569/6572 core.
|
||||
|
||||
Many thanks to:
|
||||
|
@ -23,7 +23,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
http://mail.lipsia.de/~enigma/neu/6581.html
|
||||
*/
|
||||
|
||||
public Func<int, int> ReadColorRam;
|
||||
public Func<int, int> ReadColorRam;
|
||||
public Func<int, int> ReadMemory;
|
||||
|
||||
public bool ReadAec() { return _pinAec; }
|
||||
|
@ -31,144 +31,144 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
public bool ReadIrq() { return _pinIrq; }
|
||||
|
||||
[SaveState.DoNotSave] private readonly int _cyclesPerSec;
|
||||
[SaveState.DoNotSave] private readonly int[] _rasterXPipeline;
|
||||
[SaveState.DoNotSave] private readonly int[] _fetchPipeline;
|
||||
[SaveState.DoNotSave] private readonly int[] _baPipeline;
|
||||
[SaveState.DoNotSave] private readonly int[] _actPipeline;
|
||||
[SaveState.DoNotSave] private readonly int _totalCycles;
|
||||
[SaveState.DoNotSave] private readonly int[] _rasterXPipeline;
|
||||
[SaveState.DoNotSave] private readonly int[] _fetchPipeline;
|
||||
[SaveState.DoNotSave] private readonly int[] _baPipeline;
|
||||
[SaveState.DoNotSave] private readonly int[] _actPipeline;
|
||||
[SaveState.DoNotSave] private readonly int _totalCycles;
|
||||
[SaveState.DoNotSave] private readonly int _totalLines;
|
||||
|
||||
private int _cyclesExecuted;
|
||||
[SaveState.DoNotSave] private int _hblankStartCheckXRaster;
|
||||
[SaveState.DoNotSave] private int _hblankEndCheckXRaster;
|
||||
private int _cyclesExecuted;
|
||||
[SaveState.DoNotSave] private int _hblankStartCheckXRaster;
|
||||
[SaveState.DoNotSave] private int _hblankEndCheckXRaster;
|
||||
|
||||
[SaveState.DoNotSave] private int _pixelRatioNum;
|
||||
[SaveState.DoNotSave] private int _pixelRatioDen;
|
||||
[SaveState.DoNotSave] private int _pixelRatioNum;
|
||||
[SaveState.DoNotSave] private int _pixelRatioDen;
|
||||
|
||||
public Vic(int newCycles, int newLines, IList<int[]> newPipeline, int newCyclesPerSec, int hblankStart, int hblankEnd, int vblankStart, int vblankEnd, C64.BorderType borderType, int pixelRatioNum, int pixelRatioDen)
|
||||
public Vic(int newCycles, int newLines, IList<int[]> newPipeline, int newCyclesPerSec, int hblankStart, int hblankEnd, int vblankStart, int vblankEnd, C64.BorderType borderType, int pixelRatioNum, int pixelRatioDen)
|
||||
{
|
||||
Debug.WriteLine("C64 VIC timings:");
|
||||
Debug.WriteLine("RX FTCH BA ACT");
|
||||
for (var i = 0; i < newPipeline[0].Length; i++)
|
||||
{
|
||||
Debug.WriteLine("{0:x4} {1:x4} {2:x4} {3:x8}", newPipeline[0][i], newPipeline[1][i], newPipeline[2][i], newPipeline[3][i]);
|
||||
}
|
||||
Debug.WriteLine("C64 VIC timings:");
|
||||
Debug.WriteLine("RX FTCH BA ACT");
|
||||
for (var i = 0; i < newPipeline[0].Length; i++)
|
||||
{
|
||||
Debug.WriteLine("{0:x4} {1:x4} {2:x4} {3:x8}", newPipeline[0][i], newPipeline[1][i], newPipeline[2][i], newPipeline[3][i]);
|
||||
}
|
||||
|
||||
_pixelRatioNum = pixelRatioNum;
|
||||
_pixelRatioDen = pixelRatioDen;
|
||||
_pixelRatioNum = pixelRatioNum;
|
||||
_pixelRatioDen = pixelRatioDen;
|
||||
|
||||
_rasterXPipeline = newPipeline[0];
|
||||
_fetchPipeline = newPipeline[1];
|
||||
_baPipeline = newPipeline[2];
|
||||
_actPipeline = newPipeline[3];
|
||||
_totalCycles = newCycles;
|
||||
_totalLines = newLines;
|
||||
_cyclesPerSec = newCyclesPerSec;
|
||||
_rasterXPipeline = newPipeline[0];
|
||||
_fetchPipeline = newPipeline[1];
|
||||
_baPipeline = newPipeline[2];
|
||||
_actPipeline = newPipeline[3];
|
||||
_totalCycles = newCycles;
|
||||
_totalLines = newLines;
|
||||
_cyclesPerSec = newCyclesPerSec;
|
||||
|
||||
ConfigureBlanking(newLines, hblankStart, hblankEnd, vblankStart, vblankEnd, borderType);
|
||||
ConfigureBlanking(newLines, hblankStart, hblankEnd, vblankStart, vblankEnd, borderType);
|
||||
|
||||
_sprites = new Sprite[8];
|
||||
for (var i = 0; i < 8; i++)
|
||||
_sprites[i] = new Sprite();
|
||||
_sprite0 = _sprites[0];
|
||||
_sprite1 = _sprites[1];
|
||||
_sprite2 = _sprites[2];
|
||||
_sprite3 = _sprites[3];
|
||||
_sprite4 = _sprites[4];
|
||||
_sprite5 = _sprites[5];
|
||||
_sprite6 = _sprites[6];
|
||||
_sprite7 = _sprites[7];
|
||||
_sprites = new Sprite[8];
|
||||
for (var i = 0; i < 8; i++)
|
||||
_sprites[i] = new Sprite();
|
||||
_sprite0 = _sprites[0];
|
||||
_sprite1 = _sprites[1];
|
||||
_sprite2 = _sprites[2];
|
||||
_sprite3 = _sprites[3];
|
||||
_sprite4 = _sprites[4];
|
||||
_sprite5 = _sprites[5];
|
||||
_sprite6 = _sprites[6];
|
||||
_sprite7 = _sprites[7];
|
||||
|
||||
_bufferC = new int[40];
|
||||
_bufferG = new int[40];
|
||||
}
|
||||
_bufferC = new int[40];
|
||||
_bufferG = new int[40];
|
||||
}
|
||||
|
||||
private void ConfigureBlanking(int lines, int hblankStart, int hblankEnd, int vblankStart, int vblankEnd,
|
||||
C64.BorderType borderType)
|
||||
{
|
||||
var newHblankStart = hblankStart;
|
||||
var newHblankEnd = hblankEnd;
|
||||
var newVblankStart = vblankStart;
|
||||
var newVblankEnd = vblankEnd;
|
||||
var hBorderSize = 16; // must be a multiple of 4
|
||||
var vBorderSize = hBorderSize*_pixelRatioNum/_pixelRatioDen; // to keep top and bottom in proportion
|
||||
var maxWidth = _rasterXPipeline.Max();
|
||||
private void ConfigureBlanking(int lines, int hblankStart, int hblankEnd, int vblankStart, int vblankEnd,
|
||||
C64.BorderType borderType)
|
||||
{
|
||||
var newHblankStart = hblankStart;
|
||||
var newHblankEnd = hblankEnd;
|
||||
var newVblankStart = vblankStart;
|
||||
var newVblankEnd = vblankEnd;
|
||||
var hBorderSize = 16; // must be a multiple of 4
|
||||
var vBorderSize = hBorderSize * _pixelRatioNum / _pixelRatioDen; // to keep top and bottom in proportion
|
||||
var maxWidth = _rasterXPipeline.Max();
|
||||
|
||||
switch (borderType)
|
||||
{
|
||||
case C64.BorderType.Full:
|
||||
newHblankStart = -1;
|
||||
newHblankEnd = -1;
|
||||
_hblank = false;
|
||||
newVblankStart = -1;
|
||||
newVblankEnd = -1;
|
||||
_vblank = false;
|
||||
break;
|
||||
case C64.BorderType.Normal:
|
||||
newHblankStart = hblankStart;
|
||||
newHblankEnd = hblankEnd;
|
||||
newVblankStart = vblankStart;
|
||||
newVblankEnd = vblankEnd;
|
||||
_vblank = true;
|
||||
_hblank = true;
|
||||
break;
|
||||
case C64.BorderType.SmallProportional:
|
||||
_vblank = true;
|
||||
_hblank = true;
|
||||
newHblankStart = 0x158 + PixBufferSize + hBorderSize;
|
||||
newHblankEnd = 0x018 + PixBufferSize - hBorderSize;
|
||||
newVblankStart = 0xFA + vBorderSize;
|
||||
newVblankEnd = 0x32 - vBorderSize;
|
||||
break;
|
||||
case C64.BorderType.SmallFixed:
|
||||
_vblank = true;
|
||||
_hblank = true;
|
||||
newHblankStart = 0x158 + PixBufferSize + hBorderSize;
|
||||
newHblankEnd = 0x018 + PixBufferSize - hBorderSize;
|
||||
newVblankStart = 0xFA + hBorderSize;
|
||||
newVblankEnd = 0x32 - hBorderSize;
|
||||
break;
|
||||
}
|
||||
switch (borderType)
|
||||
{
|
||||
case C64.BorderType.Full:
|
||||
newHblankStart = -1;
|
||||
newHblankEnd = -1;
|
||||
_hblank = false;
|
||||
newVblankStart = -1;
|
||||
newVblankEnd = -1;
|
||||
_vblank = false;
|
||||
break;
|
||||
case C64.BorderType.Normal:
|
||||
newHblankStart = hblankStart;
|
||||
newHblankEnd = hblankEnd;
|
||||
newVblankStart = vblankStart;
|
||||
newVblankEnd = vblankEnd;
|
||||
_vblank = true;
|
||||
_hblank = true;
|
||||
break;
|
||||
case C64.BorderType.SmallProportional:
|
||||
_vblank = true;
|
||||
_hblank = true;
|
||||
newHblankStart = 0x158 + PixBufferSize + hBorderSize;
|
||||
newHblankEnd = 0x018 + PixBufferSize - hBorderSize;
|
||||
newVblankStart = 0xFA + vBorderSize;
|
||||
newVblankEnd = 0x32 - vBorderSize;
|
||||
break;
|
||||
case C64.BorderType.SmallFixed:
|
||||
_vblank = true;
|
||||
_hblank = true;
|
||||
newHblankStart = 0x158 + PixBufferSize + hBorderSize;
|
||||
newHblankEnd = 0x018 + PixBufferSize - hBorderSize;
|
||||
newVblankStart = 0xFA + hBorderSize;
|
||||
newVblankEnd = 0x32 - hBorderSize;
|
||||
break;
|
||||
}
|
||||
|
||||
// wrap values
|
||||
newHblankStart = WrapValue(0, maxWidth, newHblankStart);
|
||||
newHblankEnd = WrapValue(0, maxWidth, newHblankEnd);
|
||||
newVblankStart = WrapValue(0, lines, newVblankStart);
|
||||
newVblankEnd = WrapValue(0, lines, newVblankEnd);
|
||||
// wrap values
|
||||
newHblankStart = WrapValue(0, maxWidth, newHblankStart);
|
||||
newHblankEnd = WrapValue(0, maxWidth, newHblankEnd);
|
||||
newVblankStart = WrapValue(0, lines, newVblankStart);
|
||||
newVblankEnd = WrapValue(0, lines, newVblankEnd);
|
||||
|
||||
// calculate output dimensions
|
||||
_hblankStartCheckXRaster = newHblankStart & 0xFFC;
|
||||
_hblankEndCheckXRaster = newHblankEnd & 0xFFC;
|
||||
_vblankStart = newVblankStart;
|
||||
_vblankEnd = newVblankEnd;
|
||||
_bufWidth = TimingBuilder_ScreenWidth(_rasterXPipeline, newHblankStart, newHblankEnd);
|
||||
_bufHeight = TimingBuilder_ScreenHeight(newVblankStart, newVblankEnd, lines);
|
||||
_buf = new int[_bufWidth * _bufHeight];
|
||||
_bufLength = _buf.Length;
|
||||
VirtualWidth = _bufWidth*_pixelRatioNum/_pixelRatioDen;
|
||||
VirtualHeight = _bufHeight;
|
||||
}
|
||||
// calculate output dimensions
|
||||
_hblankStartCheckXRaster = newHblankStart & 0xFFC;
|
||||
_hblankEndCheckXRaster = newHblankEnd & 0xFFC;
|
||||
_vblankStart = newVblankStart;
|
||||
_vblankEnd = newVblankEnd;
|
||||
_bufWidth = TimingBuilder_ScreenWidth(_rasterXPipeline, newHblankStart, newHblankEnd);
|
||||
_bufHeight = TimingBuilder_ScreenHeight(newVblankStart, newVblankEnd, lines);
|
||||
_buf = new int[_bufWidth * _bufHeight];
|
||||
_bufLength = _buf.Length;
|
||||
VirtualWidth = _bufWidth * _pixelRatioNum / _pixelRatioDen;
|
||||
VirtualHeight = _bufHeight;
|
||||
}
|
||||
|
||||
private int WrapValue(int min, int max, int val)
|
||||
{
|
||||
if (min == max)
|
||||
{
|
||||
return min;
|
||||
}
|
||||
private int WrapValue(int min, int max, int val)
|
||||
{
|
||||
if (min == max)
|
||||
{
|
||||
return min;
|
||||
}
|
||||
|
||||
var width = Math.Abs(min - max);
|
||||
while (val > max)
|
||||
{
|
||||
val -= width;
|
||||
}
|
||||
while (val < min)
|
||||
{
|
||||
val += width;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
var width = Math.Abs(min - max);
|
||||
while (val > max)
|
||||
{
|
||||
val -= width;
|
||||
}
|
||||
while (val < min)
|
||||
{
|
||||
val += width;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
public int CyclesPerFrame
|
||||
public int CyclesPerFrame
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -184,145 +184,145 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
}
|
||||
}
|
||||
|
||||
public void ExecutePhase()
|
||||
public void ExecutePhase()
|
||||
{
|
||||
// phi1
|
||||
// phi1
|
||||
|
||||
// advance cycle and optionally raster line
|
||||
_cycle++;
|
||||
if (_cycle > _totalCycles)
|
||||
{
|
||||
// border check
|
||||
if (_rasterLine == _borderB)
|
||||
_borderOnVertical = true;
|
||||
if (_rasterLine == _borderT && _displayEnable)
|
||||
_borderOnVertical = false;
|
||||
// advance cycle and optionally raster line
|
||||
_cycle++;
|
||||
if (_cycle > _totalCycles)
|
||||
{
|
||||
// border check
|
||||
if (_rasterLine == _borderB)
|
||||
_borderOnVertical = true;
|
||||
if (_rasterLine == _borderT && _displayEnable)
|
||||
_borderOnVertical = false;
|
||||
|
||||
// vblank check
|
||||
if (_rasterLine == _vblankStart)
|
||||
_vblank = true;
|
||||
if (_rasterLine == _vblankEnd)
|
||||
_vblank = false;
|
||||
// vblank check
|
||||
if (_rasterLine == _vblankStart)
|
||||
_vblank = true;
|
||||
if (_rasterLine == _vblankEnd)
|
||||
_vblank = false;
|
||||
|
||||
// reset to beginning of rasterline
|
||||
_cycleIndex = 0;
|
||||
_cycle = 1;
|
||||
_rasterLine++;
|
||||
// reset to beginning of rasterline
|
||||
_cycleIndex = 0;
|
||||
_cycle = 1;
|
||||
_rasterLine++;
|
||||
|
||||
if (_rasterLine == _totalLines)
|
||||
{
|
||||
// reset to rasterline 0
|
||||
_rasterLine = 0;
|
||||
_vcbase = 0;
|
||||
_vc = 0;
|
||||
_badlineEnable = false;
|
||||
_refreshCounter = 0xFF;
|
||||
_cyclesExecuted = 0;
|
||||
}
|
||||
}
|
||||
if (_rasterLine == _totalLines)
|
||||
{
|
||||
// reset to rasterline 0
|
||||
_rasterLine = 0;
|
||||
_vcbase = 0;
|
||||
_vc = 0;
|
||||
_badlineEnable = false;
|
||||
_refreshCounter = 0xFF;
|
||||
_cyclesExecuted = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// bg collision clear
|
||||
if (_spriteBackgroundCollisionClearPending)
|
||||
{
|
||||
foreach (var spr in _sprites)
|
||||
{
|
||||
spr.CollideData = false;
|
||||
}
|
||||
_spriteBackgroundCollisionClearPending = false;
|
||||
}
|
||||
// bg collision clear
|
||||
if (_spriteBackgroundCollisionClearPending)
|
||||
{
|
||||
foreach (var spr in _sprites)
|
||||
{
|
||||
spr.CollideData = false;
|
||||
}
|
||||
_spriteBackgroundCollisionClearPending = false;
|
||||
}
|
||||
|
||||
// sprite collision clear
|
||||
if (_spriteSpriteCollisionClearPending)
|
||||
{
|
||||
foreach (var spr in _sprites)
|
||||
{
|
||||
spr.CollideSprite = false;
|
||||
}
|
||||
_spriteSpriteCollisionClearPending = false;
|
||||
}
|
||||
// sprite collision clear
|
||||
if (_spriteSpriteCollisionClearPending)
|
||||
{
|
||||
foreach (var spr in _sprites)
|
||||
{
|
||||
spr.CollideSprite = false;
|
||||
}
|
||||
_spriteSpriteCollisionClearPending = false;
|
||||
}
|
||||
|
||||
// phi2
|
||||
// phi2
|
||||
|
||||
// start of rasterline
|
||||
if ((_cycle == RasterIrqLineXCycle && _rasterLine > 0) || (_cycle == RasterIrqLine0Cycle && _rasterLine == 0))
|
||||
{
|
||||
_rasterInterruptTriggered = false;
|
||||
// start of rasterline
|
||||
if ((_cycle == RasterIrqLineXCycle && _rasterLine > 0) || (_cycle == RasterIrqLine0Cycle && _rasterLine == 0))
|
||||
{
|
||||
_rasterInterruptTriggered = false;
|
||||
|
||||
if (_rasterLine == LastDmaLine)
|
||||
_badlineEnable = false;
|
||||
}
|
||||
if (_rasterLine == LastDmaLine)
|
||||
_badlineEnable = false;
|
||||
}
|
||||
|
||||
// rasterline IRQ compare
|
||||
if (_rasterLine != _rasterInterruptLine)
|
||||
{
|
||||
_rasterInterruptTriggered = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_rasterInterruptTriggered)
|
||||
{
|
||||
_rasterInterruptTriggered = true;
|
||||
_intRaster = true;
|
||||
}
|
||||
}
|
||||
// rasterline IRQ compare
|
||||
if (_rasterLine != _rasterInterruptLine)
|
||||
{
|
||||
_rasterInterruptTriggered = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_rasterInterruptTriggered)
|
||||
{
|
||||
_rasterInterruptTriggered = true;
|
||||
_intRaster = true;
|
||||
}
|
||||
}
|
||||
|
||||
// check top and bottom border
|
||||
if (_rasterLine == _borderB)
|
||||
{
|
||||
_borderOnVertical = true;
|
||||
}
|
||||
if (_displayEnable && _rasterLine == _borderT)
|
||||
{
|
||||
_borderOnVertical = false;
|
||||
}
|
||||
// check top and bottom border
|
||||
if (_rasterLine == _borderB)
|
||||
{
|
||||
_borderOnVertical = true;
|
||||
}
|
||||
if (_displayEnable && _rasterLine == _borderT)
|
||||
{
|
||||
_borderOnVertical = false;
|
||||
}
|
||||
|
||||
// display enable compare
|
||||
if (_rasterLine == FirstDmaLine)
|
||||
_badlineEnable |= _displayEnable;
|
||||
// display enable compare
|
||||
if (_rasterLine == FirstDmaLine)
|
||||
_badlineEnable |= _displayEnable;
|
||||
|
||||
// badline compare
|
||||
if (_badlineEnable)
|
||||
{
|
||||
if ((_rasterLine & 0x7) == _yScroll)
|
||||
{
|
||||
_badline = true;
|
||||
// badline compare
|
||||
if (_badlineEnable)
|
||||
{
|
||||
if ((_rasterLine & 0x7) == _yScroll)
|
||||
{
|
||||
_badline = true;
|
||||
|
||||
// go into display state on a badline
|
||||
_idle = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_badline = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_badline = false;
|
||||
}
|
||||
// go into display state on a badline
|
||||
_idle = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_badline = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_badline = false;
|
||||
}
|
||||
|
||||
// render
|
||||
ParseCycle();
|
||||
Render();
|
||||
ParseCycle();
|
||||
Render();
|
||||
_extraColorModeBuffer = _extraColorMode;
|
||||
// render
|
||||
ParseCycle();
|
||||
Render();
|
||||
ParseCycle();
|
||||
Render();
|
||||
_extraColorModeBuffer = _extraColorMode;
|
||||
|
||||
// if the BA counter is nonzero, allow CPU bus access
|
||||
if (_pinBa)
|
||||
_baCount = BaResetCounter;
|
||||
else if (_baCount > 0)
|
||||
_baCount--;
|
||||
_pinAec = _pinBa || _baCount > 0;
|
||||
// if the BA counter is nonzero, allow CPU bus access
|
||||
if (_pinBa)
|
||||
_baCount = BaResetCounter;
|
||||
else if (_baCount > 0)
|
||||
_baCount--;
|
||||
_pinAec = _pinBa || _baCount > 0;
|
||||
|
||||
// must always come last
|
||||
UpdatePins();
|
||||
// must always come last
|
||||
UpdatePins();
|
||||
|
||||
_cyclesExecuted++;
|
||||
_cyclesExecuted++;
|
||||
}
|
||||
|
||||
private void UpdateBorder()
|
||||
{
|
||||
_borderL = _columnSelect ? BorderLeft40 : BorderLeft38;
|
||||
_borderL = _columnSelect ? BorderLeft40 : BorderLeft38;
|
||||
_borderR = _columnSelect ? BorderRight40 : BorderRight38;
|
||||
_borderT = _rowSelect ? BorderTop25 : BorderTop24;
|
||||
_borderB = _rowSelect ? BorderBottom25 : BorderBottom24;
|
||||
|
@ -346,27 +346,27 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
_videoMode = VideoMode000;
|
||||
return;
|
||||
}
|
||||
if (!_extraColorMode && !_bitmapMode && _multicolorMode)
|
||||
{
|
||||
_videoMode = VideoMode001;
|
||||
return;
|
||||
}
|
||||
if (!_extraColorMode && _bitmapMode && !_multicolorMode)
|
||||
{
|
||||
_videoMode = VideoMode010;
|
||||
return;
|
||||
}
|
||||
if (!_extraColorMode && _bitmapMode && _multicolorMode)
|
||||
{
|
||||
_videoMode = VideoMode011;
|
||||
return;
|
||||
}
|
||||
if (_extraColorMode && !_bitmapMode && !_multicolorMode)
|
||||
{
|
||||
_videoMode = VideoMode100;
|
||||
return;
|
||||
}
|
||||
_videoMode = VideoModeInvalid;
|
||||
if (!_extraColorMode && !_bitmapMode && _multicolorMode)
|
||||
{
|
||||
_videoMode = VideoMode001;
|
||||
return;
|
||||
}
|
||||
if (!_extraColorMode && _bitmapMode && !_multicolorMode)
|
||||
{
|
||||
_videoMode = VideoMode010;
|
||||
return;
|
||||
}
|
||||
if (!_extraColorMode && _bitmapMode && _multicolorMode)
|
||||
{
|
||||
_videoMode = VideoMode011;
|
||||
return;
|
||||
}
|
||||
if (_extraColorMode && !_bitmapMode && !_multicolorMode)
|
||||
{
|
||||
_videoMode = VideoMode100;
|
||||
return;
|
||||
}
|
||||
_videoMode = VideoModeInvalid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,32 +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)
|
||||
{
|
||||
using (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)
|
||||
{
|
||||
|
@ -109,101 +109,101 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media
|
|||
var gcr = new int[8];
|
||||
var data = new byte[4];
|
||||
var count = source.Length;
|
||||
using (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));
|
||||
}
|
||||
writer.Flush();
|
||||
return mem.ToArray();
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
public static Disk Read(byte[] source)
|
||||
{
|
||||
using (var mem = new MemoryStream(source))
|
||||
{
|
||||
var reader = new BinaryReader(mem);
|
||||
var trackDatas = new List<byte[]>();
|
||||
var trackLengths = new List<int>();
|
||||
var trackNumbers = new List<int>();
|
||||
var trackDensities = new List<int>();
|
||||
int trackCount;
|
||||
using (var mem = new MemoryStream(source))
|
||||
{
|
||||
var reader = new BinaryReader(mem);
|
||||
var trackDatas = new List<byte[]>();
|
||||
var trackLengths = new List<int>();
|
||||
var trackNumbers = new List<int>();
|
||||
var trackDensities = new List<int>();
|
||||
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.");
|
||||
}
|
||||
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];
|
||||
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);
|
||||
}
|
||||
// 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]);
|
||||
}
|
||||
}
|
||||
trackDatas.Add(trackMem.ToArray());
|
||||
trackLengths.Add(trackLengthBits);
|
||||
trackNumbers.Add(i * 2);
|
||||
trackDensities.Add(DensityTable[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return new Disk(trackDatas, trackNumbers, trackDensities, 84);
|
||||
}
|
||||
}
|
||||
return new Disk(trackDatas, trackNumbers, trackDensities, 84);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,173 +7,173 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media
|
|||
{
|
||||
public sealed class Disk
|
||||
{
|
||||
[SaveState.DoNotSave] public const int FluxBitsPerEntry = 32;
|
||||
[SaveState.DoNotSave] public const int FluxBitsPerTrack = 16000000 / 5;
|
||||
[SaveState.DoNotSave] public const int FluxEntriesPerTrack = FluxBitsPerTrack/FluxBitsPerEntry;
|
||||
[SaveState.DoNotSave] private int[][] _tracks;
|
||||
[SaveState.DoNotSave] private readonly int[] _originalMedia;
|
||||
[SaveState.DoNotSave] public const int FluxBitsPerEntry = 32;
|
||||
[SaveState.DoNotSave] public const int FluxBitsPerTrack = 16000000 / 5;
|
||||
[SaveState.DoNotSave] public const int FluxEntriesPerTrack = FluxBitsPerTrack / FluxBitsPerEntry;
|
||||
[SaveState.DoNotSave] private int[][] _tracks;
|
||||
[SaveState.DoNotSave] private readonly int[] _originalMedia;
|
||||
[SaveState.DoNotSave] public bool Valid;
|
||||
[SaveState.SaveWithName("DiskIsWriteProtected")] public bool WriteProtected;
|
||||
[SaveState.SaveWithName("DiskIsWriteProtected")] public bool WriteProtected;
|
||||
|
||||
/// <summary>
|
||||
/// Create a blank, unformatted disk.
|
||||
/// </summary>
|
||||
public Disk(int trackCapacity)
|
||||
{
|
||||
WriteProtected = false;
|
||||
_tracks = new int[trackCapacity][];
|
||||
FillMissingTracks();
|
||||
_originalMedia = SerializeTracks(_tracks);
|
||||
Valid = true;
|
||||
}
|
||||
/// <summary>
|
||||
/// Create a blank, unformatted disk.
|
||||
/// </summary>
|
||||
public Disk(int trackCapacity)
|
||||
{
|
||||
WriteProtected = false;
|
||||
_tracks = new int[trackCapacity][];
|
||||
FillMissingTracks();
|
||||
_originalMedia = SerializeTracks(_tracks);
|
||||
Valid = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an expanded representation of a magnetic disk.
|
||||
/// </summary>
|
||||
/// <param name="trackData">Raw bit data.</param>
|
||||
/// <param name="trackNumbers">Track numbers for the raw bit data.</param>
|
||||
/// <param name="trackDensities">Density zones for the raw bit data.</param>
|
||||
/// <param name="trackLengths">Length, in bits, of each raw bit data.</param>
|
||||
/// <param name="trackCapacity">Total number of tracks on the media.</param>
|
||||
public Disk(IList<byte[]> trackData, IList<int> trackNumbers, IList<int> trackDensities, int trackCapacity)
|
||||
{
|
||||
WriteProtected = true;
|
||||
_tracks = new int[trackCapacity][];
|
||||
for (var i = 0; i < trackData.Count; i++)
|
||||
{
|
||||
_tracks[trackNumbers[i]] = ConvertToFluxTransitions(trackDensities[i], trackData[i], 0);
|
||||
}
|
||||
FillMissingTracks();
|
||||
Valid = true;
|
||||
_originalMedia = SerializeTracks(_tracks);
|
||||
}
|
||||
/// <summary>
|
||||
/// Create an expanded representation of a magnetic disk.
|
||||
/// </summary>
|
||||
/// <param name="trackData">Raw bit data.</param>
|
||||
/// <param name="trackNumbers">Track numbers for the raw bit data.</param>
|
||||
/// <param name="trackDensities">Density zones for the raw bit data.</param>
|
||||
/// <param name="trackLengths">Length, in bits, of each raw bit data.</param>
|
||||
/// <param name="trackCapacity">Total number of tracks on the media.</param>
|
||||
public Disk(IList<byte[]> trackData, IList<int> trackNumbers, IList<int> trackDensities, int trackCapacity)
|
||||
{
|
||||
WriteProtected = true;
|
||||
_tracks = new int[trackCapacity][];
|
||||
for (var i = 0; i < trackData.Count; i++)
|
||||
{
|
||||
_tracks[trackNumbers[i]] = ConvertToFluxTransitions(trackDensities[i], trackData[i], 0);
|
||||
}
|
||||
FillMissingTracks();
|
||||
Valid = true;
|
||||
_originalMedia = SerializeTracks(_tracks);
|
||||
}
|
||||
|
||||
private int[] ConvertToFluxTransitions(int density, byte[] bytes, int fluxBitOffset)
|
||||
{
|
||||
var paddedLength = bytes.Length;
|
||||
switch (density)
|
||||
{
|
||||
case 3:
|
||||
paddedLength = Math.Max(bytes.Length, 7692);
|
||||
break;
|
||||
case 2:
|
||||
paddedLength = Math.Max(bytes.Length, 7142);
|
||||
break;
|
||||
case 1:
|
||||
paddedLength = Math.Max(bytes.Length, 6666);
|
||||
break;
|
||||
case 0:
|
||||
paddedLength = Math.Max(bytes.Length, 6250);
|
||||
break;
|
||||
}
|
||||
private int[] ConvertToFluxTransitions(int density, byte[] bytes, int fluxBitOffset)
|
||||
{
|
||||
var paddedLength = bytes.Length;
|
||||
switch (density)
|
||||
{
|
||||
case 3:
|
||||
paddedLength = Math.Max(bytes.Length, 7692);
|
||||
break;
|
||||
case 2:
|
||||
paddedLength = Math.Max(bytes.Length, 7142);
|
||||
break;
|
||||
case 1:
|
||||
paddedLength = Math.Max(bytes.Length, 6666);
|
||||
break;
|
||||
case 0:
|
||||
paddedLength = Math.Max(bytes.Length, 6250);
|
||||
break;
|
||||
}
|
||||
|
||||
paddedLength++;
|
||||
var paddedBytes = new byte[paddedLength];
|
||||
Array.Copy(bytes, paddedBytes, bytes.Length);
|
||||
for (var i = bytes.Length; i < paddedLength; i++)
|
||||
{
|
||||
paddedBytes[i] = 0xAA;
|
||||
}
|
||||
var result = new int[FluxEntriesPerTrack];
|
||||
var lengthBits = (paddedLength * 8) - 7;
|
||||
var offsets = new List<long>();
|
||||
var remainingBits = lengthBits;
|
||||
paddedLength++;
|
||||
var paddedBytes = new byte[paddedLength];
|
||||
Array.Copy(bytes, paddedBytes, bytes.Length);
|
||||
for (var i = bytes.Length; i < paddedLength; i++)
|
||||
{
|
||||
paddedBytes[i] = 0xAA;
|
||||
}
|
||||
var result = new int[FluxEntriesPerTrack];
|
||||
var lengthBits = (paddedLength * 8) - 7;
|
||||
var offsets = new List<long>();
|
||||
var remainingBits = lengthBits;
|
||||
|
||||
const long bitsNum = FluxEntriesPerTrack * FluxBitsPerEntry;
|
||||
long bitsDen = lengthBits;
|
||||
const long bitsNum = FluxEntriesPerTrack * FluxBitsPerEntry;
|
||||
long bitsDen = lengthBits;
|
||||
|
||||
for (var i = 0; i < paddedLength; i++)
|
||||
{
|
||||
var byteData = paddedBytes[i];
|
||||
for (var j = 0; j < 8; j++)
|
||||
{
|
||||
var offset = fluxBitOffset + ((i * 8 + j) * bitsNum / bitsDen);
|
||||
var byteOffset = (int)(offset / FluxBitsPerEntry);
|
||||
var bitOffset = (int)(offset % FluxBitsPerEntry);
|
||||
offsets.Add(offset);
|
||||
result[byteOffset] |= ((byteData & 0x80) != 0 ? 1 : 0) << bitOffset;
|
||||
byteData <<= 1;
|
||||
remainingBits--;
|
||||
if (remainingBits <= 0)
|
||||
break;
|
||||
}
|
||||
if (remainingBits <= 0)
|
||||
break;
|
||||
}
|
||||
for (var i = 0; i < paddedLength; i++)
|
||||
{
|
||||
var byteData = paddedBytes[i];
|
||||
for (var j = 0; j < 8; j++)
|
||||
{
|
||||
var offset = fluxBitOffset + ((i * 8 + j) * bitsNum / bitsDen);
|
||||
var byteOffset = (int)(offset / FluxBitsPerEntry);
|
||||
var bitOffset = (int)(offset % FluxBitsPerEntry);
|
||||
offsets.Add(offset);
|
||||
result[byteOffset] |= ((byteData & 0x80) != 0 ? 1 : 0) << bitOffset;
|
||||
byteData <<= 1;
|
||||
remainingBits--;
|
||||
if (remainingBits <= 0)
|
||||
break;
|
||||
}
|
||||
if (remainingBits <= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void FillMissingTracks()
|
||||
{
|
||||
// Fill half tracks (should assist with EA "fat-track" protections)
|
||||
for (var i = 1; i < _tracks.Length; i += 2)
|
||||
{
|
||||
if (_tracks[i] == null && _tracks[i - 1] != null)
|
||||
{
|
||||
_tracks[i] = new int[FluxEntriesPerTrack];
|
||||
Array.Copy(_tracks[i - 1], _tracks[i], FluxEntriesPerTrack);
|
||||
}
|
||||
}
|
||||
private void FillMissingTracks()
|
||||
{
|
||||
// Fill half tracks (should assist with EA "fat-track" protections)
|
||||
for (var i = 1; i < _tracks.Length; i += 2)
|
||||
{
|
||||
if (_tracks[i] == null && _tracks[i - 1] != null)
|
||||
{
|
||||
_tracks[i] = new int[FluxEntriesPerTrack];
|
||||
Array.Copy(_tracks[i - 1], _tracks[i], FluxEntriesPerTrack);
|
||||
}
|
||||
}
|
||||
|
||||
// Fill vacant tracks
|
||||
for (var i = 0; i < _tracks.Length; i++)
|
||||
{
|
||||
if (_tracks[i] == null)
|
||||
{
|
||||
_tracks[i] = new int[FluxEntriesPerTrack];
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fill vacant tracks
|
||||
for (var i = 0; i < _tracks.Length; i++)
|
||||
{
|
||||
if (_tracks[i] == null)
|
||||
{
|
||||
_tracks[i] = new int[FluxEntriesPerTrack];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int[] GetDataForTrack(int halftrack)
|
||||
{
|
||||
return _tracks[halftrack];
|
||||
}
|
||||
public int[] GetDataForTrack(int halftrack)
|
||||
{
|
||||
return _tracks[halftrack];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Combine the tracks into a single bitstream.
|
||||
/// </summary>
|
||||
private int[] SerializeTracks(int[][] tracks)
|
||||
{
|
||||
var trackCount = tracks.Length;
|
||||
var result = new int[trackCount * FluxEntriesPerTrack];
|
||||
for (var i = 0; i < trackCount; i++)
|
||||
{
|
||||
Array.Copy(tracks[i], 0, result, i * FluxEntriesPerTrack, FluxEntriesPerTrack);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/// <summary>
|
||||
/// Combine the tracks into a single bitstream.
|
||||
/// </summary>
|
||||
private int[] SerializeTracks(int[][] tracks)
|
||||
{
|
||||
var trackCount = tracks.Length;
|
||||
var result = new int[trackCount * FluxEntriesPerTrack];
|
||||
for (var i = 0; i < trackCount; i++)
|
||||
{
|
||||
Array.Copy(tracks[i], 0, result, i * FluxEntriesPerTrack, FluxEntriesPerTrack);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Split a bitstream into tracks.
|
||||
/// </summary>
|
||||
private int[][] DeserializeTracks(int[] data)
|
||||
{
|
||||
var trackCount = data.Length/FluxEntriesPerTrack;
|
||||
var result = new int[trackCount][];
|
||||
for (var i = 0; i < trackCount; i++)
|
||||
{
|
||||
result[i] = new int[FluxEntriesPerTrack];
|
||||
Array.Copy(data, i * FluxEntriesPerTrack, result[i], 0, FluxEntriesPerTrack);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/// <summary>
|
||||
/// Split a bitstream into tracks.
|
||||
/// </summary>
|
||||
private int[][] DeserializeTracks(int[] data)
|
||||
{
|
||||
var trackCount = data.Length / FluxEntriesPerTrack;
|
||||
var result = new int[trackCount][];
|
||||
for (var i = 0; i < trackCount; i++)
|
||||
{
|
||||
result[i] = new int[FluxEntriesPerTrack];
|
||||
Array.Copy(data, i * FluxEntriesPerTrack, result[i], 0, FluxEntriesPerTrack);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
if (ser.IsReader)
|
||||
{
|
||||
var mediaState = new int[_originalMedia.Length];
|
||||
SaveState.SyncDelta("MediaState", ser, _originalMedia, ref mediaState);
|
||||
_tracks = DeserializeTracks(mediaState);
|
||||
}
|
||||
else if (ser.IsWriter)
|
||||
{
|
||||
var mediaState = SerializeTracks(_tracks);
|
||||
SaveState.SyncDelta("MediaState", ser, _originalMedia, ref mediaState);
|
||||
}
|
||||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
}
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
if (ser.IsReader)
|
||||
{
|
||||
var mediaState = new int[_originalMedia.Length];
|
||||
SaveState.SyncDelta("MediaState", ser, _originalMedia, ref mediaState);
|
||||
_tracks = DeserializeTracks(mediaState);
|
||||
}
|
||||
else if (ser.IsWriter)
|
||||
{
|
||||
var mediaState = SerializeTracks(_tracks);
|
||||
SaveState.SyncDelta("MediaState", ser, _originalMedia, ref mediaState);
|
||||
}
|
||||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,302 +7,302 @@ 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
|
||||
}
|
||||
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; }
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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 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 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 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 bool this[int sector]
|
||||
{
|
||||
get { return (Data & (1 << sector)) != 0; }
|
||||
set
|
||||
{
|
||||
if (value)
|
||||
Free(sector);
|
||||
else
|
||||
Allocate(sector);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] GetBytes()
|
||||
{
|
||||
return GetBytesEnumerable().ToArray();
|
||||
}
|
||||
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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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; }
|
||||
}
|
||||
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; }
|
||||
}
|
||||
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
|
||||
};
|
||||
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 List<Entry> Entries { get; set; }
|
||||
public int VersionType { get; set; }
|
||||
public string Title { get; set; }
|
||||
|
||||
public DiskBuilder()
|
||||
{
|
||||
Entries = new List<Entry>();
|
||||
VersionType = 0x41;
|
||||
}
|
||||
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;
|
||||
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)];
|
||||
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>();
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
while (!diskFull)
|
||||
{
|
||||
var outputOffset = GetOutputOffset(currentTrack, currentSector);
|
||||
|
||||
if (dataRemaining > 254)
|
||||
{
|
||||
Array.Copy(entry.Data, sourceOffset, bytes, outputOffset + 2, 254);
|
||||
dataRemaining -= 254;
|
||||
sourceOffset += 254;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dataRemaining > 0)
|
||||
{
|
||||
Array.Copy(entry.Data, sourceOffset, bytes, outputOffset + 2, dataRemaining);
|
||||
bytes[outputOffset + 0] = 0;
|
||||
bytes[outputOffset + 1] = (byte)(dataRemaining + 1);
|
||||
dataRemaining = 0;
|
||||
}
|
||||
}
|
||||
if (dataRemaining > 254)
|
||||
{
|
||||
Array.Copy(entry.Data, sourceOffset, bytes, outputOffset + 2, 254);
|
||||
dataRemaining -= 254;
|
||||
sourceOffset += 254;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dataRemaining > 0)
|
||||
{
|
||||
Array.Copy(entry.Data, sourceOffset, bytes, outputOffset + 2, dataRemaining);
|
||||
bytes[outputOffset + 0] = 0;
|
||||
bytes[outputOffset + 1] = (byte)(dataRemaining + 1);
|
||||
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;
|
||||
}
|
||||
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;
|
||||
if (dataRemaining <= 0)
|
||||
break;
|
||||
|
||||
bytes[outputOffset + 0] = (byte)(currentTrack + 1);
|
||||
bytes[outputOffset + 1] = (byte) currentSector;
|
||||
}
|
||||
bytes[outputOffset + 0] = (byte)(currentTrack + 1);
|
||||
bytes[outputOffset + 1] = (byte)currentSector;
|
||||
}
|
||||
|
||||
if (diskFull)
|
||||
break;
|
||||
}
|
||||
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 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));
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
return D64.Read(bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,56 +9,56 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media
|
|||
{
|
||||
public static Disk Read(byte[] source)
|
||||
{
|
||||
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>();
|
||||
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, 84);
|
||||
}
|
||||
return new Disk(trackDatas, trackNumbers, trackDensities, 84);
|
||||
}
|
||||
|
||||
return new Disk(84);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new Disk(84);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,22 +7,22 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media
|
|||
public static void Load(Chip90611401 pla, byte[] prgFile)
|
||||
{
|
||||
var length = prgFile.Length;
|
||||
if (length <= 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (length <= 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var addr = prgFile[0] | (prgFile[1] << 8);
|
||||
var offset = 2;
|
||||
unchecked
|
||||
{
|
||||
while (offset < length)
|
||||
{
|
||||
pla.Write(addr, prgFile[offset]);
|
||||
offset++;
|
||||
addr++;
|
||||
}
|
||||
}
|
||||
var addr = prgFile[0] | (prgFile[1] << 8);
|
||||
var offset = 2;
|
||||
unchecked
|
||||
{
|
||||
while (offset < length)
|
||||
{
|
||||
pla.Write(addr, prgFile[offset]);
|
||||
offset++;
|
||||
addr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,305 +13,305 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
{
|
||||
internal static class SaveState
|
||||
{
|
||||
public class DoNotSave : Attribute
|
||||
{
|
||||
}
|
||||
public class DoNotSave : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
public class SaveWithName : Attribute
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public class SaveWithName : Attribute
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public SaveWithName(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
public SaveWithName(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Encoding Encoding = Encoding.Unicode;
|
||||
|
||||
private static int[] GetDelta(IList<int> source, IList<int> data)
|
||||
{
|
||||
var length = Math.Min(source.Count, data.Count);
|
||||
var delta = new int[length];
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
delta[i] = source[i] ^ data[i];
|
||||
}
|
||||
return delta;
|
||||
}
|
||||
private static int[] GetDelta(IList<int> source, IList<int> data)
|
||||
{
|
||||
var length = Math.Min(source.Count, data.Count);
|
||||
var delta = new int[length];
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
delta[i] = source[i] ^ data[i];
|
||||
}
|
||||
return delta;
|
||||
}
|
||||
|
||||
private static byte[] CompressInts(int[] data)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var length = data.Length;
|
||||
var bytes = new byte[length * 4];
|
||||
for (int i = 0, j = 0; i < length; i++)
|
||||
{
|
||||
var c = data[i];
|
||||
bytes[j++] = (byte)(c);
|
||||
bytes[j++] = (byte)(c >> 8);
|
||||
bytes[j++] = (byte)(c >> 16);
|
||||
bytes[j++] = (byte)(c >> 24);
|
||||
}
|
||||
using (var mem = new MemoryStream())
|
||||
{
|
||||
using (var compressor = new DeflateStream(mem, CompressionMode.Compress))
|
||||
{
|
||||
var writer = new BinaryWriter(compressor);
|
||||
writer.Write(bytes.Length);
|
||||
writer.Write(bytes);
|
||||
compressor.Flush();
|
||||
}
|
||||
mem.Flush();
|
||||
return mem.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
private static byte[] CompressInts(int[] data)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var length = data.Length;
|
||||
var bytes = new byte[length * 4];
|
||||
for (int i = 0, j = 0; i < length; i++)
|
||||
{
|
||||
var c = data[i];
|
||||
bytes[j++] = (byte)(c);
|
||||
bytes[j++] = (byte)(c >> 8);
|
||||
bytes[j++] = (byte)(c >> 16);
|
||||
bytes[j++] = (byte)(c >> 24);
|
||||
}
|
||||
using (var mem = new MemoryStream())
|
||||
{
|
||||
using (var compressor = new DeflateStream(mem, CompressionMode.Compress))
|
||||
{
|
||||
var writer = new BinaryWriter(compressor);
|
||||
writer.Write(bytes.Length);
|
||||
writer.Write(bytes);
|
||||
compressor.Flush();
|
||||
}
|
||||
mem.Flush();
|
||||
return mem.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int[] DecompressInts(byte[] data)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
using (var mem = new MemoryStream(data))
|
||||
{
|
||||
using (var decompressor = new DeflateStream(mem, CompressionMode.Decompress))
|
||||
{
|
||||
var reader = new BinaryReader(decompressor);
|
||||
var length = reader.ReadInt32();
|
||||
var bytes = reader.ReadBytes(length);
|
||||
var result = new int[length >> 2];
|
||||
for (int i = 0, j = 0; i < length; i++)
|
||||
{
|
||||
int d = bytes[i++];
|
||||
d |= bytes[i++] << 8;
|
||||
d |= bytes[i++] << 16;
|
||||
d |= bytes[i] << 24;
|
||||
result[j++] = d;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private static int[] DecompressInts(byte[] data)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
using (var mem = new MemoryStream(data))
|
||||
{
|
||||
using (var decompressor = new DeflateStream(mem, CompressionMode.Decompress))
|
||||
{
|
||||
var reader = new BinaryReader(decompressor);
|
||||
var length = reader.ReadInt32();
|
||||
var bytes = reader.ReadBytes(length);
|
||||
var result = new int[length >> 2];
|
||||
for (int i = 0, j = 0; i < length; i++)
|
||||
{
|
||||
int d = bytes[i++];
|
||||
d |= bytes[i++] << 8;
|
||||
d |= bytes[i++] << 16;
|
||||
d |= bytes[i] << 24;
|
||||
result[j++] = d;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void SyncDelta(string name, Serializer ser, int[] source, ref int[] data)
|
||||
{
|
||||
int[] delta = null;
|
||||
if (ser.IsWriter && data != null)
|
||||
{
|
||||
delta = GetDelta(source, data);
|
||||
}
|
||||
ser.Sync(name, ref delta, false);
|
||||
if (ser.IsReader && delta != null)
|
||||
{
|
||||
data = GetDelta(source, delta);
|
||||
}
|
||||
}
|
||||
public static void SyncDelta(string name, Serializer ser, int[] source, ref int[] data)
|
||||
{
|
||||
int[] delta = null;
|
||||
if (ser.IsWriter && data != null)
|
||||
{
|
||||
delta = GetDelta(source, data);
|
||||
}
|
||||
ser.Sync(name, ref delta, false);
|
||||
if (ser.IsReader && delta != null)
|
||||
{
|
||||
data = GetDelta(source, delta);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SyncObject(Serializer ser, object obj)
|
||||
public static void SyncObject(Serializer ser, object obj)
|
||||
{
|
||||
const BindingFlags defaultFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;
|
||||
var objType = obj.GetType();
|
||||
var members = objType.GetMembers(defaultFlags);
|
||||
var objType = obj.GetType();
|
||||
var members = objType.GetMembers(defaultFlags);
|
||||
|
||||
foreach (var member in members)
|
||||
foreach (var member in members)
|
||||
{
|
||||
if (member.GetCustomAttributes(true).Any(a => a is DoNotSave))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (member.GetCustomAttributes(true).Any(a => a is DoNotSave))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var name = member.Name;
|
||||
var nameAttribute = member.GetCustomAttributes(true).FirstOrDefault(a => a is SaveWithName);
|
||||
if (nameAttribute != null)
|
||||
{
|
||||
name = ((SaveWithName) nameAttribute).Name;
|
||||
}
|
||||
var name = member.Name;
|
||||
var nameAttribute = member.GetCustomAttributes(true).FirstOrDefault(a => a is SaveWithName);
|
||||
if (nameAttribute != null)
|
||||
{
|
||||
name = ((SaveWithName)nameAttribute).Name;
|
||||
}
|
||||
|
||||
|
||||
object currentValue = null;
|
||||
object currentValue = null;
|
||||
var fail = false;
|
||||
var fieldInfo = member as FieldInfo;
|
||||
Type valueType = null;
|
||||
Type valueType = null;
|
||||
|
||||
if ((member.MemberType == MemberTypes.Field) && member.ReflectedType != null)
|
||||
if ((member.MemberType == MemberTypes.Field) && member.ReflectedType != null)
|
||||
{
|
||||
valueType = fieldInfo.FieldType;
|
||||
currentValue = fieldInfo.GetValue(obj);
|
||||
}
|
||||
valueType = fieldInfo.FieldType;
|
||||
currentValue = fieldInfo.GetValue(obj);
|
||||
}
|
||||
|
||||
if (currentValue != null)
|
||||
{
|
||||
ByteBuffer refByteBuffer;
|
||||
int refInt32;
|
||||
IntBuffer refIntBuffer;
|
||||
int refPointX;
|
||||
int refPointY;
|
||||
switch (valueType.Name)
|
||||
{
|
||||
case "Action`1":
|
||||
case "Action`2":
|
||||
break;
|
||||
case "Bit":
|
||||
var refBit = (Bit)currentValue;
|
||||
ser.Sync(name, ref refBit);
|
||||
currentValue = refBit;
|
||||
break;
|
||||
case "Boolean":
|
||||
var refBool = (bool)currentValue;
|
||||
ser.Sync(name, ref refBool);
|
||||
currentValue = refBool;
|
||||
break;
|
||||
case "Boolean[]":
|
||||
{
|
||||
var tmp = (bool[])currentValue;
|
||||
ser.Sync(name, ref tmp, false);
|
||||
currentValue = tmp;
|
||||
}
|
||||
break;
|
||||
case "Byte":
|
||||
var refByte = (byte)currentValue;
|
||||
ser.Sync(name, ref refByte);
|
||||
currentValue = refByte;
|
||||
break;
|
||||
case "Byte[]":
|
||||
refByteBuffer = new ByteBuffer((byte[])currentValue);
|
||||
ser.Sync(name, ref refByteBuffer);
|
||||
currentValue = refByteBuffer.Arr.Select(d => d).ToArray();
|
||||
refByteBuffer.Dispose();
|
||||
break;
|
||||
case "ByteBuffer":
|
||||
refByteBuffer = (ByteBuffer)currentValue;
|
||||
ser.Sync(name, ref refByteBuffer);
|
||||
currentValue = refByteBuffer;
|
||||
break;
|
||||
case "Func`1":
|
||||
case "Func`2":
|
||||
break;
|
||||
case "Int16":
|
||||
var refInt16 = (short)currentValue;
|
||||
ser.Sync(name, ref refInt16);
|
||||
currentValue = refInt16;
|
||||
break;
|
||||
case "Int32":
|
||||
refInt32 = (int)currentValue;
|
||||
ser.Sync(name, ref refInt32);
|
||||
currentValue = refInt32;
|
||||
break;
|
||||
case "Int32[]":
|
||||
refIntBuffer = new IntBuffer((int[])currentValue);
|
||||
ser.Sync(name, ref refIntBuffer);
|
||||
currentValue = refIntBuffer.Arr.Select(d => d).ToArray();
|
||||
refIntBuffer.Dispose();
|
||||
break;
|
||||
case "IntBuffer":
|
||||
refIntBuffer = (IntBuffer)currentValue;
|
||||
ser.Sync(name, ref refIntBuffer);
|
||||
currentValue = refIntBuffer;
|
||||
break;
|
||||
case "Point":
|
||||
refPointX = ((Point)currentValue).X;
|
||||
refPointY = ((Point)currentValue).Y;
|
||||
ser.Sync(name + "_X", ref refPointX);
|
||||
ser.Sync(name + "_Y", ref refPointY);
|
||||
currentValue = new Point(refPointX, refPointY);
|
||||
break;
|
||||
case "Rectangle":
|
||||
refPointX = ((Rectangle)currentValue).X;
|
||||
refPointY = ((Rectangle)currentValue).Y;
|
||||
var refRectWidth = ((Rectangle)currentValue).Width;
|
||||
var refRectHeight = ((Rectangle)currentValue).Height;
|
||||
ser.Sync(name + "_X", ref refPointX);
|
||||
ser.Sync(name + "_Y", ref refPointY);
|
||||
ser.Sync(name + "_Height", ref refRectHeight);
|
||||
ser.Sync(name + "_Width", ref refRectWidth);
|
||||
currentValue = new Rectangle(refPointX, refPointY, refRectWidth, refRectHeight);
|
||||
break;
|
||||
case "SByte":
|
||||
var refSByte = (sbyte)currentValue;
|
||||
ser.Sync(name, ref refSByte);
|
||||
currentValue = refSByte;
|
||||
break;
|
||||
case "String":
|
||||
var refString = (string)currentValue;
|
||||
var refVal = new ByteBuffer(Encoding.GetBytes(refString));
|
||||
ser.Sync(name, ref refVal);
|
||||
currentValue = Encoding.GetString(refVal.Arr);
|
||||
refVal.Dispose();
|
||||
break;
|
||||
case "UInt16":
|
||||
var refUInt16 = (ushort)currentValue;
|
||||
ser.Sync(name, ref refUInt16);
|
||||
currentValue = refUInt16;
|
||||
break;
|
||||
case "UInt32":
|
||||
var refUInt32 = (uint)currentValue;
|
||||
ser.Sync(name, ref refUInt32);
|
||||
currentValue = refUInt32;
|
||||
break;
|
||||
default:
|
||||
var t = currentValue.GetType();
|
||||
if (t.IsEnum)
|
||||
{
|
||||
refInt32 = (int)currentValue;
|
||||
ser.Sync(name, ref refInt32);
|
||||
currentValue = refInt32;
|
||||
}
|
||||
else if (t.IsArray)
|
||||
{
|
||||
var currentValueArray = (Array) currentValue;
|
||||
for (var i = 0; i < currentValueArray.Length; i++)
|
||||
{
|
||||
ser.BeginSection(string.Format("{0}_{1}", name, i));
|
||||
SyncObject(ser, currentValueArray.GetValue(i));
|
||||
ser.EndSection();
|
||||
}
|
||||
}
|
||||
else if (t.IsValueType)
|
||||
{
|
||||
fail = true;
|
||||
}
|
||||
else if (t.IsClass)
|
||||
{
|
||||
fail = true;
|
||||
foreach (var method in t.GetMethods().Where(method => method.Name == "SyncState"))
|
||||
{
|
||||
ser.BeginSection(fieldInfo.Name);
|
||||
method.Invoke(currentValue, new object[] { ser });
|
||||
ser.EndSection();
|
||||
fail = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fail = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (currentValue != null)
|
||||
{
|
||||
ByteBuffer refByteBuffer;
|
||||
int refInt32;
|
||||
IntBuffer refIntBuffer;
|
||||
int refPointX;
|
||||
int refPointY;
|
||||
switch (valueType.Name)
|
||||
{
|
||||
case "Action`1":
|
||||
case "Action`2":
|
||||
break;
|
||||
case "Bit":
|
||||
var refBit = (Bit)currentValue;
|
||||
ser.Sync(name, ref refBit);
|
||||
currentValue = refBit;
|
||||
break;
|
||||
case "Boolean":
|
||||
var refBool = (bool)currentValue;
|
||||
ser.Sync(name, ref refBool);
|
||||
currentValue = refBool;
|
||||
break;
|
||||
case "Boolean[]":
|
||||
{
|
||||
var tmp = (bool[])currentValue;
|
||||
ser.Sync(name, ref tmp, false);
|
||||
currentValue = tmp;
|
||||
}
|
||||
break;
|
||||
case "Byte":
|
||||
var refByte = (byte)currentValue;
|
||||
ser.Sync(name, ref refByte);
|
||||
currentValue = refByte;
|
||||
break;
|
||||
case "Byte[]":
|
||||
refByteBuffer = new ByteBuffer((byte[])currentValue);
|
||||
ser.Sync(name, ref refByteBuffer);
|
||||
currentValue = refByteBuffer.Arr.Select(d => d).ToArray();
|
||||
refByteBuffer.Dispose();
|
||||
break;
|
||||
case "ByteBuffer":
|
||||
refByteBuffer = (ByteBuffer)currentValue;
|
||||
ser.Sync(name, ref refByteBuffer);
|
||||
currentValue = refByteBuffer;
|
||||
break;
|
||||
case "Func`1":
|
||||
case "Func`2":
|
||||
break;
|
||||
case "Int16":
|
||||
var refInt16 = (short)currentValue;
|
||||
ser.Sync(name, ref refInt16);
|
||||
currentValue = refInt16;
|
||||
break;
|
||||
case "Int32":
|
||||
refInt32 = (int)currentValue;
|
||||
ser.Sync(name, ref refInt32);
|
||||
currentValue = refInt32;
|
||||
break;
|
||||
case "Int32[]":
|
||||
refIntBuffer = new IntBuffer((int[])currentValue);
|
||||
ser.Sync(name, ref refIntBuffer);
|
||||
currentValue = refIntBuffer.Arr.Select(d => d).ToArray();
|
||||
refIntBuffer.Dispose();
|
||||
break;
|
||||
case "IntBuffer":
|
||||
refIntBuffer = (IntBuffer)currentValue;
|
||||
ser.Sync(name, ref refIntBuffer);
|
||||
currentValue = refIntBuffer;
|
||||
break;
|
||||
case "Point":
|
||||
refPointX = ((Point)currentValue).X;
|
||||
refPointY = ((Point)currentValue).Y;
|
||||
ser.Sync(name + "_X", ref refPointX);
|
||||
ser.Sync(name + "_Y", ref refPointY);
|
||||
currentValue = new Point(refPointX, refPointY);
|
||||
break;
|
||||
case "Rectangle":
|
||||
refPointX = ((Rectangle)currentValue).X;
|
||||
refPointY = ((Rectangle)currentValue).Y;
|
||||
var refRectWidth = ((Rectangle)currentValue).Width;
|
||||
var refRectHeight = ((Rectangle)currentValue).Height;
|
||||
ser.Sync(name + "_X", ref refPointX);
|
||||
ser.Sync(name + "_Y", ref refPointY);
|
||||
ser.Sync(name + "_Height", ref refRectHeight);
|
||||
ser.Sync(name + "_Width", ref refRectWidth);
|
||||
currentValue = new Rectangle(refPointX, refPointY, refRectWidth, refRectHeight);
|
||||
break;
|
||||
case "SByte":
|
||||
var refSByte = (sbyte)currentValue;
|
||||
ser.Sync(name, ref refSByte);
|
||||
currentValue = refSByte;
|
||||
break;
|
||||
case "String":
|
||||
var refString = (string)currentValue;
|
||||
var refVal = new ByteBuffer(Encoding.GetBytes(refString));
|
||||
ser.Sync(name, ref refVal);
|
||||
currentValue = Encoding.GetString(refVal.Arr);
|
||||
refVal.Dispose();
|
||||
break;
|
||||
case "UInt16":
|
||||
var refUInt16 = (ushort)currentValue;
|
||||
ser.Sync(name, ref refUInt16);
|
||||
currentValue = refUInt16;
|
||||
break;
|
||||
case "UInt32":
|
||||
var refUInt32 = (uint)currentValue;
|
||||
ser.Sync(name, ref refUInt32);
|
||||
currentValue = refUInt32;
|
||||
break;
|
||||
default:
|
||||
var t = currentValue.GetType();
|
||||
if (t.IsEnum)
|
||||
{
|
||||
refInt32 = (int)currentValue;
|
||||
ser.Sync(name, ref refInt32);
|
||||
currentValue = refInt32;
|
||||
}
|
||||
else if (t.IsArray)
|
||||
{
|
||||
var currentValueArray = (Array)currentValue;
|
||||
for (var i = 0; i < currentValueArray.Length; i++)
|
||||
{
|
||||
ser.BeginSection(string.Format("{0}_{1}", name, i));
|
||||
SyncObject(ser, currentValueArray.GetValue(i));
|
||||
ser.EndSection();
|
||||
}
|
||||
}
|
||||
else if (t.IsValueType)
|
||||
{
|
||||
fail = true;
|
||||
}
|
||||
else if (t.IsClass)
|
||||
{
|
||||
fail = true;
|
||||
foreach (var method in t.GetMethods().Where(method => method.Name == "SyncState"))
|
||||
{
|
||||
ser.BeginSection(fieldInfo.Name);
|
||||
method.Invoke(currentValue, new object[] { ser });
|
||||
ser.EndSection();
|
||||
fail = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fail = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fail)
|
||||
{
|
||||
if (member.MemberType == MemberTypes.Property)
|
||||
{
|
||||
var propInfo = member as PropertyInfo;
|
||||
if (propInfo.CanWrite)
|
||||
{
|
||||
var setMethod = propInfo.GetSetMethod();
|
||||
if (setMethod != null)
|
||||
{
|
||||
setMethod.Invoke(obj, new[] { currentValue });
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (member.MemberType == MemberTypes.Field)
|
||||
{
|
||||
fieldInfo.SetValue(obj, currentValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!fail)
|
||||
{
|
||||
if (member.MemberType == MemberTypes.Property)
|
||||
{
|
||||
var propInfo = member as PropertyInfo;
|
||||
if (propInfo.CanWrite)
|
||||
{
|
||||
var setMethod = propInfo.GetSetMethod();
|
||||
if (setMethod != null)
|
||||
{
|
||||
setMethod.Invoke(obj, new[] { currentValue });
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (member.MemberType == MemberTypes.Field)
|
||||
{
|
||||
fieldInfo.SetValue(obj, currentValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,161 +6,161 @@ using BizHawk.Emulation.Cores.Computers.Commodore64.Media;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
|
||||
{
|
||||
public sealed partial class Drive1541
|
||||
{
|
||||
[SaveState.DoNotSave]
|
||||
private const long LEHMER_RNG_PRIME = 48271;
|
||||
[SaveState.SaveWithName("DiskDensityCounter")]
|
||||
private int _diskDensityCounter; // density .. 16
|
||||
[SaveState.SaveWithName("DiskSupplementaryCounter")]
|
||||
private int _diskSupplementaryCounter; // 0 .. 16
|
||||
[SaveState.SaveWithName("DiskFluxReversalDetected")]
|
||||
private bool _diskFluxReversalDetected;
|
||||
[SaveState.SaveWithName("DiskBitsRemainingInDataEntry")]
|
||||
private int _diskBitsLeft;
|
||||
[SaveState.SaveWithName("DiskDataEntryIndex")]
|
||||
private int _diskByteOffset;
|
||||
[SaveState.SaveWithName("DiskDataEntry")]
|
||||
private int _diskBits;
|
||||
[SaveState.SaveWithName("DiskCurrentCycle")]
|
||||
private int _diskCycle;
|
||||
[SaveState.SaveWithName("DiskDensityConfig")]
|
||||
private int _diskDensity;
|
||||
[SaveState.SaveWithName("PreviousCA1")]
|
||||
private bool _previousCa1;
|
||||
[SaveState.SaveWithName("CountsBeforeRandomTransition")]
|
||||
private int _countsBeforeRandomTransition;
|
||||
[SaveState.SaveWithName("CurrentRNG")]
|
||||
private int _rngCurrent;
|
||||
[SaveState.SaveWithName("Clocks")]
|
||||
private int _clocks;
|
||||
[SaveState.SaveWithName("CpuClocks")]
|
||||
private int _cpuClocks;
|
||||
public sealed partial class Drive1541
|
||||
{
|
||||
[SaveState.DoNotSave]
|
||||
private const long LEHMER_RNG_PRIME = 48271;
|
||||
[SaveState.SaveWithName("DiskDensityCounter")]
|
||||
private int _diskDensityCounter; // density .. 16
|
||||
[SaveState.SaveWithName("DiskSupplementaryCounter")]
|
||||
private int _diskSupplementaryCounter; // 0 .. 16
|
||||
[SaveState.SaveWithName("DiskFluxReversalDetected")]
|
||||
private bool _diskFluxReversalDetected;
|
||||
[SaveState.SaveWithName("DiskBitsRemainingInDataEntry")]
|
||||
private int _diskBitsLeft;
|
||||
[SaveState.SaveWithName("DiskDataEntryIndex")]
|
||||
private int _diskByteOffset;
|
||||
[SaveState.SaveWithName("DiskDataEntry")]
|
||||
private int _diskBits;
|
||||
[SaveState.SaveWithName("DiskCurrentCycle")]
|
||||
private int _diskCycle;
|
||||
[SaveState.SaveWithName("DiskDensityConfig")]
|
||||
private int _diskDensity;
|
||||
[SaveState.SaveWithName("PreviousCA1")]
|
||||
private bool _previousCa1;
|
||||
[SaveState.SaveWithName("CountsBeforeRandomTransition")]
|
||||
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()
|
||||
{
|
||||
if (_rngCurrent == 0)
|
||||
_rngCurrent = 1;
|
||||
_rngCurrent = (int)(_rngCurrent * LEHMER_RNG_PRIME % int.MaxValue);
|
||||
}
|
||||
// Lehmer RNG
|
||||
private void AdvanceRng()
|
||||
{
|
||||
if (_rngCurrent == 0)
|
||||
_rngCurrent = 1;
|
||||
_rngCurrent = (int)(_rngCurrent * LEHMER_RNG_PRIME % int.MaxValue);
|
||||
}
|
||||
|
||||
private void ExecuteFlux()
|
||||
{
|
||||
// This actually executes the main 16mhz clock
|
||||
while (_clocks > 0)
|
||||
{
|
||||
_clocks--;
|
||||
private void ExecuteFlux()
|
||||
{
|
||||
// This actually executes the main 16mhz clock
|
||||
while (_clocks > 0)
|
||||
{
|
||||
_clocks--;
|
||||
|
||||
// rotate disk
|
||||
if (_motorEnabled)
|
||||
{
|
||||
if (_disk == null)
|
||||
{
|
||||
_diskBitsLeft = 1;
|
||||
_diskBits = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_diskBitsLeft <= 0)
|
||||
{
|
||||
_diskByteOffset++;
|
||||
if (_diskByteOffset == Disk.FluxEntriesPerTrack)
|
||||
{
|
||||
_diskByteOffset = 0;
|
||||
}
|
||||
_diskBits = _trackImageData[_diskByteOffset];
|
||||
_diskBitsLeft = Disk.FluxBitsPerEntry;
|
||||
}
|
||||
}
|
||||
if ((_diskBits & 1) != 0)
|
||||
{
|
||||
_countsBeforeRandomTransition = 0;
|
||||
_diskFluxReversalDetected = true;
|
||||
}
|
||||
_diskBits >>= 1;
|
||||
_diskBitsLeft--;
|
||||
}
|
||||
// rotate disk
|
||||
if (_motorEnabled)
|
||||
{
|
||||
if (_disk == null)
|
||||
{
|
||||
_diskBitsLeft = 1;
|
||||
_diskBits = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_diskBitsLeft <= 0)
|
||||
{
|
||||
_diskByteOffset++;
|
||||
if (_diskByteOffset == Disk.FluxEntriesPerTrack)
|
||||
{
|
||||
_diskByteOffset = 0;
|
||||
}
|
||||
_diskBits = _trackImageData[_diskByteOffset];
|
||||
_diskBitsLeft = Disk.FluxBitsPerEntry;
|
||||
}
|
||||
}
|
||||
if ((_diskBits & 1) != 0)
|
||||
{
|
||||
_countsBeforeRandomTransition = 0;
|
||||
_diskFluxReversalDetected = true;
|
||||
}
|
||||
_diskBits >>= 1;
|
||||
_diskBitsLeft--;
|
||||
}
|
||||
|
||||
// random flux transition readings for unformatted data
|
||||
if (_countsBeforeRandomTransition > 0)
|
||||
{
|
||||
_countsBeforeRandomTransition--;
|
||||
if (_countsBeforeRandomTransition == 0)
|
||||
{
|
||||
_diskFluxReversalDetected = true;
|
||||
AdvanceRng();
|
||||
// This constant is what VICE uses. TODO: Determine accuracy.
|
||||
_countsBeforeRandomTransition = (_rngCurrent % 367) + 33;
|
||||
}
|
||||
}
|
||||
// random flux transition readings for unformatted data
|
||||
if (_countsBeforeRandomTransition > 0)
|
||||
{
|
||||
_countsBeforeRandomTransition--;
|
||||
if (_countsBeforeRandomTransition == 0)
|
||||
{
|
||||
_diskFluxReversalDetected = true;
|
||||
AdvanceRng();
|
||||
// This constant is what VICE uses. TODO: Determine accuracy.
|
||||
_countsBeforeRandomTransition = (_rngCurrent % 367) + 33;
|
||||
}
|
||||
}
|
||||
|
||||
// flux transition circuitry
|
||||
if (_diskFluxReversalDetected)
|
||||
{
|
||||
_diskDensityCounter = _diskDensity;
|
||||
_diskSupplementaryCounter = 0;
|
||||
_diskFluxReversalDetected = false;
|
||||
if (_countsBeforeRandomTransition == 0)
|
||||
{
|
||||
AdvanceRng();
|
||||
// This constant is what VICE uses. TODO: Determine accuracy.
|
||||
_countsBeforeRandomTransition = (_rngCurrent & 0x1F) + 289;
|
||||
}
|
||||
}
|
||||
// flux transition circuitry
|
||||
if (_diskFluxReversalDetected)
|
||||
{
|
||||
_diskDensityCounter = _diskDensity;
|
||||
_diskSupplementaryCounter = 0;
|
||||
_diskFluxReversalDetected = false;
|
||||
if (_countsBeforeRandomTransition == 0)
|
||||
{
|
||||
AdvanceRng();
|
||||
// This constant is what VICE uses. TODO: Determine accuracy.
|
||||
_countsBeforeRandomTransition = (_rngCurrent & 0x1F) + 289;
|
||||
}
|
||||
}
|
||||
|
||||
// counter circuitry
|
||||
if (_diskDensityCounter >= 16)
|
||||
{
|
||||
_diskDensityCounter = _diskDensity;
|
||||
_diskSupplementaryCounter++;
|
||||
if ((_diskSupplementaryCounter & 0x3) == 0x2)
|
||||
{
|
||||
_bitsRemainingInLatchedByte--;
|
||||
_byteReady = false;
|
||||
_bitHistory = (_bitHistory << 1) | ((_diskSupplementaryCounter & 0xC) == 0x0 ? 1 : 0);
|
||||
_sync = false;
|
||||
if (Via1.Cb2 && (_bitHistory & 0x3FF) == 0x3FF)
|
||||
{
|
||||
_sync = true;
|
||||
_bitsRemainingInLatchedByte = 8;
|
||||
_byteReady = false;
|
||||
}
|
||||
// counter circuitry
|
||||
if (_diskDensityCounter >= 16)
|
||||
{
|
||||
_diskDensityCounter = _diskDensity;
|
||||
_diskSupplementaryCounter++;
|
||||
if ((_diskSupplementaryCounter & 0x3) == 0x2)
|
||||
{
|
||||
_bitsRemainingInLatchedByte--;
|
||||
_byteReady = false;
|
||||
_bitHistory = (_bitHistory << 1) | ((_diskSupplementaryCounter & 0xC) == 0x0 ? 1 : 0);
|
||||
_sync = false;
|
||||
if (Via1.Cb2 && (_bitHistory & 0x3FF) == 0x3FF)
|
||||
{
|
||||
_sync = true;
|
||||
_bitsRemainingInLatchedByte = 8;
|
||||
_byteReady = false;
|
||||
}
|
||||
|
||||
if (_bitsRemainingInLatchedByte <= 0)
|
||||
{
|
||||
_bitsRemainingInLatchedByte = 8;
|
||||
if (_bitsRemainingInLatchedByte <= 0)
|
||||
{
|
||||
_bitsRemainingInLatchedByte = 8;
|
||||
|
||||
// SOE (sync output enabled)
|
||||
_byteReady = Via1.Ca2;
|
||||
}
|
||||
// SOE (sync output enabled)
|
||||
_byteReady = Via1.Ca2;
|
||||
}
|
||||
|
||||
// negative transition activates SO pin on CPU
|
||||
_previousCa1 = Via1.Ca1;
|
||||
Via1.Ca1 = !_byteReady;
|
||||
if (_previousCa1 && !Via1.Ca1)
|
||||
{
|
||||
// cycle 6 is roughly 400ns
|
||||
_overflowFlagDelaySr |= _diskCycle > 6 ? 4 : 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
// negative transition activates SO pin on CPU
|
||||
_previousCa1 = Via1.Ca1;
|
||||
Via1.Ca1 = !_byteReady;
|
||||
if (_previousCa1 && !Via1.Ca1)
|
||||
{
|
||||
// cycle 6 is roughly 400ns
|
||||
_overflowFlagDelaySr |= _diskCycle > 6 ? 4 : 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_diskSupplementaryCounter >= 16)
|
||||
{
|
||||
_diskSupplementaryCounter = 0;
|
||||
}
|
||||
if (_diskSupplementaryCounter >= 16)
|
||||
{
|
||||
_diskSupplementaryCounter = 0;
|
||||
}
|
||||
|
||||
_cpuClocks--;
|
||||
if (_cpuClocks <= 0)
|
||||
{
|
||||
ExecuteSystem();
|
||||
_cpuClocks = 16;
|
||||
}
|
||||
_cpuClocks--;
|
||||
if (_cpuClocks <= 0)
|
||||
{
|
||||
ExecuteSystem();
|
||||
_cpuClocks = 16;
|
||||
}
|
||||
|
||||
_diskDensityCounter++;
|
||||
_diskCycle = (_diskCycle + 1) & 0xF;
|
||||
}
|
||||
}
|
||||
}
|
||||
_diskDensityCounter++;
|
||||
_diskCycle = (_diskCycle + 1) & 0xF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,157 +6,157 @@ using BizHawk.Emulation.Common;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
|
||||
{
|
||||
public sealed partial class Drive1541 : IDebuggable
|
||||
{
|
||||
IDictionary<string, RegisterValue> IDebuggable.GetCpuFlagsAndRegisters()
|
||||
{
|
||||
return new Dictionary<string, RegisterValue>
|
||||
{
|
||||
{ "A", _cpu.A },
|
||||
{ "X", _cpu.X },
|
||||
{ "Y", _cpu.Y },
|
||||
{ "S", _cpu.S },
|
||||
{ "PC", _cpu.PC },
|
||||
{ "Flag C", _cpu.FlagC },
|
||||
{ "Flag Z", _cpu.FlagZ },
|
||||
{ "Flag I", _cpu.FlagI },
|
||||
{ "Flag D", _cpu.FlagD },
|
||||
{ "Flag B", _cpu.FlagB },
|
||||
{ "Flag V", _cpu.FlagV },
|
||||
{ "Flag N", _cpu.FlagN },
|
||||
{ "Flag T", _cpu.FlagT }
|
||||
};
|
||||
}
|
||||
public sealed partial class Drive1541 : IDebuggable
|
||||
{
|
||||
IDictionary<string, RegisterValue> IDebuggable.GetCpuFlagsAndRegisters()
|
||||
{
|
||||
return new Dictionary<string, RegisterValue>
|
||||
{
|
||||
{ "A", _cpu.A },
|
||||
{ "X", _cpu.X },
|
||||
{ "Y", _cpu.Y },
|
||||
{ "S", _cpu.S },
|
||||
{ "PC", _cpu.PC },
|
||||
{ "Flag C", _cpu.FlagC },
|
||||
{ "Flag Z", _cpu.FlagZ },
|
||||
{ "Flag I", _cpu.FlagI },
|
||||
{ "Flag D", _cpu.FlagD },
|
||||
{ "Flag B", _cpu.FlagB },
|
||||
{ "Flag V", _cpu.FlagV },
|
||||
{ "Flag N", _cpu.FlagN },
|
||||
{ "Flag T", _cpu.FlagT }
|
||||
};
|
||||
}
|
||||
|
||||
void IDebuggable.SetCpuRegister(string register, int value)
|
||||
{
|
||||
switch (register)
|
||||
{
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
case "A":
|
||||
_cpu.A = (byte)value;
|
||||
break;
|
||||
case "X":
|
||||
_cpu.X = (byte)value;
|
||||
break;
|
||||
case "Y":
|
||||
_cpu.Y = (byte)value;
|
||||
break;
|
||||
case "S":
|
||||
_cpu.S = (byte)value;
|
||||
break;
|
||||
case "PC":
|
||||
_cpu.PC = (ushort)value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
void IDebuggable.SetCpuRegister(string register, int value)
|
||||
{
|
||||
switch (register)
|
||||
{
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
case "A":
|
||||
_cpu.A = (byte)value;
|
||||
break;
|
||||
case "X":
|
||||
_cpu.X = (byte)value;
|
||||
break;
|
||||
case "Y":
|
||||
_cpu.Y = (byte)value;
|
||||
break;
|
||||
case "S":
|
||||
_cpu.S = (byte)value;
|
||||
break;
|
||||
case "PC":
|
||||
_cpu.PC = (ushort)value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool IDebuggable.CanStep(StepType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case StepType.Into:
|
||||
case StepType.Over:
|
||||
case StepType.Out:
|
||||
return DebuggerStep != null;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool IDebuggable.CanStep(StepType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case StepType.Into:
|
||||
case StepType.Over:
|
||||
case StepType.Out:
|
||||
return DebuggerStep != null;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void IDebuggable.Step(StepType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case StepType.Into:
|
||||
StepInto();
|
||||
break;
|
||||
case StepType.Out:
|
||||
StepOut();
|
||||
break;
|
||||
case StepType.Over:
|
||||
StepOver();
|
||||
break;
|
||||
}
|
||||
}
|
||||
void IDebuggable.Step(StepType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case StepType.Into:
|
||||
StepInto();
|
||||
break;
|
||||
case StepType.Out:
|
||||
StepOut();
|
||||
break;
|
||||
case StepType.Over:
|
||||
StepOver();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int IDebuggable.TotalExecutedCycles
|
||||
{
|
||||
get { return _cpu.TotalExecutedCycles; }
|
||||
}
|
||||
|
||||
private void StepInto()
|
||||
{
|
||||
while (_cpu.AtInstructionStart())
|
||||
{
|
||||
DebuggerStep();
|
||||
}
|
||||
while (!_cpu.AtInstructionStart())
|
||||
{
|
||||
DebuggerStep();
|
||||
}
|
||||
}
|
||||
private void StepInto()
|
||||
{
|
||||
while (_cpu.AtInstructionStart())
|
||||
{
|
||||
DebuggerStep();
|
||||
}
|
||||
while (!_cpu.AtInstructionStart())
|
||||
{
|
||||
DebuggerStep();
|
||||
}
|
||||
}
|
||||
|
||||
private void StepOver()
|
||||
{
|
||||
var instruction = CpuPeek(_cpu.PC);
|
||||
private void StepOver()
|
||||
{
|
||||
var instruction = CpuPeek(_cpu.PC);
|
||||
|
||||
if (instruction == Jsr)
|
||||
{
|
||||
var destination = _cpu.PC + JsrSize;
|
||||
while (_cpu.PC != destination)
|
||||
{
|
||||
StepInto();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
StepInto();
|
||||
}
|
||||
}
|
||||
if (instruction == Jsr)
|
||||
{
|
||||
var destination = _cpu.PC + JsrSize;
|
||||
while (_cpu.PC != destination)
|
||||
{
|
||||
StepInto();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
StepInto();
|
||||
}
|
||||
}
|
||||
|
||||
private void StepOut()
|
||||
{
|
||||
var instructionsBeforeBailout = 1000000;
|
||||
var instr = CpuPeek(_cpu.PC);
|
||||
_jsrCount = instr == Jsr ? 1 : 0;
|
||||
private void StepOut()
|
||||
{
|
||||
var instructionsBeforeBailout = 1000000;
|
||||
var instr = CpuPeek(_cpu.PC);
|
||||
_jsrCount = instr == Jsr ? 1 : 0;
|
||||
|
||||
while (--instructionsBeforeBailout > 0)
|
||||
{
|
||||
StepInto();
|
||||
instr = CpuPeek(_cpu.PC);
|
||||
if (instr == Jsr)
|
||||
{
|
||||
_jsrCount++;
|
||||
}
|
||||
else if ((instr == Rts || instr == Rti) && _jsrCount <= 0)
|
||||
{
|
||||
StepInto();
|
||||
_jsrCount = 0;
|
||||
break;
|
||||
}
|
||||
else if (instr == Rts || instr == Rti)
|
||||
{
|
||||
_jsrCount--;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (--instructionsBeforeBailout > 0)
|
||||
{
|
||||
StepInto();
|
||||
instr = CpuPeek(_cpu.PC);
|
||||
if (instr == Jsr)
|
||||
{
|
||||
_jsrCount++;
|
||||
}
|
||||
else if ((instr == Rts || instr == Rti) && _jsrCount <= 0)
|
||||
{
|
||||
StepInto();
|
||||
_jsrCount = 0;
|
||||
break;
|
||||
}
|
||||
else if (instr == Rts || instr == Rti)
|
||||
{
|
||||
_jsrCount--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
private int _jsrCount;
|
||||
[SaveState.DoNotSave]
|
||||
private const byte Jsr = 0x20;
|
||||
[SaveState.DoNotSave]
|
||||
private const byte Rti = 0x40;
|
||||
[SaveState.DoNotSave]
|
||||
private const byte Rts = 0x60;
|
||||
[SaveState.DoNotSave]
|
||||
private int _jsrCount;
|
||||
[SaveState.DoNotSave]
|
||||
private const byte Jsr = 0x20;
|
||||
[SaveState.DoNotSave]
|
||||
private const byte Rti = 0x40;
|
||||
[SaveState.DoNotSave]
|
||||
private const byte Rts = 0x60;
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
private const byte JsrSize = 3;
|
||||
[SaveState.DoNotSave]
|
||||
private const byte JsrSize = 3;
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public IMemoryCallbackSystem MemoryCallbacks { get; private set; }
|
||||
}
|
||||
[SaveState.DoNotSave]
|
||||
public IMemoryCallbackSystem MemoryCallbacks { get; private set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,32 +6,32 @@ using BizHawk.Emulation.Common;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
|
||||
{
|
||||
public sealed partial class Drive1541 : IDisassemblable
|
||||
{
|
||||
[SaveState.DoNotSave]
|
||||
IEnumerable<string> IDisassemblable.AvailableCpus
|
||||
{
|
||||
get { yield return "Disk Drive 6502"; }
|
||||
}
|
||||
public sealed partial class Drive1541 : IDisassemblable
|
||||
{
|
||||
[SaveState.DoNotSave]
|
||||
IEnumerable<string> IDisassemblable.AvailableCpus
|
||||
{
|
||||
get { yield return "Disk Drive 6502"; }
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
string IDisassemblable.Cpu
|
||||
{
|
||||
get { return "Disk Drive 6502"; }
|
||||
set
|
||||
{
|
||||
}
|
||||
}
|
||||
[SaveState.DoNotSave]
|
||||
string IDisassemblable.Cpu
|
||||
{
|
||||
get { return "Disk Drive 6502"; }
|
||||
set
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
string IDisassemblable.PCRegisterName
|
||||
{
|
||||
get { return "PC"; }
|
||||
}
|
||||
[SaveState.DoNotSave]
|
||||
string IDisassemblable.PCRegisterName
|
||||
{
|
||||
get { return "PC"; }
|
||||
}
|
||||
|
||||
string IDisassemblable.Disassemble(MemoryDomain m, uint addr, out int length)
|
||||
{
|
||||
return Components.M6502.MOS6502X.Disassemble((ushort)addr, out length, CpuPeek);
|
||||
}
|
||||
}
|
||||
string IDisassemblable.Disassemble(MemoryDomain m, uint addr, out int length)
|
||||
{
|
||||
return Components.M6502.MOS6502X.Disassemble((ushort)addr, out length, CpuPeek);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,35 +6,35 @@ using System.Text;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
|
||||
{
|
||||
public sealed partial class Drive1541
|
||||
{
|
||||
[SaveState.DoNotSave] private int _tempStep;
|
||||
[SaveState.DoNotSave] private int _tempPrB1;
|
||||
public sealed partial class Drive1541
|
||||
{
|
||||
[SaveState.DoNotSave] private int _tempStep;
|
||||
[SaveState.DoNotSave] private int _tempPrB1;
|
||||
|
||||
private void ExecuteMotor()
|
||||
{
|
||||
_tempPrB1 = Via1.EffectivePrB;
|
||||
_tempStep = _tempPrB1 & 0x3;
|
||||
_diskDensity = (_tempPrB1 & 0x60) >> 5;
|
||||
_motorEnabled = (_tempPrB1 & 0x04) != 0;
|
||||
_ledEnabled = (_tempPrB1 & 0x08) != 0;
|
||||
private void ExecuteMotor()
|
||||
{
|
||||
_tempPrB1 = Via1.EffectivePrB;
|
||||
_tempStep = _tempPrB1 & 0x3;
|
||||
_diskDensity = (_tempPrB1 & 0x60) >> 5;
|
||||
_motorEnabled = (_tempPrB1 & 0x04) != 0;
|
||||
_ledEnabled = (_tempPrB1 & 0x08) != 0;
|
||||
|
||||
// motor track stepping
|
||||
if (_tempStep != _motorStep)
|
||||
{
|
||||
if (_tempStep == ((_motorStep - 1) & 0x3))
|
||||
_trackNumber--;
|
||||
else if (_tempStep == ((_motorStep + 1) & 0x3))
|
||||
_trackNumber++;
|
||||
// motor track stepping
|
||||
if (_tempStep != _motorStep)
|
||||
{
|
||||
if (_tempStep == ((_motorStep - 1) & 0x3))
|
||||
_trackNumber--;
|
||||
else if (_tempStep == ((_motorStep + 1) & 0x3))
|
||||
_trackNumber++;
|
||||
|
||||
if (_trackNumber < 0)
|
||||
_trackNumber = 0;
|
||||
else if (_trackNumber > 83)
|
||||
_trackNumber = 83;
|
||||
if (_trackNumber < 0)
|
||||
_trackNumber = 0;
|
||||
else if (_trackNumber > 83)
|
||||
_trackNumber = 83;
|
||||
|
||||
_motorStep = _tempStep;
|
||||
UpdateMediaData();
|
||||
}
|
||||
}
|
||||
}
|
||||
_motorStep = _tempStep;
|
||||
UpdateMediaData();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,160 +5,160 @@ using System.Text;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
|
||||
{
|
||||
public sealed partial class Drive1541
|
||||
{
|
||||
[SaveState.SaveWithName("OverflowFlagDelayShiftRegister")]
|
||||
private int _overflowFlagDelaySr;
|
||||
public sealed partial class Drive1541
|
||||
{
|
||||
[SaveState.SaveWithName("OverflowFlagDelayShiftRegister")]
|
||||
private int _overflowFlagDelaySr;
|
||||
|
||||
private byte CpuPeek(ushort addr)
|
||||
{
|
||||
return unchecked((byte)Peek(addr));
|
||||
}
|
||||
private byte CpuPeek(ushort addr)
|
||||
{
|
||||
return unchecked((byte)Peek(addr));
|
||||
}
|
||||
|
||||
private byte CpuRead(ushort addr)
|
||||
{
|
||||
return unchecked((byte)Read(addr));
|
||||
}
|
||||
private byte CpuRead(ushort addr)
|
||||
{
|
||||
return unchecked((byte)Read(addr));
|
||||
}
|
||||
|
||||
private void CpuWrite(ushort addr, byte val)
|
||||
{
|
||||
Write(addr, val);
|
||||
}
|
||||
private void CpuWrite(ushort addr, byte val)
|
||||
{
|
||||
Write(addr, val);
|
||||
}
|
||||
|
||||
private bool ViaReadClock()
|
||||
{
|
||||
var inputClock = ReadMasterClk();
|
||||
var outputClock = ReadDeviceClk();
|
||||
return !(inputClock && outputClock);
|
||||
}
|
||||
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 ViaReadData()
|
||||
{
|
||||
var inputData = ReadMasterData();
|
||||
var outputData = ReadDeviceData();
|
||||
return !(inputData && outputData);
|
||||
}
|
||||
|
||||
private bool ViaReadAtn()
|
||||
{
|
||||
var inputAtn = ReadMasterAtn();
|
||||
return !inputAtn;
|
||||
}
|
||||
private bool ViaReadAtn()
|
||||
{
|
||||
var inputAtn = ReadMasterAtn();
|
||||
return !inputAtn;
|
||||
}
|
||||
|
||||
private int ReadVia1PrA()
|
||||
{
|
||||
return _bitHistory & 0xFF;
|
||||
}
|
||||
private int ReadVia1PrA()
|
||||
{
|
||||
return _bitHistory & 0xFF;
|
||||
}
|
||||
|
||||
private int ReadVia1PrB()
|
||||
{
|
||||
return (_motorStep & 0x03) | (_motorEnabled ? 0x04 : 0x00) | (_sync ? 0x00 : 0x80);
|
||||
}
|
||||
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 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 PeekVia0(int addr)
|
||||
{
|
||||
return Via0.Peek(addr);
|
||||
}
|
||||
|
||||
public int PeekVia1(int addr)
|
||||
{
|
||||
return Via1.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 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 PokeVia0(int addr, int val)
|
||||
{
|
||||
Via0.Poke(addr, val);
|
||||
}
|
||||
|
||||
public void PokeVia1(int addr, int val)
|
||||
{
|
||||
Via1.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 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 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 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;
|
||||
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;
|
||||
}
|
||||
return !(viaOutputAtna ^ viaInputAtn) && !viaOutputData;
|
||||
}
|
||||
|
||||
public override bool ReadDeviceLight()
|
||||
{
|
||||
return _driveLightOffTime > 0;
|
||||
}
|
||||
}
|
||||
public override bool ReadDeviceLight()
|
||||
{
|
||||
return _driveLightOffTime > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,167 +11,167 @@ using BizHawk.Emulation.Cores.Computers.Commodore64.MOS;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
|
||||
{
|
||||
public sealed partial class Drive1541 : SerialPortDevice
|
||||
{
|
||||
[SaveState.SaveWithName("Disk")]
|
||||
private Disk _disk;
|
||||
[SaveState.SaveWithName("BitHistory")]
|
||||
private int _bitHistory;
|
||||
[SaveState.SaveWithName("BitsRemainingInLatchedByte")]
|
||||
private int _bitsRemainingInLatchedByte;
|
||||
[SaveState.SaveWithName("Sync")]
|
||||
private bool _sync;
|
||||
[SaveState.SaveWithName("ByteReady")]
|
||||
private bool _byteReady;
|
||||
[SaveState.SaveWithName("DriveCpuClockNumerator")]
|
||||
private readonly int _driveCpuClockNum;
|
||||
[SaveState.SaveWithName("TrackNumber")]
|
||||
private int _trackNumber;
|
||||
[SaveState.SaveWithName("MotorEnabled")]
|
||||
private bool _motorEnabled;
|
||||
[SaveState.SaveWithName("LedEnabled")]
|
||||
private bool _ledEnabled;
|
||||
[SaveState.SaveWithName("MotorStep")]
|
||||
private int _motorStep;
|
||||
[SaveState.SaveWithName("CPU")]
|
||||
private readonly MOS6502X _cpu;
|
||||
[SaveState.SaveWithName("RAM")]
|
||||
private readonly int[] _ram;
|
||||
[SaveState.SaveWithName("VIA0")]
|
||||
public readonly Via Via0;
|
||||
[SaveState.SaveWithName("VIA1")]
|
||||
public readonly Via Via1;
|
||||
[SaveState.SaveWithName("SystemCpuClockNumerator")]
|
||||
private readonly int _cpuClockNum;
|
||||
[SaveState.SaveWithName("SystemDriveCpuRatioDifference")]
|
||||
private int _ratioDifference;
|
||||
[SaveState.SaveWithName("DriveLightOffTime")]
|
||||
private int _driveLightOffTime;
|
||||
[SaveState.DoNotSave]
|
||||
private int[] _trackImageData = new int[1];
|
||||
[SaveState.DoNotSave]
|
||||
public Func<int> ReadIec = () => 0xFF;
|
||||
[SaveState.DoNotSave]
|
||||
public Action DebuggerStep;
|
||||
[SaveState.DoNotSave]
|
||||
public readonly Chip23128 DriveRom;
|
||||
public sealed partial class Drive1541 : SerialPortDevice
|
||||
{
|
||||
[SaveState.SaveWithName("Disk")]
|
||||
private Disk _disk;
|
||||
[SaveState.SaveWithName("BitHistory")]
|
||||
private int _bitHistory;
|
||||
[SaveState.SaveWithName("BitsRemainingInLatchedByte")]
|
||||
private int _bitsRemainingInLatchedByte;
|
||||
[SaveState.SaveWithName("Sync")]
|
||||
private bool _sync;
|
||||
[SaveState.SaveWithName("ByteReady")]
|
||||
private bool _byteReady;
|
||||
[SaveState.SaveWithName("DriveCpuClockNumerator")]
|
||||
private readonly int _driveCpuClockNum;
|
||||
[SaveState.SaveWithName("TrackNumber")]
|
||||
private int _trackNumber;
|
||||
[SaveState.SaveWithName("MotorEnabled")]
|
||||
private bool _motorEnabled;
|
||||
[SaveState.SaveWithName("LedEnabled")]
|
||||
private bool _ledEnabled;
|
||||
[SaveState.SaveWithName("MotorStep")]
|
||||
private int _motorStep;
|
||||
[SaveState.SaveWithName("CPU")]
|
||||
private readonly MOS6502X _cpu;
|
||||
[SaveState.SaveWithName("RAM")]
|
||||
private readonly int[] _ram;
|
||||
[SaveState.SaveWithName("VIA0")]
|
||||
public readonly Via Via0;
|
||||
[SaveState.SaveWithName("VIA1")]
|
||||
public readonly Via Via1;
|
||||
[SaveState.SaveWithName("SystemCpuClockNumerator")]
|
||||
private readonly int _cpuClockNum;
|
||||
[SaveState.SaveWithName("SystemDriveCpuRatioDifference")]
|
||||
private int _ratioDifference;
|
||||
[SaveState.SaveWithName("DriveLightOffTime")]
|
||||
private int _driveLightOffTime;
|
||||
[SaveState.DoNotSave]
|
||||
private int[] _trackImageData = new int[1];
|
||||
[SaveState.DoNotSave]
|
||||
public Func<int> ReadIec = () => 0xFF;
|
||||
[SaveState.DoNotSave]
|
||||
public Action DebuggerStep;
|
||||
[SaveState.DoNotSave]
|
||||
public readonly Chip23128 DriveRom;
|
||||
|
||||
public Drive1541(int clockNum, int clockDen)
|
||||
{
|
||||
DriveRom = new Chip23128();
|
||||
_cpu = new MOS6502X
|
||||
{
|
||||
ReadMemory = CpuRead,
|
||||
WriteMemory = CpuWrite,
|
||||
DummyReadMemory = CpuRead,
|
||||
PeekMemory = CpuPeek,
|
||||
NMI = false
|
||||
};
|
||||
public Drive1541(int clockNum, int clockDen)
|
||||
{
|
||||
DriveRom = new Chip23128();
|
||||
_cpu = new MOS6502X
|
||||
{
|
||||
ReadMemory = CpuRead,
|
||||
WriteMemory = CpuWrite,
|
||||
DummyReadMemory = CpuRead,
|
||||
PeekMemory = CpuPeek,
|
||||
NMI = false
|
||||
};
|
||||
|
||||
_ram = new int[0x800];
|
||||
Via0 = Chip6522.Create(ViaReadClock, ViaReadData, ViaReadAtn, 8);
|
||||
Via1 = Chip6522.Create(ReadVia1PrA, ReadVia1PrB);
|
||||
_ram = new int[0x800];
|
||||
Via0 = Chip6522.Create(ViaReadClock, ViaReadData, ViaReadAtn, 8);
|
||||
Via1 = Chip6522.Create(ReadVia1PrA, ReadVia1PrB);
|
||||
|
||||
_cpuClockNum = clockNum;
|
||||
_driveCpuClockNum = clockDen*16000000; // 16mhz
|
||||
}
|
||||
_cpuClockNum = clockNum;
|
||||
_driveCpuClockNum = clockDen * 16000000; // 16mhz
|
||||
}
|
||||
|
||||
public override void ExecutePhase()
|
||||
{
|
||||
_ratioDifference += _driveCpuClockNum;
|
||||
while (_ratioDifference > _cpuClockNum)
|
||||
{
|
||||
_ratioDifference -= _cpuClockNum;
|
||||
_clocks++;
|
||||
}
|
||||
ExecutePhaseInternal();
|
||||
}
|
||||
public override void ExecutePhase()
|
||||
{
|
||||
_ratioDifference += _driveCpuClockNum;
|
||||
while (_ratioDifference > _cpuClockNum)
|
||||
{
|
||||
_ratioDifference -= _cpuClockNum;
|
||||
_clocks++;
|
||||
}
|
||||
ExecutePhaseInternal();
|
||||
}
|
||||
|
||||
private void ExecutePhaseInternal()
|
||||
{
|
||||
// clock output from 325572-01 drives CPU clock (phi0)
|
||||
ExecuteMotor();
|
||||
ExecuteFlux();
|
||||
}
|
||||
private void ExecutePhaseInternal()
|
||||
{
|
||||
// clock output from 325572-01 drives CPU clock (phi0)
|
||||
ExecuteMotor();
|
||||
ExecuteFlux();
|
||||
}
|
||||
|
||||
private void ExecuteSystem()
|
||||
{
|
||||
Via0.Ca1 = ViaReadAtn();
|
||||
Via0.ExecutePhase();
|
||||
Via1.ExecutePhase();
|
||||
private void ExecuteSystem()
|
||||
{
|
||||
Via0.Ca1 = ViaReadAtn();
|
||||
Via0.ExecutePhase();
|
||||
Via1.ExecutePhase();
|
||||
|
||||
// SO pin pipeline
|
||||
if ((_overflowFlagDelaySr & 0x01) != 0)
|
||||
{
|
||||
_cpu.SetOverflow();
|
||||
}
|
||||
_overflowFlagDelaySr >>= 1;
|
||||
// SO pin pipeline
|
||||
if ((_overflowFlagDelaySr & 0x01) != 0)
|
||||
{
|
||||
_cpu.SetOverflow();
|
||||
}
|
||||
_overflowFlagDelaySr >>= 1;
|
||||
|
||||
_cpu.IRQ = !(Via0.Irq && Via1.Irq); // active low IRQ line
|
||||
_cpu.ExecuteOne();
|
||||
_cpu.IRQ = !(Via0.Irq && Via1.Irq); // active low IRQ line
|
||||
_cpu.ExecuteOne();
|
||||
|
||||
if (_ledEnabled)
|
||||
{
|
||||
_driveLightOffTime = 25000;
|
||||
}
|
||||
else if (_driveLightOffTime > 0)
|
||||
{
|
||||
_driveLightOffTime--;
|
||||
}
|
||||
}
|
||||
if (_ledEnabled)
|
||||
{
|
||||
_driveLightOffTime = 25000;
|
||||
}
|
||||
else if (_driveLightOffTime > 0)
|
||||
{
|
||||
_driveLightOffTime--;
|
||||
}
|
||||
}
|
||||
|
||||
public override void HardReset()
|
||||
{
|
||||
Via0.HardReset();
|
||||
Via1.HardReset();
|
||||
_trackNumber = 34;
|
||||
for (var i = 0; i < _ram.Length; i++)
|
||||
{
|
||||
_ram[i] = 0x00;
|
||||
}
|
||||
public override void HardReset()
|
||||
{
|
||||
Via0.HardReset();
|
||||
Via1.HardReset();
|
||||
_trackNumber = 34;
|
||||
for (var i = 0; i < _ram.Length; i++)
|
||||
{
|
||||
_ram[i] = 0x00;
|
||||
}
|
||||
|
||||
_diskDensity = 0;
|
||||
_diskFluxReversalDetected = false;
|
||||
_diskByteOffset = 0;
|
||||
_diskBitsLeft = 0;
|
||||
_diskBits = 0;
|
||||
_driveLightOffTime = 0;
|
||||
_diskDensityCounter = 0;
|
||||
_diskSupplementaryCounter = 0;
|
||||
_diskCycle = 0;
|
||||
_previousCa1 = false;
|
||||
_countsBeforeRandomTransition = 0;
|
||||
_diskDensity = 0;
|
||||
_diskFluxReversalDetected = false;
|
||||
_diskByteOffset = 0;
|
||||
_diskBitsLeft = 0;
|
||||
_diskBits = 0;
|
||||
_driveLightOffTime = 0;
|
||||
_diskDensityCounter = 0;
|
||||
_diskSupplementaryCounter = 0;
|
||||
_diskCycle = 0;
|
||||
_previousCa1 = false;
|
||||
_countsBeforeRandomTransition = 0;
|
||||
|
||||
SoftReset();
|
||||
UpdateMediaData();
|
||||
}
|
||||
SoftReset();
|
||||
UpdateMediaData();
|
||||
}
|
||||
|
||||
public void SoftReset()
|
||||
{
|
||||
_cpu.NESSoftReset();
|
||||
_overflowFlagDelaySr = 0;
|
||||
}
|
||||
public void SoftReset()
|
||||
{
|
||||
_cpu.NESSoftReset();
|
||||
_overflowFlagDelaySr = 0;
|
||||
}
|
||||
|
||||
public void InsertMedia(Disk disk)
|
||||
{
|
||||
_disk = disk;
|
||||
UpdateMediaData();
|
||||
}
|
||||
public void InsertMedia(Disk disk)
|
||||
{
|
||||
_disk = disk;
|
||||
UpdateMediaData();
|
||||
}
|
||||
|
||||
private void UpdateMediaData()
|
||||
{
|
||||
if (_disk != null)
|
||||
{
|
||||
_trackImageData = _disk.GetDataForTrack(_trackNumber);
|
||||
_diskBits = _trackImageData[_diskByteOffset] >> (Disk.FluxBitsPerEntry - _diskBitsLeft);
|
||||
}
|
||||
}
|
||||
private void UpdateMediaData()
|
||||
{
|
||||
if (_disk != null)
|
||||
{
|
||||
_trackImageData = _disk.GetDataForTrack(_trackNumber);
|
||||
_diskBits = _trackImageData[_diskByteOffset] >> (Disk.FluxBitsPerEntry - _diskBitsLeft);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveMedia()
|
||||
{
|
||||
_disk = null;
|
||||
_trackImageData = null;
|
||||
_diskBits = 0;
|
||||
}
|
||||
}
|
||||
public void RemoveMedia()
|
||||
{
|
||||
_disk = null;
|
||||
_trackImageData = null;
|
||||
_diskBits = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,83 +8,83 @@ using BizHawk.Emulation.Cores.Computers.Commodore64.Cassette;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
|
||||
{
|
||||
public sealed class SerialPort : IDriveLight
|
||||
{
|
||||
[SaveState.DoNotSave]
|
||||
public Func<bool> ReadMasterAtn = () => true;
|
||||
[SaveState.DoNotSave]
|
||||
public Func<bool> ReadMasterClk = () => true;
|
||||
[SaveState.DoNotSave]
|
||||
public Func<bool> ReadMasterData = () => true;
|
||||
public sealed class SerialPort : IDriveLight
|
||||
{
|
||||
[SaveState.DoNotSave]
|
||||
public Func<bool> ReadMasterAtn = () => true;
|
||||
[SaveState.DoNotSave]
|
||||
public Func<bool> ReadMasterClk = () => true;
|
||||
[SaveState.DoNotSave]
|
||||
public Func<bool> ReadMasterData = () => true;
|
||||
|
||||
[SaveState.SaveWithName("Device")]
|
||||
private SerialPortDevice _device;
|
||||
[SaveState.SaveWithName("Connected")]
|
||||
private bool _connected;
|
||||
[SaveState.SaveWithName("Device")]
|
||||
private SerialPortDevice _device;
|
||||
[SaveState.SaveWithName("Connected")]
|
||||
private bool _connected;
|
||||
|
||||
public void HardReset()
|
||||
{
|
||||
if (_connected)
|
||||
{
|
||||
_device.HardReset();
|
||||
}
|
||||
}
|
||||
public void HardReset()
|
||||
{
|
||||
if (_connected)
|
||||
{
|
||||
_device.HardReset();
|
||||
}
|
||||
}
|
||||
|
||||
public void ExecutePhase()
|
||||
{
|
||||
if (_connected)
|
||||
{
|
||||
_device.ExecutePhase();
|
||||
}
|
||||
}
|
||||
public void ExecutePhase()
|
||||
{
|
||||
if (_connected)
|
||||
{
|
||||
_device.ExecutePhase();
|
||||
}
|
||||
}
|
||||
|
||||
public void ExecuteDeferred(int cycles)
|
||||
{
|
||||
if (_connected)
|
||||
{
|
||||
_device.ExecuteDeferred(cycles);
|
||||
}
|
||||
}
|
||||
public void ExecuteDeferred(int cycles)
|
||||
{
|
||||
if (_connected)
|
||||
{
|
||||
_device.ExecuteDeferred(cycles);
|
||||
}
|
||||
}
|
||||
|
||||
public bool ReadDeviceClock()
|
||||
{
|
||||
return !_connected || _device.ReadDeviceClk();
|
||||
}
|
||||
public bool ReadDeviceClock()
|
||||
{
|
||||
return !_connected || _device.ReadDeviceClk();
|
||||
}
|
||||
|
||||
public bool ReadDeviceData()
|
||||
{
|
||||
return !_connected || _device.ReadDeviceData();
|
||||
}
|
||||
public bool ReadDeviceData()
|
||||
{
|
||||
return !_connected || _device.ReadDeviceData();
|
||||
}
|
||||
|
||||
public bool ReadDeviceLight()
|
||||
{
|
||||
return _connected && _device.ReadDeviceLight();
|
||||
}
|
||||
public bool ReadDeviceLight()
|
||||
{
|
||||
return _connected && _device.ReadDeviceLight();
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
|
||||
public void Connect(SerialPortDevice device)
|
||||
{
|
||||
_connected = device != null;
|
||||
_device = device;
|
||||
if (_device == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
public void Connect(SerialPortDevice device)
|
||||
{
|
||||
_connected = device != null;
|
||||
_device = device;
|
||||
if (_device == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_device.ReadMasterAtn = () => ReadMasterAtn();
|
||||
_device.ReadMasterClk = () => ReadMasterClk();
|
||||
_device.ReadMasterData = () => ReadMasterData();
|
||||
}
|
||||
_device.ReadMasterAtn = () => ReadMasterAtn();
|
||||
_device.ReadMasterClk = () => ReadMasterClk();
|
||||
_device.ReadMasterData = () => ReadMasterData();
|
||||
}
|
||||
|
||||
[SaveState.DoNotSave]
|
||||
public bool DriveLightEnabled { get { return true; } }
|
||||
[SaveState.DoNotSave]
|
||||
public bool DriveLightOn { get { return ReadDeviceLight(); } }
|
||||
[SaveState.DoNotSave]
|
||||
public bool IsConnected { get { return _connected; } }
|
||||
}
|
||||
[SaveState.DoNotSave]
|
||||
public bool DriveLightEnabled { get { return true; } }
|
||||
[SaveState.DoNotSave]
|
||||
public bool DriveLightOn { get { return ReadDeviceLight(); } }
|
||||
[SaveState.DoNotSave]
|
||||
public bool IsConnected { get { return _connected; } }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,45 +6,45 @@ using BizHawk.Common;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
|
||||
{
|
||||
public abstract class SerialPortDevice
|
||||
{
|
||||
[SaveState.DoNotSave]
|
||||
public Func<bool> ReadMasterAtn = () => true;
|
||||
[SaveState.DoNotSave]
|
||||
public Func<bool> ReadMasterClk = () => true;
|
||||
[SaveState.DoNotSave]
|
||||
public Func<bool> ReadMasterData = () => true;
|
||||
public abstract class SerialPortDevice
|
||||
{
|
||||
[SaveState.DoNotSave]
|
||||
public Func<bool> ReadMasterAtn = () => true;
|
||||
[SaveState.DoNotSave]
|
||||
public Func<bool> ReadMasterClk = () => true;
|
||||
[SaveState.DoNotSave]
|
||||
public Func<bool> ReadMasterData = () => true;
|
||||
|
||||
public virtual void ExecutePhase()
|
||||
{
|
||||
}
|
||||
public virtual void ExecutePhase()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void ExecuteDeferred(int cycles)
|
||||
{
|
||||
}
|
||||
public virtual void ExecuteDeferred(int cycles)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void HardReset()
|
||||
{
|
||||
}
|
||||
public virtual void HardReset()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual bool ReadDeviceClk()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
public virtual bool ReadDeviceClk()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool ReadDeviceData()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
public virtual bool ReadDeviceData()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool ReadDeviceLight()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
public virtual bool ReadDeviceLight()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public virtual void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
}
|
||||
public virtual void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,73 +3,73 @@ using BizHawk.Common;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.User
|
||||
{
|
||||
public sealed class UserPort
|
||||
{
|
||||
public Func<bool> ReadCounter1;
|
||||
public Func<bool> ReadCounter2;
|
||||
public Func<bool> ReadHandshake;
|
||||
public Func<bool> ReadSerial1;
|
||||
public Func<bool> ReadSerial2;
|
||||
public sealed class UserPort
|
||||
{
|
||||
public Func<bool> ReadCounter1;
|
||||
public Func<bool> ReadCounter2;
|
||||
public Func<bool> ReadHandshake;
|
||||
public Func<bool> ReadSerial1;
|
||||
public Func<bool> ReadSerial2;
|
||||
|
||||
private bool _connected;
|
||||
private UserPortDevice _device;
|
||||
private bool _connected;
|
||||
private UserPortDevice _device;
|
||||
|
||||
public void Connect(UserPortDevice device)
|
||||
{
|
||||
_device = device;
|
||||
_connected = _device != null;
|
||||
if (_device != null)
|
||||
{
|
||||
_device.ReadCounter1 = () => ReadCounter1();
|
||||
_device.ReadCounter2 = () => ReadCounter2();
|
||||
_device.ReadHandshake = () => ReadHandshake();
|
||||
_device.ReadSerial1 = () => ReadSerial1();
|
||||
_device.ReadSerial2 = () => ReadSerial2();
|
||||
}
|
||||
}
|
||||
public void Connect(UserPortDevice device)
|
||||
{
|
||||
_device = device;
|
||||
_connected = _device != null;
|
||||
if (_device != null)
|
||||
{
|
||||
_device.ReadCounter1 = () => ReadCounter1();
|
||||
_device.ReadCounter2 = () => ReadCounter2();
|
||||
_device.ReadHandshake = () => ReadHandshake();
|
||||
_device.ReadSerial1 = () => ReadSerial1();
|
||||
_device.ReadSerial2 = () => ReadSerial2();
|
||||
}
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
_connected = false;
|
||||
_device = null;
|
||||
}
|
||||
public void Disconnect()
|
||||
{
|
||||
_connected = false;
|
||||
_device = null;
|
||||
}
|
||||
|
||||
public void HardReset()
|
||||
{
|
||||
if (_connected)
|
||||
{
|
||||
_device.HardReset();
|
||||
}
|
||||
}
|
||||
public void HardReset()
|
||||
{
|
||||
if (_connected)
|
||||
{
|
||||
_device.HardReset();
|
||||
}
|
||||
}
|
||||
|
||||
public bool ReadAtn()
|
||||
{
|
||||
return !_connected || _device.ReadAtn();
|
||||
}
|
||||
public bool ReadAtn()
|
||||
{
|
||||
return !_connected || _device.ReadAtn();
|
||||
}
|
||||
|
||||
public int ReadData()
|
||||
{
|
||||
return !_connected ? 0xFF : _device.ReadData();
|
||||
}
|
||||
public int ReadData()
|
||||
{
|
||||
return !_connected ? 0xFF : _device.ReadData();
|
||||
}
|
||||
|
||||
public bool ReadFlag2()
|
||||
{
|
||||
return !_connected || _device.ReadFlag2();
|
||||
}
|
||||
public bool ReadFlag2()
|
||||
{
|
||||
return !_connected || _device.ReadFlag2();
|
||||
}
|
||||
|
||||
public bool ReadPa2()
|
||||
{
|
||||
return !_connected || _device.ReadPa2();
|
||||
}
|
||||
public bool ReadPa2()
|
||||
{
|
||||
return !_connected || _device.ReadPa2();
|
||||
}
|
||||
|
||||
public bool ReadReset()
|
||||
{
|
||||
return !_connected || _device.ReadReset();
|
||||
}
|
||||
public bool ReadReset()
|
||||
{
|
||||
return !_connected || _device.ReadReset();
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
}
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
SaveState.SyncObject(ser, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue