commodore64: implement more c64-disk communications, hook up drive LED

This commit is contained in:
saxxonpike 2012-12-07 17:06:07 +00:00
parent 38adb50a10
commit e4ff87e92a
5 changed files with 373 additions and 40 deletions

View File

@ -55,6 +55,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
byte[] diskRom = File.ReadAllBytes(diskPath);
disk = new VIC1541(initRegion, diskRom);
disk.Connect(board.serPort);
}
private void InitMedia()
@ -84,7 +85,6 @@ namespace BizHawk.Emulation.Computers.Commodore64
string basicFile = "basic";
string charFile = "chargen";
string kernalFile = "kernal";
string diskFile = "dos1541";
string basicPath = Path.Combine(sourceFolder, basicFile);
string charPath = Path.Combine(sourceFolder, charFile);
@ -109,7 +109,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
{
get
{
return false;
return (disk.PeekVia1(0x00) & 0x08) != 0;
}
}

View File

@ -151,8 +151,16 @@ namespace BizHawk.Emulation.Computers.Commodore64
cia1.ReadPortB = (() => { return cia1DataB; });
cia1.WriteDirA = ((byte val) => { cia1DirA = val; });
cia1.WriteDirB = ((byte val) => { cia1DirB = val; });
cia1.WritePortA = ((byte val) => { cia1DataA = Port.CPUWrite(cia1DataA, val, cia1DirA); UpdateVicBank(); });
cia1.WritePortB = ((byte val) => { cia1DataB = Port.CPUWrite(cia1DataB, val, cia1DirB); });
cia1.WritePortA = ((byte val) => {
cia1DataA = Port.CPUWrite(cia1DataA, val, cia1DirA);
UpdateVicBank();
serPort.SystemWriteAtn((cia1DataA & 0x08) == 0);
serPort.SystemWriteClock((cia1DataA & 0x10) == 0);
serPort.SystemWriteData((cia1DataA & 0x20) == 0);
});
cia1.WritePortB = ((byte val) => {
cia1DataB = Port.CPUWrite(cia1DataB, val, cia1DirB);
});
cpu.PeekMemory = pla.Peek;
cpu.PokeMemory = pla.Poke;

View File

