From 9da1beac0e2e0efb824f97d4f813812221dd5541 Mon Sep 17 00:00:00 2001 From: "Eric P. Nusbaum" Date: Tue, 11 Jun 2024 21:48:53 -0400 Subject: [PATCH 1/7] Treat Infinity as an Invalid Comparison Value - We were only handling `NaN` as invalid, but `Infinity` is also invalid so we need to set flags properly in case of both. - Updated Unit Tests --- MBBSEmu.Tests/CPU/FCOM_Tests.cs | 9 +++++++++ MBBSEmu/CPU/CPUCore.cs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/MBBSEmu.Tests/CPU/FCOM_Tests.cs b/MBBSEmu.Tests/CPU/FCOM_Tests.cs index 3676cb4c..2cbe02c0 100644 --- a/MBBSEmu.Tests/CPU/FCOM_Tests.cs +++ b/MBBSEmu.Tests/CPU/FCOM_Tests.cs @@ -16,7 +16,10 @@ public class FCOM_Tests : CpuTestBase [InlineData(double.MinValue, 0d, (ushort)EnumFpuStatusFlags.Code0)] [InlineData(1d, 1d, (ushort)EnumFpuStatusFlags.Code3)] [InlineData(double.NaN, 0d, (ushort)(EnumFpuStatusFlags.Code0 | EnumFpuStatusFlags.Code2 | EnumFpuStatusFlags.Code3))] + [InlineData(double.NegativeInfinity, 0d, (ushort)(EnumFpuStatusFlags.Code0 | EnumFpuStatusFlags.Code2 | EnumFpuStatusFlags.Code3))] [InlineData(0d, double.NaN, (ushort)(EnumFpuStatusFlags.Code0 | EnumFpuStatusFlags.Code2 | EnumFpuStatusFlags.Code3))] + [InlineData(0d, double.PositiveInfinity, (ushort)(EnumFpuStatusFlags.Code0 | EnumFpuStatusFlags.Code2 | EnumFpuStatusFlags.Code3))] + [InlineData(double.NegativeInfinity, double.PositiveInfinity, (ushort)(EnumFpuStatusFlags.Code0 | EnumFpuStatusFlags.Code2 | EnumFpuStatusFlags.Code3))] public void FCOM_ST1_Test(double ST0Value, double ST1Value, ushort expectedFlags) { Reset(); @@ -42,7 +45,10 @@ public void FCOM_ST1_Test(double ST0Value, double ST1Value, ushort expectedFlags [InlineData(float.MinValue, 0d, (ushort)EnumFpuStatusFlags.Code0)] [InlineData(1d, 1d, (ushort)EnumFpuStatusFlags.Code3)] [InlineData(float.NaN, 0d, (ushort)(EnumFpuStatusFlags.Code0 | EnumFpuStatusFlags.Code2 | EnumFpuStatusFlags.Code3))] + [InlineData(float.NegativeInfinity, 0d, (ushort)(EnumFpuStatusFlags.Code0 | EnumFpuStatusFlags.Code2 | EnumFpuStatusFlags.Code3))] [InlineData(0d, float.NaN, (ushort)(EnumFpuStatusFlags.Code0 | EnumFpuStatusFlags.Code2 | EnumFpuStatusFlags.Code3))] + [InlineData(0d, float.PositiveInfinity, (ushort)(EnumFpuStatusFlags.Code0 | EnumFpuStatusFlags.Code2 | EnumFpuStatusFlags.Code3))] + [InlineData(float.NegativeInfinity, float.PositiveInfinity, (ushort)(EnumFpuStatusFlags.Code0 | EnumFpuStatusFlags.Code2 | EnumFpuStatusFlags.Code3))] public void FCOM_M32_Test(double ST0Value, float m32Value, ushort expectedFlags) { Reset(); @@ -70,7 +76,10 @@ public void FCOM_M32_Test(double ST0Value, float m32Value, ushort expectedFlags) [InlineData(double.MinValue, 0d, (ushort)EnumFpuStatusFlags.Code0)] [InlineData(1d, 1d, (ushort)EnumFpuStatusFlags.Code3)] [InlineData(double.NaN, 0d, (ushort)(EnumFpuStatusFlags.Code0 | EnumFpuStatusFlags.Code2 | EnumFpuStatusFlags.Code3))] + [InlineData(double.NegativeInfinity, 0d, (ushort)(EnumFpuStatusFlags.Code0 | EnumFpuStatusFlags.Code2 | EnumFpuStatusFlags.Code3))] [InlineData(0d, double.NaN, (ushort)(EnumFpuStatusFlags.Code0 | EnumFpuStatusFlags.Code2 | EnumFpuStatusFlags.Code3))] + [InlineData(0d, double.PositiveInfinity, (ushort)(EnumFpuStatusFlags.Code0 | EnumFpuStatusFlags.Code2 | EnumFpuStatusFlags.Code3))] + [InlineData(double.NegativeInfinity, double.PositiveInfinity, (ushort)(EnumFpuStatusFlags.Code0 | EnumFpuStatusFlags.Code2 | EnumFpuStatusFlags.Code3))] public void FCOM_M64_Test(double ST0Value, double m32Value, ushort expectedFlags) { Reset(); diff --git a/MBBSEmu/CPU/CPUCore.cs b/MBBSEmu/CPU/CPUCore.cs index c3044733..9077e780 100644 --- a/MBBSEmu/CPU/CPUCore.cs +++ b/MBBSEmu/CPU/CPUCore.cs @@ -3814,7 +3814,7 @@ private void Op_Fcom() var source = GetOperandValueDouble(_currentInstruction.Op0Kind, EnumOperandType.Source); var ST0 = FpuStack[Registers.Fpu.GetStackTop()]; - if (double.IsNaN(ST0) || double.IsNaN(source)) + if (double.IsNaN(ST0) || double.IsNaN(source) || double.IsInfinity(ST0) || double.IsInfinity(source)) { Registers.Fpu.SetFlag(EnumFpuStatusFlags.Code0 | EnumFpuStatusFlags.Code2 | EnumFpuStatusFlags.Code3); return; From 9419830ddbeeaaf35360a6fb40cb022762114995 Mon Sep 17 00:00:00 2001 From: "Eric P. Nusbaum" Date: Wed, 12 Jun 2024 08:32:48 -0400 Subject: [PATCH 2/7] Same Infinity Fixes for FCOMPP --- MBBSEmu.Tests/CPU/FCOMPP_Tests.cs | 2 ++ MBBSEmu/CPU/CPUCore.cs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/MBBSEmu.Tests/CPU/FCOMPP_Tests.cs b/MBBSEmu.Tests/CPU/FCOMPP_Tests.cs index 4b769329..746f5e73 100644 --- a/MBBSEmu.Tests/CPU/FCOMPP_Tests.cs +++ b/MBBSEmu.Tests/CPU/FCOMPP_Tests.cs @@ -15,6 +15,8 @@ public class FCOMPP_Tests : CpuTestBase [InlineData(1d, 1d, (ushort)EnumFpuStatusFlags.Code3)] [InlineData(double.NaN, 0d, (ushort)(EnumFpuStatusFlags.Code0 | EnumFpuStatusFlags.Code2 | EnumFpuStatusFlags.Code3))] [InlineData(0d, double.NaN, (ushort)(EnumFpuStatusFlags.Code0 | EnumFpuStatusFlags.Code2 | EnumFpuStatusFlags.Code3))] + [InlineData(double.PositiveInfinity, 0d, (ushort)(EnumFpuStatusFlags.Code0 | EnumFpuStatusFlags.Code2 | EnumFpuStatusFlags.Code3))] + [InlineData(0d, double.NegativeInfinity, (ushort)(EnumFpuStatusFlags.Code0 | EnumFpuStatusFlags.Code2 | EnumFpuStatusFlags.Code3))] public void FCOMPP_Test(double ST0Value, double ST1Value, ushort expectedFlags) { Reset(); diff --git a/MBBSEmu/CPU/CPUCore.cs b/MBBSEmu/CPU/CPUCore.cs index 9077e780..0648bb5b 100644 --- a/MBBSEmu/CPU/CPUCore.cs +++ b/MBBSEmu/CPU/CPUCore.cs @@ -3860,7 +3860,7 @@ private void Op_Fcompp() var ST0 = FpuStack[Registers.Fpu.GetStackTop()]; var ST1 = FpuStack[Registers.Fpu.GetStackPointer(Register.ST1)]; - if (double.IsNaN(ST0) || double.IsNaN(ST1)) + if (double.IsNaN(ST0) || double.IsNaN(ST1) || double.IsInfinity(ST0) || double.IsInfinity(ST1)) { Registers.Fpu.SetFlag(EnumFpuStatusFlags.Code0 | EnumFpuStatusFlags.Code2 | EnumFpuStatusFlags.Code3); } From b32d5b31195d17713338d0ea0c8dc44dab39f0b4 Mon Sep 17 00:00:00 2001 From: "Eric P. Nusbaum" Date: Mon, 17 Jun 2024 21:04:37 -0400 Subject: [PATCH 3/7] Handle Overflow Flag for RCR - Add Overflow Flag logic for RCR - Add Additional Logging for FPU stack --- MBBSEmu.Tests/CPU/RCR_Tests.cs | 78 ++++++++++++++++++++-------------- MBBSEmu/CPU/CPUCore.cs | 12 ++++++ 2 files changed, 59 insertions(+), 31 deletions(-) diff --git a/MBBSEmu.Tests/CPU/RCR_Tests.cs b/MBBSEmu.Tests/CPU/RCR_Tests.cs index 073ac653..01fe2c64 100644 --- a/MBBSEmu.Tests/CPU/RCR_Tests.cs +++ b/MBBSEmu.Tests/CPU/RCR_Tests.cs @@ -5,18 +5,20 @@ namespace MBBSEmu.Tests.CPU { - public class RCR_Tests : CpuTestBase + public class RCR_Tests : CpuTestBase { [Theory] - [InlineData(0xF, 1, 0x7, true)] - [InlineData(0xE, 1, 0x7, false)] - [InlineData(0x1FF, 1, 0xFF, true)] - [InlineData(0x1FE, 1, 0xFF, false)] - [InlineData(0x3C, 2, 0xF, false)] - [InlineData(0x3E, 2, 0xF, true)] - [InlineData(0xFFFF, 2, 0xBFFF, true)] + [InlineData(0xF, 1, 0x7, true, false)] + [InlineData(0xE, 1, 0x7, false, false)] + [InlineData(0x6, 1, 0x3, false, false)] + [InlineData(0x1FF, 1, 0xFF, true, false)] + [InlineData(0x1FE, 1, 0xFF, false, false)] + [InlineData(0x3C, 2, 0xF, false, false)] + [InlineData(0x3E, 2, 0xF, true, false)] + [InlineData(0xFFFF, 1, 0x7FFF, true, true)] + [InlineData(0xFFFF, 2, 0xBFFF, true, false)] public void RCR_AX_IMM16_CF_CLEAR(ushort axValue, byte bitsToRotate, ushort expectedValue, - bool expectedCFValue) + bool expectedCFValue, bool expectedOFValue) { Reset(); mbbsEmuCpuRegisters.AX = axValue; @@ -29,17 +31,20 @@ public void RCR_AX_IMM16_CF_CLEAR(ushort axValue, byte bitsToRotate, ushort expe Assert.Equal(expectedValue, mbbsEmuCpuRegisters.AX); Assert.Equal(expectedCFValue, mbbsEmuCpuRegisters.CarryFlag); + Assert.Equal(expectedOFValue, mbbsEmuCpuRegisters.OverflowFlag); } [Theory] - [InlineData(0xF, 1, 0x8007, true)] - [InlineData(0xE, 1, 0x8007, false)] - [InlineData(0x1FF, 1, 0x80FF, true)] - [InlineData(0x1FE, 1, 0x80FF, false)] - [InlineData(0x3C, 2, 0x400F, false)] - [InlineData(0x3E, 2, 0x400F, true)] - [InlineData(0xFFFF, 2, 0xFFFF, true)] - public void RCR_AX_IMM16_CF_SET(ushort axValue, byte bitsToRotate, ushort expectedValue, bool expectedCFValue) + [InlineData(0xF, 1, 0x8007, true, false)] + [InlineData(0xF, 2, 0xC003, true, true)] + [InlineData(0xE, 1, 0x8007, false, false)] + [InlineData(0x1FF, 1, 0x80FF, true, false)] + [InlineData(0x1FE, 1, 0x80FF, false, false)] + [InlineData(0x3C, 2, 0x400F, false, false)] + [InlineData(0x3E, 2, 0x400F, true, false)] + [InlineData(0xFFFF, 2, 0xFFFF, true, false)] + [InlineData(0xFFFF, 1, 0xFFFF, true, false)] + public void RCR_AX_IMM16_CF_SET(ushort axValue, byte bitsToRotate, ushort expectedValue, bool expectedCFValue, bool expectedOFValue) { Reset(); mbbsEmuCpuRegisters.AX = axValue; @@ -56,9 +61,12 @@ public void RCR_AX_IMM16_CF_SET(ushort axValue, byte bitsToRotate, ushort expect } [Theory] - [InlineData(0xF, 1, 0x7, true)] - [InlineData(0xE, 1, 0x7, false)] - public void RCR_AH_IMM8_CF_CLEAR(byte ahValue, byte bitsToRotate, byte expectedValue, bool expectedCFValue) + [InlineData(0xF, 1, 0x7, true, false)] + [InlineData(0xFF, 1, 0x7F, true, true)] + [InlineData(0xFF, 2, 0xBF, true, false)] + [InlineData(0x0, 1, 0x0, false, false)] + [InlineData(0xE, 1, 0x7, false, false)] + public void RCR_AH_IMM8_CF_CLEAR(byte ahValue, byte bitsToRotate, byte expectedValue, bool expectedCFValue, bool expectedOFValue) { Reset(); mbbsEmuCpuRegisters.AH = ahValue; @@ -71,12 +79,16 @@ public void RCR_AH_IMM8_CF_CLEAR(byte ahValue, byte bitsToRotate, byte expectedV Assert.Equal(expectedValue, mbbsEmuCpuRegisters.AH); Assert.Equal(expectedCFValue, mbbsEmuCpuRegisters.CarryFlag); + Assert.Equal(expectedOFValue, mbbsEmuCpuRegisters.OverflowFlag); } [Theory] - [InlineData(0xF, 1, 0x87, true)] - [InlineData(0xE, 1, 0x87, false)] - public void RCR_AH_IMM8_CF_SET(byte ahValue, byte bitsToRotate, ushort expectedValue, bool expectedCFValue) + [InlineData(0xF, 1, 0x87, true, true)] + [InlineData(0x7F, 1, 0xBF, true, true)] + [InlineData(0xFF, 2, 0xFF, true, false)] + [InlineData(0x0, 1, 0x80, false, true)] + [InlineData(0xE, 1, 0x87, false, true)] + public void RCR_AH_IMM8_CF_SET(byte ahValue, byte bitsToRotate, ushort expectedValue, bool expectedCFValue, bool expectedOFValue) { Reset(); mbbsEmuCpuRegisters.AH = ahValue; @@ -90,18 +102,21 @@ public void RCR_AH_IMM8_CF_SET(byte ahValue, byte bitsToRotate, ushort expectedV Assert.Equal(expectedValue, mbbsEmuCpuRegisters.AH); Assert.Equal(expectedCFValue, mbbsEmuCpuRegisters.CarryFlag); + Assert.Equal(expectedOFValue, mbbsEmuCpuRegisters.OverflowFlag); } [Theory] - [InlineData(0xF, 1, 0x7, true)] - [InlineData(0xE, 1, 0x7, false)] - [InlineData(0x1FF, 1, 0xFF, true)] - [InlineData(0x1FE, 1, 0xFF, false)] - [InlineData(0x3C, 2, 0xF, false)] - [InlineData(0x3E, 2, 0xF, true)] - [InlineData(0xFFFF, 2, 0xBFFF, true)] + [InlineData(0xF, 1, 0x7, true, false)] + [InlineData(0xE, 1, 0x7, false, false)] + [InlineData(0x6, 1, 0x3, false, false)] + [InlineData(0x1FF, 1, 0xFF, true, false)] + [InlineData(0x1FE, 1, 0xFF, false, false)] + [InlineData(0x3C, 2, 0xF, false, false)] + [InlineData(0x3E, 2, 0xF, true, false)] + [InlineData(0xFFFF, 1, 0x7FFF, true, true)] + [InlineData(0xFFFF, 2, 0xBFFF, true, false)] public void RCR_M16_IMM16_1(ushort memoryValue, byte bitsToRotate, ushort expectedValue, - bool expectedCFValue) + bool expectedCFValue, bool expectedOFValue) { Reset(); mbbsEmuCpuRegisters.DS = 2; @@ -115,6 +130,7 @@ public void RCR_M16_IMM16_1(ushort memoryValue, byte bitsToRotate, ushort expect Assert.Equal(expectedValue, mbbsEmuMemoryCore.GetWord(2, 0)); Assert.Equal(expectedCFValue, mbbsEmuCpuRegisters.CarryFlag); + Assert.Equal(expectedOFValue, mbbsEmuCpuRegisters.OverflowFlag); } } } diff --git a/MBBSEmu/CPU/CPUCore.cs b/MBBSEmu/CPU/CPUCore.cs index 0648bb5b..d42f6fbf 100644 --- a/MBBSEmu/CPU/CPUCore.cs +++ b/MBBSEmu/CPU/CPUCore.cs @@ -361,6 +361,10 @@ public void Tick() _showDebug = true; //Set to log Register values to console after execution _logger.Debug($"{Registers.CS:X4}:{_currentInstruction.IP16:X4} {_currentInstruction}"); _logger.Debug($"{Registers}"); + foreach(var l in Registers.ToString().Split("\n")) + _logger.Debug(l); + for(var i = 0; i < 8; i++) + _logger.Debug($"FPU[{i}]: {FpuStack[i]} {(i == Registers.Fpu.GetStackTop() ? " <--" : string.Empty)}"); } else { @@ -1597,6 +1601,10 @@ private byte Op_Rcr_8() Registers.CarryFlag = newCFValue; } + //Only on 1 Bit Rotations to we evaluate Overflow + if (source == 1) + Registers.OverflowFlag = result.IsBitSet(7) ^ result.IsBitSet(6); + return result; } } @@ -1638,6 +1646,10 @@ private ushort Op_Rcr_16() Registers.CarryFlag = newCFValue; } + //Only on 1 Bit Rotations to we evaluate Overflow + if (source == 1) + Registers.OverflowFlag = result.IsBitSet(15) ^ result.IsBitSet(14); + return result; } } From cedec4b1ecafb5302efc590c771d7fd3a7f52495 Mon Sep 17 00:00:00 2001 From: "Eric P. Nusbaum" Date: Tue, 18 Jun 2024 17:07:12 -0400 Subject: [PATCH 4/7] Handle Crash Report in Module if not executing Code - Unhandled exception would be thrown while generating a Crash Report if a module crashed without executing code (Loading, etc.) --- MBBSEmu/Module/CrashReport.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/MBBSEmu/Module/CrashReport.cs b/MBBSEmu/Module/CrashReport.cs index e102a653..04d03dfd 100644 --- a/MBBSEmu/Module/CrashReport.cs +++ b/MBBSEmu/Module/CrashReport.cs @@ -61,7 +61,15 @@ public string Save(string fileName = "") crashReportVariables.Add(_exception.StackTrace); //CPU Instruction - crashReportVariables.Add(_moduleToReport.Memory.GetInstruction(_registers.CS, _registers.IP).ToString()); + try + { + crashReportVariables.Add(_moduleToReport.Memory.GetInstruction(_registers.CS, _registers.IP).ToString()); + } + catch (Exception e) + { + crashReportVariables.Add("Exception retrieving CPU Instruction"); + } + //Registers crashReportVariables.Add(_registers.ToString()); From e74be133df1633055b44ee9b6feb446bb63a62d2 Mon Sep 17 00:00:00 2001 From: "Eric P. Nusbaum" Date: Sat, 22 Jun 2024 11:14:52 -0400 Subject: [PATCH 5/7] Add Overflow Logic to RCL (+tests) --- .../CPU/{RLC_Tests.cs => RCL_Tests.cs} | 26 ++++++++++--------- MBBSEmu/CPU/CPUCore.cs | 19 ++++++++++---- 2 files changed, 28 insertions(+), 17 deletions(-) rename MBBSEmu.Tests/CPU/{RLC_Tests.cs => RCL_Tests.cs} (50%) diff --git a/MBBSEmu.Tests/CPU/RLC_Tests.cs b/MBBSEmu.Tests/CPU/RCL_Tests.cs similarity index 50% rename from MBBSEmu.Tests/CPU/RLC_Tests.cs rename to MBBSEmu.Tests/CPU/RCL_Tests.cs index 5eab86e8..fbd5520d 100644 --- a/MBBSEmu.Tests/CPU/RLC_Tests.cs +++ b/MBBSEmu.Tests/CPU/RCL_Tests.cs @@ -7,13 +7,13 @@ namespace MBBSEmu.Tests.CPU public class RCL_Tests : CpuTestBase { [Theory] - [InlineData(0x8000, 1, false, 0x0000, true)] // Rotate left with carry in, resulting in CF set - [InlineData(0x8000, 1, true, 0x0001, true)] // Rotate left with carry in, resulting in CF set, and LSB set from previous CF - [InlineData(0x0001, 1, false, 0x0002, false)] // Simple rotate left - [InlineData(0x0000, 1, true, 0x0001, false)] // Rotate with carry flag set, no bit set in value - [InlineData(0xFFFF, 4, false, 0xFFF7, true)] // Rotate left multiple times + [InlineData(0x8000, 1, false, 0x0000, true, true)] // Rotate left with carry in, resulting in CF set + [InlineData(0x8000, 1, true, 0x0001, true, true)] // Rotate left with carry in, resulting in CF set, and LSB set from previous CF + [InlineData(0x0001, 1, false, 0x0002, false, false)] // Simple rotate left + [InlineData(0x0000, 1, true, 0x0001, false, false)] // Rotate with carry flag set, no bit set in value + [InlineData(0xFFFF, 4, false, 0xFFF7, true, false)] // Rotate left multiple times public void Op_Rcl_16_Test(ushort axValue, byte bitsToRotate, bool initialCarryFlag, ushort expectedResult, - bool expectedCarryFlag) + bool expectedCarryFlag, bool expectedOverflowFlag) { Reset(); mbbsEmuCpuRegisters.AX = axValue; @@ -27,16 +27,17 @@ public void Op_Rcl_16_Test(ushort axValue, byte bitsToRotate, bool initialCarryF Assert.Equal(expectedResult, mbbsEmuCpuRegisters.AX); Assert.Equal(expectedCarryFlag, mbbsEmuCpuRegisters.CarryFlag); + Assert.Equal(expectedOverflowFlag, mbbsEmuCpuRegisters.OverflowFlag); } [Theory] - [InlineData(0x80, 1, false, 0x00, true)] // Rotate left with carry in, resulting in CF set - [InlineData(0x80, 1, true, 0x01, true)] // Rotate left with carry in, resulting in CF set, and LSB set from previous CF - [InlineData(0x01, 1, false, 0x02, false)] // Simple rotate left - [InlineData(0x00, 1, true, 0x01, false)] // Rotate with carry flag set, no bit set in value - [InlineData(0xFF, 4, false, 0xF7, true)] // Rotate left multiple times + [InlineData(0x80, 1, false, 0x00, true, true)] // Rotate left with carry in, resulting in CF set + [InlineData(0x80, 1, true, 0x01, true, true)] // Rotate left with carry in, resulting in CF set, and LSB set from previous CF + [InlineData(0x01, 1, false, 0x02, false, false)] // Simple rotate left + [InlineData(0x00, 1, true, 0x01, false, false)] // Rotate with carry flag set, no bit set in value + [InlineData(0xFF, 4, false, 0xF7, true, false)] // Rotate left multiple times public void Op_Rcl_8_Test(byte alValue, byte bitsToRotate, bool initialCarryFlag, ushort expectedResult, - bool expectedCarryFlag) + bool expectedCarryFlag, bool expectedOverflowFlag) { Reset(); mbbsEmuCpuRegisters.AL = alValue; @@ -50,6 +51,7 @@ public void Op_Rcl_8_Test(byte alValue, byte bitsToRotate, bool initialCarryFlag Assert.Equal(expectedResult, mbbsEmuCpuRegisters.AL); Assert.Equal(expectedCarryFlag, mbbsEmuCpuRegisters.CarryFlag); + Assert.Equal(expectedOverflowFlag, mbbsEmuCpuRegisters.OverflowFlag); } } diff --git a/MBBSEmu/CPU/CPUCore.cs b/MBBSEmu/CPU/CPUCore.cs index d42f6fbf..80da4a76 100644 --- a/MBBSEmu/CPU/CPUCore.cs +++ b/MBBSEmu/CPU/CPUCore.cs @@ -360,7 +360,6 @@ public void Tick() { _showDebug = true; //Set to log Register values to console after execution _logger.Debug($"{Registers.CS:X4}:{_currentInstruction.IP16:X4} {_currentInstruction}"); - _logger.Debug($"{Registers}"); foreach(var l in Registers.ToString().Split("\n")) _logger.Debug(l); for(var i = 0; i < 8; i++) @@ -1696,6 +1695,10 @@ private byte Op_Rcl_8() Registers.CarryFlag = newCFValue; } + //For 1 Bit Rotations, we evaluate Overflow + if(source == 1) + Registers.OverflowFlag = result.IsBitSet(7) ^ Registers.CarryFlag; + return result; } } @@ -1725,6 +1728,10 @@ private ushort Op_Rcl_16() Registers.CarryFlag = newCFValue; } + //For 1 Bit Rotations, we evaluate Overflow + if (source == 1) + Registers.OverflowFlag = result.IsBitSet(7) ^ Registers.CarryFlag; + return result; } } @@ -3996,8 +4003,9 @@ private byte Op_Ror_8() //CF Set if Most Significant Bit set to 1 Registers.CarryFlag = result.IsNegative(); - //If Bits 7 & 6 are not the same, then we overflowed - Registers.OverflowFlag = result.IsBitSet(7) != result.IsBitSet(6); + //If Bits 7 & 6 are not the same, then we overflowed for 1 bit rotations + if(source == 1) + Registers.OverflowFlag = result.IsBitSet(7) != result.IsBitSet(6); return result; } @@ -4020,8 +4028,9 @@ private ushort Op_Ror_16() //CF Set if Most Significant Bit set to 1 Registers.CarryFlag = result.IsNegative(); - //If Bits 15 & 14 are not the same, then we overflowed - Registers.OverflowFlag = result.IsBitSet(15) != result.IsBitSet(14); + //If Bits 15 & 14 are not the same, then we overflowed for 1 bit rotations + if (source == 1) + Registers.OverflowFlag = result.IsBitSet(15) != result.IsBitSet(14); return result; } From bee8408ea3e186c42e9f681f3bad9fe913375802 Mon Sep 17 00:00:00 2001 From: "Eric P. Nusbaum" Date: Sun, 23 Jun 2024 22:17:44 -0400 Subject: [PATCH 6/7] Make FILD Maintain Sign when Converting - `FILD` was converting memory integer values to unsigned values before casting to double - Added helper method to maintain signed value of memory/register values - `FILD` updated to take signed value from memory/registers - Updated Unit Tests for `FILD` to use signed types --- MBBSEmu.Tests/CPU/FILD_Tests.cs | 30 ++++++++++++------------- MBBSEmu/CPU/CPUCore.cs | 39 ++++++++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 16 deletions(-) diff --git a/MBBSEmu.Tests/CPU/FILD_Tests.cs b/MBBSEmu.Tests/CPU/FILD_Tests.cs index 13069106..fac6f513 100644 --- a/MBBSEmu.Tests/CPU/FILD_Tests.cs +++ b/MBBSEmu.Tests/CPU/FILD_Tests.cs @@ -9,9 +9,9 @@ public class FILD_Tests : CpuTestBase { [Theory] [InlineData(0)] - [InlineData(ushort.MaxValue)] - [InlineData(ushort.MinValue)] - public void FILD_Test_M16(ushort valueToLoad) + [InlineData(short.MaxValue)] + [InlineData(short.MinValue)] + public void FILD_Test_M16(short valueToLoad) { Reset(); @@ -30,8 +30,8 @@ public void FILD_Test_M16(ushort valueToLoad) [Theory] [InlineData(1, 2)] - [InlineData(ushort.MaxValue, ushort.MinValue)] - public void FILD_Multiple_Test_M16(ushort st0, ushort st1) + [InlineData(short.MaxValue, short.MinValue)] + public void FILD_Multiple_Test_M16(short st0, short st1) { Reset(); @@ -54,9 +54,9 @@ public void FILD_Multiple_Test_M16(ushort st0, ushort st1) [Theory] [InlineData(0)] - [InlineData(uint.MaxValue)] - [InlineData(uint.MinValue)] - public void FILD_Test_M32(uint valueToLoad) + [InlineData(int.MaxValue)] + [InlineData(int.MinValue)] + public void FILD_Test_M32(int valueToLoad) { Reset(); @@ -75,8 +75,8 @@ public void FILD_Test_M32(uint valueToLoad) [Theory] [InlineData(1, 2)] - [InlineData(uint.MaxValue, uint.MinValue)] - public void FILD_Multiple_Test_M32(uint st0, uint st1) + [InlineData(int.MaxValue, int.MinValue)] + public void FILD_Multiple_Test_M32(int st0, int st1) { Reset(); @@ -99,9 +99,9 @@ public void FILD_Multiple_Test_M32(uint st0, uint st1) [Theory] [InlineData(0)] - [InlineData(ulong.MaxValue)] - [InlineData(ulong.MinValue)] - public void FILD_Test_M64(ulong valueToLoad) + [InlineData(long.MaxValue)] + [InlineData(long.MinValue)] + public void FILD_Test_M64(long valueToLoad) { Reset(); @@ -120,8 +120,8 @@ public void FILD_Test_M64(ulong valueToLoad) [Theory] [InlineData(1, 2)] - [InlineData(ulong.MaxValue, ulong.MinValue)] - public void FILD_Multiple_Test_M64(ulong st0, ulong st1) + [InlineData(long.MaxValue, long.MinValue)] + public void FILD_Multiple_Test_M64(long st0, long st1) { Reset(); diff --git a/MBBSEmu/CPU/CPUCore.cs b/MBBSEmu/CPU/CPUCore.cs index 80da4a76..29ff9c12 100644 --- a/MBBSEmu/CPU/CPUCore.cs +++ b/MBBSEmu/CPU/CPUCore.cs @@ -954,6 +954,43 @@ private uint GetOperandValueUInt32(OpKind opKind, EnumOperandType operandType) } } + /// + /// This is a helper method which takes the resulting value from GetOperandValueUInt64 and signs it depending on the underlying + /// OpKind and MemorySize + /// + /// + /// + [MethodImpl(OpcodeCompilerOptimizations)] + private long GetOperandValueInt64(OpKind opKind) + { + var value = GetOperandValueUInt64(opKind); + + return opKind switch + { + OpKind.Immediate8 => (sbyte)value, + OpKind.Immediate16 => (short)value, + OpKind.Immediate8to16 => (short)value, + OpKind.Immediate32 => (int)value, + OpKind.Immediate8to32 => (int)value, + OpKind.Immediate64 => (long)value, + OpKind.Immediate8to64 => (long)value, + OpKind.Memory => _currentInstruction.MemorySize switch + { + MemorySize.Int8 => (sbyte)value, + MemorySize.UInt8 => (byte)value, + MemorySize.Int16 => (short)value, + MemorySize.UInt16 => (ushort)value, + MemorySize.Int32 => (int)value, + MemorySize.UInt32 => (uint)value, + MemorySize.Int64 => (long)value, + MemorySize.UInt64 => (long)value, + _ => throw new Exception($"Invalid Operand Size: {_currentInstruction.MemorySize}") + }, + _ => throw new Exception($"Unsupported OpKind: {opKind}") + }; + + } + /// /// Returns the Operand Value as a 64-bit Integer /// @@ -3126,7 +3163,7 @@ private void Op_Fld() [MethodImpl(OpcodeCompilerOptimizations)] private void Op_Fild() { - var valueToLoad = GetOperandValueUInt64(_currentInstruction.Op0Kind); + var valueToLoad = GetOperandValueInt64(_currentInstruction.Op0Kind); Registers.Fpu.PushStackTop(); FpuStack[Registers.Fpu.GetStackTop()] = valueToLoad; From b732d5ea64f9f56ed7c3f82c6085d94238c0d0da Mon Sep 17 00:00:00 2001 From: "Eric P. Nusbaum" Date: Mon, 24 Jun 2024 07:36:24 -0400 Subject: [PATCH 7/7] Fix RCR_AX_IMM16_CF_SET --- MBBSEmu.Tests/CPU/RCR_Tests.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/MBBSEmu.Tests/CPU/RCR_Tests.cs b/MBBSEmu.Tests/CPU/RCR_Tests.cs index 01fe2c64..42841c15 100644 --- a/MBBSEmu.Tests/CPU/RCR_Tests.cs +++ b/MBBSEmu.Tests/CPU/RCR_Tests.cs @@ -35,11 +35,11 @@ public void RCR_AX_IMM16_CF_CLEAR(ushort axValue, byte bitsToRotate, ushort expe } [Theory] - [InlineData(0xF, 1, 0x8007, true, false)] - [InlineData(0xF, 2, 0xC003, true, true)] - [InlineData(0xE, 1, 0x8007, false, false)] - [InlineData(0x1FF, 1, 0x80FF, true, false)] - [InlineData(0x1FE, 1, 0x80FF, false, false)] + [InlineData(0xF, 1, 0x8007, true, true)] + [InlineData(0xF, 2, 0xC003, true, false)] + [InlineData(0xE, 1, 0x8007, false, true)] + [InlineData(0x1FF, 1, 0x80FF, true, true)] + [InlineData(0x1FE, 1, 0x80FF, false, true)] [InlineData(0x3C, 2, 0x400F, false, false)] [InlineData(0x3E, 2, 0x400F, true, false)] [InlineData(0xFFFF, 2, 0xFFFF, true, false)] @@ -58,6 +58,7 @@ public void RCR_AX_IMM16_CF_SET(ushort axValue, byte bitsToRotate, ushort expect Assert.Equal(expectedValue, mbbsEmuCpuRegisters.AX); Assert.Equal(expectedCFValue, mbbsEmuCpuRegisters.CarryFlag); + Assert.Equal(expectedOFValue, mbbsEmuCpuRegisters.OverflowFlag); } [Theory]