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

202 lines
5.3 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using BizHawk.Emulation.CPUs.M6502;
namespace BizHawk.Emulation.Computers.Commodore64
{
public enum Region
{
NTSC,
PAL
}
public partial class C64 : IEmulator
{
// input
public Input input;
// source
public Cartridge cart = null;
public Drive1541 diskDrive = null;
public bool diskDriveAttached = false;
public string extension;
public byte[] inputFile;
public List<IMedia> mediaAttached = new List<IMedia>();
// chipset
public Cia cia0;
public Cia cia1;
public MOS6502X cpu;
public Memory mem;
public Sid sid;
public VicII vic;
public ChipSignals signal;
// cpu
private bool haltCPU;
public bool DriveLED
{
get
{
if (diskDriveAttached)
{
return (diskDrive.Peek(0x1C00) & 0x8) != 0;
}
else
{
return false;
}
}
}
public void HardReset()
{
mem.HardReset();
cia0.HardReset();
cia1.HardReset();
vic.HardReset();
sid.HardReset();
if (diskDriveAttached)
diskDrive.HardReset();
}
private void Init(Region initRegion)
{
// initalize cpu
cpu = new MOS6502X();
cpu.ReadMemory = ReadMemoryCPU;
cpu.WriteMemory = WriteMemory;
cpu.DummyReadMemory = PeekMemory;
// initialize cia timers
cia0 = new Cia(initRegion);
cia1 = new Cia(initRegion);
// initialize vic
signal = new ChipSignals();
vic = new VicII(signal, initRegion);
// set vsync rate
switch (initRegion)
{
case Region.NTSC:
CoreOutputComm.VsyncDen = vic.CyclesPerFrame * 14;
CoreOutputComm.VsyncNum = 14318181;
break;
case Region.PAL:
CoreOutputComm.VsyncDen = vic.CyclesPerFrame * 18;
CoreOutputComm.VsyncNum = 17734472;
break;
}
// initialize sid
sid = new Sid(initRegion, 44100); // we'll assume 44.1k for now until there's a better way
// initialize memory (this must be done AFTER all other chips are initialized)
string romPath = CoreInputComm.C64_FirmwaresPath;
if (romPath == null)
{
romPath = @".\C64\Firmwares";
}
mem = new Memory(romPath, vic, sid, cia0, cia1);
vic.mem = mem;
// initialize cpu hard reset vector
cpu.PC = (ushort)(ReadMemory(0xFFFC) + (ReadMemory(0xFFFD) << 8));
cpu.BCD_Enabled = true;
// initailize input
input = new Input(new DataPortConnector[] { cia0.ConnectPort(0), cia0.ConnectPort(1) });
cia0.AttachWriteHook(0, input.WritePortA);
cia0.AttachWriteHook(1, input.WritePortB);
// initialize media
switch (extension.ToUpper())
{
case @".G64":
diskDrive = new Drive1541(File.ReadAllBytes(Path.Combine(romPath, @"dos1541")), initRegion, cia1);
diskDrive.Insert(G64.Read(inputFile));
break;
case @".D64":
diskDrive = new Drive1541(File.ReadAllBytes(Path.Combine(romPath, @"dos1541")), initRegion, cia1);
diskDrive.Insert(D64.Read(inputFile));
break;
case @".PRG":
if (inputFile.Length > 2)
mediaAttached.Add(new PRGFile(inputFile, mem, cpu));
break;
case @".CRT":
Cartridge newCart = new Cartridge(inputFile, mem);
if (newCart.valid)
{
cart = newCart;
mediaAttached.Add(cart);
}
break;
}
diskDriveAttached = (diskDrive != null);
}
public void PollInput()
{
input.Poll();
signal.KeyboardNMI = input.restorePressed;
}
public byte ReadMemory(ushort addr)
{
return mem.Read(addr);
}
private byte ReadMemoryCPU(ushort addr)
{
if (!signal.CpuRDY || !signal.CpuAEC)
haltCPU = true;
return mem.Read(addr);
}
public void WriteMemory(ushort addr, byte value)
{
mem.Write(addr, value);
}
public void WriteMemoryCPU(ushort addr, byte value)
{
if (!signal.CpuAEC)
haltCPU = true;
mem.Write(addr, value);
}
}
public class ChipSignals
{
private bool[] _CiaSerialInput = new bool[2];
private bool[] _CiaIRQOutput = new bool[2];
private bool _KeyboardNMIOutput;
private bool _VicAECOutput;
private bool _VicBAOutput;
private bool _VicIRQOutput;
private bool _VicLPInput;
public bool CiaIRQ0 { get { return _CiaIRQOutput[0]; } set { _CiaIRQOutput[0] = value; } }
public bool CiaIRQ1 { get { return _CiaIRQOutput[1]; } set { _CiaIRQOutput[1] = value; } }
public bool CiaSerial0 { get { return _CiaSerialInput[0]; } }
public bool CiaSerial1 { get { return _CiaSerialInput[1]; } }
public bool CpuAEC { get { return _VicAECOutput; } }
public bool CpuIRQ { get { return _VicIRQOutput | _CiaIRQOutput[0]; } }
public bool CpuNMI { get { return _CiaIRQOutput[1] | _KeyboardNMIOutput; } }
public bool CpuRDY { get { return !_VicBAOutput; } }
public bool KeyboardNMI { get { return _KeyboardNMIOutput; } set { _KeyboardNMIOutput = value; } }
public bool LPOutput { get { return _VicLPInput; } set { _VicLPInput = value; } }
public bool VicAEC { get { return _VicAECOutput; } set { _VicAECOutput = value; } }
public bool VicBA { get { return _VicBAOutput; } set { _VicBAOutput = value; } }
public bool VicIRQ { get { return _VicIRQOutput; } set { _VicIRQOutput = value; } }
public bool VicLP { get { return _VicLPInput; } }
}
}