@ -79,14 +79,22 @@ namespace BizHawk.Emulation.Computers.Commodore64.Disk
public MOS6522 via0;
public MOS6522 via1;
public byte via0dirA;
public byte via0dirB;
public byte via0portA;
public byte via0portB;
public byte via1dirA;
public byte via1dirB;
public byte via1portA;
public byte via1portB;
public bool via0CA0;
public bool via0CA1;
public bool via0CB0;
public bool via0CB1;
public byte via0DataA;
public byte via0DataB;
public byte via0DirA;
public byte via0DirB;
public bool via1CA0;
public bool via1CA1;
public bool via1CB0;
public bool via1CB1;
public byte via1DataA;
public byte via1DataB;
public byte via1DirA;
public byte via1DirB;
public VIC1541Motherboard(Region initRegion, byte[] initRom)
{
@ -119,28 +127,97 @@ namespace BizHawk.Emulation.Computers.Commodore64.Disk
pla.WriteVia0 = via0.Write;
pla.WriteVia1 = via1.Write;
via0dirA = 0x00;
via0dirB = 0x00;
via0portA = 0xFF;
via0portB = 0xFF;
via1dirA = 0x00;
via1dirB = 0x00;
via1portA = 0xFF;
via1portB = 0xFF;
via0CA0 = false;
via0CA1 = false;
via0CB0 = false;
via0CB1 = false;
via0DirA = 0x00;
via0DirB = 0x00;
via0DataA = 0xFF;
via0DataB = 0xFF;
via1CA0 = false;
via1CA1 = false;
via1CB0 = false;
via1CB1 = false;
via1DirA = 0x00;
via1DirB = 0x00;
via1DataA = 0xFF;
via1DataB = 0xFF;
via0.ReadCA0 = (() => { return via0CA0; });
via0.ReadCA1 = (() => { return via0CA1; });
via0.ReadCB0 = (() => { return via0CB0; });
via0.ReadCB1 = (() => { return via0CB1; });
via0.ReadDirA = (() => { return via0DirA; });
via0.ReadDirB = (() => { return via0DirB; });
via0.ReadPortA = (() => { return via0DataA; });
via0.ReadPortB = (() => { return via0DataB; });
via0.WriteCA0 = ((bool val) => { via0CA0 = val; });
via0.WriteCA1 = ((bool val) => { via0CA1 = val; });
via0.WriteCB0 = ((bool val) => { via0CB0 = val; });
via0.WriteCB1 = ((bool val) => { via0CB1 = val; });
via0.WriteDirA = ((byte val) => { via0DirA = val; });
via0.WriteDirB = ((byte val) => { via0DirB = val; });
via0.WritePortA = ((byte val) => {
via0DataA = Port.CPUWrite(via0DataA, val, via0DirA);
});
via0.WritePortB = ((byte val) => {
via0DataB = Port.CPUWrite(via0DataB, val, via0DirB);
serPort.DeviceWriteAtn((via0DataB & 0x80) != 0);
serPort.DeviceWriteClock((via0DataB & 0x08) != 0);
serPort.DeviceWriteData((via0DataB & 0x02) != 0);
});
via1.ReadCA0 = (() => { return via1CA0; });
via1.ReadCA1 = (() => { return via1CA1; });
via1.ReadCB0 = (() => { return via1CB0; });
via1.ReadCB1 = (() => { return via1CB1; });
via1.ReadDirA = (() => { return via1DirA; });
via1.ReadDirB = (() => { return via1DirB; });
via1.ReadPortA = (() => { return via1DataA; });
via1.ReadPortB = (() => { return via1DataB; });
via1.WriteCA0 = ((bool val) => { via1CA0 = val; });
via1.WriteCA1 = ((bool val) => { via1CA1 = val; });
via1.WriteCB0 = ((bool val) => { via1CB0 = val; });
via1.WriteCB1 = ((bool val) => { via1CB1 = val; });
via1.WriteDirA = ((byte val) => { via1DirA = val; });
via1.WriteDirB = ((byte val) => { via1DirB = val; });
via1.WritePortA = ((byte val) => { via1DataA = Port.CPUWrite(via1DataA, val, via1DirA); });
via1.WritePortB = ((byte val) => { via1DataB = Port.CPUWrite(via1DataB, val, via1DirB); });
}
public void Connect(SerialPort newSerPort)
{
// TODO: verify polarity
serPort = newSerPort;
serPort.SystemReadAtn = (() => { return true; });
serPort.SystemReadClock = (() => { return ((via0portB & 0x8) != 0); }); // bit 3
serPort.SystemReadData = (() => { return ((via0portB & 0x2) != 0); }); // bit 1
serPort.SystemReadSrq = (() => { return true; });
serPort.SystemWriteAtn = ((bool val) => { via0portB = Port.ExternalWrite(via0portB, (byte)((via0portB & 0x7F) | (val ? 0x80 : 0x00)), via0dirB); });
serPort.SystemWriteClock = ((bool val) => { via0portB = Port.ExternalWrite(via0portB, (byte)((via0portB & 0xFB) | (val ? 0x04 : 0x00)), via0dirB); });
serPort.SystemWriteData = ((bool val) => { via0portB = Port.ExternalWrite(via0portB, (byte)((via0portB & 0xFE) | (val ? 0x01 : 0x00)), via0dirB); });
serPort.SystemReadAtn = (() => {
return true;
});
serPort.SystemReadClock = (() => {
return ((via0DataB & 0x08) != 0);
}); // bit 3
serPort.SystemReadData = (() => {
return ((via0DataB & 0x02) != 0);
}); // bit 1
serPort.SystemReadSrq = (() => {
return false;
}); // device sensing
serPort.SystemWriteAtn = ((bool val) => {
via0DataB = Port.ExternalWrite(via0DataB, (byte)((via0DataB & 0x7F) | (val ? 0x80 : 0x00)), via0DataB);
via0CA0 = val;
// repeat to DATA OUT if bit 4 enabled on port B
if ((via0DataB & 0x10) != 0)
serPort.DeviceWriteData(val);
});
serPort.SystemWriteClock = ((bool val) => {
via0DataB = Port.ExternalWrite(via0DataB, (byte)((via0DataB & 0xFB) | (val ? 0x04 : 0x00)), via0DataB);
});
serPort.SystemWriteData = ((bool val) => {
via0DataB = Port.ExternalWrite(via0DataB, (byte)((via0DataB & 0xFE) | (val ? 0x01 : 0x00)), via0DataB);
});
serPort.SystemWriteReset = ((bool val) => { });
serPort.DeviceWriteSrq(false);
}
public void Execute()
@ -148,6 +225,7 @@ namespace BizHawk.Emulation.Computers.Commodore64.Disk
via0.ExecutePhase1();
via1.ExecutePhase1();
cpu.IRQ = !(via0.IRQ && via1.IRQ);
cpu.ExecuteOne();
via0.ExecutePhase2();
via1.ExecutePhase2();
@ -158,6 +236,8 @@ namespace BizHawk.Emulation.Computers.Commodore64.Disk
for (uint i = 0; i < 0x7FF; i++)
ram[i] = 0x00;
cpu.PC = (ushort)(cpu.ReadMemory(0xFFFC) | ((ushort)cpu.ReadMemory(0xFFFD) << 8));
via0.HardReset();
via1.HardReset();
}
}
}

