Simplify conditional flag handling in intel processors

This commit is contained in:
Adrian Conlon
2025-04-29 12:27:39 +01:00
parent 973590690c
commit dd1d141f15
4 changed files with 154 additions and 112 deletions

View File

@@ -205,14 +205,15 @@ namespace EightBit
this.Jump(this.MEMPTR);
}
protected void JumpRelative(byte offset) => this.JumpRelative((sbyte)offset);
protected virtual bool JumpRelativeConditional(bool condition)
{
this.Intermediate.Assign(this.PC);
++this.PC.Word;
if (condition)
{
var offset = (sbyte)this.MemoryRead(this.Intermediate);
this.JumpRelative(offset);
this.JumpRelative(this.MemoryRead(this.Intermediate));
}
return condition;
@@ -223,5 +224,15 @@ namespace EightBit
base.Return();
this.MEMPTR.Assign(this.PC);
}
protected abstract bool ConvertCondition(int flag);
protected virtual bool JumpConditionalFlag(int flag) => this.JumpConditional(this.ConvertCondition(flag));
protected virtual bool JumpRelativeConditionalFlag(int flag) => this.JumpRelativeConditional(this.ConvertCondition(flag));
protected virtual bool ReturnConditionalFlag(int flag) => this.ReturnConditional(this.ConvertCondition(flag));
protected virtual bool CallConditionalFlag(int flag) => this.CallConditional(this.ConvertCondition(flag));
}
}

View File

