570 lines
13 KiB
C#
570 lines
13 KiB
C#
using System;
|
|
|
|
#if false
|
|
namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|
{
|
|
// via
|
|
public class MOS6522 : Timer
|
|
{
|
|
private const uint acrShiftModeDisabled = 0;
|
|
private const uint acrShiftModeInT1 = 1;
|
|
private const uint acrShiftModeInClock = 2;
|
|
private const uint acrShiftModeInExtClock = 3;
|
|
private const uint acrShiftModeOutFree = 4;
|
|
private const uint acrShiftModeOutT1 = 5;
|
|
private const uint acrShiftModeOutClock = 6;
|
|
private const uint acrShiftModeOutExtClock = 7;
|
|
|
|
private const uint pcrControlInNegative = 0;
|
|
private const uint pcrControlInNegativeIndep = 1;
|
|
private const uint pcrControlInPositive = 2;
|
|
private const uint pcrControlInPositiveIndep = 3;
|
|
private const uint pcrControlHandshake = 4;
|
|
private const uint pcrControlPulse = 5;
|
|
private const uint pcrControlLow = 6;
|
|
private const uint pcrControlHigh = 7;
|
|
|
|
private const uint tControlLoad = 0;
|
|
private const uint tControlContinuous = 1;
|
|
private const uint tControlLoadPB = 2;
|
|
private const uint tControlContinuousPB = 3;
|
|
private const uint tControlPulseCounter = 4;
|
|
|
|
private static byte[] portBit = new byte[] { 0x80, 0x40 };
|
|
private static byte[] portMask = new byte[] { 0x7F, 0xBF };
|
|
|
|
private bool caPulse;
|
|
private bool cbPulse;
|
|
private bool[] enableIrqCA;
|
|
private bool[] enableIrqCB;
|
|
private bool enableIrqSR;
|
|
private bool[] enableIrqT;
|
|
private bool[] irqCA;
|
|
private bool[] irqCB;
|
|
private bool irqSR;
|
|
private bool[] irqT;
|
|
private bool[] lastca;
|
|
private bool[] lastcb;
|
|
private byte lastpb;
|
|
private byte paLatch;
|
|
private bool paLatchEnable;
|
|
private byte paOut;
|
|
private byte pbLatch;
|
|
private bool pbLatchEnable;
|
|
private byte pbOut;
|
|
private readonly bool[] pbPulse;
|
|
private readonly uint[] pcrControlA;
|
|
private readonly uint[] pcrControlB;
|
|
private byte sr;
|
|
private uint srControl;
|
|
private readonly uint[] tControl;
|
|
|
|
public Func<bool> ReadCA0;
|
|
public Func<bool> ReadCA1;
|
|
public Func<bool> ReadCB0;
|
|
public Func<bool> ReadCB1;
|
|
public Action<bool> WriteCA0;
|
|
public Action<bool> WriteCA1;
|
|
public Action<bool> WriteCB0;
|
|
public Action<bool> WriteCB1;
|
|
|
|
public MOS6522()
|
|
{
|
|
enableIrqCA = new bool[2];
|
|
enableIrqCB = new bool[2];
|
|
enableIrqT = new bool[2];
|
|
irqCA = new bool[2];
|
|
irqCB = new bool[2];
|
|
irqT = new bool[2];
|
|
lastca = new bool[2];
|
|
lastcb = new bool[2];
|
|
pbPulse = new bool[2];
|
|
pcrControlA = new uint[2];
|
|
pcrControlB = new uint[2];
|
|
tControl = new uint[2];
|
|
}
|
|
|
|
public void HardReset()
|
|
{
|
|
caPulse = false;
|
|
cbPulse = false;
|
|
enableIrqCA[0] = false;
|
|
enableIrqCA[1] = false;
|
|
enableIrqCB[0] = false;
|
|
enableIrqCB[1] = false;
|
|
enableIrqSR = false;
|
|
enableIrqT[0] = false;
|
|
enableIrqT[1] = false;
|
|
irqCA[0] = false;
|
|
irqCA[1] = false;
|
|
irqCB[0] = false;
|
|
irqCB[1] = false;
|
|
irqSR = false;
|
|
irqT[0] = false;
|
|
irqT[1] = false;
|
|
lastca[0] = ReadCA0();
|
|
lastca[1] = ReadCA1();
|
|
lastcb[0] = ReadCB0();
|
|
lastcb[1] = ReadCB1();
|
|
pbPulse[0] = false;
|
|
pbPulse[1] = false;
|
|
pcrControlA[0] = 0;
|
|
pcrControlA[1] = 0;
|
|
pcrControlB[0] = 0;
|
|
pcrControlB[1] = 0;
|
|
tControl[0] = 0;
|
|
tControl[1] = 0;
|
|
HardResetInternal();
|
|
}
|
|
|
|
// ------------------------------------
|
|
|
|
public void ExecutePhase1()
|
|
{
|
|
}
|
|
|
|
public void ExecutePhase2()
|
|
{
|
|
bool ca0 = ReadCA0();
|
|
bool ca1 = ReadCA1();
|
|
bool cb0 = ReadCB0();
|
|
bool cb1 = ReadCB1();
|
|
bool ca0Trans = (lastca[0] != ca0);
|
|
bool ca1Trans = (lastca[1] != ca1);
|
|
bool cb0Trans = (lastcb[0] != cb0);
|
|
bool cb1Trans = (lastcb[1] != cb1);
|
|
|
|
// edge triggered interrupts
|
|
|
|
switch (pcrControlA[0])
|
|
{
|
|
case pcrControlInNegative:
|
|
if (lastca[0] && !ca0)
|
|
irqCA[0] = true;
|
|
break;
|
|
case pcrControlInPositive:
|
|
if (!lastca[0] && ca0)
|
|
irqCA[0] = true;
|
|
break;
|
|
}
|
|
|
|
switch (pcrControlB[0])
|
|
{
|
|
case pcrControlInNegative:
|
|
if (lastcb[0] && !cb0)
|
|
irqCB[0] = true;
|
|
break;
|
|
case pcrControlInPositive:
|
|
if (!lastcb[0] && cb0)
|
|
irqCB[0] = true;
|
|
break;
|
|
}
|
|
|
|
switch (pcrControlA[1])
|
|
{
|
|
case pcrControlInNegative:
|
|
case pcrControlInNegativeIndep:
|
|
if (lastca[1] && !ca1)
|
|
irqCA[1] = true;
|
|
break;
|
|
case pcrControlInPositive:
|
|
case pcrControlInPositiveIndep:
|
|
if (!lastca[1] && ca1)
|
|
irqCA[1] = true;
|
|
break;
|
|
case pcrControlHandshake:
|
|
if (lastca[0] != ca0)
|
|
WriteCA1(true);
|
|
break;
|
|
case pcrControlPulse:
|
|
if (caPulse)
|
|
caPulse = false;
|
|
else
|
|
WriteCA1(true);
|
|
break;
|
|
case pcrControlLow:
|
|
WriteCA1(false);
|
|
break;
|
|
case pcrControlHigh:
|
|
WriteCA1(true);
|
|
break;
|
|
}
|
|
|
|
switch (pcrControlB[1])
|
|
{
|
|
case pcrControlInNegative:
|
|
case pcrControlInNegativeIndep:
|
|
if (lastcb[1] && !cb1)
|
|
irqCB[1] = true;
|
|
break;
|
|
case pcrControlInPositive:
|
|
case pcrControlInPositiveIndep:
|
|
if (!lastcb[1] && cb1)
|
|
irqCB[1] = true;
|
|
break;
|
|
case pcrControlHandshake:
|
|
if (lastcb[0] != cb0)
|
|
WriteCB1(true);
|
|
break;
|
|
case pcrControlPulse:
|
|
if (cbPulse)
|
|
cbPulse = false;
|
|
else
|
|
WriteCB1(true);
|
|
break;
|
|
case pcrControlLow:
|
|
WriteCB1(false);
|
|
break;
|
|
case pcrControlHigh:
|
|
WriteCB1(true);
|
|
break;
|
|
}
|
|
|
|
// run timers
|
|
for (uint i = 0; i < 2; i++)
|
|
{
|
|
switch (tControl[i])
|
|
{
|
|
case tControlLoad:
|
|
if (timer[i] > 0)
|
|
{
|
|
timer[i]--;
|
|
if (timer[i] == 0)
|
|
irqT[i] = true;
|
|
}
|
|
break;
|
|
case tControlContinuous:
|
|
if (timer[i] > 0)
|
|
{
|
|
timer[i]--;
|
|
if (timer[i] == 0)
|
|
{
|
|
irqT[i] = true;
|
|
timer[i] = timerLatch[i];
|
|
}
|
|
}
|
|
break;
|
|
case tControlLoadPB:
|
|
if (!pbPulse[i])
|
|
WritePortB((byte)(ReadPortB() & portMask[i]));
|
|
|
|
if (timer[i] > 0)
|
|
{
|
|
timer[i]--;
|
|
if (timer[i] == 0)
|
|
{
|
|
irqT[i] = true;
|
|
if (irqT[i])
|
|
WritePortB((byte)(ReadPortB() | portBit[i]));
|
|
}
|
|
}
|
|
break;
|
|
case tControlContinuousPB:
|
|
if (timer[i] > 0)
|
|
{
|
|
timer[i]--;
|
|
if (timer[i] == 0)
|
|
{
|
|
irqT[i] = true;
|
|
timer[i] = timerLatch[i];
|
|
WritePortB((byte)(ReadPortB() ^ portBit[i]));
|
|
}
|
|
}
|
|
break;
|
|
case tControlPulseCounter:
|
|
if ((lastpb & 0x40) != 0 && (ReadPortB() & 0x40) == 0)
|
|
{
|
|
if (timer[i] > 0)
|
|
{
|
|
timer[i]--;
|
|
if (timer[i] == 0)
|
|
{
|
|
irqT[i] = true;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
lastca[0] = ca0;
|
|
lastca[1] = ca1;
|
|
lastcb[0] = cb0;
|
|
lastcb[1] = cb1;
|
|
lastpb = ReadPortB();
|
|
|
|
pinIRQ = !((irqCA[0] & enableIrqCA[0]) |
|
|
(irqCA[1] & enableIrqCA[1]) |
|
|
(irqCB[0] & enableIrqCB[0]) |
|
|
(irqCB[1] & enableIrqCB[1]) |
|
|
(irqSR & enableIrqSR) |
|
|
(irqT[0] & enableIrqT[0]) |
|
|
(irqT[1] & enableIrqT[1])
|
|
);
|
|
|
|
|
|
}
|
|
|
|
// ------------------------------------
|
|
|
|
public byte Peek(int addr)
|
|
{
|
|
return ReadRegister((ushort)(addr & 0xF));
|
|
}
|
|
|
|
public void Poke(int addr, byte val)
|
|
{
|
|
WriteRegister((ushort)(addr & 0xF), val);
|
|
}
|
|
|
|
public byte Read(ushort addr)
|
|
{
|
|
|
|
//Console.WriteLine("via R: reg" + C64Util.ToHex(addr, 4));
|
|
|
|
addr &= 0xF;
|
|
switch (addr)
|
|
{
|
|
case 0x0:
|
|
irqCB[0] = false;
|
|
irqCB[1] = false;
|
|
|
|
if (pbLatchEnable)
|
|
return Port.ExternalWrite(pbLatch, ReadPortB(), ReadDirB());
|
|
else
|
|
return ReadPortB();
|
|
case 0x1:
|
|
if (pcrControlA[0] != pcrControlInNegativeIndep && pcrControlA[0] != pcrControlInPositiveIndep)
|
|
irqCA[0] = false;
|
|
if (pcrControlA[1] != pcrControlInNegativeIndep && pcrControlA[1] != pcrControlInPositiveIndep)
|
|
irqCA[1] = false;
|
|
|
|
if (paLatchEnable)
|
|
return Port.ExternalWrite(paLatch, ReadPortA(), ReadDirA());
|
|
else
|
|
return ReadPortA();
|
|
case 0x4:
|
|
irqT[0] = false;
|
|
return ReadRegister(addr);
|
|
case 0x8:
|
|
irqT[1] = false;
|
|
return ReadRegister(addr);
|
|
default:
|
|
return ReadRegister(addr);
|
|
}
|
|
}
|
|
|
|
private byte ReadRegister(ushort addr)
|
|
{
|
|
switch (addr)
|
|
{
|
|
case 0x0:
|
|
return ReadPortB();
|
|
case 0x1:
|
|
return ReadPortA();
|
|
case 0x2:
|
|
return ReadDirB();
|
|
case 0x3:
|
|
return ReadDirA();
|
|
case 0x4:
|
|
return (byte)(timer[0] & 0xFF);
|
|
case 0x5:
|
|
return (byte)(timer[0] >> 8);
|
|
case 0x6:
|
|
return (byte)(timerLatch[0] & 0xFF);
|
|
case 0x7:
|
|
return (byte)(timerLatch[0] >> 8);
|
|
case 0x8:
|
|
return (byte)(timer[1] & 0xFF);
|
|
case 0x9:
|
|
return (byte)(timer[1] >> 8);
|
|
case 0xA:
|
|
return sr;
|
|
case 0xB:
|
|
return (byte)(
|
|
(paLatchEnable ? 0x01 : 0x00) |
|
|
(pbLatchEnable ? 0x02 : 0x00) |
|
|
(byte)((srControl & 0x7) << 2) |
|
|
(byte)((tControl[1] & 0x4) << 3) |
|
|
(byte)((tControl[0] & 0x3) << 6)
|
|
);
|
|
case 0xC:
|
|
return (byte)(
|
|
(byte)((pcrControlA[0] & 0x2) >> 1) |
|
|
(byte)((pcrControlA[1] & 0x3) << 1) |
|
|
(byte)((pcrControlB[0] & 0x2) << 3) |
|
|
(byte)((pcrControlB[1] & 0x3) << 5)
|
|
);
|
|
case 0xD: //IFR
|
|
return (byte)(
|
|
(irqCA[1] ? 0x01 : 0x00) |
|
|
(irqCA[0] ? 0x02 : 0x00) |
|
|
(irqSR ? 0x04 : 0x00) |
|
|
(irqCB[1] ? 0x08 : 0x00) |
|
|
(irqCB[0] ? 0x10 : 0x00) |
|
|
(irqT[1] ? 0x20 : 0x00) |
|
|
(irqT[0] ? 0x40 : 0x00) |
|
|
(pinIRQ ? 0x00 : 0x80)
|
|
);
|
|
case 0xE: //IER
|
|
return (byte)(
|
|
(enableIrqCA[1] ? 0x01 : 0x00) |
|
|
(enableIrqCA[0] ? 0x02 : 0x00) |
|
|
(enableIrqSR ? 0x04 : 0x00) |
|
|
(enableIrqCB[1] ? 0x08 : 0x00) |
|
|
(enableIrqCB[0] ? 0x10 : 0x00) |
|
|
(enableIrqT[1] ? 0x20 : 0x00) |
|
|
(enableIrqT[0] ? 0x40 : 0x00) |
|
|
(0x00)
|
|
);
|
|
default:
|
|
return 0x00;
|
|
}
|
|
}
|
|
|
|
public void Write(ushort addr, byte val)
|
|
{
|
|
byte result;
|
|
bool intEnable;
|
|
|
|
//Console.WriteLine("via W: reg" + C64Util.ToHex(addr, 4) + " val" + C64Util.ToHex(val, 2));
|
|
|
|
addr &= 0xF;
|
|
switch (addr)
|
|
{
|
|
case 0x0:
|
|
irqCB[0] = false;
|
|
irqCB[1] = false;
|
|
pbOut = val;
|
|
WritePortB(val);
|
|
break;
|
|
case 0x1:
|
|
if (pcrControlA[0] != pcrControlInNegativeIndep && pcrControlA[0] != pcrControlInPositiveIndep)
|
|
irqCA[0] = false;
|
|
if (pcrControlA[1] != pcrControlInNegativeIndep && pcrControlA[1] != pcrControlInPositiveIndep)
|
|
irqCA[1] = false;
|
|
paOut = val;
|
|
WritePortA(val);
|
|
break;
|
|
case 0x2:
|
|
WriteDirB(val);
|
|
WritePortB(pbOut);
|
|
break;
|
|
case 0x3:
|
|
WriteDirA(val);
|
|
WritePortA(paOut);
|
|
break;
|
|
case 0x4:
|
|
case 0x6:
|
|
WriteRegister(0x6, val);
|
|
break;
|
|
case 0x5:
|
|
WriteRegister(0x7, val);
|
|
WriteRegister(0x4, ReadRegister(0x6));
|
|
WriteRegister(0x5, ReadRegister(0x7));
|
|
irqT[0] = false;
|
|
pbPulse[0] = false;
|
|
break;
|
|
case 0x9:
|
|
timer[1] = timerLatch[1];
|
|
irqT[1] = false;
|
|
pbPulse[1] = false;
|
|
break;
|
|
case 0xE:
|
|
intEnable = ((val & 0x80) != 0);
|
|
result = ReadRegister(addr);
|
|
if (intEnable)
|
|
result |= (byte)(val & 0x7F);
|
|
else
|
|
result &= (byte)((val & 0x7F) ^ 0x7F);
|
|
WriteRegister(0xE, result);
|
|
break;
|
|
default:
|
|
WriteRegister(addr, val);
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void WriteRegister(ushort addr, byte val)
|
|
{
|
|
switch (addr)
|
|
{
|
|
case 0x0:
|
|
WritePortB(val);
|
|
break;
|
|
case 0x1:
|
|
WritePortA(val);
|
|
break;
|
|
case 0x2:
|
|
WriteDirB(val);
|
|
break;
|
|
case 0x3:
|
|
WriteDirA(val);
|
|
break;
|
|
case 0x4:
|
|
timer[0] &= 0xFF00;
|
|
timer[0] |= val;
|
|
break;
|
|
case 0x5:
|
|
timer[0] &= 0x00FF;
|
|
timer[0] |= (uint)val << 8;
|
|
break;
|
|
case 0x6:
|
|
timerLatch[0] &= 0xFF00;
|
|
timerLatch[0] |= val;
|
|
break;
|
|
case 0x7:
|
|
timerLatch[0] &= 0x00FF;
|
|
timerLatch[0] |= (uint)val << 8;
|
|
break;
|
|
case 0x8:
|
|
timerLatch[1] &= 0xFF00;
|
|
timerLatch[1] |= val;
|
|
break;
|
|
case 0x9:
|
|
timer[1] &= 0x00FF;
|
|
timer[1] |= (uint)val << 8;
|
|
break;
|
|
case 0xA:
|
|
sr = val;
|
|
break;
|
|
case 0xB:
|
|
paLatchEnable = ((val & 0x01) != 0);
|
|
pbLatchEnable = ((val & 0x02) != 0);
|
|
srControl = (((uint)val >> 2) & 0x7);
|
|
tControl[1] = (((uint)val >> 3) & 0x4);
|
|
tControl[0] = (((uint)val >> 6) & 0x3);
|
|
break;
|
|
case 0xC:
|
|
pcrControlA[0] = ((uint)val << 1) & 0x2;
|
|
pcrControlA[1] = ((uint)val >> 1) & 0x7;
|
|
pcrControlB[0] = ((uint)val >> 3) & 0x2;
|
|
pcrControlB[1] = ((uint)val >> 5) & 0x7;
|
|
break;
|
|
case 0xD:
|
|
irqCA[1] = ((val & 0x01) != 0);
|
|
irqCA[0] = ((val & 0x02) != 0);
|
|
irqSR = ((val & 0x04) != 0);
|
|
irqCB[1] = ((val & 0x08) != 0);
|
|
irqCB[0] = ((val & 0x10) != 0);
|
|
irqT[1] = ((val & 0x20) != 0);
|
|
irqT[0] = ((val & 0x40) != 0);
|
|
break;
|
|
case 0xE:
|
|
enableIrqCA[1] = ((val & 0x01) != 0);
|
|
enableIrqCA[0] = ((val & 0x02) != 0);
|
|
enableIrqSR = ((val & 0x04) != 0);
|
|
enableIrqCB[1] = ((val & 0x08) != 0);
|
|
enableIrqCB[0] = ((val & 0x10) != 0);
|
|
enableIrqT[1] = ((val & 0x20) != 0);
|
|
enableIrqT[0] = ((val & 0x40) != 0);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// ------------------------------------
|
|
}
|
|
}
|
|
#endif |