mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 02:32:36 +01:00
memory viewer: Implement RSX mode
* Set the ground for RSX modes of register editor and insttruction editor, do not use shared ptrs directly. * Make register editor and instruction editor modeless to allow to copypaste values from thread context etc in the background.
This commit is contained in:
parent
8c6aa9db31
commit
2005c89baa
@ -43,7 +43,7 @@ namespace rsx
|
||||
{
|
||||
std::function<bool(u32 addr, bool is_writing)> g_access_violation_handler;
|
||||
|
||||
u32 get_address(u32 offset, u32 location, u32 line, u32 col, const char* file, const char* func)
|
||||
u32 get_address(u32 offset, u32 location, bool allow_failure, u32 line, u32 col, const char* file, const char* func)
|
||||
{
|
||||
const auto render = get_current_renderer();
|
||||
std::string_view msg;
|
||||
@ -150,6 +150,11 @@ namespace rsx
|
||||
}
|
||||
}
|
||||
|
||||
if (allow_failure)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
fmt::throw_exception("rsx::get_address(offset=0x%x, location=0x%x): %s%s", offset, location, msg, src_loc{line, col, file, func});
|
||||
}
|
||||
|
||||
|
@ -172,7 +172,7 @@ namespace rsx
|
||||
|
||||
u32 get_vertex_type_size_on_host(vertex_base_type type, u32 size);
|
||||
|
||||
u32 get_address(u32 offset, u32 location,
|
||||
u32 get_address(u32 offset, u32 location, bool allow_failure = false,
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN(),
|
||||
const char* file = __builtin_FILE(),
|
||||
|
@ -313,10 +313,14 @@ void debugger_frame::keyPressEvent(QKeyEvent* event)
|
||||
{
|
||||
case Qt::Key_E:
|
||||
{
|
||||
if (m_cpu)
|
||||
if (cpu->id_type() == 1 || cpu->id_type() == 2)
|
||||
{
|
||||
instruction_editor_dialog* dlg = new instruction_editor_dialog(this, pc, m_cpu, m_disasm.get());
|
||||
dlg->show();
|
||||
if (!m_inst_editor)
|
||||
{
|
||||
m_inst_editor = new instruction_editor_dialog(this, pc, m_disasm.get(), make_check_cpu(cpu));
|
||||
connect(m_inst_editor, &QDialog::finished, this, [this]() { m_inst_editor = nullptr; });
|
||||
m_inst_editor->show();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -332,10 +336,14 @@ void debugger_frame::keyPressEvent(QKeyEvent* event)
|
||||
}
|
||||
case Qt::Key_R:
|
||||
{
|
||||
if (m_cpu)
|
||||
if (cpu->id_type() == 1 || cpu->id_type() == 2)
|
||||
{
|
||||
register_editor_dialog* dlg = new register_editor_dialog(this, m_cpu, m_disasm.get());
|
||||
dlg->show();
|
||||
if (!m_reg_editor)
|
||||
{
|
||||
m_reg_editor = new register_editor_dialog(this, m_disasm.get(), make_check_cpu(cpu));
|
||||
connect(m_reg_editor, &QDialog::finished, this, [this]() { m_reg_editor = nullptr; });
|
||||
m_reg_editor->show();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -386,7 +394,7 @@ void debugger_frame::keyPressEvent(QKeyEvent* event)
|
||||
case Qt::Key_M:
|
||||
{
|
||||
// Memory viewer
|
||||
if (m_cpu) idm::make<memory_viewer_handle>(this, pc, m_cpu);
|
||||
idm::make<memory_viewer_handle>(this, pc, make_check_cpu(cpu));
|
||||
return;
|
||||
}
|
||||
case Qt::Key_F10:
|
||||
@ -417,19 +425,63 @@ cpu_thread* debugger_frame::get_cpu()
|
||||
// m_rsx is raw pointer, when emulation is stopped it won't be cleared
|
||||
// Therefore need to do invalidation checks manually
|
||||
|
||||
if (m_emu_state == system_state::stopped)
|
||||
{
|
||||
m_rsx = nullptr;
|
||||
return m_rsx;
|
||||
}
|
||||
|
||||
if (g_fxo->get<rsx::thread>() != m_rsx)
|
||||
{
|
||||
m_rsx = nullptr;
|
||||
return m_rsx;
|
||||
}
|
||||
|
||||
if (m_rsx && !m_rsx->ctrl)
|
||||
{
|
||||
m_rsx = nullptr;
|
||||
return m_rsx;
|
||||
}
|
||||
|
||||
return m_rsx;
|
||||
}
|
||||
|
||||
std::function<cpu_thread*()> debugger_frame::make_check_cpu(cpu_thread* cpu)
|
||||
{
|
||||
const u32 id = cpu ? cpu->id : UINT32_MAX;
|
||||
const u32 type = id >> 24;
|
||||
|
||||
std::shared_ptr<cpu_thread> shared = type == 1 ? static_cast<std::shared_ptr<cpu_thread>>(idm::get<named_thread<ppu_thread>>(id)) :
|
||||
type == 2 ? idm::get<named_thread<spu_thread>>(id) : nullptr;
|
||||
|
||||
if (shared.get() != cpu)
|
||||
{
|
||||
shared.reset();
|
||||
}
|
||||
|
||||
return [&rsx = m_rsx, cpu, type, shared = std::move(shared)]() -> cpu_thread*
|
||||
{
|
||||
if (type == 1 || type == 2)
|
||||
{
|
||||
// SPU and PPU
|
||||
if (!shared || (shared->state & cpu_flag::exit && shared->state & cpu_flag::wait))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return shared.get();
|
||||
}
|
||||
|
||||
// RSX
|
||||
if (rsx == cpu)
|
||||
{
|
||||
return cpu;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
void debugger_frame::UpdateUI()
|
||||
{
|
||||
UpdateUnitList();
|
||||
@ -476,8 +528,9 @@ void debugger_frame::UpdateUI()
|
||||
}
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(std::weak_ptr<cpu_thread>);
|
||||
Q_DECLARE_METATYPE(::rsx::thread*);
|
||||
using data_type = std::pair<cpu_thread*, u32>;
|
||||
|
||||
Q_DECLARE_METATYPE(data_type);
|
||||
|
||||
void debugger_frame::UpdateUnitList()
|
||||
{
|
||||
@ -500,15 +553,20 @@ void debugger_frame::UpdateUnitList()
|
||||
//const int old_size = m_choice_units->count();
|
||||
QVariant old_cpu = m_choice_units->currentData();
|
||||
|
||||
bool reselected = false;
|
||||
|
||||
const auto on_select = [&](u32 id, cpu_thread& cpu)
|
||||
{
|
||||
if (emu_state == system_state::stopped) return;
|
||||
|
||||
QVariant var_cpu = QVariant::fromValue<std::weak_ptr<cpu_thread>>(
|
||||
id >> 24 == 1 ? static_cast<std::weak_ptr<cpu_thread>>(idm::get_unlocked<named_thread<ppu_thread>>(id)) : idm::get_unlocked<named_thread<spu_thread>>(id));
|
||||
QVariant var_cpu = QVariant::fromValue<std::pair<cpu_thread*, u32>>(std::make_pair(&cpu, id));
|
||||
m_choice_units->addItem(qstr(id >> 24 == 0x55 ? "RSX[0x55555555]" : cpu.get_name()), var_cpu);
|
||||
|
||||
m_choice_units->addItem(qstr(cpu.get_name()), var_cpu);
|
||||
if (old_cpu == var_cpu) m_choice_units->setCurrentIndex(m_choice_units->count() - 1);
|
||||
if (!reselected && old_cpu == var_cpu)
|
||||
{
|
||||
m_choice_units->setCurrentIndex(m_choice_units->count() - 1);
|
||||
reselected = true;
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
@ -522,12 +580,17 @@ void debugger_frame::UpdateUnitList()
|
||||
|
||||
if (auto render = g_fxo->get<rsx::thread>(); emu_state != system_state::stopped && render && render->ctrl)
|
||||
{
|
||||
QVariant var_cpu = QVariant::fromValue<rsx::thread*>(render);
|
||||
m_choice_units->addItem("RSX[0x55555555]", var_cpu);
|
||||
if (old_cpu == var_cpu) m_choice_units->setCurrentIndex(m_choice_units->count() - 1);
|
||||
on_select(render->id, *render);
|
||||
}
|
||||
}
|
||||
|
||||
// Close dialogs which are tied to the specific thread selected
|
||||
if (!reselected)
|
||||
{
|
||||
if (m_reg_editor) m_reg_editor->close();
|
||||
if (m_inst_editor) m_inst_editor->close();
|
||||
}
|
||||
|
||||
OnSelectUnit();
|
||||
|
||||
m_choice_units->update();
|
||||
@ -535,65 +598,83 @@ void debugger_frame::UpdateUnitList()
|
||||
|
||||
void debugger_frame::OnSelectUnit()
|
||||
{
|
||||
if (m_choice_units->count() < 1)
|
||||
{
|
||||
m_debugger_list->UpdateCPUData(nullptr, nullptr);
|
||||
m_breakpoint_list->UpdateCPUData(nullptr, nullptr);
|
||||
m_disasm.reset();
|
||||
m_cpu.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto weak = m_choice_units->currentData().value<std::weak_ptr<cpu_thread>>();
|
||||
const auto render = m_choice_units->currentData().value<rsx::thread*>();
|
||||
auto [selected, cpu_id] = m_choice_units->currentData().value<std::pair<cpu_thread*, u32>>();
|
||||
|
||||
if (m_emu_state != system_state::stopped)
|
||||
{
|
||||
if (!render && !weak.owner_before(m_cpu) && !m_cpu.owner_before(weak))
|
||||
if (selected && m_cpu.get() == selected)
|
||||
{
|
||||
// They match, nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
if (render && render == get_cpu())
|
||||
if (selected && m_rsx == selected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!selected && !m_rsx && !m_cpu)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
selected = nullptr;
|
||||
}
|
||||
|
||||
m_disasm.reset();
|
||||
m_cpu.reset();
|
||||
m_rsx = nullptr;
|
||||
|
||||
if (!weak.expired())
|
||||
if (selected)
|
||||
{
|
||||
if (const auto cpu0 = weak.lock())
|
||||
switch (cpu_id >> 24)
|
||||
{
|
||||
if (cpu0->id_type() == 1)
|
||||
{
|
||||
if (cpu0.get() == idm::check<named_thread<ppu_thread>>(cpu0->id))
|
||||
{
|
||||
m_cpu = cpu0;
|
||||
m_disasm = std::make_shared<PPUDisAsm>(cpu_disasm_mode::interpreter, vm::g_sudo_addr);
|
||||
}
|
||||
}
|
||||
else if (cpu0->id_type() == 2)
|
||||
{
|
||||
if (cpu0.get() == idm::check<named_thread<spu_thread>>(cpu0->id))
|
||||
{
|
||||
m_cpu = cpu0;
|
||||
m_disasm = std::make_shared<SPUDisAsm>(cpu_disasm_mode::interpreter, static_cast<const spu_thread*>(cpu0.get())->ls);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_rsx = render;
|
||||
case 1:
|
||||
{
|
||||
m_cpu = idm::get<named_thread<ppu_thread>>(cpu_id);
|
||||
|
||||
if (get_cpu())
|
||||
if (selected == m_cpu.get())
|
||||
{
|
||||
m_disasm = std::make_shared<PPUDisAsm>(cpu_disasm_mode::interpreter, vm::g_sudo_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cpu.reset();
|
||||
selected = nullptr;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
m_disasm = std::make_shared<RSXDisAsm>(cpu_disasm_mode::interpreter, vm::g_sudo_addr, m_rsx);
|
||||
m_cpu = idm::get<named_thread<spu_thread>>(cpu_id);
|
||||
|
||||
if (selected == m_cpu.get())
|
||||
{
|
||||
m_disasm = std::make_shared<SPUDisAsm>(cpu_disasm_mode::interpreter, static_cast<const spu_thread*>(m_cpu.get())->ls);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cpu.reset();
|
||||
selected = nullptr;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 0x55:
|
||||
{
|
||||
m_rsx = static_cast<rsx::thread*>(selected);
|
||||
|
||||
if (get_cpu())
|
||||
{
|
||||
m_disasm = std::make_shared<RSXDisAsm>(cpu_disasm_mode::interpreter, vm::g_sudo_addr, m_rsx);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,9 @@ namespace rsx
|
||||
|
||||
enum class system_state : u32;
|
||||
|
||||
class instruction_editor_dialog;
|
||||
class register_editor_dialog;
|
||||
|
||||
class debugger_frame : public custom_dock_widget
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -62,12 +65,15 @@ class debugger_frame : public custom_dock_widget
|
||||
|
||||
breakpoint_list* m_breakpoint_list;
|
||||
breakpoint_handler* m_breakpoint_handler;
|
||||
|
||||
call_stack_list* m_call_stack_list;
|
||||
instruction_editor_dialog* m_inst_editor = nullptr;
|
||||
register_editor_dialog* m_reg_editor = nullptr;
|
||||
|
||||
std::shared_ptr<gui_settings> xgui_settings;
|
||||
|
||||
cpu_thread* get_cpu();
|
||||
std::function<cpu_thread*()> make_check_cpu(cpu_thread* cpu);
|
||||
|
||||
public:
|
||||
explicit debugger_frame(std::shared_ptr<gui_settings> settings, QWidget *parent = 0);
|
||||
|
||||
|
@ -13,17 +13,19 @@ constexpr auto qstr = QString::fromStdString;
|
||||
|
||||
extern bool ppu_patch(u32 addr, u32 value);
|
||||
|
||||
instruction_editor_dialog::instruction_editor_dialog(QWidget *parent, u32 _pc, const std::shared_ptr<cpu_thread>& _cpu, CPUDisAsm* _disasm)
|
||||
instruction_editor_dialog::instruction_editor_dialog(QWidget *parent, u32 _pc, CPUDisAsm* _disasm, std::function<cpu_thread*()> func)
|
||||
: QDialog(parent)
|
||||
, m_pc(_pc)
|
||||
, m_disasm(_disasm)
|
||||
, m_cpu(_cpu)
|
||||
, m_get_cpu(std::move(func))
|
||||
{
|
||||
setWindowTitle(tr("Edit instruction"));
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
setMinimumSize(300, sizeHint().height());
|
||||
|
||||
m_cpu_offset = m_cpu->id_type() == 2 ? static_cast<spu_thread&>(*m_cpu).ls : vm::g_sudo_addr;
|
||||
const auto cpu = m_get_cpu();
|
||||
|
||||
m_cpu_offset = cpu && cpu->id_type() == 2 ? static_cast<spu_thread&>(*cpu).ls : vm::g_sudo_addr;
|
||||
QString instruction = qstr(fmt::format("%08x", *reinterpret_cast<be_t<u32>*>(m_cpu_offset + m_pc)));
|
||||
|
||||
QVBoxLayout* vbox_panel(new QVBoxLayout());
|
||||
@ -68,11 +70,18 @@ instruction_editor_dialog::instruction_editor_dialog(QWidget *parent, u32 _pc, c
|
||||
vbox_panel->addSpacing(10);
|
||||
vbox_panel->addLayout(hbox_b_panel);
|
||||
setLayout(vbox_panel);
|
||||
setModal(true);
|
||||
|
||||
// Events
|
||||
connect(button_ok, &QAbstractButton::clicked, [=, this]()
|
||||
{
|
||||
const auto cpu = m_get_cpu();
|
||||
|
||||
if (!cpu)
|
||||
{
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
bool ok;
|
||||
ulong opcode = m_instr->text().toULong(&ok, 16);
|
||||
if (!ok || opcode > UINT32_MAX)
|
||||
@ -80,7 +89,7 @@ instruction_editor_dialog::instruction_editor_dialog(QWidget *parent, u32 _pc, c
|
||||
QMessageBox::critical(this, tr("Error"), tr("Failed to parse PPU instruction."));
|
||||
return;
|
||||
}
|
||||
else if (m_cpu->id_type() == 1)
|
||||
else if (cpu->id_type() == 1)
|
||||
{
|
||||
if (!ppu_patch(m_pc, static_cast<u32>(opcode)))
|
||||
{
|
||||
|
@ -22,10 +22,10 @@ private:
|
||||
QLineEdit* m_instr;
|
||||
QLabel* m_preview;
|
||||
|
||||
public:
|
||||
std::shared_ptr<cpu_thread> m_cpu;
|
||||
const std::function<cpu_thread*()> m_get_cpu;
|
||||
|
||||
instruction_editor_dialog(QWidget *parent, u32 _pc, const std::shared_ptr<cpu_thread>& _cpu, CPUDisAsm* _disasm);
|
||||
public:
|
||||
instruction_editor_dialog(QWidget *parent, u32 _pc, CPUDisAsm* _disasm, std::function<cpu_thread*()> func);
|
||||
|
||||
void updatePreview();
|
||||
};
|
||||
|
@ -149,9 +149,8 @@ static QTreeWidgetItem* add_solid_node(QTreeWidget* tree, QTreeWidgetItem *paren
|
||||
return node;
|
||||
}
|
||||
|
||||
kernel_explorer::kernel_explorer(QWidget* parent, std::function<void()> on_destroy)
|
||||
kernel_explorer::kernel_explorer(QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, m_on_destroy(on_destroy)
|
||||
{
|
||||
setWindowTitle(tr("Kernel Explorer"));
|
||||
setObjectName("kernel_explorer");
|
||||
@ -182,11 +181,6 @@ kernel_explorer::kernel_explorer(QWidget* parent, std::function<void()> on_destr
|
||||
Update();
|
||||
}
|
||||
|
||||
kernel_explorer::~kernel_explorer()
|
||||
{
|
||||
m_on_destroy();
|
||||
}
|
||||
|
||||
void kernel_explorer::Update()
|
||||
{
|
||||
const auto dct = g_fxo->get<lv2_memory_container>();
|
||||
|
@ -26,12 +26,10 @@ class kernel_explorer : public QDialog
|
||||
};
|
||||
|
||||
public:
|
||||
kernel_explorer(QWidget* parent, std::function<void()> on_destroy);
|
||||
~kernel_explorer();
|
||||
kernel_explorer(QWidget* parent);
|
||||
|
||||
private:
|
||||
QTreeWidget* m_tree;
|
||||
std::function<void()> m_on_destroy;
|
||||
|
||||
private Q_SLOTS:
|
||||
void Update();
|
||||
|
@ -1827,10 +1827,8 @@ void main_window::CreateConnects()
|
||||
{
|
||||
if (!m_kernel_explorer)
|
||||
{
|
||||
m_kernel_explorer = new kernel_explorer(this, [this]()
|
||||
{
|
||||
m_kernel_explorer = nullptr;
|
||||
});
|
||||
m_kernel_explorer = new kernel_explorer(this);
|
||||
connect(m_kernel_explorer, &QDialog::finished, this, [this]() { m_kernel_explorer = nullptr; });
|
||||
}
|
||||
|
||||
m_kernel_explorer->show();
|
||||
|
@ -5,6 +5,8 @@
|
||||
#include "memory_viewer_panel.h"
|
||||
|
||||
#include "Emu/Cell/SPUThread.h"
|
||||
#include "Emu/RSX/RSXThread.h"
|
||||
#include "Emu/RSX/rsx_utils.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include <QVBoxLayout>
|
||||
#include <QPushButton>
|
||||
@ -20,14 +22,35 @@
|
||||
|
||||
constexpr auto qstr = QString::fromStdString;
|
||||
|
||||
memory_viewer_panel::memory_viewer_panel(QWidget* parent, u32 addr, const std::shared_ptr<cpu_thread>& cpu)
|
||||
memory_viewer_panel::memory_viewer_panel(QWidget* parent, u32 addr, std::function<cpu_thread*()> func)
|
||||
: QDialog(parent)
|
||||
, m_addr(addr)
|
||||
, m_type(!cpu || cpu->id_type() == 1 ? thread_type::ppu : thread_type::spu)
|
||||
, m_spu_shm(m_type == thread_type::spu ? static_cast<spu_thread*>(cpu.get())->shm : nullptr)
|
||||
, m_get_cpu(std::move(func))
|
||||
, m_type([&]()
|
||||
{
|
||||
const auto cpu = m_get_cpu();
|
||||
|
||||
if (!cpu) return thread_type::none;
|
||||
if (cpu->id_type() == 1) return thread_type::ppu;
|
||||
if (cpu->id_type() == 0x55) return thread_type::rsx;
|
||||
if (cpu->id_type() == 2) return thread_type::spu;
|
||||
|
||||
fmt::throw_exception("Unknown CPU type (0x%x)", cpu->id_type());
|
||||
}())
|
||||
, m_rsx(m_type == thread_type::rsx ? static_cast<rsx::thread*>(m_get_cpu()) : nullptr)
|
||||
, m_spu_shm([&]()
|
||||
{
|
||||
const auto cpu = m_get_cpu();
|
||||
return cpu && m_type == thread_type::spu ? static_cast<spu_thread*>(cpu)->shm : nullptr;
|
||||
}())
|
||||
, m_addr_mask(m_type == thread_type::spu ? SPU_LS_SIZE - 1 : ~0)
|
||||
{
|
||||
setWindowTitle(m_type != thread_type::spu ? tr("Memory Viewer") : tr("Memory Viewer Of %0").arg(qstr(cpu->get_name())));
|
||||
const auto cpu = m_get_cpu();
|
||||
|
||||
setWindowTitle(
|
||||
cpu && m_type == thread_type::spu ? tr("Memory Viewer Of %0").arg(qstr(cpu->get_name())) :
|
||||
cpu && m_type == thread_type::rsx ? tr("Memory Viewer Of RSX[0x55555555]") :
|
||||
tr("Memory Viewer"));
|
||||
|
||||
setObjectName("memory_viewer");
|
||||
m_colcount = 4;
|
||||
@ -361,6 +384,83 @@ std::string memory_viewer_panel::getHeaderAtAddr(u32 addr)
|
||||
return {};
|
||||
}
|
||||
|
||||
void* memory_viewer_panel::to_ptr(u32 addr, u32 size)
|
||||
{
|
||||
if (m_type >= thread_type::spu && !m_get_cpu())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!size)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
switch (m_type)
|
||||
{
|
||||
case thread_type::none:
|
||||
case thread_type::ppu:
|
||||
{
|
||||
if (vm::check_addr(addr, 0, size))
|
||||
{
|
||||
return vm::get_super_ptr(addr);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case thread_type::spu:
|
||||
{
|
||||
if (size <= SPU_LS_SIZE && SPU_LS_SIZE - size >= (addr % SPU_LS_SIZE))
|
||||
{
|
||||
return m_spu_shm->map_self() + (addr % SPU_LS_SIZE);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case thread_type::rsx:
|
||||
{
|
||||
u32 final_addr = 0;
|
||||
|
||||
if (size > 0x2000'0000 || rsx::constants::local_mem_base + 0x1000'0000 - size < addr)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
for (u32 i = addr; i >> 20 <= (addr + size - 1) >> 20; i += 0x100000)
|
||||
{
|
||||
const u32 temp = rsx::get_address(i, i < rsx::constants::local_mem_base ? CELL_GCM_LOCATION_MAIN : CELL_GCM_LOCATION_LOCAL, true);
|
||||
|
||||
if (!temp)
|
||||
{
|
||||
// Failure
|
||||
final_addr = 0;
|
||||
break;
|
||||
}
|
||||
else if (!final_addr)
|
||||
{
|
||||
// First time, save starting address for later checks
|
||||
final_addr = temp;
|
||||
}
|
||||
else if (final_addr != temp - (i - addr))
|
||||
{
|
||||
// TODO: Non-contiguous memory
|
||||
final_addr = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (vm::check_addr(final_addr, 0, size))
|
||||
{
|
||||
return vm::get_super_ptr(final_addr);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
void memory_viewer_panel::ShowMemory()
|
||||
{
|
||||
QString t_mem_addr_str;
|
||||
@ -436,9 +536,9 @@ void memory_viewer_panel::ShowMemory()
|
||||
|
||||
u32 addr = (m_addr + (row - spu_passed) * m_colcount * 4 + col * 4) & m_addr_mask;
|
||||
|
||||
if (m_spu_shm || vm::check_addr(addr, 0, 4))
|
||||
if (auto ptr = this->to_ptr(addr))
|
||||
{
|
||||
const be_t<u32> rmem = m_spu_shm ? *reinterpret_cast<be_t<u32>*>(m_spu_shm->map_self() + addr) : *vm::get_super_ptr<u32>(addr);
|
||||
const be_t<u32> rmem = *reinterpret_cast<be_t<u32>*>(ptr);
|
||||
t_mem_hex_str += qstr(fmt::format("%02x %02x %02x %02x",
|
||||
static_cast<u8>(rmem >> 24),
|
||||
static_cast<u8>(rmem >> 16),
|
||||
@ -484,26 +584,17 @@ void memory_viewer_panel::SetPC(const uint pc)
|
||||
|
||||
void memory_viewer_panel::ShowImage(QWidget* parent, u32 addr, color_format format, u32 width, u32 height, bool flipv)
|
||||
{
|
||||
const u64 memsize = 4ull * width * height;
|
||||
|
||||
if (!memsize || memsize > m_addr_mask)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// If exceeds 32-bits it is invalid as well, UINT32_MAX always fails checks
|
||||
const u32 memsize = static_cast<u32>(std::min<u64>(4ull * width * height, UINT32_MAX));
|
||||
|
||||
std::shared_lock rlock(vm::g_mutex);
|
||||
|
||||
if (!m_spu_shm && !vm::check_addr(addr, 0, static_cast<u32>(memsize)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
const auto originalBuffer = static_cast<u8*>(this->to_ptr(addr, memsize));
|
||||
const auto convertedBuffer = new (std::nothrow) u8[memsize];
|
||||
|
||||
const auto originalBuffer = m_spu_shm ? (m_spu_shm->map_self() + addr) : vm::get_super_ptr<const u8>(addr);
|
||||
const auto convertedBuffer = new (std::nothrow) u8[static_cast<u32>(memsize)];
|
||||
|
||||
if (!convertedBuffer)
|
||||
if (!originalBuffer || !convertedBuffer)
|
||||
{
|
||||
// OOM, give up
|
||||
// OOM or invalid memory address, give up
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -17,12 +17,17 @@ namespace utils
|
||||
class shm;
|
||||
}
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
class thread;
|
||||
}
|
||||
|
||||
class memory_viewer_panel : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
memory_viewer_panel(QWidget* parent, u32 addr = 0, const std::shared_ptr<cpu_thread>& cpu = nullptr);
|
||||
memory_viewer_panel(QWidget* parent, u32 addr = 0, std::function<cpu_thread*()> func = []() -> cpu_thread* { return {}; });
|
||||
~memory_viewer_panel();
|
||||
|
||||
enum class color_format : int
|
||||
@ -53,17 +58,21 @@ private:
|
||||
|
||||
enum class thread_type
|
||||
{
|
||||
none,
|
||||
ppu,
|
||||
spu,
|
||||
//rsx
|
||||
rsx,
|
||||
};
|
||||
|
||||
const std::function<cpu_thread*()> m_get_cpu;
|
||||
const thread_type m_type;
|
||||
const std::add_pointer_t<rsx::thread> m_rsx;
|
||||
const std::shared_ptr<utils::shm> m_spu_shm;
|
||||
const u32 m_addr_mask;
|
||||
|
||||
std::string getHeaderAtAddr(u32 addr);
|
||||
void scroll(s32 steps);
|
||||
void* to_ptr(u32 addr, u32 size = 1);
|
||||
void SetPC(const uint pc);
|
||||
|
||||
virtual void ShowMemory();
|
||||
@ -84,7 +93,7 @@ struct memory_viewer_handle
|
||||
{
|
||||
}
|
||||
|
||||
~memory_viewer_handle() { m_mvp->deleteLater(); }
|
||||
~memory_viewer_handle() { m_mvp->close(); m_mvp->deleteLater(); }
|
||||
|
||||
private:
|
||||
const std::add_pointer_t<memory_viewer_panel> m_mvp;
|
||||
|
@ -58,10 +58,10 @@ enum registers : int
|
||||
PC,
|
||||
};
|
||||
|
||||
register_editor_dialog::register_editor_dialog(QWidget *parent, const std::shared_ptr<cpu_thread>& _cpu, CPUDisAsm* _disasm)
|
||||
register_editor_dialog::register_editor_dialog(QWidget *parent, CPUDisAsm* _disasm, std::function<cpu_thread*()> func)
|
||||
: QDialog(parent)
|
||||
, m_disasm(_disasm)
|
||||
, m_cpu(_cpu)
|
||||
, m_get_cpu(std::move(func))
|
||||
{
|
||||
setWindowTitle(tr("Edit registers"));
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
@ -95,9 +95,9 @@ register_editor_dialog::register_editor_dialog(QWidget *parent, const std::share
|
||||
hbox_button_panel->addWidget(button_cancel);
|
||||
hbox_button_panel->setAlignment(Qt::AlignCenter);
|
||||
|
||||
if (1)
|
||||
if (const auto cpu = m_get_cpu())
|
||||
{
|
||||
if (m_cpu->id_type() == 1)
|
||||
if (cpu->id_type() == 1)
|
||||
{
|
||||
for (int i = ppu_r0; i <= ppu_r31; i++) m_register_combo->addItem(qstr(fmt::format("r%d", i % 32)), i);
|
||||
for (int i = ppu_f0; i <= ppu_f31; i++) m_register_combo->addItem(qstr(fmt::format("f%d", i % 32)), i);
|
||||
@ -113,7 +113,7 @@ register_editor_dialog::register_editor_dialog(QWidget *parent, const std::share
|
||||
m_register_combo->addItem("Priority", +PPU_PRIO);
|
||||
//m_register_combo->addItem("Priority 2", +PPU_PRIO2);
|
||||
}
|
||||
else if (m_cpu->id_type() == 2)
|
||||
else if (cpu->id_type() == 2)
|
||||
{
|
||||
for (int i = spu_r0; i <= spu_r127; i++) m_register_combo->addItem(qstr(fmt::format("r%d", i % 128)), i);
|
||||
m_register_combo->addItem("MFC Pending Events", +MFC_PEVENTS);
|
||||
@ -141,7 +141,6 @@ register_editor_dialog::register_editor_dialog(QWidget *parent, const std::share
|
||||
vbox_panel->addSpacing(10);
|
||||
vbox_panel->addLayout(hbox_button_panel);
|
||||
setLayout(vbox_panel);
|
||||
setModal(true);
|
||||
|
||||
// Events
|
||||
connect(button_ok, &QAbstractButton::clicked, this, [this](){ OnOkay(); accept(); });
|
||||
@ -161,12 +160,14 @@ void register_editor_dialog::updateRegister(int reg)
|
||||
{
|
||||
std::string str = sstr(tr("Error parsing register value!"));
|
||||
|
||||
if (!m_cpu)
|
||||
const auto cpu = m_get_cpu();
|
||||
|
||||
if (!cpu)
|
||||
{
|
||||
}
|
||||
else if (m_cpu->id_type() == 1)
|
||||
else if (cpu->id_type() == 1)
|
||||
{
|
||||
const auto& ppu = *static_cast<const ppu_thread*>(m_cpu.get());
|
||||
const auto& ppu = *static_cast<const ppu_thread*>(cpu);
|
||||
|
||||
if (reg >= ppu_r0 && reg <= ppu_v31)
|
||||
{
|
||||
@ -189,9 +190,9 @@ void register_editor_dialog::updateRegister(int reg)
|
||||
else if (reg == RESERVATION_LOST) str = sstr(ppu.raddr ? tr("Lose reservation on OK") : tr("Reservation is inactive"));
|
||||
else if (reg == PC) str = fmt::format("%08x", ppu.cia);
|
||||
}
|
||||
else if (m_cpu->id_type() == 2)
|
||||
else if (cpu->id_type() == 2)
|
||||
{
|
||||
const auto& spu = *static_cast<const spu_thread*>(m_cpu.get());
|
||||
const auto& spu = *static_cast<const spu_thread*>(cpu);
|
||||
|
||||
if (reg >= spu_r0 && reg <= spu_r127)
|
||||
{
|
||||
@ -244,12 +245,18 @@ void register_editor_dialog::OnOkay()
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_cpu || value.empty())
|
||||
const auto cpu = m_get_cpu();
|
||||
|
||||
if (!cpu || value.empty())
|
||||
{
|
||||
if (!cpu)
|
||||
{
|
||||
close();
|
||||
}
|
||||
}
|
||||
else if (m_cpu->id_type() == 1)
|
||||
else if (cpu->id_type() == 1)
|
||||
{
|
||||
auto& ppu = *static_cast<ppu_thread*>(m_cpu.get());
|
||||
auto& ppu = *static_cast<ppu_thread*>(cpu);
|
||||
|
||||
if (reg >= ppu_r0 && reg <= ppu_v31)
|
||||
{
|
||||
@ -334,9 +341,9 @@ void register_editor_dialog::OnOkay()
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (m_cpu->id_type() == 2)
|
||||
else if (cpu->id_type() == 2)
|
||||
{
|
||||
auto& spu = *static_cast<spu_thread*>(m_cpu.get());
|
||||
auto& spu = *static_cast<spu_thread*>(cpu);
|
||||
|
||||
if (reg >= spu_r0 && reg <= spu_r127)
|
||||
{
|
||||
|
@ -19,14 +19,14 @@ class register_editor_dialog : public QDialog
|
||||
QComboBox* m_register_combo;
|
||||
QLineEdit* m_value_line;
|
||||
|
||||
const std::function<cpu_thread*()> m_get_cpu;
|
||||
|
||||
public:
|
||||
register_editor_dialog(QWidget *parent, const std::shared_ptr<cpu_thread>& _cpu, CPUDisAsm* _disasm);
|
||||
register_editor_dialog(QWidget *parent, CPUDisAsm* _disasm, std::function<cpu_thread*()> func);
|
||||
|
||||
private:
|
||||
void OnOkay();
|
||||
|
||||
std::shared_ptr<cpu_thread> m_cpu;
|
||||
|
||||
private Q_SLOTS:
|
||||
void updateRegister(int reg);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user