From dd1d141f1550903a1d44b4884275609f4b970cd8 Mon Sep 17 00:00:00 2001 From: Adrian Conlon <98398945+AdrianConlon@users.noreply.github.com> Date: Tue, 29 Apr 2025 12:27:39 +0100 Subject: [PATCH] Simplify conditional flag handling in intel processors --- EightBit/IntelProcessor.cs | 15 ++++- Intel8080/Intel8080.cs | 117 ++++++++++++++++++++++--------------- LR35902/LR35902.cs | 110 ++++++++++++++++++---------------- Z80/Z80.cs | 24 ++++---- 4 files changed, 154 insertions(+), 112 deletions(-) diff --git a/EightBit/IntelProcessor.cs b/EightBit/IntelProcessor.cs index cd1ad5d..ac2403e 100644 --- a/EightBit/IntelProcessor.cs +++ b/EightBit/IntelProcessor.cs @@ -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)); } } diff --git a/Intel8080/Intel8080.cs b/Intel8080/Intel8080.cs index 70ca111..73c8563 100644 --- a/Intel8080/Intel8080.cs +++ b/Intel8080/Intel8080.cs @@ -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) { diff --git a/LR35902/LR35902.cs b/LR35902/LR35902.cs index f1eb998..19b8d71 100644 --- a/LR35902/LR35902.cs +++ b/LR35902/LR35902.cs @@ -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); diff --git a/Z80/Z80.cs b/Z80/Z80.cs index 669ab7e..23e6a5a 100644 --- a/Z80/Z80.cs +++ b/Z80/Z80.cs @@ -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();