Resurrect the Register16 class. This (or something *very* much like it) is going to be necessary to add a Z80 emulator (reference access to the high/low parts of 16-bit registers).

Signed-off-by: Adrian Conlon <Adrian.conlon@gmail.com>
This commit is contained in:
Adrian Conlon
2019-02-14 23:01:31 +00:00
parent b61d884679
commit 63db46a7bc
12 changed files with 336 additions and 195 deletions
+24 -24
View File
@@ -10,65 +10,65 @@ namespace EightBit
{
}
public override ushort PeekWord(ushort address)
public override Register16 PeekWord(ushort address)
{
var high = this.Bus.Peek(address);
var low = this.Bus.Peek(++address);
return Chip.MakeWord(low, high);
return new Register16(low, high);
}
public override void PokeWord(ushort address, ushort value)
public override void PokeWord(ushort address, Register16 value)
{
this.Bus.Poke(address, Chip.LowByte(value));
this.Bus.Poke(++address, Chip.HighByte(value));
this.Bus.Poke(address, value.Low);
this.Bus.Poke(++address, value.High);
}
protected override ushort FetchWord()
protected override Register16 FetchWord()
{
var high = this.FetchByte();
var low = this.FetchByte();
return Chip.MakeWord(low, high);
return new Register16(low, high);
}
protected override ushort GetWord()
protected override Register16 GetWord()
{
var high = this.BusRead();
++this.Bus.Address;
++this.Bus.Address();
var low = this.BusRead();
return Chip.MakeWord(low, high);
return new Register16(low, high);
}
protected override ushort GetWordPaged(byte page, byte offset)
protected override Register16 GetWordPaged(byte page, byte offset)
{
var high = this.BusRead(offset, page);
var low = this.BusRead(++offset, page);
return Chip.MakeWord(low, high);
return new Register16(low, high);
}
protected override ushort PopWord()
protected override Register16 PopWord()
{
var high = this.Pop();
var low = this.Pop();
return Chip.MakeWord(low, high);
return new Register16(low, high);
}
protected override void PushWord(ushort value)
protected override void PushWord(Register16 value)
{
this.Push(Chip.LowByte(value));
this.Push(Chip.HighByte(value));
this.Push(value.Low);
this.Push(value.High);
}
protected override void SetWord(ushort value)
protected override void SetWord(Register16 value)
{
this.BusWrite(Chip.HighByte(value));
++this.Bus.Address;
this.BusWrite(Chip.LowByte(value));
this.BusWrite(value.High);
++this.Bus.Address();
this.BusWrite(value.Low);
}
protected override void SetWordPaged(byte page, byte offset, ushort value)
protected override void SetWordPaged(byte page, byte offset, Register16 value)
{
this.BusWrite(offset, page, Chip.HighByte(value));
this.BusWrite(++offset, page, Chip.LowByte(value));
this.BusWrite(offset, page, value.High);
this.BusWrite(++offset, page, value.Low);
}
}
}
+34 -7
View File
@@ -8,6 +8,7 @@ namespace EightBit
public abstract class Bus : IMapper
{
private Register16 address;
private byte data;
public event EventHandler<EventArgs> WritingByte;
@@ -20,7 +21,7 @@ namespace EightBit
public byte Data { get => this.data; set => this.data = value; }
public ushort Address { get; set; }
public ref Register16 Address() => ref this.address;
public abstract MemoryMapping Mapping(ushort absolute);
@@ -28,12 +29,16 @@ namespace EightBit
public byte Peek(ushort absolute) => this.Reference(absolute);
public byte Peek(Register16 absolute) => this.Peek(absolute.Word);
public byte Peek(byte low, byte high) => this.Reference(low, high);
public void Poke(byte value) => this.Reference() = value;
public byte Poke(ushort absolute, byte value) => this.Reference(absolute) = value;
public byte Poke(Register16 absolute, byte value) => this.Poke(absolute.Word, value);
public byte Poke(byte low, byte high, byte value) => this.Reference(low, high) = value;
public byte Read()
@@ -46,11 +51,21 @@ namespace EightBit
public byte Read(ushort absolute)
{
this.Address = absolute;
this.Address().Word = absolute;
return this.Read();
}
public byte Read(byte low, byte high) => this.Read(Chip.MakeWord(low, high));
public byte Read(Register16 absolute)
{
return this.Read(absolute.Word);
}
public byte Read(byte low, byte high)
{
this.Address().Low = low;
this.Address().High = high;
return this.Read();
}
public void Write()
{
@@ -67,11 +82,21 @@ namespace EightBit
public void Write(ushort absolute, byte value)
{
this.Address = absolute;
this.Address().Word = absolute;
this.Write(value);
}
public void Write(byte low, byte high, byte value) => this.Write(Chip.MakeWord(low, high), value);
public void Write(Register16 absolute, byte value)
{
this.Write(absolute.Word, value);
}
public void Write(byte low, byte high, byte value)
{
this.Address().Low = low;
this.Address().High = high;
this.Write(value);
}
public virtual void RaisePOWER()
{
@@ -104,9 +129,11 @@ namespace EightBit
return ref mapped.Memory.Reference(offset);
}
protected ref byte Reference() => ref this.Reference(this.Address);
protected ref byte Reference(Register16 absolute) => ref this.Reference(absolute.Word);
protected ref byte Reference(byte low, byte high) => ref this.Reference(Chip.MakeWord(low, high));
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);
////[[nodiscard]] static std::map<uint16_t, std::vector<uint8_t>> parseHexFile(std::string path);
////void loadHexFile(std::string path);
+1
View File
@@ -70,6 +70,7 @@
<Compile Include="Processor.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Ram.cs" />
<Compile Include="Register16.cs" />
<Compile Include="Rom.cs" />
<Compile Include="UnusedMemory.cs" />
</ItemGroup>
+4 -4
View File
@@ -16,11 +16,11 @@ namespace EightBit
{
}
public IntelOpCodeDecoded(byte opcode)
public IntelOpCodeDecoded(byte opCode)
{
this.x = (opcode & 0b11000000) >> 6; // 0 - 3
this.y = (opcode & 0b00111000) >> 3; // 0 - 7
this.z = opcode & 0b00000111; // 0 - 7
this.x = (opCode & 0b11000000) >> 6; // 0 - 3
this.y = (opCode & 0b00111000) >> 3; // 0 - 7
this.z = opCode & 0b00000111; // 0 - 7
this.p = (this.y & 0b110) >> 1; // 0 - 3
this.q = this.y & 1; // 0 - 1
}
+52 -50
View File
@@ -10,14 +10,15 @@ 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)
: base(bus)
{
this.SP = (ushort)Mask.Mask16;
this.MEMPTR = (ushort)Mask.Mask16;
for (int i = 0; i < 0x100; ++i)
{
this.decodedOpCodes[i] = new IntelOpCodeDecoded((byte)i);
@@ -32,43 +33,43 @@ namespace EightBit
public event EventHandler<EventArgs> LoweredHALT;
public ushort SP { get; set; }
public ushort MEMPTR { get; set; }
public abstract ushort AF { get; set; }
public byte A { get => Chip.HighByte(this.AF); set => this.AF = (ushort)(Chip.LowerPart(this.AF) | Chip.PromoteByte(value)); }
public byte F { get => Chip.LowByte(this.AF); set => this.AF = (ushort)(Chip.HigherPart(this.AF) | value); }
public abstract ushort BC { get; set; }
public byte B { get => Chip.HighByte(this.BC); set => this.BC = (ushort)(Chip.LowerPart(this.BC) | Chip.PromoteByte(value)); }
public byte C { get => Chip.LowByte(this.BC); set => this.BC = (ushort)(Chip.HigherPart(this.BC) | value); }
public abstract ushort DE { get; set; }
public byte D { get => Chip.HighByte(this.DE); set => this.DE = (ushort)(Chip.LowerPart(this.DE) | Chip.PromoteByte(value)); }
public byte E { get => Chip.LowByte(this.DE); set => this.DE = (ushort)(Chip.HigherPart(this.DE) | value); }
public abstract ushort HL { get; set; }
public byte H { get => Chip.HighByte(this.HL); set => this.HL = (ushort)(Chip.LowerPart(this.HL) | Chip.PromoteByte(value)); }
public byte L { get => Chip.LowByte(this.HL); set => this.HL = (ushort)(Chip.HigherPart(this.HL) | 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 override void RaisePOWER()
{
base.RaisePOWER();
this.RaiseHALT();
this.SP = this.AF = this.BC = this.DE = this.HL = (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()
@@ -96,40 +97,41 @@ namespace EightBit
protected override void HandleRESET()
{
base.HandleRESET();
this.PC = 0;
this.PC().Word = 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(), value);
protected sealed override byte Pop() => this.Bus.Read(this.SP++);
protected sealed override byte Pop() => this.Bus.Read(this.SP()++);
protected sealed override ushort GetWord()
protected sealed override Register16 GetWord()
{
var returned = base.GetWord();
this.MEMPTR = this.Bus.Address;
this.MEMPTR().Word = this.Bus.Address().Word;
return returned;
}
protected sealed override void SetWord(ushort value)
protected sealed override void SetWord(Register16 value)
{
base.SetWord(value);
this.MEMPTR = this.Bus.Address;
this.MEMPTR().Word = this.Bus.Address().Word;
}
////
protected void Restart(byte address)
{
this.MEMPTR = address;
this.Call(this.MEMPTR);
this.MEMPTR().Low = address;
this.MEMPTR().High = 0;
this.Call(this.MEMPTR().Word);
}
protected bool CallConditional(bool condition)
{
this.MEMPTR = this.FetchWord();
this.MEMPTR().Word = this.FetchWord().Word;
if (condition)
{
this.Call(this.MEMPTR);
this.Call(this.MEMPTR().Word);
}
return condition;
@@ -137,10 +139,10 @@ namespace EightBit
protected bool JumpConditional(bool condition)
{
this.MEMPTR = this.FetchWord();
this.MEMPTR().Word = this.FetchWord().Word;
if (condition)
{
this.Jump(this.MEMPTR);
this.Jump(this.MEMPTR().Word);
}
return condition;
@@ -158,8 +160,8 @@ namespace EightBit
protected void JumpRelative(sbyte offset)
{
this.MEMPTR = (ushort)(this.PC + offset);
this.Jump(this.MEMPTR);
this.MEMPTR().Word = (ushort)(this.PC().Word + offset);
this.Jump(this.MEMPTR().Word);
}
protected bool JumpRelativeConditional(bool condition)
@@ -176,18 +178,18 @@ namespace EightBit
protected override sealed void Return()
{
base.Return();
this.MEMPTR = this.PC;
this.MEMPTR().Word = this.PC().Word;
}
protected void Halt()
{
--this.PC;
--this.PC();
this.LowerHALT();
}
protected void Proceed()
{
++this.PC;
++this.PC();
this.RaiseHALT();
}
}
+24 -24
View File
@@ -11,65 +11,65 @@ namespace EightBit
{
}
public override ushort PeekWord(ushort address)
public override Register16 PeekWord(ushort address)
{
var low = this.Bus.Peek(address);
var high = this.Bus.Peek(++address);
return Chip.MakeWord(low, high);
return new Register16(low, high);
}
public override void PokeWord(ushort address, ushort value)
public override void PokeWord(ushort address, Register16 value)
{
this.Bus.Poke(address, Chip.LowByte(value));
this.Bus.Poke(++address, Chip.HighByte(value));
this.Bus.Poke(address, value.Low);
this.Bus.Poke(++address, value.High);
}
protected override ushort FetchWord()
protected override Register16 FetchWord()
{
var low = this.FetchByte();
var high = this.FetchByte();
return Chip.MakeWord(low, high);
return new Register16(low, high);
}
protected override ushort GetWord()
protected override Register16 GetWord()
{
var low = this.BusRead();
++this.Bus.Address;
++this.Bus.Address();
var high = this.BusRead();
return Chip.MakeWord(low, high);
return new Register16(low, high);
}
protected override ushort GetWordPaged(byte page, byte offset)
protected override Register16 GetWordPaged(byte page, byte offset)
{
var low = this.BusRead(offset, page);
var high = this.BusRead(++offset, page);
return Chip.MakeWord(low, high);
return new Register16(low, high);
}
protected override ushort PopWord()
protected override Register16 PopWord()
{
var low = this.Pop();
var high = this.Pop();
return Chip.MakeWord(low, high);
return new Register16(low, high);
}
protected override void PushWord(ushort value)
protected override void PushWord(Register16 value)
{
this.Push(Chip.HighByte(value));
this.Push(Chip.LowByte(value));
this.Push(value.High);
this.Push(value.Low);
}
protected override void SetWord(ushort value)
protected override void SetWord(Register16 value)
{
this.BusWrite(Chip.LowByte(value));
++this.Bus.Address;
this.BusWrite(Chip.HighByte(value));
this.BusWrite(value.Low);
++this.Bus.Address();
this.BusWrite(value.High);
}
protected override void SetWordPaged(byte page, byte offset, ushort value)
protected override void SetWordPaged(byte page, byte offset, Register16 value)
{
this.BusWrite(offset, page, Chip.LowByte(value));
this.BusWrite(++offset, page, Chip.HighByte(value));
this.BusWrite(offset, page, value.Low);
this.BusWrite(++offset, page, value.High);
}
}
}
+34 -25
View File
@@ -10,6 +10,7 @@ namespace EightBit
{
private PinLevel resetLine;
private PinLevel intLine;
private Register16 pc;
protected Processor(Bus memory)
{
@@ -32,12 +33,12 @@ namespace EightBit
public event EventHandler<EventArgs> LoweredINT;
public ushort PC { get; set; }
public Bus Bus { get; }
protected byte OpCode { get; set; }
public ref Register16 PC() => ref this.pc;
public ref PinLevel RESET() => ref this.resetLine;
public ref PinLevel INT() => ref this.intLine;
@@ -63,11 +64,9 @@ namespace EightBit
return this.Execute();
}
public abstract ushort PeekWord(ushort address);
public abstract Register16 PeekWord(ushort address);
public abstract void PokeWord(ushort address, ushort value);
public ushort PeekWord(byte low, byte high) => this.PeekWord((ushort)(Chip.PromoteByte(high) | low));
public abstract void PokeWord(ushort address, Register16 value);
public virtual void RaiseRESET()
{
@@ -117,11 +116,16 @@ namespace EightBit
protected virtual void HandleINT() => this.RaiseINT();
protected void BusWrite(byte low, byte high, byte data) => this.BusWrite(Chip.MakeWord(low, high), data);
protected void BusWrite(byte low, byte high, byte data)
{
this.Bus.Address().Low = low;
this.Bus.Address().High = high;
this.BusWrite(data);
}
protected void BusWrite(ushort address, byte data)
{
this.Bus.Address = address;
this.Bus.Address().Word = address;
this.BusWrite(data);
}
@@ -133,56 +137,61 @@ namespace EightBit
protected virtual void BusWrite() => this.Bus.Write(); // N.B. Should be the only real call into the "Bus.Write" code.
protected byte BusRead(byte low, byte high) => this.BusRead(Chip.MakeWord(low, high));
protected byte BusRead(byte low, byte high)
{
this.Bus.Address().Low = low;
this.Bus.Address().High = high;
return this.BusRead();
}
protected byte BusRead(ushort address)
{
this.Bus.Address = address;
this.Bus.Address().Word = address;
return this.BusRead();
}
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 ushort GetWord();
protected abstract Register16 GetWord();
protected abstract void SetWord(ushort value);
protected abstract void SetWord(Register16 value);
protected abstract ushort GetWordPaged(byte page, byte offset);
protected abstract Register16 GetWordPaged(byte page, byte offset);
protected abstract void SetWordPaged(byte page, byte offset, ushort value);
protected abstract void SetWordPaged(byte page, byte offset, Register16 value);
protected abstract ushort FetchWord();
protected abstract Register16 FetchWord();
protected abstract void Push(byte value);
protected abstract byte Pop();
protected abstract void PushWord(ushort value);
protected abstract void PushWord(Register16 value);
protected abstract ushort PopWord();
protected abstract Register16 PopWord();
protected ushort GetWord(ushort address)
protected Register16 GetWord(ushort address)
{
this.Bus.Address = address;
this.Bus.Address().Word = address;
return this.GetWord();
}
protected void SetWord(ushort address, ushort value)
protected void SetWord(ushort address, Register16 value)
{
this.Bus.Address = address;
this.Bus.Address().Word = address;
this.SetWord(value);
}
protected void Jump(ushort destination) => this.PC = destination;
protected void Jump(ushort destination) => this.PC().Word = destination;
protected void Call(ushort destination)
{
this.PushWord(this.PC);
this.PushWord(this.PC());
this.Jump(destination);
}
protected virtual void Return() => this.Jump(this.PopWord());
protected virtual void Return() => this.Jump(this.PopWord().Word);
}
}
+99
View File
@@ -0,0 +1,99 @@
// <copyright file="Register16.cs" company="Adrian Conlon">
// Copyright (c) Adrian Conlon. All rights reserved.
// </copyright>
namespace EightBit
{
using System.Runtime.InteropServices;
// This'll only work for little endian host processors...
[StructLayout(LayoutKind.Explicit)]
public struct Register16
{
[FieldOffset(0)]
public byte Low;
[FieldOffset(1)]
public byte High;
[FieldOffset(0)]
public ushort Word;
public Register16(byte low, byte high)
{
this.Word = 0;
this.Low = low;
this.High = high;
}
public Register16(ushort value)
: this(Chip.LowByte(value), Chip.HighByte(value))
{
}
public Register16(int value)
: this((ushort)value)
{
}
public Register16(byte low)
: this(low, 0)
{
}
public Register16(Register16 rhs)
{
this.Low = 0;
this.High = 0;
this.Word = rhs.Word;
}
public static Register16 operator ++(Register16 value)
{
return Increment(value);
}
public static Register16 operator --(Register16 value)
{
return Decrement(value);
}
public static bool operator ==(Register16 left, Register16 right)
{
return left.Equals(right);
}
public static bool operator !=(Register16 left, Register16 right)
{
return !(left == right);
}
public static Register16 Increment(Register16 value)
{
++value.Word;
return value;
}
public static Register16 Decrement(Register16 value)
{
--value.Word;
return value;
}
public override bool Equals(object obj)
{
if (!(obj is Register16))
{
return false;
}
Register16 rhs = (Register16)obj;
return rhs.Word == this.Word;
}
public override int GetHashCode()
{
return this.Word;
}
}
}