mirror of
https://github.com/MoleskiCoder/EightBitNet.git
synced 2026-04-20 21:16:29 +00:00
Port of EightBit library to .Net (unworking!)
Signed-off-by: Adrian Conlon <Adrian.conlon@gmail.com>
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
namespace EightBit
|
||||
{
|
||||
public enum AccessLevel
|
||||
{
|
||||
Unknown, ReadOnly, WriteOnly, ReadWrite
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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.
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace EightBit
|
||||
{
|
||||
public interface IMapper
|
||||
{
|
||||
MemoryMapping Mapping(Register16 address);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace EightBit
|
||||
{
|
||||
public enum PinLevel
|
||||
{
|
||||
Low, High
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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; } }
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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")]
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user