diff --git a/src/video_core/shader/decode/arithmetic_half.cpp b/src/video_core/shader/decode/arithmetic_half.cpp index 3b189b0d17..a6c6f31746 100644 --- a/src/video_core/shader/decode/arithmetic_half.cpp +++ b/src/video_core/shader/decode/arithmetic_half.cpp @@ -16,7 +16,54 @@ u32 ShaderIR::DecodeArithmeticHalf(BasicBlock& bb, u32 pc) { const Instruction instr = {program_code[pc]}; const auto opcode = OpCode::Decode(instr); - UNIMPLEMENTED(); + if (opcode->get().GetId() == OpCode::Id::HADD2_C || + opcode->get().GetId() == OpCode::Id::HADD2_R) { + UNIMPLEMENTED_IF(instr.alu_half.ftz != 0); + } + UNIMPLEMENTED_IF_MSG(instr.alu_half.saturate != 0, + "Half float saturation not implemented"); + + 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; + + const Node op_a = GetOperandAbsNegHalf(GetRegister(instr.gpr8), instr.alu_half.abs_a, negate_a); + + // instr.alu_half.type_a + + Node op_b = [&]() { + switch (opcode->get().GetId()) { + case OpCode::Id::HADD2_C: + case OpCode::Id::HMUL2_C: + return GetConstBuffer(instr.cbuf34.index, instr.cbuf34.offset); + case OpCode::Id::HADD2_R: + case OpCode::Id::HMUL2_R: + return GetRegister(instr.gpr20); + default: + UNREACHABLE(); + return Immediate(0); + } + }(); + op_b = GetOperandAbsNegHalf(op_b, instr.alu_half.abs_b, negate_b); + + Node value = [&]() { + MetaHalfArithmetic meta{true, {instr.alu_half_imm.type_a, instr.alu_half.type_b}}; + switch (opcode->get().GetId()) { + case OpCode::Id::HADD2_C: + case OpCode::Id::HADD2_R: + return Operation(OperationCode::HAdd, meta, op_a, op_b); + case OpCode::Id::HMUL2_C: + case OpCode::Id::HMUL2_R: + return Operation(OperationCode::HMul, meta, op_a, op_b); + default: + UNIMPLEMENTED_MSG("Unhandled half float instruction: {}", opcode->get().GetName()); + return Immediate(0); + } + }(); + value = HalfMerge(GetRegister(instr.gpr0), value, instr.alu_half.merge); + + SetRegister(bb, instr.gpr0, value); return pc; }