2019-02-04 23:52:21 +00:00
|
|
|
|
// <copyright file="IntelProcessor.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 IntelProcessor : LittleEndianProcessor
|
|
|
|
|
{
|
2019-02-16 21:32:34 +00:00
|
|
|
|
private static readonly int[] HalfCarryTableAdd = new int[8] { 0, 0, 1, 0, 1, 0, 1, 1 };
|
|
|
|
|
private static readonly int[] HalfCarryTableSub = new int[8] { 0, 1, 1, 1, 0, 0, 0, 1 };
|
|
|
|
|
|
2019-02-03 20:29:52 +00:00
|
|
|
|
private readonly IntelOpCodeDecoded[] decodedOpCodes = new IntelOpCodeDecoded[0x100];
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
|
|
|
|
private PinLevel haltLine;
|
|
|
|
|
|
|
|
|
|
protected IntelProcessor(Bus bus)
|
|
|
|
|
: base(bus)
|
|
|
|
|
{
|
2019-02-22 22:33:51 +00:00
|
|
|
|
for (var i = 0; i < 0x100; ++i)
|
2019-02-04 23:52:21 +00:00
|
|
|
|
{
|
|
|
|
|
this.decodedOpCodes[i] = new IntelOpCodeDecoded((byte)i);
|
|
|
|
|
}
|
2019-02-02 15:12:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public event EventHandler<EventArgs> RaisingHALT;
|
2019-02-04 23:52:21 +00:00
|
|
|
|
|
2019-02-02 15:12:51 +00:00
|
|
|
|
public event EventHandler<EventArgs> RaisedHALT;
|
2019-02-04 23:52:21 +00:00
|
|
|
|
|
2019-02-02 15:12:51 +00:00
|
|
|
|
public event EventHandler<EventArgs> LoweringHALT;
|
|
|
|
|
|
2019-02-04 23:52:21 +00:00
|
|
|
|
public event EventHandler<EventArgs> LoweredHALT;
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-21 19:58:49 +00:00
|
|
|
|
public Register16 SP { get; } = new Register16((ushort)Mask.Mask16);
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-21 19:58:49 +00:00
|
|
|
|
public Register16 MEMPTR { get; } = new Register16((ushort)Mask.Mask16);
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-21 19:58:49 +00:00
|
|
|
|
public abstract Register16 AF { get; }
|
2019-02-04 23:52:21 +00:00
|
|
|
|
|
2019-02-21 19:58:49 +00:00
|
|
|
|
public byte A { get => this.AF.High; set => this.AF.High = value; }
|
2019-02-04 23:52:21 +00:00
|
|
|
|
|
2019-02-21 19:58:49 +00:00
|
|
|
|
public byte F { get => this.AF.Low; set => this.AF.Low = value; }
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-21 19:58:49 +00:00
|
|
|
|
public abstract Register16 BC { get; }
|
2019-02-04 23:52:21 +00:00
|
|
|
|
|
2019-02-21 19:58:49 +00:00
|
|
|
|
public byte B { get => this.BC.High; set => this.BC.High = value; }
|
2019-02-04 23:52:21 +00:00
|
|
|
|
|
2019-02-21 19:58:49 +00:00
|
|
|
|
public byte C { get => this.BC.Low; set => this.BC.Low = value; }
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-21 19:58:49 +00:00
|
|
|
|
public abstract Register16 DE { get; }
|
2019-02-04 23:52:21 +00:00
|
|
|
|
|
2019-02-21 19:58:49 +00:00
|
|
|
|
public byte D { get => this.DE.High; set => this.DE.High = value; }
|
2019-02-04 23:52:21 +00:00
|
|
|
|
|
2019-02-21 19:58:49 +00:00
|
|
|
|
public byte E { get => this.DE.Low; set => this.DE.Low = value; }
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-21 19:58:49 +00:00
|
|
|
|
public abstract Register16 HL { get; }
|
2019-02-04 23:52:21 +00:00
|
|
|
|
|
2019-02-21 19:58:49 +00:00
|
|
|
|
public byte H { get => this.HL.High; set => this.HL.High = value; }
|
2019-02-04 23:52:21 +00:00
|
|
|
|
|
2019-02-21 19:58:49 +00:00
|
|
|
|
public byte L { get => this.HL.Low; set => this.HL.Low = value; }
|
2019-02-04 23:52:21 +00:00
|
|
|
|
|
2019-02-21 19:58:49 +00:00
|
|
|
|
protected bool Halted => this.HALT().Lowered();
|
2019-02-04 23:52:21 +00:00
|
|
|
|
|
|
|
|
|
public ref PinLevel HALT() => ref this.haltLine;
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-18 00:52:45 +00:00
|
|
|
|
public IntelOpCodeDecoded GetDecodedOpCode(byte opCode) => this.decodedOpCodes[opCode];
|
|
|
|
|
|
2019-02-02 15:12:51 +00:00
|
|
|
|
public override void RaisePOWER()
|
|
|
|
|
{
|
|
|
|
|
base.RaisePOWER();
|
2019-02-04 23:52:21 +00:00
|
|
|
|
this.RaiseHALT();
|
2019-02-21 19:58:49 +00:00
|
|
|
|
this.SP.Word = this.AF.Word = this.BC.Word = this.DE.Word = this.HL.Word = (ushort)Mask.Mask16;
|
2019-02-02 15:12:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual void RaiseHALT()
|
|
|
|
|
{
|
2019-02-04 23:52:21 +00:00
|
|
|
|
this.OnRaisingHALT();
|
|
|
|
|
this.HALT().Raise();
|
|
|
|
|
this.OnRaisedHALT();
|
2019-02-02 15:12:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual void LowerHALT()
|
|
|
|
|
{
|
2019-02-04 23:52:21 +00:00
|
|
|
|
this.OnLoweringHALT();
|
|
|
|
|
this.HALT().Lower();
|
|
|
|
|
this.OnLoweredHALT();
|
2019-02-02 15:12:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-22 22:33:51 +00:00
|
|
|
|
protected static int BuildHalfCarryIndex(byte before, byte value, int calculation) => ((before & 0x88) >> 1) | ((value & 0x88) >> 2) | ((calculation & 0x88) >> 3);
|
2019-02-16 21:32:34 +00:00
|
|
|
|
|
|
|
|
|
protected static int CalculateHalfCarryAdd(byte before, byte value, int calculation)
|
|
|
|
|
{
|
|
|
|
|
var index = BuildHalfCarryIndex(before, value, calculation);
|
|
|
|
|
return HalfCarryTableAdd[index & (int)Mask.Mask3];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected static int CalculateHalfCarrySub(byte before, byte value, int calculation)
|
|
|
|
|
{
|
|
|
|
|
var index = BuildHalfCarryIndex(before, value, calculation);
|
|
|
|
|
return HalfCarryTableSub[index & (int)Mask.Mask3];
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-04 23:52:21 +00:00
|
|
|
|
protected virtual void OnRaisingHALT() => this.RaisingHALT?.Invoke(this, EventArgs.Empty);
|
|
|
|
|
|
|
|
|
|
protected virtual void OnRaisedHALT() => this.RaisedHALT?.Invoke(this, EventArgs.Empty);
|
|
|
|
|
|
|
|
|
|
protected virtual void OnLoweringHALT() => this.LoweringHALT?.Invoke(this, EventArgs.Empty);
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-04 23:52:21 +00:00
|
|
|
|
protected virtual void OnLoweredHALT() => this.LoweredHALT?.Invoke(this, EventArgs.Empty);
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
|
|
|
|
protected override void HandleRESET()
|
|
|
|
|
{
|
|
|
|
|
base.HandleRESET();
|
2019-02-15 00:26:01 +00:00
|
|
|
|
this.Jump(0);
|
2019-02-02 15:12:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-22 19:59:42 +00:00
|
|
|
|
protected sealed override void Push(byte value) => this.BusWrite(--this.SP.Word, value);
|
2019-02-04 23:52:21 +00:00
|
|
|
|
|
2019-02-22 19:59:42 +00:00
|
|
|
|
protected sealed override byte Pop() => this.BusRead(this.SP.Word++);
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
2019-02-14 23:01:31 +00:00
|
|
|
|
protected sealed override Register16 GetWord()
|
2019-02-02 15:12:51 +00:00
|
|
|
|
{
|
|
|
|
|
var returned = base.GetWord();
|
2019-02-21 19:58:49 +00:00
|
|
|
|
this.MEMPTR.Word = this.Bus.Address.Word;
|
2019-02-04 23:52:21 +00:00
|
|
|
|
return returned;
|
2019-02-02 15:12:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-14 23:01:31 +00:00
|
|
|
|
protected sealed override void SetWord(Register16 value)
|
2019-02-02 15:12:51 +00:00
|
|
|
|
{
|
|
|
|
|
base.SetWord(value);
|
2019-02-21 19:58:49 +00:00
|
|
|
|
this.MEMPTR.Word = this.Bus.Address.Word;
|
2019-02-02 15:12:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-04 23:52:21 +00:00
|
|
|
|
////
|
2019-02-02 15:12:51 +00:00
|
|
|
|
|
|
|
|
|
protected void Restart(byte address)
|
|
|
|
|
{
|
2019-02-21 19:58:49 +00:00
|
|
|
|
this.MEMPTR.Low = address;
|
|
|
|
|
this.MEMPTR.High = 0;
|
2019-03-07 01:21:00 +00:00
|
|
|
|
this.Call(this.MEMPTR.Word);
|
2019-02-02 15:12:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected bool CallConditional(bool condition)
|
|
|
|
|
{
|
2019-02-21 19:58:49 +00:00
|
|
|
|
this.MEMPTR.Word = this.FetchWord().Word;
|
2019-02-02 15:12:51 +00:00
|
|
|
|
if (condition)
|
2019-02-04 23:52:21 +00:00
|
|
|
|
{
|
2019-03-07 01:21:00 +00:00
|
|
|
|
this.Call(this.MEMPTR.Word);
|
2019-02-04 23:52:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-02 15:12:51 +00:00
|
|
|
|
return condition;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected bool JumpConditional(bool condition)
|
|
|
|
|
{
|
2019-02-21 19:58:49 +00:00
|
|
|
|
this.MEMPTR.Word = this.FetchWord().Word;
|
2019-02-02 15:12:51 +00:00
|
|
|
|
if (condition)
|
2019-02-04 23:52:21 +00:00
|
|
|
|
{
|
2019-03-07 01:21:00 +00:00
|
|
|
|
this.Jump(this.MEMPTR.Word);
|
2019-02-04 23:52:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-02 15:12:51 +00:00
|
|
|
|
return condition;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected bool ReturnConditional(bool condition)
|
|
|
|
|
{
|
|
|
|
|
if (condition)
|
2019-02-04 23:52:21 +00:00
|
|
|
|
{
|
|
|
|
|
this.Return();
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-02 15:12:51 +00:00
|
|
|
|
return condition;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void JumpRelative(sbyte offset)
|
|
|
|
|
{
|
2019-02-21 19:58:49 +00:00
|
|
|
|
this.MEMPTR.Word = (ushort)(this.PC.Word + offset);
|
2019-03-07 01:21:00 +00:00
|
|
|
|
this.Jump(this.MEMPTR.Word);
|
2019-02-02 15:12:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected bool JumpRelativeConditional(bool condition)
|
|
|
|
|
{
|
2019-02-04 23:52:21 +00:00
|
|
|
|
var offset = (sbyte)this.FetchByte();
|
2019-02-02 15:12:51 +00:00
|
|
|
|
if (condition)
|
2019-02-04 23:52:21 +00:00
|
|
|
|
{
|
|
|
|
|
this.JumpRelative(offset);
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-02 15:12:51 +00:00
|
|
|
|
return condition;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override sealed void Return()
|
|
|
|
|
{
|
|
|
|
|
base.Return();
|
2019-02-21 19:58:49 +00:00
|
|
|
|
this.MEMPTR.Word = this.PC.Word;
|
2019-02-02 15:12:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void Halt()
|
|
|
|
|
{
|
2019-02-21 19:58:49 +00:00
|
|
|
|
--this.PC.Word;
|
2019-02-04 23:52:21 +00:00
|
|
|
|
this.LowerHALT();
|
2019-02-02 15:12:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void Proceed()
|
|
|
|
|
{
|
2019-02-21 19:58:49 +00:00
|
|
|
|
++this.PC.Word;
|
2019-02-04 23:52:21 +00:00
|
|
|
|
this.RaiseHALT();
|
2019-02-02 15:12:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|