mirror of
https://github.com/open-goal/jak-project
synced 2026-07-08 14:36:52 -04:00
fix some instruction decodings
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "Instruction.h"
|
||||
#include "decompiler/ObjectFile/LinkedObjectFile.h"
|
||||
#include "third-party/fmt/core.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace decompiler {
|
||||
@@ -26,6 +27,9 @@ std::string InstructionAtom::to_string(const std::vector<DecompilerLabel>& label
|
||||
return "Q";
|
||||
case IMM_SYM:
|
||||
return sym;
|
||||
case VF_FIELD:
|
||||
assert(imm >= 0 && imm < 4);
|
||||
return fmt::format(".{}", "xyzw"[imm]);
|
||||
default:
|
||||
throw std::runtime_error("Unsupported InstructionAtom");
|
||||
}
|
||||
@@ -77,6 +81,15 @@ void InstructionAtom::set_sym(std::string _sym) {
|
||||
sym = std::move(_sym);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Make this atom a field (x,y,z,w) of a vf.
|
||||
*/
|
||||
void InstructionAtom::set_vf_field(uint32_t value) {
|
||||
kind = VF_FIELD;
|
||||
imm = value;
|
||||
assert(value < 4);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Get as register, or error if not a register.
|
||||
*/
|
||||
@@ -224,7 +237,14 @@ std::string Instruction::to_string(const std::vector<DecompilerLabel>& labels) c
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < n_src; i++) {
|
||||
result += " " + src[i].to_string(labels) + ",";
|
||||
if (src[i].kind == InstructionAtom::VF_FIELD) {
|
||||
if (end_comma) {
|
||||
result.pop_back();
|
||||
}
|
||||
result += src[i].to_string(labels) + ",";
|
||||
} else {
|
||||
result += " " + src[i].to_string(labels) + ",";
|
||||
}
|
||||
end_comma = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
namespace decompiler {
|
||||
struct DecompilerLabel;
|
||||
|
||||
constexpr int MAX_INSTRUCTION_SOURCE = 3;
|
||||
constexpr int MAX_INSTRUCTION_SOURCE = 4;
|
||||
constexpr int MAX_INTRUCTION_DEST = 1;
|
||||
|
||||
// An "atom", representing a single register, immediate, etc... for use in an Instruction.
|
||||
@@ -28,6 +28,7 @@ struct InstructionAtom {
|
||||
LABEL, // A label in a LinkedObjectFile
|
||||
VU_ACC, // The VU0 Accumulator
|
||||
VU_Q, // The VU0 Q Register
|
||||
VF_FIELD, // Field specifier
|
||||
INVALID
|
||||
} kind = INVALID;
|
||||
|
||||
@@ -37,6 +38,7 @@ struct InstructionAtom {
|
||||
void set_vu_q();
|
||||
void set_vu_acc();
|
||||
void set_sym(std::string _sym);
|
||||
void set_vf_field(uint32_t value);
|
||||
|
||||
Register get_reg() const;
|
||||
int32_t get_imm() const;
|
||||
|
||||
@@ -40,11 +40,8 @@ struct OpcodeFields {
|
||||
////////////////
|
||||
|
||||
int32_t simm16() { return (int16_t)(data); }
|
||||
|
||||
int32_t zimm16() { return (uint16_t)(data); }
|
||||
|
||||
uint32_t imm5() { return (data >> 6) & 0x1f; }
|
||||
|
||||
uint32_t imm15() { return (data >> 6) & 0b111111111111111; }
|
||||
|
||||
////////////////////
|
||||
@@ -52,11 +49,8 @@ struct OpcodeFields {
|
||||
////////////////////
|
||||
|
||||
uint32_t cop_func() { return (data >> 21) & 0x1f; }
|
||||
|
||||
uint32_t ft() { return (data >> 16) & 0x1f; }
|
||||
|
||||
uint32_t fs() { return (data >> 11) & 0x1f; }
|
||||
|
||||
uint32_t fd() { return (data >> 6) & 0x1f; }
|
||||
|
||||
////////////
|
||||
@@ -64,16 +58,13 @@ struct OpcodeFields {
|
||||
////////////
|
||||
|
||||
uint32_t pcreg() { return (data >> 1) & 0x1f; }
|
||||
|
||||
uint32_t syscall() { return (data >> 6) & 0xfffff; }
|
||||
|
||||
uint32_t MMI_func() { return (data >> 6) & 0x1f; }
|
||||
|
||||
uint32_t lower11() { return (uint32_t)(data & 0x7ff); }
|
||||
|
||||
uint32_t lower6() { return (uint32_t)(data & 0b111111); }
|
||||
|
||||
uint32_t dest() { return (data >> 21) & 0b1111; }
|
||||
uint32_t fs_f() { return (data >> 21) & 0b11; }
|
||||
uint32_t ft_f() { return (data >> 23) & 0b11; }
|
||||
|
||||
uint32_t data;
|
||||
};
|
||||
@@ -1072,6 +1063,12 @@ Instruction decode_instruction(LinkedWord& word, LinkedObjectFile& file, int seg
|
||||
case FieldType::ZERO:
|
||||
value = 0;
|
||||
break;
|
||||
case FieldType::FT_F:
|
||||
value = fields.ft_f();
|
||||
break;
|
||||
case FieldType::FS_F:
|
||||
value = fields.fs_f();
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
@@ -1112,6 +1109,9 @@ Instruction decode_instruction(LinkedWord& word, LinkedObjectFile& file, int seg
|
||||
case DecodeType::BRANCH_TARGET:
|
||||
atom.set_label(file.get_label_id_for(seg_id, (word_id + value + 1) * 4));
|
||||
break;
|
||||
case DecodeType::VF_F:
|
||||
atom.set_vf_field(value);
|
||||
break;
|
||||
|
||||
// NOTE - these change a property of the instruction and don't add an atom.
|
||||
case DecodeType::IL:
|
||||
|
||||
@@ -405,13 +405,15 @@ void init_opcode_info() {
|
||||
def(IK::VDIV, "vdiv")
|
||||
.dst(FT::ZERO, DT::VU_Q)
|
||||
.src_vf(FT::FS)
|
||||
.src(FT::FS_F, DT::VF_F)
|
||||
.src_vf(FT::FT)
|
||||
.src(FT::BC, DT::BC); // todo
|
||||
.src(FT::FT_F, DT::VF_F);
|
||||
def(IK::VRSQRT, "vrsqrt")
|
||||
.dst(FT::ZERO, DT::VU_Q)
|
||||
.src_vf(FT::FS)
|
||||
.src(FT::FS_F, DT::VF_F)
|
||||
.src_vf(FT::FT)
|
||||
.src(FT::BC, DT::BC); // todo
|
||||
.src(FT::FT_F, DT::VF_F);
|
||||
def(IK::VCLIP, "vclip").src(FT::DEST, DT::DEST).src_vf(FT::FS).src_vf(FT::FT);
|
||||
def(IK::VMULAQ, "vmulaq")
|
||||
.src(FT::DEST, DT::DEST)
|
||||
@@ -430,7 +432,7 @@ void init_opcode_info() {
|
||||
|
||||
def(IK::QMFC2, "qmfc2").src(FT::IL, DT::IL).dst_gpr(FT::RT).src_vf(FT::FS);
|
||||
def(IK::QMTC2, "qmtc2").src(FT::IL, DT::IL).src_gpr(FT::RT).dst_vf(FT::FS);
|
||||
def(IK::VSQRT, "vsqrt").src(FT::BC, DT::BC).dst(FT::ZERO, DT::VU_Q).src_vf(FT::FT);
|
||||
def(IK::VSQRT, "vsqrt").dst(FT::ZERO, DT::VU_Q).src_vf(FT::FT).src(FT::FT_F, DT::VF_F);
|
||||
def(IK::VRXOR, "vrxor").src(FT::BC, DT::BC).src_vf(FT::FS);
|
||||
def(IK::VRNEXT, "vrnext").src(FT::DEST, DT::DEST).dst_vf(FT::FT);
|
||||
def(IK::CTC2, "ctc2").src(FT::IL, DT::IL).src_gpr(FT::RT).dst(FT::RD, DT::VI);
|
||||
|
||||
@@ -289,6 +289,8 @@ enum class FieldType {
|
||||
IMM5,
|
||||
IMM15,
|
||||
IL,
|
||||
FS_F,
|
||||
FT_F,
|
||||
ZERO
|
||||
};
|
||||
|
||||
@@ -305,6 +307,7 @@ enum class DecodeType {
|
||||
VCALLMS_TARGET,
|
||||
DEST,
|
||||
BC,
|
||||
VF_F,
|
||||
VU_Q,
|
||||
VU_ACC,
|
||||
IL
|
||||
|
||||
@@ -22,6 +22,7 @@ add_executable(goalc-test
|
||||
${CMAKE_CURRENT_LIST_DIR}/decompiler/test_FormBeforeExpressions.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/decompiler/test_FormExpressionBuild.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/decompiler/test_FormExpressionBuildLong.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/decompiler/test_InstructionDecode.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/decompiler/test_InstructionParser.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/decompiler/test_gkernel_decomp.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/decompiler/test_math_decomp.cpp
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "decompiler/Disasm/InstructionDecode.h"
|
||||
#include "decompiler/Disasm/OpcodeInfo.h"
|
||||
#include "decompiler/ObjectFile/LinkedObjectFile.h"
|
||||
|
||||
using namespace decompiler;
|
||||
|
||||
TEST(InstructionDecode, VDIV) {
|
||||
init_opcode_info();
|
||||
LinkedObjectFile file;
|
||||
u32 vdiv_test = 0b010010'1'10'01'10100'01010'01110111100;
|
||||
// ...... z y 20 10
|
||||
LinkedWord vdiv_word(vdiv_test);
|
||||
auto instr = decode_instruction(vdiv_word, file, 0, 0);
|
||||
EXPECT_EQ(instr.to_string({}), "vdiv Q, vf10.y, vf20.z");
|
||||
}
|
||||
|
||||
TEST(InstructionDecode, VRSQRT) {
|
||||
init_opcode_info();
|
||||
LinkedObjectFile file;
|
||||
u32 vdiv_test = 0b010010'1'10'01'10100'01010'01110111110;
|
||||
// ...... z y 20 10
|
||||
LinkedWord vdiv_word(vdiv_test);
|
||||
auto instr = decode_instruction(vdiv_word, file, 0, 0);
|
||||
EXPECT_EQ(instr.to_string({}), "vrsqrt Q, vf10.y, vf20.z");
|
||||
}
|
||||
|
||||
TEST(InstructionDecode, VSQRT) {
|
||||
init_opcode_info();
|
||||
LinkedObjectFile file;
|
||||
u32 vdiv_test = 0b010010'1'10'00'10100'00000'01110111101;
|
||||
// ...... z X 20 X
|
||||
LinkedWord vdiv_word(vdiv_test);
|
||||
auto instr = decode_instruction(vdiv_word, file, 0, 0);
|
||||
EXPECT_EQ(instr.to_string({}), "vsqrt Q, vf20.z");
|
||||
}
|
||||
Reference in New Issue
Block a user