From be976d2e69be26925d1d1c81f9a3a1f6f2a09766 Mon Sep 17 00:00:00 2001 From: water111 <48171810+water111@users.noreply.github.com> Date: Wed, 11 May 2022 22:53:53 -0400 Subject: [PATCH] [merc] Add merc extraction (#1356) * docs for ee merc code * wip * more extraction stuff * partial mat1 working * mat1 * cleanup * partial mat2 and mat3 support * merc extraction seems to work --- common/dma/gs.h | 2 +- decompiler/CMakeLists.txt | 2 + decompiler/config/all-types.gc | 40 +- decompiler/level_extractor/BspHeader.cpp | 11 - decompiler/level_extractor/BspHeader.h | 9 +- decompiler/level_extractor/MercData.cpp | 402 +++ decompiler/level_extractor/MercData.h | 192 ++ decompiler/level_extractor/common_formats.h | 11 + .../level_extractor/extract_collide_frags.cpp | 28 +- decompiler/level_extractor/extract_level.cpp | 131 +- decompiler/level_extractor/extract_level.h | 7 - decompiler/level_extractor/extract_merc.cpp | 849 ++++++ decompiler/level_extractor/extract_merc.h | 16 + decompiler/util/goal_data_reader.cpp | 60 + decompiler/util/goal_data_reader.h | 10 +- decompiler/util/sparticle_decompile.cpp | 4 +- docs/scratch/merc.md | 420 +++ docs/scratch/merc_asm.asm | 2331 +++++++++++++++++ game/kernel/klink.cpp | 3 + game/kernel/kmemcard.cpp | 2 +- game/mips2c/functions/bones.cpp | 238 +- game/system/Deci2Server.cpp | 2 +- goalc/compiler/nrepl/ReplServer.cpp | 4 +- 23 files changed, 4539 insertions(+), 235 deletions(-) create mode 100644 decompiler/level_extractor/MercData.cpp create mode 100644 decompiler/level_extractor/MercData.h create mode 100644 decompiler/level_extractor/common_formats.h create mode 100644 decompiler/level_extractor/extract_merc.cpp create mode 100644 decompiler/level_extractor/extract_merc.h create mode 100644 docs/scratch/merc.md create mode 100644 docs/scratch/merc_asm.asm diff --git a/common/dma/gs.h b/common/dma/gs.h index f2342413ef..cd7fb0ebd8 100644 --- a/common/dma/gs.h +++ b/common/dma/gs.h @@ -30,7 +30,7 @@ struct GifTag { }; u32 nloop() const { - return data[0] & 0x7f; // 15 bits + return data[0] & 0x7fff; // 15 bits } bool eop() const { return data[0] & (1ull << 15); } diff --git a/decompiler/CMakeLists.txt b/decompiler/CMakeLists.txt index c623693a4c..7dd1dc9cb1 100644 --- a/decompiler/CMakeLists.txt +++ b/decompiler/CMakeLists.txt @@ -54,9 +54,11 @@ add_library( level_extractor/BspHeader.cpp level_extractor/extract_collide_frags.cpp level_extractor/extract_level.cpp + level_extractor/extract_merc.cpp level_extractor/extract_tfrag.cpp level_extractor/extract_tie.cpp level_extractor/extract_shrub.cpp + level_extractor/MercData.cpp ObjectFile/LinkedObjectFile.cpp ObjectFile/LinkedObjectFileCreation.cpp diff --git a/decompiler/config/all-types.gc b/decompiler/config/all-types.gc index 71c500ec3d..5eff939ae8 100644 --- a/decompiler/config/all-types.gc +++ b/decompiler/config/all-types.gc @@ -8281,19 +8281,19 @@ ) (deftype merc-byte-header (structure) - ((srcdest-off uint8 :offset-assert 0) - (rgba-off uint8 :offset-assert 1) - (lump-off uint8 :offset-assert 2) - (fp-off uint8 :offset-assert 3) - (mat1-cnt uint8 :offset-assert 4) - (mat2-cnt uint8 :offset-assert 5) - (mat3-cnt uint8 :offset-assert 6) - (samecopy-cnt uint8 :offset-assert 7) - (crosscopy-cnt uint8 :offset-assert 8) - (strip-len uint8 :offset-assert 9) - (mm-quadword-fp-off uint8 :offset-assert 10) - (mm-quadword-size uint8 :offset-assert 11) - (perc-off uint8 :offset-assert 12) + ((srcdest-off uint8 :offset-assert 0) ; 0x + (rgba-off uint8 :offset-assert 1) ; 0y + (lump-off uint8 :offset-assert 2) ; 0z + (fp-off uint8 :offset-assert 3) ; 0w + (mat1-cnt uint8 :offset-assert 4) ; 1x + (mat2-cnt uint8 :offset-assert 5) ; 1y + (mat3-cnt uint8 :offset-assert 6) ; 1z + (samecopy-cnt uint8 :offset-assert 7) ; 1w + (crosscopy-cnt uint8 :offset-assert 8) ; 2x + (strip-len uint8 :offset-assert 9) ; 2y + (mm-quadword-fp-off uint8 :offset-assert 10) ; 2z + (mm-quadword-size uint8 :offset-assert 11) ; 2w + (perc-off uint8 :offset-assert 12) ; 3x (mat-slot uint8 10 :offset-assert 13) ) :method-count-assert 9 @@ -8336,7 +8336,7 @@ ((x-add float :offset-assert 0) (y-add float :offset-assert 4) (z-add float :offset-assert 8) - (shader-cnt uint8 :offset-assert 12) + (shader-cnt uint8 :offset-assert 12) ;; only 7 bits used? maybe flag in top bit? (kick-info-offset uint8 :offset-assert 13) (kick-info-step uint8 :offset-assert 14) (hword-cnt uint8 :offset-assert 15) @@ -8357,7 +8357,7 @@ ) (deftype merc-fragment-control (structure) - ((unsigned-four-count uint8 :offset-assert 0) + ((unsigned-four-count uint8 :offset-assert 0) ;; (in 32-bit words, not qw) (lump-four-count uint8 :offset-assert 1) ;; merc-vtx (fp-qwc uint8 :offset-assert 2) ;; merc-fp-header (mat-xfer-count uint8 :offset-assert 3) @@ -8557,11 +8557,11 @@ ) (deftype merc-vu1-low-mem (structure) - ((tri-strip-gif gs-gif-tag :inline :offset-assert 0) ;; was qword - (ad-gif gs-gif-tag :inline :offset-assert 16) ;; was qword - (hvdf-offset vector :inline :offset-assert 32) - (perspective uint128 4 :offset-assert 48) - (fog vector :inline :offset-assert 112) + ((tri-strip-gif gs-gif-tag :inline :offset-assert 0) ;; was qword 0 + (ad-gif gs-gif-tag :inline :offset-assert 16) ;; was qword 1 + (hvdf-offset vector :inline :offset-assert 32) ;; 2 + (perspective uint128 4 :offset-assert 48) ;; 3, 4, 5, 6 + (fog vector :inline :offset-assert 112) ;; 7 ) :method-count-assert 9 :size-assert #x80 diff --git a/decompiler/level_extractor/BspHeader.cpp b/decompiler/level_extractor/BspHeader.cpp index b30c5c0ccd..8064a41c33 100644 --- a/decompiler/level_extractor/BspHeader.cpp +++ b/decompiler/level_extractor/BspHeader.cpp @@ -206,17 +206,6 @@ std::string TFragmentDebugData::print(int indent) const { return result; } -u32 deref_u32(const Ref& ref, int word_offset) { - if ((ref.byte_offset % 4) != 0) { - throw Error("deref_u32 bad alignment"); - } - const auto& word = ref.data->words_by_seg.at(ref.seg).at(word_offset + (ref.byte_offset / 4)); - if (word.kind() != decompiler::LinkedWord::PLAIN_DATA) { - throw Error("deref_u32 bad kind: {}", (int)word.kind()); - } - return word.data; -} - void tfrag_debug_print_unpack(Ref start, int qwc_total) { int word_offset = 0; diff --git a/decompiler/level_extractor/BspHeader.h b/decompiler/level_extractor/BspHeader.h index 815c78e9b1..eb66a76dd1 100644 --- a/decompiler/level_extractor/BspHeader.h +++ b/decompiler/level_extractor/BspHeader.h @@ -7,6 +7,7 @@ #include #include "decompiler/util/goal_data_reader.h" +#include "decompiler/level_extractor/common_formats.h" namespace decompiler { class LinkedObjectFile; @@ -15,8 +16,6 @@ class DecompilerTypeSystem; namespace level_tools { -u32 deref_u32(const Ref& ref, int word_offset); - struct PrintSettings { bool print_tfrag = false; bool expand_draw_node = false; @@ -726,12 +725,6 @@ struct DrawableTreeArray { std::vector> trees; }; -// levels may remap textures if they provide one that should be shared -struct TextureRemap { - u32 original_texid; - u32 new_texid; -}; - // The "file info" struct FileInfo { std::string file_type; diff --git a/decompiler/level_extractor/MercData.cpp b/decompiler/level_extractor/MercData.cpp new file mode 100644 index 0000000000..e989435b95 --- /dev/null +++ b/decompiler/level_extractor/MercData.cpp @@ -0,0 +1,402 @@ +#include "MercData.h" +#include "decompiler/util/DecompilerTypeSystem.h" +#include "third-party/fmt/core.h" +#include "common/dma/gs.h" + +namespace decompiler { +void MercCtrlHeader::from_ref(TypedRef tr, const DecompilerTypeSystem& dts) { + xyz_scale = read_plain_data_field(tr, "xyz-scale", dts); + st_out_a = read_plain_data_field(tr, "st-out-a", dts); + st_out_b = read_plain_data_field(tr, "st-out-b", dts); + st_vif_add = read_plain_data_field(tr, "st-vif-add", dts); + st_int_off = read_plain_data_field(tr, "st-int-off", dts); + st_int_scale = read_plain_data_field(tr, "st-int-scale", dts); + effect_count = read_plain_data_field(tr, "effect-count", dts); + blend_target_count = read_plain_data_field(tr, "blend-target-count", dts); + fragment_count = read_plain_data_field(tr, "fragment-count", dts); + tri_count = read_plain_data_field(tr, "tri-count", dts); + matrix_count = read_plain_data_field(tr, "matrix-count", dts); + shader_count = read_plain_data_field(tr, "shader-count", dts); + transform_vertex_count = read_plain_data_field(tr, "transform-vertex-count", dts); + dvert_count = read_plain_data_field(tr, "dvert-count", dts); + one_mat_count = read_plain_data_field(tr, "one-mat-count", dts); + two_mat_count = read_plain_data_field(tr, "two-mat-count", dts); + two_mat_reuse_count = read_plain_data_field(tr, "two-mat-reuse-count", dts); + three_mat_count = read_plain_data_field(tr, "three-mat-count", dts); + three_mat_reuse_count = read_plain_data_field(tr, "three-mat-reuse-count", dts); + shader_upload_count = read_plain_data_field(tr, "shader-upload-count", dts); + matrix_upload_count = read_plain_data_field(tr, "matrix-upload-count", dts); + same_copy_count = read_plain_data_field(tr, "same-copy-count", dts); + cross_copy_count = read_plain_data_field(tr, "cross-copy-count", dts); + num_verts = read_plain_data_field(tr, "num-verts", dts); + longest_edge = read_plain_data_field(tr, "longest-edge", dts); + // todo masksk + envmap_tint = read_plain_data_field(tr, "envmap-tint", dts); + needs_clip = read_plain_data_field(tr, "needs-clip", dts); + use_isometric = read_plain_data_field(tr, "use-isometric", dts); + use_attached_shader = read_plain_data_field(tr, "use-attached-shader", dts); + display_triangles = read_plain_data_field(tr, "display-triangles", dts); + death_vertex_skip = read_plain_data_field(tr, "death-vertex-skip", dts); + death_start_vertex = read_plain_data_field(tr, "death-start-vertex", dts); + death_effect = read_plain_data_field(tr, "death-effect", dts); + use_translucent = read_plain_data_field(tr, "use-translucent", dts); + display_this_fragment = read_plain_data_field(tr, "display-this-fragment", dts); +} + +std::string MercCtrlHeader::print() const { + std::string result; + result += fmt::format(" xyz_scale: {}\n", xyz_scale); + result += fmt::format(" st_out_a: 0x{:x}\n", st_out_a); + result += fmt::format(" st_out_b: 0x{:x}\n", st_out_b); + result += fmt::format(" st_vif_add: 0x{:x}\n", st_vif_add); + result += fmt::format(" st_int_off: 0x{:x}\n", st_int_off); + result += fmt::format(" st_int_scale: {}\n", st_int_scale); + result += fmt::format(" effect_count: {}\n", effect_count); + result += fmt::format(" blend_target_count: {}\n", blend_target_count); + result += fmt::format(" fragment_count: {}\n", fragment_count); + result += fmt::format(" tri_count: {}\n", tri_count); + result += fmt::format(" matrix_count: {}\n", matrix_count); + result += fmt::format(" shader_count: {}\n", shader_count); + result += fmt::format(" transform_vertex_count: {}\n", transform_vertex_count); + result += fmt::format(" dvert_count: {}\n", dvert_count); + result += fmt::format(" one_mat_count: {}\n", one_mat_count); + result += fmt::format(" two_mat_count: {}\n", two_mat_count); + result += fmt::format(" two_mat_reuse_count: {}\n", two_mat_reuse_count); + result += fmt::format(" three_mat_count: {}\n", three_mat_count); + result += fmt::format(" three_mat_reuse_count: {}\n", three_mat_reuse_count); + result += fmt::format(" shader_upload_count: {}\n", shader_upload_count); + result += fmt::format(" matrix_upload_count: {}\n", matrix_upload_count); + result += fmt::format(" same_copy_count: {}\n", same_copy_count); + result += fmt::format(" cross_copy_count: {}\n", cross_copy_count); + result += fmt::format(" num_verts: {}\n", num_verts); + result += fmt::format(" longest_edge: {}\n", longest_edge); + result += fmt::format(" envmap_tint: {}\n", envmap_tint); + result += fmt::format(" needs_clip: {}\n", needs_clip); + result += fmt::format(" use_isometric: {}\n", use_isometric); + result += fmt::format(" use_attached_shader: {}\n", use_attached_shader); + result += fmt::format(" display_triangles: {}\n", display_triangles); + result += fmt::format(" death_vertex_skip: {}\n", death_vertex_skip); + result += fmt::format(" death_start_vertex: {}\n", death_start_vertex); + result += fmt::format(" death_effect: {}\n", death_effect); + result += fmt::format(" use_translucent: {}\n", use_translucent); + result += fmt::format(" display_this_fragment: {}\n", display_this_fragment); + return result; +} + +TypedRef MercFragmentControl::from_ref(TypedRef tr, const DecompilerTypeSystem& dts) { + unsigned_four_count = read_plain_data_field(tr, "unsigned-four-count", dts); + lump_four_count = read_plain_data_field(tr, "lump-four-count", dts); + fp_qwc = read_plain_data_field(tr, "fp-qwc", dts); + mat_xfer_count = read_plain_data_field(tr, "mat-xfer-count", dts); + ASSERT(mat_xfer_count < 10); + Ref dest_data_ref = get_field_ref(tr, "mat-dest-data", dts); + for (u8 i = 0; i < mat_xfer_count; i++) { + auto& entry = mat_dest_data.emplace_back(); + entry.matrix_number = deref_u8(dest_data_ref, i * 2); + entry.matrix_dest = deref_u8(dest_data_ref, i * 2 + 1); + } + + tr.ref.byte_offset += (4 + 2 * mat_dest_data.size()); + return tr; +} + +void MercFpHeader::from_ref(TypedRef tr, const DecompilerTypeSystem& dts) { + x_add = read_plain_data_field(tr, "x-add", dts); + y_add = read_plain_data_field(tr, "y-add", dts); + z_add = read_plain_data_field(tr, "z-add", dts); + + shader_cnt = read_plain_data_field(tr, "shader-cnt", dts); + kick_info_offset = read_plain_data_field(tr, "kick-info-offset", dts); + kick_info_step = read_plain_data_field(tr, "kick-info-step", dts); + hword_cnt = read_plain_data_field(tr, "hword-cnt", dts); +} + +std::string MercFpHeader::print() const { + std::string result; + result += fmt::format(" x_add: {}\n", x_add); + result += fmt::format(" y_add: {}\n", y_add); + result += fmt::format(" z_add: {}\n", z_add); + result += fmt::format(" shader_cnt: {}\n", shader_cnt); + result += fmt::format(" kick_info_offset: {}\n", kick_info_offset); + result += fmt::format(" kick_info_step: {}\n", kick_info_step); + result += fmt::format(" hword_cnt: {}\n", hword_cnt); + return result; +} + +void MercByteHeader::from_ref(TypedRef tr, const DecompilerTypeSystem& dts) { + srcdest_off = read_plain_data_field(tr, "srcdest-off", dts); + rgba_off = read_plain_data_field(tr, "rgba-off", dts); + lump_off = read_plain_data_field(tr, "lump-off", dts); + fp_off = read_plain_data_field(tr, "fp-off", dts); + mat1_cnt = read_plain_data_field(tr, "mat1-cnt", dts); + mat2_cnt = read_plain_data_field(tr, "mat2-cnt", dts); + mat3_cnt = read_plain_data_field(tr, "mat3-cnt", dts); + samecopy_cnt = read_plain_data_field(tr, "samecopy-cnt", dts); + crosscopy_cnt = read_plain_data_field(tr, "crosscopy-cnt", dts); + strip_len = read_plain_data_field(tr, "strip-len", dts); + mm_quadword_fp_off = read_plain_data_field(tr, "mm-quadword-fp-off", dts); + mm_quadword_size = read_plain_data_field(tr, "mm-quadword-size", dts); + perc_off = read_plain_data_field(tr, "perc-off", dts); + + auto ms = get_field_ref(tr, "perc-off", dts); + bool got_end = false; + for (int i = 0; i < MAT_SLOTS; i++) { + ms.byte_offset++; + mat_slot[i] = deref_u8(ms, 0); + if (mat_slot[i] == 128) { + got_end = true; + } else { + // ASSERT(!got_end); + if (got_end) { + // fmt::print("got something after the end\n"); // todo, should investigate more + } + } + } +} + +std::string MercByteHeader::print() const { + std::string result; + result += fmt::format(" srcdest_off: {}\n", srcdest_off); + result += fmt::format(" rgba_off: {}\n", rgba_off); + result += fmt::format(" lump_off: {}\n", lump_off); + result += fmt::format(" fp_off: {}\n", fp_off); + result += fmt::format(" mat1_cnt: {}\n", mat1_cnt); + result += fmt::format(" mat2_cnt: {}\n", mat2_cnt); + result += fmt::format(" mat3_cnt: {}\n", mat3_cnt); + result += fmt::format(" samecopy_cnt: {}\n", samecopy_cnt); + result += fmt::format(" crosscopy_cnt: {}\n", crosscopy_cnt); + result += fmt::format(" strip_len: {}\n", strip_len); + result += fmt::format(" mm_quadword_fp_off: {}\n", mm_quadword_fp_off); + result += fmt::format(" mm_quadword_size: {}\n", mm_quadword_size); + result += fmt::format(" perc_off: {}\n", perc_off); + for (int i = 0; i < MAT_SLOTS; i++) { + result += fmt::format(" mat_slot[{}]: {}\n", i, mat_slot[i]); + } + return result; +} + +std::string MercFragmentControl::print() const { + std::string result; + result += fmt::format(" unsigned_four_count: {}\n", unsigned_four_count); + result += fmt::format(" lump_four_count: {}\n", lump_four_count); + result += fmt::format(" fp_qwc: {}\n", fp_qwc); + result += fmt::format(" mat_xfer_count: {}\n", mat_xfer_count); + for (u8 i = 0; i < mat_xfer_count; i++) { + result += fmt::format(" mat[{}] {} -> {}\n", i, mat_dest_data[i].matrix_number, + mat_dest_data[i].matrix_dest); + } + return result; +} + +std::string MercShader::print() const { + std::string result; + result += fmt::format(" output_offset: {}\n", output_offset); + result += fmt::format(" strip_tag: 0x{:x}\n", next_strip_nloop); + return result; +} + +TypedRef MercFragment::from_ref(TypedRef tr, + const DecompilerTypeSystem& dts, + const MercFragmentControl& control, + const MercCtrlHeader& main_control) { + // fmt::print("frag::from_ref:\n{}\n", control.print()); + TypedRef byte_hdr(get_field_ref(tr, "header", dts), dts.ts.lookup_type("merc-byte-header")); + header.from_ref(byte_hdr, dts); + // fmt::print("{}\n", header.print()); + + // all these offsets are super confusing. + // the DMA transfers require source and dest addresses/sized to have alignment of 16 bytes. + // so the data is padded. + // the transfers increase size by 4x due to VIF unpacking + // But transferring this padding exactly would result in up to 63 bytes of wasted space. + // so they cheat the destination pointers to be slightly overlapping so the next transfer + // overlaps the padding of the previous. + // as a result, the "in VU" offsets are different from "in main memory" + + // let's figure it out from bones.gc asm + // u4 + // lbu s0, 0(gp) (fragment.control.unsigned-four-count) + // daddiu v0, s0, 3 + // srl v0, v0, 2 + // dsll32 s0, v0, 4 + // daddu t3, t2, s0 + u32 my_u4_count = ((control.unsigned_four_count + 3) / 4) * 16; + // fmt::print("my u4: {} ({} qwc)\n", my_u4_count, my_u4_count / 16); + for (u32 w = 0; w < my_u4_count / 4; w++) { + u32 val = deref_u32(tr.ref, w); + memcpy(unsigned_four_including_header.emplace_back().data(), &val, 4); + } + + // l4 + // lbu s2, 1(gp) + // daddiu s0, s2, 3 + // srl s0, s0, 2 + // dsll32 s2, s0, 4 + u32 my_l4_count = my_u4_count + ((control.lump_four_count + 3) / 4) * 16; + // fmt::print("my l4: {} ({} qwc)\n", my_l4_count, my_l4_count / 16); + // end of lump should align with mm (main memory?) fp off. which + // is used for accessing the fp data in main memory. + ASSERT(my_l4_count / 16 == header.mm_quadword_fp_off); + + // row.x/y is st-vif-add from the merc-ctrl-header. + // row.z = 0x47800000, row.w = 0x4b010000 + math::Vector row(main_control.st_vif_add, main_control.st_vif_add, 0x47800000, + 0x4b010000); + for (u32 w = my_u4_count / 4; w < my_l4_count / 4; w++) { + ASSERT((w * 4) < header.mm_quadword_fp_off * 16); + u32 val = deref_u32(tr.ref, w); + + math::Vector as_u8s; + memcpy(as_u8s.data(), &val, 4); + math::Vector as_u32s = as_u8s.cast(); + as_u32s += row; + memcpy(lump4_unpacked.emplace_back().data(), as_u32s.data(), 16); + } + + // fp header + Ref fp_ref = tr.ref; + fp_ref.byte_offset += 16 * header.mm_quadword_fp_off; + fp_header.from_ref(TypedRef(fp_ref, dts.ts.lookup_type("merc-fp-header")), dts); + fp_ref.byte_offset += 16; + + // fp shaders + for (int i = 0; i < fp_header.shader_cnt; i++) { + auto& shader = shaders.emplace_back(); + // adgif0 + u8 adgif0_addr = deref_u8(fp_ref, 8); + ASSERT(adgif0_addr == (u8)GsRegisterAddress::TEX0_1); + shader.output_offset = deref_u32(fp_ref, 3); + shader.tex0 = GsTex0(deref_u64(fp_ref, 0)); + fp_ref.byte_offset += 16; + + // adgif1 + u8 adgif1_addr = deref_u8(fp_ref, 8); + ASSERT(adgif1_addr == (u8)GsRegisterAddress::TEX1_1); + shader.tex1 = GsTex1(deref_u64(fp_ref, 0)); + u16 stash = deref_u32(fp_ref, 3); + shader.original_tex = deref_u32(fp_ref, 2); + shader.next_strip_nloop = stash & 0x7fff; + ASSERT((!!(stash & 0x8000)) == (i == fp_header.shader_cnt - 1)); // set eop on last + fp_ref.byte_offset += 16; + + // adgif2 + u8 adgif2_addr = deref_u8(fp_ref, 8); + ASSERT(adgif2_addr == (u8)GsRegisterAddress::MIPTBP1_1); + fp_ref.byte_offset += 16; + + // adgif3 + u8 adgif3_addr = deref_u8(fp_ref, 8); + ASSERT(adgif3_addr == (u8)GsRegisterAddress::CLAMP_1); + shader.clamp = deref_u64(fp_ref, 0); + fp_ref.byte_offset += 16; + + // adgif4 + u8 adgif4_addr = deref_u8(fp_ref, 8); + ASSERT(adgif4_addr == (u8)GsRegisterAddress::ALPHA_1); + shader.alpha = GsAlpha(deref_u64(fp_ref, 0)); + fp_ref.byte_offset += 16; + } + + tr.ref.byte_offset += (header.mm_quadword_size) * 16; + + // let's verify the matrix slots here. + int used_matrix_slots = 0; + for (auto x : header.mat_slot) { + if (x) { + used_matrix_slots++; + } else { + break; + } + } + ASSERT(used_matrix_slots == control.mat_xfer_count); + for (int i = 0; i < used_matrix_slots; i++) { + ASSERT(header.mat_slot[i] == control.mat_dest_data.at(i).matrix_dest); + } + + return tr; +} + +std::string MercFragment::print() const { + std::string result; + result += fmt::format(" + BYTE-HEADER\n"); + result += header.print(); + result += fmt::format(" + FP-HEADER\n"); + result += fp_header.print(); + for (const auto& shader : shaders) { + result += fmt::format(" + SHADER\n"); + result += shader.print(); + } + return result; +} + +void MercEffect::from_ref(TypedRef tr, + const DecompilerTypeSystem& dts, + const MercCtrlHeader& main_control) { + effect_bits = read_plain_data_field(tr, "effect-bits", dts); + frag_count = read_plain_data_field(tr, "frag-count", dts); + blend_frag_count = read_plain_data_field(tr, "blend-frag-count", dts); + tri_count = read_plain_data_field(tr, "tri-count", dts); + dvert_count = read_plain_data_field(tr, "dvert-count", dts); + envmap_usage = read_plain_data_field(tr, "envmap-usage", dts); + + // do frag-ctrls + TypedRef fc(deref_label(get_field_ref(tr, "frag-ctrl", dts)), + dts.ts.lookup_type("merc-fragment-control")); + for (u32 i = 0; i < frag_count; i++) { + fc = frag_ctrl.emplace_back().from_ref(fc, dts); + } + + // do actual frags + TypedRef f(deref_label(get_field_ref(tr, "frag-geo", dts)), dts.ts.lookup_type("merc-fragment")); + for (u32 i = 0; i < frag_count; i++) { + f = frag_geo.emplace_back().from_ref(f, dts, frag_ctrl.at(i), main_control); + } +} + +std::string MercEffect::print() { + std::string result; + result += fmt::format(" effect_bits: {}\n", effect_bits); + result += fmt::format(" frag_count: {}\n", frag_count); + result += fmt::format(" blend_frag_count: {}\n", blend_frag_count); + result += fmt::format(" tri_count: {}\n", tri_count); + result += fmt::format(" dvert_count: {}\n", dvert_count); + result += fmt::format(" envmap_usage: {}\n", envmap_usage); + + for (u32 i = 0; i < frag_count; i++) { + result += fmt::format(" +FRAGMENT {}\n", i); + result += fmt::format(" + CTRL\n"); + result += frag_ctrl[i].print(); + result += fmt::format(" + GEO\n"); + result += frag_geo[i].print(); + } + return result; +} + +void MercCtrl::from_ref(TypedRef tr, const DecompilerTypeSystem& dts) { + name = read_string_field(tr, "name", dts, false); + num_joints = read_plain_data_field(tr, "num-joints", dts); + auto merc_ctrl_header_ref = + TypedRef(get_field_ref(tr, "header", dts), dts.ts.lookup_type("merc-ctrl-header")); + header.from_ref(merc_ctrl_header_ref, dts); + + auto eff_ref = TypedRef(get_field_ref(tr, "effect", dts), dts.ts.lookup_type("merc-effect")); + for (u32 i = 0; i < header.effect_count; i++) { + effects.emplace_back().from_ref(eff_ref, dts, header); + eff_ref.ref.byte_offset += 32; // + } +} + +std::string MercCtrl::print() { + std::string result; + result += fmt::format("name: {}\n", name); + result += fmt::format("num_joints: {}\n", num_joints); + result += "+ HEADER\n"; + result += header.print(); + result += "\n"; + for (auto& eff : effects) { + result += fmt::format("+ EFFECT\n{}\n", eff.print()); + } + return result; +} + +} // namespace decompiler \ No newline at end of file diff --git a/decompiler/level_extractor/MercData.h b/decompiler/level_extractor/MercData.h new file mode 100644 index 0000000000..4d64f7a459 --- /dev/null +++ b/decompiler/level_extractor/MercData.h @@ -0,0 +1,192 @@ +#pragma once + +#include +#include +#include "common/common_types.h" +#include "decompiler/util/goal_data_reader.h" +#include "common/math/Vector.h" +#include "common/dma/gs.h" + +namespace decompiler { + +/*! + * per-ctrl information. the first qw is uploaded to vu1 + */ +struct MercCtrlHeader { + float xyz_scale; + u32 st_magic; + u32 st_out_a; + u32 st_out_b; + u32 st_vif_add; + u16 st_int_off; + u16 st_int_scale; + u32 effect_count; + u32 blend_target_count; + u16 fragment_count; + u16 tri_count; + u8 matrix_count; + u8 shader_count; + u16 transform_vertex_count; + u16 dvert_count; + u16 one_mat_count; + u16 two_mat_count; + u16 two_mat_reuse_count; + u16 three_mat_count; + u16 three_mat_reuse_count; + u8 shader_upload_count; + u8 matrix_upload_count; + u16 same_copy_count; + u16 cross_copy_count; + u16 num_verts; + float longest_edge; + // todo (eye-ctrl merc-eye-ctrl :offset-assert 64) + u32 masks[3]; + // (dummy-bytes uint8 48 :offset 32) + u32 envmap_tint; + // todo (query basic :offset 36) + u8 needs_clip; + u8 use_isometric; + u8 use_attached_shader; + u8 display_triangles; + u16 death_vertex_skip; + u16 death_start_vertex; + u32 death_effect; + u8 use_translucent; + u8 display_this_fragment; + + void from_ref(TypedRef tr, const DecompilerTypeSystem& dts); + std::string print() const; +}; + +/*! + * the unsigned4 data of a fragment starts with this. + */ +struct MercByteHeader { + u8 srcdest_off; + u8 rgba_off; + u8 lump_off; + u8 fp_off; + u8 mat1_cnt; + u8 mat2_cnt; + u8 mat3_cnt; + u8 samecopy_cnt; + u8 crosscopy_cnt; + u8 strip_len; + u8 mm_quadword_fp_off; + u8 mm_quadword_size; + u8 perc_off; + static constexpr int MAT_SLOTS = 10; + u8 mat_slot[MAT_SLOTS]; + void from_ref(TypedRef tr, const DecompilerTypeSystem& dts); + std::string print() const; +}; +static_assert(sizeof(MercByteHeader) == 0x17); + +/*! + * the fp data of a fragment starts with this. + */ +struct MercFpHeader { + float x_add; + float y_add; + float z_add; + u8 shader_cnt; + u8 kick_info_offset; + u8 kick_info_step; + u8 hword_cnt; + void from_ref(TypedRef tr, const DecompilerTypeSystem& dts); + std::string print() const; +}; + +struct MercShader { + GsTex0 tex0; + GsTex1 tex1; + // skip mip + u64 clamp; + GsAlpha alpha; + u16 output_offset; + u16 next_strip_nloop; + u32 original_tex; + std::string print() const; +}; + +/*! + * info about a matrix to upload. + * it maps a per-model matrix (matrix_number) to a slot in vu1 memory (matrix_dest) + */ +struct MercMatDest { + u8 matrix_number; + u8 matrix_dest; +}; + +/*! + * per-fragment info that doesn't go to the VU + */ +struct MercFragmentControl { + // memory layout + u8 unsigned_four_count; + u8 lump_four_count; + u8 fp_qwc; + + // matrix upload info + u8 mat_xfer_count; + std::vector mat_dest_data; // inline, dynamic + + TypedRef from_ref(TypedRef tr, const DecompilerTypeSystem& dts); + std::string print() const; +}; + +/*! + * the per-vu1 upload/call data for merc. + */ +struct MercFragment { + // part1: unsigned4. it is expanded to u32 by VIF. + MercByteHeader header; + std::vector> + unsigned_four_including_header; // repeats the data above. always 0 in vu. + + // part2: lump4. it is converted to floats by VIF. + std::vector> lump4_unpacked; // at lump_off qw in VU. + + // part3: fp. it contains the fp header, shaders, and ?? + MercFpHeader fp_header; + std::vector shaders; + std::vector extra_fp_data; // ?? + + TypedRef from_ref(TypedRef tr, + const DecompilerTypeSystem& dts, + const MercFragmentControl& control, + const MercCtrlHeader& main_control); + std::string print() const; +}; + +struct MercEffect { + //((frag-geo merc-fragment :offset-assert 0) ;; ? + std::vector frag_geo; + // (frag-ctrl merc-fragment-control :offset-assert 4) + std::vector frag_ctrl; + // (blend-data merc-blend-data :offset-assert 8) ?? + // (blend-ctrl merc-blend-ctrl :offset-assert 12) ?? + // (dummy0 uint8 :offset-assert 16) ?? + u8 effect_bits; + u16 frag_count; + u16 blend_frag_count; + u16 tri_count; + u16 dvert_count; + // (dummy1 uint8 :offset-assert 26) ?? + u8 envmap_usage; + // (extra-info merc-extra-info :offset-assert 28) ?? + + void from_ref(TypedRef tr, const DecompilerTypeSystem& dts, const MercCtrlHeader& main_control); + std::string print(); +}; + +struct MercCtrl { + std::string name; + s32 num_joints; + MercCtrlHeader header; + std::vector effects; + + void from_ref(TypedRef tr, const DecompilerTypeSystem& dts); + std::string print(); +}; +} // namespace decompiler \ No newline at end of file diff --git a/decompiler/level_extractor/common_formats.h b/decompiler/level_extractor/common_formats.h new file mode 100644 index 0000000000..597b3a88aa --- /dev/null +++ b/decompiler/level_extractor/common_formats.h @@ -0,0 +1,11 @@ +#pragma once +#include "common/common_types.h" + +namespace level_tools { + +// levels may remap textures if they provide one that should be shared +struct TextureRemap { + u32 original_texid; + u32 new_texid; +}; +} // namespace level_tools \ No newline at end of file diff --git a/decompiler/level_extractor/extract_collide_frags.cpp b/decompiler/level_extractor/extract_collide_frags.cpp index 83def6fd4e..d32fd25b83 100644 --- a/decompiler/level_extractor/extract_collide_frags.cpp +++ b/decompiler/level_extractor/extract_collide_frags.cpp @@ -57,32 +57,6 @@ float u32_to_float(u32 in) { return r; } -u16 deref_u16(const Ref& ref, int array_idx) { - u32 u32_offset = array_idx / 2; - u32 u32_val = level_tools::deref_u32(ref, u32_offset); - if (array_idx & 1) { - return u32_val >> 16; - } else { - return (u16)u32_val; - } -} - -s8 deref_s8(const Ref& ref, int byte) { - u32 u32_offset = byte / 4; - u32 u32_val = level_tools::deref_u32(ref, u32_offset); - s8 vals[4]; - memcpy(vals, &u32_val, 4); - return vals[byte & 3]; -} - -u8 deref_u8(const Ref& ref, int byte) { - u32 u32_offset = byte / 4; - u32 u32_val = level_tools::deref_u32(ref, u32_offset); - u8 vals[4]; - memcpy(vals, &u32_val, 4); - return vals[byte & 3]; -} - void unpack_part1_collide_list_item(CollideListItem& item) { int in_idx = 0; int out_idx = 0; @@ -204,7 +178,7 @@ void extract_pats(CollideListItem& item) { for (auto& f : item.unpacked.faces) { auto pat_idx = deref_u8(item.mesh->packed_data, byte_offset++); - u32 pat = level_tools::deref_u32(item.mesh->pat_array, pat_idx); + u32 pat = deref_u32(item.mesh->pat_array, pat_idx); // fmt::print("pat @ {} is 0x{:x}\n", pat_idx, pat); f.pat = pat; } diff --git a/decompiler/level_extractor/extract_level.cpp b/decompiler/level_extractor/extract_level.cpp index a43f028ef0..92022eb228 100644 --- a/decompiler/level_extractor/extract_level.cpp +++ b/decompiler/level_extractor/extract_level.cpp @@ -7,6 +7,7 @@ #include "decompiler/level_extractor/extract_tie.h" #include "decompiler/level_extractor/extract_shrub.h" #include "decompiler/level_extractor/extract_collide_frags.h" +#include "decompiler/level_extractor/extract_merc.h" #include "common/util/compress.h" #include "common/util/FileUtil.h" #include "common/util/SimpleThreadGroup.h" @@ -134,51 +135,32 @@ void confirm_textures_identical(const TextureDB& tex_db) { } } -/*! - * Extract common textures found in GAME.CGO - */ -void extract_common(const ObjectFileDB& db, const TextureDB& tex_db, const std::string& dgo_name) { - if (db.obj_files_by_dgo.count(dgo_name) == 0) { - lg::warn("Skipping common extract for {} because the DGO was not part of the input", dgo_name); - return; +void extract_art_groups_from_level(const ObjectFileDB& db, + const TextureDB& tex_db, + const std::vector& tex_remap, + const std::string& dgo_name, + tfrag3::Level& level_data, + bool dump_level) { + const auto& files = db.obj_files_by_dgo.at(dgo_name); + for (const auto& file : files) { + if (file.name.length() > 3 && !file.name.compare(file.name.length() - 3, 3, "-ag")) { + const auto& ag_file = db.lookup_record(file); + extract_merc(ag_file, tex_db, db.dts, tex_remap, level_data, dump_level); + } } - - if (tex_db.textures.size() == 0) { - lg::warn("Skipping common extract because there were no textures in the input"); - return; - } - - confirm_textures_identical(tex_db); - - tfrag3::Level tfrag_level; - add_all_textures_from_level(tfrag_level, dgo_name, tex_db); - Serializer ser; - tfrag_level.serialize(ser); - auto compressed = - compression::compress_zstd(ser.get_save_result().first, ser.get_save_result().second); - print_memory_usage(tfrag_level, ser.get_save_result().second); - fmt::print("compressed: {} -> {} ({:.2f}%)\n", ser.get_save_result().second, compressed.size(), - 100.f * compressed.size() / ser.get_save_result().second); - file_util::write_binary_file(file_util::get_file_path({fmt::format( - "assets/{}.fr3", dgo_name.substr(0, dgo_name.length() - 4))}), - compressed.data(), compressed.size()); } -void extract_from_level(const ObjectFileDB& db, - const TextureDB& tex_db, - const std::string& dgo_name, - const DecompileHacks& hacks, - bool dump_level, - bool extract_collision) { - if (db.obj_files_by_dgo.count(dgo_name) == 0) { - lg::warn("Skipping extract for {} because the DGO was not part of the input", dgo_name); - return; - } - +std::vector extract_bsp_from_level(const ObjectFileDB& db, + const TextureDB& tex_db, + const std::string& dgo_name, + const DecompileHacks& hacks, + bool dump_level, + bool extract_collision, + tfrag3::Level& level_data) { auto bsp_rec = get_bsp_file(db.obj_files_by_dgo.at(dgo_name)); if (!bsp_rec) { lg::warn("Skipping extract for {} because the BSP file was not found", dgo_name); - return; + return {}; } std::string level_name = bsp_rec->name.substr(0, bsp_rec->name.length() - 4); @@ -203,9 +185,6 @@ void extract_from_level(const ObjectFileDB& db, "drawable-tree-tfrag", "drawable-tree-trans-tfrag", "drawable-tree-dirt-tfrag", "drawable-tree-ice-tfrag", "drawable-tree-lowres-tfrag", "drawable-tree-lowres-trans-tfrag"}; int i = 0; - tfrag3::Level tfrag_level; - - add_all_textures_from_level(tfrag_level, dgo_name, tex_db); std::vector all_ties; for (auto& draw_tree : bsp_header.drawable_tree_array.trees) { @@ -226,19 +205,19 @@ void extract_from_level(const ObjectFileDB& db, expected_missing_textures = it->second; } extract_tfrag(as_tfrag_tree, fmt::format("{}-{}", dgo_name, i++), - bsp_header.texture_remap_table, tex_db, expected_missing_textures, tfrag_level, + bsp_header.texture_remap_table, tex_db, expected_missing_textures, level_data, dump_level); } else if (draw_tree->my_type() == "drawable-tree-instance-tie") { auto as_tie_tree = dynamic_cast(draw_tree.get()); ASSERT(as_tie_tree); extract_tie(as_tie_tree, fmt::format("{}-{}-tie", dgo_name, i++), - bsp_header.texture_remap_table, tex_db, tfrag_level, dump_level); + bsp_header.texture_remap_table, tex_db, level_data, dump_level); } else if (draw_tree->my_type() == "drawable-tree-instance-shrub") { auto as_shrub_tree = dynamic_cast(draw_tree.get()); ASSERT(as_shrub_tree); extract_shrub(as_shrub_tree, fmt::format("{}-{}-shrub", dgo_name, i++), - bsp_header.texture_remap_table, tex_db, {}, tfrag_level, dump_level); + bsp_header.texture_remap_table, tex_db, {}, level_data, dump_level); } else if (draw_tree->my_type() == "drawable-tree-collide-fragment" && extract_collision) { auto as_collide_frags = dynamic_cast(draw_tree.get()); @@ -246,14 +225,40 @@ void extract_from_level(const ObjectFileDB& db, ASSERT(!got_collide); got_collide = true; extract_collide_frags(as_collide_frags, all_ties, fmt::format("{}-{}-collide", dgo_name, i++), - tfrag_level, dump_level); + level_data, dump_level); } else { // fmt::print(" unsupported tree {}\n", draw_tree->my_type()); } } + level_data.level_name = level_name; - tfrag_level.level_name = level_name; + return bsp_header.texture_remap_table; +} +/*! + * Extract stuff found in GAME.CGO. + * Even though GAME.CGO isn't technically a level, the decompiler/loader treat it like one, + * but the bsp stuff is just empty. It will contain only textures/art groups. + */ +void extract_common(const ObjectFileDB& db, + const TextureDB& tex_db, + const std::string& dgo_name, + bool dump_levels) { + if (db.obj_files_by_dgo.count(dgo_name) == 0) { + lg::warn("Skipping common extract for {} because the DGO was not part of the input", dgo_name); + return; + } + + if (tex_db.textures.size() == 0) { + lg::warn("Skipping common extract because there were no textures in the input"); + return; + } + + confirm_textures_identical(tex_db); + + tfrag3::Level tfrag_level; + add_all_textures_from_level(tfrag_level, dgo_name, tex_db); + extract_art_groups_from_level(db, tex_db, {}, dgo_name, tfrag_level, dump_levels); Serializer ser; tfrag_level.serialize(ser); auto compressed = @@ -266,6 +271,36 @@ void extract_from_level(const ObjectFileDB& db, compressed.data(), compressed.size()); } +void extract_from_level(const ObjectFileDB& db, + const TextureDB& tex_db, + const std::string& dgo_name, + const DecompileHacks& hacks, + bool dump_level, + bool extract_collision) { + if (db.obj_files_by_dgo.count(dgo_name) == 0) { + lg::warn("Skipping extract for {} because the DGO was not part of the input", dgo_name); + return; + } + tfrag3::Level level_data; + add_all_textures_from_level(level_data, dgo_name, tex_db); + + // the bsp header file data + auto tex_remap = extract_bsp_from_level(db, tex_db, dgo_name, hacks, dump_level, + extract_collision, level_data); + extract_art_groups_from_level(db, tex_db, tex_remap, dgo_name, level_data, dump_level); + + Serializer ser; + level_data.serialize(ser); + auto compressed = + compression::compress_zstd(ser.get_save_result().first, ser.get_save_result().second); + print_memory_usage(level_data, ser.get_save_result().second); + fmt::print("compressed: {} -> {} ({:.2f}%)\n", ser.get_save_result().second, compressed.size(), + 100.f * compressed.size() / ser.get_save_result().second); + file_util::write_binary_file(file_util::get_file_path({fmt::format( + "assets/{}.fr3", dgo_name.substr(0, dgo_name.length() - 4))}), + compressed.data(), compressed.size()); +} + void extract_all_levels(const ObjectFileDB& db, const TextureDB& tex_db, const std::vector& dgo_names, @@ -273,7 +308,7 @@ void extract_all_levels(const ObjectFileDB& db, const DecompileHacks& hacks, bool debug_dump_level, bool extract_collision) { - extract_common(db, tex_db, common_name); + extract_common(db, tex_db, common_name, debug_dump_level); SimpleThreadGroup threads; threads.run( [&](int idx) { diff --git a/decompiler/level_extractor/extract_level.h b/decompiler/level_extractor/extract_level.h index d09da915d5..56996920bb 100644 --- a/decompiler/level_extractor/extract_level.h +++ b/decompiler/level_extractor/extract_level.h @@ -6,13 +6,6 @@ #include "decompiler/ObjectFile/ObjectFileDB.h" namespace decompiler { -void extract_from_level(const ObjectFileDB& db, - const TextureDB& tex_db, - const std::string& dgo_name, - const DecompileHacks& hacks, - bool dump_level, - bool extract_collision); -void extract_common(const ObjectFileDB& db, const TextureDB& tex_db, const std::string& dgo_name); // extract everything void extract_all_levels(const ObjectFileDB& db, diff --git a/decompiler/level_extractor/extract_merc.cpp b/decompiler/level_extractor/extract_merc.cpp new file mode 100644 index 0000000000..def6832276 --- /dev/null +++ b/decompiler/level_extractor/extract_merc.cpp @@ -0,0 +1,849 @@ +#include "extract_merc.h" +#include "decompiler/util/goal_data_reader.h" +#include "decompiler/level_extractor/MercData.h" +#include "common/util/FileUtil.h" +#include "common/util/colors.h" + +namespace decompiler { + +// number of slots on VU1 data memory to store matrices +constexpr int MERC_VU1_MATRIX_SLOTS = 18; +// the size of each "matrix". Includes a transformation and rotation matrix (for normals) +constexpr int MERC_MATRIX_STRIDE = 7; + +// converts a vu1 address to an index of a matrix slot. +// as far as I can tell, nothing in the game uses indices, they are always addresses already +u32 vu1_addr_to_matrix_slot(u32 addr) { + ASSERT(addr >= 6); + ASSERT(addr < (6 + MERC_MATRIX_STRIDE * MERC_VU1_MATRIX_SLOTS)); + addr -= 6; + ASSERT((addr % MERC_MATRIX_STRIDE) == 0); + return addr / MERC_MATRIX_STRIDE; +} + +u32 matrix_slot_to_vu1_addr(u32 slot) { + ASSERT(slot < MERC_VU1_MATRIX_SLOTS); + return 6 + (slot * MERC_MATRIX_STRIDE); +} + +/*! + * The GS settings of a merc draw (shader + tex) + */ +struct MercGsState { + // the blending, clamp, etc settings. from adgif shaders + DrawMode mode; + // the texture to use, as a "pc combo" texture index. + u32 pc_combo_tex_id; + u64 as_u64() const { return (((u64)pc_combo_tex_id) << 32) | mode.as_int(); } +}; + +/*! + * This is all the state that's required to understand how to draw a vertex. including both the GS + * state, and stuff (matrices) left behind in VU memory. The matrix slots are matrix indices into + * the original bones matrices (all the matrices in the skeleton). An index of -1 indicates that + * there is no known matrix in this slot. + */ +struct MercState { + MercGsState merc_draw_mode; + // vu1_matrix_slots[x] = y + // where x is the slot in VU1 memory, and y is the matrix index for the bones/skeleton stuff. + std::array vu1_matrix_slots; + MercState() { vu1_matrix_slots.fill(-1); } +}; + +/*! + * Required information for a "draw", consisting of a strip of triangles (represented as indices for + * OpenGL triangle strip) and the draw settings. + */ +struct MercDraw { + size_t ctrl_idx; // which merc ctrl in the level we correspond to + size_t effect_idx; // which effect within that control + size_t frag_idx; // which frag within that effect + // note that the above triple isn't enough to uniquely identify a draw - there can be multiple + // draws within a fragment. + + // draw settings + MercState state; + + // opengl indices. currently into a per-effect vertex list (likely to merge into a giant buffer + // eventually) + std::vector indices; + + // where we would be in VU1 data memory (used in construction) + u32 vtx_offset; // relative to writing output zone + u32 vtx_nloop; // nloop that goes in the gif tag drawing us. +}; + +/*! + * Merc Vertex. Not the format we'll want in the game data files, but most useful as an intermediate + * when building up draws. + */ +struct MercUnpackedVtx { + int kind = 0; // 1, 2, or 3 matrix + math::Vector3f pos; // position + math::Vector3f nrm; // normal (as input to the merc math, pretty sure legnth is bogus) + math::Vector2f st; // texture coordinates + math::Vector rgba; + + int skel_mats[3]; + float mat_weights[3]; + + u16 dst0; + u16 dst1; +}; + +/*! + * An entire merc-effect, split into draws. + * Note that copied or multiply-placed vertices will be de-deduplicated, but not identical vertices + * that actually appear in the input to merc. + */ +struct ConvertedMercEffect { + size_t ctrl_idx; + size_t effect_idx; + // draws from all fragments. + std::vector draws; + std::vector vertices; +}; + +/*! + * Extract a merc-ctrl data structure. This is mostly just copying the GOAL data to C++ classes, + * but does include the effect of processing the DMA data through VIF. + */ +MercCtrl extract_merc_ctrl(const LinkedObjectFile& file, + const DecompilerTypeSystem& dts, + int word_idx) { + Ref ref; + ref.data = &file; + ref.seg = 0; + ref.byte_offset = word_idx * 4; + + auto tr = typed_ref_from_basic(ref, dts); + + MercCtrl ctrl; + ctrl.from_ref(tr, dts); // the merc data import + return ctrl; +} + +/*! + * Find the word indices for the merc ctrls (the type tags) + */ +std::vector find_merc_ctrls(const LinkedObjectFile& file) { + std::vector result; + for (size_t i = 0; i < file.words_by_seg.at(0).size(); i++) { + const auto& word = file.words_by_seg[0][i]; + if (word.kind() == LinkedWord::TYPE_PTR && word.symbol_name() == "merc-ctrl") { + result.push_back(i); + } + } + return result; +} + +namespace { +/*! + * Merc models tend to have strange texture ids. I don't really understand why. + * On login, the texture is checked against a list of textures in the bsp, and replaced with this. + * It doesn't seem to be related to sharing textures between levels - the yakow texture uses this. + */ +u32 remap_texture(u32 original, const std::vector& map) { + auto masked = original & 0xffffff00; + for (auto& t : map) { + if (t.original_texid == masked) { + return t.new_texid | 20; + } + } + return original; +} + +/*! + * Set the alpha fields of a DrawMode (for PC renderers) based on gs alpha register + */ +void update_mode_from_alpha1(GsAlpha reg, DrawMode& mode) { + if (reg.a_mode() == GsAlpha::BlendMode::SOURCE && reg.b_mode() == GsAlpha::BlendMode::DEST && + reg.c_mode() == GsAlpha::BlendMode::SOURCE && reg.d_mode() == GsAlpha::BlendMode::DEST) { + // (Cs - Cd) * As + Cd + // Cs * As + (1 - As) * Cd + mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_DST_SRC_DST); + + } else if (reg.a_mode() == GsAlpha::BlendMode::SOURCE && + reg.b_mode() == GsAlpha::BlendMode::ZERO_OR_FIXED && + reg.c_mode() == GsAlpha::BlendMode::SOURCE && + reg.d_mode() == GsAlpha::BlendMode::DEST) { + // (Cs - 0) * As + Cd + // Cs * As + (1) * CD + mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_0_SRC_DST); + } else if (reg.a_mode() == GsAlpha::BlendMode::SOURCE && + reg.b_mode() == GsAlpha::BlendMode::ZERO_OR_FIXED && + reg.c_mode() == GsAlpha::BlendMode::ZERO_OR_FIXED && + reg.d_mode() == GsAlpha::BlendMode::DEST) { + ASSERT(reg.fix() == 128); + // Cv = (Cs - 0) * FIX + Cd + // if fix = 128, it works out to 1.0 + mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_0_FIX_DST); + // src plus dest + } else if (reg.a_mode() == GsAlpha::BlendMode::SOURCE && + reg.b_mode() == GsAlpha::BlendMode::DEST && + reg.c_mode() == GsAlpha::BlendMode::ZERO_OR_FIXED && + reg.d_mode() == GsAlpha::BlendMode::DEST) { + // Cv = (Cs - Cd) * FIX + Cd + ASSERT(reg.fix() == 64); + mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_DST_FIX_DST); + } else if (reg.a_mode() == GsAlpha::BlendMode::DEST && + reg.b_mode() == GsAlpha::BlendMode::SOURCE && + reg.c_mode() == GsAlpha::BlendMode::ZERO_OR_FIXED && + reg.d_mode() == GsAlpha::BlendMode::ZERO_OR_FIXED) { + } + + else { + // unsupported blend: a 0 b 1 c 0 d 2 is this part of generic? + fmt::print("unsupported blend: a {} b {} c {} d {}\n", (int)reg.a_mode(), (int)reg.b_mode(), + (int)reg.c_mode(), (int)reg.d_mode()); + mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_DST_SRC_DST); + // ASSERT(false); + } +} + +/*! + * Convert merc shader to PC draw mode + */ +DrawMode process_draw_mode(const MercShader& info) { + DrawMode mode; + /* + * (new 'static 'gs-test + :ate #x1 + :atst (gs-atest greater-equal) + :aref #x26 + :zte #x1 + :ztst (gs-ztest greater-equal) + ) + */ + mode.enable_at(); + mode.set_alpha_test(DrawMode::AlphaTest::GEQUAL); + mode.set_aref(0x26); + mode.set_alpha_fail(GsTest::AlphaFail::KEEP); + mode.set_alpha_test(DrawMode::AlphaTest::GEQUAL); + mode.enable_zt(); + mode.enable_depth_write(); + mode.set_depth_test(GsTest::ZTest::GEQUAL); + + // check these + mode.disable_ab(); + mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_DST_SRC_DST); + + // the alpha matters (maybe?) + update_mode_from_alpha1(info.alpha, mode); + + // the clamp matters + if (!(info.clamp == 0b101 || info.clamp == 0 || info.clamp == 1 || info.clamp == 0b100)) { + ASSERT_MSG(false, fmt::format("clamp: 0x{:x}", info.clamp)); + } + + mode.set_clamp_s_enable(info.clamp & 0b1); + mode.set_clamp_t_enable(info.clamp & 0b100); + + return mode; +} + +float u32_as_float(u32 in) { + float out; + memcpy(&out, &in, sizeof(float)); + return out; +} + +u32 float_as_u32(float in) { + u32 out; + memcpy(&out, &in, sizeof(float)); + return out; +} +} // namespace + +/*! + * Representing something that can be written to the merc output buffer. 1 qw + */ +struct MercOutputQuadword { + enum class Kind { + INVALID, // uninitialized, or in the middle of another thing + VTX_START, // the first qw of a vertex + SHADER_START, // the first qw of a shader (the giftag) + PRIM_START // the giftag for a list of vertices + } kind = Kind::INVALID; + + // if we're a vertex + u32 vtx_idx = -1; // index in the effect's vertex list. + bool adc = false; // if our adc flag is set. this differs between copies, so put it here. + + // if we're a primitive giftag, the number of vertices that come after us. + u32 nloop_count = 0; +}; + +struct MercMemory { + std::array memory; +}; + +/*! + * Add vertices from a fragment to memory. Emulates the unpacking. + */ +void handle_frag(const std::string& debug_name, + const MercCtrlHeader& ctrl_header, + const MercFragment& frag, + const MercFragmentControl& frag_ctrl, + const MercState& state, + std::vector& effect_vertices, + MercMemory& memory) { + (void)frag_ctrl; + (void)debug_name; + // fmt::print("handling frag: {}\n", debug_name); + // fmt::print("{}\n", frag.print()); + + // we'll iterate through the lump and rgba data + int lump_ptr = 0; // vertex data starts at the beginning of "lump" + int rgba_ptr = frag.header.rgba_off; // rgba is in u4's + int perc_ptr = frag.header.perc_off; + int last_mat2_perc = perc_ptr - 1; + int perc_toggle = 0; + + u32 mat1_cnt = frag.header.mat1_cnt; + u32 mat12_cnt = frag.header.mat2_cnt + mat1_cnt; + u32 mat123_cnt = frag.header.mat3_cnt + mat12_cnt; + + // loop through vertices. + int prev_mat0 = -1; + int prev_mat1 = -1; + int prev_mat2 = -1; + for (size_t i = 0; i < mat123_cnt; i++) { + u32 current_vtx_idx = effect_vertices.size(); // idx in effect vertex list. + auto& vtx = effect_vertices.emplace_back(); + + if (i < mat1_cnt) { + vtx.kind = 1; // 1 matrix + } else if (i < mat12_cnt) { + vtx.kind = 2; // 2 matrix + } else { + vtx.kind = 3; + } + + // the three quadwords in the source data + auto v0 = frag.lump4_unpacked.at(lump_ptr); + auto v1 = frag.lump4_unpacked.at(lump_ptr + 1); + auto v2 = frag.lump4_unpacked.at(lump_ptr + 2); + + // ilwr.x vi08, vi01 ;; load mat0 from vertex + u16 mat0_addr; + memcpy(&mat0_addr, &v0.x(), 2); + u16 mat1_addr; + memcpy(&mat1_addr, &v0.y(), 2); + + if (vtx.kind == 1) { + vtx.skel_mats[0] = state.vu1_matrix_slots.at(vu1_addr_to_matrix_slot(mat0_addr)); + vtx.skel_mats[1] = -1; + vtx.skel_mats[2] = -1; + vtx.mat_weights[0] = 1.f; + vtx.mat_weights[1] = 0.f; + vtx.mat_weights[2] = 0.f; + ASSERT(vtx.skel_mats[0] >= 0); + } else if (vtx.kind == 2) { + u8 m0 = mat0_addr & 0x7f; + u8 m1 = mat1_addr & 0x7f; + if (m0 == 0x7f) { + ASSERT(prev_mat0 != -1); + } else { + prev_mat0 = vu1_addr_to_matrix_slot(m0); + prev_mat1 = vu1_addr_to_matrix_slot(m1); + } + vtx.skel_mats[0] = state.vu1_matrix_slots.at(prev_mat0); + vtx.skel_mats[1] = state.vu1_matrix_slots.at(prev_mat1); + vtx.skel_mats[2] = -1; + + if (m0 != 0x7f && i != mat1_cnt) { + if (perc_toggle) { + perc_ptr++; + } + perc_toggle = !perc_toggle; + } + + auto perc = frag.unsigned_four_including_header.at(perc_ptr); + last_mat2_perc = perc_ptr; + + if (!perc_toggle) { + vtx.mat_weights[0] = perc.x() / 255.f; + vtx.mat_weights[1] = perc.y() / 255.f; + } else { + vtx.mat_weights[0] = perc.z() / 255.f; + vtx.mat_weights[1] = perc.w() / 255.f; + } + vtx.mat_weights[2] = 0.f; + + float sum = vtx.mat_weights[0] + vtx.mat_weights[1]; + ASSERT(std::abs(1.f - sum) < 1e-6); + } else if (vtx.kind == 3) { + u8 m0 = mat0_addr & 0x7f; + u8 m1 = mat1_addr & 0x7f; + + if (i == mat12_cnt) { + perc_ptr = last_mat2_perc; + } + + if (m0 == 0x7f) { + ASSERT(prev_mat0 != -1); + } else { + perc_ptr++; + prev_mat0 = vu1_addr_to_matrix_slot(m0); + prev_mat1 = vu1_addr_to_matrix_slot(m1); + prev_mat2 = vu1_addr_to_matrix_slot(frag.unsigned_four_including_header.at(perc_ptr).w()); + } + vtx.skel_mats[0] = state.vu1_matrix_slots.at(prev_mat0); + vtx.skel_mats[1] = state.vu1_matrix_slots.at(prev_mat1); + vtx.skel_mats[2] = state.vu1_matrix_slots.at(prev_mat2); + + auto perc = frag.unsigned_four_including_header.at(perc_ptr); + vtx.mat_weights[0] = perc.x() / 255.f; + vtx.mat_weights[1] = perc.y() / 255.f; + vtx.mat_weights[2] = perc.z() / 255.f; + + float sum = vtx.mat_weights[0] + vtx.mat_weights[1] + vtx.mat_weights[2]; + ASSERT(std::abs(1.f - sum) < 1e-6); + } else { + ASSERT(false); + } + + u16 mat1; + memcpy(&mat1, &v0.y(), 2); + u16 mat0; + memcpy(&mat0, &v0.x(), 2); + + // add.zw vf08, vf08, vf17 ;; lump offset + // vf17 = [2048, 255, -65537, xyz-add.x] (the ?? is set per fragment) + v0.z() += -65537; + v0.w() += frag.fp_header.x_add; + + // add.xyzw vf11, vf11, vf18 ;; lump offset + // vf18 = [st-out-X, st-out-X, -65537, xyz-add.y] (X = a if xtop = 0, X = b otherwise) + v1.x() += u32_as_float(ctrl_header.st_out_a); + v1.y() += u32_as_float(ctrl_header.st_out_a); + v1.z() += -65537; + v1.w() += frag.fp_header.y_add; + + // add.xyzw vf14, vf14, vf19 ;; lump offset + // vf19 = [st-magic, st-magic, -65537, xyz-add.z] + v2.x() += u32_as_float(ctrl_header.st_magic); + v2.y() += u32_as_float(ctrl_header.st_magic); + v2.z() += -65537; + v2.w() += frag.fp_header.z_add; + + vtx.pos = math::Vector3f(v0.w(), v1.w(), v2.w()); + vtx.nrm = math::Vector3f(v0.z(), v1.z(), v2.z()); + + // vtx.mat1 = 0; // not used like this + vtx.dst0 = float_as_u32(v1.x()) - 371; // xtop to output buffer offset + vtx.dst1 = float_as_u32(v1.y()) - 371; + vtx.rgba = frag.unsigned_four_including_header.at(rgba_ptr); + + // crazy flag logic to set adc + s16 mat1_flag = mat1; + s16 mat0_flag = mat0; + bool dst0_adc, dst1_adc; + if (vtx.kind == 1) { + ASSERT(mat1_flag == -1 || mat1_flag == 0 || mat1_flag == 1); + dst0_adc = mat1_flag <= 0; + dst1_adc = dst0_adc && (mat1_flag != 0); + dst0_adc = !dst0_adc; + dst1_adc = !dst1_adc; + } else { + // adc logic + // ilw.y vi09, -6(vi01) + s16 vi09 = mat1_flag; + // move.xyzw vf21, vf08 + bool vf21_has_adc = false; + bool vf08_has_adc = false; + if (!(vi09 > 0)) { + vf21_has_adc = true; + } + // ibgtz vi09, L47 + // + // addx.w vf21, vf21, vf17 + // + // L47: + // ilw.x vi09, -9(vi01) + vi09 = mat0_flag; + // ftoi4.xyzw vf21, vf21 + // + // sq.xyzw vf21, 2(vi10) + dst0_adc = !vf21_has_adc; + if (!(vi09 >= 0)) { + vf21_has_adc = vf08_has_adc; + } + dst1_adc = !vf21_has_adc; + // ibgez vi09, L50 + // + // ftoi4.xyzw vf21, vf08 + // + // L50: + // sq.xyzw vf21, 2(vi13) + + // dst0_adc = mat1_flag <= 0; + // dst1_adc = dst0_adc && (mat0_flag >= 0); + // dst0_adc = !dst0_adc; + // dst1_adc = !dst1_adc; + // fmt::print("{}\n", dst1_adc); + } + + // write to two spots in memory + auto& dst0_mem = memory.memory.at(vtx.dst0); + auto& dst1_mem = memory.memory.at(vtx.dst1); + + dst0_mem.kind = MercOutputQuadword::Kind::VTX_START; + dst0_mem.vtx_idx = current_vtx_idx; + dst0_mem.adc = dst0_adc; + memory.memory.at(vtx.dst0 + 1).kind = MercOutputQuadword::Kind::INVALID; + memory.memory.at(vtx.dst0 + 2).kind = MercOutputQuadword::Kind::INVALID; + + dst1_mem.kind = MercOutputQuadword::Kind::VTX_START; + dst1_mem.vtx_idx = current_vtx_idx; + dst1_mem.adc = dst1_adc; + memory.memory.at(vtx.dst1 + 1).kind = MercOutputQuadword::Kind::INVALID; + memory.memory.at(vtx.dst1 + 2).kind = MercOutputQuadword::Kind::INVALID; + + /* + fmt::print("place vertex {} @ {} {}: {} (adc {} {}) {}\n", current_vtx_idx, vtx.dst0, vtx.dst1, + vtx.pos.to_string_aligned(), dst0_adc, dst1_adc, mat1_flag); + */ + + lump_ptr += 3; // advance 3 qw + rgba_ptr++; + } +} + +/*! + * Build OpenGL index list from a single GIF packet. + * TODO: should check we aren't putting in x x R x x R + */ +std::vector index_list_from_packet(u32 vtx_ptr, + u32 nloop, + const MercMemory& memory, + const std::vector& vertices) { + std::vector result; + u32 prev_vtx = UINT32_MAX; + + result.push_back(UINT32_MAX); + while (nloop) { + auto& vtx_mem = memory.memory.at(vtx_ptr); + if (vtx_mem.kind == MercOutputQuadword::Kind::VTX_START) { + bool adc = vtx_mem.adc; + if (adc) { + result.push_back(vtx_mem.vtx_idx); + } else { + result.push_back(UINT32_MAX); + result.push_back(prev_vtx); + result.push_back(vtx_mem.vtx_idx); + } + prev_vtx = vtx_mem.vtx_idx; + } else { + // missing vertex! + fmt::print("MISSING VERTEX at {}\n", vtx_ptr); + result.push_back(UINT32_MAX); + } + + vtx_ptr += 3; + nloop--; + } + + result.push_back(UINT32_MAX); + return result; +} + +/*! + * Dump draws to obj file. + */ +std::string debug_dump_to_obj(const std::vector& draws, + const std::vector& vertices) { + std::string result; + std::vector verts; + std::vector> faces; + + for (auto& draw : draws) { + // add verts... + int queue[2]; + int q_idx = 0; + for (size_t ii = 2; ii < draw.indices.size(); ii++) { + u32 v0 = draw.indices[ii - 2]; + u32 v1 = draw.indices[ii - 1]; + u32 v2 = draw.indices[ii - 0]; + if (v0 != UINT32_MAX && v1 != UINT32_MAX && v2 != UINT32_MAX) { + faces.emplace_back(v0 + 1, v1 + 1, v2 + 1); + } + } + for (auto& idx : draw.indices) { + if (idx == UINT32_MAX) { + q_idx = 0; + } else { + if (q_idx >= 2) { + faces.emplace_back(queue[0] + 1, queue[1] + 1, idx + 1); + } + queue[(q_idx++) % 2] = idx; + } + } + } + + for (auto& vtx : vertices) { + result += fmt::format("v {} {} {}\n", vtx.pos.x() / 1024.f, vtx.pos.y() / 1024.f, + vtx.pos.z() / 1024.f); + } + + for (auto& face : faces) { + result += fmt::format("f {}/{} {}/{} {}/{}\n", face.x(), face.x(), face.y(), face.y(), face.z(), + face.z()); + } + + return result; +} + +math::Vector4 vtx_to_rgba_bone_debug(const MercUnpackedVtx& vtx) { + math::Vector4 result; + result.fill(0); + for (int i = 0; i < 3; i++) { + if (vtx.skel_mats[i] == -1 || vtx.mat_weights[i] == 0) { + continue; + } + u32 rgba_packed = colors::common_colors[vtx.skel_mats[i] % colors::COLOR_COUNT]; + result.x() += ((rgba_packed >> 16) & 0xff) * vtx.mat_weights[i]; + result.y() += ((rgba_packed >> 8) & 0xff) * vtx.mat_weights[i]; + result.z() += ((rgba_packed >> 0) & 0xff) * vtx.mat_weights[i]; + } + return result; +} + +std::string debug_dump_to_ply(const std::vector& draws, + const std::vector& vertices) { + std::vector verts; + std::vector> faces; + + for (auto& draw : draws) { + // add verts... + for (size_t ii = 2; ii < draw.indices.size(); ii++) { + u32 v0 = draw.indices[ii - 2]; + u32 v1 = draw.indices[ii - 1]; + u32 v2 = draw.indices[ii - 0]; + if (v0 != UINT32_MAX && v1 != UINT32_MAX && v2 != UINT32_MAX) { + faces.emplace_back(v0, v1, v2); + } + } + } + + std::string result = fmt::format( + "ply\nformat ascii 1.0\nelement vertex {}\nproperty float x\nproperty float y\nproperty " + "float z\nproperty uchar red\nproperty uchar green\nproperty uchar blue\nelement face " + "{}\nproperty list uchar int vertex_index\nend_header\n", + vertices.size(), faces.size()); + + for (auto& vtx : vertices) { + auto rgba = vtx_to_rgba_bone_debug(vtx); + result += fmt::format("{} {} {} {} {} {}\n", vtx.pos.x() / 1024.f, vtx.pos.y() / 1024.f, + vtx.pos.z() / 1024.f, rgba[0], rgba[1], rgba[2]); + } + + for (auto& face : faces) { + result += fmt::format("3 {} {} {}\n", face.x(), face.y(), face.z()); + } + + return result; +} + +ConvertedMercEffect convert_merc_effect(const MercEffect& input_effect, + const MercCtrlHeader& ctrl_header, + const TextureDB& tdb, + const std::vector& map, + const std::string& debug_name, + size_t ctrl_idx, + size_t effect_idx, + bool dump) { + ConvertedMercEffect result; + result.ctrl_idx = ctrl_idx; + result.effect_idx = effect_idx; + // full reset of state per effect. + // we have no idea what the previous effect draw will be - it might be given to + // mercneric. + bool shader_set = false; // no previous shader can reliably be known + MercState merc_state; // current gs settings/matrix slots + MercMemory merc_memories[2]; // double buffered output + int memory_buffer_toggle = 0; // which output we're in + + for (size_t fi = 0; fi < input_effect.frag_ctrl.size(); fi++) { + const auto& frag = input_effect.frag_geo[fi]; + const auto& frag_ctrl = input_effect.frag_ctrl[fi]; + + // first, deal with matrices + for (size_t mi = 0; mi < frag_ctrl.mat_xfer_count; mi++) { + const auto& xfer = frag_ctrl.mat_dest_data[mi]; + merc_state.vu1_matrix_slots[vu1_addr_to_matrix_slot(xfer.matrix_dest)] = xfer.matrix_number; + } + + if (!shader_set) { + // if we don't have a shader set, we shouldn't have anything that reuses the last shader + ASSERT(frag.header.strip_len == 0); + // and we should set the shader + ASSERT(frag.fp_header.shader_cnt > 0); + shader_set = true; + } + + // run the frag. + // this will add vertices to the per-effect vertex lists and also update the merc memory + // to point to these. + + handle_frag(debug_name, ctrl_header, frag, frag_ctrl, merc_state, result.vertices, + merc_memories[memory_buffer_toggle]); + + // we'll add draws after this draw, but wait to actually populate the index lists until + // we've processed all the vertices. + size_t first_draw_to_update = result.draws.size(); + + // continuation of a previous shader + if (frag.header.strip_len) { + // add the continued draw + auto& new_draw = result.draws.emplace_back(); + new_draw.ctrl_idx = ctrl_idx; + new_draw.effect_idx = effect_idx; + new_draw.frag_idx = fi; + new_draw.state = merc_state; + new_draw.vtx_offset = 1; + // just remember where it started. we might copy some vertices from a later draw in this + // fragment back to this draw, and at this point we don't know what the adc flags would be. + // (or their index, because we are deduplicated) + new_draw.vtx_nloop = frag.header.strip_len; + } + + // loop over fresh shaders + for (size_t i = 0; i < frag.fp_header.shader_cnt; i++) { + const auto& shader = frag.shaders.at(i); + // update merc state from shader (will hold over to next fragment, if needed) + merc_state.merc_draw_mode.mode = process_draw_mode(shader); + u32 new_tex = remap_texture(shader.original_tex, map); + + // texture the texture page/texture index, and convert to a PC port texture ID + u32 tpage = new_tex >> 20; + u32 tidx = (new_tex >> 8) & 0b1111'1111'1111; + u32 tex_combo = (((u32)tpage) << 16) | tidx; + // look up the texture to make sure it's valid + auto tex = tdb.textures.find(tex_combo); + ASSERT(tex != tdb.textures.end()); + // remember the texture id + merc_state.merc_draw_mode.pc_combo_tex_id = tex_combo; + + // add the draw + auto& new_draw = result.draws.emplace_back(); + new_draw.ctrl_idx = ctrl_idx; + new_draw.effect_idx = effect_idx; + new_draw.frag_idx = fi; + new_draw.state = merc_state; + // write the shader to memory + merc_memories[memory_buffer_toggle].memory.at(shader.output_offset).kind = + MercOutputQuadword::Kind::SHADER_START; + for (int mi = 1; mi < 6; mi++) { + // fill 5qw of adgif data with invalid. make sure we don't read verts from here + merc_memories[memory_buffer_toggle].memory.at(shader.output_offset + mi).kind = + MercOutputQuadword::Kind::INVALID; + } + // write the giftag for primitives + auto& prim_packet = merc_memories[memory_buffer_toggle].memory.at(shader.output_offset + 6); + prim_packet.kind = MercOutputQuadword::Kind::PRIM_START; + prim_packet.nloop_count = shader.next_strip_nloop; + + // update draw from hidden fields in adgif. + new_draw.vtx_offset = shader.output_offset + 7; + new_draw.vtx_nloop = shader.next_strip_nloop; + } + + // copy from other places inside this output buffer + u32 srcdst_ptr = frag.header.srcdest_off; + for (u32 sci = 0; sci < frag.header.samecopy_cnt; sci++) { + auto& cpy = frag.unsigned_four_including_header[srcdst_ptr]; + // fmt::print("sci: {}\n", cpy.to_string_hex_byte()); + u32 src = cpy[0]; + auto& vert = merc_memories[memory_buffer_toggle].memory.at(src); + u32 dst = cpy[1]; + auto& dvert = merc_memories[memory_buffer_toggle].memory.at(dst); + if (vert.kind == MercOutputQuadword::Kind::VTX_START) { + dvert = vert; + if (cpy[3]) { + // dvert.adc = true; + dvert.adc = !dvert.adc; + } + } else { + fmt::print("sc missing vert\n"); + dvert.kind = MercOutputQuadword::Kind::INVALID; + } + + srcdst_ptr++; + } + + // "cross" copy from the other output buffer + for (u32 cci = 0; cci < frag.header.crosscopy_cnt; cci++) { + auto& cpy = frag.unsigned_four_including_header[srcdst_ptr]; + // fmt::print("cci: {}\n", cpy.to_string_hex_byte()); + u32 src = cpy[0]; + auto& vert = merc_memories[memory_buffer_toggle ^ 1].memory.at(src); + u32 dst = cpy[1]; + auto& dvert = merc_memories[memory_buffer_toggle].memory.at(dst); + if (vert.kind == MercOutputQuadword::Kind::VTX_START) { + dvert = vert; + if (cpy[3]) { + // dvert.adc = true; + dvert.adc = !dvert.adc; + } + } else { + fmt::print("cc missing vert\n"); + dvert.kind = MercOutputQuadword::Kind::INVALID; + } + srcdst_ptr++; + } + + // now that we've copied all vertices, create index lists. + for (size_t i = first_draw_to_update; i < result.draws.size(); i++) { + auto& draw = result.draws[i]; + draw.indices = index_list_from_packet(draw.vtx_offset, draw.vtx_nloop, + merc_memories[memory_buffer_toggle], result.vertices); + } + + memory_buffer_toggle ^= 1; + } + + if (dump) { + file_util::write_text_file( + file_util::get_file_path( + {"debug_out/merc", fmt::format("{}_{}.ply", debug_name, effect_idx)}), + debug_dump_to_ply(result.draws, result.vertices)); + } + + return result; +} + +/*! + * Top-level merc extraction + */ +void extract_merc(const ObjectFileData& ag_data, + const TextureDB& tex_db, + const DecompilerTypeSystem& dts, + const std::vector& map, + tfrag3::Level& /*out*/, + bool dump_level) { + if (dump_level) { + file_util::create_dir_if_needed(file_util::get_file_path({"debug_out/merc"})); + } + // find all merc-ctrls in the object file + auto ctrl_locations = find_merc_ctrls(ag_data.linked_data); + + // extract them. this does very basic unpacking of data, as done by the VIF/DMA on PS2. + std::vector ctrls; + for (auto location : ctrl_locations) { + auto ctrl = extract_merc_ctrl(ag_data.linked_data, dts, location); + ctrls.push_back(ctrl); + } + + // extract draws. this does no regrouping yet. + std::vector all_effects; + for (size_t ci = 0; ci < ctrls.size(); ci++) { + for (size_t ei = 0; ei < ctrls[ci].effects.size(); ei++) { + all_effects.push_back(convert_merc_effect(ctrls[ci].effects[ei], ctrls[ci].header, tex_db, + map, ctrls[ci].name, ci, ei, dump_level)); + } + } +} +} // namespace decompiler diff --git a/decompiler/level_extractor/extract_merc.h b/decompiler/level_extractor/extract_merc.h new file mode 100644 index 0000000000..3e40dfe69f --- /dev/null +++ b/decompiler/level_extractor/extract_merc.h @@ -0,0 +1,16 @@ +#pragma once + +#include "decompiler/data/TextureDB.h" +#include "common/custom_data/Tfrag3Data.h" +#include "decompiler/ObjectFile/ObjectFileDB.h" +#include "decompiler/level_extractor/common_formats.h" + +namespace decompiler { + +void extract_merc(const ObjectFileData& ag_data, + const TextureDB& tex_db, + const DecompilerTypeSystem& dts, + const std::vector& map, + tfrag3::Level& out, + bool dump_level); +} diff --git a/decompiler/util/goal_data_reader.cpp b/decompiler/util/goal_data_reader.cpp index de4b7d64bc..80a89c362f 100644 --- a/decompiler/util/goal_data_reader.cpp +++ b/decompiler/util/goal_data_reader.cpp @@ -280,4 +280,64 @@ std::string inspect_ref(const Ref& ref) { default: ASSERT(false); } +} + +u32 deref_u32(const Ref& ref, int word_offset) { + if ((ref.byte_offset % 4) != 0) { + throw Error("deref_u32 bad alignment"); + } + const auto& word = ref.data->words_by_seg.at(ref.seg).at(word_offset + (ref.byte_offset / 4)); + if (word.kind() != decompiler::LinkedWord::PLAIN_DATA) { + throw Error("deref_u32 bad kind: {}", (int)word.kind()); + } + return word.data; +} + +u64 deref_u64(const Ref& ref, int dw_offset) { + if ((ref.byte_offset % 8) != 0) { + throw Error("deref_u64 bad alignment"); + } + const auto& word0 = ref.data->words_by_seg.at(ref.seg).at(ref.byte_offset / 4 + (dw_offset * 2)); + const auto& word1 = + ref.data->words_by_seg.at(ref.seg).at(1 + (ref.byte_offset / 4) + (dw_offset * 2)); + + if (word0.kind() != decompiler::LinkedWord::PLAIN_DATA) { + throw Error("deref_u64 bad kind: {}", (int)word0.kind()); + } + if (word1.kind() != decompiler::LinkedWord::PLAIN_DATA) { + throw Error("deref_u64 bad kind: {}", (int)word1.kind()); + } + u64 result = word1.data; + result <<= 32; + result |= word0.data; + return result; +} + +u16 deref_u16(const Ref& ref, int array_idx) { + u32 u32_offset = array_idx / 2; + u32 u32_val = deref_u32(ref, u32_offset); + if (array_idx & 1) { + return u32_val >> 16; + } else { + return (u16)u32_val; + } +} + +s8 deref_s8(const Ref& ref, int byte) { + u32 u32_offset = byte / 4; + u32 u32_val = deref_u32(ref, u32_offset); + s8 vals[4]; + memcpy(vals, &u32_val, 4); + return vals[byte & 3]; +} + +u8 deref_u8(const Ref& ref, int byte) { + u32 total_offset = ref.byte_offset + byte; + const auto& word = ref.data->words_by_seg.at(ref.seg).at(total_offset / 4); + if (word.kind() != decompiler::LinkedWord::PLAIN_DATA) { + throw Error("deref_u32 bad kind: {}", (int)word.kind()); + } + u8 vals[4]; + memcpy(vals, &word.data, 4); + return vals[total_offset & 3]; } \ No newline at end of file diff --git a/decompiler/util/goal_data_reader.h b/decompiler/util/goal_data_reader.h index 3a40e48f85..7132a73412 100644 --- a/decompiler/util/goal_data_reader.h +++ b/decompiler/util/goal_data_reader.h @@ -20,6 +20,9 @@ struct Ref { struct TypedRef { Ref ref; Type* type = nullptr; + + TypedRef() = default; + TypedRef(const Ref& r, Type* t) : ref(r), type(t) {} }; void read_plain_data_field(const TypedRef& object, @@ -34,7 +37,6 @@ T read_plain_data_field(const TypedRef& object, const decompiler::DecompilerTypeSystem& dts) { u8 data[sizeof(T)]; read_plain_data_field(object, field_name, dts, sizeof(T), data); - T result; memcpy(&result, data, sizeof(T)); return result; @@ -68,5 +70,9 @@ std::string get_type_of_basic(const Ref& object); TypedRef typed_ref_from_basic(const Ref& object, const decompiler::DecompilerTypeSystem& dts); Ref deref_label(const Ref& object); - +u32 deref_u32(const Ref& ref, int word_offset); +u16 deref_u16(const Ref& ref, int array_idx); +s8 deref_s8(const Ref& ref, int byte); +u8 deref_u8(const Ref& ref, int byte); +u64 deref_u64(const Ref& ref, int dw_offset); std::string inspect_ref(const Ref& ref); diff --git a/decompiler/util/sparticle_decompile.cpp b/decompiler/util/sparticle_decompile.cpp index 3cb2d1cc0d..632e62b5e5 100644 --- a/decompiler/util/sparticle_decompile.cpp +++ b/decompiler/util/sparticle_decompile.cpp @@ -444,10 +444,10 @@ goos::Object decompile_sparticle_sound_spec(const std::vector& /*wor goos::Object decompile_sparticle_group_item(const TypeSpec& type, const DecompilerLabel& label, - const std::vector& labels, + const std::vector& /*labels*/, const std::vector>& words, const TypeSystem& ts, - const LinkedObjectFile* file) { + const LinkedObjectFile* /*file*/) { // auto normal = decompile_structure(type, label, labels, words, ts, file, false); // fmt::print("Doing: {}\n", normal.print()); auto uncast_type_info = ts.lookup_type(type); diff --git a/docs/scratch/merc.md b/docs/scratch/merc.md new file mode 100644 index 0000000000..9eaa75b893 --- /dev/null +++ b/docs/scratch/merc.md @@ -0,0 +1,420 @@ +Loop over effect (skip those flagged with use-mercneric) + +Loop over fragments + +First thing is the "row" data. +row.x/y is st-vif-add from the merc-ctrl-header. +row.z = 0x47800000, row.w = 0x4b010000 + + +Next is the unsigned-four. +This is unpacked with unpack8. +It always goes to 140 in the VU memory. +The source data is just the merc-fragment (I believe it includes merc-byte-header) + +After is the lump-four. This has a STMOD enabled and is unpack8. +It goes after the unsigned-four (variable size) in VU memory. +The source data is after. Rounding in static data is ((u4c + 3) >> 2) << 4. + +After is the Floating Point data. This is copied as unpack32. + +_only_ on the first fragment of an effect, there's an upload to 132 of 8 qw: +the first 7 are lights. +the final is the first quadword of the merc-ctrl-header (xyz-scale, st-magic, st-out-a, st-out-b) + +there are secrets hidden in the lights: +- light 0's w is some flag with ignore alpha in it. + + +Next is (optional) matrix uploads. +There is a loop of transfers. These are all size 7 qw. + +Next is the MSCAL! +It has a different number of the first fragment of an effect. +This tells merc to load the light stuff. + +End Loop over fragments + +Increment effect +Increment effect info +Decrement effect count + +update some next-merc thing in the scratchpad + + +# Merc Renderer + +## Memory layout +Unpacks adgif shaders/giftags to the output memory. +Can reuse the last shader from the last frag in the effect. + +## Matrix Setup +The matrix contains a "tmat" and "nmat". The "tmat" transforms the point and the "nmat" rotates the normals. + +Matrices that are freshly uploaded with this fragment are preprocessed to include the effect of the perspective matrix. The inputs are in registers 8, 10, 12, 25, and the outputs are 9, 11, 13, 26. The output is written over the input. + +``` +mula.xyzw ACC, vf15, vf08 +maddz.xyzw vf09, vf16, vf08 +mula.xyzw ACC, vf15, vf10 +maddz.xyzw vf11, vf16, vf10 +mula.xyzw ACC, vf15, vf12 +maddz.xyzw vf13, vf16, vf12 +addax.xyzw vf20, vf00 +madda.xyzw ACC, vf27, vf25 +maddz.xyzw vf26, vf28, vf25 +``` + +with +``` +vf15 = [spdx, spdy, spdz, 0] +vf16 = [0, 0, 0, spdw] +vf27 = [pdx, pdy, pdz, 0] +vf28 = [0, 0, 0, pdw] +``` +(see `merc_asm.asm` for how to compute these in more detail) + +## Vertex layout +The "lump" data contains the vertices. The layout is: +``` +mat0, mat1, nrmx, posx +dst0, dst1, nrmy, posy +texs, text, nrmz, posz +``` +It begins with `mat1-cnt` vertices that are deformed by only a single matrix. + +The `rgba-offset` points to somewhere in the u4 data. Each vertex has a single rgba, stored as unpacked u8's. + +## Mat1 Loop +`vi01` is the lump pointer that reads vertices, `vf17`, `vf18`, `vf19` are the "lump offsets" to be applied to the unpacked vertices. + +The operations are: +```asm +ilwr.x vi08, vi01 ;; load mat0 from vertex +lqi.xyzw vf08, vi01 ;; load vertex qw 0 +lqi.xyzw vf11, vi01 ;; load vertex qw 1 +lqi.xyzw vf14, vi01 ;; load vertex qw 2 + +lq.xyz vf29, 4(vi08) ;; load nmat0 +lq.xyz vf30, 5(vi08) ;; load nmat1 +lq.xyzw vf31, 6(vi08) ;; load nmat2 + +add.zw vf08, vf08, vf17 ;; lump offset +add.xyzw vf11, vf11, vf18 ;; lump offset +add.xyzw vf14, vf14, vf19 ;; lump offset + +mtir vi10, vf11.x ;; get dest0 +mtir vi13, vf11.y ;; get dest1 + +;; rotate normal +mulaz.xyzw ACC, vf29, vf08 +maddaz.xyzw ACC, vf30, vf11 +maddz.xyz vf11, vf31, vf14 + +;; load tmat +lq.xyzw vf25, 0(vi08) +lq.xyzw vf26, 1(vi08) +lq.xyzw vf27, 2(vi08) +lq.xyzw vf28, 3(vi08) + +;; get normal 1/length +erleng.xyz P, vf11 + +;; transform point +mulaw.xyzw ACC, vf25, vf08 +maddaw.xyzw ACC, vf26, vf11 +maddw.xyzw vf08, vf27, vf14 +add.xyzw vf08, vf08, vf28 + +;; clear nrmz +mr32.z vf14, vf00 + +;; ONLY if merc prime miniw.w vf08, vf08, vf01 + +;; perspective divide +div Q, vf01.w, vf08.w +mul.xyz vf08, vf08, Q +mul.xyzw vf14, vf14, Q + +;; load rgba +lqi.xyzw vf23, vi03 + +;; hvdf offset +add.xyzw vf08, vf08, vf22 + +;; normalize normal +mfp.w vf20, P +mulw.xyzw vf11, vf11, vf20 + +;; fog max +miniw.w vf08, vf08, vf03 + +;; fetch mat1 (note that vi01 is incremented 3x in pipeline) +ilw.y vi09, -6(vi01) + +;; dot product with light +mulax.xyzw ACC, vf01, vf11 +madday.xyzw ACC, vf02, vf11 +maddz.xyzw vf11, vf03, vf11 + +;; fog min +maxw.w vf08, vf08, vf02 + +;; rgba itof +itof0.xyzw vf23, vf23 + +;; light clamp +maxx.xyzw vf11, vf11, vf00 + +move.xyzw vf21, vf08 + +;; color the lights +mulax.xyzw ACC, vf04, vf11 +madday.xyzw ACC, vf05, vf11 +maddaz.xyzw ACC, vf06, vf11 + +;; IF vi09 <= 0 +addx.w vf21, vf21, vf17 + +;; add ambient lighting +maddw.xyzw vf11, vf07, vf00 + +;; ftoi the vertex position +ftoi4.xyzw vf21, vf21 + +;; apply vertex color +mul.xyzw vf11, vf11, vf23 + +;; store dest +sq.xyzw vf21, 2(vi10) + +;; IF vi09 == 0 +ftoi4.xyzw vf21, vf08 + +;; store st +sq.xyzw vf14, 0(vi10) +sq.xyzw vf14, 0(vi13) + +;; store second position +sq.xyzw vf21, 2(vi13) + +;; final light +miniy.xyzw vf11, vf11, vf17 +ftoi0.xyzw vf11, vf11 +sq.xyzw vf11, 1(vi10) +sq.xyzw vf11, 1(vi13) + +``` +Note: it might be that the last vertex can't change its adc flag for dst2. Maybe only in some cases. Worth checking more if there are stripping issues. + +## Mat2 Loop + +NOTE: we might need to advance perc by 1 at the beginning if there are any mat0's. +```asm +;; compute perc ptr +ilw.x vi02, 3(vi12) +iadd vi02, vi02, vi12 + +;; load vertex +lqi.xyzw vf08, vi01 +lqi.xyzw vf11, vi01 +lqi.xyzw vf14, vi01 + +;; and perc +lqi.xyzw vf24, vi02 + +;; extract mat idx +mtir vi10, vf08.x +mtir vi13, vf08.y + +;; convert perc +itof0.xyzw vf24, vf24 + +;; lump offset +add.zw vf08, vf08, vf17 +add.xyzw vf11, vf11, vf18 +add.xyzw vf14, vf14, vf19 + +;; mask off sign bit of mat0 and mat1 +iand vi10, vi10, vi05 (vi05 = 0x7f) <- looks like a 0 here means "reuse prev mat" +iand vi13, vi13, vi05 + +;; scale perc +mulw.xyzw vf24, vf24, vf29 ;; vf29.w = 0.003921569 + +;; load matrices +lq.xyzw vf20, 0(vi10) ;; tmat0.0 +lq.xyzw vf25, 0(vi13) ;; tmat1.0 +lq.xyzw vf23, 1(vi10) ;; tmat0.1 +lq.xyzw vf26, 1(vi13) ;; tmat1.1 +lq.xyzw vf20, 2(vi10) ;; tmat0.2 +lq.xyzw vf27, 2(vi13) ;; tmat1.2 +lq.xyzw vf23, 3(vi10) ;; tmat0.3 +lq.xyzw vf28, 3(vi13) ;; tmat1.3 +lq.xyzw vf20, 4(vi10) ;; nmat0.0 +lq.xyz vf29, 4(vi13) ;; nmat1.0 +lq.xyzw vf23, 5(vi10) ;; nmat0.1 +lq.xyz vf30, 5(vi13) ;; nmat1.1 +lq.xyzw vf20, 6(vi10) ;; nmat0.2 +lq.xyzw vf31, 6(vi13) ;; nmat1.2 + +;; multiply rows by perc. +;; mat0 uses perc.x, mat0 uses perc.y. Matrices are added. +;; ex: tmat2 = tmat0.2 * perc.x + tmat1.2 * perc.y +Results are + +vf25 = tmat0 +vf26 = tmat1 +vf27 = tmat2 +vf28 = tmat3 + +vf29 = nmat0 +vf30 = nmat1 +vf31 = nmat2 + +;; rotate normal +mulaz.xyzw ACC, vf29, vf08 +maddaz.xyzw ACC, vf30, vf11 +maddz.xyz vf11, vf31, vf14 + +;; transform point +mulaw.xyzw ACC, vf25, vf08 +maddaw.xyzw ACC, vf26, vf11 +maddw.xyzw vf08, vf27, vf14 +add.xyzw vf08, vf08, vf28 + +;; length of normal +erleng.xyz P, vf11 + +;; rgba offset +ilwr.y vi03, vi12 +iadd vi03, vi03, vi12 + +;; persepctive divide +div Q, vf01.w, vf08.w +mul.xyz vf08, vf08, Q +mul.xyzw vf14, vf14, Q + +;; load rgba +lqi.xyzw vf23, vi03 + +;; hvdf offset +add.xyzw vf08, vf08, vf22 + +;; normalize normal +mfp.w vf20, P +mulw.xyzw vf11, vf11, vf20 + +;; fog +miniw.w vf08, vf08, vf03 +maxw.w vf08, vf08, vf02 + +;; go get mat1 again +ilw.y vi09, -6(vi01) + +;; light dot product +mulax.xyzw ACC, vf01, vf11 +madday.xyzw ACC, vf02, vf11 +maddz.xyzw vf11, vf03, vf11 + +;; vertex color convert +itof0.xyzw vf23, vf23 + +;; light clamp +maxx.xyzw vf11, vf11, vf00 + + +;; adc logic +ilw.y vi09, -6(vi01) +move.xyzw vf21, vf08 +ibgtz vi09, L47 + +addx.w vf21, vf21, vf17 + +L47: +ilw.x vi09, -9(vi01) +ftoi4.xyzw vf21, vf21 +ilw.x vi09, -9(vi01) + +sq.xyzw vf21, 2(vi10) +ibgez vi09, L50 + +ftoi4.xyzw vf21, vf08 + +L50: +sq.xyzw vf21, 2(vi13) +``` + + +## Final Copies +assuming no mercprime, leaving out pipe flush (which is a tangled mess to flush the pipes of whatever of the 3 different loops were) +``` +;; vi08 = mercprime flag +ilw.w vi08, 1(vi00) + +;; find the byte header again +xtop vi02 +iaddiu vi04, vi02, 0x8c + +;; srcdest-off +ilwr.x vi05, vi04 + +;; samecopy-cnt +ilw.w vi06, 1(vi04) + +;; crosscopy-cnt +ilw.x vi07, 2(vi04) + +;; zero out vf25, vf26 +minix.xyzw vf25, vf00, vf00 +minix.xyzw vf26, vf00, vf00 + +;; compute srcdest table address +iadd vi05, vi05, vi04 + +;; compute output zone +iaddiu vi04, vi02, 0x173 + +;; compute srcdest cross copy table address +iadd vi06, vi06, vi05 + +;; compute end of cross copy +iadd vi07, vi07, vi06 + +;; compute address of the _old_ output buffer +iaddiu vi08, vi00, 0x1ba +isub vi08, vi08, vi02 +iaddiu vi08, vi08, 0x173 + +;; move addrs to vf +mfir.x vf25, vi04 ;; vf25.x = output zone +mfir.y vf25, vi04 ;; vf25.y = output zone +mfir.x vf26, vi08 ;; vf26.x = old output zone +mfir.y vf26, vi04 ;; vf26.y = output zone + +;; set up +maxx.xyzw vf13, vf13, vf00 ;; vf13 = 0 +maxi.xy vf27, vf00, I, I = 8388608.0 ;; vf27.xy = [8388608.0 8388608.0] +maxi.w vf27, vf00, I, I = 256 ;; vf27.w = 256 + +itof0.xyzw vf25, vf25 +itof0.xyzw vf26, vf26 + +ior vi02, vi05, vi00 ;; vi02 = srcdst table + +add.xyzw vf25, vf25, vf27 ;; hack float add trick +add.xyzw vf26, vf26, vf27 + +miniy.xyzw vf13, vf13, vf17 ;; float tricks +ibne vi06, vi05, L150 ;; branch if there are samecopys + +ior vi06, vi07, vi00 | max.xyzw vf25, vf26, vf26 + +L150: + +;; load from copy table +lqi.xyzw vf27, vi05 +;; table to float +itof0.xyzw vf27, vf27 + +``` diff --git a/docs/scratch/merc_asm.asm b/docs/scratch/merc_asm.asm new file mode 100644 index 0000000000..7ef16356f7 --- /dev/null +++ b/docs/scratch/merc_asm.asm @@ -0,0 +1,2331 @@ +;; Register use (after init and effect setup) +;; to be extra annoying, they often stash stuff in +;; w (and sometimes z) and use xyz for other stuff. + +;; vf01 = [lt0_dir.xyz, pfog0] +;; vf02 = [lt1_dir.xyz, fog-min] +;; vf03 = [lt2_dir.xyz, fog-max] +;; vf04 = [lt0_color] +;; vf05 = [lt1_color] +;; vf06 = [lt2_color] +;; vf07 = [lt_ambient] +;; vf17 = [2048, 255, -65537, xyz-add.x] (the ?? is set per fragment) +;; vf18 = [st-out-X, st-out-X, -65537, xyz-add.y] (X = a if xtop = 0, X = b otherwise) +;; vf19 = [st-magic, st-magic, -65537, xyz-add.z] +;; vf22 = hvdf-offset (does get set to others, but is always restored) +;; vf29 = [??, ??, ??, 0.003921569] + + +;; Low Memory use (after init and effect setup) +;; 1 - [adgif_giftag, use_mercprime] +;; 2 - hvdf-offset +;; 3 - [p0x, p1y, p2z, p2w] (note p2w, not p3w here!) +;; 4 - [p3x, p3y, p3z, p3w] +;; 5 - [p0x*sc, p1y*sc, p2z*sc, p2w*sc] (where sc is the xyz-scale of the header) + +;; 132 - not double buffered, lights + merc-ctrl-header (per ctrl) +;; 132 +;; 133 light 1 dir, w has flags (0x44 for ignore alpha, ) +;; 134 light 2 dir, w has fade out parameter (how much to fade out) +;; 139 - [xyz_scale, st-magic, st-out-a, st-out-b] +;; 140 - not double buffered, header (per effect) + +;; xtop + 140 + st-out +;; this contains the uploaded fp data. +;; the first + + +;; initialization - this runs after the merc program is uploaded and the vu1 low memory +;; block is uploaded. It sets constant registers and stashes some stuff in memory. + +;; - set vf01.w to pfog0 + lq.xyzw vf01, 7(vi00) | nop ;; vf01 = fog + lq.xyzw vf25, 3(vi00) | nop ;; vf25 = perspective.row0 + lq.xyzw vf26, 4(vi00) | nop ;; vf26 = perspective.row1 + lq.xyzw vf27, 5(vi00) | nop ;; vf27 = perspective.row2 + lq.xyzw vf28, 6(vi00) | nop ;; vf28 = perspective.row3 + mr32.xyzw vf01, vf01 | nop ;; rotate pfog0 into vf01.w + move.y vf25, vf26 | nop ;; setting up vf25 + move.zw vf25, vf27 | nop ;; same + sq.xyzw vf25, 3(vi00) | nop ;; setting up low 3. + 2048.0 | nop :i ;; setup I + 255.0 | maxi.x vf17, vf00, I :i ;; setup vf17 + -65537.0 | maxi.y vf17, vf00, I :i ;; setup vf17 + mr32.xyzw vf02, vf01 | minii.z vf17, vf00, I ;; vf17, setup vf02.w + lq.xyzw vf22, 2(vi00) | minii.z vf18, vf00, I ;; vf18.z, vf22 as hvdf-offset + 0.003921569 | minii.z vf19, vf00, I :i ;; vf19.z + sq.xyzw vf28, 4(vi00) | minii.w vf29, vf00, I :e ;; setup low 4 + mr32.xyzw vf03, vf02 | nop ;; set up vf03 + +;; the 17/20 entry points are the same as 32/35, but should be used +;; on the first frag of an effect. they set up lights. + +;; enter 17 (setup lights, with merc "prime") + iaddi vi07, vi00, 0x1 | nop ;; set vi07 mercprime + b L2 | nop + isw.w vi07, 1(vi00) | nop ;; leave behind mercprime flag. +ENTER_20: ;; (setup lights, no merc prime) + iaddi vi07, vi00, 0x0 | nop ;; no mercprime for us today. +L2: ;; (setup lights common) + lq.xyzw vf25, 139(vi00) | nop ;; vf25 = merc-ctrl-header + lq.xyzw vf26, 3(vi00) | nop ;; vf26 = persp-diag + lq.xyz vf01, 132(vi00) | nop ;; setup vf01 light 0 dir + lq.xyz vf02, 133(vi00) | nop ;; setup vf02 light 1 dir + lq.xyz vf03, 134(vi00) | addy.xy vf19, vf00, vf25 ;; vf03 light setup, st-magic + lq.xyzw vf04, 135(vi00) | mulx.xyzw vf26, vf26, vf25 ;; scaled persp diag + lq.xyzw vf05, 136(vi00) | nop + lq.xyzw vf06, 137(vi00) | nop + lq.xyzw vf07, 138(vi00) | nop + b L5 | nop + sq.xyzw vf26, 5(vi00) | nop ;; stash persp diag scaled + +;; 32/35 are prime/normal entry points for normal drawing. +ENTER_32: ;; (run, use prev lights, with merc "prime") + iaddi vi07, vi00, 0x1 | nop ;; vi07 for mercprime + b L5 | nop + isw.w vi07, 1(vi00) | nop ;; stash mercprime flag +ENTER_35: + iaddi vi07, vi00, 0x0 | nop + +L5: ;; common effect drawing entry point. +;; all draw paths go to here. + lq.xyzw vf28, 139(vi00) | minix.xyzw vf15, vf00, vf00 ;; vf28 = mch, vf15 = [0, 0, 0, 0] + xtop vi15 | nop ;; vi15 = 0 (output buffer) + iaddiu vi12, vi15, 0x8c | nop ;; vi12 = xtop + 140 (merc-byte-header, u4) + ibeq vi00, vi15, L6 | nop ;; branch if output buffer a (0) + ilwr.w vi03, vi12 | maxz.xy vf18, vf00, vf28 ;; set vf18.xy = [st-out-a, st-out-a] (for a buffer) + nop | maxw.xy vf18, vf00, vf28 ;; set vf18.xy = [st-out-b, st-out-b] (for b buffer) +L6: + ilw.w vi10, 133(vi00) | nop ;; vi10 = fade out flags + iaddiu vi15, vi15, 0x173 | nop ;; vi15 = xtop + 371 + ilw.y vi02, 2(vi12) | nop ;; vi02 = strip-len + lq.xyzw vf14, 0(vi00) | nop ;; vf14 = tri-strip-gif-tag + ibeq vi00, vi10, L7 | nop ;; branch to L7 if no fade out. + iadd vi03, vi03, vi12 | nop ;; st-output location = {st-out-a, st-out-b} + xtop + 140 + + ;; modify vf14 to have :abe, setup constants for fadeout. + mr32.xyzw vf27, vf14 | nop ;; vf27 = [yzwx] of the tri-strip-gif-tag + ilw.w vi11, 134(vi00) | nop ;; vi11 = fade-out parameter + iaddiu vi13, vi00, 0x42 | nop ;; vi13 = 0x42 + mr32.y vf14, vf27 | nop ;; replace y of tag with w. (enables abe in the gs-prim) + +;; next, we set up the memory layout of the output buffer. +;; the output buffer has two (poorly name) parts: "strip" and "shader". +;; the "strip" part will continue using the shader of the previous fragment. +;; it has a single tag. This "strip" part be left out, if desired. It is always first. +;; the "strip-len" is how large this data is. + +;; the "shader" part contains a series of [shader, triangles] groups. +;; it sets the shader settings, then draws stuff. +;; the shader-cnt is how many [shader, triangle] groups there are. +;; the sizes are stored in the adgif data itself + +;; the blocks below place the shaders and gif tags in memory, setting nloops and eops. + +L7: + ilwr.w vi09, vi03 | nop ;; vi09 = fp-header u8's [shader-cnt, kick-off, kick-step, hword-cnt] + lqi.xyzw vf27, vi03 | nop ;; vf27 = xyz-add + ilw.x vi04, 1(vi12) | nop ;; vi04 = mat1-cnt + iaddiu vi05, vi00, 0x7f | addw.xyz vf15, vf15, vf00 ;; vf15 = [1, 1, 1, 0], vi05 = 0x7f + iand vi09, vi09, vi05 | nop ;; mask to get vi09 = shader-cnt + ilw.y vi06, 1(vi12) | miniz.w vf19, vf00, vf27 ;; set add, vi06 = mat2-cnt + ibeq vi00, vi02, L9 | miniy.w vf18, vf00, vf27 ;; skip to L9 if strip-len is 0 + ilwr.z vi01, vi12 | minix.w vf17, vf00, vf27 ;; vi01 = lump-off + +;; we have strip + ibne vi00, vi09, L8 | nop ;; goto L8 if we have nonzero shader-cnt + sq.yzw vf14, 0(vi15) | nop ;; store giftag (only upper 96 bits) + +;; we have strip, but no shader. set eop. + iaddiu vi02, vi02, 0x4000 | nop ;; build the first 32-bits, strip-len + eop flag + iaddiu vi02, vi02, 0x4000 | nop ;; imm 0x8000 doesn't fit, have to add 2x. + iswr.x vi02, vi15 | nop ;; store nloop = strip-len, eop. + b L12 | nop ;; skip shader setup! + nop | nop +L8: + iswr.x vi02, vi15 | nop ;; nonzero shader and nonzero strip. set nloop on the strip tag, but not eop. +L9: + lq.xyzw vf13, 1(vi00) | nop ;; vf13 = adgif gif tag. +L10: ;; shader loop + ilwr.w vi02, vi03 | nop ;; vi02 = shader control word 0 (dest offset) + lqi.xyzw vf08, vi03 | nop ;; load shader data + lqi.xyzw vf09, vi03 | nop + lqi.xyzw vf10, vi03 | nop + lqi.xyzw vf11, vi03 | nop + lqi.xyzw vf12, vi03 | nop + iadd vi02, vi02, vi15 | nop ;; compute destination + mtir vi08, vf09.w | nop ;; vi08 = shader control word 1 () + sqi.xyzw vf13, vi02 | nop ;; store giftag + sqi.xyzw vf08, vi02 | nop ;; store shader0/5 + sqi.xyzw vf09, vi02 | nop ;; store shader1/5 + mfir.x vf14, vi08 | nop ;; vf14 = post-shader giftag lower-32 + sqi.xyzw vf10, vi02 | nop ;; store shader2/5 + sqi.xyzw vf11, vi02 | nop ;; store shader3/5 + ibeq vi00, vi10, L11 | nop ;; goto L11 if no fadeout + sqi.xyzw vf12, vi02 | nop ;; store shader4/5 + +;; fade out setup (todo). it just modifies shaders + mtir vi14, vf12.z | nop + isw.x vi10, -1(vi02) | nop + ibeq vi14, vi13, L11 | nop + isw.y vi11, -1(vi02) | nop + ilw.x vi13, -4(vi02) | nop + isubiu vi14, vi00, 0x1d | nop + iand vi13, vi13, vi14 | nop + iaddi vi13, vi13, 0xc | nop + isw.x vi13, -4(vi02) | nop + iaddiu vi13, vi00, 0x42 | nop + isw.z vi13, -1(vi02) | nop + +;; loop! +L11: + ibgtz vi08, L10 | nop ;; cool trick, eop is the sign bit here. + sq.xyzw vf14, 0(vi02) | nop + +;; end of shader and strip setup. + +;; matrix crap 1 +L12: + lq.xyzw vf28, 3(vi00) | nop ;; vf28 = persp-diag + ilw.y vi08, 3(vi12) | nop ;; vi08 = mat-slot.0 + lq.xyzw vf16, 5(vi00) | nop ;; vf16 = scaled-persp-diag + lq.xyzw vf20, 4(vi00) | nop ;; vf20 = persp-off + ilw.z vi09, 3(vi12) | mul.xyzw vf27, vf28, vf15 ;; vf27 = [pdx, pdy, pdz, 0], vi09 = mat-slot.1 + ior vi11, vi08, vi00 | mul.xyzw vf28, vf28, vf00 ;; vf28 = [0, 0, 0, pdw], vi11 = vi08 = mat-slot.0 + ibeq vi00, vi08, L14 | mul.xyzw vf15, vf16, vf15 ;; vf15 = [spdx, spdy, spdz, 0], skip if slot = 0 + iaddi vi13, vi12, 0x3 | mul.xyzw vf16, vf16, vf00 ;; vi13 = mat-slot-ptr, vf16 = [0, 0, 0, spdw] + + ;; pipelined matrix thing + ;; multiply matrices and store them back + ;; run until we get a slot of 0. + ;; mula.xyzw ACC, vf15, vf08 + ;; maddz.xyzw vf09, vf16, vf08 + ;; mula.xyzw ACC, vf15, vf10 + ;; maddz.xyzw vf11, vf16, vf10 + ;; mula.xyzw ACC, vf15, vf12 + ;; maddz.xyzw vf13, vf16, vf12 + ;; addax.xyzw vf20, vf00 + ;; madda.xyzw ACC, vf27, vf25 + ;; maddz.xyzw vf26, vf28, vf25 + +L13: + lq.xyzw vf08, 0(vi08) | addax.xyzw vf20, vf00 + lq.xyzw vf10, 1(vi08) | madda.xyzw ACC, vf27, vf25 + lq.xyzw vf12, 2(vi08) | maddz.xyzw vf26, vf28, vf25 + lq.xyzw vf25, 3(vi08) | nop + sq.xyzw vf09, 0(vi11) | mula.xyzw ACC, vf15, vf08 + sq.xyzw vf11, 1(vi11) | maddz.xyzw vf09, vf16, vf08 + sq.xyzw vf13, 2(vi11) | mula.xyzw ACC, vf15, vf10 + sq.xyzw vf26, 3(vi11) | maddz.xyzw vf11, vf16, vf10 + ibeq vi00, vi08, L14 | mula.xyzw ACC, vf15, vf12 + ilwr.w vi10, vi13 | maddz.xyzw vf13, vf16, vf12 + lq.xyzw vf08, 0(vi09) | addax.xyzw vf20, vf00 + lq.xyzw vf10, 1(vi09) | madda.xyzw ACC, vf27, vf25 + lq.xyzw vf12, 2(vi09) | maddz.xyzw vf26, vf28, vf25 + lq.xyzw vf25, 3(vi09) | nop + sq.xyzw vf09, 0(vi08) | mula.xyzw ACC, vf15, vf08 + sq.xyzw vf11, 1(vi08) | maddz.xyzw vf09, vf16, vf08 + sq.xyzw vf13, 2(vi08) | mula.xyzw ACC, vf15, vf10 + sq.xyzw vf26, 3(vi08) | maddz.xyzw vf11, vf16, vf10 + ibeq vi00, vi09, L14 | mula.xyzw ACC, vf15, vf12 + ilw.x vi11, 1(vi13) | maddz.xyzw vf13, vf16, vf12 + lq.xyzw vf08, 0(vi10) | addax.xyzw vf20, vf00 + lq.xyzw vf10, 1(vi10) | madda.xyzw ACC, vf27, vf25 + lq.xyzw vf12, 2(vi10) | maddz.xyzw vf26, vf28, vf25 + lq.xyzw vf25, 3(vi10) | nop + sq.xyzw vf09, 0(vi09) | mula.xyzw ACC, vf15, vf08 + sq.xyzw vf11, 1(vi09) | maddz.xyzw vf09, vf16, vf08 + sq.xyzw vf13, 2(vi09) | mula.xyzw ACC, vf15, vf10 + sq.xyzw vf26, 3(vi09) | maddz.xyzw vf11, vf16, vf10 + ibeq vi00, vi10, L14 | mula.xyzw ACC, vf15, vf12 + ilw.y vi08, 1(vi13) | maddz.xyzw vf13, vf16, vf12 + lq.xyzw vf08, 0(vi11) | addax.xyzw vf20, vf00 + lq.xyzw vf10, 1(vi11) | madda.xyzw ACC, vf27, vf25 + lq.xyzw vf12, 2(vi11) | maddz.xyzw vf26, vf28, vf25 + lq.xyzw vf25, 3(vi11) | nop + sq.xyzw vf09, 0(vi10) | mula.xyzw ACC, vf15, vf08 + sq.xyzw vf11, 1(vi10) | maddz.xyzw vf09, vf16, vf08 + sq.xyzw vf13, 2(vi10) | mula.xyzw ACC, vf15, vf10 + sq.xyzw vf26, 3(vi10) | maddz.xyzw vf11, vf16, vf10 + iaddi vi13, vi13, 0x1 | nop + ibne vi00, vi11, L13 | mula.xyzw ACC, vf15, vf12 + ilwr.z vi09, vi13 | maddz.xyzw vf13, vf16, vf12 +;; end matrix setup + +;; the L14 -> L26 area handles mat1s. +;; it appears to set vi03 as the rgba reading pointer +;; and vi04 as the end of mat1's rgba (poniter to last, not one past the end) +;; and vi06 as the end of mat2's rgba +;; and vi07 as the end of mat3's rgba + +L14: + ilw.x vi02, 3(vi12) | nop ;; vi02 = perc-off + ibeq vi00, vi04, L26 | nop ;; goto L26 if mat1 count is 0 + iadd vi01, vi01, vi12 | nop ;; vi01 = lump. + ilwr.x vi08, vi01 | nop ;; vi08 = lump[0].x = mat-0? + lqi.xyzw vf08, vi01 | nop ;; vf08 = lump[0] = [mat0, mat1, nrmx, posx]? + lqi.xyzw vf11, vi01 | nop ;; vf11 = lump[1] = [dst0, dst1, nrmy, posy]? + lqi.xyzw vf14, vi01 | nop ;; vf14 = lump[2] = [texs, text, nrmz, posz]? + lq.xyz vf29, 4(vi08) | nop ;; vf29 = [nmat0x, nmat0y, nmat0z, 0.003921569] + lq.xyz vf30, 5(vi08) | add.zw vf08, vf08, vf17 ;; add to nrm and pos, keep loading nmat (w is ? here) + lq.xyzw vf31, 6(vi08) | add.xyzw vf11, vf11, vf18 ;; lump unpack and add + iaddi vi04, vi04, -0x1 | add.xyzw vf14, vf14, vf19 ;; lump unpack and add, subtract 1 from mat1 count + iadd vi02, vi02, vi12 | nop ;; vi02 = perc + + ;; right does matrix mul with nmat and the vertex. + ;; it rotates the normal + ;; left lqi's from perc, unpacks dst0, dst1 to vi10 and vi13 + lqi.xyzw vf24, vi02 | mulaz.xyzw ACC, vf29, vf08 + mtir vi10, vf11.x | maddaz.xyzw ACC, vf30, vf11 + mtir vi13, vf11.y | maddz.xyz vf11, vf31, vf14 + + ;; vf25, vf26, vf27, vf28 is the tmat + lq.xyzw vf25, 0(vi08) | nop + lq.xyzw vf26, 1(vi08) | itof0.xyzw vf24, vf24 ;; perc to floats: no idea what this is yet. + lq.xyzw vf27, 2(vi08) | nop + erleng.xyz P, vf11 | nop ;; p = normal length. + lq.xyzw vf28, 3(vi08) | mulaw.xyzw ACC, vf25, vf08 ;; transform point, keep loading tmat + ior vi15, vi07, vi00 | maddaw.xyzw ACC, vf26, vf11 ;; vi15 = using mercprime + mr32.z vf14, vf00 | maddw.xyzw vf08, vf27, vf14 ;; vf14.z = 1. (clears nrmz) + lqi.xyzw vf09, vi01 | nop ;; vf09 = [mat0, mat1, nrmx, posx]? (P1) + ilwr.y vi03, vi12 | nop ;; vi03 = rgba-off + ilw.z vi07, 1(vi12) | nop ;; vi07 = mat3-cnt (why.....) + lqi.xyzw vf12, vi01 | add.xyzw vf08, vf08, vf28 ;; P1 vert load | finish xf pt + lqi.xyzw vf15, vi01 | nop ;; P1 vert load + mtir vi08, vf09.x | nop ;; P1 mat0 + ibeq vi00, vi15, L15 | nop + iadd vi03, vi03, vi12 | nop ;; vi03 = rgba + + ;; only if merc-prime + nop | miniw.w vf08, vf08, vf01 + +L15: +;; rhs is lump adding + div Q, vf01.w, vf08.w | add.zw vf09, vf09, vf17 ;; perspective divide! + iadd vi04, vi04, vi03 | add.xyzw vf12, vf12, vf18 ;; vi04 = rgba + mat1-cnt - 1 (??) + ;; note: the -1 is because the last vertex is handled + lq.xyz vf29, 4(vi08) | add.xyzw vf15, vf15, vf19 ;; P1 load nmat | P1 lump add v2 + + lq.xyz vf30, 5(vi08) | nop ;; P1 load nmat + iadd vi06, vi06, vi04 | nop ;; vi06 = rgba + mat1-cnt + mat2-cnt - 1 + lq.xyzw vf31, 6(vi08) | nop ;; p1 load mat + lq.xyzw vf25, 0(vi08) | nop ;; p1 load mat + lq.xyzw vf26, 1(vi08) | mul.xyz vf08, vf08, Q ;; p1 load mat | perspective multiply + mtir vi11, vf12.x | mul.xyzw vf14, vf14, Q ;; p1 get dst | vf14 = [s*Q, t*Q, Q, posz*Q] + mtir vi14, vf12.y | nop ;; p1 get dst + lq.xyzw vf27, 2(vi08) | nop ;; p1 load mat + lqi.xyzw vf23, vi03 | add.xyzw vf08, vf08, vf22 ;; load rgba, hvdf offset + ;; rhs is p1's normal xform + iadd vi07, vi07, vi06 | mulaz.xyzw ACC, vf29, vf09 ;; vi07 = rgba + mat1-cnt + mat2-cnt + mat3-cnt - 1 + lq.xyzw vf28, 3(vi08) | maddaz.xyzw ACC, vf30, vf12 ;; + mfp.w vf20, P | maddz.xyz vf12, vf31, vf15 ;; vf20.w = normal length + nop | nop + 1024.0 | miniw.w vf08, vf08, vf03 :i ;; fog max + ibne vi00, vi15, L82 | mulaw.xyzw ACC, vf25, vf09 ;; if mercprime, goto L82 | rhs is p1 + ilw.y vi09, -6(vi01) | mulw.xyzw vf11, vf11, vf20 ;; vi09 = p0 vtx's mat1 | normalization of normal + erleng.xyz P, vf12 | nop ;; p1's nrm length + nop | maddaw.xyzw ACC, vf26, vf12 ;; p1 nrm xf + mr32.z vf15, vf00 | maddw.xyzw vf09, vf27, vf15 ;; p1 + lqi.xyzw vf10, vi01 | mulax.xyzw ACC, vf01, vf11 ;; dot with light dir + ibne vi04, vi03, L17 | madday.xyzw ACC, vf02, vf11 ;; branch to L17 if not done + nop | maddz.xyzw vf11, vf03, vf11 + ibne vi06, vi03, L31 | nop ;; branch to L31 if mat2's can be done + nop | nop + b L67 | nop ;; go to mat3 + nop | nop + +;; pipelined mat1 loop here +L16: + lqi.xyzw vf10, vi01 | mulax.xyzw ACC, vf01, vf11 + sq.xyzw vf13, 1(vi12) | madday.xyzw ACC, vf02, vf11 + sq.xyzw vf13, 1(vi15) | maddz.xyzw vf11, vf03, vf11 +L17: ;; entry from above. + lqi.xyzw vf13, vi01 | add.xyzw vf09, vf09, vf28 ;; all p1 + lqi.xyzw vf16, vi01 | maxw.w vf08, vf08, vf02 ;; p1 | fog min + mtir vi08, vf10.x | itof0.xyzw vf23, vf23 ;; rgba to float + ilw.y vi09, -9(vi01) | maxx.xyzw vf11, vf11, vf00 ;; vi09 = mat1 | light clamp + div Q, vf01.w, vf09.w | add.zw vf10, vf10, vf17 ;; pipe 1 + move.xyzw vf21, vf08 | add.xyzw vf13, vf13, vf18 ;; move | pipe1 + lq.xyz vf29, 4(vi08) | add.xyzw vf16, vf16, vf19 ;; pipe | pipe + lq.xyz vf30, 5(vi08) | mulax.xyzw ACC, vf04, vf11 ;; more lights + ibgtz vi09, L18 | madday.xyzw ACC, vf05, vf11 + lq.xyzw vf31, 6(vi08) | maddaz.xyzw ACC, vf06, vf11 + nop | addx.w vf21, vf21, vf17 +L18: + lq.xyzw vf25, 0(vi08) | maddw.xyzw vf11, vf07, vf00 ;; p1 | add ambient + lq.xyzw vf26, 1(vi08) | mul.xyz vf09, vf09, Q ;; p | p + mtir vi12, vf13.x | mul.xyzw vf15, vf15, Q ;; p | p + mtir vi15, vf13.y | ftoi4.xyzw vf21, vf21 ;; p | position ftoi + lq.xyzw vf27, 2(vi08) | mul.xyzw vf11, vf11, vf23 ;; p | vertex coloring + lqi.xyzw vf23, vi03 | add.xyzw vf09, vf09, vf22 + ibne vi00, vi09, L19 | mulaz.xyzw ACC, vf29, vf10 + sq.xyzw vf21, 2(vi10) | maddaz.xyzw ACC, vf30, vf13 + nop | ftoi4.xyzw vf21, vf08 +L19: + mfp.w vf20, P | maddz.xyz vf13, vf31, vf16 + sq.xyzw vf14, 0(vi10) | miniy.xyzw vf11, vf11, vf17 + sq.xyzw vf14, 0(vi13) | miniw.w vf09, vf09, vf03 + sq.xyzw vf21, 2(vi13) | mulaw.xyzw ACC, vf25, vf10 + lq.xyzw vf28, 3(vi08) | mulw.xyzw vf12, vf12, vf20 + erleng.xyz P, vf13 | ftoi0.xyzw vf11, vf11 + ;; branch to end (first version in this loop) + ibne vi04, vi03, L20 | maddaw.xyzw ACC, vf26, vf13 + mr32.z vf16, vf00 | maddw.xyzw vf10, vf27, vf16 + ibne vi06, vi03, L36 | nop ;; branch if there's mat2's to do + ilw.y vi09, -6(vi01) | nop ;; pipeline "exiting" + ibne vi07, vi03, L72 | nop + nop | nop + b L143 | nop + nop | nop +L20: + lqi.xyzw vf08, vi01 | mulax.xyzw ACC, vf01, vf12 ;; + sq.xyzw vf11, 1(vi10) | madday.xyzw ACC, vf02, vf12 ;; + sq.xyzw vf11, 1(vi13) | maddz.xyzw vf12, vf03, vf12 ;; + lqi.xyzw vf11, vi01 | add.xyzw vf10, vf10, vf28 ;; + lqi.xyzw vf14, vi01 | maxw.w vf09, vf09, vf02 ;; + mtir vi08, vf08.x | itof0.xyzw vf23, vf23 ;; + ilw.y vi09, -9(vi01) | maxx.xyzw vf12, vf12, vf00 ;; + div Q, vf01.w, vf10.w | add.zw vf08, vf08, vf17 ;; + move.xyzw vf21, vf09 | add.xyzw vf11, vf11, vf18 ;; + lq.xyz vf29, 4(vi08) | add.xyzw vf14, vf14, vf19 + lq.xyz vf30, 5(vi08) | mulax.xyzw ACC, vf04, vf12 ;; + ibgtz vi09, L21 | madday.xyzw ACC, vf05, vf12 ;; + lq.xyzw vf31, 6(vi08) | maddaz.xyzw ACC, vf06, vf12 ;; + nop | addx.w vf21, vf21, vf17 ;; +L21: + lq.xyzw vf25, 0(vi08) | maddw.xyzw vf12, vf07, vf00 ;; + lq.xyzw vf26, 1(vi08) | mul.xyz vf10, vf10, Q ;; + mtir vi10, vf11.x | mul.xyzw vf16, vf16, Q ;; + mtir vi13, vf11.y | ftoi4.xyzw vf21, vf21 ;; + lq.xyzw vf27, 2(vi08) | mul.xyzw vf12, vf12, vf23 + lqi.xyzw vf23, vi03 | add.xyzw vf10, vf10, vf22 + ibne vi00, vi09, L22 | mulaz.xyzw ACC, vf29, vf08 + sq.xyzw vf21, 2(vi11) | maddaz.xyzw ACC, vf30, vf11 ;; + nop | ftoi4.xyzw vf21, vf09 +L22: + mfp.w vf20, P | maddz.xyz vf11, vf31, vf14 ;; + sq.xyzw vf15, 0(vi11) | miniy.xyzw vf12, vf12, vf17 ;; + sq.xyzw vf15, 0(vi14) | miniw.w vf10, vf10, vf03 ;; + sq.xyzw vf21, 2(vi14) | mulaw.xyzw ACC, vf25, vf08 ;; + lq.xyzw vf28, 3(vi08) | mulw.xyzw vf13, vf13, vf20 ;; + erleng.xyz P, vf11 | ftoi0.xyzw vf12, vf12 ;; + ibne vi04, vi03, L23 | maddaw.xyzw ACC, vf26, vf11 + mr32.z vf14, vf00 | maddw.xyzw vf08, vf27, vf14 + ibne vi06, vi03, L41 | nop + ilw.y vi09, -6(vi01) | nop + ibne vi07, vi03, L77 | nop + nop | nop + b L153 | nop + nop | nop +L23: + lqi.xyzw vf09, vi01 | mulax.xyzw ACC, vf01, vf13 ;; + sq.xyzw vf12, 1(vi11) | madday.xyzw ACC, vf02, vf13 ;; + sq.xyzw vf12, 1(vi14) | maddz.xyzw vf13, vf03, vf13 ;; + lqi.xyzw vf12, vi01 | add.xyzw vf08, vf08, vf28 + lqi.xyzw vf15, vi01 | maxw.w vf10, vf10, vf02 ;; + mtir vi08, vf09.x | itof0.xyzw vf23, vf23 ;; + ilw.y vi09, -9(vi01) | maxx.xyzw vf13, vf13, vf00 + div Q, vf01.w, vf08.w | add.zw vf09, vf09, vf17 + move.xyzw vf21, vf10 | add.xyzw vf12, vf12, vf18 ;; + lq.xyz vf29, 4(vi08) | add.xyzw vf15, vf15, vf19 + lq.xyz vf30, 5(vi08) | mulax.xyzw ACC, vf04, vf13 ;; + ibgtz vi09, L24 | madday.xyzw ACC, vf05, vf13 ;; + lq.xyzw vf31, 6(vi08) | maddaz.xyzw ACC, vf06, vf13 ;; + nop | addx.w vf21, vf21, vf17 ;; +L24: + lq.xyzw vf25, 0(vi08) | maddw.xyzw vf13, vf07, vf00 + lq.xyzw vf26, 1(vi08) | mul.xyz vf08, vf08, Q + mtir vi11, vf12.x | mul.xyzw vf14, vf14, Q + mtir vi14, vf12.y | ftoi4.xyzw vf21, vf21 ;; + lq.xyzw vf27, 2(vi08) | mul.xyzw vf13, vf13, vf23 + lqi.xyzw vf23, vi03 | add.xyzw vf08, vf08, vf22 + ibne vi00, vi09, L25 | mulaz.xyzw ACC, vf29, vf09 + sq.xyzw vf21, 2(vi12) | maddaz.xyzw ACC, vf30, vf12 + nop | ftoi4.xyzw vf21, vf10 +L25: + mfp.w vf20, P | maddz.xyz vf12, vf31, vf15 + sq.xyzw vf16, 0(vi12) | miniy.xyzw vf13, vf13, vf17 + sq.xyzw vf16, 0(vi15) | miniw.w vf08, vf08, vf03 + sq.xyzw vf21, 2(vi15) | mulaw.xyzw ACC, vf25, vf09 + lq.xyzw vf28, 3(vi08) | mulw.xyzw vf11, vf11, vf20 + erleng.xyz P, vf12 | ftoi0.xyzw vf13, vf13 + ibne vi04, vi03, L16 | maddaw.xyzw ACC, vf26, vf12 + mr32.z vf15, vf00 | maddw.xyzw vf09, vf27, vf15 + ibne vi06, vi03, L30 | nop + ilw.y vi09, -6(vi01) | nop + ibne vi07, vi03, L66 | nop + nop | nop + b L163 | nop + nop | nop + +L26: ;; pipeline startup for mat2's (assuming you had no mat1's to get things started) + ibeq vi00, vi06, L61 | nop ;; goto L61 if no mat2's + iadd vi02, vi02, vi12 | nop ;; compute perc offset + lqi.xyzw vf08, vi01 | nop ;; vf08 = vtx0 = [mat0, mat1, nrmx, posx] + lqi.xyzw vf24, vi02 | nop ;; vf24 = perc + lqi.xyzw vf11, vi01 | nop ;; vf11 = vtx1 = [dst0, dst1, nrmy, posy] + lqi.xyzw vf14, vi01 | nop ;; vf14 = vtx2 = [texs, text, nrmz, posz] + mtir vi10, vf08.x | nop ;; vi10 = mat0 + mtir vi13, vf08.y | itof0.xyzw vf24, vf24 ;; vi13 = mat1 | vf24 = itof0(perc) + iaddi vi06, vi06, -0x1 | add.zw vf08, vf08, vf17 ;; dec count | lump offset + nop | add.xyzw vf11, vf11, vf18 ;; lump offset + iand vi10, vi10, vi05 | add.xyzw vf14, vf14, vf19 ;; vi10 = mat0 & 0x7f | lump offset + nop | mulw.xyzw vf24, vf24, vf29 ;; scale perc + iand vi13, vi13, vi05 | nop ;; vi13 = mat1 & 0x7f + + ;; left col is loading matrices, right col is multiplication by perc. + lq.xyzw vf20, 0(vi10) | nop + lq.xyzw vf25, 0(vi13) | nop + lq.xyzw vf23, 1(vi10) | nop + lq.xyzw vf26, 1(vi13) | nop + lq.xyzw vf20, 2(vi10) | mulax.xyzw ACC, vf20, vf24 + lq.xyzw vf27, 2(vi13) | maddy.xyzw vf25, vf25, vf24 + lq.xyzw vf23, 3(vi10) | mulax.xyzw ACC, vf23, vf24 + lq.xyzw vf28, 3(vi13) | maddy.xyzw vf26, vf26, vf24 + lq.xyzw vf20, 4(vi10) | mulax.xyzw ACC, vf20, vf24 + lq.xyz vf29, 4(vi13) | maddy.xyzw vf27, vf27, vf24 + lq.xyzw vf23, 5(vi10) | mulax.xyzw ACC, vf23, vf24 + lq.xyz vf30, 5(vi13) | maddy.xyzw vf28, vf28, vf24 + lq.xyzw vf20, 6(vi10) | mulax.xyzw ACC, vf20, vf24 + lq.xyzw vf31, 6(vi13) | maddy.xyz vf29, vf29, vf24 + mtir vi10, vf11.x | mulax.xyzw ACC, vf23, vf24 + mtir vi13, vf11.y | maddy.xyz vf30, vf30, vf24 + nop | mulax.xyzw ACC, vf20, vf24 + nop | maddy.xyzw vf31, vf31, vf24 ;; last perc multiply + nop | mulaz.xyzw ACC, vf29, vf08 ;; rotate normal + nop | maddaz.xyzw ACC, vf30, vf11 + nop | maddz.xyz vf11, vf31, vf14 + nop | nop + nop | nop + nop | mulaw.xyzw ACC, vf25, vf08 ;; xf point + iaddiu vi08, vi00, 0x243 | nop ;; vi08 = 0x243 = 579 + erleng.xyz P, vf11 | nop ;; length of normal + ior vi15, vi07, vi00 | maddaw.xyzw ACC, vf26, vf11 ;; vi15 = mercprimt | xf point + mr32.z vf14, vf00 | maddw.xyzw vf08, vf27, vf14 ;; set vf14.z = 1.0 | xf point + lqi.xyzw vf09, vi01 | nop ;; pipe | + ilwr.y vi03, vi12 | nop ;; vi03 = rgba-off + ilw.z vi07, 1(vi12) | nop ;; vi07 = mat3-cnt + lqi.xyzw vf12, vi01 | add.xyzw vf08, vf08, vf28 ;; pipe | xf point + lqi.xyzw vf15, vi01 | nop ;; pipe + mtir vi11, vf09.x | nop ;; pipe + ibeq vi00, vi15, L27 | nop ;; goto L27 if no merc-prim + mtir vi14, vf09.y | nop ;; pipe + iaddiu vi08, vi00, 0x539 | miniw.w vf08, vf08, vf01 ;; ONLY RUN IF MERCPRIME +L27: + div Q, vf01.w, vf08.w | add.zw vf09, vf09, vf17 ;; perspective divide | pipe + iadd vi03, vi03, vi12 | add.xyzw vf12, vf12, vf18 ;; rgba off | pipe + iand vi11, vi11, vi05 | add.xyzw vf15, vf15, vf19 ;; pipe | pipe + iadd vi06, vi06, vi03 | nop ;; end addr calc1 + iadd vi07, vi07, vi06 | nop ;; end addr calc2 + iand vi14, vi14, vi05 | nop ;; pipe + ibne vi05, vi11, L28 | nop ;; branch on next(?) vertex mat0 sign bit + nop | mul.xyz vf08, vf08, Q ;; perspective + mtir vi11, vf12.x | mul.xyzw vf14, vf14, Q + mtir vi14, vf12.y | nop + b L29 | nop ;; branch to skip matrix load, if possible + lqi.xyzw vf23, vi03 | add.xyzw vf08, vf08, vf22 ;; load rgba | hvdf offset +L28: + lq.xyzw vf20, 0(vi11) | mul.xyzw vf14, vf14, Q + lq.xyzw vf25, 0(vi14) | nop + lq.xyzw vf23, 1(vi11) | nop + lq.xyzw vf26, 1(vi14) | add.xyzw vf08, vf08, vf22 + lq.xyzw vf20, 2(vi11) | mulaz.xyzw ACC, vf20, vf24 + lq.xyzw vf27, 2(vi14) | maddw.xyzw vf25, vf25, vf24 + lq.xyzw vf23, 3(vi11) | mulaz.xyzw ACC, vf23, vf24 + lq.xyzw vf28, 3(vi14) | maddw.xyzw vf26, vf26, vf24 + lq.xyzw vf20, 4(vi11) | mulaz.xyzw ACC, vf20, vf24 + lq.xyz vf29, 4(vi14) | maddw.xyzw vf27, vf27, vf24 + lq.xyzw vf23, 5(vi11) | mulaz.xyzw ACC, vf23, vf24 + lq.xyz vf30, 5(vi14) | maddw.xyzw vf28, vf28, vf24 + lq.xyzw vf20, 6(vi11) | mulaz.xyzw ACC, vf20, vf24 + lq.xyzw vf31, 6(vi14) | maddw.xyz vf29, vf29, vf24 + lqi.xyzw vf23, vi02 | mulaz.xyzw ACC, vf23, vf24 + mtir vi11, vf12.x | maddw.xyz vf30, vf30, vf24 + mtir vi14, vf12.y | mulaz.xyzw ACC, vf20, vf24 + iaddiu vi08, vi00, 0x1a1 | maddw.xyzw vf31, vf31, vf24 + ibeq vi00, vi15, L29 | nop + lqi.xyzw vf23, vi03 | itof0.xyzw vf24, vf23 + iaddiu vi08, vi00, 0x48e | nop +L29: + nop | mulaz.xyzw ACC, vf29, vf09 ;; pipe + nop | maddaz.xyzw ACC, vf30, vf12 ;; pipe + mfp.w vf20, P | maddz.xyz vf12, vf31, vf15 ;; normal length | pipe + nop | nop + 1024.0 | miniw.w vf08, vf08, vf03 :i ;; fog max + ibne vi00, vi15, L93 | mulaw.xyzw ACC, vf25, vf09 ;; mercprime | pipe + ilw.y vi09, -6(vi01) | mulw.xyzw vf11, vf11, vf20 ;; vi09 = mat1 | normalize + erleng.xyz P, vf12 | nop ;; pipe + ibeq vi06, vi03, L65 | maddaw.xyzw ACC, vf26, vf12 ;; check done | pipe + mr32.z vf15, vf00 | maddw.xyzw vf09, vf27, vf15 ;; pipe | pipe + lqi.xyzw vf10, vi01 | mulax.xyzw ACC, vf01, vf11 ;; pipe | dot product with light + jr vi08 | madday.xyzw ACC, vf02, vf11 + nop | maddz.xyzw vf11, vf03, vf11 +L30: ;; mat2 cross entry 3 + lqi.xyzw vf10, vi01 | mulax.xyzw ACC, vf01, vf11 + sq.xyzw vf13, 1(vi12) | madday.xyzw ACC, vf02, vf11 + sq.xyzw vf13, 1(vi15) | maddz.xyzw vf11, vf03, vf11 +L31: + lqi.xyzw vf13, vi01 | add.xyzw vf09, vf09, vf28 + lqi.xyzw vf16, vi01 | maxw.w vf08, vf08, vf02 + mtir vi12, vf10.x | itof0.xyzw vf23, vf23 + mtir vi15, vf10.y | maxx.xyzw vf11, vf11, vf00 + div Q, vf01.w, vf09.w | add.zw vf10, vf10, vf17 + move.xyzw vf21, vf08 | add.xyzw vf13, vf13, vf18 + iand vi12, vi12, vi05 | add.xyzw vf16, vf16, vf19 + nop | mulax.xyzw ACC, vf04, vf11 + ibgtz vi09, L32 | madday.xyzw ACC, vf05, vf11 + iand vi15, vi15, vi05 | maddaz.xyzw ACC, vf06, vf11 + nop | addx.w vf21, vf21, vf17 +L32: + ibne vi05, vi12, L33 | maddw.xyzw vf11, vf07, vf00 + ilw.x vi09, -9(vi01) | mul.xyz vf09, vf09, Q + mtir vi12, vf13.x | mul.xyzw vf15, vf15, Q + mtir vi15, vf13.y | ftoi4.xyzw vf21, vf21 + b L34 | mul.xyzw vf11, vf11, vf23 + lqi.xyzw vf23, vi03 | add.xyzw vf09, vf09, vf22 +L33: + lq.xyzw vf20, 0(vi12) | mul.xyzw vf15, vf15, Q + nop | mulw.xyzw vf24, vf24, vf29 + lq.xyzw vf25, 0(vi15) | ftoi4.xyzw vf21, vf21 + lq.xyzw vf23, 1(vi12) | mul.xyzw vf11, vf11, vf23 + lq.xyzw vf26, 1(vi15) | add.xyzw vf09, vf09, vf22 + lq.xyzw vf20, 2(vi12) | mulax.xyzw ACC, vf20, vf24 + lq.xyzw vf27, 2(vi15) | maddy.xyzw vf25, vf25, vf24 + lq.xyzw vf23, 3(vi12) | mulax.xyzw ACC, vf23, vf24 + lq.xyzw vf28, 3(vi15) | maddy.xyzw vf26, vf26, vf24 + lq.xyzw vf20, 4(vi12) | mulax.xyzw ACC, vf20, vf24 + lq.xyz vf29, 4(vi15) | maddy.xyzw vf27, vf27, vf24 + lq.xyzw vf23, 5(vi12) | mulax.xyzw ACC, vf23, vf24 + lq.xyz vf30, 5(vi15) | maddy.xyzw vf28, vf28, vf24 + lq.xyzw vf20, 6(vi12) | mulax.xyzw ACC, vf20, vf24 + lq.xyzw vf31, 6(vi15) | maddy.xyz vf29, vf29, vf24 + mtir vi12, vf13.x | mulax.xyzw ACC, vf23, vf24 + mtir vi15, vf13.y | maddy.xyz vf30, vf30, vf24 + b L49 | mulax.xyzw ACC, vf20, vf24 + lqi.xyzw vf23, vi03 | maddy.xyzw vf31, vf31, vf24 +L34: + ibgez vi09, L35 | mulaz.xyzw ACC, vf29, vf10 + sq.xyzw vf21, 2(vi10) | maddaz.xyzw ACC, vf30, vf13 + nop | ftoi4.xyzw vf21, vf08 +L35: + mfp.w vf20, P | maddz.xyz vf13, vf31, vf16 + sq.xyzw vf14, 0(vi10) | miniy.xyzw vf11, vf11, vf17 + sq.xyzw vf14, 0(vi13) | miniw.w vf09, vf09, vf03 + sq.xyzw vf21, 2(vi13) | mulaw.xyzw ACC, vf25, vf10 + ilw.y vi09, -6(vi01) | mulw.xyzw vf12, vf12, vf20 + erleng.xyz P, vf13 | ftoi0.xyzw vf11, vf11 + ibne vi06, vi03, L36 | maddaw.xyzw ACC, vf26, vf13 + mr32.z vf16, vf00 | maddw.xyzw vf10, vf27, vf16 + ibne vi07, vi03, L72 | nop + nop | nop + b L143 | nop + nop | nop +L36: ;; mat2 cross entry 1 + lqi.xyzw vf08, vi01 | mulax.xyzw ACC, vf01, vf12 + sq.xyzw vf11, 1(vi10) | madday.xyzw ACC, vf02, vf12 + sq.xyzw vf11, 1(vi13) | maddz.xyzw vf12, vf03, vf12 + ;; END of first vertex.... + lqi.xyzw vf11, vi01 | add.xyzw vf10, vf10, vf28 + lqi.xyzw vf14, vi01 | maxw.w vf09, vf09, vf02 + mtir vi10, vf08.x | itof0.xyzw vf23, vf23 + mtir vi13, vf08.y | maxx.xyzw vf12, vf12, vf00 + div Q, vf01.w, vf10.w | add.zw vf08, vf08, vf17 + move.xyzw vf21, vf09 | add.xyzw vf11, vf11, vf18 + iand vi10, vi10, vi05 | add.xyzw vf14, vf14, vf19 + nop | mulax.xyzw ACC, vf04, vf12 + ibgtz vi09, L37 | madday.xyzw ACC, vf05, vf12 + iand vi13, vi13, vi05 | maddaz.xyzw ACC, vf06, vf12 + nop | addx.w vf21, vf21, vf17 +L37: + ibne vi05, vi10, L38 | maddw.xyzw vf12, vf07, vf00 + ilw.x vi09, -9(vi01) | mul.xyz vf10, vf10, Q + mtir vi10, vf11.x | mul.xyzw vf16, vf16, Q + mtir vi13, vf11.y | ftoi4.xyzw vf21, vf21 + b L39 | mul.xyzw vf12, vf12, vf23 + lqi.xyzw vf23, vi03 | add.xyzw vf10, vf10, vf22 +L38: + lq.xyzw vf20, 0(vi10) | mul.xyzw vf16, vf16, Q + nop | mulw.xyzw vf24, vf24, vf29 + lq.xyzw vf25, 0(vi13) | ftoi4.xyzw vf21, vf21 + lq.xyzw vf23, 1(vi10) | mul.xyzw vf12, vf12, vf23 + lq.xyzw vf26, 1(vi13) | add.xyzw vf10, vf10, vf22 + lq.xyzw vf20, 2(vi10) | mulax.xyzw ACC, vf20, vf24 + lq.xyzw vf27, 2(vi13) | maddy.xyzw vf25, vf25, vf24 + lq.xyzw vf23, 3(vi10) | mulax.xyzw ACC, vf23, vf24 + lq.xyzw vf28, 3(vi13) | maddy.xyzw vf26, vf26, vf24 + lq.xyzw vf20, 4(vi10) | mulax.xyzw ACC, vf20, vf24 + lq.xyz vf29, 4(vi13) | maddy.xyzw vf27, vf27, vf24 + lq.xyzw vf23, 5(vi10) | mulax.xyzw ACC, vf23, vf24 + lq.xyz vf30, 5(vi13) | maddy.xyzw vf28, vf28, vf24 + lq.xyzw vf20, 6(vi10) | mulax.xyzw ACC, vf20, vf24 + lq.xyzw vf31, 6(vi13) | maddy.xyz vf29, vf29, vf24 + mtir vi10, vf11.x | mulax.xyzw ACC, vf23, vf24 + mtir vi13, vf11.y | maddy.xyz vf30, vf30, vf24 + b L54 | mulax.xyzw ACC, vf20, vf24 + lqi.xyzw vf23, vi03 | maddy.xyzw vf31, vf31, vf24 +L39: + ibgez vi09, L40 | mulaz.xyzw ACC, vf29, vf08 + sq.xyzw vf21, 2(vi11) | maddaz.xyzw ACC, vf30, vf11 + nop | ftoi4.xyzw vf21, vf09 +L40: + mfp.w vf20, P | maddz.xyz vf11, vf31, vf14 + sq.xyzw vf15, 0(vi11) | miniy.xyzw vf12, vf12, vf17 + sq.xyzw vf15, 0(vi14) | miniw.w vf10, vf10, vf03 + sq.xyzw vf21, 2(vi14) | mulaw.xyzw ACC, vf25, vf08 + ilw.y vi09, -6(vi01) | mulw.xyzw vf13, vf13, vf20 + erleng.xyz P, vf11 | ftoi0.xyzw vf12, vf12 + ibne vi06, vi03, L41 | maddaw.xyzw ACC, vf26, vf11 + mr32.z vf14, vf00 | maddw.xyzw vf08, vf27, vf14 + ibne vi07, vi03, L77 | nop + nop | nop + b L153 | nop + nop | nop +L41: ;; mat2 cross entry 2 + lqi.xyzw vf09, vi01 | mulax.xyzw ACC, vf01, vf13 + sq.xyzw vf12, 1(vi11) | madday.xyzw ACC, vf02, vf13 + sq.xyzw vf12, 1(vi14) | maddz.xyzw vf13, vf03, vf13 + lqi.xyzw vf12, vi01 | add.xyzw vf08, vf08, vf28 + lqi.xyzw vf15, vi01 | maxw.w vf10, vf10, vf02 + mtir vi11, vf09.x | itof0.xyzw vf23, vf23 + mtir vi14, vf09.y | maxx.xyzw vf13, vf13, vf00 + div Q, vf01.w, vf08.w | add.zw vf09, vf09, vf17 + move.xyzw vf21, vf10 | add.xyzw vf12, vf12, vf18 + iand vi11, vi11, vi05 | add.xyzw vf15, vf15, vf19 + nop | mulax.xyzw ACC, vf04, vf13 + ibgtz vi09, L42 | madday.xyzw ACC, vf05, vf13 + iand vi14, vi14, vi05 | maddaz.xyzw ACC, vf06, vf13 + nop | addx.w vf21, vf21, vf17 +L42: + ibne vi05, vi11, L43 | maddw.xyzw vf13, vf07, vf00 + ilw.x vi09, -9(vi01) | mul.xyz vf08, vf08, Q + mtir vi11, vf12.x | mul.xyzw vf14, vf14, Q + mtir vi14, vf12.y | ftoi4.xyzw vf21, vf21 + b L44 | mul.xyzw vf13, vf13, vf23 + lqi.xyzw vf23, vi03 | add.xyzw vf08, vf08, vf22 +L43: + lq.xyzw vf20, 0(vi11) | mul.xyzw vf14, vf14, Q + nop | mulw.xyzw vf24, vf24, vf29 + lq.xyzw vf25, 0(vi14) | ftoi4.xyzw vf21, vf21 + lq.xyzw vf23, 1(vi11) | mul.xyzw vf13, vf13, vf23 + lq.xyzw vf26, 1(vi14) | add.xyzw vf08, vf08, vf22 + lq.xyzw vf20, 2(vi11) | mulax.xyzw ACC, vf20, vf24 + lq.xyzw vf27, 2(vi14) | maddy.xyzw vf25, vf25, vf24 + lq.xyzw vf23, 3(vi11) | mulax.xyzw ACC, vf23, vf24 + lq.xyzw vf28, 3(vi14) | maddy.xyzw vf26, vf26, vf24 + lq.xyzw vf20, 4(vi11) | mulax.xyzw ACC, vf20, vf24 + lq.xyz vf29, 4(vi14) | maddy.xyzw vf27, vf27, vf24 + lq.xyzw vf23, 5(vi11) | mulax.xyzw ACC, vf23, vf24 + lq.xyz vf30, 5(vi14) | maddy.xyzw vf28, vf28, vf24 + lq.xyzw vf20, 6(vi11) | mulax.xyzw ACC, vf20, vf24 + lq.xyzw vf31, 6(vi14) | maddy.xyz vf29, vf29, vf24 + mtir vi11, vf12.x | mulax.xyzw ACC, vf23, vf24 + mtir vi14, vf12.y | maddy.xyz vf30, vf30, vf24 + b L59 | mulax.xyzw ACC, vf20, vf24 + lqi.xyzw vf23, vi03 | maddy.xyzw vf31, vf31, vf24 +L44: + ibgez vi09, L45 | mulaz.xyzw ACC, vf29, vf09 + sq.xyzw vf21, 2(vi12) | maddaz.xyzw ACC, vf30, vf12 + nop | ftoi4.xyzw vf21, vf10 +L45: + mfp.w vf20, P | maddz.xyz vf12, vf31, vf15 + sq.xyzw vf16, 0(vi12) | miniy.xyzw vf13, vf13, vf17 + sq.xyzw vf16, 0(vi15) | miniw.w vf08, vf08, vf03 + sq.xyzw vf21, 2(vi15) | mulaw.xyzw ACC, vf25, vf09 + ilw.y vi09, -6(vi01) | mulw.xyzw vf11, vf11, vf20 + erleng.xyz P, vf12 | ftoi0.xyzw vf13, vf13 + ibne vi06, vi03, L30 | maddaw.xyzw ACC, vf26, vf12 + mr32.z vf15, vf00 | maddw.xyzw vf09, vf27, vf15 + ibne vi07, vi03, L66 | nop + nop | nop + b L163 | nop + nop | nop +L46: + lqi.xyzw vf10, vi01 | mulax.xyzw ACC, vf01, vf11 + sq.xyzw vf13, 1(vi12) | madday.xyzw ACC, vf02, vf11 + sq.xyzw vf13, 1(vi15) | maddz.xyzw vf11, vf03, vf11 + ;; ugh, I think we jump here. + lqi.xyzw vf13, vi01 | add.xyzw vf09, vf09, vf28 ;; pipe | pipe + lqi.xyzw vf16, vi01 | maxw.w vf08, vf08, vf02 ;; pipe | fogmin + mtir vi12, vf10.x | itof0.xyzw vf23, vf23 ;; pipe | vtx color convert + mtir vi15, vf10.y | maxx.xyzw vf11, vf11, vf00 ;; pipe | light clamp + div Q, vf01.w, vf09.w | add.zw vf10, vf10, vf17 + move.xyzw vf21, vf08 | add.xyzw vf13, vf13, vf18 + iand vi12, vi12, vi05 | add.xyzw vf16, vf16, vf19 + nop | mulax.xyzw ACC, vf04, vf11 + ibgtz vi09, L47 | madday.xyzw ACC, vf05, vf11 + iand vi15, vi15, vi05 | maddaz.xyzw ACC, vf06, vf11 + nop | addx.w vf21, vf21, vf17 +L47: + ibne vi05, vi12, L48 | maddw.xyzw vf11, vf07, vf00 + ilw.x vi09, -9(vi01) | mul.xyz vf09, vf09, Q + mtir vi12, vf13.x | mul.xyzw vf15, vf15, Q + mtir vi15, vf13.y | ftoi4.xyzw vf21, vf21 + b L49 | mul.xyzw vf11, vf11, vf23 + lqi.xyzw vf23, vi03 | add.xyzw vf09, vf09, vf22 +L48: + lq.xyzw vf20, 0(vi12) | mul.xyzw vf15, vf15, Q + lq.xyzw vf25, 0(vi15) | ftoi4.xyzw vf21, vf21 + lq.xyzw vf23, 1(vi12) | mul.xyzw vf11, vf11, vf23 + lq.xyzw vf26, 1(vi15) | add.xyzw vf09, vf09, vf22 + lq.xyzw vf20, 2(vi12) | mulaz.xyzw ACC, vf20, vf24 + lq.xyzw vf27, 2(vi15) | maddw.xyzw vf25, vf25, vf24 + lq.xyzw vf23, 3(vi12) | mulaz.xyzw ACC, vf23, vf24 + lq.xyzw vf28, 3(vi15) | maddw.xyzw vf26, vf26, vf24 + lq.xyzw vf20, 4(vi12) | mulaz.xyzw ACC, vf20, vf24 + lq.xyz vf29, 4(vi15) | maddw.xyzw vf27, vf27, vf24 + lq.xyzw vf23, 5(vi12) | mulaz.xyzw ACC, vf23, vf24 + lq.xyz vf30, 5(vi15) | maddw.xyzw vf28, vf28, vf24 + lq.xyzw vf20, 6(vi12) | mulaz.xyzw ACC, vf20, vf24 + lq.xyzw vf31, 6(vi15) | maddw.xyz vf29, vf29, vf24 + lqi.xyzw vf23, vi02 | mulaz.xyzw ACC, vf23, vf24 + mtir vi12, vf13.x | maddw.xyz vf30, vf30, vf24 + mtir vi15, vf13.y | mulaz.xyzw ACC, vf20, vf24 + b L34 | maddw.xyzw vf31, vf31, vf24 + lqi.xyzw vf23, vi03 | itof0.xyzw vf24, vf23 +L49: + ibgez vi09, L50 | mulaz.xyzw ACC, vf29, vf10 + sq.xyzw vf21, 2(vi10) | maddaz.xyzw ACC, vf30, vf13 ;; first store + nop | ftoi4.xyzw vf21, vf08 +L50: + mfp.w vf20, P | maddz.xyz vf13, vf31, vf16 + sq.xyzw vf14, 0(vi10) | miniy.xyzw vf11, vf11, vf17 + sq.xyzw vf14, 0(vi13) | miniw.w vf09, vf09, vf03 + sq.xyzw vf21, 2(vi13) | mulaw.xyzw ACC, vf25, vf10 ;; second store + ilw.y vi09, -6(vi01) | mulw.xyzw vf12, vf12, vf20 + erleng.xyz P, vf13 | ftoi0.xyzw vf11, vf11 + ibne vi06, vi03, L51 | maddaw.xyzw ACC, vf26, vf13 + mr32.z vf16, vf00 | maddw.xyzw vf10, vf27, vf16 + ibne vi07, vi03, L72 | nop + nop | nop + b L143 | nop + nop | nop +L51: + lqi.xyzw vf08, vi01 | mulax.xyzw ACC, vf01, vf12 + sq.xyzw vf11, 1(vi10) | madday.xyzw ACC, vf02, vf12 + sq.xyzw vf11, 1(vi13) | maddz.xyzw vf12, vf03, vf12 + ;; end, for real this time. + lqi.xyzw vf11, vi01 | add.xyzw vf10, vf10, vf28 + lqi.xyzw vf14, vi01 | maxw.w vf09, vf09, vf02 + mtir vi10, vf08.x | itof0.xyzw vf23, vf23 + mtir vi13, vf08.y | maxx.xyzw vf12, vf12, vf00 + div Q, vf01.w, vf10.w | add.zw vf08, vf08, vf17 + move.xyzw vf21, vf09 | add.xyzw vf11, vf11, vf18 + iand vi10, vi10, vi05 | add.xyzw vf14, vf14, vf19 + nop | mulax.xyzw ACC, vf04, vf12 + ibgtz vi09, L52 | madday.xyzw ACC, vf05, vf12 + iand vi13, vi13, vi05 | maddaz.xyzw ACC, vf06, vf12 + nop | addx.w vf21, vf21, vf17 +L52: + ibne vi05, vi10, L53 | maddw.xyzw vf12, vf07, vf00 + ilw.x vi09, -9(vi01) | mul.xyz vf10, vf10, Q + mtir vi10, vf11.x | mul.xyzw vf16, vf16, Q + mtir vi13, vf11.y | ftoi4.xyzw vf21, vf21 + b L54 | mul.xyzw vf12, vf12, vf23 + lqi.xyzw vf23, vi03 | add.xyzw vf10, vf10, vf22 +L53: + lq.xyzw vf20, 0(vi10) | mul.xyzw vf16, vf16, Q + lq.xyzw vf25, 0(vi13) | ftoi4.xyzw vf21, vf21 + lq.xyzw vf23, 1(vi10) | mul.xyzw vf12, vf12, vf23 + lq.xyzw vf26, 1(vi13) | add.xyzw vf10, vf10, vf22 + lq.xyzw vf20, 2(vi10) | mulaz.xyzw ACC, vf20, vf24 + lq.xyzw vf27, 2(vi13) | maddw.xyzw vf25, vf25, vf24 + lq.xyzw vf23, 3(vi10) | mulaz.xyzw ACC, vf23, vf24 + lq.xyzw vf28, 3(vi13) | maddw.xyzw vf26, vf26, vf24 + lq.xyzw vf20, 4(vi10) | mulaz.xyzw ACC, vf20, vf24 + lq.xyz vf29, 4(vi13) | maddw.xyzw vf27, vf27, vf24 + lq.xyzw vf23, 5(vi10) | mulaz.xyzw ACC, vf23, vf24 + lq.xyz vf30, 5(vi13) | maddw.xyzw vf28, vf28, vf24 + lq.xyzw vf20, 6(vi10) | mulaz.xyzw ACC, vf20, vf24 + lq.xyzw vf31, 6(vi13) | maddw.xyz vf29, vf29, vf24 + lqi.xyzw vf23, vi02 | mulaz.xyzw ACC, vf23, vf24 + mtir vi10, vf11.x | maddw.xyz vf30, vf30, vf24 + mtir vi13, vf11.y | mulaz.xyzw ACC, vf20, vf24 + b L39 | maddw.xyzw vf31, vf31, vf24 + lqi.xyzw vf23, vi03 | itof0.xyzw vf24, vf23 +L54: + ibgez vi09, L55 | mulaz.xyzw ACC, vf29, vf08 + sq.xyzw vf21, 2(vi11) | maddaz.xyzw ACC, vf30, vf11 + nop | ftoi4.xyzw vf21, vf09 +L55: + mfp.w vf20, P | maddz.xyz vf11, vf31, vf14 + sq.xyzw vf15, 0(vi11) | miniy.xyzw vf12, vf12, vf17 + sq.xyzw vf15, 0(vi14) | miniw.w vf10, vf10, vf03 + sq.xyzw vf21, 2(vi14) | mulaw.xyzw ACC, vf25, vf08 + ilw.y vi09, -6(vi01) | mulw.xyzw vf13, vf13, vf20 + erleng.xyz P, vf11 | ftoi0.xyzw vf12, vf12 + ibne vi06, vi03, L56 | maddaw.xyzw ACC, vf26, vf11 + mr32.z vf14, vf00 | maddw.xyzw vf08, vf27, vf14 + ibne vi07, vi03, L77 | nop + nop | nop + b L153 | nop + nop | nop +L56: + lqi.xyzw vf09, vi01 | mulax.xyzw ACC, vf01, vf13 + sq.xyzw vf12, 1(vi11) | madday.xyzw ACC, vf02, vf13 + sq.xyzw vf12, 1(vi14) | maddz.xyzw vf13, vf03, vf13 + lqi.xyzw vf12, vi01 | add.xyzw vf08, vf08, vf28 + lqi.xyzw vf15, vi01 | maxw.w vf10, vf10, vf02 + mtir vi11, vf09.x | itof0.xyzw vf23, vf23 + mtir vi14, vf09.y | maxx.xyzw vf13, vf13, vf00 + div Q, vf01.w, vf08.w | add.zw vf09, vf09, vf17 + move.xyzw vf21, vf10 | add.xyzw vf12, vf12, vf18 + iand vi11, vi11, vi05 | add.xyzw vf15, vf15, vf19 + nop | mulax.xyzw ACC, vf04, vf13 + ibgtz vi09, L57 | madday.xyzw ACC, vf05, vf13 + iand vi14, vi14, vi05 | maddaz.xyzw ACC, vf06, vf13 + nop | addx.w vf21, vf21, vf17 +L57: + ibne vi05, vi11, L58 | maddw.xyzw vf13, vf07, vf00 + ilw.x vi09, -9(vi01) | mul.xyz vf08, vf08, Q + mtir vi11, vf12.x | mul.xyzw vf14, vf14, Q + mtir vi14, vf12.y | ftoi4.xyzw vf21, vf21 + b L59 | mul.xyzw vf13, vf13, vf23 + lqi.xyzw vf23, vi03 | add.xyzw vf08, vf08, vf22 +L58: + lq.xyzw vf20, 0(vi11) | mul.xyzw vf14, vf14, Q + lq.xyzw vf25, 0(vi14) | ftoi4.xyzw vf21, vf21 + lq.xyzw vf23, 1(vi11) | mul.xyzw vf13, vf13, vf23 + lq.xyzw vf26, 1(vi14) | add.xyzw vf08, vf08, vf22 + lq.xyzw vf20, 2(vi11) | mulaz.xyzw ACC, vf20, vf24 + lq.xyzw vf27, 2(vi14) | maddw.xyzw vf25, vf25, vf24 + lq.xyzw vf23, 3(vi11) | mulaz.xyzw ACC, vf23, vf24 + lq.xyzw vf28, 3(vi14) | maddw.xyzw vf26, vf26, vf24 + lq.xyzw vf20, 4(vi11) | mulaz.xyzw ACC, vf20, vf24 + lq.xyz vf29, 4(vi14) | maddw.xyzw vf27, vf27, vf24 + lq.xyzw vf23, 5(vi11) | mulaz.xyzw ACC, vf23, vf24 + lq.xyz vf30, 5(vi14) | maddw.xyzw vf28, vf28, vf24 + lq.xyzw vf20, 6(vi11) | mulaz.xyzw ACC, vf20, vf24 + lq.xyzw vf31, 6(vi14) | maddw.xyz vf29, vf29, vf24 + lqi.xyzw vf23, vi02 | mulaz.xyzw ACC, vf23, vf24 + mtir vi11, vf12.x | maddw.xyz vf30, vf30, vf24 + mtir vi14, vf12.y | mulaz.xyzw ACC, vf20, vf24 + b L44 | maddw.xyzw vf31, vf31, vf24 + lqi.xyzw vf23, vi03 | itof0.xyzw vf24, vf23 +L59: + ibgez vi09, L60 | mulaz.xyzw ACC, vf29, vf09 + sq.xyzw vf21, 2(vi12) | maddaz.xyzw ACC, vf30, vf12 + nop | ftoi4.xyzw vf21, vf10 +L60: + mfp.w vf20, P | maddz.xyz vf12, vf31, vf15 + sq.xyzw vf16, 0(vi12) | miniy.xyzw vf13, vf13, vf17 + sq.xyzw vf16, 0(vi15) | miniw.w vf08, vf08, vf03 + sq.xyzw vf21, 2(vi15) | mulaw.xyzw ACC, vf25, vf09 + ilw.y vi09, -6(vi01) | mulw.xyzw vf11, vf11, vf20 + erleng.xyz P, vf12 | ftoi0.xyzw vf13, vf13 + ibne vi06, vi03, L46 | maddaw.xyzw ACC, vf26, vf12 + mr32.z vf15, vf00 | maddw.xyzw vf09, vf27, vf15 + ibne vi07, vi03, L72 | nop + nop | nop + b L163 | nop + nop | nop + +;; maybe mat3s +L61: + lqi.xyzw vf08, vi01 | nop + lqi.xyzw vf24, vi02 | nop + lqi.xyzw vf11, vi01 | nop + lqi.xyzw vf14, vi01 | nop + mtir vi10, vf08.x | nop + mtir vi13, vf08.y | itof0.xyzw vf24, vf24 + nop | add.zw vf08, vf08, vf17 + nop | add.xyzw vf11, vf11, vf18 + iand vi10, vi10, vi05 | add.xyzw vf14, vf14, vf19 + ilw.w vi08, -1(vi02) | mulw.xyzw vf24, vf24, vf29 + iand vi13, vi13, vi05 | nop + lq.xyzw vf20, 0(vi10) | nop + lq.xyzw vf31, 0(vi13) | nop + lq.xyzw vf25, 0(vi08) | nop + lq.xyzw vf23, 1(vi10) | nop + lq.xyzw vf20, 1(vi13) | mulax.xyzw ACC, vf20, vf24 + lq.xyzw vf26, 1(vi08) | madday.xyzw ACC, vf31, vf24 + lq.xyzw vf31, 2(vi10) | maddz.xyzw vf25, vf25, vf24 + lq.xyzw vf23, 2(vi13) | mulax.xyzw ACC, vf23, vf24 + lq.xyzw vf27, 2(vi08) | madday.xyzw ACC, vf20, vf24 + lq.xyzw vf20, 3(vi10) | maddz.xyzw vf26, vf26, vf24 + lq.xyzw vf31, 3(vi13) | mulax.xyzw ACC, vf31, vf24 + lq.xyzw vf28, 3(vi08) | madday.xyzw ACC, vf23, vf24 + lq.xyzw vf23, 4(vi10) | maddz.xyzw vf27, vf27, vf24 + lq.xyzw vf20, 4(vi13) | mulax.xyzw ACC, vf20, vf24 + lq.xyz vf29, 4(vi08) | madday.xyzw ACC, vf31, vf24 + lq.xyzw vf31, 5(vi10) | maddz.xyzw vf28, vf28, vf24 + lq.xyzw vf23, 5(vi13) | mulax.xyzw ACC, vf23, vf24 + lq.xyz vf30, 5(vi08) | madday.xyzw ACC, vf20, vf24 + lq.xyzw vf20, 6(vi10) | maddz.xyz vf29, vf29, vf24 + lq.xyzw vf22, 6(vi13) | mulax.xyzw ACC, vf31, vf24 + lq.xyzw vf31, 6(vi08) | madday.xyzw ACC, vf23, vf24 + lqi.xyzw vf23, vi02 | maddz.xyz vf30, vf30, vf24 + mtir vi10, vf11.x | mulax.xyzw ACC, vf20, vf24 + mtir vi13, vf11.y | madday.xyzw ACC, vf22, vf24 + lq.xyzw vf22, 2(vi00) | maddz.xyzw vf31, vf31, vf24 + nop | itof0.xyzw vf24, vf23 + nop | mulaz.xyzw ACC, vf29, vf08 + nop | maddaz.xyzw ACC, vf30, vf11 + nop | maddz.xyz vf11, vf31, vf14 + nop | nop + nop | nop + nop | mulaw.xyzw ACC, vf25, vf08 + nop | nop + erleng.xyz P, vf11 | nop + ior vi15, vi07, vi00 | maddaw.xyzw ACC, vf26, vf11 + mr32.z vf14, vf00 | maddw.xyzw vf08, vf27, vf14 + lqi.xyzw vf09, vi01 | nop + ilwr.y vi03, vi12 | nop + ilw.z vi07, 1(vi12) | nop + lqi.xyzw vf12, vi01 | add.xyzw vf08, vf08, vf28 + lqi.xyzw vf15, vi01 | nop + mtir vi11, vf09.x | nop + ibeq vi00, vi15, L62 | nop + mtir vi14, vf09.y | nop + nop | miniw.w vf08, vf08, vf01 +L62: + div Q, vf01.w, vf08.w | add.zw vf09, vf09, vf17 + iadd vi03, vi03, vi12 | add.xyzw vf12, vf12, vf18 + iand vi11, vi11, vi05 | add.xyzw vf15, vf15, vf19 + ilw.w vi08, -1(vi02) | nop + iadd vi07, vi07, vi03 | nop + iand vi14, vi14, vi05 | nop + ibne vi05, vi11, L63 | nop + iaddi vi07, vi07, -0x1 | mul.xyz vf08, vf08, Q + mtir vi11, vf12.x | mul.xyzw vf14, vf14, Q + mtir vi14, vf12.y | nop + b L64 | nop + lqi.xyzw vf23, vi03 | add.xyzw vf08, vf08, vf22 +L63: + lq.xyzw vf20, 0(vi11) | mul.xyzw vf14, vf14, Q + nop | mulw.xyzw vf24, vf24, vf29 + lq.xyzw vf31, 0(vi14) | nop + lq.xyzw vf25, 0(vi08) | nop + lq.xyzw vf23, 1(vi11) | add.xyzw vf08, vf08, vf22 + lq.xyzw vf20, 1(vi14) | mulax.xyzw ACC, vf20, vf24 + lq.xyzw vf26, 1(vi08) | madday.xyzw ACC, vf31, vf24 + lq.xyzw vf31, 2(vi11) | maddz.xyzw vf25, vf25, vf24 + lq.xyzw vf23, 2(vi14) | mulax.xyzw ACC, vf23, vf24 + lq.xyzw vf27, 2(vi08) | madday.xyzw ACC, vf20, vf24 + lq.xyzw vf20, 3(vi11) | maddz.xyzw vf26, vf26, vf24 + lq.xyzw vf31, 3(vi14) | mulax.xyzw ACC, vf31, vf24 + lq.xyzw vf28, 3(vi08) | madday.xyzw ACC, vf23, vf24 + lq.xyzw vf23, 4(vi11) | maddz.xyzw vf27, vf27, vf24 + lq.xyzw vf20, 4(vi14) | mulax.xyzw ACC, vf20, vf24 + lq.xyz vf29, 4(vi08) | madday.xyzw ACC, vf31, vf24 + lq.xyzw vf31, 5(vi11) | maddz.xyzw vf28, vf28, vf24 + lq.xyzw vf23, 5(vi14) | mulax.xyzw ACC, vf23, vf24 + lq.xyz vf30, 5(vi08) | madday.xyzw ACC, vf20, vf24 + lq.xyzw vf20, 6(vi11) | maddz.xyz vf29, vf29, vf24 + lq.xyzw vf22, 6(vi14) | mulax.xyzw ACC, vf31, vf24 + lq.xyzw vf31, 6(vi08) | madday.xyzw ACC, vf23, vf24 + lqi.xyzw vf23, vi02 | maddz.xyz vf30, vf30, vf24 + mtir vi11, vf12.x | mulax.xyzw ACC, vf20, vf24 + mtir vi14, vf12.y | madday.xyzw ACC, vf22, vf24 + lq.xyzw vf22, 2(vi00) | maddz.xyzw vf31, vf31, vf24 + lqi.xyzw vf23, vi03 | itof0.xyzw vf24, vf23 +L64: + nop | mulaz.xyzw ACC, vf29, vf09 + nop | maddaz.xyzw ACC, vf30, vf12 + mfp.w vf20, P | maddz.xyz vf12, vf31, vf15 + nop | nop + 1024.0 | miniw.w vf08, vf08, vf03 :i + ibne vi00, vi15, L125 | mulaw.xyzw ACC, vf25, vf09 + ilw.y vi09, -6(vi01) | mulw.xyzw vf11, vf11, vf20 + erleng.xyz P, vf12 | nop + nop | maddaw.xyzw ACC, vf26, vf12 + mr32.z vf15, vf00 | maddw.xyzw vf09, vf27, vf15 +L65: + lqi.xyzw vf10, vi01 | mulax.xyzw ACC, vf01, vf11 + b L67 | madday.xyzw ACC, vf02, vf11 + nop | maddz.xyzw vf11, vf03, vf11 +L66: ;; mat3 cross entry + lqi.xyzw vf10, vi01 | mulax.xyzw ACC, vf01, vf11 + sq.xyzw vf13, 1(vi12) | madday.xyzw ACC, vf02, vf11 + sq.xyzw vf13, 1(vi15) | maddz.xyzw vf11, vf03, vf11 +L67: + lqi.xyzw vf13, vi01 | add.xyzw vf09, vf09, vf28 + lqi.xyzw vf16, vi01 | maxw.w vf08, vf08, vf02 + mtir vi12, vf10.x | itof0.xyzw vf23, vf23 + mtir vi15, vf10.y | maxx.xyzw vf11, vf11, vf00 + div Q, vf01.w, vf09.w | add.zw vf10, vf10, vf17 + move.xyzw vf21, vf08 | add.xyzw vf13, vf13, vf18 + iand vi12, vi12, vi05 | add.xyzw vf16, vf16, vf19 + ilw.w vi08, -1(vi02) | mulax.xyzw ACC, vf04, vf11 + ibgtz vi09, L68 | madday.xyzw ACC, vf05, vf11 + iand vi15, vi15, vi05 | maddaz.xyzw ACC, vf06, vf11 + nop | addx.w vf21, vf21, vf17 +L68: + ibne vi05, vi12, L69 | maddw.xyzw vf11, vf07, vf00 + ilw.x vi09, -9(vi01) | mul.xyz vf09, vf09, Q + mtir vi12, vf13.x | mul.xyzw vf15, vf15, Q + mtir vi15, vf13.y | ftoi4.xyzw vf21, vf21 + b L70 | mul.xyzw vf11, vf11, vf23 + lqi.xyzw vf23, vi03 | add.xyzw vf09, vf09, vf22 +L69: + lq.xyzw vf20, 0(vi12) | mul.xyzw vf15, vf15, Q + nop | mulw.xyzw vf24, vf24, vf29 + lq.xyzw vf31, 0(vi15) | ftoi4.xyzw vf21, vf21 + lq.xyzw vf25, 0(vi08) | mul.xyzw vf11, vf11, vf23 + lq.xyzw vf23, 1(vi12) | add.xyzw vf09, vf09, vf22 + lq.xyzw vf20, 1(vi15) | mulax.xyzw ACC, vf20, vf24 + lq.xyzw vf26, 1(vi08) | madday.xyzw ACC, vf31, vf24 + lq.xyzw vf31, 2(vi12) | maddz.xyzw vf25, vf25, vf24 + lq.xyzw vf23, 2(vi15) | mulax.xyzw ACC, vf23, vf24 + lq.xyzw vf27, 2(vi08) | madday.xyzw ACC, vf20, vf24 + lq.xyzw vf20, 3(vi12) | maddz.xyzw vf26, vf26, vf24 + lq.xyzw vf31, 3(vi15) | mulax.xyzw ACC, vf31, vf24 + lq.xyzw vf28, 3(vi08) | madday.xyzw ACC, vf23, vf24 + lq.xyzw vf23, 4(vi12) | maddz.xyzw vf27, vf27, vf24 + lq.xyzw vf20, 4(vi15) | mulax.xyzw ACC, vf20, vf24 + lq.xyz vf29, 4(vi08) | madday.xyzw ACC, vf31, vf24 + lq.xyzw vf31, 5(vi12) | maddz.xyzw vf28, vf28, vf24 + lq.xyzw vf23, 5(vi15) | mulax.xyzw ACC, vf23, vf24 + lq.xyz vf30, 5(vi08) | madday.xyzw ACC, vf20, vf24 + lq.xyzw vf20, 6(vi12) | maddz.xyz vf29, vf29, vf24 + lq.xyzw vf22, 6(vi15) | mulax.xyzw ACC, vf31, vf24 + lq.xyzw vf31, 6(vi08) | madday.xyzw ACC, vf23, vf24 + lqi.xyzw vf23, vi02 | maddz.xyz vf30, vf30, vf24 + mtir vi12, vf13.x | mulax.xyzw ACC, vf20, vf24 + mtir vi15, vf13.y | madday.xyzw ACC, vf22, vf24 + lq.xyzw vf22, 2(vi00) | maddz.xyzw vf31, vf31, vf24 + lqi.xyzw vf23, vi03 | itof0.xyzw vf24, vf23 +L70: + ibgez vi09, L71 | mulaz.xyzw ACC, vf29, vf10 + sq.xyzw vf21, 2(vi10) | maddaz.xyzw ACC, vf30, vf13 + nop | ftoi4.xyzw vf21, vf08 +L71: + mfp.w vf20, P | maddz.xyz vf13, vf31, vf16 + sq.xyzw vf14, 0(vi10) | miniy.xyzw vf11, vf11, vf17 + sq.xyzw vf14, 0(vi13) | miniw.w vf09, vf09, vf03 + sq.xyzw vf21, 2(vi13) | mulaw.xyzw ACC, vf25, vf10 + ilw.y vi09, -6(vi01) | mulw.xyzw vf12, vf12, vf20 + erleng.xyz P, vf13 | ftoi0.xyzw vf11, vf11 + ibeq vi07, vi03, L143 | maddaw.xyzw ACC, vf26, vf13 + mr32.z vf16, vf00 | maddw.xyzw vf10, vf27, vf16 +L72: ;; mat3 cross entry + lqi.xyzw vf08, vi01 | mulax.xyzw ACC, vf01, vf12 + sq.xyzw vf11, 1(vi10) | madday.xyzw ACC, vf02, vf12 + sq.xyzw vf11, 1(vi13) | maddz.xyzw vf12, vf03, vf12 + lqi.xyzw vf11, vi01 | add.xyzw vf10, vf10, vf28 + lqi.xyzw vf14, vi01 | maxw.w vf09, vf09, vf02 + mtir vi10, vf08.x | itof0.xyzw vf23, vf23 + mtir vi13, vf08.y | maxx.xyzw vf12, vf12, vf00 + div Q, vf01.w, vf10.w | add.zw vf08, vf08, vf17 + move.xyzw vf21, vf09 | add.xyzw vf11, vf11, vf18 + iand vi10, vi10, vi05 | add.xyzw vf14, vf14, vf19 + ilw.w vi08, -1(vi02) | mulax.xyzw ACC, vf04, vf12 + ibgtz vi09, L73 | madday.xyzw ACC, vf05, vf12 + iand vi13, vi13, vi05 | maddaz.xyzw ACC, vf06, vf12 + nop | addx.w vf21, vf21, vf17 +L73: + ibne vi05, vi10, L74 | maddw.xyzw vf12, vf07, vf00 + ilw.x vi09, -9(vi01) | mul.xyz vf10, vf10, Q + mtir vi10, vf11.x | mul.xyzw vf16, vf16, Q + mtir vi13, vf11.y | ftoi4.xyzw vf21, vf21 + b L75 | mul.xyzw vf12, vf12, vf23 + lqi.xyzw vf23, vi03 | add.xyzw vf10, vf10, vf22 +L74: + lq.xyzw vf20, 0(vi10) | mul.xyzw vf16, vf16, Q + nop | mulw.xyzw vf24, vf24, vf29 + lq.xyzw vf31, 0(vi13) | ftoi4.xyzw vf21, vf21 + lq.xyzw vf25, 0(vi08) | mul.xyzw vf12, vf12, vf23 + lq.xyzw vf23, 1(vi10) | add.xyzw vf10, vf10, vf22 + lq.xyzw vf20, 1(vi13) | mulax.xyzw ACC, vf20, vf24 + lq.xyzw vf26, 1(vi08) | madday.xyzw ACC, vf31, vf24 + lq.xyzw vf31, 2(vi10) | maddz.xyzw vf25, vf25, vf24 + lq.xyzw vf23, 2(vi13) | mulax.xyzw ACC, vf23, vf24 + lq.xyzw vf27, 2(vi08) | madday.xyzw ACC, vf20, vf24 + lq.xyzw vf20, 3(vi10) | maddz.xyzw vf26, vf26, vf24 + lq.xyzw vf31, 3(vi13) | mulax.xyzw ACC, vf31, vf24 + lq.xyzw vf28, 3(vi08) | madday.xyzw ACC, vf23, vf24 + lq.xyzw vf23, 4(vi10) | maddz.xyzw vf27, vf27, vf24 + lq.xyzw vf20, 4(vi13) | mulax.xyzw ACC, vf20, vf24 + lq.xyz vf29, 4(vi08) | madday.xyzw ACC, vf31, vf24 + lq.xyzw vf31, 5(vi10) | maddz.xyzw vf28, vf28, vf24 + lq.xyzw vf23, 5(vi13) | mulax.xyzw ACC, vf23, vf24 + lq.xyz vf30, 5(vi08) | madday.xyzw ACC, vf20, vf24 + lq.xyzw vf20, 6(vi10) | maddz.xyz vf29, vf29, vf24 + lq.xyzw vf22, 6(vi13) | mulax.xyzw ACC, vf31, vf24 + lq.xyzw vf31, 6(vi08) | madday.xyzw ACC, vf23, vf24 + lqi.xyzw vf23, vi02 | maddz.xyz vf30, vf30, vf24 + mtir vi10, vf11.x | mulax.xyzw ACC, vf20, vf24 + mtir vi13, vf11.y | madday.xyzw ACC, vf22, vf24 + lq.xyzw vf22, 2(vi00) | maddz.xyzw vf31, vf31, vf24 + lqi.xyzw vf23, vi03 | itof0.xyzw vf24, vf23 +L75: + ibgez vi09, L76 | mulaz.xyzw ACC, vf29, vf08 + sq.xyzw vf21, 2(vi11) | maddaz.xyzw ACC, vf30, vf11 + nop | ftoi4.xyzw vf21, vf09 +L76: + mfp.w vf20, P | maddz.xyz vf11, vf31, vf14 + sq.xyzw vf15, 0(vi11) | miniy.xyzw vf12, vf12, vf17 + sq.xyzw vf15, 0(vi14) | miniw.w vf10, vf10, vf03 + sq.xyzw vf21, 2(vi14) | mulaw.xyzw ACC, vf25, vf08 + ilw.y vi09, -6(vi01) | mulw.xyzw vf13, vf13, vf20 + erleng.xyz P, vf11 | ftoi0.xyzw vf12, vf12 + ibeq vi07, vi03, L153 | maddaw.xyzw ACC, vf26, vf11 + mr32.z vf14, vf00 | maddw.xyzw vf08, vf27, vf14 +L77: ;; mat3 cross entry + lqi.xyzw vf09, vi01 | mulax.xyzw ACC, vf01, vf13 + sq.xyzw vf12, 1(vi11) | madday.xyzw ACC, vf02, vf13 + sq.xyzw vf12, 1(vi14) | maddz.xyzw vf13, vf03, vf13 + lqi.xyzw vf12, vi01 | add.xyzw vf08, vf08, vf28 + lqi.xyzw vf15, vi01 | maxw.w vf10, vf10, vf02 + mtir vi11, vf09.x | itof0.xyzw vf23, vf23 + mtir vi14, vf09.y | maxx.xyzw vf13, vf13, vf00 + div Q, vf01.w, vf08.w | add.zw vf09, vf09, vf17 + move.xyzw vf21, vf10 | add.xyzw vf12, vf12, vf18 + iand vi11, vi11, vi05 | add.xyzw vf15, vf15, vf19 + ilw.w vi08, -1(vi02) | mulax.xyzw ACC, vf04, vf13 + ibgtz vi09, L78 | madday.xyzw ACC, vf05, vf13 + iand vi14, vi14, vi05 | maddaz.xyzw ACC, vf06, vf13 + nop | addx.w vf21, vf21, vf17 +L78: + ibne vi05, vi11, L79 | maddw.xyzw vf13, vf07, vf00 + ilw.x vi09, -9(vi01) | mul.xyz vf08, vf08, Q + mtir vi11, vf12.x | mul.xyzw vf14, vf14, Q + mtir vi14, vf12.y | ftoi4.xyzw vf21, vf21 + b L80 | mul.xyzw vf13, vf13, vf23 + lqi.xyzw vf23, vi03 | add.xyzw vf08, vf08, vf22 +L79: + lq.xyzw vf20, 0(vi11) | mul.xyzw vf14, vf14, Q + nop | mulw.xyzw vf24, vf24, vf29 + lq.xyzw vf31, 0(vi14) | ftoi4.xyzw vf21, vf21 + lq.xyzw vf25, 0(vi08) | mul.xyzw vf13, vf13, vf23 + lq.xyzw vf23, 1(vi11) | add.xyzw vf08, vf08, vf22 + lq.xyzw vf20, 1(vi14) | mulax.xyzw ACC, vf20, vf24 + lq.xyzw vf26, 1(vi08) | madday.xyzw ACC, vf31, vf24 + lq.xyzw vf31, 2(vi11) | maddz.xyzw vf25, vf25, vf24 + lq.xyzw vf23, 2(vi14) | mulax.xyzw ACC, vf23, vf24 + lq.xyzw vf27, 2(vi08) | madday.xyzw ACC, vf20, vf24 + lq.xyzw vf20, 3(vi11) | maddz.xyzw vf26, vf26, vf24 + lq.xyzw vf31, 3(vi14) | mulax.xyzw ACC, vf31, vf24 + lq.xyzw vf28, 3(vi08) | madday.xyzw ACC, vf23, vf24 + lq.xyzw vf23, 4(vi11) | maddz.xyzw vf27, vf27, vf24 + lq.xyzw vf20, 4(vi14) | mulax.xyzw ACC, vf20, vf24 + lq.xyz vf29, 4(vi08) | madday.xyzw ACC, vf31, vf24 + lq.xyzw vf31, 5(vi11) | maddz.xyzw vf28, vf28, vf24 + lq.xyzw vf23, 5(vi14) | mulax.xyzw ACC, vf23, vf24 + lq.xyz vf30, 5(vi08) | madday.xyzw ACC, vf20, vf24 + lq.xyzw vf20, 6(vi11) | maddz.xyz vf29, vf29, vf24 + lq.xyzw vf22, 6(vi14) | mulax.xyzw ACC, vf31, vf24 + lq.xyzw vf31, 6(vi08) | madday.xyzw ACC, vf23, vf24 + lqi.xyzw vf23, vi02 | maddz.xyz vf30, vf30, vf24 + mtir vi11, vf12.x | mulax.xyzw ACC, vf20, vf24 + mtir vi14, vf12.y | madday.xyzw ACC, vf22, vf24 + lq.xyzw vf22, 2(vi00) | maddz.xyzw vf31, vf31, vf24 + lqi.xyzw vf23, vi03 | itof0.xyzw vf24, vf23 +L80: + ibgez vi09, L81 | mulaz.xyzw ACC, vf29, vf09 + sq.xyzw vf21, 2(vi12) | maddaz.xyzw ACC, vf30, vf12 + nop | ftoi4.xyzw vf21, vf10 +L81: + mfp.w vf20, P | maddz.xyz vf12, vf31, vf15 + sq.xyzw vf16, 0(vi12) | miniy.xyzw vf13, vf13, vf17 + sq.xyzw vf16, 0(vi15) | miniw.w vf08, vf08, vf03 + sq.xyzw vf21, 2(vi15) | mulaw.xyzw ACC, vf25, vf09 + ilw.y vi09, -6(vi01) | mulw.xyzw vf11, vf11, vf20 + erleng.xyz P, vf12 | ftoi0.xyzw vf13, vf13 + ibne vi07, vi03, L66 | maddaw.xyzw ACC, vf26, vf12 + mr32.z vf15, vf00 | maddw.xyzw vf09, vf27, vf15 + b L163 | nop + nop | nop + +;; merc prime, or other weird things. +L82: + erleng.xyz P, vf12 | maxi.xy vf08, vf08, I + 3072.0 | nop :i + nop | minii.xy vf08, vf08, I + nop | maddaw.xyzw ACC, vf26, vf12 + mr32.z vf15, vf00 | maddw.xyzw vf09, vf27, vf15 + lqi.xyzw vf10, vi01 | mulax.xyzw ACC, vf01, vf11 + ibne vi04, vi03, L84 | madday.xyzw ACC, vf02, vf11 + nop | maddz.xyzw vf11, vf03, vf11 + ibne vi06, vi03, L95 | nop + nop | nop + b L128 | nop + nop | nop +L83: + 3072.0 | mulax.xyzw ACC, vf01, vf11 :i + lqi.xyzw vf10, vi01 | minii.xy vf08, vf08, I + sq.xyzw vf13, 1(vi12) | madday.xyzw ACC, vf02, vf11 + sq.xyzw vf13, 1(vi15) | maddz.xyzw vf11, vf03, vf11 +L84: + lqi.xyzw vf13, vi01 | add.xyzw vf09, vf09, vf28 + lqi.xyzw vf16, vi01 | maxw.w vf08, vf08, vf02 + mtir vi08, vf10.x | itof0.xyzw vf23, vf23 + ilw.y vi09, -9(vi01) | maxx.xyzw vf11, vf11, vf00 + nop | miniw.w vf09, vf09, vf01 + div Q, vf01.w, vf09.w | add.zw vf10, vf10, vf17 + move.xyzw vf21, vf08 | add.xyzw vf13, vf13, vf18 + lq.xyz vf29, 4(vi08) | add.xyzw vf16, vf16, vf19 + lq.xyz vf30, 5(vi08) | mulax.xyzw ACC, vf04, vf11 + ibgtz vi09, L85 | madday.xyzw ACC, vf05, vf11 + lq.xyzw vf31, 6(vi08) | maddaz.xyzw ACC, vf06, vf11 + nop | addx.w vf21, vf21, vf17 +L85: + lq.xyzw vf25, 0(vi08) | maddw.xyzw vf11, vf07, vf00 + lq.xyzw vf26, 1(vi08) | mul.xyz vf09, vf09, Q + mtir vi12, vf13.x | mul.xyzw vf15, vf15, Q + mtir vi15, vf13.y | ftoi4.xyzw vf21, vf21 + lq.xyzw vf27, 2(vi08) | mul.xyzw vf11, vf11, vf23 + lqi.xyzw vf23, vi03 | add.xyzw vf09, vf09, vf22 + ibne vi00, vi09, L86 | mulaz.xyzw ACC, vf29, vf10 + sq.xyzw vf21, 2(vi10) | maddaz.xyzw ACC, vf30, vf13 + nop | ftoi4.xyzw vf21, vf08 +L86: + mfp.w vf20, P | maddz.xyz vf13, vf31, vf16 + sq.xyzw vf14, 0(vi10) | miniy.xyzw vf11, vf11, vf17 + sq.xyzw vf14, 0(vi13) | miniw.w vf09, vf09, vf03 + sq.xyzw vf21, 2(vi13) | mulaw.xyzw ACC, vf25, vf10 + lq.xyzw vf28, 3(vi08) | mulw.xyzw vf12, vf12, vf20 + 1024.0 | ftoi0.xyzw vf11, vf11 :i + erleng.xyz P, vf13 | maxi.xy vf09, vf09, I + ibne vi04, vi03, L87 | maddaw.xyzw ACC, vf26, vf13 + mr32.z vf16, vf00 | maddw.xyzw vf10, vf27, vf16 + ibne vi06, vi03, L100 | nop + ilw.y vi09, -6(vi01) | nop + ibne vi07, vi03, L133 | nop + nop | nop + b L143 | nop + nop | nop +L87: + 3072.0 | mulax.xyzw ACC, vf01, vf12 :i + lqi.xyzw vf08, vi01 | minii.xy vf09, vf09, I + sq.xyzw vf11, 1(vi10) | madday.xyzw ACC, vf02, vf12 + sq.xyzw vf11, 1(vi13) | maddz.xyzw vf12, vf03, vf12 + lqi.xyzw vf11, vi01 | add.xyzw vf10, vf10, vf28 + lqi.xyzw vf14, vi01 | maxw.w vf09, vf09, vf02 + mtir vi08, vf08.x | itof0.xyzw vf23, vf23 + ilw.y vi09, -9(vi01) | maxx.xyzw vf12, vf12, vf00 + nop | miniw.w vf10, vf10, vf01 + div Q, vf01.w, vf10.w | add.zw vf08, vf08, vf17 + move.xyzw vf21, vf09 | add.xyzw vf11, vf11, vf18 + lq.xyz vf29, 4(vi08) | add.xyzw vf14, vf14, vf19 + lq.xyz vf30, 5(vi08) | mulax.xyzw ACC, vf04, vf12 + ibgtz vi09, L88 | madday.xyzw ACC, vf05, vf12 + lq.xyzw vf31, 6(vi08) | maddaz.xyzw ACC, vf06, vf12 + nop | addx.w vf21, vf21, vf17 +L88: + lq.xyzw vf25, 0(vi08) | maddw.xyzw vf12, vf07, vf00 + lq.xyzw vf26, 1(vi08) | mul.xyz vf10, vf10, Q + mtir vi10, vf11.x | mul.xyzw vf16, vf16, Q + mtir vi13, vf11.y | ftoi4.xyzw vf21, vf21 + lq.xyzw vf27, 2(vi08) | mul.xyzw vf12, vf12, vf23 + lqi.xyzw vf23, vi03 | add.xyzw vf10, vf10, vf22 + ibne vi00, vi09, L89 | mulaz.xyzw ACC, vf29, vf08 + sq.xyzw vf21, 2(vi11) | maddaz.xyzw ACC, vf30, vf11 + nop | ftoi4.xyzw vf21, vf09 +L89: + mfp.w vf20, P | maddz.xyz vf11, vf31, vf14 + sq.xyzw vf15, 0(vi11) | miniy.xyzw vf12, vf12, vf17 + sq.xyzw vf15, 0(vi14) | miniw.w vf10, vf10, vf03 + sq.xyzw vf21, 2(vi14) | mulaw.xyzw ACC, vf25, vf08 + lq.xyzw vf28, 3(vi08) | mulw.xyzw vf13, vf13, vf20 + 1024.0 | ftoi0.xyzw vf12, vf12 :i + erleng.xyz P, vf11 | maxi.xy vf10, vf10, I + ibne vi04, vi03, L90 | maddaw.xyzw ACC, vf26, vf11 + mr32.z vf14, vf00 | maddw.xyzw vf08, vf27, vf14 + ibne vi06, vi03, L105 | nop + ilw.y vi09, -6(vi01) | nop + ibne vi07, vi03, L138 | nop + nop | nop + b L153 | nop + nop | nop +L90: + 3072.0 | mulax.xyzw ACC, vf01, vf13 :i + lqi.xyzw vf09, vi01 | minii.xy vf10, vf10, I + sq.xyzw vf12, 1(vi11) | madday.xyzw ACC, vf02, vf13 + sq.xyzw vf12, 1(vi14) | maddz.xyzw vf13, vf03, vf13 + lqi.xyzw vf12, vi01 | add.xyzw vf08, vf08, vf28 + lqi.xyzw vf15, vi01 | maxw.w vf10, vf10, vf02 + mtir vi08, vf09.x | itof0.xyzw vf23, vf23 + ilw.y vi09, -9(vi01) | maxx.xyzw vf13, vf13, vf00 + nop | miniw.w vf08, vf08, vf01 + div Q, vf01.w, vf08.w | add.zw vf09, vf09, vf17 + move.xyzw vf21, vf10 | add.xyzw vf12, vf12, vf18 + lq.xyz vf29, 4(vi08) | add.xyzw vf15, vf15, vf19 + lq.xyz vf30, 5(vi08) | mulax.xyzw ACC, vf04, vf13 + ibgtz vi09, L91 | madday.xyzw ACC, vf05, vf13 + lq.xyzw vf31, 6(vi08) | maddaz.xyzw ACC, vf06, vf13 + nop | addx.w vf21, vf21, vf17 +L91: + lq.xyzw vf25, 0(vi08) | maddw.xyzw vf13, vf07, vf00 + lq.xyzw vf26, 1(vi08) | mul.xyz vf08, vf08, Q + mtir vi11, vf12.x | mul.xyzw vf14, vf14, Q + mtir vi14, vf12.y | ftoi4.xyzw vf21, vf21 + lq.xyzw vf27, 2(vi08) | mul.xyzw vf13, vf13, vf23 + lqi.xyzw vf23, vi03 | add.xyzw vf08, vf08, vf22 + ibne vi00, vi09, L92 | mulaz.xyzw ACC, vf29, vf09 + sq.xyzw vf21, 2(vi12) | maddaz.xyzw ACC, vf30, vf12 + nop | ftoi4.xyzw vf21, vf10 +L92: + mfp.w vf20, P | maddz.xyz vf12, vf31, vf15 + sq.xyzw vf16, 0(vi12) | miniy.xyzw vf13, vf13, vf17 + sq.xyzw vf16, 0(vi15) | miniw.w vf08, vf08, vf03 + sq.xyzw vf21, 2(vi15) | mulaw.xyzw ACC, vf25, vf09 + lq.xyzw vf28, 3(vi08) | mulw.xyzw vf11, vf11, vf20 + 1024.0 | ftoi0.xyzw vf13, vf13 :i + erleng.xyz P, vf12 | maxi.xy vf08, vf08, I + ibne vi04, vi03, L83 | maddaw.xyzw ACC, vf26, vf12 + mr32.z vf15, vf00 | maddw.xyzw vf09, vf27, vf15 + ibne vi06, vi03, L94 | nop + ilw.y vi09, -6(vi01) | nop + ibne vi07, vi03, L127 | nop + nop | nop + b L163 | nop + nop | nop +L93: + erleng.xyz P, vf12 | maxi.xy vf08, vf08, I + 3072.0 | nop :i + nop | minii.xy vf08, vf08, I + ibeq vi06, vi03, L126 | maddaw.xyzw ACC, vf26, vf12 + mr32.z vf15, vf00 | maddw.xyzw vf09, vf27, vf15 + lqi.xyzw vf10, vi01 | mulax.xyzw ACC, vf01, vf11 + jr vi08 | madday.xyzw ACC, vf02, vf11 + nop | maddz.xyzw vf11, vf03, vf11 +L94: + 3072.0 | mulax.xyzw ACC, vf01, vf11 :i + lqi.xyzw vf10, vi01 | minii.xy vf08, vf08, I + sq.xyzw vf13, 1(vi12) | madday.xyzw ACC, vf02, vf11 + sq.xyzw vf13, 1(vi15) | maddz.xyzw vf11, vf03, vf11 +L95: + lqi.xyzw vf13, vi01 | add.xyzw vf09, vf09, vf28 + lqi.xyzw vf16, vi01 | maxw.w vf08, vf08, vf02 + mtir vi12, vf10.x | itof0.xyzw vf23, vf23 + mtir vi15, vf10.y | maxx.xyzw vf11, vf11, vf00 + nop | miniw.w vf09, vf09, vf01 + div Q, vf01.w, vf09.w | add.zw vf10, vf10, vf17 + move.xyzw vf21, vf08 | add.xyzw vf13, vf13, vf18 + iand vi12, vi12, vi05 | add.xyzw vf16, vf16, vf19 + nop | mulax.xyzw ACC, vf04, vf11 + ibgtz vi09, L96 | madday.xyzw ACC, vf05, vf11 + iand vi15, vi15, vi05 | maddaz.xyzw ACC, vf06, vf11 + nop | addx.w vf21, vf21, vf17 +L96: + ibne vi05, vi12, L97 | maddw.xyzw vf11, vf07, vf00 + ilw.x vi09, -9(vi01) | mul.xyz vf09, vf09, Q + mtir vi12, vf13.x | mul.xyzw vf15, vf15, Q + mtir vi15, vf13.y | ftoi4.xyzw vf21, vf21 + b L98 | mul.xyzw vf11, vf11, vf23 + lqi.xyzw vf23, vi03 | add.xyzw vf09, vf09, vf22 +L97: + lq.xyzw vf20, 0(vi12) | mul.xyzw vf15, vf15, Q + nop | mulw.xyzw vf24, vf24, vf29 + lq.xyzw vf25, 0(vi15) | ftoi4.xyzw vf21, vf21 + lq.xyzw vf23, 1(vi12) | mul.xyzw vf11, vf11, vf23 + lq.xyzw vf26, 1(vi15) | add.xyzw vf09, vf09, vf22 + lq.xyzw vf20, 2(vi12) | mulax.xyzw ACC, vf20, vf24 + lq.xyzw vf27, 2(vi15) | maddy.xyzw vf25, vf25, vf24 + lq.xyzw vf23, 3(vi12) | mulax.xyzw ACC, vf23, vf24 + lq.xyzw vf28, 3(vi15) | maddy.xyzw vf26, vf26, vf24 + lq.xyzw vf20, 4(vi12) | mulax.xyzw ACC, vf20, vf24 + lq.xyz vf29, 4(vi15) | maddy.xyzw vf27, vf27, vf24 + lq.xyzw vf23, 5(vi12) | mulax.xyzw ACC, vf23, vf24 + lq.xyz vf30, 5(vi15) | maddy.xyzw vf28, vf28, vf24 + lq.xyzw vf20, 6(vi12) | mulax.xyzw ACC, vf20, vf24 + lq.xyzw vf31, 6(vi15) | maddy.xyz vf29, vf29, vf24 + mtir vi12, vf13.x | mulax.xyzw ACC, vf23, vf24 + mtir vi15, vf13.y | maddy.xyz vf30, vf30, vf24 + b L113 | mulax.xyzw ACC, vf20, vf24 + lqi.xyzw vf23, vi03 | maddy.xyzw vf31, vf31, vf24 +L98: + ibgez vi09, L99 | mulaz.xyzw ACC, vf29, vf10 + sq.xyzw vf21, 2(vi10) | maddaz.xyzw ACC, vf30, vf13 + nop | ftoi4.xyzw vf21, vf08 +L99: + mfp.w vf20, P | maddz.xyz vf13, vf31, vf16 + sq.xyzw vf14, 0(vi10) | miniy.xyzw vf11, vf11, vf17 + sq.xyzw vf14, 0(vi13) | miniw.w vf09, vf09, vf03 + sq.xyzw vf21, 2(vi13) | mulaw.xyzw ACC, vf25, vf10 + ilw.y vi09, -6(vi01) | mulw.xyzw vf12, vf12, vf20 + 1024.0 | ftoi0.xyzw vf11, vf11 :i + erleng.xyz P, vf13 | maxi.xy vf09, vf09, I + ibne vi06, vi03, L100 | maddaw.xyzw ACC, vf26, vf13 + mr32.z vf16, vf00 | maddw.xyzw vf10, vf27, vf16 + ibne vi07, vi03, L133 | nop + nop | nop + b L143 | nop + nop | nop +L100: + 3072.0 | mulax.xyzw ACC, vf01, vf12 :i + lqi.xyzw vf08, vi01 | minii.xy vf09, vf09, I + sq.xyzw vf11, 1(vi10) | madday.xyzw ACC, vf02, vf12 + sq.xyzw vf11, 1(vi13) | maddz.xyzw vf12, vf03, vf12 + lqi.xyzw vf11, vi01 | add.xyzw vf10, vf10, vf28 + lqi.xyzw vf14, vi01 | maxw.w vf09, vf09, vf02 + mtir vi10, vf08.x | itof0.xyzw vf23, vf23 + mtir vi13, vf08.y | maxx.xyzw vf12, vf12, vf00 + nop | miniw.w vf10, vf10, vf01 + div Q, vf01.w, vf10.w | add.zw vf08, vf08, vf17 + move.xyzw vf21, vf09 | add.xyzw vf11, vf11, vf18 + iand vi10, vi10, vi05 | add.xyzw vf14, vf14, vf19 + nop | mulax.xyzw ACC, vf04, vf12 + ibgtz vi09, L101 | madday.xyzw ACC, vf05, vf12 + iand vi13, vi13, vi05 | maddaz.xyzw ACC, vf06, vf12 + nop | addx.w vf21, vf21, vf17 +L101: + ibne vi05, vi10, L102 | maddw.xyzw vf12, vf07, vf00 + ilw.x vi09, -9(vi01) | mul.xyz vf10, vf10, Q + mtir vi10, vf11.x | mul.xyzw vf16, vf16, Q + mtir vi13, vf11.y | ftoi4.xyzw vf21, vf21 + b L103 | mul.xyzw vf12, vf12, vf23 + lqi.xyzw vf23, vi03 | add.xyzw vf10, vf10, vf22 +L102: + lq.xyzw vf20, 0(vi10) | mul.xyzw vf16, vf16, Q + nop | mulw.xyzw vf24, vf24, vf29 + lq.xyzw vf25, 0(vi13) | ftoi4.xyzw vf21, vf21 + lq.xyzw vf23, 1(vi10) | mul.xyzw vf12, vf12, vf23 + lq.xyzw vf26, 1(vi13) | add.xyzw vf10, vf10, vf22 + lq.xyzw vf20, 2(vi10) | mulax.xyzw ACC, vf20, vf24 + lq.xyzw vf27, 2(vi13) | maddy.xyzw vf25, vf25, vf24 + lq.xyzw vf23, 3(vi10) | mulax.xyzw ACC, vf23, vf24 + lq.xyzw vf28, 3(vi13) | maddy.xyzw vf26, vf26, vf24 + lq.xyzw vf20, 4(vi10) | mulax.xyzw ACC, vf20, vf24 + lq.xyz vf29, 4(vi13) | maddy.xyzw vf27, vf27, vf24 + lq.xyzw vf23, 5(vi10) | mulax.xyzw ACC, vf23, vf24 + lq.xyz vf30, 5(vi13) | maddy.xyzw vf28, vf28, vf24 + lq.xyzw vf20, 6(vi10) | mulax.xyzw ACC, vf20, vf24 + lq.xyzw vf31, 6(vi13) | maddy.xyz vf29, vf29, vf24 + mtir vi10, vf11.x | mulax.xyzw ACC, vf23, vf24 + mtir vi13, vf11.y | maddy.xyz vf30, vf30, vf24 + b L118 | mulax.xyzw ACC, vf20, vf24 + lqi.xyzw vf23, vi03 | maddy.xyzw vf31, vf31, vf24 +L103: + ibgez vi09, L104 | mulaz.xyzw ACC, vf29, vf08 + sq.xyzw vf21, 2(vi11) | maddaz.xyzw ACC, vf30, vf11 + nop | ftoi4.xyzw vf21, vf09 +L104: + mfp.w vf20, P | maddz.xyz vf11, vf31, vf14 + sq.xyzw vf15, 0(vi11) | miniy.xyzw vf12, vf12, vf17 + sq.xyzw vf15, 0(vi14) | miniw.w vf10, vf10, vf03 + sq.xyzw vf21, 2(vi14) | mulaw.xyzw ACC, vf25, vf08 + ilw.y vi09, -6(vi01) | mulw.xyzw vf13, vf13, vf20 + 1024.0 | ftoi0.xyzw vf12, vf12 :i + erleng.xyz P, vf11 | maxi.xy vf10, vf10, I + ibne vi06, vi03, L105 | maddaw.xyzw ACC, vf26, vf11 + mr32.z vf14, vf00 | maddw.xyzw vf08, vf27, vf14 + ibne vi07, vi03, L138 | nop + nop | nop + b L153 | nop + nop | nop +L105: + 3072.0 | mulax.xyzw ACC, vf01, vf13 :i + lqi.xyzw vf09, vi01 | minii.xy vf10, vf10, I + sq.xyzw vf12, 1(vi11) | madday.xyzw ACC, vf02, vf13 + sq.xyzw vf12, 1(vi14) | maddz.xyzw vf13, vf03, vf13 + lqi.xyzw vf12, vi01 | add.xyzw vf08, vf08, vf28 + lqi.xyzw vf15, vi01 | maxw.w vf10, vf10, vf02 + mtir vi11, vf09.x | itof0.xyzw vf23, vf23 + mtir vi14, vf09.y | maxx.xyzw vf13, vf13, vf00 + nop | miniw.w vf08, vf08, vf01 + div Q, vf01.w, vf08.w | add.zw vf09, vf09, vf17 + move.xyzw vf21, vf10 | add.xyzw vf12, vf12, vf18 + iand vi11, vi11, vi05 | add.xyzw vf15, vf15, vf19 + nop | mulax.xyzw ACC, vf04, vf13 + ibgtz vi09, L106 | madday.xyzw ACC, vf05, vf13 + iand vi14, vi14, vi05 | maddaz.xyzw ACC, vf06, vf13 + nop | addx.w vf21, vf21, vf17 +L106: + ibne vi05, vi11, L107 | maddw.xyzw vf13, vf07, vf00 + ilw.x vi09, -9(vi01) | mul.xyz vf08, vf08, Q + mtir vi11, vf12.x | mul.xyzw vf14, vf14, Q + mtir vi14, vf12.y | ftoi4.xyzw vf21, vf21 + b L108 | mul.xyzw vf13, vf13, vf23 + lqi.xyzw vf23, vi03 | add.xyzw vf08, vf08, vf22 +L107: + lq.xyzw vf20, 0(vi11) | mul.xyzw vf14, vf14, Q + nop | mulw.xyzw vf24, vf24, vf29 + lq.xyzw vf25, 0(vi14) | ftoi4.xyzw vf21, vf21 + lq.xyzw vf23, 1(vi11) | mul.xyzw vf13, vf13, vf23 + lq.xyzw vf26, 1(vi14) | add.xyzw vf08, vf08, vf22 + lq.xyzw vf20, 2(vi11) | mulax.xyzw ACC, vf20, vf24 + lq.xyzw vf27, 2(vi14) | maddy.xyzw vf25, vf25, vf24 + lq.xyzw vf23, 3(vi11) | mulax.xyzw ACC, vf23, vf24 + lq.xyzw vf28, 3(vi14) | maddy.xyzw vf26, vf26, vf24 + lq.xyzw vf20, 4(vi11) | mulax.xyzw ACC, vf20, vf24 + lq.xyz vf29, 4(vi14) | maddy.xyzw vf27, vf27, vf24 + lq.xyzw vf23, 5(vi11) | mulax.xyzw ACC, vf23, vf24 + lq.xyz vf30, 5(vi14) | maddy.xyzw vf28, vf28, vf24 + lq.xyzw vf20, 6(vi11) | mulax.xyzw ACC, vf20, vf24 + lq.xyzw vf31, 6(vi14) | maddy.xyz vf29, vf29, vf24 + mtir vi11, vf12.x | mulax.xyzw ACC, vf23, vf24 + mtir vi14, vf12.y | maddy.xyz vf30, vf30, vf24 + b L123 | mulax.xyzw ACC, vf20, vf24 + lqi.xyzw vf23, vi03 | maddy.xyzw vf31, vf31, vf24 +L108: + ibgez vi09, L109 | mulaz.xyzw ACC, vf29, vf09 + sq.xyzw vf21, 2(vi12) | maddaz.xyzw ACC, vf30, vf12 + nop | ftoi4.xyzw vf21, vf10 +L109: + mfp.w vf20, P | maddz.xyz vf12, vf31, vf15 + sq.xyzw vf16, 0(vi12) | miniy.xyzw vf13, vf13, vf17 + sq.xyzw vf16, 0(vi15) | miniw.w vf08, vf08, vf03 + sq.xyzw vf21, 2(vi15) | mulaw.xyzw ACC, vf25, vf09 + ilw.y vi09, -6(vi01) | mulw.xyzw vf11, vf11, vf20 + 1024.0 | ftoi0.xyzw vf13, vf13 :i + erleng.xyz P, vf12 | maxi.xy vf08, vf08, I + ibne vi06, vi03, L94 | maddaw.xyzw ACC, vf26, vf12 + mr32.z vf15, vf00 | maddw.xyzw vf09, vf27, vf15 + ibne vi07, vi03, L127 | nop + nop | nop + b L163 | nop + nop | nop +L110: + 3072.0 | mulax.xyzw ACC, vf01, vf11 :i + lqi.xyzw vf10, vi01 | minii.xy vf08, vf08, I + sq.xyzw vf13, 1(vi12) | madday.xyzw ACC, vf02, vf11 + sq.xyzw vf13, 1(vi15) | maddz.xyzw vf11, vf03, vf11 + lqi.xyzw vf13, vi01 | add.xyzw vf09, vf09, vf28 + lqi.xyzw vf16, vi01 | maxw.w vf08, vf08, vf02 + mtir vi12, vf10.x | itof0.xyzw vf23, vf23 + mtir vi15, vf10.y | maxx.xyzw vf11, vf11, vf00 + nop | miniw.w vf09, vf09, vf01 + div Q, vf01.w, vf09.w | add.zw vf10, vf10, vf17 + move.xyzw vf21, vf08 | add.xyzw vf13, vf13, vf18 + iand vi12, vi12, vi05 | add.xyzw vf16, vf16, vf19 + nop | mulax.xyzw ACC, vf04, vf11 + ibgtz vi09, L111 | madday.xyzw ACC, vf05, vf11 + iand vi15, vi15, vi05 | maddaz.xyzw ACC, vf06, vf11 + nop | addx.w vf21, vf21, vf17 +L111: + ibne vi05, vi12, L112 | maddw.xyzw vf11, vf07, vf00 + ilw.x vi09, -9(vi01) | mul.xyz vf09, vf09, Q + mtir vi12, vf13.x | mul.xyzw vf15, vf15, Q + mtir vi15, vf13.y | ftoi4.xyzw vf21, vf21 + b L113 | mul.xyzw vf11, vf11, vf23 + lqi.xyzw vf23, vi03 | add.xyzw vf09, vf09, vf22 +L112: + lq.xyzw vf20, 0(vi12) | mul.xyzw vf15, vf15, Q + lq.xyzw vf25, 0(vi15) | ftoi4.xyzw vf21, vf21 + lq.xyzw vf23, 1(vi12) | mul.xyzw vf11, vf11, vf23 + lq.xyzw vf26, 1(vi15) | add.xyzw vf09, vf09, vf22 + lq.xyzw vf20, 2(vi12) | mulaz.xyzw ACC, vf20, vf24 + lq.xyzw vf27, 2(vi15) | maddw.xyzw vf25, vf25, vf24 + lq.xyzw vf23, 3(vi12) | mulaz.xyzw ACC, vf23, vf24 + lq.xyzw vf28, 3(vi15) | maddw.xyzw vf26, vf26, vf24 + lq.xyzw vf20, 4(vi12) | mulaz.xyzw ACC, vf20, vf24 + lq.xyz vf29, 4(vi15) | maddw.xyzw vf27, vf27, vf24 + lq.xyzw vf23, 5(vi12) | mulaz.xyzw ACC, vf23, vf24 + lq.xyz vf30, 5(vi15) | maddw.xyzw vf28, vf28, vf24 + lq.xyzw vf20, 6(vi12) | mulaz.xyzw ACC, vf20, vf24 + lq.xyzw vf31, 6(vi15) | maddw.xyz vf29, vf29, vf24 + lqi.xyzw vf23, vi02 | mulaz.xyzw ACC, vf23, vf24 + mtir vi12, vf13.x | maddw.xyz vf30, vf30, vf24 + mtir vi15, vf13.y | mulaz.xyzw ACC, vf20, vf24 + b L98 | maddw.xyzw vf31, vf31, vf24 + lqi.xyzw vf23, vi03 | itof0.xyzw vf24, vf23 +L113: + ibgez vi09, L114 | mulaz.xyzw ACC, vf29, vf10 + sq.xyzw vf21, 2(vi10) | maddaz.xyzw ACC, vf30, vf13 + nop | ftoi4.xyzw vf21, vf08 +L114: + mfp.w vf20, P | maddz.xyz vf13, vf31, vf16 + sq.xyzw vf14, 0(vi10) | miniy.xyzw vf11, vf11, vf17 + sq.xyzw vf14, 0(vi13) | miniw.w vf09, vf09, vf03 + sq.xyzw vf21, 2(vi13) | mulaw.xyzw ACC, vf25, vf10 + ilw.y vi09, -6(vi01) | mulw.xyzw vf12, vf12, vf20 + 1024.0 | ftoi0.xyzw vf11, vf11 :i + erleng.xyz P, vf13 | maxi.xy vf09, vf09, I + ibne vi06, vi03, L115 | maddaw.xyzw ACC, vf26, vf13 + mr32.z vf16, vf00 | maddw.xyzw vf10, vf27, vf16 + ibne vi07, vi03, L133 | nop + nop | nop + b L143 | nop + nop | nop +L115: + 3072.0 | mulax.xyzw ACC, vf01, vf12 :i + lqi.xyzw vf08, vi01 | minii.xy vf09, vf09, I + sq.xyzw vf11, 1(vi10) | madday.xyzw ACC, vf02, vf12 + sq.xyzw vf11, 1(vi13) | maddz.xyzw vf12, vf03, vf12 + lqi.xyzw vf11, vi01 | add.xyzw vf10, vf10, vf28 + lqi.xyzw vf14, vi01 | maxw.w vf09, vf09, vf02 + mtir vi10, vf08.x | itof0.xyzw vf23, vf23 + mtir vi13, vf08.y | maxx.xyzw vf12, vf12, vf00 + nop | miniw.w vf10, vf10, vf01 + div Q, vf01.w, vf10.w | add.zw vf08, vf08, vf17 + move.xyzw vf21, vf09 | add.xyzw vf11, vf11, vf18 + iand vi10, vi10, vi05 | add.xyzw vf14, vf14, vf19 + nop | mulax.xyzw ACC, vf04, vf12 + ibgtz vi09, L116 | madday.xyzw ACC, vf05, vf12 + iand vi13, vi13, vi05 | maddaz.xyzw ACC, vf06, vf12 + nop | addx.w vf21, vf21, vf17 +L116: + ibne vi05, vi10, L117 | maddw.xyzw vf12, vf07, vf00 + ilw.x vi09, -9(vi01) | mul.xyz vf10, vf10, Q + mtir vi10, vf11.x | mul.xyzw vf16, vf16, Q + mtir vi13, vf11.y | ftoi4.xyzw vf21, vf21 + b L118 | mul.xyzw vf12, vf12, vf23 + lqi.xyzw vf23, vi03 | add.xyzw vf10, vf10, vf22 +L117: + lq.xyzw vf20, 0(vi10) | mul.xyzw vf16, vf16, Q + lq.xyzw vf25, 0(vi13) | ftoi4.xyzw vf21, vf21 + lq.xyzw vf23, 1(vi10) | mul.xyzw vf12, vf12, vf23 + lq.xyzw vf26, 1(vi13) | add.xyzw vf10, vf10, vf22 + lq.xyzw vf20, 2(vi10) | mulaz.xyzw ACC, vf20, vf24 + lq.xyzw vf27, 2(vi13) | maddw.xyzw vf25, vf25, vf24 + lq.xyzw vf23, 3(vi10) | mulaz.xyzw ACC, vf23, vf24 + lq.xyzw vf28, 3(vi13) | maddw.xyzw vf26, vf26, vf24 + lq.xyzw vf20, 4(vi10) | mulaz.xyzw ACC, vf20, vf24 + lq.xyz vf29, 4(vi13) | maddw.xyzw vf27, vf27, vf24 + lq.xyzw vf23, 5(vi10) | mulaz.xyzw ACC, vf23, vf24 + lq.xyz vf30, 5(vi13) | maddw.xyzw vf28, vf28, vf24 + lq.xyzw vf20, 6(vi10) | mulaz.xyzw ACC, vf20, vf24 + lq.xyzw vf31, 6(vi13) | maddw.xyz vf29, vf29, vf24 + lqi.xyzw vf23, vi02 | mulaz.xyzw ACC, vf23, vf24 + mtir vi10, vf11.x | maddw.xyz vf30, vf30, vf24 + mtir vi13, vf11.y | mulaz.xyzw ACC, vf20, vf24 + b L103 | maddw.xyzw vf31, vf31, vf24 + lqi.xyzw vf23, vi03 | itof0.xyzw vf24, vf23 +L118: + ibgez vi09, L119 | mulaz.xyzw ACC, vf29, vf08 + sq.xyzw vf21, 2(vi11) | maddaz.xyzw ACC, vf30, vf11 + nop | ftoi4.xyzw vf21, vf09 +L119: + mfp.w vf20, P | maddz.xyz vf11, vf31, vf14 + sq.xyzw vf15, 0(vi11) | miniy.xyzw vf12, vf12, vf17 + sq.xyzw vf15, 0(vi14) | miniw.w vf10, vf10, vf03 + sq.xyzw vf21, 2(vi14) | mulaw.xyzw ACC, vf25, vf08 + ilw.y vi09, -6(vi01) | mulw.xyzw vf13, vf13, vf20 + 1024.0 | ftoi0.xyzw vf12, vf12 :i + erleng.xyz P, vf11 | maxi.xy vf10, vf10, I + ibne vi06, vi03, L120 | maddaw.xyzw ACC, vf26, vf11 + mr32.z vf14, vf00 | maddw.xyzw vf08, vf27, vf14 + ibne vi07, vi03, L138 | nop + nop | nop + b L153 | nop + nop | nop +L120: + 3072.0 | mulax.xyzw ACC, vf01, vf13 :i + lqi.xyzw vf09, vi01 | minii.xy vf10, vf10, I + sq.xyzw vf12, 1(vi11) | madday.xyzw ACC, vf02, vf13 + sq.xyzw vf12, 1(vi14) | maddz.xyzw vf13, vf03, vf13 + lqi.xyzw vf12, vi01 | add.xyzw vf08, vf08, vf28 + lqi.xyzw vf15, vi01 | maxw.w vf10, vf10, vf02 + mtir vi11, vf09.x | itof0.xyzw vf23, vf23 + mtir vi14, vf09.y | maxx.xyzw vf13, vf13, vf00 + nop | miniw.w vf08, vf08, vf01 + div Q, vf01.w, vf08.w | add.zw vf09, vf09, vf17 + move.xyzw vf21, vf10 | add.xyzw vf12, vf12, vf18 + iand vi11, vi11, vi05 | add.xyzw vf15, vf15, vf19 + nop | mulax.xyzw ACC, vf04, vf13 + ibgtz vi09, L121 | madday.xyzw ACC, vf05, vf13 + iand vi14, vi14, vi05 | maddaz.xyzw ACC, vf06, vf13 + nop | addx.w vf21, vf21, vf17 +L121: + ibne vi05, vi11, L122 | maddw.xyzw vf13, vf07, vf00 + ilw.x vi09, -9(vi01) | mul.xyz vf08, vf08, Q + mtir vi11, vf12.x | mul.xyzw vf14, vf14, Q + mtir vi14, vf12.y | ftoi4.xyzw vf21, vf21 + b L123 | mul.xyzw vf13, vf13, vf23 + lqi.xyzw vf23, vi03 | add.xyzw vf08, vf08, vf22 +L122: + lq.xyzw vf20, 0(vi11) | mul.xyzw vf14, vf14, Q + lq.xyzw vf25, 0(vi14) | ftoi4.xyzw vf21, vf21 + lq.xyzw vf23, 1(vi11) | mul.xyzw vf13, vf13, vf23 + lq.xyzw vf26, 1(vi14) | add.xyzw vf08, vf08, vf22 + lq.xyzw vf20, 2(vi11) | mulaz.xyzw ACC, vf20, vf24 + lq.xyzw vf27, 2(vi14) | maddw.xyzw vf25, vf25, vf24 + lq.xyzw vf23, 3(vi11) | mulaz.xyzw ACC, vf23, vf24 + lq.xyzw vf28, 3(vi14) | maddw.xyzw vf26, vf26, vf24 + lq.xyzw vf20, 4(vi11) | mulaz.xyzw ACC, vf20, vf24 + lq.xyz vf29, 4(vi14) | maddw.xyzw vf27, vf27, vf24 + lq.xyzw vf23, 5(vi11) | mulaz.xyzw ACC, vf23, vf24 + lq.xyz vf30, 5(vi14) | maddw.xyzw vf28, vf28, vf24 + lq.xyzw vf20, 6(vi11) | mulaz.xyzw ACC, vf20, vf24 + lq.xyzw vf31, 6(vi14) | maddw.xyz vf29, vf29, vf24 + lqi.xyzw vf23, vi02 | mulaz.xyzw ACC, vf23, vf24 + mtir vi11, vf12.x | maddw.xyz vf30, vf30, vf24 + mtir vi14, vf12.y | mulaz.xyzw ACC, vf20, vf24 + b L108 | maddw.xyzw vf31, vf31, vf24 + lqi.xyzw vf23, vi03 | itof0.xyzw vf24, vf23 +L123: + ibgez vi09, L124 | mulaz.xyzw ACC, vf29, vf09 + sq.xyzw vf21, 2(vi12) | maddaz.xyzw ACC, vf30, vf12 + nop | ftoi4.xyzw vf21, vf10 +L124: + mfp.w vf20, P | maddz.xyz vf12, vf31, vf15 + sq.xyzw vf16, 0(vi12) | miniy.xyzw vf13, vf13, vf17 + sq.xyzw vf16, 0(vi15) | miniw.w vf08, vf08, vf03 + sq.xyzw vf21, 2(vi15) | mulaw.xyzw ACC, vf25, vf09 + ilw.y vi09, -6(vi01) | mulw.xyzw vf11, vf11, vf20 + 1024.0 | ftoi0.xyzw vf13, vf13 :i + erleng.xyz P, vf12 | maxi.xy vf08, vf08, I + ibne vi06, vi03, L110 | maddaw.xyzw ACC, vf26, vf12 + mr32.z vf15, vf00 | maddw.xyzw vf09, vf27, vf15 + ibne vi07, vi03, L133 | nop + nop | nop + b L163 | nop + nop | nop +L125: + erleng.xyz P, vf12 | maxi.xy vf08, vf08, I + 3072.0 | nop :i + nop | minii.xy vf08, vf08, I + nop | maddaw.xyzw ACC, vf26, vf12 + mr32.z vf15, vf00 | maddw.xyzw vf09, vf27, vf15 +L126: + lqi.xyzw vf10, vi01 | mulax.xyzw ACC, vf01, vf11 + b L128 | madday.xyzw ACC, vf02, vf11 + nop | maddz.xyzw vf11, vf03, vf11 +L127: + 3072.0 | mulax.xyzw ACC, vf01, vf11 :i + lqi.xyzw vf10, vi01 | minii.xy vf08, vf08, I + sq.xyzw vf13, 1(vi12) | madday.xyzw ACC, vf02, vf11 + sq.xyzw vf13, 1(vi15) | maddz.xyzw vf11, vf03, vf11 +L128: + lqi.xyzw vf13, vi01 | add.xyzw vf09, vf09, vf28 + lqi.xyzw vf16, vi01 | maxw.w vf08, vf08, vf02 + mtir vi12, vf10.x | itof0.xyzw vf23, vf23 + mtir vi15, vf10.y | maxx.xyzw vf11, vf11, vf00 + nop | miniw.w vf09, vf09, vf01 + div Q, vf01.w, vf09.w | add.zw vf10, vf10, vf17 + move.xyzw vf21, vf08 | add.xyzw vf13, vf13, vf18 + iand vi12, vi12, vi05 | add.xyzw vf16, vf16, vf19 + ilw.w vi08, -1(vi02) | mulax.xyzw ACC, vf04, vf11 + ibgtz vi09, L129 | madday.xyzw ACC, vf05, vf11 + iand vi15, vi15, vi05 | maddaz.xyzw ACC, vf06, vf11 + nop | addx.w vf21, vf21, vf17 +L129: + ibne vi05, vi12, L130 | maddw.xyzw vf11, vf07, vf00 + ilw.x vi09, -9(vi01) | mul.xyz vf09, vf09, Q + mtir vi12, vf13.x | mul.xyzw vf15, vf15, Q + mtir vi15, vf13.y | ftoi4.xyzw vf21, vf21 + b L131 | mul.xyzw vf11, vf11, vf23 + lqi.xyzw vf23, vi03 | add.xyzw vf09, vf09, vf22 +L130: + lq.xyzw vf20, 0(vi12) | mul.xyzw vf15, vf15, Q + nop | mulw.xyzw vf24, vf24, vf29 + lq.xyzw vf31, 0(vi15) | ftoi4.xyzw vf21, vf21 + lq.xyzw vf25, 0(vi08) | mul.xyzw vf11, vf11, vf23 + lq.xyzw vf23, 1(vi12) | add.xyzw vf09, vf09, vf22 + lq.xyzw vf20, 1(vi15) | mulax.xyzw ACC, vf20, vf24 + lq.xyzw vf26, 1(vi08) | madday.xyzw ACC, vf31, vf24 + lq.xyzw vf31, 2(vi12) | maddz.xyzw vf25, vf25, vf24 + lq.xyzw vf23, 2(vi15) | mulax.xyzw ACC, vf23, vf24 + lq.xyzw vf27, 2(vi08) | madday.xyzw ACC, vf20, vf24 + lq.xyzw vf20, 3(vi12) | maddz.xyzw vf26, vf26, vf24 + lq.xyzw vf31, 3(vi15) | mulax.xyzw ACC, vf31, vf24 + lq.xyzw vf28, 3(vi08) | madday.xyzw ACC, vf23, vf24 + lq.xyzw vf23, 4(vi12) | maddz.xyzw vf27, vf27, vf24 + lq.xyzw vf20, 4(vi15) | mulax.xyzw ACC, vf20, vf24 + lq.xyz vf29, 4(vi08) | madday.xyzw ACC, vf31, vf24 + lq.xyzw vf31, 5(vi12) | maddz.xyzw vf28, vf28, vf24 + lq.xyzw vf23, 5(vi15) | mulax.xyzw ACC, vf23, vf24 + lq.xyz vf30, 5(vi08) | madday.xyzw ACC, vf20, vf24 + lq.xyzw vf20, 6(vi12) | maddz.xyz vf29, vf29, vf24 + lq.xyzw vf22, 6(vi15) | mulax.xyzw ACC, vf31, vf24 + lq.xyzw vf31, 6(vi08) | madday.xyzw ACC, vf23, vf24 + lqi.xyzw vf23, vi02 | maddz.xyz vf30, vf30, vf24 + mtir vi12, vf13.x | mulax.xyzw ACC, vf20, vf24 + mtir vi15, vf13.y | madday.xyzw ACC, vf22, vf24 + lq.xyzw vf22, 2(vi00) | maddz.xyzw vf31, vf31, vf24 + lqi.xyzw vf23, vi03 | itof0.xyzw vf24, vf23 +L131: + ibgez vi09, L132 | mulaz.xyzw ACC, vf29, vf10 + sq.xyzw vf21, 2(vi10) | maddaz.xyzw ACC, vf30, vf13 + nop | ftoi4.xyzw vf21, vf08 +L132: + mfp.w vf20, P | maddz.xyz vf13, vf31, vf16 + sq.xyzw vf14, 0(vi10) | miniy.xyzw vf11, vf11, vf17 + sq.xyzw vf14, 0(vi13) | miniw.w vf09, vf09, vf03 + sq.xyzw vf21, 2(vi13) | mulaw.xyzw ACC, vf25, vf10 + ilw.y vi09, -6(vi01) | mulw.xyzw vf12, vf12, vf20 + 1024.0 | ftoi0.xyzw vf11, vf11 :i + erleng.xyz P, vf13 | maxi.xy vf09, vf09, I + ibeq vi07, vi03, L143 | maddaw.xyzw ACC, vf26, vf13 + mr32.z vf16, vf00 | maddw.xyzw vf10, vf27, vf16 +L133: + 3072.0 | mulax.xyzw ACC, vf01, vf12 :i + lqi.xyzw vf08, vi01 | minii.xy vf09, vf09, I + sq.xyzw vf11, 1(vi10) | madday.xyzw ACC, vf02, vf12 + sq.xyzw vf11, 1(vi13) | maddz.xyzw vf12, vf03, vf12 + lqi.xyzw vf11, vi01 | add.xyzw vf10, vf10, vf28 + lqi.xyzw vf14, vi01 | maxw.w vf09, vf09, vf02 + mtir vi10, vf08.x | itof0.xyzw vf23, vf23 + mtir vi13, vf08.y | maxx.xyzw vf12, vf12, vf00 + nop | miniw.w vf10, vf10, vf01 + div Q, vf01.w, vf10.w | add.zw vf08, vf08, vf17 + move.xyzw vf21, vf09 | add.xyzw vf11, vf11, vf18 + iand vi10, vi10, vi05 | add.xyzw vf14, vf14, vf19 + ilw.w vi08, -1(vi02) | mulax.xyzw ACC, vf04, vf12 + ibgtz vi09, L134 | madday.xyzw ACC, vf05, vf12 + iand vi13, vi13, vi05 | maddaz.xyzw ACC, vf06, vf12 + nop | addx.w vf21, vf21, vf17 +L134: + ibne vi05, vi10, L135 | maddw.xyzw vf12, vf07, vf00 + ilw.x vi09, -9(vi01) | mul.xyz vf10, vf10, Q + mtir vi10, vf11.x | mul.xyzw vf16, vf16, Q + mtir vi13, vf11.y | ftoi4.xyzw vf21, vf21 + b L136 | mul.xyzw vf12, vf12, vf23 + lqi.xyzw vf23, vi03 | add.xyzw vf10, vf10, vf22 +L135: + lq.xyzw vf20, 0(vi10) | mul.xyzw vf16, vf16, Q + nop | mulw.xyzw vf24, vf24, vf29 + lq.xyzw vf31, 0(vi13) | ftoi4.xyzw vf21, vf21 + lq.xyzw vf25, 0(vi08) | mul.xyzw vf12, vf12, vf23 + lq.xyzw vf23, 1(vi10) | add.xyzw vf10, vf10, vf22 + lq.xyzw vf20, 1(vi13) | mulax.xyzw ACC, vf20, vf24 + lq.xyzw vf26, 1(vi08) | madday.xyzw ACC, vf31, vf24 + lq.xyzw vf31, 2(vi10) | maddz.xyzw vf25, vf25, vf24 + lq.xyzw vf23, 2(vi13) | mulax.xyzw ACC, vf23, vf24 + lq.xyzw vf27, 2(vi08) | madday.xyzw ACC, vf20, vf24 + lq.xyzw vf20, 3(vi10) | maddz.xyzw vf26, vf26, vf24 + lq.xyzw vf31, 3(vi13) | mulax.xyzw ACC, vf31, vf24 + lq.xyzw vf28, 3(vi08) | madday.xyzw ACC, vf23, vf24 + lq.xyzw vf23, 4(vi10) | maddz.xyzw vf27, vf27, vf24 + lq.xyzw vf20, 4(vi13) | mulax.xyzw ACC, vf20, vf24 + lq.xyz vf29, 4(vi08) | madday.xyzw ACC, vf31, vf24 + lq.xyzw vf31, 5(vi10) | maddz.xyzw vf28, vf28, vf24 + lq.xyzw vf23, 5(vi13) | mulax.xyzw ACC, vf23, vf24 + lq.xyz vf30, 5(vi08) | madday.xyzw ACC, vf20, vf24 + lq.xyzw vf20, 6(vi10) | maddz.xyz vf29, vf29, vf24 + lq.xyzw vf22, 6(vi13) | mulax.xyzw ACC, vf31, vf24 + lq.xyzw vf31, 6(vi08) | madday.xyzw ACC, vf23, vf24 + lqi.xyzw vf23, vi02 | maddz.xyz vf30, vf30, vf24 + mtir vi10, vf11.x | mulax.xyzw ACC, vf20, vf24 + mtir vi13, vf11.y | madday.xyzw ACC, vf22, vf24 + lq.xyzw vf22, 2(vi00) | maddz.xyzw vf31, vf31, vf24 + lqi.xyzw vf23, vi03 | itof0.xyzw vf24, vf23 +L136: + ibgez vi09, L137 | mulaz.xyzw ACC, vf29, vf08 + sq.xyzw vf21, 2(vi11) | maddaz.xyzw ACC, vf30, vf11 + nop | ftoi4.xyzw vf21, vf09 +L137: + mfp.w vf20, P | maddz.xyz vf11, vf31, vf14 + sq.xyzw vf15, 0(vi11) | miniy.xyzw vf12, vf12, vf17 + sq.xyzw vf15, 0(vi14) | miniw.w vf10, vf10, vf03 + sq.xyzw vf21, 2(vi14) | mulaw.xyzw ACC, vf25, vf08 + ilw.y vi09, -6(vi01) | mulw.xyzw vf13, vf13, vf20 + 1024.0 | ftoi0.xyzw vf12, vf12 :i + erleng.xyz P, vf11 | maxi.xy vf10, vf10, I + ibeq vi07, vi03, L153 | maddaw.xyzw ACC, vf26, vf11 + mr32.z vf14, vf00 | maddw.xyzw vf08, vf27, vf14 +L138: + 3072.0 | mulax.xyzw ACC, vf01, vf13 :i + lqi.xyzw vf09, vi01 | minii.xy vf10, vf10, I + sq.xyzw vf12, 1(vi11) | madday.xyzw ACC, vf02, vf13 + sq.xyzw vf12, 1(vi14) | maddz.xyzw vf13, vf03, vf13 + lqi.xyzw vf12, vi01 | add.xyzw vf08, vf08, vf28 + lqi.xyzw vf15, vi01 | maxw.w vf10, vf10, vf02 + mtir vi11, vf09.x | itof0.xyzw vf23, vf23 + mtir vi14, vf09.y | maxx.xyzw vf13, vf13, vf00 + nop | miniw.w vf08, vf08, vf01 + div Q, vf01.w, vf08.w | add.zw vf09, vf09, vf17 + move.xyzw vf21, vf10 | add.xyzw vf12, vf12, vf18 + iand vi11, vi11, vi05 | add.xyzw vf15, vf15, vf19 + ilw.w vi08, -1(vi02) | mulax.xyzw ACC, vf04, vf13 + ibgtz vi09, L139 | madday.xyzw ACC, vf05, vf13 + iand vi14, vi14, vi05 | maddaz.xyzw ACC, vf06, vf13 + nop | addx.w vf21, vf21, vf17 +L139: + ibne vi05, vi11, L140 | maddw.xyzw vf13, vf07, vf00 + ilw.x vi09, -9(vi01) | mul.xyz vf08, vf08, Q + mtir vi11, vf12.x | mul.xyzw vf14, vf14, Q + mtir vi14, vf12.y | ftoi4.xyzw vf21, vf21 + b L141 | mul.xyzw vf13, vf13, vf23 + lqi.xyzw vf23, vi03 | add.xyzw vf08, vf08, vf22 +L140: + lq.xyzw vf20, 0(vi11) | mul.xyzw vf14, vf14, Q + nop | mulw.xyzw vf24, vf24, vf29 + lq.xyzw vf31, 0(vi14) | ftoi4.xyzw vf21, vf21 + lq.xyzw vf25, 0(vi08) | mul.xyzw vf13, vf13, vf23 + lq.xyzw vf23, 1(vi11) | add.xyzw vf08, vf08, vf22 + lq.xyzw vf20, 1(vi14) | mulax.xyzw ACC, vf20, vf24 + lq.xyzw vf26, 1(vi08) | madday.xyzw ACC, vf31, vf24 + lq.xyzw vf31, 2(vi11) | maddz.xyzw vf25, vf25, vf24 + lq.xyzw vf23, 2(vi14) | mulax.xyzw ACC, vf23, vf24 + lq.xyzw vf27, 2(vi08) | madday.xyzw ACC, vf20, vf24 + lq.xyzw vf20, 3(vi11) | maddz.xyzw vf26, vf26, vf24 + lq.xyzw vf31, 3(vi14) | mulax.xyzw ACC, vf31, vf24 + lq.xyzw vf28, 3(vi08) | madday.xyzw ACC, vf23, vf24 + lq.xyzw vf23, 4(vi11) | maddz.xyzw vf27, vf27, vf24 + lq.xyzw vf20, 4(vi14) | mulax.xyzw ACC, vf20, vf24 + lq.xyz vf29, 4(vi08) | madday.xyzw ACC, vf31, vf24 + lq.xyzw vf31, 5(vi11) | maddz.xyzw vf28, vf28, vf24 + lq.xyzw vf23, 5(vi14) | mulax.xyzw ACC, vf23, vf24 + lq.xyz vf30, 5(vi08) | madday.xyzw ACC, vf20, vf24 + lq.xyzw vf20, 6(vi11) | maddz.xyz vf29, vf29, vf24 + lq.xyzw vf22, 6(vi14) | mulax.xyzw ACC, vf31, vf24 + lq.xyzw vf31, 6(vi08) | madday.xyzw ACC, vf23, vf24 + lqi.xyzw vf23, vi02 | maddz.xyz vf30, vf30, vf24 + mtir vi11, vf12.x | mulax.xyzw ACC, vf20, vf24 + mtir vi14, vf12.y | madday.xyzw ACC, vf22, vf24 + lq.xyzw vf22, 2(vi00) | maddz.xyzw vf31, vf31, vf24 + lqi.xyzw vf23, vi03 | itof0.xyzw vf24, vf23 +L141: + ibgez vi09, L142 | mulaz.xyzw ACC, vf29, vf09 + sq.xyzw vf21, 2(vi12) | maddaz.xyzw ACC, vf30, vf12 + nop | ftoi4.xyzw vf21, vf10 +L142: + mfp.w vf20, P | maddz.xyz vf12, vf31, vf15 + sq.xyzw vf16, 0(vi12) | miniy.xyzw vf13, vf13, vf17 + sq.xyzw vf16, 0(vi15) | miniw.w vf08, vf08, vf03 + sq.xyzw vf21, 2(vi15) | mulaw.xyzw ACC, vf25, vf09 + ilw.y vi09, -6(vi01) | mulw.xyzw vf11, vf11, vf20 + 1024.0 | ftoi0.xyzw vf13, vf13 :i + erleng.xyz P, vf12 | maxi.xy vf08, vf08, I + ibne vi07, vi03, L127 | maddaw.xyzw ACC, vf26, vf12 + mr32.z vf15, vf00 | maddw.xyzw vf09, vf27, vf15 + b L163 | nop + nop | nop +L143: ;; exit cross 1 + ilw.w vi08, 1(vi00) | nop ;; vi08 = mercprime flag + xtop vi02 | mulax.xyzw ACC, vf01, vf12 ;; vi02 = out (0) | pipe + sq.xyzw vf11, 1(vi10) | madday.xyzw ACC, vf02, vf12 ;; pipe | pipe + sq.xyzw vf11, 1(vi13) | maddz.xyzw vf12, vf03, vf12 ;; pipe | pipe + iaddiu vi04, vi02, 0x8c | add.xyzw vf10, vf10, vf28 ;; vi04 = 140 (byte header) | pipe + ilwr.x vi05, vi04 | maxw.w vf09, vf09, vf02 ;; vi05 = srcdest-off | pipe + ilw.w vi06, 1(vi04) | itof0.xyzw vf23, vf23 ;; vi06 = samecopy-cnt | pipe + ibne vi00, vi08, L151 | nop ;; goto L151 if merc prime (just a detour to set constants). + ilw.x vi07, 2(vi04) | maxx.xyzw vf12, vf12, vf00 ;; vi07 = crosscopy-cnt | pipe +L144: + div Q, vf01.w, vf10.w | minix.xyzw vf25, vf00, vf00 ;; pipe | vf25 = 0 + move.xyzw vf21, vf09 | minix.xyzw vf26, vf00, vf00 ;; pipe | vf26 = 0 + iadd vi05, vi05, vi04 | nop ;; vi05 = srcdest table addr + iaddiu vi04, vi02, 0x173 | mulax.xyzw ACC, vf04, vf12 ;; vi04 = "output zone" | pipe + ibgtz vi09, L145 | madday.xyzw ACC, vf05, vf12 ;; pipe | pipe + iadd vi06, vi06, vi05 | maddaz.xyzw ACC, vf06, vf12 ;; vi06 = cross copy table | pipe + nop | addx.w vf21, vf21, vf17 ;; pipe | pipe +L145: + iadd vi07, vi07, vi06 | maddw.xyzw vf12, vf07, vf00 ;; vi07 = end cross copy table | pipe + ilw.x vi09, -6(vi01) | mul.xyz vf10, vf10, Q ;; ?????? | pipe + iaddiu vi08, vi00, 0x1ba | mul.xyzw vf16, vf16, Q ;; vi08 = 442 | pipe + isub vi08, vi08, vi02 | ftoi4.xyzw vf21, vf21 ;; vi08 is the other buffer | pipe + iaddiu vi08, vi08, 0x173 | mul.xyzw vf12, vf12, vf23 ;; vi08 is the other buffer | pipe + lqi.xyzw vf23, vi03 | add.xyzw vf10, vf10, vf22 ;; pipe | pipe + ibgez vi09, L146 | nop ;; pipe (but weird, not applicable for mat1, but still works) + sq.xyzw vf21, 2(vi11) | nop ;; pipe + nop | ftoi4.xyzw vf21, vf09 ;; pipe (slightly wrong for mat1, but might not matter?) +L146: + mfp.w vf20, P | nop ;; pipe + sq.xyzw vf15, 0(vi11) | miniy.xyzw vf12, vf12, vf17 ;; pipe + sq.xyzw vf15, 0(vi14) | miniw.w vf10, vf10, vf03 ;; pipe + sq.xyzw vf21, 2(vi14) | nop ;; pipe + ilw.y vi09, -3(vi01) | mulw.xyzw vf13, vf13, vf20 ;; werid pipe | pipe + mfir.x vf25, vi04 | ftoi0.xyzw vf12, vf12 ;; vf25.x = output zone | pipe + mfir.y vf25, vi04 | nop ;; vf25.y = output zone + mfir.x vf26, vi08 | nop ;; vf26.x = old output zone + ilw.w vi02, 1(vi00) | nop ;; vi02 = mercprime flag + mfir.y vf26, vi04 | mulax.xyzw ACC, vf01, vf13 ;; vf26.y = output zone | pipe + sq.xyzw vf12, 1(vi11) | madday.xyzw ACC, vf02, vf13 ;; pipe | pipe + sq.xyzw vf12, 1(vi14) | maddz.xyzw vf13, vf03, vf13 ;; pipe | pipe + nop | nop ;; ? why the nop ? + ibne vi00, vi02, L152 | maxw.w vf10, vf10, vf02 ;; mercprime detour | pipe + nop | itof0.xyzw vf23, vf23 ;; pipe +L147: + 8388608.0 | maxx.xyzw vf13, vf13, vf00 :i ;; vf13 = 0 + 256.0 | maxi.xy vf27, vf00, I :i ;; vf27.xy = 8388608.0 + move.xyzw vf21, vf10 | maxi.w vf27, vf00, I ;; pipe | vf27.w = 256.0 + nop | nop ;; ?? + nop | mulax.xyzw ACC, vf04, vf13 ;; pipe + ibgtz vi09, L148 | madday.xyzw ACC, vf05, vf13 ;; pipe | pipe + nop | maddaz.xyzw ACC, vf06, vf13 ;; pipe + nop | addx.w vf21, vf21, vf17 ;; pipe +L148: + nop | maddw.xyzw vf13, vf07, vf00 ;; pipe + ilw.x vi09, -3(vi01) | itof0.xyzw vf25, vf25 ;; pipe | zone addrs to float + nop | itof0.xyzw vf26, vf26 ;; zone addrs to float + nop | ftoi4.xyzw vf21, vf21 ;; pipe + nop | mul.xyzw vf13, vf13, vf23 ;; pipe + ior vi02, vi05, vi00 | add.xyzw vf25, vf25, vf27 ;; vi02 = srcdst table | float trick + ibgez vi09, L149 | add.xyzw vf26, vf26, vf27 ;; pipe | float trick + sq.xyzw vf21, 2(vi12) | nop ;; pipe + nop | ftoi4.xyzw vf21, vf10 ;; pipe +L149: + ibne vi06, vi05, L150 | nop + sq.xyzw vf16, 0(vi12) | miniy.xyzw vf13, vf13, vf17 + ior vi06, vi07, vi00 | max.xyzw vf25, vf26, vf26 +L150: + sq.xyzw vf16, 0(vi15) | nop ;; pipe + sq.xyzw vf21, 2(vi15) | nop ;; pipe + lqi.xyzw vf27, vi05 | nop + nop | ftoi0.xyzw vf13, vf13 ;; pipe + nop | nop + nop | nop + nop | itof0.xyzw vf27, vf27 + sq.xyzw vf13, 1(vi12) | nop ;; pipe + b L173 | nop + sq.xyzw vf13, 1(vi15) | nop ;; pipe +L151: + 3072.0 | miniw.w vf10, vf10, vf01 :i + b L144 | minii.xy vf09, vf09, I + nop | nop +L152: + 1024.0 | nop :i + 3072.0 | maxi.xy vf10, vf10, I :i + b L147 | minii.xy vf10, vf10, I + isw.w vi00, 1(vi00) | nop + +L153: ;; exit cross 2 + ilw.w vi08, 1(vi00) | nop + xtop vi02 | mulax.xyzw ACC, vf01, vf13 + sq.xyzw vf12, 1(vi11) | madday.xyzw ACC, vf02, vf13 + sq.xyzw vf12, 1(vi14) | maddz.xyzw vf13, vf03, vf13 + iaddiu vi04, vi02, 0x8c | add.xyzw vf08, vf08, vf28 + ilwr.x vi05, vi04 | maxw.w vf10, vf10, vf02 + ilw.w vi06, 1(vi04) | itof0.xyzw vf23, vf23 + ibne vi00, vi08, L161 | nop + ilw.x vi07, 2(vi04) | maxx.xyzw vf13, vf13, vf00 +L154: + div Q, vf01.w, vf08.w | minix.xyzw vf25, vf00, vf00 + move.xyzw vf21, vf10 | minix.xyzw vf26, vf00, vf00 + iadd vi05, vi05, vi04 | nop + iaddiu vi04, vi02, 0x173 | mulax.xyzw ACC, vf04, vf13 + ibgtz vi09, L155 | madday.xyzw ACC, vf05, vf13 + iadd vi06, vi06, vi05 | maddaz.xyzw ACC, vf06, vf13 + nop | addx.w vf21, vf21, vf17 +L155: + iadd vi07, vi07, vi06 | maddw.xyzw vf13, vf07, vf00 + ilw.x vi09, -6(vi01) | mul.xyz vf08, vf08, Q + iaddiu vi08, vi00, 0x1ba | mul.xyzw vf14, vf14, Q + isub vi08, vi08, vi02 | ftoi4.xyzw vf21, vf21 + iaddiu vi08, vi08, 0x173 | mul.xyzw vf13, vf13, vf23 + lqi.xyzw vf23, vi03 | add.xyzw vf08, vf08, vf22 + ibgez vi09, L156 | nop + sq.xyzw vf21, 2(vi12) | nop + nop | ftoi4.xyzw vf21, vf10 +L156: + mfp.w vf20, P | nop + sq.xyzw vf16, 0(vi12) | miniy.xyzw vf13, vf13, vf17 + sq.xyzw vf16, 0(vi15) | miniw.w vf08, vf08, vf03 + sq.xyzw vf21, 2(vi15) | nop + ilw.y vi09, -3(vi01) | mulw.xyzw vf11, vf11, vf20 + mfir.x vf25, vi04 | ftoi0.xyzw vf13, vf13 + mfir.y vf25, vi04 | nop + mfir.x vf26, vi08 | nop + ilw.w vi02, 1(vi00) | nop + mfir.y vf26, vi04 | mulax.xyzw ACC, vf01, vf11 + sq.xyzw vf13, 1(vi12) | madday.xyzw ACC, vf02, vf11 + sq.xyzw vf13, 1(vi15) | maddz.xyzw vf11, vf03, vf11 + nop | nop + ibne vi00, vi02, L162 | maxw.w vf08, vf08, vf02 + nop | itof0.xyzw vf23, vf23 +L157: + 8388608.0 | maxx.xyzw vf11, vf11, vf00 :i + 256.0 | maxi.xy vf27, vf00, I :i + move.xyzw vf21, vf08 | maxi.w vf27, vf00, I + nop | nop + nop | mulax.xyzw ACC, vf04, vf11 + ibgtz vi09, L158 | madday.xyzw ACC, vf05, vf11 + nop | maddaz.xyzw ACC, vf06, vf11 + nop | addx.w vf21, vf21, vf17 +L158: + nop | maddw.xyzw vf11, vf07, vf00 + ilw.x vi09, -3(vi01) | itof0.xyzw vf25, vf25 + nop | itof0.xyzw vf26, vf26 + nop | ftoi4.xyzw vf21, vf21 + nop | mul.xyzw vf11, vf11, vf23 + ior vi02, vi05, vi00 | add.xyzw vf25, vf25, vf27 + ibgez vi09, L159 | add.xyzw vf26, vf26, vf27 + sq.xyzw vf21, 2(vi10) | nop + nop | ftoi4.xyzw vf21, vf08 +L159: + ibne vi06, vi05, L160 | nop + sq.xyzw vf14, 0(vi10) | miniy.xyzw vf11, vf11, vf17 + ior vi06, vi07, vi00 | max.xyzw vf25, vf26, vf26 +L160: + sq.xyzw vf14, 0(vi13) | nop + sq.xyzw vf21, 2(vi13) | nop + lqi.xyzw vf27, vi05 | nop + nop | ftoi0.xyzw vf11, vf11 + nop | nop + nop | nop + nop | itof0.xyzw vf27, vf27 + sq.xyzw vf11, 1(vi10) | nop + b L173 | nop + sq.xyzw vf11, 1(vi13) | nop +L161: + 3072.0 | miniw.w vf08, vf08, vf01 :i + b L154 | minii.xy vf10, vf10, I + nop | nop +L162: + 1024.0 | nop :i + 3072.0 | maxi.xy vf08, vf08, I :i + b L157 | minii.xy vf08, vf08, I + isw.w vi00, 1(vi00) | nop +L163: ;; exit cross 3 + ilw.w vi08, 1(vi00) | nop + xtop vi02 | mulax.xyzw ACC, vf01, vf11 + sq.xyzw vf13, 1(vi12) | madday.xyzw ACC, vf02, vf11 + sq.xyzw vf13, 1(vi15) | maddz.xyzw vf11, vf03, vf11 + iaddiu vi04, vi02, 0x8c | add.xyzw vf09, vf09, vf28 + ilwr.x vi05, vi04 | maxw.w vf08, vf08, vf02 + ilw.w vi06, 1(vi04) | itof0.xyzw vf23, vf23 + ibne vi00, vi08, L171 | nop + ilw.x vi07, 2(vi04) | maxx.xyzw vf11, vf11, vf00 +L164: + div Q, vf01.w, vf09.w | minix.xyzw vf25, vf00, vf00 + move.xyzw vf21, vf08 | minix.xyzw vf26, vf00, vf00 + iadd vi05, vi05, vi04 | nop + iaddiu vi04, vi02, 0x173 | mulax.xyzw ACC, vf04, vf11 + ibgtz vi09, L165 | madday.xyzw ACC, vf05, vf11 + iadd vi06, vi06, vi05 | maddaz.xyzw ACC, vf06, vf11 + nop | addx.w vf21, vf21, vf17 +L165: + iadd vi07, vi07, vi06 | maddw.xyzw vf11, vf07, vf00 + ilw.x vi09, -6(vi01) | mul.xyz vf09, vf09, Q + iaddiu vi08, vi00, 0x1ba | mul.xyzw vf15, vf15, Q + isub vi08, vi08, vi02 | ftoi4.xyzw vf21, vf21 + iaddiu vi08, vi08, 0x173 | mul.xyzw vf11, vf11, vf23 + lqi.xyzw vf23, vi03 | add.xyzw vf09, vf09, vf22 + ibgez vi09, L166 | nop + sq.xyzw vf21, 2(vi10) | nop + nop | ftoi4.xyzw vf21, vf08 +L166: + mfp.w vf20, P | nop + sq.xyzw vf14, 0(vi10) | miniy.xyzw vf11, vf11, vf17 + sq.xyzw vf14, 0(vi13) | miniw.w vf09, vf09, vf03 + sq.xyzw vf21, 2(vi13) | nop + ilw.y vi09, -3(vi01) | mulw.xyzw vf12, vf12, vf20 + mfir.x vf25, vi04 | ftoi0.xyzw vf11, vf11 + mfir.y vf25, vi04 | nop + mfir.x vf26, vi08 | nop + ilw.w vi02, 1(vi00) | nop + mfir.y vf26, vi04 | mulax.xyzw ACC, vf01, vf12 + sq.xyzw vf11, 1(vi10) | madday.xyzw ACC, vf02, vf12 + sq.xyzw vf11, 1(vi13) | maddz.xyzw vf12, vf03, vf12 + nop | nop + ibne vi00, vi02, L172 | maxw.w vf09, vf09, vf02 + nop | itof0.xyzw vf23, vf23 +L167: + 8388608.0 | maxx.xyzw vf12, vf12, vf00 :i + 256.0 | maxi.xy vf27, vf00, I :i + move.xyzw vf21, vf09 | maxi.w vf27, vf00, I + nop | nop + nop | mulax.xyzw ACC, vf04, vf12 + ibgtz vi09, L168 | madday.xyzw ACC, vf05, vf12 + nop | maddaz.xyzw ACC, vf06, vf12 + nop | addx.w vf21, vf21, vf17 +L168: + nop | maddw.xyzw vf12, vf07, vf00 + ilw.x vi09, -3(vi01) | itof0.xyzw vf25, vf25 + nop | itof0.xyzw vf26, vf26 + nop | ftoi4.xyzw vf21, vf21 + nop | mul.xyzw vf12, vf12, vf23 + ior vi02, vi05, vi00 | add.xyzw vf25, vf25, vf27 + ibgez vi09, L169 | add.xyzw vf26, vf26, vf27 + sq.xyzw vf21, 2(vi11) | nop + nop | ftoi4.xyzw vf21, vf09 +L169: + ibne vi06, vi05, L170 | nop + sq.xyzw vf15, 0(vi11) | miniy.xyzw vf12, vf12, vf17 + ior vi06, vi07, vi00 | max.xyzw vf25, vf26, vf26 +L170: + sq.xyzw vf15, 0(vi14) | nop + sq.xyzw vf21, 2(vi14) | nop + lqi.xyzw vf27, vi05 | nop + nop | ftoi0.xyzw vf12, vf12 + nop | nop + nop | nop + nop | itof0.xyzw vf27, vf27 + sq.xyzw vf12, 1(vi11) | nop + b L173 | nop + sq.xyzw vf12, 1(vi14) | nop +L171: + 3072.0 | miniw.w vf09, vf09, vf01 :i + b L164 | minii.xy vf08, vf08, I + nop | nop +L172: + 1024.0 | nop :i + 3072.0 | maxi.xy vf09, vf09, I :i + b L167 | minii.xy vf09, vf09, I + isw.w vi00, 1(vi00) | nop + +;; end routine. +L173: + ibeq vi07, vi02, L179 | nop + ilw.w vi15, 132(vi00) | nop + ibne vi06, vi05, L174 | add.xyzw vf11, vf27, vf25 + nop | nop + ibne vi07, vi06, L174 | nop + ior vi06, vi07, vi00 | max.xyzw vf25, vf26, vf26 + nop | nop + nop | nop + mtir vi08, vf11.x | nop + mtir vi10, vf11.y | nop + nop | nop + nop | nop + lq.xyzw vf16, 2(vi08) | maxx.xyzw vf15, vf11, vf00 + lq.xyzw vf13, 0(vi08) | nop + b L178 | nop + nop | nop +L174: + lqi.xyzw vf27, vi05 | nop + nop | nop + mtir vi08, vf11.x | nop + mtir vi09, vf11.y | nop + nop | itof0.xyzw vf27, vf27 + nop | nop + lq.xyzw vf12, 2(vi08) | maxx.xyzw vf15, vf11, vf00 + lq.xyzw vf13, 0(vi08) | nop + ibne vi06, vi05, L175 | add.xyzw vf11, vf27, vf25 + nop | nop + ibeq vi07, vi06, L177 | nop + ior vi06, vi07, vi00 | max.xyzw vf25, vf26, vf26 +L175: + lqi.xyzw vf27, vi05 | itof15.w vf12, vf12 + lq.xyzw vf14, 1(vi08) | nop + mtir vi08, vf11.x | nop + mtir vi10, vf11.y | nop + sq.xyzw vf13, 0(vi09) | itof0.xyzw vf27, vf27 + sq.xyzw vf14, 1(vi09) | add.w vf12, vf12, vf15 + lq.xyzw vf16, 2(vi08) | maxx.xyzw vf15, vf11, vf00 + lq.xyzw vf13, 0(vi08) | nop + ibne vi06, vi05, L176 | add.xyzw vf11, vf27, vf25 + sq.xyzw vf12, 2(vi09) | nop + ibne vi07, vi06, L176 | nop + ior vi06, vi07, vi00 | max.xyzw vf25, vf26, vf26 + move.xyzw vf12, vf16 | nop + b L177 | nop + ior vi09, vi10, vi00 | nop +L176: + lqi.xyzw vf27, vi05 | itof15.w vf16, vf16 + lq.xyzw vf14, 1(vi08) | nop + mtir vi08, vf11.x | nop + mtir vi09, vf11.y | nop + sq.xyzw vf13, 0(vi10) | itof0.xyzw vf27, vf27 + sq.xyzw vf14, 1(vi10) | add.w vf16, vf16, vf15 + lq.xyzw vf12, 2(vi08) | maxx.xyzw vf15, vf11, vf00 + lq.xyzw vf13, 0(vi08) | nop + ibne vi06, vi05, L175 | add.xyzw vf11, vf27, vf25 + sq.xyzw vf16, 2(vi10) | nop + ibne vi07, vi06, L175 | nop + ior vi06, vi07, vi00 | max.xyzw vf25, vf26, vf26 +L177: + nop | itof15.w vf12, vf12 + lq.xyzw vf14, 1(vi08) | nop + mtir vi08, vf11.x | nop + mtir vi10, vf11.y | nop + sq.xyzw vf13, 0(vi09) | nop + sq.xyzw vf14, 1(vi09) | add.w vf12, vf12, vf15 + lq.xyzw vf16, 2(vi08) | maxx.xyzw vf15, vf11, vf00 + lq.xyzw vf13, 0(vi08) | nop + nop | nop + sq.xyzw vf12, 2(vi09) | nop +L178: + nop | itof15.w vf16, vf16 + lq.xyzw vf14, 1(vi08) | nop + nop | nop + nop | nop + sq.xyzw vf13, 0(vi10) | nop + sq.xyzw vf14, 1(vi10) | add.w vf16, vf16, vf15 + nop | nop + nop | nop + nop | nop + sq.xyzw vf16, 2(vi10) | nop +L179: + ibne vi00, vi15, L180 | nop + nop | nop + xgkick vi04 | nop + nop | nop :e + nop | nop +L180: + lq.xyzw vf20, 132(vi00) | nop + lq.xyzw vf21, 1(vi00) | nop + iaddi vi01, vi00, 0x1 | nop + isw.x vi01, -2(vi04) | nop + iaddiu vi02, vi00, 0x47 | maxw.x vf20, vf00, vf20 + isw.z vi02, -1(vi04) | nop + sq.yzw vf21, -2(vi04) | nop + isw.w vi00, 132(vi00) | nop + sq.x vf20, -1(vi04) | nop + iaddi vi04, vi04, -0x2 | nop + xgkick vi04 | nop + nop | nop :e + nop | nop + diff --git a/game/kernel/klink.cpp b/game/kernel/klink.cpp index 38d0b1bcad..89b08be12b 100644 --- a/game/kernel/klink.cpp +++ b/game/kernel/klink.cpp @@ -578,6 +578,9 @@ uint32_t link_control::work_v2() { 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_object_data.offset < m_heap->current.offset) { + ASSERT(false); + } } if (m_heap_gap < diff --git a/game/kernel/kmemcard.cpp b/game/kernel/kmemcard.cpp index be5fcb08f2..6cc253f98f 100644 --- a/game/kernel/kmemcard.cpp +++ b/game/kernel/kmemcard.cpp @@ -853,7 +853,7 @@ u32 MC_check_result() { * You can call this at any time. * The slot includes the four save slots (8 banks), and a few other files. */ -void MC_get_status(s32 slot, Ptr info) { +void MC_get_status(s32 /*slot*/, Ptr info) { // slot is ignored, so you'll get the same thing regardless of what slot you pick info->handle = 0; diff --git a/game/mips2c/functions/bones.cpp b/game/mips2c/functions/bones.cpp index 3a2a91b70c..f4d1f7a9c9 100644 --- a/game/mips2c/functions/bones.cpp +++ b/game/mips2c/functions/bones.cpp @@ -714,20 +714,20 @@ u64 execute(void* ctxt) { c->sq(gp, 112, sp); // sq gp, 112(sp) c->mov64(t8, a3); // or t8, 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->lui(t0, 4096); // lui t0, 4096 0x1000 + c->lui(t1, 18304); // lui t1, 18304 0x4780 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(t7, 19201); // lui t7, 19201 + c->lui(a3, 12288); // lui a3, 12288 0x3000 + c->lui(t7, 19201); // lui t7, 19201 0x4B01 c->pcpyld(t0, a3, t0); // pcpyld t0, a3, t0 c->lbu(a3, 58, a0); // lbu a3, 58(a0) c->pcpyld(t1, t7, t1); // pcpyld t1, t7, t1 - c->lui(t2, 28160); // lui t2, 28160 + c->lui(t2, 28160); // lui t2, 28160 0x6E00 c->addiu(t7, r0, 8); // addiu t7, r0, 8 c->multu3(a3, a3, t7); // multu3 a3, a3, t7 - c->lui(t3, 1280); // lui t3, 1280 - c->lui(t4, 27648); // lui t4, 27648 + c->lui(t3, 1280); // lui t3, 1280 0x500 + c->lui(t4, 27648); // lui t4, 27648 0x6C00 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 @@ -735,11 +735,11 @@ u64 execute(void* ctxt) { 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(t7, 24, a0); // lw t7, 24(a0) + c->lw(t7, 24, a0); // lw t7, 24(a0) // load the merc-ctrl! c->pcpyld(t3, t3, r0); // pcpyld t3, t3, r0 c->pcpyld(t4, t4, r0); // pcpyld t4, t4, r0 c->mov64(a0, a2); // or a0, a2, r0 - c->lui(t5, 12288); // lui t5, 12288 + c->lui(t5, 12288); // lui t5, 12288 // 0x3000 c->lui(t6, 4096); // lui t6, 4096 c->daddiu(t5, t5, 7); // daddiu t5, t5, 7 c->lui(t9, 5120); // lui t9, 5120 @@ -748,144 +748,172 @@ u64 execute(void* ctxt) { c->dsll32(a3, a3, 0); // dsll32 a3, a3, 0 c->dsll32(t9, t8, 0); // dsll32 t9, t8, 0 c->pcpyld(t5, a3, t5); // pcpyld t5, a3, t5 - c->lwu(t8, 52, t7); // lwu t8, 52(t7) + c->lwu(t8, 52, t7); // lwu t8, 52(t7) // effect count. c->pcpyld(t6, t9, t6); // pcpyld t6, t9, t6 - c->daddiu(t9, t7, 108); // daddiu t9, t7, 108 + c->daddiu(t9, t7, 108); // daddiu t9, t7, 108 // the actual merc-effect c->load_symbol(a3, cache.merc_bucket_info); // lw a3, *merc-bucket-info*(s7) - c->daddiu(ra, a3, 124); // daddiu ra, a3, 124 + c->daddiu(ra, a3, 124); // daddiu ra, a3, 124 // effect bucket infos + // effect loop! block_1: - c->lbu(gp, 4, ra); // lbu gp, 4(ra) + c->lbu(gp, 4, ra); // lbu gp, 4(ra) effect.use-mercneric c->load_symbol(a3, cache.merc_global_stats); // lw a3, *merc-global-stats*(s7) c->daddu(a3, r0, a3); // daddu a3, r0, a3 bc = c->sgpr64(gp) != 0; // bne gp, r0, L77 - c->lhu(s4, 2, a3); // lhu s4, 2(a3) - if (bc) {goto block_11;} // branch non-likely + c->lhu(s4, 2, a3); // lhu s4, 2(a3) merc-global-stats.merc.fragments + if (bc) {goto block_11;} // branch non-likely skip mercneric effects - c->lhu(s3, 18, t9); // lhu s3, 18(t9) - c->lwu(gp, 4, a3); // lwu gp, 4(a3) - c->lhu(s5, 22, t9); // lhu s5, 22(t9) - c->daddu(s4, s4, s3); // daddu s4, s4, s3 - c->lwu(s3, 8, a3); // lwu s3, 8(a3) - c->lhu(s2, 24, t9); // lhu s2, 24(t9) - 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, t9); // lwu t2, 0(t9) - c->lwu(gp, 4, t9); // lwu gp, 4(t9) - 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->addiu(s5, r0, 0); // addiu s5, r0, 0 - c->lhu(s4, 18, t9); // lhu s4, 18(t9) + // ra is the effect-info + // t9 is the effect + // a3 is merc-global-stats + c->lhu(s3, 18, t9); // lhu s3, 18(t9) // s3 = effect.frag-count + c->lwu(gp, 4, a3); // lwu gp, 4(a3) // gp = global-stats.merc.tris + c->lhu(s5, 22, t9); // lhu s5, 22(t9) // s5 = merc-effect.tri-count + c->daddu(s4, s4, s3); // daddu s4, s4, s3 // inc frag count + c->lwu(s3, 8, a3); // lwu s3, 8(a3) // s3 = global-stats.merc.dverts + c->lhu(s2, 24, t9); // lhu s2, 24(t9) // s2 = merc-effect.dvert-count + c->daddu(gp, gp, s5); // daddu gp, gp, s5 // inc tri count + c->sh(s4, 2, a3); // sh s4, 2(a3) // store frag count + c->sw(gp, 4, a3); // sw gp, 4(a3) // store tri count + c->daddu(s5, s3, s2); // daddu s5, s3, s2 // inc dvert count + c->lwu(t2, 0, t9); // lwu t2, 0(t9) // t2 = merc-fragment + c->lwu(gp, 4, t9); // lwu gp, 4(t9) // gp = merc-fragment-control + c->lui(s4, 12288); // lui s4, 12288 // dma thing? + c->dsll32(t2, t2, 0); // dsll32 t2, t2, 0 // dma merc-fragment + c->sw(s5, 8, a3); // sw s5, 8(a3) // store dvert stats + c->or_(t2, t2, s4); // or t2, t2, s4 // lower 64 of dma tag? + c->addiu(s5, r0, 0); // addiu s5, r0, 0 // s5 = 0 (frag counter) + c->lhu(s4, 18, t9); // lhu s4, 18(t9) // s4 = effect.frag-count - block_3: - c->lbu(s0, 0, gp); // lbu s0, 0(gp) + // fragment loop + // (note: frag 0 gets added before header) + // 0 = strow tag + // 16 = strow data + // 32 = + // DMA: 0xe1e903000000f + // vif0: 0x0 + // vif1: 0x6e39c08c + // unpack8 (top true): 140, 57 + + +block_3: + c->lbu(s0, 0, gp); // lbu s0, 0(gp) // s0 = fragment-control.unsigned-four-count (4-byte word count in EE mem) // 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, 44, t7); // lw a3, 44(t7) - 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->lbu(s2, 1, gp); // lbu s2, 1(gp) // s2 = fragment-control.lump-four-count + c->xori(s1, r0, 49292); // xori s1, r0, 49292 // maybe vif crap 0xC08C + c->lbu(s3, 2, gp); // lbu s3, 2(gp) // s3 = fragment-control.fp-qwc + c->daddiu(v0, s0, 3); // daddiu v0, s0, 3 // v0 = unsigned-four-count + 3 + c->lw(a3, 44, t7); // lw a3, 44(t7) // a3 = merc-ctrl.header.st-vif-add + c->srl(v0, v0, 2); // srl v0, v0, 2 // v0 = qwc to transfer for unsigned-four-count + + c->sq(t0, 0, a2); // sq t0, 0(a2) // dma/vif template for strow setup + + c->xor_(t2, t2, v0); // xor t2, t2, v0 // add qwc + c->sq(t2, 32, a2); // sq t2, 32(a2) // this is the 0xC08C first unpack 8 with top. always to 140. unsigned-four data. + c->xor_(t2, t2, v0); // xor t2, t2, v0 // remove qwc + c->sh(s1, 44, a2); // sh s1, 44(a2) // here's the 0xc08c store + + c->daddu(s1, s1, s0); // daddu s1, s1, s0 // s1 is VU data ptr (qw), inc by number of 4 byte words because we're unpacking 4x. + c->sb(s0, 46, a2); // sb s0, 46(a2) // store qw to unpack in viftag (output qw's) + c->dsll32(s0, v0, 4); // dsll32 s0, v0, 4 // qw -> bytes for input unsigned-fours (add offset to addr field of dma tag, it's 4 + 32 bit shift) + c->daddu(t3, t2, s0); // daddu t3, t2, s0 // t3 = next + c->daddiu(s0, s2, 3); // daddiu s0, s2, 3 // s0 = lump-four-count + 3 + c->sw(a3, 12, a2); // sw a3, 12(a2) // st-vif-add's x. + c->srl(s0, s0, 2); // srl s0, s0, 2 // lump fours / 4 + c->sq(t1, 16, a2); // sq t1, 16(a2) // row y (will be overwritten) z w (nop). + + // store the dma tag for the lump fours 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->sh(s1, 60, a2); // sh s1, 60(a2) // lump 4 destination. + c->daddu(s1, s1, s2); // daddu s1, s1, s2 // inc VU dest ptr + c->sb(s2, 62, a2); // sb s2, 62(a2) // unpack qwc + c->dsll32(s2, s0, 4); // dsll32 s2, s0, 4 // EE bytes + c->sw(a3, 16, a2); // sw a3, 16(a2) // row y overwrite with st-vif-add + c->daddu(t4, t3, s2); // daddu t4, t3, s2 // next dma + c->xor_(t4, t4, s3); // xor t4, t4, s3 // fp-qwc c->xori(a3, s1, 16384); // xori a3, s1, 16384 - c->sq(t4, 64, a2); // sq t4, 64(a2) + c->sq(t4, 64, a2); // sq t4, 64(a2) // dma for fp's 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 + c->sb(s3, 78, a2); // sb s3, 78(a2) // unpack qwc + c->dsll32(s3, s3, 4); // dsll32 s3, s3, 4 // bytes (in upper 32) + c->sh(a3, 76, a2); // sh a3, 76(a2) // destination in VU + c->daddu(t2, t4, s3); // daddu t2, t4, s3 // next dma + c->lbu(s3, 3, gp); // lbu s3, 3(gp) // frag-ctrl.mat-xfer-count + c->daddiu(gp, gp, 4); // daddiu gp, gp, 4 // gp = frag-ctrl.mat-dest-data + + // skip ahead if on not-first fragment. bc = c->sgpr64(s5) != 0; // bne s5, r0, L73 c->daddiu(a2, a2, 80); // daddiu a2, a2, 80 if (bc) {goto block_5;} // branch non-likely + // on first, need to set up lights and stuff common to all fragments. + // setup 8 qw upload (132 - 140) 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->daddiu(a3, a3, 132); // daddiu a3, a3, 132 // (inc global dma buf) + c->load_symbol(s2, cache.merc_bucket_info); // lw s2, *merc-bucket-info*(s7) c->daddu(s2, r0, s2); // daddu s2, r0, s2 c->sw(a3, 12, a2); // sw a3, 12(a2) - c->lq(a3, 0, s2); // lq a3, 0(s2) - c->lq(s1, 16, s2); // lq s1, 16(s2) - c->lq(s0, 32, s2); // lq s0, 32(s2) - c->lq(v0, 48, s2); // lq v0, 48(s2) - c->sq(a3, 16, a2); // sq a3, 16(a2) - c->sq(s1, 32, a2); // sq s1, 32(a2) - c->sq(s0, 48, a2); // sq s0, 48(a2) - c->sq(v0, 64, a2); // sq v0, 64(a2) - c->lq(a3, 64, s2); // lq a3, 64(s2) - c->lq(s1, 80, s2); // lq s1, 80(s2) - c->lq(s0, 96, s2); // lq s0, 96(s2) - c->lui(v0, 16261); // lui v0, 16261 - c->lq(s2, 28, t7); // lq s2, 28(t7) - c->daddiu(v0, v0, 619); // daddiu v0, v0, 619 - c->sq(a3, 80, a2); // sq a3, 80(a2) - c->lbu(a3, 5, ra); // lbu a3, 5(ra) - c->sq(s1, 96, a2); // sq s1, 96(a2) - c->sq(s0, 112, a2); // sq s0, 112(a2) - c->dsubu(a3, v0, a3); // dsubu a3, v0, a3 + + c->lq(a3, 0, s2); // lq a3, 0(s2) // load l0 + c->lq(s1, 16, s2); // lq s1, 16(s2) // load l1 + c->lq(s0, 32, s2); // lq s0, 32(s2) // load l2 + c->lq(v0, 48, s2); // lq v0, 48(s2) // load l3 + c->sq(a3, 16, a2); // sq a3, 16(a2) // store l0 + c->sq(s1, 32, a2); // sq s1, 32(a2) // store l1 + c->sq(s0, 48, a2); // sq s0, 48(a2) // store l2 + c->sq(v0, 64, a2); // sq v0, 64(a2) // store l3 + c->lq(a3, 64, s2); // lq a3, 64(s2) // load l4 + c->lq(s1, 80, s2); // lq s1, 80(s2) // load l5 + c->lq(s0, 96, s2); // lq s0, 96(s2) // load l6 + c->lui(v0, 16261); // lui v0, 16261 // 0x3F85 + c->lq(s2, 28, t7); // lq s2, 28(t7) // first qw of merc-ctrl header. + c->daddiu(v0, v0, 619); // daddiu v0, v0, 619 // 0x26B + c->sq(a3, 80, a2); // sq a3, 80(a2) // store l4 + c->lbu(a3, 5, ra); // lbu a3, 5(ra) // effect-info.ignore-alpha + c->sq(s1, 96, a2); // sq s1, 96(a2) // store l5 + c->sq(s0, 112, a2); // sq s0, 112(a2) // store l6 + c->dsubu(a3, v0, a3); // dsubu a3, v0, a3 // c->sq(s2, 128, a2); // sq s2, 128(a2) c->sw(a3, 28, a2); // sw a3, 28(a2) c->daddiu(a2, a2, 144); // daddiu a2, a2, 144 + // after first frag setup block_5: bc = c->sgpr64(s3) == 0; // beq s3, r0, L75 - c->addiu(s2, r0, 128); // addiu s2, r0, 128 + c->addiu(s2, r0, 128); // addiu s2, r0, 128 // s2 = mat size if (bc) {goto block_8;} // branch non-likely - c->lbu(a3, 0, gp); // lbu a3, 0(gp) + c->lbu(a3, 0, gp); // lbu a3, 0(gp) // a3 = mat-number block_7: - 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 + c->multu3(s1, a3, s2); // multu3 s1, a3, s2 // s1 = mat-number * 128 + c->sq(t5, 0, a2); // sq t5, 0(a2) // dma template + c->lbu(s0, 1, gp); // lbu s0, 1(gp) // s0 = mat-dest + c->daddiu(gp, gp, 2); // daddiu gp, gp, 2 // inc mat-dest-data pr + c->lbu(a3, 0, gp); // lbu a3, 0(gp) // load for next iter (ugh) + c->daddiu(s3, s3, -1); // daddiu s3, s3, -1 // dec count + c->sb(s0, 12, a2); // sb s0, 12(a2) // store matrix destination. + c->daddiu(a2, a2, 16); // daddiu a2, a2, 16 // increment dma output. + c->daddu(s1, s1, a1); // daddu s1, s1, a1 // matrix data + 128 * mat-number // nop // sll r0, r0, 0 - bc = c->sgpr64(s3) != 0; // bne s3, r0, L74 - c->sw(s1, -12, a2); // sw s1, -12(a2) + bc = c->sgpr64(s3) != 0; // bne s3, r0, L74 // see if we're done + c->sw(s1, -12, a2); // sw s1, -12(a2) // store pointer in input matrix data in dma tag if (bc) {goto block_7;} // branch non-likely block_8: - c->sq(t6, 0, a2); // sq t6, 0(a2) - c->daddiu(a2, a2, 16); // daddiu a2, a2, 16 - bc = c->sgpr64(s5) != 0; // bne s5, r0, L76 - c->daddiu(s5, s5, 1); // daddiu s5, s5, 1 + c->sq(t6, 0, a2); // sq t6, 0(a2) // dma tag template + c->daddiu(a2, a2, 16); // daddiu a2, a2, 16 // inc + bc = c->sgpr64(s5) != 0; // bne s5, r0, L76 // skip ahead on non-first fragment + c->daddiu(s5, s5, 1); // daddiu s5, s5, 1 // inc fragment counter if (bc) {goto block_10;} // branch non-likely c->mov64(a3, v1); // or a3, v1, r0 diff --git a/game/system/Deci2Server.cpp b/game/system/Deci2Server.cpp index 8af913244d..338f64c111 100644 --- a/game/system/Deci2Server.cpp +++ b/game/system/Deci2Server.cpp @@ -93,7 +93,7 @@ void Deci2Server::read_data() { int got = 0; while (got < desired_size) { - ASSERT(got + desired_size < buffer.size()); + ASSERT(got + desired_size < (int)buffer.size()); auto x = read_from_socket(accepted_socket, buffer.data() + got, desired_size - got); if (want_exit_callback()) { return; diff --git a/goalc/compiler/nrepl/ReplServer.cpp b/goalc/compiler/nrepl/ReplServer.cpp index 72b7136881..d57ab14774 100644 --- a/goalc/compiler/nrepl/ReplServer.cpp +++ b/goalc/compiler/nrepl/ReplServer.cpp @@ -77,7 +77,7 @@ std::optional ReplServer::get_msg() { // Say hello ping_response(new_socket); // Track the new socket - if (client_sockets.size() < max_clients) { + if ((int)client_sockets.size() < max_clients) { client_sockets.insert(new_socket); } else { // TODO - Respond with NO @@ -114,7 +114,7 @@ std::optional ReplServer::get_msg() { int expected_size = header->length; int got = 0; while (got < expected_size) { - if (got + expected_size > buffer.size()) { + if (got + expected_size > (int)buffer.size()) { fmt::print(stderr, "[nREPL:{}]: Bad message, aborting the read. Got :{}, Expected: {}, Buffer " "Size: {}",