diff --git a/BizHawk.Emulation/BizHawk.Emulation.csproj b/BizHawk.Emulation/BizHawk.Emulation.csproj index 3743ffb90e..6c1441f4d4 100644 --- a/BizHawk.Emulation/BizHawk.Emulation.csproj +++ b/BizHawk.Emulation/BizHawk.Emulation.csproj @@ -81,7 +81,10 @@ + + + @@ -102,6 +105,7 @@ + diff --git a/BizHawk.Emulation/Computers/Commodore64/C64.Core.cs b/BizHawk.Emulation/Computers/Commodore64/C64.Core.cs index 5cb758f714..3fa7671363 100644 --- a/BizHawk.Emulation/Computers/Commodore64/C64.Core.cs +++ b/BizHawk.Emulation/Computers/Commodore64/C64.Core.cs @@ -39,12 +39,29 @@ namespace BizHawk.Emulation.Computers.Commodore64 { chips = new C64Chips(initRegion); InitRoms(); + InitMedia(); // configure video CoreOutputComm.VsyncDen = chips.vic.CyclesPerFrame; CoreOutputComm.VsyncNum = chips.vic.CyclesPerSecond; } + private void InitMedia() + { + switch (extension.ToUpper()) + { + case @".CRT": + Cartridges.Cartridge cart = Cartridges.Cartridge.Load(inputFile); + if (cart != null) + { + chips.cartPort.Connect(cart); + chips.pla.ExRom = chips.cartPort.ExRom; + chips.pla.Game = chips.cartPort.Game; + } + break; + } + } + private void InitRoms() { string sourceFolder = CoreInputComm.C64_FirmwaresPath; @@ -102,6 +119,7 @@ namespace BizHawk.Emulation.Computers.Commodore64 public class C64Chips { public Chip23XX basicRom; //u4 + public CartridgePort cartPort; //cn6 public Chip23XX charRom; //u5 public MOS6526 cia0; //u1 public MOS6526 cia1; //u2 @@ -111,10 +129,12 @@ namespace BizHawk.Emulation.Computers.Commodore64 public MOSPLA pla; public Chip4864 ram; //u10+11 public Sid sid; //u9 + public UserPort userPort; //cn2 (probably won't be needed for games) public Vic vic; //u7 public C64Chips(Region initRegion) { + cartPort = new CartridgePort(); cia0 = new MOS6526(initRegion); cia1 = new MOS6526(initRegion); pla = new MOSPLA(this, cia1.ReadPort0); diff --git a/BizHawk.Emulation/Computers/Commodore64/Cartridges/Cartridge.cs b/BizHawk.Emulation/Computers/Commodore64/Cartridges/Cartridge.cs new file mode 100644 index 0000000000..a6b122d8c0 --- /dev/null +++ b/BizHawk.Emulation/Computers/Commodore64/Cartridges/Cartridge.cs @@ -0,0 +1,241 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace BizHawk.Emulation.Computers.Commodore64.Cartridges +{ + // this is the base cartridge class + + public class Cartridge + { + // --------------------------------- + + static public Cartridge Load(byte[] crtFile) + { + Cartridge result = null; + MemoryStream mem = new MemoryStream(crtFile); + BinaryReader reader = new BinaryReader(mem); + + if (new string(reader.ReadChars(16)) == "C64 CARTRIDGE ") + { + List chipAddress = new List(); + List chipBank = new List(); + List chipData = new List(); + List chipType = new List(); + + uint headerLength = ReadCRTInt(reader); + uint version = ReadCRTShort(reader); + uint mapper = ReadCRTShort(reader); + bool exrom = (reader.ReadByte() != 0); + bool game = (reader.ReadByte() != 0); + + // reserved + reader.ReadBytes(6); + + // cartridge name + reader.ReadBytes(0x20); + + // skip extra header bytes + if (headerLength > 0x40) + { + reader.ReadBytes((int)headerLength - 0x40); + } + + // read chips + while (reader.PeekChar() >= 0) + { + if (new string(reader.ReadChars(4)) == "CHIP") + { + uint chipLength = ReadCRTInt(reader); + chipType.Add(ReadCRTShort(reader)); + chipBank.Add(ReadCRTShort(reader)); + chipAddress.Add(ReadCRTShort(reader)); + uint chipDataLength = ReadCRTShort(reader); + chipData.Add(reader.ReadBytes((int)chipDataLength)); + chipLength -= (chipDataLength + 0x10); + if (chipLength > 0) + reader.ReadBytes((int)chipLength); + } + } + + if (chipData.Count > 0) + { + switch (mapper) + { + case 0: + result = new Mapper0000(chipData[0], exrom, game); + break; + default: + break; + } + } + } + + return result; + } + + static private uint ReadCRTShort(BinaryReader reader) + { + uint result; + result = (uint)reader.ReadByte() << 8; + result |= (uint)reader.ReadByte(); + return result; + } + + static private uint ReadCRTInt(BinaryReader reader) + { + uint result; + result = (uint)reader.ReadByte() << 24; + result |= (uint)reader.ReadByte() << 16; + result |= (uint)reader.ReadByte() << 8; + result |= (uint)reader.ReadByte(); + return result; + } + + // --------------------------------- + + protected bool pinExRom; + protected bool pinGame; + protected bool pinIRQ; + protected bool pinNMI; + protected bool pinReset; + protected bool validCartridge; + + public virtual void ExecutePhase1() + { + } + + public virtual void ExecutePhase2() + { + } + + public bool ExRom + { + get + { + return pinExRom; + } + } + + public bool Game + { + get + { + return pinGame; + } + } + + public virtual void HardReset() + { + pinIRQ = true; + pinNMI = true; + pinReset = true; + } + + public bool IRQ + { + get + { + return pinIRQ; + } + } + + public bool NMI + { + get + { + return pinNMI; + } + } + + public virtual byte Peek8000(int addr) + { + return 0xFF; + } + + public virtual byte PeekA000(int addr) + { + return 0xFF; + } + + public virtual byte PeekDE00(int addr) + { + return 0xFF; + } + + public virtual byte PeekDF00(int addr) + { + return 0xFF; + } + + public virtual void Poke8000(int addr, byte val) + { + } + + public virtual void PokeA000(int addr, byte val) + { + } + + public virtual void PokeDE00(int addr, byte val) + { + } + + public virtual void PokeDF00(int addr, byte val) + { + } + + public virtual byte Read8000(ushort addr) + { + return 0xFF; + } + + public virtual byte ReadA000(ushort addr) + { + return 0xFF; + } + + public virtual byte ReadDE00(ushort addr) + { + return 0xFF; + } + + public virtual byte ReadDF00(ushort addr) + { + return 0xFF; + } + + public bool Reset + { + get + { + return pinReset; + } + } + + public bool Valid + { + get + { + return validCartridge; + } + } + + public virtual void Write8000(ushort addr, byte val) + { + } + + public virtual void WriteA000(ushort addr, byte val) + { + } + + public virtual void WriteDE00(ushort addr, byte val) + { + } + + public virtual void WriteDF00(ushort addr, byte val) + { + } + } +} diff --git a/BizHawk.Emulation/Computers/Commodore64/Cartridges/Mapper0000.cs b/BizHawk.Emulation/Computers/Commodore64/Cartridges/Mapper0000.cs new file mode 100644 index 0000000000..af20981372 --- /dev/null +++ b/BizHawk.Emulation/Computers/Commodore64/Cartridges/Mapper0000.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BizHawk.Emulation.Computers.Commodore64.Cartridges +{ + public class Mapper0000 : Cartridge + { + private byte[] romA; + private byte[] romB; + + public Mapper0000(byte[] data, bool exrom, bool game) + { + pinGame = game; + pinExRom = exrom; + + romA = new byte[0x2000]; + romB = new byte[0x2000]; + + Array.Copy(data, 0x0000, romA, 0x0000, 0x2000); + + if (data.Length == 0x2000) + { + for (int i = 0; i < 0x2000; i++) + romB[i] = 0xFF; + } + else + { + Array.Copy(data, 0x2000, romB, 0x0000, 0x2000); + } + + HardReset(); + } + + public override byte Peek8000(int addr) + { + return romA[addr]; + } + + public override byte PeekA000(int addr) + { + return romB[addr]; + } + + public override byte Read8000(ushort addr) + { + return romA[addr]; + } + + public override byte ReadA000(ushort addr) + { + return romB[addr]; + } + } +} diff --git a/BizHawk.Emulation/Computers/Commodore64/MOS/CartridgePort.cs b/BizHawk.Emulation/Computers/Commodore64/MOS/CartridgePort.cs new file mode 100644 index 0000000000..90e2ca4feb --- /dev/null +++ b/BizHawk.Emulation/Computers/Commodore64/MOS/CartridgePort.cs @@ -0,0 +1,91 @@ +using BizHawk.Emulation.Computers.Commodore64.Cartridges; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BizHawk.Emulation.Computers.Commodore64.MOS +{ + public class CartridgePort + { + private Cartridge cart; + private bool connected; + + public CartridgePort() + { + // start up with no media connected + Disconnect(); + } + + // ------------------------------------------ + + public byte PeekHiExp(int addr) { if (connected) { return cart.PeekDF00(addr & 0x00FF); } else { return 0xFF; } } + public byte PeekHiRom(int addr) { if (connected) { return cart.PeekA000(addr & 0x1FFF); } else { return 0xFF; } } + public byte PeekLoExp(int addr) { if (connected) { return cart.PeekDE00(addr & 0x00FF); } else { return 0xFF; } } + public byte PeekLoRom(int addr) { if (connected) { return cart.Peek8000(addr & 0x1FFF); } else { return 0xFF; } } + + public void PokeHiExp(int addr, byte val) { if (connected) { cart.PokeDF00(addr & 0x00FF, val); } } + public void PokeHiRom(int addr, byte val) { if (connected) { cart.PokeA000(addr & 0x1FFF, val); } } + public void PokeLoExp(int addr, byte val) { if (connected) { cart.PokeDE00(addr & 0x00FF, val); } } + public void PokeLoRom(int addr, byte val) { if (connected) { cart.Poke8000(addr & 0x1FFF, val); } } + + public byte ReadHiExp(ushort addr) { if (connected) { return cart.ReadDF00((ushort)(addr & 0x00FF)); } else { return 0xFF; } } + public byte ReadHiRom(ushort addr) { if (connected) { return cart.ReadA000((ushort)(addr & 0x1FFF)); } else { return 0xFF; } } + public byte ReadLoExp(ushort addr) { if (connected) { return cart.ReadDE00((ushort)(addr & 0x00FF)); } else { return 0xFF; } } + public byte ReadLoRom(ushort addr) { if (connected) { return cart.Read8000((ushort)(addr & 0x1FFF)); } else { return 0xFF; } } + + public void WriteHiExp(ushort addr, byte val) { if (connected) { cart.WriteDF00((ushort)(addr & 0x00FF), val); } } + public void WriteHiRom(ushort addr, byte val) { if (connected) { cart.WriteA000((ushort)(addr & 0x1FFF), val); } } + public void WriteLoExp(ushort addr, byte val) { if (connected) { cart.WriteDE00((ushort)(addr & 0x00FF), val); } } + public void WriteLoRom(ushort addr, byte val) { if (connected) { cart.Write8000((ushort)(addr & 0x1FFF), val); } } + + // ------------------------------------------ + + public void Connect(Cartridge newCart) + { + cart = newCart; + connected = true; + } + + public void Disconnect() + { + cart = null; + connected = false; + } + + public bool ExRom + { + get + { + if (connected) + return cart.ExRom; + else + return true; + } + } + + public bool Game + { + get + { + if (connected) + return cart.Game; + else + return true; + } + } + + public void HardReset() + { + // note: this will not disconnect any attached media + } + + public bool IsConnected + { + get + { + return connected; + } + } + } +} diff --git a/BizHawk.Emulation/Computers/Commodore64/MOS/MOS6510.cs b/BizHawk.Emulation/Computers/Commodore64/MOS/MOS6510.cs index edac0a3973..8e0cfcd5b1 100644 --- a/BizHawk.Emulation/Computers/Commodore64/MOS/MOS6510.cs +++ b/BizHawk.Emulation/Computers/Commodore64/MOS/MOS6510.cs @@ -80,6 +80,8 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS cpu.NMI = !pinNMI; cpu.IRQ = !pinIRQ; cpu.ExecuteOne(); + chips.ram.Write(0x0FFE, (byte)(cpu.PC & 0xFF)); + chips.ram.Write(0x0FFF, (byte)((cpu.PC >> 8) & 0xFF)); } // process unused pin TTL diff --git a/BizHawk.Emulation/Computers/Commodore64/MOS/MOS6526.cs b/BizHawk.Emulation/Computers/Commodore64/MOS/MOS6526.cs index c21ddc648e..b655759bc6 100644 --- a/BizHawk.Emulation/Computers/Commodore64/MOS/MOS6526.cs +++ b/BizHawk.Emulation/Computers/Commodore64/MOS/MOS6526.cs @@ -221,6 +221,11 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS } public byte Read(ushort addr) + { + return Read(addr, 0xFF); + } + + public byte Read(ushort addr, byte mask) { addr &= 0xF; byte val; @@ -236,6 +241,7 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS break; } + val &= mask; return val; } @@ -284,6 +290,13 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS public void Write(ushort addr, byte val) { + Write(addr, val, 0xFF); + } + + public void Write(ushort addr, byte val, byte mask) + { + val &= mask; + val |= (byte)(ReadRegister(addr) & ~mask); addr &= 0xF; switch (addr) diff --git a/BizHawk.Emulation/Computers/Commodore64/MOS/MOSPLA.cs b/BizHawk.Emulation/Computers/Commodore64/MOS/MOSPLA.cs index 1052d6eb53..29e86ec998 100644 --- a/BizHawk.Emulation/Computers/Commodore64/MOS/MOSPLA.cs +++ b/BizHawk.Emulation/Computers/Commodore64/MOS/MOSPLA.cs @@ -59,13 +59,13 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS { chips = newChips; vicBankPortRead = newVicBankPortRead; + pinExRom = true; + pinGame = true; } public void HardReset() { pinCharen = true; - pinExRom = true; - pinGame = true; pinHiRam = true; pinLoRam = true; UpdateMap(); @@ -358,9 +358,9 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS case PLABank.BasicROM: return chips.basicRom.Peek(addr); case PLABank.CartridgeHi: - return 0; + return chips.cartPort.PeekHiRom(addr); case PLABank.CartridgeLo: - return 0; + return chips.cartPort.PeekLoRom(addr); case PLABank.CharROM: return chips.charRom.Peek(addr); case PLABank.Cia0: @@ -370,9 +370,9 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS case PLABank.ColorRam: return chips.colorRam.Peek(addr, bus); case PLABank.Expansion0: - return 0; + return chips.cartPort.PeekLoExp(addr); case PLABank.Expansion1: - return 0; + return chips.cartPort.PeekHiExp(addr); case PLABank.KernalROM: return chips.kernalRom.Peek(addr); case PLABank.None: @@ -395,8 +395,10 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS chips.basicRom.Poke(addr, val); break; case PLABank.CartridgeHi: + chips.cartPort.PokeHiRom(addr, val); break; case PLABank.CartridgeLo: + chips.cartPort.PokeLoRom(addr, val); break; case PLABank.CharROM: chips.charRom.Poke(addr, val); @@ -411,8 +413,10 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS chips.colorRam.Poke(addr, val); break; case PLABank.Expansion0: + chips.cartPort.PokeLoExp(addr, val); break; case PLABank.Expansion1: + chips.cartPort.PokeHiExp(addr, val); break; case PLABank.KernalROM: chips.kernalRom.Poke(addr, val); @@ -439,10 +443,10 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS bus = chips.basicRom.Read(addr); break; case PLABank.CartridgeHi: - bus = 0; + bus = chips.cartPort.ReadHiRom(addr); break; case PLABank.CartridgeLo: - bus = 0; + bus = chips.cartPort.ReadLoRom(addr); break; case PLABank.CharROM: bus = chips.charRom.Read(addr); @@ -459,10 +463,10 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS bus = chips.colorRam.Read(addr, bus); break; case PLABank.Expansion0: - bus = 0; + bus = chips.cartPort.ReadLoExp(addr); break; case PLABank.Expansion1: - bus = 0; + bus = chips.cartPort.ReadHiExp(addr); break; case PLABank.KernalROM: bus = chips.kernalRom.Read(addr); @@ -518,8 +522,10 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS chips.basicRom.Write(addr, val); break; case PLABank.CartridgeHi: + chips.cartPort.WriteHiRom(addr, val); break; case PLABank.CartridgeLo: + chips.cartPort.WriteLoRom(addr, val); break; case PLABank.CharROM: chips.charRom.Write(addr, val); @@ -534,8 +540,10 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS chips.colorRam.Write(addr, val); break; case PLABank.Expansion0: + chips.cartPort.WriteLoExp(addr, val); break; case PLABank.Expansion1: + chips.cartPort.WriteHiExp(addr, val); break; case PLABank.KernalROM: chips.kernalRom.Write(addr, val); diff --git a/BizHawk.Emulation/Computers/Commodore64/MOS/UserPort.cs b/BizHawk.Emulation/Computers/Commodore64/MOS/UserPort.cs new file mode 100644 index 0000000000..c0b714022a --- /dev/null +++ b/BizHawk.Emulation/Computers/Commodore64/MOS/UserPort.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BizHawk.Emulation.Computers.Commodore64.MOS +{ + public class UserPort + { + private Func peekMemory; + private Action pokeMemory; + private Func readMemory; + private Action writeMemory; + + public UserPort() + { + // start up with no media connected + Disconnect(); + } + + public void Connect(Func funcPeek, Action actPoke, Func funcRead, Action actWrite) + { + peekMemory = funcPeek; + pokeMemory = actPoke; + readMemory = funcRead; + writeMemory = actWrite; + } + + public void Disconnect() + { + peekMemory = DummyPeek; + pokeMemory = DummyPoke; + readMemory = DummyRead; + writeMemory = DummyWrite; + } + + private byte DummyPeek(int addr) + { + return 0xFF; + } + + private void DummyPoke(int addr, byte val) + { + // do nothing + } + + private byte DummyRead(ushort addr) + { + return 0xFF; + } + + private void DummyWrite(ushort addr, byte val) + { + // do nothing + } + + public void HardReset() + { + // note: this will not disconnect any attached media + } + + public byte Peek(int addr) + { + return peekMemory(addr); + } + + public void Poke(int addr, byte val) + { + pokeMemory(addr, val); + } + + public byte Read(ushort addr) + { + return readMemory(addr); + } + + public void Write(ushort addr, byte val) + { + writeMemory(addr, val); + } + } +} diff --git a/BizHawk.Emulation/Computers/Commodore64/MOS/Vic.cs b/BizHawk.Emulation/Computers/Commodore64/MOS/Vic.cs index 9ec8dd63a2..eb55dd6754 100644 --- a/BizHawk.Emulation/Computers/Commodore64/MOS/Vic.cs +++ b/BizHawk.Emulation/Computers/Commodore64/MOS/Vic.cs @@ -254,9 +254,6 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS public void ExecutePhase1() { - // always assert access over the bus in ph1 - pinAEC = false; - // raster IRQ compare if ((cycle == 0 && rasterLine > 0) || (cycle == 1 && rasterLine == 0)) { @@ -273,6 +270,8 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS // badline compare if (badlineEnable && rasterLine >= 0x030 && rasterLine < 0x0F7 && ((rasterLine & 0x7) == yScroll)) badline = true; + else + badline = false; // go into display state on a badline if (badline) @@ -319,8 +318,7 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS // if the BA counter is nonzero, allow CPU bus access UpdateBA(); - if (baCount > 0) - pinAEC = true; + pinAEC = (baCount > 0); Render(); @@ -330,6 +328,7 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS private void ParseCycle() { + bool baPinThisCycle = true; ushort addr = 0x3FFF; uint cycleBAsprite0; uint cycleBAsprite1; @@ -433,10 +432,10 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS switch (ba) { case 0x0000: - pinBA = true; + baPinThisCycle = true; break; case 0x1000: - pinBA = !badline; + baPinThisCycle = !badline; break; default: cycleBAsprite0 = ba & 0x000F; @@ -445,9 +444,10 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS if ((cycleBAsprite0 < 8 && sprites[cycleBAsprite0].dma) || (cycleBAsprite1 < 8 && sprites[cycleBAsprite1].dma) || (cycleBAsprite2 < 8 && sprites[cycleBAsprite2].dma)) - pinBA = false; + baPinThisCycle = false; break; } + pinBA = baPinThisCycle; // perform actions borderCheckLEnable = true; @@ -859,6 +859,11 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS intSpriteCollision = false; if ((val & 0x08) != 0) intLightPen = false; + UpdatePins(); + break; + case 0x1A: + WriteRegister(addr, val); + UpdatePins(); break; case 0x1E: case 0x1F: