diff --git a/common/link_types.h b/common/link_types.h index 4ea702a835..d1b9647985 100644 --- a/common/link_types.h +++ b/common/link_types.h @@ -53,3 +53,7 @@ struct LinkHeaderV4 { uint32_t version; // always 4 uint32_t code_size; // length of object data before link data starts }; + +// when a u32/s32 symbol link contains this value, (s7 + ) should be a 4-byte aligned address, +// not including the 1 byte symbol offset. (no effect in jak 1). +constexpr u32 LINK_SYM_NO_OFFSET_FLAG = 0xbadbeef; \ No newline at end of file diff --git a/common/symbols.h b/common/symbols.h index 0eae391907..1dc291dc14 100644 --- a/common/symbols.h +++ b/common/symbols.h @@ -83,7 +83,7 @@ constexpr int FIX_FIXED_SYM_END_OFFSET = 0x1d0; namespace jak2_symbols { constexpr int FIX_SYM_EMPTY_CAR = -0x8; -constexpr int FIX_SYM_EMPTY_PAIR = -0x6; +constexpr int S7_OFF_FIX_SYM_EMPTY_PAIR = -0x6 - 1; constexpr int FIX_SYM_EMPTY_CDR = -0x4; constexpr int FIX_SYM_FALSE = 0x0; // GOAL boolean #f (note that this is equal to the $s7 register) constexpr int FIX_SYM_TRUE = 0x4; // GOAL boolean #t @@ -169,6 +169,6 @@ constexpr int empty_pair_offset_from_s7(GameVersion version) { return jak1_symbols::FIX_SYM_EMPTY_PAIR; case GameVersion::Jak2: // minus 1 for the symbol table pointer's offset. - return jak2_symbols::FIX_SYM_EMPTY_PAIR - 1; + return jak2_symbols::S7_OFF_FIX_SYM_EMPTY_PAIR; } } \ No newline at end of file diff --git a/common/type_system/TypeSystem.cpp b/common/type_system/TypeSystem.cpp index 4b1ecd60bb..d9e8d2a1ba 100644 --- a/common/type_system/TypeSystem.cpp +++ b/common/type_system/TypeSystem.cpp @@ -967,7 +967,7 @@ int TypeSystem::add_field_to_type(StructureType* type, /*! * Add types which are built-in to GOAL. */ -void TypeSystem::add_builtin_types() { +void TypeSystem::add_builtin_types(GameVersion version) { // some of the basic types have confusing circular dependencies, so this is done manually. // there are no inlined things so its ok to do some things out of order because the actual size // doesn't really matter. @@ -978,7 +978,18 @@ void TypeSystem::add_builtin_types() { auto structure_type = add_builtin_structure("object", "structure"); auto basic_type = add_builtin_basic("structure", "basic"); - auto symbol_type = add_builtin_basic("basic", "symbol"); + StructureType* symbol_type; + switch (version) { + case GameVersion::Jak1: + symbol_type = add_builtin_basic("basic", "symbol"); + break; + case GameVersion::Jak2: + symbol_type = add_builtin_structure("object", "symbol", true); + symbol_type->override_offset(1); + break; + default: + ASSERT(false); + } auto type_type = add_builtin_basic("basic", "type"); auto string_type = add_builtin_basic("basic", "string"); string_type->set_final(); // no virtual calls used on string. @@ -1059,7 +1070,9 @@ void TypeSystem::add_builtin_types() { false); // SYMBOL - builtin_structure_inherit(symbol_type); + if (version == GameVersion::Jak1) { + builtin_structure_inherit(symbol_type); + } add_field_to_type(symbol_type, "value", make_typespec("object")); // a new method which returns type none means new is illegal. declare_method(symbol_type, "new", false, make_function_typespec({}, "none"), false); diff --git a/common/type_system/TypeSystem.h b/common/type_system/TypeSystem.h index c7a52165c7..054a065489 100644 --- a/common/type_system/TypeSystem.h +++ b/common/type_system/TypeSystem.h @@ -206,7 +206,7 @@ class TypeSystem { bool skip_in_static_decomp = false, double score = 0.0); - void add_builtin_types(); + void add_builtin_types(GameVersion version); std::string print_all_type_information() const; bool typecheck_and_throw(const TypeSpec& expected, diff --git a/decompiler/ObjectFile/ObjectFileDB.cpp b/decompiler/ObjectFile/ObjectFileDB.cpp index 17e129b084..cbf7a570af 100644 --- a/decompiler/ObjectFile/ObjectFileDB.cpp +++ b/decompiler/ObjectFile/ObjectFileDB.cpp @@ -117,7 +117,8 @@ ObjectFileDB::ObjectFileDB(const std::vector& _dgos, const fs::path& obj_file_name_map_file, const std::vector& object_files, const std::vector& str_files, - const Config& config) { + const Config& config) + : dts(config.game_version) { Timer timer; lg::info("-Loading types..."); diff --git a/decompiler/ObjectFile/ObjectFileDB_IR2.cpp b/decompiler/ObjectFile/ObjectFileDB_IR2.cpp index a1679c9d23..8840852f89 100644 --- a/decompiler/ObjectFile/ObjectFileDB_IR2.cpp +++ b/decompiler/ObjectFile/ObjectFileDB_IR2.cpp @@ -311,7 +311,7 @@ void ObjectFileDB::ir2_analyze_all_types(const fs::path& output_file, std::vector per_object; - DecompilerTypeSystem previous_game_ts; + DecompilerTypeSystem previous_game_ts(GameVersion::Jak1); // version here doesn't matter. if (previous_game_types) { previous_game_ts.parse_type_defs({*previous_game_types}); } diff --git a/decompiler/extractor/main.cpp b/decompiler/extractor/main.cpp index bc2109edad..5c0e61de43 100644 --- a/decompiler/extractor/main.cpp +++ b/decompiler/extractor/main.cpp @@ -42,7 +42,6 @@ std::tuple, ExtractorErrorCode> validate( return {std::nullopt, ExtractorErrorCode::VALIDATION_BAD_EXTRACTION}; } - std::optional error_code; const auto [serial, elf_hash] = findElfFile(extracted_iso_path); if (!serial || !elf_hash) { diff --git a/decompiler/util/DecompilerTypeSystem.cpp b/decompiler/util/DecompilerTypeSystem.cpp index 23e766bf7f..f1508acf57 100644 --- a/decompiler/util/DecompilerTypeSystem.cpp +++ b/decompiler/util/DecompilerTypeSystem.cpp @@ -10,8 +10,8 @@ #include "decompiler/Disasm/Register.h" namespace decompiler { -DecompilerTypeSystem::DecompilerTypeSystem() { - ts.add_builtin_types(); +DecompilerTypeSystem::DecompilerTypeSystem(GameVersion version) { + ts.add_builtin_types(version); } namespace { diff --git a/decompiler/util/DecompilerTypeSystem.h b/decompiler/util/DecompilerTypeSystem.h index 0eba85e1bd..c9da04a0fa 100644 --- a/decompiler/util/DecompilerTypeSystem.h +++ b/decompiler/util/DecompilerTypeSystem.h @@ -11,7 +11,7 @@ class TypeState; class DecompilerTypeSystem { public: - DecompilerTypeSystem(); + DecompilerTypeSystem(GameVersion version); TypeSystem ts; std::unordered_map symbol_types; std::unordered_set symbols; diff --git a/game/kernel/jak2/klink.cpp b/game/kernel/jak2/klink.cpp index f32f483f46..89377d1a2f 100644 --- a/game/kernel/jak2/klink.cpp +++ b/game/kernel/jak2/klink.cpp @@ -171,8 +171,10 @@ uint32_t symlink_v3(Ptr link, Ptr data) { if (*data_ptr == -1) { // a "-1" indicates that we should store the address. *(data + offset).cast() = sym_addr; + } else if (*(data_ptr.cast()) == LINK_SYM_NO_OFFSET_FLAG) { + *(data + offset).cast() = sym_offset - 1; } else { - // otherwise store the offset to st. Eventually this should become an s16 instead. + // otherwise store the offset to st. *(data + offset).cast() = sym_offset; } } diff --git a/game/kernel/jak2/klisten.cpp b/game/kernel/jak2/klisten.cpp index ea0c534881..2ea86c71f2 100644 --- a/game/kernel/jak2/klisten.cpp +++ b/game/kernel/jak2/klisten.cpp @@ -114,7 +114,7 @@ void ProcessListenerMessage(Ptr msg) { int sql_query_sync(Ptr string_in) { if (!MasterDebug) { // not debugging, no sql results. - return s7.offset + FIX_SYM_EMPTY_PAIR - 1; + return s7.offset + S7_OFF_FIX_SYM_EMPTY_PAIR; } else { // clear old result SqlResult->value() = s7.offset; diff --git a/game/kernel/jak2/kscheme.cpp b/game/kernel/jak2/kscheme.cpp index e51848e578..803acab56d 100644 --- a/game/kernel/jak2/kscheme.cpp +++ b/game/kernel/jak2/kscheme.cpp @@ -615,7 +615,7 @@ Ptr> find_symbol_from_c(const char* name) { // check if we've got the empty pair. if (hash == EMPTY_HASH) { if (!strcmp(name, "_empty_")) { - return (s7 + FIX_SYM_EMPTY_PAIR).cast>(); + return (s7 + S7_OFF_FIX_SYM_EMPTY_PAIR).cast>(); } } @@ -1115,7 +1115,8 @@ u64 print_object(u32 obj) { cprintf("#", obj); } else if ((obj & OFFSET_MASK) == PAIR_OFFSET) { return print_pair(obj); - } else if ((obj & 1) == PAIR_OFFSET && obj >= SymbolTable2.offset && obj < LastSymbol.offset) { + } else if ((obj & 1) == SYMBOL_OFFSET && obj >= SymbolTable2.offset && + obj < LastSymbol.offset) { return print_symbol(obj); } else if ((obj & OFFSET_MASK) == BASIC_OFFSET) { return call_method_of_type(obj, Ptr(*Ptr(obj - 4)), GOAL_PRINT_METHOD); @@ -1146,7 +1147,7 @@ u64 print_basic(u32 obj) { * Can print improper lists */ u64 print_pair(u32 obj) { - if (obj == s7.offset + FIX_SYM_EMPTY_PAIR) { + if (obj == s7.offset + S7_OFF_FIX_SYM_EMPTY_PAIR) { cprintf("()"); } else { // clang-format off @@ -1155,7 +1156,7 @@ u64 print_pair(u32 obj) { || ((obj & 7) != 2) // this object isn't a pair || *Ptr(obj - 2) != s7.offset + FIX_SYM_QUOTE // the car isn't 'quote || (*Ptr(obj + 2) & 7) != 2 // the cdr isn't a pair - || *Ptr(*Ptr(obj + 2) + 2) != s7.offset + FIX_SYM_EMPTY_PAIR // the cddr isn't '() + || *Ptr(*Ptr(obj + 2) + 2) != s7.offset + S7_OFF_FIX_SYM_EMPTY_PAIR // the cddr isn't '() ) { // clang-format on cprintf("("); @@ -1168,7 +1169,7 @@ u64 print_pair(u32 obj) { // load up CDR auto cdr = *Ptr(toPrint + 2); toPrint = cdr; - if (cdr == s7.offset + FIX_SYM_EMPTY_PAIR) { // end of proper list + if (cdr == s7.offset + S7_OFF_FIX_SYM_EMPTY_PAIR) { // end of proper list cprintf(")"); return obj; } else { // continue list @@ -1296,7 +1297,8 @@ u64 inspect_object(u32 obj) { cprintf("#", obj); } else if ((obj & OFFSET_MASK) == PAIR_OFFSET) { return inspect_pair(obj); - } else if ((obj & 1) == PAIR_OFFSET && obj >= SymbolTable2.offset && obj < LastSymbol.offset) { + } else if ((obj & 1) == SYMBOL_OFFSET && obj >= SymbolTable2.offset && + obj < LastSymbol.offset) { return inspect_symbol(obj); } else if ((obj & OFFSET_MASK) == BASIC_OFFSET) { return call_method_of_type(obj, Ptr(*Ptr(obj - BASIC_OFFSET)), @@ -1437,16 +1439,13 @@ int InitHeapAndSymbol() { SymbolTable2 = symbol_table + 5; s7 = symbol_table + 0x8001; NumSymbols = 0; - printf("st alloced\n"); // inform compiler of s7 reset_output(); - printf("reset output\n"); // empty pair (this is extra confusing). - *Ptr(s7.offset + FIX_SYM_EMPTY_CAR - 1) = s7.offset + FIX_SYM_EMPTY_PAIR - 1; - *Ptr(s7.offset + FIX_SYM_EMPTY_CDR - 1) = s7.offset + FIX_SYM_EMPTY_PAIR - 1; - printf("setup pair\n"); + *Ptr(s7.offset + FIX_SYM_EMPTY_CAR - 1) = s7.offset + S7_OFF_FIX_SYM_EMPTY_PAIR; + *Ptr(s7.offset + FIX_SYM_EMPTY_CDR - 1) = s7.offset + S7_OFF_FIX_SYM_EMPTY_PAIR; // 'global fixed_sym_set(FIX_SYM_GLOBAL_HEAP, kglobalheap.offset); @@ -1650,7 +1649,7 @@ int InitHeapAndSymbol() { make_function_symbol_from_c("loadb", (void*)loadb); make_function_symbol_from_c("loado", (void*)loado); make_function_symbol_from_c("unload", (void*)unload); - make_function_symbol_from_c("_format", (void*)format_impl_jak2); + make_stack_arg_function_symbol_from_c("_format", (void*)format_impl_jak2); make_function_symbol_from_c("malloc", (void*)alloc_heap_memory); make_function_symbol_from_c("kmalloc", (void*)goal_malloc); make_function_symbol_from_c("kmemopen", (void*)kmemopen); diff --git a/goal_src/goal-lib.gc b/goal_src/goal-lib.gc index bb71cc2c88..9242ed978c 100644 --- a/goal_src/goal-lib.gc +++ b/goal_src/goal-lib.gc @@ -691,36 +691,6 @@ `(,(if signed 'sar 'shr) (shl ,val (- 64 (+ ,size ,base))) (- 64 ,size)) ) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; TYPE STUFF -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defmacro basic? (obj) - ;; todo, make this more efficient - `(= 4 (logand (the integer ,obj) #b111)) - ) - -(defmacro pair? (obj) - ;; todo, make this more efficient - ;`(= 2 (logand (the integer ,obj) #b111)) - `(< (shl (the-as int ,obj) 62) 0) - ) - -(defmacro not-pair? (obj) - `(>= (shl (the-as int ,obj) 62) 0) - ) - -(defmacro binteger? (obj) - `(zero? (logand (the integer ,obj) #b111)) - ) - -(defmacro rtype-of (obj) - `(cond ((binteger? ,obj) binteger) - ((pair? ,obj) pair) - (else (-> (the basic ,obj) type)) - ) - ) - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; PAIR STUFF ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/goal_src/jak1/compiler-setup.gc b/goal_src/jak1/compiler-setup.gc index ad424e8b60..2c68a0018d 100644 --- a/goal_src/jak1/compiler-setup.gc +++ b/goal_src/jak1/compiler-setup.gc @@ -15,4 +15,34 @@ (defconstant *jak1-full-game* (__get_jak1_full_game)) (defmacro load-art-import (name) - `(asm-file ,(string-append "goal_src/jak1/import/" (symbol->string name) "-ag.gc") :no-code :no-throw)) \ No newline at end of file + `(asm-file ,(string-append "goal_src/jak1/import/" (symbol->string name) "-ag.gc") :no-code :no-throw)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; TYPE STUFF +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defmacro basic? (obj) + ;; todo, make this more efficient + `(= 4 (logand (the integer ,obj) #b111)) + ) + +(defmacro pair? (obj) + ;; todo, make this more efficient + ;`(= 2 (logand (the integer ,obj) #b111)) + `(< (shl (the-as int ,obj) 62) 0) + ) + +(defmacro not-pair? (obj) + `(>= (shl (the-as int ,obj) 62) 0) + ) + +(defmacro binteger? (obj) + `(zero? (logand (the integer ,obj) #b111)) + ) + +(defmacro rtype-of (obj) + `(cond ((binteger? ,obj) binteger) + ((pair? ,obj) pair) + (else (-> (the basic ,obj) type)) + ) + ) \ No newline at end of file diff --git a/goal_src/jak1/game.gp b/goal_src/jak1/game.gp index e3bc421a56..3c344a5515 100644 --- a/goal_src/jak1/game.gp +++ b/goal_src/jak1/game.gp @@ -71,6 +71,7 @@ ;; use defmacro to define goos macros. (define defmacro defsmacro) (define defun desfun) + ;;;;;;;;;;;;;;;;;;;;;;; ;; Build Groups ;;;;;;;;;;;;;;;;;;;;;;; diff --git a/goal_src/jak2/compiler-setup.gc b/goal_src/jak2/compiler-setup.gc index 2ce625a35e..c9cdac0ea9 100644 --- a/goal_src/jak2/compiler-setup.gc +++ b/goal_src/jak2/compiler-setup.gc @@ -6,5 +6,32 @@ ;; these types/functions are provided by Jak 2's runtime. (asm-file "goal_src/jak2/kernel-defs.gc") -;; load jak 1 project -(load-project "goal_src/jak2/game.gp") \ No newline at end of file +;; load jak 2 project +(load-project "goal_src/jak2/game.gp") + +(defmacro basic? (obj) + ;; todo, make this more efficient + `(= 4 (logand (the integer ,obj) #b111)) + ) + +(defmacro pair? (obj) + ;; todo, make this more efficient + ;`(= 2 (logand (the integer ,obj) #b111)) + `(< (shl (the-as int ,obj) 62) 0) + ) + +(defmacro not-pair? (obj) + `(>= (shl (the-as int ,obj) 62) 0) + ) + +(defmacro binteger? (obj) + `(zero? (logand (the integer ,obj) #b111)) + ) + +(defmacro rtype-of (obj) + `(cond ((binteger? ,obj) binteger) + ((pair? ,obj) pair) + ((basic? ,obj) (-> (the basic ,obj) type)) + (else symbol) + ) + ) \ No newline at end of file diff --git a/goal_src/jak2/game.gp b/goal_src/jak2/game.gp index e69de29bb2..911d56dc39 100644 --- a/goal_src/jak2/game.gp +++ b/goal_src/jak2/game.gp @@ -0,0 +1,176 @@ +;;-*-Lisp-*- + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Jak 2 Project File +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; see goal_src/jak1/game.gp for more detailed explanation + +;;;;;;;;;;;;;;;;;;;;;;; +;; Inputs from ISO +;;;;;;;;;;;;;;;;;;;;;;; + +(cond + ;; extractor can override everything by providing *use-iso-data-path* + (*use-iso-data-path* + (map-path! "$ISO" (string-append *iso-data* "/"))) + (#t + (map-path! "$ISO" "iso_data/jak2/"))) + +;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Inputs from decompiler +;;;;;;;;;;;;;;;;;;;;;;;;;; + +(map-path! "$DECOMP" "decompiler_out/jak2/") + +;;;;;;;;;;;;;;;;;;;;;;; +;; Output +;;;;;;;;;;;;;;;;;;;;;;; + +;; NOTE: the game itself will load from out/jak2/iso and out/jak2/fr3. +(map-path! "$OUT" "out/jak2/") + +;; tell the compiler to put its outputs in out/jak2/ +(set-output-prefix "jak2/") + +;; use defmacro to define goos macros. +(define defmacro defsmacro) +(define defun desfun) + +;;;;;;;;;;;;;;;;;;;;;;; +;; Build Groups +;;;;;;;;;;;;;;;;;;;;;;; + +(define *all-cgos* '()) +(define *all-str* '()) +(define *all-vis* '()) +(define *all-mus* '()) +(define *all-sbk* '()) +(define *all-vag* '()) +(define *all-gc* '()) + +;;;;;;;;;;;;;;;;;;;;;;; +;; Build system macros +;;;;;;;;;;;;;;;;;;;;;;; + +(defun gc-file->o-file (filename) + "Get the name of the object file for the given GOAL (*.gc) source file." + (string-append "$OUT/obj/" (stem filename) ".o") + ) + +(defmacro goal-src (src-file &rest deps) + "Add a GOAL source file with the given dependencies" + `(let ((output-file ,(gc-file->o-file src-file))) + (set! *all-gc* (cons output-file *all-gc*)) + (defstep :in ,(string-append "goal_src/jak2/" src-file) + ;; use goal compiler + :tool 'goalc + ;; will output the obj file + :out (list output-file) + ;; dependencies are the obj files + :dep '(,@(apply gc-file->o-file deps)) + ) + ) + ) + +(defun make-src-sequence-elt (current previous prefix) + "Helper for goal-src-sequence" + `(let ((output-file ,(gc-file->o-file current))) + (set! *all-gc* (cons output-file *all-gc*)) + (defstep :in ,(string-append "goal_src/jak2/" prefix current) + :tool 'goalc + :out (list output-file) + :dep '(,(gc-file->o-file previous)) + ) + ) + ) + +(defmacro goal-src-sequence (prefix &key (deps '()) &rest sequence) + "Add a sequence of GOAL files (each depending on the previous) in the given directory, + with all depending on the given deps." + (let* ((first-thing `(goal-src ,(string-append prefix (first sequence)) ,@deps)) + (result (cons first-thing '())) + (iter result)) + + (let ((prev (first sequence)) + (in-iter (rest sequence))) + + (while (not (null? in-iter)) + ;; (fmt #t "{} dep on {}\n" (first in-iter) prev) + (let ((next (make-src-sequence-elt (first in-iter) prev prefix))) + (set-cdr! iter (cons next '())) + (set! iter (cdr iter)) + ) + + (set! prev (car in-iter)) + (set! in-iter (cdr in-iter)) + ) + ) + + `(begin ,@result) + ) + ) + +(defun cgo (output-name desc-file-name) + "Add a CGO with the given output name (in $OUT/iso) and input name (in goal_src/jak2/dgos)" + (let ((out-name (string-append "$OUT/iso/" output-name))) + (defstep :in (string-append "goal_src/jak2/dgos/" desc-file-name) + :tool 'dgo + :out `(,out-name) + ) + (set! *all-cgos* (cons out-name *all-cgos*)) + ) + ) + +(defmacro group (name &rest stuff) + `(defstep :in "" + :tool 'group + :out '(,(string-append "GROUP:" name)) + :dep '(,@stuff)) + ) + +(defun group-list (name stuff) + (defstep :in "" + :tool 'group + :out `(,(string-append "GROUP:" name)) + :dep stuff) + ) + +;;;;;;;;;;;;;;;;; +;; GOAL Kernel +;;;;;;;;;;;;;;;;; + +;; These are set up with proper dependencies + +(goal-src "kernel/gcommon.gc") +(goal-src "kernel/gstring-h.gc") +(goal-src "kernel/gkernel-h.gc" + "gcommon" + "gstring-h") +(goal-src "kernel/gkernel.gc" + "gkernel-h") +(goal-src "kernel/pskernel.gc" + "gcommon" + "gkernel-h") +(goal-src "kernel/gstring.gc" + "gcommon" + "gstring-h") +(goal-src "kernel/dgo-h.gc") +(goal-src "kernel/gstate.gc" + "gkernel") + +(cgo "KERNEL.CGO" "kernel.gd") + +;;;;;;;;;;;;;;;;;;;;; +;; ISO Group +;;;;;;;;;;;;;;;;;;;;; +;; the iso group is a group of files built by the "(mi)" command. + +(group-list "iso" + `(,@(reverse *all-vis*) + ,@(reverse *all-str*) + ,@(reverse *all-sbk*) + ,@(reverse *all-mus*) + ,@(reverse *all-vag*) + ,@(reverse *all-cgos*)) + ) \ No newline at end of file diff --git a/goal_src/jak2/kernel-defs.gc b/goal_src/jak2/kernel-defs.gc index 265e0d2d2e..7c531d76b6 100644 --- a/goal_src/jak2/kernel-defs.gc +++ b/goal_src/jak2/kernel-defs.gc @@ -56,6 +56,16 @@ (define-extern *stratch-top* pointer) (define-extern zero-func (function int)) +;; InitHeapAndSymbol +(define-extern _format (function _varargs_ object)) +(define-extern method-set! (function type int object none)) ;; may actually return function. + +(define-extern *enable-method-set* int) + +(define-extern *listener-function* (function object)) +(define-extern *debug-segment* symbol) + + (defenum kmalloc-flags :bitfield #t (align-16 4) @@ -74,4 +84,15 @@ (print-login 3) (force-debug 4) (fast-link 5) - ) \ No newline at end of file + ) + + +;; PC stuff +(defenum pc-prof-event + (begin 0) + (end 1) + (instant 2) + ) +(define-extern pc-prof (function string pc-prof-event none)) + + diff --git a/goal_src/jak2/kernel/gcommon.gc b/goal_src/jak2/kernel/gcommon.gc index dfc49e2d95..0d8ea9a33b 100644 --- a/goal_src/jak2/kernel/gcommon.gc +++ b/goal_src/jak2/kernel/gcommon.gc @@ -5,3 +5,956 @@ ;; name in dgo: gcommon ;; dgos: KERNEL +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Game constants +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; disable PS2 only code and enable PC-specific code +(defglobalconstant PC_PORT #t) + +;; whether we're allowed to use more memory than the original game or not +(defglobalconstant BIG_MEMORY #t) +(defglobalconstant PC_BIG_MEMORY (and PC_PORT BIG_MEMORY)) + +;; redirects access to EE memory mapped registers through get-vm-ptr to valid addresses that +;; are monitored in the runtime for debugging. +(defglobalconstant USE_VM #t) + +;; enables the with-profiler statements, which send profiling data from +;; GOAL code to the frame profiler in C++. +(defglobalconstant PC_PROFILER_ENABLE #t) + +(defun identity ((arg0 object)) + arg0 + ) + +(defun 1/ ((arg0 float)) + (declare (inline)) + (/ 1.0 arg0) + ) + +(defun + ((arg0 int) (arg1 int)) + (+ arg0 arg1) + ) + +(defun - ((arg0 int) (arg1 int)) + (- arg0 arg1) + ) + +(defun * ((arg0 int) (arg1 int)) + (* arg0 arg1) + ) + +(defun / ((arg0 int) (arg1 int)) + (/ arg0 arg1) + ) + +(defun mod ((arg0 int) (arg1 int)) + (mod arg0 arg1) + ) + +(defun rem ((arg0 int) (arg1 int)) + (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. + (declare (inline)) + (if (> shift-amount 0) + (shl value shift-amount) + (sar value (- shift-amount)) + ) + ) + +(defun abs ((a int)) + "Take the absolute value of an integer" + (declare (inline)) + ;; OpenGOAL doesn't support abs, so we implement it here. + (if (> a 0) + a + (- a) + ) + ) + +(defun min ((a int) (b int)) + "Compute minimum." + (declare (inline)) + ;; OpenGOAL doesn't support min, so we implement it here. + (if (> a b) b a) + ) + +(defun max ((a int) (b int)) + "Compute maximum." + (declare (inline)) + ;; OpenGOAL doesn't support max so we implement it here. + (if (> a b) a b) + ) + +(defun logior ((arg0 int) (arg1 int)) + (logior arg0 arg1) + ) + +(defun logand ((arg0 int) (arg1 int)) + (logand arg0 arg1) + ) + + +(defun lognor ((a int) (b int)) + "Compute not or." + ;; 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. + (declare (inline)) + (lognot (logior a b)) + ) + +(defun logxor ((arg0 int) (arg1 int)) + (logxor arg0 arg1) + ) + +(defun lognot ((arg0 int)) + (lognot arg0) + ) + +(defun false-func () + #f + ) + +(defun true-func () + #t + ) + +;;;;;;;;;;;;;;;;;;;;;;;;;; +;; format +;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define format _format) + +;;;;;;;;;;;;;;;;;;;;;;;;;; +;; numeric types +;;;;;;;;;;;;;;;;;;;;;;;;;; + +(deftype vec4s (uint128) + ((x float :offset 0 :size 32) + (y float :offset 32 :size 32) + (z float :offset 64 :size 32) + (w float :offset 96 :size 32) + ) + :method-count-assert 9 + :size-assert #x10 + :flag-assert #x900000010 + ) + +(defmethod inspect vec4s ((obj vec4s)) + (when (not obj) + (return obj) + ) + (format #t "[~8x] ~A~%" obj 'vec4s) + (format #t "~1Tx: ~f~%" (-> obj x)) + (format #t "~1Ty: ~f~%" (-> obj y)) + (format #t "~1Tz: ~f~%" (-> obj z)) + (format #t "~1Tw: ~f~%" (-> obj w)) + obj + ) + +(defmethod print vec4s ((obj vec4s)) + (format #t "#" + (-> obj x) + (-> obj y) + (-> obj z) + (-> obj w) + obj) + obj + ) + +(defmacro print128 (value &key (stream #t)) + "Print a 128-bit value" + `(let ((temp (new 'stack-no-clear 'array 'uint64 2))) + (set! (-> (the (pointer uint128) temp)) ,value) + (format ,stream "#x~16X~16X" (-> temp 1) (-> temp 0)) + ) + ) + +(defmacro make-u128 (upper lower) + "Make a i128 from two 64-bit values." + `(rlet ((result :class i128) + (upper-xmm :class i128) + (lower-xmm :class i128)) + (.mov upper-xmm ,upper) + (.mov lower-xmm ,lower) + (.pcpyld result upper-xmm lower-xmm) + (the-as uint result) + ) + ) + +(deftype bfloat (basic) + ((data float :offset-assert 4) + ) + :method-count-assert 9 + :size-assert #x8 + :flag-assert #x900000008 + ) + +(defmethod print bfloat ((obj bfloat)) + (format #t "~f" (-> obj data)) + obj + ) + +;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Type System +;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defmethod asize-of type ((obj type)) + (the-as int (logand (the-as uint #xfffffff0) (+ (* (-> obj allocated-length) 4) 43))) + ) + +(defun basic-type? ((arg0 basic) (arg1 type)) + (let ((v1-0 (-> arg0 type)) + (a0-1 object) + ) + (until (= v1-0 a0-1) + (if (= v1-0 arg1) + (return #t) + ) + (set! v1-0 (-> v1-0 parent)) + ) + ) + #f + ) + +(defun type-type? ((arg0 type) (arg1 type)) + (let ((v1-0 object)) + (if (= arg1 v1-0) + (return #t) + ) + (until (or (= arg0 v1-0) (zero? arg0)) + (if (= arg0 arg1) + (return #t) + ) + (set! arg0 (-> arg0 parent)) + ) + ) + #f + ) + +(defun type? ((arg0 object) (arg1 type)) + (let ((v1-0 object) + (a0-1 (rtype-of arg0)) + ) + (if (= arg1 v1-0) + (return #t) + ) + (until (or (= a0-1 v1-0) (zero? a0-1)) + (if (= a0-1 arg1) + (return #t) + ) + (set! a0-1 (-> a0-1 parent)) + ) + ) + #f + ) + +(defun find-parent-method ((arg0 type) (arg1 int)) + (local-vars (v0-0 function)) + (let ((v1-2 (-> arg0 method-table arg1))) + (until (!= v0-0 v1-2) + (if (= arg0 object) + (return nothing) + ) + (set! arg0 (-> arg0 parent)) + (set! v0-0 (-> arg0 method-table arg1)) + (if (zero? v0-0) + (return nothing) + ) + ) + ) + v0-0 + ) + +(defun ref ((arg0 object) (arg1 int)) + (dotimes (v1-0 arg1) + (nop!) + (nop!) + (set! arg0 (cdr arg0)) + ) + (car arg0) + ) + +(defmethod length pair ((obj pair)) + (local-vars (v0-0 int)) + (cond + ((null? obj) + (set! v0-0 0) + ) + (else + (let ((v1-1 (cdr obj))) + (set! v0-0 1) + (while (and (not (null? v1-1)) (pair? v1-1)) + (+! v0-0 1) + (set! v1-1 (cdr v1-1)) + ) + ) + ) + ) + v0-0 + ) + +(defmethod asize-of pair ((obj pair)) + (the-as int (-> pair size)) + ) + +(defun last ((arg0 object)) + (let ((v0-0 arg0)) + (while (not (null? (cdr v0-0))) + (nop!) + (nop!) + (set! v0-0 (cdr v0-0)) + ) + v0-0 + ) + ) + +(defun member ((arg0 object) (arg1 object)) + (let ((v1-0 arg1)) + (while (not (or (null? v1-0) (= (car v1-0) arg0))) + (set! v1-0 (cdr v1-0)) + ) + (if (not (null? v1-0)) + v1-0 + ) + ) + ) + +;; need to forward declare this, we haven't loaded the string library yet. +(define-extern name= (function basic basic symbol)) + +(defun nmember ((arg0 basic) (arg1 object)) + (while (not (or (null? arg1) (name= (the-as basic (car arg1)) arg0))) + (set! arg1 (cdr arg1)) + ) + (if (not (null? arg1)) + arg1 + ) + ) + +(defun assoc ((arg0 object) (arg1 object)) + (let ((v1-0 arg1)) + (while (not (or (null? v1-0) (= (car (car v1-0)) arg0))) + (set! v1-0 (cdr v1-0)) + ) + (if (not (null? v1-0)) + (car v1-0) + ) + ) + ) + +(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))) + (set! v1-0 (cdr v1-0)) + ) + (if (not (null? v1-0)) + (car v1-0) + ) + ) + ) + +(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= (the-as basic a1-1) arg0) + ) + ) + ) + ) + (set! arg1 (cdr arg1)) + ) + (if (not (null? arg1)) + (car arg1) + ) + ) + +(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= (the-as basic s4-0) arg0) (= s4-0 'else)) + ) + ) + ) + ) + (set! arg1 (cdr arg1)) + ) + (if (not (null? arg1)) + (car arg1) + ) + ) + +(defun append! ((arg0 object) (arg1 object)) + (cond + ((null? arg0) + arg1 + ) + (else + (let ((v1-1 arg0)) + (while (not (null? (cdr v1-1))) + (nop!) + (nop!) + (set! v1-1 (cdr v1-1)) + ) + (if (not (null? v1-1)) + (set! (cdr v1-1) arg1) + ) + ) + arg0 + ) + ) + ) + +(defun delete! ((arg0 object) (arg1 object)) + (the-as pair + (cond + ((= arg0 (car arg1)) + (cdr arg1) + ) + (else + (let ((v1-1 arg1) + (a2-0 (cdr arg1)) + ) + (while (not (or (null? a2-0) (= (car a2-0) arg0))) + (set! v1-1 a2-0) + (set! a2-0 (cdr a2-0)) + ) + (if (not (null? a2-0)) + (set! (cdr v1-1) (cdr a2-0)) + ) + ) + arg1 + ) + ) + ) + ) + +(defun delete-car! ((arg0 object) (arg1 object)) + (cond + ((= arg0 (car (car arg1))) + (cdr arg1) + ) + (else + (let ((v1-2 arg1) + (a2-0 (cdr arg1)) + ) + (while (not (or (null? a2-0) (= (car (car a2-0)) arg0))) + (set! v1-2 a2-0) + (set! a2-0 (cdr a2-0)) + ) + (if (not (null? a2-0)) + (set! (cdr v1-2) (cdr a2-0)) + ) + ) + arg1 + ) + ) + ) + +(defun insert-cons! ((arg0 object) (arg1 object)) + (let ((a3-0 (delete-car! (car arg0) arg1))) + (cons arg0 a3-0) + ) + ) + +(defun sort ((arg0 pair) (arg1 (function object object object))) + (let ((s4-0 -1)) + (while (nonzero? s4-0) + (set! s4-0 0) + (let ((s3-0 arg0)) + (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)) + ) + (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)) + ) + ) + ) + ) + arg0 + ) + +(deftype inline-array-class (basic) + ((length int32 :offset-assert 4) + (allocated-length int32 :offset-assert 8) + (_data uint8 :dynamic :offset 16) + ) + :method-count-assert 9 + :size-assert #x10 + :flag-assert #x900000010 + (:methods + (new (symbol type int) _type_ 0) + ) + ) + +(defmethod new inline-array-class ((allocation symbol) (type-to-make type) (arg0 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)))) + ) + ) + ) + (when (nonzero? v0-0) + (set! (-> v0-0 length) arg0) + (set! (-> v0-0 allocated-length) arg0) + ) + v0-0 + ) + ) + +(defmethod length inline-array-class ((obj inline-array-class)) + (-> obj length) + ) + +(defmethod asize-of inline-array-class ((obj inline-array-class)) + (the-as int (+ (-> obj type size) (* (-> obj allocated-length) (the-as int (-> obj type heap-base))))) + ) + +(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 + ) + ) + +(defmethod print array ((obj array)) + (format #t "#(") + (cond + ((type-type? (-> obj content-type) integer) + (case (-> obj content-type symbol) + (('int32) + (dotimes (s5-0 (-> obj length)) + (format + #t + (if (zero? s5-0) + "~D" + " ~D" + ) + (-> (the-as (array int32) obj) s5-0) + ) + ) + ) + (('uint32) + (dotimes (s5-1 (-> obj length)) + (format + #t + (if (zero? s5-1) + "~D" + " ~D" + ) + (-> (the-as (array uint32) obj) s5-1) + ) + ) + ) + (('int64) + (dotimes (s5-2 (-> obj length)) + (format + #t + (if (zero? s5-2) + "~D" + " ~D" + ) + (-> (the-as (array int64) obj) s5-2) + ) + ) + ) + (('uint64) + (dotimes (s5-3 (-> obj length)) + (format + #t + (if (zero? s5-3) + "#x~X" + " #x~X" + ) + (-> (the-as (array uint64) obj) s5-3) + ) + ) + ) + (('int8) + (dotimes (s5-4 (-> obj length)) + (format + #t + (if (zero? s5-4) + "~D" + " ~D" + ) + (-> (the-as (array int8) obj) s5-4) + ) + ) + ) + (('uint8) + (dotimes (s5-5 (-> obj length)) + (format + #t + (if (zero? s5-5) + "~D" + " ~D" + ) + (-> (the-as (array uint8) obj) s5-5) + ) + ) + ) + (('int16) + (dotimes (s5-6 (-> obj length)) + (format + #t + (if (zero? s5-6) + "~D" + " ~D" + ) + (-> (the-as (array int16) obj) s5-6) + ) + ) + ) + (('uint16) + (dotimes (s5-7 (-> obj length)) + (format + #t + (if (zero? s5-7) + "~D" + " ~D" + ) + (-> (the-as (array uint16) obj) s5-7) + ) + ) + ) + (('uint128 'int128) + (dotimes (s5-8 (-> obj length)) + (format + #t + (if (zero? s5-8) + "#x~X" + " #x~X" + ) + (-> (the-as (array uint128) obj) s5-8) + ) + ) + ) + (else + (dotimes (s5-9 (-> obj length)) + (format + #t + (if (zero? s5-9) + "~D" + " ~D" + ) + (-> (the-as (array int32) obj) s5-9) + ) + ) + ) + ) + ) + ((= (-> obj content-type) float) + (dotimes (s5-10 (-> obj length)) + (if (zero? s5-10) + (format #t "~f" (-> (the-as (array float) obj) s5-10)) + (format #t " ~f" (-> (the-as (array float) obj) s5-10)) + ) + ) + ) + (else + (dotimes (s5-11 (-> obj length)) + (if (zero? s5-11) + (format #t "~A" (-> (the-as (array basic) obj) s5-11)) + (format #t " ~A" (-> (the-as (array basic) obj) s5-11)) + ) + ) + ) + ) + (format #t ")") + obj + ) + +(defmethod inspect array ((obj array)) + (format #t "[~8x] ~A~%" obj (-> obj type)) + (format #t "~Tallocated-length: ~D~%" (-> obj allocated-length)) + (format #t "~Tlength: ~D~%" (-> obj length)) + (format #t "~Tcontent-type: ~A~%" (-> obj content-type)) + (format #t "~Tdata[~D]: @ #x~X~%" (-> obj allocated-length) (-> obj data)) + (cond + ((and (= (logand (the-as int (-> obj content-type)) 7) 4) (type-type? (-> obj content-type) integer)) + (case (-> obj content-type symbol) + (('int32) + (dotimes (s5-0 (-> obj length)) + (format #t "~T [~D] ~D~%" s5-0 (-> (the-as (array int32) obj) s5-0)) + ) + ) + (('uint32) + (dotimes (s5-1 (-> obj length)) + (format #t "~T [~D] ~D~%" s5-1 (-> (the-as (array uint32) obj) s5-1)) + ) + ) + (('int64) + (dotimes (s5-2 (-> obj length)) + (format #t "~T [~D] ~D~%" s5-2 (-> (the-as (array int64) obj) s5-2)) + ) + ) + (('uint64) + (dotimes (s5-3 (-> obj length)) + (format #t "~T [~D] #x~X~%" s5-3 (-> (the-as (array uint64) obj) s5-3)) + ) + ) + (('int8) + (dotimes (s5-4 (-> obj length)) + (format #t "~T [~D] ~D~%" s5-4 (-> (the-as (array int8) obj) s5-4)) + ) + ) + (('uint8) + (dotimes (s5-5 (-> obj length)) + (format #t "~T [~D] ~D~%" s5-5 (-> (the-as (array int8) obj) s5-5)) + ) + ) + (('int16) + (dotimes (s5-6 (-> obj length)) + (format #t "~T [~D] ~D~%" s5-6 (-> (the-as (array int16) obj) s5-6)) + ) + ) + (('uint16) + (dotimes (s5-7 (-> obj length)) + (format #t "~T [~D] ~D~%" s5-7 (-> (the-as (array uint16) obj) s5-7)) + ) + ) + (('int128 'uint128) + (dotimes (s5-8 (-> obj length)) + (format #t "~T [~D] #x~X~%" s5-8 (-> (the-as (array uint128) obj) s5-8)) + ) + ) + (else + (dotimes (s5-9 (-> obj length)) + (format #t "~T [~D] ~D~%" s5-9 (-> (the-as (array int32) obj) s5-9)) + ) + ) + ) + ) + ((= (-> obj content-type) float) + (dotimes (s5-10 (-> obj length)) + (format #t "~T [~D] ~f~%" s5-10 (-> (the-as (array float) obj) s5-10)) + ) + ) + (else + (dotimes (s5-11 (-> obj length)) + (format #t "~T [~D] ~A~%" s5-11 (-> (the-as (array basic) obj) s5-11)) + ) + ) + ) + obj + ) + +(defmethod length array ((obj array)) + (-> obj length) + ) + +(defmethod asize-of array ((obj array)) + (the-as + int + (+ (-> obj type size) (* (-> obj allocated-length) (if (type-type? (-> obj content-type) number) + (the-as int (-> obj content-type size)) + 4 + ) + ) + ) + ) + ) + +(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) + ) + 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) + ) + 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))) + ) + (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 + ) + ) + +(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) + (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) + ) + v0-0 + ) + ) + +(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)) + (none) + ) + +(defun-recursive fact int ((x int)) + (if (= x 1) + 1 + (* x (fact (+ x -1)))) + ) + +(define *print-column* (the-as binteger 0)) + +(defun print ((arg0 object)) + ((method-of-type (rtype-of arg0) print) arg0) + ) + +(defun printl ((arg0 object)) + (let ((a0-1 arg0)) + ((method-of-type (rtype-of a0-1) print) a0-1) + ) + (format #t "~%") + arg0 + ) + +(defun inspect ((arg0 object)) + ((method-of-type (rtype-of arg0) inspect) arg0) + ) + +(defun-debug mem-print ((arg0 (pointer uint32)) (arg1 int)) + (dotimes (s4-0 (/ arg1 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)) + ) + ) + #f + ) + +(define *trace-list* '()) + +(defun print-tree-bitmask ((arg0 int) (arg1 int)) + (dotimes (s4-0 arg1) + (if (zero? (logand arg0 1)) + (format #t " ") + (format #t "| ") + ) + (set! arg0 (shr arg0 1)) + ) + #f + ) + +(defun breakpoint-range-set! ((arg0 uint) (arg1 uint) (arg2 uint)) + (break!) + ) + +;;;;;;;;;;;;;;;;;;;; +;; Profiler Macros +;;;;;;;;;;;;;;;;;;;; + + +(defmacro profiler-instant-event (name) + "Record an 'instant' event in the profile. + This can be used however you'd like, but there should be a + 'ROOT' event logged every now and then (like once per frame) + when no timed events are in progress, to allow the profiler + to correctly recover the event stack." + `(#when PC_PROFILER_ENABLE + (pc-prof ,name (pc-prof-event instant)) + ) + ) + +(defmacro profiler-start-event (name) + "Start a timed event with the given name." + `(#when PC_PROFILER_ENABLE + (pc-prof ,name (pc-prof-event begin)) + ) + ) + +(defmacro profiler-end-event () + "End the most recently started event that hasn't been stopped yet. + It is up to you to correctly balance the starts/ends, otherwise + the profiling data will be corrupted." + `(#when PC_PROFILER_ENABLE + (pc-prof "" (pc-prof-event end)) + ) + ) + +(defmacro with-profiler (name &rest body) + "Execute the body in a named profiler block. + Do not `return` or `go` from inside this block, + otherwise the end will be skipped." + `(#if PC_PROFILER_ENABLE + (begin + (pc-prof ,name (pc-prof-event begin)) + ,@body + (pc-prof ,name (pc-prof-event end)) + ) + (begin + ,@body + ) + ) + ) \ No newline at end of file diff --git a/goal_src/jak2/kernel/gkernel-h.gc b/goal_src/jak2/kernel/gkernel-h.gc index 4891cebbfc..01392d94c5 100644 --- a/goal_src/jak2/kernel/gkernel-h.gc +++ b/goal_src/jak2/kernel/gkernel-h.gc @@ -5,3 +5,5 @@ ;; name in dgo: gkernel-h ;; dgos: KERNEL +(defconstant *kernel-major-version* 2) +(defconstant *kernel-minor-version* 0) \ No newline at end of file diff --git a/goal_src/jak2/kernel/gkernel.gc b/goal_src/jak2/kernel/gkernel.gc index cea5332f54..3aa2896f53 100644 --- a/goal_src/jak2/kernel/gkernel.gc +++ b/goal_src/jak2/kernel/gkernel.gc @@ -5,3 +5,30 @@ ;; name in dgo: gkernel ;; dgos: KERNEL +;; HACK kernel +(define *kernel-version* (the binteger (logior (ash *kernel-major-version* 16) *kernel-minor-version*))) +(define *use-old-listener-print* #f) + +(defun kernel-dispatcher () + "Run the kernel! + This is the entry point from C++ to GOAL." + + ;; outside of all profiler events, set a ROOT event + (profiler-instant-event "ROOT") + + ;; execute the listener function, if we got one. + (when *listener-function* + (+! *enable-method-set* 1) ;; allow out-of-order method definitions (slower) + ;; (let ((result (reset-and-call (-> *listener-process* main-thread) *listener-function*))) ;; run function! + (let ((result (*listener-function*))) + ;; print result. + (if *use-old-listener-print* + (format #t "~D~%" result result result) + (format #t "~D #x~X ~F ~A~%" result result result result) + ) + ) + ;; clear pending function + (set! *listener-function* #f) + (+! *enable-method-set* -1) + ) + ) \ No newline at end of file diff --git a/goalc/compiler/CodeGenerator.cpp b/goalc/compiler/CodeGenerator.cpp index 98be758210..15558dc47d 100644 --- a/goalc/compiler/CodeGenerator.cpp +++ b/goalc/compiler/CodeGenerator.cpp @@ -18,8 +18,8 @@ using namespace emitter; -CodeGenerator::CodeGenerator(FileEnv* env, DebugInfo* debug_info) - : m_fe(env), m_debug_info(debug_info) {} +CodeGenerator::CodeGenerator(FileEnv* env, DebugInfo* debug_info, GameVersion version) + : m_gen(version), m_fe(env), m_debug_info(debug_info) {} /*! * Generate an object file. diff --git a/goalc/compiler/CodeGenerator.h b/goalc/compiler/CodeGenerator.h index 958c197d7e..ad736de203 100644 --- a/goalc/compiler/CodeGenerator.h +++ b/goalc/compiler/CodeGenerator.h @@ -9,6 +9,8 @@ #include "Env.h" +#include "common/versions.h" + #include "goalc/emitter/ObjectGenerator.h" class DebugInfo; @@ -16,7 +18,7 @@ class TypeSystem; class CodeGenerator { public: - CodeGenerator(FileEnv* env, DebugInfo* debug_info); + CodeGenerator(FileEnv* env, DebugInfo* debug_info, GameVersion version); std::vector run(const TypeSystem* ts); emitter::ObjectGeneratorStats get_obj_stats() const { return m_gen.get_stats(); } diff --git a/goalc/compiler/Compiler.cpp b/goalc/compiler/Compiler.cpp index 60584de4e2..7a06f7f7b4 100644 --- a/goalc/compiler/Compiler.cpp +++ b/goalc/compiler/Compiler.cpp @@ -27,7 +27,7 @@ Compiler::Compiler(GameVersion version, m_repl(std::move(repl)), m_make(user_profile) { m_listener.add_debugger(&m_debugger); - m_ts.add_builtin_types(); + m_ts.add_builtin_types(m_version); m_global_env = std::make_unique(); m_none = std::make_unique(m_ts.make_typespec("none")); @@ -276,7 +276,7 @@ std::vector Compiler::codegen_object_file(FileEnv* env) { try { auto debug_info = &m_debugger.get_debug_info_for_object(env->name()); debug_info->clear(); - CodeGenerator gen(env, debug_info); + CodeGenerator gen(env, debug_info, m_version); bool ok = true; auto result = gen.run(&m_ts); for (auto& f : env->functions()) { @@ -299,7 +299,7 @@ bool Compiler::codegen_and_disassemble_object_file(FileEnv* env, std::string* asm_out) { auto debug_info = &m_debugger.get_debug_info_for_object(env->name()); debug_info->clear(); - CodeGenerator gen(env, debug_info); + CodeGenerator gen(env, debug_info, m_version); *data_out = gen.run(&m_ts); bool ok = true; *asm_out = debug_info->disassemble_all_functions(&ok, &m_goos.reader); diff --git a/goalc/compiler/IR.cpp b/goalc/compiler/IR.cpp index 0cf498fbcc..5d0972e0b3 100644 --- a/goalc/compiler/IR.cpp +++ b/goalc/compiler/IR.cpp @@ -9,7 +9,6 @@ #include "third-party/fmt/core.h" using namespace emitter; -using namespace jak1_symbols; // TODO jak 1 symbols namespace { Register get_reg(const RegVal* rv, const AllocationResult& allocs, emitter::IR_Record irec) { if (rv->rlet_constraint().has_value()) { @@ -239,12 +238,15 @@ void IR_LoadSymbolPointer::do_codegen(emitter::ObjectGenerator* gen, emitter::IR_Record irec) { auto dest_reg = get_reg(m_dest, allocs, irec); if (m_name == "#f") { - static_assert(FIX_SYM_FALSE == 0, "false symbol location"); + static_assert(false_symbol_offset() == 0, "false symbol location"); gen->add_instr(IGen::mov_gpr64_gpr64(dest_reg, gRegInfo.get_st_reg()), irec); } else if (m_name == "#t") { - gen->add_instr(IGen::lea_reg_plus_off8(dest_reg, gRegInfo.get_st_reg(), FIX_SYM_TRUE), irec); + gen->add_instr(IGen::lea_reg_plus_off8(dest_reg, gRegInfo.get_st_reg(), + true_symbol_offset(gen->version())), + irec); } else if (m_name == "_empty_") { - gen->add_instr(IGen::lea_reg_plus_off8(dest_reg, gRegInfo.get_st_reg(), FIX_SYM_EMPTY_PAIR), + gen->add_instr(IGen::lea_reg_plus_off8(dest_reg, gRegInfo.get_st_reg(), + empty_pair_offset_from_s7(gen->version())), irec); } else { auto instr = @@ -274,10 +276,10 @@ void IR_SetSymbolValue::do_codegen(emitter::ObjectGenerator* gen, const AllocationResult& allocs, emitter::IR_Record irec) { auto src_reg = get_reg(m_src, allocs, irec); - auto instr = - gen->add_instr(IGen::store32_gpr64_gpr64_plus_gpr64_plus_s32( - gRegInfo.get_st_reg(), gRegInfo.get_offset_reg(), src_reg, 0x0badbeef), - irec); + auto instr = gen->add_instr( + IGen::store32_gpr64_gpr64_plus_gpr64_plus_s32( + gRegInfo.get_st_reg(), gRegInfo.get_offset_reg(), src_reg, LINK_SYM_NO_OFFSET_FLAG), + irec); gen->link_instruction_symbol_mem(instr, m_dest->name()); } @@ -303,16 +305,16 @@ void IR_GetSymbolValue::do_codegen(emitter::ObjectGenerator* gen, emitter::IR_Record irec) { auto dst_reg = get_reg(m_dest, allocs, irec); if (m_sext) { - auto instr = - gen->add_instr(IGen::load32s_gpr64_gpr64_plus_gpr64_plus_s32( - dst_reg, gRegInfo.get_st_reg(), gRegInfo.get_offset_reg(), 0x0badbeef), - irec); + auto instr = gen->add_instr( + IGen::load32s_gpr64_gpr64_plus_gpr64_plus_s32( + dst_reg, gRegInfo.get_st_reg(), gRegInfo.get_offset_reg(), LINK_SYM_NO_OFFSET_FLAG), + irec); gen->link_instruction_symbol_mem(instr, m_src->name()); } else { - auto instr = - gen->add_instr(IGen::load32u_gpr64_gpr64_plus_gpr64_plus_s32( - dst_reg, gRegInfo.get_st_reg(), gRegInfo.get_offset_reg(), 0x0badbeef), - irec); + auto instr = gen->add_instr( + IGen::load32u_gpr64_gpr64_plus_gpr64_plus_s32( + dst_reg, gRegInfo.get_st_reg(), gRegInfo.get_offset_reg(), LINK_SYM_NO_OFFSET_FLAG), + irec); gen->link_instruction_symbol_mem(instr, m_src->name()); } } @@ -1379,16 +1381,16 @@ void IR_GetSymbolValueAsm::do_codegen(emitter::ObjectGenerator* gen, emitter::IR_Record irec) { auto dst_reg = m_use_coloring ? get_reg(m_dest, allocs, irec) : get_no_color_reg(m_dest); if (m_sext) { - auto instr = - gen->add_instr(IGen::load32s_gpr64_gpr64_plus_gpr64_plus_s32( - dst_reg, gRegInfo.get_st_reg(), gRegInfo.get_offset_reg(), 0x0badbeef), - irec); + auto instr = gen->add_instr( + IGen::load32s_gpr64_gpr64_plus_gpr64_plus_s32( + dst_reg, gRegInfo.get_st_reg(), gRegInfo.get_offset_reg(), LINK_SYM_NO_OFFSET_FLAG), + irec); gen->link_instruction_symbol_mem(instr, m_sym_name); } else { - auto instr = - gen->add_instr(IGen::load32u_gpr64_gpr64_plus_gpr64_plus_s32( - dst_reg, gRegInfo.get_st_reg(), gRegInfo.get_offset_reg(), 0x0badbeef), - irec); + auto instr = gen->add_instr( + IGen::load32u_gpr64_gpr64_plus_gpr64_plus_s32( + dst_reg, gRegInfo.get_st_reg(), gRegInfo.get_offset_reg(), LINK_SYM_NO_OFFSET_FLAG), + irec); gen->link_instruction_symbol_mem(instr, m_sym_name); } } diff --git a/goalc/emitter/ObjectGenerator.cpp b/goalc/emitter/ObjectGenerator.cpp index 40249f10e6..e8dd8786c1 100644 --- a/goalc/emitter/ObjectGenerator.cpp +++ b/goalc/emitter/ObjectGenerator.cpp @@ -25,6 +25,8 @@ namespace emitter { +ObjectGenerator::ObjectGenerator(GameVersion version) : m_version(version) {} + /*! * Build an object file with the v3 format. */ @@ -486,7 +488,17 @@ void ObjectGenerator::emit_link_type_pointer(int seg, const TypeSystem* ts) { out.push_back(0); // method count - out.push_back(ts->get_type_method_count(rec.first)); + switch (m_version) { + case GameVersion::Jak1: + out.push_back(ts->get_type_method_count(rec.first)); + break; + case GameVersion::Jak2: + // the linker/intern_type functions do the +3. + out.push_back(ts->get_type_method_count(rec.first) / 4); + break; + default: + ASSERT(false); + } // number of links push_data(size, out); diff --git a/goalc/emitter/ObjectGenerator.h b/goalc/emitter/ObjectGenerator.h index 90702b5ae3..c8b5244cd2 100644 --- a/goalc/emitter/ObjectGenerator.h +++ b/goalc/emitter/ObjectGenerator.h @@ -12,6 +12,8 @@ #include "Instruction.h" #include "ObjectFileData.h" +#include "common/versions.h" + #include "goalc/debugger/DebugInfo.h" struct FunctionDebugInfo; @@ -61,9 +63,8 @@ struct ObjectGeneratorStats { class ObjectGenerator { public: - ObjectGenerator() = default; + ObjectGenerator(GameVersion version); ObjectFileData generate_data_v3(const TypeSystem* ts); - FunctionRecord add_function_to_seg(int seg, FunctionDebugInfo* debug, int min_align = 16); // should align and insert function tag @@ -96,6 +97,8 @@ class ObjectGenerator { ObjectGeneratorStats get_stats() const; void count_eliminated_move(); + GameVersion version() const { return m_version; } + private: void handle_temp_static_type_links(int seg); void handle_temp_jump_links(int seg); @@ -205,6 +208,7 @@ class ObjectGenerator { template using seg_map = std::array>, N_SEG>; + GameVersion m_version; // final data seg_vector m_data_by_seg; diff --git a/test/decompiler/FormRegressionTest.cpp b/test/decompiler/FormRegressionTest.cpp index 8a695ece7a..b736799b52 100644 --- a/test/decompiler/FormRegressionTest.cpp +++ b/test/decompiler/FormRegressionTest.cpp @@ -21,7 +21,7 @@ using namespace decompiler; void FormRegressionTest::SetUpTestCase() { parser = std::make_unique(); - dts = std::make_unique(); + dts = std::make_unique(GameVersion::Jak1); dts->parse_type_defs({"decompiler", "config", "all-types.gc"}); } diff --git a/test/decompiler/test_DataParser.cpp b/test/decompiler/test_DataParser.cpp index 8528f6f3e1..0a9d10073b 100644 --- a/test/decompiler/test_DataParser.cpp +++ b/test/decompiler/test_DataParser.cpp @@ -16,7 +16,7 @@ class DataDecompTest : public ::testing::Test { static std::unique_ptr dts; static void SetUpTestCase() { - dts = std::make_unique(); + dts = std::make_unique(GameVersion::Jak1); dts->parse_type_defs({"decompiler", "config", "all-types.gc"}); } diff --git a/test/goalc/framework/test_runner.cpp b/test/goalc/framework/test_runner.cpp index af631d9543..835f34374c 100644 --- a/test/goalc/framework/test_runner.cpp +++ b/test/goalc/framework/test_runner.cpp @@ -104,6 +104,13 @@ void runtime_no_kernel() { exec_runtime(argc, const_cast(argv)); } +void runtime_no_kernel_jak2() { + constexpr int argc = 7; + const char* argv[argc] = {"", "-fakeiso", "-debug", "-nokernel", + "-nodisplay", "-nosound", "-jak2"}; + exec_runtime(argc, const_cast(argv)); +} + void runtime_with_kernel() { constexpr int argc = 5; const char* argv[argc] = {"", "-fakeiso", "-debug", "-nodisplay", "-nosound"}; diff --git a/test/goalc/framework/test_runner.h b/test/goalc/framework/test_runner.h index d7cd58f889..d86c1640a0 100644 --- a/test/goalc/framework/test_runner.h +++ b/test/goalc/framework/test_runner.h @@ -43,6 +43,7 @@ struct CompilerTestRunner { }; void runtime_no_kernel(); +void runtime_no_kernel_jak2(); void runtime_with_kernel(); void runtime_with_kernel_no_debug_segment(); diff --git a/test/goalc/source_templates/jak2/jak2-mega-test.gc b/test/goalc/source_templates/jak2/jak2-mega-test.gc new file mode 100644 index 0000000000..cf68dd2b5a --- /dev/null +++ b/test/goalc/source_templates/jak2/jak2-mega-test.gc @@ -0,0 +1,37 @@ +(define format _format) + +;; check the empty pair +(format #t "empty pair: ~A ~A ~A ~A ~A~%" '() (car '()) (cdr '()) (= '() (car '())) (= 'b (car '()))) +(format #t "empty pair type: ~A~%" (rtype-of '())) + +;; check non-empty pair +(let ((test-pair-1 '(a b -12))) + (format #t "non-empty pair: ~A ~A ~A ~A~%" test-pair-1 (car test-pair-1) (rtype-of test-pair-1) (new 'global 'pair 'a 'b)) + ) + +;; check some stuff +(format #t "basic types: ~A ~A ~A ~A~%" (-> type type) symbol string function) + +;; bools +(format #t "bools: ~A ~A ~A ~A ~A ~A~%" #t #f (-> #t value) (-> #f value) (= 1 2) (= 2 2)) + +;; weird funcs +(nothing) +(format #t "zero: ~D~%" (zero-func)) + +;; type stuff +(format #t "parent of type: ~A ~A ~A ~A~%" + (-> type parent) + (-> type parent parent) + (-> type parent parent parent) + (-> type parent parent parent parent)) + +#| +empty pair: () () () #t #f\ +empty pair type: pair +non-empty pair: (a b -12) a pair (a . b) +basic types: type symbol string function +bools: #t #f #t #f #f #t +zero: 0 +parent of type: basic structure object object +|# diff --git a/test/goalc/test_compiler.cpp b/test/goalc/test_compiler.cpp index 896d04b571..1b72d1f8bb 100644 --- a/test/goalc/test_compiler.cpp +++ b/test/goalc/test_compiler.cpp @@ -9,4 +9,57 @@ TEST(CompilerAndRuntime, ConstructCompiler) { Compiler compiler1(GameVersion::Jak1); Compiler compiler2(GameVersion::Jak2); +} + +struct Jak2Param { + // TODO - Not Needed Yet +}; + +class Jak2GoalcTests : public testing::TestWithParam { + public: + static void SetUpTestSuite() { + runtime_thread = std::make_unique(std::thread((GoalTest::runtime_no_kernel_jak2))); + compiler = std::make_unique(GameVersion::Jak2); + runner = std::make_unique(); + runner->c = compiler.get(); + } + + static void TearDownTestSuite() { + compiler->shutdown_target(); + runtime_thread->join(); + + runtime_thread.reset(); + compiler.reset(); + runner.reset(); + } + + void SetUp() { + GoalTest::createDirIfAbsent(GoalTest::getTemplateDir(testCategory)); + GoalTest::createDirIfAbsent(GoalTest::getGeneratedDir(testCategory)); + } + + void TearDown() {} + + static std::unique_ptr runtime_thread; + static std::unique_ptr compiler; + static std::unique_ptr runner; + + std::string testCategory = "jak2"; + inja::Environment env{GoalTest::getTemplateDir(testCategory), + GoalTest::getGeneratedDir(testCategory)}; +}; + +std::unique_ptr Jak2GoalcTests::runtime_thread; +std::unique_ptr Jak2GoalcTests::compiler; +std::unique_ptr Jak2GoalcTests::runner; + +TEST_F(Jak2GoalcTests, All) { + runner->run_static_test(env, testCategory, "jak2-mega-test.gc", + {"empty pair: () () () #t #f\n" + "empty pair type: pair\n" + "non-empty pair: (a b -12) a pair (a . b)\n" + "basic types: type symbol string function\n" + "bools: #t #f #t #f #f #t\n" + "zero: 0\n" + "parent of type: basic structure object object\n0\n"}); } \ No newline at end of file diff --git a/test/test_type_system.cpp b/test/test_type_system.cpp index 6c7080a1cd..b6da5d6b0b 100644 --- a/test/test_type_system.cpp +++ b/test/test_type_system.cpp @@ -8,7 +8,7 @@ TEST(TypeSystem, Construction) { // test that we can add all builtin types without any type errors TypeSystem ts; - ts.add_builtin_types(); + ts.add_builtin_types(GameVersion::Jak1); // useful for debugging. // fmt::print("{}", ts.print_all_type_information()); @@ -16,7 +16,7 @@ TEST(TypeSystem, Construction) { TEST(TypeSystem, DefaultMethods) { TypeSystem ts; - ts.add_builtin_types(); + ts.add_builtin_types(GameVersion::Jak1); // check that default methods have the right ID's used by the kernel ts.assert_method_id("object", "new", GOAL_NEW_METHOD); @@ -45,7 +45,7 @@ TEST(TypeSystemReverse, NestedInlineWeird) { // tests the case where we're accessing nested inline arrays, with a dynamic inner access // and constant outer access, which will be constant propagated by the GOAL compiler. TypeSystem ts; - ts.add_builtin_types(); + ts.add_builtin_types(GameVersion::Jak1); goos::Reader reader; auto add_type = [&](const std::string& str) { auto& in = reader.read_from_string(str).as_pair()->cdr.as_pair()->car.as_pair()->cdr; @@ -108,7 +108,7 @@ TEST(TypeSystemReverse, NestedInlineWeird) { TEST(TypeSystem, TypeSpec) { TypeSystem ts; - ts.add_builtin_types(); + ts.add_builtin_types(GameVersion::Jak1); // try some simple typespecs auto string_typespec = ts.make_typespec("string"); @@ -135,7 +135,7 @@ TEST(TypeSystem, TypeSpec) { TEST(TypeSystem, TypeSpecEquality) { TypeSystem ts; - ts.add_builtin_types(); + ts.add_builtin_types(GameVersion::Jak1); auto pointer_to_function = ts.make_pointer_typespec("function"); auto ia_to_function = ts.make_inline_array_typespec("function"); @@ -148,7 +148,7 @@ TEST(TypeSystem, TypeSpecEquality) { TEST(TypeSystem, RuntimeTypes) { TypeSystem ts; - ts.add_builtin_types(); + ts.add_builtin_types(GameVersion::Jak1); // pointers and inline arrays should all become simple pointers EXPECT_EQ(ts.get_runtime_type(ts.make_typespec("pointer")), "pointer"); @@ -163,7 +163,7 @@ TEST(TypeSystem, RuntimeTypes) { TEST(TypeSystem, ForwardDeclaration) { TypeSystem ts; - ts.add_builtin_types(); + ts.add_builtin_types(GameVersion::Jak1); // before forward declaring, lookup and creating a typespec should fail EXPECT_ANY_THROW(ts.lookup_type("test-type")); @@ -179,7 +179,7 @@ TEST(TypeSystem, ForwardDeclaration) { TEST(TypeSystem, DerefInfoNoLoadInfoOrStride) { // test the parts of deref info, other than the part where it tells you how to load or the stride. TypeSystem ts; - ts.add_builtin_types(); + ts.add_builtin_types(GameVersion::Jak1); // can't dereference a non-pointer EXPECT_FALSE(ts.get_deref_info(ts.make_typespec("string")).can_deref); @@ -229,7 +229,7 @@ TEST(TypeSystem, DerefInfoNoLoadInfoOrStride) { TEST(TypeSystem, AddMethodAndLookupMethod) { TypeSystem ts; - ts.add_builtin_types(); + ts.add_builtin_types(GameVersion::Jak1); auto parent_info = ts.declare_method(ts.lookup_type("structure"), "test-method-1", false, ts.make_function_typespec({"integer"}, "string"), false); @@ -273,7 +273,7 @@ TEST(TypeSystem, AddMethodAndLookupMethod) { TEST(TypeSystem, NewMethod) { TypeSystem ts; - ts.add_builtin_types(); + ts.add_builtin_types(GameVersion::Jak1); ts.add_type("test-1", std::make_unique("basic", "test-1", false, 0)); ts.declare_method(ts.lookup_type("test-1"), "new", false, ts.make_function_typespec({"symbol", "string"}, "test-1"), false); @@ -295,7 +295,7 @@ TEST(TypeSystem, NewMethod) { TEST(TypeSystem, MethodSubstitute) { TypeSystem ts; - ts.add_builtin_types(); + ts.add_builtin_types(GameVersion::Jak1); ts.add_type("test-1", std::make_unique("basic", "test-1", false, 0)); ts.declare_method(ts.lookup_type("test-1"), "new", false, ts.make_function_typespec({"symbol", "string", "_type_"}, "_type_"), false); @@ -312,7 +312,7 @@ bool ts_name_name(TypeSystem& ts, const std::string& ex, const std::string& act) TEST(TypeSystem, TypeCheck) { TypeSystem ts; - ts.add_builtin_types(); + ts.add_builtin_types(GameVersion::Jak1); EXPECT_TRUE(ts_name_name(ts, "none", "none")); // none - none _shouldn't_ fail (for function return types!) @@ -346,7 +346,7 @@ TEST(TypeSystem, FieldLookup) { // implementation of lookup_field_info TypeSystem ts; - ts.add_builtin_types(); + ts.add_builtin_types(GameVersion::Jak1); EXPECT_EQ(ts.lookup_field_info("type", "parent").field.offset(), 8); EXPECT_EQ(ts.lookup_field_info("string", "data").type.print(), "(pointer uint8)"); @@ -356,14 +356,14 @@ TEST(TypeSystem, FieldLookup) { TEST(TypeSystem, get_path_up_tree) { TypeSystem ts; - ts.add_builtin_types(); + ts.add_builtin_types(GameVersion::Jak1); EXPECT_EQ(ts.get_path_up_tree("type"), std::vector({"type", "basic", "structure", "object"})); } TEST(TypeSystem, lca) { TypeSystem ts; - ts.add_builtin_types(); + ts.add_builtin_types(GameVersion::Jak1); EXPECT_EQ( ts.lowest_common_ancestor(ts.make_typespec("string"), ts.make_typespec("basic")).print(), "basic"); @@ -393,7 +393,7 @@ TEST(TypeSystem, lca) { TEST(TypeSystem, DecompLookupsTypeOfBasic) { TypeSystem ts; - ts.add_builtin_types(); + ts.add_builtin_types(GameVersion::Jak1); auto string_type = ts.make_typespec("string"); FieldReverseLookupInput input; @@ -417,7 +417,7 @@ TEST(TypeSystem, DecompLookupsTypeOfBasic) { TEST(TypeSystem, DecompLookupsMethod) { TypeSystem ts; - ts.add_builtin_types(); + ts.add_builtin_types(GameVersion::Jak1); auto type_type = ts.make_typespec("type"); @@ -473,7 +473,7 @@ TEST(TypeSystem, DecompLookupsMethod) { TEST(Deftype, deftype) { TypeSystem ts; - ts.add_builtin_types(); + ts.add_builtin_types(GameVersion::Jak1); std::string input = "(deftype my-type (basic) ((f1 int64) (f2 string) (f3 int8) (f4 type :inline) (f5 uint64 " ":overlay-at f1)))"; diff --git a/tools/MemoryDumpTool/main.cpp b/tools/MemoryDumpTool/main.cpp index fe6bed9b90..b0ad64f72e 100644 --- a/tools/MemoryDumpTool/main.cpp +++ b/tools/MemoryDumpTool/main.cpp @@ -1,21 +1,24 @@ -#include #include #include #include -#include "third-party/fmt/core.h" -#include "third-party/json.hpp" +#include -#include "common/util/FileUtil.h" #include "common/goal_constants.h" #include "common/symbols.h" #include "common/type_system/TypeSystem.h" - -#include "decompiler/util/DecompilerTypeSystem.h" #include "common/util/Assert.h" +#include "common/util/FileUtil.h" #include +#include "decompiler/util/DecompilerTypeSystem.h" + +#include "third-party/fmt/core.h" +#include "third-party/json.hpp" + namespace fs = fs; +constexpr GameVersion kGameVersion = GameVersion::Jak1; + struct Ram { const u8* data = nullptr; u32 size = 0; @@ -572,7 +575,7 @@ int main(int argc, char** argv) { } fmt::print("Loading type definitions from all-types.gc...\n"); - decompiler::DecompilerTypeSystem dts; + decompiler::DecompilerTypeSystem dts(kGameVersion); dts.parse_type_defs({"decompiler", "config", "all-types.gc"}); std::string file_name = argv[1]; diff --git a/tools/level_tools/level_dump/main.cpp b/tools/level_tools/level_dump/main.cpp index bbb1ab3459..d179453704 100644 --- a/tools/level_tools/level_dump/main.cpp +++ b/tools/level_tools/level_dump/main.cpp @@ -74,7 +74,7 @@ int main(int argc, char** argv) { } fmt::print("Setting up types...\n"); - decompiler::DecompilerTypeSystem dts; + decompiler::DecompilerTypeSystem dts(kGameVersion); dts.parse_type_defs({"decompiler", "config", "all-types.gc"}); std::string file_name = argv[1];