// license:BSD-3-Clause // copyright-holders:Andrew Gardner #include "emu.h" #include "dasmwindow.h" #include "debug/debugcon.h" #include "debug/debugcpu.h" #include "debug/dvdisasm.h" #include "debug/points.h" #include #include #include #include #include DasmWindow::DasmWindow(running_machine &machine, QWidget *parent) : WindowQt(machine, nullptr) { setWindowTitle("Debug: Disassembly View"); if (parent) { QPoint parentPos = parent->pos(); setGeometry(parentPos.x()+100, parentPos.y()+100, 800, 400); } // // The main frame and its input and log widgets // QFrame *mainWindowFrame = new QFrame(this); // The top frame & groupbox that contains the input widgets QFrame *topSubFrame = new QFrame(mainWindowFrame); // The input edit m_inputEdit = new QLineEdit(topSubFrame); connect(m_inputEdit, &QLineEdit::returnPressed, this, &DasmWindow::expressionSubmitted); // The cpu combo box m_cpuComboBox = new QComboBox(topSubFrame); m_cpuComboBox->setObjectName("cpu"); m_cpuComboBox->setMinimumWidth(300); connect(m_cpuComboBox, static_cast(&QComboBox::currentIndexChanged), this, &DasmWindow::cpuChanged); // The main disasm window m_dasmView = new DebuggerView(DVT_DISASSEMBLY, m_machine, this); connect(m_dasmView, &DebuggerView::updated, this, &DasmWindow::dasmViewUpdated); // Force a recompute of the disassembly region downcast(m_dasmView->view())->set_expression("curpc"); // Populate the combo box & set the proper CPU populateComboBox(); setToCurrentCpu(); // Layout QHBoxLayout *subLayout = new QHBoxLayout(topSubFrame); subLayout->addWidget(m_inputEdit); subLayout->addWidget(m_cpuComboBox); subLayout->setSpacing(3); subLayout->setContentsMargins(2,2,2,2); QVBoxLayout *vLayout = new QVBoxLayout(mainWindowFrame); vLayout->setSpacing(3); vLayout->setContentsMargins(2,2,2,2); vLayout->addWidget(topSubFrame); vLayout->addWidget(m_dasmView); setCentralWidget(mainWindowFrame); // // Menu bars // // Create three commands m_breakpointToggleAct = new QAction("Toggle Breakpoint at Cursor", this); m_breakpointEnableAct = new QAction("Disable Breakpoint at Cursor", this); m_runToCursorAct = new QAction("Run to Cursor", this); m_breakpointToggleAct->setShortcut(Qt::Key_F9); m_breakpointEnableAct->setShortcut(Qt::SHIFT + Qt::Key_F9); m_runToCursorAct->setShortcut(Qt::Key_F4); connect(m_breakpointToggleAct, &QAction::triggered, this, &DasmWindow::toggleBreakpointAtCursor); connect(m_breakpointEnableAct, &QAction::triggered, this, &DasmWindow::enableBreakpointAtCursor); connect(m_runToCursorAct, &QAction::triggered, this, &DasmWindow::runToCursor); // Right bar options QActionGroup *rightBarGroup = new QActionGroup(this); rightBarGroup->setObjectName("rightbargroup"); QAction *rightActRaw = new QAction("Raw Opcodes", this); QAction *rightActEncrypted = new QAction("Encrypted Opcodes", this); QAction *rightActComments = new QAction("Comments", this); rightActRaw->setCheckable(true); rightActEncrypted->setCheckable(true); rightActComments->setCheckable(true); rightActRaw->setActionGroup(rightBarGroup); rightActEncrypted->setActionGroup(rightBarGroup); rightActComments->setActionGroup(rightBarGroup); rightActRaw->setShortcut(QKeySequence("Ctrl+R")); rightActEncrypted->setShortcut(QKeySequence("Ctrl+E")); rightActComments->setShortcut(QKeySequence("Ctrl+N")); rightActRaw->setChecked(true); connect(rightBarGroup, &QActionGroup::triggered, this, &DasmWindow::rightBarChanged); // Assemble the options menu QMenu *optionsMenu = menuBar()->addMenu("&Options"); optionsMenu->addAction(m_breakpointToggleAct); optionsMenu->addAction(m_breakpointEnableAct); optionsMenu->addAction(m_runToCursorAct); optionsMenu->addSeparator(); optionsMenu->addActions(rightBarGroup->actions()); } DasmWindow::~DasmWindow() { } void DasmWindow::cpuChanged(int index) { m_dasmView->view()->set_source(*m_dasmView->view()->source(index)); m_dasmView->viewport()->update(); } void DasmWindow::expressionSubmitted() { const QString expression = m_inputEdit->text(); downcast(m_dasmView->view())->set_expression(expression.toLocal8Bit().data()); m_dasmView->viewport()->update(); } void DasmWindow::toggleBreakpointAtCursor(bool changedTo) { if (m_dasmView->view()->cursor_visible()) { offs_t const address = downcast(m_dasmView->view())->selected_address(); device_t *const device = m_dasmView->view()->source()->device(); device_debug *const cpuinfo = device->debug(); // Find an existing breakpoint at this address const debug_breakpoint *bp = cpuinfo->breakpoint_find(address); // If none exists, add a new one if (!bp) { int32_t bpindex = cpuinfo->breakpoint_set(address, nullptr, nullptr); m_machine.debugger().console().printf("Breakpoint %X set\n", bpindex); } else { int32_t bpindex = bp->index(); cpuinfo->breakpoint_clear(bpindex); m_machine.debugger().console().printf("Breakpoint %X cleared\n", bpindex); } m_machine.debug_view().update_all(); m_machine.debugger().refresh_display(); } refreshAll(); } void DasmWindow::enableBreakpointAtCursor(bool changedTo) { if (m_dasmView->view()->cursor_visible()) { offs_t const address = downcast(m_dasmView->view())->selected_address(); device_t *const device = m_dasmView->view()->source()->device(); device_debug *const cpuinfo = device->debug(); // Find an existing breakpoint at this address const debug_breakpoint *bp = cpuinfo->breakpoint_find(address); if (bp) { cpuinfo->breakpoint_enable(bp->index(), !bp->enabled()); m_machine.debugger().console().printf("Breakpoint %X %s\n", (uint32_t)bp->index(), bp->enabled() ? "enabled" : "disabled"); m_machine.debug_view().update_all(); m_machine.debugger().refresh_display(); } } refreshAll(); } void DasmWindow::runToCursor(bool changedTo) { if (m_dasmView->view()->cursor_visible()) { offs_t const address = downcast(m_dasmView->view())->selected_address(); m_dasmView->view()->source()->device()->debug()->go(address); } } void DasmWindow::rightBarChanged(QAction* changedTo) { debug_view_disasm* dasmView = downcast(m_dasmView->view()); if (changedTo->text() == "Raw Opcodes") { dasmView->set_right_column(DASM_RIGHTCOL_RAW); } else if (changedTo->text() == "Encrypted Opcodes") { dasmView->set_right_column(DASM_RIGHTCOL_ENCRYPTED); } else if (changedTo->text() == "Comments") { dasmView->set_right_column(DASM_RIGHTCOL_COMMENTS); } m_dasmView->viewport()->update(); } void DasmWindow::dasmViewUpdated() { bool const haveCursor = m_dasmView->view()->cursor_visible(); bool haveBreakpoint = false; bool breakpointEnabled = false; if (haveCursor) { offs_t const address = downcast(m_dasmView->view())->selected_address(); device_t *const device = m_dasmView->view()->source()->device(); device_debug *const cpuinfo = device->debug(); // Find an existing breakpoint at this address const debug_breakpoint *bp = cpuinfo->breakpoint_find(address); if (bp) { haveBreakpoint = true; breakpointEnabled = bp->enabled(); } } m_breakpointToggleAct->setText(haveBreakpoint ? "Clear Breakpoint at Cursor" : haveCursor ? "Set Breakpoint at Cursor" : "Toggle Breakpoint at Cursor"); m_breakpointEnableAct->setText((!haveBreakpoint || breakpointEnabled) ? "Disable Breakpoint at Cursor" : "Enable Breakpoint at Cursor"); m_breakpointToggleAct->setEnabled(haveCursor); m_breakpointEnableAct->setEnabled(haveBreakpoint); m_runToCursorAct->setEnabled(haveCursor); } void DasmWindow::populateComboBox() { if (!m_dasmView) return; m_cpuComboBox->clear(); for (auto &source : m_dasmView->view()->source_list()) { m_cpuComboBox->addItem(source->name()); } } void DasmWindow::setToCurrentCpu() { device_t *curCpu = m_machine.debugger().console().get_visible_cpu(); if (curCpu) { const debug_view_source *source = m_dasmView->view()->source_for_device(curCpu); if (source) { const int listIndex = m_dasmView->view()->source_index(*source); m_cpuComboBox->setCurrentIndex(listIndex); } } } //========================================================================= // DasmWindowQtConfig //========================================================================= void DasmWindowQtConfig::buildFromQWidget(QWidget *widget) { WindowQtConfig::buildFromQWidget(widget); DasmWindow *window = dynamic_cast(widget); QComboBox *cpu = window->findChild("cpu"); m_cpu = cpu->currentIndex(); QActionGroup *rightBarGroup = window->findChild("rightbargroup"); if (rightBarGroup->checkedAction()->text() == "Raw Opcodes") m_rightBar = 0; else if (rightBarGroup->checkedAction()->text() == "Encrypted Opcodes") m_rightBar = 1; else if (rightBarGroup->checkedAction()->text() == "Comments") m_rightBar = 2; } void DasmWindowQtConfig::applyToQWidget(QWidget *widget) { WindowQtConfig::applyToQWidget(widget); DasmWindow *window = dynamic_cast(widget); QComboBox *cpu = window->findChild("cpu"); cpu->setCurrentIndex(m_cpu); QActionGroup *rightBarGroup = window->findChild("rightbargroup"); rightBarGroup->actions()[m_rightBar]->trigger(); } void DasmWindowQtConfig::addToXmlDataNode(util::xml::data_node &node) const { WindowQtConfig::addToXmlDataNode(node); node.set_attribute_int("cpu", m_cpu); node.set_attribute_int("rightbar", m_rightBar); } void DasmWindowQtConfig::recoverFromXmlNode(util::xml::data_node const &node) { WindowQtConfig::recoverFromXmlNode(node); m_cpu = node.get_attribute_int("cpu", m_cpu); m_rightBar = node.get_attribute_int("rightbar", m_rightBar); }