From ee015e3b225ae3e15d3b7683460e78cb264c6c34 Mon Sep 17 00:00:00 2001 From: water111 <48171810+water111@users.noreply.github.com> Date: Sun, 24 Mar 2024 16:30:28 -0400 Subject: [PATCH] [jak3] A bunch of small fixes to get `game.cgo` to load (#3435) The `test-play` macro is back, though it doesn't call `play` yet. We can at least load all of `game.cgo`, which involves loading a lot of the code we've decompiled, loading/linking objects files compiled by OpenGOAL (like dir-tpages), and loading/linking Jak's art-groups (for jak 3 they are stored v5 format that I added to the linker). There were no major issues - just a few forgotten mips2c entries and minor bugs/functions that needed stubs. Most of the work was updating the linker. Hopefully I'll never have to touch that code again - I think it supports everything we need for jak 3! --- decompiler/config/jak3/all-types.gc | 28 +- game/CMakeLists.txt | 3 + game/kernel/common/klink.h | 10 + game/kernel/jak3/klink.cpp | 469 +++++- game/kernel/jak3/kscheme.cpp | 2 +- game/kernel/jak3/kscheme.h | 3 + game/mips2c/jak3_functions/collide_func.cpp | 2 - game/mips2c/jak3_functions/debug.cpp | 14 +- game/mips2c/jak3_functions/foreground.cpp | 1300 +++++++++++++++++ game/mips2c/jak3_functions/joint.cpp | 162 ++ game/mips2c/jak3_functions/lights.cpp | 4 - game/mips2c/jak3_functions/texture.cpp | 188 +++ game/mips2c/mips2c_table.cpp | 23 +- goal_src/jak3/engine/anim/joint.gc | 2 +- goal_src/jak3/engine/camera/cam-start.gc | 4 +- goal_src/jak3/engine/gfx/foreground/eye-h.gc | 7 + goal_src/jak3/engine/gfx/mood/mood.gc | 5 + .../sprite/particles/sparticle-launcher.gc | 6 + goal_src/jak3/engine/gfx/texture/texture.gc | 7 +- goal_src/jak3/engine/level/level.gc | 6 +- goal_src/jak3/engine/math/matrix-h.gc | 2 +- goalc/debugger/Debugger.cpp | 2 - .../jak3/engine/math/matrix-h_REF.gc | 16 +- 23 files changed, 2188 insertions(+), 77 deletions(-) create mode 100644 game/mips2c/jak3_functions/foreground.cpp create mode 100644 game/mips2c/jak3_functions/joint.cpp create mode 100644 game/mips2c/jak3_functions/texture.cpp diff --git a/decompiler/config/jak3/all-types.gc b/decompiler/config/jak3/all-types.gc index fef62c63b8f..d0bbb113f01 100644 --- a/decompiler/config/jak3/all-types.gc +++ b/decompiler/config/jak3/all-types.gc @@ -1799,7 +1799,7 @@ some, but not all, functions assume that a matrix is an affine transform. others assume that the rotation has no scale or shear (and that its inverse is its transpose)." ((data float 16 :offset-assert 0 :score -2) ;; guessed by decompiler - (vector vector 4 :offset 0 :score -1) ;; guessed by decompiler + (vector vector 4 :inline :offset 0 :score -1) ;; guessed by decompiler (quad uint128 4 :offset 0) ;; guessed by decompiler (rvec vector :inline :offset 0 :score 1) (uvec vector :inline :offset 16 :score 1) @@ -30761,7 +30761,6 @@ ;; sparticle-launcher ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -#| (deftype sp-queued-launch-particles (structure) ((sp-system sparticle-system :offset-assert 0) ;; guessed by decompiler (sp-launcher sparticle-launcher :offset-assert 4) ;; guessed by decompiler @@ -30771,34 +30770,28 @@ :size-assert #x20 :flag-assert #x900000020 ) -|# -#| (deftype sp-launch-queue (basic) ((in-use int32 :offset-assert 4) - (queue sp-queued-launch-particles 256 :offset-assert 16) ;; guessed by decompiler + (queue sp-queued-launch-particles 256 :inline :offset-assert 16) ;; guessed by decompiler ) :method-count-assert 9 :size-assert #x2010 :flag-assert #x900002010 ) -|# -#| (deftype particle-adgif-cache (basic) ((used int32 :offset-assert 4) (last uint16 :offset-assert 8) (lastgif adgif-shader :offset-assert 12) (tidhash uint16 80 :offset-assert 16) ;; guessed by decompiler - (spadgif adgif-shader 80 :offset-assert 176) ;; guessed by decompiler + (spadgif adgif-shader 80 :inline :offset-assert 176) ;; guessed by decompiler ) :method-count-assert 9 :size-assert #x19b0 :flag-assert #x9000019b0 ) -|# -#| (deftype sp-launch-stack (structure) ((ra basic :offset-assert 0) (dummy0 basic :offset-assert 4) @@ -30822,23 +30815,22 @@ :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. ) -|# ;; sparticle-launcher is already defined! (define-extern *part-id-table* (array sparticle-launcher)) (define-extern *part-group-id-table* (array sparticle-launch-group)) -;; (define-extern *sp-temp* object) ;; float +(define-extern *sp-temp* float) ;; (define-extern lookup-part-group-by-name function) ;; (function string sparticle-launch-group) (define-extern lookup-part-group-pointer-by-name (function string (pointer object))) (define-extern part-group-pointer? (function pointer symbol)) (define-extern unlink-part-group-by-heap (function kheap int)) ;; (define-extern sp-init-fields! function) ;; (function (pointer float) (inline-array sp-field-init-spec) sp-field-id sp-field-id symbol (inline-array sp-field-init-spec)) -;; (define-extern *sp-launcher-lock* object) ;; symbol -;; (define-extern *sp-launch-queue* object) ;; sp-launch-queue -;; (define-extern *sp-launcher-enable* object) ;; symbol +(define-extern *sp-launcher-lock* symbol) +(define-extern *sp-launch-queue* sp-launch-queue) +(define-extern *sp-launcher-enable* symbol) ;; (define-extern particle-setup-adgif function) ;; (function adgif-shader int none) -;; (define-extern *particle-adgif-cache* object) ;; particle-adgif-cache +(define-extern *particle-adgif-cache* particle-adgif-cache) (define-extern particle-adgif-cache-flush (function none)) ;; (define-extern particle-adgif function) ;; (function adgif-shader texture-id none) ;; (define-extern particle-adgif-callback function) ;; (function adgif-shader texture-id none) @@ -30847,7 +30839,7 @@ ;; (define-extern sp-euler-convert function) ;; (function sparticle-launchinfo sparticle-cpuinfo none) ;; (define-extern sp-rotate-system function) ;; (function sparticle-launchinfo sparticle-cpuinfo transformq none) (define-extern sp-launch-particles-var (function sparticle-system sparticle-launcher matrix sparticle-launch-state sparticle-launch-control float none)) -;; (define-extern *death-adgif* object) ;; adgif-shader +(define-extern *death-adgif* adgif-shader) ;; (define-extern sp-launch-particles-death function) ;; (function sparticle-system sparticle-launcher vector none) ;; (define-extern sp-clear-queue function) ;; (function none) ;; (define-extern sp-relaunch-setup-fields function) ;; (function object sparticle-launcher sparticle-cpuinfo sprite-vec-data-3d none) @@ -30865,7 +30857,7 @@ ;; (define-extern birth-func-clean function) ;; (define-extern birth-func-process-clock function) ;; (define-extern birth-func-copy-rot-color function) ;; (function sparticle-system sparticle-cpuinfo sprite-vec-data-3d sparticle-launcher sparticle-launch-state none) -;; (define-extern *global-toggle* object) ;; int +(define-extern *global-toggle* int) ;; (define-extern birth-func-copy2-rot-color function) ;; (function sparticle-system sparticle-cpuinfo sprite-vec-data-3d sparticle-launcher sparticle-launch-state none) ;; (define-extern birth-func-copy-omega-to-z function) ;; (function sparticle-system sparticle-cpuinfo sprite-vec-data-3d sparticle-launcher sparticle-launch-state none) ;; (define-extern birth-func-random-next-time function) ;; (function sparticle-system sparticle-cpuinfo sprite-vec-data-3d sparticle-launcher sparticle-launch-state none) diff --git a/game/CMakeLists.txt b/game/CMakeLists.txt index a5e74f0d99b..7358bef9246 100644 --- a/game/CMakeLists.txt +++ b/game/CMakeLists.txt @@ -188,10 +188,13 @@ set(RUNTIME_SOURCE mips2c/jak3_functions/collide_func.cpp mips2c/jak3_functions/debug.cpp mips2c/jak3_functions/font.cpp + mips2c/jak3_functions/foreground.cpp mips2c/jak3_functions/generic_effect.cpp + mips2c/jak3_functions/joint.cpp mips2c/jak3_functions/lights.cpp mips2c/jak3_functions/prim.cpp mips2c/jak3_functions/sky.cpp + mips2c/jak3_functions/texture.cpp mips2c/mips2c_table.cpp overlord/common/dma.cpp overlord/common/fake_iso.cpp diff --git a/game/kernel/common/klink.h b/game/kernel/common/klink.h index 00beb5a7227..b97ed1603a7 100644 --- a/game/kernel/common/klink.h +++ b/game/kernel/common/klink.h @@ -32,6 +32,13 @@ struct ObjectFileHeader { uint32_t link_block_length; }; +struct SegmentInfoV5 { + uint32_t relocs; // offset of relocation table + uint32_t data; // offset of segment data + uint32_t size; // segment data size (0 if segment doesn't exist) + uint32_t magic; // always 0 +}; + void klink_init_globals(); /*! * Stores the state of the linker. Used for multi-threaded linking, so it can be suspended. @@ -65,6 +72,8 @@ struct link_control { bool m_on_global_heap = false; LinkHeaderV5Core* m_link_hdr = nullptr; bool m_moved_link_block = false; + int m_n_segments = 0; + SegmentInfoV5* m_link_segments_table = nullptr; void jak1_jak2_begin(Ptr object_file, const char* name, @@ -89,6 +98,7 @@ struct link_control { uint32_t jak2_work_v3(); uint32_t jak2_work_v2(); + uint32_t jak3_work_v2_v4(); uint32_t jak3_work_v5(); uint32_t jak3_work_opengoal(); diff --git a/game/kernel/jak3/klink.cpp b/game/kernel/jak3/klink.cpp index fe7440ef27e..cae87bb142f 100644 --- a/game/kernel/jak3/klink.cpp +++ b/game/kernel/jak3/klink.cpp @@ -7,6 +7,7 @@ #include "game/kernel/common/fileio.h" #include "game/kernel/common/klink.h" #include "game/kernel/common/kprint.h" +#include "game/kernel/common/memory_layout.h" #include "game/kernel/jak3/kmalloc.h" #include "game/kernel/jak3/kscheme.h" #include "game/mips2c/mips2c_table.h" @@ -145,19 +146,27 @@ void link_control::jak3_begin(Ptr object_file, LinkHeaderV5* l_hdr = (LinkHeaderV5*)m_object_data.c(); m_flags = flags; u16 version = l_hdr->core.version; - ASSERT(version == 5); // I think, since there's only a work v5. + + if (version == 4) { + // it's a v4 produced by opengoal... lets just try using jak2's linker + m_version = 4; + printf("got version 4, falling back to jak1/jak2\n"); + jak1_jak2_begin(object_file, name, size, heap, flags); + return; + } + ASSERT(version == 5); m_heap_top = heap->top; // this->unk_init1 = 1; TODO m_busy = true; m_heap = heap; - // this->m_unk_init0_0 = 0; TODO + m_entry.offset = 0; m_keep_debug = false; m_link_hdr = &l_hdr->core; // m_hdr_ptr m_code_size = 0; // this->m_ptr_2 = l_hdr; just used for cache flush, so skip it! not really the right thing?? - // this->m_unk_init0_3 = 0; TODO - // this->m_unk_init0_4 = 0; TODO - // this->m_unk_init0_5 = 0; TODO + m_state = 0; + m_segment_process = 0; + m_moved_link_block = 0; if (version == 4) { ASSERT_NOT_REACHED(); } else { @@ -183,7 +192,17 @@ void link_control::jak3_begin(Ptr object_file, m_heap->current = m_object_data; } } else { + // the link block is in the heap. This is problematic because we don't want to hang + // on to this long term, but executing the top-level may allocate on this heap, causing + // stuff to get added after the hole left by the link data. + // So, we make a temporary allocation on the top and move it there. + m_moved_link_block = true; + Ptr new_link_block_mem; + u8* link_block_move_dst; + u8* old_link_block; + u32 link_block_move_size; + if (m_link_hdr->version == 5) { // the link block is inside our heap, but we'd like to avoid this. // we'll copy the link block, and the header to the temporary part of our heap: @@ -191,9 +210,9 @@ void link_control::jak3_begin(Ptr object_file, // where we loaded the link data: auto offset_to_link_data = m_link_hdr->length_to_get_to_link; - // allocate memory for link data, and header - auto new_link_block_mem = kmalloc(m_heap, m_link_hdr->link_length + sizeof(LinkHeaderV5), - KMALLOC_TOP, "link-block"); + // allocate memory for link data, and header (pvVar5) + new_link_block_mem = kmalloc(m_heap, m_link_hdr->link_length + sizeof(LinkHeaderV5), + KMALLOC_TOP, "link-block"); // we'll place the header and link block back to back in the newly alloated block, // so patch up the offset for this new layout before copying @@ -202,30 +221,38 @@ void link_control::jak3_begin(Ptr object_file, // move header! memmove(new_link_block_mem.c(), object_file.c(), sizeof(LinkHeaderV5)); - // move link data! - auto old_link_block = object_file.c() + offset_to_link_data; - memmove(new_link_block_mem.c() + sizeof(LinkHeaderV5), old_link_block, - m_link_hdr->link_length); + // dst: pvVar6 + link_block_move_dst = new_link_block_mem.c() + sizeof(LinkHeaderV5); - // update our pointer to the link header core. - m_link_hdr = &((LinkHeaderV5*)new_link_block_mem.c())->core; + // move link data! (pcVar8) + old_link_block = object_file.c() + offset_to_link_data; - // scary: update the heap to kick out all the link data (and likely the actual data too). - // we'll be relying on the linking process to copy the data as needed.l - if (old_link_block < m_heap->current.c()) { - if (link_debug_printfs) { - printf("Kick out old link block\n"); - } - m_heap->current.offset = old_link_block - g_ee_main_mem; - } + link_block_move_size = m_link_hdr->link_length; } else { + // hm, maybe only possible with version 2 or 3?? ASSERT_NOT_REACHED(); } + + memmove(link_block_move_dst, old_link_block, link_block_move_size); + + // update our pointer to the link header core. + m_link_hdr = &((LinkHeaderV5*)new_link_block_mem.c())->core; + + // scary: update the heap to kick out all the link data (and likely the actual data too). + // we'll be relying on the linking process to copy the data as needed.l + if (old_link_block < m_heap->current.c()) { + if (link_debug_printfs) { + printf("Kick out old link block\n"); + } + m_heap->current.offset = old_link_block - g_ee_main_mem; + } } } if ((m_flags & LINK_FLAG_FORCE_DEBUG) && MasterDebug && !DiskBoot) { m_keep_debug = true; } + // hack: + m_version = m_link_hdr->version; } } @@ -248,6 +275,11 @@ uint32_t link_control::jak3_work() { ASSERT(!m_opengoal); *(u32*)(((u8*)m_link_hdr) - 4) = *((s7 + jak3_symbols::FIX_SYM_LINK_BLOCK - 1).cast()); rv = jak3_work_v5(); + } else if (m_version == 4) { + // Note: this is a bit of a hack. Jak 3 doesn't support v2/v4. But, OpenGOAL generates data + // objects in this format. We will just try reusing the jak 2 v2/v4 linker here and see if it + // works. See corresponding call to jak1_jak2_begin in begin. + rv = jak3_work_v2_v4(); } else { ASSERT_MSG(false, fmt::format("UNHANDLED OBJECT FILE VERSION {} IN WORK!", m_version)); return 0; @@ -257,9 +289,175 @@ uint32_t link_control::jak3_work() { return rv; } +namespace jak3 { +void ultimate_memcpy(void* dst, void* src, uint32_t size); +} + uint32_t link_control::jak3_work_v5() { - ASSERT_NOT_REACHED(); // save this for another day... - // TODO: there are some missing vars in begin. I just commented them out for now. + if (m_state == 0) { + // here, we change length_to_get_to_link to an actual pointer to the link table. + // since we need 32-bits, we'll store offset from g_ee_mem. + u8* link_data = ((u8*)m_link_hdr) - 4 + m_link_hdr->length_to_get_to_link; + m_link_hdr->length_to_get_to_link = link_data - g_ee_main_mem; + + m_n_segments = m_link_hdr->n_segments; + + // the link segments table is just at the start of the link data: + m_link_segments_table = (SegmentInfoV5*)link_data; + /* + for (int i = 0; i < m_n_segments; i++) { + printf(" %d: reloc %d, data %d, size %d, magic %d\n", i, m_link_segments_table[i].relocs, + m_link_segments_table[i].data, m_link_segments_table[i].size, + m_link_segments_table[i].magic); + } + */ + // for now, only supporting 1 segment + ASSERT(m_n_segments == 1); + + // fixup the relocs/data offsets into addresses (again, offsets from g_ee_main_mem) + // relocs is relative to this link data + m_link_segments_table[0].relocs += (link_data - g_ee_main_mem); + // data is relative to usual object_data + m_link_segments_table[0].data += m_object_data.offset; + ASSERT(m_link_segments_table[0].magic == 1); + + // see if there's even data + if (m_link_segments_table[0].size == 0) { + // no data. + m_link_segments_table[0].data = 0; + } else { + // check if we need to move the main segment. + if (!m_moved_link_block || + ((m_link_hdr->link_length + 0x50) <= m_link_hdr->length_to_get_to_code)) { + // printf(" v5 linker allocating for main segment... (%d)\n", m_moved_link_block); + auto old_data_offset = m_link_segments_table[0].data; // 25 + auto new_data = kmalloc(m_heap, m_link_segments_table[0].size, 0, "main-segment"); + m_link_segments_table[0].data = new_data.offset; + if (!new_data.offset) { + MsgErr("dkernel: unable to malloc %d bytes for main-segment\n", + m_link_segments_table[0].size); + return 1; + } + jak3::ultimate_memcpy(new_data.c(), old_data_offset + g_ee_main_mem, + m_link_segments_table[0].size); + } else { + m_heap->current = m_object_data + m_code_size; + if (m_heap->top.offset <= m_heap->current.offset) { + MsgErr("dkernel: heap overflow\n"); + return 1; + } + } + } + + m_segment_process = 0; + m_state = 1; + m_object_data.offset = m_link_segments_table[0].data; + + Ptr base_ptr(m_link_segments_table[0].data); + Ptr data_ptr = base_ptr - 4; + Ptr link_ptr(m_link_segments_table[0].relocs); + + bool fixing = false; + if (*link_ptr) { + // we have pointers + while (true) { + while (true) { + if (!fixing) { + // seeking + data_ptr.offset += 4 * (*link_ptr); + } else { + // fixing. + for (uint32_t i = 0; i < *link_ptr; i++) { + // uint32_t old_code = *(const uint32_t*)(&data.at(data_ptr)); + u32 old_code = *data_ptr.cast(); + if ((old_code >> 24) == 0) { + // printf("modifying pointer at 0x%x (old 0x%x) : now ", data_ptr.offset, + // *data_ptr.cast()); + *data_ptr.cast() += base_ptr.offset; + // printf("0x%x\n", *data_ptr.cast()); + } else { + ASSERT_NOT_REACHED(); + /* + f.stats.v3_split_pointers++; + auto dest_seg = (old_code >> 8) & 0xf; + auto lo_hi_offset = (old_code >> 12) & 0xf; + ASSERT(lo_hi_offset); + ASSERT(dest_seg < 3); + auto offset_upper = old_code & 0xff; + uint32_t low_code = *(const uint32_t*)(&data.at(data_ptr + 4 * lo_hi_offset)); + uint32_t offset = low_code & 0xffff; + if (offset_upper) { + offset += (offset_upper << 16); + } + f.pointer_link_split_word(seg_id, data_ptr - base_ptr, + data_ptr + 4 * lo_hi_offset - base_ptr, dest_seg, offset); + */ + } + data_ptr.offset += 4; + } + } + + if (*link_ptr != 0xff) + break; + link_ptr.offset++; + if (*link_ptr == 0) { + link_ptr.offset++; + fixing = !fixing; + } + } + + link_ptr.offset++; + fixing = !fixing; + if (*link_ptr == 0) + break; + } + } + link_ptr.offset++; + + // symbol linking. + if (*link_ptr) { + auto sub_link_ptr = link_ptr; + + while (true) { + auto reloc = *sub_link_ptr; + auto next_link_ptr = sub_link_ptr + 1; + link_ptr = next_link_ptr; + + if ((reloc & 0x80) == 0) { + link_ptr = sub_link_ptr + 3; // + const char* sname = link_ptr.cast().c(); + link_ptr.offset += strlen(sname) + 1; + // printf("linking symbol %s\n", sname); + auto goalObj = jak3::intern_from_c(-1, 0, sname); + link_ptr = c_symlink2(m_object_data, goalObj.cast(), link_ptr); + + } else if ((reloc & 0x3f) == 0x3f) { + ASSERT(false); // todo, does this ever get hit? + } else { + int n_methods_base = reloc & 0x3f; + int n_methods = n_methods_base * 4; + if (n_methods_base) { + n_methods += 3; + } + link_ptr.offset += + 2; // ghidra misses some aliasing here and would have you think this is +1! + const char* sname = link_ptr.cast().c(); + // printf("linking type %s\n", sname); + link_ptr.offset += strlen(sname) + 1; + auto goalObj = jak3::intern_type_from_c(-1, 0, sname, n_methods); + link_ptr = c_symlink2(m_object_data, goalObj.cast(), link_ptr); + } + + sub_link_ptr = link_ptr; + if (!*sub_link_ptr) + break; + } + } + m_entry = m_object_data + 4; + return 1; + } else { + ASSERT_NOT_REACHED(); + } } namespace { @@ -567,7 +765,17 @@ void link_control::jak3_finish(bool jump_from_c_to_goal) { output_segment_load(m_object_name, m_link_block_ptr, m_flags); } } else { - ASSERT_NOT_REACHED(); + if (m_flags & LINK_FLAG_EXECUTE) { + auto entry = m_entry; + auto name = basename_goal(m_object_name); + strcpy(Ptr(LINK_CONTROL_NAME_ADDR).c(), name); + // printf(" about to call... (0x%x)\n", entry.offset); + Ptr type(*((entry - 4).cast())); + // printf(" type is %s\n", jak3::sym_to_cstring(type->symbol)); + jak3::call_method_of_type_arg2(entry.offset, type, GOAL_RELOC_METHOD, m_heap.offset, + Ptr(LINK_CONTROL_NAME_ADDR).offset); + // printf(" done with call!\n"); + } } *EnableMethodSet = *EnableMethodSet - this->m_keep_debug; @@ -654,3 +862,214 @@ void ultimate_memcpy(void* dst, void* src, uint32_t size) { } } // namespace jak3 + +#define LINK_V2_STATE_INIT_COPY 0 +#define LINK_V2_STATE_OFFSETS 1 +#define LINK_V2_STATE_SYMBOL_TABLE 2 +#define OBJ_V2_CLOSE_ENOUGH 0x90 +#define OBJ_V2_MAX_TRANSFER 0x80000 + +uint32_t link_control::jak3_work_v2_v4() { + // u32 startCycle = kernel.read_clock(); todo + + if (m_state == LINK_V2_STATE_INIT_COPY) { // initialization and copying to heap + // we move the data segment to eliminate gaps + // very small gaps can be tolerated, as it is not worth the time penalty to move large objects + // many bytes. if this requires copying a large amount of data, we will do it in smaller chunks, + // allowing the copy to be spread over multiple game frames + + // state initialization + if (m_segment_process == 0) { + m_heap_gap = + m_object_data - m_heap->current; // distance between end of heap and start of object + } + + if (m_heap_gap < + OBJ_V2_CLOSE_ENOUGH) { // close enough, don't relocate the object, just expand the heap + if (link_debug_printfs) { + printf("[work_v2] close enough, not moving\n"); + } + m_heap->current = m_object_data + m_code_size; + if (m_heap->top.offset <= m_heap->current.offset) { + MsgErr("dkernel: heap overflow\n"); // game has ~% instead of \n :P + return 1; + } + + // added in jak 2, move the link block to the top of the heap so we can allocate on + // the level heap during linking without overwriting link data. this is used for level types + u32 link_block_size = *m_link_block_ptr.cast(); + auto new_link_block = kmalloc(m_heap, link_block_size, KMALLOC_TOP, "link-block"); + memmove(new_link_block.c(), m_link_block_ptr.c() - 4, link_block_size); + m_link_block_ptr = Ptr(new_link_block.offset + 4); // basic offset + + } else { // not close enough, need to move the object + // on the first run of this state... + if (m_segment_process == 0) { + m_original_object_location = m_object_data; + // allocate on heap, will have no gap + m_object_data = kmalloc(m_heap, m_code_size, 0, "data-segment"); + if (link_debug_printfs) { + printf("[work_v2] moving from 0x%x to 0x%x\n", m_original_object_location.offset, + m_object_data.offset); + } + if (!m_object_data.offset) { + MsgErr("dkernel: unable to malloc %d bytes for data-segment\n", m_code_size); + return 1; + } + } + + // the actual copy + Ptr source = m_original_object_location + m_segment_process; + u32 size = m_code_size - m_segment_process; + + if (size > OBJ_V2_MAX_TRANSFER) { // around .5 MB + jak3::ultimate_memcpy((m_object_data + m_segment_process).c(), source.c(), + OBJ_V2_MAX_TRANSFER); + m_segment_process += OBJ_V2_MAX_TRANSFER; + return 0; // return, don't want to take too long. + } + + // if we have bytes to copy, but they are less than the max transfer, do it in one shot! + if (size) { + jak3::ultimate_memcpy((m_object_data + m_segment_process).c(), source.c(), size); + if (m_segment_process > 0) { // if we did a previous copy, we return now.... + m_state = LINK_V2_STATE_OFFSETS; + m_segment_process = 0; + return 0; + } + } + } + + // otherwise go straight into the next state. + m_state = LINK_V2_STATE_OFFSETS; + m_segment_process = 0; + } + + // init offset phase + if (m_state == LINK_V2_STATE_OFFSETS && m_segment_process == 0) { + m_reloc_ptr = m_link_block_ptr + 8; // seek to link table + if (*m_reloc_ptr == 0) { // do we have pointer links to do? + m_reloc_ptr.offset++; // if not, seek past the \0, and go to next state + m_state = LINK_V2_STATE_SYMBOL_TABLE; + m_segment_process = 0; + } else { + m_base_ptr = m_object_data; // base address for offsetting. + m_loc_ptr = m_object_data; // pointer which seeks thru the code + m_table_toggle = 0; // are we seeking or fixing? + m_segment_process = 1; // we've done first time setup + } + } + + if (m_state == LINK_V2_STATE_OFFSETS) { // pointer fixup + // this state reads through a table. Values alternate between "seek amount" and "number of + // consecutive 4-byte + // words to fix up". The counts are encoded using a variable length encoding scheme. They use + // a very stupid + // method of encoding values which requires O(n) bytes to store the value n. + + // to avoid dropping a frame, we check every 0x400 relocations to see if 0.5 milliseconds have + // elapsed. + u32 relocCounter = 0x400; + while (true) { // loop over entire table + while (true) { // loop over current mode + + // read and seek table + u8 count = *m_reloc_ptr; + m_reloc_ptr.offset++; + + if (!m_table_toggle) { // seek mode + m_loc_ptr.offset += + 4 * + count; // perform seek (MIPS instructions are 4 bytes, so we >> 2 the seek amount) + } else { // offset mode + for (u32 i = 0; i < count; i++) { + if (m_loc_ptr.offset % 4) { + ASSERT(false); + } + u32 code = *(m_loc_ptr.cast()); + code += m_base_ptr.offset; + *(m_loc_ptr.cast()) = code; + m_loc_ptr.offset += 4; + } + } + + if (count != 0xff) { + break; + } + + if (*m_reloc_ptr == 0) { + m_reloc_ptr.offset++; + m_table_toggle = m_table_toggle ^ 1; + } + } + + // reached the end of the tableToggle mode + m_table_toggle = m_table_toggle ^ 1; + if (*m_reloc_ptr == 0) { + break; // end of the state + } + relocCounter--; + if (relocCounter == 0) { + // u32 clock_value = kernel.read_clock(); + // if(clock_value - startCycle > 150000) { // 0.5 milliseconds + // return 0; + // } + relocCounter = 0x400; + } + } + m_reloc_ptr.offset++; + m_state = 2; + m_segment_process = 0; + } + + if (m_state == 2) { // GOAL object fixup + if (*m_reloc_ptr == 0) { + m_state = 3; + m_segment_process = 0; + } else { + while (true) { + u32 relocation = *m_reloc_ptr; + m_reloc_ptr.offset++; + Ptr goalObj; + char* name; + if ((relocation & 0x80) == 0) { + // symbol! + if (relocation > 9) { + m_reloc_ptr.offset--; // no idea what this is. + } + name = m_reloc_ptr.cast().c(); + if (link_debug_printfs) { + printf("[work_v2] symlink: %s\n", name); + } + goalObj = jak3::intern_from_c(-1, 0, name).cast(); + } else { + // type! + u8 nMethods = relocation & 0x7f; + if (nMethods == 0) { + nMethods = 1; + } + name = m_reloc_ptr.cast().c(); + if (link_debug_printfs) { + printf("[work_v2] symlink -type: %s\n", name); + } + goalObj = jak3::intern_type_from_c(-1, 0, name, nMethods).cast(); + } + m_reloc_ptr.offset += strlen(name) + 1; + // DECOMPILER->hookStartSymlinkV3(_state - 1, _objectData, std::string(name)); + m_reloc_ptr = c_symlink2(m_object_data, goalObj, m_reloc_ptr); + // DECOMPILER->hookFinishSymlinkV3(); + if (*m_reloc_ptr == 0) { + break; // done + } + // u32 currentCycle = kernel.read_clock(); + // if(currentCycle - startCycle > 150000) { + // return 0; + // } + } + m_state = 3; + m_segment_process = 0; + } + } + m_entry = m_object_data + 4; + return 1; +} diff --git a/game/kernel/jak3/kscheme.cpp b/game/kernel/jak3/kscheme.cpp index 724026fd7ad..0676f43da2a 100644 --- a/game/kernel/jak3/kscheme.cpp +++ b/game/kernel/jak3/kscheme.cpp @@ -54,11 +54,11 @@ void kscheme_init_globals() { #endif } -namespace { u32 u32_in_fixed_sym(u32 offset) { return Ptr>(s7.offset + offset)->value(); } +namespace { void fixed_sym_set(u32 offset, u32 value) { Ptr>(s7.offset + offset)->value() = value; } diff --git a/game/kernel/jak3/kscheme.h b/game/kernel/jak3/kscheme.h index 9dc847290ae..ef76389c4da 100644 --- a/game/kernel/jak3/kscheme.h +++ b/game/kernel/jak3/kscheme.h @@ -40,6 +40,7 @@ struct Type { }; s64 load_and_link(const char* filename, char* decode_name, kheapinfo* heap, u32 flags); +u32 u32_in_fixed_sym(u32 offset); Ptr> intern_from_c(int sym_id, int flags, const char* name); u64 load(u32 /*file_name_in*/, u32 /*heap_in*/); u64 loadb(u32 /*file_name_in*/, u32 /*heap_in*/, u32 /*param3*/); @@ -56,7 +57,9 @@ u64 call_method_of_type(u32 arg, Ptr type, u32 method_id); u64 new_pair(u32 heap, u32 type, u32 car, u32 cdr); u64 call_goal_function_by_name(const char* name); Ptr intern_type_from_c(int a, int b, const char* name, u64 methods); +u64 alloc_heap_object(u32 heap, u32 type, u32 size, u32 pp); int InitHeapAndSymbol(); +u64 call_method_of_type_arg2(u32 arg, Ptr type, u32 method_id, u32 a1, u32 a2); template Ptr> sym_to_string_ptr(Ptr> in) { return Ptr>(SymbolString.offset + in.offset - s7.offset); diff --git a/game/mips2c/jak3_functions/collide_func.cpp b/game/mips2c/jak3_functions/collide_func.cpp index 11f94fa0a65..e8a30759976 100644 --- a/game/mips2c/jak3_functions/collide_func.cpp +++ b/game/mips2c/jak3_functions/collide_func.cpp @@ -241,7 +241,6 @@ void link() { } // namespace Mips2C // add moving_sphere_triangle_intersect::link to the link callback table for the object file. // FWD DEC: -namespace moving_sphere_triangle_intersect { extern void link(); } //--------------------------MIPS2C--------------------- // clang-format off @@ -503,4 +502,3 @@ void link() { } // namespace Mips2C // add collide_do_primitives::link to the link callback table for the object file. // FWD DEC: -namespace collide_do_primitives { extern void link(); } \ No newline at end of file diff --git a/game/mips2c/jak3_functions/debug.cpp b/game/mips2c/jak3_functions/debug.cpp index e1ffc1266e3..b32a8408091 100644 --- a/game/mips2c/jak3_functions/debug.cpp +++ b/game/mips2c/jak3_functions/debug.cpp @@ -149,8 +149,6 @@ struct Cache { u64 execute(void* ctxt) { auto* c = (ExecutionContext*)ctxt; - bool bc = false; - u32 call_addr = 0; c->load_symbol2(v1, cache.math_camera); // lw v1, *math-camera*(s7) c->load_symbol2(a0, cache.sky_work); // lw a0, *sky-work*(s7) c->daddiu(a0, a0, 1088); // daddiu a0, a0, 1088 @@ -215,7 +213,7 @@ struct Cache { u64 execute(void* ctxt) { auto* c = (ExecutionContext*)ctxt; bool bc = false; - u32 call_addr = 0; + // u32 call_addr = 0; // nop // sll r0, r0, 0 c->daddiu(sp, sp, -8); // daddiu sp, sp, -8 // nop // sll r0, r0, 0 @@ -223,7 +221,7 @@ u64 execute(void* ctxt) { c->load_symbol2(t9, cache.clip_polygon_against_positive_hyperplane);// lw t9, clip-polygon-against-positive-hyperplane(s7) c->mov64(a2, t4); // or a2, t4, r0 c->mov64(a3, t5); // or a3, t5, r0 - call_addr = c->gprs[t9].du32[0]; // function call: + // call_addr = c->gprs[t9].du32[0]; // function call: c->daddu(t2, a2, r0); // daddu t2, a2, r0 // c->jalr(call_addr); // jalr ra, t9 clip_polygon_against_positive_hyperplane::execute(ctxt); @@ -233,7 +231,7 @@ u64 execute(void* ctxt) { c->mov64(a2, t5); // or a2, t5, r0 c->mov64(a3, t4); // or a3, t4, r0 - call_addr = c->gprs[t9].du32[0]; // function call: + // call_addr = c->gprs[t9].du32[0]; // function call: c->daddiu(t2, a2, 4); // daddiu t2, a2, 4 // c->jalr(call_addr); // jalr ra, t9 clip_polygon_against_positive_hyperplane::execute(ctxt); @@ -243,7 +241,7 @@ u64 execute(void* ctxt) { c->mov64(a2, t4); // or a2, t4, r0 c->mov64(a3, t5); // or a3, t5, r0 - call_addr = c->gprs[t9].du32[0]; // function call: + // call_addr = c->gprs[t9].du32[0]; // function call: c->daddu(t2, a2, r0); // daddu t2, a2, r0 // c->jalr(call_addr); // jalr ra, t9 clip_polygon_against_negative_hyperplane::execute(ctxt); @@ -253,7 +251,7 @@ u64 execute(void* ctxt) { c->mov64(a2, t5); // or a2, t5, r0 c->mov64(a3, t4); // or a3, t4, r0 - call_addr = c->gprs[t9].du32[0]; // function call: + // call_addr = c->gprs[t9].du32[0]; // function call: c->daddiu(t2, a2, 4); // daddiu t2, a2, 4 // c->jalr(call_addr); // jalr ra, t9 clip_polygon_against_negative_hyperplane::execute(ctxt); @@ -355,7 +353,6 @@ u64 execute(void* ctxt) { auto* c = (ExecutionContext*)ctxt; c->copy_vfs_from_other(&sky_regs_vfs); bool bc = false; - u32 call_addr = 0; c->mov64(v1, a0); // or v1, a0, r0 c->load_symbol2(v1, cache.math_camera); // lw v1, *math-camera*(s7) c->lqc2(vf14, 780, v1); // lqc2 vf14, 780(v1) @@ -493,7 +490,6 @@ u64 execute(void* ctxt) { auto* c = (ExecutionContext*)ctxt; c->copy_vfs_from_other(&sky_regs_vfs); bool bc = false; - u32 call_addr = 0; c->mov64(v1, a0); // or v1, a0, r0 get_fake_spad_addr2(t4, cache.fake_scratchpad_data, 0, c);// lui t4, 28672 c->ori(t4, t4, 12288); // ori t4, t4, 12288 diff --git a/game/mips2c/jak3_functions/foreground.cpp b/game/mips2c/jak3_functions/foreground.cpp new file mode 100644 index 00000000000..b674a449644 --- /dev/null +++ b/game/mips2c/jak3_functions/foreground.cpp @@ -0,0 +1,1300 @@ +//--------------------------MIPS2C--------------------- +// clang-format off +#include "game/mips2c/mips2c_private.h" +#include "game/kernel/jak3/kscheme.h" +using ::jak3::intern_from_c; +namespace Mips2C::jak3 { +namespace foreground_check_longest_edge_asm { +struct Cache { + void* fake_scratchpad_data; // *fake-scratchpad-data* + void* math_camera; // *math-camera* +} cache; + +u64 execute(void* ctxt) { + auto* c = (ExecutionContext*)ctxt; + bool bc = false; + u32 call_addr = 0; + bool cop1_bc = false; + float acc; + get_fake_spad_addr2(at, cache.fake_scratchpad_data, 0, c);// lui at, 28672 + c->mov64(v0, s7); // or v0, s7, r0 + c->load_symbol2(v1, cache.math_camera); // lw v1, *math-camera*(s7) + c->lwc1(f0, 84, a0); // lwc1 f0, 84(a0) + c->lwc1(f7, 3936, at); // lwc1 f7, 3936(at) + c->lwc1(f3, 3940, at); // lwc1 f3, 3940(at) + c->lwc1(f6, 3944, at); // lwc1 f6, 3944(at) + c->lwc1(f4, 152, a0); // lwc1 f4, 152(a0) + c->lwc1(f12, 0, v1); // lwc1 f12, 0(v1) + c->lwc1(f11, 64, v1); // lwc1 f11, 64(v1) + c->mtc1(f1, a1); // mtc1 f1, a1 + c->mtc1(f9, r0); // mtc1 f9, r0 + c->mtc1(f10, r0); // mtc1 f10, r0 + c->mtc1(f2, r0); // mtc1 f2, r0 + c->mtc1(f2, r0); // mtc1 f2, r0 + c->mtc1(f5, r0); // mtc1 f5, r0 + c->mtc1(f8, r0); // mtc1 f8, r0 + c->lui(a0, 16256); // lui a0, 16256 + c->mtc1(f5, a0); // mtc1 f5, a0 + cop1_bc = c->fprs[f1] < c->fprs[f11]; // c.lt.s f1, f11 + bc = cop1_bc; // bc1t L101 + // nop // sll r0, r0, 0 + if (bc) {goto block_37;} // branch non-likely + + c->lwc1(f11, 12, v1); // lwc1 f11, 12(v1) + c->lwc1(f13, 16, v1); // lwc1 f13, 16(v1) + c->muls(f11, f11, f12); // mul.s f11, f11, f12 + c->muls(f13, f13, f12); // mul.s f13, f13, f12 + c->subs(f14, f6, f4); // sub.s f14, f6, f4 + cop1_bc = c->fprs[f12] < c->fprs[f14]; // c.lt.s f12, f14 + bc = !cop1_bc; // bc1f L85 + c->lwc1(f12, 60, v1); // lwc1 f12, 60(v1) + if (bc) {goto block_3;} // branch non-likely + + c->muls(f12, f14, f12); // mul.s f12, f14, f12 + cop1_bc = c->fprs[f0] < c->fprs[f12]; // c.lt.s f0, f12 + bc = cop1_bc; // bc1t L100 + // nop // sll r0, r0, 0 + if (bc) {goto block_36;} // branch non-likely + + +block_3: + c->subs(f14, f3, f4); // sub.s f14, f3, f4 + cop1_bc = c->fprs[f13] < c->fprs[f14]; // c.lt.s f13, f14 + bc = !cop1_bc; // bc1f L86 + c->lwc1(f12, 56, v1); // lwc1 f12, 56(v1) + if (bc) {goto block_5;} // branch non-likely + + //beq r0, r0, L87 // beq r0, r0, L87 + c->muls(f10, f14, f12); // mul.s f10, f14, f12 + goto block_7; // branch always + + +block_5: + c->adds(f14, f3, f4); // add.s f14, f3, f4 + c->negs(f13, f13); // neg.s f13, f13 + cop1_bc = c->fprs[f14] < c->fprs[f13]; // c.lt.s f14, f13 + bc = !cop1_bc; // bc1f L87 + c->negs(f13, f14); // neg.s f13, f14 + if (bc) {goto block_7;} // branch non-likely + + c->muls(f10, f13, f12); // mul.s f10, f13, f12 + +block_7: + cop1_bc = c->fprs[f0] < c->fprs[f10]; // c.lt.s f0, f10 + bc = cop1_bc; // bc1t L100 + // nop // sll r0, r0, 0 + if (bc) {goto block_36;} // branch non-likely + + c->subs(f12, f7, f4); // sub.s f12, f7, f4 + cop1_bc = c->fprs[f11] < c->fprs[f12]; // c.lt.s f11, f12 + bc = !cop1_bc; // bc1f L88 + c->lwc1(f10, 52, v1); // lwc1 f10, 52(v1) + if (bc) {goto block_10;} // branch non-likely + + //beq r0, r0, L89 // beq r0, r0, L89 + c->muls(f9, f12, f10); // mul.s f9, f12, f10 + goto block_12; // branch always + + +block_10: + c->adds(f12, f7, f4); // add.s f12, f7, f4 + c->negs(f11, f11); // neg.s f11, f11 + cop1_bc = c->fprs[f12] < c->fprs[f11]; // c.lt.s f12, f11 + bc = !cop1_bc; // bc1f L89 + c->negs(f11, f12); // neg.s f11, f12 + if (bc) {goto block_12;} // branch non-likely + + c->muls(f9, f11, f10); // mul.s f9, f11, f10 + +block_12: + cop1_bc = c->fprs[f0] < c->fprs[f9]; // c.lt.s f0, f9 + bc = cop1_bc; // bc1t L100 + // nop // sll r0, r0, 0 + if (bc) {goto block_36;} // branch non-likely + + c->abss(f14, f7); // abs.s f14, f7 + c->movs(f12, f6); // mov.s f12, f6 + acc = c->fprs[f14] * c->fprs[f14]; // Unknown instr: mula.s f14, f14 + c->fprs[f15] = acc + c->fprs[f12] * c->fprs[f12]; // Unknown instr: madd.s f15, f12, f12 + c->lwc1(f9, 76, v1); // lwc1 f9, 76(v1) + c->lwc1(f13, 80, v1); // lwc1 f13, 80(v1) + c->lwc1(f10, 84, v1); // lwc1 f10, 84(v1) + c->lwc1(f11, 88, v1); // lwc1 f11, 88(v1) + c->fprs[f16] = c->fprs[f5] / (std::sqrt(std::abs(c->fprs[f15]))); // Unknown instr: rsqrt.s f16, f5, f15 + c->muls(f15, f14, f16); // mul.s f15, f14, f16 + c->muls(f16, f12, f16); // mul.s f16, f12, f16 + acc = c->fprs[f9] * c->fprs[f16]; // Unknown instr: mula.s f9, f16 + c->fprs[f12] = acc - c->fprs[f13] * c->fprs[f15]; // Unknown instr: msub.s f12, f13, f15 + acc = c->fprs[f10] * c->fprs[f16]; // Unknown instr: mula.s f10, f16 + c->fprs[f14] = acc - c->fprs[f11] * c->fprs[f15];// Unknown instr: msub.s f14, f11, f15 + acc = c->fprs[f9] * c->fprs[f15];// Unknown instr: mula.s f9, f15 + c->fprs[f9] = acc + c->fprs[f13] * c->fprs[f16];// Unknown instr: madd.s f9, f13, f16 + acc = c->fprs[f10] * c->fprs[f15];// Unknown instr: mula.s f10, f15 + c->fprs[f10] = acc + c->fprs[f11] * c->fprs[f16];// Unknown instr: madd.s f10, f11, f16 + cop1_bc = c->fprs[f8] < c->fprs[f12]; // c.lt.s f8, f12 + bc = cop1_bc; // bc1t L90 + // nop // sll r0, r0, 0 + if (bc) {goto block_17;} // branch non-likely + + cop1_bc = c->fprs[f8] < c->fprs[f14]; // c.lt.s f8, f14 + bc = cop1_bc; // bc1t L91 + // nop // sll r0, r0, 0 + if (bc) {goto block_18;} // branch non-likely + + cop1_bc = c->fprs[f8] < c->fprs[f9]; // c.lt.s f8, f9 + bc = cop1_bc; // bc1t L92 + // nop // sll r0, r0, 0 + if (bc) {goto block_19;} // branch non-likely + + //beq r0, r0, L94 // beq r0, r0, L94 + // nop // sll r0, r0, 0 + goto block_23; // branch always + + +block_17: + //beq r0, r0, L94 // beq r0, r0, L94 + c->divs(f2, f1, f10); // div.s f2, f1, f10 + goto block_23; // branch always + + +block_18: + c->negs(f2, f12); // neg.s f2, f12 + c->divs(f2, f2, f9); // div.s f2, f2, f9 + c->divs(f7, f14, f10); // div.s f7, f14, f10 + c->adds(f2, f7, f2); // add.s f2, f7, f2 + //beq r0, r0, L94 // beq r0, r0, L94 + c->muls(f2, f2, f1); // mul.s f2, f2, f1 + goto block_23; // branch always + + +block_19: + c->subs(f8, f7, f4); // sub.s f8, f7, f4 + c->adds(f10, f7, f4); // add.s f10, f7, f4 + c->negs(f11, f7); // neg.s f11, f7 + cop1_bc = c->fprs[f7] < c->fprs[f8]; // c.lt.s f7, f8 + bc = cop1_bc; // bc1t L93 + // nop // sll r0, r0, 0 + if (bc) {goto block_22;} // branch non-likely + + cop1_bc = c->fprs[f10] < c->fprs[f11]; // c.lt.s f10, f11 + bc = cop1_bc; // bc1t L93 + // nop // sll r0, r0, 0 + if (bc) {goto block_22;} // branch non-likely + + //beq r0, r0, L94 // beq r0, r0, L94 + // nop // sll r0, r0, 0 + goto block_23; // branch always + + +block_22: + c->negs(f2, f12); // neg.s f2, f12 + c->muls(f2, f1, f2); // mul.s f2, f1, f2 + c->divs(f2, f2, f9); // div.s f2, f2, f9 + +block_23: + cop1_bc = c->fprs[f0] < c->fprs[f2]; // c.lt.s f0, f2 + bc = cop1_bc; // bc1t L100 + // nop // sll r0, r0, 0 + if (bc) {goto block_36;} // branch non-likely + + c->abss(f10, f3); // abs.s f10, f3 + c->movs(f12, f6); // mov.s f12, f6 + acc = c->fprs[10] * c->fprs[10]; // Unknown instr: mula.s f10, f10 + c->fprs[9] = acc + c->fprs[12] * c->fprs[12]; // Unknown instr: madd.s f9, f12, f12 + c->lwc1(f7, 96, v1); // lwc1 f7, 96(v1) + c->lwc1(f8, 100, v1); // lwc1 f8, 100(v1) + c->lwc1(f6, 104, v1); // lwc1 f6, 104(v1) + c->fprs[f5] = c->fprs[f5] / (std::sqrt(std::abs(c->fprs[f9]))); // Unknown instr: rsqrt.s f5, f5, f9 + c->lwc1(f11, 108, v1); // lwc1 f11, 108(v1) + c->mtc1(f9, r0); // mtc1 f9, r0 + c->muls(f13, f10, f5); // mul.s f13, f10, f5 + c->muls(f14, f12, f5); // mul.s f14, f12, f5 + acc = c->fprs[f7] * c->fprs[f14];// Unknown instr: mula.s f7, f14 + c->fprs[f10] = acc - c->fprs[f8] * c->fprs[f13];// Unknown instr: msub.s f10, f8, f13 + acc = c->fprs[f6] * c->fprs[f14];// Unknown instr: mula.s f6, f14 + c->fprs[f12] = acc - c->fprs[f11] * c->fprs[f13];// Unknown instr: msub.s f12, f11, f13 + acc = c->fprs[f7] * c->fprs[f13];// Unknown instr: mula.s f7, f13 + c->fprs[f5] = acc + c->fprs[f8] * c->fprs[f14];// Unknown instr: madd.s f5, f8, f14 + acc = c->fprs[f6] * c->fprs[f13];// Unknown instr: mula.s f6, f13 + c->fprs[f6] = acc + c->fprs[f11] * c->fprs[f14];// Unknown instr: madd.s f6, f11, f14 + cop1_bc = c->fprs[f9] < c->fprs[f10]; // c.lt.s f9, f10 + bc = cop1_bc; // bc1t L95 + // nop // sll r0, r0, 0 + if (bc) {goto block_28;} // branch non-likely + + cop1_bc = c->fprs[f9] < c->fprs[f12]; // c.lt.s f9, f12 + bc = cop1_bc; // bc1t L96 + // nop // sll r0, r0, 0 + if (bc) {goto block_29;} // branch non-likely + + cop1_bc = c->fprs[f9] < c->fprs[f5]; // c.lt.s f9, f5 + bc = cop1_bc; // bc1t L97 + // nop // sll r0, r0, 0 + if (bc) {goto block_30;} // branch non-likely + + //beq r0, r0, L99 // beq r0, r0, L99 + // nop // sll r0, r0, 0 + goto block_34; // branch always + + +block_28: + //beq r0, r0, L99 // beq r0, r0, L99 + c->divs(f1, f1, f6); // div.s f1, f1, f6 + goto block_34; // branch always + + +block_29: + c->negs(f3, f10); // neg.s f3, f10 + c->divs(f3, f3, f5); // div.s f3, f3, f5 + c->divs(f4, f12, f6); // div.s f4, f12, f6 + c->adds(f3, f4, f3); // add.s f3, f4, f3 + //beq r0, r0, L99 // beq r0, r0, L99 + c->muls(f1, f3, f1); // mul.s f1, f3, f1 + goto block_34; // branch always + + +block_30: + c->subs(f6, f3, f4); // sub.s f6, f3, f4 + c->adds(f4, f3, f4); // add.s f4, f3, f4 + c->negs(f7, f3); // neg.s f7, f3 + cop1_bc = c->fprs[f3] < c->fprs[f6]; // c.lt.s f3, f6 + bc = cop1_bc; // bc1t L98 + // nop // sll r0, r0, 0 + if (bc) {goto block_33;} // branch non-likely + + cop1_bc = c->fprs[f4] < c->fprs[f7]; // c.lt.s f4, f7 + bc = cop1_bc; // bc1t L98 + // nop // sll r0, r0, 0 + if (bc) {goto block_33;} // branch non-likely + + //beq r0, r0, L99 // beq r0, r0, L99 + // nop // sll r0, r0, 0 + goto block_34; // branch always + + +block_33: + c->negs(f3, f10); // neg.s f3, f10 + c->muls(f1, f1, f3); // mul.s f1, f1, f3 + c->divs(f1, f1, f5); // div.s f1, f1, f5 + +block_34: + cop1_bc = c->fprs[f0] < c->fprs[f2]; // c.lt.s f0, f2 + bc = cop1_bc; // bc1t L100 + // nop // sll r0, r0, 0 + if (bc) {goto block_36;} // branch non-likely + + //beq r0, r0, L101 // beq r0, r0, L101 + // nop // sll r0, r0, 0 + goto block_37; // branch always + + +block_36: + c->daddiu(v0, s7, 4); // daddiu v0, s7, #t + +block_37: + //jr ra // jr ra + c->daddu(sp, sp, r0); // daddu sp, sp, r0 + goto end_of_function; // return + + // nop // sll r0, r0, 0 + // nop // sll r0, r0, 0 + // nop // sll r0, r0, 0 +end_of_function: + return c->gprs[v0].du64[0]; +} + +void link() { + cache.fake_scratchpad_data = intern_from_c(-1, 0, "*fake-scratchpad-data*").c(); + cache.math_camera = intern_from_c(-1, 0, "*math-camera*").c(); + gLinkedFunctionTable.reg("foreground-check-longest-edge-asm", execute, 128); +} + +} // namespace foreground_check_longest_edge_asm +} // namespace Mips2C +// add foreground_check_longest_edge_asm::link to the link callback table for the object file. +// FWD DEC: + +//--------------------------MIPS2C--------------------- +// clang-format off +#include "game/mips2c/mips2c_private.h" +#include "game/kernel/jak3/kscheme.h" +using ::jak3::intern_from_c; +namespace Mips2C::jak3 { +namespace foreground_merc { +struct Cache { + void* fake_scratchpad_data; // *fake-scratchpad-data* + void* foreground; // *foreground* + void* merc_global_stats; // *merc-global-stats* +} cache; + +// TODO: hack this up for pc merc rendering. +u64 execute(void* ctxt) { + auto* c = (ExecutionContext*)ctxt; + bool bc = false; + u32 call_addr = 0; + c->daddiu(sp, sp, -128); // daddiu sp, sp, -128 + c->sd(ra, 0, sp); // sd ra, 0(sp) + c->sq(s0, 16, sp); // sq s0, 16(sp) + c->sq(s1, 32, sp); // sq s1, 32(sp) + c->sq(s2, 48, sp); // sq s2, 48(sp) + c->sq(s3, 64, sp); // sq s3, 64(sp) + c->sq(s4, 80, sp); // sq s4, 80(sp) + c->sq(s5, 96, sp); // sq s5, 96(sp) + c->sq(gp, 112, sp); // sq gp, 112(sp) + c->mov64(t7, a3); // or t7, a3, r0 + c->mov64(v1, t0); // or v1, t0, r0 + c->lui(t0, 4096); // lui t0, 4096 + c->lui(t1, 18304); // lui t1, 18304 + c->daddiu(t0, t0, 1); // daddiu t0, t0, 1 + c->dsll32(t1, t1, 0); // dsll32 t1, t1, 0 + c->lui(a3, 12288); // lui a3, 12288 + c->lui(t8, 19201); // lui t8, 19201 + c->pcpyld(t0, a3, t0); // pcpyld t0, a3, t0 + c->lbu(a3, 78, a0); // lbu a3, 78(a0) + c->pcpyld(t1, t8, t1); // pcpyld t1, t8, t1 + c->lui(t2, 28160); // lui t2, 28160 + c->addiu(t8, r0, 8); // addiu t8, r0, 8 + c->multu3(a3, a3, t8); // multu3 a3, a3, t8 + c->lui(t3, 1280); // lui t3, 1280 + c->lui(t4, 27648); // lui t4, 27648 + c->dsll32(t2, t2, 0); // dsll32 t2, t2, 0 + c->dsll32(t4, t4, 0); // dsll32 t4, t4, 0 + c->daddu(t4, t4, t3); // daddu t4, t4, t3 + c->daddu(t3, t2, t3); // daddu t3, t2, t3 + c->daddiu(t3, t3, 1); // daddiu t3, t3, 1 + c->daddu(a0, a3, a0); // daddu a0, a3, a0 + c->pcpyld(t2, t2, r0); // pcpyld t2, t2, r0 + c->lw(a0, 28, a0); // lw a0, 28(a0) + c->pcpyld(t3, t3, r0); // pcpyld t3, t3, r0 + c->pcpyld(t4, t4, r0); // pcpyld t4, t4, r0 + c->lui(t5, 12288); // lui t5, 12288 + c->lui(t6, 4096); // lui t6, 4096 + c->daddiu(t5, t5, 7); // daddiu t5, t5, 7 + c->lui(t8, 5120); // lui t8, 5120 + c->lui(a3, 27655); // lui a3, 27655 + c->daddu(t7, t8, t7); // daddu t7, t8, t7 + c->dsll32(a3, a3, 0); // dsll32 a3, a3, 0 + c->dsll32(t8, t7, 0); // dsll32 t8, t7, 0 + c->pcpyld(t5, a3, t5); // pcpyld t5, a3, t5 + c->lwu(t7, 68, a0); // lwu t7, 68(a0) + c->pcpyld(t6, t8, t6); // pcpyld t6, t8, t6 + c->daddiu(t8, a0, 172); // daddiu t8, a0, 172 + bc = c->sgpr64(t7) == 0; // beq t7, r0, L118 + c->load_symbol2(a3, cache.foreground); // lw a3, *foreground*(s7) + if (bc) {goto block_16;} // branch non-likely + + c->daddiu(t9, a3, 3852); // daddiu t9, a3, 3852 + +block_2: + c->mov64(ra, a2); // or ra, a2, r0 + c->lbu(a3, 6, t9); // lbu a3, 6(t9) + c->lbu(gp, 4, t9); // lbu gp, 4(t9) + bc = c->sgpr64(a3) != 0; // bne a3, r0, L118 + c->load_symbol2(a3, cache.merc_global_stats); // lw a3, *merc-global-stats*(s7) + if (bc) {goto block_16;} // branch non-likely + + c->daddu(a3, r0, a3); // daddu a3, r0, a3 + bc = c->sgpr64(gp) != 0; // bne gp, r0, L118 + c->lhu(s4, 2, a3); // lhu s4, 2(a3) + if (bc) {goto block_16;} // branch non-likely + + c->lhu(s3, 18, t8); // lhu s3, 18(t8) + c->lwu(gp, 4, a3); // lwu gp, 4(a3) + c->lhu(s5, 22, t8); // lhu s5, 22(t8) + c->daddu(s4, s4, s3); // daddu s4, s4, s3 + c->lwu(s3, 8, a3); // lwu s3, 8(a3) + c->lhu(s2, 24, t8); // lhu s2, 24(t8) + c->daddu(gp, gp, s5); // daddu gp, gp, s5 + c->sh(s4, 2, a3); // sh s4, 2(a3) + c->sw(gp, 4, a3); // sw gp, 4(a3) + c->daddu(s5, s3, s2); // daddu s5, s3, s2 + c->lwu(t2, 0, t8); // lwu t2, 0(t8) + c->lwu(gp, 4, t8); // lwu gp, 4(t8) + c->lui(s4, 12288); // lui s4, 12288 + c->dsll32(t2, t2, 0); // dsll32 t2, t2, 0 + c->sw(s5, 8, a3); // sw s5, 8(a3) + c->or_(t2, t2, s4); // or t2, t2, s4 + c->lhu(s5, 18, t8); // lhu s5, 18(t8) + c->addiu(s4, r0, 0); // addiu s4, r0, 0 + bc = c->sgpr64(s5) == 0; // beq s5, r0, L118 + // nop // sll r0, r0, 0 + if (bc) {goto block_16;} // branch non-likely + + // nop // sll r0, r0, 0 + +block_6: + c->lbu(s0, 0, gp); // lbu s0, 0(gp) + // nop // sll r0, r0, 0 + c->lbu(s2, 1, gp); // lbu s2, 1(gp) + c->xori(s1, r0, 49292); // xori s1, r0, 49292 + c->lbu(s3, 2, gp); // lbu s3, 2(gp) + c->daddiu(v0, s0, 3); // daddiu v0, s0, 3 + c->lw(a3, 60, a0); // lw a3, 60(a0) + c->srl(v0, v0, 2); // srl v0, v0, 2 + c->sq(t0, 0, a2); // sq t0, 0(a2) + c->xor_(t2, t2, v0); // xor t2, t2, v0 + c->sq(t2, 32, a2); // sq t2, 32(a2) + c->xor_(t2, t2, v0); // xor t2, t2, v0 + c->sh(s1, 44, a2); // sh s1, 44(a2) + c->daddu(s1, s1, s0); // daddu s1, s1, s0 + c->sb(s0, 46, a2); // sb s0, 46(a2) + c->dsll32(s0, v0, 4); // dsll32 s0, v0, 4 + c->daddu(t3, t2, s0); // daddu t3, t2, s0 + c->daddiu(s0, s2, 3); // daddiu s0, s2, 3 + c->sw(a3, 12, a2); // sw a3, 12(a2) + c->srl(s0, s0, 2); // srl s0, s0, 2 + c->sq(t1, 16, a2); // sq t1, 16(a2) + c->xor_(t3, t3, s0); // xor t3, t3, s0 + c->sq(t3, 48, a2); // sq t3, 48(a2) + c->xor_(t3, t3, s0); // xor t3, t3, s0 + c->sh(s1, 60, a2); // sh s1, 60(a2) + c->daddu(s1, s1, s2); // daddu s1, s1, s2 + c->sb(s2, 62, a2); // sb s2, 62(a2) + c->dsll32(s2, s0, 4); // dsll32 s2, s0, 4 + c->sw(a3, 16, a2); // sw a3, 16(a2) + c->daddu(t4, t3, s2); // daddu t4, t3, s2 + c->xor_(t4, t4, s3); // xor t4, t4, s3 + c->xori(a3, s1, 16384); // xori a3, s1, 16384 + c->sq(t4, 64, a2); // sq t4, 64(a2) + c->xor_(t4, t4, s3); // xor t4, t4, s3 + c->sb(s3, 78, a2); // sb s3, 78(a2) + c->dsll32(s3, s3, 4); // dsll32 s3, s3, 4 + c->sh(a3, 76, a2); // sh a3, 76(a2) + c->daddu(t2, t4, s3); // daddu t2, t4, s3 + c->lbu(s3, 3, gp); // lbu s3, 3(gp) + c->daddiu(gp, gp, 4); // daddiu gp, gp, 4 + bc = c->sgpr64(s4) != 0; // bne s4, r0, L114 + c->daddiu(a2, a2, 80); // daddiu a2, a2, 80 + if (bc) {goto block_8;} // branch non-likely + + c->sd(t6, 0, a2); // sd t6, 0(a2) + c->addiu(s2, r0, 8); // addiu s2, r0, 8 + c->sd(t6, 8, a2); // sd t6, 8(a2) + c->lui(a3, 27656); // lui a3, 27656 + c->sb(s2, 0, a2); // sb s2, 0(a2) + c->daddiu(a3, a3, 132); // daddiu a3, a3, 132 + c->load_symbol2(s2, cache.foreground); // lw s2, *foreground*(s7) + c->daddiu(s1, s2, 3728); // daddiu s1, s2, 3728 + c->sw(a3, 12, a2); // sw a3, 12(a2) + c->lq(a3, 0, s1); // lq a3, 0(s1) + c->lq(s2, 16, s1); // lq s2, 16(s1) + c->lq(s0, 32, s1); // lq s0, 32(s1) + c->lq(v0, 48, s1); // lq v0, 48(s1) + c->sq(a3, 16, a2); // sq a3, 16(a2) + c->sq(s2, 32, a2); // sq s2, 32(a2) + c->sq(s0, 48, a2); // sq s0, 48(a2) + c->sq(v0, 64, a2); // sq v0, 64(a2) + c->lq(a3, 64, s1); // lq a3, 64(s1) + c->lq(s2, 80, s1); // lq s2, 80(s1) + c->lq(s1, 96, s1); // lq s1, 96(s1) + c->lui(s0, 16261); // lui s0, 16261 + c->daddiu(v0, s0, 4715); // daddiu v0, s0, 4715 + c->daddiu(v0, s0, 619); // daddiu v0, s0, 619 + c->lq(s0, 44, a0); // lq s0, 44(a0) + c->sq(a3, 80, a2); // sq a3, 80(a2) + c->lbu(a3, 5, t9); // lbu a3, 5(t9) + c->sq(s2, 96, a2); // sq s2, 96(a2) + c->sq(s1, 112, a2); // sq s1, 112(a2) + c->dsubu(a3, v0, a3); // dsubu a3, v0, a3 + c->sq(s0, 128, a2); // sq s0, 128(a2) + c->sw(a3, 28, a2); // sw a3, 28(a2) + c->daddiu(a2, a2, 144); // daddiu a2, a2, 144 + +block_8: + bc = c->sgpr64(s3) == 0; // beq s3, r0, L116 + c->addiu(s2, r0, 128); // addiu s2, r0, 128 + if (bc) {goto block_11;} // branch non-likely + + c->lbu(a3, 0, gp); // lbu a3, 0(gp) + // nop // sll r0, r0, 0 + +block_10: + c->multu3(s1, a3, s2); // multu3 s1, a3, s2 + c->sq(t5, 0, a2); // sq t5, 0(a2) + c->lbu(s0, 1, gp); // lbu s0, 1(gp) + c->daddiu(gp, gp, 2); // daddiu gp, gp, 2 + c->lbu(a3, 0, gp); // lbu a3, 0(gp) + c->daddiu(s3, s3, -1); // daddiu s3, s3, -1 + c->sb(s0, 12, a2); // sb s0, 12(a2) + c->daddiu(a2, a2, 16); // daddiu a2, a2, 16 + c->daddu(s1, s1, a1); // daddu s1, s1, a1 + // nop // sll r0, r0, 0 + bc = c->sgpr64(s3) != 0; // bne s3, r0, L115 + c->sw(s1, -12, a2); // sw s1, -12(a2) + if (bc) {goto block_10;} // branch non-likely + + +block_11: + c->sq(t6, 0, a2); // sq t6, 0(a2) + c->daddiu(a2, a2, 16); // daddiu a2, a2, 16 + bc = c->sgpr64(s4) != 0; // bne s4, r0, L117 + c->daddiu(s4, s4, 1); // daddiu s4, s4, 1 + if (bc) {goto block_13;} // branch non-likely + + c->mov64(a3, v1); // or a3, v1, r0 + c->sb(a3, -4, a2); // sb a3, -4(a2) + +block_13: + bc = c->sgpr64(s4) != c->sgpr64(s5); // bne s4, s5, L113 + // nop // sll r0, r0, 0 + if (bc) {goto block_6;} // branch non-likely + + get_fake_spad_addr2(s5, cache.fake_scratchpad_data, 0, c);// lui s5, 28672 + c->lbu(a3, 26, t8); // lbu a3, 26(t8) + c->addiu(gp, r0, 48); // addiu gp, r0, 48 + c->lw(s5, 52, s5); // lw s5, 52(s5) + c->mult3(a3, a3, gp); // mult3 a3, a3, gp + // nop // sll r0, r0, 0 + c->daddu(a3, s5, a3); // daddu a3, s5, a3 + // nop // sll r0, r0, 0 + c->lw(s4, 0, a3); // lw s4, 0(a3) + // nop // sll r0, r0, 0 + c->lw(gp, 4, a3); // lw gp, 4(a3) + c->movz(s4, ra, s4); // movz s4, ra, s4 + c->sq(r0, 0, a2); // sq r0, 0(a2) + c->lui(s5, 8192); // lui s5, 8192 + c->sw(s4, 0, a3); // sw s4, 0(a3) + c->mov64(s4, a2); // or s4, a2, r0 + c->sw(s5, 0, a2); // sw s5, 0(a2) + c->daddiu(a2, a2, 16); // daddiu a2, a2, 16 + bc = c->sgpr64(gp) == 0; // beq gp, r0, L118 + c->sw(s4, 4, a3); // sw s4, 4(a3) + if (bc) {goto block_16;} // branch non-likely + + // nop // sll r0, r0, 0 + c->sw(ra, 4, gp); // sw ra, 4(gp) + +block_16: + c->daddiu(t8, t8, 32); // daddiu t8, t8, 32 + c->daddiu(t9, t9, 8); // daddiu t9, t9, 8 + c->daddiu(t7, t7, -1); // daddiu t7, t7, -1 + bc = c->sgpr64(t7) != 0; // bne t7, r0, L112 + // nop // sll r0, r0, 0 + if (bc) {goto block_2;} // branch non-likely + + c->mov64(v0, a2); // or v0, a2, r0 + c->ld(ra, 0, sp); // ld ra, 0(sp) + c->lq(gp, 112, sp); // lq gp, 112(sp) + c->lq(s5, 96, sp); // lq s5, 96(sp) + c->lq(s4, 80, sp); // lq s4, 80(sp) + c->lq(s3, 64, sp); // lq s3, 64(sp) + c->lq(s2, 48, sp); // lq s2, 48(sp) + c->lq(s1, 32, sp); // lq s1, 32(sp) + c->lq(s0, 16, sp); // lq s0, 16(sp) + //jr ra // jr ra + c->daddiu(sp, sp, 128); // daddiu sp, sp, 128 + goto end_of_function; // return + + // nop // sll r0, r0, 0 + // nop // sll r0, r0, 0 +end_of_function: + return c->gprs[v0].du64[0]; +} + +void link() { + cache.fake_scratchpad_data = intern_from_c(-1, 0, "*fake-scratchpad-data*").c(); + cache.foreground = intern_from_c(-1, 0, "*foreground*").c(); + cache.merc_global_stats = intern_from_c(-1, 0, "*merc-global-stats*").c(); + gLinkedFunctionTable.reg("foreground-merc", execute, 256); +} + +} // namespace foreground_merc +} // namespace Mips2C +// add foreground_merc::link to the link callback table for the object file. +// FWD DEC: + +//--------------------------MIPS2C--------------------- +// clang-format off +#include "game/mips2c/mips2c_private.h" +#include "game/kernel/jak3/kscheme.h" +using ::jak3::intern_from_c; +namespace Mips2C::jak3 { +namespace foreground_generic_merc { +struct Cache { + void* fake_scratchpad_data; // *fake-scratchpad-data* + void* foreground; // *foreground* + void* merc_global_stats; // *merc-global-stats* + void* foreground_generic_merc_add_fragments; // foreground-generic-merc-add-fragments + void* foreground_generic_merc_death; // foreground-generic-merc-death +} cache; + +u64 execute(void* ctxt) { + auto* c = (ExecutionContext*)ctxt; + bool bc = false; + u32 call_addr = 0; + c->daddiu(sp, sp, -112); // daddiu sp, sp, -112 + c->sd(ra, 0, sp); // sd ra, 0(sp) + c->sq(s1, 16, sp); // sq s1, 16(sp) + c->sq(s2, 32, sp); // sq s2, 32(sp) + c->sq(s3, 48, sp); // sq s3, 48(sp) + c->sq(s4, 64, sp); // sq s4, 64(sp) + c->sq(s5, 80, sp); // sq s5, 80(sp) + c->sq(gp, 96, sp); // sq gp, 96(sp) + c->mov64(gp, a0); // or gp, a0, r0 + get_fake_spad_addr2(v1, cache.fake_scratchpad_data, 0, c);// lui v1, 28672 + c->daddu(v1, r0, v1); // daddu v1, r0, v1 + c->sw(a2, 16, v1); // sw a2, 16(v1) + c->sw(a1, 20, v1); // sw a1, 20(v1) + c->lb(v1, 78, gp); // lb v1, 78(gp) + c->dsll(v1, v1, 3); // dsll v1, v1, 3 + c->daddu(v1, gp, v1); // daddu v1, gp, v1 + c->lwu(s5, 28, v1); // lwu s5, 28(v1) + c->daddiu(s3, a1, 16); // daddiu s3, a1, 16 + c->addiu(s4, r0, 0); // addiu s4, r0, 0 + //beq r0, r0, L156 // beq r0, r0, L156 + // nop // sll r0, r0, 0 + goto block_82; // branch always + + +block_1: + c->load_symbol2(v1, cache.foreground); // lw v1, *foreground*(s7) + c->daddiu(v1, v1, 3728); // daddiu v1, v1, 3728 + c->dsll(a0, s4, 3); // dsll a0, s4, 3 + c->daddu(a0, v1, a0); // daddu a0, v1, a0 + c->lbu(a0, 130, a0); // lbu a0, 130(a0) + c->daddiu(a0, a0, -1); // daddiu a0, a0, -1 + c->daddiu(a1, s7, 4); // daddiu a1, s7, 4 + c->movz(a1, s7, a0); // movz a1, s7, a0 + if (((s64)c->sgpr64(s7)) == ((s64)c->sgpr64(a1))) {// beql s7, a1, L121 + c->mov64(v1, a1); // or v1, a1, r0 + goto block_4; + } + +block_3: + c->dsll(a0, s4, 3); // dsll a0, s4, 3 + c->daddu(v1, v1, a0); // daddu v1, v1, a0 + c->lbu(v1, 128, v1); // lbu v1, 128(v1) + c->daddiu(a0, v1, -2); // daddiu a0, v1, -2 + c->daddiu(v1, s7, 4); // daddiu v1, s7, 4 + c->movn(v1, s7, a0); // movn v1, s7, a0 + +block_4: + bc = c->sgpr64(s7) == c->sgpr64(v1); // beq s7, v1, L155 + c->mov64(v1, s7); // or v1, s7, r0 + if (bc) {goto block_81;} // branch non-likely + + c->mov64(s1, s3); // or s1, s3, r0 + c->dsll(v1, s4, 5); // dsll v1, s4, 5 + c->daddiu(v1, v1, 172); // daddiu v1, v1, 172 + c->daddu(s2, v1, s5); // daddu s2, v1, s5 + c->load_symbol2(v1, cache.merc_global_stats); // lw v1, *merc-global-stats*(s7) + c->daddiu(v1, v1, 32); // daddiu v1, v1, 32 + c->lhu(a0, 2, v1); // lhu a0, 2(v1) + c->lhu(a1, 18, s2); // lhu a1, 18(s2) + c->daddu(a0, a0, a1); // daddu a0, a0, a1 + c->sh(a0, 2, v1); // sh a0, 2(v1) + c->lwu(a0, 4, v1); // lwu a0, 4(v1) + c->lhu(a1, 22, s2); // lhu a1, 22(s2) + c->daddu(a0, a0, a1); // daddu a0, a0, a1 + c->sw(a0, 4, v1); // sw a0, 4(v1) + c->lwu(a0, 8, v1); // lwu a0, 8(v1) + c->lhu(a1, 24, s2); // lhu a1, 24(s2) + c->daddu(a0, a0, a1); // daddu a0, a0, a1 + c->sw(a0, 8, v1); // sw a0, 8(v1) + c->load_symbol2(v1, cache.foreground); // lw v1, *foreground*(s7) + c->daddiu(v1, v1, 3728); // daddiu v1, v1, 3728 + c->daddiu(a1, s1, 16); // daddiu a1, s1, 16 + c->daddu(a2, r0, v1); // daddu a2, r0, v1 + c->addiu(a0, r0, 7); // addiu a0, r0, 7 + // nop // sll r0, r0, 0 + c->daddiu(a3, a0, -4); // daddiu a3, a0, -4 + c->mov64(a1, a1); // or a1, a1, r0 + bc = ((s64)c->sgpr64(a3)) < 0; // bltz a3, L123 + c->mov64(a2, a2); // or a2, a2, r0 + if (bc) {goto block_7;} // branch non-likely + + +block_6: + // nop // sll r0, r0, 0 + c->lq(t2, 0, a2); // lq t2, 0(a2) + // nop // sll r0, r0, 0 + c->lq(a3, 16, a2); // lq a3, 16(a2) + c->daddiu(a0, a0, -4); // daddiu a0, a0, -4 + c->lq(t0, 32, a2); // lq t0, 32(a2) + c->daddiu(a1, a1, 64); // daddiu a1, a1, 64 + c->lq(t1, 48, a2); // lq t1, 48(a2) + c->daddiu(a2, a2, 64); // daddiu a2, a2, 64 + c->sq(t2, -64, a1); // sq t2, -64(a1) + c->daddiu(t2, a0, -4); // daddiu t2, a0, -4 + c->sq(a3, -48, a1); // sq a3, -48(a1) + // nop // sll r0, r0, 0 + c->sq(t0, -32, a1); // sq t0, -32(a1) + bc = ((s64)c->sgpr64(t2)) >= 0; // bgez t2, L122 + c->sq(t1, -16, a1); // sq t1, -16(a1) + if (bc) {goto block_6;} // branch non-likely + + +block_7: + bc = c->sgpr64(a0) == 0; // beq a0, r0, L124 + c->lq(a3, 0, a2); // lq a3, 0(a2) + if (bc) {goto block_12;} // branch non-likely + + c->daddiu(a2, a2, 16); // daddiu a2, a2, 16 + c->daddiu(a1, a1, 16); // daddiu a1, a1, 16 + c->daddiu(a0, a0, -1); // daddiu a0, a0, -1 + c->sq(a3, -16, a1); // sq a3, -16(a1) + bc = c->sgpr64(a0) == 0; // beq a0, r0, L124 + c->lq(a3, 0, a2); // lq a3, 0(a2) + if (bc) {goto block_12;} // branch non-likely + + c->daddiu(a2, a2, 16); // daddiu a2, a2, 16 + c->daddiu(a1, a1, 16); // daddiu a1, a1, 16 + c->daddiu(a0, a0, -1); // daddiu a0, a0, -1 + c->sq(a3, -16, a1); // sq a3, -16(a1) + bc = c->sgpr64(a0) == 0; // beq a0, r0, L124 + c->lq(a3, 0, a2); // lq a3, 0(a2) + if (bc) {goto block_12;} // branch non-likely + + c->daddiu(a2, a2, 16); // daddiu a2, a2, 16 + c->daddiu(a1, a1, 16); // daddiu a1, a1, 16 + c->daddiu(a0, a0, -1); // daddiu a0, a0, -1 + c->sq(a3, -16, a1); // sq a3, -16(a1) + bc = c->sgpr64(a0) == 0; // beq a0, r0, L124 + c->lq(a3, 0, a2); // lq a3, 0(a2) + if (bc) {goto block_12;} // branch non-likely + + c->daddiu(a2, a2, 16); // daddiu a2, a2, 16 + c->daddiu(a1, a1, 16); // daddiu a1, a1, 16 + c->daddiu(a0, a0, -1); // daddiu a0, a0, -1 + c->sq(a3, -16, a1); // sq a3, -16(a1) + +block_12: + c->gprs[a0].du64[0] = 0; // or a0, r0, r0 + c->daddiu(a1, s1, 128); // daddiu a1, s1, 128 + c->daddiu(a2, s5, 44); // daddiu a2, s5, 44 + c->addiu(a0, r0, 8); // addiu a0, r0, 8 + c->daddiu(a3, a0, -4); // daddiu a3, a0, -4 + c->mov64(a1, a1); // or a1, a1, r0 + bc = ((s64)c->sgpr64(a3)) < 0; // bltz a3, L126 + c->mov64(a2, a2); // or a2, a2, r0 + if (bc) {goto block_14;} // branch non-likely + + +block_13: + // nop // sll r0, r0, 0 + c->lq(t2, 0, a2); // lq t2, 0(a2) + // nop // sll r0, r0, 0 + c->lq(a3, 16, a2); // lq a3, 16(a2) + c->daddiu(a0, a0, -4); // daddiu a0, a0, -4 + c->lq(t0, 32, a2); // lq t0, 32(a2) + c->daddiu(a1, a1, 64); // daddiu a1, a1, 64 + c->lq(t1, 48, a2); // lq t1, 48(a2) + c->daddiu(a2, a2, 64); // daddiu a2, a2, 64 + c->sq(t2, -64, a1); // sq t2, -64(a1) + c->daddiu(t2, a0, -4); // daddiu t2, a0, -4 + c->sq(a3, -48, a1); // sq a3, -48(a1) + // nop // sll r0, r0, 0 + c->sq(t0, -32, a1); // sq t0, -32(a1) + bc = ((s64)c->sgpr64(t2)) >= 0; // bgez t2, L125 + c->sq(t1, -16, a1); // sq t1, -16(a1) + if (bc) {goto block_13;} // branch non-likely + + +block_14: + bc = c->sgpr64(a0) == 0; // beq a0, r0, L127 + c->lq(a3, 0, a2); // lq a3, 0(a2) + if (bc) {goto block_19;} // branch non-likely + + c->daddiu(a2, a2, 16); // daddiu a2, a2, 16 + c->daddiu(a1, a1, 16); // daddiu a1, a1, 16 + c->daddiu(a0, a0, -1); // daddiu a0, a0, -1 + c->sq(a3, -16, a1); // sq a3, -16(a1) + bc = c->sgpr64(a0) == 0; // beq a0, r0, L127 + c->lq(a3, 0, a2); // lq a3, 0(a2) + if (bc) {goto block_19;} // branch non-likely + + c->daddiu(a2, a2, 16); // daddiu a2, a2, 16 + c->daddiu(a1, a1, 16); // daddiu a1, a1, 16 + c->daddiu(a0, a0, -1); // daddiu a0, a0, -1 + c->sq(a3, -16, a1); // sq a3, -16(a1) + bc = c->sgpr64(a0) == 0; // beq a0, r0, L127 + c->lq(a3, 0, a2); // lq a3, 0(a2) + if (bc) {goto block_19;} // branch non-likely + + c->daddiu(a2, a2, 16); // daddiu a2, a2, 16 + c->daddiu(a1, a1, 16); // daddiu a1, a1, 16 + c->daddiu(a0, a0, -1); // daddiu a0, a0, -1 + c->sq(a3, -16, a1); // sq a3, -16(a1) + bc = c->sgpr64(a0) == 0; // beq a0, r0, L127 + c->lq(a3, 0, a2); // lq a3, 0(a2) + if (bc) {goto block_19;} // branch non-likely + + c->daddiu(a2, a2, 16); // daddiu a2, a2, 16 + c->daddiu(a1, a1, 16); // daddiu a1, a1, 16 + c->daddiu(a0, a0, -1); // daddiu a0, a0, -1 + c->sq(a3, -16, a1); // sq a3, -16(a1) + +block_19: + c->gprs[a0].du64[0] = 0; // or a0, r0, r0 + c->lbu(a0, 17, s2); // lbu a0, 17(s2) + c->andi(a1, a0, 32); // andi a1, a0, 32 + bc = c->sgpr64(a1) == 0; // beq a1, r0, L128 + // nop // sll r0, r0, 0 + if (bc) {goto block_21;} // branch non-likely + + c->addiu(a0, r0, 1); // addiu a0, r0, 1 + c->sb(a0, 182, s1); // sb a0, 182(s1) + //beq r0, r0, L130 // beq r0, r0, L130 + // nop // sll r0, r0, 0 + goto block_24; // branch always + + +block_21: + c->andi(a0, a0, 64); // andi a0, a0, 64 + bc = c->sgpr64(a0) == 0; // beq a0, r0, L129 + // nop // sll r0, r0, 0 + if (bc) {goto block_23;} // branch non-likely + + c->addiu(a0, r0, 2); // addiu a0, r0, 2 + c->sb(a0, 182, s1); // sb a0, 182(s1) + //beq r0, r0, L130 // beq r0, r0, L130 + // nop // sll r0, r0, 0 + goto block_24; // branch always + + +block_23: + c->sb(r0, 182, s1); // sb r0, 182(s1) + c->gprs[a0].du64[0] = 0; // or a0, r0, r0 + +block_24: + c->lbu(a0, 26, s2); // lbu a0, 26(s2) + c->lbu(a1, 182, s1); // lbu a1, 182(s1) + bc = c->sgpr64(a1) == 0; // beq a1, r0, L131 + // nop // sll r0, r0, 0 + if (bc) {goto block_26;} // branch non-likely + + c->addiu(a0, r0, 3776); // addiu a0, r0, 3776 + get_fake_spad_addr2(a1, cache.fake_scratchpad_data, 0, c);// lui a1, 28672 + c->daddu(a0, a0, a1); // daddu a0, a0, a1 + //beq r0, r0, L132 // beq r0, r0, L132 + // nop // sll r0, r0, 0 + goto block_27; // branch always + + +block_26: + get_fake_spad_addr2(a1, cache.fake_scratchpad_data, 0, c);// lui a1, 28672 + c->lwu(a1, 52, a1); // lwu a1, 52(a1) + c->daddiu(a1, a1, 24); // daddiu a1, a1, 24 + c->addiu(a2, r0, 48); // addiu a2, r0, 48 + c->multu3(a0, a2, a0); // multu3 a0, a2, a0 + c->daddu(a0, a1, a0); // daddu a0, a1, a0 + +block_27: + get_fake_spad_addr2(a1, cache.fake_scratchpad_data, 0, c);// lui a1, 28672 + c->sw(a0, 48, a1); // sw a0, 48(a1) + c->lwu(a1, 4, a0); // lwu a1, 4(a0) + bc = c->sgpr64(a1) == 0; // beq a1, r0, L133 + c->mov64(a2, s7); // or a2, s7, r0 + if (bc) {goto block_29;} // branch non-likely + + c->sw(s1, 0, a1); // sw s1, 0(a1) + c->mov64(a1, s1); // or a1, s1, r0 + +block_29: + c->lwu(a1, 0, a0); // lwu a1, 0(a0) + bc = c->sgpr64(a1) != 0; // bne a1, r0, L134 + c->mov64(a1, s7); // or a1, s7, r0 + if (bc) {goto block_31;} // branch non-likely + + c->sw(s1, 0, a0); // sw s1, 0(a0) + c->mov64(a1, s1); // or a1, s1, r0 + +block_31: + c->daddiu(a1, s1, 12); // daddiu a1, s1, 12 + c->sw(a1, 4, a0); // sw a1, 4(a0) + c->dsll(a0, s4, 3); // dsll a0, s4, 3 + c->daddiu(a0, a0, 124); // daddiu a0, a0, 124 + c->daddu(a0, a0, v1); // daddu a0, a0, v1 + c->lwu(a1, 0, a0); // lwu a1, 0(a0) + c->sw(a1, 160, s1); // sw a1, 160(s1) + c->lbu(a1, 5, a0); // lbu a1, 5(a0) + c->sb(a1, 183, s1); // sb a1, 183(s1) + c->lbu(a0, 7, a0); // lbu a0, 7(a0) + c->sb(a0, 186, s1); // sb a0, 186(s1) + c->lw(v1, 112, v1); // lw v1, 112(v1) + c->sb(v1, 168, s1); // sb v1, 168(s1) + get_fake_spad_addr2(v1, cache.fake_scratchpad_data, 0, c);// lui v1, 28672 + c->lwu(v1, 16, v1); // lwu v1, 16(v1) + c->sb(v1, 169, s1); // sb v1, 169(s1) + bc = c->sgpr64(v1) == 0; // beq v1, r0, L135 + c->mov64(v1, s7); // or v1, s7, r0 + if (bc) {goto block_33;} // branch non-likely + + c->sb(r0, 168, s1); // sb r0, 168(s1) + c->gprs[v1].du64[0] = 0; // or v1, r0, r0 + +block_33: + c->sb(r0, 170, s1); // sb r0, 170(s1) + c->addiu(v1, r0, 1); // addiu v1, r0, 1 + c->sb(v1, 171, s1); // sb v1, 171(s1) + c->sh(r0, 172, s1); // sh r0, 172(s1) + c->addiu(v1, r0, 255); // addiu v1, r0, 255 + c->sb(v1, 184, s1); // sb v1, 184(s1) + c->addiu(v1, r0, 0); // addiu v1, r0, 0 + c->lbu(a0, 17, s2); // lbu a0, 17(s2) + c->andi(a0, a0, 2); // andi a0, a0, 2 + bc = c->sgpr64(a0) == 0; // beq a0, r0, L136 + c->mov64(a0, s7); // or a0, s7, r0 + if (bc) {goto block_35;} // branch non-likely + + c->addiu(v1, r0, 1); // addiu v1, r0, 1 + c->mov64(a0, v1); // or a0, v1, r0 + +block_35: + c->lhu(a0, 4, gp); // lhu a0, 4(gp) + c->andi(a0, a0, 1024); // andi a0, a0, 1024 + if (((s64)c->sgpr64(a0)) != ((s64)0)) { // bnel a0, r0, L137 + c->daddiu(a0, s7, 4); // daddiu a0, s7, 4 + goto block_40; + } + +block_37: + c->lhu(a0, 4, gp); // lhu a0, 4(gp) + c->andi(a0, a0, 2048); // andi a0, a0, 2048 + if (((s64)c->sgpr64(a0)) == ((s64)0)) { // beql a0, r0, L137 + c->mov64(a0, s7); // or a0, s7, r0 + goto block_40; + } + +block_39: + c->daddiu(a0, s7, 4); // daddiu a0, s7, 4 + c->lbu(a1, 17, s2); // lbu a1, 17(s2) + c->andi(a1, a1, 64); // andi a1, a1, 64 + c->movz(a0, s7, a1); // movz a0, s7, a1 + +block_40: + bc = c->sgpr64(s7) == c->sgpr64(a0); // beq s7, a0, L138 + c->mov64(a0, s7); // or a0, s7, r0 + if (bc) {goto block_42;} // branch non-likely + + c->lbu(v1, 206, gp); // lbu v1, 206(gp) + c->sb(v1, 184, s1); // sb v1, 184(s1) + c->addiu(v1, r0, 1); // addiu v1, r0, 1 + c->mov64(a0, v1); // or a0, v1, r0 + +block_42: + c->lbu(a0, 7, gp); // lbu a0, 7(gp) + c->andi(a0, a0, 128); // andi a0, a0, 128 + if (((s64)c->sgpr64(a0)) == ((s64)0)) { // beql a0, r0, L139 + c->mov64(a0, s7); // or a0, s7, r0 + goto block_45; + } + +block_44: + c->daddiu(a0, s7, 4); // daddiu a0, s7, 4 + c->dsll(a1, s4, 5); // dsll a1, s4, 5 + c->daddu(a1, s5, a1); // daddu a1, s5, a1 + c->lbu(a1, 199, a1); // lbu a1, 199(a1) + c->andi(a1, a1, 8); // andi a1, a1, 8 + c->movn(a0, s7, a1); // movn a0, s7, a1 + +block_45: + bc = c->sgpr64(s7) == c->sgpr64(a0); // beq s7, a0, L140 + c->mov64(a0, s7); // or a0, s7, r0 + if (bc) {goto block_47;} // branch non-likely + + c->ori(v1, v1, 2); // ori v1, v1, 2 + c->mov64(a0, v1); // or a0, v1, r0 + +block_47: + c->sb(v1, 180, s1); // sb v1, 180(s1) + c->lbu(v1, 17, s2); // lbu v1, 17(s2) + c->andi(v1, v1, 64); // andi v1, v1, 64 + bc = c->sgpr64(v1) == 0; // beq v1, r0, L141 + // nop // sll r0, r0, 0 + if (bc) {goto block_49;} // branch non-likely + + c->addiu(v1, r0, 4); // addiu v1, r0, 4 + c->sb(v1, 185, s1); // sb v1, 185(s1) + //beq r0, r0, L143 // beq r0, r0, L143 + // nop // sll r0, r0, 0 + goto block_52; // branch always + + +block_49: + c->lhu(v1, 4, gp); // lhu v1, 4(gp) + c->andi(v1, v1, 8192); // andi v1, v1, 8192 + bc = c->sgpr64(v1) == 0; // beq v1, r0, L142 + // nop // sll r0, r0, 0 + if (bc) {goto block_51;} // branch non-likely + + c->addiu(v1, r0, 4); // addiu v1, r0, 4 + c->sb(v1, 185, s1); // sb v1, 185(s1) + //beq r0, r0, L143 // beq r0, r0, L143 + // nop // sll r0, r0, 0 + goto block_52; // branch always + + +block_51: + c->sb(r0, 185, s1); // sb r0, 185(s1) + c->gprs[v1].du64[0] = 0; // or v1, r0, r0 + +block_52: + c->lbu(v1, 92, gp); // lbu v1, 92(gp) + bc = c->sgpr64(v1) == 0; // beq v1, r0, L144 + c->mov64(v1, s7); // or v1, s7, r0 + if (bc) {goto block_54;} // branch non-likely + + c->load_symbol2(t9, cache.foreground_generic_merc_death);// lw t9, foreground-generic-merc-death(s7) + c->mov64(a0, gp); // or a0, gp, r0 + c->mov64(a1, s1); // or a1, s1, r0 + call_addr = c->gprs[t9].du32[0]; // function call: + c->sll(v0, ra, 0); // sll v0, ra, 0 + c->jalr(call_addr); // jalr ra, t9 + c->mov64(v1, v0); // or v1, v0, r0 + +block_54: + c->sw(r0, 164, s1); // sw r0, 164(s1) + c->lbu(v1, 17, s2); // lbu v1, 17(s2) + c->andi(v1, v1, 4); // andi v1, v1, 4 + if (((s64)c->sgpr64(v1)) == ((s64)0)) { // beql v1, r0, L145 + c->mov64(v1, s7); // or v1, s7, r0 + goto block_59; + } + +block_56: + c->lwu(v1, 80, gp); // lwu v1, 80(gp) + if (((s64)c->sgpr64(s7)) == ((s64)c->sgpr64(v1))) {// beql s7, v1, L145 + c->mov64(v1, v1); // or v1, v1, r0 + goto block_59; + } + +block_58: + c->lwu(v1, 80, gp); // lwu v1, 80(gp) + c->lwu(v1, 28, v1); // lwu v1, 28(v1) + +block_59: + bc = c->sgpr64(s7) == c->sgpr64(v1); // beq s7, v1, L146 + c->mov64(v1, s7); // or v1, s7, r0 + if (bc) {goto block_61;} // branch non-likely + + c->lwu(v1, 80, gp); // lwu v1, 80(gp) + c->lwu(v1, 32, v1); // lwu v1, 32(v1) + c->sw(v1, 164, s1); // sw v1, 164(s1) + +block_61: + c->daddiu(a0, s1, 256); // daddiu a0, s1, 256 + c->mov64(a1, s2); // or a1, s2, r0 + c->addiu(v1, r0, 2); // addiu v1, r0, 2 + c->daddiu(a2, v1, -4); // daddiu a2, v1, -4 + c->mov64(a0, a0); // or a0, a0, r0 + bc = ((s64)c->sgpr64(a2)) < 0; // bltz a2, L148 + c->mov64(a1, a1); // or a1, a1, r0 + if (bc) {goto block_63;} // branch non-likely + + +block_62: + // nop // sll r0, r0, 0 + c->lq(t1, 0, a1); // lq t1, 0(a1) + // nop // sll r0, r0, 0 + c->lq(a2, 16, a1); // lq a2, 16(a1) + c->daddiu(v1, v1, -4); // daddiu v1, v1, -4 + c->lq(a3, 32, a1); // lq a3, 32(a1) + c->daddiu(a0, a0, 64); // daddiu a0, a0, 64 + c->lq(t0, 48, a1); // lq t0, 48(a1) + c->daddiu(a1, a1, 64); // daddiu a1, a1, 64 + c->sq(t1, -64, a0); // sq t1, -64(a0) + c->daddiu(t1, v1, -4); // daddiu t1, v1, -4 + c->sq(a2, -48, a0); // sq a2, -48(a0) + // nop // sll r0, r0, 0 + c->sq(a3, -32, a0); // sq a3, -32(a0) + bc = ((s64)c->sgpr64(t1)) >= 0; // bgez t1, L147 + c->sq(t0, -16, a0); // sq t0, -16(a0) + if (bc) {goto block_62;} // branch non-likely + + +block_63: + bc = c->sgpr64(v1) == 0; // beq v1, r0, L149 + c->lq(a2, 0, a1); // lq a2, 0(a1) + if (bc) {goto block_68;} // branch non-likely + + c->daddiu(a1, a1, 16); // daddiu a1, a1, 16 + c->daddiu(a0, a0, 16); // daddiu a0, a0, 16 + c->daddiu(v1, v1, -1); // daddiu v1, v1, -1 + c->sq(a2, -16, a0); // sq a2, -16(a0) + bc = c->sgpr64(v1) == 0; // beq v1, r0, L149 + c->lq(a2, 0, a1); // lq a2, 0(a1) + if (bc) {goto block_68;} // branch non-likely + + c->daddiu(a1, a1, 16); // daddiu a1, a1, 16 + c->daddiu(a0, a0, 16); // daddiu a0, a0, 16 + c->daddiu(v1, v1, -1); // daddiu v1, v1, -1 + c->sq(a2, -16, a0); // sq a2, -16(a0) + bc = c->sgpr64(v1) == 0; // beq v1, r0, L149 + c->lq(a2, 0, a1); // lq a2, 0(a1) + if (bc) {goto block_68;} // branch non-likely + + c->daddiu(a1, a1, 16); // daddiu a1, a1, 16 + c->daddiu(a0, a0, 16); // daddiu a0, a0, 16 + c->daddiu(v1, v1, -1); // daddiu v1, v1, -1 + c->sq(a2, -16, a0); // sq a2, -16(a0) + bc = c->sgpr64(v1) == 0; // beq v1, r0, L149 + c->lq(a2, 0, a1); // lq a2, 0(a1) + if (bc) {goto block_68;} // branch non-likely + + c->daddiu(a1, a1, 16); // daddiu a1, a1, 16 + c->daddiu(a0, a0, 16); // daddiu a0, a0, 16 + c->daddiu(v1, v1, -1); // daddiu v1, v1, -1 + c->sq(a2, -16, a0); // sq a2, -16(a0) + +block_68: + c->gprs[v1].du64[0] = 0; // or v1, r0, r0 + c->addiu(v1, r0, 18); // addiu v1, r0, 18 + c->lwu(a0, 28, s2); // lwu a0, 28(s2) + if (((s64)c->sgpr64(a0)) == ((s64)0)) { // beql a0, r0, L150 + c->mov64(a0, s7); // or a0, s7, r0 + goto block_71; + } + +block_70: + c->daddiu(a0, s7, 4); // daddiu a0, s7, 4 + c->lwu(a1, 28, s2); // lwu a1, 28(s2) + c->lbu(a1, 1, a1); // lbu a1, 1(a1) + c->movz(a0, s7, a1); // movz a0, s7, a1 + +block_71: + bc = c->sgpr64(s7) == c->sgpr64(a0); // beq s7, a0, L154 + c->mov64(a0, s7); // or a0, s7, r0 + if (bc) {goto block_80;} // branch non-likely + + c->addiu(a0, r0, 1); // addiu a0, r0, 1 + c->sb(a0, 170, s1); // sb a0, 170(s1) + c->daddiu(a1, s1, 288); // daddiu a1, s1, 288 + c->lwu(a0, 28, s2); // lwu a0, 28(s2) + c->lwu(a2, 28, s2); // lwu a2, 28(s2) + c->lbu(a2, 1, a2); // lbu a2, 1(a2) + c->dsll(a2, a2, 4); // dsll a2, a2, 4 + c->daddu(a2, a0, a2); // daddu a2, a0, a2 + c->addiu(a0, r0, 5); // addiu a0, r0, 5 + c->daddiu(a3, a0, -4); // daddiu a3, a0, -4 + c->mov64(a1, a1); // or a1, a1, r0 + bc = ((s64)c->sgpr64(a3)) < 0; // bltz a3, L152 + c->mov64(a2, a2); // or a2, a2, r0 + if (bc) {goto block_74;} // branch non-likely + + +block_73: + // nop // sll r0, r0, 0 + c->lq(t2, 0, a2); // lq t2, 0(a2) + // nop // sll r0, r0, 0 + c->lq(a3, 16, a2); // lq a3, 16(a2) + c->daddiu(a0, a0, -4); // daddiu a0, a0, -4 + c->lq(t0, 32, a2); // lq t0, 32(a2) + c->daddiu(a1, a1, 64); // daddiu a1, a1, 64 + c->lq(t1, 48, a2); // lq t1, 48(a2) + c->daddiu(a2, a2, 64); // daddiu a2, a2, 64 + c->sq(t2, -64, a1); // sq t2, -64(a1) + c->daddiu(t2, a0, -4); // daddiu t2, a0, -4 + c->sq(a3, -48, a1); // sq a3, -48(a1) + // nop // sll r0, r0, 0 + c->sq(t0, -32, a1); // sq t0, -32(a1) + bc = ((s64)c->sgpr64(t2)) >= 0; // bgez t2, L151 + c->sq(t1, -16, a1); // sq t1, -16(a1) + if (bc) {goto block_73;} // branch non-likely + + +block_74: + bc = c->sgpr64(a0) == 0; // beq a0, r0, L153 + c->lq(a3, 0, a2); // lq a3, 0(a2) + if (bc) {goto block_79;} // branch non-likely + + c->daddiu(a2, a2, 16); // daddiu a2, a2, 16 + c->daddiu(a1, a1, 16); // daddiu a1, a1, 16 + c->daddiu(a0, a0, -1); // daddiu a0, a0, -1 + c->sq(a3, -16, a1); // sq a3, -16(a1) + bc = c->sgpr64(a0) == 0; // beq a0, r0, L153 + c->lq(a3, 0, a2); // lq a3, 0(a2) + if (bc) {goto block_79;} // branch non-likely + + c->daddiu(a2, a2, 16); // daddiu a2, a2, 16 + c->daddiu(a1, a1, 16); // daddiu a1, a1, 16 + c->daddiu(a0, a0, -1); // daddiu a0, a0, -1 + c->sq(a3, -16, a1); // sq a3, -16(a1) + bc = c->sgpr64(a0) == 0; // beq a0, r0, L153 + c->lq(a3, 0, a2); // lq a3, 0(a2) + if (bc) {goto block_79;} // branch non-likely + + c->daddiu(a2, a2, 16); // daddiu a2, a2, 16 + c->daddiu(a1, a1, 16); // daddiu a1, a1, 16 + c->daddiu(a0, a0, -1); // daddiu a0, a0, -1 + c->sq(a3, -16, a1); // sq a3, -16(a1) + bc = c->sgpr64(a0) == 0; // beq a0, r0, L153 + c->lq(a3, 0, a2); // lq a3, 0(a2) + if (bc) {goto block_79;} // branch non-likely + + c->daddiu(a2, a2, 16); // daddiu a2, a2, 16 + c->daddiu(a1, a1, 16); // daddiu a1, a1, 16 + c->daddiu(a0, a0, -1); // daddiu a0, a0, -1 + c->sq(a3, -16, a1); // sq a3, -16(a1) + +block_79: + c->gprs[a0].du64[0] = 0; // or a0, r0, r0 + c->daddiu(v1, v1, 5); // daddiu v1, v1, 5 + c->mov64(a0, v1); // or a0, v1, r0 + +block_80: + c->lui(a0, 4096); // lui a0, 4096 + c->daddiu(a1, v1, -1); // daddiu a1, v1, -1 + c->dsll32(a1, a1, 16); // dsll32 a1, a1, 16 + c->dsrl32(a1, a1, 16); // dsrl32 a1, a1, 16 + c->or_(a0, a0, a1); // or a0, a0, a1 + c->sd(a0, 0, s1); // sd a0, 0(s1) + c->sw(v1, 8, s1); // sw v1, 8(s1) + c->sw(r0, 12, s1); // sw r0, 12(s1) + c->dsll(v1, v1, 4); // dsll v1, v1, 4 + c->daddu(a1, s3, v1); // daddu a1, s3, v1 + c->mov64(v1, a1); // or v1, a1, r0 + get_fake_spad_addr2(v1, cache.fake_scratchpad_data, 0, c);// lui v1, 28672 + c->lwu(a2, 48, v1); // lwu a2, 48(v1) + c->load_symbol2(t9, cache.foreground_generic_merc_add_fragments);// lw t9, foreground-generic-merc-add-fragments(s7) + c->mov64(a0, s2); // or a0, s2, r0 + call_addr = c->gprs[t9].du32[0]; // function call: + c->sll(v0, ra, 0); // sll v0, ra, 0 + c->jalr(call_addr); // jalr ra, t9 + c->mov64(s3, v0); // or s3, v0, r0 + c->mov64(v1, s3); // or v1, s3, r0 + +block_81: + c->daddiu(s4, s4, 1); // daddiu s4, s4, 1 + +block_82: + c->lwu(v1, 68, s5); // lwu v1, 68(s5) + c->slt(v1, s4, v1); // slt v1, s4, v1 + bc = c->sgpr64(v1) != 0; // bne v1, r0, L120 + // nop // sll r0, r0, 0 + if (bc) {goto block_1;} // branch non-likely + + c->mov64(v1, s7); // or v1, s7, r0 + c->mov64(v1, s7); // or v1, s7, r0 + c->mov64(v0, s3); // or v0, s3, r0 + c->ld(ra, 0, sp); // ld ra, 0(sp) + c->lq(gp, 96, sp); // lq gp, 96(sp) + c->lq(s5, 80, sp); // lq s5, 80(sp) + c->lq(s4, 64, sp); // lq s4, 64(sp) + c->lq(s3, 48, sp); // lq s3, 48(sp) + c->lq(s2, 32, sp); // lq s2, 32(sp) + c->lq(s1, 16, sp); // lq s1, 16(sp) + //jr ra // jr ra + c->daddiu(sp, sp, 112); // daddiu sp, sp, 112 + goto end_of_function; // return + + // nop // sll r0, r0, 0 + // nop // sll r0, r0, 0 + // nop // sll r0, r0, 0 +end_of_function: + return c->gprs[v0].du64[0]; +} + +void link() { + cache.fake_scratchpad_data = intern_from_c(-1, 0, "*fake-scratchpad-data*").c(); + cache.foreground = intern_from_c(-1, 0, "*foreground*").c(); + cache.merc_global_stats = intern_from_c(-1, 0, "*merc-global-stats*").c(); + cache.foreground_generic_merc_add_fragments = intern_from_c(-1, 0, "foreground-generic-merc-add-fragments").c(); + cache.foreground_generic_merc_death = intern_from_c(-1, 0, "foreground-generic-merc-death").c(); + gLinkedFunctionTable.reg("foreground-generic-merc", execute, 256); +} + +} // namespace foreground_generic_merc +} // namespace Mips2C +// add foreground_generic_merc::link to the link callback table for the object file. +// FWD DEC: diff --git a/game/mips2c/jak3_functions/joint.cpp b/game/mips2c/jak3_functions/joint.cpp new file mode 100644 index 00000000000..d5a71407017 --- /dev/null +++ b/game/mips2c/jak3_functions/joint.cpp @@ -0,0 +1,162 @@ + +//--------------------------MIPS2C--------------------- +#include "game/mips2c/mips2c_private.h" + +namespace Mips2C::jak3 { +// main function for (parent bone, transformq) -> child bone +// this is used to compute world-space bones, used for collision and similar. +// This includes the weird w divisor thing +// This does not take into account the bind pose for mesh drawing. +// (that's handled in bones.gc, which combines this with the bind pose to get the merc/pris matrix) +namespace cspace_parented_transformq_joint { +u64 execute(void* ctxt) { + auto* c = (ExecutionContext*)ctxt; + bool bc = false; + // nop // sll r0, r0, 0 + c->lw(a3, 0, a0); // lw a3, 0(a0) + c->lui(v1, 16256); // lui v1, 16256 + c->lqc2(vf5, 16, a1); // lqc2 vf5, 16(a1) + c->mtc1(f0, v1); // mtc1 f0, v1 + c->lw(t0, 16, a3); // lw t0, 16(a3) + // nop // sll r0, r0, 0 + c->lw(a2, 16, a0); // lw a2, 16(a0) + c->vadd(DEST::xyzw, vf6, vf5, vf5); // vadd.xyzw vf6, vf5, vf5 + c->lwc1(f1, 64, t0); // lwc1 f1, 64(t0) + c->vadd_bc(DEST::x, BC::w, vf2, vf0, vf5); // vaddw.x vf2, vf0, vf5 + c->lqc2(vf15, 0, a1); // lqc2 vf15, 0(a1) + c->vadd_bc(DEST::y, BC::z, vf2, vf0, vf5); // vaddz.y vf2, vf0, vf5 + c->lqc2(vf1, 32, a1); // lqc2 vf1, 32(a1) + c->divs_accurate(f4, f0, f1); // div.s f4, f0, f1 + c->lqc2(vf7, 0, t0); // lqc2 vf7, 0(t0) + c->vsub_bc(DEST::z, BC::y, vf2, vf0, vf5); // vsuby.z vf2, vf0, vf5 + c->lqc2(vf8, 16, t0); // lqc2 vf8, 16(t0) + // sets vf2.w to 0 + c->vsub_bc(DEST::w, BC::w, vf2, vf0, vf0); // vsubw.w vf2, vf0, vf0 + c->lqc2(vf9, 32, t0); // lqc2 vf9, 32(t0) + c->vsub_bc(DEST::x, BC::z, vf3, vf0, vf5); // vsubz.x vf3, vf0, vf5 + c->lqc2(vf10, 48, t0); // lqc2 vf10, 48(t0) + c->vadd_bc(DEST::y, BC::w, vf3, vf0, vf5); // vaddw.y vf3, vf0, vf5 + c->lwc1(f2, 68, t0); // lwc1 f2, 68(t0) + c->vadd_bc(DEST::z, BC::x, vf3, vf0, vf5); // vaddx.z vf3, vf0, vf5 + c->sqc2(vf1, 64, a2); // sqc2 vf1, 64(a2) + c->vsub_bc(DEST::w, BC::w, vf3, vf0, vf0); // vsubw.w vf3, vf0, vf0 + c->lwc1(f3, 72, t0); // lwc1 f3, 72(t0) + c->vadd_bc(DEST::x, BC::y, vf4, vf0, vf5); // vaddy.x vf4, vf0, vf5 + c->lw(v1, 76, t0); // lw v1, 76(t0) + c->vsub_bc(DEST::y, BC::x, vf4, vf0, vf5); // vsubx.y vf4, vf0, vf5 + c->mfc1(t1, f4); // mfc1 t1, f4 + c->vadd_bc(DEST::z, BC::w, vf4, vf0, vf5); // vaddw.z vf4, vf0, vf5 + c->divs_accurate(f4, f0, f2); // div.s f4, f0, f2 + c->vsub_bc(DEST::w, BC::w, vf4, vf0, vf0); // vsubw.w vf4, vf0, vf0 + c->vopmula(vf6, vf2); // vopmula.xyz acc, vf6, vf2 + c->vopmsub(vf2, vf2, vf6); // vopmsub.xyz vf2, vf2, vf6 + c->vopmula(vf6, vf3); // vopmula.xyz acc, vf6, vf3 + c->vopmsub(vf3, vf3, vf6); // vopmsub.xyz vf3, vf3, vf6 + c->vopmula(vf6, vf4); // vopmula.xyz acc, vf6, vf4 + c->vopmsub(vf4, vf4, vf6); // vopmsub.xyz vf4, vf4, vf6 + c->vadd_bc(DEST::x, BC::w, vf2, vf2, vf0); // vaddw.x vf2, vf2, vf0 + c->vadd_bc(DEST::y, BC::w, vf3, vf3, vf0); // vaddw.y vf3, vf3, vf0 + c->vadd_bc(DEST::z, BC::w, vf4, vf4, vf0); // vaddw.z vf4, vf4, vf0 + c->mfc1(t2, f4); // mfc1 t2, f4 + bc = c->sgpr64(v1) != 0; // bne v1, r0, L50 + c->divs_accurate(f4, f0, f3); // div.s f4, f0, f3 + if (bc) { + goto block_2; + } // branch non-likely + + c->vmul_bc(DEST::xyzw, BC::x, vf2, vf2, vf1); // vmulx.xyzw vf2, vf2, vf1 + c->vmul_bc(DEST::xyzw, BC::y, vf3, vf3, vf1); // vmuly.xyzw vf3, vf3, vf1 + c->vmul_bc(DEST::xyzw, BC::z, vf4, vf4, vf1); // vmulz.xyzw vf4, vf4, vf1 + c->vmula_bc(DEST::xyzw, BC::x, vf7, vf2); // vmulax.xyzw acc, vf7, vf2 + c->vmadda_bc(DEST::xyzw, BC::y, vf8, vf2); // vmadday.xyzw acc, vf8, vf2 + c->vmadda_bc(DEST::xyzw, BC::z, vf9, vf2); // vmaddaz.xyzw acc, vf9, vf2 + c->vmadd_bc(DEST::xyzw, BC::w, vf11, vf10, vf2); // vmaddw.xyzw vf11, vf10, vf2 + c->vmula_bc(DEST::xyzw, BC::x, vf7, vf3); // vmulax.xyzw acc, vf7, vf3 + c->vmadda_bc(DEST::xyzw, BC::y, vf8, vf3); // vmadday.xyzw acc, vf8, vf3 + c->vmadda_bc(DEST::xyzw, BC::z, vf9, vf3); // vmaddaz.xyzw acc, vf9, vf3 + c->vmadd_bc(DEST::xyzw, BC::w, vf12, vf10, vf3); // vmaddw.xyzw vf12, vf10, vf3 + c->vmula_bc(DEST::xyzw, BC::x, vf7, vf4); // vmulax.xyzw acc, vf7, vf4 + c->vmadda_bc(DEST::xyzw, BC::y, vf8, vf4); // vmadday.xyzw acc, vf8, vf4 + c->vmadda_bc(DEST::xyzw, BC::z, vf9, vf4); // vmaddaz.xyzw acc, vf9, vf4 + c->vmadd_bc(DEST::xyzw, BC::w, vf13, vf10, vf4); // vmaddw.xyzw vf13, vf10, vf4 + c->vmula_bc(DEST::xyzw, BC::x, vf7, vf15); // vmulax.xyzw acc, vf7, vf15 + c->vmadda_bc(DEST::xyzw, BC::y, vf8, vf15); // vmadday.xyzw acc, vf8, vf15 + c->vmadda_bc(DEST::xyzw, BC::z, vf9, vf15); // vmaddaz.xyzw acc, vf9, vf15 + c->vmadd_bc(DEST::xyzw, BC::w, vf14, vf10, vf0); // vmaddw.xyzw vf14, vf10, vf0 + c->sqc2(vf11, 0, a2); // sqc2 vf11, 0(a2) + c->sqc2(vf12, 16, a2); // sqc2 vf12, 16(a2) + c->sqc2(vf13, 32, a2); // sqc2 vf13, 32(a2) + c->sqc2(vf14, 48, a2); // sqc2 vf14, 48(a2) + // jr ra // jr ra + // nop // sll r0, r0, 0 + goto end_of_function; // return + +block_2: + c->pextlw(t1, t2, t1); // pextlw t1, t2, t1 + c->vmul_bc(DEST::xyzw, BC::x, vf2, vf2, vf1); // vmulx.xyzw vf2, vf2, vf1 + c->vmul_bc(DEST::xyzw, BC::y, vf3, vf3, vf1); // vmuly.xyzw vf3, vf3, vf1 + c->vmul_bc(DEST::xyzw, BC::z, vf4, vf4, vf1); // vmulz.xyzw vf4, vf4, vf1 + // here, f4 is 1/scale. Sometimes the scale out of the joint compression code is slightly negative + // this leads to mfc1 sign extending 1's into the upper 32 bits of t3 (this is weirdly how the ps2 + // does it). + c->mfc1(t3, f4); // mfc1 t3, f4 + // and this brings those ones into bits 96-128 + c->pcpyld(t1, t3, t1); // pcpyld t1, t3, t1 + // so here, vf16.w is usually 0, except for when the scale is negative, then it's 0xffff'ffff + // (NaN on x86, -BIG on PS2) + c->mov128_vf_gpr(vf16, t1); // qmtc2.i vf16, t1 + // here, vf2/3/4's w's are all 0. On PS2, this always keeps them as 0. + // but on x86, this propagates NaNs: 0 * NaN = NaN. + // so: + c->vfs[vf16].vf.w() = 0; // PATCH to clear invalid float that will be multiplied by 0 below + // (this might seem weird because the multiplication sequence could have 3 instructions removed + // because we know that vf2/3/4.w are all 0. But maybe this is just copy-pasted, or it didn't + // really matter because it would have stalled in place of that 1 cycle instruction because + // multiplication latency is 4). + + c->vmul(DEST::xyzw, vf2, vf2, vf16); // vmul.xyzw vf2, vf2, vf16 + c->vmul(DEST::xyzw, vf3, vf3, vf16); // vmul.xyzw vf3, vf3, vf16 + c->vmul(DEST::xyzw, vf4, vf4, vf16); // vmul.xyzw vf4, vf4, vf16 + c->vmula_bc(DEST::xyzw, BC::x, vf7, vf2); // vmulax.xyzw acc, vf7, vf2 + c->vmadda_bc(DEST::xyzw, BC::y, vf8, vf2); // vmadday.xyzw acc, vf8, vf2 + c->vmadda_bc(DEST::xyzw, BC::z, vf9, vf2); // vmaddaz.xyzw acc, vf9, vf2 + c->vmadd_bc(DEST::xyzw, BC::w, vf11, vf10, vf2); // vmaddw.xyzw vf11, vf10, vf2 + c->vmula_bc(DEST::xyzw, BC::x, vf7, vf3); // vmulax.xyzw acc, vf7, vf3 + c->vmadda_bc(DEST::xyzw, BC::y, vf8, vf3); // vmadday.xyzw acc, vf8, vf3 + c->vmadda_bc(DEST::xyzw, BC::z, vf9, vf3); // vmaddaz.xyzw acc, vf9, vf3 + c->vmadd_bc(DEST::xyzw, BC::w, vf12, vf10, vf3); // vmaddw.xyzw vf12, vf10, vf3 + c->vmula_bc(DEST::xyzw, BC::x, vf7, vf4); // vmulax.xyzw acc, vf7, vf4 + c->vmadda_bc(DEST::xyzw, BC::y, vf8, vf4); // vmadday.xyzw acc, vf8, vf4 + c->vmadda_bc(DEST::xyzw, BC::z, vf9, vf4); // vmaddaz.xyzw acc, vf9, vf4 + c->vmadd_bc(DEST::xyzw, BC::w, vf13, vf10, vf4); // vmaddw.xyzw vf13, vf10, vf4 + c->vmula_bc(DEST::xyzw, BC::x, vf7, vf15); // vmulax.xyzw acc, vf7, vf15 + c->vmadda_bc(DEST::xyzw, BC::y, vf8, vf15); // vmadday.xyzw acc, vf8, vf15 + c->vmadda_bc(DEST::xyzw, BC::z, vf9, vf15); // vmaddaz.xyzw acc, vf9, vf15 + c->vmadd_bc(DEST::xyzw, BC::w, vf14, vf10, vf0); // vmaddw.xyzw vf14, vf10, vf0 + c->sqc2(vf11, 0, a2); // sqc2 vf11, 0(a2) + c->sqc2(vf12, 16, a2); // sqc2 vf12, 16(a2) + c->sqc2(vf13, 32, a2); // sqc2 vf13, 32(a2) + c->sqc2(vf14, 48, a2); // sqc2 vf14, 48(a2) + // jr ra // jr ra + // nop // sll r0, r0, 0 + goto end_of_function; // return + + // jr ra // jr ra + c->daddu(sp, sp, r0); // daddu sp, sp, r0 + goto end_of_function; // return + +// nop // sll r0, r0, 0 +// nop // sll r0, r0, 0 +// nop // sll r0, r0, 0 +end_of_function: + return c->gprs[v0].du64[0]; +} + +void link() { + gLinkedFunctionTable.reg("cspace<-parented-transformq-joint!", execute, 128); +} + +} // namespace cspace_parented_transformq_joint +} // namespace Mips2C::jak3 + // add cspace<_parented_transformq_joint::link to the link callback table for the object file. + // FWD DEC: \ No newline at end of file diff --git a/game/mips2c/jak3_functions/lights.cpp b/game/mips2c/jak3_functions/lights.cpp index 8b45194523e..2eb02c32968 100644 --- a/game/mips2c/jak3_functions/lights.cpp +++ b/game/mips2c/jak3_functions/lights.cpp @@ -12,7 +12,6 @@ struct Cache { u64 execute(void* ctxt) { auto* c = (ExecutionContext*)ctxt; bool bc = false; - u32 call_addr = 0; c->daddiu(sp, sp, -48); // daddiu sp, sp, -48 c->sd(ra, 0, sp); // sd ra, 0(sp) c->daddiu(t0, sp, 16); // daddiu t0, sp, 16 @@ -158,7 +157,6 @@ struct Cache { u64 execute(void* ctxt) { auto* c = (ExecutionContext*)ctxt; bool bc = false; - u32 call_addr = 0; c->daddiu(sp, sp, -48); // daddiu sp, sp, -48 c->daddiu(v1, sp, 16); // daddiu v1, sp, 16 // nop // sll r0, r0, 0 @@ -294,7 +292,6 @@ namespace add_light_sphere_to_light_group { u64 execute(void* ctxt) { auto* c = (ExecutionContext*)ctxt; bool bc = false; - u32 call_addr = 0; bool cop1_bc = false; // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 @@ -700,7 +697,6 @@ namespace light_hash_get_bucket_index { u64 execute(void* ctxt) { auto* c = (ExecutionContext*)ctxt; bool bc = false; - u32 call_addr = 0; c->daddiu(sp, sp, -32); // daddiu sp, sp, -32 c->daddiu(v1, sp, 16); // daddiu v1, sp, 16 // nop // sll r0, r0, 0 diff --git a/game/mips2c/jak3_functions/texture.cpp b/game/mips2c/jak3_functions/texture.cpp new file mode 100644 index 00000000000..7fe6f0278e2 --- /dev/null +++ b/game/mips2c/jak3_functions/texture.cpp @@ -0,0 +1,188 @@ +//--------------------------MIPS2C--------------------- +// clang-format off +#include "game/mips2c/mips2c_private.h" +#include "game/kernel/jak3/kscheme.h" +using ::jak3::intern_from_c; +namespace Mips2C::jak3 { +namespace adgif_shader_texture_with_update { +u64 execute(void* ctxt) { + auto* c = (ExecutionContext*)ctxt; + bool bc = false; + c->ld(a2, 16, a0); // ld a2, 16(a0) + c->addiu(v1, r0, 256); // addiu v1, r0, 256 + c->andi(a2, a2, 513); // andi a2, a2, 513 + c->mtc1(f0, v1); // mtc1 f0, v1 + c->cvtsw(f0, f0); // cvt.s.w f0, f0 + c->lbu(v1, 4, a1); // lbu v1, 4(a1) + c->lwc1(f1, 44, a1); // lwc1 f1, 44(a1) + c->daddiu(v1, v1, -1); // daddiu v1, v1, -1 + c->divs(f0, f0, f1); // div.s f0, f0, f1 + c->dsll(v1, v1, 2); // dsll v1, v1, 2 + c->or_(a2, a2, v1); // or a2, a2, v1 + c->lbu(v1, 7, a1); // lbu v1, 7(a1) + c->dsll(v1, v1, 19); // dsll v1, v1, 19 + c->lbu(a3, 5, a1); // lbu a3, 5(a1) + c->or_(a2, a2, v1); // or a2, a2, v1 + c->dsll(a3, a3, 5); // dsll a3, a3, 5 + c->or_(a2, a2, a3); // or a2, a2, a3 + c->ld(t1, 0, a0); // ld t1, 0(a0) + c->dsll(t1, t1, 27); // dsll t1, t1, 27 + c->lbu(v1, 6, a1); // lbu v1, 6(a1) + c->dsra32(t1, t1, 30); // dsra32 t1, t1, 30 + c->dsll(v1, v1, 20); // dsll v1, v1, 20 + c->dsll32(t1, t1, 3); // dsll32 t1, t1, 3 + c->lhu(a3, 10, a1); // lhu a3, 10(a1) + c->or_(t1, t1, v1); // or t1, t1, v1 + c->lbu(v1, 26, a1); // lbu v1, 26(a1) + c->or_(t1, t1, a3); // or t1, t1, a3 + c->dsll(v1, v1, 14); // dsll v1, v1, 14 + c->or_(t1, t1, v1); // or t1, t1, v1 + c->lhu(v1, 0, a1); // lhu v1, 0(a1) + c->plzcw(v1, v1); // plzcw v1, v1 + c->addiu(t0, r0, 30); // addiu t0, r0, 30 + c->subu(v1, t0, v1); // subu v1, t0, v1 + c->lhu(a3, 2, a1); // lhu a3, 2(a1) + c->dsll(v1, v1, 26); // dsll v1, v1, 26 + c->plzcw(a3, a3); // plzcw a3, a3 + c->or_(t1, t1, v1); // or t1, t1, v1 + c->subu(a3, t0, a3); // subu a3, t0, a3 + c->dsll(a3, a3, 30); // dsll a3, a3, 30 + c->addiu(v1, r0, 1); // addiu v1, r0, 1 + c->or_(t1, t1, a3); // or t1, t1, a3 + c->dsll32(v1, v1, 2); // dsll32 v1, v1, 2 + c->or_(t1, t1, v1); // or t1, t1, v1 + c->lhu(v1, 24, a1); // lhu v1, 24(a1) + c->dsll32(v1, v1, 5); // dsll32 v1, v1, 5 + c->lhu(a3, 8, a1); // lhu a3, 8(a1) + c->dsll32(a3, a3, 19); // dsll32 a3, a3, 19 + c->or_(t1, t1, v1); // or t1, t1, v1 + c->or_(t1, t1, a3); // or t1, t1, a3 + c->addiu(v1, r0, 1); // addiu v1, r0, 1 + c->dsll32(v1, v1, 29); // dsll32 v1, v1, 29 + c->cvtws(f0, f0); // cvt.w.s f0, f0 + c->or_(t1, t1, v1); // or t1, t1, v1 + c->mfc1(v1, f0); // mfc1 v1, f0 + c->sd(t1, 0, a0); // sd t1, 0(a0) + c->plzcw(a3, v1); // plzcw a3, v1 + c->subu(a3, t0, a3); // subu a3, t0, a3 + c->lbu(t0, 7, a1); // lbu t0, 7(a1) + c->daddiu(t0, t0, -1); // daddiu t0, t0, -1 + // nop // sll r0, r0, 0 + bc = c->sgpr64(t0) == 0; // beq t0, r0, L43 + // nop // sll r0, r0, 0 + if (bc) {goto block_5;} // branch non-likely + + c->daddiu(t0, a3, -4); // daddiu t0, a3, -4 + c->dsll(a3, a3, 4); // dsll a3, a3, 4 + bc = ((s64)c->sgpr64(t0)) < 0; // bltz t0, L41 + c->daddiu(a3, a3, -175); // daddiu a3, a3, -175 + if (bc) {goto block_3;} // branch non-likely + + //beq r0, r0, L42 // beq r0, r0, L42 + c->dsrav(t0, v1, t0); // dsrav t0, v1, t0 + goto block_4; // branch always + + +block_3: + c->dsubu(t0, r0, t0); // dsubu t0, r0, t0 + c->dsllv(t0, v1, t0); // dsllv t0, v1, t0 + +block_4: + c->andi(t0, t0, 15); // andi t0, t0, 15 + // nop // sll r0, r0, 0 + //beq r0, r0, L46 // beq r0, r0, L46 + c->daddu(a3, a3, t0); // daddu a3, a3, t0 + goto block_9; // branch always + + +block_5: + c->daddiu(t0, a3, -5); // daddiu t0, a3, -5 + c->dsll(a3, a3, 5); // dsll a3, a3, 5 + bc = ((s64)c->sgpr64(t0)) < 0; // bltz t0, L44 + c->daddiu(a3, a3, -350); // daddiu a3, a3, -350 + if (bc) {goto block_7;} // branch non-likely + + //beq r0, r0, L45 // beq r0, r0, L45 + c->dsrav(t0, v1, t0); // dsrav t0, v1, t0 + goto block_8; // branch always + + +block_7: + c->dsubu(t0, r0, t0); // dsubu t0, r0, t0 + c->dsllv(t0, v1, t0); // dsllv t0, v1, t0 + +block_8: + c->andi(t0, t0, 31); // andi t0, t0, 31 + // nop // sll r0, r0, 0 + c->daddu(a3, a3, t0); // daddu a3, a3, t0 + // nop // sll r0, r0, 0 + +block_9: + c->andi(a3, a3, 4095); // andi a3, a3, 4095 + c->lhu(t1, 12, a1); // lhu t1, 12(a1) + c->dsll32(a3, a3, 0); // dsll32 a3, a3, 0 + c->lbu(v1, 27, a1); // lbu v1, 27(a1) + c->or_(a2, a2, a3); // or a2, a2, a3 + c->dsll(v1, v1, 14); // dsll v1, v1, 14 + c->sd(a2, 16, a0); // sd a2, 16(a0) + c->or_(a2, t1, v1); // or a2, t1, v1 + c->lhu(v1, 14, a1); // lhu v1, 14(a1) + // nop // sll r0, r0, 0 + c->lbu(a3, 28, a1); // lbu a3, 28(a1) + c->dsll(v1, v1, 20); // dsll v1, v1, 20 + c->or_(a2, a2, v1); // or a2, a2, v1 + c->dsll32(a3, a3, 2); // dsll32 a3, a3, 2 + c->or_(a2, a2, a3); // or a2, a2, a3 + c->lhu(v1, 16, a1); // lhu v1, 16(a1) + c->lbu(a3, 29, a1); // lbu a3, 29(a1) + c->dsll32(v1, v1, 8); // dsll32 v1, v1, 8 + c->or_(a2, a2, v1); // or a2, a2, v1 + c->dsll32(a3, a3, 22); // dsll32 a3, a3, 22 + c->or_(a2, a2, a3); // or a2, a2, a3 + c->lbu(t0, 4, a1); // lbu t0, 4(a1) + c->daddiu(t0, t0, -5); // daddiu t0, t0, -5 + c->sd(a2, 32, a0); // sd a2, 32(a0) + bc = ((s64)c->sgpr64(t0)) < 0; // bltz t0, L47 + c->lbu(a3, 30, a1); // lbu a3, 30(a1) + if (bc) {goto block_11;} // branch non-likely + + c->lhu(a2, 18, a1); // lhu a2, 18(a1) + c->dsll(a3, a3, 14); // dsll a3, a3, 14 + c->or_(a2, a2, a3); // or a2, a2, a3 + c->lhu(v1, 20, a1); // lhu v1, 20(a1) + c->dsll(v1, v1, 20); // dsll v1, v1, 20 + c->lbu(a3, 31, a1); // lbu a3, 31(a1) + c->or_(a2, a2, v1); // or a2, a2, v1 + c->dsll32(a3, a3, 2); // dsll32 a3, a3, 2 + c->or_(a2, a2, a3); // or a2, a2, a3 + c->lhu(v1, 22, a1); // lhu v1, 22(a1) + c->dsll32(v1, v1, 8); // dsll32 v1, v1, 8 + c->lbu(a3, 32, a1); // lbu a3, 32(a1) + c->or_(a2, a2, v1); // or a2, a2, v1 + c->dsll32(a3, a3, 22); // dsll32 a3, a3, 22 + c->or_(a2, a2, a3); // or a2, a2, a3 + c->addiu(v1, r0, 54); // addiu v1, r0, 54 + c->sd(a2, 64, a0); // sd a2, 64(a0) + // nop // sll r0, r0, 0 + c->sw(v1, 72, a0); // sw v1, 72(a0) + // nop // sll r0, r0, 0 + +block_11: + c->mov64(v0, a0); // or v0, a0, r0 + //jr ra // jr ra + c->daddu(sp, sp, r0); // daddu sp, sp, r0 + goto end_of_function; // return + + // nop // sll r0, r0, 0 + // nop // sll r0, r0, 0 +end_of_function: + return c->gprs[v0].du64[0]; +} + +void link() { + gLinkedFunctionTable.reg("adgif-shader<-texture-with-update!", execute, 128); +} + +} // namespace adgif_shader<_texture_with_update +} // namespace Mips2C + diff --git a/game/mips2c/mips2c_table.cpp b/game/mips2c/mips2c_table.cpp index d564f87a7ea..fd6f682845f 100644 --- a/game/mips2c/mips2c_table.cpp +++ b/game/mips2c/mips2c_table.cpp @@ -7,6 +7,7 @@ #include "game/kernel/common/kscheme.h" #include "game/kernel/jak1/kscheme.h" #include "game/kernel/jak2/kscheme.h" +#include "game/kernel/jak3/kscheme.h" #include "game/runtime.h" extern "C" { @@ -281,6 +282,14 @@ namespace method_9_font_work { extern void link(); } namespace draw_string_asm { extern void link(); } namespace get_string_length { extern void link(); } namespace method_9_prim_strip { extern void link(); } +namespace adgif_shader_texture_with_update { extern void link(); } +namespace moving_sphere_triangle_intersect { extern void link(); } +namespace collide_do_primitives { extern void link(); } +namespace cspace_parented_transformq_joint { extern void link(); } +namespace foreground_check_longest_edge_asm { extern void link(); } +namespace foreground_merc { extern void link(); } +namespace foreground_generic_merc { extern void link(); } + } // clang-format on @@ -466,7 +475,14 @@ PerGameVersion>> gMips2C jak3::generic_no_light_proc::link}}, {"font", {jak3::method_9_font_work::link, jak3::draw_string_asm::link, jak3::get_string_length::link}}, - {"prim", {jak3::method_9_prim_strip::link}}}}; + {"texture", {jak3::adgif_shader_texture_with_update::link}}, + {"collide-func", + {jak3::moving_sphere_triangle_intersect::link, jak3::collide_do_primitives::link}}, + {"prim", {jak3::method_9_prim_strip::link}}, + {"joint", {jak3::cspace_parented_transformq_joint::link}}, + {"foreground", + {jak3::foreground_check_longest_edge_asm::link, jak3::foreground_generic_merc::link, + jak3::foreground_merc::link}}}}; void LinkedFunctionTable::reg(const std::string& name, u64 (*exec)(void*), u32 stack_size) { const auto& it = m_executes.insert({name, {exec, Ptr()}}); @@ -488,6 +504,11 @@ void LinkedFunctionTable::reg(const std::string& name, u64 (*exec)(void*), u32 s s7.offset + jak2_symbols::FIX_SYM_GLOBAL_HEAP, ::jak2::u32_in_fixed_sym(jak2_symbols::FIX_SYM_FUNCTION_TYPE), 0x40, UNKNOWN_PP)); break; + case GameVersion::Jak3: + jump_to_asm = Ptr(::jak3::alloc_heap_object( + s7.offset + jak3_symbols::FIX_SYM_GLOBAL_HEAP, + ::jak3::u32_in_fixed_sym(jak3_symbols::FIX_SYM_FUNCTION_TYPE), 0x40, UNKNOWN_PP)); + break; default: ASSERT(false); } diff --git a/goal_src/jak3/engine/anim/joint.gc b/goal_src/jak3/engine/anim/joint.gc index 06b033de768..e0ce96764ba 100644 --- a/goal_src/jak3/engine/anim/joint.gc +++ b/goal_src/jak3/engine/anim/joint.gc @@ -2223,7 +2223,7 @@ ;; make-joint-jump-tables: not needed ;; calc-animation-from-spr: not needed -(def-mips2c calc-animation-from-spr (function joint-anim-frame int none)) +;; (def-mips2c calc-animation-from-spr (function joint-anim-frame int none)) (defun create-interpolated-joint-animation-frame ((dst joint-anim-frame) (num-joints int) (jc joint-control)) "Compute the entire joint frame by evaluating the blend tree, decompressing animations, and blending them." diff --git a/goal_src/jak3/engine/camera/cam-start.gc b/goal_src/jak3/engine/camera/cam-start.gc index c23077e7251..3c0e4680d54 100644 --- a/goal_src/jak3/engine/camera/cam-start.gc +++ b/goal_src/jak3/engine/camera/cam-start.gc @@ -45,4 +45,6 @@ (none) ) -(cam-start #f) +(format 0 "Skipping cam-start!!~%") +(format #t "Skipping cam-start!!~%") +;; (cam-start #f) diff --git a/goal_src/jak3/engine/gfx/foreground/eye-h.gc b/goal_src/jak3/engine/gfx/foreground/eye-h.gc index bf8e619fcfe..619aa911d59 100644 --- a/goal_src/jak3/engine/gfx/foreground/eye-h.gc +++ b/goal_src/jak3/engine/gfx/foreground/eye-h.gc @@ -13,6 +13,13 @@ ;; DECOMP BEGINS +;; TODO: remove this - just a stub. +(defun find-free-eye-index ((a int) (b string) (c int)) + 0) +(defun get-eye-block ((a int) (c int)) + 0) + + (deftype eye (structure) "Data for a single eye." ((data vector 2 :inline) diff --git a/goal_src/jak3/engine/gfx/mood/mood.gc b/goal_src/jak3/engine/gfx/mood/mood.gc index 75a39a24acb..80a8c82a732 100644 --- a/goal_src/jak3/engine/gfx/mood/mood.gc +++ b/goal_src/jak3/engine/gfx/mood/mood.gc @@ -8,3 +8,8 @@ ;; DECOMP BEGINS +;; TODO: remove these stubs +(defun clear-mood-context ((arg0 mood-context)) + (format 0 "no clear-mood-context~%") + #f + ) \ No newline at end of file diff --git a/goal_src/jak3/engine/gfx/sprite/particles/sparticle-launcher.gc b/goal_src/jak3/engine/gfx/sprite/particles/sparticle-launcher.gc index b9f0f5b78a7..44820a615da 100644 --- a/goal_src/jak3/engine/gfx/sprite/particles/sparticle-launcher.gc +++ b/goal_src/jak3/engine/gfx/sprite/particles/sparticle-launcher.gc @@ -35,3 +35,9 @@ ;; DECOMP BEGINS +;; TODO: stub + (kmemopen global "part-tables") + (define *part-id-table* (new 'global 'boxed-array sparticle-launcher 5500)) + (define *part-group-id-table* (new 'global 'boxed-array sparticle-launch-group 1700)) + (define *sp-temp* 0.0) + (kmemclose) \ No newline at end of file diff --git a/goal_src/jak3/engine/gfx/texture/texture.gc b/goal_src/jak3/engine/gfx/texture/texture.gc index 180892fc784..75837aacff0 100644 --- a/goal_src/jak3/engine/gfx/texture/texture.gc +++ b/goal_src/jak3/engine/gfx/texture/texture.gc @@ -1520,6 +1520,8 @@ (defmethod upload-now! ((this texture-page) (mode tex-upload-mode)) "Upload a texture to VRAM immediately, wait for DMA to finish." + + (format 0 "TODO: upload-now!~%") (let ((gp-0 *txt-dma-list*)) (let ((v1-0 gp-0)) (set! (-> v1-0 base) (-> v1-0 data)) @@ -1534,7 +1536,10 @@ (set! (-> (the-as (pointer uint64) a0-7) 1) (the-as uint 0)) (set! (-> v1-6 base) (&+ a0-7 16)) ) - (dma-buffer-send-chain (the-as dma-bank-source #x1000a000) gp-0) + ;; the actual send + (#unless PC_PORT + (dma-buffer-send-chain (the-as dma-bank-source #x1000a000) gp-0) + ) ) (dma-sync (the-as pointer #x1000a000) 0 0) (none) diff --git a/goal_src/jak3/engine/level/level.gc b/goal_src/jak3/engine/level/level.gc index efac74e3d73..6614dba6943 100644 --- a/goal_src/jak3/engine/level/level.gc +++ b/goal_src/jak3/engine/level/level.gc @@ -20,7 +20,7 @@ (define *kernel-boot-message* 'play) (start-debug "loading GAME.DGO~%") (load-package "game" global) - (play-boot) + ;; (play-boot) ) ) @@ -3744,6 +3744,8 @@ (none) ) +(format 0 "about to start level stuff...~%") + (when (zero? (-> *level* level0 art-group)) (kmemopen global "level-struct") (let ((gp-0 *level*)) @@ -3789,3 +3791,5 @@ ) (kmemclose) ) + +(format 0 "done level stuff...~%") diff --git a/goal_src/jak3/engine/math/matrix-h.gc b/goal_src/jak3/engine/math/matrix-h.gc index a228a001e48..22d8336a3dd 100644 --- a/goal_src/jak3/engine/math/matrix-h.gc +++ b/goal_src/jak3/engine/math/matrix-h.gc @@ -23,7 +23,7 @@ some, but not all, functions assume that a matrix is an affine transform. others assume that the rotation has no scale or shear (and that its inverse is its transpose)." ((data float 16) - (vector vector 4 :overlay-at (-> data 0)) + (vector vector 4 :inline :overlay-at (-> data 0)) (quad uint128 4 :overlay-at (-> data 0)) (rvec vector :inline :overlay-at (-> data 0)) (uvec vector :inline :overlay-at (-> data 4)) diff --git a/goalc/debugger/Debugger.cpp b/goalc/debugger/Debugger.cpp index a14d207e6ff..061ea375a1f 100644 --- a/goalc/debugger/Debugger.cpp +++ b/goalc/debugger/Debugger.cpp @@ -793,8 +793,6 @@ void Debugger::read_symbol_table_jak3() { continue; } - printf("got %s\n", str.c_str()); - // update maps if (m_symbol_name_to_offset_map.find(str) != m_symbol_name_to_offset_map.end()) { if (str == "asize-of-basic-func") { diff --git a/test/decompiler/reference/jak3/engine/math/matrix-h_REF.gc b/test/decompiler/reference/jak3/engine/math/matrix-h_REF.gc index 7dbc7ece491..f32c721c80f 100644 --- a/test/decompiler/reference/jak3/engine/math/matrix-h_REF.gc +++ b/test/decompiler/reference/jak3/engine/math/matrix-h_REF.gc @@ -7,12 +7,12 @@ some, but not all, functions assume that a matrix is an affine transform. others assume that the rotation has no scale or shear (and that its inverse is its transpose)." ((data float 16) - (vector vector 4 :overlay-at (-> data 0)) - (quad uint128 4 :overlay-at (-> data 0)) - (rvec vector :inline :overlay-at (-> data 0)) - (uvec vector :inline :overlay-at (-> data 4)) - (fvec vector :inline :overlay-at (-> data 8)) - (trans vector :inline :overlay-at (-> data 12)) + (vector vector 4 :inline :overlay-at (-> data 0)) + (quad uint128 4 :overlay-at (-> data 0)) + (rvec vector :inline :overlay-at (-> data 0)) + (uvec vector :inline :overlay-at (-> data 4)) + (fvec vector :inline :overlay-at (-> data 8)) + (trans vector :inline :overlay-at (-> data 12)) ) (:methods (transform-vectors! (_type_ (inline-array vector) (inline-array vector) int) none) @@ -145,7 +145,3 @@ and how they were originally packed (for example, in tie/shrub)." ;; failed to figure out what this is: 0 - - - -