mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 18:53:28 +01:00
PPU analyser improved
This commit is contained in:
parent
177084b1f4
commit
f4b95c0226
@ -60,7 +60,7 @@ void ppu_validate(const std::string& fname, const std::vector<ppu_function>& fun
|
|||||||
|
|
||||||
while (addr > found && index + 1 < funcs.size())
|
while (addr > found && index + 1 < funcs.size())
|
||||||
{
|
{
|
||||||
LOG_ERROR(LOADER, "%s.yml : validation failed at 0x%x (0x%x, 0x%x)", fname, found, addr, size);
|
LOG_WARNING(LOADER, "%s.yml : unexpected function at 0x%x (0x%x, 0x%x)", fname, found, addr, size);
|
||||||
index++;
|
index++;
|
||||||
found = funcs[index].addr - reloc;
|
found = funcs[index].addr - reloc;
|
||||||
}
|
}
|
||||||
@ -71,14 +71,12 @@ void ppu_validate(const std::string& fname, const std::vector<ppu_function>& fun
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size && size < funcs[index].size)
|
if (size && size != funcs[index].size)
|
||||||
{
|
{
|
||||||
LOG_ERROR(LOADER, "%s.yml : function size mismatch at 0x%x(size=0x%x) (0x%x, 0x%x)", fname, found, funcs[index].size, addr, size);
|
if (size + 4 != funcs[index].size || vm::read32(addr + size) != ppu_instructions::NOP())
|
||||||
}
|
{
|
||||||
|
LOG_ERROR(LOADER, "%s.yml : function size mismatch at 0x%x(size=0x%x) (0x%x, 0x%x)", fname, found, funcs[index].size, addr, size);
|
||||||
if (size > funcs[index].size)
|
}
|
||||||
{
|
|
||||||
LOG_ERROR(LOADER, "%s.yml : function size mismatch at 0x%x(size=0x%x) (0x%x, 0x%x)", fname, found, funcs[index].size, addr, size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
index++;
|
index++;
|
||||||
@ -631,6 +629,34 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ptr + 0x4 <= fend &&
|
||||||
|
(ptr[0] & 0xffff0000) == LIS(r11, 0) &&
|
||||||
|
(ptr[1] & 0xffff0000) == ADDI(r11, r11, 0) &&
|
||||||
|
ptr[2] == MTCTR(r11) &&
|
||||||
|
ptr[3] == BCTR())
|
||||||
|
{
|
||||||
|
// Simple gate
|
||||||
|
const u32 target = (ptr[0] << 16) + ppu_opcode_t{ptr[1]}.simm16;
|
||||||
|
|
||||||
|
if (target >= start && target < end)
|
||||||
|
{
|
||||||
|
auto& new_func = add_func(target, func.toc, func.addr);
|
||||||
|
|
||||||
|
if (new_func.blocks.empty())
|
||||||
|
{
|
||||||
|
func_queue.emplace_back(func);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
func.size = 0x10;
|
||||||
|
func.blocks.emplace(func.addr, func.size);
|
||||||
|
func.attr += new_func.attr & ppu_attr::no_return;
|
||||||
|
func.called_from.emplace(target);
|
||||||
|
func.gate_target = target;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ptr + 4 <= fend &&
|
if (ptr + 4 <= fend &&
|
||||||
ptr[0] == STD(r2, r1, 0x28) &&
|
ptr[0] == STD(r2, r1, 0x28) &&
|
||||||
(ptr[1] & 0xffff0000) == ADDIS(r2, r2, {}) &&
|
(ptr[1] & 0xffff0000) == ADDIS(r2, r2, {}) &&
|
||||||
@ -663,6 +689,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ptr + 8 <= fend &&
|
if (ptr + 8 <= fend &&
|
||||||
|
(ptr[0] == STD(r2, r1, 0x28) && (ptr[1] & 0xfc000000) == HACK(0) && ptr[2] == BLR() ||
|
||||||
(ptr[0] & 0xffff0000) == LI(r12, 0) &&
|
(ptr[0] & 0xffff0000) == LI(r12, 0) &&
|
||||||
(ptr[1] & 0xffff0000) == ORIS(r12, r12, 0) &&
|
(ptr[1] & 0xffff0000) == ORIS(r12, r12, 0) &&
|
||||||
(ptr[2] & 0xffff0000) == LWZ(r12, r12, 0) &&
|
(ptr[2] & 0xffff0000) == LWZ(r12, r12, 0) &&
|
||||||
@ -670,13 +697,48 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
|||||||
ptr[4] == LWZ(r0, r12, 0) &&
|
ptr[4] == LWZ(r0, r12, 0) &&
|
||||||
ptr[5] == LWZ(r2, r12, 4) &&
|
ptr[5] == LWZ(r2, r12, 4) &&
|
||||||
ptr[6] == MTCTR(r0) &&
|
ptr[6] == MTCTR(r0) &&
|
||||||
ptr[7] == BCTR())
|
ptr[7] == BCTR()))
|
||||||
{
|
{
|
||||||
// The most used simple import stub
|
// The most used simple import stub
|
||||||
func.size = 0x20;
|
func.size = 0x20;
|
||||||
func.blocks.emplace(func.addr, func.size);
|
func.blocks.emplace(func.addr, func.size);
|
||||||
func.attr += ppu_attr::known_addr;
|
func.attr += ppu_attr::known_addr;
|
||||||
func.attr += ppu_attr::known_size;
|
func.attr += ppu_attr::known_size;
|
||||||
|
|
||||||
|
// Look for another imports to fill gaps (hack)
|
||||||
|
auto p2 = ptr + 8;
|
||||||
|
|
||||||
|
while (p2 + 8 <= fend &&
|
||||||
|
(p2[0] == STD(r2, r1, 0x28) && (p2[1] & 0xfc000000) == HACK(0) && p2[2] == BLR() ||
|
||||||
|
(p2[0] & 0xffff0000) == LI(r12, 0) &&
|
||||||
|
(p2[1] & 0xffff0000) == ORIS(r12, r12, 0) &&
|
||||||
|
(p2[2] & 0xffff0000) == LWZ(r12, r12, 0) &&
|
||||||
|
p2[3] == STD(r2, r1, 0x28) &&
|
||||||
|
p2[4] == LWZ(r0, r12, 0) &&
|
||||||
|
p2[5] == LWZ(r2, r12, 4) &&
|
||||||
|
p2[6] == MTCTR(r0) &&
|
||||||
|
p2[7] == BCTR()))
|
||||||
|
{
|
||||||
|
auto& next = add_func(p2.addr(), 0, func.addr);
|
||||||
|
next.size = 0x20;
|
||||||
|
next.blocks.emplace(next.addr, next.size);
|
||||||
|
next.attr += ppu_attr::known_addr;
|
||||||
|
next.attr += ppu_attr::known_size;
|
||||||
|
p2 += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ptr + 3 <= fend &&
|
||||||
|
ptr[0] == 0x7c0004ac &&
|
||||||
|
ptr[1] == 0x00000000 &&
|
||||||
|
ptr[2] == BLR())
|
||||||
|
{
|
||||||
|
// Weird function (illegal instruction)
|
||||||
|
func.size = 0xc;
|
||||||
|
func.blocks.emplace(func.addr, func.size);
|
||||||
|
//func.attr += ppu_attr::no_return;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -884,6 +946,11 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
|||||||
block.second = _ptr.addr() - block.first;
|
block.second = _ptr.addr() - block.first;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
else if (op.opcode == ppu_instructions::TRAP())
|
||||||
|
{
|
||||||
|
block.second = _ptr.addr() - block.first;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -997,6 +1064,68 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Suspicious block start
|
||||||
|
u32 start = func.addr + func.size;
|
||||||
|
|
||||||
|
if (next == end)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Analyse gaps between functions
|
||||||
|
for (vm::cptr<u32> _ptr = vm::cast(start); _ptr.addr() < next;)
|
||||||
|
{
|
||||||
|
const u32 addr = _ptr.addr();
|
||||||
|
const ppu_opcode_t op{*_ptr++};
|
||||||
|
const ppu_itype::type type = s_ppu_itype.decode(op.opcode);
|
||||||
|
|
||||||
|
if (type == ppu_itype::UNK)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (addr == start && op.opcode == ppu_instructions::NOP())
|
||||||
|
{
|
||||||
|
if (start == func.addr + func.size)
|
||||||
|
{
|
||||||
|
// Extend function with tail NOPs (hack)
|
||||||
|
func.size += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
start += 4;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (type == ppu_itype::SC && op.opcode != ppu_instructions::SC(0))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (addr == start && op.opcode == ppu_instructions::BLR())
|
||||||
|
{
|
||||||
|
start += 4;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (type == ppu_itype::B || type == ppu_itype::BC)
|
||||||
|
{
|
||||||
|
const u32 target = (op.aa ? 0 : addr) + (type == ppu_itype::B ? +op.bt24 : +op.bt14);
|
||||||
|
|
||||||
|
if (target == addr)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_ptr.set(next);
|
||||||
|
}
|
||||||
|
else if (type == ppu_itype::BCLR || type == ppu_itype::BCCTR)
|
||||||
|
{
|
||||||
|
_ptr.set(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_ptr.addr() >= next)
|
||||||
|
{
|
||||||
|
LOG_WARNING(PPU, "Function gap: [0x%x] 0x%x bytes at 0x%x", func.addr, next - start, start);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert map to vector (destructive)
|
// Convert map to vector (destructive)
|
||||||
|
@ -899,13 +899,12 @@ void PPUDisAsm::HACK(ppu_opcode_t op)
|
|||||||
|
|
||||||
void PPUDisAsm::SC(ppu_opcode_t op)
|
void PPUDisAsm::SC(ppu_opcode_t op)
|
||||||
{
|
{
|
||||||
switch (op.lev)
|
if (op.opcode != ppu_instructions::SC(0))
|
||||||
{
|
{
|
||||||
case 0x0: Write("sc"); break;
|
return UNK(op);
|
||||||
case 0x1: Write("HyperCall LV1"); break;
|
|
||||||
case 0x3: Write("fast_stop()"); break; // hack
|
|
||||||
default: Write(fmt::format("Unknown sc: 0x%x", op.lev));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Write("sc");
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPUDisAsm::B(ppu_opcode_t op)
|
void PPUDisAsm::B(ppu_opcode_t op)
|
||||||
|
@ -1944,12 +1944,12 @@ bool ppu_interpreter::HACK(ppu_thread& ppu, ppu_opcode_t op)
|
|||||||
|
|
||||||
bool ppu_interpreter::SC(ppu_thread& ppu, ppu_opcode_t op)
|
bool ppu_interpreter::SC(ppu_thread& ppu, ppu_opcode_t op)
|
||||||
{
|
{
|
||||||
switch (u32 lv = op.lev)
|
if (op.opcode != ppu_instructions::SC(0))
|
||||||
{
|
{
|
||||||
case 0x0: ppu_execute_syscall(ppu, ppu.gpr[11]); break;
|
return UNK(ppu, op);
|
||||||
default: fmt::throw_exception("SC lv%u", lv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ppu_execute_syscall(ppu, ppu.gpr[11]);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -643,6 +643,8 @@ namespace ppu_instructions
|
|||||||
inline u32 EXTRDI(u32 x, u32 y, u32 n, u32 b) { return RLDICL(x, y, b + n, 64 - b, false); }
|
inline u32 EXTRDI(u32 x, u32 y, u32 n, u32 b) { return RLDICL(x, y, b + n, 64 - b, false); }
|
||||||
inline u32 SRDI(u32 x, u32 y, u32 n) { return RLDICL(x, y, 64 - n, n, false); }
|
inline u32 SRDI(u32 x, u32 y, u32 n) { return RLDICL(x, y, 64 - n, n, false); }
|
||||||
inline u32 CLRLDI(u32 x, u32 y, u32 n) { return RLDICL(x, y, 0, n, false); }
|
inline u32 CLRLDI(u32 x, u32 y, u32 n) { return RLDICL(x, y, 0, n, false); }
|
||||||
|
|
||||||
|
inline u32 TRAP() { return 0x7FE00008; } // tw 31,r0,r0
|
||||||
}
|
}
|
||||||
|
|
||||||
using namespace implicts;
|
using namespace implicts;
|
||||||
|
@ -1758,7 +1758,12 @@ void PPUTranslator::HACK(ppu_opcode_t op)
|
|||||||
|
|
||||||
void PPUTranslator::SC(ppu_opcode_t op)
|
void PPUTranslator::SC(ppu_opcode_t op)
|
||||||
{
|
{
|
||||||
Call(GetType<void>(), fmt::format(op.lev == 0 ? "__syscall" : "__lv%ucall", +op.lev), m_thread, m_ir->CreateLoad(m_gpr[11]));
|
if (op.opcode != ppu_instructions::SC(0) && op.opcode != ppu_instructions::SC(1))
|
||||||
|
{
|
||||||
|
return UNK(op);
|
||||||
|
}
|
||||||
|
|
||||||
|
Call(GetType<void>(), op.lev ? "__lv1call" : "__syscall", m_thread, m_ir->CreateLoad(m_gpr[11]));
|
||||||
UndefineVolatileRegisters();
|
UndefineVolatileRegisters();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user