From 41eab62ed75e5743cd4e0bc63918a7ebe687aad3 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Thu, 28 Jun 2018 14:03:25 +0300 Subject: [PATCH] Implement spu_iname helper Remove old code Report $SP anomalies --- rpcs3/Emu/Cell/PPUAnalyser.cpp | 13 ++ rpcs3/Emu/Cell/SPUAnalyser.cpp | 328 +------------------------------ rpcs3/Emu/Cell/SPUAnalyser.h | 248 ++++++++++++++++++++--- rpcs3/Emu/Cell/SPURecompiler.cpp | 126 ++++++++++++ 4 files changed, 361 insertions(+), 354 deletions(-) diff --git a/rpcs3/Emu/Cell/PPUAnalyser.cpp b/rpcs3/Emu/Cell/PPUAnalyser.cpp index a54162962..8e7cc4cb9 100644 --- a/rpcs3/Emu/Cell/PPUAnalyser.cpp +++ b/rpcs3/Emu/Cell/PPUAnalyser.cpp @@ -35,6 +35,19 @@ void fmt_class_string>::format(std::string& out, u64 arg) format_bitset(out, arg, "[", ",", "]", &fmt_class_string::format); } +template <> +void fmt_class_string::format(std::string& out, u64 arg) +{ + // Decode instruction name from the enum value + for (u32 i = 0; i < 10; i++) + { + if (u64 value = (arg >> (54 - i * 6)) & 0x3f) + { + out += static_cast(value + 0x20); + } + } +} + void ppu_module::validate(u32 reloc) { // Load custom PRX configuration if available diff --git a/rpcs3/Emu/Cell/SPUAnalyser.cpp b/rpcs3/Emu/Cell/SPUAnalyser.cpp index c59438346..ce528335b 100644 --- a/rpcs3/Emu/Cell/SPUAnalyser.cpp +++ b/rpcs3/Emu/Cell/SPUAnalyser.cpp @@ -1,331 +1,15 @@ #include "stdafx.h" -#include "Emu/Memory/vm.h" #include "SPUAnalyser.h" -#include "SPURecompiler.h" -#include "SPUOpcodes.h" -const spu_decoder s_spu_itype; - -std::shared_ptr spu_analyse(const be_t* ls, u32 entry, u32 max_limit) +template <> +void fmt_class_string::format(std::string& out, u64 arg) { - // Check arguments (bounds and alignment) - if (max_limit > 0x40000 || entry >= max_limit || entry % 4 || max_limit % 4) + // Decode instruction name from the enum value + for (u32 i = 0; i < 10; i++) { - fmt::throw_exception("Invalid arguments (entry=0x%05x, limit=0x%05x)" HERE, entry, max_limit); - } - - // Key for multimap - const u64 key = entry | u64{ ls[entry / 4] } << 32; - const be_t* base = ls + entry / 4; - const u32 block_sz = max_limit - entry; - - { - //reader_lock lock(m_mutex); - - // Try to find existing function in the database - // if (auto func = find(base, key, block_sz)) - // { - // return func; - // } - } - - { - //writer_lock lock(m_mutex); - - // Double-check - // if (auto func = find(base, key, block_sz)) - // { - // return func; - // } - } - - // Initialize block entries with the function entry point - std::set blocks{ entry }; - - // Entries of adjacent functions; jump table entries - std::set adjacent, jt; - - // Set initial limit which will be narrowed later - u32 limit = max_limit; - - // Minimal position of ila $SP,* instruction - u32 ila_sp_pos = max_limit; - - // pigeonhole optimization, addr of last ila r2, addr, or 0 if last instruction was not - u32 ila_r2_addr = 0; - - // Find preliminary set of possible block entries (first pass), `start` is the current block address - for (u32 start = entry, pos = entry; pos < limit; pos += 4) - { - const spu_opcode_t op{ ls[pos / 4] }; - - const auto type = s_spu_itype.decode(op.opcode); - + if (u64 value = (arg >> (54 - i * 6)) & 0x3f) { - //reader_lock lock(m_mutex); - - // Find existing function - // if (pos != entry && find(ls + pos / 4, pos | u64{ op.opcode } << 32, limit - pos)) - // { - // limit = pos; - // break; - // } - } - - // Additional analysis at the beginning of the block - if (start != entry && start == pos) - { - std::vector jt_abs; - std::vector jt_rel; - - for (; pos < limit; pos += 4) - { - const u32 target = ls[pos / 4]; - - if (target % 4) - { - // Address cannot be misaligned: abort jt scan - break; - } - - if (target >= entry && target < limit) - { - // Possible jump table entry (absolute) - jt_abs.emplace_back(target); - } - - if (target + start >= entry && target + start < limit) - { - // Possible jump table entry (relative) - jt_rel.emplace_back(target + start); - } - - if (std::max(jt_abs.size(), jt_rel.size()) * 4 + start <= pos) - { - break; - } - } - - if (pos - start >= 8) - { - // Register jump table block (at least 2 entries) as an ordinary block - blocks.emplace(start); - - // Register jump table entries (absolute) - if (jt_abs.size() * 4 == pos - start) - { - blocks.insert(jt_abs.begin(), jt_abs.end()); - - jt.insert(jt_abs.begin(), jt_abs.end()); - } - - // Register jump table entries (relative) - if (jt_rel.size() * 4 == pos - start) - { - blocks.insert(jt_rel.begin(), jt_rel.end()); - - jt.insert(jt_rel.begin(), jt_rel.end()); - } - - // Fix pos value - start = pos; pos = pos - 4; - - continue; - } - - // Restore pos value - pos = start; - } - - if (!type || (start == pos && start > *blocks.rbegin())) // Invalid instruction or "unrelated" block started - { - // Discard current block and abort the operation - limit = start; - break; - } - - if (op.opcode == 0) // Hack: special case (STOP 0) - { - limit = pos + 4; - break; - } - - // if upcoming instruction is not BI, reset the pigeonhole optimization - // todo: can constant propogation somewhere get rid of this check? - if ((type != spu_itype::BI)) - ila_r2_addr = 0; // reset - - if (type == spu_itype::BI || type == spu_itype::IRET) // Branch Indirect - { - blocks.emplace(start); - start = pos + 4; - - if (op.ra == 2 && ila_r2_addr > entry) - blocks.emplace(ila_r2_addr); - } - else if (type == spu_itype::BR || type == spu_itype::BRA) // Branch Relative/Absolute - { - const u32 target = spu_branch_target(type == spu_itype::BR ? pos : 0, op.i16); - - // Add adjacent function because it always could be - adjacent.emplace(target); - - if (target > entry) - { - blocks.emplace(target); - } - - blocks.emplace(start); - start = pos + 4; - } - else if (type == spu_itype::BRSL || type == spu_itype::BRASL) // Branch Relative/Absolute and Set Link - { - const u32 target = spu_branch_target(type == spu_itype::BRSL ? pos : 0, op.i16); - - if (target == pos + 4) - { - // Branch to the next instruction and set link ("get next instruction address" idiom) - - if (op.rt == 0) LOG_ERROR(SPU, "[0x%05x] Branch-to-next with $LR", pos); - } - else - { - // Add adjacent function - adjacent.emplace(target); - - if (target > entry) - { - limit = std::min(limit, target); - } - - if (op.rt != 0) LOG_ERROR(SPU, "[0x%05x] Function call without $LR", pos); - } - } - else if (type == spu_itype::BISL || type == spu_itype::BISLED) // Branch Indirect and Set Link - { - if (op.rt != 0) LOG_ERROR(SPU, "[0x%05x] Indirect function call without $LR", pos); - } - else if (type == spu_itype::BRNZ || type == spu_itype::BRZ || type == spu_itype::BRHNZ || type == spu_itype::BRHZ) // Branch Relative if (Not) Zero (Half)word - { - const u32 target = spu_branch_target(pos, op.i16); - - // Add adjacent function because it always could be - adjacent.emplace(target); - - if (target > entry) - { - blocks.emplace(target); - } - } - else if (type == spu_itype::LNOP || type == spu_itype::NOP) { - // theres a chance that theres some random lnops/nops after the end of a function - // havent found a definite pattern, but, is an easy optimization to check for, just push start down if lnop is tagged as a start - // todo: remove the last added start pos as its probly unnecessary - if (pos == start) - start = pos + 4; - } - else // Other instructions (writing rt reg) - { - const u32 rt = type & spu_itype::_quadrop ? +op.rt4 : +op.rt; - - // Analyse link register access - if (rt == 0) - { - } - // Analyse stack pointer access - else if (rt == 1) - { - if (type == spu_itype::ILA && pos < ila_sp_pos) - { - // set minimal ila $SP,* instruction position - ila_sp_pos = pos; - } - } - // pigeonhole optimize - // ila r2, addr - // bi r2 - else if (rt == 2) { - if (type == spu_itype::ILA) - ila_r2_addr = spu_branch_target(op.i18); - } + out += static_cast(value + 0x20); } } - - // Find more function calls (second pass, questionable) - for (u32 pos = 0; pos < 0x40000; pos += 4) - { - const spu_opcode_t op{ ls[pos / 4] }; - - const auto type = s_spu_itype.decode(op.opcode); - - if (type == spu_itype::BRSL || type == spu_itype::BRASL) // Branch Relative/Absolute and Set Link - { - const u32 target = spu_branch_target(type == spu_itype::BRSL ? pos : 0, op.i16); - - if (target != pos + 4 && target > entry && limit > target) - { - // Narrow the limit - limit = target; - } - } - else if (!type) // Invalid instruction - { - break; - } - } - - if (limit <= entry) - { - LOG_ERROR(SPU, "Function not found [0x%05x]", entry); - return nullptr; - } - - // Prepare new function (set addr and size) - auto func = std::make_shared(entry, limit - entry); - - // Copy function contents - func->data = { ls + entry / 4, ls + limit / 4 }; - - // Fill function block info - for (auto i = blocks.crbegin(); i != blocks.crend(); i++) - { - if (limit > *i) - { - func->blocks.emplace_hint(func->blocks.begin(), *i); - } - } - - // Fill adjacent function info - for (auto i = adjacent.crbegin(); i != adjacent.crend(); i++) - { - if (limit <= *i || entry >= *i) - { - func->adjacent.emplace_hint(func->adjacent.begin(), *i); - } - } - - // Fill jump table entries - for (auto i = jt.crbegin(); i != jt.crend(); i++) - { - if (limit > *i) - { - func->jtable.emplace_hint(func->jtable.begin(), *i); - } - } - - // Set whether the function can reset stack - func->does_reset_stack = ila_sp_pos < limit; - - // Lock here just before we write to the db - // Its is unlikely that the second check will pass anyway so we delay this step since compiling functions is very fast - { - //writer_lock lock(m_mutex); - - // Add function to the database - //m_db.emplace(key, func); - } - - LOG_NOTICE(SPU, "Function detected [0x%05x-0x%05x] (size=0x%x)", func->addr, func->addr + func->size, func->size); - - return func; } diff --git a/rpcs3/Emu/Cell/SPUAnalyser.h b/rpcs3/Emu/Cell/SPUAnalyser.h index 62121e251..a386d3a6e 100644 --- a/rpcs3/Emu/Cell/SPUAnalyser.h +++ b/rpcs3/Emu/Cell/SPUAnalyser.h @@ -1,8 +1,5 @@ #pragma once -#include -#include - // SPU Instruction Type struct spu_itype { @@ -243,38 +240,225 @@ struct spu_itype } }; -class SPUThread; - -// SPU basic function information structure -struct spu_function +// Encode instruction name: 6 bits per character (0x20..0x5f), max 10 +static constexpr u64 spu_iname_encode(const char* ptr, u64 value = 0) { - // Entry point (LS address) - const u32 addr; + return *ptr == '\0' ? value : spu_iname_encode(ptr + 1, (*ptr - 0x20) | (value << 6)); +} - // Function size (in bytes) - const u32 size; +#define NAME(x) x = spu_iname_encode(#x) - // Function contents (binary copy) - std::vector> data; - - // Basic blocks (start addresses) - std::set blocks; - - // Functions possibly called by this function (may not be available) - std::set adjacent; - - // Jump table values (start addresses) - std::set jtable; - - // Whether ila $SP,* instruction found - bool does_reset_stack; - - // Pointer to the compiled function - u32(*compiled)(SPUThread* _spu, be_t* _ls) = nullptr; - - spu_function(u32 addr, u32 size) - : addr(addr) - , size(size) +struct spu_iname +{ + enum type : u64 { + NAME(UNK), + NAME(HEQ), + NAME(HEQI), + NAME(HGT), + NAME(HGTI), + NAME(HLGT), + NAME(HLGTI), + NAME(HBR), + NAME(HBRA), + NAME(HBRR), + NAME(STOP), + NAME(STOPD), + NAME(LNOP), + NAME(NOP), + NAME(SYNC), + NAME(DSYNC), + NAME(MFSPR), + NAME(MTSPR), + NAME(RDCH), + NAME(RCHCNT), + NAME(WRCH), + NAME(LQD), + NAME(LQX), + NAME(LQA), + NAME(LQR), + NAME(STQD), + NAME(STQX), + NAME(STQA), + NAME(STQR), + NAME(CBD), + NAME(CBX), + NAME(CHD), + NAME(CHX), + NAME(CWD), + NAME(CWX), + NAME(CDD), + NAME(CDX), + NAME(ILH), + NAME(ILHU), + NAME(IL), + NAME(ILA), + NAME(IOHL), + NAME(FSMBI), + NAME(AH), + NAME(AHI), + NAME(A), + NAME(AI), + NAME(SFH), + NAME(SFHI), + NAME(SF), + NAME(SFI), + NAME(ADDX), + NAME(CG), + NAME(CGX), + NAME(SFX), + NAME(BG), + NAME(BGX), + NAME(MPY), + NAME(MPYU), + NAME(MPYI), + NAME(MPYUI), + NAME(MPYH), + NAME(MPYS), + NAME(MPYHH), + NAME(MPYHHA), + NAME(MPYHHU), + NAME(MPYHHAU), + NAME(CLZ), + NAME(CNTB), + NAME(FSMB), + NAME(FSMH), + NAME(FSM), + NAME(GBB), + NAME(GBH), + NAME(GB), + NAME(AVGB), + NAME(ABSDB), + NAME(SUMB), + NAME(XSBH), + NAME(XSHW), + NAME(XSWD), + NAME(AND), + NAME(ANDC), + NAME(ANDBI), + NAME(ANDHI), + NAME(ANDI), + NAME(OR), + NAME(ORC), + NAME(ORBI), + NAME(ORHI), + NAME(ORI), + NAME(ORX), + NAME(XOR), + NAME(XORBI), + NAME(XORHI), + NAME(XORI), + NAME(NAND), + NAME(NOR), + NAME(EQV), + NAME(MPYA), + NAME(SELB), + NAME(SHUFB), + NAME(SHLH), + NAME(SHLHI), + NAME(SHL), + NAME(SHLI), + NAME(SHLQBI), + NAME(SHLQBII), + NAME(SHLQBY), + NAME(SHLQBYI), + NAME(SHLQBYBI), + NAME(ROTH), + NAME(ROTHI), + NAME(ROT), + NAME(ROTI), + NAME(ROTQBY), + NAME(ROTQBYI), + NAME(ROTQBYBI), + NAME(ROTQBI), + NAME(ROTQBII), + NAME(ROTHM), + NAME(ROTHMI), + NAME(ROTM), + NAME(ROTMI), + NAME(ROTQMBY), + NAME(ROTQMBYI), + NAME(ROTQMBYBI), + NAME(ROTQMBI), + NAME(ROTQMBII), + NAME(ROTMAH), + NAME(ROTMAHI), + NAME(ROTMA), + NAME(ROTMAI), + NAME(CEQB), + NAME(CEQBI), + NAME(CEQH), + NAME(CEQHI), + NAME(CEQ), + NAME(CEQI), + NAME(CGTB), + NAME(CGTBI), + NAME(CGTH), + NAME(CGTHI), + NAME(CGT), + NAME(CGTI), + NAME(CLGTB), + NAME(CLGTBI), + NAME(CLGTH), + NAME(CLGTHI), + NAME(CLGT), + NAME(CLGTI), + NAME(BR), + NAME(BRA), + NAME(BRSL), + NAME(BRASL), + NAME(BI), + NAME(IRET), + NAME(BISLED), + NAME(BISL), + NAME(BRNZ), + NAME(BRZ), + NAME(BRHNZ), + NAME(BRHZ), + NAME(BIZ), + NAME(BINZ), + NAME(BIHZ), + NAME(BIHNZ), + NAME(FA), + NAME(DFA), + NAME(FS), + NAME(DFS), + NAME(FM), + NAME(DFM), + NAME(DFMA), + NAME(DFNMS), + NAME(DFMS), + NAME(DFNMA), + NAME(FREST), + NAME(FRSQEST), + NAME(FI), + NAME(CSFLT), + NAME(CFLTS), + NAME(CUFLT), + NAME(CFLTU), + NAME(FRDS), + NAME(FESD), + NAME(FCEQ), + NAME(FCMEQ), + NAME(FCGT), + NAME(FCMGT), + NAME(FSCRWR), + NAME(FSCRRD), + NAME(DFCEQ), + NAME(DFCMEQ), + NAME(DFCGT), + NAME(DFCMGT), + NAME(DFTSV), + NAME(FMA), + NAME(FNMS), + NAME(FMS), + }; + + // Enable address-of operator for spu_decoder<> + friend constexpr type operator &(type value) + { + return value; } }; + +#undef NAME diff --git a/rpcs3/Emu/Cell/SPURecompiler.cpp b/rpcs3/Emu/Cell/SPURecompiler.cpp index b0460990d..b55fb7e90 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.cpp +++ b/rpcs3/Emu/Cell/SPURecompiler.cpp @@ -20,6 +20,7 @@ extern atomic_t g_progr_ptotal; extern atomic_t g_progr_pdone; const spu_decoder s_spu_itype; +const spu_decoder s_spu_iname; spu_cache::spu_cache(const std::string& loc) : m_file(loc, fs::read + fs::write + fs::create) @@ -480,6 +481,11 @@ std::vector spu_recompiler_base::block(const be_t* ls, u32 entry_point m_regmod[pos / 4] = op.rt; vflags[op.rt] = +vf::is_const; values[op.rt] = pos + 4; + + if (op.rt == 1 && (pos + 4) % 16) + { + LOG_WARNING(SPU, "[0x%x] Unexpected instruction on $SP: BISL", pos); + } } if (test(af, vf::is_const)) @@ -710,6 +716,11 @@ std::vector spu_recompiler_base::block(const be_t* ls, u32 entry_point vflags[op.rt] = +vf::is_const; values[op.rt] = pos + 4; + if (op.rt == 1 && (pos + 4) % 16) + { + LOG_WARNING(SPU, "[0x%x] Unexpected instruction on $SP: BRSL", pos); + } + if (target == pos + 4) { // Get next instruction address idiom @@ -795,6 +806,17 @@ std::vector spu_recompiler_base::block(const be_t* ls, u32 entry_point break; } + case spu_itype::LQA: + case spu_itype::LQD: + case spu_itype::LQR: + case spu_itype::LQX: + { + // Unconst + m_regmod[pos / 4] = op.rt; + vflags[op.rt] = {}; + break; + } + case spu_itype::HBR: { hbr_loc = spu_branch_target(pos, op.roh << 7 | op.rt); @@ -821,6 +843,12 @@ std::vector spu_recompiler_base::block(const be_t* ls, u32 entry_point m_regmod[pos / 4] = op.rt; vflags[op.rt] = +vf::is_const; values[op.rt] = op.si16; + + if (op.rt == 1 && values[1] & ~0x3fff0u) + { + LOG_TODO(SPU, "[0x%x] Unexpected instruction on $SP: IL -> 0x%x", pos, values[1]); + } + break; } case spu_itype::ILA: @@ -828,6 +856,12 @@ std::vector spu_recompiler_base::block(const be_t* ls, u32 entry_point m_regmod[pos / 4] = op.rt; vflags[op.rt] = +vf::is_const; values[op.rt] = op.i18; + + if (op.rt == 1 && values[1] & ~0x3fff0u) + { + LOG_TODO(SPU, "[0x%x] Unexpected instruction on $SP: ILA -> 0x%x", pos, values[1]); + } + break; } case spu_itype::ILH: @@ -835,6 +869,12 @@ std::vector spu_recompiler_base::block(const be_t* ls, u32 entry_point m_regmod[pos / 4] = op.rt; vflags[op.rt] = +vf::is_const; values[op.rt] = op.i16 << 16 | op.i16; + + if (op.rt == 1 && values[1] & ~0x3fff0u) + { + LOG_TODO(SPU, "[0x%x] Unexpected instruction on $SP: ILH -> 0x%x", pos, values[1]); + } + break; } case spu_itype::ILHU: @@ -842,12 +882,24 @@ std::vector spu_recompiler_base::block(const be_t* ls, u32 entry_point m_regmod[pos / 4] = op.rt; vflags[op.rt] = +vf::is_const; values[op.rt] = op.i16 << 16; + + if (op.rt == 1 && values[1] & ~0x3fff0u) + { + LOG_TODO(SPU, "[0x%x] Unexpected instruction on $SP: ILHU -> 0x%x", pos, values[1]); + } + break; } case spu_itype::IOHL: { m_regmod[pos / 4] = op.rt; values[op.rt] = values[op.rt] | op.i16; + + if (op.rt == 1 && op.i16 % 16) + { + LOG_TODO(SPU, "[0x%x] Unexpected instruction on $SP: IOHL, 0x%x", pos, op.i16); + } + break; } case spu_itype::ORI: @@ -855,6 +907,12 @@ std::vector spu_recompiler_base::block(const be_t* ls, u32 entry_point m_regmod[pos / 4] = op.rt; vflags[op.rt] = vflags[op.ra] & vf::is_const; values[op.rt] = values[op.ra] | op.si10; + + if (op.rt == 1) + { + LOG_WARNING(SPU, "[0x%x] Unexpected instruction on $SP: ORI", pos); + } + break; } case spu_itype::OR: @@ -862,6 +920,12 @@ std::vector spu_recompiler_base::block(const be_t* ls, u32 entry_point m_regmod[pos / 4] = op.rt; vflags[op.rt] = vflags[op.ra] & vflags[op.rb] & vf::is_const; values[op.rt] = values[op.ra] | values[op.rb]; + + if (op.rt == 1) + { + LOG_TODO(SPU, "[0x%x] Unexpected instruction on $SP: OR", pos); + } + break; } case spu_itype::ANDI: @@ -869,6 +933,12 @@ std::vector spu_recompiler_base::block(const be_t* ls, u32 entry_point m_regmod[pos / 4] = op.rt; vflags[op.rt] = vflags[op.ra] & vf::is_const; values[op.rt] = values[op.ra] & op.si10; + + if (op.rt == 1) + { + LOG_TODO(SPU, "[0x%x] Unexpected instruction on $SP: ANDI", pos); + } + break; } case spu_itype::AND: @@ -876,6 +946,12 @@ std::vector spu_recompiler_base::block(const be_t* ls, u32 entry_point m_regmod[pos / 4] = op.rt; vflags[op.rt] = vflags[op.ra] & vflags[op.rb] & vf::is_const; values[op.rt] = values[op.ra] & values[op.rb]; + + if (op.rt == 1) + { + LOG_TODO(SPU, "[0x%x] Unexpected instruction on $SP: AND", pos); + } + break; } case spu_itype::AI: @@ -883,6 +959,12 @@ std::vector spu_recompiler_base::block(const be_t* ls, u32 entry_point m_regmod[pos / 4] = op.rt; vflags[op.rt] = vflags[op.ra] & vf::is_const; values[op.rt] = values[op.ra] + op.si10; + + if (op.rt == 1 && op.si10 % 16) + { + LOG_TODO(SPU, "[0x%x] Unexpected instruction on $SP: AI, 0x%x", pos, op.si10 + 0u); + } + break; } case spu_itype::A: @@ -890,6 +972,22 @@ std::vector spu_recompiler_base::block(const be_t* ls, u32 entry_point m_regmod[pos / 4] = op.rt; vflags[op.rt] = vflags[op.ra] & vflags[op.rb] & vf::is_const; values[op.rt] = values[op.ra] + values[op.rb]; + + if (op.rt == 1) + { + if (op.ra == 1 || op.rb == 1) + { + const u32 r2 = op.ra == 1 ? +op.rb : +op.ra; + + if (test(vflags[r2], vf::is_const) && (values[r2] % 16) == 0) + { + break; + } + } + + LOG_WARNING(SPU, "[0x%x] Unexpected instruction on $SP: A", pos); + } + break; } case spu_itype::SFI: @@ -897,6 +995,12 @@ std::vector spu_recompiler_base::block(const be_t* ls, u32 entry_point m_regmod[pos / 4] = op.rt; vflags[op.rt] = vflags[op.ra] & vf::is_const; values[op.rt] = op.si10 - values[op.ra]; + + if (op.rt == 1) + { + LOG_TODO(SPU, "[0x%x] Unexpected instruction on $SP: SFI", pos); + } + break; } case spu_itype::SF: @@ -904,12 +1008,23 @@ std::vector spu_recompiler_base::block(const be_t* ls, u32 entry_point m_regmod[pos / 4] = op.rt; vflags[op.rt] = vflags[op.ra] & vflags[op.rb] & vf::is_const; values[op.rt] = values[op.rb] - values[op.ra]; + + if (op.rt == 1) + { + LOG_TODO(SPU, "[0x%x] Unexpected instruction on $SP: SF", pos); + } + break; } case spu_itype::ROTMI: { m_regmod[pos / 4] = op.rt; + if (op.rt == 1) + { + LOG_TODO(SPU, "[0x%x] Unexpected instruction on $SP: ROTMI", pos); + } + if (-op.i7 & 0x20) { vflags[op.rt] = +vf::is_const; @@ -925,6 +1040,11 @@ std::vector spu_recompiler_base::block(const be_t* ls, u32 entry_point { m_regmod[pos / 4] = op.rt; + if (op.rt == 1) + { + LOG_TODO(SPU, "[0x%x] Unexpected instruction on $SP: SHLI", pos); + } + if (op.i7 & 0x20) { vflags[op.rt] = +vf::is_const; @@ -943,6 +1063,12 @@ std::vector spu_recompiler_base::block(const be_t* ls, u32 entry_point const u32 op_rt = type & spu_itype::_quadrop ? +op.rt4 : +op.rt; m_regmod[pos / 4] = op_rt; vflags[op_rt] = {}; + + if (op_rt == 1) + { + LOG_TODO(SPU, "[0x%x] Unexpected instruction on $SP: %s", pos, s_spu_iname.decode(data)); + } + break; } }