commodore64: VIC timing fix, implemented new cartridge I/O which handles writes into ROM addresses (apparently some carts use this)

This commit is contained in:
saxxonpike 2012-11-28 03:30:59 +00:00
parent 49b7f9165d
commit 49a847d8bc
10 changed files with 540 additions and 18 deletions

View File

@ -81,7 +81,10 @@
<Compile Include="Buffer.cs" />
<Compile Include="Computers\Commodore64\C64.Core.cs" />
<Compile Include="Computers\Commodore64\C64.cs" />
<Compile Include="Computers\Commodore64\Cartridges\Mapper0000.cs" />
<Compile Include="Computers\Commodore64\Memory.cs" />
<Compile Include="Computers\Commodore64\Cartridges\Cartridge.cs" />
<Compile Include="Computers\Commodore64\MOS\CartridgePort.cs" />
<Compile Include="Computers\Commodore64\MOS\Chip2114.cs" />
<Compile Include="Computers\Commodore64\MOS\Chip23XX.cs" />
<Compile Include="Computers\Commodore64\MOS\Chip4864.cs" />
@ -102,6 +105,7 @@
<Compile Include="Computers\Commodore64\MOS\Sid.SoundProvider.cs" />
<Compile Include="Computers\Commodore64\MOS\Sid.SyncSoundProvider.cs" />
<Compile Include="Computers\Commodore64\MOS\Timer.cs" />
<Compile Include="Computers\Commodore64\MOS\UserPort.cs" />
<Compile Include="Computers\Commodore64\MOS\Vic.cs" />
<Compile Include="Computers\Commodore64\MOS\Vic.VideoProvider.cs" />
<Compile Include="Consoles\Atari\2600\Atari2600.cs" />

View File

@ -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);

View File

@ -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<uint> chipAddress = new List<uint>();
List<uint> chipBank = new List<uint>();
List<byte[]> chipData = new List<byte[]>();
List<uint> chipType = new List<uint>();
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)
{
}
}
}

View File

@ -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];
}
}
}

View File

@ -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;
}
}
}
}

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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<int, byte> peekMemory;
private Action<int, byte> pokeMemory;
private Func<ushort, byte> readMemory;
private Action<ushort, byte> writeMemory;
public UserPort()
{
// start up with no media connected
Disconnect();
}
public void Connect(Func<int, byte> funcPeek, Action<int, byte> actPoke, Func<ushort, byte> funcRead, Action<ushort, byte> 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);
}
}
}

View File

@ -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: