Make Register16 a class, rather than struct. Tricky, but a bit faster than before.

Signed-off-by: Adrian Conlon <Adrian.conlon@gmail.com>
This commit is contained in:
Adrian Conlon 2019-02-21 19:58:49 +00:00
parent b7fbb80018
commit 27e1c5c9f8
15 changed files with 502 additions and 472 deletions

View File

@ -33,7 +33,7 @@ namespace EightBit
protected override Register16 GetWord()
{
var high = this.BusRead();
++this.Bus.Address();
++this.Bus.Address.Word;
var low = this.BusRead();
return new Register16(low, high);
}
@ -61,7 +61,7 @@ namespace EightBit
protected override void SetWord(Register16 value)
{
this.BusWrite(value.High);
++this.Bus.Address();
++this.Bus.Address.Word;
this.BusWrite(value.Low);
}

View File

@ -8,7 +8,6 @@ namespace EightBit
public abstract class Bus : IMapper
{
private Register16 address;
private byte data;
public event EventHandler<EventArgs> WritingByte;
@ -21,7 +20,7 @@ namespace EightBit
public byte Data { get => this.data; set => this.data = value; }
public ref Register16 Address() => ref this.address;
public Register16 Address { get; } = new Register16();
public abstract MemoryMapping Mapping(ushort absolute);
@ -51,7 +50,7 @@ namespace EightBit
public byte Read(ushort absolute)
{
this.Address().Word = absolute;
this.Address.Word = absolute;
return this.Read();
}
@ -59,8 +58,8 @@ namespace EightBit
public byte Read(byte low, byte high)
{
this.Address().Low = low;
this.Address().High = high;
this.Address.Low = low;
this.Address.High = high;
return this.Read();
}
@ -79,7 +78,7 @@ namespace EightBit
public void Write(ushort absolute, byte value)
{
this.Address().Word = absolute;
this.Address.Word = absolute;
this.Write(value);
}
@ -87,8 +86,8 @@ namespace EightBit
public void Write(byte low, byte high, byte value)
{
this.Address().Low = low;
this.Address().High = high;
this.Address.Low = low;
this.Address.High = high;
this.Write(value);
}
@ -125,7 +124,7 @@ namespace EightBit
protected ref byte Reference(Register16 absolute) => ref this.Reference(absolute.Word);
protected ref byte Reference() => ref this.Reference(this.Address());
protected ref byte Reference() => ref this.Reference(this.Address);
protected ref byte Reference(byte low, byte high) => ref this.Reference(new Register16(low, high).Word);

View File

@ -13,10 +13,6 @@ namespace EightBit
private readonly IntelOpCodeDecoded[] decodedOpCodes = new IntelOpCodeDecoded[0x100];
private Register16 sp = new Register16((ushort)Mask.Mask16);
private Register16 memptr = new Register16((ushort)Mask.Mask16);
private PinLevel haltLine;
protected IntelProcessor(Bus bus)
@ -36,36 +32,36 @@ namespace EightBit
public event EventHandler<EventArgs> LoweredHALT;
public Register16 SP { get; } = new Register16((ushort)Mask.Mask16);
public Register16 MEMPTR { get; } = new Register16((ushort)Mask.Mask16);
public abstract Register16 AF { get; }
public byte A { get => this.AF.High; set => this.AF.High = value; }
public byte F { get => this.AF.Low; set => this.AF.Low = value; }
public abstract Register16 BC { get; }
public byte B { get => this.BC.High; set => this.BC.High = value; }
public byte C { get => this.BC.Low; set => this.BC.Low = value; }
public abstract Register16 DE { get; }
public byte D { get => this.DE.High; set => this.DE.High = value; }
public byte E { get => this.DE.Low; set => this.DE.Low = value; }
public abstract Register16 HL { get; }
public byte H { get => this.HL.High; set => this.HL.High = value; }
public byte L { get => this.HL.Low; set => this.HL.Low = value; }
protected bool Halted => this.HALT().Lowered();
public ref Register16 SP() => ref this.sp;
public ref Register16 MEMPTR() => ref this.memptr;
public abstract ref Register16 AF();
public ref byte A() => ref this.AF().High;
public ref byte F() => ref this.AF().Low;
public abstract ref Register16 BC();
public ref byte B() => ref this.BC().High;
public ref byte C() => ref this.BC().Low;
public abstract ref Register16 DE();
public ref byte D() => ref this.DE().High;
public ref byte E() => ref this.DE().Low;
public abstract ref Register16 HL();
public ref byte H() => ref this.HL().High;
public ref byte L() => ref this.HL().Low;
public ref PinLevel HALT() => ref this.haltLine;
public IntelOpCodeDecoded GetDecodedOpCode(byte opCode) => this.decodedOpCodes[opCode];
@ -74,7 +70,7 @@ namespace EightBit
{
base.RaisePOWER();
this.RaiseHALT();
this.SP().Word = this.AF().Word = this.BC().Word = this.DE().Word = this.HL().Word = (ushort)Mask.Mask16;
this.SP.Word = this.AF.Word = this.BC.Word = this.DE.Word = this.HL.Word = (ushort)Mask.Mask16;
}
public virtual void RaiseHALT()
@ -122,38 +118,38 @@ namespace EightBit
this.Jump(0);
}
protected sealed override void Push(byte value) => this.Bus.Write(--this.SP(), value);
protected sealed override void Push(byte value) => this.Bus.Write(--this.SP.Word, value);
protected sealed override byte Pop() => this.Bus.Read(this.SP()++);
protected sealed override byte Pop() => this.Bus.Read(this.SP.Word++);
protected sealed override Register16 GetWord()
{
var returned = base.GetWord();
this.MEMPTR().Word = this.Bus.Address().Word;
this.MEMPTR.Word = this.Bus.Address.Word;
return returned;
}
protected sealed override void SetWord(Register16 value)
{
base.SetWord(value);
this.MEMPTR().Word = this.Bus.Address().Word;
this.MEMPTR.Word = this.Bus.Address.Word;
}
////
protected void Restart(byte address)
{
this.MEMPTR().Low = address;
this.MEMPTR().High = 0;
this.Call(this.MEMPTR());
this.MEMPTR.Low = address;
this.MEMPTR.High = 0;
this.Call(this.MEMPTR);
}
protected bool CallConditional(bool condition)
{
this.MEMPTR().Word = this.FetchWord().Word;
this.MEMPTR.Word = this.FetchWord().Word;
if (condition)
{
this.Call(this.MEMPTR());
this.Call(this.MEMPTR);
}
return condition;
@ -161,10 +157,10 @@ namespace EightBit
protected bool JumpConditional(bool condition)
{
this.MEMPTR().Word = this.FetchWord().Word;
this.MEMPTR.Word = this.FetchWord().Word;
if (condition)
{
this.Jump(this.MEMPTR());
this.Jump(this.MEMPTR);
}
return condition;
@ -182,8 +178,8 @@ namespace EightBit
protected void JumpRelative(sbyte offset)
{
this.MEMPTR().Word = (ushort)(this.PC().Word + offset);
this.Jump(this.MEMPTR());
this.MEMPTR.Word = (ushort)(this.PC.Word + offset);
this.Jump(this.MEMPTR);
}
protected bool JumpRelativeConditional(bool condition)
@ -200,18 +196,18 @@ namespace EightBit
protected override sealed void Return()
{
base.Return();
this.MEMPTR().Word = this.PC().Word;
this.MEMPTR.Word = this.PC.Word;
}
protected void Halt()
{
--this.PC();
--this.PC.Word;
this.LowerHALT();
}
protected void Proceed()
{
++this.PC();
++this.PC.Word;
this.RaiseHALT();
}
}

View File

@ -34,7 +34,7 @@ namespace EightBit
protected override Register16 GetWord()
{
var low = this.BusRead();
++this.Bus.Address();
++this.Bus.Address.Word;
var high = this.BusRead();
return new Register16(low, high);
}
@ -62,7 +62,7 @@ namespace EightBit
protected override void SetWord(Register16 value)
{
this.BusWrite(value.Low);
++this.Bus.Address();
++this.Bus.Address.Word;
this.BusWrite(value.High);
}

View File

@ -10,7 +10,6 @@ namespace EightBit
{
private PinLevel resetLine;
private PinLevel intLine;
private Register16 pc;
protected Processor(Bus memory)
{
@ -35,9 +34,9 @@ namespace EightBit
public Bus Bus { get; }
protected byte OpCode { get; set; }
public Register16 PC { get; } = new Register16();
public ref Register16 PC() => ref this.pc;
protected byte OpCode { get; set; }
public ref PinLevel RESET() => ref this.resetLine;
@ -118,14 +117,14 @@ namespace EightBit
protected void BusWrite(byte low, byte high, byte data)
{
this.Bus.Address().Low = low;
this.Bus.Address().High = high;
this.Bus.Address.Low = low;
this.Bus.Address.High = high;
this.BusWrite(data);
}
protected void BusWrite(ushort address, byte data)
{
this.Bus.Address().Word = address;
this.Bus.Address.Word = address;
this.BusWrite(data);
}
@ -141,14 +140,14 @@ namespace EightBit
protected byte BusRead(byte low, byte high)
{
this.Bus.Address().Low = low;
this.Bus.Address().High = high;
this.Bus.Address.Low = low;
this.Bus.Address.High = high;
return this.BusRead();
}
protected byte BusRead(ushort address)
{
this.Bus.Address().Word = address;
this.Bus.Address.Word = address;
return this.BusRead();
}
@ -156,7 +155,7 @@ namespace EightBit
protected virtual byte BusRead() => this.Bus.Read(); // N.B. Should be the only real call into the "Bus.Read" code.
protected byte FetchByte() => this.BusRead(this.PC()++);
protected byte FetchByte() => this.BusRead(this.PC.Word++);
protected abstract Register16 GetWord();
@ -178,23 +177,23 @@ namespace EightBit
protected Register16 GetWord(ushort address)
{
this.Bus.Address().Word = address;
this.Bus.Address.Word = address;
return this.GetWord();
}
protected void SetWord(ushort address, Register16 value)
{
this.Bus.Address().Word = address;
this.Bus.Address.Word = address;
this.SetWord(value);
}
protected void Jump(ushort destination) => this.PC().Word = destination;
protected void Jump(ushort destination) => this.PC.Word = destination;
protected void Jump(Register16 destination) => this.Jump(destination.Word);
protected void Call(ushort destination)
{
this.PushWord(this.PC());
this.PushWord(this.PC);
this.Jump(destination);
}

View File

@ -6,11 +6,16 @@ namespace EightBit
{
public class Ram : Rom
{
public Ram(int size = 0)
public Ram(int size)
: base(size)
{
}
public Ram()
: this(0)
{
}
public override sealed ref byte Reference(ushort address) => ref this.Bytes()[address];
public new void Poke(ushort address, byte value) => base.Poke(address, value);

View File

@ -8,11 +8,8 @@ namespace EightBit
using System.Runtime.InteropServices;
[DebuggerDisplay("Word = {Word}")]
public struct Register16
public class Register16
{
public byte Low;
public byte High;
public Register16(byte low, byte high)
{
this.Low = low;
@ -25,6 +22,11 @@ namespace EightBit
this.High = Chip.HighByte(value);
}
public Register16()
: this((ushort)0)
{
}
public Register16(int value)
: this((ushort)value)
{
@ -55,6 +57,10 @@ namespace EightBit
}
}
public byte Low { get; set; }
public byte High { get; set; }
public static Register16 operator ++(Register16 value) => Increment(value);
public static Register16 operator --(Register16 value) => Decrement(value);
@ -77,12 +83,12 @@ namespace EightBit
public override bool Equals(object obj)
{
if (!(obj is Register16))
var rhs = obj as Register16;
if (rhs == null)
{
return false;
}
var rhs = (Register16)obj;
return rhs.Low == this.Low && rhs.High == this.High;
}

View File

@ -1,4 +1,4 @@
// <copyright file="Disassembly.cs" company="Adrian Conlon">
// <copyright file="Disassembler.cs" company="Adrian Conlon">
// Copyright (c) Adrian Conlon. All rights reserved.
// </copyright>
@ -56,7 +56,7 @@ namespace EightBit
output.Append(" ");
var next = this.bus.Peek((ushort)(current + 1));
var relative = (ushort)(this.processor.PC().Word + 2 + (sbyte)next);
var relative = (ushort)(this.processor.PC.Word + 2 + (sbyte)next);
var aaa = (cell & 0b11100000) >> 5;
var bbb = (cell & 0b00011100) >> 2;

View File

@ -70,7 +70,7 @@ namespace M6502.Test
private void CPU_ExecutedInstruction(object sender, System.EventArgs e)
{
var pc = this.CPU.PC().Word;
var pc = this.CPU.PC.Word;
if (this.oldPC != pc)
{
this.oldPC = pc;
@ -87,7 +87,7 @@ namespace M6502.Test
private void CPU_ExecutingInstruction(object sender, System.EventArgs e)
{
var address = this.CPU.PC().Word;
var address = this.CPU.PC.Word;
var cell = this.Peek(address);
var output = new StringBuilder();

View File

@ -12,7 +12,7 @@ namespace EightBit
private const byte RSTvector = 0xfc; // RST vector
private const byte NMIvector = 0xfa; // NMI vector
private Register16 intermediate;
private readonly Register16 intermediate = new Register16();
private bool handlingRESET = false;
private bool handlingNMI = false;
@ -204,7 +204,7 @@ namespace EightBit
case 0x2e: this.BusReadModifyWrite(this.ROL(this.AM_Absolute())); break; // ROL (absolute)
case 0x2f: this.RLA(this.AM_Absolute()); break; // *RLA (absolute)
case 0x30: this.Branch(this.Negative); break; // BMI (relative)
case 0x30: this.Branch(this.Negative); break; // BMI (relative)
case 0x31: this.A = this.AndR(this.A, this.AM_IndirectIndexedY()); break; // AND (indirect indexed Y)
case 0x32: break;
case 0x33: this.RLA(this.AM_IndirectIndexedY()); break; // *RLA (indirect indexed Y)
@ -272,7 +272,7 @@ namespace EightBit
case 0x6e: this.BusReadModifyWrite(this.ROR(this.AM_Absolute())); break; // ROR (absolute)
case 0x6f: this.RRA(this.AM_Absolute()); break; // *RRA (absolute)
case 0x70: this.Branch(this.Overflow); break; // BVS (relative)
case 0x70: this.Branch(this.Overflow); break; // BVS (relative)
case 0x71: this.A = this.ADC(this.A, this.AM_IndirectIndexedY()); break; // ADC (indirect indexed Y)
case 0x72: break;
case 0x73: this.RRA(this.AM_IndirectIndexedY()); break; // *RRA (indirect indexed Y)
@ -340,7 +340,7 @@ namespace EightBit
case 0xae: this.X = this.Through(this.AM_Absolute()); break; // LDX (absolute)
case 0xaf: this.A = this.X = this.Through(this.AM_Absolute()); break; // *LAX (absolute)
case 0xb0: this.Branch(this.Carry); break; // BCS (relative)
case 0xb0: this.Branch(this.Carry); break; // BCS (relative)
case 0xb1: this.A = this.Through(this.AM_IndirectIndexedY()); break; // LDA (indirect indexed Y)
case 0xb2: break;
case 0xb3: this.A = this.X = this.Through(this.AM_IndirectIndexedY()); break; // *LAX (indirect indexed Y)
@ -407,7 +407,7 @@ namespace EightBit
case 0xed: this.A = this.SBC(this.A, this.AM_Absolute()); break; // SBC (absolute)
case 0xee: this.BusReadModifyWrite(this.INC(this.AM_Absolute())); break; // *ISB (absolute)
case 0xf0: this.Branch(this.Zero); break; // BEQ (relative)
case 0xf0: this.Branch(this.Zero); break; // BEQ (relative)
case 0xf1: this.A = this.SBC(this.A, this.AM_IndirectIndexedY()); break; // SBC (indirect indexed Y)
case 0xf2: break;
case 0xf3: this.ISB(this.AM_IndirectIndexedY()); break; // *ISB (indirect indexed Y)
@ -443,7 +443,7 @@ namespace EightBit
if (this.RDY().Raised())
{
this.LowerSYNC(); // Instruction fetch beginning
this.OpCode = this.Bus.Read(this.PC()++); // can't use fetchByte
this.OpCode = this.Bus.Read(this.PC.Word++); // can't use fetchByte
if (this.RESET().Lowered())
{
this.HandleRESET();
@ -579,13 +579,13 @@ namespace EightBit
var software = !hardware;
if (reset)
{
this.DummyPush(this.PC().High);
this.DummyPush(this.PC().Low);
this.DummyPush(this.PC.High);
this.DummyPush(this.PC.Low);
this.DummyPush(this.P);
}
else
{
this.PushWord(this.PC());
this.PushWord(this.PC);
this.Push((byte)(this.P | (int)(software ? StatusBits.BF : 0)));
}
@ -599,8 +599,8 @@ namespace EightBit
{
this.Tick();
this.Bus.Data = value;
this.Bus.Address().Low = this.S--;
this.Bus.Address().High = 1;
this.Bus.Address.Low = this.S--;
this.Bus.Address.High = 1;
}
private Register16 Address_Absolute() => this.FetchWord();
@ -658,7 +658,7 @@ namespace EightBit
private ushort Address_relative_byte()
{
var offset = (sbyte)this.FetchByte();
this.intermediate.Word = (ushort)(this.PC().Word + offset);
this.intermediate.Word = (ushort)(this.PC.Word + offset);
return this.intermediate.Word;
}
@ -734,11 +734,11 @@ namespace EightBit
if (condition)
{
this.BusRead();
var page = this.PC().High;
var page = this.PC.High;
this.Jump(destination);
if (this.PC().High != page)
if (this.PC.High != page)
{
this.BusRead(this.PC().Low, page);
this.BusRead(this.PC.Low, page);
}
}
}
@ -878,10 +878,10 @@ namespace EightBit
{
var low = this.FetchByte();
this.BusRead(this.S, 1); // dummy read
this.PushWord(this.PC());
this.PushWord(this.PC);
var high = this.FetchByte();
this.PC().Low = low;
this.PC().High = high;
this.PC.Low = low;
this.PC.High = high;
}
private byte LSR(byte value)

View File

@ -1,4 +1,8 @@
namespace EightBit
// <copyright file="Disassembler.cs" company="Adrian Conlon">
// Copyright (c) Adrian Conlon. All rights reserved.
// </copyright>
namespace EightBit
{
using System.Text;
@ -34,20 +38,20 @@
public static string State(Z80 cpu)
{
var pc = cpu.PC();
var sp = cpu.SP();
var pc = cpu.PC;
var sp = cpu.SP;
var a = cpu.A();
var f = cpu.F();
var a = cpu.A;
var f = cpu.F;
var b = cpu.B();
var c = cpu.C();
var b = cpu.B;
var c = cpu.C;
var d = cpu.D();
var e = cpu.E();
var d = cpu.D;
var e = cpu.E;
var h = cpu.H();
var l = cpu.L();
var h = cpu.H;
var l = cpu.L;
var i = cpu.IV;
var r = cpu.REFRESH();
@ -67,7 +71,7 @@
public string Disassemble(Z80 cpu)
{
this.prefixCB = this.prefixDD = this.prefixED = this.prefixFD = false;
return this.Disassemble(cpu, cpu.PC().Word);
return this.Disassemble(cpu, cpu.PC.Word);
}
private static string CC(int flag)

View File

@ -1,4 +1,8 @@
namespace EightBit
// <copyright file="RefreshRegister.cs" company="Adrian Conlon">
// Copyright (c) Adrian Conlon. All rights reserved.
// </copyright>
namespace EightBit
{
public struct RefreshRegister
{

View File

@ -68,13 +68,13 @@ namespace Z80.Test
private void BDOS()
{
switch (CPU.C())
switch (CPU.C)
{
case 0x2:
System.Console.Out.Write(CPU.E().ToString());
System.Console.Out.Write(CPU.E.ToString());
break;
case 0x9:
for (ushort i = CPU.DE().Word; Peek(i) != '$'; ++i)
for (ushort i = CPU.DE.Word; Peek(i) != '$'; ++i)
{
System.Console.Out.Write((char)Peek(i));
}
@ -85,7 +85,7 @@ namespace Z80.Test
private void CPU_ExecutingInstruction_CPM(object sender, System.EventArgs e)
{
switch (this.CPU.PC().Word)
switch (this.CPU.PC.Word)
{
case 0x0: // CP/M warm start
if (++this.warmstartCount == 2)

View File

@ -13,6 +13,7 @@ namespace Z80.Test
#if DEBUG
configuration.DebugMode = true;
#endif
// configuration.DebugMode = true;
using (var harness = new TestHarness(configuration))
{

File diff suppressed because it is too large Load Diff