552 lines
15 KiB
C#
552 lines
15 KiB
C#
using System;
|
|
|
|
namespace BizHawk.Emulation.Computers.Commodore64.MOS
|
|
{
|
|
// emulates the PLA
|
|
// which handles all bank switching
|
|
|
|
public class MOSPLA
|
|
{
|
|
// ------------------------------------
|
|
|
|
public Func<int, byte> PeekBasicRom;
|
|
public Func<int, byte> PeekCartridgeLo;
|
|
public Func<int, byte> PeekCartridgeHi;
|
|
public Func<int, byte> PeekCharRom;
|
|
public Func<int, byte> PeekCia0;
|
|
public Func<int, byte> PeekCia1;
|
|
public Func<int, byte> PeekColorRam;
|
|
public Func<int, byte> PeekExpansionLo;
|
|
public Func<int, byte> PeekExpansionHi;
|
|
public Func<int, byte> PeekKernalRom;
|
|
public Func<int, byte> PeekMemory;
|
|
public Func<int, byte> PeekSid;
|
|
public Func<int, byte> PeekVic;
|
|
public Action<int, byte> PokeCartridgeLo;
|
|
public Action<int, byte> PokeCartridgeHi;
|
|
public Action<int, byte> PokeCia0;
|
|
public Action<int, byte> PokeCia1;
|
|
public Action<int, byte> PokeColorRam;
|
|
public Action<int, byte> PokeExpansionLo;
|
|
public Action<int, byte> PokeExpansionHi;
|
|
public Action<int, byte> PokeMemory;
|
|
public Action<int, byte> PokeSid;
|
|
public Action<int, byte> PokeVic;
|
|
public Func<ushort, byte> ReadBasicRom;
|
|
public Func<ushort, byte> ReadCartridgeLo;
|
|
public Func<ushort, byte> ReadCartridgeHi;
|
|
public Func<bool> ReadCharen;
|
|
public Func<ushort, byte> ReadCharRom;
|
|
public Func<ushort, byte> ReadCia0;
|
|
public Func<ushort, byte> ReadCia1;
|
|
public Func<ushort, byte> ReadColorRam;
|
|
public Func<ushort, byte> ReadExpansionLo;
|
|
public Func<ushort, byte> ReadExpansionHi;
|
|
public Func<bool> ReadExRom;
|
|
public Func<bool> ReadGame;
|
|
public Func<bool> ReadHiRam;
|
|
public Func<ushort, byte> ReadKernalRom;
|
|
public Func<bool> ReadLoRam;
|
|
public Func<ushort, byte> ReadMemory;
|
|
public Func<ushort, byte> ReadSid;
|
|
public Func<ushort, byte> ReadVic;
|
|
public Action<ushort, byte> WriteCartridgeLo;
|
|
public Action<ushort, byte> WriteCartridgeHi;
|
|
public Action<ushort, byte> WriteCia0;
|
|
public Action<ushort, byte> WriteCia1;
|
|
public Action<ushort, byte> WriteColorRam;
|
|
public Action<ushort, byte> WriteExpansionLo;
|
|
public Action<ushort, byte> WriteExpansionHi;
|
|
public Action<ushort, byte> WriteMemory;
|
|
public Action<ushort, byte> WriteSid;
|
|
public Action<ushort, byte> WriteVic;
|
|
|
|
// ------------------------------------
|
|
|
|
private enum PLABank
|
|
{
|
|
None,
|
|
RAM,
|
|
BasicROM,
|
|
KernalROM,
|
|
CharROM,
|
|
IO,
|
|
CartridgeLo,
|
|
CartridgeHi,
|
|
Vic,
|
|
Sid,
|
|
ColorRam,
|
|
Cia0,
|
|
Cia1,
|
|
Expansion0,
|
|
Expansion1
|
|
}
|
|
|
|
private struct PLACpuMap
|
|
{
|
|
public PLABank layout1000;
|
|
public PLABank layout8000;
|
|
public PLABank layoutA000;
|
|
public PLABank layoutC000;
|
|
public PLABank layoutD000;
|
|
public PLABank layoutE000;
|
|
}
|
|
|
|
// ------------------------------------
|
|
|
|
private PLACpuMap map;
|
|
private bool pinCharenLast;
|
|
private bool pinExRomLast;
|
|
private bool pinGameLast;
|
|
private bool pinHiRamLast;
|
|
private bool pinLoRamLast;
|
|
|
|
public MOSPLA()
|
|
{
|
|
}
|
|
|
|
public void HardReset()
|
|
{
|
|
UpdateMap();
|
|
}
|
|
|
|
// ------------------------------------
|
|
|
|
public void ExecutePhase1()
|
|
{
|
|
UpdatePins();
|
|
}
|
|
|
|
public void ExecutePhase2()
|
|
{
|
|
UpdatePins();
|
|
}
|
|
|
|
public void UpdatePins()
|
|
{
|
|
if ((ReadExRom() != pinExRomLast) || (ReadGame() != pinGameLast) || (ReadLoRam() != pinLoRamLast) || (ReadHiRam() != pinHiRamLast) || (ReadCharen() != pinCharenLast))
|
|
{
|
|
UpdateMap();
|
|
}
|
|
}
|
|
|
|
// ------------------------------------
|
|
|
|
private void UpdateMap()
|
|
{
|
|
bool pinGame = ReadGame();
|
|
bool pinExRom = ReadExRom();
|
|
bool pinCharen = ReadCharen();
|
|
bool pinHiRam = ReadHiRam();
|
|
bool pinLoRam = ReadLoRam();
|
|
|
|
if (pinCharen && pinHiRam && pinLoRam && pinGame && pinExRom)
|
|
{
|
|
// 11111
|
|
map.layout1000 = PLABank.RAM;
|
|
map.layout8000 = PLABank.RAM;
|
|
map.layoutA000 = PLABank.BasicROM;
|
|
map.layoutC000 = PLABank.RAM;
|
|
map.layoutD000 = PLABank.IO;
|
|
map.layoutE000 = PLABank.KernalROM;
|
|
}
|
|
else if (!pinCharen && pinHiRam && pinLoRam && pinGame && pinExRom)
|
|
{
|
|
// 01111
|
|
map.layout1000 = PLABank.RAM;
|
|
map.layout8000 = PLABank.RAM;
|
|
map.layoutA000 = PLABank.BasicROM;
|
|
map.layoutC000 = PLABank.RAM;
|
|
map.layoutD000 = PLABank.CharROM;
|
|
map.layoutE000 = PLABank.KernalROM;
|
|
}
|
|
else if (pinCharen && !pinHiRam && pinLoRam && pinGame)
|
|
{
|
|
// 1011X
|
|
map.layout1000 = PLABank.RAM;
|
|
map.layout8000 = PLABank.RAM;
|
|
map.layoutA000 = PLABank.RAM;
|
|
map.layoutC000 = PLABank.RAM;
|
|
map.layoutD000 = PLABank.IO;
|
|
map.layoutE000 = PLABank.RAM;
|
|
}
|
|
else if (pinCharen && !pinHiRam && pinLoRam && !pinGame && !pinExRom)
|
|
{
|
|
// 10100
|
|
map.layout1000 = PLABank.RAM;
|
|
map.layout8000 = PLABank.RAM;
|
|
map.layoutA000 = PLABank.RAM;
|
|
map.layoutC000 = PLABank.RAM;
|
|
map.layoutD000 = PLABank.IO;
|
|
map.layoutE000 = PLABank.RAM;
|
|
}
|
|
else if (!pinCharen && !pinHiRam && pinLoRam && pinGame)
|
|
{
|
|
// 0011X
|
|
map.layout1000 = PLABank.RAM;
|
|
map.layout8000 = PLABank.RAM;
|
|
map.layoutA000 = PLABank.RAM;
|
|
map.layoutC000 = PLABank.RAM;
|
|
map.layoutD000 = PLABank.CharROM;
|
|
map.layoutE000 = PLABank.RAM;
|
|
}
|
|
else if (!pinCharen && !pinHiRam && pinLoRam && !pinGame && !pinExRom)
|
|
{
|
|
// 00100
|
|
map.layout1000 = PLABank.RAM;
|
|
map.layout8000 = PLABank.RAM;
|
|
map.layoutA000 = PLABank.RAM;
|
|
map.layoutC000 = PLABank.RAM;
|
|
map.layoutD000 = PLABank.RAM;
|
|
map.layoutE000 = PLABank.RAM;
|
|
}
|
|
else if (!pinHiRam && !pinLoRam && pinGame)
|
|
{
|
|
// X001X
|
|
map.layout1000 = PLABank.RAM;
|
|
map.layout8000 = PLABank.RAM;
|
|
map.layoutA000 = PLABank.RAM;
|
|
map.layoutC000 = PLABank.RAM;
|
|
map.layoutD000 = PLABank.RAM;
|
|
map.layoutE000 = PLABank.RAM;
|
|
}
|
|
else if (pinCharen && pinHiRam && !pinLoRam && pinGame)
|
|
{
|
|
// 1101X
|
|
map.layout1000 = PLABank.RAM;
|
|
map.layout8000 = PLABank.RAM;
|
|
map.layoutA000 = PLABank.RAM;
|
|
map.layoutC000 = PLABank.RAM;
|
|
map.layoutD000 = PLABank.IO;
|
|
map.layoutE000 = PLABank.KernalROM;
|
|
}
|
|
else if (pinCharen && !pinHiRam && !pinLoRam && !pinExRom)
|
|
{
|
|
// 100X0
|
|
map.layout1000 = PLABank.RAM;
|
|
map.layout8000 = PLABank.RAM;
|
|
map.layoutA000 = PLABank.RAM;
|
|
map.layoutC000 = PLABank.RAM;
|
|
map.layoutD000 = PLABank.IO;
|
|
map.layoutE000 = PLABank.KernalROM;
|
|
}
|
|
else if (!pinCharen && pinHiRam && !pinLoRam && pinGame)
|
|
{
|
|
// 0101X
|
|
map.layout1000 = PLABank.RAM;
|
|
map.layout8000 = PLABank.RAM;
|
|
map.layoutA000 = PLABank.RAM;
|
|
map.layoutC000 = PLABank.RAM;
|
|
map.layoutD000 = PLABank.CharROM;
|
|
map.layoutE000 = PLABank.KernalROM;
|
|
}
|
|
else if (!pinCharen && !pinHiRam && !pinLoRam && !pinExRom)
|
|
{
|
|
// 000X0
|
|
map.layout1000 = PLABank.RAM;
|
|
map.layout8000 = PLABank.RAM;
|
|
map.layoutA000 = PLABank.RAM;
|
|
map.layoutC000 = PLABank.RAM;
|
|
map.layoutD000 = PLABank.CharROM;
|
|
map.layoutE000 = PLABank.KernalROM;
|
|
}
|
|
else if (pinCharen && pinHiRam && pinLoRam && pinGame && !pinExRom)
|
|
{
|
|
// 11110
|
|
map.layout1000 = PLABank.RAM;
|
|
map.layout8000 = PLABank.CartridgeLo;
|
|
map.layoutA000 = PLABank.BasicROM;
|
|
map.layoutC000 = PLABank.RAM;
|
|
map.layoutD000 = PLABank.IO;
|
|
map.layoutE000 = PLABank.KernalROM;
|
|
}
|
|
else if (!pinCharen && pinHiRam && pinLoRam && pinGame && !pinExRom)
|
|
{
|
|
// 01110
|
|
map.layout1000 = PLABank.RAM;
|
|
map.layout8000 = PLABank.CartridgeLo;
|
|
map.layoutA000 = PLABank.BasicROM;
|
|
map.layoutC000 = PLABank.RAM;
|
|
map.layoutD000 = PLABank.CharROM;
|
|
map.layoutE000 = PLABank.KernalROM;
|
|
}
|
|
else if (pinCharen && pinHiRam && !pinLoRam && !pinGame && !pinExRom)
|
|
{
|
|
// 11000
|
|
map.layout1000 = PLABank.RAM;
|
|
map.layout8000 = PLABank.RAM;
|
|
map.layoutA000 = PLABank.CartridgeHi;
|
|
map.layoutC000 = PLABank.RAM;
|
|
map.layoutD000 = PLABank.IO;
|
|
map.layoutE000 = PLABank.KernalROM;
|
|
}
|
|
else if (!pinCharen && pinHiRam && !pinLoRam && !pinGame && !pinExRom)
|
|
{
|
|
// 01000
|
|
map.layout1000 = PLABank.RAM;
|
|
map.layout8000 = PLABank.RAM;
|
|
map.layoutA000 = PLABank.CartridgeHi;
|
|
map.layoutC000 = PLABank.RAM;
|
|
map.layoutD000 = PLABank.CharROM;
|
|
map.layoutE000 = PLABank.KernalROM;
|
|
}
|
|
else if (pinCharen && pinHiRam && pinLoRam && !pinGame && !pinExRom)
|
|
{
|
|
// 11100
|
|
map.layout1000 = PLABank.RAM;
|
|
map.layout8000 = PLABank.CartridgeLo;
|
|
map.layoutA000 = PLABank.CartridgeHi;
|
|
map.layoutC000 = PLABank.RAM;
|
|
map.layoutD000 = PLABank.IO;
|
|
map.layoutE000 = PLABank.KernalROM;
|
|
}
|
|
else if (!pinCharen && pinHiRam && pinLoRam && !pinGame && !pinExRom)
|
|
{
|
|
// 01100
|
|
map.layout1000 = PLABank.RAM;
|
|
map.layout8000 = PLABank.CartridgeLo;
|
|
map.layoutA000 = PLABank.CartridgeHi;
|
|
map.layoutC000 = PLABank.RAM;
|
|
map.layoutD000 = PLABank.CharROM;
|
|
map.layoutE000 = PLABank.KernalROM;
|
|
}
|
|
else if (!pinGame && pinExRom)
|
|
{
|
|
// XXX01 (ultimax)
|
|
map.layout1000 = PLABank.None;
|
|
map.layout8000 = PLABank.CartridgeLo;
|
|
map.layoutA000 = PLABank.None;
|
|
map.layoutC000 = PLABank.None;
|
|
map.layoutD000 = PLABank.IO;
|
|
map.layoutE000 = PLABank.CartridgeHi;
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("Memory configuration missing from PLA, fix this!");
|
|
}
|
|
|
|
pinExRomLast = pinExRom;
|
|
pinGameLast = pinGame;
|
|
pinLoRamLast = pinLoRam;
|
|
pinHiRamLast = pinHiRam;
|
|
pinCharenLast = pinCharen;
|
|
}
|
|
|
|
// ------------------------------------
|
|
|
|
private PLABank Bank(ushort addr)
|
|
{
|
|
if (addr < 0x1000)
|
|
return PLABank.RAM;
|
|
else if (addr >= 0x1000 && addr < 0x8000)
|
|
return map.layout1000;
|
|
else if (addr >= 0x8000 && addr < 0xA000)
|
|
return map.layout8000;
|
|
else if (addr >= 0xA000 && addr < 0xC000)
|
|
return map.layoutA000;
|
|
else if (addr >= 0xC000 && addr < 0xD000)
|
|
return map.layoutC000;
|
|
else if (addr >= 0xD000 && addr < 0xE000)
|
|
{
|
|
if (map.layoutD000 == PLABank.IO)
|
|
{
|
|
if (addr >= 0xD000 && addr < 0xD400)
|
|
return PLABank.Vic;
|
|
else if (addr >= 0xD400 && addr < 0xD800)
|
|
return PLABank.Sid;
|
|
else if (addr >= 0xD800 && addr < 0xDC00)
|
|
return PLABank.ColorRam;
|
|
else if (addr >= 0xDC00 && addr < 0xDD00)
|
|
return PLABank.Cia0;
|
|
else if (addr >= 0xDD00 && addr < 0xDE00)
|
|
return PLABank.Cia1;
|
|
else if (addr >= 0xDE00 && addr < 0xDF00)
|
|
return PLABank.Expansion0;
|
|
else
|
|
return PLABank.Expansion1;
|
|
}
|
|
else
|
|
{
|
|
return map.layoutD000;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return map.layoutE000;
|
|
}
|
|
}
|
|
|
|
public byte Peek(int addr)
|
|
{
|
|
switch (Bank((ushort)(addr & 0xFFFF)))
|
|
{
|
|
case PLABank.BasicROM:
|
|
return PeekBasicRom(addr);
|
|
case PLABank.CartridgeHi:
|
|
return PeekCartridgeHi(addr);
|
|
case PLABank.CartridgeLo:
|
|
return PeekCartridgeLo(addr);
|
|
case PLABank.CharROM:
|
|
return PeekCharRom(addr);
|
|
case PLABank.Cia0:
|
|
return PeekCia0(addr);
|
|
case PLABank.Cia1:
|
|
return PeekCia1(addr);
|
|
case PLABank.ColorRam:
|
|
return PeekColorRam(addr);
|
|
case PLABank.Expansion0:
|
|
return PeekExpansionLo(addr);
|
|
case PLABank.Expansion1:
|
|
return PeekExpansionHi(addr);
|
|
case PLABank.KernalROM:
|
|
return PeekKernalRom(addr);
|
|
case PLABank.None:
|
|
return 0xFF;
|
|
case PLABank.RAM:
|
|
return PeekMemory(addr);
|
|
case PLABank.Sid:
|
|
return PeekSid(addr);
|
|
case PLABank.Vic:
|
|
return PeekVic(addr);
|
|
}
|
|
return 0xFF;
|
|
}
|
|
|
|
public void Poke(int addr, byte val)
|
|
{
|
|
switch (Bank((ushort)(addr & 0xFFFF)))
|
|
{
|
|
case PLABank.BasicROM:
|
|
break;
|
|
case PLABank.CartridgeHi:
|
|
PokeCartridgeHi(addr, val);
|
|
break;
|
|
case PLABank.CartridgeLo:
|
|
PokeCartridgeLo(addr, val);
|
|
break;
|
|
case PLABank.CharROM:
|
|
break;
|
|
case PLABank.Cia0:
|
|
PokeCia0(addr, val);
|
|
break;
|
|
case PLABank.Cia1:
|
|
PokeCia1(addr, val);
|
|
break;
|
|
case PLABank.ColorRam:
|
|
PokeColorRam(addr, val);
|
|
break;
|
|
case PLABank.Expansion0:
|
|
PokeExpansionLo(addr, val);
|
|
break;
|
|
case PLABank.Expansion1:
|
|
PokeExpansionHi(addr, val);
|
|
break;
|
|
case PLABank.KernalROM:
|
|
break;
|
|
case PLABank.None:
|
|
break;
|
|
case PLABank.RAM:
|
|
PokeMemory(addr, val);
|
|
break;
|
|
case PLABank.Sid:
|
|
PokeSid(addr, val);
|
|
break;
|
|
case PLABank.Vic:
|
|
PokeVic(addr, val);
|
|
break;
|
|
}
|
|
}
|
|
|
|
public byte Read(ushort addr)
|
|
{
|
|
switch (Bank(addr))
|
|
{
|
|
case PLABank.BasicROM:
|
|
return ReadBasicRom(addr);
|
|
case PLABank.CartridgeHi:
|
|
return ReadCartridgeHi(addr);
|
|
case PLABank.CartridgeLo:
|
|
return ReadCartridgeLo(addr);
|
|
case PLABank.CharROM:
|
|
return ReadCharRom(addr);
|
|
case PLABank.Cia0:
|
|
return ReadCia0(addr);
|
|
case PLABank.Cia1:
|
|
return ReadCia1(addr);
|
|
case PLABank.ColorRam:
|
|
return ReadColorRam(addr);
|
|
case PLABank.Expansion0:
|
|
return ReadExpansionLo(addr);
|
|
case PLABank.Expansion1:
|
|
return ReadExpansionHi(addr);
|
|
case PLABank.KernalROM:
|
|
return ReadKernalRom(addr);
|
|
case PLABank.RAM:
|
|
return ReadMemory(addr);
|
|
case PLABank.Sid:
|
|
return ReadSid(addr);
|
|
case PLABank.Vic:
|
|
return ReadVic(addr);
|
|
}
|
|
return 0xFF;
|
|
}
|
|
|
|
public void SyncState(Serializer ser)
|
|
{
|
|
ser.Sync("pinCharenLast", ref pinCharenLast);
|
|
ser.Sync("pinExRomLast", ref pinExRomLast);
|
|
ser.Sync("pinGameLast", ref pinGameLast);
|
|
ser.Sync("pinHiRamLast", ref pinHiRamLast);
|
|
ser.Sync("pinLoRamLast", ref pinLoRamLast);
|
|
|
|
if (ser.IsReader) UpdateMap();
|
|
}
|
|
|
|
public void Write(ushort addr, byte val)
|
|
{
|
|
switch (Bank(addr))
|
|
{
|
|
case PLABank.BasicROM:
|
|
break;
|
|
case PLABank.CartridgeHi:
|
|
WriteCartridgeHi(addr, val);
|
|
break;
|
|
case PLABank.CartridgeLo:
|
|
WriteCartridgeLo(addr, val);
|
|
break;
|
|
case PLABank.CharROM:
|
|
break;
|
|
case PLABank.Cia0:
|
|
WriteCia0(addr, val);
|
|
break;
|
|
case PLABank.Cia1:
|
|
WriteCia1(addr, val);
|
|
break;
|
|
case PLABank.ColorRam:
|
|
WriteColorRam(addr, val);
|
|
break;
|
|
case PLABank.Expansion0:
|
|
WriteExpansionLo(addr, val);
|
|
break;
|
|
case PLABank.Expansion1:
|
|
WriteExpansionHi(addr, val);
|
|
break;
|
|
case PLABank.KernalROM:
|
|
break;
|
|
case PLABank.None:
|
|
break;
|
|
case PLABank.RAM:
|
|
// RAM is written through anyway, don't do it here
|
|
break;
|
|
case PLABank.Sid:
|
|
WriteSid(addr, val);
|
|
break;
|
|
case PLABank.Vic:
|
|
WriteVic(addr, val);
|
|
break;
|
|
}
|
|
WriteMemory(addr, val);
|
|
}
|
|
}
|
|
}
|