From 0a8355ce1add769cb827fbbbb8463a5c376011c5 Mon Sep 17 00:00:00 2001 From: saxxonpike Date: Sat, 17 Nov 2012 03:58:06 +0000 Subject: [PATCH] commodore64: full PAL support across all chips, better HardReset behavior --- .../Computers/Commodore64/C64.core.cs | 41 ++- .../Computers/Commodore64/C64.cs | 82 +++--- .../Computers/Commodore64/Cia.cs | 36 ++- .../Computers/Commodore64/Input.cs | 2 + .../Computers/Commodore64/VicII.cs | 247 +++++++++++++++++- 5 files changed, 342 insertions(+), 66 deletions(-) diff --git a/BizHawk.Emulation/Computers/Commodore64/C64.core.cs b/BizHawk.Emulation/Computers/Commodore64/C64.core.cs index c02eab68a8..43f0e732e2 100644 --- a/BizHawk.Emulation/Computers/Commodore64/C64.core.cs +++ b/BizHawk.Emulation/Computers/Commodore64/C64.core.cs @@ -55,6 +55,17 @@ namespace BizHawk.Emulation.Computers.Commodore64 } public void HardReset() + { + mem.HardReset(); + cia0.HardReset(); + cia1.HardReset(); + vic.HardReset(); + sid.HardReset(); + if (diskDriveAttached) + diskDrive.HardReset(); + } + + private void Init(Region initRegion) { // initalize cpu cpu = new MOS6502X(); @@ -63,24 +74,36 @@ namespace BizHawk.Emulation.Computers.Commodore64 cpu.DummyReadMemory = PeekMemory; // initialize cia timers - cia0 = new Cia(Region.NTSC); - cia1 = new Cia(Region.NTSC); + cia0 = new Cia(initRegion); + cia1 = new Cia(initRegion); // initialize vic signal = new ChipSignals(); - vic = new VicII(signal, Region.NTSC); + vic = new VicII(signal, initRegion); - // assume NTSC for now + // set vsync rate CoreOutputComm.VsyncDen = vic.cyclesPerFrame; - CoreOutputComm.VsyncNum = (14318181 / 14); + switch (initRegion) + { + case Region.NTSC: + CoreOutputComm.VsyncNum = (14318181 / 14); + break; + case Region.PAL: + CoreOutputComm.VsyncNum = (14318181 / 18); + break; + } // initialize sid - sid = new Sid(Region.NTSC, 44100); // we'll assume 44.1k for now until there's a better way + sid = new Sid(initRegion, 44100); // we'll assume 44.1k for now until there's a better way syncSid = new SidSyncSoundProvider(sid); //sidDCFilter = new Emulation.Sound.Utilities.DCFilter(sid, 2205); // initialize memory (this must be done AFTER all other chips are initialized) string romPath = CoreInputComm.C64_FirmwaresPath; + if (romPath == null) + { + romPath = @".\C64\Firmwares"; + } mem = new Memory(romPath, vic, sid, cia0, cia1); vic.mem = mem; @@ -89,7 +112,7 @@ namespace BizHawk.Emulation.Computers.Commodore64 cpu.BCD_Enabled = true; // initailize input - input = new Input( new DataPortConnector[] { cia0.ConnectPort(0), cia0.ConnectPort(1) } ); + input = new Input(new DataPortConnector[] { cia0.ConnectPort(0), cia0.ConnectPort(1) }); cia0.AttachWriteHook(0, input.WritePortA); cia0.AttachWriteHook(1, input.WritePortB); @@ -97,11 +120,11 @@ namespace BizHawk.Emulation.Computers.Commodore64 switch (extension.ToUpper()) { case @".G64": - diskDrive = new Drive1541(File.ReadAllBytes(Path.Combine(romPath, @"dos1541")), Region.NTSC, cia1); + diskDrive = new Drive1541(File.ReadAllBytes(Path.Combine(romPath, @"dos1541")), initRegion, cia1); diskDrive.Insert(G64.Read(inputFile)); break; case @".D64": - diskDrive = new Drive1541(File.ReadAllBytes(Path.Combine(romPath, @"dos1541")), Region.NTSC, cia1); + diskDrive = new Drive1541(File.ReadAllBytes(Path.Combine(romPath, @"dos1541")), initRegion, cia1); diskDrive.Insert(D64.Read(inputFile)); break; case @".PRG": diff --git a/BizHawk.Emulation/Computers/Commodore64/C64.cs b/BizHawk.Emulation/Computers/Commodore64/C64.cs index f111256063..a92fb73266 100644 --- a/BizHawk.Emulation/Computers/Commodore64/C64.cs +++ b/BizHawk.Emulation/Computers/Commodore64/C64.cs @@ -16,43 +16,55 @@ namespace BizHawk.Emulation.Computers.Commodore64 SetupMemoryDomains(); CoreOutputComm = new CoreOutputComm(); CoreInputComm = new CoreInputComm(); + Init(Region.NTSC); } - public string SystemId { get { return "C64"; } } - public GameInfo game; - - public CoreInputComm CoreInputComm { get; set; } - public CoreOutputComm CoreOutputComm { get; private set; } - private IList memoryDomains; - public IList MemoryDomains { get { return memoryDomains; } } - public MemoryDomain MainMemory { get { return memoryDomains[0]; } } - public int Frame { get { return _frame; } set { _frame = value; } } - public int LagCount { get { return _lagcount; } set { _lagcount = value; } } - public bool IsLagFrame { get { return _islag; } } + // internal variables private bool _islag = true; private int _lagcount = 0; private int _frame = 0; - public byte[] ReadSaveRam() { return null; } - public void StoreSaveRam(byte[] data) { } + + // bizhawk I/O + public CoreInputComm CoreInputComm { get; set; } + public CoreOutputComm CoreOutputComm { get; private set; } + + // game/rom specific + public GameInfo game; + public string SystemId { get { return "C64"; } } + + // memory domains + public MemoryDomain MainMemory { get { return memoryDomains[0]; } } + private IList memoryDomains; + public IList MemoryDomains { get { return memoryDomains; } } + + // save state/ram public void ClearSaveRam() { } + public void LoadStateBinary(BinaryReader br) { } + public void LoadStateText(TextReader reader) { } + public byte[] ReadSaveRam() { return null; } public bool SaveRamModified { get; set; } - public void Dispose() { } - public IVideoProvider VideoProvider { get { return vic; } } - public ISoundProvider SoundProvider { get { return sid; } } + public void SaveStateBinary(BinaryWriter bw) { } + public void SaveStateText(TextWriter writer) { } + public void StoreSaveRam(byte[] data) { } + + // running state + public bool DeterministicEmulation { get { return true; } set { ; } } + public int Frame { get { return _frame; } set { _frame = value; } } + public bool IsLagFrame { get { return _islag; } } + public int LagCount { get { return _lagcount; } set { _lagcount = value; } } public void ResetFrameCounter() { _frame = 0; } - /*TODO*/ - public ISyncSoundProvider SyncSoundProvider { get { return syncSid; ; } } - public bool StartAsyncSound() { return true; } //TODO + // audio/video public void EndAsyncSound() { } //TODO - public bool DeterministicEmulation { get; set; } //TODO - public void SaveStateText(TextWriter writer) { } //TODO - public void LoadStateText(TextReader reader) { } //TODO` - public void SaveStateBinary(BinaryWriter bw) { } //TODO - public void LoadStateBinary(BinaryReader br) { } //TODO + public ISoundProvider SoundProvider { get { return sid; } } + public bool StartAsyncSound() { return true; } //TODO + public ISyncSoundProvider SyncSoundProvider { get { return syncSid; ; } } + public IVideoProvider VideoProvider { get { return vic; } } + + // controller public ControllerDefinition ControllerDefinition { get { return C64ControllerDefinition; } } public IController Controller { get { return input.controller; } set { input.controller = value; } } public static readonly ControllerDefinition C64ControllerDefinition = new ControllerDefinition @@ -73,6 +85,10 @@ namespace BizHawk.Emulation.Computers.Commodore64 } }; + // framework + public void Dispose() { } + + // process frame public void FrameAdvance(bool render, bool rendersound) { _frame++; @@ -114,6 +130,15 @@ namespace BizHawk.Emulation.Computers.Commodore64 } } + public byte[] SaveStateBinary() + { + MemoryStream ms = new MemoryStream(); + BinaryWriter bw = new BinaryWriter(ms); + SaveStateBinary(bw); + bw.Flush(); + return ms.ToArray(); + } + private void SetupMemoryDomains() { var domains = new List(1); @@ -130,15 +155,6 @@ namespace BizHawk.Emulation.Computers.Commodore64 memoryDomains = domains.AsReadOnly(); } - public byte[] SaveStateBinary() - { - MemoryStream ms = new MemoryStream(); - BinaryWriter bw = new BinaryWriter(ms); - SaveStateBinary(bw); - bw.Flush(); - return ms.ToArray(); - } - void SyncState(Serializer ser) //TODO { ser.Sync("Lag", ref _lagcount); diff --git a/BizHawk.Emulation/Computers/Commodore64/Cia.cs b/BizHawk.Emulation/Computers/Commodore64/Cia.cs index 37247ded48..f584d76b5b 100644 --- a/BizHawk.Emulation/Computers/Commodore64/Cia.cs +++ b/BizHawk.Emulation/Computers/Commodore64/Cia.cs @@ -54,24 +54,13 @@ namespace BizHawk.Emulation.Computers.Commodore64 public CiaRegs() { - // power on state - TLATCH[0] = 0xFFFF; - TLATCH[1] = 0xFFFF; - T[0] = TLATCH[0]; - T[1] = TLATCH[1]; - - this[0x0B] = 0x01; - ports = new DataPortBus[2]; ports[0] = new DataPortBus(); ports[1] = new DataPortBus(); connectors = new DataPortConnector[2]; connectors[0] = ports[0].Connect(); connectors[1] = ports[1].Connect(); - connectors[0].Data = 0xFF; - connectors[1].Data = 0xFF; - connectors[0].Direction = 0xFF; - connectors[1].Direction = 0xFF; + HardReset(); } public byte this[int addr] @@ -240,6 +229,25 @@ namespace BizHawk.Emulation.Computers.Commodore64 } } } + + public void HardReset() + { + // power on state + for (int i = 0; i < 0x10; i++) + this[i] = 0x00; + + TLATCH[0] = 0xFFFF; + TLATCH[1] = 0xFFFF; + T[0] = TLATCH[0]; + T[1] = TLATCH[1]; + + this[0x0B] = 0x01; + + connectors[0].Data = 0xFF; + connectors[1].Data = 0xFF; + connectors[0].Direction = 0xFF; + connectors[1].Direction = 0xFF; + } } public class Cia @@ -247,7 +255,7 @@ namespace BizHawk.Emulation.Computers.Commodore64 public int intMask; public bool lastCNT; public byte[] outputBitMask; - private CiaRegs regs; + private CiaRegs regs = new CiaRegs(); public int todCounter; public int todFrequency; public bool[] underflow; @@ -353,7 +361,7 @@ namespace BizHawk.Emulation.Computers.Commodore64 public void HardReset() { outputBitMask = new byte[] { 0x40, 0x80 }; - regs = new CiaRegs(); + regs.HardReset(); underflow = new bool[2]; todCounter = todFrequency; } diff --git a/BizHawk.Emulation/Computers/Commodore64/Input.cs b/BizHawk.Emulation/Computers/Commodore64/Input.cs index 41c56cff53..6803c3fce4 100644 --- a/BizHawk.Emulation/Computers/Commodore64/Input.cs +++ b/BizHawk.Emulation/Computers/Commodore64/Input.cs @@ -51,6 +51,8 @@ namespace BizHawk.Emulation.Computers.Commodore64 result |= controller[joystickMatrix[index, 2]] ? (byte)0x00 : (byte)0x04; result |= controller[joystickMatrix[index, 3]] ? (byte)0x00 : (byte)0x08; result |= controller[joystickMatrix[index, 4]] ? (byte)0x00 : (byte)0x10; + if (result != 0xFF) + index = index; return result; } diff --git a/BizHawk.Emulation/Computers/Commodore64/VicII.cs b/BizHawk.Emulation/Computers/Commodore64/VicII.cs index a5baf1118e..2e0d78e538 100644 --- a/BizHawk.Emulation/Computers/Commodore64/VicII.cs +++ b/BizHawk.Emulation/Computers/Commodore64/VicII.cs @@ -502,6 +502,7 @@ namespace BizHawk.Emulation.Computers.Commodore64 public int[] pixelBuffer; public bool[] pixelBufferForeground; public int pixelBufferIndex; + public int pixelBufferLength; public int rasterInterruptLine; public int rasterLineLeft; public int rasterOffset; @@ -510,8 +511,6 @@ namespace BizHawk.Emulation.Computers.Commodore64 public int rasterWidth; public int refreshAddress; public int renderOffset; - public int spriteFetchStartCycle; - public int spriteFetchIndex; public bool spriteForeground; public SpriteGenerator[] spriteGenerators; public int totalCycles; @@ -546,19 +545,34 @@ namespace BizHawk.Emulation.Computers.Commodore64 rasterTotalLines = 263; rasterLineLeft = 0x19C; cycleLeft = 0; - spriteFetchStartCycle = 59; visibleLeft = 0x008; visibleRight = 0x168; - visibleTop = 0x023; //0x041; - visibleBottom = 0x004; //0x013; + visibleTop = 0x023; + visibleBottom = 0x004; visibleRenderX = false; visibleRenderY = false; visibleWidth = 352; visibleHeight = 232; renderOffset = 0; + pixelBufferLength = 12; PerformCycleFunction = PerformCycleNTSC; break; case Region.PAL: + totalCycles = 63; + rasterTotalLines = 312; + rasterLineLeft = 0x194; + cycleLeft = 0; + visibleLeft = 0x008; + visibleRight = 0x168; + visibleTop = 0x023; + visibleBottom = 0x10B; + visibleRenderX = false; + visibleRenderY = false; + visibleWidth = 352; + visibleHeight = 232; + renderOffset = 0; + PerformCycleFunction = PerformCyclePAL; + pixelBufferLength = 4; break; default: break; @@ -652,12 +666,11 @@ namespace BizHawk.Emulation.Computers.Commodore64 // initialize screen buffer characterMemory = new byte[40]; colorMemory = new byte[40]; - pixelBuffer = new int[12]; - pixelBufferForeground = new bool[12]; + pixelBuffer = new int[pixelBufferLength]; + pixelBufferForeground = new bool[pixelBufferLength]; pixelBufferIndex = 0; // initialize registers - spriteFetchIndex = 0; idle = true; refreshAddress = 0x3FFF; regs = new VicIIRegs(); @@ -958,6 +971,220 @@ namespace BizHawk.Emulation.Computers.Commodore64 // operations timed to PAL private void PerformCyclePAL() { + switch (cycle) + { + case 0: + // rasterline IRQ happens on cycle 1 on rasterline 0 + if (regs.RASTER > 0 && regs.RASTER == rasterInterruptLine) + regs.IRST = true; + PerformSpritePointerFetch(3); + break; + case 1: + // rasterline IRQ happens on cycle 1 on rasterline 0 + if (regs.RASTER == 0 && regs.RASTER == rasterInterruptLine) + regs.IRST = true; + PerformSpriteDataFetch(3); + break; + case 2: + PerformSpritePointerFetch(4); + break; + case 3: + PerformSpriteDataFetch(4); + break; + case 4: + PerformSpritePointerFetch(5); + break; + case 5: + PerformSpriteDataFetch(5); + break; + case 6: + PerformSpritePointerFetch(6); + break; + case 7: + PerformSpriteDataFetch(6); + break; + case 8: + PerformSpritePointerFetch(7); + break; + case 9: + PerformSpriteDataFetch(7); + break; + case 10: + signal.VicAEC = true; + PerformDRAMRefresh(); + break; + case 11: + PerformDRAMRefresh(); + break; + case 12: + PerformDRAMRefresh(); + break; + case 13: + PerformVCReset(); + PerformDRAMRefresh(); + break; + case 14: + PerformDRAMRefresh(); + break; + case 15: + spriteGenerators[0].Render(); + spriteGenerators[1].Render(); + spriteGenerators[2].Render(); + spriteGenerators[3].Render(); + spriteGenerators[4].Render(); + spriteGenerators[5].Render(); + spriteGenerators[6].Render(); + spriteGenerators[7].Render(); + PerformSpriteMCBASEAdvance(); + PerformScreenCAccess(); + break; + case 16: + PerformScreenCAccess(); + break; + case 17: + PerformScreenCAccess(); + break; + case 18: + PerformScreenCAccess(); + break; + case 19: + PerformScreenCAccess(); + break; + case 20: + PerformScreenCAccess(); + break; + case 21: + PerformScreenCAccess(); + break; + case 22: + PerformScreenCAccess(); + break; + case 23: + PerformScreenCAccess(); + break; + case 24: + PerformScreenCAccess(); + break; + case 25: + PerformScreenCAccess(); + break; + case 26: + PerformScreenCAccess(); + break; + case 27: + PerformScreenCAccess(); + break; + case 28: + PerformScreenCAccess(); + break; + case 29: + PerformScreenCAccess(); + break; + case 30: + PerformScreenCAccess(); + break; + case 31: + PerformScreenCAccess(); + break; + case 32: + PerformScreenCAccess(); + break; + case 33: + PerformScreenCAccess(); + break; + case 34: + PerformScreenCAccess(); + break; + case 35: + PerformScreenCAccess(); + break; + case 36: + PerformScreenCAccess(); + break; + case 37: + PerformScreenCAccess(); + break; + case 38: + PerformScreenCAccess(); + break; + case 39: + PerformScreenCAccess(); + break; + case 40: + PerformScreenCAccess(); + break; + case 41: + PerformScreenCAccess(); + break; + case 42: + PerformScreenCAccess(); + break; + case 43: + PerformScreenCAccess(); + break; + case 44: + PerformScreenCAccess(); + break; + case 45: + PerformScreenCAccess(); + break; + case 46: + PerformScreenCAccess(); + break; + case 47: + PerformScreenCAccess(); + break; + case 48: + PerformScreenCAccess(); + break; + case 49: + PerformScreenCAccess(); + break; + case 50: + PerformScreenCAccess(); + break; + case 51: + PerformScreenCAccess(); + break; + case 52: + PerformScreenCAccess(); + break; + case 53: + PerformScreenCAccess(); + break; + case 54: + PerformScreenCAccess(); + PerformSpriteYExpansionFlip(); + PerformSpriteComparison(); + break; + case 55: + signal.VicAEC = true; + PerformSpriteComparison(); + break; + case 56: + break; + case 57: + PerformSpriteDMAEnable(); + PerformRCReset(); + PerformSpritePointerFetch(0); + break; + case 58: + PerformSpriteDataFetch(0); + break; + case 59: + PerformSpritePointerFetch(1); + break; + case 60: + PerformSpriteDataFetch(1); + break; + case 61: + PerformSpritePointerFetch(2); + break; + case 62: + PerformBorderCheck(); + PerformSpriteDataFetch(2); + break; + } } private void PerformDRAMRefresh() @@ -1367,11 +1594,11 @@ namespace BizHawk.Emulation.Computers.Commodore64 } } - // process 12 pixel delay + // process pixel delay pixelBuffer[pixelBufferIndex] = inputPixel; pixelBufferForeground[pixelBufferIndex] = dataForeground; pixelBufferIndex++; - if (pixelBufferIndex == 12) + if (pixelBufferIndex == pixelBufferLength) { pixelBufferIndex = 0; }