Simplifications and refactorings in th intel processors

This commit is contained in:
Adrian Conlon
2025-05-05 21:06:39 +01:00
parent 37431d08bc
commit e1696721f6
4 changed files with 201 additions and 241 deletions
+10 -10
View File
@@ -173,7 +173,7 @@ namespace Intel8080
3 => this.E,
4 => this.H,
5 => this.L,
6 => this.MemoryRead(this.HL.Word),
6 => this.MemoryRead(this.HL),
7 => this.A,
_ => throw new ArgumentOutOfRangeException(nameof(r)),
};
@@ -201,7 +201,7 @@ namespace Intel8080
this.L = value;
break;
case 6:
this.MemoryWrite(this.HL.Word, value);
this.MemoryWrite(this.HL, value);
break;
case 7:
this.A = value;
@@ -251,7 +251,7 @@ namespace Intel8080
switch (q)
{
case 0: // LD rp,nn
this.RP(p).Word = this.FetchWord().Word;
this.RP(p).Assign(this.FetchWord());
this.Tick(10);
break;
case 1: // ADD HL,rp
@@ -278,12 +278,12 @@ namespace Intel8080
this.Tick(7);
break;
case 2: // LD (nn),HL
this.Bus.Address.Word = this.FetchWord().Word;
this.Bus.Address.Assign(this.FetchWord());
this.SetWord(this.HL);
this.Tick(16);
break;
case 3: // LD (nn),A
this.Bus.Address.Word = this.FetchWord().Word;
this.Bus.Address.Assign(this.FetchWord());
this.MemoryWrite(this.A);
this.Tick(13);
break;
@@ -304,12 +304,12 @@ namespace Intel8080
this.Tick(7);
break;
case 2: // LD HL,(nn)
this.Bus.Address.Word = this.FetchWord().Word;
this.HL.Word = this.GetWord().Word;
this.Bus.Address.Assign(this.FetchWord());
this.HL.Assign(this.GetWord());
this.Tick(16);
break;
case 3: // LD A,(nn)
this.Bus.Address.Word = this.FetchWord().Word;
this.Bus.Address.Assign(this.FetchWord());
this.A = this.MemoryRead();
this.Tick(13);
break;
@@ -467,7 +467,7 @@ namespace Intel8080
switch (q)
{
case 0: // POP rp2[p]
this.RP2(p).Word = this.PopWord().Word;
this.RP2(p).Assign(this.PopWord());
this.Tick(10);
break;
case 1:
@@ -482,7 +482,7 @@ namespace Intel8080
this.Tick(4);
break;
case 3: // LD SP,HL
this.SP.Word = this.HL.Word;
this.SP.Assign(this.HL);
this.Tick(4);
break;
default:
+28 -28
View File
@@ -301,6 +301,34 @@ namespace LR35902
return data & (byte)StatusBits.NF;
}
private static byte SetBit(byte f, StatusBits flag) => SetBit(f, (byte)flag);
private static byte SetBit(byte f, StatusBits flag, int condition) => SetBit(f, (byte)flag, condition);
private static byte SetBit(byte f, StatusBits flag, bool condition) => SetBit(f, (byte)flag, condition);
private static byte ClearBit(byte f, StatusBits flag) => ClearBit(f, (byte)flag);
private static byte ClearBit(byte f, StatusBits flag, int condition) => ClearBit(f, (byte)flag, condition);
private static byte AdjustZero(byte input, byte value) => ClearBit(input, StatusBits.ZF, value);
private static byte AdjustHalfCarryAdd(byte input, byte before, byte value, int calculation) => SetBit(input, StatusBits.HC, CalculateHalfCarryAdd(before, value, calculation));
private static byte AdjustHalfCarrySub(byte input, byte before, byte value, int calculation) => SetBit(input, StatusBits.HC, CalculateHalfCarrySub(before, value, calculation));
private static byte Res(int n, byte operand) => ClearBit(operand, Bit(n));
private static byte Set(int n, byte operand) => SetBit(operand, Bit(n));
protected override void DisableInterrupts() => this.IME = false;
protected override void EnableInterrupts() => this.IME = true;
private void Stop() => this.Stopped = true;
private void Start() => this.Stopped = false;
protected override void MemoryWrite()
{
this.LowerMWR();
@@ -361,34 +389,6 @@ namespace LR35902
this.TickMachine();
}
private static byte SetBit(byte f, StatusBits flag) => SetBit(f, (byte)flag);
private static byte SetBit(byte f, StatusBits flag, int condition) => SetBit(f, (byte)flag, condition);
private static byte SetBit(byte f, StatusBits flag, bool condition) => SetBit(f, (byte)flag, condition);
private static byte ClearBit(byte f, StatusBits flag) => ClearBit(f, (byte)flag);
private static byte ClearBit(byte f, StatusBits flag, int condition) => ClearBit(f, (byte)flag, condition);
private static byte AdjustZero(byte input, byte value) => ClearBit(input, StatusBits.ZF, value);
private static byte AdjustHalfCarryAdd(byte input, byte before, byte value, int calculation) => SetBit(input, StatusBits.HC, CalculateHalfCarryAdd(before, value, calculation));
private static byte AdjustHalfCarrySub(byte input, byte before, byte value, int calculation) => SetBit(input, StatusBits.HC, CalculateHalfCarrySub(before, value, calculation));
private static byte Res(int n, byte operand) => ClearBit(operand, Bit(n));
private static byte Set(int n, byte operand) => SetBit(operand, Bit(n));
protected override void DisableInterrupts() => this.IME = false;
protected override void EnableInterrupts() => this.IME = true;
private void Stop() => this.Stopped = true;
private void Start() => this.Stopped = false;
private byte R(int r) => r switch
{
0 => this.B,
+3 -2
View File
@@ -6,8 +6,9 @@
public IEnumerable<OpcodeTestSuite> OpcodeTests()
{
//var pattern = "dd 66.json";
//var pattern = "06.json";
//var pattern = "ed b2.json";
//var pattern = "04.json";
//var pattern = "1?.json";
var pattern = "*.json";
foreach (var filename in Directory.EnumerateFiles(this.Location, pattern))
{
+160 -201
View File
@@ -5,6 +5,7 @@
namespace Z80
{
using EightBit;
using System.Diagnostics;
public class Z80 : IntelProcessor
{
@@ -570,80 +571,35 @@ namespace Z80
this.Tick(5);
}
private int Zero()
{
return ZeroTest(this.F);
}
private int Zero() => ZeroTest(this.F);
private int Carry()
{
return CarryTest(this.F);
}
private int Carry() => CarryTest(this.F);
private int Parity()
{
return ParityTest(this.F);
}
private int Parity() => ParityTest(this.F);
private int Sign()
{
return SignTest(this.F);
}
private int Sign() => SignTest(this.F);
private int HalfCarry()
{
return HalfCarryTest(this.F);
}
private int HalfCarry() => HalfCarryTest(this.F);
private int Subtracting()
{
return SubtractingTest(this.F);
}
private int Subtracting() => SubtractingTest(this.F);
private static int ZeroTest(byte data)
{
return data & (byte)StatusBits.ZF;
}
private static int ZeroTest(byte data) => data & (byte)StatusBits.ZF;
private static int CarryTest(byte data)
{
return data & (byte)StatusBits.CF;
}
private static int CarryTest(byte data) => data & (byte)StatusBits.CF;
private static int ParityTest(byte data)
{
return data & (byte)StatusBits.PF;
}
private static int ParityTest(byte data) => data & (byte)StatusBits.PF;
private static int SignTest(byte data)
{
return data & (byte)StatusBits.SF;
}
private static int SignTest(byte data) => data & (byte)StatusBits.SF;
private static int HalfCarryTest(byte data)
{
return data & (byte)StatusBits.HC;
}
private static int HalfCarryTest(byte data) => data & (byte)StatusBits.HC;
private static int SubtractingTest(byte data)
{
return data & (byte)StatusBits.NF;
}
private static int SubtractingTest(byte data) => data & (byte)StatusBits.NF;
private static int XTest(byte data)
{
return data & (byte)StatusBits.XF;
}
private static int XTest(byte data) => data & (byte)StatusBits.XF;
private static int YTest(byte data)
{
return data & (byte)StatusBits.YF;
}
private static int YTest(byte data) => data & (byte)StatusBits.YF;
private void AdjustStatusFlags(byte value)
{
this._modifiedF = this.F = value;
}
private void AdjustStatusFlags(byte value) => this._modifiedF = this.F = value;
private void SetBit(StatusBits flag) => this.AdjustStatusFlags(SetBit(this.F, flag));
@@ -1068,26 +1024,10 @@ namespace Z80
this.LDD();
break;
case 6: // LDIR
if (this.LDIR())
{
this.DecrementPC();
this.MEMPTR.Assign(this.PC);
this.DecrementPC();
this.AdjustXY(this.PC.High);
}
this.Tick(5);
this.LDIR();
break;
case 7: // LDDR
if (this.LDDR())
{
this.DecrementPC();
this.MEMPTR.Assign(this.PC);
this.DecrementPC();
this.AdjustXY(this.PC.High);
}
this.Tick(5);
this.LDDR();
break;
default:
break;
@@ -1104,31 +1044,10 @@ namespace Z80
this.CPD();
break;
case 6: // CPIR
if (this.CPIR())
{
this.DecrementPC();
this.MEMPTR.Assign(this.PC);
this.DecrementPC();
this.AdjustXY(this.PC.High);
this.Tick(5);
}
this.CPIR();
break;
case 7: // CPDR
if (this.CPDR())
{
this.DecrementPC();
this.MEMPTR.Assign(this.PC);
this.DecrementPC();
this.AdjustXY(this.PC.High);
this.Tick(3);
}
else
{
this.MEMPTR.Word = (ushort)(this.PC.Word - 2);
}
this.Tick(2);
this.CPDR();
break;
default:
break;
@@ -1145,22 +1064,10 @@ namespace Z80
this.IND();
break;
case 6: // INIR
if (this.INIR())
{
this.DecrementPC();
this.DecrementPC();
this.Tick(5);
}
this.INIR();
break;
case 7: // INDR
if (this.INDR())
{
this.DecrementPC();
this.DecrementPC();
this.Tick(5);
}
this.INDR();
break;
default:
break;
@@ -1177,22 +1084,10 @@ namespace Z80
this.OUTD();
break;
case 6: // OTIR
if (this.OTIR())
{
this.DecrementPC();
this.DecrementPC();
this.Tick(5);
}
this.OTIR();
break;
case 7: // OTDR
if (this.OTDR())
{
this.DecrementPC();
this.DecrementPC();
this.Tick(5);
}
this.OTDR();
break;
default:
break;
@@ -1345,32 +1240,22 @@ namespace Z80
this.Tick(2);
break;
case 4: // 8-bit INC
if (memoryY && this._displaced)
{
if (memoryY && this._displaced)
{
this.FetchDisplacement();
this.Tick(5);
}
var original = this.R(y);
var updated = this.Increment(original);
this.R(y, updated, 1);
break;
this.FetchDisplacement();
this.Tick(5);
}
this.R(y, this.Increment(this.R(y)), 1);
break;
case 5: // 8-bit DEC
if (memoryY && this._displaced)
{
if (memoryY && this._displaced)
{
this.FetchDisplacement();
this.Tick(5);
}
var original = this.R(y);
var updated = this.Decrement(original);
this.R(y, updated, 1);
break;
this.FetchDisplacement();
this.Tick(5);
}
this.R(y, this.Decrement(this.R(y)), 1);
break;
case 6: // 8-bit load immediate
{
@@ -2076,15 +1961,23 @@ namespace Z80
this.Tick(3);
}
private void BlockCompare(Register16 source, ushort counter)
private void RepeatBlockInstruction()
{
var value = this.MemoryRead(source);
var result = (byte)(this.A - value);
this.DecrementPC();
this.MEMPTR.Assign(this.PC);
this.DecrementPC();
this.AdjustXY(this.PC.High);
}
this.SetBit(StatusBits.PF, counter);
private void BlockCompare()
{
_ = this.MemoryRead(this.HL);
var result = (byte)(this.A - this.Bus.Data);
this.SetBit(StatusBits.PF, --this.BC.Word);
this.AdjustSZ(result);
this.AdjustHalfCarrySub(this.A, value, result);
this.AdjustHalfCarrySub(this.A, this.Bus.Data, result);
this.SetBit(StatusBits.NF);
result -= (byte)(this.HalfCarry() >> 4);
@@ -2097,134 +1990,190 @@ namespace Z80
private void CPI()
{
this.BlockCompare(this.HL, --this.BC.Word);
this.BlockCompare();
++this.HL.Word;
++this.MEMPTR.Word;
}
private bool CPIR()
private void CPIR()
{
this.CPI();
return this.Parity() != 0 && this.Zero() == 0; // See CPI
if (this.Parity() != 0 && this.Zero() == 0)
{
this.RepeatBlockInstruction();
this.Tick(5);
}
}
private void CPD()
{
this.BlockCompare(this.HL, --this.BC.Word);
this.BlockCompare();
--this.HL.Word;
--this.MEMPTR.Word;
}
private bool CPDR()
private void CPDR()
{
this.CPD();
return this.Parity() != 0 && this.Zero() == 0; // See CPD
if (this.Parity() != 0 && this.Zero() == 0)
{
this.RepeatBlockInstruction();
this.Tick(5);
}
else
{
this.MEMPTR.Word = (ushort)(this.PC.Word - 2);
this.Tick(2);
}
}
private void BlockLoad(Register16 source, Register16 destination, ushort counter)
private void BlockLoad()
{
var value = this.MemoryRead(source);
this.Bus.Address.Assign(destination);
this.MemoryRead(this.HL);
this.Bus.Address.Assign(this.DE);
this.Tick();
this.MemoryUpdate(1);
this.Tick(3);
var xy = this.A + value;
var xy = this.A + this.Bus.Data;
this.SetBit(StatusBits.XF, xy & (int)Bits.Bit3);
this.SetBit(StatusBits.YF, xy & (int)Bits.Bit1);
this.ClearBit(StatusBits.NF | StatusBits.HC);
this.SetBit(StatusBits.PF, counter);
this.SetBit(StatusBits.PF, --this.BC.Word);
}
private void LDI()
{
this.BlockLoad(this.HL, this.DE, --this.BC.Word);
this.BlockLoad();
++this.HL.Word;
++this.DE.Word;
}
private bool LDIR()
private void LDIR()
{
this.LDI();
return this.Parity() != 0; // See "BlockLoad"
if (this.Parity() != 0)
{
this.RepeatBlockInstruction();
}
this.Tick(5);
}
private void LDD()
{
this.BlockLoad(this.HL, this.DE, --this.BC.Word);
this.BlockLoad();
--this.HL.Word;
--this.DE.Word;
}
private bool LDDR()
private void LDDR()
{
this.LDD();
return this.Parity() != 0; // See "BlockLoad"
if (this.Parity() != 0)
{
this.RepeatBlockInstruction();
}
this.Tick(5);
}
private void AdjustBlockInFlagsIncrement(Register16 source)
private void AdjustBlockRepeatFlagsIO()
{
var basis = (byte)(source.Low + 1) + this.Bus.Data;
this.SetBit(StatusBits.CF | StatusBits.HC, basis > 0xff);
this.AdjustParity((byte)(basis & (byte)Mask.Three ^ source.High));
var previousParity = this.Parity() >> 2;
Debug.Assert(previousParity < 2);
if (this.Carry() != 0)
{
if (SignTest(this.Bus.Data) != 0)
{
var parity = previousParity ^ (EvenParity((byte)((byte)(this.B - 1) & (byte)Mask.Three)) ? 1 : 0) ^ 1;
this.SetBit(StatusBits.PF, parity != 0);
this.SetBit(StatusBits.HC, (this.B & (byte)Mask.Four) == 0);
}
else
{
var parity = previousParity ^ (EvenParity((byte)((byte)(this.B + 1) & (byte)Mask.Three)) ? 1 : 0) ^ 1;
this.SetBit(StatusBits.PF, parity != 0);
this.SetBit(StatusBits.HC, (this.B & (byte)Mask.Four) == (int)Mask.Four);
}
}
else
{
this.AdjustParity((byte)(this.B & (byte)Mask.Three));
}
}
private void AdjustBlockInFlagsDecrement(Register16 source)
private void AdjustBlockInFlagsIncrement()
{
var basis = (byte)(source.Low - 1) + this.Bus.Data;
var basis = (byte)(this.C + 1) + this.Bus.Data;
this.SetBit(StatusBits.CF | StatusBits.HC, basis > 0xff);
this.AdjustParity((byte)(basis & (byte)Mask.Three ^ source.High));
this.AdjustParity((byte)(basis & (byte)Mask.Three ^ this.B));
}
private void BlockIn(Register16 source, Register16 destination)
private void AdjustBlockInFlagsDecrement()
{
var basis = (byte)(this.C - 1) + this.Bus.Data;
this.SetBit(StatusBits.CF | StatusBits.HC, basis > 0xff);
this.AdjustParity((byte)(basis & (byte)Mask.Three ^ this.B));
}
private void BlockIn()
{
this.Tick();
this.Bus.Address.Assign(source);
this.Bus.Address.Assign(this.BC);
this.MEMPTR.Assign(this.Bus.Address);
this.ReadPort();
this.Bus.Address.Assign(destination);
this.Bus.Address.Assign(this.HL);
this.Tick();
this.MemoryUpdate(1);
this.Tick();
this.AdjustSZXY(--source.High);
this.AdjustSZXY(--this.B);
this.SetBit(StatusBits.NF, (this.Bus.Data & (byte)StatusBits.SF) != 0);
}
private void INI()
{
this.BlockIn(this.BC, this.HL);
this.AdjustBlockInFlagsIncrement(this.BC);
this.BlockIn();
this.AdjustBlockInFlagsIncrement();
++this.HL.Word;
++this.MEMPTR.Word;
}
private bool INIR()
private void INIR()
{
this.INI();
return this.Zero() == 0; // See "BlockIn"/"Decrement"
if (this.Zero() == 0)
{
this.RepeatBlockInstruction();
this.AdjustBlockRepeatFlagsIO();
this.Tick(5);
}
}
private void IND()
{
this.BlockIn(this.BC, this.HL);
this.AdjustBlockInFlagsDecrement(this.BC);
this.BlockIn();
this.AdjustBlockInFlagsDecrement();
--this.HL.Word;
--this.MEMPTR.Word;
}
private bool INDR()
private void INDR()
{
this.IND();
return this.Zero() == 0; // See "BlockIn"/"Decrement"
if (this.Zero() == 0)
{
this.RepeatBlockInstruction();
this.AdjustBlockRepeatFlagsIO();
this.Tick(5);
}
}
private void BlockOut(Register16 source, Register16 destination)
private void BlockOut()
{
this.Tick();
_ = this.MemoryRead(source);
destination.High = this.Decrement(destination.High);
this.Bus.Address.Assign(destination);
_ = this.MemoryRead(this.HL);
this.B = this.Decrement(this.B);
this.Bus.Address.Assign(this.BC);
this.MEMPTR.Assign(this.Bus.Address);
this.WritePort();
this.MEMPTR.Assign(destination);
}
private void AdjustBlockOutFlags()
@@ -2238,30 +2187,40 @@ namespace Z80
private void OUTI()
{
this.BlockOut(this.HL, this.BC);
this.BlockOut();
++this.HL.Word;
this.AdjustBlockOutFlags();
++this.MEMPTR.Word;
}
private bool OTIR()
private void OTIR()
{
this.OUTI();
return this.Zero() == 0; // See OUTI
if (this.Zero() == 0)
{
this.RepeatBlockInstruction();
this.AdjustBlockRepeatFlagsIO();
this.Tick(5);
}
}
private void OUTD()
{
this.BlockOut(this.HL, this.BC);
this.BlockOut();
--this.HL.Word;
this.AdjustBlockOutFlags();
--this.MEMPTR.Word;
}
private bool OTDR()
private void OTDR()
{
this.OUTD();
return this.Zero() == 0; // See OUTD
if (this.Zero() == 0)
{
this.RepeatBlockInstruction();
this.AdjustBlockRepeatFlagsIO();
this.Tick(5);
}
}
private void NEG()