using System; using BizHawk.Common; using BizHawk.Emulation.Common; using BizHawk.Emulation.Cores.Components.M6502; namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS { // an extension of the 6502 processor public sealed partial class Chip6510 { // ------------------------------------ private readonly MOS6502X _cpu; private LatchedPort _port; private int _irqDelay; private int _nmiDelay; private struct CpuLink : IMOS6502XLink { private readonly Chip6510 _chip; public CpuLink(Chip6510 chip) { _chip = chip; } public byte DummyReadMemory(ushort address) => unchecked((byte)_chip.Read(address)); public void OnExecFetch(ushort address) { } public byte PeekMemory(ushort address) => unchecked((byte)_chip.Peek(address)); public byte ReadMemory(ushort address) => unchecked((byte)_chip.Read(address)); public void WriteMemory(ushort address, byte value) => _chip.Write(address, value); } public Func PeekMemory; public Action PokeMemory; public Func ReadAec; public Func ReadIrq; public Func ReadNmi; public Func ReadRdy; public Func ReadBus; public Func ReadMemory; public Func ReadPort; public Action WriteMemory; public Action WriteMemoryPort; public Action DebuggerStep; public Chip6510() { // configure cpu r/w _cpu = new MOS6502X(new CpuLink(this)); // perform hard reset HardReset(); } public string TraceHeader => "6510: PC, machine code, mnemonic, operands, registers (A, X, Y, P, SP), flags (NVTBDIZCR)"; public Action TraceCallback { get { return _cpu.TraceCallback; } set { _cpu.TraceCallback = value; } } public void HardReset() { _cpu.NESSoftReset(); _port = new LatchedPort { Direction = 0x00, Latch = 0xFF }; } public void SoftReset() { _cpu.NESSoftReset(); _port.Direction = 0x00; _port.Latch = 0xFF; } public void ExecutePhase() { _irqDelay >>= 1; _nmiDelay >>= 1; _irqDelay |= ReadIrq() ? 0x0 : 0x2; _nmiDelay |= ReadNmi() ? 0x0 : 0x2; _cpu.RDY = ReadRdy(); _cpu.IRQ = (_irqDelay & 1) != 0; _cpu.NMI |= (_nmiDelay & 3) == 2; _cpu.ExecuteOne(); } public int Peek(int addr) { switch (addr) { case 0x0000: return _port.Direction; case 0x0001: return PortData; default: return PeekMemory(addr); } } public void Poke(int addr, int val) { switch (addr) { case 0x0000: _port.Direction = val; break; case 0x0001: _port.Latch = val; break; default: PokeMemory(addr, val); break; } } public int PortData => _port.ReadInput(ReadPort()); public int Read(int addr) { switch (addr) { case 0x0000: return _port.Direction; case 0x0001: return PortData; default: if (ReadAec()) return ReadMemory(addr); else return ReadBus(); } } public void SyncState(Serializer ser) { ser.BeginSection("Chip6510Cpu"); _cpu.SyncState(ser); ser.EndSection(); ser.BeginSection(nameof(_port)); _port.SyncState(ser); ser.EndSection(); ser.Sync(nameof(_irqDelay), ref _irqDelay); ser.Sync(nameof(_nmiDelay), ref _nmiDelay); } public void Write(int addr, int val) { switch (addr) { case 0x0000: _port.Direction = val; WriteMemoryPort(addr); break; case 0x0001: _port.Latch = val; WriteMemoryPort(addr); break; default: if (ReadAec()) WriteMemory(addr, val); break; } } } }