diff --git a/BizHawk.Emulation/Computers/Commodore64/C64.core.cs b/BizHawk.Emulation/Computers/Commodore64/C64.core.cs index 8f31c5dfe7..c5984d183d 100644 --- a/BizHawk.Emulation/Computers/Commodore64/C64.core.cs +++ b/BizHawk.Emulation/Computers/Commodore64/C64.core.cs @@ -32,7 +32,11 @@ namespace BizHawk.Emulation.Computers.Commodore64 // initialize cia timers cia0 = new Cia(signal); + cia0.ports[0] = new DirectionalDataPort(0x00, 0x00); + cia0.ports[1] = new DirectionalDataPort(0x00, 0x00); cia1 = new Cia(signal); + cia1.ports[0] = new DirectionalDataPort(0x00, 0x00); + cia1.ports[1] = new DirectionalDataPort(0x00, 0x00); // initialize vic signal = new ChipSignals(); @@ -99,6 +103,7 @@ namespace BizHawk.Emulation.Computers.Commodore64 public bool CpuAEC { get { return _VicAECOutput; } } public bool CpuIRQ { get { return _VicIRQOutput | _CiaIRQOutput[0] | _CiaIRQOutput[1]; } } public bool CpuRDY { get { return _VicBAOutput; } } + public bool LPOutput { get { return _VicLPInput; } set { _VicLPInput = value; } } public bool VicAEC { get { return _VicAECOutput; } set { _VicAECOutput = value; } } public bool VicBA { get { return _VicBAOutput; } set { _VicBAOutput = value; } } public bool VicIRQ { get { return _VicIRQOutput; } set { _VicIRQOutput = value; } } diff --git a/BizHawk.Emulation/Computers/Commodore64/Cia.cs b/BizHawk.Emulation/Computers/Commodore64/Cia.cs index 5d6e8040cb..53fdf34af5 100644 --- a/BizHawk.Emulation/Computers/Commodore64/Cia.cs +++ b/BizHawk.Emulation/Computers/Commodore64/Cia.cs @@ -29,6 +29,7 @@ namespace BizHawk.Emulation.Computers.Commodore64 public bool SPMODE; public bool[] START = new bool[2]; public int[] T = new int[2]; + public int[] TLATCH = new int[2]; public int TOD10; public bool TODIN; public int TODHR; @@ -45,10 +46,11 @@ namespace BizHawk.Emulation.Computers.Commodore64 signal = newSignal; // power on state - this[0x04] = 0xFF; - this[0x05] = 0xFF; - this[0x06] = 0xFF; - this[0x07] = 0xFF; + TLATCH[0] = 0xFFFF; + TLATCH[1] = 0xFFFF; + T[0] = TLATCH[0]; + T[1] = TLATCH[1]; + this[0x0B] = 0x01; } @@ -223,24 +225,68 @@ namespace BizHawk.Emulation.Computers.Commodore64 public class Cia { public int intMask; + public bool lastCNT; + public byte[] outputBitMask; public DirectionalDataPort[] ports; public CiaRegs regs; public ChipSignals signal; + public bool thisCNT; + public bool[] underflow; + + public Func ReadSerial; + public Action WriteSerial; public Cia(ChipSignals newSignal) { signal = newSignal; + ReadSerial = ReadSerialDummy; + WriteSerial = WriteSerialDummy; HardReset(); } public void HardReset() { + outputBitMask = new byte[] { 0x40, 0x80 }; ports = new DirectionalDataPort[2]; regs = new CiaRegs(signal, ports); + underflow = new bool[2]; } public void PerformCycle() { + lastCNT = thisCNT; + thisCNT = ReadSerial(); + + for (int i = 0; i < 2; i++) + { + if (regs.START[i]) + { + TimerTick(i); + if (regs.PBON[i]) + { + // output the clock data to port B + + if (regs.OUTMODE[i]) + { + // clear bit if set + ports[1].Data &= (byte)~outputBitMask[i]; + } + if (underflow[i]) + { + if (regs.OUTMODE[i]) + { + // toggle bit + ports[1].Data ^= outputBitMask[i]; + } + else + { + // set for a cycle + ports[1].Data |= outputBitMask[i]; + } + } + } + } + } } public byte Read(ushort addr) @@ -259,14 +305,83 @@ namespace BizHawk.Emulation.Computers.Commodore64 } } + private bool ReadSerialDummy() + { + return false; + } + + public void TimerDec(int index) + { + int timer = regs.T[index]; + timer--; + if (timer < 0) + { + underflow[index] = true; + if (regs.RUNMODE[index]) + { + // one shot timer + regs.START[index] = false; + } + timer = regs.TLATCH[index]; + } + else + { + underflow[index] = false; + } + + regs.T[index] = timer; + } + public void TimerTick(int index) { + switch (regs.INMODE[index]) + { + case 0: + TimerDec(index); + break; + case 1: + if (thisCNT & !lastCNT) + TimerDec(index); + break; + case 2: + if (underflow[0]) + TimerDec(index); + break; + case 3: + if (underflow[0] || (thisCNT & !lastCNT)) + TimerDec(index); + break; + } } public void Write(ushort addr, byte val) { switch (addr) { + case 0x04: + regs.TLATCH[0] &= 0xFF00; + regs.TLATCH[0] |= val; + if (regs.LOAD[0]) + regs.T[0] = regs.TLATCH[0]; + break; + case 0x05: + regs.TLATCH[0] &= 0xFF; + regs.TLATCH[0] |= (int)val << 8; + if (regs.LOAD[0] || !regs.START[0]) + regs.T[0] = regs.TLATCH[0]; + break; + case 0x06: + regs.TLATCH[1] &= 0xFF00; + regs.TLATCH[1] |= val; + if (regs.LOAD[1]) + regs.T[1] = regs.TLATCH[1]; + break; + case 0x07: + regs.TLATCH[1] &= 0xFF; + regs.TLATCH[1] |= (int)val << 8; + if (regs.LOAD[1] || !regs.START[1]) + regs.T[1] = regs.TLATCH[1]; + break; case 0x08: if (regs.ALARM) regs.ALARM10 = val & 0x0F; @@ -305,5 +420,10 @@ namespace BizHawk.Emulation.Computers.Commodore64 } } + + private void WriteSerialDummy(bool val) + { + // do nothing + } } } diff --git a/BizHawk.Emulation/Computers/Commodore64/MemBus.cs b/BizHawk.Emulation/Computers/Commodore64/MemBus.cs index 491062ceaa..676d4a6e72 100644 --- a/BizHawk.Emulation/Computers/Commodore64/MemBus.cs +++ b/BizHawk.Emulation/Computers/Commodore64/MemBus.cs @@ -19,10 +19,10 @@ namespace BizHawk.Emulation.Computers.Commodore64 Vic, Sid, ColorRam, + Cia0, Cia1, - Cia2, - Expansion1, - Expansion2 + Expansion0, + Expansion1 } public class MemoryLayout @@ -38,8 +38,8 @@ namespace BizHawk.Emulation.Computers.Commodore64 public class Memory { // chips + public Cia cia0; public Cia cia1; - public Cia cia2; public VicII vic; public Sid sid; @@ -68,7 +68,7 @@ namespace BizHawk.Emulation.Computers.Commodore64 public bool readTrigger = true; public bool writeTrigger = true; - public Memory(string sourceFolder, VicII newVic, Sid newSid, Cia newCia1, Cia newCia2) + public Memory(string sourceFolder, VicII newVic, Sid newSid, Cia newCia0, Cia newCia1) { ram = new byte[0x10000]; WipeMemory(); @@ -84,9 +84,9 @@ namespace BizHawk.Emulation.Computers.Commodore64 vic = newVic; sid = newSid; + cia0 = newCia0; cia1 = newCia1; - cia2 = newCia2; - cpuPort = new DirectionalDataPort(0x2F, 0x37); + cpuPort = new DirectionalDataPort(0x37, 0x2F); layout = new MemoryLayout(); UpdateLayout(); @@ -175,19 +175,19 @@ namespace BizHawk.Emulation.Computers.Commodore64 } else if (addr < 0x0D00) { - result = MemoryDesignation.Cia1; + result = MemoryDesignation.Cia0; } else if (addr < 0x0E00) { - result = MemoryDesignation.Cia2; + result = MemoryDesignation.Cia1; } else if (addr < 0x0F00) { - result = MemoryDesignation.Expansion1; + result = MemoryDesignation.Expansion0; } else { - result = MemoryDesignation.Expansion2; + result = MemoryDesignation.Expansion1; } } @@ -227,16 +227,16 @@ namespace BizHawk.Emulation.Computers.Commodore64 case MemoryDesignation.ColorRam: result = colorRam[addr & 0x03FF]; break; + case MemoryDesignation.Cia0: + result = cia0.regs[addr & 0x0F]; + break; case MemoryDesignation.Cia1: result = cia1.regs[addr & 0x0F]; break; - case MemoryDesignation.Cia2: - result = cia2.regs[addr & 0x0F]; - break; - case MemoryDesignation.Expansion1: + case MemoryDesignation.Expansion0: result = 0; break; - case MemoryDesignation.Expansion2: + case MemoryDesignation.Expansion1: result = 0; break; case MemoryDesignation.Kernal: @@ -293,16 +293,16 @@ namespace BizHawk.Emulation.Computers.Commodore64 case MemoryDesignation.ColorRam: result = ReadColorRam(addr); break; + case MemoryDesignation.Cia0: + result = cia0.Read(addr); + break; case MemoryDesignation.Cia1: result = cia1.Read(addr); break; - case MemoryDesignation.Cia2: - result = cia2.Read(addr); - break; - case MemoryDesignation.Expansion1: + case MemoryDesignation.Expansion0: result = 0; break; - case MemoryDesignation.Expansion2: + case MemoryDesignation.Expansion1: result = 0; break; case MemoryDesignation.Kernal: @@ -467,16 +467,16 @@ namespace BizHawk.Emulation.Computers.Commodore64 case MemoryDesignation.ColorRam: colorRam[addr & 0x03FF] = (byte)(val & 0x0F); break; + case MemoryDesignation.Cia0: + cia0.Write(addr, val); + break; case MemoryDesignation.Cia1: cia1.Write(addr, val); break; - case MemoryDesignation.Cia2: - cia2.Write(addr, val); + case MemoryDesignation.Expansion0: break; case MemoryDesignation.Expansion1: break; - case MemoryDesignation.Expansion2: - break; case MemoryDesignation.RAM: ram[addr] = val; break; diff --git a/BizHawk.Emulation/Computers/Commodore64/VicII.cs b/BizHawk.Emulation/Computers/Commodore64/VicII.cs index 90e9a8df19..502af25cdd 100644 --- a/BizHawk.Emulation/Computers/Commodore64/VicII.cs +++ b/BizHawk.Emulation/Computers/Commodore64/VicII.cs @@ -131,7 +131,7 @@ namespace BizHawk.Emulation.Computers.Commodore64 result |= (MxE[7] ? 0x80 : 0x00); break; case 0x16: - result &= 0xBF; + result &= 0xC0; result |= XSCROLL & 0x07; result |= (CSEL ? 0x08 : 0x00); result |= (MCM ? 0x10 : 0x00); @@ -347,7 +347,6 @@ namespace BizHawk.Emulation.Computers.Commodore64 IMBC = ((val & 0x02) != 0x00); IMMC = ((val & 0x04) != 0x00); ILP = ((val & 0x08) != 0x00); - IRQ = ((val & 0x80) != 0x00); break; case 0x1A: ERST = ((val & 0x01) != 0x00); @@ -470,6 +469,8 @@ namespace BizHawk.Emulation.Computers.Commodore64 public bool borderOnVertical; public int borderRight; public int borderTop; + public int cycle; + public bool displayEnabled; public int rasterInterruptLine; public int rasterLineLeft; public int rasterOffset; @@ -501,12 +502,12 @@ namespace BizHawk.Emulation.Computers.Commodore64 rasterTotalLines = 263; rasterLineLeft = 0x19C; visibleLeft = 0x1E9; - visibleRight = 0x18B; + visibleRight = 0x159; visibleTop = 0x41; visibleBottom = 0x13; visibleRenderX = false; - visibleRenderY = true; - visibleWidth = 418; + visibleRenderY = false; + visibleWidth = 368; visibleHeight = 217; renderOffset = 0; characterFetchOffset = rasterWidth - 3; @@ -519,6 +520,8 @@ namespace BizHawk.Emulation.Computers.Commodore64 // initialize raster rasterOffsetX = rasterLineLeft; + borderOnHorizontal = true; + borderOnVertical = true; // initialize buffer buffer = new int[rasterWidth * rasterTotalLines]; @@ -531,12 +534,94 @@ namespace BizHawk.Emulation.Computers.Commodore64 public void HardReset() { regs = new VicIIRegs(); + signal.VicBA = true; + signal.VicIRQ = false; UpdateBorder(); } public void PerformCycle() { + // display enable check on line $30 + if (regs.RASTER == 0x30) + { + displayEnabled = (displayEnabled | regs.DEN); + } + // pixel clock is 8x the VIC clock + for (int i = 0; i < 8; i++) + { + int pixel; + + // process raster position + if (rasterOffsetX >= rasterWidth) + { + // reset to the left side + rasterOffsetX -= rasterWidth; + regs.RASTER = rasterOffset >> 9; + cycle = 0; + + // if vblank, reset the raster position + if (regs.RASTER == rasterTotalLines) + { + rasterOffset = 0; + regs.RASTER = 0; + regs.VCBASE = 0; + renderOffset = 0; + displayEnabled = false; + } + + // check to see if we are within viewing area Y + if (regs.RASTER == visibleTop) + visibleRenderY = true; + if (regs.RASTER == visibleBottom) + visibleRenderY = false; + + // check to see if we are on a horizontal border + if (displayEnabled && (regs.RASTER == borderTop || regs.RASTER == borderBottom)) + borderOnHorizontal = !borderOnHorizontal; + + // check for raster IRQ + if (regs.RASTER == rasterInterruptLine) + regs.IRST = true; + } + + // check to see if we are within viewing area X + if (rasterOffsetX == visibleLeft) + visibleRenderX = true; + if (rasterOffsetX == visibleRight) + visibleRenderX = false; + + // check to see if we are on a vertical border + if (rasterOffsetX == borderLeft) + borderOnVertical = false; + if (rasterOffsetX == borderRight) + borderOnVertical = true; + + // draw the border if it is on, otherwise draw the screen + if (borderOnHorizontal || borderOnVertical) + pixel = regs.EC; + else + pixel = regs.BxC[0]; + + // plot the pixel if within visible range + if (visibleRenderX && visibleRenderY) + { + WritePixel(pixel); + } + + // increment raster position + rasterOffset++; + rasterOffsetX++; + } + + // check for anything that would've triggered an interrupt and raise the flag if so + if ((regs.IRST & regs.ERST) || (regs.IMMC & regs.EMMC) || (regs.IMBC & regs.EMBC) || (regs.ILP & regs.ELP)) + { + regs.IRQ = true; + } + + signal.VicIRQ = regs.IRQ; + cycle++; } public byte Read(ushort addr) @@ -565,7 +650,7 @@ namespace BizHawk.Emulation.Computers.Commodore64 borderTop = regs.RSEL ? 0x033 : 0x037; borderBottom = regs.RSEL ? 0x0FA : 0x0F6; borderLeft = regs.CSEL ? 0x018 : 0x01F; - borderRight = regs.CSEL ? 0x14E : 0x157; + borderRight = regs.CSEL ? 0x157 : 0x14E; } public void Write(ushort addr, byte val) @@ -592,6 +677,17 @@ namespace BizHawk.Emulation.Computers.Commodore64 regs[addr] = val; UpdateBorder(); break; + case 0x19: + // only allow clearing of these flags + if ((val & 0x01) == 0x00) + regs.IRST = false; + if ((val & 0x02) == 0x00) + regs.IMBC = false; + if ((val & 0x04) == 0x00) + regs.IMMC = false; + if ((val & 0x08) == 0x00) + regs.ILP = false; + break; case 0x1E: case 0x1F: // can't write to these regs @@ -604,11 +700,7 @@ namespace BizHawk.Emulation.Computers.Commodore64 private void WritePixel(int value) { - if (visibleRenderX && visibleRenderY) - { - value &= 0x0F; - buffer[renderOffset++] = palette[value]; - } + buffer[renderOffset++] = palette[value]; } } }