mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-10 16:14:29 +00:00
Implement spu_iname helper
Remove old code Report $SP anomalies
This commit is contained in:
parent
e009bbac10
commit
41eab62ed7
@ -35,6 +35,19 @@ void fmt_class_string<bs_t<ppu_attr>>::format(std::string& out, u64 arg)
|
||||
format_bitset(out, arg, "[", ",", "]", &fmt_class_string<ppu_attr>::format);
|
||||
}
|
||||
|
||||
template <>
|
||||
void fmt_class_string<ppu_iname::type>::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<char>(value + 0x20);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ppu_module::validate(u32 reloc)
|
||||
{
|
||||
// Load custom PRX configuration if available
|
||||
|
@ -1,331 +1,15 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/Memory/vm.h"
|
||||
#include "SPUAnalyser.h"
|
||||
#include "SPURecompiler.h"
|
||||
#include "SPUOpcodes.h"
|
||||
|
||||
const spu_decoder<spu_itype> s_spu_itype;
|
||||
|
||||
std::shared_ptr<spu_function> spu_analyse(const be_t<u32>* ls, u32 entry, u32 max_limit)
|
||||
template <>
|
||||
void fmt_class_string<spu_iname::type>::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<u32>* 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<u32> blocks{ entry };
|
||||
|
||||
// Entries of adjacent functions; jump table entries
|
||||
std::set<u32> 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<u32> jt_abs;
|
||||
std::vector<u32> 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<u32>(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<char>(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<spu_function>(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;
|
||||
}
|
||||
|
@ -1,8 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
// 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<be_t<u32>> data;
|
||||
|
||||
// Basic blocks (start addresses)
|
||||
std::set<u32> blocks;
|
||||
|
||||
// Functions possibly called by this function (may not be available)
|
||||
std::set<u32> adjacent;
|
||||
|
||||
// Jump table values (start addresses)
|
||||
std::set<u32> jtable;
|
||||
|
||||
// Whether ila $SP,* instruction found
|
||||
bool does_reset_stack;
|
||||
|
||||
// Pointer to the compiled function
|
||||
u32(*compiled)(SPUThread* _spu, be_t<u32>* _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
|
||||
|
@ -20,6 +20,7 @@ extern atomic_t<u64> g_progr_ptotal;
|
||||
extern atomic_t<u64> g_progr_pdone;
|
||||
|
||||
const spu_decoder<spu_itype> s_spu_itype;
|
||||
const spu_decoder<spu_iname> 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<u32> spu_recompiler_base::block(const be_t<u32>* 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<u32> spu_recompiler_base::block(const be_t<u32>* 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<u32> spu_recompiler_base::block(const be_t<u32>* 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<u32> spu_recompiler_base::block(const be_t<u32>* 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<u32> spu_recompiler_base::block(const be_t<u32>* 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<u32> spu_recompiler_base::block(const be_t<u32>* 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<u32> spu_recompiler_base::block(const be_t<u32>* 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<u32> spu_recompiler_base::block(const be_t<u32>* 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<u32> spu_recompiler_base::block(const be_t<u32>* 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<u32> spu_recompiler_base::block(const be_t<u32>* 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<u32> spu_recompiler_base::block(const be_t<u32>* 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<u32> spu_recompiler_base::block(const be_t<u32>* 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<u32> spu_recompiler_base::block(const be_t<u32>* 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<u32> spu_recompiler_base::block(const be_t<u32>* 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<u32> spu_recompiler_base::block(const be_t<u32>* 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<u32> spu_recompiler_base::block(const be_t<u32>* 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<u32> spu_recompiler_base::block(const be_t<u32>* 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;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user