BizHawk/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/MOS6522.cs

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