mirror of
https://gitlab.com/suyu-emu/suyu.git
synced 2024-03-15 23:15:44 +00:00
GPU: Partially implemented the shader BRA instruction.
This commit is contained in:
parent
06c72b4fcf
commit
b481d8a00d
|
@ -288,6 +288,19 @@ union Instruction {
|
||||||
}
|
}
|
||||||
} texs;
|
} texs;
|
||||||
|
|
||||||
|
union {
|
||||||
|
BitField<20, 5, u64> target;
|
||||||
|
BitField<5, 1, u64> constant_buffer;
|
||||||
|
|
||||||
|
s32 GetBranchTarget() const {
|
||||||
|
// Sign extend the branch target offset
|
||||||
|
u32 mask = 1U << (5 - 1);
|
||||||
|
u32 value = static_cast<u32>(target);
|
||||||
|
// The branch offset is relative to the next instruction, so add 1 to it.
|
||||||
|
return static_cast<s32>((value ^ mask) - mask) + 1;
|
||||||
|
}
|
||||||
|
} bra;
|
||||||
|
|
||||||
BitField<61, 1, u64> is_b_imm;
|
BitField<61, 1, u64> is_b_imm;
|
||||||
BitField<60, 1, u64> is_b_gpr;
|
BitField<60, 1, u64> is_b_gpr;
|
||||||
BitField<59, 1, u64> is_c_gpr;
|
BitField<59, 1, u64> is_c_gpr;
|
||||||
|
|
|
@ -88,6 +88,20 @@ private:
|
||||||
return *subroutines.insert(std::move(subroutine)).first;
|
return *subroutines.insert(std::move(subroutine)).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Merges exit method of two parallel branches.
|
||||||
|
static ExitMethod ParallelExit(ExitMethod a, ExitMethod b) {
|
||||||
|
if (a == ExitMethod::Undetermined) {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
if (b == ExitMethod::Undetermined) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
if (a == b) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
return ExitMethod::Conditional;
|
||||||
|
}
|
||||||
|
|
||||||
/// Scans a range of code for labels and determines the exit method.
|
/// Scans a range of code for labels and determines the exit method.
|
||||||
ExitMethod Scan(u32 begin, u32 end, std::set<u32>& labels) {
|
ExitMethod Scan(u32 begin, u32 end, std::set<u32>& labels) {
|
||||||
auto [iter, inserted] =
|
auto [iter, inserted] =
|
||||||
|
@ -97,11 +111,19 @@ private:
|
||||||
return exit_method;
|
return exit_method;
|
||||||
|
|
||||||
for (u32 offset = begin; offset != end && offset != PROGRAM_END; ++offset) {
|
for (u32 offset = begin; offset != end && offset != PROGRAM_END; ++offset) {
|
||||||
if (const auto opcode = OpCode::Decode({program_code[offset]})) {
|
const Instruction instr = {program_code[offset]};
|
||||||
|
if (const auto opcode = OpCode::Decode(instr)) {
|
||||||
switch (opcode->GetId()) {
|
switch (opcode->GetId()) {
|
||||||
case OpCode::Id::EXIT: {
|
case OpCode::Id::EXIT: {
|
||||||
return exit_method = ExitMethod::AlwaysEnd;
|
return exit_method = ExitMethod::AlwaysEnd;
|
||||||
}
|
}
|
||||||
|
case OpCode::Id::BRA: {
|
||||||
|
u32 target = offset + instr.bra.GetBranchTarget();
|
||||||
|
labels.insert(target);
|
||||||
|
ExitMethod no_jmp = Scan(offset + 1, end, labels);
|
||||||
|
ExitMethod jmp = Scan(target, end, labels);
|
||||||
|
return exit_method = ParallelExit(no_jmp, jmp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1081,6 +1103,13 @@ private:
|
||||||
shader.AddLine("discard;");
|
shader.AddLine("discard;");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case OpCode::Id::BRA: {
|
||||||
|
ASSERT_MSG(instr.bra.constant_buffer == 0,
|
||||||
|
"BRA with constant buffers are not implemented");
|
||||||
|
u32 target = offset + instr.bra.GetBranchTarget();
|
||||||
|
shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }");
|
||||||
|
break;
|
||||||
|
}
|
||||||
case OpCode::Id::IPA: {
|
case OpCode::Id::IPA: {
|
||||||
const auto& attribute = instr.attribute.fmt28;
|
const auto& attribute = instr.attribute.fmt28;
|
||||||
regs.SetRegisterToInputAttibute(instr.gpr0, attribute.element, attribute.index);
|
regs.SetRegisterToInputAttibute(instr.gpr0, attribute.element, attribute.index);
|
||||||
|
|
Loading…
Reference in a new issue