diff --git a/BizHawk.Emulation/Computers/Commodore64/C64.Core.cs b/BizHawk.Emulation/Computers/Commodore64/C64.Core.cs index 11cdd346e3..01aadbe677 100644 --- a/BizHawk.Emulation/Computers/Commodore64/C64.Core.cs +++ b/BizHawk.Emulation/Computers/Commodore64/C64.Core.cs @@ -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; } } diff --git a/BizHawk.Emulation/Computers/Commodore64/C64.Motherboard.cs b/BizHawk.Emulation/Computers/Commodore64/C64.Motherboard.cs index 794f8e40c6..2f274a25a5 100644 --- a/BizHawk.Emulation/Computers/Commodore64/C64.Motherboard.cs +++ b/BizHawk.Emulation/Computers/Commodore64/C64.Motherboard.cs @@ -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; diff --git a/BizHawk.Emulation/Computers/Commodore64/Disk/VIC1541.cs b/BizHawk.Emulation/Computers/Commodore64/Disk/VIC1541.cs index a02e6bffc8..f8e088ef52 100644 --- a/BizHawk.Emulation/Computers/Commodore64/Disk/VIC1541.cs +++ b/BizHawk.Emulation/Computers/Commodore64/Disk/VIC1541.cs @@ -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(); } } } diff --git a/BizHawk.Emulation/Computers/Commodore64/MOS/MOS6522.cs b/BizHawk.Emulation/Computers/Commodore64/MOS/MOS6522.cs index ce391f6d3b..d8f42ab0d7 100644 --- a/BizHawk.Emulation/Computers/Commodore64/MOS/MOS6522.cs +++ b/BizHawk.Emulation/Computers/Commodore64/MOS/MOS6522.cs @@ -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 ReadCA0; + public Func ReadCA1; + public Func ReadCB0; + public Func ReadCB1; + public Action WriteCA0; + public Action WriteCA1; + public Action WriteCB0; + public Action 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: diff --git a/BizHawk.Emulation/Computers/Commodore64/MOS/Timer.cs b/BizHawk.Emulation/Computers/Commodore64/MOS/Timer.cs index acc77b2f57..1222fabc17 100644 --- a/BizHawk.Emulation/Computers/Commodore64/MOS/Timer.cs +++ b/BizHawk.Emulation/Computers/Commodore64/MOS/Timer.cs @@ -15,14 +15,14 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS protected bool[] timerOn; protected bool[] underflow; - public Func ReadDirA; - public Func ReadDirB; - public Func ReadPortA; - public Func ReadPortB; - public Action WriteDirA; - public Action WriteDirB; - public Action WritePortA; - public Action WritePortB; + public Func ReadDirA = (() => { return 0xFF; }); + public Func ReadDirB = (() => { return 0xFF; }); + public Func ReadPortA = (() => { return 0xFF; }); + public Func ReadPortB = (() => { return 0xFF; }); + public Action WriteDirA = ((byte val) => { }); + public Action WriteDirB = ((byte val) => { }); + public Action WritePortA = ((byte val) => { }); + public Action 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];