View File

@ -26,7 +26,18 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
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 uint acrShiftMode;
private bool caPulse;
private bool cbPulse;
private bool[] enableIrqCA;
private bool[] enableIrqCB;
private bool enableIrqSR;
@ -35,18 +46,32 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
private bool[] irqCB;
private bool irqSR;
private bool[] irqT;
private bool[] lastca;
private bool[] lastcb;
private byte lastpb;
private byte paLatch;
private byte pbLatch;
private bool paLatchEnable;
private bool pbLatchEnable;
private byte paOut;
private byte pbOut;
private bool[] pbPulse;
private uint[] pcrControlA;
private uint[] pcrControlB;
private byte sr;
private uint srControl;
private uint srCounter;
private 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];
@ -55,6 +80,9 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
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];
@ -63,6 +91,8 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
public void HardReset()
{
acrShiftMode = 0;
caPulse = false;
cbPulse = false;
enableIrqCA[0] = false;
enableIrqCA[1] = false;
enableIrqCB[0] = false;
@ -77,12 +107,19 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
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();
}
// ------------------------------------
@ -93,10 +130,185 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
public void ExecutePhase2()
{
pinIRQ = !(irqCA[0] | irqCA[1] |
irqCB[0] | irqCB[1] |
irqSR | irqT[0] | irqT[1]
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])
pbPulse[i] = false;
else
WritePortB((byte)(ReadPortB() & portMask[i]));
if (timer[i] > 0)
{
timer[i]--;
if (timer[i] == 0)
{
irqT[i] = true;
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])
);
}
// ------------------------------------
@ -113,15 +325,26 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
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
@ -168,7 +391,7 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
(paLatchEnable ? 0x01 : 0x00) |
(pbLatchEnable ? 0x02 : 0x00) |
(byte)((srControl & 0x7) << 2) |
(byte)((tControl[1] & 0x1) << 5) |
(byte)((tControl[1] & 0x4) << 3) |
(byte)((tControl[0] & 0x3) << 6)
);
case 0xC:
@ -207,14 +430,25 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
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;
@ -240,6 +474,15 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
timer[1] = timerLatch[1];
irqT[1] = false;
break;
case 0xE:
intEnable = ((val & 0x80) != 0);
result = ReadRegister(addr);
if (intEnable)
result |= val;
else
result &= (byte)(val ^ 0x7F);
WriteRegister(0xE, result);
break;
default:
WriteRegister(addr, val);
break;
@ -293,7 +536,7 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
paLatchEnable = ((val & 0x01) != 0);
pbLatchEnable = ((val & 0x02) != 0);
srControl = (((uint)val >> 2) & 0x7);
tControl[1] = (((uint)val >> 5) & 0x1);
tControl[1] = (((uint)val >> 3) & 0x4);
tControl[0] = (((uint)val >> 6) & 0x3);
break;
case 0xC:

View File

@ -15,14 +15,14 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
protected bool[] timerOn;
protected bool[] underflow;
public Func<byte> ReadDirA;
public Func<byte> ReadDirB;
public Func<byte> ReadPortA;
public Func<byte> ReadPortB;
public Action<byte> WriteDirA;
public Action<byte> WriteDirB;
public Action<byte> WritePortA;
public Action<byte> WritePortB;
public Func<byte> ReadDirA = (() => { return 0xFF; });
public Func<byte> ReadDirB = (() => { return 0xFF; });
public Func<byte> ReadPortA = (() => { return 0xFF; });
public Func<byte> ReadPortB = (() => { return 0xFF; });
public Action<byte> WriteDirA = ((byte val) => { });
public Action<byte> WriteDirB = ((byte val) => { });
public Action<byte> WritePortA = ((byte val) => { });
public Action<byte> WritePortB = ((byte val) => { });
public Timer()
{
@ -34,6 +34,8 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
protected void HardResetInternal()
{
WriteDirA(0x00);
WriteDirB(0x00);
timer[0] = 0xFFFF;
timer[1] = 0xFFFF;
timerLatch[0] = timer[0];