2012-11-27 05:11:40 +00:00
|
|
|
|
using BizHawk.Emulation.CPUs.M6502;
|
|
|
|
|
using BizHawk.Emulation.Computers.Commodore64.MOS;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
|
|
|
|
namespace BizHawk.Emulation.Computers.Commodore64
|
|
|
|
|
{
|
|
|
|
|
public enum Region
|
|
|
|
|
{
|
|
|
|
|
NTSC,
|
|
|
|
|
PAL
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// emulated chips:
|
|
|
|
|
// U1: 6526 CIA0
|
|
|
|
|
// U2: 6526 CIA1
|
|
|
|
|
// U4: KERNAL & BASIC ROM
|
|
|
|
|
// U5: CHARACTER ROM
|
|
|
|
|
// U6: 6510 CPU
|
|
|
|
|
// U7: VIC 6567 (NTSC) or 6569 (PAL)
|
|
|
|
|
// U8: Memory multiplexer
|
|
|
|
|
// U9: SID 6581 or 8580
|
|
|
|
|
// U10: RAM
|
|
|
|
|
// U11: RAM
|
|
|
|
|
// U19: 2114 color RAM
|
|
|
|
|
|
|
|
|
|
public partial class C64 : IEmulator
|
|
|
|
|
{
|
|
|
|
|
// ------------------------------------
|
|
|
|
|
|
2012-11-28 17:49:42 +00:00
|
|
|
|
private C64Chips chips;
|
|
|
|
|
|
|
|
|
|
// ------------------------------------
|
|
|
|
|
|
|
|
|
|
private bool loadPrg;
|
2012-11-27 05:11:40 +00:00
|
|
|
|
|
|
|
|
|
// ------------------------------------
|
|
|
|
|
|
|
|
|
|
private void Init(Region initRegion)
|
|
|
|
|
{
|
|
|
|
|
chips = new C64Chips(initRegion);
|
|
|
|
|
InitRoms();
|
2012-11-28 03:30:59 +00:00
|
|
|
|
InitMedia();
|
2012-11-27 05:11:40 +00:00
|
|
|
|
|
|
|
|
|
// configure video
|
|
|
|
|
CoreOutputComm.VsyncDen = chips.vic.CyclesPerFrame;
|
|
|
|
|
CoreOutputComm.VsyncNum = chips.vic.CyclesPerSecond;
|
2012-11-28 17:26:40 +00:00
|
|
|
|
|
|
|
|
|
// configure input
|
|
|
|
|
InitInput();
|
2012-11-27 05:11:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-11-28 03:30:59 +00:00
|
|
|
|
private void InitMedia()
|
|
|
|
|
{
|
|
|
|
|
switch (extension.ToUpper())
|
|
|
|
|
{
|
|
|
|
|
case @".CRT":
|
|
|
|
|
Cartridges.Cartridge cart = Cartridges.Cartridge.Load(inputFile);
|
|
|
|
|
if (cart != null)
|
|
|
|
|
{
|
|
|
|
|
chips.cartPort.Connect(cart);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2012-11-28 17:49:42 +00:00
|
|
|
|
case @".PRG":
|
|
|
|
|
if (inputFile.Length > 2)
|
|
|
|
|
loadPrg = true;
|
|
|
|
|
break;
|
2012-11-28 03:30:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-27 05:11:40 +00:00
|
|
|
|
private void InitRoms()
|
|
|
|
|
{
|
|
|
|
|
string sourceFolder = CoreInputComm.C64_FirmwaresPath;
|
|
|
|
|
if (sourceFolder == null)
|
|
|
|
|
sourceFolder = @".\C64\Firmwares";
|
|
|
|
|
|
|
|
|
|
string basicFile = "basic";
|
|
|
|
|
string charFile = "chargen";
|
|
|
|
|
string kernalFile = "kernal";
|
|
|
|
|
|
|
|
|
|
string basicPath = Path.Combine(sourceFolder, basicFile);
|
|
|
|
|
string charPath = Path.Combine(sourceFolder, charFile);
|
|
|
|
|
string kernalPath = Path.Combine(sourceFolder, kernalFile);
|
|
|
|
|
|
|
|
|
|
if (!File.Exists(basicPath)) HandleFirmwareError(basicFile);
|
|
|
|
|
if (!File.Exists(charPath)) HandleFirmwareError(charFile);
|
|
|
|
|
if (!File.Exists(kernalPath)) HandleFirmwareError(kernalFile);
|
|
|
|
|
|
|
|
|
|
byte[] basicRom = File.ReadAllBytes(basicPath);
|
|
|
|
|
byte[] charRom = File.ReadAllBytes(charPath);
|
|
|
|
|
byte[] kernalRom = File.ReadAllBytes(kernalPath);
|
|
|
|
|
|
|
|
|
|
chips.basicRom = new Chip23XX(Chip23XXmodel.Chip2364, basicRom);
|
|
|
|
|
chips.kernalRom = new Chip23XX(Chip23XXmodel.Chip2364, kernalRom);
|
|
|
|
|
chips.charRom = new Chip23XX(Chip23XXmodel.Chip2332, charRom);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ------------------------------------
|
|
|
|
|
|
|
|
|
|
public bool DriveLED
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Execute(uint count)
|
|
|
|
|
{
|
|
|
|
|
for (; count > 0; count--)
|
|
|
|
|
{
|
2012-11-28 17:26:40 +00:00
|
|
|
|
WriteInputPort();
|
2012-11-27 05:11:40 +00:00
|
|
|
|
chips.ExecutePhase1();
|
|
|
|
|
chips.ExecutePhase2();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void HardReset()
|
|
|
|
|
{
|
|
|
|
|
chips.HardReset();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ------------------------------------
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class C64Chips
|
|
|
|
|
{
|
|
|
|
|
public Chip23XX basicRom; //u4
|
2012-11-28 03:30:59 +00:00
|
|
|
|
public CartridgePort cartPort; //cn6
|
2012-11-27 05:11:40 +00:00
|
|
|
|
public Chip23XX charRom; //u5
|
|
|
|
|
public MOS6526 cia0; //u1
|
|
|
|
|
public MOS6526 cia1; //u2
|
|
|
|
|
public Chip2114 colorRam; //u19
|
|
|
|
|
public MOS6510 cpu; //u6
|
|
|
|
|
public Chip23XX kernalRom; //u4
|
2012-11-27 20:47:03 +00:00
|
|
|
|
public MOSPLA pla;
|
2012-11-27 05:11:40 +00:00
|
|
|
|
public Chip4864 ram; //u10+11
|
|
|
|
|
public Sid sid; //u9
|
2012-11-28 03:30:59 +00:00
|
|
|
|
public UserPort userPort; //cn2 (probably won't be needed for games)
|
2012-11-27 05:11:40 +00:00
|
|
|
|
public Vic vic; //u7
|
|
|
|
|
|
|
|
|
|
public C64Chips(Region initRegion)
|
|
|
|
|
{
|
2012-11-28 03:30:59 +00:00
|
|
|
|
cartPort = new CartridgePort();
|
2012-11-27 05:11:40 +00:00
|
|
|
|
cia0 = new MOS6526(initRegion);
|
|
|
|
|
cia1 = new MOS6526(initRegion);
|
2012-11-29 02:46:35 +00:00
|
|
|
|
pla = new MOSPLA(this);
|
2012-11-27 05:11:40 +00:00
|
|
|
|
switch (initRegion)
|
|
|
|
|
{
|
|
|
|
|
case Region.NTSC:
|
|
|
|
|
vic = new MOS6567(this);
|
|
|
|
|
break;
|
|
|
|
|
case Region.PAL:
|
|
|
|
|
vic = new MOS6569(this);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
colorRam = new Chip2114();
|
|
|
|
|
cpu = new MOS6510(this);
|
|
|
|
|
ram = new Chip4864();
|
|
|
|
|
sid = new MOS6581();
|
2012-11-30 21:12:23 +00:00
|
|
|
|
pla.UpdatePins();
|
2012-11-27 05:11:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void ExecutePhase1()
|
|
|
|
|
{
|
2012-11-30 21:12:23 +00:00
|
|
|
|
pla.ExecutePhase1();
|
2012-11-27 05:11:40 +00:00
|
|
|
|
cia0.ExecutePhase1();
|
|
|
|
|
cia1.ExecutePhase1();
|
|
|
|
|
sid.ExecutePhase1();
|
|
|
|
|
vic.ExecutePhase1();
|
|
|
|
|
cpu.ExecutePhase1();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void ExecutePhase2()
|
|
|
|
|
{
|
2012-11-30 21:12:23 +00:00
|
|
|
|
pla.ExecutePhase2();
|
2012-11-27 05:11:40 +00:00
|
|
|
|
cia0.ExecutePhase2();
|
|
|
|
|
cia1.ExecutePhase2();
|
|
|
|
|
sid.ExecutePhase2();
|
|
|
|
|
vic.ExecutePhase2();
|
|
|
|
|
cpu.ExecutePhase2();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void HardReset()
|
|
|
|
|
{
|
|
|
|
|
// note about hard reset: NOT identical to cold start
|
|
|
|
|
|
|
|
|
|
// reset all chips
|
|
|
|
|
cia0.HardReset();
|
|
|
|
|
cia1.HardReset();
|
|
|
|
|
colorRam.HardReset();
|
|
|
|
|
cpu.HardReset();
|
|
|
|
|
pla.HardReset();
|
|
|
|
|
ram.HardReset();
|
|
|
|
|
sid.HardReset();
|
|
|
|
|
vic.HardReset();
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-11-30 21:12:23 +00:00
|
|
|
|
|
|
|
|
|
static public class C64Util
|
|
|
|
|
{
|
|
|
|
|
static public string ToBinary(uint n, uint charsmin)
|
|
|
|
|
{
|
|
|
|
|
string result = "";
|
|
|
|
|
|
|
|
|
|
while (n > 0 || charsmin > 0)
|
|
|
|
|
{
|
|
|
|
|
result = (((n & 0x1) != 0) ? "1" : "0") + result;
|
|
|
|
|
n >>= 1;
|
|
|
|
|
if (charsmin > 0)
|
|
|
|
|
charsmin--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static public string ToHex(uint n, uint charsmin)
|
|
|
|
|
{
|
|
|
|
|
string result = "";
|
|
|
|
|
|
|
|
|
|
while (n > 0 || charsmin > 0)
|
|
|
|
|
{
|
|
|
|
|
result = "0123456789ABCDEF".Substring((int)(n & 0xF), 1) + result;
|
|
|
|
|
n >>= 4;
|
|
|
|
|
if (charsmin > 0)
|
|
|
|
|
charsmin--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-11-27 05:11:40 +00:00
|
|
|
|
}
|