mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-12-16 04:09:07 +00:00
rsx/fp/asm: Implement asm support for branches
- Allows creating more complex command sequences from text
This commit is contained in:
parent
856eaac1b6
commit
f4ba548748
@ -2,6 +2,8 @@
|
|||||||
#include "FPASM.h"
|
#include "FPASM.h"
|
||||||
#include "Emu/RSX/Program/RSXFragmentProgram.h"
|
#include "Emu/RSX/Program/RSXFragmentProgram.h"
|
||||||
|
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#define sscanf_s sscanf
|
#define sscanf_s sscanf
|
||||||
#endif
|
#endif
|
||||||
@ -156,11 +158,32 @@ namespace rsx::assembler
|
|||||||
inst->opcode = RSX_FP_OPCODE_ADD;
|
inst->opcode = RSX_FP_OPCODE_ADD;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Instruction> FPIR::build()
|
const std::vector<Instruction>& FPIR::instructions() const
|
||||||
{
|
{
|
||||||
return m_instructions;
|
return m_instructions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<u32> FPIR::compile() const
|
||||||
|
{
|
||||||
|
std::vector<u32> result;
|
||||||
|
result.reserve(m_instructions.size() * 4);
|
||||||
|
|
||||||
|
for (u32 i = 0; i < m_instructions.size(); ++i)
|
||||||
|
{
|
||||||
|
const auto& inst = m_instructions[i];
|
||||||
|
auto src = reinterpret_cast<const be_t<u16>*>(inst.bytecode);
|
||||||
|
for (u32 j = 0; j < inst.length; ++j)
|
||||||
|
{
|
||||||
|
const u16 low = src[j * 2];
|
||||||
|
const u16 hi = src[j * 2 + 1];
|
||||||
|
const u32 word = static_cast<u16>(low) | (static_cast<u32>(hi) << 16u);
|
||||||
|
result.push_back(word);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
FPIR FPIR::from_source(const std::string& asm_)
|
FPIR FPIR::from_source(const std::string& asm_)
|
||||||
{
|
{
|
||||||
std::vector<std::string> instructions = fmt::split(asm_, { "\n", ";" });
|
std::vector<std::string> instructions = fmt::split(asm_, { "\n", ";" });
|
||||||
@ -271,6 +294,20 @@ namespace rsx::assembler
|
|||||||
fmt::throw_exception("Invalid constant literal");
|
fmt::throw_exception("Invalid constant literal");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
auto encode_branch_end = [](Instruction *inst, u32 end)
|
||||||
|
{
|
||||||
|
SRC2 src2 { .HEX = inst->bytecode[3] };
|
||||||
|
src2.end_offset = static_cast<u32>(end);
|
||||||
|
inst->bytecode[3] = src2.HEX;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto encode_branch_else = [](Instruction* inst, u32 end)
|
||||||
|
{
|
||||||
|
SRC1 src1{ .HEX = inst->bytecode[2] };
|
||||||
|
src1.else_offset = static_cast<u32>(end);
|
||||||
|
inst->bytecode[2] = src1.HEX;
|
||||||
|
};
|
||||||
|
|
||||||
auto encode_opcode = [](const std::string& op, Instruction* inst)
|
auto encode_opcode = [](const std::string& op, Instruction* inst)
|
||||||
{
|
{
|
||||||
OPDEST d0 { .HEX = inst->bytecode[0] };
|
OPDEST d0 { .HEX = inst->bytecode[0] };
|
||||||
@ -280,7 +317,7 @@ namespace rsx::assembler
|
|||||||
#define SET_OPCODE(encoding) \
|
#define SET_OPCODE(encoding) \
|
||||||
do { \
|
do { \
|
||||||
inst->opcode = encoding.op; \
|
inst->opcode = encoding.op; \
|
||||||
d0.opcode = encoding.op; \
|
d0.opcode = encoding.op & 0x3F; \
|
||||||
s1.opcode_is_branch = (encoding.op > 0x3F)? 1 : 0; \
|
s1.opcode_is_branch = (encoding.op > 0x3F)? 1 : 0; \
|
||||||
s0.exec_if_eq = encoding.exec_if_eq ? 1 : 0; \
|
s0.exec_if_eq = encoding.exec_if_eq ? 1 : 0; \
|
||||||
s0.exec_if_gr = encoding.exec_if_gt ? 1 : 0; \
|
s0.exec_if_gr = encoding.exec_if_gt ? 1 : 0; \
|
||||||
@ -305,6 +342,10 @@ namespace rsx::assembler
|
|||||||
std::string op, dst;
|
std::string op, dst;
|
||||||
std::vector<std::string> sources;
|
std::vector<std::string> sources;
|
||||||
|
|
||||||
|
std::stack<size_t> if_ops;
|
||||||
|
std::stack<size_t> loop_ops;
|
||||||
|
u32 pc = 0;
|
||||||
|
|
||||||
FPIR ir{};
|
FPIR ir{};
|
||||||
|
|
||||||
for (const auto& instruction : instructions)
|
for (const auto& instruction : instructions)
|
||||||
@ -319,15 +360,45 @@ namespace rsx::assembler
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (op.starts_with("IF."))
|
||||||
|
{
|
||||||
|
if_ops.push(ir.m_instructions.size());
|
||||||
|
}
|
||||||
|
else if (op == "LOOP")
|
||||||
|
{
|
||||||
|
loop_ops.push(ir.m_instructions.size());
|
||||||
|
}
|
||||||
|
else if (op == "ELSE")
|
||||||
|
{
|
||||||
|
ensure(!if_ops.empty());
|
||||||
|
encode_branch_else(&ir.m_instructions[if_ops.top()], pc);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (op == "ENDIF")
|
||||||
|
{
|
||||||
|
ensure(!if_ops.empty());
|
||||||
|
encode_branch_end(&ir.m_instructions[if_ops.top()], pc);
|
||||||
|
if_ops.pop();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (op == "ENDLOOP")
|
||||||
|
{
|
||||||
|
ensure(!loop_ops.empty());
|
||||||
|
encode_branch_end(&ir.m_instructions[loop_ops.top()], pc);
|
||||||
|
loop_ops.pop();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
ir.m_instructions.push_back({});
|
ir.m_instructions.push_back({});
|
||||||
Instruction* target = &ir.m_instructions.back();
|
Instruction* target = &ir.m_instructions.back();
|
||||||
|
pc += 4;
|
||||||
|
|
||||||
encode_opcode(op, target);
|
encode_opcode(op, target);
|
||||||
ensure(sources.size() == FP::get_operand_count(static_cast<FP_opcode>(target->opcode)), "Invalid operand count for opcode");
|
ensure(sources.size() == FP::get_operand_count(static_cast<FP_opcode>(target->opcode)), "Invalid operand count for opcode");
|
||||||
|
|
||||||
if (dst.empty())
|
if (dst.empty())
|
||||||
{
|
{
|
||||||
OPDEST dst{};
|
OPDEST dst{ .HEX = target->bytecode[0] };
|
||||||
dst.no_dest = 1;
|
dst.no_dest = 1;
|
||||||
target->bytecode[0] = dst.HEX;
|
target->bytecode[0] = dst.HEX;
|
||||||
}
|
}
|
||||||
@ -337,17 +408,24 @@ namespace rsx::assembler
|
|||||||
}
|
}
|
||||||
|
|
||||||
int operand = 0;
|
int operand = 0;
|
||||||
|
bool has_literal = false;
|
||||||
for (const auto& source : sources)
|
for (const auto& source : sources)
|
||||||
{
|
{
|
||||||
if (source.front() == '#')
|
if (source.front() == '#')
|
||||||
{
|
{
|
||||||
const auto literal = get_constants(source);
|
const auto literal = get_constants(source);
|
||||||
ir.load(literal, operand++, target);
|
ir.load(literal, operand++, target);
|
||||||
|
has_literal = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ir.load(get_ref(source), operand++, target);
|
ir.load(get_ref(source), operand++, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (has_literal)
|
||||||
|
{
|
||||||
|
pc += 4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ir.m_instructions.empty())
|
if (!ir.m_instructions.empty())
|
||||||
|
|||||||
@ -13,7 +13,8 @@ namespace rsx::assembler
|
|||||||
void add(const RegisterRef& dst, const std::array<f32, 4>& constants);
|
void add(const RegisterRef& dst, const std::array<f32, 4>& constants);
|
||||||
void add(const RegisterRef& dst, const RegisterRef& src);
|
void add(const RegisterRef& dst, const RegisterRef& src);
|
||||||
|
|
||||||
std::vector<Instruction> build();
|
const std::vector<Instruction>& instructions() const;
|
||||||
|
std::vector<u32> compile() const;
|
||||||
|
|
||||||
static FPIR from_source(const std::string& asm_);
|
static FPIR from_source(const std::string& asm_);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user