2019-02-04 23:52:21 +00:00
|
|
|
|
// <copyright file="Processor.cs" company="Adrian Conlon">
|
|
|
|
|
// Copyright (c) Adrian Conlon. All rights reserved.
|
|
|
|
|
// </copyright>
|
|
|
|
|
|
|
|
|
|
namespace EightBit
|
2019-02-02 15:12:51 +00:00
|
|
|
|
{
|
|
|
|
|
using System;
|
|
|
|
|
|
|
|
|
|
public abstract class Processor : ClockedChip
|
|
|
|
|
{
|
|
|
|
|
private PinLevel resetLine;
|
|
|
|
|
private PinLevel intLine;
|
|
|
|
|
|
|
|
|
|
protected Processor(Bus memory)
|
|
|
|
|
{
|
2019-02-06 23:41:56 +00:00
|
|
|
|
this.Bus = memory;
|
2019-02-02 15:12:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public event EventHandler<EventArgs> RaisingRESET;
|
2019-02-04 23:52:21 +00:00
|
|
|
|
|
2019-02-02 15:12:51 +00:00
|
|
|
|
public event EventHandler<EventArgs> RaisedRESET;
|
2019-02-04 23:52:21 +00:00
|
|
|
|
|
2019-02-02 15:12:51 +00:00
|
|
|
|
public event EventHandler<EventArgs> LoweringRESET;
|
2019-02-04 23:52:21 +00:00
|
|
|
|
|
2019-02-02 15:12:51 +00:00
|
|
|
|
public event EventHandler<EventArgs> LoweredRESET;
|
|
|
|
|
|
|
|
|
|
public event EventHandler<EventArgs> RaisingINT;
|
2019-02-04 23:52:21 +00:00
|
|
|
|
|
2019-02-02 15:12:51 +00:00
|
|
|
|
public event EventHandler<EventArgs> RaisedINT;
|
2019-02-04 23:52:21 +00:00
|
|
|
|
|
2019-02-02 15:12:51 +00:00
|
|
|
|
public event EventHandler<EventArgs> LoweringINT;
|
2019-02-04 23:52:21 +00:00
|
|
|
|
|
2019-02-02 15:12:51 +00:00
|
|
|
|
public event EventHandler<EventArgs> LoweredINT;
|
|
|
|
|
|
2019-02-06 23:41:56 +00:00
|
|
|
|
public Bus Bus { get; }
|
2019-02-04 23:52:21 +00:00
|
|
|
|
|
2019-02-21 19:58:49 +00:00
|
|
|
|
public Register16 PC { get; } = new Register16();
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-21 19:58:49 +00:00
|
|
|
|
protected byte OpCode { get; set; }
|
2019-02-14 23:01:31 +00:00
|
|
|
|
|
2019-02-04 23:52:21 +00:00
|
|
|
|
public ref PinLevel RESET() => ref this.resetLine;
|
|
|
|
|
|
|
|
|
|
public ref PinLevel INT() => ref this.intLine;
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
|
|
|
|
public abstract int Step();
|
2019-02-04 23:52:21 +00:00
|
|
|
|
|
2019-02-02 15:12:51 +00:00
|
|
|
|
public abstract int Execute();
|
|
|
|
|
|
|
|
|
|
public int Run(int limit)
|
|
|
|
|
{
|
|
|
|
|
int current = 0;
|
2019-02-04 23:52:21 +00:00
|
|
|
|
while (this.Powered && (current < limit))
|
|
|
|
|
{
|
|
|
|
|
current += this.Step();
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-02 15:12:51 +00:00
|
|
|
|
return current;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int Execute(byte value)
|
|
|
|
|
{
|
2019-02-04 23:52:21 +00:00
|
|
|
|
this.OpCode = value;
|
|
|
|
|
return this.Execute();
|
2019-02-02 15:12:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-14 23:01:31 +00:00
|
|
|
|
public abstract Register16 PeekWord(ushort address);
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-14 23:01:31 +00:00
|
|
|
|
public abstract void PokeWord(ushort address, Register16 value);
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
|
|
|
|
public virtual void RaiseRESET()
|
|
|
|
|
{
|
2019-02-04 23:52:21 +00:00
|
|
|
|
this.OnRaisingRESET();
|
|
|
|
|
this.RESET().Raise();
|
|
|
|
|
this.OnRaisedRESET();
|
2019-02-02 15:12:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual void LowerRESET()
|
|
|
|
|
{
|
2019-02-04 23:52:21 +00:00
|
|
|
|
this.OnLoweringRESET();
|
|
|
|
|
this.RESET().Lower();
|
|
|
|
|
this.OnLoweredRESET();
|
2019-02-02 15:12:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual void RaiseINT()
|
|
|
|
|
{
|
2019-02-04 23:52:21 +00:00
|
|
|
|
this.OnRaisingINT();
|
|
|
|
|
this.INT().Raise();
|
|
|
|
|
this.OnRaisedINT();
|
2019-02-02 15:12:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual void LowerINT()
|
|
|
|
|
{
|
2019-02-04 23:52:21 +00:00
|
|
|
|
this.OnLoweringINT();
|
|
|
|
|
this.INT().Lower();
|
|
|
|
|
this.OnLoweredINT();
|
2019-02-02 15:12:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-04 23:52:21 +00:00
|
|
|
|
protected virtual void OnRaisingRESET() => this.RaisingRESET?.Invoke(this, EventArgs.Empty);
|
|
|
|
|
|
|
|
|
|
protected virtual void OnRaisedRESET() => this.RaisedRESET?.Invoke(this, EventArgs.Empty);
|
|
|
|
|
|
|
|
|
|
protected virtual void OnLoweringRESET() => this.LoweringRESET?.Invoke(this, EventArgs.Empty);
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-04 23:52:21 +00:00
|
|
|
|
protected virtual void OnLoweredRESET() => this.LoweredRESET?.Invoke(this, EventArgs.Empty);
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-04 23:52:21 +00:00
|
|
|
|
protected virtual void OnRaisingINT() => this.RaisingINT?.Invoke(this, EventArgs.Empty);
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-04 23:52:21 +00:00
|
|
|
|
protected virtual void OnRaisedINT() => this.RaisedINT?.Invoke(this, EventArgs.Empty);
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-04 23:52:21 +00:00
|
|
|
|
protected virtual void OnLoweringINT() => this.LoweringINT?.Invoke(this, EventArgs.Empty);
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-04 23:52:21 +00:00
|
|
|
|
protected virtual void OnLoweredINT() => this.LoweredINT?.Invoke(this, EventArgs.Empty);
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-04 23:52:21 +00:00
|
|
|
|
protected virtual void HandleRESET() => this.RaiseRESET();
|
|
|
|
|
|
|
|
|
|
protected virtual void HandleINT() => this.RaiseINT();
|
|
|
|
|
|
2019-02-14 23:01:31 +00:00
|
|
|
|
protected void BusWrite(byte low, byte high, byte data)
|
|
|
|
|
{
|
2019-02-21 19:58:49 +00:00
|
|
|
|
this.Bus.Address.Low = low;
|
|
|
|
|
this.Bus.Address.High = high;
|
2019-02-14 23:01:31 +00:00
|
|
|
|
this.BusWrite(data);
|
|
|
|
|
}
|
2019-02-03 00:42:55 +00:00
|
|
|
|
|
|
|
|
|
protected void BusWrite(ushort address, byte data)
|
|
|
|
|
{
|
2019-02-21 19:58:49 +00:00
|
|
|
|
this.Bus.Address.Word = address;
|
2019-02-04 23:52:21 +00:00
|
|
|
|
this.BusWrite(data);
|
2019-02-02 15:12:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-15 00:26:01 +00:00
|
|
|
|
protected void BusWrite(Register16 address, byte data) => this.BusWrite(address.Word, data);
|
|
|
|
|
|
2019-02-02 15:12:51 +00:00
|
|
|
|
protected void BusWrite(byte data)
|
|
|
|
|
{
|
2019-02-04 23:52:21 +00:00
|
|
|
|
this.Bus.Data = data;
|
|
|
|
|
this.BusWrite();
|
2019-02-02 15:12:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-04 23:52:21 +00:00
|
|
|
|
protected virtual void BusWrite() => this.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-14 23:01:31 +00:00
|
|
|
|
protected byte BusRead(byte low, byte high)
|
|
|
|
|
{
|
2019-02-21 19:58:49 +00:00
|
|
|
|
this.Bus.Address.Low = low;
|
|
|
|
|
this.Bus.Address.High = high;
|
2019-02-14 23:01:31 +00:00
|
|
|
|
return this.BusRead();
|
|
|
|
|
}
|
2019-02-03 00:42:55 +00:00
|
|
|
|
|
|
|
|
|
protected byte BusRead(ushort address)
|
|
|
|
|
{
|
2019-02-21 19:58:49 +00:00
|
|
|
|
this.Bus.Address.Word = address;
|
2019-02-04 23:52:21 +00:00
|
|
|
|
return this.BusRead();
|
2019-02-02 15:12:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-15 00:26:01 +00:00
|
|
|
|
protected byte BusRead(Register16 address) => this.BusRead(address.Word);
|
|
|
|
|
|
2019-02-04 23:52:21 +00:00
|
|
|
|
protected virtual byte BusRead() => this.Bus.Read(); // N.B. Should be the only real call into the "Bus.Read" code.
|
2019-02-03 00:42:55 +00:00
|
|
|
|
|
2019-02-21 19:58:49 +00:00
|
|
|
|
protected byte FetchByte() => this.BusRead(this.PC.Word++);
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-14 23:01:31 +00:00
|
|
|
|
protected abstract Register16 GetWord();
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-14 23:01:31 +00:00
|
|
|
|
protected abstract void SetWord(Register16 value);
|
2019-02-04 23:52:21 +00:00
|
|
|
|
|
2019-02-14 23:01:31 +00:00
|
|
|
|
protected abstract Register16 GetWordPaged(byte page, byte offset);
|
2019-02-04 23:52:21 +00:00
|
|
|
|
|
2019-02-14 23:01:31 +00:00
|
|
|
|
protected abstract void SetWordPaged(byte page, byte offset, Register16 value);
|
2019-02-04 23:52:21 +00:00
|
|
|
|
|
2019-02-14 23:01:31 +00:00
|
|
|
|
protected abstract Register16 FetchWord();
|
2019-02-04 23:52:21 +00:00
|
|
|
|
|
|
|
|
|
protected abstract void Push(byte value);
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-04 23:52:21 +00:00
|
|
|
|
protected abstract byte Pop();
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-14 23:01:31 +00:00
|
|
|
|
protected abstract void PushWord(Register16 value);
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-14 23:01:31 +00:00
|
|
|
|
protected abstract Register16 PopWord();
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-14 23:01:31 +00:00
|
|
|
|
protected Register16 GetWord(ushort address)
|
2019-02-02 15:12:51 +00:00
|
|
|
|
{
|
2019-02-21 19:58:49 +00:00
|
|
|
|
this.Bus.Address.Word = address;
|
2019-02-04 23:52:21 +00:00
|
|
|
|
return this.GetWord();
|
2019-02-02 15:12:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-14 23:01:31 +00:00
|
|
|
|
protected void SetWord(ushort address, Register16 value)
|
2019-02-02 15:12:51 +00:00
|
|
|
|
{
|
2019-02-21 19:58:49 +00:00
|
|
|
|
this.Bus.Address.Word = address;
|
2019-02-04 23:52:21 +00:00
|
|
|
|
this.SetWord(value);
|
2019-02-02 15:12:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-21 19:58:49 +00:00
|
|
|
|
protected void Jump(ushort destination) => this.PC.Word = destination;
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-15 00:26:01 +00:00
|
|
|
|
protected void Jump(Register16 destination) => this.Jump(destination.Word);
|
|
|
|
|
|
2019-02-03 00:42:55 +00:00
|
|
|
|
protected void Call(ushort destination)
|
2019-02-02 15:12:51 +00:00
|
|
|
|
{
|
2019-02-21 19:58:49 +00:00
|
|
|
|
this.PushWord(this.PC);
|
2019-02-04 23:52:21 +00:00
|
|
|
|
this.Jump(destination);
|
2019-02-02 15:12:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-15 00:26:01 +00:00
|
|
|
|
protected void Call(Register16 destination) => this.Call(destination.Word);
|
|
|
|
|
|
2019-02-14 23:01:31 +00:00
|
|
|
|
protected virtual void Return() => this.Jump(this.PopWord().Word);
|
2019-02-02 15:12:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|