diff --git a/BizHawk.Emulation/Computers/Commodore64/Cia.cs b/BizHawk.Emulation/Computers/Commodore64/Cia.cs index 889e6a6db2..bcc65ba18a 100644 --- a/BizHawk.Emulation/Computers/Commodore64/Cia.cs +++ b/BizHawk.Emulation/Computers/Commodore64/Cia.cs @@ -33,6 +33,11 @@ namespace BizHawk.Emulation.Computers.Commodore64 public int TODHR; // time of day hour public int TODMIN; // time of day minute public bool TODPM; // time of day AM/PM + public bool TODREADLATCH; // read latch (internal) + public int TODREADLATCH10; // tod read latch (internal) + public int TODREADLATCHSEC; // tod read latch (internal) + public int TODREADLATCHMIN; // tod read latch (internal) + public int TODREADLATCHHR; // tod read latch (internal) public int TODSEC; // time of day seconds private ChipSignals signal; @@ -203,6 +208,8 @@ namespace BizHawk.Emulation.Computers.Commodore64 public CiaRegs regs; public ChipSignals signal; public bool thisCNT; + public int todCounter; + public int todFrequency; public bool[] underflow; public Func ReadSerial; @@ -213,15 +220,86 @@ namespace BizHawk.Emulation.Computers.Commodore64 signal = newSignal; ReadSerial = ReadSerialDummy; WriteSerial = WriteSerialDummy; + switch (newRegion) + { + case Region.NTSC: + todFrequency = 14318181 / 14 / 10; + break; + case Region.PAL: + todFrequency = 14318181 / 18 / 10; + break; + } HardReset(); } + private void AdvanceTOD() + { + bool overflow; + int tenths = regs.TOD10; + int seconds = regs.TODSEC; + int minutes = regs.TODMIN; + int hours = regs.TODHR; + bool ampm = regs.TODPM; + todCounter = todFrequency; + + tenths = BCDAdd(tenths, 1, out overflow); + if (tenths >= 10) + { + tenths = 0; + seconds = BCDAdd(seconds, 1, out overflow); + if (overflow) + { + seconds = 0; + minutes = BCDAdd(minutes, 1, out overflow); + if (overflow) + { + minutes = 0; + hours = BCDAdd(hours, 1, out overflow); + if (hours > 12) + { + hours = 1; + ampm = !ampm; + } + } + } + } + + regs.TOD10 = tenths; + regs.TODSEC = seconds; + regs.TODMIN = minutes; + regs.TODHR = hours; + regs.TODPM = ampm; + } + + private int BCDAdd(int i, int j, out bool overflow) + { + int lo; + int hi; + int result; + + lo = (i & 0x0F) + (j & 0x0F); + hi = (i & 0x70) + (j & 0x70); + if (lo > 0x09) + { + hi += 0x10; + lo += 0x06; + } + if (hi > 0x50) + { + hi += 0xA0; + } + overflow = hi >= 0x60; + result = (hi & 0x70) + (lo & 0x0F); + return result; + } + public void HardReset() { outputBitMask = new byte[] { 0x40, 0x80 }; ports = new DirectionalDataPort[2]; regs = new CiaRegs(signal); underflow = new bool[2]; + todCounter = todFrequency; } public byte Peek(int addr) @@ -247,6 +325,11 @@ namespace BizHawk.Emulation.Computers.Commodore64 lastCNT = thisCNT; thisCNT = ReadSerial(); + // process time of day counter + todCounter--; + if (todCounter <= 0) + AdvanceTOD(); + for (int i = 0; i < 2; i++) { if (regs.START[i]) @@ -317,6 +400,26 @@ namespace BizHawk.Emulation.Computers.Commodore64 return ports[0].Direction; case 0x03: return ports[1].Direction; + case 0x08: + regs.TODREADLATCH = false; + return (byte)regs.TODREADLATCH10; + case 0x09: + if (!regs.TODREADLATCH) + return regs[addr]; + else + return (byte)regs.TODREADLATCHSEC; + case 0x0A: + if (!regs.TODREADLATCH) + return regs[addr]; + else + return (byte)regs.TODREADLATCHMIN; + case 0x0B: + regs.TODREADLATCH = true; + regs.TODREADLATCH10 = regs.TOD10; + regs.TODREADLATCHSEC = regs.TODSEC; + regs.TODREADLATCHMIN = regs.TODMIN; + regs.TODREADLATCHHR = regs.TODHR; + return (byte)regs.TODREADLATCHHR; case 0x0D: // reading this reg clears it result = regs[0x0D]; @@ -442,7 +545,9 @@ namespace BizHawk.Emulation.Computers.Commodore64 regs.ALARMPM = ((val & 0x80) != 0x00); } else + { regs[addr] = val; + } break; case 0x0D: intMask &= ~val; diff --git a/BizHawk.Emulation/Computers/Commodore64/VicII.cs b/BizHawk.Emulation/Computers/Commodore64/VicII.cs index d8fc017c60..6b03d3721b 100644 --- a/BizHawk.Emulation/Computers/Commodore64/VicII.cs +++ b/BizHawk.Emulation/Computers/Commodore64/VicII.cs @@ -43,9 +43,11 @@ namespace BizHawk.Emulation.Computers.Commodore64 public bool[] MxMC = new bool[8]; // sprite multicolor public int[] MxX = new int[8]; // sprite X coordinate public bool[] MxXE = new bool[8]; // sprite X expansion + public bool[] MxXEToggle = new bool[8]; // (internal) + public int[] MxXLatch = new int[8]; // (internal) public int[] MxY = new int[8]; // sprite Y coordinate public bool[] MxYE = new bool[8]; // sprite Y expansion - public bool[] MYE = new bool[8]; // (internal) + public bool[] MxYEToggle = new bool[8]; // (internal) public int RASTER; // current raster line public int RC; // (internal) public bool RES; // reset bit (does nothing in this version of the VIC) @@ -705,7 +707,7 @@ namespace BizHawk.Emulation.Computers.Commodore64 // sprite Y stretch flipflop for (int i = 0; i < 8; i++) if (!regs.MxYE[i]) - regs.MYE[i] = true; + regs.MxYEToggle[i] = true; } // operations timed to NTSC @@ -965,19 +967,14 @@ namespace BizHawk.Emulation.Computers.Commodore64 // sprite comparison for (int i = 0; i < 8; i++) { - if (regs.MYE[i] && regs.MCBASE[i] == 63) - { - regs.MD[i] = false; - regs.MDMA[i] = false; - } - if (regs.MxE[i] == true && regs.MxY[i] == (regs.RASTER & 0xFF) && regs.MDMA[i] == false) { regs.MDMA[i] = true; regs.MCBASE[i] = 0; if (regs.MxYE[i]) - regs.MYE[i] = false; + regs.MxYEToggle[i] = false; } + regs.MxXEToggle[i] = false; } } @@ -1002,7 +999,10 @@ namespace BizHawk.Emulation.Computers.Commodore64 { regs.MC[i] = regs.MCBASE[i]; if (regs.MDMA[i] && regs.MxY[i] == (regs.RASTER & 0xFF)) + { regs.MD[i] = true; + regs.MxXEToggle[i] = false; + } } } @@ -1010,11 +1010,13 @@ namespace BizHawk.Emulation.Computers.Commodore64 { for (int i = 0; i < 8; i++) { - if (regs.MYE[i]) + if (regs.MxYEToggle[i]) { - if (regs.MD[i]) + regs.MCBASE[i] += 3; + if (regs.MxYEToggle[i] && regs.MCBASE[i] == 63) { - regs.MCBASE[i] += 3; + regs.MD[i] = false; + regs.MDMA[i] = false; } } } @@ -1040,7 +1042,7 @@ namespace BizHawk.Emulation.Computers.Commodore64 { for (int i = 0; i < 8; i++) if (regs.MxYE[i]) - regs.MYE[i] = !regs.MYE[i]; + regs.MxYEToggle[i] = !regs.MxYEToggle[i]; } private void PerformVCReset() @@ -1293,6 +1295,7 @@ namespace BizHawk.Emulation.Computers.Commodore64 if (regs.MxX[j] == rasterOffsetX) { regs.MSRA[j] = true; + regs.MxXLatch[j] = rasterOffsetX; } if (regs.MSRA[j]) { @@ -1300,23 +1303,25 @@ namespace BizHawk.Emulation.Computers.Commodore64 if (regs.MxMC[j]) { spriteBits = (int)((regs.MSR[j] >> 22) & 0x3); - if ((rasterOffsetX & 0x1) != (regs.MxX[j] & 0x1)) + if ((rasterOffsetX & 0x1) != (regs.MxXLatch[j] & 0x1)) { - if ((!regs.MxXE[j]) || ((rasterOffsetX & 0x2) != (regs.MxX[j] & 0x2))) + if (!regs.MxXE[j] || regs.MxXEToggle[j]) { regs.MSR[j] <<= 2; regs.MSRC[j]--; } + regs.MxXEToggle[j] = !regs.MxXEToggle[j]; } } else { spriteBits = (int)((regs.MSR[j] >> 22) & 0x2); - if ((!regs.MxXE[j]) || ((rasterOffsetX & 0x1) != (regs.MxX[j] & 0x1))) + if (!regs.MxXE[j] || regs.MxXEToggle[j]) { regs.MSR[j] <<= 1; regs.MSRC[j]--; } + regs.MxXEToggle[j] = !regs.MxXEToggle[j]; } // if not transparent, process collisions and color