2019-02-02 15:12:51 +00:00
|
|
|
|
namespace EightBit
|
|
|
|
|
{
|
|
|
|
|
using System;
|
|
|
|
|
|
|
|
|
|
public abstract class Processor : ClockedChip
|
|
|
|
|
{
|
2019-02-03 20:49:07 +00:00
|
|
|
|
private readonly Bus bus;
|
2019-02-02 15:12:51 +00:00
|
|
|
|
private byte opcode;
|
2019-02-03 20:49:07 +00:00
|
|
|
|
private ushort pc = 0;
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
|
|
|
|
private PinLevel resetLine;
|
|
|
|
|
private PinLevel intLine;
|
|
|
|
|
|
|
|
|
|
protected Processor(Bus memory)
|
|
|
|
|
{
|
|
|
|
|
bus = memory;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
2019-02-03 00:42:55 +00:00
|
|
|
|
public ushort PC { get => pc; set => pc = value; }
|
2019-02-02 15:12:51 +00:00
|
|
|
|
protected byte OpCode { get => opcode; set => opcode = value; }
|
2019-02-03 20:49:07 +00:00
|
|
|
|
public Bus Bus { get => bus; }
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-03 20:29:52 +00:00
|
|
|
|
public ref PinLevel RESET() => ref resetLine;
|
|
|
|
|
public ref PinLevel INT() => ref intLine;
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-03 00:42:55 +00:00
|
|
|
|
public abstract ushort PeekWord(ushort address);
|
|
|
|
|
public abstract void PokeWord(ushort address, ushort value);
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-03 00:42:55 +00:00
|
|
|
|
public ushort PeekWord(byte low, byte high) => PeekWord((ushort)(PromoteByte(high) | low));
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
|
2019-02-03 00:42:55 +00:00
|
|
|
|
#region BusWrite
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-03 20:29:52 +00:00
|
|
|
|
protected void BusWrite(byte low, byte high, byte data) => BusWrite(MakeWord(low, high), data);
|
2019-02-03 00:42:55 +00:00
|
|
|
|
|
|
|
|
|
protected void BusWrite(ushort address, byte data)
|
|
|
|
|
{
|
|
|
|
|
Bus.Address = address;
|
2019-02-02 15:12:51 +00:00
|
|
|
|
BusWrite(data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void BusWrite(byte data)
|
|
|
|
|
{
|
|
|
|
|
Bus.Data = data;
|
|
|
|
|
BusWrite();
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-03 00:42:55 +00:00
|
|
|
|
protected virtual void BusWrite() => Bus.Write(); // N.B. Should be the only real call into the "Bus.Write" code.
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-03 00:42:55 +00:00
|
|
|
|
#endregion
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-03 00:42:55 +00:00
|
|
|
|
#region BusRead
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-03 20:29:52 +00:00
|
|
|
|
protected byte BusRead(byte low, byte high) => BusRead(MakeWord(low, high));
|
2019-02-03 00:42:55 +00:00
|
|
|
|
|
|
|
|
|
protected byte BusRead(ushort address)
|
|
|
|
|
{
|
|
|
|
|
Bus.Address = address;
|
2019-02-02 15:12:51 +00:00
|
|
|
|
return BusRead();
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-03 00:42:55 +00:00
|
|
|
|
protected virtual byte BusRead() => Bus.Read(); // N.B. Should be the only real call into the "Bus.Read" code.
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2019-02-02 15:12:51 +00:00
|
|
|
|
protected byte FetchByte() => BusRead(PC++);
|
|
|
|
|
|
2019-02-03 00:42:55 +00:00
|
|
|
|
protected abstract ushort GetWord();
|
|
|
|
|
protected abstract void SetWord(ushort value);
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-03 00:42:55 +00:00
|
|
|
|
protected abstract ushort GetWordPaged(byte page, byte offset);
|
|
|
|
|
protected abstract void SetWordPaged(byte page, byte offset, ushort value);
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-03 00:42:55 +00:00
|
|
|
|
protected abstract ushort FetchWord();
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
|
|
|
|
protected abstract void Push(byte value);
|
|
|
|
|
protected abstract byte Pop();
|
|
|
|
|
|
2019-02-03 00:42:55 +00:00
|
|
|
|
protected abstract void PushWord(ushort value);
|
|
|
|
|
protected abstract ushort PopWord();
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-03 00:42:55 +00:00
|
|
|
|
protected ushort GetWord(ushort address)
|
2019-02-02 15:12:51 +00:00
|
|
|
|
{
|
2019-02-03 00:42:55 +00:00
|
|
|
|
Bus.Address = address;
|
2019-02-02 15:12:51 +00:00
|
|
|
|
return GetWord();
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-03 00:42:55 +00:00
|
|
|
|
protected void SetWord(ushort address, ushort value)
|
2019-02-02 15:12:51 +00:00
|
|
|
|
{
|
2019-02-03 00:42:55 +00:00
|
|
|
|
Bus.Address = address;
|
2019-02-02 15:12:51 +00:00
|
|
|
|
SetWord(value);
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-03 20:29:52 +00:00
|
|
|
|
protected void Jump(ushort destination) => PC = destination;
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-03 00:42:55 +00:00
|
|
|
|
protected void Call(ushort destination)
|
2019-02-02 15:12:51 +00:00
|
|
|
|
{
|
|
|
|
|
PushWord(PC);
|
|
|
|
|
Jump(destination);
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-03 20:29:52 +00:00
|
|
|
|
protected virtual void Return() => Jump(PopWord());
|
2019-02-02 15:12:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|