mirror of
https://github.com/yuzu-mirror/yuzu.git
synced 2024-11-18 03:37:32 +01:00
decode/arithmetic_half: Fix HADD2 and HMUL2 absolute and negation bits
The encoding for negation and absolute value was wrong.
Extracting is now done manually. Similar instructions having different
encodings is the rule, not the exception. To keep sanity and readability
I preferred to extract the desired bit manually.
This is implemented against nxas:
8dbc389957/table.h (L68)
That is itself tested against nvdisasm (Nvidia's official disassembler).
This commit is contained in:
parent
4d7d3651f3
commit
dbaebd8582
@ -817,11 +817,9 @@ union Instruction {
|
||||
BitField<32, 1, u64> saturate;
|
||||
BitField<49, 2, HalfMerge> merge;
|
||||
|
||||
BitField<43, 1, u64> negate_a;
|
||||
BitField<44, 1, u64> abs_a;
|
||||
BitField<47, 2, HalfType> type_a;
|
||||
|
||||
BitField<31, 1, u64> negate_b;
|
||||
BitField<30, 1, u64> abs_b;
|
||||
BitField<28, 2, HalfType> type_b;
|
||||
|
||||
|
@ -19,22 +19,46 @@ u32 ShaderIR::DecodeArithmeticHalf(NodeBlock& bb, u32 pc) {
|
||||
const Instruction instr = {program_code[pc]};
|
||||
const auto opcode = OpCode::Decode(instr);
|
||||
|
||||
if (opcode->get().GetId() == OpCode::Id::HADD2_C ||
|
||||
opcode->get().GetId() == OpCode::Id::HADD2_R) {
|
||||
bool negate_a = false;
|
||||
bool negate_b = false;
|
||||
bool absolute_a = false;
|
||||
bool absolute_b = false;
|
||||
|
||||
switch (opcode->get().GetId()) {
|
||||
case OpCode::Id::HADD2_R:
|
||||
if (instr.alu_half.ftz == 0) {
|
||||
LOG_DEBUG(HW_GPU, "{} without FTZ is not implemented", opcode->get().GetName());
|
||||
}
|
||||
negate_a = ((instr.value >> 43) & 1) != 0;
|
||||
negate_b = ((instr.value >> 31) & 1) != 0;
|
||||
absolute_a = ((instr.value >> 44) & 1) != 0;
|
||||
absolute_b = ((instr.value >> 30) & 1) != 0;
|
||||
break;
|
||||
case OpCode::Id::HADD2_C:
|
||||
if (instr.alu_half.ftz == 0) {
|
||||
LOG_DEBUG(HW_GPU, "{} without FTZ is not implemented", opcode->get().GetName());
|
||||
}
|
||||
negate_a = ((instr.value >> 43) & 1) != 0;
|
||||
negate_b = ((instr.value >> 56) & 1) != 0;
|
||||
absolute_a = ((instr.value >> 44) & 1) != 0;
|
||||
absolute_b = ((instr.value >> 54) & 1) != 0;
|
||||
break;
|
||||
case OpCode::Id::HMUL2_R:
|
||||
negate_a = ((instr.value >> 43) & 1) != 0;
|
||||
absolute_a = ((instr.value >> 44) & 1) != 0;
|
||||
absolute_b = ((instr.value >> 30) & 1) != 0;
|
||||
break;
|
||||
case OpCode::Id::HMUL2_C:
|
||||
negate_b = ((instr.value >> 31) & 1) != 0;
|
||||
absolute_a = ((instr.value >> 44) & 1) != 0;
|
||||
absolute_b = ((instr.value >> 54) & 1) != 0;
|
||||
break;
|
||||
}
|
||||
|
||||
const bool negate_a =
|
||||
opcode->get().GetId() != OpCode::Id::HMUL2_R && instr.alu_half.negate_a != 0;
|
||||
const bool negate_b =
|
||||
opcode->get().GetId() != OpCode::Id::HMUL2_C && instr.alu_half.negate_b != 0;
|
||||
|
||||
Node op_a = UnpackHalfFloat(GetRegister(instr.gpr8), instr.alu_half.type_a);
|
||||
op_a = GetOperandAbsNegHalf(op_a, instr.alu_half.abs_a, negate_a);
|
||||
op_a = GetOperandAbsNegHalf(op_a, absolute_a, negate_a);
|
||||
|
||||
auto [type_b, op_b] = [&]() -> std::tuple<HalfType, Node> {
|
||||
auto [type_b, op_b] = [this, instr, opcode]() -> std::pair<HalfType, Node> {
|
||||
switch (opcode->get().GetId()) {
|
||||
case OpCode::Id::HADD2_C:
|
||||
case OpCode::Id::HMUL2_C:
|
||||
@ -48,17 +72,16 @@ u32 ShaderIR::DecodeArithmeticHalf(NodeBlock& bb, u32 pc) {
|
||||
}
|
||||
}();
|
||||
op_b = UnpackHalfFloat(op_b, type_b);
|
||||
// redeclaration to avoid a bug in clang with reusing local bindings in lambdas
|
||||
Node op_b_alt = GetOperandAbsNegHalf(op_b, instr.alu_half.abs_b, negate_b);
|
||||
op_b = GetOperandAbsNegHalf(op_b, absolute_b, negate_b);
|
||||
|
||||
Node value = [&]() {
|
||||
Node value = [this, opcode, op_a, op_b = op_b] {
|
||||
switch (opcode->get().GetId()) {
|
||||
case OpCode::Id::HADD2_C:
|
||||
case OpCode::Id::HADD2_R:
|
||||
return Operation(OperationCode::HAdd, PRECISE, op_a, op_b_alt);
|
||||
return Operation(OperationCode::HAdd, PRECISE, op_a, op_b);
|
||||
case OpCode::Id::HMUL2_C:
|
||||
case OpCode::Id::HMUL2_R:
|
||||
return Operation(OperationCode::HMul, PRECISE, op_a, op_b_alt);
|
||||
return Operation(OperationCode::HMul, PRECISE, op_a, op_b);
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unhandled half float instruction: {}", opcode->get().GetName());
|
||||
return Immediate(0);
|
||||
|
Loading…
Reference in New Issue
Block a user