161 lines
5.1 KiB
C#
161 lines
5.1 KiB
C#
// Copyright (C) 2026 SharpEmu Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
using SharpEmu.Core.Cpu.Emulation;
|
|
using Xunit;
|
|
|
|
namespace SharpEmu.Libs.Tests.Cpu;
|
|
|
|
// These exercise the pure EXTRQ/INSERTQ bit-field semantics used by the general SSE4a
|
|
// illegal-instruction software fallback (DirectExecutionBackend.Amd64Compat.cs). Expected values
|
|
// were computed from the AMD64 Architecture Programmer's Manual definitions and cross-checked
|
|
// with an independent Python re-implementation before being written here, so a regression in the
|
|
// ported bit math fails in this file without needing a live guest or a Windows host.
|
|
public sealed class Sse4aBitFieldEmulatorTests
|
|
{
|
|
[Fact]
|
|
public void ExtractBitField_ExtractsLowByte()
|
|
{
|
|
var result = Sse4aBitFieldEmulator.ExtractBitField(0x1234_5678_9ABC_DEF0, length: 8, index: 0);
|
|
|
|
Assert.Equal(0xF0UL, result);
|
|
}
|
|
|
|
[Fact]
|
|
public void ExtractBitField_ExtractsMidFieldAtNonZeroIndex()
|
|
{
|
|
// bits [31:16] of 0x1234_5678_9ABC_DEF0 == 0x9ABC
|
|
var result = Sse4aBitFieldEmulator.ExtractBitField(0x1234_5678_9ABC_DEF0, length: 16, index: 16);
|
|
|
|
Assert.Equal(0x9ABCUL, result);
|
|
}
|
|
|
|
[Fact]
|
|
public void ExtractBitField_LengthZeroMeansSixtyFour()
|
|
{
|
|
var result = Sse4aBitFieldEmulator.ExtractBitField(0xFFFF_FFFF_FFFF_FFFF, length: 0, index: 0);
|
|
|
|
Assert.Equal(0xFFFF_FFFF_FFFF_FFFFUL, result);
|
|
}
|
|
|
|
[Fact]
|
|
public void ExtractBitField_MasksImmediatesToLowSixBits()
|
|
{
|
|
var result = Sse4aBitFieldEmulator.ExtractBitField(0x0000_0000_0000_00FF, length: 0x28, index: 0);
|
|
|
|
Assert.Equal(0xFFUL, result);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(0x1234_5678_9ABC_DEF0UL)]
|
|
[InlineData(0x0000_0000_0000_0000UL)]
|
|
[InlineData(0xFFFF_FFFF_FFFF_FFFFUL)]
|
|
[InlineData(0x00FF_00FF_00FF_00FFUL)]
|
|
public void ExtractBitField_FortyBitFieldRetainsOnlyByteFourInUpperWord(ulong value)
|
|
{
|
|
var extractedLow64 = Sse4aBitFieldEmulator.ExtractBitField(value, length: 0x28, index: 0);
|
|
var upperWord = (uint)(extractedLow64 >> 32);
|
|
var byteFourZeroExtended = (uint)((value >> 32) & 0xFF);
|
|
|
|
Assert.Equal(byteFourZeroExtended, upperWord);
|
|
}
|
|
|
|
[Fact]
|
|
public void ExtractBitField_ClampsUndefinedFieldPastRegisterEnd()
|
|
{
|
|
Assert.False(Sse4aBitFieldEmulator.IsValidBitField(length: 8, index: 60));
|
|
Assert.Equal(0xFUL, Sse4aBitFieldEmulator.ExtractBitField(
|
|
0xFFFF_FFFF_FFFF_FFFF,
|
|
length: 8,
|
|
index: 60));
|
|
}
|
|
|
|
[Fact]
|
|
public void ExtractBitField_RejectsZeroLengthAtNonZeroIndex()
|
|
{
|
|
Assert.False(Sse4aBitFieldEmulator.IsValidBitField(length: 0, index: 1));
|
|
Assert.Equal(
|
|
0x7FFF_FFFF_FFFF_FFFFUL,
|
|
Sse4aBitFieldEmulator.ExtractBitField(
|
|
0xFFFF_FFFF_FFFF_FFFF,
|
|
length: 0,
|
|
index: 1));
|
|
}
|
|
|
|
[Fact]
|
|
public void InsertBitField_InsertsFieldAtNonZeroIndexWithoutDisturbingOtherBits()
|
|
{
|
|
var result = Sse4aBitFieldEmulator.InsertBitField(
|
|
destination: 0x0000_0000_0000_0000,
|
|
source: 0xFFFF_FFFF_FFFF_FFFF,
|
|
length: 8,
|
|
index: 8);
|
|
|
|
Assert.Equal(0x0000_0000_0000_FF00UL, result);
|
|
}
|
|
|
|
[Fact]
|
|
public void InsertBitField_ClearsExactlyTheDestinationWindowBeforeInserting()
|
|
{
|
|
var result = Sse4aBitFieldEmulator.InsertBitField(
|
|
destination: 0xFFFF_FFFF_FFFF_FFFF,
|
|
source: 0x0000_0000_0000_0000,
|
|
length: 16,
|
|
index: 16);
|
|
|
|
Assert.Equal(0xFFFF_FFFF_0000_FFFFUL, result);
|
|
}
|
|
|
|
[Fact]
|
|
public void InsertBitField_InsertsLowByteAtIndexZero()
|
|
{
|
|
var result = Sse4aBitFieldEmulator.InsertBitField(
|
|
destination: 0x1122_3344_5566_7788,
|
|
source: 0xAABB_CCDD_EEFF_0011,
|
|
length: 8,
|
|
index: 0);
|
|
|
|
Assert.Equal(0x1122_3344_5566_7711UL, result);
|
|
}
|
|
|
|
[Fact]
|
|
public void InsertBitField_LengthZeroMeansSixtyFourAndOverwritesEverything()
|
|
{
|
|
var result = Sse4aBitFieldEmulator.InsertBitField(
|
|
destination: 0x1111_1111_1111_1111,
|
|
source: 0xFFFF_FFFF_FFFF_FFFF,
|
|
length: 0,
|
|
index: 0);
|
|
|
|
Assert.Equal(0xFFFF_FFFF_FFFF_FFFFUL, result);
|
|
}
|
|
|
|
[Fact]
|
|
public void InsertBitField_ZeroSourceFieldClearsOnlyItsOwnWindow()
|
|
{
|
|
// A zero-valued 12-bit field inserted at index 20 clears exactly bits [31:20]
|
|
// (0x234 -> 0x000) and leaves every bit outside that window untouched.
|
|
var result = Sse4aBitFieldEmulator.InsertBitField(
|
|
destination: 0xABCD_EF01_2345_6789,
|
|
source: 0,
|
|
length: 12,
|
|
index: 20);
|
|
|
|
Assert.Equal(0xABCD_EF01_0005_6789UL, result);
|
|
}
|
|
|
|
[Fact]
|
|
public void InsertBitField_ClampsUndefinedFieldPastRegisterEnd()
|
|
{
|
|
Assert.False(Sse4aBitFieldEmulator.IsValidBitField(length: 8, index: 60));
|
|
|
|
var result = Sse4aBitFieldEmulator.InsertBitField(
|
|
destination: 0,
|
|
source: ulong.MaxValue,
|
|
length: 8,
|
|
index: 60);
|
|
|
|
Assert.Equal(0xF000_0000_0000_0000UL, result);
|
|
}
|
|
}
|