Use generic interface type on MOS 6052X for talking to the emulator core (#1189)

* Use generic interface type on MOS 6052X for talking to the emulator core
* Change CpuLink constructors to not use expression-bodies, to get the AppVeyor build to pass.
* Add comment explaining why IMOS6502XLink exists.
This commit is contained in:
Scepheo 2018-05-20 22:18:53 +02:00 committed by feos
parent e650f14d24
commit f3ea6fe025
12 changed files with 383 additions and 309 deletions

View File

@ -1301,6 +1301,7 @@
<Compile Include="CPUs\LR35902\Registers.cs" /> <Compile Include="CPUs\LR35902\Registers.cs" />
<Compile Include="CPUs\LR35902\Tables_Direct.cs" /> <Compile Include="CPUs\LR35902\Tables_Direct.cs" />
<Compile Include="CPUs\LR35902\Tables_Indirect.cs" /> <Compile Include="CPUs\LR35902\Tables_Indirect.cs" />
<Compile Include="CPUs\MOS 6502X\IMOS6502XLink.cs" />
<Compile Include="CPUs\W65816\Disassembler.cs" /> <Compile Include="CPUs\W65816\Disassembler.cs" />
<Compile Include="CPUs\68000\Diassembler.cs" /> <Compile Include="CPUs\68000\Diassembler.cs" />
<Compile Include="CPUs\68000\Instructions\BitArithemetic.cs" /> <Compile Include="CPUs\68000\Instructions\BitArithemetic.cs" />
@ -1441,6 +1442,7 @@
<None Include="Consoles\Nintendo\NES\Docs\BoardTable.xlsx" /> <None Include="Consoles\Nintendo\NES\Docs\BoardTable.xlsx" />
<None Include="Consoles\Nintendo\NES\Docs\MapperCompatibilityList.url" /> <None Include="Consoles\Nintendo\NES\Docs\MapperCompatibilityList.url" />
<None Include="Consoles\Nintendo\NES\Docs\nesasm.pdf" /> <None Include="Consoles\Nintendo\NES\Docs\nesasm.pdf" />
<Compile Include="Consoles\Nintendo\NES\NES.CpuLink.cs" />
<None Include="Resources\128.ROM.gz" /> <None Include="Resources\128.ROM.gz" />
<None Include="Resources\48.ROM.gz" /> <None Include="Resources\48.ROM.gz" />
<None Include="Resources\cgb_boot.bin.gz" /> <None Include="Resources\cgb_boot.bin.gz" />

View File

@ -4,7 +4,7 @@ using System.Collections.Generic;
namespace BizHawk.Emulation.Cores.Components.M6502 namespace BizHawk.Emulation.Cores.Components.M6502
{ {
public partial class MOS6502X : IDisassemblable public partial class MOS6502X<TLink> : IDisassemblable
{ {
private static ushort peeker_word(ushort address, Func<ushort, byte> peeker) private static ushort peeker_word(ushort address, Func<ushort, byte> peeker)
{ {
@ -15,7 +15,43 @@ namespace BizHawk.Emulation.Cores.Components.M6502
public string Disassemble(ushort pc, out int bytesToAdvance) public string Disassemble(ushort pc, out int bytesToAdvance)
{ {
return Disassemble(pc, out bytesToAdvance, PeekMemory); return MOS6502X.Disassemble(pc, out bytesToAdvance, _link.PeekMemory);
}
public string Cpu
{
get
{
return "6502";
}
set
{
}
}
public string PCRegisterName
{
get { return "PC"; }
}
public IEnumerable<string> AvailableCpus
{
get { yield return "6502"; }
}
public string Disassemble(MemoryDomain m, uint addr, out int length)
{
return MOS6502X.Disassemble((ushort)addr, out length, a => m.PeekByte((int)a));
}
}
public static class MOS6502X
{
private static ushort peeker_word(ushort address, Func<ushort, byte> peeker)
{
byte l = peeker(address);
byte h = peeker(++address);
return (ushort)((h << 8) | l);
} }
/// <summary> /// <summary>
@ -208,31 +244,5 @@ namespace BizHawk.Emulation.Cores.Components.M6502
bytesToAdvance = 1; bytesToAdvance = 1;
return "???"; return "???";
} }
public string Cpu
{
get
{
return "6502";
}
set
{
}
}
public string PCRegisterName
{
get { return "PC"; }
}
public IEnumerable<string> AvailableCpus
{
get { yield return "6502"; }
}
public string Disassemble(MemoryDomain m, uint addr, out int length)
{
return Disassemble((ushort)addr, out length, a => m.PeekByte((int)a));
}
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,18 @@
namespace BizHawk.Emulation.Cores.Components.M6502
{
// Interface that has all the methods required by the MOS 6502X to talk to
// the emulator core.
// Should only be used as a generic type argument for the MOS 6502X, and
// implementations should be structs where possible. This combination allows
// the JITer to generate much faster code than calling a Func<> or Action<>.
public interface IMOS6502XLink
{
byte ReadMemory(ushort address);
byte DummyReadMemory(ushort address);
byte PeekMemory(ushort address);
void WriteMemory(ushort address, byte value);
// This only calls when the first byte of an instruction is fetched.
void OnExecFetch(ushort address);
}
}

View File

@ -6,10 +6,13 @@ using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Components.M6502 namespace BizHawk.Emulation.Cores.Components.M6502
{ {
public sealed partial class MOS6502X public sealed partial class MOS6502X<TLink> where TLink : IMOS6502XLink
{ {
public MOS6502X() private readonly TLink _link;
public MOS6502X(TLink link)
{ {
_link = link;
InitOpcodeHandlers(); InitOpcodeHandlers();
Reset(); Reset();
} }
@ -62,7 +65,7 @@ namespace BizHawk.Emulation.Cores.Components.M6502
for (int i = 0; i < length; i++) for (int i = 0; i < length; i++)
{ {
rawbytes += string.Format(" {0:X2}", PeekMemory((ushort)(PC + i))); rawbytes += string.Format(" {0:X2}", _link.PeekMemory((ushort)(PC + i)));
} }
return new TraceInfo return new TraceInfo
@ -206,39 +209,17 @@ namespace BizHawk.Emulation.Cores.Components.M6502
public long TotalExecutedCycles; public long TotalExecutedCycles;
public Func<ushort, byte> ReadMemory;
public Func<ushort, byte> DummyReadMemory;
public Func<ushort, byte> PeekMemory;
public Action<ushort, byte> WriteMemory;
//this only calls when the first byte of an instruction is fetched.
public Action<ushort> OnExecFetch;
public void SetCallbacks
(
Func<ushort, byte> ReadMemory,
Func<ushort, byte> DummyReadMemory,
Func<ushort, byte> PeekMemory,
Action<ushort, byte> WriteMemory
)
{
this.ReadMemory = ReadMemory;
this.DummyReadMemory = DummyReadMemory;
this.PeekMemory = PeekMemory;
this.WriteMemory = WriteMemory;
}
public ushort ReadWord(ushort address) public ushort ReadWord(ushort address)
{ {
byte l = ReadMemory(address); byte l = _link.ReadMemory(address);
byte h = ReadMemory(++address); byte h = _link.ReadMemory(++address);
return (ushort)((h << 8) | l); return (ushort)((h << 8) | l);
} }
public ushort PeekWord(ushort address) public ushort PeekWord(ushort address)
{ {
byte l = PeekMemory(address); byte l = _link.PeekMemory(address);
byte h = PeekMemory(++address); byte h = _link.PeekMemory(++address);
return (ushort)((h << 8) | l); return (ushort)((h << 8) | l);
} }
@ -246,14 +227,14 @@ namespace BizHawk.Emulation.Cores.Components.M6502
{ {
byte l = (byte)(value & 0xFF); byte l = (byte)(value & 0xFF);
byte h = (byte)(value >> 8); byte h = (byte)(value >> 8);
WriteMemory(address, l); _link.WriteMemory(address, l);
WriteMemory(++address, h); _link.WriteMemory(++address, h);
} }
private ushort ReadWordPageWrap(ushort address) private ushort ReadWordPageWrap(ushort address)
{ {
ushort highAddress = (ushort)((address & 0xFF00) + ((address + 1) & 0xFF)); ushort highAddress = (ushort)((address & 0xFF00) + ((address + 1) & 0xFF));
return (ushort)(ReadMemory(address) | (ReadMemory(highAddress) << 8)); return (ushort)(_link.ReadMemory(address) | (_link.ReadMemory(highAddress) << 8));
} }
// SO pin // SO pin

View File

@ -10,11 +10,31 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
public sealed partial class Chip6510 public sealed partial class Chip6510
{ {
// ------------------------------------ // ------------------------------------
private readonly MOS6502X _cpu; private readonly MOS6502X<CpuLink> _cpu;
private bool _pinNmiLast; private bool _pinNmiLast;
private LatchedPort _port; private LatchedPort _port;
private bool _thisNmi; private bool _thisNmi;
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<int, int> PeekMemory; public Func<int, int> PeekMemory;
public Action<int, int> PokeMemory; public Action<int, int> PokeMemory;
public Func<bool> ReadAec; public Func<bool> ReadAec;
@ -33,13 +53,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
public Chip6510() public Chip6510()
{ {
// configure cpu r/w // configure cpu r/w
_cpu = new MOS6502X _cpu = new MOS6502X<CpuLink>(new CpuLink(this));
{
DummyReadMemory = CpuRead,
ReadMemory = CpuRead,
WriteMemory = CpuWrite,
PeekMemory = CpuPeek
};
// perform hard reset // perform hard reset
HardReset(); HardReset();

View File

@ -19,7 +19,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
private bool _motorEnabled; private bool _motorEnabled;
private bool _ledEnabled; private bool _ledEnabled;
private int _motorStep; private int _motorStep;
private readonly MOS6502X _cpu; private readonly MOS6502X<CpuLink> _cpu;
private int[] _ram; private int[] _ram;
public readonly Via Via0; public readonly Via Via0;
public readonly Via Via1; public readonly Via Via1;
@ -31,15 +31,31 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
public Action DebuggerStep; public Action DebuggerStep;
public readonly Chip23128 DriveRom; public readonly Chip23128 DriveRom;
private struct CpuLink : IMOS6502XLink
{
private readonly Drive1541 _drive;
public CpuLink(Drive1541 drive)
{
_drive = drive;
}
public byte DummyReadMemory(ushort address) => unchecked((byte)_drive.Read(address));
public void OnExecFetch(ushort address) { }
public byte PeekMemory(ushort address) => unchecked((byte)_drive.Peek(address));
public byte ReadMemory(ushort address) => unchecked((byte)_drive.Read(address));
public void WriteMemory(ushort address, byte value) => _drive.Write(address, value);
}
public Drive1541(int clockNum, int clockDen) public Drive1541(int clockNum, int clockDen)
{ {
DriveRom = new Chip23128(); DriveRom = new Chip23128();
_cpu = new MOS6502X _cpu = new MOS6502X<CpuLink>(new CpuLink(this))
{ {
ReadMemory = CpuRead,
WriteMemory = CpuWrite,
DummyReadMemory = CpuRead,
PeekMemory = CpuPeek,
NMI = false NMI = false
}; };

View File

@ -28,11 +28,31 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
private bool _leftDifficultySwitchHeld; private bool _leftDifficultySwitchHeld;
private bool _rightDifficultySwitchHeld; private bool _rightDifficultySwitchHeld;
internal MOS6502X Cpu { get; private set; } internal MOS6502X<CpuLink> Cpu { get; private set; }
internal byte[] Ram => _ram; internal byte[] Ram => _ram;
internal byte[] Rom { get; } internal byte[] Rom { get; }
internal int DistinctAccessCount { get; private set; } internal int DistinctAccessCount { get; private set; }
internal struct CpuLink : IMOS6502XLink
{
private readonly Atari2600 _atari2600;
public CpuLink(Atari2600 atari2600)
{
_atari2600 = atari2600;
}
public byte DummyReadMemory(ushort address) => _atari2600.ReadMemory(address);
public void OnExecFetch(ushort address) => _atari2600.ExecFetch(address);
public byte PeekMemory(ushort address) => _atari2600.ReadMemory(address);
public byte ReadMemory(ushort address) => _atari2600.ReadMemory(address);
public void WriteMemory(ushort address, byte value) => _atari2600.WriteMemory(address, value);
}
// keeps track of tia cycles, 3 cycles per CPU cycle // keeps track of tia cycles, 3 cycles per CPU cycle
private int cyc_counter; private int cyc_counter;
@ -292,14 +312,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
_mapper.Core = this; _mapper.Core = this;
_lagcount = 0; _lagcount = 0;
Cpu = new MOS6502X Cpu = new MOS6502X<CpuLink>(new CpuLink(this));
{
ReadMemory = ReadMemory,
WriteMemory = WriteMemory,
PeekMemory = PeekMemory,
DummyReadMemory = ReadMemory,
OnExecFetch = ExecFetch
};
if (_game["PAL"]) if (_game["PAL"])
{ {
@ -334,14 +347,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
_ram = new byte[128]; _ram = new byte[128];
_mapper.HardReset(); _mapper.HardReset();
Cpu = new MOS6502X Cpu = new MOS6502X<CpuLink>(new CpuLink(this));
{
ReadMemory = ReadMemory,
WriteMemory = WriteMemory,
PeekMemory = PeekMemory,
DummyReadMemory = ReadMemory,
OnExecFetch = ExecFetch
};
_tia.Reset(); _tia.Reset();
_m6532 = new M6532(this); _m6532 = new M6532(this);

View File

@ -44,13 +44,33 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
private readonly ITraceable _tracer; private readonly ITraceable _tracer;
public MOS6502X cpu; public MOS6502X<CpuLink> cpu;
public Maria maria; public Maria maria;
public bool _isPAL; public bool _isPAL;
public M6532 m6532; public M6532 m6532;
public TIA tia; public TIA tia;
public Pokey pokey; public Pokey pokey;
public struct CpuLink : IMOS6502XLink
{
private readonly A7800Hawk _a7800;
public CpuLink(A7800Hawk a7800)
{
_a7800 = a7800;
}
public byte DummyReadMemory(ushort address) => _a7800.ReadMemory(address);
public void OnExecFetch(ushort address) => _a7800.ExecFetch(address);
public byte PeekMemory(ushort address) => _a7800.ReadMemory(address);
public byte ReadMemory(ushort address) => _a7800.ReadMemory(address);
public void WriteMemory(ushort address, byte value) => _a7800.WriteMemory(address, value);
}
public A7800Hawk(CoreComm comm, GameInfo game, byte[] rom, string gameDbFn, object settings, object syncSettings) public A7800Hawk(CoreComm comm, GameInfo game, byte[] rom, string gameDbFn, object settings, object syncSettings)
{ {
var ser = new BasicServiceProvider(this); var ser = new BasicServiceProvider(this);
@ -60,14 +80,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
m6532 = new M6532(); m6532 = new M6532();
pokey = new Pokey(); pokey = new Pokey();
cpu = new MOS6502X cpu = new MOS6502X<CpuLink>(new CpuLink(this));
{
ReadMemory = ReadMemory,
WriteMemory = WriteMemory,
PeekMemory = ReadMemory,
DummyReadMemory = ReadMemory,
OnExecFetch = ExecFetch
};
maria = new Maria maria = new Maria
{ {
@ -255,7 +268,6 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
tia.Reset(); tia.Reset();
cpu.Reset(); cpu.Reset();
cpu.SetCallbacks(ReadMemory, ReadMemory, ReadMemory, WriteMemory);
maria.Reset(); maria.Reset();
m6532.Reset(); m6532.Reset();

View File

@ -12,7 +12,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
public partial class NES : IEmulator, ICycleTiming public partial class NES : IEmulator, ICycleTiming
{ {
//hardware/state //hardware/state
public MOS6502X cpu; public MOS6502X<CpuLink> cpu;
public PPU ppu; public PPU ppu;
public APU apu; public APU apu;
public byte[] ram; public byte[] ram;
@ -159,11 +159,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
public void HardReset() public void HardReset()
{ {
cpu = new MOS6502X(); cpu = new MOS6502X<CpuLink>(new CpuLink(this))
cpu.SetCallbacks(ReadMemory, ReadMemory, PeekMemory, WriteMemory); {
BCD_Enabled = false
};
cpu.BCD_Enabled = false;
cpu.OnExecFetch = ExecFetch;
ppu = new PPU(this); ppu = new PPU(this);
ram = new byte[0x800]; ram = new byte[0x800];
CIRAM = new byte[0x800]; CIRAM = new byte[0x800];

View File

@ -0,0 +1,27 @@
using BizHawk.Emulation.Cores.Components.M6502;
namespace BizHawk.Emulation.Cores.Nintendo.NES
{
public partial class NES
{
public struct CpuLink : IMOS6502XLink
{
private readonly NES _nes;
public CpuLink(NES nes)
{
_nes = nes;
}
public byte DummyReadMemory(ushort address) => _nes.ReadMemory(address);
public void OnExecFetch(ushort address) => _nes.ExecFetch(address);
public byte PeekMemory(ushort address) => _nes.CDL == null ? _nes.PeekMemory(address) : _nes.FetchMemory_CDL(address);
public byte ReadMemory(ushort address) => _nes.CDL == null ? _nes.ReadMemory(address) : _nes.ReadMemory_CDL(address);
public void WriteMemory(ushort address, byte value) => _nes.WriteMemory(address, value);
}
}
}

View File

@ -9,18 +9,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
public void SetCDL(ICodeDataLog cdl) public void SetCDL(ICodeDataLog cdl)
{ {
CDL = cdl; CDL = cdl;
if (cdl == null)
{
cpu.ReadMemory = ReadMemory;
cpu.WriteMemory = WriteMemory;
cpu.PeekMemory = PeekMemory;
}
else
{
cpu.ReadMemory = ReadMemory_CDL;
cpu.WriteMemory = WriteMemory;
cpu.PeekMemory = FetchMemory_CDL;
}
} }
public void NewCDL(ICodeDataLog cdl) public void NewCDL(ICodeDataLog cdl)