mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-22 19:06:15 +08:00
[ShaderCompiler] Fix VReadlane scalar destination field (#344)
V_READLANE uses the gfx10 VOP3A vdst byte even though its result is scalar. Decode bits 0-7 and cover the public LLVM s5 and s101 encodings so the VOP3B sdst field cannot be confused with this opcode again.
This commit is contained in:
@@ -1872,8 +1872,9 @@ public static class Gen5ShaderTranslator
|
|||||||
destinations = [Gen5Operand.Vector(word & 0xFF)];
|
destinations = [Gen5Operand.Vector(word & 0xFF)];
|
||||||
if (opcode == "VReadlaneB32")
|
if (opcode == "VReadlaneB32")
|
||||||
{
|
{
|
||||||
// The scalar destination lives in the low vdst byte (bits 0-7);
|
// V_READLANE uses the VOP3A vdst byte even though the
|
||||||
// bits 8-14 are the VOP3B carry-out sdst, which readlane lacks.
|
// destination register is scalar. Bits 8-14 are the
|
||||||
|
// distinct sdst field used by VOP3B encodings.
|
||||||
destinations = [Gen5Operand.Scalar(word & 0xFF)];
|
destinations = [Gen5Operand.Scalar(word & 0xFF)];
|
||||||
}
|
}
|
||||||
var isVop3B = IsVop3BOpcode((word >> 16) & 0x3FF);
|
var isVop3B = IsVop3BOpcode((word >> 16) & 0x3FF);
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
// Copyright (C) 2026 SharpEmu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
using System.Buffers.Binary;
|
||||||
|
using SharpEmu.HLE;
|
||||||
|
using SharpEmu.ShaderCompiler;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace SharpEmu.Libs.Tests.ShaderCompiler;
|
||||||
|
|
||||||
|
public sealed class Gen5ShaderTranslatorTests
|
||||||
|
{
|
||||||
|
private const ulong ProgramAddress = 0x1_0000_0000;
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(0xD7600005u, 5u)]
|
||||||
|
[InlineData(0xD7600065u, 101u)]
|
||||||
|
public void VReadlaneB32DecodesScalarDestinationFromVdstByte(
|
||||||
|
uint instructionWord,
|
||||||
|
uint expectedDestination)
|
||||||
|
{
|
||||||
|
var memory = new FakeCpuMemory(ProgramAddress, 0x100);
|
||||||
|
Span<byte> code = stackalloc byte[3 * sizeof(uint)];
|
||||||
|
BinaryPrimitives.WriteUInt32LittleEndian(code, instructionWord);
|
||||||
|
BinaryPrimitives.WriteUInt32LittleEndian(code[sizeof(uint)..], 0x02000501u);
|
||||||
|
BinaryPrimitives.WriteUInt32LittleEndian(code[(2 * sizeof(uint))..], 0xBF810000u);
|
||||||
|
Assert.True(memory.TryWrite(ProgramAddress, code));
|
||||||
|
|
||||||
|
var context = new CpuContext(memory, Generation.Gen5);
|
||||||
|
Assert.True(
|
||||||
|
Gen5ShaderTranslator.TryDecodeProgram(
|
||||||
|
context,
|
||||||
|
ProgramAddress,
|
||||||
|
out var program,
|
||||||
|
out var error),
|
||||||
|
error);
|
||||||
|
|
||||||
|
var instruction = Assert.Single(
|
||||||
|
program.Instructions,
|
||||||
|
static item => item.Opcode == "VReadlaneB32");
|
||||||
|
Assert.Equal(Gen5ShaderEncoding.Vop3, instruction.Encoding);
|
||||||
|
|
||||||
|
var destination = Assert.Single(instruction.Destinations);
|
||||||
|
Assert.Equal(Gen5OperandKind.ScalarRegister, destination.Kind);
|
||||||
|
Assert.Equal(expectedDestination, destination.Value);
|
||||||
|
|
||||||
|
Assert.Equal(Gen5OperandKind.VectorRegister, instruction.Sources[0].Kind);
|
||||||
|
Assert.Equal(1u, instruction.Sources[0].Value);
|
||||||
|
Assert.Equal(Gen5OperandKind.ScalarRegister, instruction.Sources[1].Kind);
|
||||||
|
Assert.Equal(2u, instruction.Sources[1].Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user