Skip to content

Commit

Permalink
Update FPU Unit Tests for Rounding Mode
Browse files Browse the repository at this point in the history
- Add Control Word to Unit Tests for `FLDCW` and `FRNDINT`
- Verify Different Rounding Modes in these Unit Test cases
  • Loading branch information
enusbaum committed Aug 28, 2024
1 parent 56339ec commit 6040f78
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 18 deletions.
29 changes: 24 additions & 5 deletions MBBSEmu.Tests/CPU/FLDCW_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,41 @@ namespace MBBSEmu.Tests.CPU
{
public class FLDCW_Tests : CpuTestBase
{
[Fact]
public void FLDCW_Test()
/// <summary>
/// Loads the FPU Control Word from Memory and sets the FPU Control Word
///
/// We'll verify this by not only setting the Control Word, but also verify
/// the Round Mode is set correctly
///
/// Rounding Flag Conversion:
/// Rounding Mode = (ControlWord >> 10) &amp; 0x3;
/// 0 => MidpointRounding.ToEven
/// 1 => MidpointRounding.ToNegativeInfinity
/// 2 => MidpointRounding.ToPositiveInfinity
/// 3 => MidpointRounding.ToZero
/// </summary>
[Theory]
[InlineData(0x0000, MidpointRounding.ToEven)]
[InlineData(0x0400, MidpointRounding.ToNegativeInfinity)]
[InlineData(0x0800, MidpointRounding.ToPositiveInfinity)]
[InlineData(0x0C00, MidpointRounding.ToZero)]
public void FLDCW_Test(ushort controlWord, MidpointRounding roundingMode)
{
Reset();
mbbsEmuCpuRegisters.Fpu.ControlWord = 0;
CreateDataSegment(new ReadOnlySpan<byte>(), 2);
mbbsEmuMemoryCore.SetWord(2,0, 0xFFFF);
mbbsEmuMemoryCore.SetArray(2, 0, [0, 0, 0]); //Set some junk data ahead of the actual address
mbbsEmuMemoryCore.SetWord(2,3, controlWord);
mbbsEmuCpuRegisters.DS = 2;

var instructions = new Assembler(16);
instructions.fldcw(__word_ptr[0]);
instructions.fldcw(__word_ptr[3]);
CreateCodeSegment(instructions);

mbbsEmuCpuCore.Tick();

Assert.Equal(0xFFFF, mbbsEmuCpuRegisters.Fpu.ControlWord);
Assert.Equal(controlWord, mbbsEmuCpuRegisters.Fpu.ControlWord);
Assert.Equal(roundingMode, mbbsEmuCpuRegisters.Fpu.GetRoundingControl());
}
}
}
36 changes: 28 additions & 8 deletions MBBSEmu.Tests/CPU/FRNDINT_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,40 @@ namespace MBBSEmu.Tests.CPU
{
public class FRNDINT_Tests : CpuTestBase
{
/// <summary>
/// Tests the FRNDINT Instruction which rounds the value in ST(0) to the nearest integer
///
/// We'll test this by setting the FPU Control Mode to Round to different modes and verify.
///
/// Rounding Flag Conversion:
/// Rounding Mode = (ControlWord >> 10) &amp; 0x3;
/// 0 => MidpointRounding.ToEven
/// 1 => MidpointRounding.ToNegativeInfinity
/// 2 => MidpointRounding.ToPositiveInfinity
/// 3 => MidpointRounding.ToZero
/// </summary>
/// <param name="ST0Value"></param>
/// <param name="expectedValue"></param>
[Theory]
[InlineData(2.1d, 2d)]
[InlineData(0.1d, 0d)]
[InlineData(1.9d, 2d)]
[InlineData(-1.9d, -2d)]
[InlineData(0.5d, 0d)]
[InlineData(0.49999999d, 0d)]
public void FRNDINT_Test(double ST0Value, double expectedValue)
//Round to Even
[InlineData(1.5, 2.0, 0x0000)]
[InlineData(-1.5, -2.0, 0x0000)]
//Round to Negative Infinity
[InlineData(1.5, 1.0, 0x0400)]
[InlineData(-1.5, -2.0, 0x0400)]
//Round to Positive Infinity
[InlineData(1.5, 2.0, 0x0800)]
[InlineData(-1.5, -1.0, 0x0800)]
//Round to Zero
[InlineData(1.5, 1.0, 0x0C00)]
[InlineData(-1.5, -1.0, 0x0C00)]
public void FRNDINT_Test(double ST0Value, double expectedValue, ushort controlWord)
{
Reset();
mbbsEmuCpuCore.FpuStack[mbbsEmuCpuRegisters.Fpu.GetStackTop()] = ST0Value;

//Set FPU Control Word to set rounding to even
mbbsEmuCpuRegisters.Fpu.ControlWord = 0x0000000C;
mbbsEmuCpuRegisters.Fpu.ControlWord = controlWord;

var instructions = new Assembler(16);
instructions.frndint();
Expand Down
1 change: 1 addition & 0 deletions MBBSEmu/CPU/CpuRegisters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ public void SetPointer(FarPtr ptr)
public void PopStackTop() => Registers.Fpu.PopStackTop();
public void PushStackTop() => Registers.Fpu.PushStackTop();
public void ClearExceptions() => Registers.Fpu.ClearExceptions();
public MidpointRounding GetRoundingControl() => Registers.Fpu.GetRoundingControl();

/// <summary>
/// Overridden ToString() to display the current state of the CPU Registers
Expand Down
6 changes: 1 addition & 5 deletions MBBSEmu/CPU/ICpuRegisters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,16 @@ namespace MBBSEmu.CPU
public interface IFpuRegisters
{
ushort StatusWord { get; set; }

ushort ControlWord { get; set; }

void SetFlag(EnumFpuStatusFlags statusFlag);
void ClearFlag(EnumFpuStatusFlags statusFlag);

byte GetStackTop();

void SetStackTop(byte value);

int GetStackPointer(Register register);
void PopStackTop();
void PushStackTop();
void ClearExceptions();
MidpointRounding GetRoundingControl();
}

/// <summary>
Expand Down

0 comments on commit 6040f78

Please sign in to comment.