mirror of
https://github.com/open-goal/jak-project
synced 2026-07-08 22:45:00 -04:00
[Decompile] pad and gs (#389)
* update stuff * gs reference added * update config
This commit is contained in:
@@ -289,6 +289,8 @@ std::string get_simple_expression_op_name(SimpleExpression::Kind kind) {
|
||||
return "max.si";
|
||||
case SimpleExpression::Kind::MAX_UNSIGNED:
|
||||
return "max.ui";
|
||||
case SimpleExpression::Kind::PCPYLD:
|
||||
return "pcypld";
|
||||
default:
|
||||
assert(false);
|
||||
return {};
|
||||
@@ -338,6 +340,7 @@ int get_simple_expression_arg_count(SimpleExpression::Kind kind) {
|
||||
case SimpleExpression::Kind::MIN_UNSIGNED:
|
||||
case SimpleExpression::Kind::MAX_SIGNED:
|
||||
case SimpleExpression::Kind::MAX_UNSIGNED:
|
||||
case SimpleExpression::Kind::PCPYLD:
|
||||
return 2;
|
||||
default:
|
||||
assert(false);
|
||||
|
||||
@@ -221,7 +221,8 @@ class SimpleExpression {
|
||||
MIN_SIGNED,
|
||||
MAX_SIGNED,
|
||||
MIN_UNSIGNED,
|
||||
MAX_UNSIGNED
|
||||
MAX_UNSIGNED,
|
||||
PCPYLD,
|
||||
};
|
||||
|
||||
// how many arguments?
|
||||
|
||||
@@ -636,7 +636,10 @@ Form* LoadVarOp::get_load_src(FormPool& pool, const Env& env) const {
|
||||
// smaller. We should check that the higher bits are all zero.
|
||||
int bits = as_bitfield->get_size_in_memory() * 8;
|
||||
assert(bits <= 64);
|
||||
assert((value >> bits) == 0);
|
||||
if (bits < 64) {
|
||||
assert((value >> bits) == 0);
|
||||
// technically ub if bits == 64.
|
||||
}
|
||||
TypeSpec typespec(hint->second.type_name);
|
||||
auto defs = decompile_bitfield_from_int(typespec, ts, value);
|
||||
return pool.alloc_single_element_form<BitfieldStaticDefElement>(nullptr, typespec, defs,
|
||||
|
||||
@@ -192,6 +192,7 @@ TP_Type SimpleExpression::get_type(const TypeState& input,
|
||||
return get_type_int1(input, env, dts);
|
||||
case Kind::DIV_UNSIGNED:
|
||||
case Kind::MOD_UNSIGNED:
|
||||
case Kind::PCPYLD:
|
||||
return TP_Type::make_from_ts("uint");
|
||||
default:
|
||||
throw std::runtime_error("Simple expression can't get_type: " +
|
||||
|
||||
@@ -1503,6 +1503,8 @@ std::string fixed_operator_to_string(FixedOperatorKind kind) {
|
||||
return "pair?";
|
||||
case FixedOperatorKind::NONE:
|
||||
return "none";
|
||||
case FixedOperatorKind::PCPYLD:
|
||||
return ".pcpyld";
|
||||
default:
|
||||
assert(false);
|
||||
return "";
|
||||
|
||||
@@ -177,6 +177,11 @@ class SimpleExpressionElement : public FormElement {
|
||||
FormStack& stack,
|
||||
std::vector<FormElement*>* result,
|
||||
bool allow_side_effects);
|
||||
void update_from_stack_pcypld(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
std::vector<FormElement*>* result,
|
||||
bool allow_side_effects);
|
||||
|
||||
const SimpleExpression& expr() const { return m_expr; }
|
||||
|
||||
|
||||
@@ -201,6 +201,19 @@ void pop_helper(const std::vector<RegisterAccess>& vars,
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
Form* strip_pcypld_64(Form* in) {
|
||||
auto m = match(Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::PCPYLD),
|
||||
{Matcher::integer(0), Matcher::any(0)}),
|
||||
in);
|
||||
if (m.matched) {
|
||||
return m.maps.forms.at(0);
|
||||
} else {
|
||||
return in;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
/*!
|
||||
* This should be used to generate all casts.
|
||||
*/
|
||||
@@ -213,6 +226,9 @@ Form* cast_form(Form* in, const TypeSpec& new_type, FormPool& pool, const Env& e
|
||||
auto type_info = env.dts->ts.lookup_type(new_type);
|
||||
auto bitfield_info = dynamic_cast<BitFieldType*>(type_info);
|
||||
if (bitfield_info) {
|
||||
if (bitfield_info->get_load_size() == 8) {
|
||||
in = strip_pcypld_64(in);
|
||||
}
|
||||
return cast_to_bitfield(bitfield_info, new_type, pool, env, in);
|
||||
}
|
||||
|
||||
@@ -314,13 +330,6 @@ bool is_ptr_or_child(const Env& env, int my_idx, RegisterAccess var, bool) {
|
||||
return type == "pointer";
|
||||
}
|
||||
|
||||
bool is_var(Form* form) {
|
||||
auto atom = form_as_atom(form);
|
||||
if (atom) {
|
||||
return atom->is_var();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
/*!
|
||||
@@ -846,6 +855,36 @@ void SimpleExpressionElement::update_from_stack_force_ui_2(const Env& env,
|
||||
result->push_back(new_form);
|
||||
}
|
||||
|
||||
void SimpleExpressionElement::update_from_stack_pcypld(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
std::vector<FormElement*>* result,
|
||||
bool allow_side_effects) {
|
||||
std::vector<Form*> args;
|
||||
std::vector<RegisterAccess> ras;
|
||||
for (int arg_idx = 0; arg_idx < m_expr.args(); arg_idx++) {
|
||||
if (m_expr.get_arg(arg_idx).is_var()) {
|
||||
ras.push_back(m_expr.get_arg(arg_idx).var());
|
||||
}
|
||||
}
|
||||
auto popped_args = pop_to_forms(ras, env, pool, stack, allow_side_effects);
|
||||
|
||||
int ras_idx = 0;
|
||||
for (int arg_idx = 0; arg_idx < m_expr.args(); arg_idx++) {
|
||||
if (m_expr.get_arg(arg_idx).is_var()) {
|
||||
args.push_back(popped_args.at(ras_idx));
|
||||
ras_idx++;
|
||||
} else {
|
||||
args.push_back(
|
||||
pool.alloc_single_element_form<SimpleAtomElement>(nullptr, m_expr.get_arg(arg_idx)));
|
||||
}
|
||||
}
|
||||
|
||||
auto new_form = pool.alloc_element<GenericElement>(
|
||||
GenericOperator::make_fixed(FixedOperatorKind::PCPYLD), args.at(0), args.at(1));
|
||||
result->push_back(new_form);
|
||||
}
|
||||
|
||||
void SimpleExpressionElement::update_from_stack_copy_first_int_2(const Env& env,
|
||||
FixedOperatorKind kind,
|
||||
FormPool& pool,
|
||||
@@ -966,9 +1005,11 @@ void SimpleExpressionElement::update_from_stack_logor_or_logand(const Env& env,
|
||||
|
||||
if (bitfield_info) {
|
||||
// either the immediate didn't fit in the 16-bit imm or it's with a variable
|
||||
bool made_new_read_elt = false;
|
||||
auto read_elt = dynamic_cast<BitfieldAccessElement*>(args.at(0)->try_as_single_element());
|
||||
if (!read_elt) {
|
||||
read_elt = pool.alloc_element<BitfieldAccessElement>(args.at(0), arg0_type);
|
||||
made_new_read_elt = true;
|
||||
}
|
||||
|
||||
auto stripped_arg1 = strip_int_or_uint_cast(args.at(1));
|
||||
@@ -987,7 +1028,7 @@ void SimpleExpressionElement::update_from_stack_logor_or_logand(const Env& env,
|
||||
assert(!other); // shouldn't be complete.
|
||||
result->push_back(read_elt);
|
||||
return;
|
||||
} else {
|
||||
} else if (!made_new_read_elt) {
|
||||
BitfieldManip::Kind manip_kind;
|
||||
if (kind == FixedOperatorKind::LOGAND) {
|
||||
manip_kind = BitfieldManip::Kind::LOGAND_WITH_FORM;
|
||||
@@ -1325,6 +1366,9 @@ void SimpleExpressionElement::update_from_stack(const Env& env,
|
||||
case SimpleExpression::Kind::FLOAT_TO_INT:
|
||||
update_from_stack_float_to_int(env, pool, stack, result, allow_side_effects);
|
||||
break;
|
||||
case SimpleExpression::Kind::PCPYLD:
|
||||
update_from_stack_pcypld(env, pool, stack, result, allow_side_effects);
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error(
|
||||
fmt::format("SimpleExpressionElement::update_from_stack NYI for {}", to_string(env)));
|
||||
@@ -2292,14 +2336,20 @@ void ShortCircuitElement::update_from_stack(const Env& env,
|
||||
already_rewritten = true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
Matcher make_int_uint_cast_matcher(const Matcher& thing) {
|
||||
return Matcher::match_or({Matcher::cast("uint", thing), Matcher::cast("int", thing), thing});
|
||||
}
|
||||
} // namespace
|
||||
|
||||
///////////////////
|
||||
// ConditionElement
|
||||
///////////////////
|
||||
|
||||
FormElement* ConditionElement::make_zero_check_generic(const Env&,
|
||||
FormElement* ConditionElement::make_zero_check_generic(const Env& env,
|
||||
FormPool& pool,
|
||||
const std::vector<Form*>& source_forms,
|
||||
const std::vector<TypeSpec>&) {
|
||||
const std::vector<TypeSpec>& source_types) {
|
||||
// (zero? (+ thing small-integer)) -> (= thing (- small-integer))
|
||||
assert(source_forms.size() == 1);
|
||||
auto mr = match(Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::ADDITION),
|
||||
@@ -2311,9 +2361,26 @@ FormElement* ConditionElement::make_zero_check_generic(const Env&,
|
||||
nullptr, SimpleAtom::make_int_constant(value));
|
||||
return pool.alloc_element<GenericElement>(GenericOperator::make_fixed(FixedOperatorKind::EQ),
|
||||
std::vector<Form*>{mr.maps.forms.at(0), value_form});
|
||||
} else {
|
||||
return pool.alloc_element<GenericElement>(GenericOperator::make_compare(m_kind), source_forms);
|
||||
}
|
||||
|
||||
auto enum_type_info = env.dts->ts.try_enum_lookup(source_types.at(0));
|
||||
if (enum_type_info && !enum_type_info->is_bitfield()) {
|
||||
// (zero? (+ (the-as uint arg0) (the-as uint -2))) check enum value
|
||||
mr = match(Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::ADDITION),
|
||||
{make_int_uint_cast_matcher(Matcher::any(0)),
|
||||
make_int_uint_cast_matcher(Matcher::any_integer(1))}),
|
||||
source_forms.at(0));
|
||||
if (mr.matched) {
|
||||
s64 value = mr.maps.ints.at(1);
|
||||
value = -value;
|
||||
auto enum_constant = cast_to_int_enum(enum_type_info, pool, env, value);
|
||||
return pool.alloc_element<GenericElement>(
|
||||
GenericOperator::make_fixed(FixedOperatorKind::EQ),
|
||||
std::vector<Form*>{mr.maps.forms.at(0), enum_constant});
|
||||
}
|
||||
}
|
||||
|
||||
return pool.alloc_element<GenericElement>(GenericOperator::make_compare(m_kind), source_forms);
|
||||
}
|
||||
|
||||
FormElement* ConditionElement::make_nonzero_check_generic(const Env& env,
|
||||
@@ -2682,6 +2749,7 @@ void ReturnElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void push_asm_srl_to_stack(const AsmOp* op,
|
||||
FormElement* form_elt,
|
||||
const Env& env,
|
||||
@@ -2714,6 +2782,21 @@ void push_asm_srl_to_stack(const AsmOp* op,
|
||||
}
|
||||
}
|
||||
|
||||
void push_asm_to_stack(const AsmOp* op,
|
||||
FormElement* form_elt,
|
||||
const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack) {
|
||||
switch (op->instruction().kind) {
|
||||
case InstructionKind::SRL:
|
||||
push_asm_srl_to_stack(op, form_elt, env, pool, stack);
|
||||
break;
|
||||
default:
|
||||
stack.push_form_element(form_elt, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void AtomicOpElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
|
||||
@@ -2737,14 +2820,7 @@ void AtomicOpElement::push_to_stack(const Env& env, FormPool& pool, FormStack& s
|
||||
|
||||
auto as_asm = dynamic_cast<const AsmOp*>(m_op);
|
||||
if (as_asm) {
|
||||
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;
|
||||
}
|
||||
push_asm_to_stack(as_asm, this, env, pool, stack);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2753,15 +2829,7 @@ void AtomicOpElement::push_to_stack(const Env& env, FormPool& pool, FormStack& s
|
||||
|
||||
void AsmOpElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
|
||||
mark_popped();
|
||||
|
||||
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;
|
||||
}
|
||||
push_asm_to_stack(m_op, this, env, pool, stack);
|
||||
}
|
||||
|
||||
void GenericElement::update_from_stack(const Env& env,
|
||||
|
||||
@@ -141,6 +141,7 @@ enum class FixedOperatorKind {
|
||||
NULLP,
|
||||
PAIRP,
|
||||
NONE,
|
||||
PCPYLD,
|
||||
INVALID
|
||||
};
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ typedef OpenGOALAsm::InstructionModifiers MOD;
|
||||
const std::map<InstructionKind, OpenGOALAsm::Function> MIPS_ASM_TO_OPEN_GOAL_FUNCS = {
|
||||
// ----- EE -------
|
||||
// TODO - these are waiting on proper 128-bit int support in OpenGOAL
|
||||
{InstructionKind::PSLLW, {"TODO.PSLLW", {}}},
|
||||
{InstructionKind::PSRAW, {"TODO.PSRAW", {}}},
|
||||
{InstructionKind::PSLLW, {".pw.sll", {}}},
|
||||
{InstructionKind::PSRAW, {".pw.sra", {}}},
|
||||
{InstructionKind::PSUBW, {"TODO.PSUBW", {}}},
|
||||
|
||||
{InstructionKind::PEXTUW, {".pextuw", {}}},
|
||||
|
||||
@@ -216,6 +216,24 @@ std::optional<BitFieldDef> get_bitfield_initial_set(Form* form,
|
||||
return def;
|
||||
}
|
||||
|
||||
// also possible to omit the shr if it would be zero:
|
||||
auto matcher_no_shr = Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::SHL),
|
||||
{Matcher::any(0), Matcher::any_integer(1)});
|
||||
auto mr_no_shr = match(matcher_no_shr, strip_int_or_uint_cast(form));
|
||||
if (mr_no_shr.matched) {
|
||||
auto value = mr_no_shr.maps.forms.at(0);
|
||||
int left = mr_no_shr.maps.ints.at(1);
|
||||
int right = 0;
|
||||
int size = 64 - left;
|
||||
int offset = left - right;
|
||||
auto& f = find_field(ts, type, offset, size, {});
|
||||
BitFieldDef def;
|
||||
def.value = value;
|
||||
def.field_name = f.name();
|
||||
def.is_signed = false; // we don't know.
|
||||
return def;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -228,7 +246,7 @@ std::optional<BitFieldDef> get_bitfield_initial_set(Form* form,
|
||||
FormElement* BitfieldAccessElement::push_step(const BitfieldManip step,
|
||||
const TypeSystem& ts,
|
||||
FormPool& pool,
|
||||
const Env& env) {
|
||||
const Env&) {
|
||||
if (m_steps.empty() && step.kind == BitfieldManip::Kind::LEFT_SHIFT) {
|
||||
// for left/right shift combo to get a field.
|
||||
m_steps.push_back(step);
|
||||
@@ -354,6 +372,12 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step,
|
||||
std::vector<BitFieldDef>{*val});
|
||||
}
|
||||
|
||||
lg::error("Invalid state in BitfieldReadElement. Previous steps:");
|
||||
for (auto& old_step : m_steps) {
|
||||
lg::error(" {}", old_step.print());
|
||||
}
|
||||
lg::error("Current: {}\n", step.print());
|
||||
|
||||
throw std::runtime_error("Unknown state in BitfieldReadElement");
|
||||
}
|
||||
|
||||
@@ -409,8 +433,14 @@ BitFieldDef BitFieldDef::from_constant(const BitFieldConstantDef& constant, Form
|
||||
BitFieldDef bfd;
|
||||
bfd.field_name = constant.field_name;
|
||||
bfd.is_signed = constant.is_signed;
|
||||
bfd.value = pool.alloc_single_element_form<SimpleAtomElement>(
|
||||
nullptr, SimpleAtom::make_int_constant(constant.value));
|
||||
if (constant.enum_constant) {
|
||||
bfd.value =
|
||||
pool.alloc_single_element_form<ConstantTokenElement>(nullptr, *constant.enum_constant);
|
||||
} else {
|
||||
bfd.value = pool.alloc_single_element_form<SimpleAtomElement>(
|
||||
nullptr, SimpleAtom::make_int_constant(constant.value));
|
||||
}
|
||||
|
||||
return bfd;
|
||||
}
|
||||
|
||||
@@ -426,7 +456,7 @@ Form* cast_to_bitfield(const BitFieldType* type_info,
|
||||
in = strip_int_or_uint_cast(in);
|
||||
// check if it's just a constant:
|
||||
auto in_as_atom = form_as_atom(in);
|
||||
if (in_as_atom) {
|
||||
if (in_as_atom && in_as_atom->is_int()) {
|
||||
auto fields = decompile_bitfield_from_int(typespec, env.dts->ts, in_as_atom->get_int());
|
||||
return pool.alloc_single_element_form<BitfieldStaticDefElement>(nullptr, typespec, fields,
|
||||
pool);
|
||||
@@ -458,7 +488,8 @@ Form* cast_to_bitfield(const BitFieldType* type_info,
|
||||
|
||||
// now variables
|
||||
for (auto& arg : args) {
|
||||
auto maybe_field = get_bitfield_initial_set(arg, type_info, env.dts->ts);
|
||||
auto maybe_field =
|
||||
get_bitfield_initial_set(strip_int_or_uint_cast(arg), type_info, env.dts->ts);
|
||||
if (!maybe_field) {
|
||||
// failed, just return cast.
|
||||
return pool.alloc_single_element_form<CastElement>(nullptr, typespec, in);
|
||||
@@ -503,16 +534,19 @@ Form* cast_to_int_enum(const EnumType* type_info,
|
||||
assert(!type_info->is_bitfield());
|
||||
auto integer = get_goal_integer_constant(strip_int_or_uint_cast(in), env);
|
||||
if (integer) {
|
||||
auto entry =
|
||||
decompile_int_enum_from_int(TypeSpec(type_info->get_name()), env.dts->ts, *integer);
|
||||
auto oper = GenericOperator::make_function(
|
||||
pool.alloc_single_element_form<ConstantTokenElement>(nullptr, type_info->get_name()));
|
||||
return pool.alloc_single_element_form<GenericElement>(
|
||||
nullptr, oper, pool.alloc_single_element_form<ConstantTokenElement>(nullptr, entry));
|
||||
return cast_to_int_enum(type_info, pool, env, *integer);
|
||||
} else {
|
||||
// all failed, just return whatever.
|
||||
return pool.alloc_single_element_form<CastElement>(nullptr, typespec, in);
|
||||
}
|
||||
}
|
||||
|
||||
Form* cast_to_int_enum(const EnumType* type_info, FormPool& pool, const Env& env, s64 in) {
|
||||
auto entry = decompile_int_enum_from_int(TypeSpec(type_info->get_name()), env.dts->ts, in);
|
||||
auto oper = GenericOperator::make_function(
|
||||
pool.alloc_single_element_form<ConstantTokenElement>(nullptr, type_info->get_name()));
|
||||
return pool.alloc_single_element_form<GenericElement>(
|
||||
nullptr, oper, pool.alloc_single_element_form<ConstantTokenElement>(nullptr, entry));
|
||||
}
|
||||
|
||||
} // namespace decompiler
|
||||
@@ -54,6 +54,30 @@ struct BitfieldManip {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string print() const {
|
||||
switch (kind) {
|
||||
case Kind::LEFT_SHIFT:
|
||||
return "left-shift";
|
||||
case Kind::RIGHT_SHIFT_LOGICAL:
|
||||
return "right-shift-logical";
|
||||
case Kind::RIGHT_SHIFT_LOGICAL_32BIT:
|
||||
return "right-shift-logical32";
|
||||
case Kind::LOGAND_WITH_CONSTANT_INT:
|
||||
return "logand-constant";
|
||||
case Kind::LOGIOR_WITH_CONSTANT_INT:
|
||||
return "logior-constant";
|
||||
case Kind::LOGIOR_WITH_FORM:
|
||||
return "logior-form";
|
||||
case Kind::LOGAND_WITH_FORM:
|
||||
return "logand-form";
|
||||
case Kind::NONZERO_COMPARE:
|
||||
return "nonzero-compare";
|
||||
case Kind::INVALID:
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
BitfieldManip() = default;
|
||||
};
|
||||
@@ -153,6 +177,8 @@ Form* cast_to_int_enum(const EnumType* type_info,
|
||||
const Env& env,
|
||||
Form* in);
|
||||
|
||||
Form* cast_to_int_enum(const EnumType* type_info, FormPool& pool, const Env& env, s64 in);
|
||||
|
||||
std::optional<u64> get_goal_integer_constant(Form* in, const Env&);
|
||||
|
||||
const BitField& find_field(const TypeSystem& ts,
|
||||
|
||||
@@ -275,7 +275,11 @@ void ObjectFileDB::ir2_atomic_op_pass() {
|
||||
func.ir2.atomic_ops_attempted = true;
|
||||
attempted++;
|
||||
try {
|
||||
auto ops = convert_function_to_atomic_ops(func, data.linked_data.labels, func.warnings);
|
||||
bool inline_asm =
|
||||
get_config().hint_inline_assembly_functions.find(func.guessed_name.to_string()) !=
|
||||
get_config().hint_inline_assembly_functions.end();
|
||||
auto ops = convert_function_to_atomic_ops(func, data.linked_data.labels, func.warnings,
|
||||
inline_asm);
|
||||
func.ir2.atomic_ops = std::make_shared<FunctionAtomicOps>(std::move(ops));
|
||||
func.ir2.atomic_ops_succeeded = true;
|
||||
func.ir2.env.set_end_var(func.ir2.atomic_ops->end_op().return_var());
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace decompiler {
|
||||
|
||||
namespace {
|
||||
|
||||
std::unique_ptr<AtomicOp> convert_1(const Instruction& i0, int idx);
|
||||
std::unique_ptr<AtomicOp> convert_1(const Instruction& i0, int idx, bool hint_inline_asm);
|
||||
|
||||
//////////////////////
|
||||
// Register Helpers
|
||||
@@ -67,6 +67,9 @@ RegisterAccess make_dst_var(const Instruction& i, int idx) {
|
||||
////////////////////////
|
||||
|
||||
SimpleAtom make_src_atom(Register reg, int idx) {
|
||||
if (reg == Register(Reg::GPR, Reg::R0)) {
|
||||
return SimpleAtom::make_int_constant(0);
|
||||
}
|
||||
return SimpleAtom::make_var(make_src_var(reg, idx));
|
||||
}
|
||||
|
||||
@@ -399,7 +402,7 @@ std::unique_ptr<AtomicOp> make_branch(const IR2_Condition& condition,
|
||||
if (branch_delay.is_known()) {
|
||||
return std::make_unique<BranchOp>(likely, condition, dest_label, branch_delay, my_idx);
|
||||
} else {
|
||||
auto delay_op = std::shared_ptr<AtomicOp>(convert_1(delay, my_idx));
|
||||
auto delay_op = std::shared_ptr<AtomicOp>(convert_1(delay, my_idx, false));
|
||||
return std::make_unique<AsmBranchOp>(likely, condition, dest_label, delay_op, my_idx);
|
||||
}
|
||||
}
|
||||
@@ -707,7 +710,7 @@ std::unique_ptr<AtomicOp> convert_bnel_1(const Instruction& i0, int idx, bool li
|
||||
return make_branch_no_delay(condition, likely, dest, idx);
|
||||
}
|
||||
|
||||
std::unique_ptr<AtomicOp> convert_1(const Instruction& i0, int idx) {
|
||||
std::unique_ptr<AtomicOp> convert_1(const Instruction& i0, int idx, bool hint_inline_asm) {
|
||||
switch (i0.kind) {
|
||||
case InstructionKind::OR:
|
||||
return convert_or_1(i0, idx);
|
||||
@@ -715,6 +718,12 @@ std::unique_ptr<AtomicOp> convert_1(const Instruction& i0, int idx) {
|
||||
return convert_ori_1(i0, idx);
|
||||
case InstructionKind::AND:
|
||||
return make_3reg_op(i0, SimpleExpression::Kind::AND, idx);
|
||||
case InstructionKind::PCPYLD:
|
||||
if (hint_inline_asm) {
|
||||
break;
|
||||
} else {
|
||||
return make_3reg_op(i0, SimpleExpression::Kind::PCPYLD, idx);
|
||||
}
|
||||
case InstructionKind::MTC1:
|
||||
return convert_mtc1_1(i0, idx);
|
||||
case InstructionKind::MFC1:
|
||||
@@ -835,6 +844,7 @@ std::unique_ptr<AtomicOp> convert_1(const Instruction& i0, int idx) {
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
///////////////////////
|
||||
@@ -1406,7 +1416,8 @@ int convert_block_to_atomic_ops(int begin_idx,
|
||||
std::vector<Instruction>::const_iterator end,
|
||||
const std::vector<DecompilerLabel>& labels,
|
||||
FunctionAtomicOps* container,
|
||||
DecompWarnings& warnings) {
|
||||
DecompWarnings& warnings,
|
||||
bool hint_inline_asm) {
|
||||
container->block_id_to_first_atomic_op.push_back(container->ops.size());
|
||||
for (auto& instr = begin; instr < end;) {
|
||||
// how many instructions can we look at, at most?
|
||||
@@ -1461,7 +1472,7 @@ int convert_block_to_atomic_ops(int begin_idx,
|
||||
|
||||
if (!converted) {
|
||||
// try 1 instruction
|
||||
op = convert_1(*instr, op_idx);
|
||||
op = convert_1(*instr, op_idx, hint_inline_asm);
|
||||
if (op) {
|
||||
converted = true;
|
||||
length = 1;
|
||||
@@ -1502,7 +1513,8 @@ int convert_block_to_atomic_ops(int begin_idx,
|
||||
|
||||
FunctionAtomicOps convert_function_to_atomic_ops(const Function& func,
|
||||
const std::vector<DecompilerLabel>& labels,
|
||||
DecompWarnings& warnings) {
|
||||
DecompWarnings& warnings,
|
||||
bool hint_inline_asm) {
|
||||
FunctionAtomicOps result;
|
||||
|
||||
int last_op = 0;
|
||||
@@ -1512,8 +1524,8 @@ FunctionAtomicOps convert_function_to_atomic_ops(const Function& func,
|
||||
if (block.end_word > block.start_word) {
|
||||
auto begin = func.instructions.begin() + block.start_word;
|
||||
auto end = func.instructions.begin() + block.end_word;
|
||||
last_op =
|
||||
convert_block_to_atomic_ops(block.start_word, begin, end, labels, &result, warnings);
|
||||
last_op = convert_block_to_atomic_ops(block.start_word, begin, end, labels, &result, warnings,
|
||||
hint_inline_asm);
|
||||
if (i == int(func.basic_blocks.size()) - 1) {
|
||||
// we're the last block. insert the function end op.
|
||||
result.ops.push_back(std::make_unique<FunctionEndOp>(int(result.ops.size())));
|
||||
|
||||
@@ -47,12 +47,14 @@ int convert_block_to_atomic_ops(int begin_idx,
|
||||
std::vector<Instruction>::const_iterator end,
|
||||
const std::vector<DecompilerLabel>& labels,
|
||||
FunctionAtomicOps* container,
|
||||
DecompWarnings& warnings);
|
||||
DecompWarnings& warnings,
|
||||
bool inline_asm_hint = false);
|
||||
|
||||
/*!
|
||||
* Convert an entire function to AtomicOps
|
||||
*/
|
||||
FunctionAtomicOps convert_function_to_atomic_ops(const Function& func,
|
||||
const std::vector<DecompilerLabel>& labels,
|
||||
DecompWarnings& warnings);
|
||||
DecompWarnings& warnings,
|
||||
bool hint_inline_asm);
|
||||
} // namespace decompiler
|
||||
@@ -55,6 +55,8 @@ void set_config(const std::string& path_to_config_file) {
|
||||
gConfig.analyze_expressions = cfg.at("analyze_expressions").get<bool>();
|
||||
gConfig.run_ir2 = cfg.at("run_ir2").get<bool>();
|
||||
gConfig.insert_lets = cfg.at("insert_lets").get<bool>();
|
||||
gConfig.hint_inline_assembly_functions =
|
||||
cfg.at("inline_asm_hint").get<std::unordered_set<std::string>>();
|
||||
|
||||
std::vector<std::string> asm_functions_by_name =
|
||||
cfg.at("asm_functions_by_name").get<std::vector<std::string>>();
|
||||
|
||||
@@ -78,6 +78,8 @@ struct Config {
|
||||
std::unordered_map<std::string, std::unordered_map<std::string, LabelType>> label_types;
|
||||
std::unordered_map<std::string, std::vector<StackVariableHint>> stack_var_hints_by_function;
|
||||
bool run_ir2 = false;
|
||||
|
||||
std::unordered_set<std::string> hint_inline_assembly_functions;
|
||||
};
|
||||
|
||||
Config& get_config();
|
||||
|
||||
@@ -2881,14 +2881,32 @@
|
||||
:flag-assert #x900000008
|
||||
)
|
||||
|
||||
(define-extern psm-size (function int int))
|
||||
(define-extern psm-page-height (function int int))
|
||||
(define-extern psm->string (function int string))
|
||||
(defenum gs-psm
|
||||
:bitfield #f
|
||||
:type uint8
|
||||
(ct32 0)
|
||||
(ct24 1)
|
||||
(ct16 2)
|
||||
(ct16s 10)
|
||||
(mt8 19)
|
||||
(mt4 20)
|
||||
(mt8h 27)
|
||||
(mt4hl 36)
|
||||
(mt4hh 44)
|
||||
(mz32 48)
|
||||
(mz24 49)
|
||||
(mz16 50)
|
||||
(mz16s 58)
|
||||
)
|
||||
|
||||
(define-extern psm-size (function gs-psm int))
|
||||
(define-extern psm-page-height (function gs-psm int))
|
||||
(define-extern psm->string (function gs-psm string))
|
||||
|
||||
(deftype gs-display-fb (uint64)
|
||||
((fbp uint16 :offset 0 :size 9)
|
||||
(fbw uint8 :offset 9 :size 6)
|
||||
(psm uint8 :offset 15 :size 5)
|
||||
(psm gs-psm :offset 15 :size 5)
|
||||
(dbx uint16 :offset 32 :size 11)
|
||||
(dby uint16 :offset 43 :size 11)
|
||||
)
|
||||
@@ -3300,7 +3318,13 @@
|
||||
:flag-assert #x900000004
|
||||
)
|
||||
(deftype gif-tag64 (uint64)
|
||||
()
|
||||
((nloop uint16 :offset 0 :size 15)
|
||||
(eop uint8 :offset 15 :size 1)
|
||||
(id uint16 :offset 32 :size 14)
|
||||
(pre uint8 :offset 46 :size 1)
|
||||
(prim uint16 :offset 47 :size 11)
|
||||
(flg uint8 :offset 58 :size 2)
|
||||
(nreg uint8 :offset 60 :size 4))
|
||||
:flag-assert #x900000008
|
||||
)
|
||||
(deftype gif-tag (uint128)
|
||||
@@ -3331,12 +3355,55 @@
|
||||
:flag-assert #x900000010
|
||||
)
|
||||
|
||||
(defenum gs-reg-id
|
||||
:bitfield #f
|
||||
:type uint8
|
||||
(prim 0)
|
||||
(rgbaq 1)
|
||||
(st 2)
|
||||
(uv 3)
|
||||
(xyzf2 4)
|
||||
(xyz2 5)
|
||||
(tex0-1 6)
|
||||
(tex0-2 7)
|
||||
(clamp-1 8)
|
||||
(clamp-2 9)
|
||||
(fog 10)
|
||||
(xyzf3 12)
|
||||
(xyz3 13)
|
||||
(a+d 14)
|
||||
(nop 15)
|
||||
)
|
||||
|
||||
(deftype gif-tag-regs (uint64)
|
||||
((regs0 gs-reg-id :offset 0 :size 4)
|
||||
(regs1 gs-reg-id :offset 4 :size 4)
|
||||
(regs2 gs-reg-id :offset 8 :size 4)
|
||||
(regs3 gs-reg-id :offset 12 :size 4)
|
||||
(regs4 gs-reg-id :offset 16 :size 4)
|
||||
(regs5 gs-reg-id :offset 20 :size 4)
|
||||
(regs6 gs-reg-id :offset 24 :size 4)
|
||||
(regs7 gs-reg-id :offset 28 :size 4)
|
||||
(regs8 gs-reg-id :offset 32 :size 4)
|
||||
(regs9 gs-reg-id :offset 36 :size 4)
|
||||
(regs10 gs-reg-id :offset 40 :size 4)
|
||||
(regs11 gs-reg-id :offset 44 :size 4)
|
||||
(regs12 gs-reg-id :offset 48 :size 4)
|
||||
(regs13 gs-reg-id :offset 52 :size 4)
|
||||
(regs14 gs-reg-id :offset 56 :size 4)
|
||||
(regs15 gs-reg-id :offset 60 :size 4)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
(deftype gs-gif-tag (structure)
|
||||
((qword uint128 :offset-assert 0) ;; is "qword" and inline? in game
|
||||
(dword uint64 2 :offset 0)
|
||||
(word uint32 4 :offset 0)
|
||||
(tag uint64 :offset 0)
|
||||
(regs uint64 :offset 8)
|
||||
|
||||
(tag gif-tag64 :offset 0)
|
||||
(regs gif-tag-regs :offset 8)
|
||||
|
||||
(dword uint64 2 :offset 0)
|
||||
(word uint32 4 :offset 0)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x10
|
||||
@@ -3350,8 +3417,9 @@
|
||||
|
||||
(deftype gif-packet (basic)
|
||||
((reg-count int32 :offset-assert 4)
|
||||
(gif-tag0 uint128 :offset-assert 16)
|
||||
(gif-tag gs-gif-tag :inline :offset 16) ;; note- added
|
||||
|
||||
(gif-tag gs-gif-tag :inline :offset-assert 16) ;; note- added
|
||||
(gif-tag0 uint128 :offset 16)
|
||||
(args uint64 1 :offset-assert 32)
|
||||
|
||||
)
|
||||
@@ -3627,15 +3695,15 @@
|
||||
(define-extern vector-cvt.s.w! (function vector vector vector))
|
||||
(define-extern rot-zxy-from-vector! (function vector vector vector))
|
||||
(define-extern rot-zyx-from-vector! (function vector vector vector))
|
||||
(define-extern vector-lerp! (function vector vector vector))
|
||||
(define-extern vector-lerp-clamp! (function vector vector float float vector))
|
||||
(define-extern vector4-lerp! (function vector vector vector))
|
||||
(define-extern vector4-lerp-clamp! (function vector vector float float vector))
|
||||
(define-extern vector-lerp! (function vector vector vector float vector))
|
||||
(define-extern vector-lerp-clamp! (function vector vector vector float vector))
|
||||
(define-extern vector4-lerp! (function vector vector vector float vector))
|
||||
(define-extern vector4-lerp-clamp! (function vector vector vector float vector))
|
||||
(define-extern vector-degi (function vector vector vector))
|
||||
(define-extern vector-degf (function vector vector vector))
|
||||
(define-extern vector-degmod (function vector vector vector))
|
||||
(define-extern vector-deg-diff (function vector vector vector vector))
|
||||
(define-extern vector-deg-lerp-clamp! function) ;; todo
|
||||
(define-extern vector-deg-lerp-clamp! (function vector vector vector float vector)) ;; todo
|
||||
(define-extern vector3s-copy! (function vector vector vector))
|
||||
(define-extern vector3s+! (function vector vector vector vector))
|
||||
(define-extern vector3s*float! (function vector vector float vector))
|
||||
@@ -3643,7 +3711,7 @@
|
||||
(define-extern spheres-overlap? (function vector vector symbol))
|
||||
(define-extern sphere<-vector! (function sphere vector sphere))
|
||||
(define-extern sphere<-vector+r! (function sphere vector float sphere))
|
||||
(define-extern rand-vu-sphere-point! function) ;; todo
|
||||
(define-extern rand-vu-sphere-point! (function vector sphere vector)) ;; todo
|
||||
|
||||
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
@@ -97,6 +97,8 @@
|
||||
|
||||
"no_type_analysis_functions_by_name":[],
|
||||
|
||||
// this provides a hint to the decompiler that these functions will have a lot of inline assembly.
|
||||
"inline_asm_hint":["matrix-transpose!"],
|
||||
|
||||
"asm_functions_by_name":[
|
||||
// gcommon
|
||||
|
||||
@@ -123,9 +123,13 @@
|
||||
["L41", "float", true]
|
||||
],
|
||||
|
||||
"dma-disasm": [["L148", "(array vif-disasm-element)", true]],
|
||||
"gs": [["L53", "gif-tag64", true],
|
||||
["L51", "gif-tag-regs", true],
|
||||
["L52", "uint64", true]],
|
||||
|
||||
"loader-h": [["L10", "float", true]],
|
||||
|
||||
"dma-disasm": [["L148", "(array vif-disasm-element)", true]],
|
||||
"level-h": [["L3", "level-group", true]],
|
||||
|
||||
"level-info": [
|
||||
@@ -377,6 +381,7 @@
|
||||
"collide-edge-grab-h": [["L1", "collide-edge-work", true]],
|
||||
|
||||
"vector": [
|
||||
["L114", "float", true],
|
||||
["L113", "float", true],
|
||||
["L112", "float", true],
|
||||
["L111", "float", true]
|
||||
|
||||
@@ -211,6 +211,13 @@
|
||||
[334, "v1", "(pointer uint64)"]
|
||||
],
|
||||
|
||||
"default-buffer-init": [
|
||||
[[8, 15], "a1", "dma-gif-packet"],
|
||||
[[18, 24], "a1", "gs-gif-tag"],
|
||||
[[29, 64], "a1", "(pointer uint64)"],
|
||||
[[69, 72], "a0", "dma-packet"]
|
||||
],
|
||||
|
||||
// LEVEL
|
||||
"lookup-level-info": [
|
||||
[3, "a1", "symbol"],
|
||||
|
||||
@@ -762,15 +762,15 @@
|
||||
"default-buffer-init": {
|
||||
"args": ["buff"],
|
||||
"vars": {
|
||||
"v1-0": "buff",
|
||||
"v1-1": "buff",
|
||||
"v1-3": "buff",
|
||||
"v1-4": "buff",
|
||||
"a1-4": "tag",
|
||||
"a1-6": "tag2",
|
||||
"a1-8": "data",
|
||||
"a0-1": "tag3",
|
||||
"v1-2": "buff"
|
||||
"v1-0": "buff-ptr",
|
||||
"v1-1": "buff-ptr2",
|
||||
"v1-3": "buff-ptr3",
|
||||
"v1-4": "buff-ptr4",
|
||||
"a1-4": ["packet", "dma-gif-packet"],
|
||||
"a1-6": ["gif-tag", "gs-gif-tag"],
|
||||
"a1-8": ["data", "(pointer uint64)"],
|
||||
"a0-1": ["ret-packet", "dma-packet"],
|
||||
"v1-2": "buff-ptr5"
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -532,7 +532,11 @@ goos::Object bitfield_defs_print(const TypeSpec& type,
|
||||
std::vector<goos::Object> result;
|
||||
result.push_back(pretty_print::to_symbol(fmt::format("new 'static '{}", type.print())));
|
||||
for (auto& def : defs) {
|
||||
if (def.is_signed) {
|
||||
if (def.enum_constant) {
|
||||
assert(false); // this is untested.
|
||||
result.push_back(
|
||||
pretty_print::to_symbol(fmt::format(":{} {}", def.field_name, *def.enum_constant)));
|
||||
} else if (def.is_signed) {
|
||||
result.push_back(
|
||||
pretty_print::to_symbol(fmt::format(":{} {}", def.field_name, (s64)def.value)));
|
||||
} else {
|
||||
@@ -865,6 +869,11 @@ std::vector<BitFieldConstantDef> decompile_bitfield_from_int(const TypeSpec& typ
|
||||
def.value = bitfield_value;
|
||||
def.field_name = field.name();
|
||||
def.is_signed = is_signed;
|
||||
auto enum_info = ts.try_enum_lookup(field.type());
|
||||
if (enum_info && !enum_info->is_bitfield()) {
|
||||
auto name = decompile_int_enum_from_int(field.type(), ts, bitfield_value);
|
||||
def.enum_constant = fmt::format("({} {})", field.type().print(), name);
|
||||
}
|
||||
result.push_back(def);
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ goos::Object decompile_bitfield(const TypeSpec& type,
|
||||
struct BitFieldConstantDef {
|
||||
bool is_signed = false;
|
||||
u64 value = -1;
|
||||
std::optional<std::string> enum_constant;
|
||||
std::string field_name;
|
||||
};
|
||||
|
||||
|
||||
+251
-153
@@ -34,69 +34,81 @@
|
||||
;; 50 = PSMZ16
|
||||
;; 58 = PSMZ16S
|
||||
|
||||
(defconstant TEX_MZ16S 58)
|
||||
(defconstant TEX_MZ16 50)
|
||||
(defconstant TEX_MZ24 49)
|
||||
(defconstant TEX_MZ32 48)
|
||||
(defconstant TEX_MT4HH 44)
|
||||
(defconstant TEX_MT4HL 36)
|
||||
(defconstant TEX_MT8H 27)
|
||||
(defconstant TEX_MT4 20)
|
||||
(defconstant TEX_MT8 19)
|
||||
(defconstant TEX_CT16S 10)
|
||||
(defconstant TEX_CT16 2)
|
||||
(defconstant TEX_CT24 1)
|
||||
(defconstant TEX_CT32 0)
|
||||
|
||||
(defun psm-size ((arg0 int))
|
||||
"Not sure exactly what 'size' means, but this likely takes a texture format as an input."
|
||||
(cond
|
||||
((= arg0 TEX_MT8) 64)
|
||||
((= arg0 TEX_MT4) 32)
|
||||
(else
|
||||
(if (or (= arg0 TEX_CT16) (= arg0 TEX_CT16S) (= arg0 TEX_MZ16) (= arg0 TEX_MZ16S))
|
||||
128
|
||||
256
|
||||
)
|
||||
(defenum gs-psm
|
||||
:bitfield #f
|
||||
:type uint8
|
||||
(ct32 0)
|
||||
(ct24 1)
|
||||
(ct16 2)
|
||||
(ct16s 10)
|
||||
(mt8 19)
|
||||
(mt4 20)
|
||||
(mt8h 27)
|
||||
(mt4hl 36)
|
||||
(mt4hh 44)
|
||||
(mz32 48)
|
||||
(mz24 49)
|
||||
(mz16 50)
|
||||
(mz16s 58)
|
||||
)
|
||||
|
||||
(defun psm-size ((arg0 gs-psm))
|
||||
"Convert texture format to some type of size."
|
||||
(cond
|
||||
((= arg0 (gs-psm mt8)) 64)
|
||||
((= arg0 (gs-psm mt4)) 32)
|
||||
(else
|
||||
(if (or (= arg0 (gs-psm ct16))
|
||||
(= arg0 (gs-psm ct16s))
|
||||
(= arg0 (gs-psm mz16))
|
||||
(= arg0 (gs-psm mz16s))
|
||||
)
|
||||
128
|
||||
256
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defun psm-page-height ((arg0 int))
|
||||
"texture format -> page height?"
|
||||
(defun psm-page-height ((arg0 gs-psm))
|
||||
"Convert texture format to some type of page height"
|
||||
(cond
|
||||
((= arg0 TEX_MT8) 64)
|
||||
((= arg0 TEX_MT4) 128)
|
||||
(else
|
||||
(if (or (= arg0 TEX_CT16) (= arg0 TEX_CT16S) (= arg0 TEX_MZ16) (= arg0 TEX_MZ16S))
|
||||
64
|
||||
32
|
||||
)
|
||||
((= arg0 (gs-psm mt8)) 64)
|
||||
((= arg0 (gs-psm mt4)) 128)
|
||||
(else
|
||||
(if (or (= arg0 (gs-psm ct16))
|
||||
(= arg0 (gs-psm ct16s))
|
||||
(= arg0 (gs-psm mz16))
|
||||
(= arg0 (gs-psm mz16s))
|
||||
)
|
||||
64
|
||||
32
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
(defun psm->string ((arg0 int))
|
||||
"Convert texture format to its name"
|
||||
(local-vars (v1-0 int))
|
||||
(set! v1-0 arg0)
|
||||
(cond
|
||||
((= v1-0 TEX_MZ16S) "mz16s")
|
||||
((= v1-0 TEX_MZ16) "mz16")
|
||||
((= v1-0 TEX_MZ24) "mz24")
|
||||
((= v1-0 TEX_MZ32) "mz32")
|
||||
((= v1-0 TEX_MT4HH) "mt4hh")
|
||||
((= v1-0 TEX_MT4HL) "mt4hl")
|
||||
((= v1-0 TEX_MT8H) "mt8h")
|
||||
((= v1-0 TEX_MT4) "mt4")
|
||||
((= v1-0 TEX_MT8) "mt8")
|
||||
((= v1-0 TEX_CT16S) "ct16s")
|
||||
((= v1-0 TEX_CT16) "ct16")
|
||||
((= v1-0 TEX_CT24) "ct24")
|
||||
((zero? v1-0) "ct32")
|
||||
(else "*unknown*")
|
||||
)
|
||||
(defun psm->string ((arg0 gs-psm))
|
||||
"Get the name of a texture format."
|
||||
(let ((v1-0 arg0))
|
||||
(cond
|
||||
((= v1-0 (gs-psm mz16s)) "mz16s")
|
||||
((= v1-0 (gs-psm mz16)) "mz16")
|
||||
((= v1-0 (gs-psm mz24)) "mz24")
|
||||
((= v1-0 (gs-psm mz32)) "mz32")
|
||||
((= v1-0 (gs-psm mt4hh)) "mt4hh")
|
||||
((= v1-0 (gs-psm mt4hl)) "mt4hl")
|
||||
((= v1-0 (gs-psm mt8h)) "mt8h")
|
||||
((= v1-0 (gs-psm mt4)) "mt4")
|
||||
((= v1-0 (gs-psm mt8)) "mt8")
|
||||
((= v1-0 (gs-psm ct16s)) "ct16s")
|
||||
((= v1-0 (gs-psm ct16)) "ct16")
|
||||
((= v1-0 (gs-psm ct24)) "ct24")
|
||||
((zero? v1-0) "ct32")
|
||||
(else "*unknown*")
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
;; the GS's DISPFB registers make settings for the frame buffer regarding information on
|
||||
@@ -105,12 +117,13 @@
|
||||
(deftype gs-display-fb (uint64)
|
||||
((fbp uint16 :offset 0 :size 9)
|
||||
(fbw uint8 :offset 9 :size 6)
|
||||
(psm uint8 :offset 15 :size 5)
|
||||
(psm gs-psm :offset 15 :size 5)
|
||||
(dbx uint16 :offset 32 :size 11)
|
||||
(dby uint16 :offset 43 :size 11)
|
||||
)
|
||||
:flag-assert #x900000008
|
||||
)
|
||||
|
||||
;; the GS's DISPLAY registers make settings for the display position on the screen regarding
|
||||
;; information on Rectangular Area Read Output Circuit n for the PCRTC.
|
||||
;; write-only
|
||||
@@ -124,6 +137,7 @@
|
||||
)
|
||||
:flag-assert #x900000008
|
||||
)
|
||||
|
||||
;; the GS's BGCOLOR register sets the background color of the PCRTC with RGB value.
|
||||
;; write-only
|
||||
(deftype gs-bgcolor (uint64)
|
||||
@@ -133,6 +147,7 @@
|
||||
)
|
||||
:flag-assert #x900000008
|
||||
)
|
||||
|
||||
;; the GS's CSR register sets and obtains various GS statuses.
|
||||
;; read-write. the fields have different effects depending on whether they're being read from
|
||||
;; or written to.
|
||||
@@ -175,6 +190,7 @@
|
||||
:size-assert #x1048
|
||||
:flag-assert #x900001048
|
||||
)
|
||||
|
||||
;; the GS's FRAME registers store various settings related to the frame buffer.
|
||||
(deftype gs-frame (uint64)
|
||||
((fbp uint16 :offset 0 :size 9)
|
||||
@@ -184,6 +200,7 @@
|
||||
)
|
||||
:flag-assert #x900000008
|
||||
)
|
||||
|
||||
;; the GS's ZBUF registers make various settings regarding Z buffer.
|
||||
(deftype gs-zbuf (uint64)
|
||||
((zbp uint16 :offset 0 :size 9)
|
||||
@@ -517,7 +534,13 @@
|
||||
:flag-assert #x900000004
|
||||
)
|
||||
(deftype gif-tag64 (uint64)
|
||||
()
|
||||
((nloop uint16 :offset 0 :size 15)
|
||||
(eop uint8 :offset 15 :size 1)
|
||||
(id uint16 :offset 32 :size 14)
|
||||
(pre uint8 :offset 46 :size 1)
|
||||
(prim uint16 :offset 47 :size 11)
|
||||
(flg uint8 :offset 58 :size 2)
|
||||
(nreg uint8 :offset 60 :size 4))
|
||||
:flag-assert #x900000008
|
||||
)
|
||||
(deftype gif-tag (uint128)
|
||||
@@ -548,12 +571,52 @@
|
||||
:flag-assert #x900000010
|
||||
)
|
||||
|
||||
(defenum gs-reg-id
|
||||
:bitfield #f
|
||||
:type uint8
|
||||
(prim 0)
|
||||
(rgbaq 1)
|
||||
(st 2)
|
||||
(uv 3)
|
||||
(xyzf2 4)
|
||||
(xyz2 5)
|
||||
(tex0-1 6)
|
||||
(tex0-2 7)
|
||||
(clamp-1 8)
|
||||
(clamp-2 9)
|
||||
(fog 10)
|
||||
(xyzf3 12)
|
||||
(xyz3 13)
|
||||
(a+d 14)
|
||||
(nop 15)
|
||||
)
|
||||
|
||||
(deftype gif-tag-regs (uint64)
|
||||
((regs0 gs-reg-id :offset 0 :size 4)
|
||||
(regs1 gs-reg-id :offset 4 :size 4)
|
||||
(regs2 gs-reg-id :offset 8 :size 4)
|
||||
(regs3 gs-reg-id :offset 12 :size 4)
|
||||
(regs4 gs-reg-id :offset 16 :size 4)
|
||||
(regs5 gs-reg-id :offset 20 :size 4)
|
||||
(regs6 gs-reg-id :offset 24 :size 4)
|
||||
(regs7 gs-reg-id :offset 28 :size 4)
|
||||
(regs8 gs-reg-id :offset 32 :size 4)
|
||||
(regs9 gs-reg-id :offset 36 :size 4)
|
||||
(regs10 gs-reg-id :offset 40 :size 4)
|
||||
(regs11 gs-reg-id :offset 44 :size 4)
|
||||
(regs12 gs-reg-id :offset 48 :size 4)
|
||||
(regs13 gs-reg-id :offset 52 :size 4)
|
||||
(regs14 gs-reg-id :offset 56 :size 4)
|
||||
(regs15 gs-reg-id :offset 60 :size 4)
|
||||
)
|
||||
)
|
||||
|
||||
(deftype gs-gif-tag (structure)
|
||||
((qword uint128 :offset-assert 0) ;; is "qword" and inline? in game
|
||||
(tag gif-tag64 :offset 0)
|
||||
(regs gif-tag-regs :offset 8)
|
||||
(dword uint64 2 :offset 0)
|
||||
(word uint32 4 :offset 0)
|
||||
(tag uint64 :offset 0)
|
||||
(regs uint64 :offset 8)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x10
|
||||
@@ -570,66 +633,108 @@
|
||||
(define *default-regs-buffer* (new 'global 'dma-buffer 1024))
|
||||
|
||||
(defun default-buffer-init ((buff dma-buffer))
|
||||
"Puts some currently unknown gif tags in the buffer."
|
||||
(local-vars
|
||||
(tag3 gs-gif-tag)
|
||||
(tag gs-gif-tag)
|
||||
(tag2 gs-gif-tag)
|
||||
(data (pointer uint64))
|
||||
)
|
||||
;; reset the buffer base and end.
|
||||
(set! (-> buff base) (-> buff data))
|
||||
(set! (-> buff end) (&-> buff data-buffer (-> buff allocated-length)))
|
||||
"Set some GS registers back to default values. Ends with a ret dma-tag.
|
||||
This is intended to live in its own separate dma-buffer and not be added
|
||||
to the global buffer. Calling this will reset this dma-buffer."
|
||||
|
||||
;; make a tag (maybe this is actually a dma/vif tag?)
|
||||
(set! tag (the gs-gif-tag (-> buff base)))
|
||||
(set! (-> tag dword 0) #x1000000a)
|
||||
(set! (-> tag word 2) #x13000000)
|
||||
(set! (-> tag word 3) #x5000000a)
|
||||
(set! (-> buff base) (&+ (the-as pointer tag) 16))
|
||||
;; reset the buffer.
|
||||
(let ((buff-ptr buff))
|
||||
(set! (-> buff-ptr base) (-> buff-ptr data))
|
||||
(set! (-> buff-ptr end)
|
||||
(&-> buff-ptr data-buffer (-> buff-ptr allocated-length))
|
||||
)
|
||||
)
|
||||
|
||||
;; make another tag.
|
||||
(set! tag2 (the gs-gif-tag (-> buff base)))
|
||||
;; no idea what this is about, it doesn't matter.
|
||||
;;(set! a2-3 (l.d L53))
|
||||
;;(.pcpyld a2-4 r0-0 a2-3)
|
||||
(set! (-> tag2 dword 0) #x9000000000008001)
|
||||
(set! (-> tag2 dword 1) #xeeeeeeeeeeeeeeee)
|
||||
(set! (-> buff base) (&+ (the-as pointer tag2) 16))
|
||||
;; set up a GIF transfer
|
||||
(let* ((buff-ptr2 buff)
|
||||
(tag (the-as dma-gif-packet (-> buff-ptr2 base)))
|
||||
)
|
||||
;; transfer 10 quadwords
|
||||
(set! (-> tag dma-vif dma)
|
||||
(new 'static 'dma-tag :qwc #xa :id (dma-tag-id cnt))
|
||||
)
|
||||
;; flush the VIF
|
||||
(set! (-> tag dma-vif vif0)
|
||||
(new 'static 'vif-tag :cmd (vif-cmd flusha) :msk #x1)
|
||||
)
|
||||
;; DIRECT transfer to GIF.
|
||||
(set! (-> tag dma-vif vif1)
|
||||
(new 'static 'vif-tag :imm #xa :cmd (vif-cmd direct) :msk #x1)
|
||||
)
|
||||
(set! (-> buff-ptr2 base) (&+ (the-as pointer tag) 16))
|
||||
)
|
||||
|
||||
;; now some payload.
|
||||
(set! data (the (pointer uint64) (-> buff base)))
|
||||
(set! (-> data 0) 68)
|
||||
(set! (-> data 1) 66)
|
||||
(set! (-> data 2) #x10001c0)
|
||||
(set! (-> data 3) 78)
|
||||
(set! (-> data 4) #x5000e)
|
||||
(set! (-> data 5) 71)
|
||||
(set! (-> data 6) 0)
|
||||
(set! (-> data 7) 73)
|
||||
(set! (-> data 8) 5)
|
||||
(set! (-> data 9) 8)
|
||||
(set! (-> data 10) 96)
|
||||
(set! (-> data 11) 20)
|
||||
(set! (-> data 12) (shl 128 32))
|
||||
(set! (-> data 13) 59)
|
||||
(set! (-> data 14) 4)
|
||||
(set! (-> data 15) 28)
|
||||
(set! (-> data 16) *fog-color*)
|
||||
(set! (-> data 17) 61)
|
||||
(set! (-> buff base) (&-> data 18))
|
||||
;; set up for 9 registers (each reg is 1 qw + 1 qw for this tag)
|
||||
(let* ((buff-ptr5 buff)
|
||||
(gif-tag (the-as gs-gif-tag (-> buff-ptr5 base)))
|
||||
)
|
||||
;; nreg = 9 here.
|
||||
(set! (-> gif-tag tag) (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x9))
|
||||
;; this sets all the regs to a+d, but the ones after 9 are ignored.
|
||||
(set! (-> gif-tag regs)
|
||||
(new 'static 'gif-tag-regs
|
||||
:regs0 (gs-reg-id a+d)
|
||||
:regs1 (gs-reg-id a+d)
|
||||
:regs2 (gs-reg-id a+d)
|
||||
:regs3 (gs-reg-id a+d)
|
||||
:regs4 (gs-reg-id a+d)
|
||||
:regs5 (gs-reg-id a+d)
|
||||
:regs6 (gs-reg-id a+d)
|
||||
:regs7 (gs-reg-id a+d)
|
||||
:regs8 (gs-reg-id a+d)
|
||||
:regs9 (gs-reg-id a+d)
|
||||
:regs10 (gs-reg-id a+d)
|
||||
:regs11 (gs-reg-id a+d)
|
||||
:regs12 (gs-reg-id a+d)
|
||||
:regs13 (gs-reg-id a+d)
|
||||
:regs14 (gs-reg-id a+d)
|
||||
:regs15 (gs-reg-id a+d)
|
||||
)
|
||||
)
|
||||
(set! (-> buff-ptr5 base) (&+ (the-as pointer gif-tag) 16))
|
||||
)
|
||||
|
||||
;; and a final tag.
|
||||
(set! tag3 (the gs-gif-tag (-> buff base)))
|
||||
(set! (-> tag3 dword 0) #x60000000)
|
||||
(set! (-> tag3 word 2) 0)
|
||||
(set! (-> tag3 word 3) 0)
|
||||
(set! (-> buff base) (&+ (the-as pointer tag3) 16))
|
||||
;; the actual address + register data.
|
||||
(let* ((buff-ptr3 buff)
|
||||
(data (the-as (pointer uint64) (-> buff-ptr3 base)))
|
||||
)
|
||||
(set! (-> data 0) (the-as uint 68))
|
||||
(set! (-> data 1) (the-as uint 66))
|
||||
(set! (-> data 2) (the-as uint #x10001c0))
|
||||
(set! (-> data 3) (the-as uint 78))
|
||||
(set! (-> data 4) (the-as uint #x5000e))
|
||||
(set! (-> data 5) (the-as uint 71))
|
||||
(set! (-> data 6) (the-as uint 0))
|
||||
(set! (-> data 7) (the-as uint 73))
|
||||
(set! (-> data 8) (the-as uint 5))
|
||||
(set! (-> data 9) (the-as uint 8))
|
||||
(set! (-> data 10) (the-as uint 96))
|
||||
(set! (-> data 11) (the-as uint 20))
|
||||
(set! (-> data 12) (the-as uint (shl 128 32)))
|
||||
(set! (-> data 13) (the-as uint 59))
|
||||
(set! (-> data 14) (the-as uint 4))
|
||||
(set! (-> data 15) (the-as uint 28))
|
||||
(set! (-> data 16) (the-as uint *fog-color*))
|
||||
(set! (-> data 17) (the-as uint 61))
|
||||
(set! (-> buff-ptr3 base) (&+ (the-as pointer data) 144))
|
||||
)
|
||||
|
||||
;; return dma-tag.
|
||||
(let* ((buff-ptr4 buff)
|
||||
(ret-packet (the-as dma-packet (-> buff-ptr4 base)))
|
||||
)
|
||||
(set! (-> ret-packet dma) (new 'static 'dma-tag :id (dma-tag-id ret)))
|
||||
(set! (-> ret-packet vif0) (new 'static 'vif-tag))
|
||||
(set! (-> ret-packet vif1) (new 'static 'vif-tag))
|
||||
(set! (-> buff-ptr4 base) (&+ (the-as pointer ret-packet) 16))
|
||||
)
|
||||
(none)
|
||||
)
|
||||
|
||||
|
||||
(default-buffer-init *default-regs-buffer*)
|
||||
|
||||
|
||||
;; This isn't a dynamic type in the type system, but it's used as one.
|
||||
;; the array at the end is used as a dynamic array.
|
||||
;; NOTE - this gif-packet stuff seems unused. Instead dma-gif-packet is used.
|
||||
@@ -644,8 +749,8 @@
|
||||
|
||||
(deftype gif-packet (basic)
|
||||
((reg-count int32 :offset-assert 4)
|
||||
(gif-tag0 uint128 :offset-assert 16)
|
||||
(gif-tag gs-gif-tag :inline :offset 16)
|
||||
(gif-tag gs-gif-tag :inline :offset-assert 16)
|
||||
(gif-tag0 uint128 :offset 16)
|
||||
(args uint64 1 :offset-assert 32) ;; there's one here already.
|
||||
)
|
||||
(:methods
|
||||
@@ -664,40 +769,38 @@
|
||||
)
|
||||
|
||||
(defun open-gif-packet ((arg0 gif-packet))
|
||||
"Initialize a gif packet"
|
||||
"Initialize an existing gif-packet for 0 registers"
|
||||
(set! (-> arg0 reg-count) 0)
|
||||
(set! (-> arg0 gif-tag dword 1) 0)
|
||||
(set! (-> arg0 gif-tag regs) (new 'static 'gif-tag-regs))
|
||||
arg0
|
||||
)
|
||||
|
||||
(defun add-reg-gif-packet ((packet gif-packet) (reg-idx int) (reg-val int))
|
||||
"Adds a register to reglist packet."
|
||||
(local-vars (tag gs-gif-tag))
|
||||
(set! tag (-> packet gif-tag))
|
||||
;; dword 1 contains the list of registers to set. each is 4-bits.
|
||||
(set! (-> tag dword 1)
|
||||
(logior (-> tag dword 1)
|
||||
(the-as uint (ash reg-idx (shl (-> packet reg-count) 2))) ;; shift to the correct spot
|
||||
"Add a register to the packet"
|
||||
(let ((tag (-> packet gif-tag)))
|
||||
;; shift the register index into the right slot
|
||||
(set! (-> tag regs) (logior
|
||||
(-> tag regs)
|
||||
(the-as uint (ash reg-idx (shl (-> packet reg-count) 2)))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
;; ?? (-> packet args (-> packet reg-count))
|
||||
;; store the value for the register.
|
||||
(set! (-> (&-> packet args (-> packet reg-count)) 0) reg-val)
|
||||
;; increment the reg we're on.
|
||||
;; set register value and increment count.
|
||||
(set! (-> packet args (-> packet reg-count)) (the-as uint reg-val))
|
||||
(set! (-> packet reg-count) (+ (-> packet reg-count) 1))
|
||||
(none)
|
||||
)
|
||||
|
||||
(defun close-gif-packet ((arg0 gif-packet) (arg1 int))
|
||||
"Sets the lower dword of the giftag for reglist"
|
||||
(local-vars (v1-2 int) (v1-3 int))
|
||||
(set! v1-2
|
||||
(logior (logior #x400000000000001 (the-as uint (shl (-> arg0 reg-count) 60)))
|
||||
(the-as uint (shr (shl arg1 63) 48))
|
||||
)
|
||||
)
|
||||
;;(.pcpyld v1-3 r0-0 v1-2)?? GOAL compiler is confused.
|
||||
(set! (-> arg0 gif-tag dword 0) v1-2)
|
||||
(defun close-gif-packet ((arg0 gif-packet) (eop int))
|
||||
"Finish adding registers."
|
||||
(set! (-> arg0 gif-tag tag)
|
||||
(new 'static 'gif-tag64
|
||||
:nloop #x1
|
||||
:flg #x1
|
||||
:eop eop
|
||||
:nreg (-> arg0 reg-count)
|
||||
)
|
||||
)
|
||||
arg0
|
||||
)
|
||||
|
||||
@@ -727,24 +830,19 @@
|
||||
(color-0 rgba)
|
||||
)
|
||||
"Allocate and initialize a draw-context"
|
||||
(let
|
||||
((obj
|
||||
(object-new allocation type-to-make (the-as int (-> type-to-make size)))
|
||||
)
|
||||
(let ((obj (object-new allocation type-to-make (the-as int (-> type-to-make size)))))
|
||||
(let ((v1-3 (the int (* (the float org-y) (-> *video-parms* relative-y-scale))))
|
||||
(a0-2 (the int (* (the float height) (-> *video-parms* relative-y-scale))))
|
||||
)
|
||||
(set! (-> obj orgx) org-x)
|
||||
(set! (-> obj orgy) v1-3)
|
||||
(set! (-> obj orgz) #xffffff)
|
||||
(set! (-> obj width) width)
|
||||
(set! (-> obj height) a0-2)
|
||||
)
|
||||
(set! (-> obj color 0) color-0)
|
||||
obj
|
||||
)
|
||||
(let
|
||||
((v1-3 (the int (* (the float org-y) (-> *video-parms* relative-y-scale))))
|
||||
(a0-2 (the int (* (the float height) (-> *video-parms* relative-y-scale))))
|
||||
)
|
||||
(set! (-> obj orgx) org-x)
|
||||
(set! (-> obj orgy) v1-3)
|
||||
(set! (-> obj orgz) #xffffff)
|
||||
(set! (-> obj width) width)
|
||||
(set! (-> obj height) a0-2)
|
||||
)
|
||||
(set! (-> obj color 0) color-0)
|
||||
obj
|
||||
)
|
||||
)
|
||||
|
||||
(defun draw-context-set-xy ((arg0 draw-context) (x int) (y int))
|
||||
|
||||
+1176
-1036
File diff suppressed because it is too large
Load Diff
+199
-212
@@ -12,36 +12,38 @@
|
||||
;; this gets set to #f later on.
|
||||
(define *cheat-mode* #t)
|
||||
|
||||
;; data that comes directly from hardware.
|
||||
(deftype hw-cpad (basic)
|
||||
((valid uint8 :offset-assert 4)
|
||||
(status uint8 :offset-assert 5)
|
||||
(button0 uint16 :offset-assert 6)
|
||||
(rightx uint8 :offset-assert 8)
|
||||
(righty uint8 :offset-assert 9)
|
||||
(leftx uint8 :offset-assert 10)
|
||||
(lefty uint8 :offset-assert 11)
|
||||
(abutton uint8 12 :offset-assert 12)
|
||||
(dummy uint8 12 :offset-assert 24)
|
||||
((valid uint8 :offset-assert 4)
|
||||
(status uint8 :offset-assert 5)
|
||||
(button0 uint16 :offset-assert 6)
|
||||
(rightx uint8 :offset-assert 8)
|
||||
(righty uint8 :offset-assert 9)
|
||||
(leftx uint8 :offset-assert 10)
|
||||
(lefty uint8 :offset-assert 11)
|
||||
(abutton uint8 12 :offset-assert 12)
|
||||
(dummy uint8 12 :offset-assert 24)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x24
|
||||
:flag-assert #x900000024
|
||||
)
|
||||
|
||||
;; data from hardware + additional info calculated here.
|
||||
(deftype cpad-info (hw-cpad)
|
||||
((number int32 :offset-assert 36)
|
||||
(cpad-file int32 :offset-assert 40)
|
||||
(button0-abs uint32 3 :offset-assert 44) ;; bitmask of buttons, pressed or not, with history
|
||||
(button0-shadow-abs uint32 1 :offset-assert 56) ;; modify this to change button history in the future.
|
||||
(button0-rel uint32 3 :offset-assert 60) ;; bitmask of if button going down.
|
||||
(button0-abs uint32 3 :offset-assert 44) ;; bitmask of buttons, pressed or not, with history
|
||||
(button0-shadow-abs uint32 1 :offset-assert 56) ;; modify this to change button history in the future.
|
||||
(button0-rel uint32 3 :offset-assert 60) ;; bitmask of if button going down.
|
||||
(stick0-dir float :offset-assert 72)
|
||||
(stick0-speed float :offset-assert 76)
|
||||
(new-pad int32 :offset-assert 80)
|
||||
(state int32 :offset-assert 84)
|
||||
(align uint8 6 :offset-assert 88)
|
||||
(direct uint8 6 :offset-assert 94) ;; hardware control of buzzing.
|
||||
(buzz-val uint8 2 :offset-assert 100) ;; intensity for buzzing
|
||||
(buzz-time uint64 2 :offset-assert 104) ;; when to stop buzzing
|
||||
(align uint8 6 :offset-assert 88)
|
||||
(direct uint8 6 :offset-assert 94) ;; hardware control of buzzing.
|
||||
(buzz-val uint8 2 :offset-assert 100) ;; intensity for buzzing
|
||||
(buzz-time uint64 2 :offset-assert 104) ;; when to stop buzzing
|
||||
(buzz basic :offset-assert 120) ;; is vibration enabled?
|
||||
(buzz-act int32 :offset-assert 124)
|
||||
(change-time uint64 :offset-assert 128)
|
||||
@@ -54,9 +56,54 @@
|
||||
:flag-assert #x900000088
|
||||
)
|
||||
|
||||
(defun cpad-invalid! ((pad cpad-info))
|
||||
"Reset all data in a cpad-info"
|
||||
(set! (-> pad valid) (logior (-> pad valid) 128))
|
||||
(set! (-> pad button0) (the-as uint 0))
|
||||
(set! (-> pad button0-abs 0) (the-as uint 0))
|
||||
(set! (-> pad button0-shadow-abs 0) (the-as uint 0))
|
||||
(set! (-> pad button0-rel 0) (the-as uint 0))
|
||||
(dotimes (v1-2 12)
|
||||
(nop!)
|
||||
(set! (-> pad abutton v1-2) 0)
|
||||
)
|
||||
(set! (-> pad stick0-dir) 0.0)
|
||||
(set! (-> pad stick0-speed) 0.0)
|
||||
(set! (-> pad rightx) (the-as uint 128))
|
||||
(set! (-> pad righty) (the-as uint 128))
|
||||
(set! (-> pad leftx) (the-as uint 128))
|
||||
(set! (-> pad lefty) (the-as uint 128))
|
||||
(set! (-> pad align 0) (the-as uint 0))
|
||||
(set! (-> pad align 1) (the-as uint 1))
|
||||
(set! (-> pad align 2) (the-as uint 255))
|
||||
(set! (-> pad align 3) (the-as uint 255))
|
||||
(set! (-> pad align 4) (the-as uint 255))
|
||||
(set! (-> pad align 5) (the-as uint 255))
|
||||
(dotimes (v1-14 6)
|
||||
(set! (-> pad direct v1-14) 0)
|
||||
)
|
||||
;; probably a bug here, this should use v1-17 as the index.
|
||||
(dotimes (v1-17 2)
|
||||
(set! (-> pad buzz-val 0) (the-as uint 0))
|
||||
(set! (-> pad buzz-time 0) (the-as uint 0))
|
||||
)
|
||||
pad
|
||||
)
|
||||
|
||||
(defmethod new cpad-info ((alloction symbol) (type-to-make type) (idx int))
|
||||
"Allocate a new cpad-info and open the pad itself through the kernel"
|
||||
(let ((obj (object-new alloction type-to-make (the-as int (-> type-to-make size)))))
|
||||
(set! (-> obj number) idx)
|
||||
(set! (-> obj buzz) #f)
|
||||
(cpad-open obj idx) ;; kernel function.
|
||||
(cpad-invalid! obj)
|
||||
)
|
||||
)
|
||||
|
||||
;; List of controllers. It always has 2 controllers.
|
||||
(deftype cpad-list (basic)
|
||||
((num-cpads int32 :offset-assert 4)
|
||||
(cpads cpad-info 2 :offset-assert 8) ;; guess
|
||||
((num-cpads int32 :offset-assert 4)
|
||||
(cpads cpad-info 2 :offset-assert 8)
|
||||
)
|
||||
(:methods
|
||||
(new (symbol type) _type_ 0)
|
||||
@@ -66,92 +113,44 @@
|
||||
:flag-assert #x900000010
|
||||
)
|
||||
|
||||
(defun cpad-invalid! ((pad cpad-info))
|
||||
"Make everything in a cpad-info set to default"
|
||||
(local-vars (v1-2 int) (v1-14 int) (v1-17 int))
|
||||
(set! (-> pad valid) (logior (-> pad valid) 128))
|
||||
(set! (-> pad button0) 0)
|
||||
(set! (-> pad button0-abs 0) 0)
|
||||
(set! (-> pad button0-shadow-abs 0) 0)
|
||||
(set! (-> pad button0-rel 0) 0)
|
||||
(set! v1-2 0)
|
||||
(while (< v1-2 12)
|
||||
(nop!)
|
||||
(set! (-> pad abutton v1-2) 0)
|
||||
(+! v1-2 1)
|
||||
)
|
||||
(set! (-> pad stick0-dir) 0.000000)
|
||||
(set! (-> pad stick0-speed) 0.000000)
|
||||
(set! (-> pad rightx) 128)
|
||||
(set! (-> pad righty) 128)
|
||||
(set! (-> pad leftx) 128)
|
||||
(set! (-> pad lefty) 128)
|
||||
(set! (-> pad align 0) 0)
|
||||
(set! (-> pad align 1) 1)
|
||||
(set! (-> pad align 2) 255)
|
||||
(set! (-> pad align 3) 255)
|
||||
(set! (-> pad align 4) 255)
|
||||
(set! (-> pad align 5) 255)
|
||||
(set! v1-14 0)
|
||||
(while (< v1-14 6)
|
||||
(set! (-> pad direct v1-14) 0)
|
||||
(+! v1-14 1)
|
||||
)
|
||||
(set! v1-17 0)
|
||||
(while (< v1-17 2)
|
||||
(set! (-> pad buzz-val 0) 0)
|
||||
(set! (-> pad buzz-time 0) 0)
|
||||
(+! v1-17 1)
|
||||
)
|
||||
pad
|
||||
)
|
||||
|
||||
(defmethod new cpad-info ((alloction symbol) (type-to-make type) (idx int))
|
||||
"Allocate a cpad. Also opens it using functions from the kernel."
|
||||
(local-vars (obj cpad-info))
|
||||
(set! obj (object-new alloction type-to-make (the-as int (-> type-to-make size))))
|
||||
(set! (-> obj number) idx)
|
||||
(set! (-> obj buzz) #f)
|
||||
(cpad-open obj idx)
|
||||
(cpad-invalid! obj)
|
||||
)
|
||||
|
||||
(defmethod new cpad-list ((allocation symbol) (type-to-make type))
|
||||
"Allocate a cpad-list and set up two controllers, including openeing them."
|
||||
(local-vars (gp-0 cpad-list))
|
||||
(set! gp-0 (object-new allocation type-to-make (the-as int (-> type-to-make size))))
|
||||
(set! (-> gp-0 num-cpads) 2)
|
||||
(set! (-> gp-0 cpads 0) (new 'global 'cpad-info 0))
|
||||
(set! (-> gp-0 cpads 1) (new 'global 'cpad-info 1))
|
||||
gp-0
|
||||
"Create a cpad-list for 2 controllers. It's fine to do this even if one or both controllers
|
||||
aren't connected yet. "
|
||||
(let ((gp-0 (object-new allocation type-to-make (the-as int (-> type-to-make size)))))
|
||||
(set! (-> gp-0 num-cpads) 2)
|
||||
(set! (-> gp-0 cpads 0) (new 'global 'cpad-info 0))
|
||||
(set! (-> gp-0 cpads 1) (new 'global 'cpad-info 1))
|
||||
gp-0
|
||||
)
|
||||
)
|
||||
|
||||
(defun analog-input ((in int) (offset float) (center-val float) (max-val float) (out-range float))
|
||||
"Take an integer input and convert it to a float between -out-range and +out-range.
|
||||
"Convert integer input from pad into a float between -out-range and +out-range.
|
||||
The offset is applied directly to the input.
|
||||
The center val is the expected value for 0 (after offset)
|
||||
The max val is the expected value with the stick all the way pushed
|
||||
"
|
||||
(local-vars
|
||||
(max-magnitude float)
|
||||
(magnitude float)
|
||||
(offset-in float)
|
||||
)
|
||||
;; do the offset
|
||||
(set! offset-in (- (the float in) offset))
|
||||
;; figure out the absolute value of the displacement from 0.
|
||||
(set! magnitude (- (fabs offset-in) center-val))
|
||||
;; the maximum allowed magnitude
|
||||
(set! max-magnitude (- max-val center-val))
|
||||
;; if we are negative, our output range should be negative.
|
||||
(when (< offset-in 0.000000)
|
||||
(set! out-range (- out-range))
|
||||
)
|
||||
(cond
|
||||
((>= 0.000000 magnitude) 0.000000) ;; shouldn't happen
|
||||
((>= magnitude max-magnitude) out-range) ;; too big
|
||||
(else (/ (* magnitude out-range) max-magnitude)) ;; scale!
|
||||
)
|
||||
The center val is the expected value for 0, after applying offset.
|
||||
The max val is the expected value with the stick pushed all the way"
|
||||
(let* ((offset-in (- (the float in) offset)) ;; apply offset to in
|
||||
(magnitude (- (fabs offset-in) center-val)) ;; determine our magnitude
|
||||
(max-magnitude (- max-val center-val)) ;; maximum expected magnitude.
|
||||
)
|
||||
;; flip the output if negative
|
||||
(if (< offset-in 0.0)
|
||||
(set! out-range (- out-range))
|
||||
)
|
||||
;; scale and return value.
|
||||
(cond
|
||||
((>= 0.0 magnitude)
|
||||
0.0
|
||||
)
|
||||
((>= magnitude max-magnitude)
|
||||
out-range
|
||||
)
|
||||
(else
|
||||
(/ (* magnitude out-range) max-magnitude)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defun cpad-set-buzz! ((pad cpad-info) (buzz-idx int) (buzz-amount int) (duration int))
|
||||
@@ -188,125 +187,113 @@
|
||||
(define *cpad-debug* #f)
|
||||
|
||||
(defun service-cpads ()
|
||||
"Call this once a frame to read the pad, handle vibration, and process the left stick"
|
||||
(local-vars
|
||||
(v1-10 int)
|
||||
(current-button0 uint)
|
||||
(buzz-idx int)
|
||||
(pad cpad-info)
|
||||
(pad-idx int)
|
||||
(pad-list cpad-list)
|
||||
(lefty-pos float)
|
||||
(leftx-pos float)
|
||||
)
|
||||
|
||||
;; iterate through cpads.
|
||||
(set! pad-list *cpad-list*)
|
||||
(set! pad-idx 0)
|
||||
(while (< pad-idx (-> pad-list num-cpads))
|
||||
(set! pad (-> *cpad-list* cpads pad-idx))
|
||||
;; read data from pad.
|
||||
(cpad-get-data pad)
|
||||
(cond
|
||||
((zero? (logand (-> pad valid) 128))
|
||||
;; pad is valid! update buzz.
|
||||
(set! buzz-idx 0)
|
||||
(while (< buzz-idx 2)
|
||||
(cond
|
||||
;; when buzz enbaled, in buzz time, and in game mode:
|
||||
((and (-> pad buzz)
|
||||
(< (the-as int (get-current-time))
|
||||
(the-as int (-> pad buzz-time buzz-idx))
|
||||
"Read from cpads and update vibration"
|
||||
;; iterate over pads
|
||||
(let ((pad-list *cpad-list*))
|
||||
(dotimes (pad-idx (-> pad-list num-cpads))
|
||||
(let ((pad (-> *cpad-list* cpads pad-idx)))
|
||||
;; read from hardware.
|
||||
(cpad-get-data pad)
|
||||
(cond
|
||||
((zero? (logand (-> pad valid) 128))
|
||||
(dotimes (buzz-idx 2)
|
||||
(cond
|
||||
;; check if okay to buzz:
|
||||
((and (-> pad buzz)
|
||||
(< (the-as int (get-current-time))
|
||||
(the-as int (-> pad buzz-time buzz-idx))
|
||||
)
|
||||
(= *master-mode* 'game)
|
||||
)
|
||||
(let ((v1-10 buzz-idx))
|
||||
(cond
|
||||
((zero? v1-10)
|
||||
;; vibration motor 0 only has on/off. This pulses it to approximate
|
||||
;; an analog control
|
||||
(set! (-> pad direct buzz-idx)
|
||||
(logand (ash (-> pad buzz-val buzz-idx)
|
||||
(- (the-as int (logand (get-integral-current-time) 7)))
|
||||
)
|
||||
1
|
||||
)
|
||||
)
|
||||
)
|
||||
((= v1-10 1)
|
||||
;; vibration motor 1 has analog control. set the speed.
|
||||
(set! (-> pad direct buzz-idx) (-> pad buzz-val buzz-idx))
|
||||
)
|
||||
)
|
||||
(= *master-mode* 'game)
|
||||
)
|
||||
;; case statement?
|
||||
(set! v1-10 buzz-idx)
|
||||
(cond ((zero? v1-10)
|
||||
;; buzz 0, I think the small one, doesn't have analog control.
|
||||
;; I _think_ this is some clever way to pulse it at a duty cycle proportional
|
||||
;; to the desired intensity.
|
||||
(set! (-> pad direct buzz-idx)
|
||||
(logand (ash (-> pad buzz-val buzz-idx)
|
||||
(- (the-as int (logand (get-integral-current-time) 7)))
|
||||
)
|
||||
1
|
||||
)
|
||||
)
|
||||
)
|
||||
((= v1-10 1)
|
||||
;; buzz 1, the big motor can be controlled directly by the PS2.
|
||||
(set! (-> pad direct buzz-idx) (-> pad buzz-val buzz-idx))
|
||||
)
|
||||
)
|
||||
)
|
||||
(else
|
||||
;; time to stop buzzing. set buzz-val and the hardware command to 0.
|
||||
(set! (-> pad buzz-val buzz-idx) 0)
|
||||
(set! (-> pad direct buzz-idx) 0)
|
||||
)
|
||||
)
|
||||
(+! buzz-idx 1)
|
||||
)
|
||||
;; update buttons history
|
||||
(set! (-> pad button0-abs 2) (-> pad button0-abs 1))
|
||||
;; update abs history from shadow-abs
|
||||
(set! (-> pad button0-abs 1) (-> pad button0-shadow-abs 0))
|
||||
;; update rel history
|
||||
(set! (-> pad button0-rel 2) (-> pad button0-rel 1))
|
||||
(set! (-> pad button0-rel 1) (-> pad button0-rel 0))
|
||||
;; put in new buttons
|
||||
(set! current-button0 (-> pad button0))
|
||||
(set! (-> pad button0-shadow-abs 0) current-button0)
|
||||
(set! (-> pad button0-abs 0) current-button0)
|
||||
;; buttons going down
|
||||
(set! (-> pad button0-rel 0)
|
||||
(logand (-> pad button0-abs 0) (lognot (-> pad button0-abs 1)))
|
||||
)
|
||||
;; some weird leftover from debugging.
|
||||
(when *cpad-debug*
|
||||
(set! (-> pad leftx) 255)
|
||||
(set! (-> pad rightx) 255)
|
||||
)
|
||||
(set! (-> pad stick0-speed) 1.000)
|
||||
(cond
|
||||
((= (shr (-> pad status) 4) 7) ;; status that we have analog?
|
||||
(set! leftx-pos (* 0.0078125 (the float (+ (-> pad leftx) -128))))
|
||||
(set! lefty-pos (* 0.0078125 (the float (- 127 (-> pad lefty)))))
|
||||
;; heading of the stick. note that y -> -x, x -> y, so it's rotated...
|
||||
(set! (-> pad stick0-dir) (atan (- leftx-pos) lefty-pos))
|
||||
;; the "speed" is just the magnitude.
|
||||
(set! (-> pad stick0-speed) (fmin 1.0 (sqrtf (+ (* leftx-pos leftx-pos) (* lefty-pos lefty-pos)))))
|
||||
;; deadband the speed at 0.3? this seems kinda high.
|
||||
(when (< (-> pad stick0-speed) 0.3)
|
||||
(set! (-> pad stick0-speed) 0.0)
|
||||
)
|
||||
)
|
||||
(else
|
||||
;; invalid analog state, set things to safe defaults.
|
||||
(set! (-> pad leftx) 128)
|
||||
(set! (-> pad lefty) 128)
|
||||
(set! (-> pad rightx) 128)
|
||||
(set! (-> pad righty) 128)
|
||||
(set! (-> pad stick0-dir) 0.000000)
|
||||
(set! (-> pad stick0-speed) 0.0)
|
||||
)
|
||||
)
|
||||
;; did the pad change?
|
||||
(if (or (!= (-> pad button0-abs 0) (-> pad button0-abs 1)) ;; button pushed
|
||||
(or (< 0.3 (-> pad stick0-speed)) ;; stick away from origin
|
||||
(zero? (-> pad change-time)) ;; initially zero
|
||||
)
|
||||
)
|
||||
(else
|
||||
;; not okay to buzz this motor, set to zero.
|
||||
(set! (-> pad buzz-val buzz-idx) 0)
|
||||
(set! (-> pad direct buzz-idx) 0)
|
||||
)
|
||||
)
|
||||
)
|
||||
;; update button history.
|
||||
(set! (-> pad button0-abs 2) (-> pad button0-abs 1))
|
||||
(set! (-> pad button0-abs 1) (-> pad button0-shadow-abs 0))
|
||||
(set! (-> pad button0-rel 2) (-> pad button0-rel 1))
|
||||
(set! (-> pad button0-rel 1) (-> pad button0-rel 0))
|
||||
;; update current button
|
||||
(let ((current-button0 (-> pad button0)))
|
||||
(set! (-> pad button0-shadow-abs 0) current-button0)
|
||||
(set! (-> pad button0-abs 0) current-button0)
|
||||
)
|
||||
;; buttons going down
|
||||
(set! (-> pad button0-rel 0)
|
||||
(logand (-> pad button0-abs 0) (lognot (-> pad button0-abs 1)))
|
||||
)
|
||||
;; ??
|
||||
(when *cpad-debug*
|
||||
(set! (-> pad leftx) (the-as uint 255))
|
||||
(set! (-> pad rightx) (the-as uint 255))
|
||||
)
|
||||
|
||||
;; compute a speed and direction for stick0
|
||||
(set! (-> pad stick0-speed) 1.0)
|
||||
(cond
|
||||
;; check if analog is valid?
|
||||
((= (shr (-> pad status) 4) 7)
|
||||
;; compute speed and direction, with deadband.
|
||||
(let ((f30-0 (* 0.0078125 (the float (+ (-> pad leftx) -128))))
|
||||
(f28-0 (* 0.0078125 (the float (- 127 (the-as int (-> pad lefty))))))
|
||||
)
|
||||
(set! (-> pad stick0-dir) (atan (- f30-0) f28-0))
|
||||
(set! (-> pad stick0-speed)
|
||||
(fmin 1.0 (sqrtf (+ (* f30-0 f30-0) (* f28-0 f28-0))))
|
||||
)
|
||||
)
|
||||
(if (< (-> pad stick0-speed) 0.3)
|
||||
(set! (-> pad stick0-speed) 0.0)
|
||||
)
|
||||
)
|
||||
(else
|
||||
;; analog is invalid? set to zero.
|
||||
(set! (-> pad leftx) (the-as uint 128))
|
||||
(set! (-> pad lefty) (the-as uint 128))
|
||||
(set! (-> pad rightx) (the-as uint 128))
|
||||
(set! (-> pad righty) (the-as uint 128))
|
||||
(set! (-> pad stick0-dir) 0.0)
|
||||
(set! (-> pad stick0-speed) 0.0)
|
||||
)
|
||||
)
|
||||
;; if the pad was changed or stick0 pushed, update the last changed time.
|
||||
(if (or (!= (-> pad button0-abs 0) (-> pad button0-abs 1))
|
||||
(or (< 0.3 (-> pad stick0-speed)) (zero? (-> pad change-time)))
|
||||
)
|
||||
(set! (-> pad change-time) (get-current-time))
|
||||
)
|
||||
(set! (-> pad change-time) (get-current-time))
|
||||
)
|
||||
)
|
||||
(else
|
||||
;; invalid pad
|
||||
(cpad-invalid! pad)
|
||||
)
|
||||
(else
|
||||
;; invalid bits set, controller is not connected.
|
||||
(cpad-invalid! pad)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(+! pad-idx 1)
|
||||
)
|
||||
*cpad-list*
|
||||
)
|
||||
|
||||
@@ -1172,13 +1172,13 @@
|
||||
|
||||
;; these are not quite right, but it's close enough.
|
||||
(defmacro start-of-symbol-table ()
|
||||
`(rlet ((st :reg r15 :reset-here #t :type uint))
|
||||
`(rlet ((st :reg r14 :reset-here #t :type uint))
|
||||
(the uint (- st 32768))
|
||||
)
|
||||
)
|
||||
|
||||
(defmacro end-of-symbol-table ()
|
||||
`(rlet ((st :reg r15 :reset-here #t :type uint))
|
||||
`(rlet ((st :reg r14 :reset-here #t :type uint))
|
||||
(the uint (+ st 32768))
|
||||
)
|
||||
)
|
||||
|
||||
@@ -96,10 +96,10 @@ class Compiler {
|
||||
IR_VFMath2Asm::Kind kind,
|
||||
Env* env);
|
||||
|
||||
Val* compile_asm_vf_math2_imm_u8(const goos::Object& form,
|
||||
const goos::Object& rest,
|
||||
IR_VFMath2Asm::Kind kind,
|
||||
Env* env);
|
||||
Val* compile_asm_int128_math2_imm_u8(const goos::Object& form,
|
||||
const goos::Object& rest,
|
||||
IR_Int128Math2Asm::Kind kind,
|
||||
Env* env);
|
||||
|
||||
Val* compile_asm_vf_math4_two_operation(const goos::Object& form,
|
||||
const goos::Object& rest,
|
||||
|
||||
+56
-17
@@ -1523,16 +1523,11 @@ void IR_Int128Math3Asm::do_codegen(emitter::ObjectGenerator* gen,
|
||||
// AsmVF2
|
||||
///////////////////////
|
||||
|
||||
IR_VFMath2Asm::IR_VFMath2Asm(bool use_color,
|
||||
const RegVal* dst,
|
||||
const RegVal* src,
|
||||
Kind kind,
|
||||
std::optional<int64_t> imm)
|
||||
: IR_Asm(use_color), m_dst(dst), m_src(src), m_kind(kind), m_imm(std::move(imm)) {}
|
||||
IR_VFMath2Asm::IR_VFMath2Asm(bool use_color, const RegVal* dst, const RegVal* src, Kind kind)
|
||||
: IR_Asm(use_color), m_dst(dst), m_src(src), m_kind(kind) {}
|
||||
|
||||
std::string IR_VFMath2Asm::print() {
|
||||
std::string function;
|
||||
bool use_imm = false;
|
||||
switch (m_kind) {
|
||||
case Kind::ITOF:
|
||||
function = ".itof.vf";
|
||||
@@ -1540,6 +1535,56 @@ std::string IR_VFMath2Asm::print() {
|
||||
case Kind::FTOI:
|
||||
function = ".ftoi.vf";
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
return fmt::format("{}{} {}, {}", function, get_color_suffix_string(), m_dst->print(),
|
||||
m_src->print());
|
||||
}
|
||||
|
||||
RegAllocInstr IR_VFMath2Asm::to_rai() {
|
||||
RegAllocInstr rai;
|
||||
if (m_use_coloring) {
|
||||
rai.write.push_back(m_dst->ireg());
|
||||
rai.read.push_back(m_src->ireg());
|
||||
}
|
||||
return rai;
|
||||
}
|
||||
|
||||
void IR_VFMath2Asm::do_codegen(emitter::ObjectGenerator* gen,
|
||||
const AllocationResult& allocs,
|
||||
emitter::IR_Record irec) {
|
||||
auto dst = get_reg_asm(m_dst, allocs, irec, m_use_coloring);
|
||||
auto src = get_reg_asm(m_src, allocs, irec, m_use_coloring);
|
||||
|
||||
switch (m_kind) {
|
||||
case Kind::ITOF:
|
||||
gen->add_instr(IGen::itof_vf(dst, src), irec);
|
||||
break;
|
||||
case Kind::FTOI:
|
||||
gen->add_instr(IGen::ftoi_vf(dst, src), irec);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////
|
||||
// AsmInt128-2
|
||||
///////////////////////
|
||||
|
||||
IR_Int128Math2Asm::IR_Int128Math2Asm(bool use_color,
|
||||
const RegVal* dst,
|
||||
const RegVal* src,
|
||||
Kind kind,
|
||||
std::optional<int64_t> imm)
|
||||
: IR_Asm(use_color), m_dst(dst), m_src(src), m_kind(kind), m_imm(std::move(imm)) {}
|
||||
|
||||
std::string IR_Int128Math2Asm::print() {
|
||||
std::string function;
|
||||
bool use_imm = false;
|
||||
switch (m_kind) {
|
||||
case Kind::PW_SLL:
|
||||
use_imm = true;
|
||||
function = ".pw.sll";
|
||||
@@ -1582,7 +1627,7 @@ std::string IR_VFMath2Asm::print() {
|
||||
}
|
||||
}
|
||||
|
||||
RegAllocInstr IR_VFMath2Asm::to_rai() {
|
||||
RegAllocInstr IR_Int128Math2Asm::to_rai() {
|
||||
RegAllocInstr rai;
|
||||
if (m_use_coloring) {
|
||||
rai.write.push_back(m_dst->ireg());
|
||||
@@ -1591,19 +1636,13 @@ RegAllocInstr IR_VFMath2Asm::to_rai() {
|
||||
return rai;
|
||||
}
|
||||
|
||||
void IR_VFMath2Asm::do_codegen(emitter::ObjectGenerator* gen,
|
||||
const AllocationResult& allocs,
|
||||
emitter::IR_Record irec) {
|
||||
void IR_Int128Math2Asm::do_codegen(emitter::ObjectGenerator* gen,
|
||||
const AllocationResult& allocs,
|
||||
emitter::IR_Record irec) {
|
||||
auto dst = get_reg_asm(m_dst, allocs, irec, m_use_coloring);
|
||||
auto src = get_reg_asm(m_src, allocs, irec, m_use_coloring);
|
||||
|
||||
switch (m_kind) {
|
||||
case Kind::ITOF:
|
||||
gen->add_instr(IGen::itof_vf(dst, src), irec);
|
||||
break;
|
||||
case Kind::FTOI:
|
||||
gen->add_instr(IGen::ftoi_vf(dst, src), irec);
|
||||
break;
|
||||
case Kind::PW_SLL:
|
||||
// you are technically allowed to put values > 32 in here.
|
||||
assert(m_imm.has_value());
|
||||
|
||||
+23
-7
@@ -567,14 +567,14 @@ class IR_Int128Math3Asm : public IR_Asm {
|
||||
Kind m_kind;
|
||||
};
|
||||
|
||||
class IR_VFMath2Asm : public IR_Asm {
|
||||
class IR_Int128Math2Asm : public IR_Asm {
|
||||
public:
|
||||
enum class Kind { ITOF, FTOI, PW_SLL, PW_SRL, PW_SRA, VPSRLDQ, VPSLLDQ, VPSHUFLW, VPSHUFHW };
|
||||
IR_VFMath2Asm(bool use_color,
|
||||
const RegVal* dst,
|
||||
const RegVal* src,
|
||||
Kind kind,
|
||||
std::optional<int64_t> = std::nullopt);
|
||||
enum class Kind { PW_SLL, PW_SRL, PW_SRA, VPSRLDQ, VPSLLDQ, VPSHUFLW, VPSHUFHW };
|
||||
IR_Int128Math2Asm(bool use_color,
|
||||
const RegVal* dst,
|
||||
const RegVal* src,
|
||||
Kind kind,
|
||||
std::optional<int64_t> = std::nullopt);
|
||||
std::string print() override;
|
||||
RegAllocInstr to_rai() override;
|
||||
void do_codegen(emitter::ObjectGenerator* gen,
|
||||
@@ -588,6 +588,22 @@ class IR_VFMath2Asm : public IR_Asm {
|
||||
std::optional<int64_t> m_imm;
|
||||
};
|
||||
|
||||
class IR_VFMath2Asm : public IR_Asm {
|
||||
public:
|
||||
enum class Kind { ITOF, FTOI };
|
||||
IR_VFMath2Asm(bool use_color, const RegVal* dst, const RegVal* src, Kind kind);
|
||||
std::string print() override;
|
||||
RegAllocInstr to_rai() override;
|
||||
void do_codegen(emitter::ObjectGenerator* gen,
|
||||
const AllocationResult& allocs,
|
||||
emitter::IR_Record irec) override;
|
||||
|
||||
protected:
|
||||
const RegVal* m_dst = nullptr;
|
||||
const RegVal* m_src = nullptr;
|
||||
Kind m_kind;
|
||||
};
|
||||
|
||||
class IR_BlendVF : public IR_Asm {
|
||||
public:
|
||||
IR_BlendVF(bool use_color, const RegVal* dst, const RegVal* src1, const RegVal* src2, u8 mask);
|
||||
|
||||
@@ -546,10 +546,10 @@ Val* Compiler::compile_asm_vf_math2(const goos::Object& form,
|
||||
return get_none();
|
||||
}
|
||||
|
||||
Val* Compiler::compile_asm_vf_math2_imm_u8(const goos::Object& form,
|
||||
const goos::Object& rest,
|
||||
IR_VFMath2Asm::Kind kind,
|
||||
Env* env) {
|
||||
Val* Compiler::compile_asm_int128_math2_imm_u8(const goos::Object& form,
|
||||
const goos::Object& rest,
|
||||
IR_Int128Math2Asm::Kind kind,
|
||||
Env* env) {
|
||||
auto args = get_va(form, rest);
|
||||
va_check(
|
||||
form, args, {{}, {}, {}},
|
||||
@@ -561,7 +561,6 @@ Val* Compiler::compile_asm_vf_math2_imm_u8(const goos::Object& form,
|
||||
|
||||
auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(env);
|
||||
auto src = compile_error_guard(args.unnamed.at(1), env)->to_reg(env);
|
||||
check_vector_float_regs(form, env, {{"destination", dest}, {"source", src}});
|
||||
s64 imm;
|
||||
if (!try_getting_constant_integer(args.unnamed.at(2), &imm, env)) {
|
||||
throw_compiler_error(form, "Could not evaluate {} as a compile-time integer.",
|
||||
@@ -584,11 +583,11 @@ Val* Compiler::compile_asm_vf_math2_imm_u8(const goos::Object& form,
|
||||
|
||||
// If the entire destination is to be copied, we can optimize out the blend
|
||||
if (mask == 0b1111) {
|
||||
env->emit_ir<IR_VFMath2Asm>(color, dest, src, kind, imm);
|
||||
env->emit_ir<IR_Int128Math2Asm>(color, dest, src, kind, imm);
|
||||
} else {
|
||||
auto temp_reg = env->make_vfr(dest->type());
|
||||
// Perform the arithmetic operation on the two vectors into a temporary register
|
||||
env->emit_ir<IR_VFMath2Asm>(color, temp_reg, src, kind, imm);
|
||||
env->emit_ir<IR_Int128Math2Asm>(color, temp_reg, src, kind, imm);
|
||||
// Blend the result back into the destination register using the mask
|
||||
env->emit_ir<IR_BlendVF>(color, dest, dest, temp_reg, mask);
|
||||
}
|
||||
@@ -597,15 +596,15 @@ Val* Compiler::compile_asm_vf_math2_imm_u8(const goos::Object& form,
|
||||
}
|
||||
|
||||
Val* Compiler::compile_asm_pw_sll(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
return compile_asm_vf_math2_imm_u8(form, rest, IR_VFMath2Asm::Kind::PW_SLL, env);
|
||||
return compile_asm_int128_math2_imm_u8(form, rest, IR_Int128Math2Asm::Kind::PW_SLL, env);
|
||||
}
|
||||
|
||||
Val* Compiler::compile_asm_pw_srl(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
return compile_asm_vf_math2_imm_u8(form, rest, IR_VFMath2Asm::Kind::PW_SRL, env);
|
||||
return compile_asm_int128_math2_imm_u8(form, rest, IR_Int128Math2Asm::Kind::PW_SRL, env);
|
||||
}
|
||||
|
||||
Val* Compiler::compile_asm_pw_sra(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
return compile_asm_vf_math2_imm_u8(form, rest, IR_VFMath2Asm::Kind::PW_SRA, env);
|
||||
return compile_asm_int128_math2_imm_u8(form, rest, IR_Int128Math2Asm::Kind::PW_SRA, env);
|
||||
}
|
||||
|
||||
Val* Compiler::compile_asm_pextlw(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
@@ -641,12 +640,12 @@ Val* Compiler::compile_asm_ppach(const goos::Object& form, const goos::Object& r
|
||||
throw_compiler_error(form, "Cannot set destination");
|
||||
}
|
||||
|
||||
env->emit_ir<IR_VFMath2Asm>(true, temp, src1, IR_VFMath2Asm::Kind::VPSHUFLW, 0x88);
|
||||
env->emit_ir<IR_VFMath2Asm>(true, dest, src2, IR_VFMath2Asm::Kind::VPSHUFLW, 0x88);
|
||||
env->emit_ir<IR_VFMath2Asm>(true, temp, temp, IR_VFMath2Asm::Kind::VPSHUFHW, 0x88);
|
||||
env->emit_ir<IR_VFMath2Asm>(true, dest, dest, IR_VFMath2Asm::Kind::VPSHUFHW, 0x88);
|
||||
env->emit_ir<IR_VFMath2Asm>(true, temp, temp, IR_VFMath2Asm::Kind::VPSRLDQ, 4);
|
||||
env->emit_ir<IR_VFMath2Asm>(true, dest, dest, IR_VFMath2Asm::Kind::VPSRLDQ, 4);
|
||||
env->emit_ir<IR_Int128Math2Asm>(true, temp, src1, IR_Int128Math2Asm::Kind::VPSHUFLW, 0x88);
|
||||
env->emit_ir<IR_Int128Math2Asm>(true, dest, src2, IR_Int128Math2Asm::Kind::VPSHUFLW, 0x88);
|
||||
env->emit_ir<IR_Int128Math2Asm>(true, temp, temp, IR_Int128Math2Asm::Kind::VPSHUFHW, 0x88);
|
||||
env->emit_ir<IR_Int128Math2Asm>(true, dest, dest, IR_Int128Math2Asm::Kind::VPSHUFHW, 0x88);
|
||||
env->emit_ir<IR_Int128Math2Asm>(true, temp, temp, IR_Int128Math2Asm::Kind::VPSRLDQ, 4);
|
||||
env->emit_ir<IR_Int128Math2Asm>(true, dest, dest, IR_Int128Math2Asm::Kind::VPSRLDQ, 4);
|
||||
// is actually a VPUNPCKLQDQ with srcs swapped.
|
||||
env->emit_ir<IR_Int128Math3Asm>(true, dest, temp, dest, IR_Int128Math3Asm::Kind::PCPYLD);
|
||||
|
||||
|
||||
@@ -161,7 +161,7 @@ std::unique_ptr<FormRegressionTest::TestData> FormRegressionTest::make_function(
|
||||
|
||||
// convert instruction to atomic ops
|
||||
DecompWarnings warnings;
|
||||
auto ops = convert_function_to_atomic_ops(test->func, program.labels, warnings);
|
||||
auto ops = convert_function_to_atomic_ops(test->func, program.labels, warnings, false);
|
||||
test->func.ir2.atomic_ops = std::make_shared<FunctionAtomicOps>(std::move(ops));
|
||||
test->func.ir2.atomic_ops_succeeded = true;
|
||||
test->func.ir2.env.set_end_var(test->func.ir2.atomic_ops->end_op().return_var());
|
||||
|
||||
@@ -63,7 +63,17 @@
|
||||
(define-extern *listener-process* process)
|
||||
(define-extern *active-pool* process-tree)
|
||||
(define-extern reset-and-call (function thread function object))
|
||||
(define-extern ash (function int int int))
|
||||
(defun ash ((value int) (shift-amount int))
|
||||
"Arithmetic shift value by shift-amount.
|
||||
A positive shift-amount will shift to the left and a negative will shift to the right.
|
||||
"
|
||||
;; OpenGOAL does not support ash in the compiler, so we implement it here as an inline function.
|
||||
(declare (inline))
|
||||
(if (> shift-amount 0)
|
||||
(shl value shift-amount)
|
||||
(sar value (- shift-amount))
|
||||
)
|
||||
)
|
||||
(define-extern inspect-process-tree (function process-tree int int symbol process-tree))
|
||||
(define-extern set-to-run-bootstrap (function none))
|
||||
(define-extern dead-state state)
|
||||
@@ -87,6 +97,11 @@
|
||||
'(none)
|
||||
)
|
||||
|
||||
(defmacro gpr->fpr (in)
|
||||
in)
|
||||
|
||||
(define-extern get-current-time (function uint))
|
||||
(define-extern get-integral-current-time (function uint))
|
||||
|
||||
;; math
|
||||
(define-extern fabs (function float float))
|
||||
@@ -199,6 +214,75 @@
|
||||
(end 7) ;; next, but ends.
|
||||
)
|
||||
|
||||
(defenum gs-psm
|
||||
:bitfield #f
|
||||
:type uint8
|
||||
(ct32 0)
|
||||
(ct24 1)
|
||||
(ct16 2)
|
||||
(ct16s 10)
|
||||
(mt8 19)
|
||||
(mt4 20)
|
||||
(mt8h 27)
|
||||
(mt4hl 36)
|
||||
(mt4hh 44)
|
||||
(mz32 48)
|
||||
(mz24 49)
|
||||
(mz16 50)
|
||||
(mz16s 58)
|
||||
)
|
||||
(defenum gs-prim-type
|
||||
:type uint8
|
||||
(point 0)
|
||||
(line 1)
|
||||
(line-strip 2)
|
||||
(tri 3)
|
||||
(tri-strip 4)
|
||||
(tri-fan 5)
|
||||
(sprite 6)
|
||||
)
|
||||
|
||||
(defenum gs-reg-id
|
||||
:bitfield #f
|
||||
:type uint8
|
||||
(prim 0)
|
||||
(rgbaq 1)
|
||||
(st 2)
|
||||
(uv 3)
|
||||
(xyzf2 4)
|
||||
(xyz2 5)
|
||||
(tex0-1 6)
|
||||
(tex0-2 7)
|
||||
(clamp-1 8)
|
||||
(clamp-2 9)
|
||||
(fog 10)
|
||||
(xyzf3 12)
|
||||
(xyz3 13)
|
||||
(a+d 14)
|
||||
(nop 15)
|
||||
)
|
||||
|
||||
(deftype gif-tag-regs (uint64)
|
||||
((regs0 gs-reg-id :offset 0 :size 4)
|
||||
(regs1 gs-reg-id :offset 4 :size 4)
|
||||
(regs2 gs-reg-id :offset 8 :size 4)
|
||||
(regs3 gs-reg-id :offset 12 :size 4)
|
||||
(regs4 gs-reg-id :offset 16 :size 4)
|
||||
(regs5 gs-reg-id :offset 20 :size 4)
|
||||
(regs6 gs-reg-id :offset 24 :size 4)
|
||||
(regs7 gs-reg-id :offset 28 :size 4)
|
||||
(regs8 gs-reg-id :offset 32 :size 4)
|
||||
(regs9 gs-reg-id :offset 36 :size 4)
|
||||
(regs10 gs-reg-id :offset 40 :size 4)
|
||||
(regs11 gs-reg-id :offset 44 :size 4)
|
||||
(regs12 gs-reg-id :offset 48 :size 4)
|
||||
(regs13 gs-reg-id :offset 52 :size 4)
|
||||
(regs14 gs-reg-id :offset 56 :size 4)
|
||||
(regs15 gs-reg-id :offset 60 :size 4)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
;; display-h
|
||||
(deftype display-env (structure)
|
||||
((pmode uint64 :offset-assert 0)
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
(set!
|
||||
(-> current-bucket tag)
|
||||
(new 'static 'dma-tag
|
||||
:id #x2
|
||||
:id (dma-tag-id next)
|
||||
:addr (the-as int (&+ (the-as pointer current-bucket) 16))
|
||||
)
|
||||
)
|
||||
|
||||
@@ -149,7 +149,11 @@
|
||||
)
|
||||
(set!
|
||||
(-> buf-ptr dma)
|
||||
(new 'static 'dma-tag :id #x3 :addr (the-as int func-ptr) :qwc qwc-now)
|
||||
(new 'static 'dma-tag
|
||||
:id (dma-tag-id ref)
|
||||
:addr (the-as int func-ptr)
|
||||
:qwc qwc-now
|
||||
)
|
||||
)
|
||||
(set!
|
||||
(-> buf-ptr vif0)
|
||||
@@ -157,7 +161,11 @@
|
||||
)
|
||||
(set!
|
||||
(-> buf-ptr vif1)
|
||||
(new 'static 'vif-tag :cmd #x4a :num (shl qwc-now 1) :imm origin)
|
||||
(new 'static 'vif-tag
|
||||
:cmd (vif-cmd mpg)
|
||||
:num (shl qwc-now 1)
|
||||
:imm origin
|
||||
)
|
||||
)
|
||||
(set! (-> dma-buf-2 base) (&+ (the-as pointer buf-ptr) 16))
|
||||
)
|
||||
|
||||
@@ -725,8 +725,8 @@
|
||||
(empty-form)
|
||||
(cond
|
||||
((or
|
||||
(zero? (+ (the-as uint (-> current-tag id)) (the-as uint -3)))
|
||||
(zero? (+ (the-as uint (-> current-tag id)) (the-as uint -4)))
|
||||
(= (-> current-tag id) (dma-tag-id ref))
|
||||
(= (-> current-tag id) (dma-tag-id refs))
|
||||
(zero? (-> current-tag id))
|
||||
)
|
||||
(set! addr (-> current-tag addr))
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,371 @@
|
||||
;;-*-Lisp-*-
|
||||
(in-package goal)
|
||||
|
||||
;; definition for symbol *cheat-mode*, type symbol
|
||||
(define *cheat-mode* #t)
|
||||
|
||||
;; definition of type hw-cpad
|
||||
(deftype hw-cpad (basic)
|
||||
((valid uint8 :offset-assert 4)
|
||||
(status uint8 :offset-assert 5)
|
||||
(button0 uint16 :offset-assert 6)
|
||||
(rightx uint8 :offset-assert 8)
|
||||
(righty uint8 :offset-assert 9)
|
||||
(leftx uint8 :offset-assert 10)
|
||||
(lefty uint8 :offset-assert 11)
|
||||
(abutton uint8 12 :offset-assert 12)
|
||||
(dummy uint8 12 :offset-assert 24)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x24
|
||||
:flag-assert #x900000024
|
||||
)
|
||||
|
||||
;; definition for method 3 of type hw-cpad
|
||||
(defmethod inspect hw-cpad ((obj hw-cpad))
|
||||
(format #t "[~8x] ~A~%" obj (-> obj type))
|
||||
(format #t "~Tvalid: #x~X~%" (-> obj valid))
|
||||
(format #t "~Tstatus: #x~X~%" (-> obj status))
|
||||
(format #t "~Tbutton0: #x~X~%" (-> obj button0))
|
||||
(format #t "~Trightx: ~D~%" (-> obj rightx))
|
||||
(format #t "~Trighty: ~D~%" (-> obj righty))
|
||||
(format #t "~Tleftx: ~D~%" (-> obj leftx))
|
||||
(format #t "~Tlefty: ~D~%" (-> obj lefty))
|
||||
(format #t "~Tabutton[12] @ #x~X~%" (-> obj abutton))
|
||||
(format #t "~Tdummy[12] @ #x~X~%" (-> obj dummy))
|
||||
obj
|
||||
)
|
||||
|
||||
;; definition of type cpad-info
|
||||
(deftype cpad-info (hw-cpad)
|
||||
((number int32 :offset-assert 36)
|
||||
(cpad-file int32 :offset-assert 40)
|
||||
(button0-abs uint32 3 :offset-assert 44)
|
||||
(button0-shadow-abs uint32 1 :offset-assert 56)
|
||||
(button0-rel uint32 3 :offset-assert 60)
|
||||
(stick0-dir float :offset-assert 72)
|
||||
(stick0-speed float :offset-assert 76)
|
||||
(new-pad int32 :offset-assert 80)
|
||||
(state int32 :offset-assert 84)
|
||||
(align uint8 6 :offset-assert 88)
|
||||
(direct uint8 6 :offset-assert 94)
|
||||
(buzz-val uint8 2 :offset-assert 100)
|
||||
(buzz-time uint64 2 :offset-assert 104)
|
||||
(buzz basic :offset-assert 120)
|
||||
(buzz-act int32 :offset-assert 124)
|
||||
(change-time uint64 :offset-assert 128)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x88
|
||||
:flag-assert #x900000088
|
||||
(:methods
|
||||
(new (symbol type int) _type_ 0)
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for method 3 of type cpad-info
|
||||
(defmethod inspect cpad-info ((obj cpad-info))
|
||||
(format #t "[~8x] ~A~%" obj (-> obj type))
|
||||
(format #t "~Tvalid: #x~X~%" (-> obj valid))
|
||||
(format #t "~Tstatus: #x~X~%" (-> obj status))
|
||||
(format #t "~Tbutton0: #x~X~%" (-> obj button0))
|
||||
(format #t "~Trightx: ~D~%" (-> obj rightx))
|
||||
(format #t "~Trighty: ~D~%" (-> obj righty))
|
||||
(format #t "~Tleftx: ~D~%" (-> obj leftx))
|
||||
(format #t "~Tlefty: ~D~%" (-> obj lefty))
|
||||
(format #t "~Tabutton[12] @ #x~X~%" (-> obj abutton))
|
||||
(format #t "~Tdummy[12] @ #x~X~%" (-> obj dummy))
|
||||
(format #t "~Tnumber: ~D~%" (-> obj number))
|
||||
(format #t "~Tcpad-file: ~D~%" (-> obj cpad-file))
|
||||
(format #t "~Tbutton0-abs[3] @ #x~X~%" (-> obj button0-abs))
|
||||
(format #t "~Tbutton0-shadow-abs[1] @ #x~X~%" (-> obj button0-shadow-abs))
|
||||
(format #t "~Tbutton0-rel[3] @ #x~X~%" (-> obj button0-rel))
|
||||
(format #t "~Tstick0-dir: ~f~%" (-> obj stick0-dir))
|
||||
(format #t "~Tstick0-speed: ~f~%" (-> obj stick0-speed))
|
||||
(format #t "~Tnew-pad: ~D~%" (-> obj new-pad))
|
||||
(format #t "~Tstate: ~D~%" (-> obj state))
|
||||
(format #t "~Talign[6] @ #x~X~%" (-> obj align))
|
||||
(format #t "~Tdirect[6] @ #x~X~%" (-> obj direct))
|
||||
(format #t "~Tbuzz-val[2] @ #x~X~%" (-> obj buzz-val))
|
||||
(format #t "~Tbuzz-time[2] @ #x~X~%" (-> obj buzz-time))
|
||||
(format #t "~Tbuzz: ~A~%" (-> obj buzz))
|
||||
(format #t "~Tbuzz-act: ~D~%" (-> obj buzz-act))
|
||||
(format #t "~Tchange-time: ~D~%" (-> obj change-time))
|
||||
obj
|
||||
)
|
||||
|
||||
;; definition for function cpad-invalid!
|
||||
(defun cpad-invalid! ((pad cpad-info))
|
||||
(set! (-> pad valid) (logior (-> pad valid) 128))
|
||||
(set! (-> pad button0) (the-as uint 0))
|
||||
(set! (-> pad button0-abs 0) (the-as uint 0))
|
||||
(set! (-> pad button0-shadow-abs 0) (the-as uint 0))
|
||||
(set! (-> pad button0-rel 0) (the-as uint 0))
|
||||
(dotimes (v1-2 12)
|
||||
(nop!)
|
||||
(set! (-> pad abutton v1-2) 0)
|
||||
)
|
||||
(set! (-> pad stick0-dir) 0.0)
|
||||
(set! (-> pad stick0-speed) 0.0)
|
||||
(set! (-> pad rightx) (the-as uint 128))
|
||||
(set! (-> pad righty) (the-as uint 128))
|
||||
(set! (-> pad leftx) (the-as uint 128))
|
||||
(set! (-> pad lefty) (the-as uint 128))
|
||||
(set! (-> pad align 0) (the-as uint 0))
|
||||
(set! (-> pad align 1) (the-as uint 1))
|
||||
(set! (-> pad align 2) (the-as uint 255))
|
||||
(set! (-> pad align 3) (the-as uint 255))
|
||||
(set! (-> pad align 4) (the-as uint 255))
|
||||
(set! (-> pad align 5) (the-as uint 255))
|
||||
(dotimes (v1-14 6)
|
||||
(set! (-> pad direct v1-14) 0)
|
||||
)
|
||||
(dotimes (v1-17 2)
|
||||
(set! (-> pad buzz-val 0) (the-as uint 0))
|
||||
(set! (-> pad buzz-time 0) (the-as uint 0))
|
||||
)
|
||||
pad
|
||||
)
|
||||
|
||||
;; definition for method 0 of type cpad-info
|
||||
(defmethod new cpad-info ((alloction symbol) (type-to-make type) (idx int))
|
||||
(let
|
||||
((obj
|
||||
(object-new alloction type-to-make (the-as int (-> type-to-make size)))
|
||||
)
|
||||
)
|
||||
(set! (-> obj number) idx)
|
||||
(set! (-> obj buzz) #f)
|
||||
(cpad-open obj idx)
|
||||
(cpad-invalid! obj)
|
||||
)
|
||||
)
|
||||
|
||||
;; definition of type cpad-list
|
||||
(deftype cpad-list (basic)
|
||||
((num-cpads int32 :offset-assert 4)
|
||||
(cpads cpad-info 2 :offset-assert 8)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x10
|
||||
:flag-assert #x900000010
|
||||
(:methods
|
||||
(new (symbol type) _type_ 0)
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for method 3 of type cpad-list
|
||||
(defmethod inspect cpad-list ((obj cpad-list))
|
||||
(format #t "[~8x] ~A~%" obj (-> obj type))
|
||||
(format #t "~Tnum-cpads: ~D~%" (-> obj num-cpads))
|
||||
(format #t "~Tcpads[2] @ #x~X~%" (-> obj cpads))
|
||||
obj
|
||||
)
|
||||
|
||||
;; definition for method 0 of type cpad-list
|
||||
(defmethod new cpad-list ((allocation symbol) (type-to-make type))
|
||||
(let
|
||||
((gp-0
|
||||
(object-new allocation type-to-make (the-as int (-> type-to-make size)))
|
||||
)
|
||||
)
|
||||
(set! (-> gp-0 num-cpads) 2)
|
||||
(set! (-> gp-0 cpads 0) (new 'global 'cpad-info 0))
|
||||
(set! (-> gp-0 cpads 1) (new 'global 'cpad-info 1))
|
||||
gp-0
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for function analog-input
|
||||
(defun
|
||||
analog-input
|
||||
((in int) (offset float) (center-val float) (max-val float) (out-range float))
|
||||
(let* ((in (gpr->fpr in))
|
||||
(offset-in (- (the float in) offset))
|
||||
(magnitude (- (fabs offset-in) center-val))
|
||||
(max-magnitude (- max-val center-val))
|
||||
)
|
||||
(if (< offset-in 0.0)
|
||||
(set! out-range (- out-range))
|
||||
)
|
||||
(cond
|
||||
((>= 0.0 magnitude)
|
||||
0.0
|
||||
)
|
||||
((>= magnitude max-magnitude)
|
||||
out-range
|
||||
)
|
||||
(else
|
||||
(/ (* magnitude out-range) max-magnitude)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for function cpad-set-buzz!
|
||||
;; INFO: Return type mismatch int vs none.
|
||||
(defun
|
||||
cpad-set-buzz!
|
||||
((pad cpad-info) (buzz-idx int) (buzz-amount int) (duration int))
|
||||
(cond
|
||||
((zero? buzz-amount)
|
||||
(set! (-> pad buzz-val buzz-idx) 0)
|
||||
(let ((v1-2 0))
|
||||
)
|
||||
)
|
||||
((= buzz-amount (-> pad buzz-val buzz-idx))
|
||||
(set!
|
||||
(-> pad buzz-time buzz-idx)
|
||||
(max
|
||||
(the-as int (-> pad buzz-time buzz-idx))
|
||||
(the-as int (+ (get-current-time) (the-as uint duration)))
|
||||
)
|
||||
)
|
||||
)
|
||||
((< (-> pad buzz-val buzz-idx) (the-as uint buzz-amount))
|
||||
(set! (-> pad buzz-val buzz-idx) buzz-amount)
|
||||
(set!
|
||||
(-> pad buzz-time buzz-idx)
|
||||
(+ (get-current-time) (the-as uint duration))
|
||||
)
|
||||
)
|
||||
)
|
||||
(let ((v0-2 0))
|
||||
)
|
||||
(none)
|
||||
)
|
||||
|
||||
;; definition for symbol *cpad-list*, type cpad-list
|
||||
(define *cpad-list* (new 'global 'cpad-list))
|
||||
|
||||
;; definition for symbol *cpad-debug*, type symbol
|
||||
(define *cpad-debug* #f)
|
||||
|
||||
;; definition for function service-cpads
|
||||
(defun service-cpads ()
|
||||
(let ((pad-list *cpad-list*))
|
||||
(dotimes (pad-idx (-> pad-list num-cpads))
|
||||
(let ((pad (-> *cpad-list* cpads pad-idx)))
|
||||
(cpad-get-data pad)
|
||||
(cond
|
||||
((zero? (logand (-> pad valid) 128))
|
||||
(dotimes (buzz-idx 2)
|
||||
(cond
|
||||
((and
|
||||
(-> pad buzz)
|
||||
(<
|
||||
(the-as int (get-current-time))
|
||||
(the-as int (-> pad buzz-time buzz-idx))
|
||||
)
|
||||
(= *master-mode* 'game)
|
||||
)
|
||||
(let ((v1-10 buzz-idx))
|
||||
(cond
|
||||
((zero? v1-10)
|
||||
(set!
|
||||
(-> pad direct buzz-idx)
|
||||
(logand
|
||||
(ash
|
||||
(-> pad buzz-val buzz-idx)
|
||||
(- (the-as int (logand (get-integral-current-time) 7)))
|
||||
)
|
||||
1
|
||||
)
|
||||
)
|
||||
)
|
||||
((= v1-10 1)
|
||||
(set! (-> pad direct buzz-idx) (-> pad buzz-val buzz-idx))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(else
|
||||
(set! (-> pad buzz-val buzz-idx) 0)
|
||||
(set! (-> pad direct buzz-idx) 0)
|
||||
(let ((v1-22 0))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(set! (-> pad button0-abs 2) (-> pad button0-abs 1))
|
||||
(set! (-> pad button0-abs 1) (-> pad button0-shadow-abs 0))
|
||||
(set! (-> pad button0-rel 2) (-> pad button0-rel 1))
|
||||
(set! (-> pad button0-rel 1) (-> pad button0-rel 0))
|
||||
(let ((current-button0 (-> pad button0)))
|
||||
(set! (-> pad button0-shadow-abs 0) current-button0)
|
||||
(set! (-> pad button0-abs 0) current-button0)
|
||||
)
|
||||
(set!
|
||||
(-> pad button0-rel 0)
|
||||
(logand (-> pad button0-abs 0) (lognot (-> pad button0-abs 1)))
|
||||
)
|
||||
(when *cpad-debug*
|
||||
(set! (-> pad leftx) (the-as uint 255))
|
||||
(set! (-> pad rightx) (the-as uint 255))
|
||||
)
|
||||
(set! (-> pad stick0-speed) 1.0)
|
||||
(cond
|
||||
((= (shr (-> pad status) 4) 7)
|
||||
(let ((f30-0 (* 0.0078125 (the float (+ (-> pad leftx) -128))))
|
||||
(f28-0
|
||||
(* 0.0078125 (the float (- 127 (the-as int (-> pad lefty)))))
|
||||
)
|
||||
)
|
||||
(set! (-> pad stick0-dir) (atan (- f30-0) f28-0))
|
||||
(set!
|
||||
(-> pad stick0-speed)
|
||||
(fmin 1.0 (sqrtf (+ (* f30-0 f30-0) (* f28-0 f28-0))))
|
||||
)
|
||||
)
|
||||
(if (< (-> pad stick0-speed) 0.3)
|
||||
(let ((f0-8 0.0))
|
||||
(set! (-> pad stick0-speed) f0-8)
|
||||
)
|
||||
)
|
||||
)
|
||||
(else
|
||||
(set! (-> pad leftx) (the-as uint 128))
|
||||
(set! (-> pad lefty) (the-as uint 128))
|
||||
(set! (-> pad rightx) (the-as uint 128))
|
||||
(set! (-> pad righty) (the-as uint 128))
|
||||
(set! (-> pad stick0-dir) 0.0)
|
||||
(let ((f0-10 0.0))
|
||||
(set! (-> pad stick0-speed) f0-10)
|
||||
)
|
||||
)
|
||||
)
|
||||
(if
|
||||
(or
|
||||
(!= (-> pad button0-abs 0) (-> pad button0-abs 1))
|
||||
(or (< 0.3 (-> pad stick0-speed)) (zero? (-> pad change-time)))
|
||||
)
|
||||
(set! (-> pad change-time) (get-current-time))
|
||||
)
|
||||
)
|
||||
(else
|
||||
(cpad-invalid! pad)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
*cpad-list*
|
||||
)
|
||||
|
||||
;; definition for function buzz-stop!
|
||||
;; INFO: Return type mismatch int vs none.
|
||||
(defun buzz-stop! ((idx int))
|
||||
(cpad-set-buzz! (-> *cpad-list* cpads idx) 0 0 0)
|
||||
(cpad-set-buzz! (-> *cpad-list* cpads idx) 1 0 0)
|
||||
(let ((v0-0 0))
|
||||
)
|
||||
(none)
|
||||
)
|
||||
|
||||
;; failed to figure out what this is:
|
||||
(let ((v0-4 0))
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -967,7 +967,7 @@ TEST_F(FormRegressionTest, DmaBufferAddVuFunction) {
|
||||
" (quote static)\n"
|
||||
" (quote dma-tag)\n"
|
||||
" :id\n"
|
||||
" 3\n"
|
||||
" (dma-tag-id ref)\n"
|
||||
" :addr\n"
|
||||
" (the-as int v1-0)\n"
|
||||
" :qwc\n"
|
||||
@@ -984,7 +984,7 @@ TEST_F(FormRegressionTest, DmaBufferAddVuFunction) {
|
||||
" )\n"
|
||||
" (set!\n"
|
||||
" (-> (the-as dma-packet t2-0) vif1)\n"
|
||||
" (new (quote static) (quote vif-tag) :cmd 74 :num (shl t0-1 1) :imm a1-1)\n"
|
||||
" (new (quote static) (quote vif-tag) :cmd (vif-cmd mpg) :num (shl t0-1 1) :imm a1-1)\n"
|
||||
" )\n"
|
||||
" (set! (-> t1-1 base) (&+ (the-as pointer t2-0) 16))\n"
|
||||
" )\n"
|
||||
|
||||
@@ -17,7 +17,7 @@ const std::unordered_set<std::string> g_object_files_to_decompile = {
|
||||
"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", "dma-buffer",
|
||||
"dma-bucket", "dma-disasm",
|
||||
"dma-bucket", "dma-disasm", "pad", "gs",
|
||||
/* gap */
|
||||
"bounding-box",
|
||||
/* gap */
|
||||
@@ -32,7 +32,7 @@ const std::vector<std::string> g_object_files_to_check_against_reference = {
|
||||
/* transformq-h, */
|
||||
"matrix", "transform", "quaternion", "euler", /* geometry, trigonometry */
|
||||
"gsound-h", "timer-h", /* timer, */ "vif-h", "dma-h", "video-h", "vu1-user-h", "dma",
|
||||
"dma-buffer", "dma-bucket", "dma-disasm",
|
||||
"dma-buffer", "dma-bucket", "dma-disasm", "pad", "gs",
|
||||
/* gap */ "bounding-box",
|
||||
/* gap */
|
||||
"sync-info-h", "sync-info"};
|
||||
@@ -118,7 +118,10 @@ const std::unordered_set<std::string> skip_in_compiling = {
|
||||
"(method 3 profile-frame)", // double definition.
|
||||
|
||||
// dma-disasm
|
||||
"disasm-dma-list",
|
||||
"disasm-dma-list", // missing a single cast :(
|
||||
|
||||
// gs
|
||||
"(method 3 gif-tag)", // inspect for a 128-bit type.
|
||||
|
||||
// sync-info
|
||||
"(method 15 sync-info)", // needs display stuff first
|
||||
|
||||
Reference in New Issue
Block a user