BizHawk/BizHawk.Emulation/Computers/Commodore64/C64.Motherboard.cs

277 lines
10 KiB
C#

using BizHawk.Emulation.Computers.Commodore64.MOS;
namespace BizHawk.Emulation.Computers.Commodore64
{
public partial class Motherboard
{
// chips
public Chip23XX basicRom;
public Chip23XX charRom;
public MOS6526 cia0;
public MOS6526 cia1;
public Chip2114 colorRam;
public MOS6510 cpu;
public Chip23XX kernalRom;
public MOSPLA pla;
public Chip4864 ram;
public Sid sid;
public Vic vic;
// ports
public CartridgePort cartPort;
public CassettePort cassPort;
public IController controller;
public SerialPort serPort;
public UserPort userPort;
// state
public ushort address;
public byte bus;
public byte cia0DataA;
public byte cia0DataB;
public byte cia0DirA;
public byte cia0DirB;
public bool cia0FlagCassette;
public bool cia0FlagSerial;
public byte cia1DataA;
public byte cia1DataB;
public byte cia1DirA;
public byte cia1DirB;
public bool inputRead;
// cache
private ushort vicBank;
public Motherboard(Region initRegion)
{
// note: roms need to be added on their own externally
cartPort = new CartridgePort();
cassPort = new CassettePort();
cia0 = new MOS6526(initRegion);
cia1 = new MOS6526(initRegion);
colorRam = new Chip2114();
cpu = new MOS6510();
pla = new MOSPLA();
ram = new Chip4864();
serPort = new SerialPort();
sid = new MOS6581(44100, initRegion);
switch (initRegion)
{
case Region.NTSC: vic = new MOS6567(); break;
case Region.PAL: vic = new MOS6569(); break;
}
userPort = new UserPort();
}
// -----------------------------------------
public void Execute()
{
WriteInputPort();
cia0.ExecutePhase1();
cia1.ExecutePhase1();
pla.ExecutePhase1();
sid.ExecutePhase1();
vic.ExecutePhase1();
cpu.ExecutePhase1();
cia0.ExecutePhase2();
cia1.ExecutePhase2();
pla.ExecutePhase2();
sid.ExecutePhase2();
vic.ExecutePhase2();
cpu.ExecutePhase2();
}
// -----------------------------------------
public void HardReset()
{
address = 0xFFFF;
bus = 0xFF;
cia0DataA = 0xFF;
cia0DataB = 0xFF;
cia0DirA = 0xFF;
cia0DirB = 0xFF;
cia0FlagCassette = true;
cia0FlagSerial = true;
cia1DataA = 0xFF;
cia1DataB = 0xFF;
cia1DirA = 0xFF;
cia1DirB = 0xFF;
inputRead = false;
cpu.HardReset();
cia0.HardReset();
cia1.HardReset();
colorRam.HardReset();
pla.HardReset();
ram.HardReset();
serPort.HardReset();
sid.HardReset();
vic.HardReset();
userPort.HardReset();
// because of how mapping works, the cpu needs to be hard reset twice
cpu.HardReset();
// now reset the cache
UpdateVicBank();
}
public void Init()
{
cassPort.DeviceReadLevel = (() => { return cpu.CassetteOutputLevel; });
cassPort.DeviceReadMotor = (() => { return cpu.CassetteMotor; });
cassPort.DeviceWriteButton = ((bool val) => { cpu.CassetteButton = val; });
cassPort.DeviceWriteLevel = ((bool val) => { cia0FlagCassette = val; cia0.FLAG = cia0FlagCassette & cia0FlagSerial; });
cassPort.SystemReadButton = (() => { return true; });
cassPort.SystemReadLevel = (() => { return true; });
cassPort.SystemWriteLevel = ((bool val) => { });
cassPort.SystemWriteMotor = ((bool val) => { });
cia0.ReadDirA = (() => { return cia0DirA; });
cia0.ReadDirB = (() => { return cia0DirB; });
cia0.ReadPortA = (() => { return cia0DataA; });
cia0.ReadPortB = (() => { return cia0DataB; });
cia0.WriteDirA = ((byte val) => { cia0DirA = val; });
cia0.WriteDirB = ((byte val) => { cia0DirB = val; });
cia0.WritePortA = ((byte val) => { cia0DataA = Port.CPUWrite(cia0DataA, val, cia0DirA); });
cia0.WritePortB = ((byte val) => { cia0DataB = Port.CPUWrite(cia0DataB, val, cia0DirB); });
cia1.ReadDirA = (() => { return cia1DirA; });
cia1.ReadDirB = (() => { return cia1DirB; });
cia1.ReadPortA = (() => { return cia1DataA; });
cia1.ReadPortB = (() => { return cia1DataB; });
cia1.WriteDirA = ((byte val) => { cia1DirA = val; });
cia1.WriteDirB = ((byte val) => { cia1DirB = val; });
cia1.WritePortA = ((byte val) => {
cia1DataA = Port.CPUWrite(cia1DataA, val, cia1DirA);
UpdateVicBank();
serPort.SystemWriteAtn((cia1DataA & 0x08) == 0);
serPort.SystemWriteClock((cia1DataA & 0x10) == 0);
serPort.SystemWriteData((cia1DataA & 0x20) == 0);
});
cia1.WritePortB = ((byte val) => {
cia1DataB = Port.CPUWrite(cia1DataB, val, cia1DirB);
});
cpu.PeekMemory = pla.Peek;
cpu.PokeMemory = pla.Poke;
cpu.ReadAEC = (() => { return vic.AEC; });
cpu.ReadIRQ = (() => { return cia0.IRQ & vic.IRQ & cartPort.IRQ; });
cpu.ReadNMI = (() => { return cia1.IRQ; });
cpu.ReadRDY = (() => { return vic.BA; });
cpu.ReadMemory = pla.Read;
cpu.WriteMemory = pla.Write;
pla.PeekBasicRom = basicRom.Peek;
pla.PeekCartridgeHi = cartPort.PeekHiRom;
pla.PeekCartridgeLo = cartPort.PeekLoRom;
pla.PeekCharRom = charRom.Peek;
pla.PeekCia0 = cia0.Peek;
pla.PeekCia1 = cia1.Peek;
pla.PeekColorRam = colorRam.Peek;
pla.PeekExpansionHi = cartPort.PeekHiExp;
pla.PeekExpansionLo = cartPort.PeekLoExp;
pla.PeekKernalRom = kernalRom.Peek;
pla.PeekMemory = ram.Peek;
pla.PeekSid = sid.Peek;
pla.PeekVic = vic.Peek;
pla.PokeCartridgeHi = cartPort.PokeHiRom;
pla.PokeCartridgeLo = cartPort.PokeLoRom;
pla.PokeCia0 = cia0.Poke;
pla.PokeCia1 = cia1.Poke;
pla.PokeColorRam = colorRam.Poke;
pla.PokeExpansionHi = cartPort.PokeHiExp;
pla.PokeExpansionLo = cartPort.PokeLoExp;
pla.PokeMemory = ram.Poke;
pla.PokeSid = sid.Poke;
pla.PokeVic = vic.Poke;
pla.ReadBasicRom = ((ushort addr) => { address = addr; bus = basicRom.Read(addr); return bus; });
pla.ReadCartridgeHi = ((ushort addr) => { address = addr; bus = cartPort.ReadHiRom(addr); return bus; });
pla.ReadCartridgeLo = ((ushort addr) => { address = addr; bus = cartPort.ReadLoRom(addr); return bus; });
pla.ReadCharen = (() => { return cpu.Charen; });
pla.ReadCharRom = ((ushort addr) => { address = addr; bus = charRom.Read(addr); return bus; });
pla.ReadCia0 = ((ushort addr) =>
{
address = addr;
bus = cia0.Read(addr);
if (!inputRead && (addr == 0xDC00 || addr == 0xDC01))
inputRead = true;
return bus;
});
pla.ReadCia1 = ((ushort addr) => { address = addr; bus = cia1.Read(addr); return bus; });
pla.ReadColorRam = ((ushort addr) => { address = addr; bus &= 0xF0; bus |= colorRam.Read(addr); return bus; });
pla.ReadExpansionHi = ((ushort addr) => { address = addr; bus = cartPort.ReadHiExp(addr); return bus; });
pla.ReadExpansionLo = ((ushort addr) => { address = addr; bus = cartPort.ReadLoExp(addr); return bus; });
pla.ReadExRom = (() => { return cartPort.ExRom; });
pla.ReadGame = (() => { return cartPort.Game; });
pla.ReadHiRam = (() => { return cpu.HiRam; });
pla.ReadKernalRom = ((ushort addr) => { address = addr; bus = kernalRom.Read(addr); return bus; });
pla.ReadLoRam = (() => { return cpu.LoRam; });
pla.ReadMemory = ((ushort addr) => { address = addr; bus = ram.Read(addr); return bus; });
pla.ReadSid = ((ushort addr) => { address = addr; bus = sid.Read(addr); return bus; });
pla.ReadVic = ((ushort addr) => { address = addr; bus = vic.Read(addr); return bus; });
pla.WriteCartridgeHi = ((ushort addr, byte val) => { address = addr; bus = val; cartPort.WriteHiRom(addr, val); });
pla.WriteCartridgeLo = ((ushort addr, byte val) => { address = addr; bus = val; cartPort.WriteLoRom(addr, val); });
pla.WriteCia0 = ((ushort addr, byte val) => { address = addr; bus = val; cia0.Write(addr, val); });
pla.WriteCia1 = ((ushort addr, byte val) => { address = addr; bus = val; cia1.Write(addr, val); });
pla.WriteColorRam = ((ushort addr, byte val) => { address = addr; bus = val; colorRam.Write(addr, val); });
pla.WriteExpansionHi = ((ushort addr, byte val) => { address = addr; bus = val; cartPort.WriteHiExp(addr, val); });
pla.WriteExpansionLo = ((ushort addr, byte val) => { address = addr; bus = val; cartPort.WriteLoExp(addr, val); });
pla.WriteMemory = ((ushort addr, byte val) => { address = addr; bus = val; ram.Write(addr, val); });
pla.WriteSid = ((ushort addr, byte val) => { address = addr; bus = val; sid.Write(addr, val); });
pla.WriteVic = ((ushort addr, byte val) => { address = addr; bus = val; vic.Write(addr, val); });
// note: c64 serport lines are inverted
serPort.DeviceReadAtn = (() => { return (cia1DataA & 0x08) == 0; });
serPort.DeviceReadClock = (() => { return (cia1DataA & 0x10) == 0; });
serPort.DeviceReadData = (() => { return (cia1DataA & 0x20) == 0; });
serPort.DeviceReadReset = (() => { return true; }); // this triggers hard reset on ext device when low
serPort.DeviceWriteAtn = ((bool val) => { }); // currently not wired
serPort.DeviceWriteClock = ((bool val) => { cia1DataA = Port.ExternalWrite(cia1DataA, (byte)((cia1DataA & 0xBF) | (val ? 0x00 : 0x40)), cia1DirA); });
serPort.DeviceWriteData = ((bool val) => { cia1DataA = Port.ExternalWrite(cia1DataA, (byte)((cia1DataA & 0x7F) | (val ? 0x00 : 0x80)), cia1DirA); });
serPort.DeviceWriteSrq = ((bool val) => { cia0FlagSerial = val; cia0.FLAG = cia0FlagCassette & cia0FlagSerial; });
sid.ReadPotX = (() => { return 0; });
sid.ReadPotY = (() => { return 0; });
vic.ReadMemory = ((ushort addr) =>
{
addr |= vicBank;
address = addr;
if ((addr & 0x7000) == 0x1000)
bus = charRom.Read(addr);
else
bus = ram.Read(addr);
return bus;
});
vic.ReadColorRam = ((ushort addr) =>
{
address = addr;
bus &= 0xF0;
bus |= colorRam.Read(addr);
return bus;
});
}
public void SyncState(Serializer ser)
{
}
private void UpdateVicBank()
{
switch (cia1DataA & 0x3)
{
case 0: vicBank = 0xC000; break;
case 1: vicBank = 0x8000; break;
case 2: vicBank = 0x4000; break;
default: vicBank = 0x0000; break;
}
}
}
}