mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-11 08:39:13 +01:00
d0ae3f7d24
This cleans up some of the code between core and UI for disassembling and dumping code blocks. Should help the QT UI in bringing up its debug UI since it won't have to deal with this garbage now.
187 lines
5.2 KiB
C++
187 lines
5.2 KiB
C++
// Copyright 2008 Dolphin Emulator Project
|
|
// Licensed under GPLv2+
|
|
// Refer to the license.txt file included.
|
|
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <disasm.h> // Bochs
|
|
#include <sstream>
|
|
|
|
#include <wx/button.h>
|
|
#include <wx/listctrl.h>
|
|
#include <wx/panel.h>
|
|
#include <wx/sizer.h>
|
|
#include <wx/textctrl.h>
|
|
|
|
#include "Common/CommonTypes.h"
|
|
#include "Common/GekkoDisassembler.h"
|
|
#include "Core/PowerPC/Gekko.h"
|
|
#include "Core/PowerPC/PPCAnalyst.h"
|
|
#include "DolphinWX/Globals.h"
|
|
#include "DolphinWX/WxUtils.h"
|
|
#include "DolphinWX/Debugger/JitWindow.h"
|
|
#include "UICommon/Disassembler.h"
|
|
|
|
CJitWindow::CJitWindow(wxWindow* parent, wxWindowID id, const wxPoint& pos,
|
|
const wxSize& size, long style, const wxString& name)
|
|
: wxPanel(parent, id, pos, size, style, name)
|
|
{
|
|
wxBoxSizer* sizerBig = new wxBoxSizer(wxVERTICAL);
|
|
wxBoxSizer* sizerSplit = new wxBoxSizer(wxHORIZONTAL);
|
|
sizerSplit->Add(ppc_box = new wxTextCtrl(this, wxID_ANY, "(ppc)",
|
|
wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE), 1, wxEXPAND);
|
|
sizerSplit->Add(x86_box = new wxTextCtrl(this, wxID_ANY, "(x86)",
|
|
wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE), 1, wxEXPAND);
|
|
sizerBig->Add(block_list = new JitBlockList(this, wxID_ANY,
|
|
wxDefaultPosition, wxSize(100, 140),
|
|
wxLC_REPORT | wxSUNKEN_BORDER | wxLC_ALIGN_LEFT | wxLC_SINGLE_SEL | wxLC_SORT_ASCENDING),
|
|
0, wxEXPAND);
|
|
sizerBig->Add(sizerSplit, 2, wxEXPAND);
|
|
|
|
sizerBig->Add(button_refresh = new wxButton(this, wxID_ANY, _("&Refresh")));
|
|
button_refresh->Bind(wxEVT_BUTTON, &CJitWindow::OnRefresh, this);
|
|
|
|
SetSizer(sizerBig);
|
|
|
|
sizerSplit->Fit(this);
|
|
sizerBig->Fit(this);
|
|
|
|
#if defined(_M_X86)
|
|
m_disassembler.reset(GetNewDisassembler("x86"));
|
|
#elif defined(_M_ARM_64)
|
|
m_disassembler.reset(GetNewDisassembler("aarch64"));
|
|
#elif defined(_M_ARM_32)
|
|
m_disassembler.reset(GetNewDisassembler("armv7"));
|
|
#else
|
|
m_disassembler.reset(GetNewDisassembler("UNK"));
|
|
#endif
|
|
}
|
|
|
|
void CJitWindow::OnRefresh(wxCommandEvent& /*event*/)
|
|
{
|
|
block_list->Update();
|
|
}
|
|
|
|
void CJitWindow::ViewAddr(u32 em_address)
|
|
{
|
|
Show(true);
|
|
Compare(em_address);
|
|
SetFocus();
|
|
}
|
|
|
|
void CJitWindow::Compare(u32 em_address)
|
|
{
|
|
// Get host side code disassembly
|
|
u32 host_instructions_count = 0;
|
|
u32 host_code_size = 0;
|
|
std::string host_instructions_disasm;
|
|
host_instructions_disasm = DisassembleBlock(m_disassembler.get(), &em_address, &host_instructions_count, &host_code_size);
|
|
|
|
x86_box->SetValue(host_instructions_disasm);
|
|
|
|
// == Fill in ppc box
|
|
u32 ppc_addr = em_address;
|
|
PPCAnalyst::CodeBuffer code_buffer(32000);
|
|
PPCAnalyst::BlockStats st;
|
|
PPCAnalyst::BlockRegStats gpa;
|
|
PPCAnalyst::BlockRegStats fpa;
|
|
PPCAnalyst::CodeBlock code_block;
|
|
PPCAnalyst::PPCAnalyzer analyzer;
|
|
analyzer.SetOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE);
|
|
|
|
code_block.m_stats = &st;
|
|
code_block.m_gpa = &gpa;
|
|
code_block.m_fpa = &fpa;
|
|
|
|
if (analyzer.Analyze(ppc_addr, &code_block, &code_buffer, 32000) != 0xFFFFFFFF)
|
|
{
|
|
std::ostringstream ppc_disasm;
|
|
for (u32 i = 0; i < code_block.m_num_instructions; i++)
|
|
{
|
|
const PPCAnalyst::CodeOp &op = code_buffer.codebuffer[i];
|
|
std::string opcode = GekkoDisassembler::Disassemble(op.inst.hex, op.address);
|
|
ppc_disasm << std::setfill('0') << std::setw(8) << std::hex << op.address;
|
|
ppc_disasm << " " << opcode << std::endl;
|
|
}
|
|
|
|
// Add stats to the end of the ppc box since it's generally the shortest.
|
|
ppc_disasm << std::dec << std::endl;
|
|
|
|
// Add some generic analysis
|
|
if (st.isFirstBlockOfFunction)
|
|
ppc_disasm << "(first block of function)" << std::endl;
|
|
if (st.isLastBlockOfFunction)
|
|
ppc_disasm << "(last block of function)" << std::endl;
|
|
|
|
ppc_disasm << st.numCycles << " estimated cycles" << std::endl;
|
|
|
|
ppc_disasm << "Num instr: PPC: " << code_block.m_num_instructions
|
|
<< " x86: " << host_instructions_count
|
|
<< " (blowup: " << 100 * host_instructions_count / code_block.m_num_instructions - 100
|
|
<< "%)" << std::endl;
|
|
|
|
ppc_disasm << "Num bytes: PPC: " << code_block.m_num_instructions * 4
|
|
<< " x86: " << host_code_size
|
|
<< " (blowup: " << 100 * host_code_size / (4 * code_block.m_num_instructions) - 100
|
|
<< "%)" << std::endl;
|
|
|
|
ppc_box->SetValue(ppc_disasm.str());
|
|
}
|
|
else
|
|
{
|
|
ppc_box->SetValue(StringFromFormat("(non-code address: %08x)", em_address));
|
|
x86_box->SetValue("---");
|
|
}
|
|
}
|
|
|
|
void CJitWindow::Update()
|
|
{
|
|
|
|
}
|
|
|
|
void CJitWindow::OnHostMessage(wxCommandEvent& event)
|
|
{
|
|
switch (event.GetId())
|
|
{
|
|
case IDM_NOTIFY_MAP_LOADED:
|
|
//NotifyMapLoaded();
|
|
break;
|
|
}
|
|
}
|
|
|
|
// JitBlockList
|
|
//================
|
|
|
|
enum
|
|
{
|
|
COLUMN_ADDRESS,
|
|
COLUMN_PPCSIZE,
|
|
COLUMN_X86SIZE,
|
|
COLUMN_NAME,
|
|
COLUMN_FLAGS,
|
|
COLUMN_NUMEXEC,
|
|
COLUMN_COST, // (estimated as x86size * numexec)
|
|
};
|
|
|
|
JitBlockList::JitBlockList(wxWindow* parent, const wxWindowID id,
|
|
const wxPoint& pos, const wxSize& size, long style)
|
|
: wxListCtrl(parent, id, pos, size, style) // | wxLC_VIRTUAL)
|
|
{
|
|
Init();
|
|
}
|
|
|
|
void JitBlockList::Init()
|
|
{
|
|
InsertColumn(COLUMN_ADDRESS, _("Address"));
|
|
InsertColumn(COLUMN_PPCSIZE, _("PPC Size"));
|
|
InsertColumn(COLUMN_X86SIZE, _("x86 Size"));
|
|
InsertColumn(COLUMN_NAME, _("Symbol"));
|
|
InsertColumn(COLUMN_FLAGS, _("Flags"));
|
|
InsertColumn(COLUMN_NUMEXEC, _("NumExec"));
|
|
InsertColumn(COLUMN_COST, _("Cost"));
|
|
}
|
|
|
|
void JitBlockList::Update()
|
|
{
|
|
}
|