@@ -101,6 +101,57 @@ namespace Intel8080
--this.PC.Word; // Keep the PC on the HALT instruction (i.e. executing NOP)
}
private int Sign()
{
return SignTest(this.F);
}
private int Zero()
{
return ZeroTest(this.F);
}
private int AuxiliaryCarry()
{
return AuxiliaryCarryTest(this.F);
}
private int Parity()
{
return ParityTest(this.F);
}
private int Carry()
{
return CarryTest(this.F);
}
private static int SignTest(byte data)
{
return data & (byte)StatusBits.SF;
}
private static int ZeroTest(byte data)
{
return data & (byte)StatusBits.ZF;
}
private static int AuxiliaryCarryTest(byte data)
{
return data & (byte)StatusBits.AC;
}
private static int ParityTest(byte data)
{
return data & (byte)StatusBits.PF;
}
private static int CarryTest(byte data)
{
return data & (byte)StatusBits.CF;
}
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);
@@ -111,7 +162,7 @@ namespace Intel8080
private static byte ClearBit(byte f, StatusBits flag, int condition) => ClearBit(f, (byte)flag, condition);
private static byte AdjustSign(byte input, byte value) => SetBit(input, StatusBits.SF, value & (byte)StatusBits.SF);
private static byte AdjustSign(byte input, byte value) => SetBit(input, StatusBits.SF, SignTest(value));
private static byte AdjustZero(byte input, byte value) => ClearBit(input, StatusBits.ZF, value);
@@ -600,42 +651,16 @@ namespace Intel8080
return operand;
}
private bool JumpConditionalFlag(int flag) => flag switch
protected sealed override bool ConvertCondition(int flag) => flag switch
{
0 => this.JumpConditional((this.F & (byte)StatusBits.ZF) == 0), // NZ
1 => this.JumpConditional((this.F & (byte)StatusBits.ZF) != 0), // Z
2 => this.JumpConditional((this.F & (byte)StatusBits.CF) == 0), // NC
3 => this.JumpConditional((this.F & (byte)StatusBits.CF) != 0), // C
4 => this.JumpConditional((this.F & (byte)StatusBits.PF) == 0), // PO
5 => this.JumpConditional((this.F & (byte)StatusBits.PF) != 0), // PE
6 => this.JumpConditional((this.F & (byte)StatusBits.SF) == 0), // P
7 => this.JumpConditional((this.F & (byte)StatusBits.SF) != 0), // M
_ => throw new ArgumentOutOfRangeException(nameof(flag)),
};
private bool ReturnConditionalFlag(int flag) => flag switch
{
0 => this.ReturnConditional((this.F & (byte)StatusBits.ZF) == 0), // NZ
1 => this.ReturnConditional((this.F & (byte)StatusBits.ZF) != 0), // Z
2 => this.ReturnConditional((this.F & (byte)StatusBits.CF) == 0), // NC
3 => this.ReturnConditional((this.F & (byte)StatusBits.CF) != 0), // C
4 => this.ReturnConditional((this.F & (byte)StatusBits.PF) == 0), // PO
5 => this.ReturnConditional((this.F & (byte)StatusBits.PF) != 0), // PE
6 => this.ReturnConditional((this.F & (byte)StatusBits.SF) == 0), // P
7 => this.ReturnConditional((this.F & (byte)StatusBits.SF) != 0), // M
_ => throw new ArgumentOutOfRangeException(nameof(flag)),
};
private bool CallConditionalFlag(int flag) => flag switch
{
0 => this.CallConditional((this.F & (byte)StatusBits.ZF) == 0), // NZ
1 => this.CallConditional((this.F & (byte)StatusBits.ZF) != 0), // Z
2 => this.CallConditional((this.F & (byte)StatusBits.CF) == 0), // NC
3 => this.CallConditional((this.F & (byte)StatusBits.CF) != 0), // C
4 => this.CallConditional((this.F & (byte)StatusBits.PF) == 0), // PO
5 => this.CallConditional((this.F & (byte)StatusBits.PF) != 0), // PE
6 => this.CallConditional((this.F & (byte)StatusBits.SF) == 0), // P
7 => this.CallConditional((this.F & (byte)StatusBits.SF) != 0), // M
0 => this.Zero() == 0,
1 => this.Zero() != 0,
2 => this.Carry() == 0,
3 => this.Carry() != 0,
4 => this.Parity() == 0,
5 => this.Parity() != 0,
6 => this.Sign() == 0,
7 => this.Sign() != 0,
_ => throw new ArgumentOutOfRangeException(nameof(flag)),
};
@@ -654,11 +679,11 @@ namespace Intel8080
this.A = this.MEMPTR.Low;
this.F = SetBit(this.F, StatusBits.CF, this.MEMPTR.High & (byte)StatusBits.CF);
this.F = SetBit(this.F, StatusBits.CF, CarryTest(this.MEMPTR.High));
this.F = AdjustSZP(this.F, this.A);
}
private void ADC(byte value) => this.Add(value, this.F & (byte)StatusBits.CF);
private void ADC(byte value) => this.Add(value, this.Carry());
private byte Subtract(byte operand, byte value, int carry = 0)
{
@@ -668,7 +693,7 @@ namespace Intel8080
var result = this.MEMPTR.Low;
this.F = SetBit(this.F, StatusBits.CF, this.MEMPTR.High & (byte)StatusBits.CF);
this.F = SetBit(this.F, StatusBits.CF, CarryTest(this.MEMPTR.High));
this.F = AdjustSZP(this.F, result);
return result;
@@ -676,7 +701,7 @@ namespace Intel8080
private void SUB(byte value, int carry = 0) => this.A = this.Subtract(this.A, value, carry);
private void SBB(byte value) => this.SUB(value, this.F & (byte)StatusBits.CF);
private void SBB(byte value) => this.SUB(value, this.Carry());
private void AndR(byte value)
{
@@ -715,14 +740,14 @@ namespace Intel8080
private byte RL(byte operand)
{
var carry = this.F & (byte)StatusBits.CF;
var carry = this.Carry();
this.F = SetBit(this.F, StatusBits.CF, operand & (byte)Bits.Bit7);
return (byte)((operand << 1) | carry);
}
private byte RR(byte operand)
{
var carry = this.F & (byte)StatusBits.CF;
var carry = this.Carry();
this.F = SetBit(this.F, StatusBits.CF, operand & (byte)Bits.Bit0);
return (byte)((operand >> 1) | (carry << 7));
}
@@ -730,14 +755,14 @@ namespace Intel8080
private void DAA()
{
var before = this.A;
var carry = (this.F & (byte)StatusBits.CF) != 0;
var carry = this.Carry() != 0;
byte addition = 0;
if ((this.F & (byte)StatusBits.AC) != 0 || LowNibble(before) > 9)
if (this.AuxiliaryCarry() != 0 || LowNibble(before ) > 9)
{
addition = 0x6;
}
if ((this.F & (byte)StatusBits.CF) != 0 || HighNibble(before) > 9 || (HighNibble(before) >= 9 && LowNibble(before) > 9))
if (this.Carry() != 0 || HighNibble(before) > 9 || (HighNibble(before) >= 9 && LowNibble(before) > 9))
{
addition |= 0x60;
carry = true;
@@ -751,7 +776,7 @@ namespace Intel8080
private void STC() => this.F = SetBit(this.F, StatusBits.CF);
private void CMC() => this.F = ClearBit(this.F, StatusBits.CF, this.F & (byte)StatusBits.CF);
private void CMC() => this.F = ClearBit(this.F, StatusBits.CF, this.Carry());
private void XHTL(Register16 exchange)
{

View File

@@ -266,6 +266,46 @@ namespace LR35902
MachineTicked?.Invoke(this, EventArgs.Empty);
}
private int Zero()
{
return ZeroTest(this.F);
}
private int Carry()
{
return CarryTest(this.F);
}
private int HalfCarry()
{
return HalfCarryTest(this.F);
}
private int Subtracting()
{
return SubtractingTest(this.F);
}
private static int ZeroTest(byte data)
{
return data & (byte)StatusBits.ZF;
}
private static int CarryTest(byte data)
{
return data & (byte)StatusBits.CF;
}
private static int HalfCarryTest(byte data)
{
return data & (byte)StatusBits.HC;
}
private static int SubtractingTest(byte data)
{
return data & (byte)StatusBits.NF;
}
protected override void MemoryWrite()
{
this.LowerMWR();
@@ -311,8 +351,7 @@ namespace LR35902
protected override bool ReturnConditional(bool condition)
{
this.TickMachine();
_ = base.ReturnConditional(condition);
return condition;
return base.ReturnConditional(condition);
}
protected override bool JumpRelativeConditional(bool condition)
@@ -490,7 +529,7 @@ namespace LR35902
this.TickMachine(2);
break;
case 3: // JR d
this.JumpRelative((sbyte)this.FetchByte());
this.JumpRelative(this.FetchByte());
break;
case 4: // JR cc,d
case 5:
@@ -779,16 +818,14 @@ namespace LR35902
break;
case 5: // GB: LD (nn),A
this.MEMPTR.Assign(this.FetchWord());
this.Bus.Address.Assign(this.MEMPTR);
this.MemoryWrite(this.A);
this.MemoryWrite(this.MEMPTR, this.A);
break;
case 6: // GB: LD A,(FF00 + C)
this.A = this.MemoryRead(this.C, IoRegisters.BasePage);
break;
case 7: // GB: LD A,(nn)
this.MEMPTR.Assign(this.FetchWord());
this.Bus.Address.Assign(this.MEMPTR);
this.A = this.MemoryRead();
this.A = this.MemoryRead(this.MEMPTR);
break;
default:
throw new InvalidOperationException("Invalid operation mode");
@@ -908,39 +945,12 @@ namespace LR35902
return operand;
}
private bool JumpConditionalFlag(int flag) => flag switch
protected sealed override bool ConvertCondition(int flag) => flag switch
{
0 => this.JumpConditional((this.F & (byte)StatusBits.ZF) == 0), // NZ
1 => this.JumpConditional((this.F & (byte)StatusBits.ZF) != 0), // Z
2 => this.JumpConditional((this.F & (byte)StatusBits.CF) == 0), // NC
3 => this.JumpConditional((this.F & (byte)StatusBits.CF) != 0), // C
_ => throw new ArgumentOutOfRangeException(nameof(flag)),
};
private bool JumpRelativeConditionalFlag(int flag) => flag switch
{
0 => this.JumpRelativeConditional((this.F & (byte)StatusBits.ZF) == 0), // NZ
1 => this.JumpRelativeConditional((this.F & (byte)StatusBits.ZF) != 0), // Z
2 => this.JumpRelativeConditional((this.F & (byte)StatusBits.CF) == 0), // NC
3 => this.JumpRelativeConditional((this.F & (byte)StatusBits.CF) != 0), // C
_ => throw new ArgumentOutOfRangeException(nameof(flag)),
};
private bool ReturnConditionalFlag(int flag) => flag switch
{
0 => this.ReturnConditional((this.F & (byte)StatusBits.ZF) == 0), // NZ
1 => this.ReturnConditional((this.F & (byte)StatusBits.ZF) != 0), // Z
2 => this.ReturnConditional((this.F & (byte)StatusBits.CF) == 0), // NC
3 => this.ReturnConditional((this.F & (byte)StatusBits.CF) != 0), // C
_ => throw new ArgumentOutOfRangeException(nameof(flag)),
};
private bool CallConditionalFlag(int flag) => flag switch
{
0 => this.CallConditional((this.F & (byte)StatusBits.ZF) == 0), // NZ
1 => this.CallConditional((this.F & (byte)StatusBits.ZF) != 0), // Z
2 => this.CallConditional((this.F & (byte)StatusBits.CF) == 0), // NC
3 => this.CallConditional((this.F & (byte)StatusBits.CF) != 0), // C
0 => this.Zero() == 0, // NZ
1 => this.Zero() != 0, // Z
2 => this.Carry() == 0, // NC
3 => this.Carry() != 0, // C
_ => throw new ArgumentOutOfRangeException(nameof(flag)),
};
@@ -974,7 +984,7 @@ namespace LR35902
return operand;
}
private byte ADC(byte operand, byte value) => this.Add(operand, value, (this.F & (byte)StatusBits.CF) >> 4);
private byte ADC(byte operand, byte value) => this.Add(operand, value, this.Carry() >> 4);
private byte Subtract(byte operand, byte value, int carry = 0)
{
@@ -991,7 +1001,7 @@ namespace LR35902
return result;
}
private byte SBC(byte operand, byte value) => this.Subtract(operand, value, (this.F & (byte)StatusBits.CF) >> 4);
private byte SBC(byte operand, byte value) => this.Subtract(operand, value, this.Carry() >> 4);
private byte AndR(byte operand, byte value)
{
@@ -1042,7 +1052,7 @@ namespace LR35902
private byte RL(byte operand)
{
this.F = ClearBit(this.F, StatusBits.NF | StatusBits.HC | StatusBits.ZF);
var carry = this.F & (byte)StatusBits.CF;
var carry = this.Carry();
this.F = SetBit(this.F, StatusBits.CF, operand & (byte)Bits.Bit7);
return (byte)((operand << 1) | (carry >> 4)); // CF at Bit4
}
@@ -1050,7 +1060,7 @@ namespace LR35902
private byte RR(byte operand)
{
this.F = ClearBit(this.F, StatusBits.NF | StatusBits.HC | StatusBits.ZF);
var carry = this.F & (byte)StatusBits.CF;
var carry = this.Carry();
this.F = SetBit(this.F, StatusBits.CF, operand & (byte)Bits.Bit0);
return (byte)((operand >> 1) | (carry << 3)); // CF at Bit4
}
@@ -1084,7 +1094,7 @@ namespace LR35902
private void Bit(int n, byte operand)
{
var carry = this.F & (byte)StatusBits.CF;
var carry = this.Carry();
_ = this.AndR(operand, Bit(n));
this.F = SetBit(this.F, StatusBits.CF, carry);
}
@@ -1093,33 +1103,33 @@ namespace LR35902
{
int updated = this.A;
if ((this.F & (byte)StatusBits.NF) != 0)
if (this.Subtracting() != 0)
{
if ((this.F & (byte)StatusBits.HC) != 0)
if (this.HalfCarry() != 0)
{
updated = LowByte(updated - 6);
}
if ((this.F & (byte)StatusBits.CF) != 0)
if (this.Carry() != 0)
{
updated -= 0x60;
}
}
else
{
if ((this.F & (byte)StatusBits.HC) != 0 || LowNibble((byte)updated) > 9)
if (this.HalfCarry() != 0 || LowNibble((byte)updated) > 9)
{
updated += 6;
}
if ((this.F & (byte)StatusBits.CF) != 0 || updated > 0x9F)
if (this.Carry() != 0 || updated > 0x9F)
{
updated += 0x60;
}
}
this.F = ClearBit(this.F, (byte)StatusBits.HC | (byte)StatusBits.ZF);
this.F = SetBit(this.F, StatusBits.CF, (this.F & (byte)StatusBits.CF) != 0 || (updated & (int)Bits.Bit8) != 0);
this.F = SetBit(this.F, StatusBits.CF, this.Carry() != 0 || (updated & (int)Bits.Bit8) != 0);
this.A = LowByte(updated);
this.F = AdjustZero(this.F, this.A);

View File

@@ -1145,13 +1145,13 @@ namespace Z80
this.Tick(3);
break;
case 3: // JR d
this.JumpRelative((sbyte)this.FetchByte());
this.JumpRelative(this.FetchByte());
break;
case 4: // JR cc,d
case 5:
case 6:
case 7:
this.JumpRelativeConditionalFlag(y - 4);
_ = this.JumpRelativeConditionalFlag(y - 4);
break;
default:
throw new NotSupportedException("Invalid operation mode");
@@ -1467,7 +1467,7 @@ namespace Z80
switch (z)
{
case 0: // Conditional return
this.ReturnConditionalFlag(y);
_ = this.ReturnConditionalFlag(y);
break;
case 1: // POP & various ops
switch (q)
@@ -1501,7 +1501,7 @@ namespace Z80
break;
case 2: // Conditional jump
this.JumpConditionalFlag(y);
_ = this.JumpConditionalFlag(y);
break;
case 3: // Assorted operations
switch (y)
@@ -1551,7 +1551,7 @@ namespace Z80
break;
case 4: // Conditional call: CALL cc[y], nn
this.CallConditionalFlag(y);
_ = this.CallConditionalFlag(y);
break;
case 5: // PUSH & various ops
switch (q)
@@ -1730,7 +1730,7 @@ namespace Z80
private void RetI() => this.RetN();
private bool ConvertCondition(int flag) => flag switch
protected sealed override bool ConvertCondition(int flag) => flag switch
{
0 => this.Zero() == 0,
1 => this.Zero() != 0,
@@ -1743,21 +1743,17 @@ namespace Z80
_ => throw new ArgumentOutOfRangeException(nameof(flag)),
};
private void ReturnConditionalFlag(int flag)
protected sealed override bool ReturnConditionalFlag(int flag)
{
if (this.ConvertCondition(flag))
var condition = this.ConvertCondition(flag);
if (condition)
{
this.Tick();
this.Return();
}
return condition;
}
private void JumpRelativeConditionalFlag(int flag) => this.JumpRelativeConditional(this.ConvertCondition(flag));
private void JumpConditionalFlag(int flag) => this.JumpConditional(this.ConvertCondition(flag));
private void CallConditionalFlag(int flag) => this.CallConditional(this.ConvertCondition(flag));
private Register16 SBC(Register16 operand, Register16 value)
{
var subtraction = operand.Word - value.Word - this.Carry();