From 44ea70ed80765c10f85a72fa45314a277e03b8e8 Mon Sep 17 00:00:00 2001 From: "Eric P. Nusbaum" Date: Sun, 5 Nov 2023 14:13:48 -0500 Subject: [PATCH] Fix RCL Implementation - Fixes RCL Implementation to be accurate - Added Unit tests for both 8-bit and 16-bit RCL operations - Minor code cleanup --- MBBSEmu.Tests/CPU/RLC_Tests.cs | 56 ++++++++++++++++++++++++++++++++++ MBBSEmu/CPU/CPUCore.cs | 26 +++++++++------- MBBSEmu/CPU/ICpuRegisters.cs | 2 -- 3 files changed, 71 insertions(+), 13 deletions(-) create mode 100644 MBBSEmu.Tests/CPU/RLC_Tests.cs diff --git a/MBBSEmu.Tests/CPU/RLC_Tests.cs b/MBBSEmu.Tests/CPU/RLC_Tests.cs new file mode 100644 index 00000000..5eab86e8 --- /dev/null +++ b/MBBSEmu.Tests/CPU/RLC_Tests.cs @@ -0,0 +1,56 @@ +using Iced.Intel; +using Xunit; +using static Iced.Intel.AssemblerRegisters; + +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 + public void Op_Rcl_16_Test(ushort axValue, byte bitsToRotate, bool initialCarryFlag, ushort expectedResult, + bool expectedCarryFlag) + { + Reset(); + mbbsEmuCpuRegisters.AX = axValue; + mbbsEmuCpuRegisters.CarryFlag = initialCarryFlag; + + var instructions = new Assembler(16); + instructions.rcl(ax, bitsToRotate); + CreateCodeSegment(instructions); + + mbbsEmuCpuCore.Tick(); + + Assert.Equal(expectedResult, mbbsEmuCpuRegisters.AX); + Assert.Equal(expectedCarryFlag, mbbsEmuCpuRegisters.CarryFlag); + } + + [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 + public void Op_Rcl_8_Test(byte alValue, byte bitsToRotate, bool initialCarryFlag, ushort expectedResult, + bool expectedCarryFlag) + { + Reset(); + mbbsEmuCpuRegisters.AL = alValue; + mbbsEmuCpuRegisters.CarryFlag = initialCarryFlag; + + var instructions = new Assembler(16); + instructions.rcl(al, bitsToRotate); + CreateCodeSegment(instructions); + + mbbsEmuCpuCore.Tick(); + + Assert.Equal(expectedResult, mbbsEmuCpuRegisters.AL); + Assert.Equal(expectedCarryFlag, mbbsEmuCpuRegisters.CarryFlag); + + } + } +} diff --git a/MBBSEmu/CPU/CPUCore.cs b/MBBSEmu/CPU/CPUCore.cs index 65346349..3d7b2b47 100644 --- a/MBBSEmu/CPU/CPUCore.cs +++ b/MBBSEmu/CPU/CPUCore.cs @@ -349,7 +349,7 @@ public void Tick() }; //Set this value to TRUE if you want the CPU to break after each instruction - var CPUDebugBreak = true; + var CPUDebugBreak = false; //Evaluate Breakpoints if (CPUBreakpoints.Contains(_currentInstructionPointer)) @@ -1641,6 +1641,10 @@ private ushort Op_Rcr_16() } } + /// + /// Performs a left circular rotate (RCL) operation on the current operation size. + /// + /// [MethodImpl(OpcodeCompilerOptimizations)] private void Op_Rcl() { @@ -1665,17 +1669,17 @@ private byte Op_Rcl_8() var result = destination; for (var i = 0; i < source; i++) { - //Determine the CF Value after rotation+carry + // Determine the CF Value after rotation+carry var newCFValue = result.IsBitSet(7); - //Perform Rotation + // Perform Rotation result = (byte)(result << 1); - //If CF was set, rotate that value in + // If CF was set, rotate that value in to the LSB (0th bit) if (Registers.CarryFlag) - result.SetFlag(1); + result |= 1; - //Set new CF Value + // Set new CF Value Registers.CarryFlag = newCFValue; } @@ -1694,17 +1698,17 @@ private ushort Op_Rcl_16() var result = destination; for (var i = 0; i < source; i++) { - //Determine the CF Value after rotation+carry + // Determine the CF Value after rotation+carry var newCFValue = result.IsBitSet(15); - //Perform Rotation + // Perform Rotation result = (ushort)(result << 1); - //If CF was set, rotate that value in + // If CF was set, rotate that value in to the LSB (0th bit) if (Registers.CarryFlag) - result.SetFlag(1); + result |= 1; - //Set new CF Value + // Set new CF Value Registers.CarryFlag = newCFValue; } diff --git a/MBBSEmu/CPU/ICpuRegisters.cs b/MBBSEmu/CPU/ICpuRegisters.cs index ee0b28bb..edb6aee4 100644 --- a/MBBSEmu/CPU/ICpuRegisters.cs +++ b/MBBSEmu/CPU/ICpuRegisters.cs @@ -1,8 +1,6 @@ using Iced.Intel; -using MBBSEmu.Extensions; using MBBSEmu.Memory; using System; -using System.Runtime.InteropServices; namespace MBBSEmu.CPU {