2016-02-22 23:50:11 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
|
|
|
|
|
using BizHawk.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
|
|
|
|
|
{
|
|
|
|
|
// ------------------------------------
|
|
|
|
|
|
2017-04-24 13:35:05 +00:00
|
|
|
|
private MOS6502X _cpu;
|
|
|
|
|
private bool _pinNmiLast;
|
|
|
|
|
private LatchedPort _port;
|
|
|
|
|
private bool _thisNmi;
|
2016-02-22 23:50:11 +00:00
|
|
|
|
|
|
|
|
|
public Func<int, int> PeekMemory;
|
|
|
|
|
public Action<int, int> PokeMemory;
|
|
|
|
|
public Func<bool> ReadAec;
|
|
|
|
|
public Func<bool> ReadIrq;
|
|
|
|
|
public Func<bool> ReadNmi;
|
|
|
|
|
public Func<bool> ReadRdy;
|
|
|
|
|
public Func<int, int> ReadMemory;
|
|
|
|
|
public Func<int> ReadPort;
|
|
|
|
|
public Action<int, int> WriteMemory;
|
|
|
|
|
public Action<int, int> WriteMemoryPort;
|
|
|
|
|
|
2017-04-24 13:35:05 +00:00
|
|
|
|
public Action DebuggerStep;
|
2016-02-22 23:50:11 +00:00
|
|
|
|
|
|
|
|
|
// ------------------------------------
|
|
|
|
|
|
|
|
|
|
public Chip6510()
|
|
|
|
|
{
|
2017-04-24 13:35:05 +00:00
|
|
|
|
// configure cpu r/w
|
|
|
|
|
_cpu = new MOS6502X
|
|
|
|
|
{
|
|
|
|
|
DummyReadMemory = CpuRead,
|
|
|
|
|
ReadMemory = CpuRead,
|
|
|
|
|
WriteMemory = CpuWrite,
|
|
|
|
|
PeekMemory = CpuPeek
|
|
|
|
|
};
|
2016-02-22 23:50:11 +00:00
|
|
|
|
|
2017-04-24 13:35:05 +00:00
|
|
|
|
// perform hard reset
|
2016-02-22 23:50:11 +00:00
|
|
|
|
HardReset();
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-24 13:35:05 +00:00
|
|
|
|
public void SetOverflow()
|
|
|
|
|
{
|
|
|
|
|
}
|
2016-02-22 23:50:11 +00:00
|
|
|
|
|
2017-04-24 13:35:05 +00:00
|
|
|
|
private byte CpuPeek(ushort addr)
|
|
|
|
|
{
|
|
|
|
|
return unchecked((byte)Peek(addr));
|
|
|
|
|
}
|
2016-02-22 23:50:11 +00:00
|
|
|
|
|
2017-04-24 13:35:05 +00:00
|
|
|
|
private byte CpuRead(ushort addr)
|
|
|
|
|
{
|
|
|
|
|
return unchecked((byte)Read(addr));
|
|
|
|
|
}
|
2016-02-22 23:50:11 +00:00
|
|
|
|
|
2017-04-24 13:35:05 +00:00
|
|
|
|
private void CpuWrite(ushort addr, byte val)
|
|
|
|
|
{
|
|
|
|
|
Write(addr, val);
|
|
|
|
|
}
|
2016-02-22 23:50:11 +00:00
|
|
|
|
|
|
|
|
|
public void HardReset()
|
|
|
|
|
{
|
|
|
|
|
_cpu.NESSoftReset();
|
2017-04-24 13:35:05 +00:00
|
|
|
|
_port = new LatchedPort
|
|
|
|
|
{
|
|
|
|
|
Direction = 0x00,
|
|
|
|
|
Latch = 0xFF
|
|
|
|
|
};
|
2016-02-22 23:50:11 +00:00
|
|
|
|
_pinNmiLast = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ------------------------------------
|
|
|
|
|
|
|
|
|
|
public void ExecutePhase()
|
|
|
|
|
{
|
2017-04-24 13:35:05 +00:00
|
|
|
|
_cpu.RDY = ReadRdy();
|
2016-02-22 23:50:11 +00:00
|
|
|
|
|
2017-04-24 13:35:05 +00:00
|
|
|
|
if (ReadAec())
|
|
|
|
|
{
|
|
|
|
|
_cpu.IRQ = !ReadIrq();
|
|
|
|
|
_pinNmiLast = _thisNmi;
|
|
|
|
|
_thisNmi = ReadNmi();
|
|
|
|
|
_cpu.NMI |= _pinNmiLast && !_thisNmi;
|
|
|
|
|
_cpu.ExecuteOne();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
LagCycles++;
|
|
|
|
|
}
|
2016-02-22 23:50:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-24 13:35:05 +00:00
|
|
|
|
public int LagCycles;
|
2016-02-22 23:50:11 +00:00
|
|
|
|
|
2017-04-24 13:35:05 +00:00
|
|
|
|
internal bool AtInstructionStart()
|
2016-02-22 23:50:11 +00:00
|
|
|
|
{
|
|
|
|
|
return _cpu.AtInstructionStart();
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-24 13:35:05 +00:00
|
|
|
|
// ------------------------------------
|
2016-02-22 23:50:11 +00:00
|
|
|
|
|
2017-04-24 13:35:05 +00:00
|
|
|
|
[SaveState.DoNotSave]
|
|
|
|
|
public ushort Pc
|
2016-02-22 23:50:11 +00:00
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return _cpu.PC;
|
|
|
|
|
}
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_cpu.PC = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-24 13:35:05 +00:00
|
|
|
|
[SaveState.DoNotSave]
|
|
|
|
|
public int A
|
2016-02-22 23:50:11 +00:00
|
|
|
|
{
|
2017-04-24 13:35:05 +00:00
|
|
|
|
get { return _cpu.A; }
|
|
|
|
|
set { _cpu.A = unchecked((byte)value); }
|
2016-02-22 23:50:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-24 13:35:05 +00:00
|
|
|
|
[SaveState.DoNotSave]
|
|
|
|
|
public int X
|
2016-02-22 23:50:11 +00:00
|
|
|
|
{
|
2017-04-24 13:35:05 +00:00
|
|
|
|
get { return _cpu.X; }
|
|
|
|
|
set { _cpu.X = unchecked((byte)value); }
|
2016-02-22 23:50:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-24 13:35:05 +00:00
|
|
|
|
[SaveState.DoNotSave]
|
|
|
|
|
public int Y
|
2016-02-22 23:50:11 +00:00
|
|
|
|
{
|
2017-04-24 13:35:05 +00:00
|
|
|
|
get { return _cpu.Y; }
|
|
|
|
|
set { _cpu.Y = unchecked((byte)value); }
|
2016-02-22 23:50:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-24 13:35:05 +00:00
|
|
|
|
[SaveState.DoNotSave]
|
|
|
|
|
public int S
|
2016-02-22 23:50:11 +00:00
|
|
|
|
{
|
2017-04-24 13:35:05 +00:00
|
|
|
|
get { return _cpu.S; }
|
|
|
|
|
set { _cpu.S = unchecked((byte)value); }
|
2016-02-22 23:50:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-24 13:35:05 +00:00
|
|
|
|
[SaveState.DoNotSave]
|
|
|
|
|
public bool FlagC { get { return _cpu.FlagC; } }
|
|
|
|
|
[SaveState.DoNotSave]
|
|
|
|
|
public bool FlagZ { get { return _cpu.FlagZ; } }
|
|
|
|
|
[SaveState.DoNotSave]
|
|
|
|
|
public bool FlagI { get { return _cpu.FlagI; } }
|
|
|
|
|
[SaveState.DoNotSave]
|
|
|
|
|
public bool FlagD { get { return _cpu.FlagD; } }
|
|
|
|
|
[SaveState.DoNotSave]
|
|
|
|
|
public bool FlagB { get { return _cpu.FlagB; } }
|
|
|
|
|
[SaveState.DoNotSave]
|
|
|
|
|
public bool FlagV { get { return _cpu.FlagV; } }
|
|
|
|
|
[SaveState.DoNotSave]
|
|
|
|
|
public bool FlagN { get { return _cpu.FlagN; } }
|
|
|
|
|
[SaveState.DoNotSave]
|
|
|
|
|
public bool FlagT { get { return _cpu.FlagT; } }
|
2016-02-22 23:50:11 +00:00
|
|
|
|
|
|
|
|
|
public int Peek(int addr)
|
|
|
|
|
{
|
2017-04-24 13:35:05 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SaveState.DoNotSave]
|
|
|
|
|
public int PortData
|
2016-02-22 23:50:11 +00:00
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return _port.ReadInput(ReadPort());
|
|
|
|
|
}
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_port.Latch = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int Read(int addr)
|
|
|
|
|
{
|
2017-04-24 13:35:05 +00:00
|
|
|
|
switch (addr)
|
|
|
|
|
{
|
|
|
|
|
case 0x0000:
|
|
|
|
|
return _port.Direction;
|
|
|
|
|
case 0x0001:
|
|
|
|
|
return PortData;
|
|
|
|
|
default:
|
|
|
|
|
return ReadMemory(addr);
|
|
|
|
|
}
|
2016-02-22 23:50:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-24 13:35:05 +00:00
|
|
|
|
public void SyncState(Serializer ser)
|
2016-02-22 23:50:11 +00:00
|
|
|
|
{
|
|
|
|
|
SaveState.SyncObject(ser, this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Write(int addr, int val)
|
|
|
|
|
{
|
2017-04-24 13:35:05 +00:00
|
|
|
|
switch (addr)
|
|
|
|
|
{
|
|
|
|
|
case 0x0000:
|
|
|
|
|
_port.Direction = val;
|
|
|
|
|
WriteMemoryPort(addr, val);
|
|
|
|
|
break;
|
|
|
|
|
case 0x0001:
|
|
|
|
|
_port.Latch = val;
|
|
|
|
|
WriteMemoryPort(addr, val);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
WriteMemory(addr, val);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-02-22 23:50:11 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|