diff --git a/rpcs3/rpcs3qt/register_editor_dialog.cpp b/rpcs3/rpcs3qt/register_editor_dialog.cpp index 6069a1b864..f5fc3ee947 100644 --- a/rpcs3/rpcs3qt/register_editor_dialog.cpp +++ b/rpcs3/rpcs3qt/register_editor_dialog.cpp @@ -9,11 +9,45 @@ #include #include #include +#include constexpr auto qstr = QString::fromStdString; inline std::string sstr(const QString& _in) { return _in.toStdString(); } inline std::string sstr(const QVariant& _in) { return sstr(_in.toString()); } +enum registers : int +{ + ppu_r0, + ppu_r31 = ppu_r0 + 31, + ppu_f0, + ppu_f31 = ppu_f0 + 31, + ppu_ff0, + ppu_ff31 = ppu_ff0 + 31, + ppu_v0, + ppu_v31 = ppu_v0 + 31, + spu_r0 = ::align(ppu_v31 + 1u, 128), + spu_r127 = spu_r0 + 127, + PPU_CR, + PPU_LR, + PPU_CTR, + PPU_XER, + PPU_VSCR, + PPU_FPSCR, + PPU_VRSAVE, + MFC_PEVENTS, + MFC_EVENTS_MASK, + MFC_TAG_UPD, + MFC_TAG_MASK, + MFC_ATOMIC_STAT, + SPU_SRR0, + SPU_SNR1, + SPU_SNR2, + SPU_OUT_MBOX, + SPU_OUT_INTR_MBOX, + SPU_FPSCR, + PC, +}; + register_editor_dialog::register_editor_dialog(QWidget *parent, u32 _pc, const std::shared_ptr& _cpu, CPUDisAsm* _disasm) : QDialog(parent) , m_pc(_pc) @@ -56,19 +90,34 @@ register_editor_dialog::register_editor_dialog(QWidget *parent, u32 _pc, const s { if (_cpu->id_type() == 1) { - for (int i = 0; i < 32; i++) m_register_combo->addItem(qstr(fmt::format("r%d", i))); - for (int i = 0; i < 32; i++) m_register_combo->addItem(qstr(fmt::format("f%d", i))); - for (int i = 0; i < 32; i++) m_register_combo->addItem(qstr(fmt::format("v%d", i))); - m_register_combo->addItem("CR"); - m_register_combo->addItem("LR"); - m_register_combo->addItem("CTR"); - //m_register_combo->addItem("XER"); - //m_register_combo->addItem("FPSCR"); + 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); + for (int i = ppu_ff0; i <= ppu_ff31; i++) m_register_combo->addItem(qstr(fmt::format("ff%d", i % 32)), i); + for (int i = ppu_v0; i <= ppu_v31; i++) m_register_combo->addItem(qstr(fmt::format("v%d", i % 32)), i); + m_register_combo->addItem("CR", +PPU_CR); + m_register_combo->addItem("LR", +PPU_LR); + m_register_combo->addItem("CTR", PPU_CTR); + m_register_combo->addItem("VRSAVE", +PPU_VRSAVE); + //m_register_combo->addItem("XER", +PPU_XER); + //m_register_combo->addItem("FPSCR", +PPU_FPSCR); + //m_register_combo->addItem("VSCR", +PPU_VSCR); } else { - for (int i = 0; i < 128; i++) m_register_combo->addItem(qstr(fmt::format("r%d", i))); + 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); + m_register_combo->addItem("MFC Events Mask", +MFC_EVENTS_MASK); + m_register_combo->addItem("MFC Tag Mask", +MFC_TAG_MASK); + //m_register_combo->addItem("MFC Tag Update", +MFC_TAG_UPD); + //m_register_combo->addItem("MFC Atomic Status", +MFC_ATOMIC_STAT); + m_register_combo->addItem("SPU SNR1", +SPU_SNR1); + m_register_combo->addItem("SPU SNR2", +SPU_SNR2); + m_register_combo->addItem("SPU Out Mailbox", +SPU_OUT_MBOX); + m_register_combo->addItem("SPU Out-Intr Mailbox", +SPU_OUT_INTR_MBOX); + m_register_combo->addItem("SRR0", +SPU_SRR0); } + + m_register_combo->addItem("PC", +PC); } // Main Layout @@ -84,51 +133,62 @@ register_editor_dialog::register_editor_dialog(QWidget *parent, u32 _pc, const s // Events connect(button_ok, &QAbstractButton::clicked, this, [=, this](){OnOkay(_cpu); accept();}); connect(button_cancel, &QAbstractButton::clicked, this, ®ister_editor_dialog::reject); - connect(m_register_combo, &QComboBox::currentTextChanged, this, ®ister_editor_dialog::updateRegister); + connect(m_register_combo, &QComboBox::currentTextChanged, this, [this](const QString&) + { + if (auto qvar = m_register_combo->currentData(); qvar.canConvert(QMetaType::Int)) + { + updateRegister(qvar.toInt()); + } + }); - updateRegister(m_register_combo->currentText()); + updateRegister(m_register_combo->currentData().toInt()); } -void register_editor_dialog::updateRegister(const QString& text) +void register_editor_dialog::updateRegister(int reg) { - if (text.isEmpty()) - { - m_value_line->setText(""); - return; - } - const auto cpu = this->cpu.lock(); + std::string str = sstr(tr("Error parsing register value!")); - std::string reg = sstr(text); - std::string str; - - if (cpu->id_type() == 1) + if (!cpu) { - auto& ppu = *static_cast(cpu.get()); + } + else if (cpu->id_type() == 1) + { + const auto& ppu = *static_cast(cpu.get()); - std::size_t first_brk = reg.find('['); - if (first_brk != umax) + if (reg >= ppu_r0 && reg <= ppu_v31) { - long reg_index = std::atol(reg.substr(first_brk + 1, reg.length() - first_brk - 2).c_str()); - if (reg.starts_with("r")) str = fmt::format("%016llx", ppu.gpr[reg_index]); - else if (reg.starts_with("f")) str = fmt::format("%016llx", ppu.fpr[reg_index]); - else if (reg.starts_with("v")) str = fmt::format("%016llx%016llx", ppu.vr[reg_index]._u64[1], ppu.vr[reg_index]._u64[0]); + const u32 reg_index = reg % 32; + + if (reg >= ppu_r0 && reg <= ppu_r31) str = fmt::format("%016llx", ppu.gpr[reg_index]); + else if (reg >= ppu_ff0 && reg <= ppu_ff31) str = fmt::format("%g", ppu.fpr[reg_index]); + else if (reg >= ppu_ff0 && reg <= ppu_ff31) str = fmt::format("%016llx", std::bit_cast(ppu.fpr[reg_index])); + else if (reg >= ppu_v0 && reg <= ppu_v31) str = fmt::format("%016llx%016llx", ppu.vr[reg_index]._u64[1], ppu.vr[reg_index]._u64[0]); } - else if (reg == "CR") str = fmt::format("%08x", ppu.cr.pack()); - else if (reg == "LR") str = fmt::format("%016llx", ppu.lr); - else if (reg == "CTR") str = fmt::format("%016llx", ppu.ctr); + else if (reg == PPU_CR) str = fmt::format("%08x", ppu.cr.pack()); + else if (reg == PPU_LR) str = fmt::format("%016llx", ppu.lr); + else if (reg == PPU_CTR) str = fmt::format("%016llx", ppu.ctr); + else if (reg == PPU_VRSAVE) str = fmt::format("%08x", ppu.vrsave); + else if (reg == PC) str = fmt::format("%08x", ppu.cia); } else { - auto& spu = *static_cast(cpu.get()); + const auto& spu = *static_cast(cpu.get()); - std::string::size_type first_brk = reg.find('['); - if (first_brk != umax) + if (reg >= spu_r0 && reg <= spu_r127) { - long reg_index; - reg_index = atol(reg.substr(first_brk + 1, reg.length() - 2).c_str()); - if (reg.starts_with("r")) str = fmt::format("%016llx%016llx", spu.gpr[reg_index]._u64[1], spu.gpr[reg_index]._u64[0]); + const u32 reg_index = reg % 128; + str = fmt::format("%016llx%016llx", spu.gpr[reg_index]._u64[1], spu.gpr[reg_index]._u64[0]); } + else if (reg == MFC_PEVENTS) str = fmt::format("%08x", +spu.ch_event_stat); + else if (reg == MFC_EVENTS_MASK) str = fmt::format("%08x", +spu.ch_event_mask); + else if (reg == MFC_TAG_MASK) str = fmt::format("%08x", spu.ch_tag_mask); + else if (reg == SPU_SRR0) str = fmt::format("%08x", spu.srr0); + else if (reg == SPU_SNR1) str = fmt::format("%s", spu.ch_snr1); + else if (reg == SPU_SNR2) str = fmt::format("%s", spu.ch_snr2); + else if (reg == SPU_OUT_MBOX) str = fmt::format("%s", spu.ch_out_mbox); + else if (reg == SPU_OUT_INTR_MBOX) str = fmt::format("%s", spu.ch_out_intr_mbox); + else if (reg == PC) str = fmt::format("%08x", spu.pc); } m_value_line->setText(qstr(str)); @@ -138,48 +198,94 @@ void register_editor_dialog::OnOkay(const std::shared_ptr& _cpu) { const auto cpu = _cpu.get(); - std::string reg = sstr(m_register_combo->currentText()); + const int reg = m_register_combo->currentData().toInt(); std::string value = sstr(m_value_line->text()); - if (cpu->id_type() == 1) + auto check_res = [](std::from_chars_result res, const char* end) + { + return res.ec == std::errc() && res.ptr == end; + }; + + if (auto len = value.size(); len < 32 && !(reg >= ppu_ff0 && reg <= ppu_ff31)) + { + const bool is_int = !value.empty() && std::isxdigit(value[0]); + + if (value.starts_with("0x") || value.starts_with("0X")) + { + value = value.substr(2); + } + + if (is_int) + { + value.insert(0, 32 - len, '0'); + } + } + else if (value.size() > 32u && !(reg >= ppu_ff0 && reg <= ppu_ff31)) + { + // Invalid integer + value.clear(); + } + + if (!cpu) + { + } + else if (cpu->id_type() == 1) { auto& ppu = *static_cast(cpu); - if (auto len = value.length(); len < 32) value.insert(0, 32 - len, '0'); - const auto first_brk = reg.find('['); - // TODO: handle invalid conversions + if (reg >= ppu_r0 && reg <= ppu_v31) { - if (first_brk != umax) + const u32 reg_index = reg % 32; + + if ((reg >= ppu_r0 && reg <= ppu_r31) || (reg >= ppu_f0 && reg <= ppu_f31)) { - const long reg_index = std::atol(reg.substr(first_brk + 1, reg.length() - first_brk - 2).c_str()); - if (reg.starts_with("r") || reg.starts_with("f")) + if (u64 reg_value; check_res(std::from_chars(value.c_str() + 16, value.c_str() + 32, reg_value, 16), value.c_str() + 32)) { - const ullong reg_value = std::stoull(value.substr(16, 31), 0, 16); - if (reg.starts_with("r")) ppu.gpr[reg_index] = static_cast(reg_value); - else if (reg.starts_with("f")) ppu.fpr[reg_index] = std::bit_cast(reg_value); - return; - } - else if (reg.starts_with("v")) - { - const ullong reg_value0 = std::stoull(value.substr(16, 31), 0, 16); - const ullong reg_value1 = std::stoull(value.substr(0, 15), 0, 16); - ppu.vr[reg_index]._u64[0] = static_cast(reg_value0); - ppu.vr[reg_index]._u64[1] = static_cast(reg_value1); + if (reg >= ppu_r0 && reg <= ppu_r31) ppu.gpr[reg_index] = reg_value; + else if (reg >= ppu_f0 && reg <= ppu_f31) ppu.fpr[reg_index] = std::bit_cast(reg_value); return; } } - else if (reg == "LR" || reg == "CTR") + else if (reg >= ppu_ff0 && reg <= ppu_ff31) { - const ullong reg_value = std::stoull(value.substr(16, 31), 0, 16); - if (reg == "LR") ppu.lr = static_cast(reg_value); - else if (reg == "CTR") ppu.ctr = static_cast(reg_value); + char* end{}; + if (double reg_value = std::strtod(value.c_str(), &end); end != value.c_str()) + { + ppu.fpr[reg_index] = static_cast(reg_value); + return; + } + } + else if (reg >= ppu_v0 && reg <= ppu_v31) + { + u64 reg_value0, reg_value1; + + if (check_res(std::from_chars(value.c_str(), value.c_str() + 16, reg_value0, 16), value.c_str() + 16) && + check_res(std::from_chars(value.c_str() + 16, value.c_str() + 32, reg_value1, 16), value.c_str() + 32)) + { + ppu.vr[reg_index] = v128::from64(reg_value0, reg_value1); + return; + } + } + } + else if (reg == PPU_LR || reg == PPU_CTR) + { + if (u64 reg_value; check_res(std::from_chars(value.c_str() + 16, value.c_str() + 32, reg_value, 16), value.c_str() + 32)) + { + if (reg == PPU_LR) ppu.lr = reg_value; + else if (reg == PPU_CTR) ppu.ctr = reg_value; return; } - else if (reg == "CR") + } + else if (reg == PPU_CR || reg == PPU_VRSAVE || reg == PC) + { + if (u32 reg_value; check_res(std::from_chars(value.c_str() + 24, value.c_str() + 32, reg_value, 16), value.c_str() + 32)) { - const ullong reg_value = std::stoull(value.substr(24, 31), 0, 16); - ppu.cr.unpack(static_cast(reg_value)); - return; + bool ok = true; + if (reg == PPU_CR) ppu.cr.unpack(reg_value); + else if (reg == PPU_VRSAVE) ppu.vrsave = reg_value; + else if (reg == PC && reg_value % 4 == 0 && vm::check_addr(reg_value, 4, vm::page_executable)) ppu.cia = reg_value & -4; + else ok = false; + if (ok) return; } } } @@ -187,23 +293,47 @@ void register_editor_dialog::OnOkay(const std::shared_ptr& _cpu) { auto& spu = *static_cast(cpu); - if (auto len = value.length(); len < 32) value.insert(0, 32 - len, '0'); - const auto first_brk = reg.find('['); - // TODO: handle invalid conversions + if (reg >= spu_r0 && reg <= spu_r127) { - if (first_brk != umax) + const u32 reg_index = reg % 128; + u64 reg_value0, reg_value1; + + if (check_res(std::from_chars(value.c_str(), value.c_str() + 16, reg_value0, 16), value.c_str() + 16) && + check_res(std::from_chars(value.c_str() + 16, value.c_str() + 32, reg_value1, 16), value.c_str() + 32)) { - const long reg_index = std::atol(reg.substr(first_brk + 1, reg.length() - 2).c_str()); - if (reg.starts_with("r")) - { - const ullong reg_value0 = std::stoull(value.substr(16, 31), 0, 16); - const ullong reg_value1 = std::stoull(value.substr(0, 15), 0, 16); - spu.gpr[reg_index]._u64[0] = static_cast(reg_value0); - spu.gpr[reg_index]._u64[1] = static_cast(reg_value1); - return; - } + spu.gpr[reg_index] = v128::from64(reg_value0, reg_value1); + return; + } + } + else if (reg == MFC_PEVENTS || reg == MFC_EVENTS_MASK || reg == MFC_TAG_MASK || reg == SPU_SRR0 || reg == PC) + { + if (u32 reg_value; check_res(std::from_chars(value.c_str() + 24, value.c_str() + 32, reg_value, 16), value.c_str() + 32)) + { + bool ok = true; + if (reg == MFC_PEVENTS && !(reg_value & ~SPU_EVENT_IMPLEMENTED)) spu.ch_event_stat = reg_value; + else if (reg == MFC_EVENTS_MASK && !(reg_value & ~SPU_EVENT_IMPLEMENTED)) spu.ch_event_mask = reg_value; + else if (reg == MFC_TAG_MASK) spu.ch_tag_mask = reg_value; + else if (reg == SPU_SRR0) spu.srr0 = reg_value & 0x3fffc; + else if (reg == PC) spu.pc = reg_value & 0x3fffc; + else ok = false; + + if (ok) return; + } + } + else if (reg == SPU_SNR1 || reg == SPU_SNR2 || reg == SPU_OUT_MBOX || reg == SPU_OUT_INTR_MBOX) + { + const bool count = (value != "empty"); + if (u32 reg_value = 0; + !count || check_res(std::from_chars(value.c_str() + 24, value.c_str() + 32, reg_value, 16), value.c_str() + 32)) + { + if (reg == SPU_SNR1) spu.ch_snr1.set_value(reg_value, count); + else if (reg == SPU_SNR2) spu.ch_snr2.set_value(reg_value, count); + else if (reg == SPU_OUT_MBOX) spu.ch_out_mbox.set_value(reg_value, count); + else if (reg == SPU_OUT_INTR_MBOX) spu.ch_out_intr_mbox.set_value(reg_value, count); + return; } } } + QMessageBox::critical(this, tr("Error"), tr("This value could not be converted.\nNo changes were made.")); } diff --git a/rpcs3/rpcs3qt/register_editor_dialog.h b/rpcs3/rpcs3qt/register_editor_dialog.h index a79274d268..5e39f98f60 100644 --- a/rpcs3/rpcs3qt/register_editor_dialog.h +++ b/rpcs3/rpcs3qt/register_editor_dialog.h @@ -28,5 +28,5 @@ private: void OnOkay(const std::shared_ptr& _cpu); private Q_SLOTS: - void updateRegister(const QString& text); + void updateRegister(int reg); };