Port of EightBit library to .Net (unworking!)

Signed-off-by: Adrian Conlon <Adrian.conlon@gmail.com>
This commit is contained in:
Adrian Conlon
2019-02-02 15:12:51 +00:00
parent d693218618
commit 9a06b1743f
53 changed files with 16224 additions and 0 deletions
+7
View File
@@ -0,0 +1,7 @@
namespace EightBit
{
public enum AccessLevel
{
Unknown, ReadOnly, WriteOnly, ReadWrite
}
}
+73
View File
@@ -0,0 +1,73 @@
namespace EightBit
{
public abstract class BigEndianProcessor : Processor
{
protected BigEndianProcessor(Bus memory)
: base(memory)
{
}
public override Register16 PeekWord(Register16 address)
{
var high = Bus.Peek(address);
var low = Bus.Peek(++address);
return new Register16(low, high);
}
public override void PokeWord(Register16 address, Register16 value)
{
Bus.Poke(address, value.High);
Bus.Poke(++address, value.Low);
}
protected override Register16 FetchWord()
{
var high = FetchByte();
var low = FetchByte();
return new Register16(low, high);
}
protected override Register16 GetWord()
{
var high = BusRead();
++Bus.Address.Word;
var low = BusRead();
return new Register16(low, high);
}
protected override Register16 GetWordPaged(byte page, byte offset)
{
var high = GetBytePaged(page, offset);
++Bus.Address.Low;
var low = BusRead();
return new Register16(low, high);
}
protected override Register16 PopWord()
{
var high = Pop();
var low = Pop();
return new Register16(low, high);
}
protected override void PushWord(Register16 value)
{
Push(value.Low);
Push(value.High);
}
protected override void SetWord(Register16 value)
{
BusWrite(value.High);
++Bus.Address.Word;
BusWrite(value.Low);
}
protected override void SetWordPaged(byte page, byte offset, Register16 value)
{
SetBytePaged(page, offset, value.High);
++Bus.Address.Low;
BusWrite(value.Low);
}
}
}
+26
View File
@@ -0,0 +1,26 @@
using System;
namespace EightBit
{
[Flags]
public enum Bits
{
Bit0 = 1,
Bit1 = Bit0 << 1,
Bit2 = Bit1 << 1,
Bit3 = Bit2 << 1,
Bit4 = Bit3 << 1,
Bit5 = Bit4 << 1,
Bit6 = Bit5 << 1,
Bit7 = Bit6 << 1,
Bit8 = Bit7 << 1,
Bit9 = Bit8 << 1,
Bit10 = Bit9 << 1,
Bit11 = Bit10 << 1,
Bit12 = Bit11 << 1,
Bit13 = Bit12 << 1,
Bit14 = Bit13 << 1,
Bit15 = Bit14 << 1,
Bit16 = Bit15 << 1
}
}
+109
View File
@@ -0,0 +1,109 @@
namespace EightBit
{
using System;
abstract public class Bus : IMapper
{
private byte data;
private Register16 address = new Register16();
public event EventHandler<EventArgs> WritingByte;
public event EventHandler<EventArgs> WrittenByte;
public event EventHandler<EventArgs> ReadingByte;
public event EventHandler<EventArgs> ReadByte;
public byte Data
{
get { return data; }
set { data = value; }
}
public Register16 Address
{
get { return address; }
}
public abstract MemoryMapping Mapping(Register16 absolute);
public byte Peek() => Reference();
public byte Peek(Register16 absolute) => Reference(absolute);
public byte Peek(ushort absolute) => Peek(Chip.LowByte(absolute), Chip.HighByte(absolute));
public byte Peek(byte low, byte high) => Reference(new Register16(low, high));
public void Poke(byte value) => Reference() = value;
public void Poke(Register16 absolute, byte value) => Reference(absolute) = value;
public byte Poke(ushort absolute, byte value) => Poke(Chip.LowByte(absolute), Chip.HighByte(absolute), value);
public byte Poke(byte low, byte high, byte value) => Reference(new Register16(low, high)) = value;
public byte Read()
{
OnReadingByte();
var returned = Data = Reference();
OnReadByte();
return returned;
}
public byte Read(Register16 absolute)
{
Address.Word = absolute.Word;
return Read();
}
public void Write()
{
OnWritingByte();
Reference() = Data;
OnWrittenByte();
}
public void Write(byte value)
{
Data = value;
Write();
}
public void Write(Register16 absolute, byte value)
{
Address.Word = absolute.Word;
Write(value);
}
public virtual void RaisePOWER() {}
public virtual void LowerPOWER() {}
public abstract void Initialize();
protected virtual void OnWritingByte() => WritingByte?.Invoke(this, EventArgs.Empty);
protected virtual void OnWrittenByte() => WrittenByte?.Invoke(this, EventArgs.Empty);
protected virtual void OnReadingByte() => ReadingByte?.Invoke(this, EventArgs.Empty);
protected virtual void OnReadByte() => ReadByte?.Invoke(this, EventArgs.Empty);
protected ref byte Reference(Register16 absolute)
{
var mapped = Mapping(absolute);
var offset = (ushort)((absolute - mapped.Begin) & mapped.Mask);
if (mapped.Access == AccessLevel.ReadOnly)
{
Data = mapped.Memory.Peek(offset);
return ref data;
}
return ref mapped.Memory.Reference(offset);
}
protected ref byte Reference() => ref Reference(Address);
protected ref byte Reference(ushort absolute) => ref Reference(Chip.LowByte(absolute), Chip.HighByte(absolute));
protected ref byte Reference(byte low, byte high)
{
Address.Low = low;
Address.High = high;
return ref Reference();
}
//[[nodiscard]] static std::map<uint16_t, std::vector<uint8_t>> parseHexFile(std::string path);
//void loadHexFile(std::string path);
}
}
+42
View File
@@ -0,0 +1,42 @@
namespace EightBit
{
public class Chip : Device
{
protected Chip() { }
public static void ClearFlag(ref byte f, byte flag) => f &= (byte)~flag;
public static void SetFlag(ref byte f, byte flag) => f |= flag;
public static void SetFlag(ref byte f, byte flag, int condition) => SetFlag(ref f, flag, condition != 0);
public static void SetFlag(ref byte f, byte flag, bool condition)
{
if (condition)
SetFlag(ref f, flag);
else
ClearFlag(ref f, flag);
}
public static void ClearFlag(ref byte f, byte flag, int condition) => ClearFlag(ref f, flag, condition == 0);
public static void ClearFlag(ref byte f, byte flag, bool condition) => SetFlag(ref f, flag, !condition);
public static int HighByte(int value) => LowByte(value >> 8);
public static byte HighByte(ushort value) => (byte)LowByte((int)value);
public static int LowByte(int value) => value & (int)Mask.Mask8;
public static byte LowByte(ushort value) => (byte)LowByte((int)value);
public static int PromoteByte(int value) => value << 8;
public static ushort PromoteByte(byte value) => (ushort)PromoteByte((int)value);
public static int DemoteByte(int value) => HighByte(value);
public static byte DemoteByte(ushort value) => (byte)HighByte((int)value);
public static int HighNibble(byte value) => value >> 4;
public static int LowNibble(byte value) => value & 0xf;
public static int HigherNibble(byte value) => value & 0xf0;
public static int LowerNibble(byte value) => LowNibble(value);
public static int PromoteNibble(byte value) => value << 4;
public static int DemoteNibble(byte value) => HighNibble(value);
}
}
+31
View File
@@ -0,0 +1,31 @@
namespace EightBit
{
using System;
public class ClockedChip : Chip
{
private int cycles;
protected ClockedChip() { }
public int Cycles { get => cycles; protected set => cycles = value; }
public event EventHandler<EventArgs> Ticked;
public void Tick(int extra)
{
for (int i = 0; i < extra; ++i)
Tick();
}
public void Tick()
{
++Cycles;
OnTicked();
}
protected virtual void OnTicked() => Ticked?.Invoke(this, EventArgs.Empty);
protected void ResetCycles() => Cycles = 0;
}
}
+40
View File
@@ -0,0 +1,40 @@
namespace EightBit
{
using System;
public class Device
{
private PinLevel powerLine;
protected Device() { }
public event EventHandler<EventArgs> RaisingPOWER;
public event EventHandler<EventArgs> RaisedPOWER;
public event EventHandler<EventArgs> LoweringPOWER;
public event EventHandler<EventArgs> LoweredPOWER;
public ref PinLevel POWER() { return ref powerLine; }
public bool Powered => POWER().Raised();
public virtual void RaisePOWER()
{
OnRaisingPOWER();
POWER().Raise();
OnRaisedPOWER();
}
public virtual void LowerPOWER()
{
OnLoweringPOWER();
POWER().Lower();
OnLoweredPOWER();
}
protected virtual void OnRaisingPOWER() => RaisingPOWER?.Invoke(this, EventArgs.Empty);
protected virtual void OnRaisedPOWER() => RaisedPOWER?.Invoke(this, EventArgs.Empty);
protected virtual void OnLoweringPOWER() => LoweringPOWER?.Invoke(this, EventArgs.Empty);
protected virtual void OnLoweredPOWER() => LoweredPOWER?.Invoke(this, EventArgs.Empty);
}
}
+76
View File
@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{6EBF8857-62A3-4EF4-AF21-C1844031D7E4}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>EightBit</RootNamespace>
<AssemblyName>EightBit</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<LangVersion>latest</LangVersion>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="AccessLevel.cs" />
<Compile Include="BigEndianProcessor.cs" />
<Compile Include="Bits.cs" />
<Compile Include="Bus.cs" />
<Compile Include="Chip.cs" />
<Compile Include="ClockedChip.cs" />
<Compile Include="Device.cs" />
<Compile Include="GlobalSuppressions.cs" />
<Compile Include="IntelOpCodeDecoded.cs" />
<Compile Include="Memory.cs" />
<Compile Include="InputOutput.cs" />
<Compile Include="IntelProcessor.cs" />
<Compile Include="LittleEndianProcessor.cs" />
<Compile Include="Mapper.cs" />
<Compile Include="Mask.cs" />
<Compile Include="MemoryMapping.cs" />
<Compile Include="PinLevel.cs" />
<Compile Include="PinLevelExtensions.cs" />
<Compile Include="PortEventArgs.cs" />
<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>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
Binary file not shown.
+50
View File
@@ -0,0 +1,50 @@
namespace EightBit
{
using System;
public sealed class InputOutput
{
private byte[] input;
private byte[] output;
public InputOutput()
{
input = new byte[0x100];
output = new byte[0x100];
}
public event EventHandler<PortEventArgs> ReadingPort;
public event EventHandler<PortEventArgs> ReadPort;
public event EventHandler<PortEventArgs> WritingPort;
public event EventHandler<PortEventArgs> WrittenPort;
byte Read(byte port) { return ReadInputPort(port); }
void Write(byte port, byte value) { WriteOutputPort(port, value); }
byte ReadInputPort(byte port)
{
OnReadingPort(port);
var value = input[port];
OnReadPort(port);
return value;
}
void WriteInputPort(byte port, byte value) => input[port] = value;
byte ReadOutputPort(byte port) => output[port];
void WriteOutputPort(byte port, byte value)
{
OnWritingPort(port);
output[port] = value;
OnWrittenPort(port);
}
private void OnReadingPort(byte port) => ReadingPort?.Invoke(this, new PortEventArgs(port));
private void OnReadPort(byte port) => ReadPort?.Invoke(this, new PortEventArgs(port));
private void OnWritingPort(byte port) => WritingPort?.Invoke(this, new PortEventArgs(port));
private void OnWrittenPort(byte port) => WrittenPort?.Invoke(this, new PortEventArgs(port));
}
}
+21
View File
@@ -0,0 +1,21 @@
namespace EightBit
{
class IntelOpCodeDecoded
{
public int x;
public int y;
public int z;
public int p;
public int q;
public IntelOpCodeDecoded() { }
public IntelOpCodeDecoded(byte opcode) {
x = (opcode & 0b11000000) >> 6; // 0 - 3
y = (opcode & 0b00111000) >> 3; // 0 - 7
z = (opcode & 0b00000111); // 0 - 7
p = (y & 0b110) >> 1; // 0 - 3
q = (y & 1); // 0 - 1
}
}
}
+165
View File
@@ -0,0 +1,165 @@
namespace EightBit
{
using System;
public abstract class IntelProcessor : LittleEndianProcessor
{
private readonly IntelOpCodeDecoded[] decodedOpCodes;
private Register16 sp;
private Register16 memptr;
private PinLevel haltLine;
protected IntelProcessor(Bus bus)
: base(bus)
{
decodedOpCodes = new IntelOpCodeDecoded[0x100];
sp = new Register16((ushort)Mask.Mask16);
memptr = new Register16();
for (int i = 0; i < 0x100; ++i)
decodedOpCodes[i] = new IntelOpCodeDecoded((byte)i);
}
public event EventHandler<EventArgs> RaisingHALT;
public event EventHandler<EventArgs> RaisedHALT;
public event EventHandler<EventArgs> LoweringHALT;
public event EventHandler<EventArgs> LoweredHALT;
public ref PinLevel HALT() { return ref haltLine; }
protected bool Halted => HALT().Lowered();
public Register16 SP { get => sp; set => sp = value; }
public Register16 MEMPTR { get => memptr; set => memptr = value; }
public abstract Register16 AF { get; set; }
public byte A { get { return AF.High; } set { AF.High = value; } }
public byte F { get { return AF.Low; } set { AF.Low = value; } }
public abstract Register16 BC { get; set; }
public byte B { get { return BC.High; } set { BC.High = value; } }
public byte C { get { return BC.Low; } set { BC.Low = value; } }
public abstract Register16 DE { get; set; }
public byte D { get { return DE.High; } set { DE.High = value; } }
public byte E { get { return DE.Low; } set { DE.Low = value; } }
public abstract Register16 HL { get; set; }
public byte H { get { return HL.High; } set { HL.High = value; } }
public byte L { get { return HL.Low; } set { HL.Low = value; } }
public override void RaisePOWER()
{
base.RaisePOWER();
RaiseHALT();
SP = AF = BC = DE = HL = new Register16((ushort)Mask.Mask16);
}
public virtual void RaiseHALT()
{
OnRaisingHALT();
HALT().Raise();
OnRaisedHALT();
}
public virtual void LowerHALT()
{
OnLoweringHALT();
HALT().Lower();
OnLoweredHALT();
}
protected virtual void OnRaisingHALT() => RaisingHALT?.Invoke(this, EventArgs.Empty);
protected virtual void OnRaisedHALT() => RaisedHALT?.Invoke(this, EventArgs.Empty);
protected virtual void OnLoweringHALT() => LoweringHALT?.Invoke(this, EventArgs.Empty);
protected virtual void OnLoweredHALT() => LoweredHALT?.Invoke(this, EventArgs.Empty);
protected override void HandleRESET()
{
base.HandleRESET();
PC.Word = 0;
}
protected sealed override void Push(byte value) => Bus.Write(--SP, value);
protected sealed override byte Pop() => Bus.Read(SP++);
protected sealed override Register16 GetWord()
{
var returned = base.GetWord();
MEMPTR = Bus.Address;
return returned;
}
protected sealed override void SetWord(Register16 value)
{
base.SetWord(value);
MEMPTR = Bus.Address;
}
//
protected void Restart(byte address)
{
MEMPTR.Low = address;
MEMPTR.High = 0;
Call(MEMPTR);
}
protected bool CallConditional(bool condition)
{
MEMPTR = FetchWord();
if (condition)
Call(MEMPTR);
return condition;
}
protected bool JumpConditional(bool condition)
{
MEMPTR = FetchWord();
if (condition)
Jump(MEMPTR);
return condition;
}
protected bool ReturnConditional(bool condition)
{
if (condition)
Return();
return condition;
}
protected void JumpRelative(sbyte offset)
{
MEMPTR.Word = (ushort)(PC.Word + offset);
Jump(MEMPTR);
}
protected bool JumpRelativeConditional(bool condition)
{
var offset = (sbyte)FetchByte();
if (condition)
JumpRelative(offset);
return condition;
}
protected override sealed void Return()
{
base.Return();
MEMPTR = PC;
}
protected void Halt()
{
--PC;
LowerHALT();
}
protected void Proceed()
{
++PC;
RaiseHALT();
}
}
}
+83
View File
@@ -0,0 +1,83 @@
using System;
namespace EightBit
{
public abstract class LittleEndianProcessor : Processor
{
protected LittleEndianProcessor(Bus memory)
: base(memory)
{
}
public override Register16 PeekWord(Register16 address)
{
var low = Bus.Peek(address);
var high = Bus.Peek(++address);
return new Register16(low, high);
}
public override void PokeWord(Register16 address, Register16 value)
{
if (value == null)
throw new ArgumentNullException(nameof(value));
Bus.Poke(address, value.Low);
Bus.Poke(++address, value.High);
}
protected override Register16 FetchWord()
{
var low = FetchByte();
var high = FetchByte();
return new Register16(low, high);
}
protected override Register16 GetWord()
{
var low = BusRead();
++Bus.Address.Word;
var high = BusRead();
return new Register16(low, high);
}
protected override Register16 GetWordPaged(byte page, byte offset)
{
var low = GetBytePaged(page, offset);
++Bus.Address.Low;
var high = BusRead();
return new Register16(low, high);
}
protected override Register16 PopWord()
{
var low = Pop();
var high = Pop();
return new Register16(low, high);
}
protected override void PushWord(Register16 value)
{
if (value == null)
throw new ArgumentNullException(nameof(value));
Push(value.High);
Push(value.Low);
}
protected override void SetWord(Register16 value)
{
if (value == null)
throw new ArgumentNullException(nameof(value));
BusWrite(value.Low);
++Bus.Address.Word;
BusWrite(value.High);
}
protected override void SetWordPaged(byte page, byte offset, Register16 value)
{
if (value == null)
throw new ArgumentNullException(nameof(value));
SetBytePaged(page, offset, value.Low);
++Bus.Address.Low;
BusWrite(value.High);
}
}
}
+7
View File
@@ -0,0 +1,7 @@
namespace EightBit
{
public interface IMapper
{
MemoryMapping Mapping(Register16 address);
}
}
+25
View File
@@ -0,0 +1,25 @@
using System;
namespace EightBit
{
public enum Mask
{
None = 0,
Mask1 = Bits.Bit1 - 1,
Mask2 = Bits.Bit2 - 1,
Mask3 = Bits.Bit3 - 1,
Mask4 = Bits.Bit4 - 1,
Mask5 = Bits.Bit5 - 1,
Mask6 = Bits.Bit6 - 1,
Mask7 = Bits.Bit7 - 1,
Mask8 = Bits.Bit8 - 1,
Mask9 = Bits.Bit9 - 1,
Mask10 = Bits.Bit10 - 1,
Mask11 = Bits.Bit11 - 1,
Mask12 = Bits.Bit12 - 1,
Mask13 = Bits.Bit13 - 1,
Mask14 = Bits.Bit14 - 1,
Mask15 = Bits.Bit15 - 1,
Mask16 = Bits.Bit16 - 1
}
}
+26
View File
@@ -0,0 +1,26 @@
namespace EightBit
{
using System;
using System.IO;
public abstract class Memory
{
public abstract int Size
{
get;
}
public abstract byte Peek(ushort address);
public virtual ref byte Reference(ushort address)
{
throw new NotImplementedException();
}
public abstract int Load(FileStream file, int writeOffset = 0, int readOffset = 0, int limit = -1);
public abstract int Load(string path, int writeOffset = 0, int readOffset = 0, int limit = -1);
public abstract int Load(byte[] from, int writeOffset = 0, int readOffset = 0, int limit = -1);
protected abstract void Poke(ushort address, byte value);
}
}
+23
View File
@@ -0,0 +1,23 @@
namespace EightBit
{
public class MemoryMapping
{
private Memory memory;
private ushort begin;
private ushort mask;
private AccessLevel access;
public MemoryMapping(Memory memory, ushort begin, ushort mask, AccessLevel access)
{
this.memory = memory;
this.begin = begin;
this.mask = mask;
this.access = access;
}
public Memory Memory { get => memory; set => memory = value; }
public ushort Begin { get => begin; set => begin = value; }
public ushort Mask { get => mask; set => mask = value; }
public AccessLevel Access { get => access; set => access = value; }
}
}
+7
View File
@@ -0,0 +1,7 @@
namespace EightBit
{
public enum PinLevel
{
Low, High
}
}
+13
View File
@@ -0,0 +1,13 @@
namespace EightBit
{
public static class PinLevelExtensions
{
public static bool Raised(this PinLevel line) => line == PinLevel.High;
public static bool Lowered(this PinLevel line) => line == PinLevel.Low;
public static void Raise(this ref PinLevel line) => line = PinLevel.High;
public static void Lower(this ref PinLevel line) => line = PinLevel.Low;
}
}
+16
View File
@@ -0,0 +1,16 @@
using System;
namespace EightBit
{
public sealed class PortEventArgs : EventArgs
{
private byte port;
public PortEventArgs(byte value)
{
port = value;
}
public byte Port { get { return port; } }
}
}
+183
View File
@@ -0,0 +1,183 @@
namespace EightBit
{
using System;
public abstract class Processor : ClockedChip
{
private Bus bus;
private byte opcode;
private Register16 pc;
private PinLevel resetLine;
private PinLevel intLine;
protected Processor(Bus memory)
{
bus = memory;
pc = new Register16();
}
public event EventHandler<EventArgs> RaisingRESET;
public event EventHandler<EventArgs> RaisedRESET;
public event EventHandler<EventArgs> LoweringRESET;
public event EventHandler<EventArgs> LoweredRESET;
public event EventHandler<EventArgs> RaisingINT;
public event EventHandler<EventArgs> RaisedINT;
public event EventHandler<EventArgs> LoweringINT;
public event EventHandler<EventArgs> LoweredINT;
public Register16 PC { get => pc; set => pc = value; }
protected byte OpCode { get => opcode; set => opcode = value; }
public Bus Bus { get => bus; set => bus = value; }
public ref PinLevel RESET() { return ref resetLine; }
public ref PinLevel INT() { return ref intLine; }
public abstract int Step();
public abstract int Execute();
public int Run(int limit)
{
int current = 0;
while (Powered && (current < limit))
current += Step();
return current;
}
public int Execute(byte value)
{
OpCode = value;
return Execute();
}
public abstract Register16 PeekWord(Register16 address);
public abstract void PokeWord(Register16 address, Register16 value);
public Register16 PeekWord(byte low, byte high) => PeekWord(new Register16(low, high));
public Register16 PeekWord(ushort address) => PeekWord(LowByte(address), HighByte(address));
public virtual void RaiseRESET()
{
OnRaisingRESET();
RESET().Raise();
OnRaisedRESET();
}
public virtual void LowerRESET()
{
OnLoweringRESET();
RESET().Lower();
OnLoweredRESET();
}
public virtual void RaiseINT()
{
OnRaisingINT();
INT().Raise();
OnRaisedINT();
}
public virtual void LowerINT()
{
OnLoweringINT();
INT().Lower();
OnLoweredINT();
}
protected virtual void OnRaisingRESET() => RaisingRESET?.Invoke(this, EventArgs.Empty);
protected virtual void OnRaisedRESET() => RaisedRESET?.Invoke(this, EventArgs.Empty);
protected virtual void OnLoweringRESET() => LoweringRESET?.Invoke(this, EventArgs.Empty);
protected virtual void OnLoweredRESET() => LoweredRESET?.Invoke(this, EventArgs.Empty);
protected virtual void OnRaisingINT() => RaisingINT?.Invoke(this, EventArgs.Empty);
protected virtual void OnRaisedINT() => RaisedINT?.Invoke(this, EventArgs.Empty);
protected virtual void OnLoweringINT() => LoweringINT?.Invoke(this, EventArgs.Empty);
protected virtual void OnLoweredINT() => LoweredINT?.Invoke(this, EventArgs.Empty);
protected virtual void HandleRESET() => RaiseRESET();
protected virtual void HandleINT() => RaiseINT();
protected void BusWrite(byte low, byte data) => BusWrite(low, 0, data);
protected void BusWrite(Register16 address, byte data) => BusWrite(address.Low, address.High, data);
protected void BusWrite(byte low, byte high, byte data)
{
Bus.Address.Low = low;
Bus.Address.High = high;
BusWrite(data);
}
protected void BusWrite(byte data)
{
Bus.Data = data;
BusWrite();
}
protected virtual void BusWrite() => Bus.Write();
protected byte BusRead(byte low) => BusRead(low, 0);
protected byte BusRead(Register16 address) => BusRead(address.Low, address.High);
protected byte BusRead(byte low, byte high)
{
Bus.Address.Low = low;
Bus.Address.High = high;
return BusRead();
}
protected virtual byte BusRead() => Bus.Read();
protected byte GetBytePaged(byte page, byte offset) => BusRead(new Register16(offset, page));
protected void SetBytePaged(byte page, byte offset, byte value) => BusWrite(new Register16(offset, page), value);
protected byte FetchByte() => BusRead(PC++);
protected abstract Register16 GetWord();
protected abstract void SetWord(Register16 value);
protected abstract Register16 GetWordPaged(byte page, byte offset);
protected abstract void SetWordPaged(byte page, byte offset, Register16 value);
protected abstract Register16 FetchWord();
protected abstract void Push(byte value);
protected abstract byte Pop();
protected abstract void PushWord(Register16 value);
protected abstract Register16 PopWord();
protected Register16 GetWord(Register16 address)
{
Bus.Address.Word = address.Word;
return GetWord();
}
protected void SetWord(Register16 address, Register16 value)
{
Bus.Address.Word = address.Word;
SetWord(value);
}
protected void Jump(Register16 destination)
{
PC = destination;
}
protected void Call(Register16 destination)
{
PushWord(PC);
Jump(destination);
}
protected virtual void Return()
{
Jump(PopWord());
}
}
}
+36
View File
@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("EightBit")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("EightBit")]
[assembly: AssemblyCopyright("Copyright © 2019")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("6ebf8857-62a3-4ef4-af21-c1844031d7e4")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
+19
View File
@@ -0,0 +1,19 @@
namespace EightBit
{
public class Ram : Rom
{
public Ram(int size = 0)
: base(size)
{
}
public override sealed ref byte Reference(ushort address) {
return ref Bytes()[address];
}
public new void Poke(ushort address, byte value)
{
base.Poke(address, value);
}
}
}
+86
View File
@@ -0,0 +1,86 @@
namespace EightBit
{
public sealed class Register16
{
private byte low;
private byte high;
public Register16() { }
public Register16(ushort value) => Word = value;
public Register16(byte lowValue, byte highValue)
{
Low = lowValue;
High = highValue;
}
public byte Low { get => low; set => low = value; }
public byte High { get => high; set => high = value; }
public ushort Word
{
get
{
return (ushort)(Chip.PromoteByte(high) | low);
}
set
{
high = Chip.DemoteByte(value);
low = Chip.LowByte(value);
}
}
public static implicit operator ushort(Register16 value) { return ToUInt16(value); }
public static Register16 operator ++(Register16 left) => Increment(left);
public static Register16 operator --(Register16 left) => Decrement(left);
public static bool operator ==(Register16 left, Register16 right) => Equals(left, right);
public static bool operator !=(Register16 left, Register16 right) => !(left == right);
public static Register16 operator +(Register16 left, Register16 right) => Add(left, right);
public static Register16 operator -(Register16 left, Register16 right) => Subtract(left, right);
public static ushort ToUInt16(Register16 value) { return value.Word; }
public ushort ToUInt16() { return ToUInt16(this); }
public static Register16 Increment(Register16 left)
{
++left.Word;
return left;
}
public static Register16 Decrement(Register16 left)
{
--left.Word;
return left;
}
public static Register16 Add(Register16 left, Register16 right)
{
left.Word += right.Word;
return left;
}
public static Register16 Subtract(Register16 left, Register16 right)
{
left.Word -= right.Word;
return left;
}
public override int GetHashCode() => Word;
public override bool Equals(object obj)
{
var register = obj as Register16;
return Equals(register);
}
public bool Equals(Register16 register)
{
return register != null && low == register.low && high == register.high;
}
}
}
+87
View File
@@ -0,0 +1,87 @@
namespace EightBit
{
using System;
using System.IO;
public class Rom : Memory
{
private byte[] bytes;
public Rom(int size) => bytes = new byte[size];
public Rom() : this(0) { }
public override int Size { get { return bytes.Length; } }
protected ref byte[] Bytes() { return ref bytes; }
static public int Load(FileStream file, ref byte[] output, int writeOffset = 0, int readOffset = 0, int limit = -1, int maximumSize = -1)
{
var size = (int)file.Length;
if ((maximumSize > 0) && ((size - readOffset) > maximumSize))
throw new InvalidOperationException("File is too large");
if ((limit < 0) || (limit > size))
limit = (int)size;
var extent = limit + writeOffset;
if (output.Length < extent)
{
var updated = new byte[extent];
Array.Copy(output, updated, output.Length);
output = updated;
}
file.Seek(readOffset, SeekOrigin.Begin);
using (var reader = new BinaryReader(file))
{
reader.Read(output, writeOffset, size);
}
return size;
}
public static int Load(string path, ref byte[] output, int writeOffset = 0, int readOffset = 0, int limit = -1, int maximumSize = -1)
{
using (var file = File.Open(path, FileMode.Open))
{
return Load(file, ref output, writeOffset, readOffset, limit, maximumSize);
}
}
public override int Load(FileStream file, int writeOffset = 0, int readOffset = 0, int limit = -1)
{
var maximumSize = Size - writeOffset;
return Load(file, ref Bytes(), writeOffset, readOffset, limit, maximumSize);
}
public override int Load(string path, int writeOffset = 0, int readOffset = 0, int limit = -1)
{
var maximumSize = Size - writeOffset;
return Load(path, ref Bytes(), writeOffset, readOffset, limit, maximumSize);
}
public override int Load(byte[] from, int writeOffset = 0, int readOffset = 0, int limit = -1)
{
if (limit < 0)
limit = Size - readOffset;
var extent = limit + writeOffset;
if (Size < extent)
{
var updated = new byte[extent];
Array.Copy(Bytes(), updated, Size);
Bytes() = updated;
}
Array.Copy(from, readOffset, Bytes(), writeOffset, limit);
return limit;
}
public override byte Peek(ushort address) => Bytes()[address];
protected override void Poke(ushort address, byte value) => Bytes()[address] = value;
}
}
+25
View File
@@ -0,0 +1,25 @@
namespace EightBit
{
using System.IO;
public class UnusedMemory : Memory
{
private readonly int size;
private readonly byte unchanging;
UnusedMemory(int size, byte unchanging)
{
this.size = size;
this.unchanging = unchanging;
}
public override int Size => size;
public override int Load(FileStream file, int writeOffset = 0, int readOffset = 0, int limit = -1) => throw new System.NotImplementedException();
public override int Load(string path, int writeOffset = 0, int readOffset = 0, int limit = -1) => throw new System.NotImplementedException();
public override int Load(byte[] from, int writeOffset = 0, int readOffset = 0, int limit = -1) => throw new System.NotImplementedException();
public override byte Peek(ushort address) => unchanging;
protected override void Poke(ushort address, byte value) => throw new System.NotImplementedException();
}
}