From 1c0038294f38f2c5164d08eb1e2e85b2769d6f2f Mon Sep 17 00:00:00 2001 From: water111 <48171810+water111@users.noreply.github.com> Date: Sat, 20 Jan 2024 12:33:39 -0500 Subject: [PATCH] [jak3] Decompile `gcommon` (#3321) Decompile `gcommon`. I adjusted the spacing of docstring comments, and removed some spammy decompiler warning prints. I also added some random notes I had on VU programs from jak1/jak2. They are not polished, but I think it's still worth including since we'll have to go through them again for jak 3. --- decompiler/analysis/cfg_builder.cpp | 4 +- decompiler/analysis/final_output.cpp | 45 +- decompiler/analysis/final_output.h | 2 +- decompiler/analysis/static_refs.cpp | 2 +- decompiler/config/jak3/all-types.gc | 501 ++++-- .../config/jak3/ntsc_v1/var_names.jsonc | 319 ++++ decompiler/util/DecompilerTypeSystem.cpp | 2 +- decompiler/util/DecompilerTypeSystem.h | 3 + decompiler/util/data_decompile.cpp | 2 +- docs/progress-notes/blerc.md | 44 + .../jak1/scratch/generic_tie_to_etie.md | 137 ++ docs/progress-notes/jak2/blerc_asm.md | 513 ++++++ docs/progress-notes/jak2/generic.md | 261 +++ docs/scratch/shrub.md | 319 ++++ goal_src/jak3/kernel-defs.gc | 1 + goal_src/jak3/kernel/gcommon.gc | 1012 ++++++----- .../jak3/engine/geometry/bounding-box_REF.gc | 6 +- .../reference/jak3/engine/math/euler_REF.gc | 6 +- .../reference/jak3/engine/math/math_REF.gc | 38 +- .../reference/jak3/engine/math/matrix_REF.gc | 48 +- .../jak3/engine/math/quaternion_REF.gc | 24 +- .../jak3/engine/math/transformq-h_REF.gc | 8 +- .../jak3/engine/math/trigonometry_REF.gc | 24 +- .../jak3/engine/math/vector-h_REF.gc | 10 +- .../reference/jak3/kernel/gcommon_REF.gc | 1551 +++++++++++++++++ test/offline/config/jak3/config.jsonc | 7 + test_no_filter.sh | 6 + 27 files changed, 4173 insertions(+), 722 deletions(-) create mode 100644 docs/progress-notes/blerc.md create mode 100644 docs/progress-notes/jak1/scratch/generic_tie_to_etie.md create mode 100644 docs/progress-notes/jak2/blerc_asm.md create mode 100644 docs/progress-notes/jak2/generic.md create mode 100644 docs/scratch/shrub.md create mode 100644 test/decompiler/reference/jak3/kernel/gcommon_REF.gc create mode 100755 test_no_filter.sh diff --git a/decompiler/analysis/cfg_builder.cpp b/decompiler/analysis/cfg_builder.cpp index 083a46b7e..0597225fb 100644 --- a/decompiler/analysis/cfg_builder.cpp +++ b/decompiler/analysis/cfg_builder.cpp @@ -1428,7 +1428,9 @@ Form* try_sc_as_type_of_jak2(FormPool& pool, Function& f, const ShortCircuit* vt f.ir2.env.disable_def(b2_delay_op.dst(), f.warnings); f.ir2.env.disable_use(shift_left->expr().get_arg(0).var()); - f.warnings.warning("Using new Jak 2 rtype-of"); + if (f.ir2.env.version != GameVersion::Jak3) { + f.warnings.warning("Using new Jak 2 rtype-of"); + } return b0_ptr; } diff --git a/decompiler/analysis/final_output.cpp b/decompiler/analysis/final_output.cpp index 1abcf75c0..0bb109853 100644 --- a/decompiler/analysis/final_output.cpp +++ b/decompiler/analysis/final_output.cpp @@ -23,10 +23,27 @@ goos::Object get_arg_list_for_function(const Function& func, const Env& env) { } namespace { + +std::string fix_docstring_indent(const std::string& input) { + std::string result; + for (auto c : input) { + if (c == '\n') { + result += '\n'; + for (int i = 0; i < 3; i++) { + result += ' '; + } + } else { + result += c; + } + } + return result; +} + void append_body_to_function_definition(goos::Object* top_form, const std::vector& inline_body, const FunctionVariableDefinitions& var_dec, - const TypeSpec& ts) { + const TypeSpec& ts, + GameVersion version) { // Some forms like docstrings and local-vars we _always_ want to be at the top level and first (in // the order added) std::vector initial_top_level_forms; @@ -35,7 +52,12 @@ void append_body_to_function_definition(goos::Object* top_form, body_elements.insert(body_elements.end(), inline_body.begin(), inline_body.end()); // If the first element in the body is a docstring, add it first if (body_elements.size() > 0 && body_elements.at(0).is_string()) { - initial_top_level_forms.push_back(inline_body.at(0)); + if (version > GameVersion::Jak2) { + initial_top_level_forms.push_back( + goos::StringObject::make_new(fix_docstring_indent(inline_body.at(0).as_string()->data))); + } else { + initial_top_level_forms.push_back(inline_body.at(0)); + } body_elements.erase(body_elements.begin()); } @@ -65,7 +87,7 @@ void append_body_to_function_definition(goos::Object* top_form, } } // namespace -goos::Object final_output_lambda(const Function& func) { +goos::Object final_output_lambda(const Function& func, GameVersion version) { std::vector inline_body; func.ir2.top_form->inline_forms(inline_body, func.ir2.env); auto var_dec = func.ir2.env.local_var_type_list(func.ir2.top_form, func.type.arg_count() - 1); @@ -74,11 +96,11 @@ goos::Object final_output_lambda(const Function& func) { if (behavior) { auto result = pretty_print::build_list(fmt::format("lambda :behavior {}", *behavior), get_arg_list_for_function(func, func.ir2.env)); - append_body_to_function_definition(&result, inline_body, var_dec, func.type); + append_body_to_function_definition(&result, inline_body, var_dec, func.type, version); return result; } else { auto result = pretty_print::build_list("lambda", get_arg_list_for_function(func, func.ir2.env)); - append_body_to_function_definition(&result, inline_body, var_dec, func.type); + append_body_to_function_definition(&result, inline_body, var_dec, func.type, version); return result; } } @@ -115,7 +137,7 @@ goos::Object final_output_defstate_anonymous_behavior(const Function& func, auto var_dec = func.ir2.env.local_var_type_list(func.ir2.top_form, func.type.arg_count() - 1); auto result = pretty_print::build_list("behavior", get_arg_list_for_function(func, func.ir2.env)); - append_body_to_function_definition(&result, inline_body, var_dec, func.type); + append_body_to_function_definition(&result, inline_body, var_dec, func.type, dts.version()); return result; } @@ -167,7 +189,7 @@ std::string final_defun_out(const Function& func, } } - append_body_to_function_definition(&top_form, inline_body, var_dec, func.type); + append_body_to_function_definition(&top_form, inline_body, var_dec, func.type, dts.version()); return pretty_print::to_string(top_form); } @@ -188,7 +210,8 @@ std::string final_defun_out(const Function& func, inline_body.insert(inline_body.begin(), pretty_print::new_string(method_info.docstring.value())); } - append_body_to_function_definition(&top_form, inline_body, var_dec, method_info.type); + append_body_to_function_definition(&top_form, inline_body, var_dec, method_info.type, + dts.version()); return pretty_print::to_string(top_form); } @@ -199,7 +222,7 @@ std::string final_defun_out(const Function& func, top.push_back(arguments); auto top_form = pretty_print::build_list(top); - append_body_to_function_definition(&top_form, inline_body, var_dec, func.type); + append_body_to_function_definition(&top_form, inline_body, var_dec, func.type, dts.version()); return pretty_print::to_string(top_form); } @@ -212,7 +235,7 @@ std::string final_defun_out(const Function& func, top.push_back(arguments); auto top_form = pretty_print::build_list(top); - append_body_to_function_definition(&top_form, inline_body, var_dec, func.type); + append_body_to_function_definition(&top_form, inline_body, var_dec, func.type, dts.version()); return pretty_print::to_string(top_form); } @@ -226,7 +249,7 @@ std::string final_defun_out(const Function& func, top.push_back(arguments); auto top_form = pretty_print::build_list(top); - append_body_to_function_definition(&top_form, inline_body, var_dec, func.type); + append_body_to_function_definition(&top_form, inline_body, var_dec, func.type, dts.version()); return pretty_print::to_string(top_form); } diff --git a/decompiler/analysis/final_output.h b/decompiler/analysis/final_output.h index 20f41a164..7dc01f998 100644 --- a/decompiler/analysis/final_output.h +++ b/decompiler/analysis/final_output.h @@ -18,7 +18,7 @@ std::string write_from_top_level(const Function& top_level, const std::unordered_set& skip_functions); goos::Object get_arg_list_for_function(const Function& func, const Env& env); -goos::Object final_output_lambda(const Function& function); +goos::Object final_output_lambda(const Function& function, GameVersion version); goos::Object final_output_defstate_anonymous_behavior(const Function& func, const DecompilerTypeSystem& dts); } // namespace decompiler diff --git a/decompiler/analysis/static_refs.cpp b/decompiler/analysis/static_refs.cpp index d0d0fdfff..5692320ea 100644 --- a/decompiler/analysis/static_refs.cpp +++ b/decompiler/analysis/static_refs.cpp @@ -46,7 +46,7 @@ bool try_convert_lambda(const Function& parent_function, if (defstate_behavior) { result = final_output_defstate_anonymous_behavior(*other_func, dts); } else { - result = final_output_lambda(*other_func); + result = final_output_lambda(*other_func, dts.version()); } f->clear(); diff --git a/decompiler/config/jak3/all-types.gc b/decompiler/config/jak3/all-types.gc index f0d845788..31b57380b 100644 --- a/decompiler/config/jak3/all-types.gc +++ b/decompiler/config/jak3/all-types.gc @@ -74,6 +74,7 @@ (define-extern dgo-load (function string kheap link-flag int none)) (define-extern *listener-function* (function object)) (define-extern *enable-method-set* int) +(define-extern *kernel-symbol-warnings* symbol) (declare-type cpad-info basic) (declare-type mouse-info basic) @@ -104,6 +105,7 @@ (define-extern link-reset (function none)) (define-extern kset-language (function language-enum int)) (define-extern reset-graph (function int int int int none)) +(define-extern symbol->string (function symbol string)) (declare-type sql-result basic) (define-extern sql-query (function string sql-result)) @@ -133,6 +135,9 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (deftype vec4s (uint128) + "Vector of four floats, packed into a 128-bit integer as bitfields. + This behaves like a value type. + This is not the main vector type." ((x float :offset 0) (y float :offset 32) (z float :offset 64) @@ -143,6 +148,9 @@ ) (deftype vector (structure) + "Vector of four floats, stored in a structure. + This behaves like a reference type. + This is the main vector type." ((data float 4 :score -1 :offset-assert 0) ;; guessed by decompiler (x float :offset 0) (y float :offset 4) @@ -156,14 +164,16 @@ ) (deftype bfloat (basic) - ((data float :offset-assert 4) - ) + "Boxed (or basic?) float. Just a basic that wraps a single float." + ((data float)) :method-count-assert 9 :size-assert #x8 :flag-assert #x900000008 ) (deftype inline-array-class (basic) + "Base class for basic inline arrays. + The stride is stored in the heap-base of the inline-array-class child class." ((length int32 :offset-assert 4) (allocated-length int32 :offset-assert 8) ;; this is 16-byte aligned. @@ -175,35 +185,31 @@ :flag-assert #xe00000010 (:methods (new (symbol type int) _type_) ;; 0 - (push-back (_type_ object) int);; 9 + (push-back "Copy object to the end, then increment length. No bounds check." (_type_ object) int);; 9 (inline-array-class-method-10 () none) ;; 10 - (clear-1 (_type_) symbol) ;; 11 - (clear-2 (_type_) none) ;; 12 - (pop-front (_type_ int) pointer) ;; 13 + (clear-1 "Set length to 0, return #t." (_type_) symbol) ;; 11 + (clear-2 "Set length to 0" (_type_) none) ;; 12 + (pop-front "Remove first object by copying last object to the front, then decrement length." (_type_ int) pointer) ;; 13 ) ) -#| (deftype inline-array-class-uint64 (inline-array-class) - ((length int32 :offset-assert 4) - (allocated-length int32 :offset-assert 8) - ) + "Specialization of inline-array-class for uint64. It's unclear why + this would be preferred over a normal (array uint64), since both store data the same way." + ((data uint64 :dynamic :overlay-at _data)) :method-count-assert 14 :size-assert #x10 :flag-assert #xe00000010 ) -|# -#| (deftype inline-array-class-uint32 (inline-array-class) - ((length int32 :offset-assert 4) - (allocated-length int32 :offset-assert 8) - ) + "Specialization of inline-array-class for uint32. It's unclear why this would be preferred + over a normal (array uint32), since both store data the same way." + ((data uint32 :dynamic :overlay-at _data)) :method-count-assert 14 :size-assert #x10 :flag-assert #xe00000010 ) -|# #| (deftype array (UNKNOWN) @@ -230,64 +236,243 @@ ) |# -;; (define-extern identity function) ;; (function object object) -;; (define-extern 1/ function) ;; (function float float) -;; (define-extern + function) ;; (function int int int) -;; (define-extern - function) ;; (function int int int) -;; (define-extern * function) ;; (function int int int) -;; (define-extern / function) ;; (function int int int) -(define-extern ash (function int int int)) -(define-extern mod (function int int int)) -(define-extern rem (function int int int)) -(define-extern abs (function int int)) -(define-extern min (function int int int)) -(define-extern max (function int int int)) -(define-extern logior (function int int int)) -(define-extern logand (function int int int)) -(define-extern lognor (function int int int)) -(define-extern logxor (function int int int)) -(define-extern lognot (function int int)) -;; (define-extern false-func function) ;; (function symbol) -;; (define-extern true-func function) ;; (function symbol) +(define-extern identity + "The identity function." + (function object object)) + +(define-extern 1/ + "Floating point reciprocal." + (function float float)) + +(define-extern + + "64-bit integer addition." + (function int int int)) + +(define-extern - + "64-bit integer subraction." + (function int int int)) + +(define-extern * + "32-bit signed integer multiplication." + (function int int int)) + +(define-extern / + "32-bit signed integer division." + (function int int int)) + +(define-extern ash + "64-bit arithmetic shift. (sign-extends)" + (function int int int)) + +(define-extern mod + "32-bit mod." + (function int int int)) + +(define-extern rem + "32-bit mod (same as mod)." + (function int int int)) + +(define-extern abs + "64-bit integer absolute value." + (function int int)) + +(define-extern min + "64-bit integer minimum." + (function int int int)) + +(define-extern max + "64-bit integer maximum." + (function int int int)) + +(define-extern logior + "64-bit bitwise or." + (function int int int)) + +(define-extern logand + "64-bit bitwise and." + (function int int int)) + +(define-extern lognor + "64-bit bitwise not-or." + (function int int int)) + +(define-extern logxor + "64-bit bitwise exclusive or." + (function int int int)) + +(define-extern lognot + "64-bit bitwise not." + (function int int)) + +(define-extern false-func + "Returns false." + (function symbol)) + +(define-extern true-func + "Returns true." + (function symbol)) + (define-extern format (function _varargs_ object)) -;; (define-extern basic-type? function) ;; (function basic type symbol) -;; (define-extern type-type? function) ;; (function type type symbol) -(define-extern type? (function object type symbol)) -;; (define-extern find-parent-method function) ;; (function type int function) -;; (define-extern ref& function) -;; (define-extern ref function) ;; (function object int object) -;; (define-extern last function) ;; (function object object) -;; (define-extern member function) ;; (function object object object) -;; (define-extern nmember function) ;; (function basic object object) -;; (define-extern assoc function) ;; (function object object object) -;; (define-extern assoce function) ;; (function object object object) -;; (define-extern nassoc function) ;; (function string object object) -;; (define-extern nassoce function) ;; (function string object object) -;; (define-extern append! function) ;; (function object object object) -;; (define-extern delete! function) ;; (function object object pair) -;; (define-extern delete-car! function) ;; (function object object object) -;; (define-extern insert-cons! function) ;; (function object object pair) -;; (define-extern sort function) ;; (function pair (function object object object) pair) -;; (define-extern string->symbol-debug function) -;; (define-extern symbol->string-debug function) -;; (define-extern symbol->hash function) -;; (define-extern mem-copy! function) ;; (function pointer pointer int pointer) -;; (define-extern qmem-copy<-! function) ;; (function pointer pointer int pointer) -;; (define-extern qmem-copy->! function) ;; (function pointer pointer int pointer) -;; (define-extern qmem-clear! function) -;; (define-extern mem-set32! function) ;; (function pointer int int pointer) -;; (define-extern mem-or! function) ;; (function pointer pointer int pointer) -;; (define-extern quad-copy! function) ;; (function pointer pointer int none) -;; (define-extern fact function) ;; (function int int) -;; (define-extern *print-column* object) ;; binteger -;; (define-extern print function) ;; (function object object) -;; (define-extern printl function) ;; (function object object) -;; (define-extern inspect function) ;; (function object object) -;; (define-extern mem-print function) ;; (function (pointer uint32) int symbol) -;; (define-extern *trace-list* object) ;; pair -;; (define-extern print-tree-bitmask function) ;; (function int int symbol) -;; (define-extern breakpoint-range-set! function) ;; (function uint uint uint int) -;; (define-extern valid? function) ;; (function object type string symbol object symbol) + +(define-extern basic-type? + "Return if the given basic is a given type. A child of the given type is also acceptable." + (function basic type symbol)) + +(define-extern type-type? + "Return if the first type is the second type, or a child of it." + (function type type symbol)) + +(define-extern type? + "Return if the given object is an instance of the given type. + Works on basics, bintegers, or symbols." + (function object type symbol)) + +(define-extern find-parent-method + "Find the closest parent type that has a different implementation of the given method and return that method. + If it does not exist, return `nothing` function. + This is used to implement call-parent-method." + (function type int function)) + +(define-extern ref& + "Return the n-th pair in a linked list of pairs. No bounds checking. + If it is the null pair, return #f." + (function object int object)) + +(define-extern ref + "Return the n-th item in a proper list. No bounds checking." + (function object int object)) + +(define-extern last + "Return the last object in a proper list." + (function object object)) + +(define-extern member + "See if the first argument is in the proper list of the second argument. + Checked with simple equality. + If so, return the list starting at the at point (a truthy value). + Otherwise, return #f. + (member 'b '(a b c)) -> (b c d). + (member 'w '(a b c)) -> #f" + (function object object object)) + +(define-extern nmember + "Like member, but membership is checked with the name= function to handle symbols or strings." + (function basic object object)) + +(define-extern assoc + "Search an association list for given object. Return #f if not found, otherwise the element with matching car. + (assoc 'a '((a . 1) (b . 2) (c . 3))) -> (a . 1) + (assoc 'x '((a . 1) (b . 2) (c . 3))) -> #f" + (function object object object)) + +(define-extern assoce + "Like assoc, but supports a special `else` key which is always considered a match." + (function object object object)) + +(define-extern nassoc + "Like assoc, but uses name= instead of = to check equality." + (function string object object)) + +(define-extern nassoce + "Like assoce, but uses name= instead of = to check equality." + (function string object object)) + +(define-extern append! + "Append the second argument to the end of the list (or empty pair) in the first argument." + (function object object object)) + +(define-extern delete! + "Remove an element from the given list, return the list." + (function object object pair)) + +(define-extern delete-car! + "Remove an element from the given list with a matching car. Return the list." + (function object object object)) + +(define-extern insert-cons! + "Update an association list to have the given (key . value) pair. + If a previous value exists, it is deleted first. + This function always allocates a pair through `cons` on the global heap, which can never be freed, + so it should almost never be used at runtime." + (function object object pair)) + +(define-extern sort + "Sort a list using the given comparision function. + The function can return a #t/#f value, or a positive/negative value. + For example, you could use either `-` or `<` as functions to sort integers." + (function pair (function object object object) pair)) + +(define-extern string->symbol-debug + "Convert a string to a symbol. The symbol must be known, and this cannot + create a new symbol. (in the PC port, it will still work.) + This is inteded to be used in debug only, and will not trigger a warning. + In debug, this will work for all symbols." + (function string symbol)) + +(define-extern symbol->string-debug + "Get the name of a symbol. This is intended to be used in debug only. + In debug, this will work for all symbols. (In PC port, this works always)" + (function symbol string)) + +(define-extern symbol->hash + "Convert a symbol to a unique integer value, which is just the symbol's address." + (function symbol int)) + +(define-extern mem-copy! + "Basic memory copy. This is not an optimized implementation." + (function pointer pointer int pointer)) + +(define-extern qmem-copy<-! + "Copy memory by quadword (16-bytes). Must by 16-byte aligned, size in 16-byte units. Increasing address copy. Not an optimized version." + (function pointer pointer int pointer)) + +(define-extern qmem-copy->! + "Copy memory by quadword (16-bytes). Must by 16-byte aligned, size in 16-byte units. Decreasing address copy. Not an optimized version." + (function pointer pointer int pointer)) + +(define-extern qmem-clear! + "Clear memory by quadword (16-bytes). Must by 16-byte aligned, size in 16-byte units. Not an optimized version." + (function pointer int pointer)) + +(define-extern mem-set32! + "Set memory to the given 32-bit value, repeated n times. (like C memset, but setting int32_t instead of char). + Not an optimized implementation. Must be 4-byte aligned." + (function pointer int int pointer)) + +(define-extern mem-or! + "Set the destiation to `dest = dest | src`. Size in bytes. Not an optimized version." + (function pointer pointer int pointer)) + +(define-extern quad-copy! + "Optimized memory copy. Must be 16-byte aligned. Size in 16-byte units." + (function pointer pointer int none)) +(define-extern fact + "Factorial." + (function int int)) + +(define-extern *print-column* binteger) +(define-extern print + "Print any boxed object (symbol, pair, basic, binteger) to #t (the REPL). No newline." + (function object object)) +(define-extern printl + "Print any boxed object (symbol, pair, basic, binteger) to #t (the REPL), followed by a newline." + (function object object)) + +(define-extern inspect + "Inspect any boxed object (symbol, pair, basic, binteger) to #t (the REPL)." + (function object object)) + +(define-extern mem-print + "Print out data in memory in hex." + (function (pointer uint32) int symbol)) +(define-extern *trace-list* pair) +(define-extern print-tree-bitmask + "Print out ASCII-art tree structure, from a bitmask of nesting levels." + (function int int symbol)) +(define-extern breakpoint-range-set! + "Unsupported function to set a CPU breakpoint." + (function uint uint uint int)) +(define-extern valid? (function object type string symbol object symbol)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; gstring-h ;; @@ -787,7 +972,7 @@ ;; (define-extern string-suffix= function) ;; (function string string symbol) ;; (define-extern string-position function) ;; (function string string int) ;; (define-extern string-charp= function) ;; (function string (pointer uint8) symbol) -;; (define-extern name= function) ;; (function object object symbol) +(define-extern name= (function object object symbol)) ;; (define-extern copyn-string<-charp function) ;; (function string (pointer uint8) int string) ;; (define-extern string<-charp function) ;; (function string (pointer uint8) string) ;; (define-extern charp<-string function) ;; (function (pointer uint8) string int) @@ -5386,7 +5571,7 @@ :method-count-assert 11 :size-assert #xa0 :flag-assert #xb000000a0 - ;; field extra-sound-bank uses ~A with a signed load. + ;; field extra-sound-bank uses ~A with a signed load. (:methods (level-load-info-method-9 () none) ;; 9 (level-load-info-method-10 () none) ;; 10 @@ -6122,7 +6307,7 @@ :method-count-assert 14 :size-assert #x20 :flag-assert #xe00000020 - ;; field param1 uses ~A with a signed load. field param2 uses ~A with a signed load. field param3 uses ~A with a signed load. + ;; field param1 uses ~A with a signed load. field param2 uses ~A with a signed load. field param3 uses ~A with a signed load. (:methods (connection-method-9 () none) ;; 9 ;; (get-engine (connection) engine) (connection-method-10 () none) ;; 10 ;; (get-process (connection) process) @@ -6190,7 +6375,7 @@ :method-count-assert 9 :size-assert #x20 :flag-assert #x900000020 - ;; field key uses ~A with a signed load. + ;; field key uses ~A with a signed load. ) |# @@ -6567,7 +6752,7 @@ :method-count-assert 9 :size-assert #x50 :flag-assert #x900000050 - ;; field key uses ~A with a signed load. + ;; field key uses ~A with a signed load. ) |# @@ -6964,7 +7149,7 @@ :method-count-assert 11 :size-assert #x30c :flag-assert #xb0000030c - ;; field cam-slave-options is likely a value type. field cam-master-options is likely a value type. + ;; field cam-slave-options is likely a value type. field cam-master-options is likely a value type. (:methods (cam-setting-data-method-9 () none) ;; 9 ;; (cam-setting-data-method-9 (_type_ engine engine-pers engine) _type_) (cam-setting-data-method-10 () none) ;; 10 ;; (cam-setting-data-method-10 (_type_ object (pointer process) float int) _type_) @@ -8335,7 +8520,7 @@ :method-count-assert 10 :size-assert #x20 :flag-assert #xa00000020 - ;; field param1 uses ~A with a signed load. field param2 uses ~A with a signed load. + ;; field param1 uses ~A with a signed load. field param2 uses ~A with a signed load. (:methods (new (symbol type) _type_) ;; 0 ;; (new (symbol type drawable) _type_) (cspace-method-9 () none) ;; 9 ;; (reset-and-assign-geo! (_type_ drawable) _type_) @@ -8441,7 +8626,7 @@ :method-count-assert 17 :size-assert #x20 :flag-assert #x1100000020 - ;; field distance is a float printed as hex? + ;; field distance is a float printed as hex? ) |# @@ -8516,7 +8701,7 @@ :method-count-assert 10 :size-assert #x10 :flag-assert #xa00000010 - ;; field on-enter uses ~A with a signed load. field on-inside uses ~A with a signed load. field on-exit uses ~A with a signed load. + ;; field on-enter uses ~A with a signed load. field on-inside uses ~A with a signed load. field on-exit uses ~A with a signed load. (:methods (region-method-9 () none) ;; 9 ;; (region-method-9 (_type_ vector) symbol) ) @@ -8743,7 +8928,7 @@ :method-count-assert 9 :size-assert #x10 :flag-assert #x900000010 - ;; field execute uses ~A with a signed load. + ;; field execute uses ~A with a signed load. ) |# @@ -8760,7 +8945,7 @@ :method-count-assert 9 :size-assert #x30 :flag-assert #x900000030 - ;; field resetter-flag is likely a value type. + ;; field resetter-flag is likely a value type. ) |# @@ -8787,7 +8972,7 @@ :method-count-assert 9 :size-assert #x3c :flag-assert #x90000003c - ;; field handle is likely a value type. field resolution-scene uses ~A with a signed load. field on-complete uses ~A with a signed load. field on-fail uses ~A with a signed load. + ;; field handle is likely a value type. field resolution-scene uses ~A with a signed load. field on-complete uses ~A with a signed load. field on-fail uses ~A with a signed load. ) |# @@ -8832,7 +9017,7 @@ :method-count-assert 14 :size-assert #x50 :flag-assert #xe00000050 - ;; field on-open uses ~A with a signed load. field on-close uses ~A with a signed load. + ;; field on-open uses ~A with a signed load. field on-close uses ~A with a signed load. (:methods (game-task-node-info-method-9 () none) ;; 9 ;; (close! (_type_ symbol) int) (game-task-node-info-method-10 () none) ;; 10 ;; (open! (_type_ symbol) int) @@ -8857,7 +9042,7 @@ :method-count-assert 10 :size-assert #x20 :flag-assert #xa00000020 - ;; field kiosk-play-continue uses ~A with a signed load. + ;; field kiosk-play-continue uses ~A with a signed load. (:methods (game-task-info-method-9 () none) ;; 9 ) @@ -9545,7 +9730,7 @@ :method-count-assert 14 :size-assert #x3c :flag-assert #xe0000003c - ;; field blend-shape-anim uses ~A with a signed load. + ;; field blend-shape-anim uses ~A with a signed load. ) |# @@ -9721,7 +9906,7 @@ :method-count-assert 16 :size-assert #xdc :flag-assert #x10000000dc - ;; field draw-control-status is likely a value type. field draw-control-global-effect is likely a value type. + ;; field draw-control-status is likely a value type. field draw-control-global-effect is likely a value type. (:methods (new (symbol type) _type_) ;; 0 ;; (new (symbol type process symbol) _type_) (draw-control-method-9 () none) ;; 9 ;; (get-skeleton-origin (_type_) vector) @@ -10156,7 +10341,7 @@ :method-count-assert 9 :size-assert #x80 :flag-assert #x900000080 - ;; field xyz-scale is a float printed as hex? + ;; field xyz-scale is a float printed as hex? ) |# @@ -11291,7 +11476,7 @@ :method-count-assert 12 :size-assert #x68 :flag-assert #xc00000068 - ;; field on-goto uses ~A with a signed load. + ;; field on-goto uses ~A with a signed load. (:methods (continue-point-method-9 () none) ;; 9 ;; (debug-draw (_type_) int) (continue-point-method-10 () none) ;; 10 ;; (continue-point-method-10 (_type_ load-state) continue-point) @@ -11482,7 +11667,7 @@ :method-count-assert 14 :size-assert #x30 :flag-assert #xe00000030 - ;; field param1 uses ~A with a signed load. field param2 uses ~A with a signed load. field param3 uses ~A with a signed load. + ;; field param1 uses ~A with a signed load. field param2 uses ~A with a signed load. field param3 uses ~A with a signed load. ) |# @@ -11513,7 +11698,7 @@ :method-count-assert 14 :size-assert #x20 :flag-assert #xe00000020 - ;; field on-close uses ~A with a signed load. + ;; field on-close uses ~A with a signed load. (:methods (talker-speech-class-method-9 () none) ;; 9 ;; (talker-speech-class-method-9 (_type_) symbol) (talker-speech-class-method-10 () none) ;; 10 ;; (play-communicator-speech! (_type_) none) @@ -11575,7 +11760,7 @@ :method-count-assert 9 :size-assert #x20 :flag-assert #x900000020 - ;; field speech-type-flag is likely a value type. + ;; field speech-type-flag is likely a value type. ) |# @@ -11609,7 +11794,7 @@ :method-count-assert 15 :size-assert #x64 :flag-assert #xf00000064 - ;; field speech-channel-flag is likely a value type. + ;; field speech-channel-flag is likely a value type. (:methods (speech-channel-method-9 () none) ;; 9 ;; (speech-channel-method-9 (_type_ process-drawable speech-type) none) (speech-channel-method-10 () none) ;; 10 ;; (speech-channel-method-10 (_type_ handle) none) @@ -11987,7 +12172,7 @@ :method-count-assert 13 :size-assert #x40 :flag-assert #xd00000040 - ;; field joint-control-status is likely a value type. + ;; field joint-control-status is likely a value type. (:methods (new (symbol type) _type_) ;; 0 ;; (new (symbol type int) _type_) (joint-control-method-9 () none) ;; 9 ;; (current-cycle-distance (_type_) float) @@ -12347,7 +12532,7 @@ :method-count-assert 14 :size-assert #xb0 :flag-assert #xe000000b0 - ;; field param1 uses ~A with a signed load. field param2 uses ~A with a signed load. field param3 uses ~A with a signed load. + ;; field param1 uses ~A with a signed load. field param2 uses ~A with a signed load. field param3 uses ~A with a signed load. ) |# @@ -12480,7 +12665,7 @@ :method-count-assert 22 :size-assert #x20 :flag-assert #x1600000020 - ;; field extra uses ~A with a signed load. + ;; field extra uses ~A with a signed load. (:methods (new (symbol type) _type_) ;; 0 ;; (new (symbol type int int) _type_) (res-lump-method-9 () none) ;; 9 ;; (get-property-data (_type_ symbol symbol float pointer (pointer res-tag) pointer) pointer) @@ -12787,7 +12972,7 @@ :method-count-assert 12 :size-assert #x28 :flag-assert #xc00000028 - ;; field actor-option is likely a value type. + ;; field actor-option is likely a value type. (:methods (new (symbol type) _type_) ;; 0 ;; (new (symbol type process pickup-type float) _type_) (fact-info-method-9 () none) ;; 9 ;; (drop-pickup (_type_ symbol process-tree fact-info int) (pointer process)) @@ -12848,7 +13033,7 @@ :method-count-assert 13 :size-assert #x138 :flag-assert #xd00000138 - ;; field actor-option is likely a value type. + ;; field actor-option is likely a value type. (:methods (new (symbol type) _type_) ;; 0 ;; (new (symbol type process-drawable pickup-type float) _type_) (fact-info-target-method-12 () none) ;; 12 ;; (get-gun-ammo (_type_) float) @@ -12879,7 +13064,7 @@ :method-count-assert 13 :size-assert #x53 :flag-assert #xd00000053 - ;; field actor-option is likely a value type. + ;; field actor-option is likely a value type. (:methods (new (symbol type) _type_) ;; 0 ;; (new (symbol type process (pointer float) pickup-type float) _type_) (fact-info-enemy-method-12 () none) ;; 12 ;; (clear-mask-bits (_type_ int) none) @@ -12899,7 +13084,7 @@ :method-count-assert 12 :size-assert #x2c :flag-assert #xc0000002c - ;; field actor-option is likely a value type. + ;; field actor-option is likely a value type. (:methods (new (symbol type) _type_) ;; 0 ;; (new (symbol type process pickup-type float) _type_) ) @@ -13258,7 +13443,7 @@ :method-count-assert 12 :size-assert #xa8 :flag-assert #xc000000a8 - ;; field handle is likely a value type. + ;; field handle is likely a value type. (:methods (attack-info-method-9 () none) ;; 9 ;; (attack-info-method-9 (_type_ attack-info process-drawable process-drawable) none) (attack-info-method-10 () none) ;; 10 ;; (compute-intersect-info (_type_ object process-drawable process touching-shapes-entry) attack-info) @@ -13317,7 +13502,7 @@ :method-count-assert 12 :size-assert #xa0 :flag-assert #xc000000a0 - ;; field key uses ~A with a signed load. field expr uses ~A with a signed load. + ;; field key uses ~A with a signed load. field expr uses ~A with a signed load. (:methods (new (symbol type) _type_) ;; 0 ;; (new (symbol type object process vector) _type_) (script-context-method-9 () none) ;; 9 ;; (eval! (_type_ pair) object) @@ -13398,7 +13583,7 @@ :method-count-assert 18 :size-assert #x84 :flag-assert #x1200000084 - ;; field on-running uses ~A with a signed load. field on-complete uses ~A with a signed load. + ;; field on-running uses ~A with a signed load. field on-complete uses ~A with a signed load. (:methods (scene-method-16 () none) ;; 16 ;; (scene-method-16 (_type_) _type_) (scene-method-17 () none) ;; 17 @@ -13441,7 +13626,7 @@ :method-count-assert 26 :size-assert #x198 :flag-assert #x1a01200198 - ;; field user-data uses ~A with a 64-bit load. + ;; field user-data uses ~A with a 64-bit load. (:methods (scene-player-method-20 () none) ;; 20 ;; (wait (symbol) _type_ :state) (scene-player-method-21 () none) ;; 21 ;; (release () _type_ :state) @@ -13807,7 +13992,7 @@ :method-count-assert 16 :size-assert #xac :flag-assert #x10000000ac - ;; field track-mode is likely a value type. + ;; field track-mode is likely a value type. (:methods (new (symbol type) _type_) ;; 0 ;; (new (symbol type joint-mod-mode process-drawable int) _type_) (joint-mod-method-9 () none) ;; 9 ;; (mode-set! (_type_ joint-mod-mode) none) @@ -14391,7 +14576,7 @@ :method-count-assert 55 :size-assert #xc8 :flag-assert #x37000000c8 - ;; field penetrate is likely a value type. field penetrate is likely a value type. + ;; field penetrate is likely a value type. field penetrate is likely a value type. (:methods (new (symbol type) _type_) ;; 0 ;; (new (symbol type process-drawable collide-list-enum) _type_) (collide-shape-method-28 () none) ;; 28 ;; (move-by-vector! (_type_ vector) none) @@ -14454,7 +14639,7 @@ :method-count-assert 68 :size-assert #x1dc :flag-assert #x44000001dc - ;; field penetrate is likely a value type. field penetrate is likely a value type. + ;; field penetrate is likely a value type. field penetrate is likely a value type. (:methods (new (symbol type) _type_) ;; 0 ;; (new (symbol type process-drawable collide-list-enum) _type_) (collide-shape-moving-method-55 () none) ;; 55 ;; (find-ground (_type_ collide-query collide-spec float float float) symbol) @@ -14536,7 +14721,7 @@ :method-count-assert 18 :size-assert #x15c :flag-assert #x1200e0015c - ;; field userdata uses ~A with a 64-bit load. + ;; field userdata uses ~A with a 64-bit load. (:methods (part-tracker-method-14 () none) ;; 14 ;; (active () _type_ :state) (part-tracker-method-15 () none) ;; 15 ;; (notify-parent-of-death (_type_) none) @@ -14558,7 +14743,7 @@ :method-count-assert 9 :size-assert #x20 :flag-assert #x900000020 - ;; field userdata uses ~A with a 64-bit load. field mat-joint uses ~A with a signed load. + ;; field userdata uses ~A with a 64-bit load. field mat-joint uses ~A with a signed load. ) |# @@ -14575,7 +14760,7 @@ :method-count-assert 9 :size-assert #x24 :flag-assert #x900000024 - ;; field userdata uses ~A with a 64-bit load. field mat-joint uses ~A with a signed load. + ;; field userdata uses ~A with a 64-bit load. field mat-joint uses ~A with a signed load. ) |# @@ -14611,7 +14796,7 @@ :method-count-assert 17 :size-assert #x130 :flag-assert #x1100b00130 - ;; field userdata uses ~A with a 64-bit load. + ;; field userdata uses ~A with a 64-bit load. (:methods (lightning-tracker-method-14 () none) ;; 14 ;; (active () _type_ :state) (lightning-tracker-method-15 () none) ;; 15 ;; (notify-parent-of-death (_type_) none) @@ -16085,7 +16270,7 @@ :method-count-assert 30 :size-assert #xa00 :flag-assert #x1e09800a00 - ;; field mode-param2 uses ~A with a 64-bit load. field mode-param3 uses ~A with a 64-bit load. + ;; field mode-param2 uses ~A with a 64-bit load. field mode-param3 uses ~A with a 64-bit load. (:methods (target-method-28 () none) ;; 28 ;; (init-target (_type_ continue-point symbol) none) (target-method-29 () none) ;; 29 @@ -18855,7 +19040,7 @@ :method-count-assert 9 :size-assert #x10 :flag-assert #x900000010 - ;; field object uses ~A with a signed load. + ;; field object uses ~A with a signed load. ) |# @@ -19039,7 +19224,7 @@ :method-count-assert 9 :size-assert #x8c :flag-assert #x90000008c - ;; field user-object uses ~A with a signed load. field key uses ~A with a signed load. + ;; field user-object uses ~A with a signed load. field key uses ~A with a signed load. ) |# @@ -20946,7 +21131,7 @@ :method-count-assert 50 :size-assert #x70 :flag-assert #x3200000070 - ;; field nav-mesh-flag is likely a value type. + ;; field nav-mesh-flag is likely a value type. (:methods (nav-mesh-method-9 () none) ;; 9 ;; (debug-draw (_type_) none) (nav-mesh-method-10 () none) ;; 10 ;; (nav-mesh-method-10 (_type_ vector vector nav-poly) nav-poly) @@ -21509,7 +21694,7 @@ :method-count-assert 56 :size-assert #x120 :flag-assert #x3800a00120 - ;; field rigid-body-object-flag is likely a value type. + ;; field rigid-body-object-flag is likely a value type. (:methods (rigid-body-object-method-28 () none) ;; 28 ;; (active () _type_ :state) (rigid-body-object-method-29 () none) ;; 29 ;; (rigid-body-object-method-29 (_type_ float) none) @@ -22417,7 +22602,7 @@ :method-count-assert 12 :size-assert #x28 :flag-assert #xc00000028 - ;; field out uses ~A with a signed load. + ;; field out uses ~A with a signed load. (:methods (new (symbol type) _type_) ;; 0 ;; (new (symbol type uint) _type_) (history-iterator-method-9 () none) ;; 9 ;; (frame-counter-delta (_type_ history-elt) time-frame) @@ -23553,7 +23738,7 @@ :method-count-assert 9 :size-assert #x130 :flag-assert #x900000130 - ;; field ra uses ~A with a signed load. field dummy0 uses ~A with a signed load. field dummy1 uses ~A with a signed load. field b-spfic uses ~A with a signed load. field l-spfic uses ~A with a signed load. + ;; field ra uses ~A with a signed load. field dummy0 uses ~A with a signed load. field dummy1 uses ~A with a signed load. field b-spfic uses ~A with a signed load. field l-spfic uses ~A with a signed load. ) |# @@ -25472,7 +25657,7 @@ :method-count-assert 9 :size-assert #x1c :flag-assert #x90000001c - ;; field parm0 uses ~A with a signed load. field parm1 uses ~A with a signed load. + ;; field parm0 uses ~A with a signed load. field parm1 uses ~A with a signed load. ) |# @@ -25500,7 +25685,7 @@ :method-count-assert 9 :size-assert #x1c :flag-assert #x90000001c - ;; field track-val uses ~A with a signed load. field val-parm0 uses ~A with a signed load. field val-parm1 uses ~A with a signed load. + ;; field track-val uses ~A with a signed load. field val-parm0 uses ~A with a signed load. field val-parm1 uses ~A with a signed load. ) |# @@ -26021,7 +26206,7 @@ :method-count-assert 38 :size-assert #xac :flag-assert #x26000000ac - ;; field cloth-flag is likely a value type. + ;; field cloth-flag is likely a value type. (:methods (cloth-system-method-16 () none) ;; 16 (cloth-system-method-17 () none) ;; 17 @@ -26059,7 +26244,7 @@ :method-count-assert 38 :size-assert #x110 :flag-assert #x2600000110 - ;; field cloth-flag is likely a value type. + ;; field cloth-flag is likely a value type. ) |# @@ -27155,7 +27340,7 @@ :method-count-assert 17 :size-assert #xb0 :flag-assert #x11000000b0 - ;; field carry-mode is likely a value type. + ;; field carry-mode is likely a value type. (:methods (new (symbol type) _type_) ;; 0 ;; (new (symbol type process-drawable int vector vector float) _type_) (carry-info-method-9 () none) ;; 9 ;; (carry-info-method-9 (_type_) none) @@ -31076,7 +31261,7 @@ :method-count-assert 9 :size-assert #x14 :flag-assert #x900000014 - ;; field info uses ~A with a signed load. + ;; field info uses ~A with a signed load. ) |# @@ -31647,7 +31832,7 @@ :method-count-assert 13 :size-assert #x30 :flag-assert #xd00000030 - ;; field on-enter uses ~A with a signed load. field on-inside uses ~A with a signed load. field on-exit uses ~A with a signed load. + ;; field on-enter uses ~A with a signed load. field on-inside uses ~A with a signed load. field on-exit uses ~A with a signed load. (:methods (new (symbol type) _type_) ;; 0 ;; (new (symbol type) _type_) (editable-region-method-9 () none) ;; 9 ;; (editable-region-method-9 (_type_ editable-array int int) symbol) @@ -32910,7 +33095,7 @@ :method-count-assert 30 :size-assert #x1b0 :flag-assert #x1e013001b0 - ;; field level-name uses ~A with a signed load. field open-test uses ~A with a signed load. field on-running uses ~A with a signed load. + ;; field level-name uses ~A with a signed load. field open-test uses ~A with a signed load. field on-running uses ~A with a signed load. (:methods (com-airlock-method-22 () none) ;; 22 ;; (init-airlock! (_type_) _type_) (com-airlock-method-23 () none) ;; 23 ;; (want-cross-airlock? (_type_) symbol) @@ -33078,7 +33263,7 @@ :method-count-assert 9 :size-assert #x14 :flag-assert #x900000014 - ;; field param2 uses ~A with a signed load. + ;; field param2 uses ~A with a signed load. ) |# @@ -33382,7 +33567,7 @@ :method-count-assert 155 :size-assert #x228 :flag-assert #x9b01b00228 - ;; field enemy-flag is likely a value type. field on-notice uses ~A with a signed load. field on-active uses ~A with a signed load. field on-hostile uses ~A with a signed load. field on-death uses ~A with a signed load. + ;; field enemy-flag is likely a value type. field on-notice uses ~A with a signed load. field on-active uses ~A with a signed load. field on-hostile uses ~A with a signed load. field on-death uses ~A with a signed load. (:methods (enemy-method-28 () none) ;; 28 ;; (dormant-aware () _type_ :state) (enemy-method-29 () none) ;; 29 ;; (hit () _type_ :state) @@ -33879,7 +34064,7 @@ :method-count-assert 52 :size-assert #x1a0 :flag-assert #x34012001a0 - ;; field on-activate uses ~A with a signed load. field on-deactivate uses ~A with a signed load. field on-up uses ~A with a signed load. field on-down uses ~A with a signed load. field on-running uses ~A with a signed load. field on-notice uses ~A with a signed load. field on-wait uses ~A with a signed load. field activate-test uses ~A with a signed load. + ;; field on-activate uses ~A with a signed load. field on-deactivate uses ~A with a signed load. field on-up uses ~A with a signed load. field on-down uses ~A with a signed load. field on-running uses ~A with a signed load. field on-notice uses ~A with a signed load. field on-wait uses ~A with a signed load. field activate-test uses ~A with a signed load. (:methods (elevator-method-39 () none) ;; 39 ;; (calc-dist-between-points! (_type_ int int) none) (elevator-method-41 () none) ;; 41 ;; (init-defaults! (_type_) none) @@ -34317,7 +34502,7 @@ :method-count-assert 26 :size-assert #x100 :flag-assert #x1a00800100 - ;; field on-notice uses ~A with a signed load. field on-activate uses ~A with a signed load. field on-close uses ~A with a signed load. + ;; field on-notice uses ~A with a signed load. field on-activate uses ~A with a signed load. field on-close uses ~A with a signed load. (:methods (warp-gate-method-23 () none) ;; 23 ;; (init-skel-and-collide (_type_) none) (warp-gate-method-24 () none) ;; 24 ;; (setup-fields (_type_) none) @@ -35178,7 +35363,7 @@ :method-count-assert 53 :size-assert #x110 :flag-assert #x3500900110 - ;; field on-notice uses ~A with a signed load. field on-hostile uses ~A with a signed load. field on-beaten uses ~A with a signed load. + ;; field on-notice uses ~A with a signed load. field on-hostile uses ~A with a signed load. field on-beaten uses ~A with a signed load. (:methods (battle-method-21 () none) ;; 21 ;; (battle-state-21 () _type_ :state) (battle-method-25 () none) ;; 25 ;; (spawner-blocked? (_type_ battle-spawner) symbol) @@ -35357,7 +35542,7 @@ :method-count-assert 9 :size-assert #x1c :flag-assert #x90000001c - ;; field net-path-node-status is likely a value type. + ;; field net-path-node-status is likely a value type. ) |# @@ -37341,7 +37526,7 @@ :method-count-assert 15 :size-assert #xa0 :flag-assert #xf002000a0 - ;; field activate-script uses ~A with a signed load. field enter-script uses ~A with a signed load. field exit-script uses ~A with a signed load. + ;; field activate-script uses ~A with a signed load. field enter-script uses ~A with a signed load. field exit-script uses ~A with a signed load. (:state-methods active ;; 14 ) @@ -39503,7 +39688,7 @@ :method-count-assert 59 :size-assert #x224 :flag-assert #x3b01b00224 - ;; field pause-proc uses ~A with a signed load. + ;; field pause-proc uses ~A with a signed load. (:methods (target-turret-method-34 () none) ;; 34 (target-turret-method-35 () none) ;; 35 @@ -40264,7 +40449,7 @@ :method-count-assert 22 :size-assert #x20 :flag-assert #x1600000020 - ;; field nav-node-flag is likely a value type. + ;; field nav-node-flag is likely a value type. (:methods (nav-node-method-9 () none) ;; 9 ;; (debug-draw (_type_) none) (nav-node-method-10 () none) ;; 10 ;; (debug-print (_type_ symbol string) none) @@ -40568,7 +40753,7 @@ :method-count-assert 11 :size-assert #x20 :flag-assert #xb00000020 - ;; field vis-cell-flag is likely a value type. field vis-cell-flag is likely a value type. + ;; field vis-cell-flag is likely a value type. field vis-cell-flag is likely a value type. (:methods (vis-cell-method-9 () none) ;; 9 ;; (reset-segment-counts (_type_) none) (vis-cell-method-10 () none) ;; 10 ;; (debug-draw (_type_) none) @@ -41120,7 +41305,7 @@ :method-count-assert 216 :size-assert #x404 :flag-assert #xd803900404 - ;; field citizen-flag is likely a value type. + ;; field citizen-flag is likely a value type. (:methods (citizen-method-190 () none) ;; 190 ;; (citizen-method-190 (_type_ vector) none) (citizen-method-191 () none) ;; 191 ;; (gen-clear-path (_type_) nav-segment) @@ -41847,7 +42032,7 @@ :method-count-assert 68 :size-assert #x1dc :flag-assert #x44000001dc - ;; field penetrate is likely a value type. field penetrate is likely a value type. + ;; field penetrate is likely a value type. field penetrate is likely a value type. ) |# @@ -45103,7 +45288,7 @@ :method-count-assert 9 :size-assert #x44 :flag-assert #x900000044 - ;; field squad-target-flag is likely a value type. + ;; field squad-target-flag is likely a value type. ) |# @@ -45126,7 +45311,7 @@ :method-count-assert 10 :size-assert #x120 :flag-assert #xa00000120 - ;; field squad-alert-flag is likely a value type. + ;; field squad-alert-flag is likely a value type. (:methods (squad-alert-state-method-9 () none) ;; 9 ) @@ -45733,7 +45918,7 @@ :method-count-assert 152 :size-assert #x2b8 :flag-assert #x98024002b8 - ;; field vehicle-flag is likely a value type. + ;; field vehicle-flag is likely a value type. (:methods (vehicle-method-56 () none) ;; 56 ;; (vehicle-state-56 () _type_ :state) (vehicle-method-57 () none) ;; 57 ;; (player-control () _type_ :state) @@ -46137,7 +46322,7 @@ :method-count-assert 18 :size-assert #x60 :flag-assert #x1200000060 - ;; field turret-flag is likely a value type. + ;; field turret-flag is likely a value type. (:methods (turret-control-method-9 () none) ;; 9 ;; (turret-control-method-9 (_type_ vehicle vector vector) none) (turret-control-method-10 () none) ;; 10 ;; (turret-control-method-10 (_type_ vehicle) none) @@ -46699,7 +46884,7 @@ :method-count-assert 31 :size-assert #x200 :flag-assert #x1f01800200 - ;; field on-start uses ~A with a signed load. field on-stop uses ~A with a signed load. field on-shutdown uses ~A with a signed load. field on-trigger uses ~A with a signed load. + ;; field on-start uses ~A with a signed load. field on-stop uses ~A with a signed load. field on-shutdown uses ~A with a signed load. field on-trigger uses ~A with a signed load. (:methods (elec-gate-method-24 () none) ;; 24 ;; (elec-gate-method-24 (_type_) none) (elec-gate-method-25 () none) ;; 25 ;; (set-palette! (_type_) none) @@ -48285,7 +48470,7 @@ :method-count-assert 10 :size-assert #xaa :flag-assert #xa000000aa - ;; field borrow uses ~A with a signed load. + ;; field borrow uses ~A with a signed load. (:methods (race-info-method-9 () none) ;; 9 ;; (initialize-mesh (_type_) none) ) @@ -49771,7 +49956,7 @@ :method-count-assert 9 :size-assert #x2c :flag-assert #x90000002c - ;; field vehicle-wheel-surface-flag is likely a value type. + ;; field vehicle-wheel-surface-flag is likely a value type. ) |# @@ -50931,7 +51116,7 @@ :method-count-assert 9 :size-assert #x20 :flag-assert #x900000020 - ;; field check-too-far uses ~A with a signed load. + ;; field check-too-far uses ~A with a signed load. ) |# @@ -50954,7 +51139,7 @@ :method-count-assert 9 :size-assert #x30 :flag-assert #x900000030 - ;; field default-check-too-far uses ~A with a signed load. + ;; field default-check-too-far uses ~A with a signed load. ) |# @@ -51134,7 +51319,7 @@ :method-count-assert 9 :size-assert #x38 :flag-assert #x900000038 - ;; field default-check-too-far uses ~A with a signed load. + ;; field default-check-too-far uses ~A with a signed load. ) |# @@ -52264,7 +52449,7 @@ :method-count-assert 209 :size-assert #x4e0 :flag-assert #xd1046004e0 - ;; field gekko-flag is likely a value type. + ;; field gekko-flag is likely a value type. (:methods (gekko-method-202 () none) ;; 202 (gekko-method-203 () none) ;; 203 @@ -54409,7 +54594,7 @@ :method-count-assert 23 :size-assert #xe4 :flag-assert #x17007000e4 - ;; field open-test uses ~A with a signed load. + ;; field open-test uses ~A with a signed load. (:methods (precura-door-a-method-22 () none) ;; 22 ) @@ -54624,7 +54809,7 @@ :method-count-assert 30 :size-assert #x1b4 :flag-assert #x1e014001b4 - ;; field open-test uses ~A with a signed load. + ;; field open-test uses ~A with a signed load. (:state-methods open ;; 20 ) @@ -55669,7 +55854,7 @@ :method-count-assert 45 :size-assert #x15c :flag-assert #x2d00e0015c - ;; field on-activate uses ~A with a signed load. + ;; field on-activate uses ~A with a signed load. (:methods (wstd-arena-plat-method-43 () none) ;; 43 (wstd-arena-plat-method-44 () none) ;; 44 @@ -55773,7 +55958,7 @@ :method-count-assert 9 :size-assert #x28 :flag-assert #x900000028 - ;; field textures uses ~A with a signed load. + ;; field textures uses ~A with a signed load. ) |# @@ -56534,7 +56719,7 @@ :method-count-assert 207 :size-assert #x2e0 :flag-assert #xcf026002e0 - ;; field mantis-flag is likely a value type. + ;; field mantis-flag is likely a value type. (:methods (mantis-method-195 () none) ;; 195 (mantis-method-199 () none) ;; 199 @@ -61002,7 +61187,7 @@ :method-count-assert 23 :size-assert #xe0 :flag-assert #x17006000e0 - ;; field open-test uses ~A with a signed load. + ;; field open-test uses ~A with a signed load. (:methods (precur-door-a-method-22 () none) ;; 22 ) @@ -64966,7 +65151,7 @@ :method-count-assert 9 :size-assert #x18 :flag-assert #x900000018 - ;; field param uses ~A with a signed load. + ;; field param uses ~A with a signed load. ) |# diff --git a/decompiler/config/jak3/ntsc_v1/var_names.jsonc b/decompiler/config/jak3/ntsc_v1/var_names.jsonc index e72d67eb0..98bfe546d 100644 --- a/decompiler/config/jak3/ntsc_v1/var_names.jsonc +++ b/decompiler/config/jak3/ntsc_v1/var_names.jsonc @@ -1,4 +1,323 @@ { + "(method 0 inline-array-class)": { + "args": [ + "allocation", + "type-to-make", + "count" + ] + }, + "(method 9 inline-array-class)": { + "args": [ + "object-to-insert" + ] + }, + "(method 3 inline-array-class)": { + "args": [ + "idx-to-remove" + ] + }, + "identity": { + "args": [ + "obj" + ] + }, + "1/": { + "args": [ + "x" + ] + }, + "+": { + "args": [ + "a", + "b" + ] + }, + "-": { + "args": [ + "a", + "b" + ] + }, + "*": { + "args": [ + "a", + "b" + ] + }, + "/": { + "args": [ + "a", + "b" + ] + }, + "ash": { + "args": [ + "x", + "shift-amount" + ] + }, + "mod": { + "args": [ + "a", + "b" + ] + }, + "rem": { + "args": [ + "a", + "b" + ] + }, + "abs": { + "args": [ + "x" + ] + }, + "min": { + "args": [ + "a", + "b" + ] + }, + "max": { + "args": [ + "a", + "b" + ] + }, + "logior": { + "args": [ + "a", + "b" + ] + }, + "logand": { + "args": [ + "a", + "b" + ] + }, + "lognor": { + "args": [ + "a", + "b" + ] + }, + "logxor": { + "args": [ + "a", + "b" + ] + }, + "lognot": { + "args": [ + "x" + ] + }, + "basic-type?": { + "args": [ + "obj", + "typ" + ] + }, + "type-type?": { + "args": [ + "check-type", + "parent-type" + ] + }, + "type?": { + "args": [ + "obj", + "desired-type" + ] + }, + "find-parent-method": { + "args": [ + "typ", + "method-id" + ] + }, + "ref&": { + "args": [ + "list", + "idx" + ] + }, + "ref": { + "args": [ + "list", + "idx" + ] + }, + "last": { + "args": [ + "list" + ] + }, + "member": { + "args": [ + "obj-to-find", + "list" + ] + }, + "nmember": { + "args": [ + "obj-to-find", + "list" + ] + }, + "assoc": { + "args": [ + "key", + "assoc-list" + ] + }, + "assoce": { + "args": [ + "key", + "assoc-list" + ] + }, + "nassoc": { + "args": [ + "key", + "assoc-list" + ] + }, + "nassoce": { + "args": [ + "key", + "assoc-list" + ] + }, + "append!": { + "args": [ + "list", + "new-obj" + ] + }, + "delete!": { + "args": [ + "obj", + "list" + ] + }, + "delete-car!": { + "args": [ + "car-to-match", + "list" + ] + }, + "insert-cons!": { + "args": [ + "new-obj", + "list" + ] + }, + "sort": { + "args": [ + "list", + "compare-func" + ] + }, + "string->symbol-debug": { + "args": [ + "str" + ] + }, + "symbol->string-debug": { + "args": [ + "sym" + ] + }, + "symbol->hash": { + "args": [ + "sym" + ] + }, + "mem-copy!": { + "args": [ + "dst", + "src", + "bytes" + ] + }, + "qmem-copy<-!": { + "args": [ + "dst", + "src", + "qwc" + ] + }, + "qmem-copy->!": { + "args": [ + "dst", + "src", + "qwc" + ] + }, + "qmem-clear!": { + "args": [ + "dst", + "qwc" + ] + }, + "mem-set32!": { + "args": [ + "dst", + "word-count", + "value" + ] + }, + "mem-or!": { + "args": [ + "dst", + "src", + "bytes" + ] + }, + "fact": { + "args": [ + "x" + ] + }, + "print": { + "args": [ + "obj" + ] + }, + "printl": { + "args": [ + "obj" + ] + }, + "inspect": { + "args": [ + "obj" + ] + }, + "mem-print": { + "args": [ + "ptr", + "word-count" + ] + }, + "print-tree-bitmask": { + "args": [ + "mask", + "count" + ] + }, + "valid?": { + "args": [ + "obj", + "expected-type", + "err-msg-str", + "allow-false", + "err-msg-dest" + ] + }, "matrix-transpose!": { "args": [ "dst", diff --git a/decompiler/util/DecompilerTypeSystem.cpp b/decompiler/util/DecompilerTypeSystem.cpp index d006ab704..990a71454 100644 --- a/decompiler/util/DecompilerTypeSystem.cpp +++ b/decompiler/util/DecompilerTypeSystem.cpp @@ -11,7 +11,7 @@ #include "decompiler/Disasm/Register.h" namespace decompiler { -DecompilerTypeSystem::DecompilerTypeSystem(GameVersion version) { +DecompilerTypeSystem::DecompilerTypeSystem(GameVersion version) : m_version(version) { ts.add_builtin_types(version); } diff --git a/decompiler/util/DecompilerTypeSystem.h b/decompiler/util/DecompilerTypeSystem.h index dcff54bb1..60fd82f4f 100644 --- a/decompiler/util/DecompilerTypeSystem.h +++ b/decompiler/util/DecompilerTypeSystem.h @@ -95,7 +95,10 @@ class DecompilerTypeSystem { void reset() { current_method_type.clear(); } } type_prop_settings; + GameVersion version() const { return m_version; } + private: + GameVersion m_version; mutable goos::Reader m_reader; }; } // namespace decompiler diff --git a/decompiler/util/data_decompile.cpp b/decompiler/util/data_decompile.cpp index 2898582bb..5436e8e8a 100644 --- a/decompiler/util/data_decompile.cpp +++ b/decompiler/util/data_decompile.cpp @@ -179,7 +179,7 @@ goos::Object decompile_function_at_label(const DecompilerLabel& label, auto other_func = file->try_get_function_at_label(label); if (other_func && other_func->ir2.env.has_local_vars() && other_func->ir2.top_form && other_func->ir2.expressions_succeeded) { - auto out = final_output_lambda(*other_func); + auto out = final_output_lambda(*other_func, file->version); if (in_static_pair) { return pretty_print::build_list("unquote", out); } else { diff --git a/docs/progress-notes/blerc.md b/docs/progress-notes/blerc.md new file mode 100644 index 000000000..0739eea49 --- /dev/null +++ b/docs/progress-notes/blerc.md @@ -0,0 +1,44 @@ +# BLERC +"blerc" = "merc blend shape" is the face animation program. + +It works by updating the vertices used by merc. + +It begine with a call to `(blerc-init)`, which resets the list of things to blerc. + +Then, each process-drawable calls `merc-blend-shape` (if needed), which figures out the blend shape coefficients for the current frame, and passes it to `setup-blerc-chains`. This builds a DMA chain of all blercs. + +However, this DMA chain doesn't get put in a VU1 bucket. Instead, after the full chain is build, `(blerc-execute)` will do a bunch of math and update the merc vertex data. + +This was checked by running `(-> (the process-drawable (process-by-name "sidekick" *active-pool*)) draw mgeo effect 0 frag-geo)` and seeing that the `spad_from_dma_no_sadr_off` in `merc_blend_shape.cpp` was writing to this data. + +There is a system to avoid doing blerc computations when not needed. Once blerc is disabled, it does a single final run with all 0's, which puts everything "back to normal", and then blerc no longer runs. + +# Determining which fragments can be blerc'd +In the PC port, we will need to update the vertices. We want to update as few vertices as possible at runtime because this will likely be slow. Additionally, we need metadata to figure out how to go from modified merc data back to PC-port format. If we know which vertices can possibly be modified by blerc, we can skip including the metadata for the rest. Only a small number of merc vertices are faces, so this could be a big win for data size. + +As far as I can tell, there's a `merc-blend-ctrl` per each fragment. It's size is `2 + merc_ctrl.header.blend_target_count`. If the `blend-vtx-count` field of a merc-blend-ctrl is 0, then this fragment has no blerc. + +Checking some common models: +(showing number of effects, frags, lump4 bytes that have possible blerc) +``` +BLERC: eichar-lod0, 3/4 e, 15/85 f, 1737/9984 v +BLERC: sidekick-lod0, 3/4 e, 9/35 f, 957/3933 v +``` + +# PC draw lists: +The plan is to make 3 sets of draws: +- Normal draw list +- Draw list that touches no blerc vertices +- Alternate draw list for blerc vertices + +The first list is what is normally used. This may contain draws that mix together blerc and non-blerc vertices. + +The second draw list can be used when blerc is active for this character for all the non-blerc vertices. + +The third draw list will contain the blerc vertices, but will do indexing slightly differently. Instead of indexing into the giant array of all merc vertices, it will index into the yet-to-be-filled blerc index buffer for this character. + +This approach gives us: +- the same performance as before if blerc is off +- easy way to do per-character blerc'd vertex uploads +- possibility to do per-frame blerc'd vertex uploads with some clever indexing. +- per-fragment granularity for blerc on/off \ No newline at end of file diff --git a/docs/progress-notes/jak1/scratch/generic_tie_to_etie.md b/docs/progress-notes/jak1/scratch/generic_tie_to_etie.md new file mode 100644 index 000000000..867e2c285 --- /dev/null +++ b/docs/progress-notes/jak1/scratch/generic_tie_to_etie.md @@ -0,0 +1,137 @@ +## Finding the Normals +We're going to assume that the generic tie math in Jak 1 is the same as ETIE as Jak 2. This could be wrong, but it should be easy to verify. + +The tricky part is finding the normals. These are needed for ETIE, but not plain TIE. + +For looking through the types, it seems like generic TIE uses the same normals as ETIE: +```lisp +(deftype generic-tie-normal (structure) + ((x int8 :offset-assert 0) + (y int8 :offset-assert 1) + (z int8 :offset-assert 2) + (dummy int8 :offset-assert 3) ;; was 0 in ETIE normals. + ) + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ) +``` + +Searching around for normal +```lisp +(deftype generic-tie-header (structure) + ((effect uint8 :offset-assert 0) + (interp-table-size uint8 :offset-assert 1) + (num-bps uint8 :offset-assert 2) + (num-ips uint8 :offset-assert 3) + (tint-color uint32 :offset-assert 4) + (index-table-offset uint16 :offset-assert 8) + (kick-table-offset uint16 :offset-assert 10) + (normal-table-offset uint16 :offset-assert 12) ;; here it is! + (interp-table-offset uint16 :offset-assert 14) + (gsf-header gsf-header :inline :offset-assert 16) + ) + :method-count-assert 9 + :size-assert #x20 + :flag-assert #x900000020 + ) +``` + +My first guess is that the generic data for a TIE fragment is just a header, and these `uint16`s are byte-offsets for the normal data. I'd guess that there's a header per-fragment - they used `uint8`'s for `num-bps`/`num-ips` (base points, interpolated points). A single proto might have more than 255 points, but a fragment won't. + +My guess is that `generic-ref` in a `tie-fragment` points to some data that starts with `generic-tie-header`. +```lisp +(deftype tie-fragment (drawable) + ((gif-ref (inline-array adgif-shader) :offset 4) + (point-ref uint32 :offset 8) + (color-index uint16 :offset 12) + (base-colors uint8 :offset 14) + (tex-count uint16 :offset-assert 32) + (gif-count uint16 :offset-assert 34) + (vertex-count uint16 :offset-assert 36) + (color-count uint16 :offset-assert 38) + (num-tris uint16 :offset-assert 40) + (num-dverts uint16 :offset-assert 42) + (dp-ref uint32 :offset-assert 44) + (dp-qwc uint32 :offset-assert 48) + (generic-ref uint32 :offset-assert 52) ;; the data we want + (generic-count uint32 :offset-assert 56) + (debug-lines (array vector-array) :offset-assert 60) + ) + :method-count-assert 18 + :size-assert #x40 + :flag-assert #x1200000040 + ) +``` + +Extract the data from the file +```cpp + u16 generic_qwc = read_plain_data_field(ref, "generic-count", dts); + if (generic_qwc) { + generic_data.resize(16 * generic_qwc); + auto generic_data_ref = deref_label(get_field_ref(ref, "generic-ref", dts)); + memcpy_plain_data((u8*)generic_data.data(), generic_data_ref, generic_qwc * 16); +``` + +The data made sense. There were some cases where the `interp-table` and the `normal-table` appeared to be on top of each other, but this only occured when `num-ips` was 0 and `interp-table-size` was 0 too. + +Treating `normal-table-offset` as a byte-offset from the start of the header seemed to work. + +One fear I had is that the mesh for generic/non-generic is somehow different, so I sanity checked that `num-ips` + `num-bps` from the generic header matched the total unique vertex count from the TIE unpacker. + +## Finding the Envmap shader +We need an additional shader for the environment map draw. Fortunately, this seems the same as Jak 2 - there's a field in `prototype-bucket-tie` for it. I turned on that code for Jak 1, and it found envmap shaders on reasonable things. + +## Finding the tint color +This is a little trickier. In jak 2, the tint color was specified per bucket, but in Jak 1, it's specified per fragment. Luckily my data format for ETIE can support this, but `extract_tie.cpp` needs some refactoring to actually generate it. + +## Normal Bugs + +Some very small number of fragments appear totally wrong. + +The most likely explanation is the normals are in the wrong order. The normals seems like valid normals, but looking at the mesh, they are clearly wrong. + +I made the assumption that the order of normals would match the order of points, but could this be wrong? + +There's this table called `index_table`: +``` +0 2 32 33 +1 3 16 17 +34 35 4 5 +6 8 36 37 +7 9 18 20 +38 39 19 21 +10 11 40 41 +22 23 12 13 +42 43 24 25 +14 15 44 45 +26 27 28 29 +46 47 30 31 +``` +but going through extremely carefully showed nothing interesting... It all matches up perfectly + +Next step: maybe the normal matrix is wrong... let's try to actually find the mystery scaling factor: + +``` +vmulx.xyz vf16, vf10, vf14 +``` +the `vf14.x` here. + +``` +lui t6, 16256 +mtc1 f1, t6 ;; 1.0 + +qmfc2.i s1, vf10 +mtc1 f12, s1 +dsra32 s2, s1, 0 +mtc1 f13, s2 +pextuw s2, r0, s2 +mtc1 f14, s2 +mula.s f12, f12 +madda.s f13, f13 +madd.s f15, f14, f14 +rsqrt.s f15, f1, f15 +mfc1 s1, f15 +qmtc2.i vf14, s1 +vmulx.xyz vf16, vf10, vf14 +``` \ No newline at end of file diff --git a/docs/progress-notes/jak2/blerc_asm.md b/docs/progress-notes/jak2/blerc_asm.md new file mode 100644 index 000000000..0e209f2bf --- /dev/null +++ b/docs/progress-notes/jak2/blerc_asm.md @@ -0,0 +1,513 @@ +``` +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; .function setup-blerc-chains-for-one-fragment +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(setup-blerc-chains-for-one-fragment + a0: num-targets + a1: blend-shape-coeffs (s16 array) + a2: dma-mem-ptr + a3: blend-data + t0: blend-ctrl + t1: geo-data) + +B0: +L9: + daddiu sp, sp, -128 + sd ra, 0(sp) + sq s0, 16(sp) + sq s1, 32(sp) + sq s2, 48(sp) + sq s3, 64(sp) + sq s4, 80(sp) + sq s5, 96(sp) + sq gp, 112(sp) + lb v1, 0(t0) ;; v1 = blend-vtx-count + addiu t2, r0, 0 ;; t2 = 0 + por t7, r0, r0 ;; t7 = 0 + lw t3, *blerc-globals*(s7) ;; t3 = *blerc-globals* + lw t3, 4(t3) ;; t3 = blec-globals.next + or t4, v1, r0 ;; t4 = blend-vtx-count. + ;; link +B1: +L10: + lui t7, 4096 + sll r0, r0, 0 + daddiu t7, t7, 1 + sll r0, r0, 0 + beq t3, r0, L11 + sq t7, 0(a2) + +B2: + sw a2, 12(t3) + sll r0, r0, 0 +B3: +L11: + or t3, a2, r0 + daddu t6, t4, t4 + daddu t5, v1, v1 + daddu t6, t6, t4 + daddu t7, t5, v1 + daddu t5, t6, t6 + daddu t6, t7, t7 + daddu t7, t5, t5 + daddiu t6, t6, 15 + daddiu t5, t5, 15 + andi t6, t6, 65520 + dsrl t5, t5, 4 + daddu t8, t2, t2 + daddiu t7, t7, 15 + daddu t9, t8, t2 + dsrl t8, t7, 4 + daddu ra, t9, t9 + addiu t9, r0, 0 + daddu t7, ra, ra + daddiu s3, a2, 32 + daddu s2, ra, a3 + daddu ra, t7, t1 + lui t7, 12288 + daddiu gp, a0, -1 + daddu t7, t7, t5 + or s5, a1, r0 + sq t7, 0(s3) + daddiu s4, t0, 2 + sw s2, 4(s3) + daddu s2, s2, t6 + daddiu s3, s3, 16 + sll r0, r0, 0 +B4: +L12: + lb s1, 0(s4) + daddiu s4, s4, 1 + lh s0, 0(s5) + daddiu s5, s5, 2 + beq s1, r0, L13 + sq t7, 0(s3) + +B5: + sw s2, 4(s3) + daddu s2, s2, t6 + beq s0, r0, L13 + sw s0, 12(s3) + +B6: + daddiu s3, s3, 16 + daddiu t9, t9, 1 +B7: +L13: + bne gp, r0, L12 + daddiu gp, gp, -1 + +B8: + sq t7, 0(s3) + por t6, r0, r0 + sw ra, 4(s3) + lui t6, 28672 + sb t8, 0(s3) + sll r0, r0, 0 + sq t6, 16(s3) + daddiu t6, s3, 32 + sw t9, 20(a2) + sll r0, r0, 0 + sw t4, 16(a2) + sll r0, r0, 0 + sw ra, 24(a2) + sll r0, r0, 0 + sw t8, 28(a2) + sll r0, r0, 0 + bne t4, v1, L14 + daddiu t5, t5, 1 + +B9: + daddiu t7, t9, 3 + multu3 t5, t5, t7 + daddiu t5, t5, -457 + sll r0, r0, 0 + blez t5, L14 + sll r0, r0, 0 + +B10: + beq r0, r0, L10 + addiu t4, r0, 24 + +B11: +L14: + or a2, t6, r0 + daddu t2, t2, t4 + beq t2, v1, L15 + daddu t5, t2, t4 + +B12: + dsubu t5, t5, v1 + sll r0, r0, 0 + blez t5, L10 + sll r0, r0, 0 + +B13: + beq r0, r0, L10 + dsubu t4, v1, t2 + +B14: +L15: + lw v1, *blerc-globals*(s7) + sw t3, 4(v1) + or v0, a2, r0 + ld ra, 0(sp) + lq gp, 112(sp) + lq s5, 96(sp) + lq s4, 80(sp) + lq s3, 64(sp) + lq s2, 48(sp) + lq s1, 32(sp) + lq s0, 16(sp) + jr ra + daddiu sp, sp, 128 + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; .function blerc-execute +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;BAD PROLOGUE +;; Warnings: +;; INFO: Flagged as mips2c by config +;; INFO: Assembly Function + +B0: +L37: + daddiu sp, sp, -96 + sd ra, 0(sp) + sq s2, 16(sp) + sq s3, 32(sp) + sq s4, 48(sp) + sq s5, 64(sp) + sq gp, 80(sp) + lw v1, *blerc-globals*(s7) + lwu s5, 0(v1) + beq s5, r0, L56 + or v1, s7, r0 + +B1: + addiu v1, r0, 0 + addiu gp, r0, 0 + addiu v1, r0, 0 + lw v1, *gsf-buffer*(s7) + lw t9, flush-cache(s7) + addiu a0, r0, 0 + jalr ra, t9 + sll v0, ra, 0 + + addiu v1, r0, 848 + lui a0, 28672 + daddu a1, v1, a0 + lw v1, *blerc-globals*(s7) + daddu v1, r0, v1 + sll r0, r0, 0 + lui a0, 4096 + sll r0, r0, 0 + ori a0, a0, 54272 + andi a1, a1, 16383 +B2: +L38: + lw a2, 0(a0) + sll r0, r0, 0 + sll r0, r0, 0 + sll r0, r0, 0 + andi a2, a2, 256 + sll r0, r0, 0 + bne a2, r0, L38 + lw a2, 0(v1) + +B3: + beq a2, r0, L39 + sw a1, 128(a0) + +B4: + addiu v1, r0, 324 + sw a2, 48(a0) + sw r0, 32(a0) + sync.l + sw v1, 0(a0) + sync.l +B5: +L39: + or v1, r0, r0 + beq r0, r0, L55 + sll r0, r0, 0 + +B6: +L40: + bne gp, r0, L41 + sll r0, r0, 0 + +B7: + lui v1, 28672 + daddu a0, r0, v1 + beq r0, r0, L42 + sll r0, r0, 0 + +B8: +L41: + addiu v1, r0, 8192 + lui a0, 28672 + daddu a0, v1, a0 +B9: +L42: + bne gp, r0, L43 + sll r0, r0, 0 + +B10: + addiu v1, r0, 8192 + lui a1, 28672 + daddu a1, v1, a1 + beq r0, r0, L44 + sll r0, r0, 0 + +B11: +L43: + lui v1, 28672 + daddu a1, r0, v1 +B12: +L44: + daddiu v1, a0, 848 + daddu a2, r0, a0 + daddiu a3, a1, 848 + daddiu a1, v1, 12 + sll r0, r0, 0 + lui a2, 4096 + sll r0, r0, 0 + ori a2, a2, 54272 + andi a3, a3, 16383 +B13: +L45: + lw t0, 0(a2) + sll r0, r0, 0 + sll r0, r0, 0 + sll r0, r0, 0 + andi t0, t0, 256 + sll r0, r0, 0 + bne t0, r0, L45 + lw t0, 0(a1) + +B14: + beq t0, r0, L46 + sw a3, 128(a2) + +B15: + addiu a1, r0, 324 + sw t0, 48(a2) + sw r0, 32(a2) + sync.l + sw a1, 0(a2) + sync.l +B16: +L46: + ;; blend ctrl + ;; blend data + ;; coeffs. + ;; + or a1, r0, r0 + or a2, a0, r0 ;; likely the blerc-block. + lw a3, *gsf-buffer*(s7) + daddiu t2, a2, 880 ;; t2 is whatever's after blerc-block + lb t1, 0(t2) ;; size of whatever's after + sll r0, r0, 0 + or t0, a2, r0 ;; t0 is the blerc block + lw a1, 868(a2) ;; a1 = block.header.overlap + daddiu t3, t1, 1 ;; some counts?? + or t1, a3, r0 ;; t1 = ee buffer. + sll t8, t3, 4 ;; t8 = some count (stride) + sll t3, a1, 4 ;; t3 = overlap * 16 + daddu t9, t3, a3 ;; t9 = &buffer[overlap] (qws) + daddu t3, t2, t8 ;; t3 = &dummy[unk_count + 1] (qws) + beq a1, r0, L49 + daddiu ra, t2, 16 ;; ra = after block ptr (+1 qw to skip a header I guess) + + ;; this block expands "overlap"s to +B17: + lh t5, 12(t3) + daddu t2, t3, t8 + beq r0, r0, L48 + sll r0, r0, 0 + +B18: +L47: + lh t5, 12(t2) + daddu t2, t2, t8 + sq t6, 0(t1) + daddiu t1, t1, 16 +B19: +L48: + pcpyh t5, t5 + mfc1 r0, f31 + bne t1, t9, L47 + pcpyld t6, t5, t5 + +B20: + dsubu t3, t2, t8 + sll r0, r0, 0 +B21: +L49: + addiu t1, r0, 255 ;; cs + addiu t2, r0, 8192 ;; cs + lb s5, 0(t3) + daddiu s4, t3, 16 + pcpyh t1, t1 + mfc1 r0, f31 + pcpyld t1, t1, t1 + mfc1 r0, f31 + pcpyh t2, t2 + mfc1 r0, f31 + pcpyld t2, t2, t2 ;; t2 = 8192's + mfc1 r0, f31 + por t3, t1, r0 ;; t3 = 255's + mfc1 r0, f31 + por t4, r0, r0 + mfc1 r0, f31 +B22: +L50: + ld t6, 0(ra) + daddu s2, ra, t8 + daddiu ra, ra, 8 + or s3, a3, r0 + pextlb t6, r0, t6 + mfc1 r0, f31 + pmulth t7, t6, t2 + ld t5, 0(s2) + daddiu s5, s5, -1 + sll r0, r0, 0 + beq r0, r0, L52 + daddu s2, s2, t8 + +B23: +L51: + pmaddh t7, t5, t6 + ld t5, 0(s2) + daddu s2, s2, t8 + daddiu s3, s3, 16 +B24: +L52: + lq t6, 0(s3) + pextlb t5, t5, r0 + bne s3, t9, L51 + psrah t5, t5, 8 + +B25: + pmfhl.uw t5 + mfc1 r0, f31 + psraw t7, t7, 13 + mfc1 r0, f31 + psraw t5, t5, 13 + mfc1 r0, f31 + pinteh t5, t5, t7 + mfc1 r0, f31 + pminh t3, t3, t5 + mfc1 r0, f31 + pmaxh t4, t4, t5 + mfc1 r0, f31 + pminh t5, t5, t1 + mfc1 r0, f31 + pmaxh t5, t5, r0 + lq t7, 0(s4) + ppacb t5, r0, t5 + mfc1 r0, f31 + ppach t7, r0, t7 + mfc1 r0, f31 + pextlh t5, t5, t7 + mfc1 r0, f31 + sq t5, 0(t0) + daddiu t0, t0, 16 + bne s5, r0, L50 + daddiu s4, s4, 16 + +B26: + lw a3, *stats-blerc*(s7) + beq a3, s7, L53 + lw a3, *blerc-globals*(s7) + +B27: + lw t2, 12(a3) + lw t1, 16(a3) + lw t0, 20(a3) + lw a2, 864(a2) + multu3 a1, a1, a2 + daddiu t2, t2, 1 + daddu a2, t1, a2 + daddu a1, t0, a1 + sw t2, 12(a3) + sw a2, 16(a3) + sw a1, 20(a3) + pcpyud a1, t3, r0 + pminh t3, t3, a1 + dsrl32 a1, t3, 0 + pminh t3, t3, a1 + dsrl t3, t3, 16 + lh a1, 8(a3) + pminh t3, t3, a1 + sh t3, 8(a3) + pcpyud a1, t4, r0 + pmaxh t4, t4, a1 + dsrl32 a1, t4, 0 + pmaxh t4, t4, a1 + dsrl t4, t4, 16 + lh a1, 10(a3) + pmaxh t4, t4, a1 + sh t4, 10(a3) +B28: +L53: + or a1, r0, r0 + lwu a1, 872(a0) + or a3, a0, r0 + lwu a0, 876(a0) + lui a2, 4096 + sll r0, r0, 0 + ori a2, a2, 53248 + andi a3, a3, 16383 +B29: +L54: + lw t0, 0(a2) + sll r0, r0, 0 + sll r0, r0, 0 + sll r0, r0, 0 + andi t0, t0, 256 + sll r0, r0, 0 + bne t0, r0, L54 + sll r0, r0, 0 + +B30: + sw a3, 128(a2) + addiu a3, r0, 256 + sw a1, 16(a2) + sll r0, r0, 0 + sw a0, 32(a2) + sync.l + sw a3, 0(a2) + sync.l + or a0, r0, r0 + addiu a0, r0, 1 + dsubu gp, a0, gp + lwu s5, 12(v1) + or v1, s5, r0 +B31: +L55: + bne s5, r0, L40 + sll r0, r0, 0 + +B32: + or v1, s7, r0 +B33: +L56: + or v0, r0, r0 + ld ra, 0(sp) + lq gp, 80(sp) + lq s5, 64(sp) + lq s4, 48(sp) + lq s3, 32(sp) + lq s2, 16(sp) + jr ra + daddiu sp, sp, 96 + + sll r0, r0, 0 + sll r0, r0, 0 + sll r0, r0, 0 +``` \ No newline at end of file diff --git a/docs/progress-notes/jak2/generic.md b/docs/progress-notes/jak2/generic.md new file mode 100644 index 000000000..63eefdeff --- /dev/null +++ b/docs/progress-notes/jak2/generic.md @@ -0,0 +1,261 @@ +# Generic +What do we expect to fix by adding generic? + +- "warp" effect (distortion effect that samples the framebuffer) +- "death" effect (get transformed vertices in world for spawning death effect particles) +- "ripple query" feature (get transformed vertices in world, kinda like depth) +- "hud drawing" for the orb/metal head gem + +# Part 1: redirecting stuff to generic +Right now, we send everything to PC merc all the time, completely ignoring the original decision. I added code to redirect stuff back to generic when any of the above features are used. I noticed that warp stuff often contained two merc "effects" (really just chunks of frags drawn with the same renderer). One has `warp`, and the other has `force-mercneric`. So I redirected both of these to mercneric for now, though it's possible that the `force-mercneric` one can work with PC merc. (doesn't seem like a big deal either way...). + +This seemed to work - lots of broken merc stuff is correclty redirected. + +I also checked for the same sort of issue that we had with jak 1's "transparent sculptor visor". They have a trick to draw transparent stuff in a texture bucket that normally doesn't have transparency - they set `force-mercneric` and set bit `0b10` in the effect bits, which changes the blending mode for this effect. This same thing is possible in jak 2, and I added support for it as well. I couldn't find any cases where this actually mattered, but it doesn't hurt. + +# Part 2: Generic Buffer Setup +Like with many renderers, the bucket setup is only done if the renderer is actually used. +This path is: +- `swap-display` is called in `main.gc` +- this calls `display-frame-finish` +- this calls `generic-vu1-init-buffers` +- this calls a function to initialize each generic bucket. For warp, it does +``` +;; s5-0 is the usual gs-zbuf with depth writes enabled +(generic-vu1-init-buf-special (bucket-id gmerc-warp) s5-0) +``` + +``` +(defun generic-vu1-init-buf-special ((arg0 bucket-id) (arg1 gs-zbuf)) + "At the beginning of this bucket's chain, insert DMA data for fx-copy-buf and initializing generic." + (let ((s5-0 (-> *display* frames (-> *display* on-screen) bucket-group arg0))) + (when (!= s5-0 (-> s5-0 last)) + (let* ((s4-0 (-> *display* frames (-> *display* on-screen) global-buf)) + (s3-1 (-> s4-0 base)) + ) + ;; generate DMA data for copying the framebuffer + (fx-copy-buf s4-0) + ;; generate DMA data for initializing generic VU1. + (generic-init-buf s4-0 arg1) + + (let ((v1-12 (the-as dma-packet (-> s4-0 base)))) + (set! (-> v1-12 dma) (new 'static 'dma-tag :id (dma-tag-id next) :addr (-> s5-0 next))) + (set! (-> v1-12 vif0) (new 'static 'vif-tag)) + (set! (-> v1-12 vif1) (new 'static 'vif-tag)) + (set! (-> s4-0 base) (the-as pointer (&+ v1-12 16))) + ) + (set! (-> s5-0 next) (the-as uint s3-1)) + ) + ) + ) + 0 + (none) + ) +``` + +The import part is +``` +;; generate DMA data for copying the framebuffer +(fx-copy-buf s4-0) +;; generate DMA data for initializing generic VU1. +(generic-init-buf s4-0 arg1) +``` +The `fx-copy-buf` function needs to be decompiled. There's nothing too interesting, other than it copies the screen in chunks, rather than one giant sprite. The offsets and stuff are a bit confusing, but we might be able to guess our way through it. + +For now, I'm going to leave out this function, and we'll just remember to do the copy on the C++ at the start of this bucket. + +# Part 3: Submitting merc models to generic +In part 1, we set things up so the main `foreground-draw` functions sends models to `foreground-generic-merc`, which isn't decompiled yet. If this works like Jak 1, this doesn't actually do the EE side of generic yet - it just adds them to a list. + +The next step was to mips2c/decompile `foreground-generic-merc` and the functions it calls. Unfortunately, the main function can't easily be decompiled. I suspect it's very similar to `draw-bones-generic-merc` where it fills out generic parameters based on settings. The death vertex and fragment adding loop are split into separate functions that we can decompile this time: + +``` +(defun foreground-generic-merc-death ((arg0 draw-control) (arg1 generic-merc-ctrl)) + "Modify a generic-merc-ctrl to set up merc-death effect." + + ;; possibly disable drawing if requested + (when (and (>= (the-as int (- (-> arg0 death-timer-org) (-> arg0 death-timer))) + (the-as int (-> arg0 death-draw-overlap)) + ) + (!= (-> arg0 death-draw-overlap) 255) + ) + (set! (-> arg1 header display-triangles) (the-as uint 0)) + 0 + ) + + ;; update the vertices that we're querying. + (when (not (paused?)) + (let ((v1-6 (+ (-> arg0 death-vertex-skip) (rand-vu-int-count (the-as int (-> arg0 death-vertex-skip)))))) + (set! (-> arg1 header death-vertex-skip) v1-6) + (set! (-> arg1 header death-effect) (-> arg0 death-effect)) + (set! (-> arg1 header death-start-vertex) + (/ (* v1-6 (- (-> arg0 death-timer-org) (-> arg0 death-timer))) (-> arg0 death-timer-org)) + ) + ) + ) + (none) + ) + +(defun foreground-generic-merc-add-fragments ((arg0 merc-effect) (arg1 pointer) (arg2 mercneric-chain)) + "Add fragments from a merc-effect to the generic chain." + (let ((v1-0 (-> arg0 frag-geo)) + (a3-0 (the-as structure (-> arg0 frag-ctrl))) + (a0-1 (-> arg0 frag-count)) + ) + + ;; loop over fragments, adding matrix refs. + (dotimes (t0-0 (the-as int a0-1)) + (let ((t1-2 (+ (* (-> (the-as merc-fragment-control a3-0) mat-xfer-count) 2) 4)) + (t2-0 (-> v1-0 header mm-quadword-size)) + ) + (set! (-> (the-as dma-packet arg1) dma) + (new 'static 'dma-tag :id (dma-tag-id ref) :addr (the-as int v1-0) :qwc t2-0) + ) + (set! (-> (the-as dma-packet arg1) vif0) (new 'static 'vif-tag)) + (set! (-> (the-as dma-packet arg1) vif1) (new 'static 'vif-tag)) + (when (nonzero? t0-0) + (set! (-> (the-as (pointer int32) (-> arg2 next)) 0) (the-as int arg1)) + (set! (-> arg2 next) (the-as uint (&+ arg1 12))) + ) + (let ((a1-1 (the-as object (&+ arg1 16)))) + (dotimes (t3-6 (the-as int (-> (the-as merc-fragment-control a3-0) mat-xfer-count))) + (let ((t5-4 + (-> (scratchpad-object foreground-work) + regs + mtxs + (-> (the-as merc-fragment-control a3-0) mat-dest-data t3-6 matrix-number) + ) + ) + ) + (set! (-> (the-as dma-packet a1-1) dma) + (new 'static 'dma-tag :qwc #x7 :id (dma-tag-id ref) :addr (the-as int t5-4)) + ) + ) + (set! (-> (the-as dma-packet a1-1) vif0) (new 'static 'vif-tag)) + (set! (-> (the-as dma-packet a1-1) vif1) (new 'static 'vif-tag)) + (set! a1-1 (&+ (the-as pointer a1-1) 16)) + ) + (set! (-> (the-as dma-packet a1-1) dma) (new 'static 'dma-tag :id (dma-tag-id end))) + (set! (-> (the-as dma-packet a1-1) vif0) (new 'static 'vif-tag)) + (set! (-> (the-as dma-packet a1-1) vif1) (new 'static 'vif-tag)) + (set! arg1 (&+ (the-as pointer a1-1) 16)) + ) + (set! a3-0 (&+ a3-0 t1-2)) + (set! v1-0 (the-as merc-fragment (+ (the-as uint v1-0) (* t2-0 16)))) + ) + ) + ) + arg1 + ) +``` +It's overall very similar, but the way of finding the matrices is little different, but it all makes sense. The generic chain will be processed later, and it will dma these matrices to the scratchpad for transforming generic merc data. + +# Part 4: Running Generic Merc EE processing +Part 3 just adds fragments to a list. We actually have to process these fragments on the EE before drawing them with VU1. Assuming it's like Jak 1, the EE step transforms vertices to world frame and computes stuff like envmap coordinates. The VU1 part does the perspective tranformation and clipping. + +This is run from `generic-merc-execute-all`, called from `drawable.gc`. + +``` +(defun generic-merc-execute-all ((arg0 dma-buffer)) + "Run EE processing on all generic merc chains." + (let ((s4-0 (-> *foreground* foreground-grid)) + (gp-0 (-> *display* frames (-> *display* on-screen) global-buf base)) + ) + + (with-profiler 'generic-merc *profile-generic-merc-color* + ;; reset profiling + (reset! (-> *perf-stats* data (perf-stat-bucket mercneric))) + (set! (-> (scratchpad-object generic-work) saves to-vu0-waits) (the-as uint 0)) + (set! (-> (scratchpad-object generic-work) saves to-spr-waits) (the-as uint 0)) + (set! (-> (scratchpad-object generic-work) saves from-spr-waits) (the-as uint 0)) + (flush-cache 0) + + ;; init generic + (generic-initialize-without-sync (-> *math-camera* perspective) *default-lights*) + (generic-merc-init-asm) + (set! (-> (scratchpad-object generic-work) in-buf merc shadow write-limit) (the-as int (&+ (-> arg0 end) -262144))) + + ;; loop over grid of chains (levels x textures) and do the chain. + (dotimes (s3-1 7) + (dotimes (s2-1 7) + (generic-merc-do-chain (-> s4-0 level-buckets s3-1 data s2-1 mercneric) arg0) + ) + ) + + ;; do separate warp chain + (generic-merc-do-chain (-> s4-0 warp-chain) arg0) + + ;; finish profiling + (read! (-> *perf-stats* data (perf-stat-bucket mercneric))) + (update-wait-stats + (-> *perf-stats* data 38) + (-> (scratchpad-object generic-work) saves to-vu0-waits) + (-> (scratchpad-object generic-work) saves to-spr-waits) + (-> (scratchpad-object generic-work) saves from-spr-waits) + ) + ) + + ;; update dma memory usage stats. + (let ((v1-66 *dma-mem-usage*)) + (when (nonzero? v1-66) + (set! (-> v1-66 length) (max 90 (-> v1-66 length))) + (set! (-> v1-66 data 89 name) "pris-generic") + (+! (-> v1-66 data 89 count) 1) + (+! (-> v1-66 data 89 used) + (&- (-> *display* frames (-> *display* on-screen) global-buf base) (the-as uint gp-0)) + ) + (set! (-> v1-66 data 89 total) (-> v1-66 data 89 used)) + ) + ) + ) + (none) + ) +``` + +This function doesn't look too bad... + + + +# Part 5: Decompiling `generic-merc` stuff + +- `generic-merc-init-asm` +Nothing interesting, dma sync patched out. + +- `mercneric-convert` +The worst function. Copied all the vu0 stuff from jak 1. + +- `high-speed-reject` +Copied vu0 stuff from jak1 + +- `generic-translucent` +New for jak 2, easy. + +- `generic-merc-query` +New for jak 2, easy. (maybe no mips2c?) + +- `generic-merc-death` +New for jak 2, easy. (maybe no mips2c?) + +- `generic-merc-execute-asm` +Did the same direct-call patch for the `mercneric-convert` call. Not sure why I did this originally, but it can only help. + +- `generic-merc-do-chain` +New for jak 2, easy (patched out dma sync). + + + + +# Part 6: Decompiling `generic-effect` stuff +- `generic-work-init` +Not mips2c. Just copies stuff to generic-work. + +- `generic-light-proc` + +- `generic-warp-source` +- `generic-warp-envmap-dest` +- `generic-warp-dest` +- `generic-prepare-dma-single` (`generic-effect`) +- `generic-prepare-dma-double` (`generic-effect`) + +- `generic-envmap-proc` + diff --git a/docs/scratch/shrub.md b/docs/scratch/shrub.md new file mode 100644 index 000000000..9a75e356c --- /dev/null +++ b/docs/scratch/shrub.md @@ -0,0 +1,319 @@ +# Shrub EE code notes + +## Looking through village1-vis.asm +The "prototype" main class is `prototype-bucket-shrub`. These are stored in a `prototype-inline-array-shrub`. + +Example of a `prototype-bucket-shrub`: +``` + .type prototype-bucket-shrub + .word L22404 + .word 0x0 + .word 0x20025 + .word L4630 + .word L4604 + .word L4617 + .word L4641 + .word 0x48a00000 + .word 0x48200000 +``` + +The `.word L22404` is a string `"palmplant-top.mb"`. +The four `L4630`, `L4604`, `L4617`, `L4641` are the 4 `geometry`. In this case, it looks like each is a different kind, but I don't think we can make any assumptions about this. + +### Highest Detail `prototype-generic-shrub` +For now, let's ignore this because we don't have a generic renderer. It also really looks like no shrubs ever draw with generic in-game, but I could be wrong. It looks like every single shrub has this as their first geomery. + +### 2nd Highest `prototype-shrubbery` +I think this is the "normal" shrub. Each prototype is made up of one or more `shrubbery`. Again, every shrub has this. + +### 3rd Highest `prototype-trans-shrubbery` +Based on PCSX2, it looks like these are usually lower-res models that fade out as you move away. Like the 2nd, they are made of `shrubbery`, and every shrub has one. + +### 4th Highest `billboard` +These are the lowest res, always face toward the camera. Each `billboard` is just a single thing - no sub-parts. I suspect that each prototype can become a single rectangle "billboard", no matter how complicated the original shrub is. + +I think we should work on `prototype-shrubbery` (and possibly the transparent one) first. Maybe we can leave out the billboard and claim that we're "increasing the level of detail" :). + +## Looking through `shrubbery.gc` decomp +Doing reverse order in the `ir2.asm` file. + +### `login billboard` +No surprise here, billboard is a single rectangle, it can have only one texture, and there's exactly one `adgif-shader-login`. + +### `mem-usage-shrub-walk` +This function recursively iterates over a `draw-node` tree, computing memory usage, and is a good example of how these `draw-node` trees work. Each `draw-node` has a sphere. Inside this sphere are between 1 and 8 "children", which are in an `inline-array`. The children are usually `draw-node`, except for the leaf nodes, which are some other drawable type. In this case, they are `instance-shrubbery`. This is used for frustum culling. If a `draw-node` sphere is outside of the view of the camera, you can just skip all instances in that `draw-node`. + +Unlike a normal tree, they rarely refer to a single `draw-node`, but instead a group of between 1 and 8 draw-nodes. These are passed around as a `draw-node` (the first in the group) and an integer (the number in the group). This might seem weird, but simplifies the iteration logic. (if you don't know the type/size of the leaf node, you can't iterate over an inline-array of them, but you could call some virtual function that expects the object to be the first one in an `inline-array` with a size argument.) + +This is how to recursively iterate over `draw-node` tree: +```lisp + (dotimes (s1-0 arg1) + (let ((a1-2 (-> s2-0 child-count))) + (cond + ((logtest? (-> s2-0 flags) 1) ;; flag means that we aren't a leaf. + (mem-usage-shrub-walk (the-as draw-node (-> s2-0 child)) (the-as int a1-2) arg2 arg3) + ) + (else + ;; you are at an inline-array of leaves. + ;; (-> s2-0 child) is an inline-array of a1-2 leaves + ;; a1-2 is between 1 and 8. + ) + ) + ) + ;; move on to the next child draw node. + (&+! s2-0 32) + ) +``` + +NOTE: `arg1` should be an int here. + +We learned here that `shrub` does use the `draw-node` BVH system. (this was unclear because `shrub` does not appear to use the compressed visibility string based vis system, which is often used simultaneously with `draw-node`). + +### `login generic-shrub-fragment` +`generic-shrub-fragment`'s have a variable number of textures. The `cnt-qwc` field refers to the total size of the `textures` array, as each `adgif-shader` is 5 qw. + +### `login prototype-shrubbery` +From village1-vis, we know this is just logging in `shrubbery`s. + +### `asize-of prototype-shrubbery` +The size calculation makes sense for an inline-array of `shrubbery`, with 1 `shrubbery` being inside the type, and the rest running off the end of the array. + +### `login prototype-generic-shrub` +No surprises. Confirms that these aren't inline arrays (and we could tell from village1-vis anyway) + +### `login shrubbery` +Gives us some idea of the layout of the "header". The first `u32` is the number of textures / 2. Each `shrubbery` may have multiple textures. + +### `login drawable-tree-instance-shrub` +Nothing interesting + +### `shrub-num-tris` +This tells us the number of triangles in a `shrubbery` is `header[2] - 2*header[1]`. One of the most popular GS formats is "triangle strip". The number of triangles in a triangle strip is `num_verts - 2`. So, very likely `header[2]` is the total number of vertices, and `header[1]` is the number of strips + +### `shrub-make-perspective-matrix` +This probably makes the matrix used to transform shrubbery. I'm not sure why yet, but they take the normal transformation (`camera-temp`) and modify it a bit. We may be able to get away with ignoring this. Ideally we just get the shrub positions (in the world coordinate system, just like with TIE/TFRAG), and then use the same logic we used for TIE/TFRAG. + +### `shrub-init-view-data`. +Note: change `texture-giftag` in `shrub-view-data` to a `gs-gif-tag`. + +This populates fields of a `shrub-view-data`, which will probably end up in VU memory. + +There's two things here that are suspicious. First: +```lisp + (set! (-> arg0 texture-giftag tag) (new 'static 'gif-tag64 :nloop #x1 :nreg #x4)) + (set! (-> arg0 texture-giftag regs) (new 'static 'gif-tag-regs + :regs0 (gif-reg-id a+d) + :regs1 (gif-reg-id a+d) + :regs2 (gif-reg-id a+d) + :regs3 (gif-reg-id a+d) + ) + ) +``` +usually an `adgif-shader` is 5 qw's of a+d data. This sets up 4. The fifth one is usually `gs-alpha`, and it seems reasonable that they could set this once, then not bother setting it again. + +Second, they put `#x40a00000` in the 3rd word of the giftag: +``` +(set! (-> arg0 texture-giftag word 3) (the-as uint #x40a00000)) +``` +as far as I can tell the GIF will ignore this. They might use it as a constant `5.0`. But it seems weird to put it here. + +If you change the `score` so it uses the named fields, the rest of the constants are: +``` + (set! (-> arg0 tex-start-ptr) (the-as int 25167696.0)) + (set! (-> arg0 mtx-buf-ptr) (the-as int 8388608.0)) + (set! (-> arg0 fog-0) (-> *math-camera* pfog0)) + (set! (-> arg0 fog-1) (-> *math-camera* pfog1)) + (set! (-> arg0 fog-clamp x) (-> *math-camera* fog-min)) + (set! (-> arg0 fog-clamp y) (-> *math-camera* fog-max)) +``` +the fog stuff seems reasonable to me (it's involved in computing the perspective division and the GS fog coefficient, don't worry for now). + +The `buf-ptr` stuff is very likely this awful trick they do. The VU doesn't have good instructions for common integer operations (like you'd use to mainpulate memory addresses), so they find floating point values, then when added/subtracted in certain ways, have the lower 16 bits of the float equal to the VU memory address. Gross. Maybe the `5.0` is also part of this. + + +### `shrub-upload-view-data` +Note: I changed the type casts: +``` + "shrub-upload-view-data": [ + [[3, 16], "a0", "dma-packet"] + ], + +``` + +and got a very typical upload. + +``` +(defun shrub-upload-view-data ((arg0 dma-buffer)) + (let ((s5-0 3)) + (let* ((v1-0 arg0) + (a0-1 (the-as object (-> v1-0 base))) + ) + (set! (-> (the-as dma-packet a0-1) dma) (new 'static 'dma-tag :id (dma-tag-id cnt) :qwc s5-0)) + (set! (-> (the-as dma-packet a0-1) vif0) (new 'static 'vif-tag :imm #x404 :cmd (vif-cmd stcycl))) + (set! (-> (the-as dma-packet a0-1) vif1) (new 'static 'vif-tag :cmd (vif-cmd unpack-v4-32) :num s5-0)) + (set! (-> v1-0 base) (&+ (the-as pointer a0-1) 16)) + ) + (shrub-init-view-data (the-as shrub-view-data (-> arg0 base))) + (&+! (-> arg0 base) (* s5-0 16)) + ) + #f + ) +``` + +- `s5-0` this is the number of quadwords they will upload. +- `dma-tag`: `cnt`, means the data will come after the tag (and the next thing comes after that). `qwc` makes sense +- As part of a DMA tag, you get 2 VIF tags "for free". These are sent to the VIF. +- `vif0`: the `stcycl` sets the `cl`/`wl` register of VIF to `0x404` which is the mode for just copying stuff like normal (doesn't skip data) +- `vif1`: the `unpack` command means copy data to data memory. The `v4-32` is the mode for copying quadwords. + +The `0x404 stcycl` and `v4-32` format is used if you just want to copy memory exactly, so it shows up a lot. The other formats can do weird unpacking stuff, but are less common. + + +### `shrub-time` +Not really sure what this is. I noticed in PCSX2 there's a `time:` that shows up in instance info. Maybe it computes the number of VU cycles. + + +### `shrub-do-init-frame` +This adds stuff to the DMA list to get the hardware ready for shrub. + +Note: +``` + "shrub-do-init-frame": [ + [[10, 21], "a0", "dma-packet"], + [[24, 29], "a0", "dma-packet"], + [33, "v1", "(pointer vif-tag)"], + [[35, 41], "v1", "(pointer uint32)"], + [42, "v1", "(pointer vif-tag)"], + [[43, 51], "v1", "(pointer uint32)"], + [52, "v1", "(pointer vif-tag)"], + [54, "v1", "(pointer uint32)"] + ], +``` +All the data gets sent to the VIF. You can check the VIFcode reference part of the manual to see how long the data for each vifcode is. + +upload the shrub program. In the PC port we usually set the VU program definitions to have a size of 0, then this function will do nothing. +``` +(dma-buffer-add-vu-function arg0 shrub-vu1-block 1) +``` + +upload the shrub view data: +``` +(shrub-upload-view-data arg0) +``` + +Add a DMA tag. Note that `qwc` is zero so this one just sends the two `vif` tags that are part of the dma tag: +``` + (set! (-> (the-as dma-packet a0-3) dma) (new 'static 'dma-tag :id (dma-tag-id cnt))) + (set! (-> (the-as dma-packet a0-3) vif0) (new 'static 'vif-tag :cmd (vif-cmd mscalf) :msk #x1 :imm #x0)) + (set! (-> (the-as dma-packet a0-3) vif1) (new 'static 'vif-tag :cmd (vif-cmd flushe) :msk #x1)) + (set! (-> v1-0 base) (&+ (the-as pointer a0-3) 16)) +``` +The `mscalf` runs a VU1 program. The `imm` is 0, so it runs starting at the beginning of VU1 program memory. Let's ignore this for now. It's probably an initialization program that sets up the VU memory and registers. We'll look at it when we get to the actual drawing. + +The `flushe` waits for that program to end. + +Next it sets the `strow`/`stcol`/`stmask` registers of the VIF. These are used for unpacking settings. + +### `shrub-init-frame` +Calls `shrub-do-init-frame` then sets the `gs-test` register. + +### `shrub-upload-model` +Seems to upload a model +``` +(function shrubbery dma-buffer int symbol) + +and + + + "shrub-upload-model": [ + [[17, 26], "a3", "dma-packet"], + [[33, 41], "a0", "dma-packet"], + [[47, 55], "a0", "dma-packet"] + ], +``` + +The model data upload: +``` + (set! (-> (the-as dma-packet a3-0) dma) + (new 'static 'dma-tag + :id (dma-tag-id ref) + :addr (-> arg0 obj) + :qwc (+ (-> arg0 obj-qwc) (-> arg0 vtx-qwc) (-> arg0 col-qwc) (-> arg0 stq-qwc)) + ) + ) + (set! (-> (the-as dma-packet a3-0) vif0) (new 'static 'vif-tag :cmd (vif-cmd base) :imm *shrub-state*)) + (set! (-> (the-as dma-packet a3-0) vif1) (new 'static 'vif-tag :cmd (vif-cmd offset))) + (set! (-> v1-0 base) (&+ (the-as pointer a3-0) 16)) + ) +``` +this tells us that there is a static DMA chain, starting at the `obj` field of the `shrubbery`. This includes `obj`, `vtx`, `col`, `stq`. The fact that it's a `ref` likely means the DMA will do one big transfer of all that data, then come back to the DMA buffer we're filling. + +The use of the `base` with `offset = 0` indicates they aren't using the normal VU double buffering (the weird float tricker earlier was also a clue). They have insane buffering schemes so you can have one model uploading, another model generating GIF tags, and a third model (no longer in VU1 memory) having its GIF tags being processed by the GS. Luckily we can mostly ignore this and just make non-buffered versions because there's no performance benefit to doing this on a PC. + +Next, is: +``` + (cond + ((= arg2 1) + (let* ((v1-2 arg1) + (a0-9 (the-as object (-> v1-2 base))) + ) + (set! (-> (the-as dma-packet a0-9) dma) (new 'static 'dma-tag :id (dma-tag-id cnt))) + (set! (-> (the-as dma-packet a0-9) vif0) (new 'static 'vif-tag)) + (set! (-> (the-as dma-packet a0-9) vif1) (new 'static 'vif-tag :cmd (vif-cmd mscal) :msk #x1 :imm #x11)) + (set! (-> v1-2 base) (&+ (the-as pointer a0-9) 16)) + ) + ) + (else + (let* ((v1-3 arg1) + (a0-11 (the-as object (-> v1-3 base))) + ) + (set! (-> (the-as dma-packet a0-11) dma) (new 'static 'dma-tag :id (dma-tag-id cnt))) + (set! (-> (the-as dma-packet a0-11) vif0) (new 'static 'vif-tag)) + (set! (-> (the-as dma-packet a0-11) vif1) (new 'static 'vif-tag :cmd (vif-cmd mscal) :msk #x1 :imm #x15)) + (set! (-> v1-3 base) (&+ (the-as pointer a0-11) 16)) + ) + ) + ) +``` +which adds a tag that runs a VU1 program. Either program starting at `0x11` or `0x15`, depending on the argument. + +Then +``` +(set! *shrub-state* (- 164 *shrub-state*)) +``` +Based on the use of `*shrub-state*`, I think it is a VU buffer management thing. + +### `draw-inline-array-instance-shrub` +asm. I'll come back to this later. I assume this runs _before_ the prototype draw, and that it will build lists of instances in each bucket, to be processed by the next function. + +### `draw-prototype-inline-array-shrub` +This one is tricky too, I'll come back later. + + +### `draw-drawable-tree-instance-shrub` +This is the main draw. It does: +- setup `instance-shrub-work` (likely used in the instance asm function) +- set the `next-clear` stuff to 0. This is just a shortcut fast way to reset lists of instances from the previous frame. Will make more sense once we see the previous two functions, I think. +- call `draw-inline-array-instance-shrub` +- call `draw-prototype-inline-array-shrub` +- a whole bunch of performance counters we can skip + +### `draw drawable-tree-instance-shrub` +This connects the background system and the drawable/bsp system. When the draw engine executes, it calls this function, adding the drawable tree to `background-work`. When `finish-background` is called, it calls `draw-drawable-tree-instance-shrub` that does the real work + +### `unpack-vis` +Having this do nothing makes the shrub system not part of the occlusion culling system. + +### `collect-stats` +This shows that geometry 0 is `shrub-near`, geometry 1 is `shrub`, 2 is `trans-shrub`, and 3 is billboard. + +It appears that near shrubs are drawn with the generic renderer (also looking at the prototype draw to confirm). + +If this is the case, we can probably get away with ignoring geometry 0 and making a single shrub renderer that can handle the near case. From playing in PCSX2, "near" doesn't mean higher resolution, it just means the shrub is partially behind the camera, or close to that. If we port the rendering to opengl properly, we get this "for free". + + +## Shrubbery Header + +- `[0] u32` - number of textures divided by 2. +- `[4] u32` - number of vertices to draw. +- `[8] u32` - number of triangle strips. \ No newline at end of file diff --git a/goal_src/jak3/kernel-defs.gc b/goal_src/jak3/kernel-defs.gc index 6183a4fe4..9b7c63ddd 100644 --- a/goal_src/jak3/kernel-defs.gc +++ b/goal_src/jak3/kernel-defs.gc @@ -45,6 +45,7 @@ (define-extern basic type) (define-extern string type) (define-extern symbol type) +(define-extern boolean type) (define-extern type type) (define-extern object type) (define-extern link-block type) diff --git a/goal_src/jak3/kernel/gcommon.gc b/goal_src/jak3/kernel/gcommon.gc index 446de05ef..d70da51f2 100644 --- a/goal_src/jak3/kernel/gcommon.gc +++ b/goal_src/jak3/kernel/gcommon.gc @@ -5,8 +5,6 @@ ;; name in dgo: gcommon ;; dgos: KERNEL -;; DECOMP BEGINS - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Game constants ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -25,138 +23,124 @@ ;; pointers larger than this are invalid by valid? (defconstant END_OF_MEMORY #x8000000) -(defun identity ((arg0 object)) - "Return the input. Works for any 64-bit value." - arg0 +(define-extern valid? (function object type string symbol object symbol)) + +;; DECOMP BEGINS + +(defun identity ((obj object)) + "The identity function." + obj ) -(defun 1/ ((arg0 float)) - "Floating point reciprocal" - (declare (inline)) - (/ 1.0 arg0) +(defun 1/ ((x float)) + "Floating point reciprocal." + (declare (inline)) ;; og:preserve-this + (/ 1.0 x) ) -;; These functions exist a function objects that wrap the compiler's built-in operators. - -(defun + ((arg0 int) (arg1 int)) - "Add two integers (64-bit)." - (+ arg0 arg1) +(defun + ((a int) (b int)) + "64-bit integer addition." + (+ a b) ) -(defun - ((arg0 int) (arg1 int)) - "Subtract two integers (64-bit)." - (- arg0 arg1) +(defun - ((a int) (b int)) + "64-bit integer subraction." + (- a b) ) -(defun * ((arg0 int) (arg1 int)) - "Multiply two integers (32-bit)" - (* arg0 arg1) +(defun * ((a int) (b int)) + "32-bit signed integer multiplication." + (* a b) ) -(defun / ((arg0 int) (arg1 int)) - "Divide two integers (32-bit, signed)" - (/ arg0 arg1) +(defun / ((a int) (b int)) + "32-bit signed integer division." + (/ a b) ) -(defun mod ((arg0 int) (arg1 int)) - "Integer mod (signed, 32-bit)" - (mod arg0 arg1) - ) - -(defun rem ((arg0 int) (arg1 int)) - "Integer mod (signed, 32-bit). Even though it's called rem, it behaves the same as mod." - (mod arg0 arg1) - ) - - -(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. +(defun ash ((x int) (shift-amount int)) + "64-bit arithmetic shift. (sign-extends)" + ;; og:preserve-this (declare (inline)) (if (> shift-amount 0) - (shl value shift-amount) - (sar value (- shift-amount)) + (shl x shift-amount) + (sar x (- shift-amount)) ) ) -(defun abs ((a int)) - "Take the absolute value of a 64-bit signed integer" - (declare (inline)) +(defun mod ((a int) (b int)) + "32-bit mod." + (mod a b) + ) + +(defun rem ((a int) (b int)) + "32-bit mod (same as mod)." + (mod a b) + ) + +(defun abs ((x int)) + "64-bit integer absolute value." ;; OpenGOAL doesn't support abs, so we implement it here. - (if (> a 0) - a - (- a) + ;; og:preserve-this + (if (> x 0) + x + (- x) ) ) (defun min ((a int) (b int)) - "Compute minimum of two 64-bit signed integers." - (declare (inline)) - ;; OpenGOAL doesn't support min, so we implement it here. - (if (> a b) b a) + "64-bit integer minimum." + (if (> a b) b a) ;; og:preserve-this ) (defun max ((a int) (b int)) - "Compute maximum of two 64-bit signed integer." - (declare (inline)) - ;; OpenGOAL doesn't support max so we implement it here. - (if (> a b) a b) + "64-bit integer maximum." + (if (> a b) a b) ;; og:preserve-this ) -(defun logior ((arg0 int) (arg1 int)) - "Logical or (64-bit)" - (logior arg0 arg1) +(defun logior ((a int) (b int)) + "64-bit bitwise or." + (logior a b) ) -(defun logand ((arg0 int) (arg1 int)) - "Logical and (64-bit)" - (logand arg0 arg1) +(defun logand ((a int) (b int)) + "64-bit bitwise and." + (logand a b) ) (defun lognor ((a int) (b int)) - "Compute not or (64-bit)." - ;; Note - MIPS has a 'nor' instruction, but x86 doesn't. - ;; the OpenGOAL x86 compiler therefore doesn't have a nor operation, - ;; so lognor is implemented by this inline function instead. + "64-bit bitwise not-or." + ;; og:preserve-this (declare (inline)) (lognot (logior a b)) ) -(defun logxor ((arg0 int) (arg1 int)) - "Logical exclusive or (64-bit)" - (logxor arg0 arg1) +(defun logxor ((a int) (b int)) + "64-bit bitwise exclusive or." + (logxor a b) ) -(defun lognot ((arg0 int)) - "Logical not (64-bit)" - (lognot arg0) +(defun lognot ((x int)) + "64-bit bitwise not." + (lognot x) ) (defun false-func () - "Return #f." + "Returns false." #f ) (defun true-func () - "Return #t." + "Returns true." #t ) -;;;;;;;;;;;;;;;;;;;;;;;;;; -;; format -;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The "format" function is implemented in C but is called _format. -;; This defines the format function to point to the same thing as _format. (define format _format) -;;;;;;;;;;;;;;;;;;;;;;;;;; -;; numeric types -;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; vec4s: 4 floats packed into a 128-bit integer register. This is rarely used. (deftype vec4s (uint128) + "Vector of four floats, packed into a 128-bit integer as bitfields. +This behaves like a value type. +This is not the main vector type." ((x float :offset 0 :size 32) (y float :offset 32 :size 32) (z float :offset 64 :size 32) @@ -164,27 +148,7 @@ ) ) -(defmethod print ((this vec4s)) - "Custom print for vec4s that prints the 4 values." - (format #t "#" - (-> this x) - (-> this y) - (-> this z) - (-> this w) - this) - this - ) - -(deftype vector (structure) - ((data float 4) - (x float :overlay-at (-> data 0)) - (y float :overlay-at (-> data 1)) - (z float :overlay-at (-> data 2)) - (w float :overlay-at (-> data 3)) - (quad uint128 :overlay-at (-> data 0)) - ) - ) - +;; og:preserve-this (defmacro print128 (value &key (stream #t)) "Print a 128-bit value" `(let ((temp (new 'stack-no-clear 'array 'uint64 2))) @@ -205,9 +169,27 @@ ) ) -;; bfloat: boxed float type. A floating point number with type information. -;; It's a heap allocated basic. +(defmethod print ((this vec4s)) + (format #t "#" (-> this x) (-> this y) (-> this z) (-> this w) this) + this + ) + +(deftype vector (structure) + "Vector of four floats, stored in a structure. +This behaves like a reference type. +This is the main vector type." + ((data float 4) + (x float :overlay-at (-> data 0)) + (y float :overlay-at (-> data 1)) + (z float :overlay-at (-> data 2)) + (w float :overlay-at (-> data 3)) + (quad uint128 :overlay-at (-> data 0)) + ) + ) + + (deftype bfloat (basic) + "Boxed (or basic?) float. Just a basic that wraps a single float." ((data float) ) ) @@ -218,22 +200,18 @@ this ) -;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Type System -;;;;;;;;;;;;;;;;;;;;;;;;;; - +;; WARN: Return type mismatch uint vs int. (defmethod asize-of ((this type)) - "Get the size in memory of a type. The value calculated here is wrong." (the-as int (logand (the-as uint #xfffffff0) (+ (* (-> this allocated-length) 4) 43))) ) -(defun basic-type? ((arg0 basic) (arg1 type)) - "Is the given basic an object of the given type?" - (let ((v1-0 (-> arg0 type)) +(defun basic-type? ((obj basic) (typ type)) + "Return if the given basic is a given type. A child of the given type is also acceptable." + (let ((v1-0 (-> obj type)) (a0-1 object) ) (until (= v1-0 a0-1) - (if (= v1-0 arg1) + (if (= v1-0 typ) (return #t) ) (set! v1-0 (-> v1-0 parent)) @@ -242,32 +220,34 @@ #f ) -(defun type-type? ((arg0 type) (arg1 type)) - "Is the given type equal to, or a child of, the second type?" +(defun type-type? ((check-type type) (parent-type type)) + "Return if the first type is the second type, or a child of it." (let ((v1-0 object)) - (if (= arg1 v1-0) + (if (= parent-type v1-0) (return #t) ) - (until (or (= arg0 v1-0) (zero? arg0)) - (if (= arg0 arg1) + (until (or (= check-type v1-0) (zero? check-type)) + (if (= check-type parent-type) (return #t) ) - (set! arg0 (-> arg0 parent)) + (set! check-type (-> check-type parent)) ) ) #f ) -(defun type? ((arg0 object) (arg1 type)) - "Is the given object an object of the given type? Works for any boxed object (basic, symbol, binteger, pair)." +;; WARN: Using new Jak 2 rtype-of +(defun type? ((obj object) (desired-type type)) + "Return if the given object is an instance of the given type. + Works on basics, bintegers, or symbols." (let ((v1-0 object) - (a0-1 (rtype-of arg0)) + (a0-1 (rtype-of obj)) ) - (if (= arg1 v1-0) + (if (= desired-type v1-0) (return #t) ) (until (or (= a0-1 v1-0) (zero? a0-1)) - (if (= a0-1 arg1) + (if (= a0-1 desired-type) (return #t) ) (set! a0-1 (-> a0-1 parent)) @@ -276,16 +256,18 @@ #f ) -(defun find-parent-method ((arg0 type) (arg1 int)) - "Go up the type tree and find the first parent type that has a different implementation for the given method." +(defun find-parent-method ((typ type) (method-id int)) + "Find the closest parent type that has a different implementation of the given method and return that method. + If it does not exist, return `nothing` function. + This is used to implement call-parent-method." (local-vars (v0-0 function)) - (let ((v1-2 (-> arg0 method-table arg1))) + (let ((v1-2 (-> typ method-table method-id))) (until (!= v0-0 v1-2) - (if (= arg0 object) + (if (= typ object) (return nothing) ) - (set! arg0 (-> arg0 parent)) - (set! v0-0 (-> arg0 method-table arg1)) + (set! typ (-> typ parent)) + (set! v0-0 (-> typ method-table method-id)) (if (zero? v0-0) (return nothing) ) @@ -294,33 +276,35 @@ v0-0 ) +;; og:preserve-this (defmacro call-parent-method (&rest args) "Find the first different implementation of the current method in a parent type and call it with these arguments." `((the (current-method-function-type) (find-parent-method (current-method-type) (current-method-id))) ,@args) ) -(defun ref ((arg0 object) (arg1 int)) - "Get the n-th item in a linked list. No range checking." - (dotimes (v1-0 arg1) +(defun ref& ((list object) (idx int)) + "Return the n-th pair in a linked list of pairs. No bounds checking. + If it is the null pair, return #f." + (dotimes (v1-0 idx) (nop!) (nop!) - (set! arg0 (cdr arg0)) + (set! list (cdr list)) ) - (car arg0) + (if (null? list) + #f + list + ) ) -(defun ref& ((arg0 object) (arg1 int)) - "Get the pair containing the n-th item in a linked list. No range checking." - (dotimes (v1-0 arg1) +(defun ref ((list object) (idx int)) + "Return the n-th item in a proper list. No bounds checking." + (dotimes (v1-0 idx) (nop!) (nop!) - (set! arg0 (cdr arg0)) + (set! list (cdr list)) ) - (if (null? arg0) - #f - arg0 - ) + (car list) ) (defmethod length ((this pair)) @@ -342,12 +326,14 @@ v0-0 ) +;; WARN: Return type mismatch uint vs int. (defmethod asize-of ((this pair)) (the-as int (-> pair size)) ) -(defun last ((arg0 object)) - (let ((v0-0 arg0)) +(defun last ((list object)) + "Return the last object in a proper list." + (let ((v0-0 list)) (while (not (null? (cdr v0-0))) (nop!) (nop!) @@ -357,9 +343,15 @@ ) ) -(defun member ((arg0 object) (arg1 object)) - (let ((v1-0 arg1)) - (while (not (or (null? v1-0) (= (car v1-0) arg0))) +(defun member ((obj-to-find object) (list object)) + "See if the first argument is in the proper list of the second argument. + Checked with simple equality. + If so, return the list starting at the at point (a truthy value). + Otherwise, return #f. + (member 'b '(a b c)) -> (b c d). + (member 'w '(a b c)) -> #f" + (let ((v1-0 list)) + (while (not (or (null? v1-0) (= (car v1-0) obj-to-find))) (set! v1-0 (cdr v1-0)) ) (if (not (null? v1-0)) @@ -369,20 +361,25 @@ ) ;; need to forward declare this, we haven't loaded the string library yet. +;; og:preserve-this (define-extern name= (function object object symbol)) -(defun nmember ((arg0 basic) (arg1 object)) - (while (not (or (null? arg1) (name= (car arg1) arg0))) - (set! arg1 (cdr arg1)) +(defun nmember ((obj-to-find basic) (list object)) + "Like member, but membership is checked with the name= function to handle symbols or strings." + (while (not (or (null? list) (name= (car list) obj-to-find))) + (set! list (cdr list)) ) - (if (not (null? arg1)) - arg1 + (if (not (null? list)) + list ) ) -(defun assoc ((arg0 object) (arg1 object)) - (let ((v1-0 arg1)) - (while (not (or (null? v1-0) (= (car (car v1-0)) arg0))) +(defun assoc ((key object) (assoc-list object)) + "Search an association list for given object. Return #f if not found, otherwise the element with matching car. + (assoc 'a '((a . 1) (b . 2) (c . 3))) -> (a . 1) + (assoc 'x '((a . 1) (b . 2) (c . 3))) -> #f" + (let ((v1-0 assoc-list)) + (while (not (or (null? v1-0) (= (car (car v1-0)) key))) (set! v1-0 (cdr v1-0)) ) (if (not (null? v1-0)) @@ -391,9 +388,10 @@ ) ) -(defun assoce ((arg0 object) (arg1 object)) - (let ((v1-0 arg1)) - (while (not (or (null? v1-0) (= (car (car v1-0)) arg0) (= (car (car v1-0)) 'else))) +(defun assoce ((key object) (assoc-list object)) + "Like assoc, but supports a special `else` key which is always considered a match." + (let ((v1-0 assoc-list)) + (while (not (or (null? v1-0) (= (car (car v1-0)) key) (= (car (car v1-0)) 'else))) (set! v1-0 (cdr v1-0)) ) (if (not (null? v1-0)) @@ -402,69 +400,74 @@ ) ) -(defun nassoc ((arg0 string) (arg1 object)) - (while (not (or (null? arg1) (let ((a1-1 (car (car arg1)))) - (if (pair? a1-1) - (nmember arg0 a1-1) - (name= a1-1 arg0) - ) - ) +(defun nassoc ((key string) (assoc-list object)) + "Like assoc, but uses name= instead of = to check equality." + (while (not (or (null? assoc-list) (let ((a1-1 (car (car assoc-list)))) + (if (pair? a1-1) + (nmember key a1-1) + (name= a1-1 key) + ) + ) ) ) - (set! arg1 (cdr arg1)) + (set! assoc-list (cdr assoc-list)) ) - (if (not (null? arg1)) - (car arg1) + (if (not (null? assoc-list)) + (car assoc-list) ) ) -(defun nassoce ((arg0 string) (arg1 object)) - (while (not (or (null? arg1) (let ((s4-0 (car (car arg1)))) - (if (pair? s4-0) - (nmember arg0 s4-0) - (or (name= s4-0 arg0) (= s4-0 'else)) - ) - ) +(defun nassoce ((key string) (assoc-list object)) + "Like assoce, but uses name= instead of = to check equality." + (while (not (or (null? assoc-list) (let ((s4-0 (car (car assoc-list)))) + (if (pair? s4-0) + (nmember key s4-0) + (or (name= s4-0 key) (= s4-0 'else)) + ) + ) ) ) - (set! arg1 (cdr arg1)) + (set! assoc-list (cdr assoc-list)) ) - (if (not (null? arg1)) - (car arg1) + (if (not (null? assoc-list)) + (car assoc-list) ) ) -(defun append! ((arg0 object) (arg1 object)) +(defun append! ((list object) (new-obj object)) + "Append the second argument to the end of the list (or empty pair) in the first argument." (cond - ((null? arg0) - arg1 + ((null? list) + new-obj ) (else - (let ((v1-1 arg0)) + (let ((v1-1 list)) (while (not (null? (cdr v1-1))) (nop!) (nop!) (set! v1-1 (cdr v1-1)) ) (if (not (null? v1-1)) - (set! (cdr v1-1) arg1) + (set! (cdr v1-1) new-obj) ) ) - arg0 + list ) ) ) -(defun delete! ((arg0 object) (arg1 object)) +;; WARN: Return type mismatch object vs pair. +(defun delete! ((obj object) (list object)) + "Remove an element from the given list, return the list." (the-as pair (cond - ((= arg0 (car arg1)) - (cdr arg1) + ((= obj (car list)) + (cdr list) ) (else - (let ((v1-1 arg1) - (a2-0 (cdr arg1)) + (let ((v1-1 list) + (a2-0 (cdr list)) ) - (while (not (or (null? a2-0) (= (car a2-0) arg0))) + (while (not (or (null? a2-0) (= (car a2-0) obj))) (set! v1-1 a2-0) (set! a2-0 (cdr a2-0)) ) @@ -472,22 +475,23 @@ (set! (cdr v1-1) (cdr a2-0)) ) ) - arg1 + list ) ) ) ) -(defun delete-car! ((arg0 object) (arg1 object)) +(defun delete-car! ((car-to-match object) (list object)) + "Remove an element from the given list with a matching car. Return the list." (cond - ((= arg0 (car (car arg1))) - (cdr arg1) + ((= car-to-match (car (car list))) + (cdr list) ) (else - (let ((v1-2 arg1) - (a2-0 (cdr arg1)) + (let ((v1-2 list) + (a2-0 (cdr list)) ) - (while (not (or (null? a2-0) (= (car (car a2-0)) arg0))) + (while (not (or (null? a2-0) (= (car (car a2-0)) car-to-match))) (set! v1-2 a2-0) (set! a2-0 (cdr a2-0)) ) @@ -495,26 +499,33 @@ (set! (cdr v1-2) (cdr a2-0)) ) ) - arg1 + list ) ) ) -(defun insert-cons! ((arg0 object) (arg1 object)) - (let ((a3-0 (delete-car! (car arg0) arg1))) - (cons arg0 a3-0) +(defun insert-cons! ((new-obj object) (list object)) + "Update an association list to have the given (key . value) pair. + If a previous value exists, it is deleted first. + This function always allocates a pair through `cons` on the global heap, which can never be freed, + so it should almost never be used at runtime." + (let ((a3-0 (delete-car! (car new-obj) list))) + (cons new-obj a3-0) ) ) -(defun sort ((arg0 pair) (arg1 (function object object object))) +(defun sort ((list pair) (compare-func (function object object object))) + "Sort a list using the given comparision function. + The function can return a #t/#f value, or a positive/negative value. + For example, you could use either `-` or `<` as functions to sort integers." (let ((s4-0 -1)) (while (nonzero? s4-0) (set! s4-0 0) - (let ((s3-0 arg0)) + (let ((s3-0 list)) (while (not (or (null? (cdr s3-0)) (not (pair? (cdr s3-0))))) (let* ((s2-0 (car s3-0)) (s1-0 (car (cdr s3-0))) - (v1-1 (arg1 s2-0 s1-0)) + (v1-1 (compare-func s2-0 s1-0)) ) (when (and (or (not v1-1) (> (the-as int v1-1) 0)) (!= v1-1 #t)) (+! s4-0 1) @@ -527,31 +538,39 @@ ) ) ) - arg0 + list ) -(defun string->symbol-debug ((arg0 string)) +(defun string->symbol-debug ((str string)) + "Convert a string to a symbol. The symbol must be known, and this cannot + create a new symbol. (in the PC port, it will still work.) + This is inteded to be used in debug only, and will not trigger a warning. + In debug, this will work for all symbols." (let ((gp-0 *kernel-symbol-warnings*)) (set! *kernel-symbol-warnings* #f) - (let ((v0-0 (string->symbol arg0))) + (let ((v0-0 (string->symbol str))) (set! *kernel-symbol-warnings* gp-0) v0-0 ) ) ) -(defun symbol->string-debug ((arg0 symbol)) +(defun symbol->string-debug ((sym symbol)) + "Get the name of a symbol. This is intended to be used in debug only. + In debug, this will work for all symbols. (In PC port, this works always)" (let ((gp-0 *kernel-symbol-warnings*)) (set! *kernel-symbol-warnings* #f) - (let ((v0-0 (symbol->string arg0))) + (let ((v0-0 (symbol->string sym))) (set! *kernel-symbol-warnings* gp-0) v0-0 ) ) ) -(defun symbol->hash ((arg0 symbol)) - (the-as pointer arg0) +;; WARN: Return type mismatch symbol vs int. +(defun symbol->hash ((sym symbol)) + "Convert a symbol to a unique integer value, which is just the symbol's address." + (the-as int sym) ) (defmethod new array ((allocation symbol) (type-to-make type) (arg0 type) (arg1 int)) @@ -723,6 +742,7 @@ this ) +;; og:preserve-this (defmethod inspect ((this array)) (format #t "[~8x] ~A~%" this (-> this type)) (format #t "~Tallocated-length: ~D~%" (-> this allocated-length)) @@ -802,6 +822,7 @@ (-> this length) ) +;; WARN: Return type mismatch uint vs int. (defmethod asize-of ((this array)) (the-as int @@ -814,33 +835,36 @@ ) ) -(defun mem-copy! ((arg0 pointer) (arg1 pointer) (arg2 int)) - (let ((v0-0 arg0)) - (dotimes (v1-0 arg2) - (set! (-> (the-as (pointer uint8) arg0)) (-> (the-as (pointer uint8) arg1))) - (&+! arg0 1) - (&+! arg1 1) +(defun mem-copy! ((dst pointer) (src pointer) (bytes int)) + "Basic memory copy. This is not an optimized implementation." + (let ((v0-0 dst)) + (dotimes (v1-0 bytes) + (set! (-> (the-as (pointer uint8) dst)) (-> (the-as (pointer uint8) src))) + (&+! dst 1) + (&+! src 1) ) v0-0 ) ) -(defun qmem-copy<-! ((arg0 pointer) (arg1 pointer) (arg2 int)) - (let ((v0-0 arg0)) - (countdown (v1-1 (/ (+ arg2 15) 16)) - (set! (-> (the-as (pointer uint128) arg0)) (-> (the-as (pointer uint128) arg1))) - (&+! arg0 16) - (&+! arg1 16) +(defun qmem-copy<-! ((dst pointer) (src pointer) (qwc int)) + "Copy memory by quadword (16-bytes). Must by 16-byte aligned, size in 16-byte units. Increasing address copy. Not an optimized version." + (let ((v0-0 dst)) + (countdown (v1-1 (/ (+ qwc 15) 16)) + (set! (-> (the-as (pointer uint128) dst)) (-> (the-as (pointer uint128) src))) + (&+! dst 16) + (&+! src 16) ) v0-0 ) ) -(defun qmem-copy->! ((arg0 pointer) (arg1 pointer) (arg2 int)) - (let ((v0-0 arg0)) - (let* ((v1-1 (/ (+ arg2 15) 16)) - (a0-1 (&+ arg0 (* v1-1 16))) - (a1-1 (&+ arg1 (* v1-1 16))) +(defun qmem-copy->! ((dst pointer) (src pointer) (qwc int)) + "Copy memory by quadword (16-bytes). Must by 16-byte aligned, size in 16-byte units. Decreasing address copy. Not an optimized version." + (let ((v0-0 dst)) + (let* ((v1-1 (/ (+ qwc 15) 16)) + (a0-1 (&+ dst (* v1-1 16))) + (a1-1 (&+ src (* v1-1 16))) ) (while (nonzero? v1-1) (+! v1-1 -1) @@ -853,38 +877,43 @@ ) ) -(defun qmem-clear! ((arg0 pointer) (arg1 int)) - (let ((v0-0 arg0)) - (dotimes (v1-0 arg1) - (set! (-> (the-as (pointer int128) arg0)) (the int128 0)) - (&+! arg0 16) +(defun qmem-clear! ((dst pointer) (qwc int)) + "Clear memory by quadword (16-bytes). Must by 16-byte aligned, size in 16-byte units. Not an optimized version." + (let ((v0-0 dst)) + (dotimes (v1-0 qwc) + (set! (-> (the-as (pointer int128) dst)) (the int128 0)) + (&+! dst 16) ) v0-0 ) ) -(defun mem-set32! ((arg0 pointer) (arg1 int) (arg2 int)) - (let ((v0-0 arg0)) - (dotimes (v1-0 arg1) - (set! (-> (the-as (pointer int32) arg0)) arg2) - (&+! arg0 4) +(defun mem-set32! ((dst pointer) (word-count int) (value int)) + "Set memory to the given 32-bit value, repeated n times. (like C memset, but setting int32_t instead of char). + Not an optimized implementation. Must be 4-byte aligned." + (let ((v0-0 dst)) + (dotimes (v1-0 word-count) + (set! (-> (the-as (pointer int32) dst)) value) + (&+! dst 4) (nop!) ) v0-0 ) ) -(defun mem-or! ((arg0 pointer) (arg1 pointer) (arg2 int)) - (let ((v0-0 arg0)) - (dotimes (v1-0 arg2) - (logior! (-> (the-as (pointer uint8) arg0)) (-> (the-as (pointer uint8) arg1))) - (&+! arg0 1) - (&+! arg1 1) +(defun mem-or! ((dst pointer) (src pointer) (bytes int)) + "Set the destiation to `dest = dest | src`. Size in bytes. Not an optimized version." + (let ((v0-0 dst)) + (dotimes (v1-0 bytes) + (logior! (-> (the-as (pointer uint8) dst)) (-> (the-as (pointer uint8) src))) + (&+! dst 1) + (&+! src 1) ) v0-0 ) ) +;; og:preserve-this (defun quad-copy! ((dst pointer) (src pointer) (qwc int)) "Optimized memory copy. The original is pretty clever, but this isn't." (qmem-copy<-! dst src (* qwc 16)) @@ -892,6 +921,8 @@ ) (deftype inline-array-class (basic) + "Base class for basic inline arrays. +The stride is stored in the heap-base of the inline-array-class child class." ((length int32) (allocated-length int32) (_data uint8 :dynamic :offset 16) @@ -906,31 +937,34 @@ ) ) -;; these specicializations exist so the push-back and pop-front methods can be hard-coded to have -;; a fixed sized store/load, rather than mem-cpy the size of the element. -;; This is kinda like a manual version of C++ templates (and perhaps was a attempt to use GOOS macros to do -;; something similar? or they just copy-pasted it, idk) + (deftype inline-array-class-uint64 (inline-array-class) + "Specialization of inline-array-class for uint64. It's unclear why +this would be preferred over a normal (array uint64), since both store data the same way." ((data uint64 :dynamic :offset 16) ) ) + (deftype inline-array-class-uint32 (inline-array-class) + "Specialization of inline-array-class for uint32. It's unclear why this would be preferred +over a normal (array uint32), since both store data the same way." ((data uint32 :dynamic :offset 16) ) ) -(defmethod new inline-array-class ((allocation symbol) (type-to-make type) (arg0 int)) + +(defmethod new inline-array-class ((allocation symbol) (type-to-make type) (count int)) (let ((v0-0 (object-new allocation type-to-make - (the-as int (+ (-> type-to-make size) (* (the-as uint arg0) (-> type-to-make heap-base)))) + (the-as int (+ (-> type-to-make size) (* (the-as uint count) (-> type-to-make heap-base)))) ) ) ) (when (nonzero? v0-0) - (set! (-> v0-0 length) arg0) - (set! (-> v0-0 allocated-length) arg0) + (set! (-> v0-0 length) count) + (set! (-> v0-0 allocated-length) count) ) v0-0 ) @@ -940,28 +974,33 @@ (-> this length) ) +;; WARN: Return type mismatch uint vs int. (defmethod asize-of ((this inline-array-class)) (the-as int (+ (-> this type size) (* (-> this allocated-length) (the-as int (-> this type heap-base))))) ) -(defmethod push-back ((this inline-array-class) (arg0 object)) - (let ((s5-0 (-> this length))) - (let ((a2-0 (-> this type heap-base))) +(defmethod push-back ((object-to-insert inline-array-class) (arg0 object)) + "Copy object to the end, then increment length. No bounds check." + (let ((s5-0 (-> object-to-insert length))) + (let ((a2-0 (-> object-to-insert type heap-base))) (mem-copy! (the-as pointer - (+ (+ (* s5-0 (the-as int (-> this type heap-base))) -4 (-> this type size)) (the-as int this)) + (+ (+ (* s5-0 (the-as int (-> object-to-insert type heap-base))) -4 (-> object-to-insert type size)) + (the-as int object-to-insert) + ) ) (the-as pointer arg0) (the-as int a2-0) ) ) - (+! (-> this length) 1) + (+! (-> object-to-insert length) 1) s5-0 ) ) (defmethod push-back ((this inline-array-class-uint32) (arg0 object)) + "Copy object to the end, then increment length. No bounds check." (let ((v0-0 (-> this length))) (-> this type heap-base) (set! (-> (the-as @@ -977,6 +1016,7 @@ ) (defmethod push-back ((this inline-array-class-uint64) (arg0 object)) + "Copy object to the end, then increment length. No bounds check." (let ((v0-0 (-> this length))) (-> this type heap-base) (set! (-> (the-as @@ -992,6 +1032,7 @@ ) (defmethod pop-front ((this inline-array-class) (arg0 int)) + "Remove first object by copying last object to the front, then decrement length." (+! (-> this length) -1) (+ (-> this length) -1) (let ((a2-0 (-> this type heap-base)) @@ -1007,7 +1048,9 @@ ) ) +;; WARN: Return type mismatch uint vs pointer. (defmethod pop-front ((this inline-array-class-uint64) (arg0 int)) + "Remove first object by copying last object to the front, then decrement length." (+! (-> this length) -1) (+ (-> this length) -1) (-> this type heap-base) @@ -1030,7 +1073,9 @@ ) ) +;; WARN: Return type mismatch uint vs pointer. (defmethod pop-front ((this inline-array-class-uint32) (arg0 int)) + "Remove first object by copying last object to the front, then decrement length." (+! (-> this length) -1) (+ (-> this length) -1) (-> this type heap-base) @@ -1054,51 +1099,60 @@ ) (defmethod clear-2 ((this inline-array-class)) + "Set length to 0" (set! (-> this length) 0) 0 (none) ) (defmethod clear-1 ((this inline-array-class)) + "Set length to 0, return #t." (set! (-> this length) 0) #t ) -(defun-recursive fact int ((arg0 int)) - (if (= arg0 1) +;; og:preserve-this +(defun-recursive fact int ((x int)) + (if (= x 1) 1 - (* arg0 (fact (+ arg0 -1))) - ) + (* x (fact (+ x -1)))) ) (define *print-column* (the-as binteger 0)) -(defun print ((arg0 object)) - ((method-of-type (rtype-of arg0) print) arg0) +;; WARN: Using new Jak 2 rtype-of +(defun print ((obj object)) + "Print any boxed object (symbol, pair, basic, binteger) to #t (the REPL). No newline." + ((method-of-type (rtype-of obj) print) obj) ) -(defun printl ((arg0 object)) - (let ((a0-1 arg0)) +;; WARN: Using new Jak 2 rtype-of +(defun printl ((obj object)) + "Print any boxed object (symbol, pair, basic, binteger) to #t (the REPL), followed by a newline." + (let ((a0-1 obj)) ((method-of-type (rtype-of a0-1) print) a0-1) ) (format #t "~%") - arg0 + obj ) -(defun inspect ((arg0 object)) - ((method-of-type (rtype-of arg0) inspect) arg0) +;; WARN: Using new Jak 2 rtype-of +(defun inspect ((obj object)) + "Inspect any boxed object (symbol, pair, basic, binteger) to #t (the REPL)." + ((method-of-type (rtype-of obj) inspect) obj) ) -(defun-debug mem-print ((arg0 (pointer uint32)) (arg1 int)) - (dotimes (s4-0 (/ arg1 4)) +(defun-debug mem-print ((ptr (pointer uint32)) (word-count int)) + "Print out data in memory in hex." + (dotimes (s4-0 (/ word-count 4)) (format 0 "~X: ~X ~X ~X ~X~%" - (&-> arg0 (* s4-0 4)) - (-> arg0 (* s4-0 4)) - (-> arg0 (+ (* s4-0 4) 1)) - (-> arg0 (+ (* s4-0 4) 2)) - (-> arg0 (+ (* s4-0 4) 3)) + (&-> ptr (* s4-0 4)) + (-> ptr (* s4-0 4)) + (-> ptr (+ (* s4-0 4) 1)) + (-> ptr (+ (* s4-0 4) 2)) + (-> ptr (+ (* s4-0 4) 3)) ) ) #f @@ -1106,42 +1160,67 @@ (define *trace-list* '()) -(defun print-tree-bitmask ((arg0 int) (arg1 int)) - (dotimes (s4-0 arg1) - (if (not (logtest? arg0 1)) +(defun print-tree-bitmask ((mask int) (count int)) + "Print out ASCII-art tree structure, from a bitmask of nesting levels." + (dotimes (s4-0 count) + (if (not (logtest? mask 1)) (format #t " ") (format #t "| ") ) - (set! arg0 (shr arg0 1)) + (set! mask (shr mask 1)) ) #f ) +;; ERROR: Unsupported inline assembly instruction kind - [mtdab a1] +;; ERROR: Unsupported inline assembly instruction kind - [mtdabm a2] (defun breakpoint-range-set! ((arg0 uint) (arg1 uint) (arg2 uint)) - "Sets some debug register (COP0 Debug, dab, dabm) to break on memory access. - This is not supported in OpenGOAL." - (break!) + "Unsupported function to set a CPU breakpoint." + (break!) ;; og:preserve-this + ; (.mtc0 Debug arg0) + ; (.mtdab arg1) + ; (.mtdabm arg2) + 0 ) -#| -(defun valid? ((arg0 object) (arg1 type) (arg2 string) (arg3 symbol) (arg4 object)) - (local-vars (v1-11 int) (v1-26 int) (v1-56 int) (v1-60 int) (s7-0 none)) +(defmacro start-of-symbol-table () + "Get the address for the start of the symbol table." + `(rlet ((st :reg r14 :reset-here #t :type uint)) + (the uint (- st 32768)) + ) + ) + +(defmacro end-of-symbol-table () + "Get the address of the end of the symbol table." + `(rlet ((st :reg r14 :reset-here #t :type uint)) + (the uint (+ st 32768)) + ) + ) + +;; ERROR: Unsupported inline assembly instruction kind - [daddu v1, v1, s7] +;; ERROR: Unsupported inline assembly instruction kind - [daddu v1, v1, s7] +;; ERROR: Unsupported inline assembly instruction kind - [daddu v1, v1, s7] +;; ERROR: Unsupported inline assembly instruction kind - [daddu v1, v1, s7] +(defun valid? ((obj object) (expected-type type) (err-msg-str string) (allow-false symbol) (err-msg-dest object)) + ;; og:preserve-this + ;; cleaned up significantly. + ;; (local-vars (v1-11 int) (v1-26 int) (v1-56 int) (v1-60 int) (s7-0 none)) (let ((v1-1 - (and (>= (the-as uint arg0) (the-as uint __START-OF-TABLE__)) (< (the-as uint arg0) (the-as uint #x8000000))) + (and (>= (the-as uint obj) (start-of-symbol-table)) (< (the-as uint obj) END_OF_MEMORY)) ) ) (cond - ((not arg1) + ((not expected-type) (cond - ((logtest? (the-as int arg0) 3) - (if arg2 - (format arg4 "ERROR: object #x~X ~S is not a valid object (misaligned)~%" arg0 arg2) + ((logtest? (the-as int obj) 3) + (if err-msg-str + (format err-msg-dest "ERROR: object #x~X ~S is not a valid object (misaligned)~%" obj err-msg-str) ) #f ) ((not v1-1) - (if arg2 - (format arg4 "ERROR: object #x~X ~S is not a valid object (bad address)~%" arg0 arg2) + (if err-msg-str + (format err-msg-dest "ERROR: object #x~X ~S is not a valid object (bad address)~%" obj err-msg-str) ) #f ) @@ -1150,155 +1229,31 @@ ) ) ) - ((and arg3 (not arg0)) + ((and allow-false (not obj)) #t ) - ((= arg1 structure) + ((= expected-type structure) (cond - ((logtest? (the-as int arg0) 15) - (if arg2 - (format arg4 "ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%" arg0 arg2 arg1) - ) - #f - ) - ((or (not v1-1) (begin - (let ((v1-10 #x8000)) - (.daddu v1-11 v1-10 s7-0) - ) - (< (the-as uint arg0) (the-as uint v1-11)) - ) - ) - (if arg2 - (format arg4 "ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%" arg0 arg2 arg1) - ) - #f - ) - (else - #t - ) - ) - ) - ((= arg1 pair) - (cond - ((not (pair? arg0)) - (if arg2 - (format arg4 "ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%" arg0 arg2 arg1) - ) - #f - ) - ((not v1-1) - (if arg2 - (format arg4 "ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%" arg0 arg2 arg1) - ) - #f - ) - (else - #t - ) - ) - ) - ((= arg1 binteger) - (cond - ((not (logtest? (the-as int arg0) 7)) - #t - ) - (else - (if arg2 - (format arg4 "ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%" arg0 arg2 arg1) - ) - #f - ) - ) - ) - ((or (= arg1 symbol) (= arg1 boolean)) - (cond - ((not (logtest? (the-as int arg0) 1)) - (if arg2 - (format arg4 "ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%" arg0 arg2 arg1) - ) - #f - ) - ((or (not v1-1) (< (the-as int arg0) (the-as int __START-OF-TABLE__)) (begin - (let ((v1-25 #x8000)) - (.daddu v1-26 v1-25 s7-0) - ) - (>= (the-as int arg0) v1-26) - ) - ) - (if arg2 - (format arg4 "ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%" arg0 arg2 arg1) - ) - #f - ) - (else - #t - ) - ) - ) - ((!= (logand (the-as int arg0) 7) 4) - (if arg2 - (format arg4 "ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%" arg0 arg2 arg1) - ) - #f - ) - ((not v1-1) - (if arg2 - (format arg4 "ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%" arg0 arg2 arg1) - ) - #f - ) - ((and (= arg1 type) (!= (rtype-of arg0) type)) - (if arg2 - (format - arg4 - "ERROR: object #x~X ~S is not a valid object of type '~A' (invalid type #x~X)~%" - arg0 - arg2 - arg1 - (rtype-of arg0) - ) - ) - #f - ) - ((and (!= arg1 type) (not (valid? (rtype-of arg0) type (the-as string #f) #t 0))) - (if arg2 - (format - arg4 - "ERROR: object #x~X ~S is not a valid object of type '~A' (invalid type #x~X)~%" - arg0 - arg2 - arg1 - (rtype-of arg0) - ) - ) - #f - ) - ((not (type? arg0 arg1)) - (if arg2 - (format - arg4 - "ERROR: object #x~X ~S is not a valid object of type '~A' (is type '~A' instead)~%" - arg0 - arg2 - arg1 - (rtype-of arg0) - ) - ) - #f - ) - ((= arg1 symbol) - (let ((v1-55 #x8000)) - (.daddu v1-56 v1-55 s7-0) - ) - (cond - ((>= (the-as uint arg0) (the-as uint v1-56)) - (if arg2 + ((logtest? (the-as int obj) 15) + (if err-msg-str (format - arg4 - "ERROR: object #x~X ~S is not a valid object of type '~A' (not in symbol table)~%" - arg0 - arg2 - arg1 + err-msg-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%" + obj + err-msg-str + expected-type + ) + ) + #f + ) + ((or (not v1-1) (< (the-as uint obj) (end-of-symbol-table))) + (if err-msg-str + (format + err-msg-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%" + obj + err-msg-str + expected-type ) ) #f @@ -1308,19 +1263,177 @@ ) ) ) - ((begin - (let ((v1-59 #x8000)) - (.daddu v1-60 v1-59 s7-0) + ((= expected-type pair) + (cond + ((not (pair? obj)) + (if err-msg-str + (format + err-msg-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%" + obj + err-msg-str + expected-type + ) + ) + #f + ) + ((not v1-1) + (if err-msg-str + (format + err-msg-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%" + obj + err-msg-str + expected-type + ) + ) + #f + ) + (else + #t ) - (< (the-as uint arg0) (the-as uint v1-60)) ) - (if arg2 + ) + ((= expected-type binteger) + (cond + ((not (logtest? (the-as int obj) 7)) + #t + ) + (else + (if err-msg-str + (format + err-msg-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%" + obj + err-msg-str + expected-type + ) + ) + #f + ) + ) + ) + ((or (= expected-type symbol) (= expected-type boolean)) + (cond + ((not (logtest? (the-as int obj) 1)) + (if err-msg-str + (format + err-msg-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%" + obj + err-msg-str + expected-type + ) + ) + #f + ) + ((or (not v1-1) (< (the-as int obj) (start-of-symbol-table)) (>= (the-as int obj) (end-of-symbol-table))) + (if err-msg-str + (format + err-msg-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%" + obj + err-msg-str + expected-type + ) + ) + #f + ) + (else + #t + ) + ) + ) + ((!= (logand (the-as int obj) 7) 4) + (if err-msg-str (format - arg4 + err-msg-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%" + obj + err-msg-str + expected-type + ) + ) + #f + ) + ((not v1-1) + (if err-msg-str + (format + err-msg-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%" + obj + err-msg-str + expected-type + ) + ) + #f + ) + ((and (= expected-type type) (!= (rtype-of obj) type)) + (if err-msg-str + (format + err-msg-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (invalid type #x~X)~%" + obj + err-msg-str + expected-type + (rtype-of obj) + ) + ) + #f + ) + ((and (!= expected-type type) (not (valid? (rtype-of obj) type (the-as string #f) #t 0))) + (if err-msg-str + (format + err-msg-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (invalid type #x~X)~%" + obj + err-msg-str + expected-type + (rtype-of obj) + ) + ) + #f + ) + ((not (type? obj expected-type)) + (if err-msg-str + (format + err-msg-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (is type '~A' instead)~%" + obj + err-msg-str + expected-type + (rtype-of obj) + ) + ) + #f + ) + ((= expected-type symbol) + (cond + ((>= (the-as uint obj) (end-of-symbol-table)) + (if err-msg-str + (format + err-msg-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (not in symbol table)~%" + obj + err-msg-str + expected-type + ) + ) + #f + ) + (else + #t + ) + ) + ) + ((< (the-as uint obj) (end-of-symbol-table)) + (if err-msg-str + (format + err-msg-dest "ERROR: object #x~X ~S is not a valid object of type '~A' (inside symbol table)~%" - arg0 - arg2 - arg1 + obj + err-msg-str + expected-type ) ) #f @@ -1331,4 +1444,3 @@ ) ) ) -|# diff --git a/test/decompiler/reference/jak3/engine/geometry/bounding-box_REF.gc b/test/decompiler/reference/jak3/engine/geometry/bounding-box_REF.gc index 80eb1f65e..49659dc66 100644 --- a/test/decompiler/reference/jak3/engine/geometry/bounding-box_REF.gc +++ b/test/decompiler/reference/jak3/engine/geometry/bounding-box_REF.gc @@ -249,7 +249,7 @@ ;; WARN: disable def twice: 23. This may happen when a cond (no else) is nested inside of another conditional, but it should be rare. (defmethod intersects-line-segment? ((this bounding-box) (arg0 vector) (arg1 vector)) "Check intersection in xz plane, using liang-barsky. Not sure if this actually -a useful check or not..." + a useful check or not..." (let ((f28-0 (- (-> arg1 x) (-> arg0 x))) (f30-0 (- (-> arg1 z) (-> arg0 z))) ) @@ -275,7 +275,3 @@ a useful check or not..." ) ) ) - - - - diff --git a/test/decompiler/reference/jak3/engine/math/euler_REF.gc b/test/decompiler/reference/jak3/engine/math/euler_REF.gc index efff8e2f1..b31642922 100644 --- a/test/decompiler/reference/jak3/engine/math/euler_REF.gc +++ b/test/decompiler/reference/jak3/engine/math/euler_REF.gc @@ -97,7 +97,7 @@ ;; definition for function matrix->eul (defun matrix->eul ((arg0 euler-angles) (arg1 matrix) (arg2 int)) "Convert matrix to euler angles with given order flag. -Not clear how this works if the matrix has more than just a rotation." + Not clear how this works if the matrix has more than just a rotation." 0 0 0 @@ -213,7 +213,3 @@ Not clear how this works if the matrix has more than just a rotation." ) arg0 ) - - - - diff --git a/test/decompiler/reference/jak3/engine/math/math_REF.gc b/test/decompiler/reference/jak3/engine/math/math_REF.gc index 9db1fe7ae..81b943db5 100644 --- a/test/decompiler/reference/jak3/engine/math/math_REF.gc +++ b/test/decompiler/reference/jak3/engine/math/math_REF.gc @@ -4,7 +4,7 @@ ;; definition for function truncate (defun truncate ((arg0 float)) "Round (toward zero) to an integer. -@param arg0 float to truncate" + @param arg0 float to truncate" (the float (the int arg0)) ) @@ -340,8 +340,8 @@ ;; definition for function seek-ease (defun seek-ease ((arg0 float) (arg1 float) (arg2 float) (arg3 float) (arg4 float)) "Move arg0 toward arg1, and slow down before reaching the end. -When farther than arg3 away, move by at most arg2. -When closer than arg3, linearly ramp down the movement amount from arg2 to 0 but no lower than arg4." + When farther than arg3 away, move by at most arg2. + When closer than arg3, linearly ramp down the movement amount from arg2 to 0 but no lower than arg4." (let ((f2-0 (- arg1 arg0))) (when (>= arg3 (fabs f2-0)) (set! arg2 (* arg2 (- 1.0 (/ (- arg3 (fabs f2-0)) arg3)))) @@ -366,9 +366,9 @@ When closer than arg3, linearly ramp down the movement amount from arg2 to 0 but ;; definition for function seek-ease-in-out (defun seek-ease-in-out ((arg0 float) (arg1 float) (arg2 float) (arg3 float) (arg4 float) (arg5 float) (arg6 float)) "Move arg0 toward arg2, and slow down at the start and end. -When within arg4 of arg1 (at the beginning of movement), ramp up speed, with a minimum speed of arg6 -When within arg5 of arg2 (at the end of movement), ramp down speed, with a minimum speed of arg5 -Normally, move at most arg3" + When within arg4 of arg1 (at the beginning of movement), ramp up speed, with a minimum speed of arg6 + When within arg5 of arg2 (at the end of movement), ramp down speed, with a minimum speed of arg5 + Normally, move at most arg3" (let ((f2-0 (- arg2 arg0))) (let ((f4-1 (- arg0 arg1))) (when (>= arg4 (fabs f4-1)) @@ -407,7 +407,7 @@ Normally, move at most arg3" ;; definition (debug) for function lerp-scale-old (defun-debug lerp-scale-old ((arg0 float) (arg1 float) (arg2 float) (arg3 float) (arg4 float)) "Linearly remap arg2 in [arg3, arg4] to [arg0, arg1]. -This is the jak 1 implementation, which I claimed was a bad implementation..." + This is the jak 1 implementation, which I claimed was a bad implementation..." (let ((f0-1 (fmax 0.0 (fmin 1.0 (/ (- arg2 arg3) (- arg4 arg3)))))) (+ (* (- 1.0 f0-1) arg0) (* f0-1 arg1)) ) @@ -418,7 +418,7 @@ This is the jak 1 implementation, which I claimed was a bad implementation..." ;; ERROR: Unsupported inline assembly instruction kind - [madd.s f0, f1, f3] (defun lerp-scale ((arg0 float) (arg1 float) (arg2 float) (arg3 float) (arg4 float)) "Linearly remap arg2 in [arg3, arg4] to [arg0, arg1]. -More efficient than the -old version." + More efficient than the -old version." (local-vars (f0-2 float)) (let* ((v1-0 1.0) (f1-0 0.0) @@ -563,8 +563,8 @@ More efficient than the -old version." ;; ERROR: Inline assembly instruction marked with TODO - [TODO.VRGET] (defun rand-vu-nostep () "Get the number currently in the random generator. -This will be equal to the last call of (rand-vu). -This will not update the random generator." + This will be equal to the last call of (rand-vu). + This will not update the random generator." (local-vars (v0-0 float)) (rlet ((vf0 :class vf) (vf1 :class vf) @@ -614,7 +614,7 @@ This will not update the random generator." ;; WARN: new jak 2 until loop case, check carefully (defun rand-vu-int-count-excluding ((arg0 int) (arg1 int)) "Get an integer in the range [0, arg0). -If bit n is set in arg1, exclude this value from being returned." + If bit n is set in arg1, exclude this value from being returned." (let ((s4-0 0) (s5-0 0) ) @@ -657,7 +657,7 @@ If bit n is set in arg1, exclude this value from being returned." ;; WARN: new jak 2 until loop case, check carefully (defun rand-vu-int-range-exclude ((arg0 int) (arg1 int) (arg2 int)) "Get an integer in the range [0, arg0), excluding arg2. -Note that this doesn't use bits like rand-vu-int-count-excluding." + Note that this doesn't use bits like rand-vu-int-count-excluding." (until #f (let ((v1-0 (rand-vu-int-range arg0 arg1))) (if (!= v1-0 arg2) @@ -742,7 +742,7 @@ Note that this doesn't use bits like rand-vu-int-count-excluding." ;; definition for function smooth-step (defun smooth-step ((arg0 float)) "Interpolate between 0, 1 with a cubic polynomial. -These are picked so f(0) = 0, f(1) = 1, f'(0) = f'(1) = 0." + These are picked so f(0) = 0, f(1) = 1, f'(0) = f'(1) = 0." (cond ((>= 0.0 arg0) 0.0 @@ -759,13 +759,9 @@ These are picked so f(0) = 0, f(1) = 1, f'(0) = f'(1) = 0." ;; definition for function smooth-interp (defun smooth-interp ((arg0 float) (arg1 float) (arg2 float) (arg3 float) (arg4 float)) "Remap arg2 from (arg3, arg4) to (arg0, arg1), using cubic interpolation. -Satisfies: -- f(arg3) = arg0 -- f(arg4) = arg1 -- f'(arg3) = f'(arg4) = 0" + Satisfies: + - f(arg3) = arg0 + - f(arg4) = arg1 + - f'(arg3) = f'(arg4) = 0" (+ arg0 (* (- arg1 arg0) (smooth-step (/ (- arg2 arg3) (- arg4 arg3))))) ) - - - - diff --git a/test/decompiler/reference/jak3/engine/math/matrix_REF.gc b/test/decompiler/reference/jak3/engine/math/matrix_REF.gc index 8567e44c0..fcacb1e17 100644 --- a/test/decompiler/reference/jak3/engine/math/matrix_REF.gc +++ b/test/decompiler/reference/jak3/engine/math/matrix_REF.gc @@ -52,7 +52,7 @@ ;; definition for function matrix+! (defun matrix+! ((arg0 matrix) (arg1 matrix) (arg2 matrix)) "Set dst = src1 + src2. It is okay for any arguments to be the same data. -This is not an efficient implementation." + This is not an efficient implementation." (dotimes (v1-0 16) (set! (-> arg0 rvec data v1-0) (+ (-> arg1 rvec data v1-0) (-> arg2 rvec data v1-0))) ) @@ -62,7 +62,7 @@ This is not an efficient implementation." ;; definition for function matrix-! (defun matrix-! ((arg0 matrix) (arg1 matrix) (arg2 matrix)) "Set dst = src1 - src1. It is okay for any arugments to be the same data. -This is not an efficient implementation." + This is not an efficient implementation." (dotimes (v1-0 16) (set! (-> arg0 rvec data v1-0) (- (-> arg1 rvec data v1-0) (-> arg2 rvec data v1-0))) ) @@ -72,7 +72,7 @@ This is not an efficient implementation." ;; definition for function matrix*! (defun matrix*! ((arg0 matrix) (arg1 matrix) (arg2 matrix)) "Set dst = src1 * src2. It is okay for any arguments to be the same data. -This is a moderately efficient implementation." + This is a moderately efficient implementation." (rlet ((acc :class vf) (vf10 :class vf) (vf11 :class vf) @@ -123,8 +123,8 @@ This is a moderately efficient implementation." ;; INFO: Used lq/sq (defun matrixp*! ((arg0 matrix) (arg1 matrix) (arg2 matrix)) "Set dst = src1 * src2. NOTE: this function is a wrapper around matrix*! -that adds no additional functionality. It seems to be a leftover from -a time when matrix*! wasn't safe to use in place. This is unused." + that adds no additional functionality. It seems to be a leftover from + a time when matrix*! wasn't safe to use in place. This is unused." (let ((s5-0 (new 'stack-no-clear 'matrix))) (set! (-> s5-0 rvec quad) (the-as uint128 0)) (set! (-> s5-0 uvec quad) (the-as uint128 0)) @@ -198,8 +198,8 @@ a time when matrix*! wasn't safe to use in place. This is unused." ;; definition for function vector-rotate*! (defun vector-rotate*! ((arg0 vector) (arg1 vector) (arg2 matrix)) "Set dst to be the input vector rotated by the rotation part of mat. -The input matrix should be a homogeneous transform with a rotation matrix as its upper-left 3x3. -dst may be equal to src." + The input matrix should be a homogeneous transform with a rotation matrix as its upper-left 3x3. + dst may be equal to src." (rlet ((acc :class vf) (vf1 :class vf) (vf2 :class vf) @@ -230,7 +230,7 @@ dst may be equal to src." ;; INFO: Used lq/sq (defun vector3s-matrix*! ((arg0 vector3s) (arg1 vector3s) (arg2 matrix)) "Set dst to be ([src 1.0] * mat).xyz. Doesn't touch the w of dst. -dst and vec can be the same memory" + dst and vec can be the same memory" (let ((s5-0 (new-stack-vector0))) (set-vector! s5-0 (-> arg1 x) (-> arg1 y) (-> arg1 z) 1.0) (vector-matrix*! s5-0 s5-0 arg2) @@ -245,7 +245,7 @@ dst and vec can be the same memory" ;; INFO: Used lq/sq (defun vector3s-rotate*! ((arg0 vector3s) (arg1 vector3s) (arg2 matrix)) "Set dst to vec rotated by the rotation in the homogeneous transform mat. -mat should not have a scale/shear (the upper 3x3 should be a pure rotation)." + mat should not have a scale/shear (the upper 3x3 should be a pure rotation)." (let ((s5-0 (new-stack-vector0))) (set-vector! s5-0 (-> arg1 x) (-> arg1 y) (-> arg1 z) 1.0) (vector-rotate*! s5-0 s5-0 arg2) @@ -298,7 +298,7 @@ mat should not have a scale/shear (the upper 3x3 should be a pure rotation)." ;; definition for function matrix-inverse-of-rot-trans! (defun matrix-inverse-of-rot-trans! ((arg0 matrix) (arg1 matrix)) "Set dst = src^-1, assuming src is a homogeneous tranform with only rotation/translation. -NOTE: THIS FUNCTION REQUIRES dst != src" + NOTE: THIS FUNCTION REQUIRES dst != src" (rlet ((acc :class vf) (vf0 :class vf) (vf1 :class vf) @@ -335,7 +335,7 @@ NOTE: THIS FUNCTION REQUIRES dst != src" ;; ERROR: Bad vector register dependency: vf5 (defun matrix-4x4-inverse! ((arg0 matrix) (arg1 matrix)) "Invert a 4x4 matrix. This assumes that the input is a homogeneous transform. -Src and dst can be the same." + Src and dst can be the same." (rlet ((acc :class vf) (Q :class vf) (vf0 :class vf) @@ -499,7 +499,7 @@ Src and dst can be the same." ;; INFO: Used lq/sq (defun matrix-translate+! ((arg0 matrix) (arg1 matrix) (arg2 vector)) "Add the given translation to the translation of homogenous transform mat src -and store in dst. It is okay for dst = src." + and store in dst. It is okay for dst = src." (set! (-> arg0 trans x) (+ (-> arg1 trans x) (-> arg2 x))) (set! (-> arg0 trans y) (+ (-> arg1 trans y) (-> arg2 y))) (set! (-> arg0 trans z) (+ (-> arg1 trans z) (-> arg2 z))) @@ -515,7 +515,7 @@ and store in dst. It is okay for dst = src." ;; INFO: Used lq/sq (defun matrix-scale! ((arg0 matrix) (arg1 vector)) "Set dst to a homogenous transform with only a scale. The x,y,z components -of scale become the x,y,z scaling factors" + of scale become the x,y,z scaling factors" (set! (-> arg0 rvec quad) (the-as uint128 0)) (set! (-> arg0 uvec quad) (the-as uint128 0)) (set! (-> arg0 fvec quad) (the-as uint128 0)) @@ -530,8 +530,8 @@ of scale become the x,y,z scaling factors" ;; definition for function scale-matrix! (defun scale-matrix! ((arg0 matrix) (arg1 vector) (arg2 matrix)) "Scale an existing matrix. Okay for dst = src. The scaling is applied per row. -This means the x component of scale is used to scale the first row of src. -The w component of scale is used." + This means the x component of scale is used to scale the first row of src. + The w component of scale is used." (rlet ((vf4 :class vf) (vf5 :class vf) (vf6 :class vf) @@ -559,7 +559,7 @@ The w component of scale is used." ;; INFO: Used lq/sq (defun matrix-inv-scale! ((arg0 matrix) (arg1 vector)) "Set dst to a homogeneous transform with only a scale. -The x,y,z components of scale are inverted and used as the x,y,z scaling factors" + The x,y,z components of scale are inverted and used as the x,y,z scaling factors" (set! (-> arg0 rvec quad) (the-as uint128 0)) (set! (-> arg0 uvec quad) (the-as uint128 0)) (set! (-> arg0 fvec quad) (the-as uint128 0)) @@ -574,7 +574,7 @@ The x,y,z components of scale are inverted and used as the x,y,z scaling factors ;; definition for function column-scale-matrix! (defun column-scale-matrix! ((arg0 matrix) (arg1 vector) (arg2 matrix)) "Scale an existing matrix. Okay for dst = src. The scaling is applied column-wise. -Meaning the x component of scale will scale the first column of src." + Meaning the x component of scale will scale the first column of src." (rlet ((vf4 :class vf) (vf5 :class vf) (vf6 :class vf) @@ -815,7 +815,7 @@ Meaning the x component of scale will scale the first column of src." ;; definition for function matrix-rotate-yxy! (defun matrix-rotate-yxy! ((arg0 matrix) (arg1 vector)) "Rotate. I believe in yxy order? Compared to the other rotations, this one -is quite a bit more optimized and avoid repeated trig operations." + is quite a bit more optimized and avoid repeated trig operations." (let ((a2-0 (new 'stack-no-clear 'vector)) (s5-0 (new 'stack-no-clear 'vector)) (s4-0 (new 'stack-no-clear 'vector)) @@ -1194,7 +1194,7 @@ is quite a bit more optimized and avoid repeated trig operations." ;; definition for function matrix-3x3-inverse! (defun matrix-3x3-inverse! ((arg0 matrix) (arg1 matrix)) "Compute the inverse of a 3x3 matrix. Not very efficient. -Requires src != dst." + Requires src != dst." (let ((f0-0 (matrix-3x3-determinant arg1))) (set! (-> arg0 rvec x) (/ (- (* (-> arg1 uvec y) (-> arg1 fvec z)) (* (-> arg1 uvec z) (-> arg1 fvec y))) f0-0) @@ -1230,7 +1230,7 @@ Requires src != dst." ;; definition for function matrix-3x3-inverse-transpose! (defun matrix-3x3-inverse-transpose! ((arg0 matrix) (arg1 matrix)) "Invert and transpose. -Requires dst != src." + Requires dst != src." (let ((f0-0 (matrix-3x3-determinant arg1))) (set! (-> arg0 rvec x) (/ (- (* (-> arg1 uvec y) (-> arg1 fvec z)) (* (-> arg1 uvec z) (-> arg1 fvec y))) f0-0) @@ -1426,7 +1426,7 @@ Requires dst != src." ;; definition for function matrix-4x4-inverse-transpose! (defun matrix-4x4-inverse-transpose! ((arg0 matrix) (arg1 matrix)) "Invert and transpose an entire 4x4. I think has no restrictions, other than dst != src. Unused. -The answer is wrong. The determinant function is wrong." + The answer is wrong. The determinant function is wrong." (let ((f0-0 (matrix-4x4-determinant arg1))) (let ((f9-0 (-> arg1 uvec y)) (f2-0 (-> arg1 uvec z)) @@ -1771,7 +1771,7 @@ The answer is wrong. The determinant function is wrong." ;; INFO: Used lq/sq (defun matrix->quat ((arg0 matrix) (arg1 quaternion)) "Convert matrix to quaternion, works for matrix with scale. -unlike matrix->quaternion." + unlike matrix->quaternion." (let ((s5-0 (new 'stack-no-clear 'matrix))) (let* ((a2-0 arg0) (v1-0 (-> a2-0 rvec quad)) @@ -1901,7 +1901,3 @@ unlike matrix->quaternion." ) arg0 ) - - - - diff --git a/test/decompiler/reference/jak3/engine/math/quaternion_REF.gc b/test/decompiler/reference/jak3/engine/math/quaternion_REF.gc index 66f7a29a4..96446c8e7 100644 --- a/test/decompiler/reference/jak3/engine/math/quaternion_REF.gc +++ b/test/decompiler/reference/jak3/engine/math/quaternion_REF.gc @@ -184,8 +184,8 @@ ;; ERROR: Bad vector register dependency: vf2 (defun quaternion-conjugate! ((arg0 quaternion) (arg1 quaternion)) "Set arg0 to the conjugate of arg1 (negate only ijk). -If arg1 is normalized, this is equivalent to the inverse -NOTE: this gives you the inverse rotation." + If arg1 is normalized, this is equivalent to the inverse + NOTE: this gives you the inverse rotation." (rlet ((vf1 :class vf) (vf2 :class vf) ) @@ -290,7 +290,7 @@ NOTE: this gives you the inverse rotation." ;; ERROR: Bad vector register dependency: vf3 (defun quaternion-inverse! ((arg0 quaternion) (arg1 quaternion)) "Invert a quaternion. The inverse will satisfy q * q^-1 = identity, even if q is not normalized. -If your quaternion is normalized, it is faster/more accurate to do quaternion-conjugate!" + If your quaternion is normalized, it is faster/more accurate to do quaternion-conjugate!" (rlet ((acc :class vf) (Q :class vf) (vf0 :class vf) @@ -371,9 +371,9 @@ If your quaternion is normalized, it is faster/more accurate to do quaternion-co ;; definition for function quaternion-right-mult-matrix! (defun quaternion-right-mult-matrix! ((arg0 matrix) (arg1 quaternion)) "Place quaternion coefficients into a matrix. -You can convert a quaternion to a matrix by taking the product of this -right-mult and left-mult matrix, but this method is not used. -Instead, quaternion->matrix is a more efficient implementation." + You can convert a quaternion to a matrix by taking the product of this + right-mult and left-mult matrix, but this method is not used. + Instead, quaternion->matrix is a more efficient implementation." (let ((f3-0 (-> arg1 x)) (f2-0 (-> arg1 y)) (f1-0 (-> arg1 z)) @@ -663,7 +663,7 @@ Instead, quaternion->matrix is a more efficient implementation." ;; definition for function quaternion-slerp! (defun quaternion-slerp! ((arg0 quaternion) (arg1 quaternion) (arg2 quaternion) (arg3 float)) "Real quaternion slerp. Spherical-linear interpolation is a nice way to interpolate -between quaternions." + between quaternions." (local-vars (v1-15 float)) (rlet ((acc :class vf) (vf1 :class vf) @@ -729,8 +729,8 @@ between quaternions." ;; definition for function quaternion-pseudo-slerp! (defun quaternion-pseudo-slerp! ((arg0 quaternion) (arg1 quaternion) (arg2 quaternion) (arg3 float)) "This is a bad interpolation between quaternions. It lerps then normalizes. -It will behave extremely poorly for 180 rotations. -It is unused." + It will behave extremely poorly for 180 rotations. + It is unused." (rlet ((acc :class vf) (vf1 :class vf) (vf2 :class vf) @@ -764,7 +764,7 @@ It is unused." ;; definition for function quaternion-pseudo-seek (defun quaternion-pseudo-seek ((arg0 quaternion) (arg1 quaternion) (arg2 quaternion) (arg3 float)) "Seek one quaternion toward another. Not using real slerp, so this is only good if the quaternions -are pretty similar." + are pretty similar." (let ((s3-0 (new 'stack-no-clear 'quaternion))) (let ((s5-0 (new 'stack-no-clear 'quaternion))) (quaternion-copy! s3-0 arg2) @@ -1086,7 +1086,3 @@ are pretty similar." (vector-y-angle s5-0) ) ) - - - - diff --git a/test/decompiler/reference/jak3/engine/math/transformq-h_REF.gc b/test/decompiler/reference/jak3/engine/math/transformq-h_REF.gc index 06dc0ea50..258975981 100644 --- a/test/decompiler/reference/jak3/engine/math/transformq-h_REF.gc +++ b/test/decompiler/reference/jak3/engine/math/transformq-h_REF.gc @@ -112,20 +112,16 @@ As a result, this type has a lot of weird methods and extra stuff hidden in it." ;; definition for method 23 of type trsqv (defmethod global-y-angle-to-point ((this trsqv) (arg0 vector)) "Get the angle in the xz plane from the position of this trsqv to the point arg0 -(ignores our current yaw)." + (ignores our current yaw)." (vector-y-angle (vector-! (new 'stack-no-clear 'vector) arg0 (-> this trans))) ) ;; definition for method 24 of type trsqv (defmethod relative-y-angle-to-point ((this trsqv) (arg0 vector)) "Get the y angle between the current orientation and arg0 -(how much we'd have to yaw to point at arg0)." + (how much we'd have to yaw to point at arg0)." (deg-diff (y-angle this) (vector-y-angle (vector-! (new 'stack-no-clear 'vector) arg0 (-> this trans)))) ) ;; failed to figure out what this is: 0 - - - - diff --git a/test/decompiler/reference/jak3/engine/math/trigonometry_REF.gc b/test/decompiler/reference/jak3/engine/math/trigonometry_REF.gc index 64b558f02..03d112e73 100644 --- a/test/decompiler/reference/jak3/engine/math/trigonometry_REF.gc +++ b/test/decompiler/reference/jak3/engine/math/trigonometry_REF.gc @@ -15,7 +15,7 @@ ;; definition for function deg- (defun deg- ((arg0 float) (arg1 float)) "Compute arg0-arg1, unwrapped, using rotation units. -Result should be in the range (-180, 180)" + Result should be in the range (-180, 180)" (the float (sar (- (shl (the int arg0) 48) (shl (the int arg1) 48)) 48)) ) @@ -195,9 +195,9 @@ Result should be in the range (-180, 180)" ;; definition for function vector-sin-rad! (defun vector-sin-rad! ((arg0 vector) (arg1 vector)) "Taylor series approximation of sine on all 4 elements in a vector. -Inputs should be in radians, in -pi to pi. -Somehow their coefficients are a little bit off. -Like the first coefficient, which should obviously be 1, is not quite 1." + Inputs should be in radians, in -pi to pi. + Somehow their coefficients are a little bit off. + Like the first coefficient, which should obviously be 1, is not quite 1." (rlet ((acc :class vf) (vf1 :class vf) (vf10 :class vf) @@ -239,7 +239,7 @@ Like the first coefficient, which should obviously be 1, is not quite 1." ;; ERROR: Bad vector register dependency: vf2 (defun vector-cos-rad! ((arg0 vector) (arg1 vector)) "Compute the cosine of all 4 vector elements. -Radians, with no wrapping. Uses taylor series with 4 coefficients." + Radians, with no wrapping. Uses taylor series with 4 coefficients." (rlet ((acc :class vf) (vf0 :class vf) (vf1 :class vf) @@ -272,8 +272,8 @@ Radians, with no wrapping. Uses taylor series with 4 coefficients." ;; ERROR: Bad vector register dependency: vf14 (defun vector-sincos-rad! ((arg0 vector) (arg1 vector) (arg2 vector)) "Compute the sine and cosine of each element of src, storing it in dst-sin and dst-cos. -This is more efficient than separate calls to sin and cos. -Inputs should be radians in -pi to pi." + This is more efficient than separate calls to sin and cos. + Inputs should be radians in -pi to pi." (rlet ((acc :class vf) (vf0 :class vf) (vf1 :class vf) @@ -331,7 +331,7 @@ Inputs should be radians in -pi to pi." ;; WARN: Return type mismatch float vs none. (defun vector-rad<-vector-deg! ((out vector) (in vector)) "Convert a vector in rotation units to radians, and unwrap. -Input can be anything, output will be -2pi to pi." + Input can be anything, output will be -2pi to pi." (local-vars (v0-0 float) (v1-1 uint128) (v1-2 uint128) (v1-3 uint128)) (rlet ((vf1 :class vf) (vf2 :class vf) @@ -357,7 +357,7 @@ Input can be anything, output will be -2pi to pi." ;; WARN: Return type mismatch float vs int. (defun vector-rad<-vector-deg/2! ((out vector) (in vector)) "Divide the input by two, and then convert from rotation units to radians, unwrapping. -Not sure why this really needs to be separate the from previous function..." + Not sure why this really needs to be separate the from previous function..." (local-vars (v0-0 float) (v1-1 uint128) (v1-2 uint128) (v1-3 uint128)) (rlet ((vf1 :class vf) (vf2 :class vf) @@ -438,7 +438,7 @@ Not sure why this really needs to be separate the from previous function..." ;; definition for function sign (defun sign ((arg0 float)) "Similar to above, but returns 0 if input is 0. -But is more complicated." + But is more complicated." (cond ((< 0.0 arg0) 1.0 @@ -658,7 +658,3 @@ But is more complicated." ) ) ) - - - - diff --git a/test/decompiler/reference/jak3/engine/math/vector-h_REF.gc b/test/decompiler/reference/jak3/engine/math/vector-h_REF.gc index 525dee434..74db919e4 100644 --- a/test/decompiler/reference/jak3/engine/math/vector-h_REF.gc +++ b/test/decompiler/reference/jak3/engine/math/vector-h_REF.gc @@ -923,8 +923,8 @@ ;; definition for function vector-dot (defun vector-dot ((arg0 vector) (arg1 vector)) "Take the dot product of two vectors. -Only does the x, y, z compoments. -Originally handwritten assembly to space out loads and use FPU accumulator" + Only does the x, y, z compoments. + Originally handwritten assembly to space out loads and use FPU accumulator" (vector-dot arg0 arg1) ) @@ -948,7 +948,7 @@ Originally handwritten assembly to space out loads and use FPU accumulator" ;; definition for function vector4-dot (defun vector4-dot ((arg0 vector) (arg1 vector)) "Take the dot product of two vectors. -Does the x, y, z, and w compoments" + Does the x, y, z, and w compoments" (vector4-dot arg0 arg1) ) @@ -1033,7 +1033,3 @@ Does the x, y, z, and w compoments" ;; failed to figure out what this is: 0 - - - - diff --git a/test/decompiler/reference/jak3/kernel/gcommon_REF.gc b/test/decompiler/reference/jak3/kernel/gcommon_REF.gc new file mode 100644 index 000000000..acb99bbac --- /dev/null +++ b/test/decompiler/reference/jak3/kernel/gcommon_REF.gc @@ -0,0 +1,1551 @@ +;;-*-Lisp-*- +(in-package goal) + +;; definition for function identity +(defun identity ((obj object)) + "The identity function." + obj + ) + +;; definition for function 1/ +(defun 1/ ((x float)) + "Floating point reciprocal." + (/ 1.0 x) + ) + +;; definition for function + +(defun + ((a int) (b int)) + "64-bit integer addition." + (+ a b) + ) + +;; definition for function - +(defun - ((a int) (b int)) + "64-bit integer subraction." + (- a b) + ) + +;; definition for function * +(defun * ((a int) (b int)) + "32-bit signed integer multiplication." + (* a b) + ) + +;; definition for function / +(defun / ((a int) (b int)) + "32-bit signed integer division." + (/ a b) + ) + +;; definition for function ash +(defun ash ((x int) (shift-amount int)) + "64-bit arithmetic shift. (sign-extends)" + (ash x shift-amount) + ) + +;; definition for function mod +(defun mod ((a int) (b int)) + "32-bit mod." + (mod a b) + ) + +;; definition for function rem +(defun rem ((a int) (b int)) + "32-bit mod (same as mod)." + (mod a b) + ) + +;; definition for function abs +(defun abs ((x int)) + "64-bit integer absolute value." + (abs x) + ) + +;; definition for function min +(defun min ((a int) (b int)) + "64-bit integer minimum." + (min a b) + ) + +;; definition for function max +(defun max ((a int) (b int)) + "64-bit integer maximum." + (max a b) + ) + +;; definition for function logior +(defun logior ((a int) (b int)) + "64-bit bitwise or." + (logior a b) + ) + +;; definition for function logand +(defun logand ((a int) (b int)) + "64-bit bitwise and." + (logand a b) + ) + +;; definition for function lognor +(defun lognor ((a int) (b int)) + "64-bit bitwise not-or." + (lognor a b) + ) + +;; definition for function logxor +(defun logxor ((a int) (b int)) + "64-bit bitwise exclusive or." + (logxor a b) + ) + +;; definition for function lognot +(defun lognot ((x int)) + "64-bit bitwise not." + (lognot x) + ) + +;; definition for function false-func +(defun false-func () + "Returns false." + #f + ) + +;; definition for function true-func +(defun true-func () + "Returns true." + #t + ) + +;; definition for symbol format, type (function _varargs_ object) +(define format _format) + +;; definition of type vec4s +(deftype vec4s (uint128) + "Vector of four floats, packed into a 128-bit integer as bitfields. +This behaves like a value type. +This is not the main vector type." + ((x float :offset 0 :size 32) + (y float :offset 32 :size 32) + (z float :offset 64 :size 32) + (w float :offset 96 :size 32) + ) + ) + +;; definition for method 3 of type vec4s +(defmethod inspect ((this vec4s)) + (when (not this) + (set! this this) + (goto cfg-4) + ) + (format #t "[~8x] ~A~%" this 'vec4s) + (format #t "~1Tx: ~f~%" (-> this x)) + (format #t "~1Ty: ~f~%" (-> this y)) + (format #t "~1Tz: ~f~%" (-> this z)) + (format #t "~1Tw: ~f~%" (-> this w)) + (label cfg-4) + this + ) + +;; definition for method 2 of type vec4s +(defmethod print ((this vec4s)) + (format #t "#" (-> this x) (-> this y) (-> this z) (-> this w) this) + this + ) + +;; definition of type vector +(deftype vector (structure) + "Vector of four floats, stored in a structure. +This behaves like a reference type. +This is the main vector type." + ((data float 4) + (x float :overlay-at (-> data 0)) + (y float :overlay-at (-> data 1)) + (z float :overlay-at (-> data 2)) + (w float :overlay-at (-> data 3)) + (quad uint128 :overlay-at (-> data 0)) + ) + ) + +;; definition for method 3 of type vector +;; INFO: Used lq/sq +(defmethod inspect ((this vector)) + (when (not this) + (set! this this) + (goto cfg-4) + ) + (format #t "[~8x] ~A~%" this 'vector) + (format #t "~1Tdata[4] @ #x~X~%" (&-> this x)) + (format #t "~1Tx: ~f~%" (-> this x)) + (format #t "~1Ty: ~f~%" (-> this y)) + (format #t "~1Tz: ~f~%" (-> this z)) + (format #t "~1Tw: ~f~%" (-> this w)) + (format #t "~1Tquad: ~D~%" (-> this quad)) + (label cfg-4) + this + ) + +;; definition of type bfloat +(deftype bfloat (basic) + "Boxed (or basic?) float. Just a basic that wraps a single float." + ((data float) + ) + ) + +;; definition for method 3 of type bfloat +(defmethod inspect ((this bfloat)) + (when (not this) + (set! this this) + (goto cfg-4) + ) + (format #t "[~8x] ~A~%" this (-> this type)) + (format #t "~1Tdata: ~f~%" (-> this data)) + (label cfg-4) + this + ) + +;; definition for method 2 of type bfloat +(defmethod print ((this bfloat)) + (format #t "~f" (-> this data)) + this + ) + +;; definition for method 5 of type type +;; WARN: Return type mismatch uint vs int. +(defmethod asize-of ((this type)) + (the-as int (logand (the-as uint #xfffffff0) (+ (* (-> this allocated-length) 4) 43))) + ) + +;; definition for function basic-type? +(defun basic-type? ((obj basic) (typ type)) + "Return if the given basic is a given type. A child of the given type is also acceptable." + (let ((v1-0 (-> obj type)) + (a0-1 object) + ) + (until (= v1-0 a0-1) + (if (= v1-0 typ) + (return #t) + ) + (set! v1-0 (-> v1-0 parent)) + ) + ) + #f + ) + +;; definition for function type-type? +(defun type-type? ((check-type type) (parent-type type)) + "Return if the first type is the second type, or a child of it." + (let ((v1-0 object)) + (if (= parent-type v1-0) + (return #t) + ) + (until (or (= check-type v1-0) (zero? check-type)) + (if (= check-type parent-type) + (return #t) + ) + (set! check-type (-> check-type parent)) + ) + ) + #f + ) + +;; definition for function type? +;; WARN: Using new Jak 2 rtype-of +(defun type? ((obj object) (desired-type type)) + "Return if the given object is an instance of the given type. + Works on basics, bintegers, or symbols." + (let ((v1-0 object) + (a0-1 (rtype-of obj)) + ) + (if (= desired-type v1-0) + (return #t) + ) + (until (or (= a0-1 v1-0) (zero? a0-1)) + (if (= a0-1 desired-type) + (return #t) + ) + (set! a0-1 (-> a0-1 parent)) + ) + ) + #f + ) + +;; definition for function find-parent-method +(defun find-parent-method ((typ type) (method-id int)) + "Find the closest parent type that has a different implementation of the given method and return that method. + If it does not exist, return `nothing` function. + This is used to implement call-parent-method." + (local-vars (v0-0 function)) + (let ((v1-2 (-> typ method-table method-id))) + (until (!= v0-0 v1-2) + (if (= typ object) + (return nothing) + ) + (set! typ (-> typ parent)) + (set! v0-0 (-> typ method-table method-id)) + (if (zero? v0-0) + (return nothing) + ) + ) + ) + v0-0 + ) + +;; definition for function ref& +(defun ref& ((list object) (idx int)) + "Return the n-th pair in a linked list of pairs. No bounds checking. + If it is the null pair, return #f." + (dotimes (v1-0 idx) + (nop!) + (nop!) + (set! list (cdr list)) + ) + (if (null? list) + #f + list + ) + ) + +;; definition for function ref +(defun ref ((list object) (idx int)) + "Return the n-th item in a proper list. No bounds checking." + (dotimes (v1-0 idx) + (nop!) + (nop!) + (set! list (cdr list)) + ) + (car list) + ) + +;; definition for method 4 of type pair +(defmethod length ((this pair)) + (local-vars (v0-0 int)) + (cond + ((null? this) + (set! v0-0 0) + ) + (else + (let ((v1-1 (cdr this))) + (set! v0-0 1) + (while (and (not (null? v1-1)) (pair? v1-1)) + (+! v0-0 1) + (set! v1-1 (cdr v1-1)) + ) + ) + ) + ) + v0-0 + ) + +;; definition for method 5 of type pair +;; WARN: Return type mismatch uint vs int. +(defmethod asize-of ((this pair)) + (the-as int (-> pair size)) + ) + +;; definition for function last +(defun last ((list object)) + "Return the last object in a proper list." + (let ((v0-0 list)) + (while (not (null? (cdr v0-0))) + (nop!) + (nop!) + (set! v0-0 (cdr v0-0)) + ) + v0-0 + ) + ) + +;; definition for function member +(defun member ((obj-to-find object) (list object)) + "See if the first argument is in the proper list of the second argument. + Checked with simple equality. + If so, return the list starting at the at point (a truthy value). + Otherwise, return #f. + (member 'b '(a b c)) -> (b c d). + (member 'w '(a b c)) -> #f" + (let ((v1-0 list)) + (while (not (or (null? v1-0) (= (car v1-0) obj-to-find))) + (set! v1-0 (cdr v1-0)) + ) + (if (not (null? v1-0)) + v1-0 + ) + ) + ) + +;; definition for function nmember +(defun nmember ((obj-to-find basic) (list object)) + "Like member, but membership is checked with the name= function to handle symbols or strings." + (while (not (or (null? list) (name= (car list) obj-to-find))) + (set! list (cdr list)) + ) + (if (not (null? list)) + list + ) + ) + +;; definition for function assoc +(defun assoc ((key object) (assoc-list object)) + "Search an association list for given object. Return #f if not found, otherwise the element with matching car. + (assoc 'a '((a . 1) (b . 2) (c . 3))) -> (a . 1) + (assoc 'x '((a . 1) (b . 2) (c . 3))) -> #f" + (let ((v1-0 assoc-list)) + (while (not (or (null? v1-0) (= (car (car v1-0)) key))) + (set! v1-0 (cdr v1-0)) + ) + (if (not (null? v1-0)) + (car v1-0) + ) + ) + ) + +;; definition for function assoce +(defun assoce ((key object) (assoc-list object)) + "Like assoc, but supports a special `else` key which is always considered a match." + (let ((v1-0 assoc-list)) + (while (not (or (null? v1-0) (= (car (car v1-0)) key) (= (car (car v1-0)) 'else))) + (set! v1-0 (cdr v1-0)) + ) + (if (not (null? v1-0)) + (car v1-0) + ) + ) + ) + +;; definition for function nassoc +(defun nassoc ((key string) (assoc-list object)) + "Like assoc, but uses name= instead of = to check equality." + (while (not (or (null? assoc-list) (let ((a1-1 (car (car assoc-list)))) + (if (pair? a1-1) + (nmember key a1-1) + (name= a1-1 key) + ) + ) + ) + ) + (set! assoc-list (cdr assoc-list)) + ) + (if (not (null? assoc-list)) + (car assoc-list) + ) + ) + +;; definition for function nassoce +(defun nassoce ((key string) (assoc-list object)) + "Like assoce, but uses name= instead of = to check equality." + (while (not (or (null? assoc-list) (let ((s4-0 (car (car assoc-list)))) + (if (pair? s4-0) + (nmember key s4-0) + (or (name= s4-0 key) (= s4-0 'else)) + ) + ) + ) + ) + (set! assoc-list (cdr assoc-list)) + ) + (if (not (null? assoc-list)) + (car assoc-list) + ) + ) + +;; definition for function append! +(defun append! ((list object) (new-obj object)) + "Append the second argument to the end of the list (or empty pair) in the first argument." + (cond + ((null? list) + new-obj + ) + (else + (let ((v1-1 list)) + (while (not (null? (cdr v1-1))) + (nop!) + (nop!) + (set! v1-1 (cdr v1-1)) + ) + (if (not (null? v1-1)) + (set! (cdr v1-1) new-obj) + ) + ) + list + ) + ) + ) + +;; definition for function delete! +;; WARN: Return type mismatch object vs pair. +(defun delete! ((obj object) (list object)) + "Remove an element from the given list, return the list." + (the-as pair (cond + ((= obj (car list)) + (cdr list) + ) + (else + (let ((v1-1 list) + (a2-0 (cdr list)) + ) + (while (not (or (null? a2-0) (= (car a2-0) obj))) + (set! v1-1 a2-0) + (set! a2-0 (cdr a2-0)) + ) + (if (not (null? a2-0)) + (set! (cdr v1-1) (cdr a2-0)) + ) + ) + list + ) + ) + ) + ) + +;; definition for function delete-car! +(defun delete-car! ((car-to-match object) (list object)) + "Remove an element from the given list with a matching car. Return the list." + (cond + ((= car-to-match (car (car list))) + (cdr list) + ) + (else + (let ((v1-2 list) + (a2-0 (cdr list)) + ) + (while (not (or (null? a2-0) (= (car (car a2-0)) car-to-match))) + (set! v1-2 a2-0) + (set! a2-0 (cdr a2-0)) + ) + (if (not (null? a2-0)) + (set! (cdr v1-2) (cdr a2-0)) + ) + ) + list + ) + ) + ) + +;; definition for function insert-cons! +(defun insert-cons! ((new-obj object) (list object)) + "Update an association list to have the given (key . value) pair. + If a previous value exists, it is deleted first. + This function always allocates a pair through `cons` on the global heap, which can never be freed, + so it should almost never be used at runtime." + (let ((a3-0 (delete-car! (car new-obj) list))) + (cons new-obj a3-0) + ) + ) + +;; definition for function sort +(defun sort ((list pair) (compare-func (function object object object))) + "Sort a list using the given comparision function. + The function can return a #t/#f value, or a positive/negative value. + For example, you could use either `-` or `<` as functions to sort integers." + (let ((s4-0 -1)) + (while (nonzero? s4-0) + (set! s4-0 0) + (let ((s3-0 list)) + (while (not (or (null? (cdr s3-0)) (not (pair? (cdr s3-0))))) + (let* ((s2-0 (car s3-0)) + (s1-0 (car (cdr s3-0))) + (v1-1 (compare-func s2-0 s1-0)) + ) + (when (and (or (not v1-1) (> (the-as int v1-1) 0)) (!= v1-1 #t)) + (+! s4-0 1) + (set! (car s3-0) s1-0) + (set! (car (cdr s3-0)) s2-0) + ) + ) + (set! s3-0 (cdr s3-0)) + ) + ) + ) + ) + list + ) + +;; definition for function string->symbol-debug +(defun string->symbol-debug ((str string)) + "Convert a string to a symbol. The symbol must be known, and this cannot + create a new symbol. (in the PC port, it will still work.) + This is inteded to be used in debug only, and will not trigger a warning. + In debug, this will work for all symbols." + (let ((gp-0 *kernel-symbol-warnings*)) + (set! *kernel-symbol-warnings* #f) + (let ((v0-0 (string->symbol str))) + (set! *kernel-symbol-warnings* gp-0) + v0-0 + ) + ) + ) + +;; definition for function symbol->string-debug +(defun symbol->string-debug ((sym symbol)) + "Get the name of a symbol. This is intended to be used in debug only. + In debug, this will work for all symbols. (In PC port, this works always)" + (let ((gp-0 *kernel-symbol-warnings*)) + (set! *kernel-symbol-warnings* #f) + (let ((v0-0 (symbol->string sym))) + (set! *kernel-symbol-warnings* gp-0) + v0-0 + ) + ) + ) + +;; definition for function symbol->hash +;; WARN: Return type mismatch symbol vs int. +(defun symbol->hash ((sym symbol)) + "Convert a symbol to a unique integer value, which is just the symbol's address." + (the-as int sym) + ) + +;; definition for method 0 of type array +(defmethod new array ((allocation symbol) (type-to-make type) (arg0 type) (arg1 int)) + (let ((v0-1 (object-new + allocation + type-to-make + (the-as int (+ (-> type-to-make size) (* arg1 (if (type-type? arg0 number) + (the-as int (-> arg0 size)) + 4 + ) + ) + ) + ) + ) + ) + ) + (set! (-> v0-1 allocated-length) arg1) + (set! (-> v0-1 length) arg1) + (set! (-> v0-1 content-type) arg0) + v0-1 + ) + ) + +;; definition for method 2 of type array +;; INFO: Used lq/sq +(defmethod print ((this array)) + (format #t "#(") + (cond + ((type-type? (-> this content-type) integer) + (case (-> this content-type symbol) + (('int32) + (dotimes (s5-0 (-> this length)) + (format + #t + (if (zero? s5-0) + "~D" + " ~D" + ) + (-> (the-as (array int32) this) s5-0) + ) + ) + ) + (('uint32) + (dotimes (s5-1 (-> this length)) + (format + #t + (if (zero? s5-1) + "~D" + " ~D" + ) + (-> (the-as (array uint32) this) s5-1) + ) + ) + ) + (('int64) + (dotimes (s5-2 (-> this length)) + (format + #t + (if (zero? s5-2) + "~D" + " ~D" + ) + (-> (the-as (array int64) this) s5-2) + ) + ) + ) + (('uint64) + (dotimes (s5-3 (-> this length)) + (format + #t + (if (zero? s5-3) + "#x~X" + " #x~X" + ) + (-> (the-as (array uint64) this) s5-3) + ) + ) + ) + (('int8) + (dotimes (s5-4 (-> this length)) + (format + #t + (if (zero? s5-4) + "~D" + " ~D" + ) + (-> (the-as (array int8) this) s5-4) + ) + ) + ) + (('uint8) + (dotimes (s5-5 (-> this length)) + (format + #t + (if (zero? s5-5) + "~D" + " ~D" + ) + (-> (the-as (array uint8) this) s5-5) + ) + ) + ) + (('int16) + (dotimes (s5-6 (-> this length)) + (format + #t + (if (zero? s5-6) + "~D" + " ~D" + ) + (-> (the-as (array int16) this) s5-6) + ) + ) + ) + (('uint16) + (dotimes (s5-7 (-> this length)) + (format + #t + (if (zero? s5-7) + "~D" + " ~D" + ) + (-> (the-as (array uint16) this) s5-7) + ) + ) + ) + (('uint128 'int128) + (dotimes (s5-8 (-> this length)) + (format + #t + (if (zero? s5-8) + "#x~X" + " #x~X" + ) + (-> (the-as (array uint128) this) s5-8) + ) + ) + ) + (else + (dotimes (s5-9 (-> this length)) + (format + #t + (if (zero? s5-9) + "~D" + " ~D" + ) + (-> (the-as (array int32) this) s5-9) + ) + ) + ) + ) + ) + ((= (-> this content-type) float) + (dotimes (s5-10 (-> this length)) + (if (zero? s5-10) + (format #t "~f" (-> (the-as (array float) this) s5-10)) + (format #t " ~f" (-> (the-as (array float) this) s5-10)) + ) + ) + ) + (else + (dotimes (s5-11 (-> this length)) + (if (zero? s5-11) + (format #t "~A" (-> (the-as (array basic) this) s5-11)) + (format #t " ~A" (-> (the-as (array basic) this) s5-11)) + ) + ) + ) + ) + (format #t ")") + this + ) + +;; definition for method 3 of type array +;; INFO: Used lq/sq +(defmethod inspect ((this array)) + (format #t "[~8x] ~A~%" this (-> this type)) + (format #t "~Tallocated-length: ~D~%" (-> this allocated-length)) + (format #t "~Tlength: ~D~%" (-> this length)) + (format #t "~Tcontent-type: ~A~%" (-> this content-type)) + (format #t "~Tdata[~D]: @ #x~X~%" (-> this allocated-length) (-> this data)) + (cond + ((and (= (logand (the-as int (-> this content-type)) 7) 4) (type-type? (-> this content-type) integer)) + (case (-> this content-type symbol) + (('int32) + (dotimes (s5-0 (-> this length)) + (format #t "~T [~D] ~D~%" s5-0 (-> (the-as (array int32) this) s5-0)) + ) + ) + (('uint32) + (dotimes (s5-1 (-> this length)) + (format #t "~T [~D] ~D~%" s5-1 (-> (the-as (array uint32) this) s5-1)) + ) + ) + (('int64) + (dotimes (s5-2 (-> this length)) + (format #t "~T [~D] ~D~%" s5-2 (-> (the-as (array int64) this) s5-2)) + ) + ) + (('uint64) + (dotimes (s5-3 (-> this length)) + (format #t "~T [~D] #x~X~%" s5-3 (-> (the-as (array uint64) this) s5-3)) + ) + ) + (('int8) + (dotimes (s5-4 (-> this length)) + (format #t "~T [~D] ~D~%" s5-4 (-> (the-as (array int8) this) s5-4)) + ) + ) + (('uint8) + (dotimes (s5-5 (-> this length)) + (format #t "~T [~D] ~D~%" s5-5 (-> (the-as (array int8) this) s5-5)) + ) + ) + (('int16) + (dotimes (s5-6 (-> this length)) + (format #t "~T [~D] ~D~%" s5-6 (-> (the-as (array int16) this) s5-6)) + ) + ) + (('uint16) + (dotimes (s5-7 (-> this length)) + (format #t "~T [~D] ~D~%" s5-7 (-> (the-as (array uint16) this) s5-7)) + ) + ) + (('int128 'uint128) + (dotimes (s5-8 (-> this length)) + (format #t "~T [~D] #x~X~%" s5-8 (-> (the-as (array uint128) this) s5-8)) + ) + ) + (else + (dotimes (s5-9 (-> this length)) + (format #t "~T [~D] ~D~%" s5-9 (-> (the-as (array int32) this) s5-9)) + ) + ) + ) + ) + ((= (-> this content-type) float) + (dotimes (s5-10 (-> this length)) + (format #t "~T [~D] ~f~%" s5-10 (-> (the-as (array float) this) s5-10)) + ) + ) + (else + (dotimes (s5-11 (-> this length)) + (format #t "~T [~D] ~A~%" s5-11 (-> (the-as (array basic) this) s5-11)) + ) + ) + ) + this + ) + +;; definition for method 4 of type array +(defmethod length ((this array)) + (-> this length) + ) + +;; definition for method 5 of type array +;; WARN: Return type mismatch uint vs int. +(defmethod asize-of ((this array)) + (the-as + int + (+ (-> this type size) (* (-> this allocated-length) (if (type-type? (-> this content-type) number) + (the-as int (-> this content-type size)) + 4 + ) + ) + ) + ) + ) + +;; definition for function mem-copy! +(defun mem-copy! ((dst pointer) (src pointer) (bytes int)) + "Basic memory copy. This is not an optimized implementation." + (let ((v0-0 dst)) + (dotimes (v1-0 bytes) + (set! (-> (the-as (pointer uint8) dst)) (-> (the-as (pointer uint8) src))) + (&+! dst 1) + (&+! src 1) + ) + v0-0 + ) + ) + +;; definition for function qmem-copy<-! +;; INFO: Used lq/sq +(defun qmem-copy<-! ((dst pointer) (src pointer) (qwc int)) + "Copy memory by quadword (16-bytes). Must by 16-byte aligned, size in 16-byte units. Increasing address copy. Not an optimized version." + (let ((v0-0 dst)) + (countdown (v1-1 (/ (+ qwc 15) 16)) + (set! (-> (the-as (pointer uint128) dst)) (-> (the-as (pointer uint128) src))) + (&+! dst 16) + (&+! src 16) + ) + v0-0 + ) + ) + +;; definition for function qmem-copy->! +;; INFO: Used lq/sq +(defun qmem-copy->! ((dst pointer) (src pointer) (qwc int)) + "Copy memory by quadword (16-bytes). Must by 16-byte aligned, size in 16-byte units. Decreasing address copy. Not an optimized version." + (let ((v0-0 dst)) + (let* ((v1-1 (/ (+ qwc 15) 16)) + (a0-1 (&+ dst (* v1-1 16))) + (a1-1 (&+ src (* v1-1 16))) + ) + (while (nonzero? v1-1) + (+! v1-1 -1) + (&+! a0-1 -16) + (&+! a1-1 -16) + (set! (-> (the-as (pointer uint128) a0-1)) (-> (the-as (pointer uint128) a1-1))) + ) + ) + v0-0 + ) + ) + +;; definition for function qmem-clear! +;; INFO: Used lq/sq +(defun qmem-clear! ((dst pointer) (qwc int)) + "Clear memory by quadword (16-bytes). Must by 16-byte aligned, size in 16-byte units. Not an optimized version." + (let ((v0-0 dst)) + (dotimes (v1-0 qwc) + (set! (-> (the-as (pointer int128) dst)) 0) + (&+! dst 16) + ) + v0-0 + ) + ) + +;; definition for function mem-set32! +(defun mem-set32! ((dst pointer) (word-count int) (value int)) + "Set memory to the given 32-bit value, repeated n times. (like C memset, but setting int32_t instead of char). + Not an optimized implementation. Must be 4-byte aligned." + (let ((v0-0 dst)) + (dotimes (v1-0 word-count) + (set! (-> (the-as (pointer int32) dst)) value) + (&+! dst 4) + (nop!) + ) + v0-0 + ) + ) + +;; definition for function mem-or! +(defun mem-or! ((dst pointer) (src pointer) (bytes int)) + "Set the destiation to `dest = dest | src`. Size in bytes. Not an optimized version." + (let ((v0-0 dst)) + (dotimes (v1-0 bytes) + (logior! (-> (the-as (pointer uint8) dst)) (-> (the-as (pointer uint8) src))) + (&+! dst 1) + (&+! src 1) + ) + v0-0 + ) + ) + +;; definition for function quad-copy! +;; ERROR: function was not converted to expressions. Cannot decompile. + +;; definition of type inline-array-class +(deftype inline-array-class (basic) + "Base class for basic inline arrays. +The stride is stored in the heap-base of the inline-array-class child class." + ((length int32) + (allocated-length int32) + (_data uint8 :dynamic :offset 16) + ) + (:methods + (new (symbol type int) _type_) + (push-back (_type_ object) int) + (inline-array-class-method-10 () none) + (clear-1 (_type_) symbol) + (clear-2 (_type_) none) + (pop-front (_type_ int) pointer) + ) + ) + +;; definition for method 3 of type inline-array-class +(defmethod inspect ((idx-to-remove inline-array-class)) + (when (not idx-to-remove) + (set! idx-to-remove idx-to-remove) + (goto cfg-4) + ) + (format #t "[~8x] ~A~%" idx-to-remove (-> idx-to-remove type)) + (format #t "~1Tlength: ~D~%" (-> idx-to-remove length)) + (format #t "~1Tallocated-length: ~D~%" (-> idx-to-remove allocated-length)) + (label cfg-4) + idx-to-remove + ) + +;; definition of type inline-array-class-uint64 +(deftype inline-array-class-uint64 (inline-array-class) + "Specialization of inline-array-class for uint64. It's unclear why +this would be preferred over a normal (array uint64), since both store data the same way." + ((data uint64 :dynamic :offset 16) + ) + ) + +;; definition for method 3 of type inline-array-class-uint64 +(defmethod inspect ((this inline-array-class-uint64)) + (when (not this) + (set! this this) + (goto cfg-4) + ) + (format #t "[~8x] ~A~%" this (-> this type)) + (format #t "~1Tlength: ~D~%" (-> this length)) + (format #t "~1Tallocated-length: ~D~%" (-> this allocated-length)) + (label cfg-4) + this + ) + +;; definition of type inline-array-class-uint32 +(deftype inline-array-class-uint32 (inline-array-class) + "Specialization of inline-array-class for uint32. It's unclear why this would be preferred +over a normal (array uint32), since both store data the same way." + ((data uint32 :dynamic :offset 16) + ) + ) + +;; definition for method 3 of type inline-array-class-uint32 +(defmethod inspect ((this inline-array-class-uint32)) + (when (not this) + (set! this this) + (goto cfg-4) + ) + (format #t "[~8x] ~A~%" this (-> this type)) + (format #t "~1Tlength: ~D~%" (-> this length)) + (format #t "~1Tallocated-length: ~D~%" (-> this allocated-length)) + (label cfg-4) + this + ) + +;; definition for method 0 of type inline-array-class +(defmethod new inline-array-class ((allocation symbol) (type-to-make type) (count int)) + (let ((v0-0 (object-new + allocation + type-to-make + (the-as int (+ (-> type-to-make size) (* (the-as uint count) (-> type-to-make heap-base)))) + ) + ) + ) + (when (nonzero? v0-0) + (set! (-> v0-0 length) count) + (set! (-> v0-0 allocated-length) count) + ) + v0-0 + ) + ) + +;; definition for method 4 of type inline-array-class +(defmethod length ((this inline-array-class)) + (-> this length) + ) + +;; definition for method 5 of type inline-array-class +;; WARN: Return type mismatch uint vs int. +(defmethod asize-of ((this inline-array-class)) + (the-as int (+ (-> this type size) (* (-> this allocated-length) (the-as int (-> this type heap-base))))) + ) + +;; definition for method 9 of type inline-array-class +(defmethod push-back ((object-to-insert inline-array-class) (arg0 object)) + "Copy object to the end, then increment length. No bounds check." + (let ((s5-0 (-> object-to-insert length))) + (let ((a2-0 (-> object-to-insert type heap-base))) + (mem-copy! + (the-as + pointer + (+ (+ (* s5-0 (the-as int (-> object-to-insert type heap-base))) -4 (-> object-to-insert type size)) + (the-as int object-to-insert) + ) + ) + (the-as pointer arg0) + (the-as int a2-0) + ) + ) + (+! (-> object-to-insert length) 1) + s5-0 + ) + ) + +;; definition for method 9 of type inline-array-class-uint32 +(defmethod push-back ((this inline-array-class-uint32) (arg0 object)) + "Copy object to the end, then increment length. No bounds check." + (let ((v0-0 (-> this length))) + (-> this type heap-base) + (set! (-> (the-as + (pointer int32) + (+ (+ (* v0-0 (the-as int (-> this type heap-base))) -4 (-> this type size)) (the-as int this)) + ) + ) + arg0 + ) + (+! (-> this length) 1) + v0-0 + ) + ) + +;; definition for method 9 of type inline-array-class-uint64 +(defmethod push-back ((this inline-array-class-uint64) (arg0 object)) + "Copy object to the end, then increment length. No bounds check." + (let ((v0-0 (-> this length))) + (-> this type heap-base) + (set! (-> (the-as + (pointer int64) + (+ (+ (* v0-0 (the-as int (-> this type heap-base))) -4 (-> this type size)) (the-as int this)) + ) + ) + arg0 + ) + (+! (-> this length) 1) + v0-0 + ) + ) + +;; definition for method 13 of type inline-array-class +(defmethod pop-front ((this inline-array-class) (arg0 int)) + "Remove first object by copying last object to the front, then decrement length." + (+! (-> this length) -1) + (+ (-> this length) -1) + (let ((a2-0 (-> this type heap-base)) + (t9-0 mem-copy!) + (v1-10 (+ (+ (* (the-as uint arg0) (-> this type heap-base)) -4 (-> this type size)) (the-as uint this))) + (a1-4 (-> this type heap-base)) + ) + (t9-0 + (the-as pointer v1-10) + (the-as pointer (+ (+ (* (-> this length) (the-as int a1-4)) -4 (-> this type size)) (the-as int this))) + (the-as int a2-0) + ) + ) + ) + +;; definition for method 13 of type inline-array-class-uint64 +;; WARN: Return type mismatch uint vs pointer. +(defmethod pop-front ((this inline-array-class-uint64) (arg0 int)) + "Remove first object by copying last object to the front, then decrement length." + (+! (-> this length) -1) + (+ (-> this length) -1) + (-> this type heap-base) + (let* ((v1-7 (-> this type heap-base)) + (v0-0 (-> (the-as + (pointer uint64) + (+ (+ (* (-> this length) (the-as int v1-7)) -4 (-> this type size)) (the-as int this)) + ) + ) + ) + ) + (set! (-> (the-as + (pointer uint64) + (+ (+ (* (the-as uint arg0) (-> this type heap-base)) -4 (-> this type size)) (the-as uint this)) + ) + ) + v0-0 + ) + (the-as pointer v0-0) + ) + ) + +;; definition for method 13 of type inline-array-class-uint32 +;; WARN: Return type mismatch uint vs pointer. +(defmethod pop-front ((this inline-array-class-uint32) (arg0 int)) + "Remove first object by copying last object to the front, then decrement length." + (+! (-> this length) -1) + (+ (-> this length) -1) + (-> this type heap-base) + (let* ((v1-7 (-> this type heap-base)) + (v0-0 (-> (the-as + (pointer uint32) + (+ (+ (* (-> this length) (the-as int v1-7)) -4 (-> this type size)) (the-as int this)) + ) + ) + ) + ) + (set! (-> (the-as + (pointer uint32) + (+ (+ (* (the-as uint arg0) (-> this type heap-base)) -4 (-> this type size)) (the-as uint this)) + ) + ) + v0-0 + ) + (the-as pointer v0-0) + ) + ) + +;; definition for method 12 of type inline-array-class +;; WARN: Return type mismatch int vs none. +(defmethod clear-2 ((this inline-array-class)) + "Set length to 0" + (set! (-> this length) 0) + 0 + (none) + ) + +;; definition for method 11 of type inline-array-class +(defmethod clear-1 ((this inline-array-class)) + "Set length to 0, return #t." + (set! (-> this length) 0) + #t + ) + +;; definition for function fact +(defun fact ((x int)) + "Factorial." + (if (= x 1) + 1 + (* x (fact (+ x -1))) + ) + ) + +;; definition for symbol *print-column*, type binteger +(define *print-column* (the-as binteger 0)) + +;; definition for function print +;; WARN: Using new Jak 2 rtype-of +(defun print ((obj object)) + "Print any boxed object (symbol, pair, basic, binteger) to #t (the REPL). No newline." + ((method-of-type (rtype-of obj) print) obj) + ) + +;; definition for function printl +;; WARN: Using new Jak 2 rtype-of +(defun printl ((obj object)) + "Print any boxed object (symbol, pair, basic, binteger) to #t (the REPL), followed by a newline." + (let ((a0-1 obj)) + ((method-of-type (rtype-of a0-1) print) a0-1) + ) + (format #t "~%") + obj + ) + +;; definition for function inspect +;; WARN: Using new Jak 2 rtype-of +(defun inspect ((obj object)) + "Inspect any boxed object (symbol, pair, basic, binteger) to #t (the REPL)." + ((method-of-type (rtype-of obj) inspect) obj) + ) + +;; definition (debug) for function mem-print +(defun-debug mem-print ((ptr (pointer uint32)) (word-count int)) + "Print out data in memory in hex." + (dotimes (s4-0 (/ word-count 4)) + (format + 0 + "~X: ~X ~X ~X ~X~%" + (&-> ptr (* s4-0 4)) + (-> ptr (* s4-0 4)) + (-> ptr (+ (* s4-0 4) 1)) + (-> ptr (+ (* s4-0 4) 2)) + (-> ptr (+ (* s4-0 4) 3)) + ) + ) + #f + ) + +;; definition for symbol *trace-list*, type pair +(define *trace-list* '()) + +;; definition for function print-tree-bitmask +(defun print-tree-bitmask ((mask int) (count int)) + "Print out ASCII-art tree structure, from a bitmask of nesting levels." + (dotimes (s4-0 count) + (if (not (logtest? mask 1)) + (format #t " ") + (format #t "| ") + ) + (set! mask (shr mask 1)) + ) + #f + ) + +;; definition for function breakpoint-range-set! +;; ERROR: Unsupported inline assembly instruction kind - [mtdab a1] +;; ERROR: Unsupported inline assembly instruction kind - [mtdabm a2] +(defun breakpoint-range-set! ((arg0 uint) (arg1 uint) (arg2 uint)) + "Unsupported function to set a CPU breakpoint." + (.mtc0 Debug arg0) + (.mtdab arg1) + (.mtdabm arg2) + 0 + ) + +;; definition for function valid? +;; WARN: Using new Jak 2 rtype-of +;; WARN: Using new Jak 2 rtype-of +;; WARN: Using new Jak 2 rtype-of +;; WARN: Using new Jak 2 rtype-of +;; WARN: Using new Jak 2 rtype-of +;; ERROR: Unsupported inline assembly instruction kind - [daddu v1, v1, s7] +;; ERROR: Unsupported inline assembly instruction kind - [daddu v1, v1, s7] +;; ERROR: Unsupported inline assembly instruction kind - [daddu v1, v1, s7] +;; ERROR: Unsupported inline assembly instruction kind - [daddu v1, v1, s7] +(defun valid? ((obj object) (expected-type type) (err-msg-str string) (allow-false symbol) (err-msg-dest object)) + (local-vars (v1-11 int) (v1-26 int) (v1-56 int) (v1-60 int) (s7-0 none)) + (let ((v1-1 + (and (>= (the-as uint obj) (the-as uint __START-OF-TABLE__)) (< (the-as uint obj) (the-as uint #x8000000))) + ) + ) + (cond + ((not expected-type) + (cond + ((logtest? (the-as int obj) 3) + (if err-msg-str + (format err-msg-dest "ERROR: object #x~X ~S is not a valid object (misaligned)~%" obj err-msg-str) + ) + #f + ) + ((not v1-1) + (if err-msg-str + (format err-msg-dest "ERROR: object #x~X ~S is not a valid object (bad address)~%" obj err-msg-str) + ) + #f + ) + (else + #t + ) + ) + ) + ((and allow-false (not obj)) + #t + ) + ((= expected-type structure) + (cond + ((logtest? (the-as int obj) 15) + (if err-msg-str + (format + err-msg-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%" + obj + err-msg-str + expected-type + ) + ) + #f + ) + ((or (not v1-1) (begin + (let ((v1-10 #x8000)) + (.daddu v1-11 v1-10 s7-0) + ) + (< (the-as uint obj) (the-as uint v1-11)) + ) + ) + (if err-msg-str + (format + err-msg-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%" + obj + err-msg-str + expected-type + ) + ) + #f + ) + (else + #t + ) + ) + ) + ((= expected-type pair) + (cond + ((not (pair? obj)) + (if err-msg-str + (format + err-msg-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%" + obj + err-msg-str + expected-type + ) + ) + #f + ) + ((not v1-1) + (if err-msg-str + (format + err-msg-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%" + obj + err-msg-str + expected-type + ) + ) + #f + ) + (else + #t + ) + ) + ) + ((= expected-type binteger) + (cond + ((not (logtest? (the-as int obj) 7)) + #t + ) + (else + (if err-msg-str + (format + err-msg-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%" + obj + err-msg-str + expected-type + ) + ) + #f + ) + ) + ) + ((or (= expected-type symbol) (= expected-type boolean)) + (cond + ((not (logtest? (the-as int obj) 1)) + (if err-msg-str + (format + err-msg-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%" + obj + err-msg-str + expected-type + ) + ) + #f + ) + ((or (not v1-1) (< (the-as int obj) (the-as int __START-OF-TABLE__)) (begin + (let ((v1-25 #x8000)) + (.daddu v1-26 v1-25 s7-0) + ) + (>= (the-as int obj) v1-26) + ) + ) + (if err-msg-str + (format + err-msg-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%" + obj + err-msg-str + expected-type + ) + ) + #f + ) + (else + #t + ) + ) + ) + ((!= (logand (the-as int obj) 7) 4) + (if err-msg-str + (format + err-msg-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%" + obj + err-msg-str + expected-type + ) + ) + #f + ) + ((not v1-1) + (if err-msg-str + (format + err-msg-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%" + obj + err-msg-str + expected-type + ) + ) + #f + ) + ((and (= expected-type type) (!= (rtype-of obj) type)) + (if err-msg-str + (format + err-msg-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (invalid type #x~X)~%" + obj + err-msg-str + expected-type + (rtype-of obj) + ) + ) + #f + ) + ((and (!= expected-type type) (not (valid? (rtype-of obj) type (the-as string #f) #t 0))) + (if err-msg-str + (format + err-msg-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (invalid type #x~X)~%" + obj + err-msg-str + expected-type + (rtype-of obj) + ) + ) + #f + ) + ((not (type? obj expected-type)) + (if err-msg-str + (format + err-msg-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (is type '~A' instead)~%" + obj + err-msg-str + expected-type + (rtype-of obj) + ) + ) + #f + ) + ((= expected-type symbol) + (let ((v1-55 #x8000)) + (.daddu v1-56 v1-55 s7-0) + ) + (cond + ((>= (the-as uint obj) (the-as uint v1-56)) + (if err-msg-str + (format + err-msg-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (not in symbol table)~%" + obj + err-msg-str + expected-type + ) + ) + #f + ) + (else + #t + ) + ) + ) + ((begin + (let ((v1-59 #x8000)) + (.daddu v1-60 v1-59 s7-0) + ) + (< (the-as uint obj) (the-as uint v1-60)) + ) + (if err-msg-str + (format + err-msg-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (inside symbol table)~%" + obj + err-msg-str + expected-type + ) + ) + #f + ) + (else + #t + ) + ) + ) + ) + +;; failed to figure out what this is: +0 diff --git a/test/offline/config/jak3/config.jsonc b/test/offline/config/jak3/config.jsonc index 586d8f430..b9eb17d50 100644 --- a/test/offline/config/jak3/config.jsonc +++ b/test/offline/config/jak3/config.jsonc @@ -7,6 +7,13 @@ "skip_compile_files": [], "skip_compile_functions": [ + // gcommon + "qmem-clear!", + "(method 9 inline-array-class-uint32)", + "(method 9 inline-array-class-uint64)", + "breakpoint-range-set!", + "valid?", + // math "logf", "log2f", diff --git a/test_no_filter.sh b/test_no_filter.sh new file mode 100755 index 000000000..03e27f415 --- /dev/null +++ b/test_no_filter.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +# Directory of this script +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + + $DIR/build/goalc-test --gtest_color=yes "$@"