fix some instruction decodings

This commit is contained in:
water
2021-02-13 12:05:50 -05:00
parent 126dfc1c45
commit b0780ce2c8
7 changed files with 80 additions and 16 deletions
+21 -1
View File
@@ -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;
}
+3 -1
View File
@@ -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;
+11 -11
View File
@@ -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:
+5 -3
View File
@@ -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);
+3
View File
@@ -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
+1
View File
@@ -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");
}