diff --git a/decompiler/VuDisasm/VuDisassembler.cpp b/decompiler/VuDisasm/VuDisassembler.cpp index 786a1c4c4a..dbbbc06dd6 100644 --- a/decompiler/VuDisasm/VuDisassembler.cpp +++ b/decompiler/VuDisasm/VuDisassembler.cpp @@ -1007,6 +1007,13 @@ std::string VuDisassembler::to_cpp(const VuInstruction& instr, bool mips2c_forma case VuInstrK::XTOP: return fmt::format("vu.{} = xtop();", instr.src.at(0).to_string(m_label_names)); + case VuInstrK::OPMULA: + return fmt::format("vu.acc.opmula(vu.{}, vu.{});", instr.src.at(0).to_string(m_label_names), + instr.src.at(1).to_string(m_label_names)); + case VuInstrK::OPMSUB: + return fmt::format("vu.acc.opmsub(vu.{}, vu.{}, vu.{});", instr.dst->to_string(m_label_names), + instr.src.at(0).to_string(m_label_names), + instr.src.at(1).to_string(m_label_names)); default: unk++; fmt::print("unknown 0 is {}\n", to_string(instr)); diff --git a/game/CMakeLists.txt b/game/CMakeLists.txt index c8993139c6..1967b4bd50 100644 --- a/game/CMakeLists.txt +++ b/game/CMakeLists.txt @@ -109,6 +109,7 @@ set(RUNTIME_SOURCE graphics/opengl_renderer/OpenGLRenderer.cpp graphics/opengl_renderer/Profiler.cpp graphics/opengl_renderer/Shader.cpp + graphics/opengl_renderer/Shadow_PS2.cpp graphics/opengl_renderer/ShadowRenderer.cpp graphics/opengl_renderer/SkyBlendCPU.cpp graphics/opengl_renderer/SkyBlendGPU.cpp diff --git a/game/common/vu.h b/game/common/vu.h index 3d0631180d..c8b3946264 100644 --- a/game/common/vu.h +++ b/game/common/vu.h @@ -1,6 +1,7 @@ #pragma once #include "immintrin.h" #include "common/math/Vector.h" +#include enum class Mask { NONE = 0, @@ -76,6 +77,8 @@ struct alignas(16) Vf { std::string print() const { return fmt::format("{} {} {} {}", x(), y(), z(), w()); } + float length_xyz() const { return std::sqrt(x() * x() + y() * y() + z() * z()); } + std::string print_hex() const { return fmt::format("0x{:x} 0x{:x} 0x{:x} 0x{:x}", x_as_u32(), y_as_u32(), z_as_u32(), w_as_u32()); @@ -232,6 +235,14 @@ struct alignas(16) Vf { } } + void mini(Mask mask, const Vf& a, const Vf& b) { + for (int i = 0; i < 4; i++) { + if ((u64)mask & (1 << i)) { + data[i] = vu_min(a[i], b[i]); + } + } + } + void fill(float f) { for (auto& x : data) { x = f; @@ -274,6 +285,32 @@ struct alignas(16) Vf { } } + u32 add_and_set_sf_s(Mask mask, const Vf& a, float b) { + u32 flag = 0; + for (int i = 0; i < 4; i++) { + if ((u64)mask & (1 << i)) { + data[i] = a[i] + b; + if (data[i] < 0) { + flag = 0x2; + } + } + } + return flag; + } + + u32 sub_and_set_sf_s(Mask mask, const Vf& a, float b) { + u32 flag = 0; + for (int i = 0; i < 4; i++) { + if ((u64)mask & (1 << i)) { + data[i] = a[i] - b; + if (data[i] < 0) { + flag = 0x2; + } + } + } + return flag; + } + void sub(Mask mask, const Vf& a, float b) { for (int i = 0; i < 4; i++) { if ((u64)mask & (1 << i)) { @@ -306,6 +343,18 @@ struct alignas(16) Vf { } } + void saturate_infs() { + for (auto& val : data) { + if (std::isinf(val)) { + if (val > 0) { + val = FLT_MAX; + } else { + val = -FLT_MAX; + } + } + } + } + void mul(Mask mask, const Vf& a, float b) { for (int i = 0; i < 4; i++) { if ((u64)mask & (1 << i)) { @@ -522,4 +571,16 @@ struct alignas(16) Accumulator { auto a = _mm_load_ps(_a.data); _mm_store_ps(data, _mm_mul_ps(a, b)); } + + void opmula(const Vf& a, const Vf& b) { + data[0] = a.data[1] * b.data[2]; + data[1] = a.data[2] * b.data[0]; + data[2] = a.data[0] * b.data[1]; + } + + void opmsub(Vf& dst, Vf a, Vf b) { + dst.data[0] = data[0] - a.data[1] * b.data[2]; + dst.data[1] = data[1] - a.data[2] * b.data[0]; + dst.data[2] = data[2] - a.data[0] * b.data[1]; + } }; diff --git a/game/graphics/opengl_renderer/DirectRenderer.cpp b/game/graphics/opengl_renderer/DirectRenderer.cpp index 99f0638633..fe8b150f6c 100644 --- a/game/graphics/opengl_renderer/DirectRenderer.cpp +++ b/game/graphics/opengl_renderer/DirectRenderer.cpp @@ -682,6 +682,16 @@ void DirectRenderer::handle_ad(const u8* data, break; case GsRegisterAddress::FRAME_1: break; + case GsRegisterAddress::RGBAQ: + // shadow scissor does this? + { + m_prim_building.rgba_reg[0] = data[0]; + m_prim_building.rgba_reg[1] = data[1]; + m_prim_building.rgba_reg[2] = data[2]; + m_prim_building.rgba_reg[3] = data[3]; + memcpy(&m_prim_building.Q, data + 4, 4); + } + break; default: fmt::print("Address {} is not supported\n", register_address_name(addr)); ASSERT(false); diff --git a/game/graphics/opengl_renderer/OpenGLRenderer.cpp b/game/graphics/opengl_renderer/OpenGLRenderer.cpp index 79a81c4f9c..1f17ed8f88 100644 --- a/game/graphics/opengl_renderer/OpenGLRenderer.cpp +++ b/game/graphics/opengl_renderer/OpenGLRenderer.cpp @@ -391,7 +391,7 @@ void OpenGLRenderer::setup_frame(int window_width_px, glClearColor(0.0, 0.0, 0.0, 0.0); glClearDepth(0.0); glDepthMask(GL_TRUE); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glDisable(GL_BLEND); } diff --git a/game/graphics/opengl_renderer/Shader.cpp b/game/graphics/opengl_renderer/Shader.cpp index fcba3a563f..e30ef6558d 100644 --- a/game/graphics/opengl_renderer/Shader.cpp +++ b/game/graphics/opengl_renderer/Shader.cpp @@ -81,4 +81,5 @@ ShaderLibrary::ShaderLibrary() { at(ShaderId::OCEAN_TEXTURE) = {"ocean_texture"}; at(ShaderId::OCEAN_TEXTURE_MIPMAP) = {"ocean_texture_mipmap"}; at(ShaderId::OCEAN_COMMON) = {"ocean_common"}; + at(ShaderId::SHADOW) = {"shadow"}; } diff --git a/game/graphics/opengl_renderer/Shader.h b/game/graphics/opengl_renderer/Shader.h index 9d0a8bede9..ee63cef1f1 100644 --- a/game/graphics/opengl_renderer/Shader.h +++ b/game/graphics/opengl_renderer/Shader.h @@ -38,6 +38,7 @@ enum class ShaderId { OCEAN_TEXTURE = 13, OCEAN_TEXTURE_MIPMAP = 14, OCEAN_COMMON = 15, + SHADOW = 16, MAX_SHADERS }; @@ -45,7 +46,6 @@ class ShaderLibrary { public: ShaderLibrary(); Shader& operator[](ShaderId id) { return m_shaders[(int)id]; } - Shader& at(ShaderId id) { return m_shaders[(int)id]; } private: diff --git a/game/graphics/opengl_renderer/ShadowRenderer.cpp b/game/graphics/opengl_renderer/ShadowRenderer.cpp index d6c062af2b..6245f35f69 100644 --- a/game/graphics/opengl_renderer/ShadowRenderer.cpp +++ b/game/graphics/opengl_renderer/ShadowRenderer.cpp @@ -1,16 +1,426 @@ #include "ShadowRenderer.h" +#include "third-party/imgui/imgui.h" + +#include ShadowRenderer::ShadowRenderer(const std::string& name, BucketId my_id) - : BucketRenderer(name, my_id), m_direct(name, my_id, 0x4000) {} + : BucketRenderer(name, my_id) { + // create OpenGL objects + glGenBuffers(1, &m_ogl.vertex_buffer); + + glGenBuffers(2, m_ogl.index_buffer); + glGenVertexArrays(1, &m_ogl.vao); + + // set up the vertex array + glBindVertexArray(m_ogl.vao); + for (int i = 0; i < 2; i++) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ogl.index_buffer[i]); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_INDICES * sizeof(u32), nullptr, GL_STREAM_DRAW); + } + glBindBuffer(GL_ARRAY_BUFFER, m_ogl.vertex_buffer); + glBufferData(GL_ARRAY_BUFFER, MAX_VERTICES * sizeof(Vertex), nullptr, GL_STREAM_DRAW); + + // xyz + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, // location 0 in the shader + 3, // 3 floats per vert + GL_FLOAT, // floats + GL_TRUE, // normalized, ignored, + sizeof(Vertex), // + (void*)offsetof(Vertex, xyz) // offset in array + ); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); +} void ShadowRenderer::draw_debug_window() { - m_direct.draw_debug_window(); + ImGui::Checkbox("Volume", &m_debug_draw_volume); + ImGui::Text("Vert: %d, Front: %d, Back: %d\n", m_next_vertex, m_next_front_index, + m_next_back_index); +} + +ShadowRenderer::~ShadowRenderer() { + glDeleteBuffers(1, &m_ogl.vertex_buffer); + glDeleteBuffers(2, m_ogl.index_buffer); + glDeleteVertexArrays(1, &m_ogl.vao); +} + +void ShadowRenderer::xgkick(u16 imm) { + u32 ind_of_fan_start = UINT32_MAX; + bool fan_running = false; + const u8* data = (const u8*)(m_vu_data + imm); + + u8 rgba[4] = {1, 2, 3, 4}; + + bool eop = false; + + u32 offset = 0; + while (!eop) { + GifTag tag(data + offset); + offset += 16; + + // unpack registers. + // faster to do it once outside of the nloop loop. + GifTag::RegisterDescriptor reg_desc[16]; + u32 nreg = tag.nreg(); + for (u32 i = 0; i < nreg; i++) { + reg_desc[i] = tag.reg(i); + } + + auto format = tag.flg(); + if (format == GifTag::Format::PACKED) { + if (tag.pre()) { + GsPrim prim(tag.prim()); + ASSERT(prim.kind() == GsPrim::Kind::TRI_FAN); + } + for (u32 loop = 0; loop < tag.nloop(); loop++) { + for (u32 reg = 0; reg < nreg; reg++) { + switch (reg_desc[reg]) { + case GifTag::RegisterDescriptor::AD: { + u64 value; + GsRegisterAddress addr; + memcpy(&value, data + offset, sizeof(u64)); + memcpy(&addr, data + offset + 8, sizeof(GsRegisterAddress)); + + switch (addr) { + case GsRegisterAddress::TEXFLUSH: + break; + case GsRegisterAddress::RGBAQ: { + rgba[0] = data[0 + offset]; + rgba[1] = data[1 + offset]; + rgba[2] = data[2 + offset]; + rgba[3] = data[3 + offset]; + float Q; + memcpy(&Q, data + offset + 4, 4); + // fmt::print("rgba: {} {} {} {}: {}\n", rgba[0], rgba[1], rgba[2], rgba[3], Q); + } break; + default: + fmt::print("Address {} is not supported\n", register_address_name(addr)); + ASSERT(false); + } + } break; + case GifTag::RegisterDescriptor::ST: { + float s, t; + memcpy(&s, data + offset, 4); + memcpy(&t, data + offset + 4, 4); + // fmt::print("st: {} {}\n", s, t); + } break; + case GifTag::RegisterDescriptor::RGBAQ: + for (int i = 0; i < 4; i++) { + rgba[i] = data[offset + i * 4]; + } + // fmt::print("rgbap: {} {} {} {}\n", rgba[0], rgba[1], rgba[2], rgba[3]); + break; + case GifTag::RegisterDescriptor::XYZF2: + // handle_xyzf2_packed(data + offset, render_state, prof); + { + u32 x, y; + memcpy(&x, data + offset, 4); + memcpy(&y, data + offset + 4, 4); + + u64 upper; + memcpy(&upper, data + offset + 8, 8); + u32 z = (upper >> 4) & 0xffffff; + + x <<= 16; + y <<= 16; + z <<= 8; + u32 vidx = m_next_vertex++; + auto& v = m_vertices[vidx]; + ASSERT(m_next_vertex < MAX_VERTICES); + v.xyz[0] = (float)x / (float)UINT32_MAX; + v.xyz[1] = (float)y / (float)UINT32_MAX; + v.xyz[2] = (float)z / (float)UINT32_MAX; + + if (ind_of_fan_start == UINT32_MAX) { + ind_of_fan_start = vidx; + } else { + if (fan_running) { + // todo, actually use triangle fans in opengl... + if (rgba[0] > 0) { + // back + m_back_indices[m_next_back_index++] = vidx; + m_back_indices[m_next_back_index++] = vidx - 1; + m_back_indices[m_next_back_index++] = ind_of_fan_start; + } else { + m_front_indices[m_next_front_index++] = vidx; + m_front_indices[m_next_front_index++] = vidx - 1; + m_front_indices[m_next_front_index++] = ind_of_fan_start; + } + } else { + fan_running = true; + } + } + + // fmt::print("xyzfadc: {} {} {} {} {}\n", x, y, z, f, adc); + } + break; + default: + fmt::print("Register {} is not supported in packed mode yet\n", + reg_descriptor_name(reg_desc[reg])); + ASSERT(false); + } + offset += 16; // PACKED = quadwords + } + } + } else { + ASSERT(false); // format not packed or reglist. + } + + eop = tag.eop(); + } } void ShadowRenderer::render(DmaFollower& dma, SharedRenderState* render_state, - ScopedProfilerNode& /*prof*/) { - while (dma.current_tag_offset() != render_state->next_bucket) { + ScopedProfilerNode& prof) { + if (!m_enabled) { + while (dma.current_tag_offset() != render_state->next_bucket) { + dma.read_and_advance(); + } + return; + } + + m_next_vertex = 0; + m_next_back_index = 0; + m_next_front_index = 0; + + // jump to bucket + auto data0 = dma.read_and_advance(); + ASSERT(data0.vif1() == 0); + ASSERT(data0.vif0() == 0); + ASSERT(data0.size_bytes == 0); + + // see if bucket is empty or not + if (dma.current_tag().kind == DmaTag::Kind::CALL) { + // renderer didn't run, let's just get out of here. + for (int i = 0; i < 4; i++) { + dma.read_and_advance(); + } + ASSERT(dma.current_tag_offset() == render_state->next_bucket); + return; + } + + { + // constants + auto constants = dma.read_and_advance(); + auto v0 = constants.vifcode0(); + auto v1 = constants.vifcode1(); + ASSERT(v0.kind == VifCode::Kind::STCYCL); + ASSERT(v0.immediate == 0x404); + ASSERT(v1.kind == VifCode::Kind::UNPACK_V4_32); + ASSERT(v1.immediate == Vu1Data::CONSTANTS); + ASSERT(v1.num == 13); + memcpy(m_vu_data + v1.immediate, constants.data, v1.num * 16); + } + + { + // gif constants + auto constants = dma.read_and_advance(); + auto v0 = constants.vifcode0(); + auto v1 = constants.vifcode1(); + ASSERT(v0.kind == VifCode::Kind::STCYCL); + ASSERT(v0.immediate == 0x404); + ASSERT(v1.kind == VifCode::Kind::UNPACK_V4_32); + ASSERT(v1.immediate == Vu1Data::GIF_CONSTANTS); + ASSERT(v1.num == 4); + memcpy(m_vu_data + v1.immediate, constants.data, v1.num * 16); + } + + { + // matrix constants + auto constants = dma.read_and_advance(); + auto v0 = constants.vifcode0(); + auto v1 = constants.vifcode1(); + ASSERT(v0.kind == VifCode::Kind::STCYCL); + ASSERT(v0.immediate == 0x404); + ASSERT(v1.kind == VifCode::Kind::UNPACK_V4_32); + ASSERT(v1.immediate == Vu1Data::MATRIX); + ASSERT(v1.num == 4); + memcpy(m_vu_data + v1.immediate, constants.data, v1.num * 16); + } + + { + // exec 10 + auto mscal = dma.read_and_advance(); + ASSERT(mscal.vifcode1().kind == VifCode::Kind::FLUSHE); + ASSERT(mscal.vifcode0().kind == VifCode::Kind::MSCALF); + ASSERT(mscal.vifcode0().immediate == Vu1Code::INIT); + run_mscal10_vu2c(); + } + + { + // init gs direct dma.read_and_advance(); } + + while (dma.current_tag().kind != DmaTag::Kind::CALL) { + auto next = dma.read_and_advance(); + auto v1 = next.vifcode1(); + if (next.vifcode0().kind == VifCode::Kind::FLUSHA && + next.vifcode1().kind == VifCode::Kind::UNPACK_V4_32) { + auto up = next.vifcode1(); + VifCodeUnpack unpack(up); + ASSERT(!unpack.use_tops_flag); + ASSERT((u32)unpack.addr_qw + up.num < 1024); + memcpy(m_vu_data + unpack.addr_qw, next.data, up.num * 16); + ASSERT(up.num * 16 == next.size_bytes); + } else if (next.vifcode0().kind == VifCode::Kind::NOP && + next.vifcode1().kind == VifCode::Kind::UNPACK_V4_32) { + auto up = next.vifcode1(); + VifCodeUnpack unpack(up); + ASSERT(!unpack.use_tops_flag); + ASSERT((u32)unpack.addr_qw + up.num < 1024); + memcpy(m_vu_data + unpack.addr_qw, next.data, up.num * 16); + ASSERT(up.num * 16 == next.size_bytes); + } else if (next.vifcode0().kind == VifCode::Kind::NOP && + next.vifcode1().kind == VifCode::Kind::UNPACK_V4_8) { + auto up = VifCodeUnpack(v1); + ASSERT(!up.use_tops_flag); + ASSERT(up.is_unsigned); + u16 addr = up.addr_qw; + ASSERT(addr + v1.num <= 1024); + + u32 temp[4]; + for (u32 i = 0; i < v1.num; i++) { + for (u32 j = 0; j < 4; j++) { + temp[j] = next.data[4 * i + j]; + } + memcpy(m_vu_data + addr + i, temp, 16); + } + + u32 offset = 4 * v1.num; + ASSERT(offset + 16 == next.size_bytes); + + u32 after[4]; + memcpy(&after, next.data + offset, 16); + ASSERT(after[0] == 0); + ASSERT(after[1] == 0); + ASSERT(after[2] == 0); + VifCode mscal(after[3]); + ASSERT(mscal.kind == VifCode::Kind::MSCALF); + run_mscal_vu2c(mscal.immediate); + } else if (next.vifcode0().kind == VifCode::Kind::FLUSHA && + next.vifcode1().kind == VifCode::Kind::DIRECT) { + dma.read_and_advance(); + dma.read_and_advance(); + dma.read_and_advance(); + + } else { + fmt::print("{} {}\n", next.vifcode0().print(), next.vifcode1().print()); + ASSERT(false); + } + } + + for (int i = 0; i < 4; i++) { + dma.read_and_advance(); + } + ASSERT(dma.current_tag_offset() == render_state->next_bucket); + + draw(render_state, prof); +} + +void ShadowRenderer::draw(SharedRenderState* render_state, ScopedProfilerNode& prof) { + // enable stencil! + glEnable(GL_STENCIL_TEST); + glStencilMask(0xFF); + + u32 clear_vertices = m_next_vertex; + m_vertices[m_next_vertex++] = Vertex{math::Vector3f(0.3, 0.3, 0), 0}; + m_vertices[m_next_vertex++] = Vertex{math::Vector3f(0.3, 0.7, 0), 0}; + m_vertices[m_next_vertex++] = Vertex{math::Vector3f(0.7, 0.3, 0), 0}; + m_vertices[m_next_vertex++] = Vertex{math::Vector3f(0.7, 0.7, 0), 0}; + m_front_indices[m_next_front_index++] = clear_vertices; + m_front_indices[m_next_front_index++] = clear_vertices + 1; + m_front_indices[m_next_front_index++] = clear_vertices + 2; + m_front_indices[m_next_front_index++] = clear_vertices + 3; + m_front_indices[m_next_front_index++] = clear_vertices + 2; + m_front_indices[m_next_front_index++] = clear_vertices + 1; + + glBindVertexArray(m_ogl.vao); + glBindBuffer(GL_ARRAY_BUFFER, m_ogl.vertex_buffer); + glBufferData(GL_ARRAY_BUFFER, m_next_vertex * sizeof(Vertex), m_vertices, GL_STREAM_DRAW); + + glEnable(GL_DEPTH_TEST); + glDisable(GL_BLEND); + glDepthFunc(GL_GEQUAL); + + render_state->shaders.at(ShaderId::SHADOW).activate(); + + glUniform4f(glGetUniformLocation(render_state->shaders[ShaderId::SHADOW].id(), "color_uniform"), + 0., 0.4, 0., 0.5); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ogl.index_buffer[1]); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_next_back_index * sizeof(u32), m_back_indices, + GL_STREAM_DRAW); + + // First pass. + // here, we don't write depth or color. + // but we increment stencil on depth fail. + + glDepthMask(GL_FALSE); // no depth writes. + if (m_debug_draw_volume) { + glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_ADD); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); + } else { + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // no color writes. + } + glStencilFunc(GL_ALWAYS, 0, 0); // always pass stencil + glStencilOp(GL_KEEP, GL_INCR, GL_KEEP); // increment on depth fail. + glDrawElements(GL_TRIANGLES, m_next_back_index, GL_UNSIGNED_INT, nullptr); + + if (m_debug_draw_volume) { + glDisable(GL_BLEND); + glUniform4f(glGetUniformLocation(render_state->shaders[ShaderId::SHADOW].id(), "color_uniform"), + 0., 0.0, 0., 0.5); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + glDrawElements(GL_TRIANGLES, m_next_back_index, GL_UNSIGNED_INT, nullptr); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glEnable(GL_BLEND); + } + prof.add_draw_call(); + prof.add_tri(m_next_back_index / 3); + + glUniform4f(glGetUniformLocation(render_state->shaders[ShaderId::SHADOW].id(), "color_uniform"), + 0.4, 0.0, 0., 0.5); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ogl.index_buffer[0]); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_next_front_index * sizeof(u32), m_front_indices, + GL_STREAM_DRAW); + // Second pass. + // same settings, but decrement. + glStencilOp(GL_KEEP, GL_DECR, GL_KEEP); // decrement on depth fail. + glDrawElements(GL_TRIANGLES, (m_next_front_index - 6), GL_UNSIGNED_INT, nullptr); + if (m_debug_draw_volume) { + glDisable(GL_BLEND); + glUniform4f(glGetUniformLocation(render_state->shaders[ShaderId::SHADOW].id(), "color_uniform"), + 0., 0.0, 0., 0.5); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + glDrawElements(GL_TRIANGLES, (m_next_front_index - 6), GL_UNSIGNED_INT, nullptr); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glEnable(GL_BLEND); + } + + prof.add_draw_call(); + prof.add_tri(m_next_front_index / 3); + + // finally, draw shadow. + glUniform4f(glGetUniformLocation(render_state->shaders[ShaderId::SHADOW].id(), "color_uniform"), + 0.13, 0.13, 0.13, 0.5); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + // glStencilFunc(GL_GREATER, 0, 0); + glStencilFunc(GL_NOTEQUAL, 0, 0xFF); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glDepthFunc(GL_ALWAYS); + + glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); + glBlendFuncSeparate(GL_ONE, GL_ONE, GL_ONE, GL_ZERO); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (void*)(sizeof(u32) * (m_next_front_index - 6))); + prof.add_draw_call(); + prof.add_tri(2); + glBlendEquation(GL_FUNC_ADD); + glDepthMask(GL_TRUE); + + glDisable(GL_STENCIL_TEST); } \ No newline at end of file diff --git a/game/graphics/opengl_renderer/ShadowRenderer.h b/game/graphics/opengl_renderer/ShadowRenderer.h index 2463bc4d64..5ab3332596 100644 --- a/game/graphics/opengl_renderer/ShadowRenderer.h +++ b/game/graphics/opengl_renderer/ShadowRenderer.h @@ -1,14 +1,129 @@ #pragma once #include "game/graphics/opengl_renderer/BucketRenderer.h" -#include "game/graphics/opengl_renderer/DirectRenderer.h" + +#include "game/common/vu.h" class ShadowRenderer : public BucketRenderer { public: ShadowRenderer(const std::string& name, BucketId my_id); + ~ShadowRenderer(); void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override; void draw_debug_window() override; private: - DirectRenderer m_direct; + void run_mscal_vu2c(u16 imm); + void xgkick(u16 imm); + void run_mscal10_vu2c(); + void handle_jalr_to_end_block(u16 val, u32& first_flag, u32& second_flag); + void handle_bal52(); + void draw(SharedRenderState* render_state, ScopedProfilerNode& prof); + + Vf m_vu_data[1024]; + + enum Vu1Data { + MATRIX = 0, + CONSTANTS = 0x370, + GIF_CONSTANTS = 0x3ac, + }; + + enum Vu1Code { + INIT = 10, + }; + + void lq_buffer(Mask mask, Vf& dest, u16 addr) { + ASSERT(addr < 1024); + for (int i = 0; i < 4; i++) { + if ((u64)mask & (1 << i)) { + dest[i] = m_vu_data[addr].data[i]; + } + } + } + + void sq_buffer(Mask mask, const Vf& val, u16 addr) { + ASSERT(addr < 1024); + for (int i = 0; i < 4; i++) { + if ((u64)mask & (1 << i)) { + m_vu_data[addr].data[i] = val[i]; + } + } + } + + void ilw_buffer(Mask mask, u16& dest, u16 addr) { + ASSERT(addr < 1024); + switch (mask) { + case Mask::x: + dest = m_vu_data[addr].x_as_u16(); + break; + case Mask::y: + dest = m_vu_data[addr].y_as_u16(); + break; + case Mask::z: + dest = m_vu_data[addr].z_as_u16(); + break; + case Mask::w: + dest = m_vu_data[addr].w_as_u16(); + break; + default: + ASSERT(false); + } + } + + void isw_buffer(Mask mask, u16 src, u16 addr) { + ASSERT(addr < 1024); + u32 val32 = src; + switch (mask) { + case Mask::x: + memcpy(&m_vu_data[addr].data[0], &val32, 4); + break; + case Mask::y: + memcpy(&m_vu_data[addr].data[1], &val32, 4); + break; + case Mask::z: + memcpy(&m_vu_data[addr].data[2], &val32, 4); + break; + case Mask::w: + memcpy(&m_vu_data[addr].data[3], &val32, 4); + break; + default: + ASSERT(false); + } + } + + struct Vu { + const Vf vf00; + Vu() : vf00(0, 0, 0, 1) {} + + u16 vi01, vi02, vi03, vi04, vi05, vi06, vi07, vi08, vi09, vi10, vi12, vi15; + Vf vf01, vf02, vf03, vf04, vf05, vf06, vf07, vf08, vf09, vf10, vf11, vf12, vf13, vf14, vf15, + vf16, vf17, vf18, vf19, vf20, vf21, vf22, vf23, vf24, vf25, vf26, vf27, vf28, vf29, vf30, + vf31; + Accumulator acc; + float Q; + const u16 vi00 = 0; + } vu; + + struct Vertex { + math::Vector3f xyz; + u32 flag; // 1 if front face, 0 otherwise + }; + static_assert(sizeof(Vertex) == 16); + + static constexpr int MAX_VERTICES = 8192; + static constexpr int MAX_INDICES = 8192; + + Vertex m_vertices[MAX_VERTICES]; + u32 m_front_indices[MAX_INDICES]; + u32 m_back_indices[MAX_INDICES]; + + u32 m_next_vertex = 0; + u32 m_next_front_index = 0; + u32 m_next_back_index = 0; + + struct { + // index is front, back + GLuint vertex_buffer, index_buffer[2], vao; + } m_ogl; + + bool m_debug_draw_volume = false; }; diff --git a/game/graphics/opengl_renderer/Shadow_PS2.cpp b/game/graphics/opengl_renderer/Shadow_PS2.cpp new file mode 100644 index 0000000000..fed663f0b6 --- /dev/null +++ b/game/graphics/opengl_renderer/Shadow_PS2.cpp @@ -0,0 +1,1896 @@ +#include "game/graphics/opengl_renderer/ShadowRenderer.h" + +void ShadowRenderer::run_mscal10_vu2c() { + // ENTER_10: + // iaddiu vi01, vi00, 0x358 | nop 10 + vu.vi01 = 0x358; /* 856 */ + // iaddiu vi02, vi00, 0x364 | nop 11 + vu.vi02 = 0x364; /* 868 */ + // mfir.x vf01, vi01 | nop 12 + vu.vf01.mfir(Mask::x, vu.vi01); + // mfir.y vf01, vi02 | nop 13 + vu.vf01.mfir(Mask::y, vu.vi02); + // mfir.z vf01, vi01 | nop 14 + vu.vf01.mfir(Mask::z, vu.vi01); + // mfir.w vf01, vi02 | nop 15 + vu.vf01.mfir(Mask::w, vu.vi02); + // lq.xyzw vf02, 880(vi00) | nop 16 + lq_buffer(Mask::xyzw, vu.vf02, 880); + // lq.xyzw vf03, 882(vi00) | nop 17 + lq_buffer(Mask::xyzw, vu.vf03, 882); + // lq.xyzw vf04, 883(vi00) | nop 18 + lq_buffer(Mask::xyzw, vu.vf04, 883); + // lq.xyzw vf05, 884(vi00) | nop 19 + lq_buffer(Mask::xyzw, vu.vf05, 884); + // lq.xyzw vf12, 885(vi00) | nop :e 20 + lq_buffer(Mask::xyzw, vu.vf12, 885); + // lq.xyzw vf13, 881(vi00) | nop 21 + lq_buffer(Mask::xyzw, vu.vf13, 881); +} + +namespace { +u32 clip(const Vf& vector, float val, u32 old_clip) { + u32 result = (old_clip << 6); + float plus = std::abs(val); + float minus = -plus; + + if (vector.x() > plus) { + result |= 0b1; + } + if (vector.x() < minus) { + result |= 0b10; + } + + if (vector.y() > plus) { + result |= 0b100; + } + if (vector.y() < minus) { + result |= 0b1000; + } + + if (vector.z() > plus) { + result |= 0b10000; + } + if (vector.z() < minus) { + result |= 0b100000; + } + return result & 0xffffff; // only 24 bits +} + +void fcand(u16& dest, u32 imm, u32 cf) { + // dest = (cf & imm) ? 1 : 0; + if ((cf & 0xFFFFFF) & (imm & 0xFFFFFF)) + dest = 1; + else + dest = 0; + // dest = cf & imm; // wrong +} + +void fsand(u16& dest, u16 a, u16 b) { + dest = a & b; +} + +} // namespace + +void ShadowRenderer::handle_bal52() { + // nop | sub.xyzw vf16, vf15, vf14 736 + vu.vf16.sub(Mask::xyzw, vu.vf15, vu.vf14); + // waitq | mul.xyzw vf16, vf16, Q 737 + vu.vf16.mul(Mask::xyzw, vu.vf16, vu.Q); + // jr vi11 | add.xyzw vf16, vf14, vf16 738 + vu.vf16.add(Mask::xyzw, vu.vf14, vu.vf16); + // nop | nop 739 +} + +void ShadowRenderer::handle_jalr_to_end_block(u16 val, u32& first_flag, u32& second_flag) { + switch (val) { + case 724: + // jr vi11 | addx.w vf30, vf14, vf14 724 + first_flag = vu.vf30.add_and_set_sf_s(Mask::w, vu.vf14, vu.vf14.x()); + // nop | addx.w vf31, vf15, vf15 725 + second_flag = vu.vf31.add_and_set_sf_s(Mask::w, vu.vf15, vu.vf15.x()); + return; + case 726: + // jr vi11 | subx.w vf30, vf14, vf14 726 + first_flag = vu.vf30.sub_and_set_sf_s(Mask::w, vu.vf14, vu.vf14.x()); + // nop | subx.w vf31, vf15, vf15 727 + second_flag = vu.vf31.sub_and_set_sf_s(Mask::w, vu.vf15, vu.vf15.x()); + return; + case 728: + // jr vi11 | addy.w vf30, vf14, vf14 728 + first_flag = vu.vf30.add_and_set_sf_s(Mask::w, vu.vf14, vu.vf14.y()); + // nop | addy.w vf31, vf15, vf15 729 + second_flag = vu.vf31.add_and_set_sf_s(Mask::w, vu.vf15, vu.vf15.y()); + return; + case 730: + // jr vi11 | suby.w vf30, vf14, vf14 730 + first_flag = vu.vf30.sub_and_set_sf_s(Mask::w, vu.vf14, vu.vf14.y()); + // nop | suby.w vf31, vf15, vf15 731 + second_flag = vu.vf31.sub_and_set_sf_s(Mask::w, vu.vf15, vu.vf15.y()); + return; + case 732: + // jr vi11 | addz.w vf30, vf14, vf14 732 + first_flag = vu.vf30.add_and_set_sf_s(Mask::w, vu.vf14, vu.vf14.z()); + // nop | addz.w vf31, vf15, vf15 733 + second_flag = vu.vf31.add_and_set_sf_s(Mask::w, vu.vf15, vu.vf15.z()); + return; + case 734: + // jr vi11 | subz.w vf30, vf14, vf14 734 + first_flag = vu.vf30.sub_and_set_sf_s(Mask::w, vu.vf14, vu.vf14.z()); + // nop | subz.w vf31, vf15, vf15 735 + second_flag = vu.vf31.sub_and_set_sf_s(Mask::w, vu.vf15, vu.vf15.z()); + return; + case 736: + ASSERT(false); // bad because we don't set flags here + // nop | sub.xyzw vf16, vf15, vf14 736 + vu.vf16.sub(Mask::xyzw, vu.vf15, vu.vf14); + // waitq | mul.xyzw vf16, vf16, Q 737 + vu.vf16.mul(Mask::xyzw, vu.vf16, vu.Q); + // jr vi11 | add.xyzw vf16, vf14, vf16 738 + vu.vf16.add(Mask::xyzw, vu.vf14, vu.vf16); + // nop | nop 739 + return; + default: + fmt::print("unhandled end block: {}\n", val); + ASSERT(false); + } +} + +void ShadowRenderer::run_mscal_vu2c(u16 imm) { + u32 cf = 0, sf0, sf1; + bool bc; + switch (imm) { + case 2: + goto L2; + break; + case 4: + goto L13; + case 6: + goto L21; + + default: + fmt::print("didn't know mscal imm: {}\n", imm); + // ASSERT(false); + } + // clang-format off + + L2: + // iaddiu vi03, vi00, 0x158 | nop 22 + vu.vi03 = 0x158; /* 344 */ + // ilwr.x vi08, vi03 | nop 23 + ilw_buffer(Mask::x, vu.vi08, vu.vi03); + // mtir vi02, vf01.x | nop 24 + vu.vi02 = vu.vf01.x_as_u16(); + // iaddi vi03, vi03, 0x1 | addw.z vf25, vf00, vf00 25 + vu.vf25.add(Mask::z, vu.vf00, vu.vf00.w()); vu.vi03 = vu.vi03 + 1; + // lq.xyzw vf25, 888(vi00) | addw.z vf26, vf00, vf00 26 + vu.vf26.add(Mask::z, vu.vf00, vu.vf00.w()); lq_buffer(Mask::xyzw, vu.vf25, 888); + // lq.xyzw vf29, 889(vi00) | addw.z vf27, vf00, vf00 27 + vu.vf27.add(Mask::z, vu.vf00, vu.vf00.w()); lq_buffer(Mask::xyzw, vu.vf29, 889); + // lq.xyzw vf30, 891(vi00) | addw.z vf28, vf00, vf00 28 + vu.vf28.add(Mask::z, vu.vf00, vu.vf00.w()); lq_buffer(Mask::xyzw, vu.vf30, 891); + // lq.xyzw vf06, 0(vi00) | nop 29 + lq_buffer(Mask::xyzw, vu.vf06, 0); + // lq.xyzw vf07, 1(vi00) | nop 30 + lq_buffer(Mask::xyzw, vu.vf07, 1); + // lq.xyzw vf08, 2(vi00) | nop 31 + lq_buffer(Mask::xyzw, vu.vf08, 2); + // lq.xyzw vf09, 3(vi00) | nop 32 + lq_buffer(Mask::xyzw, vu.vf09, 3); + // mtir vi01, vf01.y | nop 33 + vu.vi01 = vu.vf01.y_as_u16(); + // sq.xyzw vf25, 0(vi02) | nop 34 + sq_buffer(Mask::xyzw, vu.vf25, vu.vi02); + // sq.xyzw vf29, 1(vi02) | nop 35 + sq_buffer(Mask::xyzw, vu.vf29, vu.vi02 + 1); + // sq.xyzw vf30, 2(vi02) | nop 36 + sq_buffer(Mask::xyzw, vu.vf30, vu.vi02 + 2); + // sq.xyzw vf25, 0(vi01) | nop 37 + sq_buffer(Mask::xyzw, vu.vf25, vu.vi01); + // sq.xyzw vf29, 1(vi01) | nop 38 + sq_buffer(Mask::xyzw, vu.vf29, vu.vi01 + 1); + // sq.xyzw vf30, 2(vi01) | nop 39 + sq_buffer(Mask::xyzw, vu.vf30, vu.vi01 + 2); + L3: + // lqi.xyzw vf16, vi03 | nop 40 + lq_buffer(Mask::xyzw, vu.vf16, vu.vi03++); + // nop | nop 41 + + // nop | nop 42 + + // nop | nop 43 + + // mtir vi04, vf16.x | nop 44 + vu.vi04 = vu.vf16.x_as_u16(); + // mtir vi05, vf16.y | nop 45 + vu.vi05 = vu.vf16.y_as_u16(); + // mtir vi06, vf16.z | nop 46 + vu.vi06 = vu.vf16.z_as_u16(); + // nop | nop 47 + + // lq.xyzw vf17, 4(vi04) | nop 48 + lq_buffer(Mask::xyzw, vu.vf17, vu.vi04 + 4); + // lq.xyzw vf18, 4(vi05) | nop 49 + lq_buffer(Mask::xyzw, vu.vf18, vu.vi05 + 4); + // lq.xyzw vf19, 4(vi06) | nop 50 + lq_buffer(Mask::xyzw, vu.vf19, vu.vi06 + 4); + // nop | mulaw.xyzw ACC, vf09, vf00 51 + vu.acc.mula(Mask::xyzw, vu.vf09, vu.vf00.w()); + // move.xyzw vf15, vf17 | maddax.xyzw ACC, vf06, vf17 52 + vu.acc.madda(Mask::xyzw, vu.vf06, vu.vf17.x()); vu.vf15.move(Mask::xyzw, vu.vf17); + // nop | madday.xyzw ACC, vf07, vf17 53 + vu.acc.madda(Mask::xyzw, vu.vf07, vu.vf17.y()); + // nop | maddz.xyzw vf17, vf08, vf17 54 + vu.acc.madd(Mask::xyzw, vu.vf17, vu.vf08, vu.vf17.z()); + // nop | mulaw.xyzw ACC, vf09, vf00 55 + vu.acc.mula(Mask::xyzw, vu.vf09, vu.vf00.w()); + // nop | sub.xyzw vf29, vf18, vf15 56 + vu.vf29.sub(Mask::xyzw, vu.vf18, vu.vf15); + // nop | sub.xyzw vf30, vf19, vf15 57 + vu.vf30.sub(Mask::xyzw, vu.vf19, vu.vf15); + // div Q, vf12.x, vf17.w | maddax.xyzw ACC, vf06, vf18 58 + vu.acc.madda(Mask::xyzw, vu.vf06, vu.vf18.x()); vu.Q = vu.vf12.x() / vu.vf17.w(); + // nop | mul.xyzw vf21, vf17, vf02 59 + vu.vf21.mul(Mask::xyzw, vu.vf17, vu.vf02); + // nop | madday.xyzw ACC, vf07, vf18 60 + vu.acc.madda(Mask::xyzw, vu.vf07, vu.vf18.y()); + // nop | maddz.xyzw vf18, vf08, vf18 61 + vu.acc.madd(Mask::xyzw, vu.vf18, vu.vf08, vu.vf18.z()); + // nop | mulaw.xyzw ACC, vf09, vf00 62 + vu.acc.mula(Mask::xyzw, vu.vf09, vu.vf00.w()); + // nop | maddax.xyzw ACC, vf06, vf19 63 + vu.acc.madda(Mask::xyzw, vu.vf06, vu.vf19.x()); + // nop | madday.xyzw ACC, vf07, vf19 64 + vu.acc.madda(Mask::xyzw, vu.vf07, vu.vf19.y()); + // div Q, vf12.x, vf18.w | mul.xyz vf17, vf17, Q 65 + vu.vf17.mul(Mask::xyz, vu.vf17, vu.Q); vu.Q = vu.vf12.x() / vu.vf18.w(); + // nop | maddz.xyzw vf19, vf08, vf19 66 + vu.acc.madd(Mask::xyzw, vu.vf19, vu.vf08, vu.vf19.z()); + // nop | mul.xyzw vf22, vf18, vf02 67 + vu.vf22.mul(Mask::xyzw, vu.vf18, vu.vf02); + // nop | opmula.xyz ACC, vf29, vf30 68 + vu.acc.opmula(vu.vf29, vu.vf30); + // nop | opmsub.xyz vf29, vf30, vf29 69 + vu.acc.opmsub(vu.vf29, vu.vf30, vu.vf29); + // nop | add.xy vf25, vf17, vf03 70 + vu.vf25.add(Mask::xy, vu.vf17, vu.vf03); + // nop | add.xyzw vf17, vf17, vf05 71 + vu.vf17.add(Mask::xyzw, vu.vf17, vu.vf05); + // div Q, vf12.x, vf19.w | mul.xyz vf18, vf18, Q 72 + vu.vf18.mul(Mask::xyz, vu.vf18, vu.Q); vu.Q = vu.vf12.x() / vu.vf19.w(); + // nop | mul.xyzw vf23, vf19, vf02 73 + vu.vf23.mul(Mask::xyzw, vu.vf19, vu.vf02); + // nop | mul.xyz vf29, vf29, vf15 74 + vu.vf29.mul(Mask::xyz, vu.vf29, vu.vf15); + // nop | mul.xy vf25, vf25, vf04 75 + vu.vf25.mul(Mask::xy, vu.vf25, vu.vf04); + // nop | mini.xyzw vf10, vf10, vf17 76 + vu.vf10.mini(Mask::xyzw, vu.vf10, vu.vf17); + // nop | max.xyzw vf11, vf11, vf17 77 + vu.vf11.max(Mask::xyzw, vu.vf11, vu.vf17); + // nop | ftoi4.xyzw vf17, vf17 78 + vu.vf17.ftoi4(Mask::xyzw, vu.vf17); + // nop | add.xy vf26, vf18, vf03 79 + vu.vf26.add(Mask::xy, vu.vf18, vu.vf03); + // nop | add.xyzw vf18, vf18, vf05 80 + vu.vf18.add(Mask::xyzw, vu.vf18, vu.vf05); + // fcset 0x0 | addy.x vf29, vf29, vf29 81 + vu.vf29.add(Mask::x, vu.vf29, vu.vf29.y()); cf = 0x0; + + // nop | mul.xyz vf19, vf19, Q 82 + vu.vf19.mul(Mask::xyz, vu.vf19, vu.Q); + // sq.xyzw vf25, 4(vi02) | mini.xyzw vf10, vf10, vf18 83 + vu.vf10.mini(Mask::xyzw, vu.vf10, vu.vf18); sq_buffer(Mask::xyzw, vu.vf25, vu.vi02 + 4); + // sq.xyzw vf17, 5(vi02) | max.xyzw vf11, vf11, vf18 84 + vu.vf11.max(Mask::xyzw, vu.vf11, vu.vf18); sq_buffer(Mask::xyzw, vu.vf17, vu.vi02 + 5); + // nop | clipw.xyz vf21, vf21 85 + cf = clip(vu.vf21, vu.vf21.w(), cf); + // nop | mul.xy vf26, vf26, vf04 86 + vu.vf26.mul(Mask::xy, vu.vf26, vu.vf04); + // nop | addz.x vf29, vf29, vf29 87 + sf0 = vu.vf29.add_and_set_sf_s(Mask::x, vu.vf29, vu.vf29.z()); + // nop | ftoi4.xyzw vf18, vf18 88 + vu.vf18.ftoi4(Mask::xyzw, vu.vf18); + // nop | add.xy vf27, vf19, vf03 89 + vu.vf27.add(Mask::xy, vu.vf19, vu.vf03); + // sq.xyzw vf26, 6(vi02) | add.xyzw vf19, vf19, vf05 90 + vu.vf19.add(Mask::xyzw, vu.vf19, vu.vf05); sq_buffer(Mask::xyzw, vu.vf26, vu.vi02 + 6); + // fsand vi01, 0x2 | clipw.xyz vf22, vf22 91 + cf = clip(vu.vf22, vu.vf22.w(), cf); fsand(vu.vi01, 0x2, sf0); + + // sq.xyzw vf18, 7(vi02) | clipw.xyz vf23, vf23 92 + cf = clip(vu.vf23, vu.vf23.w(), cf); sq_buffer(Mask::xyzw, vu.vf18, vu.vi02 + 7); + // BRANCH! + // ibeq vi00, vi01, L4 | mul.xy vf27, vf27, vf04 93 + vu.vf27.mul(Mask::xy, vu.vf27, vu.vf04); bc = (vu.vi01 == 0); + // nop | mini.xyzw vf10, vf10, vf19 94 + vu.vf10.mini(Mask::xyzw, vu.vf10, vu.vf19); + if (bc) { goto L4; } + + // BRANCH! + // b L5 | nop 95 + bc = true; + // lq.xyzw vf31, 887(vi00) | max.xyzw vf11, vf11, vf19 96 + vu.vf11.max(Mask::xyzw, vu.vf11, vu.vf19); lq_buffer(Mask::xyzw, vu.vf31, 887); + if (bc) { goto L5; } + + L4: + // lq.xyzw vf31, 886(vi00) | max.xyzw vf11, vf11, vf19 97 + vu.vf11.max(Mask::xyzw, vu.vf11, vu.vf19); lq_buffer(Mask::xyzw, vu.vf31, 886); + L5: + // fcand vi01, 0x3ffff | ftoi4.xyzw vf19, vf19 98 + vu.vf19.ftoi4(Mask::xyzw, vu.vf19); fcand(vu.vi01, 0x3ffff, cf); + + // BRANCH! + // ibne vi00, vi01, L11 | nop 99 + bc = (vu.vi01 != 0); + // iaddi vi08, vi08, -0x1 | nop 100 + vu.vi08 = vu.vi08 + -1; + if (bc) { goto L11; } + + // sq.xyzw vf27, 8(vi02) | nop 101 + sq_buffer(Mask::xyzw, vu.vf27, vu.vi02 + 8); + // sq.xyzw vf31, 3(vi02) | nop 102 + sq_buffer(Mask::xyzw, vu.vf31, vu.vi02 + 3); + // sq.xyzw vf19, 9(vi02) | nop 103 + sq_buffer(Mask::xyzw, vu.vf19, vu.vi02 + 9); + // xgkick vi02 | nop 104 + xgkick(vu.vi02); + // mtir vi02, vf01.y | nop 105 + vu.vi02 = vu.vf01.y_as_u16(); + // mr32.xyzw vf01, vf01 | nop 106 + vu.vf01.mr32(Mask::xyzw, vu.vf01); + L6: + // BRANCH! + // ibgtz vi08, L3 | nop 107 + bc = ((s16)vu.vi08) > 0; + // nop | nop 108 + + if (bc) { goto L3; } + + // iaddiu vi03, vi00, 0x158 | nop 109 + vu.vi03 = 0x158; /* 344 */ + // ilwr.x vi08, vi03 | nop 110 + ilw_buffer(Mask::x, vu.vi08, vu.vi03); + // iaddi vi03, vi03, 0x1 | nop 111 + vu.vi03 = vu.vi03 + 1; + L7: + // lqi.xyzw vf16, vi03 | nop 112 + lq_buffer(Mask::xyzw, vu.vf16, vu.vi03++); + // nop | nop 113 + + // nop | nop 114 + + // nop | nop 115 + + // mtir vi04, vf16.x | nop 116 + vu.vi04 = vu.vf16.x_as_u16(); + // mtir vi05, vf16.y | nop 117 + vu.vi05 = vu.vf16.y_as_u16(); + // mtir vi06, vf16.z | nop 118 + vu.vi06 = vu.vf16.z_as_u16(); + // nop | nop 119 + + // lq.xyzw vf17, 174(vi04) | nop 120 + lq_buffer(Mask::xyzw, vu.vf17, vu.vi04 + 174); + // lq.xyzw vf18, 174(vi06) | nop 121 + lq_buffer(Mask::xyzw, vu.vf18, vu.vi06 + 174); + // lq.xyzw vf19, 174(vi05) | nop 122 + lq_buffer(Mask::xyzw, vu.vf19, vu.vi05 + 174); + // nop | mulaw.xyzw ACC, vf09, vf00 123 + vu.acc.mula(Mask::xyzw, vu.vf09, vu.vf00.w()); + // move.xyzw vf15, vf17 | maddax.xyzw ACC, vf06, vf17 124 + vu.acc.madda(Mask::xyzw, vu.vf06, vu.vf17.x()); vu.vf15.move(Mask::xyzw, vu.vf17); + // nop | madday.xyzw ACC, vf07, vf17 125 + vu.acc.madda(Mask::xyzw, vu.vf07, vu.vf17.y()); + // nop | maddz.xyzw vf17, vf08, vf17 126 + vu.acc.madd(Mask::xyzw, vu.vf17, vu.vf08, vu.vf17.z()); + // nop | mulaw.xyzw ACC, vf09, vf00 127 + vu.acc.mula(Mask::xyzw, vu.vf09, vu.vf00.w()); + // nop | sub.xyzw vf29, vf18, vf15 128 + vu.vf29.sub(Mask::xyzw, vu.vf18, vu.vf15); + // nop | sub.xyzw vf30, vf19, vf15 129 + vu.vf30.sub(Mask::xyzw, vu.vf19, vu.vf15); + // div Q, vf12.x, vf17.w | maddax.xyzw ACC, vf06, vf18 130 + vu.acc.madda(Mask::xyzw, vu.vf06, vu.vf18.x()); vu.Q = vu.vf12.x() / vu.vf17.w(); + // nop | mul.xyzw vf21, vf17, vf02 131 + vu.vf21.mul(Mask::xyzw, vu.vf17, vu.vf02); + // nop | madday.xyzw ACC, vf07, vf18 132 + vu.acc.madda(Mask::xyzw, vu.vf07, vu.vf18.y()); + // nop | maddz.xyzw vf18, vf08, vf18 133 + vu.acc.madd(Mask::xyzw, vu.vf18, vu.vf08, vu.vf18.z()); + // nop | mulaw.xyzw ACC, vf09, vf00 134 + vu.acc.mula(Mask::xyzw, vu.vf09, vu.vf00.w()); + // nop | maddax.xyzw ACC, vf06, vf19 135 + vu.acc.madda(Mask::xyzw, vu.vf06, vu.vf19.x()); + // nop | madday.xyzw ACC, vf07, vf19 136 + vu.acc.madda(Mask::xyzw, vu.vf07, vu.vf19.y()); + // div Q, vf12.x, vf18.w | mul.xyz vf17, vf17, Q 137 + vu.vf17.mul(Mask::xyz, vu.vf17, vu.Q); vu.Q = vu.vf12.x() / vu.vf18.w(); + // nop | maddz.xyzw vf19, vf08, vf19 138 + vu.acc.madd(Mask::xyzw, vu.vf19, vu.vf08, vu.vf19.z()); + // nop | mul.xyzw vf22, vf18, vf02 139 + vu.vf22.mul(Mask::xyzw, vu.vf18, vu.vf02); + // nop | opmula.xyz ACC, vf29, vf30 140 + vu.acc.opmula(vu.vf29, vu.vf30); + // nop | opmsub.xyz vf29, vf30, vf29 141 + vu.acc.opmsub(vu.vf29, vu.vf30, vu.vf29); + // nop | add.xy vf25, vf17, vf03 142 + vu.vf25.add(Mask::xy, vu.vf17, vu.vf03); + // nop | add.xyzw vf17, vf17, vf05 143 + vu.vf17.add(Mask::xyzw, vu.vf17, vu.vf05); + // div Q, vf12.x, vf19.w | mul.xyz vf18, vf18, Q 144 + vu.vf18.mul(Mask::xyz, vu.vf18, vu.Q); vu.Q = vu.vf12.x() / vu.vf19.w(); + // nop | mul.xyzw vf23, vf19, vf02 145 + vu.vf23.mul(Mask::xyzw, vu.vf19, vu.vf02); + // nop | mul.xyz vf29, vf29, vf15 146 + vu.vf29.mul(Mask::xyz, vu.vf29, vu.vf15); + // nop | mul.xy vf25, vf25, vf04 147 + vu.vf25.mul(Mask::xy, vu.vf25, vu.vf04); + // nop | mini.xyzw vf10, vf10, vf17 148 + vu.vf10.mini(Mask::xyzw, vu.vf10, vu.vf17); + // nop | max.xyzw vf11, vf11, vf17 149 + vu.vf11.max(Mask::xyzw, vu.vf11, vu.vf17); + // nop | ftoi4.xyzw vf17, vf17 150 + vu.vf17.ftoi4(Mask::xyzw, vu.vf17); + // nop | add.xy vf26, vf18, vf03 151 + vu.vf26.add(Mask::xy, vu.vf18, vu.vf03); + // nop | add.xyzw vf18, vf18, vf05 152 + vu.vf18.add(Mask::xyzw, vu.vf18, vu.vf05); + // fcset 0x0 | addy.x vf29, vf29, vf29 153 + vu.vf29.add(Mask::x, vu.vf29, vu.vf29.y()); cf = 0x0; + + // nop | mul.xyz vf19, vf19, Q 154 + vu.vf19.mul(Mask::xyz, vu.vf19, vu.Q); + // sq.xyzw vf25, 4(vi02) | mini.xyzw vf10, vf10, vf18 155 + vu.vf10.mini(Mask::xyzw, vu.vf10, vu.vf18); sq_buffer(Mask::xyzw, vu.vf25, vu.vi02 + 4); + // sq.xyzw vf17, 5(vi02) | max.xyzw vf11, vf11, vf18 156 + vu.vf11.max(Mask::xyzw, vu.vf11, vu.vf18); sq_buffer(Mask::xyzw, vu.vf17, vu.vi02 + 5); + // nop | clipw.xyz vf21, vf21 157 + cf = clip(vu.vf21, vu.vf21.w(), cf); + // nop | mul.xy vf26, vf26, vf04 158 + vu.vf26.mul(Mask::xy, vu.vf26, vu.vf04); + // iaddi vi08, vi08, -0x1 | addz.x vf29, vf29, vf29 159 + sf0 = vu.vf29.add_and_set_sf_s(Mask::x, vu.vf29, vu.vf29.z()); vu.vi08 = vu.vi08 + -1; + // nop | ftoi4.xyzw vf18, vf18 160 + vu.vf18.ftoi4(Mask::xyzw, vu.vf18); + // nop | add.xy vf27, vf19, vf03 161 + vu.vf27.add(Mask::xy, vu.vf19, vu.vf03); + // sq.xyzw vf26, 6(vi02) | add.xyzw vf19, vf19, vf05 162 + vu.vf19.add(Mask::xyzw, vu.vf19, vu.vf05); sq_buffer(Mask::xyzw, vu.vf26, vu.vi02 + 6); + // fsand vi01, 0x2 | clipw.xyz vf22, vf22 163 + cf = clip(vu.vf22, vu.vf22.w(), cf); fsand(vu.vi01, 0x2, sf0); + + // sq.xyzw vf18, 7(vi02) | clipw.xyz vf23, vf23 164 + cf = clip(vu.vf23, vu.vf23.w(), cf); sq_buffer(Mask::xyzw, vu.vf18, vu.vi02 + 7); + // BRANCH! + // ibeq vi00, vi01, L8 | mul.xy vf27, vf27, vf04 165 + vu.vf27.mul(Mask::xy, vu.vf27, vu.vf04); bc = (vu.vi01 == 0); + // nop | mini.xyzw vf10, vf10, vf19 166 + vu.vf10.mini(Mask::xyzw, vu.vf10, vu.vf19); + if (bc) { goto L8; } + + // BRANCH! + // b L9 | nop 167 + bc = true; + // lq.xyzw vf31, 887(vi00) | max.xyzw vf11, vf11, vf19 168 + vu.vf11.max(Mask::xyzw, vu.vf11, vu.vf19); lq_buffer(Mask::xyzw, vu.vf31, 887); + if (bc) { goto L9; } + + L8: + // lq.xyzw vf31, 886(vi00) | max.xyzw vf11, vf11, vf19 169 + vu.vf11.max(Mask::xyzw, vu.vf11, vu.vf19); lq_buffer(Mask::xyzw, vu.vf31, 886); + L9: + // fcand vi01, 0x3ffff | ftoi4.xyzw vf19, vf19 170 + vu.vf19.ftoi4(Mask::xyzw, vu.vf19); fcand(vu.vi01, 0x3ffff, cf); + + // BRANCH! + // ibne vi00, vi01, L12 | nop 171 + bc = (vu.vi01 != 0); + // sq.xyzw vf27, 8(vi02) | nop 172 + sq_buffer(Mask::xyzw, vu.vf27, vu.vi02 + 8); + if (bc) { goto L12; } + + // sq.xyzw vf31, 3(vi02) | nop 173 + sq_buffer(Mask::xyzw, vu.vf31, vu.vi02 + 3); + // sq.xyzw vf19, 9(vi02) | nop 174 + sq_buffer(Mask::xyzw, vu.vf19, vu.vi02 + 9); + // xgkick vi02 | nop 175 + xgkick(vu.vi02); + // mtir vi02, vf01.y | nop 176 + vu.vi02 = vu.vf01.y_as_u16(); + // mr32.xyzw vf01, vf01 | nop 177 + vu.vf01.mr32(Mask::xyzw, vu.vf01); + L10: + // BRANCH! + // ibgtz vi08, L7 | nop 178 + bc = ((s16)vu.vi08) > 0; + // nop | nop 179 + + if (bc) { goto L7; } + + // nop | nop :e 180 + + // nop | nop 181 + + return; + + L11: + // sq.xyzw vf21, 1000(vi00) | nop 182 + sq_buffer(Mask::xyzw, vu.vf21, 1000); + // sq.xyzw vf22, 1003(vi00) | nop 183 + sq_buffer(Mask::xyzw, vu.vf22, 1003); + // sq.xyzw vf23, 1006(vi00) | nop 184 + sq_buffer(Mask::xyzw, vu.vf23, 1006); + // sq.xyzw vf31, 942(vi00) | nop 185 + sq_buffer(Mask::xyzw, vu.vf31, 942); + // mfir.x vf29, vi02 | nop 186 + vu.vf29.mfir(Mask::x, vu.vi02); + // mfir.y vf29, vi03 | nop 187 + vu.vf29.mfir(Mask::y, vu.vi03); + // mfir.z vf29, vi07 | nop 188 + vu.vf29.mfir(Mask::z, vu.vi07); + // BRANCH! + // bal vi15, L36 | nop 189 + // mfir.w vf29, vi08 | nop 190 + vu.vf29.mfir(Mask::w, vu.vi08); + vu.vi15 = 191; + goto L36; + + INSTR_191: + // mtir vi08, vf29.w | nop 191 + vu.vi08 = vu.vf29.w_as_u16(); + // mtir vi03, vf29.y | nop 192 + vu.vi03 = vu.vf29.y_as_u16(); + // mtir vi07, vf29.z | nop 193 + vu.vi07 = vu.vf29.z_as_u16(); + // BRANCH! + // b L6 | nop 194 + bc = true; + // mtir vi02, vf29.x | nop 195 + vu.vi02 = vu.vf29.x_as_u16(); + if (bc) { goto L6; } + + L12: + // sq.xyzw vf21, 1000(vi00) | nop 196 + sq_buffer(Mask::xyzw, vu.vf21, 1000); + // sq.xyzw vf22, 1003(vi00) | nop 197 + sq_buffer(Mask::xyzw, vu.vf22, 1003); + // sq.xyzw vf23, 1006(vi00) | nop 198 + sq_buffer(Mask::xyzw, vu.vf23, 1006); + // sq.xyzw vf31, 942(vi00) | nop 199 + sq_buffer(Mask::xyzw, vu.vf31, 942); + // mfir.x vf29, vi02 | nop 200 + vu.vf29.mfir(Mask::x, vu.vi02); + // mfir.y vf29, vi03 | nop 201 + vu.vf29.mfir(Mask::y, vu.vi03); + // mfir.z vf29, vi07 | nop 202 + vu.vf29.mfir(Mask::z, vu.vi07); + // BRANCH! + // bal vi15, L36 | nop 203 + // mfir.w vf29, vi08 | nop 204 + vu.vf29.mfir(Mask::w, vu.vi08); + vu.vi15 = 205; + goto L36; + + INSTR_205: + // mtir vi08, vf29.w | nop 205 + vu.vi08 = vu.vf29.w_as_u16(); + // mtir vi03, vf29.y | nop 206 + vu.vi03 = vu.vf29.y_as_u16(); + // mtir vi07, vf29.z | nop 207 + vu.vi07 = vu.vf29.z_as_u16(); + // BRANCH! + // b L10 | nop 208 + bc = true; + // mtir vi02, vf29.x | nop 209 + vu.vi02 = vu.vf29.x_as_u16(); + if (bc) { goto L10; } + + L13: + // iaddiu vi03, vi00, 0x258 | nop 210 + vu.vi03 = 0x258; /* 600 */ + // ilwr.x vi08, vi03 | nop 211 + ilw_buffer(Mask::x, vu.vi08, vu.vi03); + // mtir vi02, vf01.x | nop 212 + vu.vi02 = vu.vf01.x_as_u16(); + // iaddi vi03, vi03, 0x1 | addw.z vf25, vf00, vf00 213 + vu.vf25.add(Mask::z, vu.vf00, vu.vf00.w()); vu.vi03 = vu.vi03 + 1; + // lq.xyzw vf25, 888(vi00) | addw.z vf26, vf00, vf00 214 + vu.vf26.add(Mask::z, vu.vf00, vu.vf00.w()); lq_buffer(Mask::xyzw, vu.vf25, 888); + // lq.xyzw vf29, 889(vi00) | addw.z vf27, vf00, vf00 215 + vu.vf27.add(Mask::z, vu.vf00, vu.vf00.w()); lq_buffer(Mask::xyzw, vu.vf29, 889); + // lq.xyzw vf30, 892(vi00) | nop 216 + lq_buffer(Mask::xyzw, vu.vf30, 892); + // lq.xyzw vf06, 0(vi00) | nop 217 + lq_buffer(Mask::xyzw, vu.vf06, 0); + // lq.xyzw vf07, 1(vi00) | nop 218 + lq_buffer(Mask::xyzw, vu.vf07, 1); + // lq.xyzw vf08, 2(vi00) | nop 219 + lq_buffer(Mask::xyzw, vu.vf08, 2); + // lq.xyzw vf09, 3(vi00) | nop 220 + lq_buffer(Mask::xyzw, vu.vf09, 3); + // mtir vi01, vf01.y | nop 221 + vu.vi01 = vu.vf01.y_as_u16(); + // sq.xyzw vf25, 0(vi02) | nop 222 + sq_buffer(Mask::xyzw, vu.vf25, vu.vi02); + // sq.xyzw vf29, 1(vi02) | nop 223 + sq_buffer(Mask::xyzw, vu.vf29, vu.vi02 + 1); + // sq.xyzw vf30, 2(vi02) | nop 224 + sq_buffer(Mask::xyzw, vu.vf30, vu.vi02 + 2); + // sq.xyzw vf25, 0(vi01) | nop 225 + sq_buffer(Mask::xyzw, vu.vf25, vu.vi01); + // sq.xyzw vf29, 1(vi01) | nop 226 + sq_buffer(Mask::xyzw, vu.vf29, vu.vi01 + 1); + // sq.xyzw vf30, 2(vi01) | nop 227 + sq_buffer(Mask::xyzw, vu.vf30, vu.vi01 + 2); + L14: + // lqi.xyzw vf16, vi03 | nop 228 + lq_buffer(Mask::xyzw, vu.vf16, vu.vi03++); + // nop | nop 229 + + // nop | nop 230 + + // nop | nop 231 + + // mtir vi06, vf16.z | nop 232 + vu.vi06 = vu.vf16.z_as_u16(); + // mtir vi04, vf16.x | nop 233 + vu.vi04 = vu.vf16.x_as_u16(); + // mtir vi05, vf16.y | nop 234 + vu.vi05 = vu.vf16.y_as_u16(); + // BRANCH! + // ibeq vi00, vi06, L15 | nop 235 + bc = (vu.vi06 == 0); + // nop | nop 236 + + if (bc) { goto L15; } + + // lq.xyzw vf17, 4(vi04) | nop 237 + lq_buffer(Mask::xyzw, vu.vf17, vu.vi04 + 4); + // lq.xyzw vf18, 4(vi05) | nop 238 + lq_buffer(Mask::xyzw, vu.vf18, vu.vi05 + 4); + // lq.xyzw vf19, 174(vi05) | nop 239 + lq_buffer(Mask::xyzw, vu.vf19, vu.vi05 + 174); + // BRANCH! + // b L16 | nop 240 + bc = true; + // lq.xyzw vf20, 174(vi04) | nop 241 + lq_buffer(Mask::xyzw, vu.vf20, vu.vi04 + 174); + if (bc) { goto L16; } + + L15: + // lq.xyzw vf17, 4(vi05) | nop 242 + lq_buffer(Mask::xyzw, vu.vf17, vu.vi05 + 4); + // lq.xyzw vf18, 4(vi04) | nop 243 + lq_buffer(Mask::xyzw, vu.vf18, vu.vi04 + 4); + // lq.xyzw vf19, 174(vi04) | nop 244 + lq_buffer(Mask::xyzw, vu.vf19, vu.vi04 + 174); + // lq.xyzw vf20, 174(vi05) | nop 245 + lq_buffer(Mask::xyzw, vu.vf20, vu.vi05 + 174); + L16: + // move.xyzw vf15, vf17 | mulaw.xyzw ACC, vf09, vf00 246 + vu.acc.mula(Mask::xyzw, vu.vf09, vu.vf00.w()); vu.vf15.move(Mask::xyzw, vu.vf17); + // nop | maddax.xyzw ACC, vf06, vf17 247 + vu.acc.madda(Mask::xyzw, vu.vf06, vu.vf17.x()); + // nop | madday.xyzw ACC, vf07, vf17 248 + vu.acc.madda(Mask::xyzw, vu.vf07, vu.vf17.y()); + // nop | maddz.xyzw vf17, vf08, vf17 249 + vu.acc.madd(Mask::xyzw, vu.vf17, vu.vf08, vu.vf17.z()); + // nop | mulaw.xyzw ACC, vf09, vf00 250 + vu.acc.mula(Mask::xyzw, vu.vf09, vu.vf00.w()); + // nop | sub.xyzw vf29, vf18, vf15 251 + vu.vf29.sub(Mask::xyzw, vu.vf18, vu.vf15); + // nop | sub.xyzw vf30, vf19, vf15 252 + vu.vf30.sub(Mask::xyzw, vu.vf19, vu.vf15); + // div Q, vf12.x, vf17.w | maddax.xyzw ACC, vf06, vf18 253 + vu.acc.madda(Mask::xyzw, vu.vf06, vu.vf18.x()); vu.Q = vu.vf12.x() / vu.vf17.w(); + // nop | mul.xyzw vf21, vf17, vf02 254 + vu.vf21.mul(Mask::xyzw, vu.vf17, vu.vf02); + // nop | madday.xyzw ACC, vf07, vf18 255 + vu.acc.madda(Mask::xyzw, vu.vf07, vu.vf18.y()); + // nop | maddz.xyzw vf18, vf08, vf18 256 + vu.acc.madd(Mask::xyzw, vu.vf18, vu.vf08, vu.vf18.z()); + // nop | mulaw.xyzw ACC, vf09, vf00 257 + vu.acc.mula(Mask::xyzw, vu.vf09, vu.vf00.w()); + // nop | maddax.xyzw ACC, vf06, vf19 258 + vu.acc.madda(Mask::xyzw, vu.vf06, vu.vf19.x()); + // nop | madday.xyzw ACC, vf07, vf19 259 + vu.acc.madda(Mask::xyzw, vu.vf07, vu.vf19.y()); + // div Q, vf12.x, vf18.w | mul.xyz vf17, vf17, Q 260 + vu.vf17.mul(Mask::xyz, vu.vf17, vu.Q); vu.Q = vu.vf12.x() / vu.vf18.w(); + // nop | maddz.xyzw vf19, vf08, vf19 261 + vu.acc.madd(Mask::xyzw, vu.vf19, vu.vf08, vu.vf19.z()); + // nop | mulaw.xyzw ACC, vf09, vf00 262 + vu.acc.mula(Mask::xyzw, vu.vf09, vu.vf00.w()); + // nop | maddax.xyzw ACC, vf06, vf20 263 + vu.acc.madda(Mask::xyzw, vu.vf06, vu.vf20.x()); + // nop | madday.xyzw ACC, vf07, vf20 264 + vu.acc.madda(Mask::xyzw, vu.vf07, vu.vf20.y()); + // nop | maddz.xyzw vf20, vf08, vf20 265 + vu.acc.madd(Mask::xyzw, vu.vf20, vu.vf08, vu.vf20.z()); + // nop | mul.xyzw vf22, vf18, vf02 266 + vu.vf22.mul(Mask::xyzw, vu.vf18, vu.vf02); + // div Q, vf12.x, vf19.w | mul.xyz vf18, vf18, Q 267 + vu.vf18.mul(Mask::xyz, vu.vf18, vu.Q); vu.Q = vu.vf12.x() / vu.vf19.w(); + // nop | add.xy vf25, vf17, vf03 268 + vu.vf25.add(Mask::xy, vu.vf17, vu.vf03); + // nop | add.xyzw vf17, vf17, vf05 269 + vu.vf17.add(Mask::xyzw, vu.vf17, vu.vf05); + // nop | opmula.xyz ACC, vf29, vf30 270 + vu.acc.opmula(vu.vf29, vu.vf30); + // nop | opmsub.xyz vf29, vf30, vf29 271 + vu.acc.opmsub(vu.vf29, vu.vf30, vu.vf29); + // nop | mul.xyzw vf23, vf19, vf02 272 + vu.vf23.mul(Mask::xyzw, vu.vf19, vu.vf02); + // nop | mul.xyz vf29, vf29, vf15 273 + vu.vf29.mul(Mask::xyz, vu.vf29, vu.vf15); + // div Q, vf12.x, vf20.w | mul.xyz vf19, vf19, Q 274 + vu.vf19.mul(Mask::xyz, vu.vf19, vu.Q); vu.Q = vu.vf12.x() / vu.vf20.w(); + // nop | mul.xyzw vf24, vf20, vf02 275 + vu.vf24.mul(Mask::xyzw, vu.vf20, vu.vf02); + // nop | mul.xy vf25, vf25, vf04 276 + vu.vf25.mul(Mask::xy, vu.vf25, vu.vf04); + // nop | mini.xyzw vf10, vf10, vf17 277 + vu.vf10.mini(Mask::xyzw, vu.vf10, vu.vf17); + // nop | max.xyzw vf11, vf11, vf17 278 + vu.vf11.max(Mask::xyzw, vu.vf11, vu.vf17); + // nop | ftoi4.xyzw vf17, vf17 279 + vu.vf17.ftoi4(Mask::xyzw, vu.vf17); + // nop | add.xy vf26, vf18, vf03 280 + vu.vf26.add(Mask::xy, vu.vf18, vu.vf03); + // nop | mul.xyz vf20, vf20, Q 281 + vu.vf20.mul(Mask::xyz, vu.vf20, vu.Q); + // nop | add.xyzw vf18, vf18, vf05 282 + vu.vf18.add(Mask::xyzw, vu.vf18, vu.vf05); + // nop | addy.x vf29, vf29, vf29 283 + vu.vf29.add(Mask::x, vu.vf29, vu.vf29.y()); + // sq.xyzw vf25, 4(vi02) | mini.xyzw vf10, vf10, vf18 284 + vu.vf10.mini(Mask::xyzw, vu.vf10, vu.vf18); sq_buffer(Mask::xyzw, vu.vf25, vu.vi02 + 4); + // sq.xyzw vf17, 5(vi02) | max.xyzw vf11, vf11, vf18 285 + vu.vf11.max(Mask::xyzw, vu.vf11, vu.vf18); sq_buffer(Mask::xyzw, vu.vf17, vu.vi02 + 5); + // nop | clipw.xyz vf21, vf21 286 + cf = clip(vu.vf21, vu.vf21.w(), cf); + // nop | mul.xy vf26, vf26, vf04 287 + vu.vf26.mul(Mask::xy, vu.vf26, vu.vf04); + // nop | addz.x vf29, vf29, vf29 288 + sf0 = vu.vf29.add_and_set_sf_s(Mask::x, vu.vf29, vu.vf29.z()); + // nop | ftoi4.xyzw vf18, vf18 289 + vu.vf18.ftoi4(Mask::xyzw, vu.vf18); + // nop | add.xy vf27, vf19, vf03 290 + vu.vf27.add(Mask::xy, vu.vf19, vu.vf03); + // sq.xyzw vf26, 6(vi02) | add.xyzw vf19, vf19, vf05 291 + vu.vf19.add(Mask::xyzw, vu.vf19, vu.vf05); sq_buffer(Mask::xyzw, vu.vf26, vu.vi02 + 6); + // fsand vi01, 0x2 | clipw.xyz vf22, vf22 292 + cf = clip(vu.vf22, vu.vf22.w(), cf); fsand(vu.vi01, 0x2, sf0); + + // sq.xyzw vf18, 7(vi02) | clipw.xyz vf23, vf23 293 + cf = clip(vu.vf23, vu.vf23.w(), cf); sq_buffer(Mask::xyzw, vu.vf18, vu.vi02 + 7); + // nop | clipw.xyz vf24, vf24 294 + cf = clip(vu.vf24, vu.vf24.w(), cf); + // nop | add.xy vf28, vf20, vf03 295 + vu.vf28.add(Mask::xy, vu.vf20, vu.vf03); + // nop | add.xyzw vf20, vf20, vf05 296 + vu.vf20.add(Mask::xyzw, vu.vf20, vu.vf05); + // nop | mul.xy vf27, vf27, vf04 297 + vu.vf27.mul(Mask::xy, vu.vf27, vu.vf04); + // nop | mini.xyzw vf10, vf10, vf19 298 + vu.vf10.mini(Mask::xyzw, vu.vf10, vu.vf19); + // nop | max.xyzw vf11, vf11, vf19 299 + vu.vf11.max(Mask::xyzw, vu.vf11, vu.vf19); + // BRANCH! + // ibeq vi00, vi01, L17 | mul.xy vf28, vf28, vf04 300 + vu.vf28.mul(Mask::xy, vu.vf28, vu.vf04); bc = (vu.vi01 == 0); + // nop | mini.xyzw vf10, vf10, vf20 301 + vu.vf10.mini(Mask::xyzw, vu.vf10, vu.vf20); + if (bc) { goto L17; } + + // BRANCH! + // b L18 | nop 302 + bc = true; + // lq.xyzw vf31, 887(vi00) | max.xyzw vf11, vf11, vf20 303 + vu.vf11.max(Mask::xyzw, vu.vf11, vu.vf20); lq_buffer(Mask::xyzw, vu.vf31, 887); + if (bc) { goto L18; } + + L17: + // lq.xyzw vf31, 886(vi00) | max.xyzw vf11, vf11, vf20 304 + vu.vf11.max(Mask::xyzw, vu.vf11, vu.vf20); lq_buffer(Mask::xyzw, vu.vf31, 886); + L18: + // fcand vi01, 0xffffff | ftoi4.xyzw vf19, vf19 305 + vu.vf19.ftoi4(Mask::xyzw, vu.vf19); fcand(vu.vi01, 0xffffff, cf); + + // BRANCH! + // ibne vi00, vi01, L20 | max.xyzw vf11, vf11, vf20 306 + vu.vf11.max(Mask::xyzw, vu.vf11, vu.vf20); bc = (vu.vi01 != 0); + // iaddi vi08, vi08, -0x1 | nop 307 + vu.vi08 = vu.vi08 + -1; + if (bc) { goto L20; } + + // sq.xyzw vf27, 8(vi02) | ftoi4.xyzw vf20, vf20 308 + vu.vf20.ftoi4(Mask::xyzw, vu.vf20); sq_buffer(Mask::xyzw, vu.vf27, vu.vi02 + 8); + // sq.xyzw vf31, 3(vi02) | nop 309 + sq_buffer(Mask::xyzw, vu.vf31, vu.vi02 + 3); + // sq.xyzw vf19, 9(vi02) | nop 310 + sq_buffer(Mask::xyzw, vu.vf19, vu.vi02 + 9); + // sq.xyzw vf28, 10(vi02) | nop 311 + sq_buffer(Mask::xyzw, vu.vf28, vu.vi02 + 10); + // sq.xyzw vf20, 11(vi02) | nop 312 + sq_buffer(Mask::xyzw, vu.vf20, vu.vi02 + 11); + // xgkick vi02 | nop 313 + xgkick(vu.vi02); + // mtir vi02, vf01.y | nop 314 + vu.vi02 = vu.vf01.y_as_u16(); + // mr32.xyzw vf01, vf01 | nop 315 + vu.vf01.mr32(Mask::xyzw, vu.vf01); + L19: + // BRANCH! + // ibgtz vi08, L14 | nop 316 + bc = ((s16)vu.vi08) > 0; + // nop | nop 317 + + if (bc) { goto L14; } + + // nop | nop :e 318 + + // nop | nop 319 + + return; + + L20: + // sq.xyzw vf21, 1000(vi00) | nop 320 + sq_buffer(Mask::xyzw, vu.vf21, 1000); + // sq.xyzw vf22, 1003(vi00) | nop 321 + sq_buffer(Mask::xyzw, vu.vf22, 1003); + // sq.xyzw vf23, 1006(vi00) | nop 322 + sq_buffer(Mask::xyzw, vu.vf23, 1006); + // sq.xyzw vf24, 1009(vi00) | nop 323 + sq_buffer(Mask::xyzw, vu.vf24, 1009); + // sq.xyzw vf31, 942(vi00) | nop 324 + sq_buffer(Mask::xyzw, vu.vf31, 942); + // mfir.x vf29, vi02 | nop 325 + vu.vf29.mfir(Mask::x, vu.vi02); + // mfir.y vf29, vi03 | nop 326 + vu.vf29.mfir(Mask::y, vu.vi03); + // mfir.z vf29, vi07 | nop 327 + vu.vf29.mfir(Mask::z, vu.vi07); + // BRANCH! + // bal vi15, L37 | nop 328 + // mfir.w vf29, vi08 | nop 329 + vu.vf29.mfir(Mask::w, vu.vi08); + vu.vi15 = 330; + goto L37; + + INSTR_330: + // mtir vi08, vf29.w | nop 330 + vu.vi08 = vu.vf29.w_as_u16(); + // mtir vi03, vf29.y | nop 331 + vu.vi03 = vu.vf29.y_as_u16(); + // mtir vi07, vf29.z | nop 332 + vu.vi07 = vu.vf29.z_as_u16(); + // BRANCH! + // b L19 | nop 333 + bc = true; + // mtir vi02, vf29.x | nop 334 + vu.vi02 = vu.vf29.x_as_u16(); + if (bc) { goto L19; } + + L21: + // iaddiu vi03, vi00, 0x158 | nop 335 + vu.vi03 = 0x158; /* 344 */ + // ilwr.x vi08, vi03 | nop 336 + ilw_buffer(Mask::x, vu.vi08, vu.vi03); + // mtir vi02, vf01.x | nop 337 + vu.vi02 = vu.vf01.x_as_u16(); + // iaddi vi03, vi03, 0x1 | addw.z vf25, vf00, vf00 338 + vu.vf25.add(Mask::z, vu.vf00, vu.vf00.w()); vu.vi03 = vu.vi03 + 1; + // lq.xyzw vf25, 888(vi00) | addw.z vf26, vf00, vf00 339 + vu.vf26.add(Mask::z, vu.vf00, vu.vf00.w()); lq_buffer(Mask::xyzw, vu.vf25, 888); + // lq.xyzw vf29, 889(vi00) | addw.z vf27, vf00, vf00 340 + vu.vf27.add(Mask::z, vu.vf00, vu.vf00.w()); lq_buffer(Mask::xyzw, vu.vf29, 889); + // lq.xyzw vf30, 891(vi00) | addw.z vf28, vf00, vf00 341 + vu.vf28.add(Mask::z, vu.vf00, vu.vf00.w()); lq_buffer(Mask::xyzw, vu.vf30, 891); + // lq.xyzw vf06, 0(vi00) | nop 342 + lq_buffer(Mask::xyzw, vu.vf06, 0); + // lq.xyzw vf07, 1(vi00) | nop 343 + lq_buffer(Mask::xyzw, vu.vf07, 1); + // lq.xyzw vf08, 2(vi00) | nop 344 + lq_buffer(Mask::xyzw, vu.vf08, 2); + // lq.xyzw vf09, 3(vi00) | nop 345 + lq_buffer(Mask::xyzw, vu.vf09, 3); + // mtir vi01, vf01.y | nop 346 + vu.vi01 = vu.vf01.y_as_u16(); + // sq.xyzw vf25, 0(vi02) | nop 347 + sq_buffer(Mask::xyzw, vu.vf25, vu.vi02); + // sq.xyzw vf29, 1(vi02) | nop 348 + sq_buffer(Mask::xyzw, vu.vf29, vu.vi02 + 1); + // sq.xyzw vf30, 2(vi02) | nop 349 + sq_buffer(Mask::xyzw, vu.vf30, vu.vi02 + 2); + // sq.xyzw vf25, 0(vi01) | nop 350 + sq_buffer(Mask::xyzw, vu.vf25, vu.vi01); + // sq.xyzw vf29, 1(vi01) | nop 351 + sq_buffer(Mask::xyzw, vu.vf29, vu.vi01 + 1); + // sq.xyzw vf30, 2(vi01) | nop 352 + sq_buffer(Mask::xyzw, vu.vf30, vu.vi01 + 2); + L22: + // lqi.xyzw vf16, vi03 | nop 353 + lq_buffer(Mask::xyzw, vu.vf16, vu.vi03++); + // nop | nop 354 + + // nop | nop 355 + + // nop | nop 356 + + // mtir vi01, vf16.w | nop 357 + vu.vi01 = vu.vf16.w_as_u16(); + // mtir vi04, vf16.x | nop 358 + vu.vi04 = vu.vf16.x_as_u16(); + // mtir vi05, vf16.y | nop 359 + vu.vi05 = vu.vf16.y_as_u16(); + // mtir vi06, vf16.z | nop 360 + vu.vi06 = vu.vf16.z_as_u16(); + // BRANCH! + // ibeq vi00, vi01, L23 | nop 361 + bc = (vu.vi01 == 0); + // lq.xyzw vf17, 4(vi04) | nop 362 + lq_buffer(Mask::xyzw, vu.vf17, vu.vi04 + 4); + if (bc) { goto L23; } + + // lq.xyzw vf18, 4(vi05) | nop 363 + lq_buffer(Mask::xyzw, vu.vf18, vu.vi05 + 4); + // BRANCH! + // b L24 | nop 364 + bc = true; + // lq.xyzw vf19, 4(vi06) | nop 365 + lq_buffer(Mask::xyzw, vu.vf19, vu.vi06 + 4); + if (bc) { goto L24; } + + L23: + // lq.xyzw vf19, 4(vi05) | nop 366 + lq_buffer(Mask::xyzw, vu.vf19, vu.vi05 + 4); + // lq.xyzw vf18, 4(vi06) | nop 367 + lq_buffer(Mask::xyzw, vu.vf18, vu.vi06 + 4); + L24: + // nop | mulaw.xyzw ACC, vf09, vf00 368 + vu.acc.mula(Mask::xyzw, vu.vf09, vu.vf00.w()); + // move.xyzw vf15, vf17 | maddax.xyzw ACC, vf06, vf17 369 + vu.acc.madda(Mask::xyzw, vu.vf06, vu.vf17.x()); vu.vf15.move(Mask::xyzw, vu.vf17); + // nop | madday.xyzw ACC, vf07, vf17 370 + vu.acc.madda(Mask::xyzw, vu.vf07, vu.vf17.y()); + // nop | sub.xyzw vf29, vf18, vf17 371 + vu.vf29.sub(Mask::xyzw, vu.vf18, vu.vf17); + // nop | sub.xyzw vf30, vf19, vf17 372 + vu.vf30.sub(Mask::xyzw, vu.vf19, vu.vf17); + // nop | maddz.xyzw vf17, vf08, vf17 373 + vu.acc.madd(Mask::xyzw, vu.vf17, vu.vf08, vu.vf17.z()); + // nop | mulaw.xyzw ACC, vf09, vf00 374 + vu.acc.mula(Mask::xyzw, vu.vf09, vu.vf00.w()); + // div Q, vf12.x, vf17.w | maddax.xyzw ACC, vf06, vf18 375 + vu.acc.madda(Mask::xyzw, vu.vf06, vu.vf18.x()); vu.Q = vu.vf12.x() / vu.vf17.w(); + // nop | madday.xyzw ACC, vf07, vf18 376 + vu.acc.madda(Mask::xyzw, vu.vf07, vu.vf18.y()); + // nop | mul.xyzw vf21, vf17, vf02 377 + vu.vf21.mul(Mask::xyzw, vu.vf17, vu.vf02); + // nop | maddz.xyzw vf18, vf08, vf18 378 + vu.acc.madd(Mask::xyzw, vu.vf18, vu.vf08, vu.vf18.z()); + // nop | mulaw.xyzw ACC, vf09, vf00 379 + vu.acc.mula(Mask::xyzw, vu.vf09, vu.vf00.w()); + // nop | maddax.xyzw ACC, vf06, vf19 380 + vu.acc.madda(Mask::xyzw, vu.vf06, vu.vf19.x()); + // nop | madday.xyzw ACC, vf07, vf19 381 + vu.acc.madda(Mask::xyzw, vu.vf07, vu.vf19.y()); + // div Q, vf12.x, vf18.w | mul.xyz vf17, vf17, Q 382 + vu.vf17.mul(Mask::xyz, vu.vf17, vu.Q); vu.Q = vu.vf12.x() / vu.vf18.w(); + // nop | maddz.xyzw vf19, vf08, vf19 383 + vu.acc.madd(Mask::xyzw, vu.vf19, vu.vf08, vu.vf19.z()); + // nop | mul.xyzw vf22, vf18, vf02 384 + vu.vf22.mul(Mask::xyzw, vu.vf18, vu.vf02); + // nop | opmula.xyz ACC, vf29, vf30 385 + vu.acc.opmula(vu.vf29, vu.vf30); + // nop | opmsub.xyz vf29, vf30, vf29 386 + vu.acc.opmsub(vu.vf29, vu.vf30, vu.vf29); + // nop | add.xy vf25, vf17, vf03 387 + vu.vf25.add(Mask::xy, vu.vf17, vu.vf03); + // nop | add.xyzw vf17, vf17, vf05 388 + vu.vf17.add(Mask::xyzw, vu.vf17, vu.vf05); + // div Q, vf12.x, vf19.w | mul.xyz vf18, vf18, Q 389 + vu.vf18.mul(Mask::xyz, vu.vf18, vu.Q); vu.Q = vu.vf12.x() / vu.vf19.w(); + // nop | mul.xyzw vf23, vf19, vf02 390 + vu.vf23.mul(Mask::xyzw, vu.vf19, vu.vf02); + // nop | mul.xyz vf29, vf29, vf15 391 + vu.vf29.mul(Mask::xyz, vu.vf29, vu.vf15); + // nop | mul.xy vf25, vf25, vf04 392 + vu.vf25.mul(Mask::xy, vu.vf25, vu.vf04); + // nop | mini.xyzw vf10, vf10, vf17 393 + vu.vf10.mini(Mask::xyzw, vu.vf10, vu.vf17); + // nop | max.xyzw vf11, vf11, vf17 394 + vu.vf11.max(Mask::xyzw, vu.vf11, vu.vf17); + // nop | ftoi4.xyzw vf17, vf17 395 + vu.vf17.ftoi4(Mask::xyzw, vu.vf17); + // nop | add.xy vf26, vf18, vf03 396 + vu.vf26.add(Mask::xy, vu.vf18, vu.vf03); + // nop | add.xyzw vf18, vf18, vf05 397 + vu.vf18.add(Mask::xyzw, vu.vf18, vu.vf05); + // fcset 0x0 | addy.x vf29, vf29, vf29 398 + vu.vf29.add(Mask::x, vu.vf29, vu.vf29.y()); cf = 0x0; + + // nop | mul.xyz vf19, vf19, Q 399 + vu.vf19.mul(Mask::xyz, vu.vf19, vu.Q); + // sq.xyzw vf25, 4(vi02) | mini.xyzw vf10, vf10, vf18 400 + vu.vf10.mini(Mask::xyzw, vu.vf10, vu.vf18); sq_buffer(Mask::xyzw, vu.vf25, vu.vi02 + 4); + // sq.xyzw vf17, 5(vi02) | max.xyzw vf11, vf11, vf18 401 + vu.vf11.max(Mask::xyzw, vu.vf11, vu.vf18); sq_buffer(Mask::xyzw, vu.vf17, vu.vi02 + 5); + // nop | clipw.xyz vf21, vf21 402 + cf = clip(vu.vf21, vu.vf21.w(), cf); + // nop | mul.xy vf26, vf26, vf04 403 + vu.vf26.mul(Mask::xy, vu.vf26, vu.vf04); + // nop | addz.x vf29, vf29, vf29 404 + sf0 = vu.vf29.add_and_set_sf_s(Mask::x, vu.vf29, vu.vf29.z()); + // nop | ftoi4.xyzw vf18, vf18 405 + vu.vf18.ftoi4(Mask::xyzw, vu.vf18); + // nop | add.xy vf27, vf19, vf03 406 + vu.vf27.add(Mask::xy, vu.vf19, vu.vf03); + // sq.xyzw vf26, 6(vi02) | add.xyzw vf19, vf19, vf05 407 + vu.vf19.add(Mask::xyzw, vu.vf19, vu.vf05); sq_buffer(Mask::xyzw, vu.vf26, vu.vi02 + 6); + // fsand vi01, 0x2 | clipw.xyz vf22, vf22 408 + cf = clip(vu.vf22, vu.vf22.w(), cf); fsand(vu.vi01, 0x2, sf0); + + // sq.xyzw vf18, 7(vi02) | clipw.xyz vf23, vf23 409 + cf = clip(vu.vf23, vu.vf23.w(), cf); sq_buffer(Mask::xyzw, vu.vf18, vu.vi02 + 7); + // BRANCH! + // ibeq vi00, vi01, L25 | mul.xy vf27, vf27, vf04 410 + vu.vf27.mul(Mask::xy, vu.vf27, vu.vf04); bc = (vu.vi01 == 0); + // nop | mini.xyzw vf10, vf10, vf19 411 + vu.vf10.mini(Mask::xyzw, vu.vf10, vu.vf19); + if (bc) { goto L25; } + + // BRANCH! + // b L26 | nop 412 + bc = true; + // lq.xyzw vf31, 887(vi00) | max.xyzw vf11, vf11, vf19 413 + vu.vf11.max(Mask::xyzw, vu.vf11, vu.vf19); lq_buffer(Mask::xyzw, vu.vf31, 887); + if (bc) { goto L26; } + + L25: + // lq.xyzw vf31, 886(vi00) | max.xyzw vf11, vf11, vf19 414 + vu.vf11.max(Mask::xyzw, vu.vf11, vu.vf19); lq_buffer(Mask::xyzw, vu.vf31, 886); + L26: + // fcand vi01, 0x3ffff | ftoi4.xyzw vf19, vf19 415 + vu.vf19.ftoi4(Mask::xyzw, vu.vf19); fcand(vu.vi01, 0x3ffff, cf); + + // BRANCH! + // ibne vi00, vi01, L34 | nop 416 + bc = (vu.vi01 != 0); + // iaddi vi08, vi08, -0x1 | nop 417 + vu.vi08 = vu.vi08 + -1; + if (bc) { goto L34; } + + // sq.xyzw vf27, 8(vi02) | nop 418 + sq_buffer(Mask::xyzw, vu.vf27, vu.vi02 + 8); + // sq.xyzw vf31, 3(vi02) | nop 419 + sq_buffer(Mask::xyzw, vu.vf31, vu.vi02 + 3); + // sq.xyzw vf19, 9(vi02) | nop 420 + sq_buffer(Mask::xyzw, vu.vf19, vu.vi02 + 9); + // xgkick vi02 | nop 421 + xgkick(vu.vi02); + // mtir vi02, vf01.y | nop 422 + vu.vi02 = vu.vf01.y_as_u16(); + // mr32.xyzw vf01, vf01 | nop 423 + vu.vf01.mr32(Mask::xyzw, vu.vf01); + L27: + // BRANCH! + // ibgtz vi08, L22 | nop 424 + bc = ((s16)vu.vi08) > 0; + // nop | nop 425 + + if (bc) { goto L22; } + + // iaddiu vi03, vi00, 0x158 | nop 426 + vu.vi03 = 0x158; /* 344 */ + // ilwr.x vi08, vi03 | nop 427 + ilw_buffer(Mask::x, vu.vi08, vu.vi03); + // iaddi vi03, vi03, 0x1 | nop 428 + vu.vi03 = vu.vi03 + 1; + L28: + // lqi.xyzw vf16, vi03 | nop 429 + lq_buffer(Mask::xyzw, vu.vf16, vu.vi03++); + // nop | nop 430 + + // nop | nop 431 + + // nop | nop 432 + + // mtir vi01, vf16.w | nop 433 + vu.vi01 = vu.vf16.w_as_u16(); + // mtir vi04, vf16.x | nop 434 + vu.vi04 = vu.vf16.x_as_u16(); + // mtir vi05, vf16.y | nop 435 + vu.vi05 = vu.vf16.y_as_u16(); + // mtir vi06, vf16.z | nop 436 + vu.vi06 = vu.vf16.z_as_u16(); + // BRANCH! + // ibne vi00, vi01, L29 | nop 437 + bc = (vu.vi01 != 0); + // lq.xyzw vf17, 174(vi04) | nop 438 + lq_buffer(Mask::xyzw, vu.vf17, vu.vi04 + 174); + if (bc) { goto L29; } + + // lq.xyzw vf18, 174(vi05) | nop 439 + lq_buffer(Mask::xyzw, vu.vf18, vu.vi05 + 174); + // BRANCH! + // b L30 | nop 440 + bc = true; + // lq.xyzw vf19, 174(vi06) | nop 441 + lq_buffer(Mask::xyzw, vu.vf19, vu.vi06 + 174); + if (bc) { goto L30; } + + L29: + // lq.xyzw vf19, 174(vi05) | nop 442 + lq_buffer(Mask::xyzw, vu.vf19, vu.vi05 + 174); + // lq.xyzw vf18, 174(vi06) | nop 443 + lq_buffer(Mask::xyzw, vu.vf18, vu.vi06 + 174); + L30: + // nop | mulaw.xyzw ACC, vf09, vf00 444 + vu.acc.mula(Mask::xyzw, vu.vf09, vu.vf00.w()); + // move.xyzw vf15, vf17 | maddax.xyzw ACC, vf06, vf17 445 + vu.acc.madda(Mask::xyzw, vu.vf06, vu.vf17.x()); vu.vf15.move(Mask::xyzw, vu.vf17); + // nop | madday.xyzw ACC, vf07, vf17 446 + vu.acc.madda(Mask::xyzw, vu.vf07, vu.vf17.y()); + // nop | maddz.xyzw vf17, vf08, vf17 447 + vu.acc.madd(Mask::xyzw, vu.vf17, vu.vf08, vu.vf17.z()); + // nop | mulaw.xyzw ACC, vf09, vf00 448 + vu.acc.mula(Mask::xyzw, vu.vf09, vu.vf00.w()); + // nop | sub.xyzw vf29, vf18, vf15 449 + vu.vf29.sub(Mask::xyzw, vu.vf18, vu.vf15); + // nop | sub.xyzw vf30, vf19, vf15 450 + vu.vf30.sub(Mask::xyzw, vu.vf19, vu.vf15); + // div Q, vf12.x, vf17.w | maddax.xyzw ACC, vf06, vf18 451 + vu.acc.madda(Mask::xyzw, vu.vf06, vu.vf18.x()); vu.Q = vu.vf12.x() / vu.vf17.w(); + // nop | mul.xyzw vf21, vf17, vf02 452 + vu.vf21.mul(Mask::xyzw, vu.vf17, vu.vf02); + // nop | madday.xyzw ACC, vf07, vf18 453 + vu.acc.madda(Mask::xyzw, vu.vf07, vu.vf18.y()); + // nop | maddz.xyzw vf18, vf08, vf18 454 + vu.acc.madd(Mask::xyzw, vu.vf18, vu.vf08, vu.vf18.z()); + // nop | mulaw.xyzw ACC, vf09, vf00 455 + vu.acc.mula(Mask::xyzw, vu.vf09, vu.vf00.w()); + // nop | maddax.xyzw ACC, vf06, vf19 456 + vu.acc.madda(Mask::xyzw, vu.vf06, vu.vf19.x()); + // nop | madday.xyzw ACC, vf07, vf19 457 + vu.acc.madda(Mask::xyzw, vu.vf07, vu.vf19.y()); + // div Q, vf12.x, vf18.w | mul.xyz vf17, vf17, Q 458 + vu.vf17.mul(Mask::xyz, vu.vf17, vu.Q); vu.Q = vu.vf12.x() / vu.vf18.w(); + // nop | maddz.xyzw vf19, vf08, vf19 459 + vu.acc.madd(Mask::xyzw, vu.vf19, vu.vf08, vu.vf19.z()); + // nop | mul.xyzw vf22, vf18, vf02 460 + vu.vf22.mul(Mask::xyzw, vu.vf18, vu.vf02); + // nop | opmula.xyz ACC, vf29, vf30 461 + vu.acc.opmula(vu.vf29, vu.vf30); + // nop | opmsub.xyz vf29, vf30, vf29 462 + vu.acc.opmsub(vu.vf29, vu.vf30, vu.vf29); + // nop | add.xy vf25, vf17, vf03 463 + vu.vf25.add(Mask::xy, vu.vf17, vu.vf03); + // nop | add.xyzw vf17, vf17, vf05 464 + vu.vf17.add(Mask::xyzw, vu.vf17, vu.vf05); + // div Q, vf12.x, vf19.w | mul.xyz vf18, vf18, Q 465 + vu.vf18.mul(Mask::xyz, vu.vf18, vu.Q); vu.Q = vu.vf12.x() / vu.vf19.w(); + // nop | mul.xyzw vf23, vf19, vf02 466 + vu.vf23.mul(Mask::xyzw, vu.vf19, vu.vf02); + // nop | mul.xyz vf29, vf29, vf15 467 + vu.vf29.mul(Mask::xyz, vu.vf29, vu.vf15); + // nop | mul.xy vf25, vf25, vf04 468 + vu.vf25.mul(Mask::xy, vu.vf25, vu.vf04); + // nop | mini.xyzw vf10, vf10, vf17 469 + vu.vf10.mini(Mask::xyzw, vu.vf10, vu.vf17); + // nop | max.xyzw vf11, vf11, vf17 470 + vu.vf11.max(Mask::xyzw, vu.vf11, vu.vf17); + // nop | ftoi4.xyzw vf17, vf17 471 + vu.vf17.ftoi4(Mask::xyzw, vu.vf17); + // nop | add.xy vf26, vf18, vf03 472 + vu.vf26.add(Mask::xy, vu.vf18, vu.vf03); + // nop | add.xyzw vf18, vf18, vf05 473 + vu.vf18.add(Mask::xyzw, vu.vf18, vu.vf05); + // fcset 0x0 | addy.x vf29, vf29, vf29 474 + vu.vf29.add(Mask::x, vu.vf29, vu.vf29.y()); cf = 0x0; + + // nop | mul.xyz vf19, vf19, Q 475 + vu.vf19.mul(Mask::xyz, vu.vf19, vu.Q); + // sq.xyzw vf25, 4(vi02) | mini.xyzw vf10, vf10, vf18 476 + vu.vf10.mini(Mask::xyzw, vu.vf10, vu.vf18); sq_buffer(Mask::xyzw, vu.vf25, vu.vi02 + 4); + // sq.xyzw vf17, 5(vi02) | max.xyzw vf11, vf11, vf18 477 + vu.vf11.max(Mask::xyzw, vu.vf11, vu.vf18); sq_buffer(Mask::xyzw, vu.vf17, vu.vi02 + 5); + // nop | clipw.xyz vf21, vf21 478 + cf = clip(vu.vf21, vu.vf21.w(), cf); + // nop | mul.xy vf26, vf26, vf04 479 + vu.vf26.mul(Mask::xy, vu.vf26, vu.vf04); + // nop | addz.x vf29, vf29, vf29 480 + sf0 = vu.vf29.add_and_set_sf_s(Mask::x, vu.vf29, vu.vf29.z()); + // nop | ftoi4.xyzw vf18, vf18 481 + vu.vf18.ftoi4(Mask::xyzw, vu.vf18); + // nop | add.xy vf27, vf19, vf03 482 + vu.vf27.add(Mask::xy, vu.vf19, vu.vf03); + // sq.xyzw vf26, 6(vi02) | add.xyzw vf19, vf19, vf05 483 + vu.vf19.add(Mask::xyzw, vu.vf19, vu.vf05); sq_buffer(Mask::xyzw, vu.vf26, vu.vi02 + 6); + // fsand vi01, 0x2 | clipw.xyz vf22, vf22 484 + cf = clip(vu.vf22, vu.vf22.w(), cf); fsand(vu.vi01, 0x2, sf0); + + // sq.xyzw vf18, 7(vi02) | clipw.xyz vf23, vf23 485 + cf = clip(vu.vf23, vu.vf23.w(), cf); sq_buffer(Mask::xyzw, vu.vf18, vu.vi02 + 7); + // BRANCH! + // ibeq vi00, vi01, L31 | mul.xy vf27, vf27, vf04 486 + vu.vf27.mul(Mask::xy, vu.vf27, vu.vf04); bc = (vu.vi01 == 0); + // nop | mini.xyzw vf10, vf10, vf19 487 + vu.vf10.mini(Mask::xyzw, vu.vf10, vu.vf19); + if (bc) { goto L31; } + + // BRANCH! + // b L32 | nop 488 + bc = true; + // lq.xyzw vf31, 887(vi00) | max.xyzw vf11, vf11, vf19 489 + vu.vf11.max(Mask::xyzw, vu.vf11, vu.vf19); lq_buffer(Mask::xyzw, vu.vf31, 887); + if (bc) { goto L32; } + + L31: + // lq.xyzw vf31, 886(vi00) | max.xyzw vf11, vf11, vf19 490 + vu.vf11.max(Mask::xyzw, vu.vf11, vu.vf19); lq_buffer(Mask::xyzw, vu.vf31, 886); + L32: + // fcand vi01, 0x3ffff | ftoi4.xyzw vf19, vf19 491 + vu.vf19.ftoi4(Mask::xyzw, vu.vf19); fcand(vu.vi01, 0x3ffff, cf); + + // BRANCH! + // ibne vi00, vi01, L35 | nop 492 + bc = (vu.vi01 != 0); + // iaddi vi08, vi08, -0x1 | nop 493 + vu.vi08 = vu.vi08 + -1; + if (bc) { goto L35; } + + // sq.xyzw vf27, 8(vi02) | nop 494 + sq_buffer(Mask::xyzw, vu.vf27, vu.vi02 + 8); + // sq.xyzw vf31, 3(vi02) | nop 495 + sq_buffer(Mask::xyzw, vu.vf31, vu.vi02 + 3); + // sq.xyzw vf19, 9(vi02) | nop 496 + sq_buffer(Mask::xyzw, vu.vf19, vu.vi02 + 9); + // xgkick vi02 | nop 497 + xgkick(vu.vi02); + // mtir vi02, vf01.y | nop 498 + vu.vi02 = vu.vf01.y_as_u16(); + // mr32.xyzw vf01, vf01 | nop 499 + vu.vf01.mr32(Mask::xyzw, vu.vf01); + L33: + // BRANCH! + // ibgtz vi08, L28 | nop 500 + bc = ((s16)vu.vi08) > 0; + // nop | nop 501 + + if (bc) { goto L28; } + + // nop | nop :e 502 + + // nop | nop 503 + + return; + + L34: + // sq.xyzw vf21, 1000(vi00) | nop 504 + sq_buffer(Mask::xyzw, vu.vf21, 1000); + // sq.xyzw vf22, 1003(vi00) | nop 505 + sq_buffer(Mask::xyzw, vu.vf22, 1003); + // sq.xyzw vf23, 1006(vi00) | nop 506 + sq_buffer(Mask::xyzw, vu.vf23, 1006); + // sq.xyzw vf31, 942(vi00) | nop 507 + sq_buffer(Mask::xyzw, vu.vf31, 942); + // mfir.x vf29, vi02 | nop 508 + vu.vf29.mfir(Mask::x, vu.vi02); + // mfir.y vf29, vi03 | nop 509 + vu.vf29.mfir(Mask::y, vu.vi03); + // mfir.z vf29, vi07 | nop 510 + vu.vf29.mfir(Mask::z, vu.vi07); + // BRANCH! + // bal vi15, L36 | nop 511 + // mfir.w vf29, vi08 | nop 512 + vu.vf29.mfir(Mask::w, vu.vi08); + vu.vi15 = 513; + goto L36; + + INSTR_513: + // mtir vi08, vf29.w | nop 513 + vu.vi08 = vu.vf29.w_as_u16(); + // mtir vi03, vf29.y | nop 514 + vu.vi03 = vu.vf29.y_as_u16(); + // mtir vi07, vf29.z | nop 515 + vu.vi07 = vu.vf29.z_as_u16(); + // BRANCH! + // b L27 | nop 516 + bc = true; + // mtir vi02, vf29.x | nop 517 + vu.vi02 = vu.vf29.x_as_u16(); + if (bc) { goto L27; } + + L35: + // sq.xyzw vf21, 1000(vi00) | nop 518 + sq_buffer(Mask::xyzw, vu.vf21, 1000); + // sq.xyzw vf22, 1003(vi00) | nop 519 + sq_buffer(Mask::xyzw, vu.vf22, 1003); + // sq.xyzw vf23, 1006(vi00) | nop 520 + sq_buffer(Mask::xyzw, vu.vf23, 1006); + // sq.xyzw vf31, 942(vi00) | nop 521 + sq_buffer(Mask::xyzw, vu.vf31, 942); + // mfir.x vf29, vi02 | nop 522 + vu.vf29.mfir(Mask::x, vu.vi02); + // mfir.y vf29, vi03 | nop 523 + vu.vf29.mfir(Mask::y, vu.vi03); + // mfir.z vf29, vi07 | nop 524 + vu.vf29.mfir(Mask::z, vu.vi07); + // BRANCH! + // bal vi15, L36 | nop 525 + // mfir.w vf29, vi08 | nop 526 + vu.vf29.mfir(Mask::w, vu.vi08); + vu.vi15 = 527; + goto L36; + + INSTR_527: + // mtir vi08, vf29.w | nop 527 + vu.vi08 = vu.vf29.w_as_u16(); + // mtir vi03, vf29.y | nop 528 + vu.vi03 = vu.vf29.y_as_u16(); + // mtir vi07, vf29.z | nop 529 + vu.vi07 = vu.vf29.z_as_u16(); + // BRANCH! + // b L33 | nop 530 + bc = true; + // mtir vi02, vf29.x | nop 531 + vu.vi02 = vu.vf29.x_as_u16(); + if (bc) { goto L33; } + + L36: + // sq.xyzw vf00, 893(vi00) | nop 532 + sq_buffer(Mask::xyzw, vu.vf00, 893); + // sq.xyzw vf00, 900(vi00) | nop 533 + sq_buffer(Mask::xyzw, vu.vf00, 900); + // sq.xyzw vf00, 907(vi00) | nop 534 + sq_buffer(Mask::xyzw, vu.vf00, 907); + // sq.xyzw vf00, 914(vi00) | nop 535 + sq_buffer(Mask::xyzw, vu.vf00, 914); + // sq.xyzw vf00, 921(vi00) | nop 536 + sq_buffer(Mask::xyzw, vu.vf00, 921); + // sq.xyzw vf00, 928(vi00) | nop 537 + sq_buffer(Mask::xyzw, vu.vf00, 928); + // iaddiu vi01, vi00, 0x2d4 | nop 538 + vu.vi01 = 0x2d4; /* 724 */ + // isw.z vi01, 893(vi00) | nop 539 + isw_buffer(Mask::z, vu.vi01, 893); + // iaddiu vi01, vi00, 0x2d6 | nop 540 + vu.vi01 = 0x2d6; /* 726 */ + // isw.z vi01, 900(vi00) | nop 541 + isw_buffer(Mask::z, vu.vi01, 900); + // iaddiu vi01, vi00, 0x2d8 | nop 542 + vu.vi01 = 0x2d8; /* 728 */ + // isw.z vi01, 907(vi00) | nop 543 + isw_buffer(Mask::z, vu.vi01, 907); + // iaddiu vi01, vi00, 0x2da | nop 544 + vu.vi01 = 0x2da; /* 730 */ + // isw.z vi01, 914(vi00) | nop 545 + isw_buffer(Mask::z, vu.vi01, 914); + // iaddiu vi01, vi00, 0x2dc | nop 546 + vu.vi01 = 0x2dc; /* 732 */ + // isw.z vi01, 921(vi00) | nop 547 + isw_buffer(Mask::z, vu.vi01, 921); + // iaddiu vi01, vi00, 0x2de | nop 548 + vu.vi01 = 0x2de; /* 734 */ + // isw.z vi01, 928(vi00) | nop 549 + isw_buffer(Mask::z, vu.vi01, 928); + // iaddiu vi03, vi00, 0x3b0 | nop 550 + vu.vi03 = 0x3b0; /* 944 */ + // iaddiu vi04, vi00, 0x3af | nop 551 + vu.vi04 = 0x3af; /* 943 */ + // mfir.x vf31, vi15 | nop 552 + vu.vf31.mfir(Mask::x, vu.vi15); + // iaddi vi05, vi00, 0x0 | nop 553 + vu.vi05 = 0; + // BRANCH! + // bal vi15, L38 | nop 554 + // iaddiu vi07, vi00, 0x3e8 | nop 555 + vu.vi07 = 0x3e8; /* 1000 */ + vu.vi15 = 556; + goto L38; + + INSTR_556: + // BRANCH! + // bal vi15, L38 | nop 556 + // iaddiu vi07, vi00, 0x3eb | nop 557 + vu.vi07 = 0x3eb; /* 1003 */ + vu.vi15 = 558; + goto L38; + + INSTR_558: + // BRANCH! + // bal vi15, L38 | nop 558 + // iaddiu vi07, vi00, 0x3ee | nop 559 + vu.vi07 = 0x3ee; /* 1006 */ + vu.vi15 = 560; + goto L38; + + INSTR_560: + // BRANCH! + // b L47 | nop 560 + bc = true; + // nop | nop 561 + + if (bc) { goto L47; } + + L37: + // sq.xyzw vf00, 893(vi00) | nop 562 + sq_buffer(Mask::xyzw, vu.vf00, 893); + // sq.xyzw vf00, 900(vi00) | nop 563 + sq_buffer(Mask::xyzw, vu.vf00, 900); + // sq.xyzw vf00, 907(vi00) | nop 564 + sq_buffer(Mask::xyzw, vu.vf00, 907); + // sq.xyzw vf00, 914(vi00) | nop 565 + sq_buffer(Mask::xyzw, vu.vf00, 914); + // sq.xyzw vf00, 921(vi00) | nop 566 + sq_buffer(Mask::xyzw, vu.vf00, 921); + // sq.xyzw vf00, 928(vi00) | nop 567 + sq_buffer(Mask::xyzw, vu.vf00, 928); + // iaddiu vi01, vi00, 0x2d4 | nop 568 + vu.vi01 = 0x2d4; /* 724 */ + // isw.z vi01, 893(vi00) | nop 569 + isw_buffer(Mask::z, vu.vi01, 893); + // iaddiu vi01, vi00, 0x2d6 | nop 570 + vu.vi01 = 0x2d6; /* 726 */ + // isw.z vi01, 900(vi00) | nop 571 + isw_buffer(Mask::z, vu.vi01, 900); + // iaddiu vi01, vi00, 0x2d8 | nop 572 + vu.vi01 = 0x2d8; /* 728 */ + // isw.z vi01, 907(vi00) | nop 573 + isw_buffer(Mask::z, vu.vi01, 907); + // iaddiu vi01, vi00, 0x2da | nop 574 + vu.vi01 = 0x2da; /* 730 */ + // isw.z vi01, 914(vi00) | nop 575 + isw_buffer(Mask::z, vu.vi01, 914); + // iaddiu vi01, vi00, 0x2dc | nop 576 + vu.vi01 = 0x2dc; /* 732 */ + // isw.z vi01, 921(vi00) | nop 577 + isw_buffer(Mask::z, vu.vi01, 921); + // iaddiu vi01, vi00, 0x2de | nop 578 + vu.vi01 = 0x2de; /* 734 */ + // isw.z vi01, 928(vi00) | nop 579 + isw_buffer(Mask::z, vu.vi01, 928); + // iaddiu vi03, vi00, 0x3b0 | nop 580 + vu.vi03 = 0x3b0; /* 944 */ + // iaddiu vi04, vi00, 0x3af | nop 581 + vu.vi04 = 0x3af; /* 943 */ + // mfir.x vf31, vi15 | nop 582 + vu.vf31.mfir(Mask::x, vu.vi15); + // iaddi vi05, vi00, 0x0 | nop 583 + vu.vi05 = 0; + // BRANCH! + // bal vi15, L38 | nop 584 + // iaddiu vi07, vi00, 0x3e8 | nop 585 + vu.vi07 = 0x3e8; /* 1000 */ + vu.vi15 = 586; + goto L38; + + INSTR_586: + // BRANCH! + // bal vi15, L38 | nop 586 + // iaddiu vi07, vi00, 0x3eb | nop 587 + vu.vi07 = 0x3eb; /* 1003 */ + vu.vi15 = 588; + goto L38; + + INSTR_588: + // BRANCH! + // bal vi15, L38 | nop 588 + // iaddiu vi07, vi00, 0x3ee | nop 589 + vu.vi07 = 0x3ee; /* 1006 */ + vu.vi15 = 590; + goto L38; + + INSTR_590: + // BRANCH! + // bal vi15, L38 | nop 590 + // iaddiu vi07, vi00, 0x3f1 | nop 591 + vu.vi07 = 0x3f1; /* 1009 */ + vu.vi15 = 592; + goto L38; + + INSTR_592: + // BRANCH! + // b L47 | nop 592 + bc = true; + // nop | nop 593 + + if (bc) { goto L47; } + + L38: + // iaddiu vi09, vi00, 0x37d | nop 594 + vu.vi09 = 0x37d; /* 893 */ + L39: + // iaddi vi10, vi00, 0x0 | nop 595 + vu.vi10 = 0; + L40: + // isubiu vi01, vi09, 0x3a7 | nop 596 + vu.vi01 = vu.vi09 - 0x3a7; /* 935 */ + // ilwr.y vi08, vi09 | nop 597 + ilw_buffer(Mask::y, vu.vi08, vu.vi09); + // BRANCH! + // ibgez vi01, L44 | nop 598 + bc = ((s16)vu.vi01) >= 0; + // ilwr.z vi06, vi09 | nop 599 + ilw_buffer(Mask::z, vu.vi06, vu.vi09); + if (bc) { goto L44; } + + // lq.xyzw vf15, 0(vi07) | nop 600 + lq_buffer(Mask::xyzw, vu.vf15, vu.vi07); + // lq.xyzw vf14, 0(vi08) | nop 601 + lq_buffer(Mask::xyzw, vu.vf14, vu.vi08); + // BRANCH! + // ibne vi00, vi08, L41 | nop 602 + bc = (vu.vi08 != 0); + // iswr.y vi07, vi09 | nop 603 + isw_buffer(Mask::y, vu.vi07, vu.vi09); + if (bc) { goto L41; } + + // jalr vi11, vi06 | nop 604 + // ASSERT(false); + // iswr.x vi07, vi09 | nop 605 + isw_buffer(Mask::x, vu.vi07, vu.vi09); + handle_jalr_to_end_block(vu.vi06, sf0, sf1); + // nop | nop 606 + + // nop | nop 607 + + // nop | nop 608 + + // fsand vi02, 0x2 | nop 609 + fsand(vu.vi02, 0x2, sf1); + + // BRANCH! + // ibne vi00, vi02, L45 | nop 610 + bc = (vu.vi02 != 0); + // nop | nop 611 + + if (bc) { goto L45; } + + // BRANCH! + // b L40 | nop 612 + bc = true; + // iaddi vi09, vi09, 0x7 | nop 613 + vu.vi09 = vu.vi09 + 7; + if (bc) { goto L40; } + + L41: + // jalr vi11, vi06 | nop 614 + // ASSERT(false); + // nop | nop 615 + handle_jalr_to_end_block(vu.vi06, sf0, sf1); + + // nop | nop 616 + + // nop | nop 617 + + // fsand vi01, 0x2 | nop 618 + fsand(vu.vi01, 0x2, sf0); + + // fsand vi02, 0x2 | subw.w vf31, vf30, vf31 619 + vu.vf31.sub(Mask::w, vu.vf30, vu.vf31.w()); fsand(vu.vi02, 0x2, sf1); + + // BRANCH! + // ibne vi00, vi01, L43 | nop 620 + bc = (vu.vi01 != 0); + // nop | nop 621 + + if (bc) { goto L43; } + + // BRANCH! + // ibne vi00, vi02, L42 | nop 622 + bc = (vu.vi02 != 0); + // div Q, vf30.w, vf31.w | nop 623 + vu.Q = vu.vf30.w() / vu.vf31.w(); + if (bc) { goto L42; } + + // BRANCH! + // b L40 | nop 624 + bc = true; + // iaddi vi09, vi09, 0x7 | nop 625 + vu.vi09 = vu.vi09 + 7; + if (bc) { goto L40; } + + L42: + // BRANCH! + // bal vi11, L52 | nop 626 + // iaddi vi07, vi09, 0x1 | nop 627 + vu.vi07 = vu.vi09 + 1; + // if (bc) { goto L52; } + handle_bal52(); + + // sq.xyzw vf16, 1(vi09) | nop 628 + sq_buffer(Mask::xyzw, vu.vf16, vu.vi09 + 1); + // BRANCH! + // b L40 | nop 629 + bc = true; + // iaddi vi09, vi09, 0x7 | nop 630 + vu.vi09 = vu.vi09 + 7; + if (bc) { goto L40; } + + L43: + // BRANCH! + // ibne vi00, vi02, L45 | nop 631 + bc = (vu.vi02 != 0); + // div Q, vf30.w, vf31.w | nop 632 + vu.Q = vu.vf30.w() / vu.vf31.w(); + if (bc) { goto L45; } + + // BRANCH! + // bal vi11, L52 | nop 633 + + // nop | nop 634 + + handle_bal52(); + + // sq.xyzw vf16, 4(vi09) | nop 635 + sq_buffer(Mask::xyzw, vu.vf16, vu.vi09 + 4); + // iaddi vi09, vi09, 0x7 | nop 636 + vu.vi09 = vu.vi09 + 7; + // isw.x vi09, 935(vi10) | nop 637 + isw_buffer(Mask::x, vu.vi09, vu.vi10 + 935); + // isw.y vi07, 935(vi10) | nop 638 + isw_buffer(Mask::y, vu.vi07, vu.vi10 + 935); + // iaddi vi10, vi10, 0x1 | nop 639 + vu.vi10 = vu.vi10 + 1; + // BRANCH! + // b L40 | nop 640 + bc = true; + // iaddi vi07, vi09, -0x3 | nop 641 + vu.vi07 = vu.vi09 + -3; + if (bc) { goto L40; } + + L44: + // lq.xyzw vf14, 0(vi07) | nop 642 + lq_buffer(Mask::xyzw, vu.vf14, vu.vi07); + // iaddi vi05, vi05, 0x1 | nop 643 + vu.vi05 = vu.vi05 + 1; + // div Q, vf00.w, vf14.w | nop 644 + vu.Q = vu.vf00.w() / vu.vf14.w(); + // nop | mul.xyzw vf14, vf14, vf13 645 + vu.vf14.mul(Mask::xyzw, vu.vf14, vu.vf13); + // iaddi vi03, vi03, 0x2 | nop 646 + vu.vi03 = vu.vi03 + 2; + // waitq | subw.w vf14, vf00, vf00 647 + vu.vf14.sub(Mask::w, vu.vf00, vu.vf00.w()); + // nop | mul.xyz vf14, vf14, Q 648 + vu.vf14.mul(Mask::xyz, vu.vf14, vu.Q); + // nop | add.xy vf26, vf14, vf03 649 + vu.vf26.add(Mask::xy, vu.vf14, vu.vf03); + // nop | add.xyzw vf14, vf14, vf05 650 + vu.vf14.add(Mask::xyzw, vu.vf14, vu.vf05); + // nop | mul.xy vf26, vf26, vf04 651 + vu.vf26.mul(Mask::xy, vu.vf26, vu.vf04); + // nop | mini.xyzw vf10, vf10, vf14 652 + vu.vf10.mini(Mask::xyzw, vu.vf10, vu.vf14); + // nop | max.xyzw vf11, vf11, vf14 653 + vu.vf11.max(Mask::xyzw, vu.vf11, vu.vf14); + // sq.xyzw vf26, -2(vi03) | ftoi4.xyzw vf14, vf14 654 + vu.vf14.ftoi4(Mask::xyzw, vu.vf14); sq_buffer(Mask::xyzw, vu.vf26, vu.vi03 + -2); + // sq.xyzw vf14, -1(vi03) | nop 655 + sq_buffer(Mask::xyzw, vu.vf14, vu.vi03 + -1); + L45: + // BRANCH! + // iblez vi10, L46 | nop 656 + bc = ((s16)vu.vi10) <= 0; + // nop | nop 657 + + if (bc) { goto L46; } + + // ilw.x vi09, 934(vi10) | nop 658 + ilw_buffer(Mask::x, vu.vi09, vu.vi10 + 934); + // ilw.y vi07, 934(vi10) | nop 659 + ilw_buffer(Mask::y, vu.vi07, vu.vi10 + 934); + // BRANCH! + // b L40 | nop 660 + bc = true; + // iaddi vi10, vi10, -0x1 | nop 661 + vu.vi10 = vu.vi10 + -1; + if (bc) { goto L40; } + + L46: + // jr vi15 | nop 662 + // clang-format on + switch (vu.vi15) { + case 556: + goto INSTR_556; + case 558: + goto INSTR_558; + case 560: + goto INSTR_560; + case 586: + goto INSTR_586; + case 588: + goto INSTR_588; + case 590: + goto INSTR_590; + case 592: + goto INSTR_592; + case 690: + goto INSTR_690; + case 699: + goto INSTR_699; + default: + fmt::print("unknown vu.vi15 @ L46: {}\n", vu.vi15); + ASSERT(false); + } + // clang-format off + // nop | nop 663 + + L47: + // iaddiu vi09, vi00, 0x37d | nop 664 + vu.vi09 = 0x37d; /* 893 */ + L48: + // ilwr.x vi08, vi09 | nop 665 + ilw_buffer(Mask::x, vu.vi08, vu.vi09); + // ilwr.y vi07, vi09 | nop 666 + ilw_buffer(Mask::y, vu.vi07, vu.vi09); + // ilwr.z vi06, vi09 | nop 667 + ilw_buffer(Mask::z, vu.vi06, vu.vi09); + // nop | nop 668 + + // BRANCH! + // ibeq vi00, vi08, L50 | nop 669 + bc = (vu.vi08 == 0); + // lq.xyzw vf14, 0(vi07) | nop 670 + lq_buffer(Mask::xyzw, vu.vf14, vu.vi07); + if (bc) { goto L50; } + + // BRANCH! + // ibeq vi07, vi08, L50 | nop 671 + bc = (vu.vi07 == vu.vi08); + // lq.xyzw vf15, 0(vi08) | nop 672 + lq_buffer(Mask::xyzw, vu.vf15, vu.vi08); + if (bc) { goto L50; } + + // jalr vi11, vi06 | nop 673 + // ASSERT(false); + // nop | nop 674 + handle_jalr_to_end_block(vu.vi06, sf0, sf1); + + // nop | nop 675 + + // nop | nop 676 + + // fsand vi01, 0x2 | nop 677 + fsand(vu.vi01, 0x2, sf0); + + // fsand vi02, 0x2 | subw.w vf31, vf30, vf31 678 + vu.vf31.sub(Mask::w, vu.vf30, vu.vf31.w()); fsand(vu.vi02, 0x2, sf1); + + // BRANCH! + // ibeq vi02, vi01, L50 | nop 679 + bc = (vu.vi02 == vu.vi01); + // nop | nop 680 + + if (bc) { goto L50; } + + // BRANCH! + // ibeq vi00, vi01, L49 | nop 681 + bc = (vu.vi01 == 0); + // div Q, vf30.w, vf31.w | nop 682 + vu.Q = vu.vf30.w() / vu.vf31.w(); + if (bc) { goto L49; } + + // BRANCH! + // bal vi11, L52 | nop 683 + handle_bal52(); + // nop | nop 684 + + // sq.xyzw vf16, 4(vi09) | nop 685 + sq_buffer(Mask::xyzw, vu.vf16, vu.vi09 + 4); + // iaddi vi07, vi09, 0x4 | nop 686 + vu.vi07 = vu.vi09 + 4; + // ior vi12, vi09, vi00 | nop 687 + vu.vi12 = vu.vi09; + // BRANCH! + // bal vi15, L39 | nop 688 + // iaddi vi09, vi09, 0x7 | nop 689 + vu.vi09 = vu.vi09 + 7; + vu.vi15 = 690; + goto L39; + + INSTR_690: + // BRANCH! + // b L50 | nop 690 + bc = true; + // ior vi09, vi12, vi00 | nop 691 + vu.vi09 = vu.vi12; + if (bc) { goto L50; } + + L49: + // BRANCH! + // bal vi11, L52 | nop 692 + handle_bal52(); + // nop | nop 693 + + // sq.xyzw vf16, 1(vi09) | nop 694 + sq_buffer(Mask::xyzw, vu.vf16, vu.vi09 + 1); + // iaddi vi07, vi09, 0x1 | nop 695 + vu.vi07 = vu.vi09 + 1; + // ior vi12, vi09, vi00 | nop 696 + vu.vi12 = vu.vi09; + // BRANCH! + // bal vi15, L39 | nop 697 + // iaddi vi09, vi09, 0x7 | nop 698 + vu.vi09 = vu.vi09 + 7; + vu.vi15 = 699; + goto L39; + + INSTR_699: + // ior vi09, vi12, vi00 | nop 699 + vu.vi09 = vu.vi12; + L50: + // isubiu vi01, vi09, 0x3a0 | nop 700 + vu.vi01 = vu.vi09 - 0x3a0; /* 928 */ + // iswr.x vi00, vi09 | nop 701 + isw_buffer(Mask::x, vu.vi00, vu.vi09); + // iswr.y vi00, vi09 | nop 702 + isw_buffer(Mask::y, vu.vi00, vu.vi09); + // BRANCH! + // ibltz vi01, L48 | nop 703 + bc = ((s16)vu.vi01) < 0; + // iaddi vi09, vi09, 0x7 | nop 704 + vu.vi09 = vu.vi09 + 7; + if (bc) { goto L48; } + + // BRANCH! + // ibeq vi00, vi05, L51 | nop 705 + bc = (vu.vi05 == 0); + // mtir vi15, vf31.x | nop 706 + vu.vi15 = vu.vf31.x_as_u16(); + if (bc) { goto L51; } + + // iaddiu vi05, vi05, 0x4000 | nop 707 + vu.vi05 = vu.vi05 + 0x4000; /* 16384 */ + // iaddiu vi05, vi05, 0x4000 | nop 708 + vu.vi05 = vu.vi05 + 0x4000; /* 16384 */ + // iswr.x vi05, vi04 | nop 709 + isw_buffer(Mask::x, vu.vi05, vu.vi04); + // iaddiu vi01, vi00, 0x3ac | nop 710 + vu.vi01 = 0x3ac; /* 940 */ + // xgkick vi01 | nop 711 + xgkick(vu.vi01); + // lq.xyzw vf30, 888(vi00) | nop 712 + lq_buffer(Mask::xyzw, vu.vf30, 888); + // lq.xyzw vf31, 890(vi00) | nop 713 + lq_buffer(Mask::xyzw, vu.vf31, 890); + // iaddiu vi01, vi00, 0x3fe | nop 714 + vu.vi01 = 0x3fe; /* 1022 */ + // isubiu vi02, vi00, 0x7fff | nop 715 + vu.vi02 = -32767; + // sq.xyzw vf30, 0(vi01) | nop 716 + sq_buffer(Mask::xyzw, vu.vf30, vu.vi01); + // iswr.x vi02, vi01 | nop 717 + isw_buffer(Mask::x, vu.vi02, vu.vi01); + // sq.xyzw vf31, 1(vi01) | nop 718 + sq_buffer(Mask::xyzw, vu.vf31, vu.vi01 + 1); + // nop | nop 719 + + // xgkick vi01 | nop 720 + xgkick(vu.vi01); + L51: + // nop | nop 721 + + // jr vi15 | nop 722 + // clang-format on + switch (vu.vi15) { + case 191: + goto INSTR_191; + case 205: + goto INSTR_205; + case 330: + goto INSTR_330; + case 513: + goto INSTR_513; + case 527: + goto INSTR_527; + default: + fmt::print("unknown vu.vi15 @ 722: {}\n", vu.vi15); + ASSERT(false); + } +} diff --git a/game/graphics/opengl_renderer/shaders/shadow.frag b/game/graphics/opengl_renderer/shaders/shadow.frag new file mode 100644 index 0000000000..9d07e32b5d --- /dev/null +++ b/game/graphics/opengl_renderer/shaders/shadow.frag @@ -0,0 +1,8 @@ +#version 430 core + +out vec4 color; +uniform vec4 color_uniform; + +void main() { + color = color_uniform; +} diff --git a/game/graphics/opengl_renderer/shaders/shadow.vert b/game/graphics/opengl_renderer/shaders/shadow.vert new file mode 100644 index 0000000000..c5ffbb5732 --- /dev/null +++ b/game/graphics/opengl_renderer/shaders/shadow.vert @@ -0,0 +1,10 @@ +#version 430 core + +layout (location = 0) in vec3 position_in; + +void main() { + // Note: position.y is multiplied by 32 instead of 16 to undo the half-height for interlacing stuff. + gl_Position = vec4((position_in.x - 0.5) * 16., -(position_in.y - 0.5) * 32, position_in.z * 2 - 1., 1.0); + // scissoring area adjust + gl_Position.y *= 512.0/448.0; +} diff --git a/game/mips2c/functions/shadow.cpp b/game/mips2c/functions/shadow.cpp index 4d470d3cbd..0e4d6effdf 100644 --- a/game/mips2c/functions/shadow.cpp +++ b/game/mips2c/functions/shadow.cpp @@ -64,7 +64,7 @@ void exec_0(ExecutionContext* c) { } void exec_28(ExecutionContext* c) { - // nop | mul.xyzw vf27, vf20, Q 28 +// nop | mul.xyzw vf27, vf20, Q 28 c->vfs[vf27].vf.mul(Mask::xyzw, c->vf_src(vf20).vf, c->Q); // div Q, vf13.x, vf17.x | sub.xyzw vf19, vf01, vf03 29 c->vfs[vf19].vf.sub(Mask::xyzw, c->vf_src(vf01).vf, c->vf_src(vf03).vf); c->Q = c->vfs[vf13].vf.x() / c->vfs[vf17].vf.x(); @@ -81,9 +81,10 @@ void exec_28(ExecutionContext* c) { // nop | mul.xyz vf15, vf19, vf02 35 c->vfs[vf15].vf.mul(Mask::xyz, c->vf_src(vf19).vf, c->vf_src(vf02).vf); // div Q, vf14.x, vf18.x | mul.xyzw vf12, vf04, vf02 36 + float oldQ = c->Q; c->vfs[vf12].vf.mul(Mask::xyzw, c->vf_src(vf04).vf, c->vf_src(vf02).vf); c->Q = c->vfs[vf14].vf.x() / c->vfs[vf18].vf.x(); // move.xyzw vf07, vf03 | mul.xyzw vf28, vf28, Q 37 - c->vfs[vf28].vf.mul(Mask::xyzw, c->vf_src(vf28).vf, c->Q); c->vfs[vf07].vf.move(Mask::xyzw, c->vf_src(vf03).vf); + c->vfs[vf28].vf.mul(Mask::xyzw, c->vf_src(vf28).vf, oldQ); c->vfs[vf07].vf.move(Mask::xyzw, c->vf_src(vf03).vf); // move.xyzw vf08, vf04 | mul.xyz vf16, vf20, vf02 38 c->vfs[vf16].vf.mul(Mask::xyz, c->vf_src(vf20).vf, c->vf_src(vf02).vf); c->vfs[vf08].vf.move(Mask::xyzw, c->vf_src(vf04).vf); // move.xyzw vf09, vf05 | addy.x vf11, vf11, vf11 39 @@ -111,37 +112,51 @@ void exec_28(ExecutionContext* c) { // nop | addw.x vf11, vf11, vf11 50 c->vfs[vf11].vf.add(Mask::x, c->vf_src(vf11).vf, c->vf_src(vf11).vf.w()); // nop | mul.xyzw vf13, vf09, vf02 51 + c->vfs[vf13].vf.mul(Mask::xyzw, c->vf_src(vf09).vf, c->vf_src(vf02).vf); + c->vfs[vf13].vf.saturate_infs(); + // nop | addw.x vf12, vf12, vf12 52 c->vfs[vf12].vf.add(Mask::x, c->vf_src(vf12).vf, c->vf_src(vf12).vf.w()); // nop | mul.xyz vf17, vf21, vf02 53 c->vfs[vf17].vf.mul(Mask::xyz, c->vf_src(vf21).vf, c->vf_src(vf02).vf); // nop | mul.xyzw vf14, vf10, vf02 54 c->vfs[vf14].vf.mul(Mask::xyzw, c->vf_src(vf10).vf, c->vf_src(vf02).vf); + c->vfs[vf14].vf.saturate_infs(); + // div Q, vf11.x, vf15.x | mul.xyz vf18, vf22, vf02 55 c->vfs[vf18].vf.mul(Mask::xyz, c->vf_src(vf22).vf, c->vf_src(vf02).vf); c->Q = c->vfs[vf11].vf.x() / c->vfs[vf15].vf.x(); // nop | addy.x vf13, vf13, vf13 56 c->vfs[vf13].vf.add(Mask::x, c->vf_src(vf13).vf, c->vf_src(vf13).vf.y()); + // nop | addy.x vf17, vf17, vf17 57 c->vfs[vf17].vf.add(Mask::x, c->vf_src(vf17).vf, c->vf_src(vf17).vf.y()); // nop | addy.x vf14, vf14, vf14 58 c->vfs[vf14].vf.add(Mask::x, c->vf_src(vf14).vf, c->vf_src(vf14).vf.y()); + // nop | addy.x vf18, vf18, vf18 59 c->vfs[vf18].vf.add(Mask::x, c->vf_src(vf18).vf, c->vf_src(vf18).vf.y()); // nop | addz.x vf13, vf13, vf13 60 c->vfs[vf13].vf.add(Mask::x, c->vf_src(vf13).vf, c->vf_src(vf13).vf.z()); + // nop | addz.x vf17, vf17, vf17 61 c->vfs[vf17].vf.add(Mask::x, c->vf_src(vf17).vf, c->vf_src(vf17).vf.z()); // div Q, vf12.x, vf16.x | addz.x vf14, vf14, vf14 62 + oldQ = c->Q; c->vfs[vf14].vf.add(Mask::x, c->vf_src(vf14).vf, c->vf_src(vf14).vf.z()); c->Q = c->vfs[vf12].vf.x() / c->vfs[vf16].vf.x(); + // nop | mul.xyzw vf19, vf19, Q 63 - c->vfs[vf19].vf.mul(Mask::xyzw, c->vf_src(vf19).vf, c->Q); + c->vfs[vf19].vf.mul(Mask::xyzw, c->vf_src(vf19).vf, oldQ); // move.xyzw vf28, vf21 | addz.x vf18, vf18, vf18 64 c->vfs[vf18].vf.add(Mask::x, c->vf_src(vf18).vf, c->vf_src(vf18).vf.z()); c->vfs[vf28].vf.move(Mask::xyzw, c->vf_src(vf21).vf); // move.xyzw vf29, vf22 | addw.x vf13, vf13, vf13 65 c->vfs[vf13].vf.add(Mask::x, c->vf_src(vf13).vf, c->vf_src(vf13).vf.w()); c->vfs[vf29].vf.move(Mask::xyzw, c->vf_src(vf22).vf); + c->vfs[vf13].vf.saturate_infs(); + // nop | addw.x vf14, vf14, vf14 :e 66 c->vfs[vf14].vf.add(Mask::x, c->vf_src(vf14).vf, c->vf_src(vf14).vf.w()); + c->vfs[vf14].vf.saturate_infs(); + // nop | sub.xyzw vf07, vf07, vf19 67 c->vfs[vf07].vf.sub(Mask::xyzw, c->vf_src(vf07).vf, c->vf_src(vf19).vf); } @@ -164,9 +179,10 @@ void exec_68(ExecutionContext* c) { // nop | nop 75 // div Q, vf14.x, vf18.x | nop 76 + float oldQ = c->Q; c->Q = c->vfs[vf14].vf.x() / c->vfs[vf18].vf.x(); // nop | mul.xyzw vf28, vf28, Q 77 - c->vfs[vf28].vf.mul(Mask::xyzw, c->vf_src(vf28).vf, c->Q); + c->vfs[vf28].vf.mul(Mask::xyzw, c->vf_src(vf28).vf, oldQ); // nop | nop 78 // nop | nop 79 @@ -174,7 +190,7 @@ void exec_68(ExecutionContext* c) { // nop | nop 80 // nop | sub.xyzw vf25, vf25, vf28 81 - c->vfs[vf25].vf.sub(Mask::xyzw, c->vf_src(vf25).vf, c->vf_src(vf28).vf); + c->vfs[vf25].vf.sub(Mask::xyzw, c->vf_src(vf25).vf, c->vf_src(vf28).vf); // was bad // nop | nop 82 // nop | mul.xyzw vf29, vf29, Q 83 @@ -324,6 +340,7 @@ u64 execute(void* ctxt) { // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 c->sqc2(vf9, 0, a2); // sqc2 vf9, 0(a2) + c->daddiu(a2, a2, 16); // daddiu a2, a2, 16 // nop // sll r0, r0, 0 bc = c->sgpr64(a0) != 0; // bne a0, r0, L101 @@ -398,6 +415,7 @@ u64 execute(void* ctxt) { // nop // sll r0, r0, 0 c->mov128_vf_gpr(vf6, t2); // qmtc2.ni vf6, t2 exec_28(c);// Unknown instr: vcallms 28 + // nop // sll r0, r0, 0 c->daddiu(a0, a0, -4); // daddiu a0, a0, -4 c->lq(a3, 0, a2); // lq a3, 0(a2) @@ -430,7 +448,7 @@ u64 execute(void* ctxt) { // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 - c->mov128_gpr_vf(a3, vf23); // qmfc2.i a3, vf23 + c->mov128_gpr_vf(a3, vf23); // qmfc2.i a3, vf23 // 39 // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 @@ -438,11 +456,11 @@ u64 execute(void* ctxt) { // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 - c->sq(a3, 0, v1); // sq a3, 0(v1) + c->sq(a3, 0, v1); // sq a3, 0(v1) // 47 // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 - c->mov128_gpr_vf(a3, vf24); // qmfc2.ni a3, vf24 + c->mov128_gpr_vf(a3, vf24); // qmfc2.ni a3, vf24 // 51 // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 @@ -450,7 +468,7 @@ u64 execute(void* ctxt) { // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 - c->sq(a3, 16, v1); // sq a3, 16(v1) + c->sq(a3, 16, v1); // sq a3, 16(v1) // 59 // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 @@ -458,7 +476,7 @@ u64 execute(void* ctxt) { // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 - c->mov128_gpr_vf(a3, vf25); // qmfc2.ni a3, vf25 + c->mov128_gpr_vf(a3, vf25); // qmfc2.ni a3, vf25 // 67 // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 @@ -466,7 +484,7 @@ u64 execute(void* ctxt) { // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 - c->sq(a3, 32, v1); // sq a3, 32(v1) + c->sq(a3, 32, v1); // sq a3, 32(v1) // 75 // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 @@ -474,7 +492,7 @@ u64 execute(void* ctxt) { // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 - c->mov128_gpr_vf(a3, vf26); // qmfc2.ni a3, vf26 + c->mov128_gpr_vf(a3, vf26); // qmfc2.ni a3, vf26 // 83 // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 @@ -482,7 +500,7 @@ u64 execute(void* ctxt) { // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 - c->sq(a3, 48, v1); // sq a3, 48(v1) + c->sq(a3, 48, v1); // sq a3, 48(v1) // 91 // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 // nop // sll r0, r0, 0 @@ -505,7 +523,6 @@ u64 execute(void* ctxt) { c->mov128_vf_gpr(vf6, t2); // qmtc2.ni vf6, t2 if (bc) {goto block_3;} // branch non-likely - block_4: exec_68(c);// Unknown instr: vcallms 68 // nop // sll r0, r0, 0 @@ -637,7 +654,7 @@ u64 execute(void* ctxt) { // nop // vnop c->vadd(DEST::xyzw, vf1, vf1, vf4); // vadd.xyzw vf1, vf1, vf4 //beq r0, r0, L91 // beq r0, r0, L91 - c->sqc2(vf1, 0, a0); // sqc2 vf1, 0(a0) + c->sqc2(vf1, 0, a0); // sqc2 vf1, 0(a0) was bad goto block_7; // branch always diff --git a/game/mips2c/mips2c_private.h b/game/mips2c/mips2c_private.h index 9ac8860f46..d0a678146a 100644 --- a/game/mips2c/mips2c_private.h +++ b/game/mips2c/mips2c_private.h @@ -2,6 +2,7 @@ #include #include +#include #include "common/common_types.h" #include "game/mips2c/mips2c_table.h"