#include "instruction_editor_dialog.h" #include "Emu/Cell/SPUThread.h" #include "Emu/CPU/CPUThread.h" #include "Emu/CPU/CPUDisAsm.h" #include "Emu/Cell/lv2/sys_spu.h" #include #include #include #include #include constexpr auto qstr = QString::fromStdString; extern bool ppu_patch(u32 addr, u32 value); instruction_editor_dialog::instruction_editor_dialog(QWidget *parent, u32 _pc, CPUDisAsm* _disasm, std::function func) : QDialog(parent) , m_pc(_pc) , m_disasm(_disasm->copy_type_erased()) , m_get_cpu(std::move(func)) { setWindowTitle(tr("Edit instruction")); setAttribute(Qt::WA_DeleteOnClose); setMinimumSize(300, sizeHint().height()); const auto cpu = m_get_cpu(); m_cpu_offset = cpu && cpu->id_type() == 2 ? static_cast(*cpu).ls : vm::g_sudo_addr; QVBoxLayout* vbox_panel(new QVBoxLayout()); QHBoxLayout* hbox_panel(new QHBoxLayout()); QVBoxLayout* vbox_left_panel(new QVBoxLayout()); QVBoxLayout* vbox_right_panel(new QVBoxLayout()); QHBoxLayout* hbox_b_panel(new QHBoxLayout()); QPushButton* button_ok(new QPushButton(tr("OK"))); QPushButton* button_cancel(new QPushButton(tr("Cancel"))); button_ok->setFixedWidth(80); button_cancel->setFixedWidth(80); m_instr = new QLineEdit(this); m_instr->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); m_instr->setMaxLength(8); m_instr->setMaximumWidth(65); m_disasm->change_mode(cpu_disasm_mode::normal); m_disasm->disasm(m_pc); m_preview = new QLabel(qstr(m_disasm->last_opcode), this); // Layouts vbox_left_panel->addWidget(new QLabel(tr("Address: "))); vbox_left_panel->addWidget(new QLabel(tr("Instruction: "))); vbox_left_panel->addWidget(new QLabel(tr("Preview: "))); vbox_right_panel->addWidget(new QLabel(qstr(fmt::format("%08x", m_pc)))); vbox_right_panel->addWidget(m_instr); vbox_right_panel->addWidget(m_preview); if (cpu && cpu->id_type() == 2) { const auto& spu = static_cast(*cpu); if (spu.group && spu.group->max_num > 1) { m_apply_for_spu_group = new QCheckBox(tr("For SPUs Group")); vbox_left_panel->addWidget(m_apply_for_spu_group); vbox_right_panel->addWidget(new QLabel("")); // For alignment } } vbox_right_panel->setAlignment(Qt::AlignLeft); hbox_b_panel->addWidget(button_ok); hbox_b_panel->addWidget(button_cancel); hbox_b_panel->setAlignment(Qt::AlignCenter); // Main Layout hbox_panel->addLayout(vbox_left_panel); hbox_panel->addSpacing(10); hbox_panel->addLayout(vbox_right_panel); vbox_panel->addLayout(hbox_panel); vbox_panel->addSpacing(10); vbox_panel->addLayout(hbox_b_panel); setLayout(vbox_panel); // Events connect(button_ok, &QAbstractButton::clicked, [this]() { const auto cpu = m_get_cpu(); if (!cpu) { close(); return; } bool ok; const ulong opcode = m_instr->text().toULong(&ok, 16); if (!ok || opcode > u32{umax}) { QMessageBox::critical(this, tr("Error"), tr("Failed to parse PPU instruction.")); return; } const be_t swapped{static_cast(opcode)}; if (cpu->id_type() == 1) { if (!ppu_patch(m_pc, static_cast(opcode))) { QMessageBox::critical(this, tr("Error"), tr("Failed to patch PPU instruction.")); return; } } else if (m_apply_for_spu_group && m_apply_for_spu_group->isChecked()) { for (auto& spu : static_cast(*cpu).group->threads) { if (spu) { std::memcpy(spu->ls + m_pc, &swapped, 4); } } } else { std::memcpy(m_cpu_offset + m_pc, &swapped, 4); } accept(); }); connect(button_cancel, &QAbstractButton::clicked, this, &instruction_editor_dialog::reject); connect(m_instr, &QLineEdit::textChanged, this, &instruction_editor_dialog::updatePreview); updatePreview(); } void instruction_editor_dialog::updatePreview() const { bool ok; const be_t opcode{static_cast(m_instr->text().toULong(&ok, 16))}; m_disasm->change_ptr(reinterpret_cast(&opcode) - std::intptr_t{m_pc}); if (ok && m_disasm->disasm(m_pc)) { m_preview->setText(qstr(m_disasm->last_opcode)); } else { m_preview->setText(tr("Could not parse instruction.")); } }