From e5f0fecf174abaa68de23ad3b79235631c8cae5a Mon Sep 17 00:00:00 2001 From: water111 <48171810+water111@users.noreply.github.com> Date: Sun, 11 Apr 2021 16:07:01 -0400 Subject: [PATCH] [Decompiler] bitfield support and clean up of DMA (#350) * get to vif * support basic bitfield access * make bitfields in dma work * clean up dma * fix merge conflict --- common/util/BitUtils.h | 42 + common/util/Range.h | 4 + decompiler/CMakeLists.txt | 1 + decompiler/Disasm/InstructionParser.cpp | 2 +- decompiler/IR2/AtomicOp.cpp | 7 + decompiler/IR2/AtomicOp.h | 5 + decompiler/IR2/AtomicOpForm.cpp | 11 +- decompiler/IR2/BitfieldForms.cpp | 323 +++++++ decompiler/IR2/Form.cpp | 8 +- decompiler/IR2/Form.h | 134 +++ decompiler/IR2/FormExpressionAnalysis.cpp | 413 +++++++-- decompiler/IR2/IR2_common.h | 9 +- decompiler/config/all-types.gc | 24 +- .../jak1_ntsc_black_label/label_types.jsonc | 6 + .../jak1_ntsc_black_label/type_casts.jsonc | 33 +- .../jak1_ntsc_black_label/var_names.jsonc | 8 +- goal_src/engine/dma/dma-h.gc | 36 +- goal_src/engine/dma/dma.gc | 143 ++-- goal_src/engine/math/euler-h.gc | 2 + goal_src/engine/math/euler.gc | 249 ++++++ goal_src/engine/math/vector-h.gc | 3 + goal_src/engine/math/vector.gc | 26 - goal_src/engine/ps2/vif-h.gc | 2 +- goal_src/goal-lib.gc | 5 + .../reference/all_forward_declarations.gc | 5 +- test/decompiler/reference/dma-h_REF.gc | 312 +++++++ test/decompiler/reference/dma_REF.gc | 419 +++++++++ test/decompiler/reference/euler_REF.gc | 516 ++++++++++++ test/decompiler/reference/gcommon_REF.gc | 2 +- test/decompiler/reference/gkernel-h_REF.gc | 12 +- test/decompiler/reference/gsound-h_REF.gc | 796 ++++++++++++++++++ test/decompiler/reference/timer-h_REF.gc | 175 ++++ test/decompiler/reference/timer_REF.gc | 179 ++++ test/decompiler/reference/video-h_REF.gc | 84 ++ test/decompiler/reference/vif-h_REF.gc | 128 +++ test/decompiler/reference/vu1-user-h_REF.gc | 121 +++ test/decompiler/test_FormExpressionBuild2.cpp | 463 ++++++++++ test/offline/offline_test_main.cpp | 16 +- test/test_common_util.cpp | 21 +- 39 files changed, 4524 insertions(+), 221 deletions(-) create mode 100644 common/util/BitUtils.h create mode 100644 decompiler/IR2/BitfieldForms.cpp create mode 100644 test/decompiler/reference/dma-h_REF.gc create mode 100644 test/decompiler/reference/dma_REF.gc create mode 100644 test/decompiler/reference/euler_REF.gc create mode 100644 test/decompiler/reference/gsound-h_REF.gc create mode 100644 test/decompiler/reference/timer-h_REF.gc create mode 100644 test/decompiler/reference/timer_REF.gc create mode 100644 test/decompiler/reference/video-h_REF.gc create mode 100644 test/decompiler/reference/vif-h_REF.gc create mode 100644 test/decompiler/reference/vu1-user-h_REF.gc diff --git a/common/util/BitUtils.h b/common/util/BitUtils.h new file mode 100644 index 0000000000..2be9b37ee7 --- /dev/null +++ b/common/util/BitUtils.h @@ -0,0 +1,42 @@ +#pragma once + +#include + +#include "common/util/Range.h" + +constexpr int BITS_PER_BYTE = 8; +template +std::optional> get_bit_range(T value) { + enum State { INITIAL_ZEROS, ONES, TRAILING_ZEROS } state = INITIAL_ZEROS; + + int start_bit = 0; + int end_bit = 0; + int max_bit = BITS_PER_BYTE * sizeof(T); + + for (int i = 0; i < max_bit; i++) { + bool bit = (value) & (T(1) << i); + if (state == INITIAL_ZEROS) { + if (bit) { + start_bit = i; + state = ONES; + } + } else if (state == ONES) { + if (!bit) { + end_bit = i; + state = TRAILING_ZEROS; + } + } else if (state == TRAILING_ZEROS) { + if (bit) { + return std::nullopt; + } + } + } + + if (state == INITIAL_ZEROS) { + return std::nullopt; + } else if (state == ONES) { + end_bit = max_bit; + } + + return Range{start_bit, end_bit}; +} \ No newline at end of file diff --git a/common/util/Range.h b/common/util/Range.h index cae263593d..f44f0555db 100644 --- a/common/util/Range.h +++ b/common/util/Range.h @@ -24,6 +24,10 @@ class Range { bool contains(T& val) const { return val >= m_start && val < m_end; } bool empty() const { return m_end <= m_start; } T size() const { return m_end - m_start; } + bool operator==(const Range& other) const { + return m_start == other.m_start && m_end == other.m_end; + } + bool operator!=(const Range& other) const { return !((*this) == other); } struct Iterator { using iterator_category = std::input_iterator_tag; diff --git a/decompiler/CMakeLists.txt b/decompiler/CMakeLists.txt index ce86115710..8f056e300f 100644 --- a/decompiler/CMakeLists.txt +++ b/decompiler/CMakeLists.txt @@ -36,6 +36,7 @@ add_library( IR2/AtomicOp.cpp IR2/AtomicOpForm.cpp IR2/AtomicOpTypeAnalysis.cpp + IR2/BitfieldForms.cpp IR2/Env.cpp IR2/Form.cpp IR2/FormExpressionAnalysis.cpp diff --git a/decompiler/Disasm/InstructionParser.cpp b/decompiler/Disasm/InstructionParser.cpp index 24901cfbc6..5859c17ead 100644 --- a/decompiler/Disasm/InstructionParser.cpp +++ b/decompiler/Disasm/InstructionParser.cpp @@ -43,7 +43,7 @@ InstructionParser::InstructionParser() { InstructionKind::BGTZ, InstructionKind::BLTZL, InstructionKind::BGTZL, InstructionKind::BGEZL, InstructionKind::MTC1, InstructionKind::MFC1, InstructionKind::MFLO, InstructionKind::MFHI, InstructionKind::MTLO1, - InstructionKind::MFLO1}) { + InstructionKind::MFLO1, InstructionKind::SYNCL}) { auto& info = gOpcodeInfo[int(i)]; if (info.defined) { m_opcode_name_lookup[info.name] = int(i); diff --git a/decompiler/IR2/AtomicOp.cpp b/decompiler/IR2/AtomicOp.cpp index a3ca0f9b8a..891f90b408 100644 --- a/decompiler/IR2/AtomicOp.cpp +++ b/decompiler/IR2/AtomicOp.cpp @@ -33,6 +33,13 @@ goos::Object RegisterAccess::to_form(const Env& env, Print mode) const { m_mode == AccessMode::READ ? 'r' : 'w')); case Print::AS_VARIABLE: return env.get_variable_name_with_cast(m_reg, m_atomic_idx, m_mode); + case Print::AS_VARIABLE_NO_CAST: + if (env.has_local_vars()) { + return pretty_print::to_symbol(env.get_variable_name(*this)); + } else { + return pretty_print::to_symbol(fmt::format("{}-{:03d}-{}", m_reg.to_charp(), m_atomic_idx, + m_mode == AccessMode::READ ? 'r' : 'w')); + } case Print::AUTOMATIC: if (env.has_local_vars()) { return env.get_variable_name_with_cast(m_reg, m_atomic_idx, m_mode); diff --git a/decompiler/IR2/AtomicOp.h b/decompiler/IR2/AtomicOp.h index 0ebf2c2d36..013baefa9a 100644 --- a/decompiler/IR2/AtomicOp.h +++ b/decompiler/IR2/AtomicOp.h @@ -310,6 +310,11 @@ class AsmOp : public AtomicOp { DecompilerTypeSystem& dts) override; void collect_vars(RegAccessSet& vars) const override; const Instruction& instruction() const { return m_instr; } + const std::optional dst() const { return m_dst; } + const std::optional src(int i) const { + assert(i < 4); + return m_src[i]; + } private: Instruction m_instr; diff --git a/decompiler/IR2/AtomicOpForm.cpp b/decompiler/IR2/AtomicOpForm.cpp index 68dcba5527..393fad694d 100644 --- a/decompiler/IR2/AtomicOpForm.cpp +++ b/decompiler/IR2/AtomicOpForm.cpp @@ -391,7 +391,8 @@ FormElement* StoreOp::get_as_form(FormPool& pool, const Env& env) const { } std::string cast_type; - if (input_type.typespec() == TypeSpec("pointer") && ro.offset == 0) { + if (ro.offset == 0 && (input_type.typespec() == TypeSpec("pointer") || + input_type.kind == TP_Type::Kind::OBJECT_PLUS_PRODUCT_WITH_CONSTANT)) { switch (m_size) { case 1: cast_type = "int8"; @@ -419,6 +420,10 @@ FormElement* StoreOp::get_as_form(FormPool& pool, const Env& env) const { } } + if (m_kind == Kind::FLOAT) { + cast_type = "float"; + } + auto source = pool.alloc_single_element_form( nullptr, SimpleAtom::make_var(ro.var).as_expr(), m_my_idx); auto cast_source = pool.alloc_single_element_form( @@ -540,8 +545,8 @@ Form* LoadVarOp::get_load_src(FormPool& pool, const Env& env) const { return pool.alloc_single_element_form(nullptr, source, rd.addr_of, tokens); } - if (input_type.typespec() == TypeSpec("pointer") || - input_type.kind == TP_Type::Kind::OBJECT_PLUS_PRODUCT_WITH_CONSTANT) { + if (ro.offset == 0 && (input_type.typespec() == TypeSpec("pointer") || + input_type.kind == TP_Type::Kind::OBJECT_PLUS_PRODUCT_WITH_CONSTANT)) { std::string cast_type; switch (m_size) { case 1: diff --git a/decompiler/IR2/BitfieldForms.cpp b/decompiler/IR2/BitfieldForms.cpp new file mode 100644 index 0000000000..180d84e46f --- /dev/null +++ b/decompiler/IR2/BitfieldForms.cpp @@ -0,0 +1,323 @@ +#include "Form.h" +#include "common/goos/PrettyPrinter.h" +#include "common/util/Range.h" +#include "common/util/BitUtils.h" + +namespace decompiler { + +//////////////////////////////// +// BitfieldStaticDefElement +//////////////////////////////// + +BitfieldStaticDefElement::BitfieldStaticDefElement(const TypeSpec& type, + const std::vector& field_defs) + : m_type(type), m_field_defs(field_defs) {} + +goos::Object BitfieldStaticDefElement::to_form_internal(const Env&) const { + std::vector result; + + result.push_back(pretty_print::to_symbol(fmt::format("new 'static '{}", m_type.print()))); + + for (auto& def : m_field_defs) { + if (def.is_signed) { + result.push_back( + pretty_print::to_symbol(fmt::format(":{} {}", def.field_name, (s64)def.value))); + } else { + result.push_back( + pretty_print::to_symbol(fmt::format(":{} #x{:x}", def.field_name, def.value))); + } + } + + return pretty_print::build_list(result); +} + +void BitfieldStaticDefElement::apply(const std::function& f) { + f(this); +} + +void BitfieldStaticDefElement::apply_form(const std::function&) {} +void BitfieldStaticDefElement::collect_vars(RegAccessSet&, bool) const {} +void BitfieldStaticDefElement::get_modified_regs(RegSet&) const {} + +ModifiedCopyBitfieldElement::ModifiedCopyBitfieldElement( + const TypeSpec& type, + Form* base, + const std::vector& field_modifications) + : m_type(type), m_base(base), m_field_modifications(field_modifications) { + m_base->parent_element = this; +} + +goos::Object ModifiedCopyBitfieldElement::to_form_internal(const Env& env) const { + std::vector result = {pretty_print::to_symbol("copy-and-set-bf")}; + result.push_back(m_base->to_form(env)); + for (auto& def : m_field_modifications) { + result.push_back(pretty_print::to_symbol(fmt::format(":{}", def.field_name))); + result.push_back(def.value->to_form(env)); + } + return pretty_print::build_list(result); +} + +void ModifiedCopyBitfieldElement::apply(const std::function& f) { + f(this); + for (auto& mod : m_field_modifications) { + mod.value->apply(f); + } + m_base->apply(f); +} + +void ModifiedCopyBitfieldElement::apply_form(const std::function& f) { + for (auto& mod : m_field_modifications) { + mod.value->apply_form(f); + } + m_base->apply_form(f); +} + +void ModifiedCopyBitfieldElement::collect_vars(RegAccessSet& vars, bool recursive) const { + if (recursive) { + for (auto& mod : m_field_modifications) { + mod.value->collect_vars(vars, recursive); + } + m_base->collect_vars(vars, recursive); + } +} + +void ModifiedCopyBitfieldElement::get_modified_regs(RegSet& regs) const { + for (auto& mod : m_field_modifications) { + mod.value->get_modified_regs(regs); + } + m_base->get_modified_regs(regs); +} + +//////////////////////////////// +// BitfieldReadElement +//////////////////////////////// + +BitfieldReadElement::BitfieldReadElement(Form* base_value, const TypeSpec& ts) + : m_base(base_value), m_type(ts) { + m_base->parent_element = this; +} + +goos::Object BitfieldReadElement::to_form_internal(const Env& env) const { + return pretty_print::build_list("incomplete-bitfield-access", m_base->to_form(env)); +} + +void BitfieldReadElement::apply(const std::function& f) { + f(this); + m_base->apply(f); +} + +void BitfieldReadElement::apply_form(const std::function& f) { + m_base->apply_form(f); +} + +void BitfieldReadElement::collect_vars(RegAccessSet& vars, bool recursive) const { + m_base->collect_vars(vars, recursive); +} + +void BitfieldReadElement::get_modified_regs(RegSet& regs) const { + m_base->get_modified_regs(regs); +} + +namespace { +const BitField& find_field(const TypeSystem& ts, + const BitFieldType* type, + int start_bit, + int size, + std::optional looking_for_unsigned) { + for (auto& field : type->fields()) { + if (field.size() == size && field.offset() == start_bit) { + bool is_int = ts.tc(TypeSpec("integer"), field.type()); + bool is_uint = ts.tc(TypeSpec("uinteger"), field.type()); + // allow sign match, or unsigned+not a number. + + if (looking_for_unsigned) { + bool want_unsigned = *looking_for_unsigned; + if ((is_int && !want_unsigned) || (is_uint && want_unsigned) || + (!is_int && !is_uint && want_unsigned)) { + // matched! + return field; + } + } else { + return field; + } + } + } + throw std::runtime_error( + fmt::format("Unmatched field: start bit {}, size {}, signed? {}, type {}", start_bit, size, + !looking_for_unsigned, type->get_name())); +} + +std::optional find_field_from_mask(const TypeSystem& ts, + const BitFieldType* type, + uint64_t mask) { + // try to find a field that is masked by this: + auto mask_range = get_bit_range(mask); + if (!mask_range) { + // it wasn't even a valid mask... + return {}; + } + + return find_field(ts, type, mask_range->first(), mask_range->size(), {}); +} + +template +T extract_bitfield(T input, int start_bit, int size) { + int end_bit = start_bit + size; + T left_shifted = input << (64 - end_bit); + return left_shifted >> (64 - size); +} +} // namespace + +/*! + * Add a step to the bitfield access. If this completes the access, returns a form representing the + * access + */ +FormElement* BitfieldReadElement::push_step(const BitfieldManip step, + const TypeSystem& ts, + FormPool& pool) { + if (m_steps.empty() && step.kind == BitfieldManip::Kind::LEFT_SHIFT) { + // for left/right shift combo to get a field. + m_steps.push_back(step); + return nullptr; + } + + if (m_steps.empty() && step.is_right_shift()) { + // could be a single step right shift to get a field + bool is_unsigned = step.right_shift_unsigned(); + int shift_size = step.get_shift_start_bit(); + int size = shift_size - step.amount; + int start_bit = shift_size - size; + auto type = ts.lookup_type(m_type); + auto as_bitfield = dynamic_cast(type); + assert(as_bitfield); + auto field = find_field(ts, as_bitfield, start_bit, size, is_unsigned); + return pool.alloc_element(m_base, false, + DerefToken::make_field_name(field.name())); + } + + if (m_steps.size() == 1 && m_steps.at(0).kind == BitfieldManip::Kind::LEFT_SHIFT) { + // second op in left/right shift combo + int end_bit = 64 - m_steps.at(0).amount; + if (!step.is_right_shift()) { + throw std::runtime_error("Unexpected step 1"); + } + bool is_unsigned = step.right_shift_unsigned(); + + int size = 64 - step.amount; + int start_bit = end_bit - size; + assert(start_bit >= 0); + + auto type = ts.lookup_type(m_type); + auto as_bitfield = dynamic_cast(type); + assert(as_bitfield); + auto field = find_field(ts, as_bitfield, start_bit, size, is_unsigned); + return pool.alloc_element(m_base, false, + DerefToken::make_field_name(field.name())); + } + + if (m_steps.empty() && step.kind == BitfieldManip::Kind::LOGAND) { + // and with mask + m_steps.push_back(step); + return nullptr; + } + + if (m_steps.size() == 1 && m_steps.at(0).kind == BitfieldManip::Kind::LOGAND && + step.kind == BitfieldManip::Kind::NONZERO_COMPARE) { + auto type = ts.lookup_type(m_type); + auto as_bitfield = dynamic_cast(type); + assert(as_bitfield); + auto field = find_field_from_mask(ts, as_bitfield, m_steps.at(0).amount); + if (field) { + auto get_field = pool.alloc_element(m_base, false, + DerefToken::make_field_name(field->name())); + get_field->inline_nested(); + return pool.alloc_element( + GenericOperator::make_compare(IR2_Condition::Kind::NONZERO), + pool.alloc_single_form(nullptr, get_field)); + } + } + + if (m_steps.size() == 1 && m_steps.at(0).kind == BitfieldManip::Kind::LOGAND && + step.kind == BitfieldManip::Kind::LOGIOR_WITH_CONSTANT_INT) { + // this is setting a bitfield. + // first, let's check that the mask is used properly: + u64 mask = m_steps.at(0).amount; + u64 value = step.amount; + if ((mask & value) != 0) { + throw std::runtime_error(fmt::format( + "Got invalid bitmask set: mask was 0x{:x} and value was 0x{:x}", mask, value)); + } + auto type = ts.lookup_type(m_type); + auto as_bitfield = dynamic_cast(type); + assert(as_bitfield); + // use the mask to figure out the field. + auto field = find_field_from_mask(ts, as_bitfield, ~mask); + assert(field); + bool is_signed = + ts.tc(TypeSpec("int"), field->type()) && !ts.tc(TypeSpec("uint"), field->type()); + + // use the field to figure out what value is being set. + u64 set_value; + if (is_signed) { + set_value = extract_bitfield(value, field->offset(), field->size()); + } else { + set_value = extract_bitfield(value, field->offset(), field->size()); + } + + BitfieldFormDef def; + def.field_name = field->name(); + def.value = pool.alloc_single_element_form( + nullptr, SimpleAtom::make_int_constant(set_value)); + return pool.alloc_element(m_type, m_base, + std::vector{def}); + } + + throw std::runtime_error("Unknown state in BitfieldReadElement"); +} + +std::vector decompile_static_bitfield(const TypeSpec& type, + const TypeSystem& ts, + u64 value) { + u64 touched_bits = 0; + std::vector result; + + auto type_info = dynamic_cast(ts.lookup_type(type)); + assert(type_info); + + for (auto& field : type_info->fields()) { + u64 bitfield_value; + bool is_signed = ts.tc(TypeSpec("int"), field.type()) && !ts.tc(TypeSpec("uint"), field.type()); + if (is_signed) { + // signed + s64 signed_value = value; + bitfield_value = extract_bitfield(signed_value, field.offset(), field.size()); + } else { + // unsigned + bitfield_value = extract_bitfield(value, field.offset(), field.size()); + } + + if (bitfield_value != 0) { + BitFieldDef def; + def.value = bitfield_value; + def.field_name = field.name(); + def.is_signed = is_signed; + result.push_back(def); + } + + for (int i = field.offset(); i < field.offset() + field.size(); i++) { + touched_bits |= (u64(1) << i); + } + } + + u64 untouched_but_set = value & (~touched_bits); + + if (untouched_but_set) { + throw std::runtime_error( + fmt::format("Failed to decompile static bitfield of type {}. Original value is 0x{:x} but " + "we didn't touch", + type.print(), value, untouched_but_set)); + } + return result; +} + +} // namespace decompiler \ No newline at end of file diff --git a/decompiler/IR2/Form.cpp b/decompiler/IR2/Form.cpp index ad29961aff..6c6a192e7a 100644 --- a/decompiler/IR2/Form.cpp +++ b/decompiler/IR2/Form.cpp @@ -2097,7 +2097,9 @@ goos::Object LetElement::to_form_internal(const Env& env) const { std::vector def_list; for (auto& entry : m_entries) { - def_list.push_back(pretty_print::build_list(entry.dest.to_form(env), entry.src->to_form(env))); + def_list.push_back(pretty_print::build_list( + entry.dest.to_form(env, RegisterAccess::Print::AS_VARIABLE_NO_CAST), + entry.src->to_form(env))); } outer.push_back(pretty_print::build_list(def_list)); @@ -2288,6 +2290,10 @@ void VectorFloatLoadStoreElement::collect_vf_regs(RegSet& regs) const { regs.insert(m_vf_reg); } +//////////////////////////////// +// Utilities +//////////////////////////////// + std::optional form_as_atom(const Form* f) { auto as_single = f->try_as_single_element(); auto as_atom = dynamic_cast(as_single); diff --git a/decompiler/IR2/Form.h b/decompiler/IR2/Form.h index 47a6775574..5bea8e8fb0 100644 --- a/decompiler/IR2/Form.h +++ b/decompiler/IR2/Form.h @@ -156,6 +156,27 @@ class SimpleExpressionElement : public FormElement { FormStack& stack, std::vector* result, bool allow_side_effects); + void update_from_stack_left_shift(const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result, + bool allow_side_effects); + void update_from_stack_right_shift_logic(const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result, + bool allow_side_effects); + void update_from_stack_right_shift_arith(const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result, + bool allow_side_effects); + void update_from_stack_logor_or_logand(const Env& env, + FixedOperatorKind kind, + FormPool& pool, + FormStack& stack, + std::vector* result, + bool allow_side_effects); const SimpleExpression& expr() const { return m_expr; } @@ -443,6 +464,10 @@ class ConditionElement : public FormElement { FormPool& pool, const std::vector& source_forms, const std::vector& types); + FormElement* make_nonzero_check_generic(const Env& env, + FormPool& pool, + const std::vector& source_forms, + const std::vector& types); FormElement* make_equal_check_generic(const Env& env, FormPool& pool, const std::vector& source_forms, @@ -1285,6 +1310,115 @@ class VectorFloatLoadStoreElement : public FormElement { bool m_is_load = false; }; +struct BitfieldManip { + enum class Kind { + LEFT_SHIFT, + RIGHT_SHIFT_LOGICAL, + RIGHT_SHIFT_LOGICAL_32BIT, + RIGHT_SHIFT_ARITH, + LOGAND, + LOGIOR_WITH_CONSTANT_INT, + NONZERO_COMPARE, + INVALID + } kind = Kind::INVALID; + s64 amount = -1; + + bool is_right_shift() const { + return kind == Kind::RIGHT_SHIFT_ARITH || kind == Kind::RIGHT_SHIFT_LOGICAL || + kind == Kind::RIGHT_SHIFT_LOGICAL_32BIT; + } + + bool right_shift_unsigned() const { + assert(is_right_shift()); + return kind == Kind::RIGHT_SHIFT_LOGICAL || kind == Kind::RIGHT_SHIFT_LOGICAL_32BIT; + } + + bool is_64bit_shift() const { + return kind == Kind::RIGHT_SHIFT_LOGICAL || kind == Kind::RIGHT_SHIFT_ARITH || + kind == Kind::LEFT_SHIFT; + } + + int get_shift_start_bit() const { + if (is_64bit_shift()) { + return 64; + } else { + return 32; + } + } + + BitfieldManip(Kind k, s64 imm) : kind(k), amount(imm) {} +}; + +class BitfieldReadElement : public FormElement { + public: + BitfieldReadElement(Form* base_value, const TypeSpec& ts); + goos::Object to_form_internal(const Env& env) const override; + void apply(const std::function& f) override; + void apply_form(const std::function& f) override; + void collect_vars(RegAccessSet& vars, bool recursive) const override; + void get_modified_regs(RegSet& regs) const override; + FormElement* push_step(const BitfieldManip step, const TypeSystem& ts, FormPool& pool); + + private: + Form* m_base = nullptr; + TypeSpec m_type; + std::vector m_steps; +}; + +struct BitFieldDef { + bool is_signed = false; + u64 value = -1; + std::string field_name; +}; + +std::vector decompile_static_bitfield(const TypeSpec& type, + const TypeSystem& ts, + u64 value); + +class BitfieldStaticDefElement : public FormElement { + public: + BitfieldStaticDefElement(const TypeSpec& type, const std::vector& field_defs); + goos::Object to_form_internal(const Env& env) const override; + void apply(const std::function& f) override; + void apply_form(const std::function& f) override; + void collect_vars(RegAccessSet& vars, bool recursive) const override; + void get_modified_regs(RegSet& regs) const override; + + private: + TypeSpec m_type; + std::vector m_field_defs; +}; + +struct BitfieldFormDef { + Form* value; + std::string field_name; +}; + +/*! + * This represents copying a bitfield object, then modifying the type. + * It's an intermediate step to modifying a bitfield in place and it's not expected to appear + * in the final output. + */ +class ModifiedCopyBitfieldElement : public FormElement { + public: + ModifiedCopyBitfieldElement(const TypeSpec& type, + Form* base, + const std::vector& field_modifications); + goos::Object to_form_internal(const Env& env) const override; + void apply(const std::function& f) override; + void apply_form(const std::function& f) override; + void collect_vars(RegAccessSet& vars, bool recursive) const override; + void get_modified_regs(RegSet& regs) const override; + + Form* base() const { return m_base; } + const std::vector mods() const { return m_field_modifications; } + + private: + TypeSpec m_type; + Form* m_base = nullptr; + std::vector m_field_modifications; +}; + /*! * A Form is a wrapper around one or more FormElements. * This is done for two reasons: diff --git a/decompiler/IR2/FormExpressionAnalysis.cpp b/decompiler/IR2/FormExpressionAnalysis.cpp index b73d86b30f..aba133c62e 100644 --- a/decompiler/IR2/FormExpressionAnalysis.cpp +++ b/decompiler/IR2/FormExpressionAnalysis.cpp @@ -200,6 +200,32 @@ void pop_helper(const std::vector& vars, } } +/*! + * This should be used to generate all casts. + */ +Form* cast_form(Form* in, const TypeSpec& new_type, FormPool& pool, const Env& env) { + auto in_as_cast = dynamic_cast(in->try_as_single_element()); + if (in_as_cast && in_as_cast->type() == new_type) { + return in; + } + + auto in_as_atom = form_as_atom(in); + if (in_as_atom && in_as_atom->is_int()) { + auto type_info = env.dts->ts.lookup_type(new_type); + auto bitfield_info = dynamic_cast(type_info); + if (bitfield_info) { + // GOT BITFIELD: + // fmt::print("Integer constant {} is likely a static bitfield of type {}\n", + // in_as_atom->get_int(), bitfield_info->get_name()); + + auto fields = decompile_static_bitfield(new_type, env.dts->ts, in_as_atom->get_int()); + return pool.alloc_single_element_form(nullptr, new_type, fields); + } + } + + return pool.alloc_single_element_form(nullptr, new_type, in); +} + /*! * Pop each variable in the input list into a form. The variables should be given in the order * they are evaluated in the source. It is safe to put the result of these in the same expression. @@ -238,7 +264,8 @@ std::vector pop_to_forms(const std::vector& vars, // only cast if we didn't get a var (compacting expressions). // there is a separate system for casting variables that will do a better job. if (cast && !is_var) { - forms[i] = pool.alloc_single_element_form(nullptr, *cast, forms[i]); + forms[i] = cast_form(forms[i], *cast, pool, env); + // pool.alloc_single_element_form(nullptr, *cast, forms[i]); } } @@ -338,27 +365,26 @@ void FormElement::update_from_stack(const Env& env, } namespace { -Form* make_cast(Form* in, const TypeSpec& in_type, const TypeSpec& out_type, FormPool& pool) { +Form* make_cast_if_needed(Form* in, + const TypeSpec& in_type, + const TypeSpec& out_type, + FormPool& pool, + const Env& env) { if (in_type == out_type) { return in; } - - auto in_as_cast = dynamic_cast(in->try_as_single_element()); - if (in_as_cast && in_as_cast->type() == out_type) { - return in; - } - - return pool.alloc_single_element_form(nullptr, out_type, in); + return cast_form(in, out_type, pool, env); } -std::vector make_cast(const std::vector& in, - const std::vector& in_types, - const TypeSpec& out_type, - FormPool& pool) { +std::vector make_casts_if_needed(const std::vector& in, + const std::vector& in_types, + const TypeSpec& out_type, + FormPool& pool, + const Env& env) { std::vector out; assert(in.size() == in_types.size()); for (size_t i = 0; i < in_types.size(); i++) { - out.push_back(make_cast(in.at(i), in_types.at(i), out_type, pool)); + out.push_back(make_cast_if_needed(in.at(i), in_types.at(i), out_type, pool, env)); } return out; } @@ -543,7 +569,8 @@ void SimpleExpressionElement::update_from_stack_si_1(const Env& env, auto in_type = env.get_types_before_op(m_my_idx).get(m_expr.get_arg(0).var().reg()).typespec(); auto arg = pop_to_forms({m_expr.get_arg(0).var()}, env, pool, stack, allow_side_effects).at(0); result->push_back(pool.alloc_element( - GenericOperator::make_fixed(kind), make_cast(arg, in_type, TypeSpec("int"), pool))); + GenericOperator::make_fixed(kind), + make_cast_if_needed(arg, in_type, TypeSpec("int"), pool, env))); } void SimpleExpressionElement::update_from_stack_add_i(const Env& env, @@ -855,6 +882,180 @@ void SimpleExpressionElement::update_from_stack_copy_first_int_2(const Env& env, } } +void SimpleExpressionElement::update_from_stack_logor_or_logand(const Env& env, + FixedOperatorKind kind, + FormPool& pool, + FormStack& stack, + std::vector* result, + bool allow_side_effects) { + auto arg0_type = env.get_variable_type(m_expr.get_arg(0).var(), true); + BitfieldManip::Kind manip_kind; + if (kind == FixedOperatorKind::LOGAND) { + manip_kind = BitfieldManip::Kind::LOGAND; + } else if (kind == FixedOperatorKind::LOGIOR) { + manip_kind = BitfieldManip::Kind::LOGIOR_WITH_CONSTANT_INT; + } else { + assert(false); + } + + auto type_info = env.dts->ts.lookup_type(arg0_type); + auto bitfield_info = dynamic_cast(type_info); + if (bitfield_info && m_expr.get_arg(1).is_int()) { + // andi, bitfield + auto base = pop_to_forms({m_expr.get_arg(0).var()}, env, pool, stack, allow_side_effects).at(0); + auto read_elt = dynamic_cast(base->try_as_single_element()); + if (!read_elt) { + read_elt = pool.alloc_element(base, arg0_type); + } + BitfieldManip step(manip_kind, m_expr.get_arg(1).get_int()); + auto other = read_elt->push_step(step, env.dts->ts, pool); + if (other) { + result->push_back(other); + } else { + result->push_back(read_elt); + } + return; + + } else if (!m_expr.get_arg(1).is_var()) { + // andi, something else (don't think this can happen?) + update_from_stack_copy_first_int_2(env, kind, pool, stack, result, allow_side_effects); + } else { + // and, two forms + auto arg0_i = is_int_type(env, m_my_idx, m_expr.get_arg(0).var()); + auto arg0_u = is_uint_type(env, m_my_idx, m_expr.get_arg(0).var()); + auto arg1_i = is_int_type(env, m_my_idx, m_expr.get_arg(1).var()); + auto arg1_u = is_uint_type(env, m_my_idx, m_expr.get_arg(1).var()); + + auto args = pop_to_forms({m_expr.get_arg(0).var(), m_expr.get_arg(1).var()}, env, pool, stack, + allow_side_effects); + + if (bitfield_info) { + // mask didn't fit in imm + auto arg1_atom = form_as_atom(args.at(1)); + if (arg1_atom && arg1_atom->is_int()) { + auto read_elt = dynamic_cast(args.at(0)->try_as_single_element()); + if (!read_elt) { + read_elt = pool.alloc_element(args.at(0), arg0_type); + } + BitfieldManip step(manip_kind, arg1_atom->get_int()); + auto other = read_elt->push_step(step, env.dts->ts, pool); + assert(!other); // shouldn't be complete. + result->push_back(read_elt); + return; + } + } + + if ((arg0_i && arg1_i) || (arg0_u && arg1_u)) { + // types already good + auto new_form = pool.alloc_element(GenericOperator::make_fixed(kind), + args.at(0), args.at(1)); + result->push_back(new_form); + } else { + // types bad, insert cast. + auto cast = pool.alloc_single_element_form( + nullptr, TypeSpec(arg0_i ? "int" : "uint"), args.at(1)); + auto new_form = + pool.alloc_element(GenericOperator::make_fixed(kind), args.at(0), cast); + result->push_back(new_form); + } + } +} + +void SimpleExpressionElement::update_from_stack_left_shift(const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result, + bool allow_side_effects) { + auto arg0_type = env.get_variable_type(m_expr.get_arg(0).var(), true); + + auto type_info = env.dts->ts.lookup_type(arg0_type); + auto bitfield_info = dynamic_cast(type_info); + if (bitfield_info && m_expr.get_arg(1).is_int()) { + auto base = pop_to_forms({m_expr.get_arg(0).var()}, env, pool, stack, allow_side_effects).at(0); + auto read_elt = pool.alloc_element(base, arg0_type); + BitfieldManip step(BitfieldManip::Kind::LEFT_SHIFT, m_expr.get_arg(1).get_int()); + auto other = read_elt->push_step(step, env.dts->ts, pool); + assert(!other); // shouldn't be complete. + result->push_back(read_elt); + } else { + update_from_stack_copy_first_int_2(env, FixedOperatorKind::SHL, pool, stack, result, + allow_side_effects); + } +} + +void SimpleExpressionElement::update_from_stack_right_shift_logic(const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result, + bool allow_side_effects) { + auto arg0_type = env.get_variable_type(m_expr.get_arg(0).var(), true); + auto type_info = env.dts->ts.lookup_type(arg0_type); + auto bitfield_info = dynamic_cast(type_info); + if (bitfield_info && m_expr.get_arg(1).is_int()) { + auto base = pop_to_forms({m_expr.get_arg(0).var()}, env, pool, stack, allow_side_effects).at(0); + auto read_elt = pool.alloc_element(base, arg0_type); + BitfieldManip step(BitfieldManip::Kind::RIGHT_SHIFT_LOGICAL, m_expr.get_arg(1).get_int()); + auto other = read_elt->push_step(step, env.dts->ts, pool); + assert(other); // should be a high field. + result->push_back(other); + } else { + auto arg0_i = is_int_type(env, m_my_idx, m_expr.get_arg(0).var()); + auto arg0_u = is_uint_type(env, m_my_idx, m_expr.get_arg(0).var()); + if (m_expr.get_arg(1).is_int()) { + auto arg = + pop_to_forms({m_expr.get_arg(0).var()}, env, pool, stack, allow_side_effects).at(0); + auto as_bitfield_access = dynamic_cast(arg->try_as_single_element()); + + if (as_bitfield_access) { + BitfieldManip step(BitfieldManip::Kind::RIGHT_SHIFT_LOGICAL, m_expr.get_arg(1).get_int()); + auto next = as_bitfield_access->push_step(step, env.dts->ts, pool); + if (next) { + result->push_back(next); + } else { + result->push_back(as_bitfield_access); + } + } else { + if (!arg0_i && !arg0_u) { + auto new_form = pool.alloc_element( + GenericOperator::make_fixed(FixedOperatorKind::SHR), + pool.alloc_single_element_form(nullptr, TypeSpec("int"), arg), + pool.alloc_single_element_form(nullptr, m_expr.get_arg(1))); + result->push_back(new_form); + } else { + auto new_form = pool.alloc_element( + GenericOperator::make_fixed(FixedOperatorKind::SHR), arg, + pool.alloc_single_element_form(nullptr, m_expr.get_arg(1))); + result->push_back(new_form); + } + } + } else { + update_from_stack_copy_first_int_2(env, FixedOperatorKind::SHR, pool, stack, result, + allow_side_effects); + } + } +} + +void SimpleExpressionElement::update_from_stack_right_shift_arith(const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result, + bool allow_side_effects) { + auto arg0_type = env.get_variable_type(m_expr.get_arg(0).var(), true); + auto type_info = env.dts->ts.lookup_type(arg0_type); + auto bitfield_info = dynamic_cast(type_info); + if (bitfield_info && m_expr.get_arg(1).is_int()) { + auto base = pop_to_forms({m_expr.get_arg(0).var()}, env, pool, stack, allow_side_effects).at(0); + auto read_elt = pool.alloc_element(base, arg0_type); + BitfieldManip step(BitfieldManip::Kind::RIGHT_SHIFT_ARITH, m_expr.get_arg(1).get_int()); + auto other = read_elt->push_step(step, env.dts->ts, pool); + assert(other); // should be a high field. + result->push_back(other); + } else { + update_from_stack_copy_first_int_2(env, FixedOperatorKind::SAR, pool, stack, result, + allow_side_effects); + } +} + void SimpleExpressionElement::update_from_stack_lognot(const Env& env, FormPool& pool, FormStack& stack, @@ -991,12 +1192,12 @@ void SimpleExpressionElement::update_from_stack(const Env& env, allow_side_effects, false); break; case SimpleExpression::Kind::AND: - update_from_stack_copy_first_int_2(env, FixedOperatorKind::LOGAND, pool, stack, result, - allow_side_effects); + update_from_stack_logor_or_logand(env, FixedOperatorKind::LOGAND, pool, stack, result, + allow_side_effects); break; case SimpleExpression::Kind::OR: - update_from_stack_copy_first_int_2(env, FixedOperatorKind::LOGIOR, pool, stack, result, - allow_side_effects); + update_from_stack_logor_or_logand(env, FixedOperatorKind::LOGIOR, pool, stack, result, + allow_side_effects); break; case SimpleExpression::Kind::NOR: update_from_stack_copy_first_int_2(env, FixedOperatorKind::LOGNOR, pool, stack, result, @@ -1010,16 +1211,13 @@ void SimpleExpressionElement::update_from_stack(const Env& env, update_from_stack_lognot(env, pool, stack, result, allow_side_effects); break; case SimpleExpression::Kind::LEFT_SHIFT: - update_from_stack_copy_first_int_2(env, FixedOperatorKind::SHL, pool, stack, result, - allow_side_effects); + update_from_stack_left_shift(env, pool, stack, result, allow_side_effects); break; case SimpleExpression::Kind::RIGHT_SHIFT_LOGIC: - update_from_stack_copy_first_int_2(env, FixedOperatorKind::SHR, pool, stack, result, - allow_side_effects); + update_from_stack_right_shift_logic(env, pool, stack, result, allow_side_effects); break; case SimpleExpression::Kind::RIGHT_SHIFT_ARITH: - update_from_stack_copy_first_int_2(env, FixedOperatorKind::SAR, pool, stack, result, - allow_side_effects); + update_from_stack_right_shift_arith(env, pool, stack, result, allow_side_effects); break; case SimpleExpression::Kind::MUL_UNSIGNED: update_from_stack_force_ui_2(env, FixedOperatorKind::MULTIPLICATION, pool, stack, result, @@ -1115,11 +1313,31 @@ void SetVarElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta } } -void SetFormFormElement::push_to_stack(const Env&, FormPool&, FormStack& stack) { - // todo - is the order here right? +void SetFormFormElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { assert(m_popped); assert(m_real_push_count == 0); m_real_push_count++; + + // check for bitfield setting: + auto src_as_bf_set = dynamic_cast(m_src->try_as_single_element()); + if (src_as_bf_set && src_as_bf_set->mods().size() == 1) { + auto dst_form = m_dst->to_form(env); + auto src_form = src_as_bf_set->base()->to_form(env); + if (dst_form == src_form) { + // success! + auto value = src_as_bf_set->mods().at(0).value; + + // make the (-> thing bitfield) + auto field_token = DerefToken::make_field_name(src_as_bf_set->mods().at(0).field_name); + auto loc_elt = pool.alloc_element(m_dst, false, field_token); + loc_elt->inline_nested(); + auto loc = pool.alloc_single_form(nullptr, loc_elt); + + m_dst = loc; + m_src = value; + } + } + stack.push_form_element(this, true); } @@ -1159,14 +1377,13 @@ void StoreInPairElement::push_to_stack(const Env& env, FormPool& pool, FormStack } namespace { -Form* make_optional_cast(const std::optional& cast_type, Form* in, FormPool& pool) { - if (cast_type) { - auto in_as_cast = dynamic_cast(in->try_as_single_element()); - if (in_as_cast && in_as_cast->type() == cast_type) { - return in; - } - return pool.alloc_single_element_form(nullptr, *cast_type, in); +Form* make_optional_cast(const std::optional& cast_type, + Form* in, + FormPool& pool, + const Env& env) { + if (cast_type) { + return cast_form(in, *cast_type, pool, env); } else { return in; } @@ -1179,24 +1396,26 @@ void StorePlainDeref::push_to_stack(const Env& env, FormPool& pool, FormStack& s // this matches the order in Compiler::compile_set auto vars = std::vector({m_expr.var(), m_base_var}); auto popped = pop_to_forms(vars, env, pool, stack, true); - m_dst->set_base(make_optional_cast(m_dst_cast_type, popped.at(1), pool)); + m_dst->set_base(make_optional_cast(m_dst_cast_type, popped.at(1), pool, env)); m_dst->mark_popped(); m_dst->inline_nested(); auto fr = pool.alloc_element( pool.alloc_single_form(nullptr, m_dst), - make_optional_cast(m_src_cast_type, popped.at(0), pool)); + make_optional_cast(m_src_cast_type, popped.at(0), pool, env)); + // so the bitfield set check can run fr->mark_popped(); - stack.push_form_element(fr, true); + fr->push_to_stack(env, pool, stack); } else { auto vars = std::vector({m_base_var}); auto popped = pop_to_forms(vars, env, pool, stack, true); - m_dst->set_base(make_optional_cast(m_dst_cast_type, popped.at(0), pool)); + m_dst->set_base(make_optional_cast(m_dst_cast_type, popped.at(0), pool, env)); m_dst->mark_popped(); m_dst->inline_nested(); auto val = pool.alloc_single_element_form(nullptr, m_expr, m_my_idx); val->mark_popped(); - auto fr = pool.alloc_element( - pool.alloc_single_form(nullptr, m_dst), make_optional_cast(m_src_cast_type, val, pool)); + auto fr = + pool.alloc_element(pool.alloc_single_form(nullptr, m_dst), + make_optional_cast(m_src_cast_type, val, pool, env)); fr->mark_popped(); stack.push_form_element(fr, true); } @@ -1992,6 +2211,27 @@ FormElement* ConditionElement::make_zero_check_generic(const Env&, } } +FormElement* ConditionElement::make_nonzero_check_generic(const Env& env, + FormPool& pool, + const std::vector& source_forms, + const std::vector&) { + // for (nonzero? (-> obj bitfield)) + FormElement* bitfield_compare = nullptr; + assert(source_forms.size() == 1); + auto as_bitfield_op = + dynamic_cast(source_forms.at(0)->try_as_single_element()); + if (as_bitfield_op) { + bitfield_compare = as_bitfield_op->push_step( + BitfieldManip(BitfieldManip::Kind::NONZERO_COMPARE, 0), env.dts->ts, pool); + } + + if (bitfield_compare) { + return bitfield_compare; + } else { + return pool.alloc_element(GenericOperator::make_compare(m_kind), source_forms); + } +} + FormElement* ConditionElement::make_equal_check_generic(const Env&, FormPool& pool, const std::vector& source_forms, @@ -2031,7 +2271,7 @@ FormElement* ConditionElement::make_not_equal_check_generic(const Env&, } FormElement* ConditionElement::make_less_than_zero_signed_check_generic( - const Env&, + const Env& env, FormPool& pool, const std::vector& source_forms, const std::vector& types) { @@ -2052,7 +2292,7 @@ FormElement* ConditionElement::make_less_than_zero_signed_check_generic( return pool.alloc_element(GenericOperator::make_fixed(FixedOperatorKind::PAIRP), shift_match.maps.forms.at(0)); } else { - auto casted = make_cast(source_forms, types, TypeSpec("int"), pool); + auto casted = make_casts_if_needed(source_forms, types, TypeSpec("int"), pool, env); auto zero = pool.alloc_single_element_form(nullptr, SimpleAtom::make_int_constant(0)); casted.push_back(zero); @@ -2062,7 +2302,7 @@ FormElement* ConditionElement::make_less_than_zero_signed_check_generic( } FormElement* ConditionElement::make_geq_zero_signed_check_generic( - const Env&, + const Env& env, FormPool& pool, const std::vector& source_forms, const std::vector& types) { @@ -2086,7 +2326,7 @@ FormElement* ConditionElement::make_geq_zero_signed_check_generic( nullptr, GenericOperator::make_fixed(FixedOperatorKind::PAIRP), shift_match.maps.forms.at(0))); } else { - auto casted = make_cast(source_forms, types, TypeSpec("int"), pool); + auto casted = make_casts_if_needed(source_forms, types, TypeSpec("int"), pool, env); auto zero = pool.alloc_single_element_form(nullptr, SimpleAtom::make_int_constant(0)); casted.push_back(zero); @@ -2102,8 +2342,9 @@ FormElement* ConditionElement::make_generic(const Env& env, switch (m_kind) { case IR2_Condition::Kind::ZERO: return make_zero_check_generic(env, pool, source_forms, types); - case IR2_Condition::Kind::TRUTHY: case IR2_Condition::Kind::NONZERO: + return make_nonzero_check_generic(env, pool, source_forms, types); + case IR2_Condition::Kind::TRUTHY: case IR2_Condition::Kind::FALSE: case IR2_Condition::Kind::IS_PAIR: case IR2_Condition::Kind::IS_NOT_PAIR: @@ -2122,28 +2363,28 @@ FormElement* ConditionElement::make_generic(const Env& env, case IR2_Condition::Kind::LESS_THAN_SIGNED: return pool.alloc_element( GenericOperator::make_fixed(FixedOperatorKind::LT), - make_cast(source_forms, types, TypeSpec("int"), pool)); + make_casts_if_needed(source_forms, types, TypeSpec("int"), pool, env)); case IR2_Condition::Kind::LESS_THAN_UNSIGNED: return pool.alloc_element( GenericOperator::make_fixed(FixedOperatorKind::LT), - make_cast(source_forms, types, TypeSpec("uint"), pool)); + make_casts_if_needed(source_forms, types, TypeSpec("uint"), pool, env)); case IR2_Condition::Kind::GEQ_UNSIGNED: return pool.alloc_element( GenericOperator::make_fixed(FixedOperatorKind::GEQ), - make_cast(source_forms, types, TypeSpec("uint"), pool)); + make_casts_if_needed(source_forms, types, TypeSpec("uint"), pool, env)); case IR2_Condition::Kind::GEQ_SIGNED: return pool.alloc_element( GenericOperator::make_fixed(FixedOperatorKind::GEQ), - make_cast(source_forms, types, TypeSpec("int"), pool)); + make_casts_if_needed(source_forms, types, TypeSpec("int"), pool, env)); case IR2_Condition::Kind::LESS_THAN_ZERO_SIGNED: { return make_less_than_zero_signed_check_generic(env, pool, source_forms, types); } case IR2_Condition::Kind::LEQ_ZERO_SIGNED: { - auto casted = make_cast(source_forms, types, TypeSpec("int"), pool); + auto casted = make_casts_if_needed(source_forms, types, TypeSpec("int"), pool, env); auto zero = pool.alloc_single_element_form( nullptr, SimpleAtom::make_int_constant(0)); casted.push_back(zero); @@ -2156,7 +2397,7 @@ FormElement* ConditionElement::make_generic(const Env& env, } case IR2_Condition::Kind::GREATER_THAN_ZERO_UNSIGNED: { - auto casted = make_cast(source_forms, types, TypeSpec("uint"), pool); + auto casted = make_casts_if_needed(source_forms, types, TypeSpec("uint"), pool, env); auto zero = pool.alloc_single_element_form( nullptr, SimpleAtom::make_int_constant(0)); casted.push_back(zero); @@ -2165,7 +2406,7 @@ FormElement* ConditionElement::make_generic(const Env& env, } case IR2_Condition::Kind::GREATER_THAN_ZERO_SIGNED: { - auto casted = make_cast(source_forms, types, TypeSpec("int"), pool); + auto casted = make_casts_if_needed(source_forms, types, TypeSpec("int"), pool, env); auto zero = pool.alloc_single_element_form( nullptr, SimpleAtom::make_int_constant(0)); casted.push_back(zero); @@ -2174,31 +2415,31 @@ FormElement* ConditionElement::make_generic(const Env& env, } case IR2_Condition::Kind::FLOAT_NOT_EQUAL: { - auto casted = make_cast(source_forms, types, TypeSpec("float"), pool); + auto casted = make_casts_if_needed(source_forms, types, TypeSpec("float"), pool, env); return pool.alloc_element(GenericOperator::make_fixed(FixedOperatorKind::NEQ), casted); } case IR2_Condition::Kind::FLOAT_EQUAL: { - auto casted = make_cast(source_forms, types, TypeSpec("float"), pool); + auto casted = make_casts_if_needed(source_forms, types, TypeSpec("float"), pool, env); return pool.alloc_element(GenericOperator::make_fixed(FixedOperatorKind::EQ), casted); } case IR2_Condition::Kind::FLOAT_LEQ: { - auto casted = make_cast(source_forms, types, TypeSpec("float"), pool); + auto casted = make_casts_if_needed(source_forms, types, TypeSpec("float"), pool, env); return pool.alloc_element(GenericOperator::make_fixed(FixedOperatorKind::LEQ), casted); } case IR2_Condition::Kind::FLOAT_LESS_THAN: { - auto casted = make_cast(source_forms, types, TypeSpec("float"), pool); + auto casted = make_casts_if_needed(source_forms, types, TypeSpec("float"), pool, env); return pool.alloc_element(GenericOperator::make_fixed(FixedOperatorKind::LT), casted); } case IR2_Condition::Kind::FLOAT_GEQ: { - auto casted = make_cast(source_forms, types, TypeSpec("float"), pool); + auto casted = make_casts_if_needed(source_forms, types, TypeSpec("float"), pool, env); return pool.alloc_element(GenericOperator::make_fixed(FixedOperatorKind::GEQ), casted); } @@ -2322,7 +2563,42 @@ void ReturnElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta stack.push_form_element(this, true); } -void AtomicOpElement::push_to_stack(const Env& env, FormPool&, FormStack& stack) { +namespace { +void push_asm_srl_to_stack(const AsmOp* op, + FormElement* form_elt, + const Env& env, + FormPool& pool, + FormStack& stack) { + // we will try to convert this into a bitfield operation. If this fails, fall back to assembly. + auto var = op->src(0); + assert(var.has_value()); // srl should always have this. + + auto dst = op->dst(); + assert(dst.has_value()); + + auto integer_atom = op->instruction().get_src(1); + assert(integer_atom.is_imm()); + auto integer = integer_atom.get_imm(); + + auto arg0_type = env.get_variable_type(*var, true); + auto type_info = env.dts->ts.lookup_type(arg0_type); + auto bitfield_info = dynamic_cast(type_info); + if (bitfield_info) { + auto base = pop_to_forms({*var}, env, pool, stack, true).at(0); + auto read_elt = pool.alloc_element(base, arg0_type); + BitfieldManip step(BitfieldManip::Kind::RIGHT_SHIFT_LOGICAL_32BIT, integer); + auto other = read_elt->push_step(step, env.dts->ts, pool); + assert(other); // should be a high field. + stack.push_value_to_reg(*dst, pool.alloc_single_form(nullptr, other), true, + env.get_variable_type(*dst, true)); + } else { + stack.push_form_element(form_elt, true); + } +} + +} // namespace + +void AtomicOpElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { mark_popped(); auto as_end = dynamic_cast(m_op); if (as_end) { @@ -2343,15 +2619,30 @@ void AtomicOpElement::push_to_stack(const Env& env, FormPool&, FormStack& stack) auto as_asm = dynamic_cast(m_op); if (as_asm) { - stack.push_form_element(this, true); + switch (as_asm->instruction().kind) { + case InstructionKind::SRL: + push_asm_srl_to_stack(as_asm, this, env, pool, stack); + break; + default: + stack.push_form_element(this, true); + break; + } return; } throw std::runtime_error("Can't push atomic op to stack: " + m_op->to_string(env)); } -void AsmOpElement::push_to_stack(const Env&, FormPool&, FormStack& stack) { +void AsmOpElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { mark_popped(); - stack.push_form_element(this, true); + + switch (m_op->instruction().kind) { + case InstructionKind::SRL: + push_asm_srl_to_stack(m_op, this, env, pool, stack); + break; + default: + stack.push_form_element(this, true); + break; + } } void GenericElement::update_from_stack(const Env& env, diff --git a/decompiler/IR2/IR2_common.h b/decompiler/IR2/IR2_common.h index a6769d0fb7..82973b86f2 100644 --- a/decompiler/IR2/IR2_common.h +++ b/decompiler/IR2/IR2_common.h @@ -64,10 +64,11 @@ class RegisterAccess { RegisterAccess(AccessMode mode, Register reg, int atomic_idx, bool allow_all = false); enum class Print { - AS_REG, // print as a PS2 register name - FULL, // print as a register name, plus an index, plus read or write - AS_VARIABLE, // print local variable name, error if impossible - AUTOMATIC, // print as variable, but if that's not possible print as reg. + AS_REG, // print as a PS2 register name + FULL, // print as a register name, plus an index, plus read or write + AS_VARIABLE, // print local variable name, error if impossible + AS_VARIABLE_NO_CAST, // same as above, but no cast + AUTOMATIC, // print as variable, but if that's not possible print as reg. }; goos::Object to_form(const Env& env, Print mode = Print::AUTOMATIC) const; diff --git a/decompiler/config/all-types.gc b/decompiler/config/all-types.gc index 3ca3b8ed62..3963dd95b3 100644 --- a/decompiler/config/all-types.gc +++ b/decompiler/config/all-types.gc @@ -1665,11 +1665,9 @@ ;(define-extern sound-rpc-set-falloff-curve object) ;; unknown type -;;(define-extern *sound-bank-2* object) ;; unknown type ;;(define-extern sound-rpc-reload-info object) ;; unknown type ;;(define-extern sound-rpc-stop-sound object) ;; unknown type ;;(define-extern sound-rpc-list-sounds object) ;; unknown type -;;(define-extern *current-sound-id* object) ;; unknown type ;;(define-extern sound-bank-id object) ;; unknown type ;;(define-extern sound-rpc-get-irx-version object) ;; unknown type ;;(define-extern sound-rpc-load-music object) ;; unknown type @@ -1688,6 +1686,8 @@ :flag-assert #xa00000004 ) +(define-extern *current-sound-id* sound-id) + (deftype sound-bank-id (uint32) () :flag-assert #x900000004 @@ -1701,7 +1701,8 @@ ;;(define-extern sound-rpc-load-bank object) ;; unknown type ;;(define-extern sound-rpc-set-master-volume object) ;; unknown type ;;(define-extern sound-rpc-set-param object) ;; unknown type -;;(define-extern *sound-bank-1* object) ;; unknown type +(define-extern *sound-bank-1* symbol) +(define-extern *sound-bank-2* symbol) ;;(define-extern sound-rpc-stop-group object) ;; unknown type ;;(define-extern sound-rpc-play object) ;; unknown type ;;(define-extern sound-rpc-cmd object) ;; unknown type @@ -2203,7 +2204,7 @@ (deftype vif-bank (structure) ((stat uint32 :offset-assert 0) (fbrst uint32 :offset 16) - (err uint32 :offset 32) + (err vif-err :offset 32) (mark uint32 :offset 48) (cycle uint32 :offset 64) (mode uint32 :offset 80) @@ -2353,18 +2354,18 @@ ) ;; dma-h - (deftype vif-tag (uint32) ((imm uint16 :offset 0 :size 16) (num uint8 :offset 16 :size 8) - (cmd uint8 :offset 24 :size 8) + (cmd uint8 :offset 24 :size 7) + (msk uint8 :offset 28 :size 1) (irq uint8 :offset 31 :size 1) ;;? - (msk uint8 :offset 15 :size 1) ) :method-count-assert 9 :size-assert #x4 :flag-assert #x900000004 ) + (deftype dma-enable (uint32) () :flag-assert #x900000004 @@ -2479,6 +2480,9 @@ :flag-assert #x900000014 ) +(define-extern *vu1-enable-user-menu* int) +(define-extern *vu1-enable-user* int) + ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -2536,10 +2540,10 @@ (define-extern *video-parms* video-parms) ;; unknown type ;;(define-extern video-parms object) ;; unknown type ;;(define-extern generic-bucket-state object) ;; unknown type -;;(define-extern *vu1-enable-user-menu* object) ;; unknown type + ;; unknown type (define-extern dma-foreground-sink type) (define-extern dma-foreground-sink-group type) -;;(define-extern *vu1-enable-user* object) ;; unknown type +;; ;; unknown type (define-extern generic-dma-foreground-sink type) @@ -3243,7 +3247,7 @@ (define-extern vector-vector-distance-squared (function vector vector float)) (define-extern vector-vector-xz-distance (function vector vector float)) (define-extern vector-vector-xz-distance-squared (function vector vector float)) -(define-extern vector-normalize! (function vector vector vector)) +(define-extern vector-normalize! (function vector float vector)) (define-extern vector-normalize-ret-len! (function vector float float)) (define-extern vector-normalize-copy! (function vector vector float vector)) (define-extern vector-xz-normalize! (function vector float vector)) diff --git a/decompiler/config/jak1_ntsc_black_label/label_types.jsonc b/decompiler/config/jak1_ntsc_black_label/label_types.jsonc index 3400ef93b6..eb284df904 100644 --- a/decompiler/config/jak1_ntsc_black_label/label_types.jsonc +++ b/decompiler/config/jak1_ntsc_black_label/label_types.jsonc @@ -108,6 +108,12 @@ ["L136", "float", true] ], + "timer": [["L20", "float", true]], + + "dma": [["L56", "uint64", true]], + + "video-h": [["L1", "video-parms", true]], + "pad": [ ["L44", "float", true], ["L42", "float", true], diff --git a/decompiler/config/jak1_ntsc_black_label/type_casts.jsonc b/decompiler/config/jak1_ntsc_black_label/type_casts.jsonc index 20b465eac6..e5cf129b6b 100644 --- a/decompiler/config/jak1_ntsc_black_label/type_casts.jsonc +++ b/decompiler/config/jak1_ntsc_black_label/type_casts.jsonc @@ -40,7 +40,7 @@ [132, "gp", "(array int8)"], // bug in game [150, "gp", "(array int16)"], [168, "gp", "(array uint16)"], - [190, "gp", "(array uint128)"], + [191, "gp", "(array uint128)"], [207, "gp", "(array int32)"], [226, "gp", "(array float)"], [243, "gp", "(array basic)"] @@ -49,9 +49,7 @@ // GKERNEL-H "(method 2 handle)": [ [10, "a2", "(pointer process)"], - [11, "a3", "process"], - [12, "v1", "int"], - [16, "gp", "int"] + [11, "a3", "process"] ], // GKERNEL @@ -120,6 +118,33 @@ "vector-y-quaternion!": [[10, "v1", "(pointer uint128)"]], "vector-z-quaternion!": [[10, "v1", "(pointer uint128)"]], + // Matrix + //"eul->matrix": [[[110, 228], "gp", "(pointer float)"]], + + // DMA + "dma-send-to-spr": [[[0, 32], "s5", "dma-bank-spr"]], + "dma-send-to-spr-no-flush": [[[0, 32], "s5", "dma-bank-spr"]], + "dma-send-from-spr": [[[0, 32], "s5", "dma-bank-spr"]], + "dma-send-from-spr-no-flush": [[[0, 32], "s5", "dma-bank-spr"]], + "dma-initialize": [ + [1, "v1", "vif-bank"], + [8, "v1", "vif-bank"], + [6, "a0", "vif-bank"], + [13, "a0", "vif-bank"] + ], + + "clear-vu1-mem": [[[0, 11], "v1", "(pointer uint32)"]], + "clear-vu0-mem": [[[0, 11], "v1", "(pointer uint32)"]], + + "dump-vu1-mem": [[[0, 49], "gp", "(pointer uint32)"]], + + "dump-vu1-range": [[[0, 54], "s4", "(pointer uint32)"]], + + "ultimate-memcpy": [ + [[0, 54], "s4", "dma-bank-spr"], + [[0, 54], "s3", "dma-bank-spr"] + ], + // LEVEL "lookup-level-info": [ [3, "a1", "symbol"], diff --git a/decompiler/config/jak1_ntsc_black_label/var_names.jsonc b/decompiler/config/jak1_ntsc_black_label/var_names.jsonc index 9da10fa8f9..a144bd9669 100644 --- a/decompiler/config/jak1_ntsc_black_label/var_names.jsonc +++ b/decompiler/config/jak1_ntsc_black_label/var_names.jsonc @@ -578,14 +578,18 @@ "args": ["tf", "dst-mat"] }, - "quaternion-axis-angle!":{ + "quaternion-axis-angle!": { "args": ["quat", "x", "y", "z", "angle"] }, - "quaternion-vector-angle!":{ + "quaternion-vector-angle!": { "args": ["quat", "axis", "angle"] }, + "vector-flatten!": { + "args": ["dst", "src", "plane-normal"] + }, + "deg-seek": { "args": ["in", "target", "max-diff"], "vars": { diff --git a/goal_src/engine/dma/dma-h.gc b/goal_src/engine/dma/dma-h.gc index 0a53a981e6..319591f516 100644 --- a/goal_src/engine/dma/dma-h.gc +++ b/goal_src/engine/dma/dma-h.gc @@ -10,14 +10,17 @@ ;; The PS2 supports several types of DMA, including simple chunk transfer and more complicated ;; "chain" transfers, where the hardware can follow a linked data-structure. -;; In OpenGOAL, "DMA" will be instant. By default, DMA syncs will be disabled by this flag. +;; In OpenGOAL, "DMA" will be instant, meaning the game code will stop, wait until the +;; DMA is finished, and then continue. As a result, there is no need for DMA synchronization. +;; When this flag is set, all DMA syncs will be instantaneous. (defglobalconstant INSTANT_DMA #t) -;; count returned by dma-sync-with-count -;; when instant dma is enabled. +;; Some DMA sync functions return a count for how long it took. +;; When INSTANT_DMA is enabled, these functions will return this value. (defglobalconstant INSTANT_DMA_COUNT 123) ;; DMA Channel Control Register. This starts the DMA and can be checked to see if it done. +;; There is one CHCR per DMA channel. (deftype dma-chcr (uint32) ((dir uint8 :offset 0 :size 1) ;; 1 - from memory (mod uint8 :offset 2 :size 2) ;; normal, chain, interleave @@ -43,7 +46,8 @@ obj ) -;; Most basic DMA register layout +;; Each DMA Channel has a bank of registers with the following layout. +;; Some channels have more advanced features, but all support at least these three. (deftype dma-bank (structure) ((chcr dma-chcr :offset 0) ;; control register (madr uint32 :offset 16) ;; memory address @@ -84,6 +88,8 @@ :flag-assert #x900000084 ) +;; These addresses are the location of DMA banks for each channel. +;; These do not exist in OpenGOAL. (defconstant VIF0_DMA_BANK (the dma-bank-vif #x10008000)) (defconstant VIF1_DMA_BANK (the dma-bank-vif #x10009000)) (defconstant GIF_DMA_BANK (the dma-bank #x1000a000)) @@ -91,7 +97,14 @@ (defconstant SPR_FROM_BANK (the dma-bank-spr #x1000d000)) (defconstant SPR_TO_BANK (the dma-bank-spr #x1000d400)) -;; D_CTRL, master DMA control register, shraed for all channels. +(defconstant VU0_DATA_MEM_MAP (the (pointer uint32) #x11004000)) +(defconstant VU1_DATA_MEM_MAP (the (pointer uint32) #x1100c000)) + + +;; The DMA system also has some shared control registers that +;; apply to all channels. + +;; D_CTRL, master DMA control register, shared for all channels. (deftype dma-ctrl (uint32) () :method-count-assert 9 @@ -202,9 +215,9 @@ (deftype vif-tag (uint32) ((imm uint16 :offset 0 :size 16) (num uint8 :offset 16 :size 8) - (cmd uint8 :offset 24 :size 8) + (cmd uint8 :offset 24 :size 7) + (msk uint8 :offset 28 :size 1) (irq uint8 :offset 31 :size 1) ;;? - (msk uint8 :offset 15 :size 1) ) :method-count-assert 9 :size-assert #x4 @@ -252,7 +265,8 @@ Makes sure any ongoing transfer on the channel is done Flushes the cache. Sets dir to 0, so I don't expect this to be used for VIF1 transfers. - Madr should not be a scratchpad address." + Madr should not be a scratchpad address. + This function is unused." ((inline dma-sync-fast) bank) (flush-cache 0) ;; (.sync.l) @@ -272,7 +286,8 @@ (count (pointer int32))) "Wait for DMA to finish, incrementing count. This doesn't seem like a very accurate way - to find out how long it takes..." + to find out how long it takes... + This function is unused." (#cond (INSTANT_DMA (set! (-> count) INSTANT_DMA_COUNT) @@ -294,7 +309,8 @@ (defun dma-count-until-done ((bank dma-bank) (count (pointer int32))) - "Like the previous one, kinda" + "Like the previous one, kinda. + This function is unused." (#cond (INSTANT_DMA (set! (-> count) INSTANT_DMA_COUNT) diff --git a/goal_src/engine/dma/dma.gc b/goal_src/engine/dma/dma.gc index 891f94cd38..cc3c4d5289 100644 --- a/goal_src/engine/dma/dma.gc +++ b/goal_src/engine/dma/dma.gc @@ -17,14 +17,12 @@ ;; these functions are just here for completeness and won't work properly on PC. ;; DMA sync functions will succeed and return instantly, so it's safe to leave those in. -(defconstant SPR_FROM_BANK (the dma-bank-spr #x100D000)) -(defconstant SPR_TO_BANK (the dma-bank-spr #x1000D400)) - (defun dma-sync-hang ((bank dma-bank)) "Hang here until the dma transfer is completed. This is worse than the dma-sync-fast because it ends up spamming the DMA bank register more often, and reduces - the speed of the DMA transfer." + the speed of the DMA transfer. + This function is unused." (#cond (INSTANT_DMA 0) @@ -38,59 +36,68 @@ ) (defun dma-sync-crash ((arg0 dma-bank)) - "Try to sync DMA for a bit, then crash if we can't" - (local-vars (count int)) - (#when INSTANT_DMA - (return 0) + "Wait for DMA to finish for a while, then crash if we can't. + This function is unused." + (#cond + (INSTANT_DMA + (return 0) + ) ) - (set! count 5000000) - ;; checking str - (while (nonzero? (logand (the-as int (-> arg0 chcr)) 256)) - (if (zero? count) - (segfault) - (set! count (+ count -1)) - ) + (let ((v1-0 5000000)) + (while (nonzero? (-> arg0 chcr str)) + (if (zero? v1-0) + (crash!) + (+! v1-0 -1) + ) + ) + (none) ) - (none) ) +(defmacro make-madr-addr (addr) + "Convert an address to one suitable for MADR. + This works with Main RAM (all mappings) and for spad" + `(let ((int-addr (the-as int ,addr))) + (logior (logand #xfffffff int-addr) ;; mask off spad/mapping bits + (if (= (logand #x70000000 int-addr) #x70000000) + #x80000000 ;; if we're in spad, set high bit. + 0 ;; otherwise nothing. + ) + ) + ) + ) + + + (defun dma-send ((arg0 dma-bank) (madr uint) (qwc uint)) - "Send DMA! madr can be a scratchpad address. - Like dma-send-no-scratch, this sets chcr to zero, which may be undesirable." + "Send DMA given an address and a quadword count. + The madr can be in main memory or scratchpad. + This is appropriate for VIF0/GIF transfers. + It can be used for VIF1, but will do VIF -> madr, which is probably + not what you want." (dma-sync (the-as pointer arg0) 0 0) (flush-cache 0) (.sync.l) - (set! (-> arg0 madr) - (logior (logand #xfffffff (the-as int madr)) ;; lower 28 bits are untouched - ;; if we are transferring to the scratchpad (at 70000000) - ;; we should set bit 31 in madr, per the manual. - (if (= (logand #x70000000 (the-as int madr)) #x70000000) - (shl #x8000 16) ;; set bit 31 - 0) - ) - ) + (set! (-> arg0 madr) (make-madr-addr madr)) (set! (-> arg0 qwc) qwc) (.sync.l) - ;; set str! + ;; begin DMA! (set! (-> arg0 chcr) (new 'static 'dma-chcr :str 1)) (.sync.l) (none) ) (defun dma-send-chain ((arg0 dma-bank-source) (tadr uint)) - "Send DMA! tadr should be a tag address, possibly in spad ram." + "Send DMA! tadr should be a tag address, possibly in spad ram. + This is useful for sending to VIF. + Tag transfer is enabled, and DIR is set so a VIF1 transfer + goes from tadr -> VIF." (dma-sync (the-as pointer arg0) 0 0) (flush-cache 0) (.sync.l) (set! (-> arg0 qwc) 0) ;; adjust address - (set! (-> arg0 tadr) - (logior (logand #xfffffff (the-as int tadr)) - (if (= (logand #x70000000 (the-as int tadr)) #x70000000) - (shl #x8000 16) - 0) - ) - ) + (set! (-> arg0 tadr) (make-madr-addr tadr)) (.sync.l) ;;(set! (-> arg0 chcr) 325) (set! (-> arg0 chcr) @@ -105,21 +112,13 @@ ) (defun dma-send-chain-no-tte ((arg0 dma-bank-source) (arg1 uint)) - "Send DMA chain! TTE bit is not set, don't transfer tags." + "Send DMA chain! TTE bit is not set, don't transfer tags. + This is never used." (dma-sync (the-as pointer arg0) 0 0) (flush-cache 0) (.sync.l) (set! (-> arg0 qwc) 0) - (set! - (-> arg0 tadr) - (logior - (logand #xfffffff (the-as int arg1)) - (the-as - uint - (if (= (logand #x70000000 (the-as int arg1)) #x70000000) (shl #x8000 16) 0) - ) - ) - ) + (set! (-> arg0 tadr) (make-madr-addr arg1)) (.sync.l) (set! (-> arg0 chcr) (new 'static 'dma-chcr @@ -138,16 +137,7 @@ (dma-sync (the-as pointer arg0) 0 0) (.sync.l) (set! (-> arg0 qwc) 0) - (set! - (-> arg0 tadr) - (logior - (logand #xfffffff (the-as int arg1)) - (the-as - uint - (if (= (logand #x70000000 (the-as int arg1)) #x70000000) (shl #x8000 16) 0) - ) - ) - ) + (set! (-> arg0 tadr) arg1) (.sync.l) ;;(set! (-> arg0 chcr) 325) (set! (-> arg0 chcr) @@ -158,7 +148,6 @@ :str 1) ) (.sync.l) - (set! v0-1 0) (none) ) @@ -232,49 +221,35 @@ (defun dma-initialize () "Due to a bug in the PS2 hardware, you must always disable the DMAtag mismatch error. This is done here." + + ;; (declare (print-asm)) (#when PC_PORT (format 0 "[dma.gc] skipping dma-initialize for PC port~%") (return 0) ) - (set! (-> VIF0_BANK err) - (logior (logand (-> VIF0_BANK err) (the-as uint -3)) 2) - ) - (set! (-> (the vif-bank #x10003c00) err) - (logior (logand (-> VIF1_BANK err) (the-as uint -3)) 2) - ) + (set! (-> (the-as vif-bank #x10003800) err me0) 1) + (set! (-> (the-as vif-bank #x10003c00) err me0) 1) (none) ) (defun clear-vu0-mem () - "Clear the data memory of VU0, filling it with abadbeef - This uses the slow memory mapping of VU0's data memory at 0x11004000" - (local-vars - (v1-0 (pointer uint32)) - (a0-0 int) - ) - (set! v1-0 (the (pointer uint32) #x11004000)) - (set! a0-0 0) - (while (< a0-0 1024) + "Set the vu0 data memory to 0xabadbeef. This uses the slow EE mapping of VU memory." + (let ((v1-0 VU0_DATA_MEM_MAP)) + (dotimes (a0-0 1024) (set! (-> v1-0 a0-0) #xabadbeef) - (set! a0-0 (+ a0-0 1)) ) + ) (none) ) (defun clear-vu1-mem () - "Clear the data memory of VU1, filling it with abadbeef - This uses the slow memory mapping of VU1's data memory at 0x1100C000" - (local-vars - (v1-0 (pointer uint32)) - (a0-0 int) - ) - (set! v1-0 (the (pointer uint32) #x1100c000)) - (set! a0-0 0) - (while (< a0-0 4096) + "Set the vu1 data memory to 0xabadbeef. This uses the slow EE mapping of VU memory." + (let ((v1-0 VU1_DATA_MEM_MAP)) + (dotimes (a0-0 4096) (set! (-> v1-0 a0-0) #xabadbeef) - (set! a0-0 (+ a0-0 1)) ) + ) (none) ) diff --git a/goal_src/engine/math/euler-h.gc b/goal_src/engine/math/euler-h.gc index 14d2e87982..029b85e34e 100644 --- a/goal_src/engine/math/euler-h.gc +++ b/goal_src/engine/math/euler-h.gc @@ -10,6 +10,8 @@ (define EulNext (new 'static 'boxed-array int32 4 1 2 0 1)) ;; just uses the same xyzw and data array as vector. +;; the w stores a float that should be an integer that seems to have +;; bitfields for... something? Like maybe the order? (deftype euler-angles (vector) () :method-count-assert 9 diff --git a/goal_src/engine/math/euler.gc b/goal_src/engine/math/euler.gc index f5643c154d..b095528142 100644 --- a/goal_src/engine/math/euler.gc +++ b/goal_src/engine/math/euler.gc @@ -5,3 +5,252 @@ ;; name in dgo: euler ;; dgos: GAME, ENGINE +;; In general, the euler angle stuff is really inefficient. I don't think it's really used outside of +;; a few camera debugging functions. + +(defun set-eul! ((arg0 euler-angles) (arg1 float) (arg2 float) (arg3 float) (arg4 int)) + "Set the euler angles. The 4th argument is for flags." + (set! (-> arg0 data 0) arg1) + (set! (-> arg0 data 1) arg2) + (set! (-> arg0 data 2) arg3) + (set! (-> arg0 data 3) (the float arg4)) + arg0 + ) + +(defun eul->matrix ((arg0 matrix) (arg1 euler-angles)) + "Convert euler angles to rotation matrix." + (matrix-identity! arg0) + (let ((s5-0 (new 'stack 'vector))) + ;; copy to temp storage. + (set! (-> s5-0 quad) (-> arg1 quad)) + (if (= (logand (the int (-> s5-0 data 3)) 1) 1) + (let ((f0-2 (-> s5-0 data 0))) + (set! (-> s5-0 data 0) (-> s5-0 data 2)) + (set! (-> s5-0 data 2) f0-2) + ) + ) + (when (= (logand (sar (the int (-> s5-0 data 3)) 2) 1) 1) + (set! (-> s5-0 data 0) (- (-> s5-0 data 0))) + (set! (-> s5-0 data 1) (- (-> s5-0 data 1))) + (set! (-> s5-0 data 2) (- (-> s5-0 data 2))) + ) + (let* ((f26-0 (cos (-> s5-0 data 0))) + (f30-0 (cos (-> s5-0 data 1))) + (f22-0 (cos (-> s5-0 data 2))) + (f24-0 (sin (-> s5-0 data 0))) + (f28-0 (sin (-> s5-0 data 1))) + (f4-0 (sin (-> s5-0 data 2))) + (f0-17 (* f26-0 f22-0)) + (f1-1 (* f26-0 f4-0)) + (f2-0 (* f24-0 f22-0)) + (f3-0 (* f24-0 f4-0)) + ) + (let* ((v1-12 (logand (sar (the int (-> s5-0 data 3)) 2) 1)) + (a1-2 (-> EulSafe (logand (sar (the int (-> s5-0 data 3)) 3) 3))) + (a0-21 (-> EulNext (+ a1-2 v1-12))) + (v1-17 (-> EulNext (+ (- 1 v1-12) a1-2))) + ) + (cond + ((= (logand (sar (the int (-> s5-0 data 3)) 1) 1) 1) + (set! (-> (the-as (pointer float) (+ (+ (shl a1-2 4) (shl a1-2 2)) (the-as int arg0)))) + f30-0 + ) + (set! (-> (the-as (pointer float) (+ (+ (shl a1-2 4) (shl a0-21 2)) (the-as int arg0)))) + (* f28-0 f24-0) + ) + (set! (-> (the-as (pointer float) (+ (+ (shl a1-2 4) (shl v1-17 2)) (the-as int arg0)))) + (* f28-0 f26-0) + ) + (set! (-> (the-as (pointer float) (+ (+ (shl a0-21 4) (shl a1-2 2)) (the-as int arg0)))) + (* f28-0 f4-0) + ) + (set! (-> (the-as (pointer float) (+ (+ (shl a0-21 4) (shl a0-21 2)) (the-as int arg0)))) + (- f0-17 (* f30-0 f3-0)) + ) + (set! (-> (the-as (pointer float) (+ (+ (shl a0-21 4) (shl v1-17 2)) (the-as int arg0)))) + (- (- f2-0) (* f30-0 f1-1)) + ) + (set! (-> (the-as (pointer float) (+ (+ (shl v1-17 4) (shl a1-2 2)) (the-as int arg0)))) + (- (* f28-0 f22-0)) + ) + (set! (-> (the-as (pointer float) (+ (+ (shl v1-17 4) (shl a0-21 2)) (the-as int arg0)))) + (+ f1-1 (* f30-0 f2-0)) + ) + (let ((f0-19 (+ (- f3-0) (* f30-0 f0-17)))) + (set! (-> (the-as (pointer float) (+ (+ (shl v1-17 4) (shl v1-17 2)) (the-as int arg0)))) + f0-19 + ) + ) + ) + (else + (set! (-> (the-as (pointer float) (+ (+ (shl a1-2 4) (shl a1-2 2)) (the-as int arg0)))) + (* f30-0 f22-0) + ) + (set! (-> (the-as (pointer float) (+ (+ (shl a1-2 4) (shl a0-21 2)) (the-as int arg0)))) + (+ (- f1-1) (* f28-0 f2-0)) + ) + (set! (-> (the-as (pointer float) (+ (+ (shl a1-2 4) (shl v1-17 2)) (the-as int arg0)))) + (+ f3-0 (* f28-0 f0-17)) + ) + (set! (-> (the-as (pointer float) (+ (+ (shl a0-21 4) (shl a1-2 2)) (the-as int arg0)))) + (* f30-0 f4-0) + ) + (set! (-> (the-as (pointer float) (+ (+ (shl a0-21 4) (shl a0-21 2)) (the-as int arg0)))) + (+ f0-17 (* f28-0 f3-0)) + ) + (set! (-> (the-as (pointer float) (+ (+ (shl a0-21 4) (shl v1-17 2)) (the-as int arg0)))) + (+ (- f2-0) (* f28-0 f1-1)) + ) + (set! (-> (the-as (pointer float) (+ (+ (shl v1-17 4) (shl a1-2 2)) (the-as int arg0)))) + (- f28-0) + ) + (set! (-> (the-as (pointer float) (+ (+ (shl v1-17 4) (shl a0-21 2)) (the-as int arg0)))) + (* f30-0 f24-0) + ) + (let ((f0-25 (* f30-0 f26-0))) + (set! (-> (the-as (pointer float) (+ (+ (shl v1-17 4) (shl v1-17 2)) (the-as int arg0)))) + f0-25 + ) + ) + ) + ) + ) + ) + ) + arg0 + ) + +(defun matrix->eul ((arg0 euler-angles) (arg1 matrix) (arg2 int)) + "Conver matrix to euler angles. Takes some weird flag for what kind of euler angles" + (let* ((v1-4 (logand (sar arg2 2) 1)) + (s3-0 (-> EulSafe (logand (sar arg2 3) 3))) + (s2-0 (-> EulNext (+ s3-0 v1-4))) + (s1-0 (-> EulNext (+ (- 1 v1-4) s3-0))) + ) + (if (= (logand (sar arg2 1) 1) 1) + (let* ((f0-0 (-> (the-as (pointer float) (+ (+ (shl s2-0 2) (shl s3-0 4)) (the-as int arg1))))) + (f0-2 (* f0-0 f0-0)) + (f1-0 (-> (the-as (pointer float) (+ (+ (shl s1-0 2) (shl s3-0 4)) (the-as int arg1))))) + (f30-0 (sqrtf (+ f0-2 (* f1-0 f1-0)))) + ) + (cond + ((< 0.00001 f30-0) + (set! (-> arg0 data 0) + (atan (-> (the-as (pointer float) (+ (+ (shl s2-0 2) (shl s3-0 4)) (the-as int arg1)))) + (-> (the-as (pointer float) (+ (+ (shl s1-0 2) (shl s3-0 4)) (the-as int arg1)))) + ) + ) + (set! (-> arg0 data 1) + (atan f30-0 (-> (the-as (pointer float) (+ (+ (shl s3-0 2) (shl s3-0 4)) (the-as int arg1))))) + ) + (let ((f0-13 (atan + (-> (the-as (pointer float) (+ (+ (shl s3-0 2) (shl s2-0 4)) (the-as int arg1)))) + (- (-> (the-as (pointer float) (+ (+ (shl s3-0 2) (shl s1-0 4)) (the-as int arg1))))) + ) + ) + ) + (set! (-> arg0 data 2) f0-13) + ) + ) + (else + (set! (-> arg0 data 0) + (atan (- (-> (the-as (pointer float) (+ (+ (shl s1-0 2) (shl s2-0 4)) (the-as int arg1))))) + (-> (the-as (pointer float) (+ (+ (shl s2-0 2) (shl s2-0 4)) (the-as int arg1)))) + ) + ) + (set! (-> arg0 data 1) + (atan + f30-0 + (-> (the-as (pointer float) (+ (+ (shl s3-0 2) (shl s3-0 4)) (the-as int arg1)))) + ) + ) + (let ((f0-20 0.0)) + (set! (-> arg0 data 2) f0-20) + ) + ) + ) + ) + (let* ((f0-21 (-> (the-as (pointer float) (+ (+ (shl s3-0 2) (shl s3-0 4)) (the-as int arg1))))) + (f0-23 (* f0-21 f0-21)) + (f1-3 (-> (the-as (pointer float) (+ (+ (shl s3-0 2) (shl s2-0 4)) (the-as int arg1))))) + (f30-1 (sqrtf (+ f0-23 (* f1-3 f1-3)))) + ) + (cond + ((< 0.00001 f30-1) + (set! (-> arg0 data 0) + (atan + (-> (the-as (pointer float) (+ (+ (shl s2-0 2) (shl s1-0 4)) (the-as int arg1)))) + (-> (the-as (pointer float) (+ (+ (shl s1-0 2) (shl s1-0 4)) (the-as int arg1)))) + ) + ) + (set! (-> arg0 data 1) + (atan + (- (-> (the-as (pointer float) (+ (+ (shl s3-0 2) (shl s1-0 4)) (the-as int arg1))))) + f30-1 + ) + ) + (let ((f0-34 (atan + (-> (the-as (pointer float) (+ (+ (shl s3-0 2) (shl s2-0 4)) (the-as int arg1)))) + (-> (the-as (pointer float) (+ (+ (shl s3-0 2) (shl s3-0 4)) (the-as int arg1)))) + ) + ) + ) + (set! (-> arg0 data 2) f0-34) + ) + ) + (else + (set! (-> arg0 data 0) + (atan + (- (-> (the-as (pointer float) (+ (+ (shl s1-0 2) (shl s2-0 4)) (the-as int arg1))))) + (-> (the-as (pointer float) (+ (+ (shl s2-0 2) (shl s2-0 4)) (the-as int arg1)))) + ) + ) + (set! (-> arg0 data 1) + (atan + (- (-> (the-as (pointer float) (+ (+ (shl s3-0 2) (shl s1-0 4)) (the-as int arg1))))) + f30-1 + ) + ) + (let ((f0-42 0.0)) + (set! (-> arg0 data 2) f0-42) + ) + ) + ) + ) + ) + ) + (when (= (logand (sar arg2 2) 1) 1) + (set! (-> arg0 data 0) (- (-> arg0 data 0))) + (set! (-> arg0 data 1) (- (-> arg0 data 1))) + (let ((f0-48 (- (-> arg0 data 2)))) + (set! (-> arg0 data 2) f0-48) + ) + ) + (if (= (logand arg2 1) 1) + (let ((f0-49 (-> arg0 data 0))) + (set! (-> arg0 data 0) (-> arg0 data 2)) + (set! (-> arg0 data 2) f0-49) + ) + ) + (set! (-> arg0 data 3) (the float arg2)) + arg0 + ) + +(defun eul->quat ((arg0 quaternion) (arg1 euler-angles)) + "Convert euler angles to quaternion" + (let ((s5-0 (new 'stack 'matrix))) + (eul->matrix s5-0 arg1) + (matrix->quaternion arg0 s5-0) + ) + arg0 + ) + +(defun quat->eul ((arg0 euler-angles) (arg1 quaternion) (arg2 int)) + "Convert quaternion to euler angles. The last argument is euler flags" + (let ((s5-0 (new 'stack 'matrix))) + (quaternion->matrix s5-0 arg1) + (matrix->eul arg0 s5-0 arg2) + ) + arg0 + ) + diff --git a/goal_src/engine/math/vector-h.gc b/goal_src/engine/math/vector-h.gc index 87757af772..2d046c8a8f 100644 --- a/goal_src/engine/math/vector-h.gc +++ b/goal_src/engine/math/vector-h.gc @@ -686,3 +686,6 @@ (define-extern vector-length (function vector float)) (define-extern vector-xz-normalize! (function vector float vector)) (define-extern vector-xz-length (function vector float)) +(defun-extern vector+float*! vector vector vector float vector) +(defun-extern vector-normalize! vector float vector) +(defun-extern vector-float*! vector vector float vector) diff --git a/goal_src/engine/math/vector.gc b/goal_src/engine/math/vector.gc index 28b3525ced..f2ce71a320 100644 --- a/goal_src/engine/math/vector.gc +++ b/goal_src/engine/math/vector.gc @@ -464,32 +464,6 @@ ;; (.svf a0-0 vf1) ;; (ret-value v0-0))) -(defun vector-normalize! ((arg0 vector) (arg1 vector)) - "TODO" - (local-vars (v1-0 vector)) - (rlet ((acc :class vf) - (Q :class vf) - (vf0 :class vf) - (vf1 :class vf) - (vf2 :class vf) - (vf3 :class vf)) - (.lvf vf0 (new 'static 'vector :x 0.0 :y 0.0 :z 0.0 :w 1.0)) - (.lvf vf1 arg0) - (.mul.vf vf2 vf1 vf1 :mask #b1110) - (set! v1-0 arg1) - (.mov vf3 v1-0) - (.mul.x.vf acc vf0 vf2 :mask #b1) - (.add.mul.y.vf acc vf0 vf2 acc :mask #b1) - (.add.mul.z.vf vf2 vf0 vf2 acc :mask #b1) - (.isqrt.vf Q vf3 vf2 :ftf #b0 :fsf #b11) - (.wait.vf) - (.mul.vf vf1 vf1 Q :mask #b1110) - (.nop.vf) - (.nop.vf) - (.nop.vf) - (.svf arg0 vf1) - arg0)) - (defun vector-vector-xz-distance-squared ((arg0 vector) (arg1 vector)) "TODO" (local-vars (v0-0 int)) diff --git a/goal_src/engine/ps2/vif-h.gc b/goal_src/engine/ps2/vif-h.gc index 6ffc04395c..8c4310c61d 100644 --- a/goal_src/engine/ps2/vif-h.gc +++ b/goal_src/engine/ps2/vif-h.gc @@ -68,7 +68,7 @@ (deftype vif-bank (structure) ((stat uint32 :offset-assert 0) (fbrst uint32 :offset 16) - (err uint32 :offset 32) + (err vif-err :offset 32) (mark uint32 :offset 48) (cycle uint32 :offset 64) (mode uint32 :offset 80) diff --git a/goal_src/goal-lib.gc b/goal_src/goal-lib.gc index e4cb65f2b4..46a5ce838d 100644 --- a/goal_src/goal-lib.gc +++ b/goal_src/goal-lib.gc @@ -177,6 +177,11 @@ `(/ 0 0) ) +(defmacro crash! () + "Cause a crash by attempting to deference 0x0" + `(-> (the (pointer uint8) 0)) + ) + ;;;;;;;;;;;;;;;;;;; ;; GOAL Syntax ;;;;;;;;;;;;;;;;;;; diff --git a/test/decompiler/reference/all_forward_declarations.gc b/test/decompiler/reference/all_forward_declarations.gc index 144ea5f66b..e27ae5a2d9 100644 --- a/test/decompiler/reference/all_forward_declarations.gc +++ b/test/decompiler/reference/all_forward_declarations.gc @@ -118,6 +118,9 @@ (define-extern quaternion-from-two-vectors-max-angle! (function quaternion vector vector float quaternion)) (define-extern vector-xz-length (function vector float)) +(defmacro .sync.l () + `(none)) + ;; display-h (deftype display-env (structure) ((pmode uint64 :offset-assert 0) @@ -216,4 +219,4 @@ ) ) -(define-extern *display* display) \ No newline at end of file +(define-extern *display* display) diff --git a/test/decompiler/reference/dma-h_REF.gc b/test/decompiler/reference/dma-h_REF.gc new file mode 100644 index 0000000000..79638752c7 --- /dev/null +++ b/test/decompiler/reference/dma-h_REF.gc @@ -0,0 +1,312 @@ +;;-*-Lisp-*- +(in-package goal) + +;; definition of type dma-chcr +(deftype dma-chcr (uint32) + ((dir uint8 :offset 0 :size 1) + (mod uint8 :offset 2 :size 2) + (asp uint8 :offset 4 :size 2) + (tte uint8 :offset 6 :size 1) + (tie uint8 :offset 7 :size 1) + (str uint8 :offset 8 :size 1) + (tag uint16 :offset 16 :size 16) + ) + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ) + +;; definition for method 3 of type dma-chcr +(defmethod inspect dma-chcr ((obj dma-chcr)) + (format #t "[~8x] ~A~%" obj 'dma-chcr) + (format #t "~Tdir: ~D~%" (-> obj dir)) + (format #t "~Tmod: ~D~%" (-> obj mod)) + (format #t "~Tasp: ~D~%" (-> obj asp)) + (format #t "~Ttte: ~D~%" (-> obj tte)) + (format #t "~Ttie: ~D~%" (-> obj tie)) + (format #t "~Tstr: ~D~%" (-> obj str)) + (format #t "~Ttag: #x~X~%" (-> obj tag)) + obj + ) + +;; definition of type dma-bank +(deftype dma-bank (structure) + ((chcr dma-chcr :offset 0) + (madr uint32 :offset 16) + (qwc uint32 :offset 32) + ) + :method-count-assert 9 + :size-assert #x24 + :flag-assert #x900000024 + ) + +;; definition for method 3 of type dma-bank +(defmethod inspect dma-bank ((obj dma-bank)) + (format #t "[~8x] ~A~%" obj 'dma-bank) + (format #t "~Tchcr: #x~X~%" (-> obj chcr)) + (format #t "~Tmadr: #x~X~%" (-> obj madr)) + (format #t "~Tqwc: #x~X~%" (-> obj qwc)) + obj + ) + +;; definition of type dma-bank-source +(deftype dma-bank-source (dma-bank) + ((tadr uint32 :offset 48) + ) + :method-count-assert 9 + :size-assert #x34 + :flag-assert #x900000034 + ) + +;; definition for method 3 of type dma-bank-source +(defmethod inspect dma-bank-source ((obj dma-bank-source)) + (format #t "[~8x] ~A~%" obj 'dma-bank-source) + (format #t "~Tchcr: #x~X~%" (-> obj chcr)) + (format #t "~Tmadr: #x~X~%" (-> obj madr)) + (format #t "~Tqwc: #x~X~%" (-> obj qwc)) + (format #t "~Ttadr: #x~X~%" (-> obj tadr)) + obj + ) + +;; definition of type dma-bank-vif +(deftype dma-bank-vif (dma-bank-source) + ((as0 uint32 :offset 64) + (as1 uint32 :offset 80) + ) + :method-count-assert 9 + :size-assert #x54 + :flag-assert #x900000054 + ) + +;; definition for method 3 of type dma-bank-vif +(defmethod inspect dma-bank-vif ((obj dma-bank-vif)) + (format #t "[~8x] ~A~%" obj 'dma-bank-vif) + (format #t "~Tchcr: #x~X~%" (-> obj chcr)) + (format #t "~Tmadr: #x~X~%" (-> obj madr)) + (format #t "~Tqwc: #x~X~%" (-> obj qwc)) + (format #t "~Ttadr: #x~X~%" (-> obj tadr)) + (format #t "~Tas0: #x~X~%" (-> obj as0)) + (format #t "~Tas1: #x~X~%" (-> obj as1)) + obj + ) + +;; definition of type dma-bank-spr +(deftype dma-bank-spr (dma-bank-source) + ((sadr uint32 :offset 128) + ) + :method-count-assert 9 + :size-assert #x84 + :flag-assert #x900000084 + ) + +;; definition for method 3 of type dma-bank-spr +(defmethod inspect dma-bank-spr ((obj dma-bank-spr)) + (format #t "[~8x] ~A~%" obj 'dma-bank-spr) + (format #t "~Tchcr: #x~X~%" (-> obj chcr)) + (format #t "~Tmadr: #x~X~%" (-> obj madr)) + (format #t "~Tqwc: #x~X~%" (-> obj qwc)) + (format #t "~Ttadr: #x~X~%" (-> obj tadr)) + (format #t "~Tsadr: #x~X~%" (-> obj sadr)) + obj + ) + +;; definition of type dma-ctrl +(deftype dma-ctrl (uint32) + () + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ) + +;; definition of type dma-enable +(deftype dma-enable (uint32) + () + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ) + +;; definition of type dma-sqwc +(deftype dma-sqwc (uint32) + () + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ) + +;; definition of type dma-bank-control +(deftype dma-bank-control (structure) + ((ctrl dma-ctrl :offset 0) + (stat uint32 :offset 16) + (pcr uint32 :offset 32) + (sqwc dma-sqwc :offset 48) + (rbsr uint32 :offset 64) + (rbor uint32 :offset 80) + (stadr uint32 :offset 96) + (enabler uint32 :offset 5408) + (enablew uint32 :offset 5520) + ) + :method-count-assert 9 + :size-assert #x1594 + :flag-assert #x900001594 + ) + +;; definition for method 3 of type dma-bank-control +(defmethod inspect dma-bank-control ((obj dma-bank-control)) + (format #t "[~8x] ~A~%" obj 'dma-bank-control) + (format #t "~Tctrl: #x~X~%" (-> obj ctrl)) + (format #t "~Tstat: #x~X~%" (-> obj stat)) + (format #t "~Tpcr: #x~X~%" (-> obj pcr)) + (format #t "~Tsqwc: #x~X~%" (-> obj sqwc)) + (format #t "~Trbsr: #x~X~%" (-> obj rbsr)) + (format #t "~Trbor: #x~X~%" (-> obj rbor)) + (format #t "~Tstadr: #x~X~%" (-> obj stadr)) + (format #t "~Tenabler: ~D~%" (-> obj enabler)) + (format #t "~Tenablew: ~D~%" (-> obj enablew)) + obj + ) + +;; definition of type vu-code-block +(deftype vu-code-block (basic) + ((name basic :offset-assert 4) + (code uint32 :offset-assert 8) + (size int32 :offset-assert 12) + (dest-address uint32 :offset-assert 16) + ) + :method-count-assert 9 + :size-assert #x14 + :flag-assert #x900000014 + ) + +;; definition for method 3 of type vu-code-block +(defmethod inspect vu-code-block ((obj vu-code-block)) + (format #t "[~8x] ~A~%" obj (-> obj type)) + (format #t "~Tname: ~A~%" (-> obj name)) + (format #t "~Tcode: #x~X~%" (-> obj code)) + (format #t "~Tsize: ~D~%" (-> obj size)) + (format #t "~Tdest-address: ~D~%" (-> obj dest-address)) + obj + ) + +;; definition of type vu-stat +(deftype vu-stat (uint64) + () + :method-count-assert 9 + :size-assert #x8 + :flag-assert #x900000008 + ) + +;; definition of type dma-tag +(deftype dma-tag (uint64) + ((qwc uint16 :offset 0 :size 16) + (pce uint8 :offset 26 :size 2) + (id uint8 :offset 28 :size 3) + (irq uint8 :offset 31 :size 1) + (addr uint32 :offset 32 :size 31) + (spr uint8 :offset 63 :size 1) + ) + :method-count-assert 9 + :size-assert #x8 + :flag-assert #x900000008 + ) + +;; definition for method 3 of type dma-tag +(defmethod inspect dma-tag ((obj dma-tag)) + (format #t "[~8x] ~A~%" obj 'dma-tag) + (format #t "~Tqwc: ~D~%" (-> obj qwc)) + (format #t "~Tpce: ~D~%" (-> obj pce)) + (format #t "~Tid: ~D~%" (-> obj id)) + (format #t "~Tirq: ~D~%" (-> obj irq)) + (format #t "~Taddr: #x~X~%" (-> obj addr)) + (format #t "~Tspr: ~D~%" (-> obj spr)) + obj + ) + +;; definition of type dma-bucket +(deftype dma-bucket (structure) + ((tag dma-tag :offset-assert 0) + (last (pointer uint64) :offset-assert 8) + (dummy uint32 :offset-assert 12) + (next uint32 :offset 4) + ) + :method-count-assert 9 + :size-assert #x10 + :flag-assert #x900000010 + ) + +;; definition for method 3 of type dma-bucket +(defmethod inspect dma-bucket ((obj dma-bucket)) + (format #t "[~8x] ~A~%" obj 'dma-bucket) + (format #t "~Ttag: ~D~%" (-> obj tag)) + (format #t "~Tlast: #x~X~%" (-> obj last)) + (format #t "~Tdummy: ~D~%" (-> obj dummy)) + (format #t "~Tnext: #x~X~%" (-> obj next)) + obj + ) + +;; definition of type vif-mask +(deftype vif-mask (uint32) + () + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ) + +;; definition of type vif-stcycl-imm +(deftype vif-stcycl-imm (uint16) + () + :method-count-assert 9 + :size-assert #x2 + :flag-assert #x900000002 + ) + +;; definition of type vif-unpack-imm +(deftype vif-unpack-imm (uint16) + () + :method-count-assert 9 + :size-assert #x2 + :flag-assert #x900000002 + ) + +;; definition of type vif-tag +(deftype vif-tag (uint32) + ((imm uint16 :offset 0 :size 16) + (num uint8 :offset 16 :size 8) + (cmd uint8 :offset 24 :size 7) + (msk uint8 :offset 28 :size 1) + (irq uint8 :offset 31 :size 1) + ) + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ) + +;; definition for method 3 of type vif-tag +(defmethod inspect vif-tag ((obj vif-tag)) + (format #t "[~8x] ~A~%" obj 'vif-tag) + (format #t "~Timm: #x~X~%" (-> obj imm)) + (format #t "~Tnum: ~D~%" (-> obj num)) + (format #t "~Tcmd: #x~X~%" (-> obj cmd)) + (format #t "~Tmsk: ~D~%" (-> obj msk)) + (format #t "~Tirq: ~D~%" (-> obj irq)) + obj + ) + +;; definition for function dma-sync-fast +;; ERROR: function was not converted to expressions. Cannot decompile. + +;; definition for function dma-send-no-scratch +;; ERROR: function was not converted to expressions. Cannot decompile. + +;; definition for function dma-sync-with-count +;; ERROR: function was not converted to expressions. Cannot decompile. + +;; definition for function dma-count-until-done +;; ERROR: function was not converted to expressions. Cannot decompile. + +;; failed to figure out what this is: +(none) + + + + diff --git a/test/decompiler/reference/dma_REF.gc b/test/decompiler/reference/dma_REF.gc new file mode 100644 index 0000000000..af57597f49 --- /dev/null +++ b/test/decompiler/reference/dma_REF.gc @@ -0,0 +1,419 @@ +;;-*-Lisp-*- +(in-package goal) + +;; definition for function dma-sync-hang +;; ERROR: function was not converted to expressions. Cannot decompile. + +;; definition for function dma-sync-crash +;; INFO: Return type mismatch int vs none. +(defun dma-sync-crash ((arg0 dma-bank)) + (let ((v1-0 #x4c4b40)) + (while (nonzero? (-> arg0 chcr str)) + (cond + ((zero? v1-0) + (crash!) + (let ((a1-0 0)) + ) + ) + (else + (+! v1-0 -1) + ) + ) + ) + ) + (let ((v0-0 0)) + ) + (none) + ) + +;; definition for function dma-send +;; INFO: Return type mismatch int vs none. +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +(defun dma-send ((arg0 dma-bank) (arg1 uint) (arg2 uint)) + (dma-sync (the-as pointer arg0) 0 0) + (flush-cache 0) + (.sync.l) + (set! + (-> arg0 madr) + (logior + (logand #xfffffff (the-as int arg1)) + (the-as uint (if (= (logand #x70000000 (the-as int arg1)) #x70000000) + (shl #x8000 16) + 0 + ) + ) + ) + ) + (set! (-> arg0 qwc) arg2) + (.sync.l) + (set! (-> arg0 chcr) (new 'static 'dma-chcr :str #x1)) + (.sync.l) + (let ((v0-1 0)) + ) + (none) + ) + +;; definition for function dma-send-chain +;; INFO: Return type mismatch int vs none. +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +(defun dma-send-chain ((arg0 dma-bank-source) (arg1 uint)) + (dma-sync (the-as pointer arg0) 0 0) + (flush-cache 0) + (.sync.l) + (set! (-> arg0 qwc) (the-as uint 0)) + (set! + (-> arg0 tadr) + (logior + (logand #xfffffff (the-as int arg1)) + (the-as uint (if (= (logand #x70000000 (the-as int arg1)) #x70000000) + (shl #x8000 16) + 0 + ) + ) + ) + ) + (.sync.l) + (set! + (-> arg0 chcr) + (new 'static 'dma-chcr :dir #x1 :mod #x1 :tte #x1 :str #x1) + ) + (.sync.l) + (let ((v0-1 0)) + ) + (none) + ) + +;; definition for function dma-send-chain-no-tte +;; INFO: Return type mismatch int vs none. +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +(defun dma-send-chain-no-tte ((arg0 dma-bank-source) (arg1 uint)) + (dma-sync (the-as pointer arg0) 0 0) + (flush-cache 0) + (.sync.l) + (set! (-> arg0 qwc) (the-as uint 0)) + (set! + (-> arg0 tadr) + (logior + (logand #xfffffff (the-as int arg1)) + (the-as uint (if (= (logand #x70000000 (the-as int arg1)) #x70000000) + (shl #x8000 16) + 0 + ) + ) + ) + ) + (.sync.l) + (set! (-> arg0 chcr) (new 'static 'dma-chcr :dir #x1 :mod #x1 :str #x1)) + (.sync.l) + (let ((v0-1 0)) + ) + (none) + ) + +;; definition for function dma-send-chain-no-flush +;; INFO: Return type mismatch int vs none. +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +(defun dma-send-chain-no-flush ((arg0 dma-bank-source) (arg1 uint)) + (dma-sync (the-as pointer arg0) 0 0) + (.sync.l) + (set! (-> arg0 qwc) (the-as uint 0)) + (set! + (-> arg0 tadr) + (logior + (logand #xfffffff (the-as int arg1)) + (the-as uint (if (= (logand #x70000000 (the-as int arg1)) #x70000000) + (shl #x8000 16) + 0 + ) + ) + ) + ) + (.sync.l) + (set! + (-> arg0 chcr) + (new 'static 'dma-chcr :dir #x1 :mod #x1 :tte #x1 :str #x1) + ) + (.sync.l) + (let ((v0-1 0)) + ) + (none) + ) + +;; definition for function dma-send-to-spr +;; INFO: Return type mismatch int vs none. +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +(defun dma-send-to-spr ((sadr uint) (madr uint) (qwc uint) (sync symbol)) + (let ((s5-0 (the-as dma-bank-spr #x1000d400))) + (dma-sync (the-as pointer s5-0) 0 0) + (flush-cache 0) + (.sync.l) + (set! (-> s5-0 madr) (logand #xfffffff (the-as int madr))) + (set! (-> s5-0 sadr) (logand #xfffffff (the-as int sadr))) + (set! (-> s5-0 qwc) qwc) + (.sync.l) + (set! (-> s5-0 chcr) (new 'static 'dma-chcr :str #x1)) + (.sync.l) + (if sync + (dma-sync (the-as pointer s5-0) 0 0) + ) + ) + (let ((v0-2 0)) + ) + (none) + ) + +;; definition for function dma-send-to-spr-no-flush +;; INFO: Return type mismatch int vs none. +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +(defun + dma-send-to-spr-no-flush + ((sadr uint) (madr uint) (qwc uint) (sync symbol)) + (let ((s5-0 (the-as dma-bank-spr #x1000d400))) + (dma-sync (the-as pointer s5-0) 0 0) + (.sync.l) + (set! (-> s5-0 madr) (logand #xfffffff (the-as int madr))) + (set! (-> s5-0 sadr) (logand #xfffffff (the-as int sadr))) + (set! (-> s5-0 qwc) qwc) + (.sync.l) + (set! (-> s5-0 chcr) (new 'static 'dma-chcr :str #x1)) + (.sync.l) + (if sync + (dma-sync (the-as pointer s5-0) 0 0) + ) + ) + (let ((v0-2 0)) + ) + (none) + ) + +;; definition for function dma-send-from-spr +;; INFO: Return type mismatch int vs none. +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +(defun dma-send-from-spr ((madr uint) (sadr uint) (qwc uint) (sync symbol)) + (let ((s5-0 (the-as dma-bank-spr #x1000d000))) + (dma-sync (the-as pointer s5-0) 0 0) + (flush-cache 0) + (.sync.l) + (set! (-> s5-0 madr) (logand #xfffffff (the-as int madr))) + (set! (-> s5-0 sadr) (logand #xfffffff (the-as int sadr))) + (set! (-> s5-0 qwc) qwc) + (.sync.l) + (set! (-> s5-0 chcr) (new 'static 'dma-chcr :str #x1)) + (.sync.l) + (if sync + (dma-sync (the-as pointer s5-0) 0 0) + ) + ) + (let ((v0-2 0)) + ) + (none) + ) + +;; definition for function dma-send-from-spr-no-flush +;; INFO: Return type mismatch int vs none. +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +(defun + dma-send-from-spr-no-flush + ((madr uint) (sadr uint) (qwc uint) (sync symbol)) + (let ((s5-0 (the-as dma-bank-spr #x1000d000))) + (dma-sync (the-as pointer s5-0) 0 0) + (.sync.l) + (set! (-> s5-0 madr) (logand #xfffffff (the-as int madr))) + (set! (-> s5-0 sadr) (logand #xfffffff (the-as int sadr))) + (set! (-> s5-0 qwc) qwc) + (.sync.l) + (set! (-> s5-0 chcr) (new 'static 'dma-chcr :str #x1)) + (.sync.l) + (if sync + (dma-sync (the-as pointer s5-0) 0 0) + ) + ) + (let ((v0-2 0)) + ) + (none) + ) + +;; definition for function dma-initialize +;; INFO: Return type mismatch int vs none. +(defun dma-initialize () + (set! (-> (the-as vif-bank #x10003800) err me0) 1) + (set! (-> (the-as vif-bank #x10003c00) err me0) 1) + (let ((v0-0 0)) + ) + (none) + ) + +;; definition for function clear-vu0-mem +;; INFO: Return type mismatch int vs none. +(defun clear-vu0-mem () + (let ((v1-0 (the-as (pointer uint32) #x11004000))) + (dotimes (a0-0 1024) + (set! (-> v1-0 a0-0) #xabadbeef) + ) + ) + (let ((v0-0 0)) + ) + (none) + ) + +;; definition for function clear-vu1-mem +;; INFO: Return type mismatch int vs none. +(defun clear-vu1-mem () + (let ((v1-0 (the-as (pointer uint32) #x1100c000))) + (dotimes (a0-0 4096) + (set! (-> v1-0 a0-0) #xabadbeef) + ) + ) + (let ((v0-0 0)) + ) + (none) + ) + +;; definition for function dump-vu1-mem +;; INFO: Return type mismatch symbol vs none. +(defun dump-vu1-mem () + (let ((gp-0 (the-as (pointer uint32) #x1100c000))) + (dotimes (s5-0 1024) + (format + 0 + "~4,'0X: ~8,'0X ~8,'0X ~8,'0X ~8,'0X" + s5-0 + (-> gp-0 (shl s5-0 2)) + (-> gp-0 (+ (shl s5-0 2) 1)) + (-> gp-0 (+ (shl s5-0 2) 2)) + (-> gp-0 (+ (shl s5-0 2) 3)) + ) + (format + 0 + " ~F ~F ~F ~F ~%" + (-> gp-0 (shl s5-0 2)) + (-> gp-0 (+ (shl s5-0 2) 1)) + (-> gp-0 (+ (shl s5-0 2) 2)) + (-> gp-0 (+ (shl s5-0 2) 3)) + ) + ) + ) + (none) + ) + +;; definition for function dump-vu1-range +(defun dump-vu1-range ((start uint) (total-count uint)) + (let ((s4-0 (the-as (pointer uint32) #x1100c000))) + (dotimes (s3-0 (the-as int total-count)) + (let ((s2-0 (+ s3-0 (the-as int start)))) + (format + 0 + "~4,'0X: ~8x ~8x ~8x ~8x" + s2-0 + (-> s4-0 (shl s2-0 2)) + (-> s4-0 (+ (shl s2-0 2) 1)) + (-> s4-0 (+ (shl s2-0 2) 2)) + (-> s4-0 (+ (shl s2-0 2) 3)) + ) + (format + 0 + " ~F ~F ~F ~F ~%" + (-> s4-0 (shl s2-0 2)) + (-> s4-0 (+ (shl s2-0 2) 1)) + (-> s4-0 (+ (shl s2-0 2) 2)) + (-> s4-0 (+ (shl s2-0 2) 3)) + ) + ) + ) + ) + #f + ) + +;; definition for symbol *video-reset-parm*, type int +(define *video-reset-parm* 2) + +;; definition for function reset-vif1-path +;; INFO: Return type mismatch int vs none. +(defun reset-vif1-path () + ((method-of-type dma-bank-vif inspect) (the-as dma-bank-vif #x10009000)) + ((method-of-type vif-bank inspect) (the-as vif-bank #x10003c00)) + (reset-path) + (reset-graph 1 1 *video-reset-parm* 1) + (format 0 "gkernel: vif1 path reset!~%") + (let ((v0-3 0)) + ) + (none) + ) + +;; definition for function ultimate-memcpy +;; INFO: Return type mismatch int vs none. +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +(defun ultimate-memcpy ((dst pointer) (src pointer) (size-bytes uint)) + (let ((spr-to-bank (the-as dma-bank-spr #x1000d400)) + (spr-from-bank (the-as dma-bank-spr #x1000d000)) + (qwc-remaining (shr size-bytes 4)) + ) + (flush-cache 0) + (dma-sync (the-as pointer spr-to-bank) 0 0) + (dma-sync (the-as pointer spr-from-bank) 0 0) + (while (> qwc-remaining 0) + (let ((qwc-transferred-now (the-as int qwc-remaining))) + (if (< (the-as uint 1024) (the-as uint qwc-transferred-now)) + (set! qwc-transferred-now 1024) + ) + (set! qwc-remaining (- qwc-remaining (the-as uint qwc-transferred-now))) + (.sync.l) + (set! (-> spr-to-bank madr) (the-as uint src)) + (set! (-> spr-to-bank sadr) (the-as uint 0)) + (set! (-> spr-to-bank qwc) (the-as uint qwc-transferred-now)) + (.sync.l) + (set! (-> spr-to-bank chcr) (new 'static 'dma-chcr :str #x1)) + (.sync.l) + (dma-sync (the-as pointer spr-to-bank) 0 0) + (&+! src (shl qwc-transferred-now 4)) + (set! (-> spr-from-bank madr) (the-as uint dst)) + (set! (-> spr-from-bank sadr) (the-as uint 0)) + (set! (-> spr-from-bank qwc) (the-as uint qwc-transferred-now)) + (.sync.l) + (set! (-> spr-from-bank chcr) (new 'static 'dma-chcr :str #x1)) + (.sync.l) + (dma-sync (the-as pointer spr-from-bank) 0 0) + (&+! dst (shl qwc-transferred-now 4)) + ) + ) + ) + (let ((v0-4 0)) + ) + (none) + ) + +;; definition for function symlink2 +;; ERROR: function was not converted to expressions. Cannot decompile. + +;; definition for function symlink3 +;; ERROR: function was not converted to expressions. Cannot decompile. + +;; failed to figure out what this is: +(dma-initialize) + +;; failed to figure out what this is: +(none) + + + + diff --git a/test/decompiler/reference/euler_REF.gc b/test/decompiler/reference/euler_REF.gc new file mode 100644 index 0000000000..6e8d96be4a --- /dev/null +++ b/test/decompiler/reference/euler_REF.gc @@ -0,0 +1,516 @@ +;;-*-Lisp-*- +(in-package goal) + +;; definition for function set-eul! +(defun + set-eul! + ((arg0 euler-angles) (arg1 float) (arg2 float) (arg3 float) (arg4 int)) + (set! (-> arg0 data 0) arg1) + (set! (-> arg0 data 1) arg2) + (set! (-> arg0 data 2) arg3) + (set! (-> arg0 data 3) (the float arg4)) + arg0 + ) + +;; definition for function eul->matrix +;; Used lq/sq +(defun eul->matrix ((arg0 matrix) (arg1 euler-angles)) + (matrix-identity! arg0) + (let ((s5-0 (new 'stack 'vector))) + (set! (-> s5-0 quad) (-> arg1 quad)) + (if (= (logand (the int (-> s5-0 data 3)) 1) 1) + (let ((f0-2 (-> s5-0 data 0))) + (set! (-> s5-0 data 0) (-> s5-0 data 2)) + (set! (-> s5-0 data 2) f0-2) + ) + ) + (when (= (logand (sar (the int (-> s5-0 data 3)) 2) 1) 1) + (set! (-> s5-0 data 0) (- (-> s5-0 data 0))) + (set! (-> s5-0 data 1) (- (-> s5-0 data 1))) + (let ((f0-10 (- (-> s5-0 data 2)))) + (set! (-> s5-0 data 2) f0-10) + ) + ) + (let* ((f26-0 (cos (-> s5-0 data 0))) + (f30-0 (cos (-> s5-0 data 1))) + (f22-0 (cos (-> s5-0 data 2))) + (f24-0 (sin (-> s5-0 data 0))) + (f28-0 (sin (-> s5-0 data 1))) + (f4-0 (sin (-> s5-0 data 2))) + (f0-17 (* f26-0 f22-0)) + (f1-1 (* f26-0 f4-0)) + (f2-0 (* f24-0 f22-0)) + (f3-0 (* f24-0 f4-0)) + ) + (let ((v1-7 0)) + ) + (let ((v1-8 0)) + ) + (let ((v1-9 0)) + ) + (let* ((v1-12 (logand (sar (the int (-> s5-0 data 3)) 2) 1)) + (a1-2 (-> EulSafe (logand (sar (the int (-> s5-0 data 3)) 3) 3))) + (a0-21 (-> EulNext (+ a1-2 v1-12))) + (v1-17 (-> EulNext (+ (- 1 v1-12) a1-2))) + ) + (cond + ((= (logand (sar (the int (-> s5-0 data 3)) 1) 1) 1) + (set! + (-> + (the-as + (pointer float) + (+ (+ (shl a1-2 4) (shl a1-2 2)) (the-as int arg0)) + ) + ) + f30-0 + ) + (set! + (-> + (the-as + (pointer float) + (+ (+ (shl a1-2 4) (shl a0-21 2)) (the-as int arg0)) + ) + ) + (* f28-0 f24-0) + ) + (set! + (-> + (the-as + (pointer float) + (+ (+ (shl a1-2 4) (shl v1-17 2)) (the-as int arg0)) + ) + ) + (* f28-0 f26-0) + ) + (set! + (-> + (the-as + (pointer float) + (+ (+ (shl a0-21 4) (shl a1-2 2)) (the-as int arg0)) + ) + ) + (* f28-0 f4-0) + ) + (set! + (-> + (the-as + (pointer float) + (+ (+ (shl a0-21 4) (shl a0-21 2)) (the-as int arg0)) + ) + ) + (- f0-17 (* f30-0 f3-0)) + ) + (set! + (-> + (the-as + (pointer float) + (+ (+ (shl a0-21 4) (shl v1-17 2)) (the-as int arg0)) + ) + ) + (- (- f2-0) (* f30-0 f1-1)) + ) + (set! + (-> + (the-as + (pointer float) + (+ (+ (shl v1-17 4) (shl a1-2 2)) (the-as int arg0)) + ) + ) + (- (* f28-0 f22-0)) + ) + (set! + (-> + (the-as + (pointer float) + (+ (+ (shl v1-17 4) (shl a0-21 2)) (the-as int arg0)) + ) + ) + (+ f1-1 (* f30-0 f2-0)) + ) + (let ((f0-19 (+ (- f3-0) (* f30-0 f0-17)))) + (set! + (-> + (the-as + (pointer float) + (+ (+ (shl v1-17 4) (shl v1-17 2)) (the-as int arg0)) + ) + ) + f0-19 + ) + ) + ) + (else + (set! + (-> + (the-as + (pointer float) + (+ (+ (shl a1-2 4) (shl a1-2 2)) (the-as int arg0)) + ) + ) + (* f30-0 f22-0) + ) + (set! + (-> + (the-as + (pointer float) + (+ (+ (shl a1-2 4) (shl a0-21 2)) (the-as int arg0)) + ) + ) + (+ (- f1-1) (* f28-0 f2-0)) + ) + (set! + (-> + (the-as + (pointer float) + (+ (+ (shl a1-2 4) (shl v1-17 2)) (the-as int arg0)) + ) + ) + (+ f3-0 (* f28-0 f0-17)) + ) + (set! + (-> + (the-as + (pointer float) + (+ (+ (shl a0-21 4) (shl a1-2 2)) (the-as int arg0)) + ) + ) + (* f30-0 f4-0) + ) + (set! + (-> + (the-as + (pointer float) + (+ (+ (shl a0-21 4) (shl a0-21 2)) (the-as int arg0)) + ) + ) + (+ f0-17 (* f28-0 f3-0)) + ) + (set! + (-> + (the-as + (pointer float) + (+ (+ (shl a0-21 4) (shl v1-17 2)) (the-as int arg0)) + ) + ) + (+ (- f2-0) (* f28-0 f1-1)) + ) + (set! + (-> + (the-as + (pointer float) + (+ (+ (shl v1-17 4) (shl a1-2 2)) (the-as int arg0)) + ) + ) + (- f28-0) + ) + (set! + (-> + (the-as + (pointer float) + (+ (+ (shl v1-17 4) (shl a0-21 2)) (the-as int arg0)) + ) + ) + (* f30-0 f24-0) + ) + (let ((f0-25 (* f30-0 f26-0))) + (set! + (-> + (the-as + (pointer float) + (+ (+ (shl v1-17 4) (shl v1-17 2)) (the-as int arg0)) + ) + ) + f0-25 + ) + ) + ) + ) + ) + ) + ) + arg0 + ) + +;; definition for function matrix->eul +(defun matrix->eul ((arg0 euler-angles) (arg1 matrix) (arg2 int)) + (let ((v1-0 0)) + ) + (let ((v1-1 0)) + ) + (let ((v1-2 0)) + ) + (let* ((v1-4 (logand (sar arg2 2) 1)) + (s3-0 (-> EulSafe (logand (sar arg2 3) 3))) + (s2-0 (-> EulNext (+ s3-0 v1-4))) + (s1-0 (-> EulNext (+ (- 1 v1-4) s3-0))) + ) + (if (= (logand (sar arg2 1) 1) 1) + (let* + ((f0-0 + (-> + (the-as + (pointer float) + (+ (+ (shl s2-0 2) (shl s3-0 4)) (the-as int arg1)) + ) + ) + ) + (f0-2 (* f0-0 f0-0)) + (f1-0 + (-> + (the-as + (pointer float) + (+ (+ (shl s1-0 2) (shl s3-0 4)) (the-as int arg1)) + ) + ) + ) + (f30-0 (sqrtf (+ f0-2 (* f1-0 f1-0)))) + ) + (cond + ((< 0.00001 f30-0) + (set! + (-> arg0 data 0) + (atan + (-> + (the-as + (pointer float) + (+ (+ (shl s2-0 2) (shl s3-0 4)) (the-as int arg1)) + ) + ) + (-> + (the-as + (pointer float) + (+ (+ (shl s1-0 2) (shl s3-0 4)) (the-as int arg1)) + ) + ) + ) + ) + (set! + (-> arg0 data 1) + (atan + f30-0 + (-> + (the-as + (pointer float) + (+ (+ (shl s3-0 2) (shl s3-0 4)) (the-as int arg1)) + ) + ) + ) + ) + (let + ((f0-13 + (atan + (-> + (the-as + (pointer float) + (+ (+ (shl s3-0 2) (shl s2-0 4)) (the-as int arg1)) + ) + ) + (- + (-> + (the-as + (pointer float) + (+ (+ (shl s3-0 2) (shl s1-0 4)) (the-as int arg1)) + ) + ) + ) + ) + ) + ) + (set! (-> arg0 data 2) f0-13) + ) + ) + (else + (set! + (-> arg0 data 0) + (atan + (- + (-> + (the-as + (pointer float) + (+ (+ (shl s1-0 2) (shl s2-0 4)) (the-as int arg1)) + ) + ) + ) + (-> + (the-as + (pointer float) + (+ (+ (shl s2-0 2) (shl s2-0 4)) (the-as int arg1)) + ) + ) + ) + ) + (set! + (-> arg0 data 1) + (atan + f30-0 + (-> + (the-as + (pointer float) + (+ (+ (shl s3-0 2) (shl s3-0 4)) (the-as int arg1)) + ) + ) + ) + ) + (let ((f0-20 0.0)) + (set! (-> arg0 data 2) f0-20) + ) + ) + ) + ) + (let* + ((f0-21 + (-> + (the-as + (pointer float) + (+ (+ (shl s3-0 2) (shl s3-0 4)) (the-as int arg1)) + ) + ) + ) + (f0-23 (* f0-21 f0-21)) + (f1-3 + (-> + (the-as + (pointer float) + (+ (+ (shl s3-0 2) (shl s2-0 4)) (the-as int arg1)) + ) + ) + ) + (f30-1 (sqrtf (+ f0-23 (* f1-3 f1-3)))) + ) + (cond + ((< 0.00001 f30-1) + (set! + (-> arg0 data 0) + (atan + (-> + (the-as + (pointer float) + (+ (+ (shl s2-0 2) (shl s1-0 4)) (the-as int arg1)) + ) + ) + (-> + (the-as + (pointer float) + (+ (+ (shl s1-0 2) (shl s1-0 4)) (the-as int arg1)) + ) + ) + ) + ) + (set! + (-> arg0 data 1) + (atan + (- + (-> + (the-as + (pointer float) + (+ (+ (shl s3-0 2) (shl s1-0 4)) (the-as int arg1)) + ) + ) + ) + f30-1 + ) + ) + (let + ((f0-34 + (atan + (-> + (the-as + (pointer float) + (+ (+ (shl s3-0 2) (shl s2-0 4)) (the-as int arg1)) + ) + ) + (-> + (the-as + (pointer float) + (+ (+ (shl s3-0 2) (shl s3-0 4)) (the-as int arg1)) + ) + ) + ) + ) + ) + (set! (-> arg0 data 2) f0-34) + ) + ) + (else + (set! + (-> arg0 data 0) + (atan + (- + (-> + (the-as + (pointer float) + (+ (+ (shl s1-0 2) (shl s2-0 4)) (the-as int arg1)) + ) + ) + ) + (-> + (the-as + (pointer float) + (+ (+ (shl s2-0 2) (shl s2-0 4)) (the-as int arg1)) + ) + ) + ) + ) + (set! + (-> arg0 data 1) + (atan + (- + (-> + (the-as + (pointer float) + (+ (+ (shl s3-0 2) (shl s1-0 4)) (the-as int arg1)) + ) + ) + ) + f30-1 + ) + ) + (let ((f0-42 0.0)) + (set! (-> arg0 data 2) f0-42) + ) + ) + ) + ) + ) + ) + (when (= (logand (sar arg2 2) 1) 1) + (set! (-> arg0 data 0) (- (-> arg0 data 0))) + (set! (-> arg0 data 1) (- (-> arg0 data 1))) + (let ((f0-48 (- (-> arg0 data 2)))) + (set! (-> arg0 data 2) f0-48) + ) + ) + (if (= (logand arg2 1) 1) + (let ((f0-49 (-> arg0 data 0))) + (set! (-> arg0 data 0) (-> arg0 data 2)) + (set! (-> arg0 data 2) f0-49) + ) + ) + (set! (-> arg0 data 3) (the float arg2)) + arg0 + ) + +;; definition for function eul->quat +(defun eul->quat ((arg0 quaternion) (arg1 euler-angles)) + (let ((s5-0 (new 'stack 'matrix))) + (eul->matrix s5-0 arg1) + (matrix->quaternion arg0 s5-0) + ) + arg0 + ) + +;; definition for function quat->eul +(defun quat->eul ((arg0 euler-angles) (arg1 quaternion) (arg2 int)) + (let ((s5-0 (new 'stack 'matrix))) + (quaternion->matrix s5-0 arg1) + (matrix->eul arg0 s5-0 arg2) + ) + arg0 + ) + +;; failed to figure out what this is: +(none) + + + + diff --git a/test/decompiler/reference/gcommon_REF.gc b/test/decompiler/reference/gcommon_REF.gc index 63cc696230..883ce8dbbf 100644 --- a/test/decompiler/reference/gcommon_REF.gc +++ b/test/decompiler/reference/gcommon_REF.gc @@ -816,7 +816,7 @@ #t "~T [~D] #x~X~%" s5-8 - (-> (the-as (pointer uint128) (+ (shl s5-8 4) (the-as int obj)))) + (-> (the-as (array uint128) obj) s5-8) ) ) ) diff --git a/test/decompiler/reference/gkernel-h_REF.gc b/test/decompiler/reference/gkernel-h_REF.gc index 11b2ac03c4..7c215a264c 100644 --- a/test/decompiler/reference/gkernel-h_REF.gc +++ b/test/decompiler/reference/gkernel-h_REF.gc @@ -279,8 +279,8 @@ ;; definition for method 3 of type handle (defmethod inspect handle ((obj handle)) (format #t "[~8x] ~A~%" obj 'handle) - (format #t "~Tprocess: #x~X~%" (shr (shl (the-as int obj) 32) 32)) - (format #t "~Tpid: ~D~%" (sar (the-as int obj) 32)) + (format #t "~Tprocess: #x~X~%" (-> obj process)) + (format #t "~Tpid: ~D~%" (-> obj pid)) obj ) @@ -295,17 +295,17 @@ (a1-0 "#") (v1-0 obj) ) - (.subu a2-0 (the-as handle v1-0) s7-0) + (.subu a2-0 v1-0 s7-0) (t9-0 a0-1 a1-0 (and (nonzero? a2-0) (begin - (.sllv a2-2 (the-as handle v1-0) r0-0) + (.sllv a2-2 v1-0 r0-0) (let ((a3-0 (-> a2-2 0))) - (if (= (sar v1-0 32) (-> a3-0 pid)) + (if (= (-> v1-0 pid) (-> a3-0 pid)) a3-0 ) ) ) ) - (sar (the-as int obj) 32) + (-> obj pid) ) ) (format #t "#") diff --git a/test/decompiler/reference/gsound-h_REF.gc b/test/decompiler/reference/gsound-h_REF.gc new file mode 100644 index 0000000000..21328036d8 --- /dev/null +++ b/test/decompiler/reference/gsound-h_REF.gc @@ -0,0 +1,796 @@ +;;-*-Lisp-*- +(in-package goal) + +;; definition of type sound-id +(deftype sound-id (uint32) + () + :method-count-assert 10 + :size-assert #x4 + :flag-assert #xa00000004 + (:methods + (dummy-9 () none 9) + ) + ) + +;; definition of type sound-bank-id +(deftype sound-bank-id (uint32) + () + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ) + +;; definition of type sound-name +(deftype sound-name (uint128) + () + :method-count-assert 9 + :size-assert #x10 + :flag-assert #x900000010 + ) + +;; definition of type sound-rpc-cmd +(deftype sound-rpc-cmd (structure) + ((rsvd1 uint16 :offset-assert 0) + (command uint16 :offset-assert 2) + ) + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ) + +;; definition for method 3 of type sound-rpc-cmd +(defmethod inspect sound-rpc-cmd ((obj sound-rpc-cmd)) + (format #t "[~8x] ~A~%" obj 'sound-rpc-cmd) + (format #t "~Trsvd1: ~D~%" (-> obj rsvd1)) + (format #t "~Tcommand: ~D~%" (-> obj command)) + obj + ) + +;; definition of type sound-play-parms +(deftype sound-play-parms (structure) + ((mask uint16 :offset-assert 0) + (pitch-mod int16 :offset-assert 2) + (bend int16 :offset-assert 4) + (fo-min int16 :offset-assert 6) + (fo-max int16 :offset-assert 8) + (fo-curve int8 :offset-assert 10) + (priority int8 :offset-assert 11) + (volume int32 :offset-assert 12) + (trans float 3 :offset-assert 16) + (group uint8 :offset-assert 28) + ) + :pack-me + :method-count-assert 9 + :size-assert #x1d + :flag-assert #x90000001d + ) + +;; definition for method 3 of type sound-play-parms +(defmethod inspect sound-play-parms ((obj sound-play-parms)) + (format #t "[~8x] ~A~%" obj 'sound-play-parms) + (format #t "~Tmask: ~D~%" (-> obj mask)) + (format #t "~Tpitch-mod: ~D~%" (-> obj pitch-mod)) + (format #t "~Tbend: ~D~%" (-> obj bend)) + (format #t "~Tfo-min: ~D~%" (-> obj fo-min)) + (format #t "~Tfo-max: ~D~%" (-> obj fo-max)) + (format #t "~Tfo-curve: ~D~%" (-> obj fo-curve)) + (format #t "~Tpriority: ~D~%" (-> obj priority)) + (format #t "~Tvolume: ~D~%" (-> obj volume)) + (format #t "~Ttrans[3] @ #x~X~%" (-> obj trans)) + (format #t "~Tgroup: ~D~%" (-> obj group)) + obj + ) + +;; definition of type sound-rpc-bank-cmd +(deftype sound-rpc-bank-cmd (sound-rpc-cmd) + ((bank-name uint128 :offset-assert 16) + ) + :method-count-assert 9 + :size-assert #x20 + :flag-assert #x900000020 + ) + +;; definition for method 3 of type sound-rpc-bank-cmd +;; Used lq/sq +(defmethod inspect sound-rpc-bank-cmd ((obj sound-rpc-bank-cmd)) + (format #t "[~8x] ~A~%" obj 'sound-rpc-bank-cmd) + (format #t "~Trsvd1: ~D~%" (-> obj rsvd1)) + (format #t "~Tcommand: ~D~%" (-> obj command)) + (format #t "~Tbank-name: ~D~%" (-> obj bank-name)) + obj + ) + +;; definition of type sound-rpc-sound-cmd +(deftype sound-rpc-sound-cmd (sound-rpc-cmd) + ((id uint32 :offset-assert 4) + ) + :method-count-assert 9 + :size-assert #x8 + :flag-assert #x900000008 + ) + +;; definition for method 3 of type sound-rpc-sound-cmd +(defmethod inspect sound-rpc-sound-cmd ((obj sound-rpc-sound-cmd)) + (format #t "[~8x] ~A~%" obj 'sound-rpc-sound-cmd) + (format #t "~Trsvd1: ~D~%" (-> obj rsvd1)) + (format #t "~Tcommand: ~D~%" (-> obj command)) + (format #t "~Tid: ~D~%" (-> obj id)) + obj + ) + +;; definition of type sound-rpc-group-cmd +(deftype sound-rpc-group-cmd (sound-rpc-cmd) + ((group uint8 :offset-assert 4) + ) + :method-count-assert 9 + :size-assert #x5 + :flag-assert #x900000005 + ) + +;; definition for method 3 of type sound-rpc-group-cmd +(defmethod inspect sound-rpc-group-cmd ((obj sound-rpc-group-cmd)) + (format #t "[~8x] ~A~%" obj 'sound-rpc-group-cmd) + (format #t "~Trsvd1: ~D~%" (-> obj rsvd1)) + (format #t "~Tcommand: ~D~%" (-> obj command)) + (format #t "~Tgroup: ~D~%" (-> obj group)) + obj + ) + +;; definition of type sound-rpc-load-bank +(deftype sound-rpc-load-bank (sound-rpc-bank-cmd) + () + :method-count-assert 9 + :size-assert #x20 + :flag-assert #x900000020 + ) + +;; definition for method 3 of type sound-rpc-load-bank +;; Used lq/sq +(defmethod inspect sound-rpc-load-bank ((obj sound-rpc-load-bank)) + (format #t "[~8x] ~A~%" obj 'sound-rpc-load-bank) + (format #t "~Trsvd1: ~D~%" (-> obj rsvd1)) + (format #t "~Tcommand: ~D~%" (-> obj command)) + (format #t "~Tbank-name: ~D~%" (-> obj bank-name)) + obj + ) + +;; definition of type sound-rpc-load-music +(deftype sound-rpc-load-music (sound-rpc-bank-cmd) + () + :method-count-assert 9 + :size-assert #x20 + :flag-assert #x900000020 + ) + +;; definition for method 3 of type sound-rpc-load-music +;; Used lq/sq +(defmethod inspect sound-rpc-load-music ((obj sound-rpc-load-music)) + (format #t "[~8x] ~A~%" obj 'sound-rpc-load-music) + (format #t "~Trsvd1: ~D~%" (-> obj rsvd1)) + (format #t "~Tcommand: ~D~%" (-> obj command)) + (format #t "~Tbank-name: ~D~%" (-> obj bank-name)) + obj + ) + +;; definition of type sound-rpc-unload-bank +(deftype sound-rpc-unload-bank (sound-rpc-bank-cmd) + () + :method-count-assert 9 + :size-assert #x20 + :flag-assert #x900000020 + ) + +;; definition for method 3 of type sound-rpc-unload-bank +;; Used lq/sq +(defmethod inspect sound-rpc-unload-bank ((obj sound-rpc-unload-bank)) + (format #t "[~8x] ~A~%" obj 'sound-rpc-unload-bank) + (format #t "~Trsvd1: ~D~%" (-> obj rsvd1)) + (format #t "~Tcommand: ~D~%" (-> obj command)) + (format #t "~Tbank-name: ~D~%" (-> obj bank-name)) + obj + ) + +;; definition of type sound-rpc-play +(deftype sound-rpc-play (sound-rpc-sound-cmd) + ((name uint128 :offset-assert 16) + (parms sound-play-parms :inline :offset-assert 32) + ) + :method-count-assert 9 + :size-assert #x3d + :flag-assert #x90000003d + ) + +;; definition for method 3 of type sound-rpc-play +;; Used lq/sq +(defmethod inspect sound-rpc-play ((obj sound-rpc-play)) + (format #t "[~8x] ~A~%" obj 'sound-rpc-play) + (format #t "~Trsvd1: ~D~%" (-> obj rsvd1)) + (format #t "~Tcommand: ~D~%" (-> obj command)) + (format #t "~Tid: ~D~%" (-> obj id)) + (format #t "~Tname: ~D~%" (-> obj name)) + (format #t "~Tparms: #~%" (-> obj parms)) + obj + ) + +;; definition of type sound-rpc-pause-sound +(deftype sound-rpc-pause-sound (sound-rpc-sound-cmd) + () + :method-count-assert 9 + :size-assert #x8 + :flag-assert #x900000008 + ) + +;; definition for method 3 of type sound-rpc-pause-sound +(defmethod inspect sound-rpc-pause-sound ((obj sound-rpc-pause-sound)) + (format #t "[~8x] ~A~%" obj 'sound-rpc-pause-sound) + (format #t "~Trsvd1: ~D~%" (-> obj rsvd1)) + (format #t "~Tcommand: ~D~%" (-> obj command)) + (format #t "~Tid: ~D~%" (-> obj id)) + obj + ) + +;; definition of type sound-rpc-stop-sound +(deftype sound-rpc-stop-sound (sound-rpc-sound-cmd) + () + :method-count-assert 9 + :size-assert #x8 + :flag-assert #x900000008 + ) + +;; definition for method 3 of type sound-rpc-stop-sound +(defmethod inspect sound-rpc-stop-sound ((obj sound-rpc-stop-sound)) + (format #t "[~8x] ~A~%" obj 'sound-rpc-stop-sound) + (format #t "~Trsvd1: ~D~%" (-> obj rsvd1)) + (format #t "~Tcommand: ~D~%" (-> obj command)) + (format #t "~Tid: ~D~%" (-> obj id)) + obj + ) + +;; definition of type sound-rpc-continue-sound +(deftype sound-rpc-continue-sound (sound-rpc-sound-cmd) + () + :method-count-assert 9 + :size-assert #x8 + :flag-assert #x900000008 + ) + +;; definition for method 3 of type sound-rpc-continue-sound +(defmethod inspect sound-rpc-continue-sound ((obj sound-rpc-continue-sound)) + (format #t "[~8x] ~A~%" obj 'sound-rpc-continue-sound) + (format #t "~Trsvd1: ~D~%" (-> obj rsvd1)) + (format #t "~Tcommand: ~D~%" (-> obj command)) + (format #t "~Tid: ~D~%" (-> obj id)) + obj + ) + +;; definition of type sound-rpc-set-param +(deftype sound-rpc-set-param (sound-rpc-sound-cmd) + ((parms sound-play-parms :inline :offset-assert 8) + (auto-time int32 :offset-assert 40) + (auto-from int32 :offset-assert 44) + ) + :method-count-assert 9 + :size-assert #x30 + :flag-assert #x900000030 + ) + +;; definition for method 3 of type sound-rpc-set-param +(defmethod inspect sound-rpc-set-param ((obj sound-rpc-set-param)) + (format #t "[~8x] ~A~%" obj 'sound-rpc-set-param) + (format #t "~Trsvd1: ~D~%" (-> obj rsvd1)) + (format #t "~Tcommand: ~D~%" (-> obj command)) + (format #t "~Tid: ~D~%" (-> obj id)) + (format #t "~Tparms: #~%" (-> obj parms)) + (format #t "~Tauto-time: ~D~%" (-> obj auto-time)) + (format #t "~Tauto-from: ~D~%" (-> obj auto-from)) + obj + ) + +;; definition of type sound-rpc-set-master-volume +(deftype sound-rpc-set-master-volume (sound-rpc-group-cmd) + ((volume int32 :offset-assert 8) + ) + :method-count-assert 9 + :size-assert #xc + :flag-assert #x90000000c + ) + +;; definition for method 3 of type sound-rpc-set-master-volume +(defmethod + inspect + sound-rpc-set-master-volume + ((obj sound-rpc-set-master-volume)) + (format #t "[~8x] ~A~%" obj 'sound-rpc-set-master-volume) + (format #t "~Trsvd1: ~D~%" (-> obj rsvd1)) + (format #t "~Tcommand: ~D~%" (-> obj command)) + (format #t "~Tgroup: ~D~%" (-> obj group)) + (format #t "~Tvolume: ~D~%" (-> obj volume)) + obj + ) + +;; definition of type sound-rpc-pause-group +(deftype sound-rpc-pause-group (sound-rpc-group-cmd) + () + :method-count-assert 9 + :size-assert #x5 + :flag-assert #x900000005 + ) + +;; definition for method 3 of type sound-rpc-pause-group +(defmethod inspect sound-rpc-pause-group ((obj sound-rpc-pause-group)) + (format #t "[~8x] ~A~%" obj 'sound-rpc-pause-group) + (format #t "~Trsvd1: ~D~%" (-> obj rsvd1)) + (format #t "~Tcommand: ~D~%" (-> obj command)) + (format #t "~Tgroup: ~D~%" (-> obj group)) + obj + ) + +;; definition of type sound-rpc-stop-group +(deftype sound-rpc-stop-group (sound-rpc-group-cmd) + () + :method-count-assert 9 + :size-assert #x5 + :flag-assert #x900000005 + ) + +;; definition for method 3 of type sound-rpc-stop-group +(defmethod inspect sound-rpc-stop-group ((obj sound-rpc-stop-group)) + (format #t "[~8x] ~A~%" obj 'sound-rpc-stop-group) + (format #t "~Trsvd1: ~D~%" (-> obj rsvd1)) + (format #t "~Tcommand: ~D~%" (-> obj command)) + (format #t "~Tgroup: ~D~%" (-> obj group)) + obj + ) + +;; definition of type sound-rpc-continue-group +(deftype sound-rpc-continue-group (sound-rpc-group-cmd) + () + :method-count-assert 9 + :size-assert #x5 + :flag-assert #x900000005 + ) + +;; definition for method 3 of type sound-rpc-continue-group +(defmethod inspect sound-rpc-continue-group ((obj sound-rpc-continue-group)) + (format #t "[~8x] ~A~%" obj 'sound-rpc-continue-group) + (format #t "~Trsvd1: ~D~%" (-> obj rsvd1)) + (format #t "~Tcommand: ~D~%" (-> obj command)) + (format #t "~Tgroup: ~D~%" (-> obj group)) + obj + ) + +;; definition of type sound-rpc-get-irx-version +(deftype sound-rpc-get-irx-version (sound-rpc-cmd) + ((major uint32 :offset-assert 4) + (minor uint32 :offset-assert 8) + (ee-addr uint32 :offset-assert 12) + ) + :method-count-assert 9 + :size-assert #x10 + :flag-assert #x900000010 + ) + +;; definition for method 3 of type sound-rpc-get-irx-version +(defmethod inspect sound-rpc-get-irx-version ((obj sound-rpc-get-irx-version)) + (format #t "[~8x] ~A~%" obj 'sound-rpc-get-irx-version) + (format #t "~Trsvd1: ~D~%" (-> obj rsvd1)) + (format #t "~Tcommand: ~D~%" (-> obj command)) + (format #t "~Tmajor: ~D~%" (-> obj major)) + (format #t "~Tminor: ~D~%" (-> obj minor)) + (format #t "~Tee-addr: ~D~%" (-> obj ee-addr)) + obj + ) + +;; definition of type sound-rpc-set-language +(deftype sound-rpc-set-language (sound-rpc-cmd) + ((lang uint32 :offset-assert 4) + ) + :method-count-assert 9 + :size-assert #x8 + :flag-assert #x900000008 + ) + +;; definition for method 3 of type sound-rpc-set-language +(defmethod inspect sound-rpc-set-language ((obj sound-rpc-set-language)) + (format #t "[~8x] ~A~%" obj 'sound-rpc-set-language) + (format #t "~Trsvd1: ~D~%" (-> obj rsvd1)) + (format #t "~Tcommand: ~D~%" (-> obj command)) + (format #t "~Tlang: ~D~%" (-> obj lang)) + obj + ) + +;; definition of type sound-rpc-set-falloff-curve +(deftype sound-rpc-set-falloff-curve (sound-rpc-cmd) + ((curve int32 :offset-assert 4) + (falloff int32 :offset-assert 8) + (ease int32 :offset-assert 12) + ) + :method-count-assert 9 + :size-assert #x10 + :flag-assert #x900000010 + ) + +;; definition for method 3 of type sound-rpc-set-falloff-curve +(defmethod + inspect + sound-rpc-set-falloff-curve + ((obj sound-rpc-set-falloff-curve)) + (format #t "[~8x] ~A~%" obj 'sound-rpc-set-falloff-curve) + (format #t "~Trsvd1: ~D~%" (-> obj rsvd1)) + (format #t "~Tcommand: ~D~%" (-> obj command)) + (format #t "~Tcurve: ~D~%" (-> obj curve)) + (format #t "~Tfalloff: ~D~%" (-> obj falloff)) + (format #t "~Tease: ~D~%" (-> obj ease)) + obj + ) + +;; definition of type sound-rpc-set-sound-falloff +(deftype sound-rpc-set-sound-falloff (sound-rpc-cmd) + ((name uint128 :offset-assert 16) + (curve int32 :offset-assert 32) + (min int32 :offset-assert 36) + (max int32 :offset-assert 40) + ) + :method-count-assert 9 + :size-assert #x2c + :flag-assert #x90000002c + ) + +;; definition for method 3 of type sound-rpc-set-sound-falloff +;; Used lq/sq +(defmethod + inspect + sound-rpc-set-sound-falloff + ((obj sound-rpc-set-sound-falloff)) + (format #t "[~8x] ~A~%" obj 'sound-rpc-set-sound-falloff) + (format #t "~Trsvd1: ~D~%" (-> obj rsvd1)) + (format #t "~Tcommand: ~D~%" (-> obj command)) + (format #t "~Tname: ~D~%" (-> obj name)) + (format #t "~Tcurve: ~D~%" (-> obj curve)) + (format #t "~Tmin: ~D~%" (-> obj min)) + (format #t "~Tmax: ~D~%" (-> obj max)) + obj + ) + +;; definition of type sound-rpc-reload-info +(deftype sound-rpc-reload-info (sound-rpc-cmd) + () + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ) + +;; definition for method 3 of type sound-rpc-reload-info +(defmethod inspect sound-rpc-reload-info ((obj sound-rpc-reload-info)) + (format #t "[~8x] ~A~%" obj 'sound-rpc-reload-info) + (format #t "~Trsvd1: ~D~%" (-> obj rsvd1)) + (format #t "~Tcommand: ~D~%" (-> obj command)) + obj + ) + +;; definition of type sound-rpc-set-reverb +(deftype sound-rpc-set-reverb (sound-rpc-cmd) + ((core uint8 :offset-assert 4) + (reverb int32 :offset-assert 8) + (left uint32 :offset-assert 12) + (right uint32 :offset-assert 16) + ) + :method-count-assert 9 + :size-assert #x14 + :flag-assert #x900000014 + ) + +;; definition for method 3 of type sound-rpc-set-reverb +(defmethod inspect sound-rpc-set-reverb ((obj sound-rpc-set-reverb)) + (format #t "[~8x] ~A~%" obj 'sound-rpc-set-reverb) + (format #t "~Trsvd1: ~D~%" (-> obj rsvd1)) + (format #t "~Tcommand: ~D~%" (-> obj command)) + (format #t "~Tcore: ~D~%" (-> obj core)) + (format #t "~Treverb: ~D~%" (-> obj reverb)) + (format #t "~Tleft: ~D~%" (-> obj left)) + (format #t "~Tright: ~D~%" (-> obj right)) + obj + ) + +;; definition of type sound-rpc-set-ear-trans +(deftype sound-rpc-set-ear-trans (sound-rpc-cmd) + ((ear-trans float 3 :offset-assert 4) + (cam-trans float 3 :offset-assert 16) + (cam-angle int32 :offset-assert 28) + ) + :method-count-assert 9 + :size-assert #x20 + :flag-assert #x900000020 + ) + +;; definition for method 3 of type sound-rpc-set-ear-trans +(defmethod inspect sound-rpc-set-ear-trans ((obj sound-rpc-set-ear-trans)) + (format #t "[~8x] ~A~%" obj 'sound-rpc-set-ear-trans) + (format #t "~Trsvd1: ~D~%" (-> obj rsvd1)) + (format #t "~Tcommand: ~D~%" (-> obj command)) + (format #t "~Tear-trans[3] @ #x~X~%" (-> obj ear-trans)) + (format #t "~Tcam-trans[3] @ #x~X~%" (-> obj cam-trans)) + (format #t "~Tcam-angle: ~D~%" (-> obj cam-angle)) + obj + ) + +;; definition of type sound-rpc-set-flava +(deftype sound-rpc-set-flava (sound-rpc-cmd) + ((flava uint8 :offset-assert 4) + ) + :method-count-assert 9 + :size-assert #x5 + :flag-assert #x900000005 + ) + +;; definition for method 3 of type sound-rpc-set-flava +(defmethod inspect sound-rpc-set-flava ((obj sound-rpc-set-flava)) + (format #t "[~8x] ~A~%" obj 'sound-rpc-set-flava) + (format #t "~Trsvd1: ~D~%" (-> obj rsvd1)) + (format #t "~Tcommand: ~D~%" (-> obj command)) + (format #t "~Tflava: ~D~%" (-> obj flava)) + obj + ) + +;; definition of type sound-rpc-shutdown +(deftype sound-rpc-shutdown (sound-rpc-cmd) + () + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ) + +;; definition for method 3 of type sound-rpc-shutdown +(defmethod inspect sound-rpc-shutdown ((obj sound-rpc-shutdown)) + (format #t "[~8x] ~A~%" obj 'sound-rpc-shutdown) + (format #t "~Trsvd1: ~D~%" (-> obj rsvd1)) + (format #t "~Tcommand: ~D~%" (-> obj command)) + obj + ) + +;; definition of type sound-rpc-list-sounds +(deftype sound-rpc-list-sounds (sound-rpc-cmd) + () + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ) + +;; definition for method 3 of type sound-rpc-list-sounds +(defmethod inspect sound-rpc-list-sounds ((obj sound-rpc-list-sounds)) + (format #t "[~8x] ~A~%" obj 'sound-rpc-list-sounds) + (format #t "~Trsvd1: ~D~%" (-> obj rsvd1)) + (format #t "~Tcommand: ~D~%" (-> obj command)) + obj + ) + +;; definition of type sound-rpc-unload-music +(deftype sound-rpc-unload-music (sound-rpc-cmd) + () + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ) + +;; definition for method 3 of type sound-rpc-unload-music +(defmethod inspect sound-rpc-unload-music ((obj sound-rpc-unload-music)) + (format #t "[~8x] ~A~%" obj 'sound-rpc-unload-music) + (format #t "~Trsvd1: ~D~%" (-> obj rsvd1)) + (format #t "~Tcommand: ~D~%" (-> obj command)) + obj + ) + +;; definition of type sound-rpc-union +(deftype sound-rpc-union (structure) + ((data uint32 20 :offset-assert 0) + (load-bank sound-rpc-load-bank :offset 0) + (unload-bank sound-rpc-unload-bank :offset 0) + (play sound-rpc-play :offset 0) + (pause-sound sound-rpc-pause-sound :offset 0) + (stop-sound sound-rpc-stop-sound :offset 0) + (continue-sound sound-rpc-continue-sound :offset 0) + (set-param sound-rpc-set-param :offset 0) + (set-master-volume sound-rpc-set-master-volume :offset 0) + (pause-group sound-rpc-pause-group :offset 0) + (stop-group sound-rpc-stop-group :offset 0) + (continue-group sound-rpc-continue-group :offset 0) + (get-irx-version sound-rpc-get-irx-version :offset 0) + (set-falloff-curve sound-rpc-set-falloff-curve :offset 0) + (set-sound-falloff sound-rpc-set-sound-falloff :offset 0) + (reload-info sound-rpc-reload-info :offset 0) + (set-language sound-rpc-set-language :offset 0) + (set-reverb sound-rpc-set-reverb :offset 0) + (set-ear-trans sound-rpc-set-ear-trans :offset 0) + (set-flava sound-rpc-set-flava :offset 0) + (shutdown sound-rpc-shutdown :offset 0) + (list-sounds sound-rpc-list-sounds :offset 0) + (unload-music sound-rpc-unload-music :offset 0) + ) + :method-count-assert 9 + :size-assert #x50 + :flag-assert #x900000050 + ) + +;; definition for method 3 of type sound-rpc-union +(defmethod inspect sound-rpc-union ((obj sound-rpc-union)) + (format #t "[~8x] ~A~%" obj 'sound-rpc-union) + (format #t "~Tdata[20] @ #x~X~%" (-> obj data)) + (format #t "~Tload-bank: #~%" (-> obj data 0)) + (format #t "~Tunload-bank: #~%" (-> obj data 0)) + (format #t "~Tplay: #~%" (-> obj data 0)) + (format #t "~Tpause-sound: #~%" (-> obj data 0)) + (format #t "~Tstop-sound: #~%" (-> obj data 0)) + (format + #t + "~Tcontinue-sound: #~%" + (-> obj data 0) + ) + (format #t "~Tset-param: #~%" (-> obj data 0)) + (format + #t + "~Tset-master-volume: #~%" + (-> obj data 0) + ) + (format #t "~Tpause-group: #~%" (-> obj data 0)) + (format #t "~Tstop-group: #~%" (-> obj data 0)) + (format + #t + "~Tcontinue-group: #~%" + (-> obj data 0) + ) + (format + #t + "~Tget-irx-version: #~%" + (-> obj data 0) + ) + (format + #t + "~Tset-falloff-curve: #~%" + (-> obj data 0) + ) + (format + #t + "~Tset-sound-falloff: #~%" + (-> obj data 0) + ) + (format #t "~Treload-info: #~%" (-> obj data 0)) + (format + #t + "~Tset-language: #~%" + (-> obj data 0) + ) + (format #t "~Tset-reverb: #~%" (-> obj data 0)) + (format + #t + "~Tset-ear-trans: #~%" + (-> obj data 0) + ) + (format #t "~Tset-flava: #~%" (-> obj data 0)) + (format #t "~Tshutdown: #~%" (-> obj data 0)) + (format #t "~Tlist-sounds: #~%" (-> obj data 0)) + (format + #t + "~Tunload-music: #~%" + (-> obj data 0) + ) + obj + ) + +;; definition of type sound-spec +(deftype sound-spec (basic) + ((mask uint16 :offset-assert 4) + (num float :offset-assert 8) + (group uint8 :offset-assert 12) + (sound-name-char uint8 16 :offset 16) + (sound-name uint128 :offset 16) + (trans float 4 :offset-assert 32) + (volume int32 :offset-assert 48) + (pitch-mod int32 :offset-assert 52) + (bend int32 :offset-assert 56) + (fo-min int16 :offset-assert 60) + (fo-max int16 :offset-assert 62) + (fo-curve int8 :offset-assert 64) + (priority int8 :offset-assert 65) + (auto-time int32 :offset-assert 68) + (auto-from int32 :offset-assert 72) + ) + :method-count-assert 9 + :size-assert #x4c + :flag-assert #x90000004c + ) + +;; definition for method 3 of type sound-spec +;; Used lq/sq +(defmethod inspect sound-spec ((obj sound-spec)) + (format #t "[~8x] ~A~%" obj (-> obj type)) + (format #t "~Tmask: ~D~%" (-> obj mask)) + (format #t "~Tnum: ~f~%" (-> obj num)) + (format #t "~Tgroup: ~D~%" (-> obj group)) + (format #t "~Tsound-name-char[16] @ #x~X~%" (-> obj sound-name-char)) + (format #t "~Tsound-name: ~D~%" (-> obj sound-name)) + (format #t "~Ttrans[4] @ #x~X~%" (-> obj trans)) + (format #t "~Tvolume: ~D~%" (-> obj volume)) + (format #t "~Tpitch-mod: ~D~%" (-> obj pitch-mod)) + (format #t "~Tbend: ~D~%" (-> obj bend)) + (format #t "~Tfo-min: ~D~%" (-> obj fo-min)) + (format #t "~Tfo-max: ~D~%" (-> obj fo-max)) + (format #t "~Tfo-curve: ~D~%" (-> obj fo-curve)) + (format #t "~Tpriority: ~D~%" (-> obj priority)) + (format #t "~Tauto-time: ~D~%" (-> obj auto-time)) + (format #t "~Tauto-from: ~D~%" (-> obj auto-from)) + obj + ) + +;; definition for symbol *current-sound-id*, type sound-id +(define *current-sound-id* (the-as sound-id #x10000)) + +;; definition of type ambient-sound +(deftype ambient-sound (basic) + ((spec basic :offset-assert 4) + (playing-id uint32 :offset-assert 8) + (trans vector :inline :offset-assert 16) + (name uint128 :offset-assert 32) + (play-time uint64 :offset-assert 48) + (time-base uint64 :offset-assert 56) + (time-random uint64 :offset-assert 64) + (volume int32 :offset-assert 72) + (pitch int32 :offset-assert 76) + (falloff-near int32 :offset-assert 80) + (falloff-far int32 :offset-assert 84) + (falloff-mode int32 :offset-assert 88) + (params uint32 :offset-assert 92) + (param-count int32 :offset-assert 96) + (entity basic :offset-assert 100) + (sound-count int32 :offset-assert 104) + ) + :method-count-assert 14 + :size-assert #x6c + :flag-assert #xe0000006c + (:methods + (dummy-9 () none 9) + (dummy-10 () none 10) + (dummy-11 () none 11) + (dummy-12 () none 12) + (dummy-13 () none 13) + ) + ) + +;; definition for method 3 of type ambient-sound +;; Used lq/sq +(defmethod inspect ambient-sound ((obj ambient-sound)) + (format #t "[~8x] ~A~%" obj (-> obj type)) + (format #t "~Tspec: ~A~%" (-> obj spec)) + (format #t "~Tplaying-id: ~D~%" (-> obj playing-id)) + (format #t "~Ttrans: ~`vector`P~%" (-> obj trans)) + (format #t "~Tname: ~D~%" (-> obj name)) + (format #t "~Tplay-time: ~D~%" (-> obj play-time)) + (format #t "~Ttime-base: ~D~%" (-> obj time-base)) + (format #t "~Ttime-random: ~D~%" (-> obj time-random)) + (format #t "~Tvolume: ~D~%" (-> obj volume)) + (format #t "~Tpitch: ~D~%" (-> obj pitch)) + (format #t "~Tfalloff-near: ~D~%" (-> obj falloff-near)) + (format #t "~Tfalloff-far: ~D~%" (-> obj falloff-far)) + (format #t "~Tfalloff-mode: ~D~%" (-> obj falloff-mode)) + (format #t "~Tparams: #x~X~%" (-> obj params)) + (format #t "~Tparam-count: ~D~%" (-> obj param-count)) + (format #t "~Tentity: ~A~%" (-> obj entity)) + (format #t "~Tsound-count: ~D~%" (-> obj sound-count)) + obj + ) + +;; definition for symbol *sound-bank-1*, type symbol +(define *sound-bank-1* #f) + +;; definition for symbol *sound-bank-2*, type symbol +(define *sound-bank-2* #f) + +;; failed to figure out what this is: +(let ((v0-34 0)) + ) + +;; failed to figure out what this is: +(none) + + + + diff --git a/test/decompiler/reference/timer-h_REF.gc b/test/decompiler/reference/timer-h_REF.gc new file mode 100644 index 0000000000..4a80fac698 --- /dev/null +++ b/test/decompiler/reference/timer-h_REF.gc @@ -0,0 +1,175 @@ +;;-*-Lisp-*- +(in-package goal) + +;; definition of type timer-mode +(deftype timer-mode (uint32) + ((clks uint8 :offset 0 :size 2) + (gate uint8 :offset 2 :size 1) + (gats uint8 :offset 3 :size 1) + (gatm uint8 :offset 4 :size 2) + (zret uint8 :offset 6 :size 1) + (cue uint8 :offset 7 :size 1) + (cmpe uint8 :offset 8 :size 1) + (ovfe uint8 :offset 9 :size 1) + (equf uint8 :offset 10 :size 1) + (ovff uint8 :offset 11 :size 1) + ) + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ) + +;; definition of type timer-bank +(deftype timer-bank (structure) + ((count uint32 :offset-assert 0) + (mode timer-mode :offset 16) + (comp uint32 :offset 32) + ) + :method-count-assert 9 + :size-assert #x24 + :flag-assert #x900000024 + ) + +;; definition for method 3 of type timer-bank +(defmethod inspect timer-bank ((obj timer-bank)) + (format #t "[~8x] ~A~%" obj 'timer-bank) + (format #t "~Tcount: #x~X~%" (-> obj count)) + (format #t "~Tmode: #x~X~%" (-> obj mode)) + (format #t "~Tcomp: #x~X~%" (-> obj comp)) + obj + ) + +;; definition of type timer-hold-bank +(deftype timer-hold-bank (timer-bank) + ((hold uint32 :offset 48) + ) + :method-count-assert 9 + :size-assert #x34 + :flag-assert #x900000034 + ) + +;; definition for method 3 of type timer-hold-bank +(defmethod inspect timer-hold-bank ((obj timer-hold-bank)) + (format #t "[~8x] ~A~%" obj 'timer-hold-bank) + (format #t "~Tcount: #x~X~%" (-> obj count)) + (format #t "~Tmode: #x~X~%" (-> obj mode)) + (format #t "~Tcomp: #x~X~%" (-> obj comp)) + (format #t "~Thold: #x~X~%" (-> obj hold)) + obj + ) + +;; definition of type stopwatch +(deftype stopwatch (basic) + ((prev-time-elapsed uint64 :offset-assert 8) + (start-time uint64 :offset-assert 16) + (begin-level int32 :offset-assert 24) + ) + :method-count-assert 9 + :size-assert #x1c + :flag-assert #x90000001c + ) + +;; definition for method 3 of type stopwatch +(defmethod inspect stopwatch ((obj stopwatch)) + (format #t "[~8x] ~A~%" obj (-> obj type)) + (format #t "~Tprev-time-elapsed: ~D~%" (-> obj prev-time-elapsed)) + (format #t "~Tstart-time: ~D~%" (-> obj start-time)) + (format #t "~Tbegin-level: ~D~%" (-> obj begin-level)) + obj + ) + +;; definition for symbol *ticks-per-frame*, type int +(define *ticks-per-frame* 9765) + +;; definition for function timer-init +(defun timer-init ((arg0 timer-bank) (arg1 timer-mode)) + (set! (-> arg0 mode) arg1) + (set! (-> arg0 count) (the-as uint 0)) + 0 + ) + +;; failed to figure out what this is: +(timer-init (the-as timer-bank #x10000800) (the-as timer-mode 130)) + +;; definition of type profile-frame +(deftype profile-frame (structure) + ((name basic :offset-assert 0) + (time-stamp uint32 :offset-assert 4) + (color uint32 :offset-assert 8) + (r uint8 :offset 8) + (g uint8 :offset 9) + (b uint8 :offset 10) + ) + :method-count-assert 9 + :size-assert #xc + :flag-assert #x90000000c + ) + +;; definition for method 3 of type profile-frame +;; INFO: this function exists in multiple non-identical object files +(defmethod inspect profile-frame ((obj profile-frame)) + (format #t "[~8x] ~A~%" obj 'profile-frame) + (format #t "~Tname: ~A~%" (-> obj name)) + (format #t "~Ttime-stamp: ~D~%" (-> obj time-stamp)) + (format #t "~Tcolor: ~D~%" (-> obj color)) + obj + ) + +;; definition for method 3 of type profile-frame +;; INFO: this function exists in multiple non-identical object files +(defmethod inspect profile-frame ((obj profile-frame)) + (format #t "[~8x] profile-frame~%" obj) + (format #t "~Tname: ~A~%" (-> obj name)) + (format #t "~Ttime-stamp: ~D~%" (-> obj time-stamp)) + (format + #t + "~Tcolor: ~D ~D ~D~%" + (shr (shl (-> obj color) 56) 56) + (shr (shl (-> obj color) 48) 56) + (shr (shl (-> obj color) 40) 56) + ) + obj + ) + +;; definition of type profile-bar +(deftype profile-bar (basic) + ((profile-frame-count int32 :offset-assert 4) + (cache-time uint64 :offset-assert 8) + (data profile-frame 1024 :inline :offset-assert 16) + ) + :method-count-assert 14 + :size-assert #x4010 + :flag-assert #xe00004010 + (:methods + (get-last-frame-time-stamp (profile-bar) uint 9) + (dummy-10 () none 10) + (dummy-11 () none 11) + (dummy-12 () none 12) + (dummy-13 () none 13) + ) + ) + +;; definition for method 3 of type profile-bar +(defmethod inspect profile-bar ((obj profile-bar)) + (format #t "[~8x] ~A~%" obj (-> obj type)) + (format #t "~Tprofile-frame-count: ~D~%" (-> obj profile-frame-count)) + (format #t "~Tcache-time: ~D~%" (-> obj cache-time)) + (format #t "~Tdata[1024] @ #x~X~%" (-> obj data)) + obj + ) + +;; definition for method 9 of type profile-bar +(defmethod get-last-frame-time-stamp profile-bar ((obj profile-bar)) + (-> obj data (+ (-> obj profile-frame-count) -2) time-stamp) + ) + +;; failed to figure out what this is: +(let ((v0-7 0)) + ) + +;; failed to figure out what this is: +(none) + + + + diff --git a/test/decompiler/reference/timer_REF.gc b/test/decompiler/reference/timer_REF.gc new file mode 100644 index 0000000000..83b43b618b --- /dev/null +++ b/test/decompiler/reference/timer_REF.gc @@ -0,0 +1,179 @@ +;;-*-Lisp-*- +(in-package goal) + +;; definition for function timer-reset +;; INFO: Return type mismatch int vs none. +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +(defun timer-reset ((arg0 timer-bank)) + (.sync.l) + (set! (-> arg0 count) (the-as uint 0)) + (.sync.l) + (let ((v0-0 0)) + ) + (none) + ) + +;; definition for function timer-count +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +;; WARN: Unsupported inline assembly instruction kind - [sync.l] +(defun timer-count ((arg0 timer-bank)) + (.sync.l) + (let ((v0-0 (-> arg0 count))) + (.sync.l) + v0-0 + ) + ) + +;; definition for function disable-irq +;; INFO: Return type mismatch int vs none. +;; WARN: Unsupported inline assembly instruction kind - [mfc0 v0, Status] +;; WARN: Unsupported inline assembly instruction kind - [mtc0 Status, v0] +;; WARN: Unsupported inline assembly instruction kind - [sync.p] +(defun disable-irq () + (local-vars (v0-0 int)) + (let ((v1-0 (l.d L21))) + (.mfc0 v0-0 Status) + (let ((v0-1 (logand v0-0 (the-as int v1-0)))) + (.mtc0 Status v0-1) + ) + ) + (.sync.p) + (let ((v0-2 0)) + ) + (none) + ) + +;; definition for function enable-irq +;; INFO: Return type mismatch int vs none. +;; WARN: Unsupported inline assembly instruction kind - [mfc0 v0, Status] +;; WARN: Unsupported inline assembly instruction kind - [mtc0 Status, v0] +;; WARN: Unsupported inline assembly instruction kind - [sync.p] +(defun enable-irq () + (local-vars (v0-0 int)) + (.mfc0 v0-0 Status) + (let ((v0-1 (logior v0-0 1))) + (.mtc0 Status v0-1) + ) + (.sync.p) + (let ((v0-2 0)) + ) + (none) + ) + +;; definition for function stopwatch-init +(defun stopwatch-init ((arg0 stopwatch)) + (set! (-> arg0 begin-level) 0) + (set! (-> arg0 prev-time-elapsed) (the-as uint 0)) + 0 + ) + +;; definition for function stopwatch-reset +;; WARN: Unsupported inline assembly instruction kind - [mfc0 v1, Count] +(defun stopwatch-reset ((arg0 stopwatch)) + (local-vars (v1-3 int)) + (set! (-> arg0 prev-time-elapsed) (the-as uint 0)) + (when (> (-> arg0 begin-level) 0) + (let ((v1-2 0)) + ) + (.mfc0 v1-3 Count) + (set! (-> arg0 start-time) (the-as uint v1-3)) + ) + 0 + ) + +;; definition for function stopwatch-start +;; WARN: Unsupported inline assembly instruction kind - [mfc0 v1, Count] +(defun stopwatch-start ((arg0 stopwatch)) + (local-vars (v1-4 int)) + (when (zero? (-> arg0 begin-level)) + (set! (-> arg0 begin-level) 1) + (let ((v1-3 0)) + ) + (.mfc0 v1-4 Count) + (set! (-> arg0 start-time) (the-as uint v1-4)) + ) + 0 + ) + +;; definition for function stopwatch-stop +;; INFO: Return type mismatch int vs uint. +;; WARN: Unsupported inline assembly instruction kind - [mfc0 a1, Count] +(defun stopwatch-stop ((arg0 stopwatch)) + (local-vars (a1-0 int)) + (when (> (-> arg0 begin-level) 0) + (set! (-> arg0 begin-level) 0) + (let ((v1-2 0)) + ) + (.mfc0 a1-0 Count) + (set! + (-> arg0 prev-time-elapsed) + (+ + (-> arg0 prev-time-elapsed) + (the-as uint (- a1-0 (the-as int (-> arg0 start-time)))) + ) + ) + ) + (the-as uint 0) + ) + +;; definition for function stopwatch-begin +;; WARN: Unsupported inline assembly instruction kind - [mfc0 v1, Count] +(defun stopwatch-begin ((arg0 stopwatch)) + (local-vars (v1-3 int)) + (when (zero? (-> arg0 begin-level)) + (let ((v1-2 0)) + ) + (.mfc0 v1-3 Count) + (set! (-> arg0 start-time) (the-as uint v1-3)) + ) + (set! (-> arg0 begin-level) (+ (-> arg0 begin-level) 1)) + 0 + ) + +;; definition for function stopwatch-end +;; INFO: Return type mismatch int vs uint. +;; WARN: Unsupported inline assembly instruction kind - [mfc0 a1, Count] +(defun stopwatch-end ((arg0 stopwatch)) + (local-vars (a1-0 int)) + (set! (-> arg0 begin-level) (+ (-> arg0 begin-level) -1)) + (when (zero? (-> arg0 begin-level)) + (let ((v1-4 0)) + ) + (.mfc0 a1-0 Count) + (set! + (-> arg0 prev-time-elapsed) + (+ + (-> arg0 prev-time-elapsed) + (the-as uint (- a1-0 (the-as int (-> arg0 start-time)))) + ) + ) + ) + (the-as uint 0) + ) + +;; definition for function stopwatch-elapsed-ticks +;; WARN: Unsupported inline assembly instruction kind - [mfc0 v1, Count] +(defun stopwatch-elapsed-ticks ((arg0 stopwatch)) + (local-vars (v1-3 int)) + (let ((v0-0 (-> arg0 prev-time-elapsed))) + (when (> (-> arg0 begin-level) 0) + (let ((v1-2 0)) + ) + (.mfc0 v1-3 Count) + (+! v0-0 (the-as uint (- v1-3 (the-as int (-> arg0 start-time))))) + ) + v0-0 + ) + ) + +;; definition for function stopwatch-elapsed-seconds +(defun stopwatch-elapsed-seconds ((arg0 stopwatch)) + (let ((v1-0 (stopwatch-elapsed-ticks arg0))) + (* 0.0000000033333334 (the float v1-0)) + ) + ) + +;; failed to figure out what this is: +(none) + diff --git a/test/decompiler/reference/video-h_REF.gc b/test/decompiler/reference/video-h_REF.gc new file mode 100644 index 0000000000..a14541f34b --- /dev/null +++ b/test/decompiler/reference/video-h_REF.gc @@ -0,0 +1,84 @@ +;;-*-Lisp-*- +(in-package goal) + +;; definition of type video-parms +(deftype video-parms (structure) + ((set-video-mode basic :offset-assert 0) + (reset-video-mode basic :offset-assert 4) + (screen-sy int32 :offset-assert 8) + (screen-hy int32 :offset-assert 12) + (screen-miny int32 :offset-assert 16) + (screen-maxy int32 :offset-assert 20) + (screen-masky int32 :offset-assert 24) + (display-dx int32 :offset-assert 28) + (display-dy int32 :offset-assert 32) + (screen-pages-high int32 :offset-assert 36) + (_pad int64 :offset-assert 40) + (relative-x-scale float :offset-assert 48) + (relative-y-scale float :offset-assert 52) + (_pad2 int64 :offset-assert 56) + (relative-x-scale-reciprical float :offset-assert 64) + (relative-y-scale-reciprical float :offset-assert 68) + ) + :method-count-assert 9 + :size-assert #x48 + :flag-assert #x900000048 + ) + +;; definition for method 3 of type video-parms +(defmethod inspect video-parms ((obj video-parms)) + (format #t "[~8x] ~A~%" obj 'video-parms) + (format #t "~Tset-video-mode: ~A~%" (-> obj set-video-mode)) + (format #t "~Treset-video-mode: ~A~%" (-> obj reset-video-mode)) + (format #t "~Tscreen-sy: ~D~%" (-> obj screen-sy)) + (format #t "~Tscreen-hy: ~D~%" (-> obj screen-hy)) + (format #t "~Tscreen-miny: ~D~%" (-> obj screen-miny)) + (format #t "~Tscreen-maxy: ~D~%" (-> obj screen-maxy)) + (format #t "~Tscreen-masky: ~D~%" (-> obj screen-masky)) + (format #t "~Tdisplay-dx: ~D~%" (-> obj display-dx)) + (format #t "~Tdisplay-dy: ~D~%" (-> obj display-dy)) + (format #t "~Tscreen-pages-high: ~D~%" (-> obj screen-pages-high)) + (format #t "~Trelative-x-scale: ~f~%" (-> obj relative-x-scale)) + (format #t "~Trelative-y-scale: ~f~%" (-> obj relative-y-scale)) + (format + #t + "~Trelative-x-scale-reciprical: ~f~%" + (-> obj relative-x-scale-reciprical) + ) + (format + #t + "~Trelative-y-scale-reciprical: ~f~%" + (-> obj relative-y-scale-reciprical) + ) + obj + ) + +;; definition for symbol *video-parms*, type video-parms +(define + *video-parms* + (new 'static 'video-parms + :set-video-mode #f + :reset-video-mode #f + :screen-sy #xe0 + :screen-hy #x70 + :screen-miny #x720 + :screen-maxy #x8e0 + :screen-masky #xdf + :display-dy 8 + :screen-pages-high 7 + :relative-x-scale 1.0 + :relative-y-scale 1.0 + :relative-x-scale-reciprical 1.0 + ) + ) + +;; failed to figure out what this is: +(let ((v0-1 0)) + ) + +;; failed to figure out what this is: +(none) + + + + diff --git a/test/decompiler/reference/vif-h_REF.gc b/test/decompiler/reference/vif-h_REF.gc new file mode 100644 index 0000000000..0cfbc4bdab --- /dev/null +++ b/test/decompiler/reference/vif-h_REF.gc @@ -0,0 +1,128 @@ +;;-*-Lisp-*- +(in-package goal) + +;; definition of type vif-stat +(deftype vif-stat (uint32) + ((vps uint8 :offset 0 :size 2) + (vew uint8 :offset 2 :size 1) + (mrk uint8 :offset 6 :size 1) + (vss uint8 :offset 8 :size 1) + (vfs uint8 :offset 9 :size 1) + (vis uint8 :offset 10 :size 1) + (int uint8 :offset 11 :size 1) + (er0 uint8 :offset 12 :size 1) + (er1 uint8 :offset 13 :size 1) + (fqc uint8 :offset 24 :size 4) + ) + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ) + +;; definition for method 3 of type vif-stat +(defmethod inspect vif-stat ((obj vif-stat)) + (format #t "[~8x] ~A~%" obj 'vif-stat) + (format #t "~Tvps: ~D~%" (-> obj vps)) + (format #t "~Tvew: ~D~%" (-> obj vew)) + (format #t "~Tmrk: ~D~%" (-> obj mrk)) + (format #t "~Tvss: ~D~%" (-> obj vss)) + (format #t "~Tvfs: ~D~%" (-> obj vfs)) + (format #t "~Tvis: ~D~%" (-> obj vis)) + (format #t "~Tint: ~D~%" (-> obj int)) + (format #t "~Ter0: ~D~%" (-> obj er0)) + (format #t "~Ter1: ~D~%" (-> obj er1)) + (format #t "~Tfqc: ~D~%" (-> obj fqc)) + obj + ) + +;; definition of type vif-fbrst +(deftype vif-fbrst (uint32) + ((rst uint8 :offset 0 :size 1) + (fbk uint8 :offset 1 :size 1) + (stp uint8 :offset 2 :size 1) + (stc uint8 :offset 3 :size 1) + ) + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ) + +;; definition of type vif-err +(deftype vif-err (uint32) + ((mii uint8 :offset 0 :size 1) + (me0 uint8 :offset 1 :size 1) + (me1 uint8 :offset 2 :size 1) + ) + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ) + +;; definition of type vif-bank +(deftype vif-bank (structure) + ((stat uint32 :offset-assert 0) + (fbrst uint32 :offset 16) + (err vif-err :offset 32) + (mark uint32 :offset 48) + (cycle uint32 :offset 64) + (mode uint32 :offset 80) + (num uint32 :offset 96) + (mask uint32 :offset 112) + (code uint32 :offset 128) + (itops uint32 :offset 144) + (base uint32 :offset 160) + (offset uint32 :offset 176) + (tops uint32 :offset 192) + (itop uint32 :offset 208) + (top uint32 :offset 224) + (r0 uint32 :offset 256) + (r1 uint32 :offset 272) + (r2 uint32 :offset 288) + (r3 uint32 :offset 304) + (c0 uint32 :offset 320) + (c1 uint32 :offset 336) + (c2 uint32 :offset 352) + (c3 uint32 :offset 368) + ) + :method-count-assert 9 + :size-assert #x174 + :flag-assert #x900000174 + ) + +;; definition for method 3 of type vif-bank +(defmethod inspect vif-bank ((obj vif-bank)) + (format #t "[~8x] ~A~%" obj 'vif-bank) + (format #t "~Tstat: #x~X~%" (-> obj stat)) + (format #t "~Tfbrst: #x~X~%" (-> obj fbrst)) + (format #t "~Terr: #x~X~%" (-> obj err)) + (format #t "~Tmark: #x~X~%" (-> obj mark)) + (format #t "~Tcycle: #x~X~%" (-> obj cycle)) + (format #t "~Tmode: #x~X~%" (-> obj mode)) + (format #t "~Tnum: #x~X~%" (-> obj num)) + (format #t "~Tmask: #x~X~%" (-> obj mask)) + (format #t "~Tcode: #x~X~%" (-> obj code)) + (format #t "~Titops: #x~X~%" (-> obj itops)) + (format #t "~Tbase: #x~X~%" (-> obj base)) + (format #t "~Toffset: #x~X~%" (-> obj offset)) + (format #t "~Ttops: #x~X~%" (-> obj tops)) + (format #t "~Titop: #x~X~%" (-> obj itop)) + (format #t "~Ttop: #x~X~%" (-> obj top)) + (format #t "~Tr0: #x~X~%" (-> obj r0)) + (format #t "~Tr1: #x~X~%" (-> obj r1)) + (format #t "~Tr2: #x~X~%" (-> obj r2)) + (format #t "~Tr3: #x~X~%" (-> obj r3)) + (format #t "~Tc0: #x~X~%" (-> obj c0)) + (format #t "~Tc1: #x~X~%" (-> obj c1)) + (format #t "~Tc2: #x~X~%" (-> obj c2)) + (format #t "~Tc3: #x~X~%" (-> obj c3)) + obj + ) + +;; failed to figure out what this is: +(let ((v0-4 0)) + ) + +;; failed to figure out what this is: +(none) + + diff --git a/test/decompiler/reference/vu1-user-h_REF.gc b/test/decompiler/reference/vu1-user-h_REF.gc new file mode 100644 index 0000000000..7e3690556e --- /dev/null +++ b/test/decompiler/reference/vu1-user-h_REF.gc @@ -0,0 +1,121 @@ +;;-*-Lisp-*- +(in-package goal) + +;; definition for symbol *vu1-enable-user-menu*, type int +(define *vu1-enable-user-menu* #x1ffff8) + +;; definition for symbol *vu1-enable-user*, type int +(define *vu1-enable-user* 0) + +;; definition of type dma-foreground-sink +(deftype dma-foreground-sink (basic) + ((bucket int32 :offset-assert 4) + (foreground-texture-page int8 :offset-assert 8) + (foreground-texture-level int8 :offset-assert 9) + (foreground-output-bucket int8 :offset-assert 10) + ) + :method-count-assert 9 + :size-assert #xb + :flag-assert #x90000000b + ) + +;; definition for method 3 of type dma-foreground-sink +(defmethod inspect dma-foreground-sink ((obj dma-foreground-sink)) + (format #t "[~8x] ~A~%" obj (-> obj type)) + (format #t "~Tbucket: ~D~%" (-> obj bucket)) + (format #t "~Tforeground-texture-page: ~D~%" (-> obj foreground-texture-page)) + (format + #t + "~Tforeground-texture-level: ~D~%" + (-> obj foreground-texture-level) + ) + (format + #t + "~Tforeground-output-bucket: ~D~%" + (-> obj foreground-output-bucket) + ) + obj + ) + +;; definition of type generic-bucket-state +(deftype generic-bucket-state (structure) + ((gifbuf-adr uint32 :offset-assert 0) + (inbuf-adr uint32 :offset-assert 4) + ) + :pack-me + :method-count-assert 9 + :size-assert #x8 + :flag-assert #x900000008 + ) + +;; definition for method 3 of type generic-bucket-state +(defmethod inspect generic-bucket-state ((obj generic-bucket-state)) + (format #t "[~8x] ~A~%" obj 'generic-bucket-state) + (format #t "~Tgifbuf-adr: ~D~%" (-> obj gifbuf-adr)) + (format #t "~Tinbuf-adr: ~D~%" (-> obj inbuf-adr)) + obj + ) + +;; definition of type generic-dma-foreground-sink +(deftype generic-dma-foreground-sink (dma-foreground-sink) + ((state generic-bucket-state :inline :offset-assert 12) + ) + :method-count-assert 9 + :size-assert #x14 + :flag-assert #x900000014 + ) + +;; definition for method 3 of type generic-dma-foreground-sink +(defmethod + inspect + generic-dma-foreground-sink + ((obj generic-dma-foreground-sink)) + (format #t "[~8x] ~A~%" obj (-> obj type)) + (format #t "~Tbucket: ~D~%" (-> obj bucket)) + (format #t "~Tforeground-texture-page: ~D~%" (-> obj foreground-texture-page)) + (format + #t + "~Tforeground-texture-level: ~D~%" + (-> obj foreground-texture-level) + ) + (format + #t + "~Tforeground-output-bucket: ~D~%" + (-> obj foreground-output-bucket) + ) + (format #t "~Tstate: #~%" (-> obj state)) + obj + ) + +;; definition of type dma-foreground-sink-group +(deftype dma-foreground-sink-group (basic) + ((sink dma-foreground-sink 3 :offset-assert 4) + (merc-sink dma-foreground-sink :offset 4) + (generic-sink generic-dma-foreground-sink :offset 8) + (level basic :offset-assert 16) + ) + :method-count-assert 9 + :size-assert #x14 + :flag-assert #x900000014 + ) + +;; definition for method 3 of type dma-foreground-sink-group +(defmethod inspect dma-foreground-sink-group ((obj dma-foreground-sink-group)) + (format #t "[~8x] ~A~%" obj (-> obj type)) + (format #t "~Tsink[3] @ #x~X~%" (-> obj sink)) + (format #t "~Tmerc-sink: ~A~%" (-> obj sink 0)) + (format #t "~Tgeneric-sink: ~A~%" (-> obj sink 1)) + (format #t "~Tlevel: ~A~%" (-> obj level)) + obj + ) + +;; failed to figure out what this is: +(let ((v0-4 0)) + ) + +;; failed to figure out what this is: +(none) + + + + diff --git a/test/decompiler/test_FormExpressionBuild2.cpp b/test/decompiler/test_FormExpressionBuild2.cpp index 952cbc7eb2..445ddbae72 100644 --- a/test/decompiler/test_FormExpressionBuild2.cpp +++ b/test/decompiler/test_FormExpressionBuild2.cpp @@ -325,4 +325,467 @@ TEST_F(FormRegressionTest, IterateProcessTree) { " s4-0\n" " )"; test_with_stack_vars(func, type, expected, "[]"); +} + +TEST_F(FormRegressionTest, InspectVifStatBitfield) { + std::string func = + "sll r0, r0, 0\n" + + " daddiu sp, sp, -32\n" + " sd ra, 0(sp)\n" + " sd fp, 8(sp)\n" + " or fp, t9, r0\n" + " sq gp, 16(sp)\n" + + " or gp, a0, r0\n" + " lw t9, format(s7)\n" + " daddiu a0, s7, #t\n" + " daddiu a1, fp, L37\n" + " or a2, gp, r0\n" + " daddiu a3, s7, vif-stat\n" + " jalr ra, t9\n" + + " sll v0, ra, 0\n" + + " lw t9, format(s7)\n" + " daddiu a0, s7, #t\n" + " daddiu a1, fp, L36\n" + " dsll32 v1, gp, 30\n" + " dsrl32 a2, v1, 30\n" + " jalr ra, t9\n" + + " sll v0, ra, 0\n" + + " lw t9, format(s7)\n" + " daddiu a0, s7, #t\n" + " daddiu a1, fp, L35\n" + " dsll32 v1, gp, 29\n" + " dsrl32 a2, v1, 31\n" + " jalr ra, t9\n" + + " sll v0, ra, 0\n" + + " lw t9, format(s7)\n" + " daddiu a0, s7, #t\n" + " daddiu a1, fp, L34\n" + " dsll32 v1, gp, 25\n" + " dsrl32 a2, v1, 31\n" + " jalr ra, t9\n" + + " sll v0, ra, 0\n" + + " lw t9, format(s7)\n" + " daddiu a0, s7, #t\n" + " daddiu a1, fp, L33\n" + " dsll32 v1, gp, 23\n" + " dsrl32 a2, v1, 31\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " lw t9, format(s7)\n" + " daddiu a0, s7, #t\n" + " daddiu a1, fp, L32\n" + " dsll32 v1, gp, 22\n" + " dsrl32 a2, v1, 31\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " lw t9, format(s7)\n" + " daddiu a0, s7, #t\n" + " daddiu a1, fp, L31\n" + " dsll32 v1, gp, 21\n" + " dsrl32 a2, v1, 31\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " lw t9, format(s7)\n" + " daddiu a0, s7, #t\n" + " daddiu a1, fp, L30\n" + " dsll32 v1, gp, 20\n" + " dsrl32 a2, v1, 31\n" + " jalr ra, t9\n" + + " sll v0, ra, 0\n" + + " lw t9, format(s7)\n" + " daddiu a0, s7, #t\n" + " daddiu a1, fp, L29\n" + " dsll32 v1, gp, 19\n" + " dsrl32 a2, v1, 31\n" + " jalr ra, t9\n" + + " sll v0, ra, 0\n" + + " lw t9, format(s7)\n" + " daddiu a0, s7, #t\n" + " daddiu a1, fp, L28\n" + " dsll32 v1, gp, 18\n" + " dsrl32 a2, v1, 31\n" + " jalr ra, t9\n" + + " sll v0, ra, 0\n" + + " lw t9, format(s7)\n" + " daddiu a0, s7, #t\n" + " daddiu a1, fp, L27\n" + " dsll32 v1, gp, 4\n" + " dsrl32 a2, v1, 28\n" + " jalr ra, t9\n" + + " sll v0, ra, 0\n" + + " or v0, gp, r0\n" + " ld ra, 0(sp)\n" + " ld fp, 8(sp)\n" + " lq gp, 16(sp)\n" + " jr ra\n" + " daddiu sp, sp, 32"; + std::string type = "(function vif-stat vif-stat)"; + std::string expected = + "(begin\n" + " (format #t \"[~8x] ~A~%\" arg0 (quote vif-stat))\n" + " (format #t \"~T ~D~%\" (-> arg0 vps))\n" + " (format #t \"~T ~D~%\" (-> arg0 vew))\n" + " (format #t \"~T ~D~%\" (-> arg0 mrk))\n" + " (format #t \"~T ~D~%\" (-> arg0 vss))\n" + " (format #t \"~T ~D~%\" (-> arg0 vfs))\n" + " (format #t \"~T ~D~%\" (-> arg0 vis))\n" + " (format #t \"~T ~D~%\" (-> arg0 int))\n" + " (format #t \"~T ~D~%\" (-> arg0 er0))\n" + " (format #t \"~T ~D~%\" (-> arg0 er1))\n" + " (format #t \"~T ~D~%\" (-> arg0 fqc))\n" + " arg0\n" + " )"; + test_with_expr(func, type, expected, false, "", + {{"L37", "[~8x] ~A~%"}, + {"L36", "~T ~D~%"}, + {"L35", "~T ~D~%"}, + {"L34", "~T ~D~%"}, + {"L33", "~T ~D~%"}, + {"L32", "~T ~D~%"}, + {"L31", "~T ~D~%"}, + {"L30", "~T ~D~%"}, + {"L29", "~T ~D~%"}, + {"L28", "~T ~D~%"}, + {"L27", "~T ~D~%"}}); +} + +TEST_F(FormRegressionTest, InspectHandleBitfield) { + std::string func = + "sll r0, r0, 0\n" + " daddiu sp, sp, -32\n" + " sd ra, 0(sp)\n" + " sd fp, 8(sp)\n" + " or fp, t9, r0\n" + " sq gp, 16(sp)\n" + + " or gp, a0, r0\n" + " lw t9, format(s7)\n" + " daddiu a0, s7, #t\n" + " daddiu a1, fp, L79\n" + " or a2, gp, r0\n" + " daddiu a3, s7, handle\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " lw t9, format(s7)\n" + " daddiu a0, s7, #t\n" + " daddiu a1, fp, L32\n" + " dsll32 v1, gp, 0\n" + " dsrl32 a2, v1, 0\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " lw t9, format(s7)\n" + " daddiu a0, s7, #t\n" + " daddiu a1, fp, L31\n" + " dsra32 a2, gp, 0\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " or v0, gp, r0\n" + " ld ra, 0(sp)\n" + " ld fp, 8(sp)\n" + " lq gp, 16(sp)\n" + " jr ra\n" + " daddiu sp, sp, 32"; + std::string type = "(function handle handle)"; + std::string expected = + "(begin\n" + " (format #t \"[~8x] ~A~%\" arg0 (quote handle))\n" + " (format #t \"~Tprocess: #x~X~%\" (-> arg0 process))\n" + " (format #t \"~Tpid: ~D~%\" (-> arg0 pid))\n" + " arg0\n" + " )"; + test_with_expr(func, type, expected, false, "", + {{"L79", "[~8x] ~A~%"}, {"L32", "~Tprocess: #x~X~%"}, {"L31", "~Tpid: ~D~%"}}); +} + +TEST_F(FormRegressionTest, InspectDmaTagBitfield) { + std::string func = + "sll r0, r0, 0\n" + " daddiu sp, sp, -32\n" + " sd ra, 0(sp)\n" + " sd fp, 8(sp)\n" + " or fp, t9, r0\n" + " sq gp, 16(sp)\n" + + " or gp, a0, r0\n" + " lw t9, format(s7)\n" + " daddiu a0, s7, #t\n" + " daddiu a1, fp, L65\n" + " or a2, gp, r0\n" + " daddiu a3, s7, dma-tag\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " lw t9, format(s7)\n" + " daddiu a0, s7, #t\n" + " daddiu a1, fp, L37\n" + " dsll32 v1, gp, 16\n" + " dsrl32 a2, v1, 16\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " lw t9, format(s7)\n" + " daddiu a0, s7, #t\n" + " daddiu a1, fp, L36\n" + " dsll32 v1, gp, 4\n" + " dsrl32 a2, v1, 30\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " lw t9, format(s7)\n" + " daddiu a0, s7, #t\n" + " daddiu a1, fp, L35\n" + " dsll32 v1, gp, 1\n" + " dsrl32 a2, v1, 29\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " lw t9, format(s7)\n" + " daddiu a0, s7, #t\n" + " daddiu a1, fp, L34\n" + " srl a2, gp, 31\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " lw t9, format(s7)\n" + " daddiu a0, s7, #t\n" + " daddiu a1, fp, L33\n" + " dsll v1, gp, 1\n" + " dsrl32 a2, v1, 1\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " lw t9, format(s7)\n" + " daddiu a0, s7, #t\n" + " daddiu a1, fp, L32\n" + " dsrl32 a2, gp, 31\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " or v0, gp, r0\n" + " ld ra, 0(sp)\n" + " ld fp, 8(sp)\n" + " lq gp, 16(sp)\n" + " jr ra\n" + " daddiu sp, sp, 32"; + std::string type = "(function dma-tag dma-tag)"; + std::string expected = + "(begin\n" + " (format #t \"[~8x] ~A~%\" arg0 (quote dma-tag))\n" + " (format #t \"~Ta: ~D~%\" (-> arg0 qwc))\n" + " (format #t \"~Ta: ~D~%\" (-> arg0 pce))\n" + " (format #t \"~Ta: ~D~%\" (-> arg0 id))\n" + " (format #t \"~Ta: ~D~%\" (-> arg0 irq))\n" + " (format #t \"~Ta: ~D~%\" (-> arg0 addr))\n" + " (format #t \"~Ta: ~D~%\" (-> arg0 spr))\n" + " arg0\n" + " )"; + test_with_expr(func, type, expected, false, "", + { + {"L65", "[~8x] ~A~%"}, + {"L37", "~Ta: ~D~%"}, + {"L36", "~Ta: ~D~%"}, + {"L35", "~Ta: ~D~%"}, + {"L34", "~Ta: ~D~%"}, + {"L33", "~Ta: ~D~%"}, + {"L32", "~Ta: ~D~%"}, + }); +} + +// Tests nonzero-check on bitfield +TEST_F(FormRegressionTest, DmaSyncCrash) { + std::string func = + "sll r0, r0, 0\n" + "L46:\n" + " lui v1, 76\n" + " ori v1, v1, 19264\n" + " beq r0, r0, L49\n" + " sll r0, r0, 0\n" + + "L47:\n" + " bne v1, r0, L48\n" + " sll r0, r0, 0\n" + + " sd r0, 2(r0)\n" + " or a1, r0, r0\n" + " beq r0, r0, L49\n" + " sll r0, r0, 0\n" + + "L48:\n" + " daddiu v1, v1, -1\n" + " or a1, v1, r0\n" + + "L49:\n" + " lwu a1, 0(a0)\n" + " andi a1, a1, 256\n" + " bne a1, r0, L47\n" + " sll r0, r0, 0\n" + + " or v1, s7, r0\n" + " or v0, r0, r0\n" + " jr ra\n" + " daddu sp, sp, r0"; + std::string type = "(function dma-bank int)"; + std::string expected = + "(begin\n" + " (let ((v1-0 #x4c4b40))\n" + " (while (nonzero? (-> arg0 chcr str))\n" + " (cond\n" + " ((zero? v1-0)\n" + " (crash!)\n" + " (let ((a1-0 0))\n" + " )\n" + " )\n" + " (else\n" + " (+! v1-0 -1)\n" + " )\n" + " )\n" + " )\n" + " )\n" + " 0\n" + " )"; + test_with_expr(func, type, expected); +} + +TEST_F(FormRegressionTest, DmaSend) { + std::string func = + "sll r0, r0, 0\n" + " daddiu sp, sp, -64\n" + " sd ra, 0(sp)\n" + " sq s4, 16(sp)\n" + " sq s5, 32(sp)\n" + " sq gp, 48(sp)\n" + + " or gp, a0, r0\n" + " or s4, a1, r0\n" + " or s5, a2, r0\n" + " lw t9, dma-sync(s7)\n" + " or a0, gp, r0\n" + " addiu a1, r0, 0\n" + " addiu a2, r0, 0\n" + " jalr ra, t9\n" + + " sll v0, ra, 0\n" + + " lw t9, flush-cache(s7)\n" + " addiu a0, r0, 0\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " sync.l\n" + " lui v1, 4095\n" + " ori v1, v1, 65535\n" + " and v1, v1, s4\n" + " lui a0, 28672\n" + " lui a1, 28672\n" + " and a1, a1, s4\n" + " bne a1, a0, L44\n" + " sll r0, r0, 0\n" + + " ori a0, r0, 32768\n" + " dsll a0, a0, 16\n" + " beq r0, r0, L45\n" + " sll r0, r0, 0\n" + + "L44:\n" + " addiu a0, r0, 0\n" + + "L45:\n" + " or v1, v1, a0\n" + " sw v1, 16(gp)\n" + " sw s5, 32(gp)\n" + " sync.l\n" + " addiu v1, r0, 256\n" + " sw v1, 0(gp)\n" + " sync.l\n" + " or v0, r0, r0\n" + " ld ra, 0(sp)\n" + " lq gp, 48(sp)\n" + " lq s5, 32(sp)\n" + " lq s4, 16(sp)\n" + " jr ra\n" + " daddiu sp, sp, 64"; + std::string type = "(function dma-bank uint uint int)"; + std::string expected = + "(begin\n" + " (dma-sync (the-as pointer arg0) 0 0)\n" + " (flush-cache 0)\n" + " (.sync.l)\n" + " (set!\n" + " (-> arg0 madr)\n" + " (logior\n" + " (logand #xfffffff (the-as int arg1))\n" + " (the-as uint (if (= (logand #x70000000 (the-as int arg1)) #x70000000)\n" + " (shl #x8000 16)\n" // note: maybe this should be #x80000000? Not sure. + " 0\n" + " )\n" + " )\n" + " )\n" + " )\n" + " (set! (-> arg0 qwc) arg2)\n" + " (.sync.l)\n" + " (set! (-> arg0 chcr) (new 'static 'dma-chcr :str 1))\n" + " (.sync.l)\n" + " 0\n" + " )"; + test_with_expr(func, type, expected); +} + +TEST_F(FormRegressionTest, DmaInitialize) { + std::string func = + "sll r0, r0, 0\n" + " lui v1, 4096\n" + " ori v1, v1, 14336\n" + " lwu v1, 32(v1)\n" + " addiu a0, r0, -3\n" + " and v1, v1, a0\n" + " ori v1, v1, 2\n" + " lui a0, 4096\n" + " ori a0, a0, 14336\n" + " sw v1, 32(a0)\n" + " lui v1, 4096\n" + " ori v1, v1, 15360\n" + " lwu v1, 32(v1)\n" + " addiu a0, r0, -3\n" + " and v1, v1, a0\n" + " ori v1, v1, 2\n" + " lui a0, 4096\n" + " ori a0, a0, 15360\n" + " sw v1, 32(a0)\n" + " or v0, r0, r0\n" + " jr ra\n" + " daddu sp, sp, r0"; + std::string type = "(function int)"; + std::string expected = + "(begin\n" + " (set! (-> (the-as vif-bank #x10003800) err me0) 1)\n" + " (set! (-> (the-as vif-bank #x10003c00) err me0) 1)\n" + " 0\n" + " )"; + test_with_expr(func, type, expected, false, "", {}, + "[[1, \"v1\", \"vif-bank\"], [8, \"v1\", \"vif-bank\"], [6, \"a0\", " + "\"vif-bank\"], [13, \"a0\", \"vif-bank\"]]"); } \ No newline at end of file diff --git a/test/offline/offline_test_main.cpp b/test/offline/offline_test_main.cpp index 1ef718f762..83634af28f 100644 --- a/test/offline/offline_test_main.cpp +++ b/test/offline/offline_test_main.cpp @@ -15,6 +15,8 @@ const std::unordered_set g_object_files_to_decompile = { /*"pskernel",*/ "gstring", "dgo-h", "gstate", "types-h", "vu1-macros", "math", "vector-h", "bounding-box-h", "matrix-h", "quaternion-h", "euler-h", "transform-h", "geometry-h", "trigonometry-h", /* transformq-h */ "matrix", "transform", "quaternion", + "euler", /* geometry, trigonometry, */ + "gsound-h", "timer-h", "timer", "vif-h", "dma-h", "video-h", "vu1-user-h", "dma", /* gap */ "bounding-box", /* gap */ @@ -27,9 +29,9 @@ const std::vector g_object_files_to_check_against_reference = { "math", "vector-h", "bounding-box-h", "matrix-h", "quaternion-h", "euler-h", "transform-h", "geometry-h", "trigonometry-h", /* transformq-h, */ - "matrix", "transform", "quaternion", - /* gap */ - "bounding-box", + "matrix", "transform", "quaternion", "euler", /* geometry, trigonometry */ + "gsound-h", "timer-h", /* timer, */ "vif-h", "dma-h", "video-h", "vu1-user-h", "dma", + /* gap */ "bounding-box", /* gap */ "sync-info-h", "sync-info"}; @@ -62,6 +64,11 @@ const std::unordered_set expected_skip_in_decompiler = { // matrix "(method 9 matrix)", // handwritten asm loop "matrix-axis-sin-cos!", "matrix-axis-sin-cos-vu!", + // dma-h + "dma-count-until-done", // dma asm loop + "dma-sync-with-count", "dma-send-no-scratch", "dma-sync-fast", + // dma + "symlink2", "symlink3", "dma-sync-hang", // handwritten asm // sync-info "(method 15 sync-info)", // needs *res-static-buf* "(method 15 sync-info-eased)", // needs *res-static-buf* @@ -106,11 +113,12 @@ const std::unordered_set skip_in_compiling = { "matrix-with-scale->quaternion", // fpu acc "quaternion-delta-y", // fpu acc + "(method 3 profile-frame)", // double definition. + // sync-info "(method 15 sync-info)", // needs display stuff first "(method 15 sync-info-eased)", // needs display stuff first "(method 15 sync-info-paused)", // needs display stuff first - }; // default location for the data. It can be changed with a command line argument. diff --git a/test/test_common_util.cpp b/test/test_common_util.cpp index c8e23d12b0..bda506680f 100644 --- a/test/test_common_util.cpp +++ b/test/test_common_util.cpp @@ -1,11 +1,14 @@ +#include +#include + #include "common/util/FileUtil.h" #include "common/util/Trie.h" +#include "common/util/BitUtils.h" #include "gtest/gtest.h" #include "test/all_jak1_symbols.h" #include "common/util/json_util.h" #include "common/util/Range.h" -#include -#include +#include "third-party/fmt/core.h" TEST(CommonUtil, get_file_path) { std::vector test = {"cabbage", "banana", "apple"}; @@ -77,4 +80,18 @@ TEST(CommonUtil, RangeIterator) { EXPECT_FALSE(Range(3, 4).empty()); EXPECT_EQ(1, Range(3, 4).size()); EXPECT_EQ(4, Range(4, 8).size()); +} + +TEST(CommonUtil, BitRange) { + for (int x : {0, 0b1001, 0b1010, 0b01110001, 0b000100110}) { + EXPECT_EQ(get_bit_range(x), std::nullopt); // invalids + } + + EXPECT_EQ(get_bit_range(0b1), Range(0, 1)); + EXPECT_EQ(get_bit_range(0b10), Range(1, 2)); + EXPECT_EQ(get_bit_range(0b11), Range(0, 2)); + EXPECT_EQ(get_bit_range(0b110), Range(1, 3)); + EXPECT_EQ(get_bit_range(UINT64_MAX), Range(0, 64)); + EXPECT_EQ(get_bit_range(UINT64_MAX - 1), Range(1, 64)); + EXPECT_EQ(get_bit_range(UINT64_MAX / 2), Range(0, 63)); } \ No newline at end of file