commodore64: VIA timer chip registers added. Also, writes to mirrored registers now work correctly on all chips
This commit is contained in:
parent
8196caf731
commit
5b701a58e9
|
@ -14,6 +14,15 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
// two 6522 VIA chips, mapped at 1800 (communication to C64) and 1C00 (drive mechanics)
|
||||
// drive ROM, mapped C000-FFFF
|
||||
|
||||
// default 1800:
|
||||
// 07 00 1A FF 05 00 FF FF
|
||||
// 04 00 00 00 00 00 00 00
|
||||
// default 1C00:
|
||||
// 90 00 00 00 05 00 FF FF
|
||||
// 04 00 00 00 00 00 80 00
|
||||
|
||||
private Cia cia;
|
||||
|
||||
public MOS6502X cpu;
|
||||
public int cyclesPerRevolution;
|
||||
public int cyclesPerSecond;
|
||||
|
@ -21,14 +30,17 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
public byte[] ram;
|
||||
public byte[] rom;
|
||||
public double rpm;
|
||||
public ChipSignals signal;
|
||||
public Via via0;
|
||||
public Via via1;
|
||||
|
||||
public Drive1541(byte[] driveRom, Region driveRegion)
|
||||
public Drive1541(byte[] driveRom, Region driveRegion, Cia ciaInterface)
|
||||
{
|
||||
rom = new byte[driveRom.Length];
|
||||
Array.Copy(driveRom, rom, driveRom.Length);
|
||||
|
||||
cia = ciaInterface;
|
||||
|
||||
switch (driveRegion)
|
||||
{
|
||||
case Region.NTSC:
|
||||
|
@ -38,6 +50,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
cyclesPerSecond = 14318181 / 18;
|
||||
break;
|
||||
}
|
||||
|
||||
HardReset();
|
||||
}
|
||||
|
||||
|
@ -58,6 +71,24 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
via0 = new Via();
|
||||
via1 = new Via();
|
||||
SetRPM(300.0);
|
||||
|
||||
// attach VIA/CIA
|
||||
|
||||
// set VIA values
|
||||
via0.Poke(0x0, 0x07);
|
||||
via0.Poke(0x2, 0x1A);
|
||||
via0.Poke(0x3, 0xFF);
|
||||
via0.Poke(0x4, 0x05);
|
||||
via0.Poke(0x6, 0xFF);
|
||||
via0.Poke(0x7, 0xFF);
|
||||
via0.Poke(0x8, 0x04);
|
||||
via0.Poke(0xE, 0x80);
|
||||
via1.Poke(0x0, 0x90);
|
||||
via1.Poke(0x4, 0x05);
|
||||
via1.Poke(0x6, 0xFF);
|
||||
via1.Poke(0x7, 0xFF);
|
||||
via1.Poke(0x8, 0x04);
|
||||
via1.Poke(0xE, 0x80);
|
||||
}
|
||||
|
||||
public void Insert(Disk newDisk)
|
||||
|
@ -72,11 +103,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
{
|
||||
return ram[addr];
|
||||
}
|
||||
else if (addr >= 0x1800 && addr < 0x1810)
|
||||
else if (addr >= 0x1800 && addr < 0x1C00)
|
||||
{
|
||||
return via0.Peek(addr);
|
||||
}
|
||||
else if (addr >= 0x1C00 && addr < 0x1C10)
|
||||
else if (addr >= 0x1C00 && addr < 0x2000)
|
||||
{
|
||||
return via1.Peek(addr);
|
||||
}
|
||||
|
@ -89,7 +120,10 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
|
||||
public void PerformCycle()
|
||||
{
|
||||
cpu.IRQ = via0.IRQ | via1.IRQ;
|
||||
cpu.ExecuteOne();
|
||||
via0.PerformCycle();
|
||||
via1.PerformCycle();
|
||||
}
|
||||
|
||||
public void Poke(int addr, byte val)
|
||||
|
@ -99,11 +133,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
{
|
||||
ram[addr] = val;
|
||||
}
|
||||
else if (addr >= 0x1800 && addr < 0x1810)
|
||||
else if (addr >= 0x1800 && addr < 0x1C00)
|
||||
{
|
||||
via0.Poke(addr, val);
|
||||
}
|
||||
else if (addr >= 0x1C00 && addr < 0x1C10)
|
||||
else if (addr >= 0x1C00 && addr < 0x2000)
|
||||
{
|
||||
via1.Poke(addr, val);
|
||||
}
|
||||
|
@ -115,11 +149,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
{
|
||||
return ram[addr];
|
||||
}
|
||||
else if (addr >= 0x1800 && addr < 0x1810)
|
||||
else if (addr >= 0x1800 && addr < 0x1C00)
|
||||
{
|
||||
return via0.Read(addr);
|
||||
}
|
||||
else if (addr >= 0x1C00 && addr < 0x1C10)
|
||||
else if (addr >= 0x1C00 && addr < 0x2000)
|
||||
{
|
||||
return via1.Read(addr);
|
||||
}
|
||||
|
@ -142,11 +176,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
{
|
||||
ram[addr] = val;
|
||||
}
|
||||
else if (addr >= 0x1800 && addr < 0x1810)
|
||||
else if (addr >= 0x1800 && addr < 0x1C00)
|
||||
{
|
||||
via0.Write(addr, val);
|
||||
}
|
||||
else if (addr >= 0x1C00 && addr < 0x1C10)
|
||||
else if (addr >= 0x1C00 && addr < 0x2000)
|
||||
{
|
||||
via1.Write(addr, val);
|
||||
}
|
||||
|
|
|
@ -63,8 +63,8 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
cpu.DummyReadMemory = PeekMemory;
|
||||
|
||||
// initialize cia timers
|
||||
cia0 = new Cia(signal, Region.NTSC);
|
||||
cia1 = new Cia(signal, Region.NTSC);
|
||||
cia0 = new Cia(Region.NTSC);
|
||||
cia1 = new Cia(Region.NTSC);
|
||||
|
||||
// initialize vic
|
||||
signal = new ChipSignals();
|
||||
|
@ -97,11 +97,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
switch (extension.ToUpper())
|
||||
{
|
||||
case @".G64":
|
||||
diskDrive = new Drive1541(File.ReadAllBytes(Path.Combine(romPath, @"dos1541")), Region.NTSC);
|
||||
diskDrive = new Drive1541(File.ReadAllBytes(Path.Combine(romPath, @"dos1541")), Region.NTSC, cia1);
|
||||
diskDrive.Insert(G64.Read(inputFile));
|
||||
break;
|
||||
case @".D64":
|
||||
diskDrive = new Drive1541(File.ReadAllBytes(Path.Combine(romPath, @"dos1541")), Region.NTSC);
|
||||
diskDrive = new Drive1541(File.ReadAllBytes(Path.Combine(romPath, @"dos1541")), Region.NTSC, cia1);
|
||||
diskDrive.Insert(D64.Read(inputFile));
|
||||
break;
|
||||
case @".PRG":
|
||||
|
|
|
@ -51,12 +51,9 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
public DataPortBus[] ports;
|
||||
|
||||
private DataPortConnector[] connectors;
|
||||
private ChipSignals signal;
|
||||
|
||||
public CiaRegs(ChipSignals newSignal)
|
||||
public CiaRegs()
|
||||
{
|
||||
signal = newSignal;
|
||||
|
||||
// power on state
|
||||
TLATCH[0] = 0xFFFF;
|
||||
TLATCH[1] = 0xFFFF;
|
||||
|
@ -251,7 +248,6 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
public bool lastCNT;
|
||||
public byte[] outputBitMask;
|
||||
private CiaRegs regs;
|
||||
public ChipSignals signal;
|
||||
public int todCounter;
|
||||
public int todFrequency;
|
||||
public bool[] underflow;
|
||||
|
@ -259,9 +255,8 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
public Func<bool> ReadSerial;
|
||||
public Action<bool> WriteSerial;
|
||||
|
||||
public Cia(ChipSignals newSignal, Region newRegion)
|
||||
public Cia(Region newRegion)
|
||||
{
|
||||
signal = newSignal;
|
||||
ReadSerial = ReadSerialDummy;
|
||||
WriteSerial = WriteSerialDummy;
|
||||
switch (newRegion)
|
||||
|
@ -350,7 +345,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
public void HardReset()
|
||||
{
|
||||
outputBitMask = new byte[] { 0x40, 0x80 };
|
||||
regs = new CiaRegs(signal);
|
||||
regs = new CiaRegs();
|
||||
underflow = new bool[2];
|
||||
todCounter = todFrequency;
|
||||
}
|
||||
|
|
|
@ -7,15 +7,23 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
{
|
||||
public class DataPortBus
|
||||
{
|
||||
private DataPortConnector[] connectors;
|
||||
private bool[] connected = new bool[2];
|
||||
private byte[] direction = new byte[2];
|
||||
private byte[] latch = new byte[2];
|
||||
private List<int> servingHooks = new List<int>();
|
||||
private List<Action> writeHooks = new List<Action>();
|
||||
protected bool[] connected = new bool[2];
|
||||
protected DataPortConnector[] connectors;
|
||||
protected byte[] direction = new byte[2];
|
||||
protected DataPortConverter[] inputConverters;
|
||||
protected byte[] latch = new byte[2];
|
||||
protected DataPortConverter[] outputConverters;
|
||||
protected List<int> servingHooks = new List<int>();
|
||||
protected List<Action> writeHooks = new List<Action>();
|
||||
|
||||
public DataPortBus()
|
||||
{
|
||||
inputConverters = new DataPortConverter[2];
|
||||
inputConverters[0] = new DataPortConverter();
|
||||
inputConverters[1] = new DataPortConverter();
|
||||
outputConverters = new DataPortConverter[2];
|
||||
outputConverters[0] = new DataPortConverter();
|
||||
outputConverters[1] = new DataPortConverter();
|
||||
connectors = new DataPortConnector[2];
|
||||
connectors[0] = new DataPortConnector(ReadData0, ReadDirection0, ReadRemoteData0, WriteData0, WriteDirection0);
|
||||
connectors[1] = new DataPortConnector(ReadData1, ReadDirection1, ReadRemoteData1, WriteData1, WriteDirection1);
|
||||
|
@ -27,13 +35,37 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
latch[1] = 0x00;
|
||||
}
|
||||
|
||||
public void AttachInputConverter(DataPortConnector connector, DataPortConverter converter)
|
||||
{
|
||||
if (connector.Equals(connectors[0]))
|
||||
{
|
||||
inputConverters[0] = converter;
|
||||
}
|
||||
else if (connector.Equals(connectors[1]))
|
||||
{
|
||||
inputConverters[1] = converter;
|
||||
}
|
||||
}
|
||||
|
||||
public void AttachOutputConverter(DataPortConnector connector, DataPortConverter converter)
|
||||
{
|
||||
if (connector.Equals(connectors[0]))
|
||||
{
|
||||
outputConverters[0] = converter;
|
||||
}
|
||||
else if (connector.Equals(connectors[1]))
|
||||
{
|
||||
outputConverters[1] = converter;
|
||||
}
|
||||
}
|
||||
|
||||
public void AttachWriteHook(Action act)
|
||||
{
|
||||
writeHooks.Add(act);
|
||||
servingHooks.Add(0);
|
||||
}
|
||||
|
||||
private void ClearHooks()
|
||||
protected void ClearHooks()
|
||||
{
|
||||
int count = servingHooks.Count;
|
||||
for (int i = 0; i < count; i++)
|
||||
|
@ -57,6 +89,21 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
throw new Exception("Two connections to this bus have already been established..");
|
||||
}
|
||||
|
||||
public void Connect(DataPortConnector connection)
|
||||
{
|
||||
if (!connected[0])
|
||||
{
|
||||
connected[0] = true;
|
||||
connectors[0] = connection;
|
||||
}
|
||||
else if (!connected[1])
|
||||
{
|
||||
connected[1] = true;
|
||||
connectors[1] = connection;
|
||||
}
|
||||
throw new Exception("Two connections to this bus have already been established..");
|
||||
}
|
||||
|
||||
public void Disconnect(DataPortConnector connector)
|
||||
{
|
||||
if (connector.Equals(connectors[0]))
|
||||
|
@ -73,7 +120,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
}
|
||||
}
|
||||
|
||||
private void ExecuteWriteHooks()
|
||||
protected void ExecuteWriteHooks()
|
||||
{
|
||||
int count = servingHooks.Count;
|
||||
for (int i = 0; i < count; i++)
|
||||
|
@ -91,63 +138,71 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
ClearHooks();
|
||||
}
|
||||
|
||||
private byte ReadData0()
|
||||
protected virtual byte ReadData0()
|
||||
{
|
||||
byte result;
|
||||
if (connected[1])
|
||||
return (byte)((~direction[0] & latch[1]) | (direction[0] & latch[0]));
|
||||
result = (byte)((~direction[0] & latch[1]) | (direction[0] & latch[0]));
|
||||
else
|
||||
return latch[0];
|
||||
result = latch[0];
|
||||
return inputConverters[0].Convert(result, latch[1]);
|
||||
}
|
||||
|
||||
private byte ReadData1()
|
||||
protected virtual byte ReadData1()
|
||||
{
|
||||
byte result;
|
||||
if (connected[0])
|
||||
return (byte)((~direction[1] & latch[0]) | (direction[1] & latch[1]));
|
||||
result = (byte)((~direction[1] & latch[0]) | (direction[1] & latch[1]));
|
||||
else
|
||||
return latch[1];
|
||||
result = latch[1];
|
||||
return inputConverters[1].Convert(result, latch[0]);
|
||||
}
|
||||
|
||||
private byte ReadDirection0()
|
||||
protected virtual byte ReadDirection0()
|
||||
{
|
||||
return direction[0];
|
||||
}
|
||||
|
||||
private byte ReadDirection1()
|
||||
protected virtual byte ReadDirection1()
|
||||
{
|
||||
return direction[1];
|
||||
}
|
||||
|
||||
private byte ReadRemoteData0()
|
||||
protected virtual byte ReadRemoteData0()
|
||||
{
|
||||
return latch[1];
|
||||
}
|
||||
|
||||
private byte ReadRemoteData1()
|
||||
protected virtual byte ReadRemoteData1()
|
||||
{
|
||||
return latch[0];
|
||||
}
|
||||
|
||||
private void WriteData0(byte val)
|
||||
protected virtual void WriteData0(byte val)
|
||||
{
|
||||
latch[0] &= (byte)~direction[0];
|
||||
latch[0] |= (byte)(val & direction[0]);
|
||||
byte result = latch[0];
|
||||
result &= (byte)~direction[0];
|
||||
result |= (byte)(val & direction[0]);
|
||||
latch[0] = outputConverters[0].Convert(result, latch[1]);
|
||||
ExecuteWriteHooks();
|
||||
}
|
||||
|
||||
private void WriteData1(byte val)
|
||||
protected virtual void WriteData1(byte val)
|
||||
{
|
||||
latch[1] &= (byte)~direction[1];
|
||||
latch[1] |= (byte)(val & direction[1]);
|
||||
byte result = latch[1];
|
||||
result &= (byte)~direction[1];
|
||||
result |= (byte)(val & direction[1]);
|
||||
latch[1] = outputConverters[1].Convert(result, latch[0]);
|
||||
ExecuteWriteHooks();
|
||||
}
|
||||
|
||||
private void WriteDirection0(byte val)
|
||||
protected virtual void WriteDirection0(byte val)
|
||||
{
|
||||
direction[0] = val;
|
||||
ExecuteWriteHooks();
|
||||
}
|
||||
|
||||
private void WriteDirection1(byte val)
|
||||
protected virtual void WriteDirection1(byte val)
|
||||
{
|
||||
direction[1] = val;
|
||||
ExecuteWriteHooks();
|
||||
|
@ -204,6 +259,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
}
|
||||
}
|
||||
|
||||
public DataPortListener Listener()
|
||||
{
|
||||
return new DataPortListener(ReadData, ReadDirection);
|
||||
}
|
||||
|
||||
public byte RemoteData
|
||||
{
|
||||
get
|
||||
|
@ -211,10 +271,14 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
return ReadRemoteData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public DataPortListener Listener()
|
||||
public class DataPortConverter
|
||||
{
|
||||
public virtual byte Convert(byte input, byte remote)
|
||||
{
|
||||
return new DataPortListener(ReadData, ReadDirection);
|
||||
// the base converter transfers the values directly
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,60 +5,31 @@ using System.Text;
|
|||
|
||||
namespace BizHawk.Emulation.Computers.Commodore64
|
||||
{
|
||||
// adapter for converting CIA output to VIA
|
||||
// inherits DataPortConnector so the conversion is invisible
|
||||
// to both devices
|
||||
|
||||
struct SerialCableData
|
||||
public class DataPortSerialInputConverter : DataPortConverter
|
||||
{
|
||||
public bool ATNIN;
|
||||
public bool ATNOUT;
|
||||
public bool CLOCKIN;
|
||||
public bool CLOCKOUT;
|
||||
public bool DATAIN;
|
||||
public bool DATAOUT;
|
||||
}
|
||||
|
||||
class SerialCable : DataPortConnector
|
||||
{
|
||||
private DataPortConnector connector;
|
||||
|
||||
public SerialCable(DataPortConnector baseConnector) : base(baseConnector)
|
||||
public override byte Convert(byte local, byte remote)
|
||||
{
|
||||
connector = baseConnector;
|
||||
}
|
||||
|
||||
new public byte Data
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.Data;
|
||||
}
|
||||
set
|
||||
{
|
||||
base.Data = value;
|
||||
}
|
||||
}
|
||||
|
||||
new public byte Direction
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.Direction;
|
||||
}
|
||||
set
|
||||
{
|
||||
base.Direction = value;
|
||||
}
|
||||
}
|
||||
|
||||
new public byte RemoteData
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.RemoteData;
|
||||
}
|
||||
int via = (local & 0x70);
|
||||
via |= ((remote & 0x08) == 0) ? 0x80 : 0x00; //CIA ATNOUT - VIA ATNIN
|
||||
via |= ((remote & 0x10) == 0) ? 0x04 : 0x00; //CIA CLKOUT - VIA CLKIN
|
||||
via |= ((remote & 0x20) == 0) ? 0x01 : 0x00; //CIA DATOUT - VIA DATIN
|
||||
via |= ((remote & 0x40) == 0) ? 0x08 : 0x00; //CIA CLKIN - VIA CLKOUT
|
||||
via |= ((remote & 0x80) == 0) ? 0x02 : 0x00; //CIA DATIN - VIA DATOUT
|
||||
return (byte)via;
|
||||
}
|
||||
}
|
||||
|
||||
public class DataPortSerialOutputConverter : DataPortConverter
|
||||
{
|
||||
public override byte Convert(byte local, byte remote)
|
||||
{
|
||||
int cia = (remote & 0x7);
|
||||
cia |= ((local & 0x01) == 0) ? 0x20 : 0x00; //VIA DATIN - CIA DATOUT
|
||||
cia |= ((local & 0x02) == 0) ? 0x80 : 0x00; //VIA DATOUT - CIA DATIN
|
||||
cia |= ((local & 0x04) == 0) ? 0x10 : 0x00; //VIA CLKIN - CIA CLKOUT
|
||||
cia |= ((local & 0x08) == 0) ? 0x40 : 0x00; //VIA CLKOUT - CIA CLKIN
|
||||
cia |= ((local & 0x80) == 0) ? 0x08 : 0x00; //VIA DATIN - CIA DATOUT
|
||||
return (byte)cia;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,28 +11,204 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
|
||||
public class ViaRegs
|
||||
{
|
||||
public int ACR;
|
||||
public int IER;
|
||||
public int IFR;
|
||||
public int PCR;
|
||||
public int[] CACONTROL = new int[2];
|
||||
public int[] CBCONTROL = new int[2];
|
||||
public bool[] EICA = new bool[2];
|
||||
public bool[] EICB = new bool[2];
|
||||
public bool EISR;
|
||||
public bool[] EIT = new bool[2];
|
||||
public bool[] ICA = new bool[2];
|
||||
public bool[] ICB = new bool[2];
|
||||
public bool IRQ;
|
||||
public bool ISR;
|
||||
public bool[] IT = new bool[2];
|
||||
public bool PALE;
|
||||
public bool PBLE;
|
||||
public int SR;
|
||||
public int SRCONTROL;
|
||||
public int[] TC = new int[2];
|
||||
public int[] TCONTROL = new int[2];
|
||||
public int[] TL = new int[2];
|
||||
|
||||
public DataPortBus[] ports;
|
||||
|
||||
private DataPortConnector[] connectors;
|
||||
|
||||
public ViaRegs()
|
||||
{
|
||||
// power on state
|
||||
ports = new DataPortBus[2];
|
||||
ports[0] = new DataPortBus();
|
||||
ports[1] = new DataPortBus();
|
||||
connectors = new DataPortConnector[2];
|
||||
connectors[0] = ports[0].Connect();
|
||||
connectors[1] = ports[1].Connect();
|
||||
connectors[0].Data = 0xFF;
|
||||
connectors[1].Data = 0xFF;
|
||||
connectors[0].Direction = 0xFF;
|
||||
connectors[1].Direction = 0xFF;
|
||||
}
|
||||
|
||||
public byte this[int addr]
|
||||
{
|
||||
get
|
||||
{
|
||||
return 0xFF;
|
||||
int result = 0xFF;
|
||||
|
||||
addr &= 0xF;
|
||||
switch (addr)
|
||||
{
|
||||
case 0x0: // port B data
|
||||
result = connectors[1].Data;
|
||||
break;
|
||||
case 0x1: // port A data
|
||||
case 0xF: // port A data without handshake
|
||||
result = connectors[0].Data;
|
||||
break;
|
||||
case 0x2: // port B direction
|
||||
result = connectors[1].Direction;
|
||||
break;
|
||||
case 0x3: // port A direction
|
||||
result = connectors[0].Direction;
|
||||
break;
|
||||
case 0x4: // timer 0 lo
|
||||
result = TC[0] & 0xFF;
|
||||
break;
|
||||
case 0x5: // timer 0 hi
|
||||
result = (TC[0] & 0xFF00) >> 8;
|
||||
break;
|
||||
case 0x6: // timer 0 latch lo
|
||||
result = TL[0] & 0xFF;
|
||||
break;
|
||||
case 0x7: // timer 0 latch hi
|
||||
result = (TL[0] & 0xFF00) >> 8;
|
||||
break;
|
||||
case 0x8: // timer 1 lo
|
||||
result = TC[1] & 0xFF;
|
||||
break;
|
||||
case 0x9: // timer 1 hi
|
||||
result = (TC[1] & 0xFF00) >> 8;
|
||||
break;
|
||||
case 0xA: // shift register
|
||||
result = SR;
|
||||
break;
|
||||
case 0xB: // peripheral control register
|
||||
result = (CACONTROL[0] & 0x01);
|
||||
result |= (CACONTROL[1] & 0x07) << 1;
|
||||
result |= (CBCONTROL[0] & 0x01) << 4;
|
||||
result |= (CBCONTROL[1] & 0x07) << 5;
|
||||
break;
|
||||
case 0xC: // auxilary control register
|
||||
result = (PALE) ? 0x01 : 0x00;
|
||||
result |= (PBLE) ? 0x02 : 0x00;
|
||||
result |= (SRCONTROL & 0x7) << 2;
|
||||
result |= (TCONTROL[0] & 0x1) << 5;
|
||||
result |= (TCONTROL[1] & 0x3) << 6;
|
||||
break;
|
||||
case 0xD: // interrupt status register
|
||||
result = ICA[1] ? 0x01 : 0x00;
|
||||
result |= ICA[0] ? 0x02 : 0x00;
|
||||
result |= ISR ? 0x04 : 0x00;
|
||||
result |= ICB[1] ? 0x08 : 0x00;
|
||||
result |= ICB[0] ? 0x10 : 0x00;
|
||||
result |= IT[1] ? 0x20 : 0x00;
|
||||
result |= IT[0] ? 0x40 : 0x00;
|
||||
result |= IRQ ? 0x80 : 0x00;
|
||||
break;
|
||||
case 0xE: // interrupt control register
|
||||
result = EICA[1] ? 0x01 : 0x00;
|
||||
result |= EICA[0] ? 0x02 : 0x00;
|
||||
result |= EISR ? 0x04 : 0x00;
|
||||
result |= EICB[1] ? 0x08 : 0x00;
|
||||
result |= EICB[0] ? 0x10 : 0x00;
|
||||
result |= EIT[1] ? 0x20 : 0x00;
|
||||
result |= EIT[0] ? 0x40 : 0x00;
|
||||
result |= 0x80; // TODO: check if this is needed
|
||||
break;
|
||||
}
|
||||
|
||||
return (byte)result;
|
||||
}
|
||||
set
|
||||
{
|
||||
// set register
|
||||
byte val = value;
|
||||
addr &= 0xF;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0x0: // port B data
|
||||
connectors[1].Data = val;
|
||||
break;
|
||||
case 0x1: // port A data
|
||||
case 0xF: // port A data without handshake
|
||||
connectors[0].Data = val;
|
||||
break;
|
||||
case 0x2: // port B direction
|
||||
connectors[1].Direction = val;
|
||||
break;
|
||||
case 0x3: // port A direction
|
||||
connectors[0].Direction = val;
|
||||
break;
|
||||
case 0x4: // timer 0 lo
|
||||
TC[0] &= 0xFF00;
|
||||
TC[0] |= val;
|
||||
break;
|
||||
case 0x5: // timer 0 hi
|
||||
TC[0] &= 0x00FF;
|
||||
TC[0] |= (int)val << 8;
|
||||
break;
|
||||
case 0x6: // timer 0 latch lo
|
||||
TL[0] &= 0xFF00;
|
||||
TL[0] |= val;
|
||||
break;
|
||||
case 0x7: // timer 0 latch hi
|
||||
TL[0] &= 0x00FF;
|
||||
TL[0] |= (int)val << 8;
|
||||
break;
|
||||
case 0x8: // timer 1 lo
|
||||
TC[1] &= 0xFF00;
|
||||
TC[1] |= val;
|
||||
break;
|
||||
case 0x9: // timer 1 hi
|
||||
TC[1] &= 0x00FF;
|
||||
TC[1] |= (int)val << 8;
|
||||
break;
|
||||
case 0xA: // shift register
|
||||
SR = val;
|
||||
break;
|
||||
case 0xB: // peripheral control register
|
||||
CACONTROL[0] = (val & 0x1);
|
||||
CACONTROL[1] = ((val >> 1) & 0x7);
|
||||
CBCONTROL[0] = ((val >> 4) & 0x1);
|
||||
CBCONTROL[1] = ((val >> 5) & 0x7);
|
||||
break;
|
||||
case 0xC: // auxilary control register
|
||||
PALE = ((val & 0x01) != 0);
|
||||
PBLE = ((val & 0x02) != 0);
|
||||
SRCONTROL = (val >> 2) & 0x7;
|
||||
TCONTROL[0] = (val >> 5) & 0x1;
|
||||
TCONTROL[1] = (val >> 6) & 0x3;
|
||||
break;
|
||||
case 0xD: // interrupt status register
|
||||
ICA[1] = ((val & 0x01) != 0);
|
||||
ICA[0] = ((val & 0x02) != 0);
|
||||
ISR = ((val & 0x04) != 0);
|
||||
ICB[1] = ((val & 0x08) != 0);
|
||||
ICB[0] = ((val & 0x10) != 0);
|
||||
IT[1] = ((val & 0x20) != 0);
|
||||
IT[0] = ((val & 0x40) != 0);
|
||||
IRQ = ((val & 0x80) != 0);
|
||||
break;
|
||||
case 0xE: // interrupt control register
|
||||
EICA[1] = ((val & 0x01) != 0);
|
||||
EICA[0] = ((val & 0x02) != 0);
|
||||
EISR = ((val & 0x04) != 0);
|
||||
EICB[1] = ((val & 0x08) != 0);
|
||||
EICB[0] = ((val & 0x10) != 0);
|
||||
EIT[1] = ((val & 0x20) != 0);
|
||||
EIT[0] = ((val & 0x40) != 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,24 +244,73 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
regs = new ViaRegs();
|
||||
}
|
||||
|
||||
public bool IRQ
|
||||
{
|
||||
get
|
||||
{
|
||||
return regs.IRQ;
|
||||
}
|
||||
}
|
||||
|
||||
public byte Peek(int addr)
|
||||
{
|
||||
addr &= 0xF;
|
||||
return 0;
|
||||
return regs[addr];
|
||||
}
|
||||
|
||||
public void PerformCycle()
|
||||
{
|
||||
// do stuff
|
||||
UpdateInterrupts();
|
||||
}
|
||||
|
||||
public void Poke(int addr, byte val)
|
||||
{
|
||||
addr &= 0xF;
|
||||
regs[addr] = val;
|
||||
}
|
||||
|
||||
public byte Read(ushort addr)
|
||||
{
|
||||
return 0x00;
|
||||
byte result;
|
||||
|
||||
addr &= 0xF;
|
||||
switch (addr)
|
||||
{
|
||||
case 0xD:
|
||||
// reading this clears it
|
||||
result = regs[addr];
|
||||
regs[addr] = 0x00;
|
||||
break;
|
||||
default:
|
||||
result = regs[addr];
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void UpdateInterrupts()
|
||||
{
|
||||
regs.IRQ =
|
||||
(regs.ICA[0] & regs.EICA[0]) |
|
||||
(regs.ICA[1] & regs.EICA[1]) |
|
||||
(regs.ICB[0] & regs.EICB[0]) |
|
||||
(regs.ICB[1] & regs.EICB[1]) |
|
||||
(regs.IT[0] & regs.EIT[0]) |
|
||||
(regs.IT[1] & regs.EIT[1]) |
|
||||
(regs.ISR & regs.EISR);
|
||||
}
|
||||
|
||||
public void Write(ushort addr, byte val)
|
||||
{
|
||||
addr &= 0xF;
|
||||
switch (addr)
|
||||
{
|
||||
default:
|
||||
regs[addr] = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue