forked from qt-creator/qt-creator
Debugger: Add peripheral registers description file support
This feature is useful for the bare-metal programming. It allows to view the peripheral registers of the debugged device using the GDB. An information about the peripheral registers for a concrete device contains in a special SVD file. A format of this file described e.g. here: * https://www.keil.com/pack/doc/CMSIS/SVD/html/svd_Format_pg.html This feature supported only for ARM devices, and an appropriate SVD files can be found in the Internet, also this files provides by KEIL or IAR EW IDE's. A use case in QtC is that the user should to choose desired SVD file and set its path to the bare-metal device configuration widget. After this, the user can enable the "Peripheral Registers" view, choose a desired register group and to see a peripheral register values. Currently the following basic features are implemented: * Choosing SVD file for a target bare-metal device. * Choosing any peripheral register group, which is available for this device. * Seeing the info about the each peripheral register and its fields. * Seeing the value for the each peripheral register and its fields. * Changing the value for the each peripheral register and its fields (if it is allowed by access for a concrete register or field). * Changing the format of the values (hexadecimal, decimal, octal, binary). Fixes: QTCREATORBUG-18729 Change-Id: I3c38ea50ccd2e128746458f9b918095b4c2d644a Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -30,6 +30,7 @@
|
||||
#include "gdbserverprovider.h"
|
||||
#include "gdbserverproviderchooser.h"
|
||||
|
||||
#include <utils/pathchooser.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QFormLayout>
|
||||
@@ -56,6 +57,19 @@ BareMetalDeviceConfigurationWidget::BareMetalDeviceConfigurationWidget(
|
||||
|
||||
connect(m_gdbServerProviderChooser, &GdbServerProviderChooser::providerChanged,
|
||||
this, &BareMetalDeviceConfigurationWidget::gdbServerProviderChanged);
|
||||
|
||||
m_peripheralDescriptionFileChooser = new Utils::PathChooser(this);
|
||||
m_peripheralDescriptionFileChooser->setExpectedKind(Utils::PathChooser::File);
|
||||
m_peripheralDescriptionFileChooser->setPromptDialogFilter(
|
||||
tr("Peripheral description files (*.svd)"));
|
||||
m_peripheralDescriptionFileChooser->setPromptDialogTitle(
|
||||
tr("Select Peripheral Description File"));
|
||||
m_peripheralDescriptionFileChooser->setPath(dev->peripheralDescriptionFilePath());
|
||||
formLayout->addRow(tr("Peripheral description file:"),
|
||||
m_peripheralDescriptionFileChooser);
|
||||
|
||||
connect(m_peripheralDescriptionFileChooser, &Utils::PathChooser::pathChanged,
|
||||
this, &BareMetalDeviceConfigurationWidget::peripheralDescriptionFileChanged);
|
||||
}
|
||||
|
||||
void BareMetalDeviceConfigurationWidget::gdbServerProviderChanged()
|
||||
@@ -65,6 +79,13 @@ void BareMetalDeviceConfigurationWidget::gdbServerProviderChanged()
|
||||
dev->setGdbServerProviderId(m_gdbServerProviderChooser->currentProviderId());
|
||||
}
|
||||
|
||||
void BareMetalDeviceConfigurationWidget::peripheralDescriptionFileChanged()
|
||||
{
|
||||
const auto dev = qSharedPointerCast<BareMetalDevice>(device());
|
||||
QTC_ASSERT(dev, return);
|
||||
dev->setPeripheralDescriptionFilePath(m_peripheralDescriptionFileChooser->path());
|
||||
}
|
||||
|
||||
void BareMetalDeviceConfigurationWidget::updateDeviceFromUi()
|
||||
{
|
||||
gdbServerProviderChanged();
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
|
||||
#include <projectexplorer/devicesupport/idevicewidget.h>
|
||||
|
||||
namespace Utils { class PathChooser; }
|
||||
|
||||
namespace BareMetal {
|
||||
namespace Internal {
|
||||
|
||||
@@ -46,9 +48,11 @@ public:
|
||||
|
||||
private:
|
||||
void gdbServerProviderChanged();
|
||||
void peripheralDescriptionFileChanged();
|
||||
void updateDeviceFromUi() final;
|
||||
|
||||
GdbServerProviderChooser *m_gdbServerProviderChooser = nullptr;
|
||||
Utils::PathChooser *m_peripheralDescriptionFileChooser = nullptr;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
@@ -17,29 +17,36 @@ HEADERS += \
|
||||
commonoptionspage.h \
|
||||
debugger_global.h \
|
||||
debuggeractions.h \
|
||||
debuggercore.h \
|
||||
debuggerconstants.h \
|
||||
debuggercore.h \
|
||||
debuggerdialogs.h \
|
||||
debuggerengine.h \
|
||||
debuggericons.h \
|
||||
debuggerinternalconstants.h \
|
||||
debuggeritem.h \
|
||||
debuggeritemmanager.h \
|
||||
debuggerdialogs.h \
|
||||
debuggerengine.h \
|
||||
debuggerkitinformation.h \
|
||||
debuggermainwindow.h \
|
||||
debuggerplugin.h \
|
||||
debuggerprotocol.h \
|
||||
debuggerrunconfigurationaspect.h \
|
||||
debuggerruncontrol.h \
|
||||
debuggerkitinformation.h \
|
||||
debuggersourcepathmappingwidget.h \
|
||||
debuggertooltipmanager.h \
|
||||
disassembleragent.h \
|
||||
disassemblerlines.h \
|
||||
enginemanager.h \
|
||||
imageviewer.h \
|
||||
loadcoredialog.h \
|
||||
localsandexpressionswindow.h \
|
||||
logwindow.h \
|
||||
memoryagent.h \
|
||||
moduleshandler.h \
|
||||
outputcollector.h \
|
||||
peripheralregisterhandler.h \
|
||||
procinterrupt.h \
|
||||
registerhandler.h \
|
||||
enginemanager.h \
|
||||
simplifytype.h \
|
||||
sourceagent.h \
|
||||
sourcefileshandler.h \
|
||||
sourceutils.h \
|
||||
@@ -47,19 +54,13 @@ HEADERS += \
|
||||
stackhandler.h \
|
||||
stackwindow.h \
|
||||
terminal.h \
|
||||
watchhandler.h \
|
||||
watchutils.h \
|
||||
watchwindow.h \
|
||||
threaddata.h \
|
||||
threadshandler.h \
|
||||
watchdelegatewidgets.h \
|
||||
debuggertooltipmanager.h \
|
||||
debuggersourcepathmappingwidget.h \
|
||||
localsandexpressionswindow.h \
|
||||
imageviewer.h \
|
||||
simplifytype.h \
|
||||
unstartedappwatcherdialog.h \
|
||||
debuggericons.h
|
||||
watchdelegatewidgets.h \
|
||||
watchhandler.h \
|
||||
watchutils.h \
|
||||
watchwindow.h
|
||||
|
||||
SOURCES += \
|
||||
breakhandler.cpp \
|
||||
@@ -68,44 +69,45 @@ SOURCES += \
|
||||
debuggeractions.cpp \
|
||||
debuggerdialogs.cpp \
|
||||
debuggerengine.cpp \
|
||||
debuggericons.cpp \
|
||||
debuggeritem.cpp \
|
||||
debuggeritemmanager.cpp \
|
||||
debuggerkitinformation.cpp \
|
||||
debuggermainwindow.cpp \
|
||||
debuggerplugin.cpp \
|
||||
debuggerprotocol.cpp \
|
||||
debuggerrunconfigurationaspect.cpp \
|
||||
debuggerruncontrol.cpp \
|
||||
debuggerkitinformation.cpp \
|
||||
debuggersourcepathmappingwidget.cpp \
|
||||
debuggertooltipmanager.cpp \
|
||||
disassembleragent.cpp \
|
||||
disassemblerlines.cpp \
|
||||
enginemanager.cpp \
|
||||
imageviewer.cpp \
|
||||
loadcoredialog.cpp \
|
||||
localsandexpressionswindow.cpp \
|
||||
logwindow.cpp \
|
||||
memoryagent.cpp \
|
||||
moduleshandler.cpp \
|
||||
outputcollector.cpp \
|
||||
peripheralregisterhandler.cpp \
|
||||
procinterrupt.cpp \
|
||||
registerhandler.cpp \
|
||||
enginemanager.cpp \
|
||||
simplifytype.cpp \
|
||||
sourceagent.cpp \
|
||||
sourcefileshandler.cpp \
|
||||
sourceutils.cpp \
|
||||
stackframe.cpp \
|
||||
stackhandler.cpp \
|
||||
stackwindow.cpp \
|
||||
threadshandler.cpp \
|
||||
terminal.cpp \
|
||||
threadshandler.cpp \
|
||||
unstartedappwatcherdialog.cpp \
|
||||
watchdata.cpp \
|
||||
watchdelegatewidgets.cpp \
|
||||
watchhandler.cpp \
|
||||
watchutils.cpp \
|
||||
watchwindow.cpp \
|
||||
stackframe.cpp \
|
||||
watchdelegatewidgets.cpp \
|
||||
debuggertooltipmanager.cpp \
|
||||
debuggersourcepathmappingwidget.cpp \
|
||||
localsandexpressionswindow.cpp \
|
||||
imageviewer.cpp \
|
||||
simplifytype.cpp \
|
||||
unstartedappwatcherdialog.cpp \
|
||||
debuggericons.cpp
|
||||
watchwindow.cpp
|
||||
|
||||
RESOURCES += debugger.qrc
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include "memoryagent.h"
|
||||
#include "moduleshandler.h"
|
||||
#include "registerhandler.h"
|
||||
#include "peripheralregisterhandler.h"
|
||||
#include "sourcefileshandler.h"
|
||||
#include "sourceutils.h"
|
||||
#include "stackhandler.h"
|
||||
@@ -274,6 +275,7 @@ public:
|
||||
m_breakHandler(engine),
|
||||
m_modulesHandler(engine),
|
||||
m_registerHandler(engine),
|
||||
m_peripheralRegisterHandler(engine),
|
||||
m_sourceFilesHandler(engine),
|
||||
m_stackHandler(engine),
|
||||
m_threadsHandler(engine),
|
||||
@@ -343,6 +345,7 @@ public:
|
||||
delete m_watchersWindow;
|
||||
delete m_inspectorWindow;
|
||||
delete m_registerWindow;
|
||||
delete m_peripheralRegisterWindow;
|
||||
delete m_modulesWindow;
|
||||
delete m_sourceFilesWindow;
|
||||
delete m_stackWindow;
|
||||
@@ -354,6 +357,7 @@ public:
|
||||
delete m_watchersView;
|
||||
delete m_inspectorView;
|
||||
delete m_registerView;
|
||||
delete m_peripheralRegisterView;
|
||||
delete m_modulesView;
|
||||
delete m_sourceFilesView;
|
||||
delete m_stackView;
|
||||
@@ -469,6 +473,7 @@ public:
|
||||
BreakHandler m_breakHandler;
|
||||
ModulesHandler m_modulesHandler;
|
||||
RegisterHandler m_registerHandler;
|
||||
PeripheralRegisterHandler m_peripheralRegisterHandler;
|
||||
SourceFilesHandler m_sourceFilesHandler;
|
||||
StackHandler m_stackHandler;
|
||||
ThreadsHandler m_threadsHandler;
|
||||
@@ -493,6 +498,7 @@ public:
|
||||
QPointer<BaseTreeView> m_watchersView;
|
||||
QPointer<WatchTreeView> m_inspectorView;
|
||||
QPointer<BaseTreeView> m_registerView;
|
||||
QPointer<BaseTreeView> m_peripheralRegisterView;
|
||||
QPointer<BaseTreeView> m_modulesView;
|
||||
QPointer<BaseTreeView> m_sourceFilesView;
|
||||
QPointer<BaseTreeView> m_stackView;
|
||||
@@ -503,6 +509,7 @@ public:
|
||||
QPointer<QWidget> m_watchersWindow;
|
||||
QPointer<QWidget> m_inspectorWindow;
|
||||
QPointer<QWidget> m_registerWindow;
|
||||
QPointer<QWidget> m_peripheralRegisterWindow;
|
||||
QPointer<QWidget> m_modulesWindow;
|
||||
QPointer<QWidget> m_sourceFilesWindow;
|
||||
QPointer<QWidget> m_stackWindow;
|
||||
@@ -643,6 +650,17 @@ void DebuggerEnginePrivate::setupViews()
|
||||
m_registerWindow->setObjectName("Debugger.Dock.Register." + engineId);
|
||||
m_registerWindow->setWindowTitle(tr("Reg&isters"));
|
||||
|
||||
m_peripheralRegisterView = new BaseTreeView;
|
||||
m_peripheralRegisterView->setModel(m_peripheralRegisterHandler.model());
|
||||
m_peripheralRegisterView->setRootIsDecorated(true);
|
||||
m_peripheralRegisterView->setSettings(settings, "Debugger.PeripheralRegisterView");
|
||||
connect(m_peripheralRegisterView, &BaseTreeView::aboutToShow,
|
||||
m_engine, &DebuggerEngine::reloadPeripheralRegisters,
|
||||
Qt::QueuedConnection);
|
||||
m_peripheralRegisterWindow = addSearch(m_peripheralRegisterView);
|
||||
m_peripheralRegisterWindow->setObjectName("Debugger.Dock.PeripheralRegister." + engineId);
|
||||
m_peripheralRegisterWindow->setWindowTitle(tr("Peripheral Reg&isters"));
|
||||
|
||||
m_stackView = new StackTreeView;
|
||||
m_stackView->setModel(m_stackHandler.model());
|
||||
m_stackView->setSettings(settings, "Debugger.StackView");
|
||||
@@ -816,6 +834,7 @@ void DebuggerEnginePrivate::setupViews()
|
||||
m_modulesWindow->setFont(font);
|
||||
//m_consoleWindow->setFont(font);
|
||||
m_registerWindow->setFont(font);
|
||||
m_peripheralRegisterWindow->setFont(font);
|
||||
m_returnWindow->setFont(font);
|
||||
m_sourceFilesWindow->setFont(font);
|
||||
m_stackWindow->setFont(font);
|
||||
@@ -832,6 +851,7 @@ void DebuggerEnginePrivate::setupViews()
|
||||
m_perspective->addWindow(m_localsAndInspectorWindow, Perspective::AddToTab, nullptr, true, Qt::RightDockWidgetArea);
|
||||
m_perspective->addWindow(m_watchersWindow, Perspective::SplitVertical, m_localsAndInspectorWindow, true, Qt::RightDockWidgetArea);
|
||||
m_perspective->addWindow(m_registerWindow, Perspective::AddToTab, m_localsAndInspectorWindow, false, Qt::RightDockWidgetArea);
|
||||
m_perspective->addWindow(m_peripheralRegisterWindow, Perspective::AddToTab, m_localsAndInspectorWindow, false, Qt::RightDockWidgetArea);
|
||||
m_perspective->addWindow(m_logWindow, Perspective::AddToTab, nullptr, false, Qt::TopDockWidgetArea);
|
||||
|
||||
m_perspective->select();
|
||||
@@ -909,6 +929,11 @@ bool DebuggerEngine::isRegistersWindowVisible() const
|
||||
return d->m_registerWindow->isVisible();
|
||||
}
|
||||
|
||||
bool DebuggerEngine::isPeripheralRegistersWindowVisible() const
|
||||
{
|
||||
return d->m_peripheralRegisterWindow->isVisible();
|
||||
}
|
||||
|
||||
bool DebuggerEngine::isModulesWindowVisible() const
|
||||
{
|
||||
return d->m_modulesWindow->isVisible();
|
||||
@@ -940,6 +965,11 @@ RegisterHandler *DebuggerEngine::registerHandler() const
|
||||
return &d->m_registerHandler;
|
||||
}
|
||||
|
||||
PeripheralRegisterHandler *DebuggerEngine::peripheralRegisterHandler() const
|
||||
{
|
||||
return &d->m_peripheralRegisterHandler;
|
||||
}
|
||||
|
||||
StackHandler *DebuggerEngine::stackHandler() const
|
||||
{
|
||||
return &d->m_stackHandler;
|
||||
@@ -993,6 +1023,12 @@ void DebuggerEngine::setRegisterValue(const QString &name, const QString &value)
|
||||
Q_UNUSED(value)
|
||||
}
|
||||
|
||||
void DebuggerEngine::setPeripheralRegisterValue(quint64 address, quint64 value)
|
||||
{
|
||||
Q_UNUSED(address)
|
||||
Q_UNUSED(value)
|
||||
}
|
||||
|
||||
void DebuggerEngine::setRunParameters(const DebuggerRunParameters &runParameters)
|
||||
{
|
||||
d->m_runParameters = runParameters;
|
||||
@@ -1593,6 +1629,7 @@ void DebuggerEnginePrivate::setBusyCursor(bool busy)
|
||||
m_modulesWindow->setCursor(cursor);
|
||||
m_logWindow->setCursor(cursor);
|
||||
m_registerWindow->setCursor(cursor);
|
||||
m_peripheralRegisterWindow->setCursor(cursor);
|
||||
m_returnWindow->setCursor(cursor);
|
||||
m_sourceFilesWindow->setCursor(cursor);
|
||||
m_stackWindow->setCursor(cursor);
|
||||
@@ -2075,6 +2112,10 @@ void DebuggerEngine::reloadRegisters()
|
||||
{
|
||||
}
|
||||
|
||||
void DebuggerEngine::reloadPeripheralRegisters()
|
||||
{
|
||||
}
|
||||
|
||||
void DebuggerEngine::reloadSourceFiles()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -101,6 +101,7 @@ class LocationMark;
|
||||
class LogWindow;
|
||||
class ModulesHandler;
|
||||
class RegisterHandler;
|
||||
class PeripheralRegisterHandler;
|
||||
class StackHandler;
|
||||
class StackFrame;
|
||||
class SourceFilesHandler;
|
||||
@@ -316,12 +317,14 @@ public:
|
||||
virtual void requestModuleSections(const QString &moduleName);
|
||||
|
||||
virtual void reloadRegisters();
|
||||
virtual void reloadPeripheralRegisters();
|
||||
virtual void reloadSourceFiles();
|
||||
virtual void reloadFullStack();
|
||||
virtual void loadAdditionalQmlStack();
|
||||
virtual void reloadDebuggingHelpers();
|
||||
|
||||
virtual void setRegisterValue(const QString &name, const QString &value);
|
||||
virtual void setPeripheralRegisterValue(quint64 address, quint64 value);
|
||||
virtual void addOptionPages(QList<Core::IOptionsPage*> *) const;
|
||||
virtual bool hasCapability(unsigned cap) const = 0;
|
||||
virtual void debugLastCommand() {}
|
||||
@@ -356,6 +359,7 @@ public:
|
||||
|
||||
ModulesHandler *modulesHandler() const;
|
||||
RegisterHandler *registerHandler() const;
|
||||
PeripheralRegisterHandler *peripheralRegisterHandler() const;
|
||||
StackHandler *stackHandler() const;
|
||||
ThreadsHandler *threadsHandler() const;
|
||||
WatchHandler *watchHandler() const;
|
||||
@@ -453,6 +457,7 @@ public:
|
||||
QString debuggerName() const;
|
||||
|
||||
bool isRegistersWindowVisible() const;
|
||||
bool isPeripheralRegistersWindowVisible() const;
|
||||
bool isModulesWindowVisible() const;
|
||||
|
||||
void openMemoryEditor();
|
||||
@@ -551,6 +556,7 @@ private:
|
||||
friend class DebuggerPluginPrivate;
|
||||
friend class DebuggerEnginePrivate;
|
||||
friend class LocationMark;
|
||||
friend class PeripheralRegisterHandler;
|
||||
DebuggerEnginePrivate *d;
|
||||
};
|
||||
|
||||
|
||||
@@ -1030,6 +1030,7 @@ void GdbEngine::updateAll()
|
||||
stackHandler()->setCurrentIndex(0);
|
||||
runCommand({"-thread-info", CB(handleThreadInfo)});
|
||||
reloadRegisters();
|
||||
reloadPeripheralRegisters();
|
||||
updateLocals();
|
||||
}
|
||||
|
||||
@@ -2903,6 +2904,7 @@ void GdbEngine::handleStackListFrames(const DebuggerResponse &response, bool isF
|
||||
// logStreamOutput: "Previous frame identical to this frame (corrupt stack?)\n"
|
||||
//qDebug() << "LISTING STACK FAILED: " << response.toString();
|
||||
reloadRegisters();
|
||||
reloadPeripheralRegisters();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2943,6 +2945,7 @@ void GdbEngine::activateFrame(int frameIndex)
|
||||
|
||||
updateLocals();
|
||||
reloadRegisters();
|
||||
reloadPeripheralRegisters();
|
||||
}
|
||||
|
||||
void GdbEngine::handleThreadInfo(const DebuggerResponse &response)
|
||||
@@ -3062,6 +3065,22 @@ void GdbEngine::reloadRegisters()
|
||||
}
|
||||
}
|
||||
|
||||
void GdbEngine::reloadPeripheralRegisters()
|
||||
{
|
||||
if (!isPeripheralRegistersWindowVisible())
|
||||
return;
|
||||
|
||||
const QList<quint64> addresses = peripheralRegisterHandler()->activeRegisters();
|
||||
if (addresses.isEmpty())
|
||||
return; // Nothing to update.
|
||||
|
||||
for (const quint64 address : addresses) {
|
||||
const QString fun = QStringLiteral("x/1u 0x%1")
|
||||
.arg(QString::number(address, 16));
|
||||
runCommand({fun, CB(handlePeripheralRegisterListValues)});
|
||||
}
|
||||
}
|
||||
|
||||
static QString readWord(const QString &ba, int *pos)
|
||||
{
|
||||
const int n = ba.size();
|
||||
@@ -3127,6 +3146,15 @@ void GdbEngine::setRegisterValue(const QString &name, const QString &value)
|
||||
reloadRegisters();
|
||||
}
|
||||
|
||||
void GdbEngine::setPeripheralRegisterValue(quint64 address, quint64 value)
|
||||
{
|
||||
const QString fun = QStringLiteral("set {int}0x%1=%2")
|
||||
.arg(QString::number(address, 16))
|
||||
.arg(value);
|
||||
runCommand({fun});
|
||||
reloadPeripheralRegisters();
|
||||
}
|
||||
|
||||
void GdbEngine::handleRegisterListNames(const DebuggerResponse &response)
|
||||
{
|
||||
if (response.resultClass != ResultDone) {
|
||||
@@ -3227,6 +3255,28 @@ void GdbEngine::handleRegisterListValues(const DebuggerResponse &response)
|
||||
handler->commitUpdates();
|
||||
}
|
||||
|
||||
void GdbEngine::handlePeripheralRegisterListValues(
|
||||
const DebuggerResponse &response)
|
||||
{
|
||||
if (response.resultClass != ResultDone)
|
||||
return;
|
||||
|
||||
const QString output = response.consoleStreamOutput;
|
||||
// Regexp to match for '0x50060800:\t0\n'.
|
||||
const QRegularExpression re("^(0x[0-9A-F]+):\\t(\\d+)\\n$");
|
||||
const QRegularExpressionMatch m = re.match(output);
|
||||
if (!m.hasMatch())
|
||||
return;
|
||||
enum { AddressMatch = 1, ValueMatch = 2 };
|
||||
bool aok = false;
|
||||
bool vok = false;
|
||||
const quint64 address = m.captured(AddressMatch).toULongLong(&aok, 16);
|
||||
const quint64 value = m.captured(ValueMatch).toULongLong(&vok, 10);
|
||||
if (!aok || !vok)
|
||||
return;
|
||||
|
||||
peripheralRegisterHandler()->updateRegister(address, value);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
@@ -3703,6 +3753,9 @@ void GdbEngine::setupEngine()
|
||||
runCommand({commands});
|
||||
|
||||
runCommand({"loadDumpers", CB(handlePythonSetup)});
|
||||
|
||||
// Reload peripheral register description.
|
||||
peripheralRegisterHandler()->updateRegisterGroups();
|
||||
}
|
||||
|
||||
void GdbEngine::handleGdbStartFailed()
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include <debugger/breakhandler.h>
|
||||
#include <debugger/registerhandler.h>
|
||||
#include <debugger/peripheralregisterhandler.h>
|
||||
#include <debugger/watchhandler.h>
|
||||
#include <debugger/watchutils.h>
|
||||
#include <debugger/debuggeritem.h>
|
||||
@@ -266,10 +267,13 @@ private: ////////// General Interface //////////
|
||||
// Register specific stuff
|
||||
//
|
||||
void reloadRegisters() final;
|
||||
void reloadPeripheralRegisters() final;
|
||||
void setRegisterValue(const QString &name, const QString &value) final;
|
||||
void setPeripheralRegisterValue(quint64 address, quint64 value) final;
|
||||
void handleRegisterListNames(const DebuggerResponse &response);
|
||||
void handleRegisterListing(const DebuggerResponse &response);
|
||||
void handleRegisterListValues(const DebuggerResponse &response);
|
||||
void handlePeripheralRegisterListValues(const DebuggerResponse &response);
|
||||
void handleMaintPrintRegisters(const DebuggerResponse &response);
|
||||
QHash<int, Register> m_registers; // Map GDB register numbers to indices
|
||||
|
||||
|
||||
956
src/plugins/debugger/peripheralregisterhandler.cpp
Normal file
956
src/plugins/debugger/peripheralregisterhandler.cpp
Normal file
@@ -0,0 +1,956 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "peripheralregisterhandler.h"
|
||||
|
||||
#include "debuggeractions.h"
|
||||
#include "debuggercore.h"
|
||||
#include "debuggerdialogs.h"
|
||||
|
||||
#include <utils/basetreeview.h>
|
||||
#include <utils/savedaction.h>
|
||||
|
||||
#include <QItemDelegate>
|
||||
#include <QLineEdit>
|
||||
#include <QMenu>
|
||||
#include <QPainter>
|
||||
|
||||
using namespace Utils;
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
namespace {
|
||||
// Keys of a properties in SVD file.
|
||||
constexpr char kAccess[] = "access";
|
||||
constexpr char kAddressOffset[] = "addressOffset";
|
||||
constexpr char kBaseAddress[] = "baseAddress";
|
||||
constexpr char kBitOffset[] = "bitOffset";
|
||||
constexpr char kBitRange[] = "bitRange";
|
||||
constexpr char kBitWidth[] = "bitWidth";
|
||||
constexpr char kDerivedFrom[] = "derivedFrom";
|
||||
constexpr char kDescription[] = "description";
|
||||
constexpr char kField[] = "field";
|
||||
constexpr char kFields[] = "fields";
|
||||
constexpr char kGroupName[] = "groupName";
|
||||
constexpr char kName[] = "name";
|
||||
constexpr char kPeripheral[] = "peripheral";
|
||||
constexpr char kPeripherals[] = "peripherals";
|
||||
constexpr char kReadOnly[] = "read-only";
|
||||
constexpr char kReadWrite[] = "read-write";
|
||||
constexpr char kRegister[] = "register";
|
||||
constexpr char kRegisters[] = "registers";
|
||||
constexpr char kResetvalue[] = "resetValue";
|
||||
constexpr char kSize[] = "size";
|
||||
constexpr char kWritOnlye[] = "write-only";
|
||||
} // namespace
|
||||
|
||||
enum PeripheralRegisterColumns
|
||||
{
|
||||
PeripheralRegisterNameColumn,
|
||||
PeripheralRegisterValueColumn,
|
||||
PeripheralRegisterAccessColumn,
|
||||
PeripheralRegisterColumnCount
|
||||
};
|
||||
|
||||
enum PeripheralRegisterDataRole
|
||||
{
|
||||
PeripheralRegisterChangedRole = Qt::UserRole
|
||||
};
|
||||
|
||||
static QString accessName(PeripheralRegisterAccess access)
|
||||
{
|
||||
switch (access) {
|
||||
case PeripheralRegisterAccess::ReadOnly:
|
||||
return PeripheralRegisterHandler::tr("RO");
|
||||
case PeripheralRegisterAccess::WriteOnly:
|
||||
return PeripheralRegisterHandler::tr("WO");
|
||||
case PeripheralRegisterAccess::ReadWrite:
|
||||
return PeripheralRegisterHandler::tr("RW");
|
||||
default:
|
||||
return PeripheralRegisterHandler::tr("N/A");
|
||||
}
|
||||
}
|
||||
|
||||
static PeripheralRegisterAccess decodeAccess(const QString &accessText)
|
||||
{
|
||||
if (accessText == QLatin1String(kReadWrite))
|
||||
return PeripheralRegisterAccess::ReadWrite;
|
||||
if (accessText == QLatin1String(kReadOnly))
|
||||
return PeripheralRegisterAccess::ReadOnly;
|
||||
if (accessText == QLatin1String(kWritOnlye))
|
||||
return PeripheralRegisterAccess::WriteOnly;
|
||||
return PeripheralRegisterAccess::Unknown;
|
||||
}
|
||||
|
||||
static quint64 decodeNumeric(const QString &text)
|
||||
{
|
||||
bool ok = false;
|
||||
const quint64 result = text.toULongLong(&ok, 10);
|
||||
if (ok)
|
||||
return result;
|
||||
return text.toUInt(&ok, 16);
|
||||
}
|
||||
|
||||
static QString valueToString(quint64 value, int size, PeripheralRegisterFormat fmt)
|
||||
{
|
||||
QString result;
|
||||
if (fmt == PeripheralRegisterFormat::Hexadecimal) {
|
||||
result = QString::number(value, 16);
|
||||
result.prepend("0x" + QString(size / 4 - result.size(), '0'));
|
||||
} else if (fmt == PeripheralRegisterFormat::Decimal) {
|
||||
result = QString::number(value, 10);
|
||||
} else if (fmt == PeripheralRegisterFormat::Octal) {
|
||||
result = QString::number(value, 8);
|
||||
result.prepend('0' + QString(size / 2 - result.size(), '0'));
|
||||
} else if (fmt == PeripheralRegisterFormat::Binary) {
|
||||
result = QString::number(value, 2);
|
||||
result.prepend("0b" + QString(size - result.size(), '0'));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static quint64 valueFromString(const QString &string, PeripheralRegisterFormat fmt,
|
||||
bool *ok)
|
||||
{
|
||||
if (fmt == PeripheralRegisterFormat::Hexadecimal) {
|
||||
const QRegularExpression re("^(0x)?([0-9A-F]+)$");
|
||||
const QRegularExpressionMatch m = re.match(string);
|
||||
if (m.hasMatch())
|
||||
return m.captured(2).toULongLong(ok, 16);
|
||||
} else if (fmt == PeripheralRegisterFormat::Decimal) {
|
||||
const QRegularExpression re("^([0-9]+)$");
|
||||
const QRegularExpressionMatch m = re.match(string);
|
||||
if (m.hasMatch())
|
||||
return m.captured(1).toULongLong(ok, 10);
|
||||
} else if (fmt == PeripheralRegisterFormat::Octal) {
|
||||
const QRegularExpression re("^(0)?([0-7]+)$");
|
||||
const QRegularExpressionMatch m = re.match(string);
|
||||
if (m.hasMatch())
|
||||
return m.captured(2).toULongLong(ok, 8);
|
||||
} else if (fmt == PeripheralRegisterFormat::Binary) {
|
||||
const QRegularExpression re("^(0b)?([0-1]+)$");
|
||||
const QRegularExpressionMatch m = re.match(string);
|
||||
if (m.hasMatch())
|
||||
return m.captured(2).toULongLong(ok, 2);
|
||||
}
|
||||
|
||||
*ok = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// PeripheralRegisterField
|
||||
|
||||
QString PeripheralRegisterField::bitRangeString() const
|
||||
{
|
||||
const int from = bitOffset;
|
||||
const int to = bitOffset + bitWidth - 1;
|
||||
return PeripheralRegisterHandler::tr("[%1..%2]").arg(from).arg(to);
|
||||
}
|
||||
|
||||
QString PeripheralRegisterField::bitValueString(quint64 regValue) const
|
||||
{
|
||||
const quint64 value = bitValue(regValue);
|
||||
return valueToString(value, bitWidth, format);
|
||||
}
|
||||
|
||||
quint64 PeripheralRegisterField::bitValue(quint64 regValue) const
|
||||
{
|
||||
const quint64 mask = bitMask();
|
||||
regValue &= mask;
|
||||
regValue >>= bitOffset;
|
||||
return regValue;
|
||||
}
|
||||
|
||||
quint64 PeripheralRegisterField::bitMask() const
|
||||
{
|
||||
quint64 mask = 0;
|
||||
for (auto pos = bitOffset; pos < bitOffset + bitWidth; ++pos)
|
||||
mask |= quint64(quint64(1) << pos);
|
||||
return mask;
|
||||
}
|
||||
|
||||
// PeripheralRegisterValue
|
||||
|
||||
bool PeripheralRegisterValue::fromString(const QString &string,
|
||||
PeripheralRegisterFormat fmt)
|
||||
{
|
||||
bool ok = false;
|
||||
const quint64 newVal = valueFromString(string, fmt, &ok);
|
||||
if (!ok)
|
||||
return false;
|
||||
v = newVal;
|
||||
return true;
|
||||
}
|
||||
|
||||
QString PeripheralRegisterValue::toString(
|
||||
int size, PeripheralRegisterFormat fmt) const
|
||||
{
|
||||
return valueToString(v, size, fmt);
|
||||
}
|
||||
|
||||
// PeripheralRegister
|
||||
|
||||
QString PeripheralRegister::currentValueString() const
|
||||
{
|
||||
return currentValue.toString(size, format);
|
||||
}
|
||||
|
||||
QString PeripheralRegister::previousValueString() const
|
||||
{
|
||||
return previousValue.toString(size, format);
|
||||
}
|
||||
|
||||
QString PeripheralRegister::resetValueString() const
|
||||
{
|
||||
return resetValue.toString(size, format);
|
||||
}
|
||||
|
||||
QString PeripheralRegister::addressString(quint64 baseAddress) const
|
||||
{
|
||||
return "0x" + QString::number(address(baseAddress), 16);
|
||||
}
|
||||
|
||||
quint64 PeripheralRegister::address(quint64 baseAddress) const
|
||||
{
|
||||
return baseAddress + addressOffset;
|
||||
}
|
||||
|
||||
// PeripheralRegisterFieldItem
|
||||
|
||||
class PeripheralRegisterFieldItem final
|
||||
: public TypedTreeItem<PeripheralRegisterFieldItem>
|
||||
{
|
||||
public:
|
||||
explicit PeripheralRegisterFieldItem(
|
||||
DebuggerEngine *engine, const PeripheralRegisterGroup &group,
|
||||
PeripheralRegister ®, PeripheralRegisterField &fld);
|
||||
|
||||
QVariant data(int column, int role) const final;
|
||||
bool setData(int column, const QVariant &value, int role) final;
|
||||
Qt::ItemFlags flags(int column) const final;
|
||||
|
||||
void triggerChange();
|
||||
|
||||
DebuggerEngine *m_engine = nullptr;
|
||||
const PeripheralRegisterGroup &m_group;
|
||||
PeripheralRegister &m_reg;
|
||||
PeripheralRegisterField &m_fld;
|
||||
};
|
||||
|
||||
PeripheralRegisterFieldItem::PeripheralRegisterFieldItem(
|
||||
DebuggerEngine *engine, const PeripheralRegisterGroup &group,
|
||||
PeripheralRegister ®, PeripheralRegisterField &fld)
|
||||
: m_engine(engine), m_group(group), m_reg(reg), m_fld(fld)
|
||||
{
|
||||
}
|
||||
|
||||
QVariant PeripheralRegisterFieldItem::data(int column, int role) const
|
||||
{
|
||||
switch (role) {
|
||||
case PeripheralRegisterChangedRole:
|
||||
return m_fld.bitValue(m_reg.currentValue.v)
|
||||
!= m_fld.bitValue(m_reg.previousValue.v);
|
||||
|
||||
case Qt::DisplayRole:
|
||||
switch (column) {
|
||||
case PeripheralRegisterNameColumn:
|
||||
return m_fld.name;
|
||||
case PeripheralRegisterValueColumn:
|
||||
return m_fld.bitValueString(m_reg.currentValue.v);
|
||||
case PeripheralRegisterAccessColumn:
|
||||
return accessName(m_fld.access);
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::ToolTipRole:
|
||||
switch (column) {
|
||||
case PeripheralRegisterNameColumn:
|
||||
return QString("%1.%2\n%3\nBits: %4, %5")
|
||||
.arg(m_reg.name)
|
||||
.arg(m_fld.name)
|
||||
.arg(m_fld.description)
|
||||
.arg(m_fld.bitRangeString())
|
||||
.arg(m_fld.bitWidth);
|
||||
case PeripheralRegisterValueColumn:
|
||||
return QString("Value: %1").arg(
|
||||
m_fld.bitValueString(m_reg.currentValue.v));
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::EditRole:
|
||||
return m_fld.bitValueString(m_reg.currentValue.v);
|
||||
|
||||
case Qt::TextAlignmentRole: {
|
||||
if (column == PeripheralRegisterValueColumn)
|
||||
return Qt::AlignRight;
|
||||
return {};
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool PeripheralRegisterFieldItem::setData(
|
||||
int column, const QVariant &value, int role)
|
||||
{
|
||||
if (column == PeripheralRegisterValueColumn && role == Qt::EditRole) {
|
||||
bool ok = false;
|
||||
quint64 bitValue = valueFromString(value.toString(), m_fld.format, &ok);
|
||||
if (!ok)
|
||||
return false;
|
||||
bitValue <<= m_fld.bitOffset;
|
||||
const quint64 mask = m_fld.bitMask();
|
||||
m_reg.currentValue.v &= ~mask;
|
||||
m_reg.currentValue.v |= bitValue;
|
||||
triggerChange();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Qt::ItemFlags PeripheralRegisterFieldItem::flags(int column) const
|
||||
{
|
||||
const Qt::ItemFlags notEditable = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
|
||||
if (column != PeripheralRegisterValueColumn)
|
||||
return notEditable;
|
||||
if (m_fld.access == PeripheralRegisterAccess::ReadWrite
|
||||
|| m_fld.access == PeripheralRegisterAccess::WriteOnly) {
|
||||
return notEditable | Qt::ItemIsEditable;
|
||||
}
|
||||
return notEditable;
|
||||
}
|
||||
|
||||
void PeripheralRegisterFieldItem::triggerChange()
|
||||
{
|
||||
m_engine->setPeripheralRegisterValue(m_reg.address(m_group.baseAddress),
|
||||
m_reg.currentValue.v);
|
||||
}
|
||||
|
||||
// PeripheralRegisterItem
|
||||
|
||||
class PeripheralRegisterItem final
|
||||
: public TypedTreeItem<PeripheralRegisterItem>
|
||||
{
|
||||
public:
|
||||
explicit PeripheralRegisterItem(
|
||||
DebuggerEngine *engine,
|
||||
const PeripheralRegisterGroup &group,
|
||||
PeripheralRegister ®);
|
||||
|
||||
QVariant data(int column, int role) const final;
|
||||
bool setData(int column, const QVariant &value, int role) final;
|
||||
Qt::ItemFlags flags(int column) const final;
|
||||
|
||||
void triggerChange();
|
||||
|
||||
DebuggerEngine *m_engine = nullptr;
|
||||
const PeripheralRegisterGroup &m_group;
|
||||
PeripheralRegister &m_reg;
|
||||
};
|
||||
|
||||
PeripheralRegisterItem::PeripheralRegisterItem(
|
||||
DebuggerEngine *engine,
|
||||
const PeripheralRegisterGroup &group,
|
||||
PeripheralRegister ®)
|
||||
: m_engine(engine), m_group(group), m_reg(reg)
|
||||
{
|
||||
for (auto &fld : m_reg.fields) {
|
||||
const auto item = new PeripheralRegisterFieldItem(
|
||||
m_engine, m_group, m_reg, fld);
|
||||
appendChild(item);
|
||||
}
|
||||
}
|
||||
|
||||
QVariant PeripheralRegisterItem::data(int column, int role) const
|
||||
{
|
||||
switch (role) {
|
||||
case PeripheralRegisterChangedRole:
|
||||
return m_reg.currentValue != m_reg.previousValue;
|
||||
|
||||
case Qt::DisplayRole:
|
||||
switch (column) {
|
||||
case PeripheralRegisterNameColumn:
|
||||
return m_reg.name;
|
||||
case PeripheralRegisterValueColumn:
|
||||
return m_reg.currentValueString();
|
||||
case PeripheralRegisterAccessColumn:
|
||||
return accessName(m_reg.access);
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::ToolTipRole:
|
||||
switch (column) {
|
||||
case PeripheralRegisterNameColumn:
|
||||
return QStringLiteral("%1 / %2\n%3\n%4 @ %5, %6")
|
||||
.arg(m_group.name)
|
||||
.arg(m_reg.name)
|
||||
.arg(m_reg.description)
|
||||
.arg(accessName(m_reg.access))
|
||||
.arg(m_reg.addressString(m_group.baseAddress))
|
||||
.arg(m_reg.size);
|
||||
case PeripheralRegisterValueColumn:
|
||||
return QStringLiteral("Current value: %1\n"
|
||||
"Previous value: %2\n"
|
||||
"Reset value: %3")
|
||||
.arg(m_reg.currentValueString(),
|
||||
m_reg.previousValueString(),
|
||||
m_reg.resetValueString());
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::EditRole:
|
||||
return m_reg.currentValueString();
|
||||
|
||||
case Qt::TextAlignmentRole: {
|
||||
if (column == PeripheralRegisterValueColumn)
|
||||
return Qt::AlignRight;
|
||||
return {};
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool PeripheralRegisterItem::setData(int column, const QVariant &value, int role)
|
||||
{
|
||||
if (column == PeripheralRegisterValueColumn && role == Qt::EditRole) {
|
||||
if (m_reg.currentValue.fromString(value.toString(), m_reg.format)) {
|
||||
triggerChange();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Qt::ItemFlags PeripheralRegisterItem::flags(int column) const
|
||||
{
|
||||
const Qt::ItemFlags notEditable = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
|
||||
if (column != PeripheralRegisterValueColumn)
|
||||
return notEditable;
|
||||
if (m_reg.access == PeripheralRegisterAccess::ReadWrite
|
||||
|| m_reg.access == PeripheralRegisterAccess::WriteOnly) {
|
||||
return notEditable | Qt::ItemIsEditable;
|
||||
}
|
||||
return notEditable;
|
||||
}
|
||||
|
||||
void PeripheralRegisterItem::triggerChange()
|
||||
{
|
||||
m_engine->setPeripheralRegisterValue(m_reg.address(m_group.baseAddress),
|
||||
m_reg.currentValue.v);
|
||||
}
|
||||
|
||||
// PeripheralRegisterDelegate
|
||||
|
||||
class PeripheralRegisterDelegate final : public QItemDelegate
|
||||
{
|
||||
public:
|
||||
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &,
|
||||
const QModelIndex &index) const final
|
||||
{
|
||||
if (index.column() == PeripheralRegisterValueColumn) {
|
||||
const auto lineEdit = new QLineEdit(parent);
|
||||
lineEdit->setAlignment(Qt::AlignLeft);
|
||||
lineEdit->setFrame(false);
|
||||
return lineEdit;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void setEditorData(QWidget *editor, const QModelIndex &index) const final
|
||||
{
|
||||
const auto lineEdit = qobject_cast<QLineEdit *>(editor);
|
||||
QTC_ASSERT(lineEdit, return);
|
||||
lineEdit->setText(index.data(Qt::EditRole).toString());
|
||||
}
|
||||
|
||||
void setModelData(QWidget *editor, QAbstractItemModel *model,
|
||||
const QModelIndex &index) const final
|
||||
{
|
||||
if (index.column() == PeripheralRegisterValueColumn) {
|
||||
const auto lineEdit = qobject_cast<QLineEdit *>(editor);
|
||||
QTC_ASSERT(lineEdit, return);
|
||||
model->setData(index, lineEdit->text(), Qt::EditRole);
|
||||
}
|
||||
}
|
||||
|
||||
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &) const final
|
||||
{
|
||||
editor->setGeometry(option.rect);
|
||||
}
|
||||
|
||||
void paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const final
|
||||
{
|
||||
if (index.column() == PeripheralRegisterValueColumn) {
|
||||
const bool paintRed = index.data(PeripheralRegisterChangedRole).toBool();
|
||||
const QPen oldPen = painter->pen();
|
||||
const QColor lightColor(140, 140, 140);
|
||||
if (paintRed)
|
||||
painter->setPen(QColor(200, 0, 0));
|
||||
else
|
||||
painter->setPen(lightColor);
|
||||
// FIXME: performance? this changes only on real font changes.
|
||||
const QFontMetrics fm(option.font);
|
||||
const int charWidth = qMax(fm.horizontalAdvance('x'),
|
||||
fm.horizontalAdvance('0'));
|
||||
const QString str = index.data(Qt::DisplayRole).toString();
|
||||
int x = option.rect.x();
|
||||
bool light = !paintRed;
|
||||
for (int i = 0; i < str.size(); ++i) {
|
||||
const QChar c = str.at(i);
|
||||
const int uc = c.unicode();
|
||||
if (light && (uc != 'x' && uc != '0')) {
|
||||
light = false;
|
||||
painter->setPen(oldPen.color());
|
||||
}
|
||||
if (uc == ' ') {
|
||||
light = true;
|
||||
painter->setPen(lightColor);
|
||||
} else {
|
||||
QRect r = option.rect;
|
||||
r.setX(x);
|
||||
r.setWidth(charWidth);
|
||||
painter->drawText(r, Qt::AlignHCenter, c);
|
||||
}
|
||||
x += charWidth;
|
||||
}
|
||||
painter->setPen(oldPen);
|
||||
} else {
|
||||
QItemDelegate::paint(painter, option, index);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// PeripheralRegisterHandler
|
||||
|
||||
PeripheralRegisterHandler::PeripheralRegisterHandler(DebuggerEngine *engine)
|
||||
: m_engine(engine)
|
||||
{
|
||||
setObjectName("PeripheralRegisterModel");
|
||||
setHeader({tr("Name"), tr("Value"), tr("Access")});
|
||||
}
|
||||
|
||||
static PeripheralRegisterGroups availablePeripheralRegisterGroups(
|
||||
const QString &filePath)
|
||||
{
|
||||
QFile f(filePath);
|
||||
if (!f.open(QIODevice::ReadOnly))
|
||||
return {};
|
||||
|
||||
QXmlStreamReader in(&f);
|
||||
|
||||
PeripheralRegisterGroups foundGroups;
|
||||
|
||||
while (!in.atEnd()) {
|
||||
const auto token = in.readNext();
|
||||
if (token == QXmlStreamReader::EndElement
|
||||
&& in.name() == QLatin1String(kPeripherals)) {
|
||||
break;
|
||||
} else if (token != QXmlStreamReader::StartElement
|
||||
|| in.name() != QLatin1String(kPeripheral)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PeripheralRegisterGroup group;
|
||||
|
||||
const auto fromGroupName = in.attributes().value(
|
||||
QLatin1String(kDerivedFrom));
|
||||
const auto foundGroupEnd = foundGroups.cend();
|
||||
const auto foundGroupIt = std::find_if(
|
||||
foundGroups.cbegin(), foundGroupEnd,
|
||||
[fromGroupName](const PeripheralRegisterGroup &foundGroup) {
|
||||
return fromGroupName == foundGroup.name;
|
||||
});
|
||||
if (foundGroupIt != foundGroupEnd)
|
||||
group = *foundGroupIt;
|
||||
|
||||
while (!in.atEnd()) {
|
||||
const auto token = in.readNext();
|
||||
if (token == QXmlStreamReader::EndElement
|
||||
&& in.name() == QLatin1String(kPeripheral)) {
|
||||
foundGroups.push_back(group);
|
||||
break;
|
||||
} else if (token == QXmlStreamReader::StartElement) {
|
||||
const auto elementName = in.name();
|
||||
if (elementName == QLatin1String(kName)) {
|
||||
group.name = in.readElementText();
|
||||
} else if (elementName == QLatin1String(kDescription)) {
|
||||
group.description = in.readElementText();
|
||||
} else if (elementName == QLatin1String(kGroupName)) {
|
||||
group.displayName = in.readElementText();
|
||||
} else if (elementName == QLatin1String(kBaseAddress)) {
|
||||
group.baseAddress = decodeNumeric(in.readElementText());
|
||||
} else if (elementName == QLatin1String(kSize)) {
|
||||
group.size = int(decodeNumeric(in.readElementText()));
|
||||
} else if (elementName == QLatin1String(kAccess)) {
|
||||
group.access = decodeAccess(in.readElementText());
|
||||
} else if (elementName == QLatin1String(kRegisters)
|
||||
|| elementName == QLatin1String(kRegister)) {
|
||||
PeripheralRegister reg;
|
||||
while (!in.atEnd()) {
|
||||
const auto token = in.readNext();
|
||||
if (token == QXmlStreamReader::EndElement
|
||||
&& in.name() == QLatin1String(kRegister)) {
|
||||
group.registers.push_back(reg);
|
||||
break;
|
||||
} else if (token == QXmlStreamReader::StartElement) {
|
||||
const auto elementName = in.name();
|
||||
if (elementName == QLatin1String(kRegister)) {
|
||||
continue;
|
||||
} else if (elementName == QLatin1String(kName)) {
|
||||
reg.name = in.readElementText();
|
||||
} else if (elementName == QLatin1String(kDescription)) {
|
||||
reg.description = in.readElementText();
|
||||
} else if (elementName == QLatin1String(kAddressOffset)) {
|
||||
reg.addressOffset = decodeNumeric(in.readElementText());
|
||||
} else if (elementName == QLatin1String(kSize)) {
|
||||
reg.size = int(decodeNumeric(in.readElementText()));
|
||||
} else if (elementName == QLatin1String(kAccess)) {
|
||||
reg.access = decodeAccess(in.readElementText());
|
||||
} else if (elementName == QLatin1String(kResetvalue)) {
|
||||
reg.resetValue = decodeNumeric(in.readElementText());
|
||||
} else if (elementName == QLatin1String(kFields)
|
||||
|| elementName == QLatin1String(kField)) {
|
||||
PeripheralRegisterField fld;
|
||||
while (!in.atEnd()) {
|
||||
const auto token = in.readNext();
|
||||
if (token == QXmlStreamReader::EndElement
|
||||
&& in.name() == QLatin1String(kField)) {
|
||||
reg.fields.push_back(fld);
|
||||
break;
|
||||
} else if (token == QXmlStreamReader::StartElement) {
|
||||
const auto elementName = in.name();
|
||||
if (elementName == QLatin1String(kField)) {
|
||||
continue;
|
||||
} else if (elementName == QLatin1String(kName)) {
|
||||
fld.name = in.readElementText();
|
||||
} else if (elementName == QLatin1String(kDescription)) {
|
||||
fld.description = in.readElementText();
|
||||
} else if (elementName == QLatin1String(kAccess)) {
|
||||
fld.access = decodeAccess(in.readElementText());
|
||||
} else if (elementName == QLatin1String(kBitRange)) {
|
||||
const QString elementText = in.readElementText();
|
||||
const int startBracket = elementText.indexOf('[');
|
||||
const int endBracket = elementText.indexOf(']');
|
||||
if (startBracket == -1 || endBracket == -1
|
||||
|| (endBracket - startBracket) <= 0) {
|
||||
continue;
|
||||
}
|
||||
const QString range = elementText.mid(
|
||||
startBracket + 1, endBracket - 1);
|
||||
const QStringList items = range.split(':');
|
||||
enum { MaxBit, MinBit, BitsCount };
|
||||
if (items.count() != BitsCount)
|
||||
continue;
|
||||
const int from = int(decodeNumeric(items.at(MinBit)));
|
||||
const int to = int(decodeNumeric(items.at(MaxBit)));
|
||||
fld.bitOffset = from;
|
||||
fld.bitWidth = to - from + 1;
|
||||
} else if (elementName == QLatin1String(kBitOffset)) {
|
||||
fld.bitOffset = int(decodeNumeric(in.readElementText()));
|
||||
} else if (elementName == QLatin1String(kBitWidth)) {
|
||||
fld.bitWidth = int(decodeNumeric(in.readElementText()));
|
||||
} else {
|
||||
in.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
in.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
in.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return foundGroups;
|
||||
}
|
||||
|
||||
void PeripheralRegisterHandler::updateRegisterGroups()
|
||||
{
|
||||
clear();
|
||||
|
||||
const auto dev = m_engine->device();
|
||||
QTC_ASSERT(dev, return);
|
||||
|
||||
const QString filePath = dev->peripheralDescriptionFilePath();
|
||||
if (filePath.isEmpty())
|
||||
return;
|
||||
|
||||
m_peripheralRegisterGroups = availablePeripheralRegisterGroups(filePath);
|
||||
}
|
||||
|
||||
void PeripheralRegisterHandler::updateRegister(quint64 address, quint64 value)
|
||||
{
|
||||
const auto regItem = m_activeRegisters.value(address);
|
||||
if (!regItem)
|
||||
return;
|
||||
|
||||
regItem->m_reg.previousValue = regItem->m_reg.currentValue;
|
||||
regItem->m_reg.currentValue = value;
|
||||
|
||||
commitUpdates();
|
||||
}
|
||||
|
||||
QList<quint64> PeripheralRegisterHandler::activeRegisters() const
|
||||
{
|
||||
return m_activeRegisters.keys();
|
||||
}
|
||||
|
||||
QVariant PeripheralRegisterHandler::data(const QModelIndex &idx, int role) const
|
||||
{
|
||||
if (role == BaseTreeView::ItemDelegateRole) {
|
||||
return QVariant::fromValue(static_cast<QAbstractItemDelegate *>(
|
||||
new PeripheralRegisterDelegate));
|
||||
}
|
||||
return PeripheralRegisterModel::data(idx, role);
|
||||
}
|
||||
|
||||
bool PeripheralRegisterHandler::setData(const QModelIndex &idx,
|
||||
const QVariant &data, int role)
|
||||
{
|
||||
if (role == BaseTreeView::ItemViewEventRole) {
|
||||
const auto ev = data.value<ItemViewEvent>();
|
||||
if (ev.type() == QEvent::ContextMenu)
|
||||
return contextMenuEvent(ev);
|
||||
}
|
||||
return PeripheralRegisterModel::setData(idx, data, role);
|
||||
}
|
||||
|
||||
bool PeripheralRegisterHandler::contextMenuEvent(const ItemViewEvent &ev)
|
||||
{
|
||||
const DebuggerState state = m_engine->state();
|
||||
const auto menu = new QMenu;
|
||||
|
||||
QMenu *groupMenu = createRegisterGroupsMenu(state);
|
||||
menu->addMenu(groupMenu);
|
||||
|
||||
if (const auto regItem = itemForIndexAtLevel<PeripheralRegisterLevel>(
|
||||
ev.sourceModelIndex())) {
|
||||
// Show the register value format menu only
|
||||
// if a register item chose.
|
||||
QMenu *fmtMenu = createRegisterFormatMenu(state, regItem);
|
||||
menu->addMenu(fmtMenu);
|
||||
} else if (const auto fldItem = itemForIndexAtLevel<PeripheralRegisterFieldLevel>(
|
||||
ev.sourceModelIndex())) {
|
||||
// Show the register field value format menu only
|
||||
// if a register field item chose.
|
||||
QMenu *fmtMenu = createRegisterFieldFormatMenu(state, fldItem);
|
||||
menu->addMenu(fmtMenu);
|
||||
}
|
||||
|
||||
menu->addSeparator();
|
||||
menu->addAction(action(SettingsDialog));
|
||||
menu->popup(ev.globalPos());
|
||||
return true;
|
||||
}
|
||||
|
||||
QMenu *PeripheralRegisterHandler::createRegisterGroupsMenu(DebuggerState state) const
|
||||
{
|
||||
const auto groupMenu = new QMenu(tr("View Groups"));
|
||||
const auto actionGroup = new QActionGroup(groupMenu);
|
||||
bool hasActions = false;
|
||||
for (const PeripheralRegisterGroup &group : qAsConst(m_peripheralRegisterGroups)) {
|
||||
const QString actName = QStringLiteral("%1: %2")
|
||||
.arg(group.name, group.description);
|
||||
QAction *act = groupMenu->addAction(actName);
|
||||
const bool on = m_engine->hasCapability(RegisterCapability)
|
||||
&& (state == InferiorStopOk || state == InferiorUnrunnable);
|
||||
act->setEnabled(on);
|
||||
act->setData(group.name);
|
||||
act->setCheckable(true);
|
||||
act->setChecked(group.active);
|
||||
actionGroup->addAction(act);
|
||||
QObject::connect(act, &QAction::triggered,
|
||||
this, &PeripheralRegisterHandler::setActiveGroup);
|
||||
hasActions = true;
|
||||
}
|
||||
groupMenu->setEnabled(hasActions);
|
||||
return groupMenu;
|
||||
}
|
||||
|
||||
QMenu *PeripheralRegisterHandler::createRegisterFormatMenu(
|
||||
DebuggerState state, PeripheralRegisterItem *item) const
|
||||
{
|
||||
const auto fmtMenu = new QMenu(tr("Format"));
|
||||
const auto actionGroup = new QActionGroup(fmtMenu);
|
||||
|
||||
const bool on = m_engine->hasCapability(RegisterCapability)
|
||||
&& (state == InferiorStopOk || state == InferiorUnrunnable);
|
||||
|
||||
const PeripheralRegisterFormat fmt = item->m_reg.format;
|
||||
|
||||
// Hexadecimal action.
|
||||
const auto hexAct = addCheckableAction(
|
||||
fmtMenu, tr("Hexadecimal"), on,
|
||||
fmt == PeripheralRegisterFormat::Hexadecimal,
|
||||
[item] {
|
||||
item->m_reg.format = PeripheralRegisterFormat::Hexadecimal;
|
||||
item->update();
|
||||
});
|
||||
actionGroup->addAction(hexAct);
|
||||
|
||||
// Decimal action.
|
||||
const auto decAct = addCheckableAction(
|
||||
fmtMenu, tr("Decimal"), on,
|
||||
fmt == PeripheralRegisterFormat::Decimal,
|
||||
[item] {
|
||||
item->m_reg.format = PeripheralRegisterFormat::Decimal;
|
||||
item->update();
|
||||
});
|
||||
actionGroup->addAction(decAct);
|
||||
|
||||
// Octal action.
|
||||
const auto octAct = addCheckableAction(
|
||||
fmtMenu, tr("Octal"), on,
|
||||
fmt == PeripheralRegisterFormat::Octal,
|
||||
[item] {
|
||||
item->m_reg.format = PeripheralRegisterFormat::Octal;
|
||||
item->update();
|
||||
});
|
||||
actionGroup->addAction(octAct);
|
||||
|
||||
// Binary action.
|
||||
const auto binAct = addCheckableAction(
|
||||
fmtMenu, tr("Binary"), on,
|
||||
fmt == PeripheralRegisterFormat::Binary,
|
||||
[item] {
|
||||
item->m_reg.format = PeripheralRegisterFormat::Binary;
|
||||
item->update();
|
||||
});
|
||||
actionGroup->addAction(binAct);
|
||||
|
||||
return fmtMenu;
|
||||
}
|
||||
|
||||
QMenu *PeripheralRegisterHandler::createRegisterFieldFormatMenu(
|
||||
DebuggerState state, PeripheralRegisterFieldItem *item) const
|
||||
{
|
||||
const auto fmtMenu = new QMenu(tr("Format"));
|
||||
const auto actionGroup = new QActionGroup(fmtMenu);
|
||||
|
||||
const bool on = m_engine->hasCapability(RegisterCapability)
|
||||
&& (state == InferiorStopOk || state == InferiorUnrunnable);
|
||||
|
||||
const PeripheralRegisterFormat fmt = item->m_fld.format;
|
||||
|
||||
// Hexadecimal action.
|
||||
const auto hexAct = addCheckableAction(
|
||||
fmtMenu, tr("Hexadecimal"), on,
|
||||
fmt == PeripheralRegisterFormat::Hexadecimal,
|
||||
[item] {
|
||||
item->m_fld.format = PeripheralRegisterFormat::Hexadecimal;
|
||||
item->update();
|
||||
});
|
||||
actionGroup->addAction(hexAct);
|
||||
|
||||
// Decimal action.
|
||||
const auto decAct = addCheckableAction(
|
||||
fmtMenu, tr("Decimal"), on,
|
||||
fmt == PeripheralRegisterFormat::Decimal,
|
||||
[item] {
|
||||
item->m_fld.format = PeripheralRegisterFormat::Decimal;
|
||||
item->update();
|
||||
});
|
||||
actionGroup->addAction(decAct);
|
||||
|
||||
// Octal action.
|
||||
const auto octAct = addCheckableAction(
|
||||
fmtMenu, tr("Octal"), on,
|
||||
fmt == PeripheralRegisterFormat::Octal,
|
||||
[item] {
|
||||
item->m_fld.format = PeripheralRegisterFormat::Octal;
|
||||
item->update();
|
||||
});
|
||||
actionGroup->addAction(octAct);
|
||||
|
||||
// Binary action.
|
||||
const auto binAct = addCheckableAction(
|
||||
fmtMenu, tr("Binary"), on,
|
||||
fmt == PeripheralRegisterFormat::Binary,
|
||||
[item] {
|
||||
item->m_fld.format = PeripheralRegisterFormat::Binary;
|
||||
item->update();
|
||||
});
|
||||
actionGroup->addAction(binAct);
|
||||
|
||||
return fmtMenu;
|
||||
}
|
||||
|
||||
void PeripheralRegisterHandler::setActiveGroup(bool checked)
|
||||
{
|
||||
if (!checked)
|
||||
return;
|
||||
deactivateGroups();
|
||||
if (const auto act = qobject_cast<QAction *>(sender())) {
|
||||
const QString groupName = act->data().toString();
|
||||
const auto groupEnd = m_peripheralRegisterGroups.end();
|
||||
const auto groupIt = std::find_if(
|
||||
m_peripheralRegisterGroups.begin(), groupEnd,
|
||||
[groupName](const PeripheralRegisterGroup &group){
|
||||
return group.name == groupName;
|
||||
});
|
||||
if (groupIt == groupEnd)
|
||||
return; // Group not found.
|
||||
// Set active group.
|
||||
groupIt->active = true;
|
||||
|
||||
// Add all register items of active register group.
|
||||
m_activeRegisters.reserve(groupIt->registers.count());
|
||||
for (PeripheralRegister ® : groupIt->registers) {
|
||||
const auto item = new PeripheralRegisterItem(m_engine, *groupIt, reg);
|
||||
rootItem()->appendChild(item);
|
||||
|
||||
const quint64 address = reg.address(groupIt->baseAddress);
|
||||
m_activeRegisters.insert(address, item);
|
||||
}
|
||||
|
||||
m_engine->reloadPeripheralRegisters();
|
||||
}
|
||||
}
|
||||
|
||||
void PeripheralRegisterHandler::deactivateGroups()
|
||||
{
|
||||
clear();
|
||||
|
||||
for (PeripheralRegisterGroup &group : m_peripheralRegisterGroups)
|
||||
group.active = false;
|
||||
|
||||
m_activeRegisters.clear();
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Debugger
|
||||
185
src/plugins/debugger/peripheralregisterhandler.h
Normal file
185
src/plugins/debugger/peripheralregisterhandler.h
Normal file
@@ -0,0 +1,185 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "debuggerengine.h"
|
||||
|
||||
#include <utils/treemodel.h>
|
||||
|
||||
#include <QHash>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QMenu;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Utils { class ItemViewEvent; }
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
class DebuggerEngine;
|
||||
|
||||
enum class PeripheralRegisterAccess
|
||||
{
|
||||
Unknown,
|
||||
ReadOnly,
|
||||
WriteOnly,
|
||||
ReadWrite
|
||||
};
|
||||
|
||||
enum class PeripheralRegisterFormat
|
||||
{
|
||||
Hexadecimal,
|
||||
Decimal,
|
||||
Octal,
|
||||
Binary
|
||||
};
|
||||
|
||||
// PeripheralRegisterField
|
||||
|
||||
class PeripheralRegisterField final
|
||||
{
|
||||
public:
|
||||
QString bitRangeString() const;
|
||||
QString bitValueString(quint64 regValue) const;
|
||||
quint64 bitValue(quint64 regValue) const;
|
||||
quint64 bitMask() const;
|
||||
|
||||
QString name;
|
||||
QString description;
|
||||
int bitOffset = 0;
|
||||
int bitWidth = 0;
|
||||
PeripheralRegisterAccess access = PeripheralRegisterAccess::Unknown;
|
||||
PeripheralRegisterFormat format = PeripheralRegisterFormat::Hexadecimal;
|
||||
};
|
||||
|
||||
// PeripheralRegisterValue
|
||||
|
||||
class PeripheralRegisterValue final
|
||||
{
|
||||
public:
|
||||
PeripheralRegisterValue(quint64 v = 0) : v(v) {}
|
||||
bool operator==(const PeripheralRegisterValue &other) { return v == other.v; }
|
||||
bool operator!=(const PeripheralRegisterValue &other) { return !operator==(other); }
|
||||
|
||||
bool fromString(const QString &string, PeripheralRegisterFormat fmt);
|
||||
QString toString(int size, PeripheralRegisterFormat fmt) const;
|
||||
|
||||
quint64 v = 0;
|
||||
};
|
||||
|
||||
// PeripheralRegister
|
||||
|
||||
class PeripheralRegister final
|
||||
{
|
||||
public:
|
||||
QString currentValueString() const;
|
||||
QString previousValueString() const;
|
||||
QString resetValueString() const;
|
||||
|
||||
QString addressString(quint64 baseAddress) const;
|
||||
quint64 address(quint64 baseAddress) const;
|
||||
|
||||
QString name;
|
||||
QString displayName;
|
||||
QString description;
|
||||
quint64 addressOffset = 0;
|
||||
int size = 0; // in bits
|
||||
PeripheralRegisterAccess access = PeripheralRegisterAccess::Unknown;
|
||||
PeripheralRegisterFormat format = PeripheralRegisterFormat::Hexadecimal;
|
||||
|
||||
QVector<PeripheralRegisterField> fields;
|
||||
|
||||
PeripheralRegisterValue currentValue;
|
||||
PeripheralRegisterValue previousValue;
|
||||
PeripheralRegisterValue resetValue;
|
||||
};
|
||||
|
||||
// PeripheralRegisterGroup
|
||||
|
||||
class PeripheralRegisterGroup final
|
||||
{
|
||||
public:
|
||||
QString name;
|
||||
QString displayName;
|
||||
QString description;
|
||||
quint64 baseAddress = 0;
|
||||
int size = 0; // in bits
|
||||
PeripheralRegisterAccess access = PeripheralRegisterAccess::Unknown;
|
||||
bool active = false;
|
||||
QVector<PeripheralRegister> registers;
|
||||
};
|
||||
|
||||
// PeripheralRegisterGroups
|
||||
|
||||
using PeripheralRegisterGroups = QVector<PeripheralRegisterGroup>;
|
||||
|
||||
// PeripheralRegisterItem's
|
||||
|
||||
enum { PeripheralRegisterLevel = 1, PeripheralRegisterFieldLevel = 2 };
|
||||
|
||||
class PeripheralRegisterFieldItem;
|
||||
class PeripheralRegisterItem;
|
||||
using PeripheralRegisterRootItem = Utils::TypedTreeItem<PeripheralRegisterItem>;
|
||||
using PeripheralRegisterModel = Utils::TreeModel<PeripheralRegisterRootItem,
|
||||
PeripheralRegisterItem,
|
||||
PeripheralRegisterFieldItem>;
|
||||
|
||||
// PeripheralRegisterHandler
|
||||
|
||||
class PeripheralRegisterHandler final : public PeripheralRegisterModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PeripheralRegisterHandler(DebuggerEngine *engine);
|
||||
|
||||
QAbstractItemModel *model() { return this; }
|
||||
|
||||
void updateRegisterGroups();
|
||||
void updateRegister(quint64 address, quint64 value);
|
||||
void commitUpdates() { emit layoutChanged(); }
|
||||
QList<quint64> activeRegisters() const;
|
||||
|
||||
private:
|
||||
QVariant data(const QModelIndex &idx, int role) const final;
|
||||
bool setData(const QModelIndex &idx, const QVariant &data, int role) final;
|
||||
|
||||
bool contextMenuEvent(const Utils::ItemViewEvent &ev);
|
||||
QMenu *createRegisterGroupsMenu(DebuggerState state) const;
|
||||
QMenu *createRegisterFormatMenu(DebuggerState state,
|
||||
PeripheralRegisterItem *item) const;
|
||||
QMenu *createRegisterFieldFormatMenu(DebuggerState state,
|
||||
PeripheralRegisterFieldItem *item) const;
|
||||
void setActiveGroup(bool checked);
|
||||
void deactivateGroups();
|
||||
|
||||
PeripheralRegisterGroups m_peripheralRegisterGroups;
|
||||
QHash<quint64, PeripheralRegisterItem *> m_activeRegisters;
|
||||
DebuggerEngine * const m_engine;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Debugger
|
||||
@@ -123,6 +123,7 @@ const char TimeoutKey[] = "Timeout";
|
||||
const char HostKeyCheckingKey[] = "HostKeyChecking";
|
||||
|
||||
const char DebugServerKey[] = "DebugServerKey";
|
||||
const char PeripheralDescriptionFileKey[] = "PeripheralDescriptionFileKey";
|
||||
const char QmlsceneKey[] = "QmlsceneKey";
|
||||
|
||||
using AuthType = QSsh::SshConnectionParameters::AuthenticationType;
|
||||
@@ -149,6 +150,7 @@ public:
|
||||
QSsh::SshConnectionParameters sshParameters;
|
||||
Utils::PortList freePorts;
|
||||
QString debugServerPath;
|
||||
QString peripheralDescriptionFilePath;
|
||||
QString qmlsceneCommand;
|
||||
|
||||
QList<Utils::Icon> deviceIcons;
|
||||
@@ -378,6 +380,7 @@ void IDevice::fromMap(const QVariantMap &map)
|
||||
d->version = map.value(QLatin1String(VersionKey), 0).toInt();
|
||||
|
||||
d->debugServerPath = map.value(QLatin1String(DebugServerKey)).toString();
|
||||
d->peripheralDescriptionFilePath = map.value(QLatin1String(PeripheralDescriptionFileKey)).toString();
|
||||
d->qmlsceneCommand = map.value(QLatin1String(QmlsceneKey)).toString();
|
||||
d->extraData = map.value(ExtraDataKey).toMap();
|
||||
}
|
||||
@@ -409,6 +412,7 @@ QVariantMap IDevice::toMap() const
|
||||
map.insert(QLatin1String(VersionKey), d->version);
|
||||
|
||||
map.insert(QLatin1String(DebugServerKey), d->debugServerPath);
|
||||
map.insert(QLatin1String(PeripheralDescriptionFileKey), d->peripheralDescriptionFilePath);
|
||||
map.insert(QLatin1String(QmlsceneKey), d->qmlsceneCommand);
|
||||
map.insert(ExtraDataKey, d->extraData);
|
||||
|
||||
@@ -488,6 +492,17 @@ void IDevice::setDebugServerPath(const QString &path)
|
||||
d->debugServerPath = path;
|
||||
}
|
||||
|
||||
|
||||
QString IDevice::peripheralDescriptionFilePath() const
|
||||
{
|
||||
return d->peripheralDescriptionFilePath;
|
||||
}
|
||||
|
||||
void IDevice::setPeripheralDescriptionFilePath(const QString &path)
|
||||
{
|
||||
d->peripheralDescriptionFilePath = path;
|
||||
}
|
||||
|
||||
QString IDevice::qmlsceneCommand() const
|
||||
{
|
||||
return d->qmlsceneCommand;
|
||||
|
||||
@@ -212,6 +212,9 @@ public:
|
||||
QString debugServerPath() const;
|
||||
void setDebugServerPath(const QString &path);
|
||||
|
||||
QString peripheralDescriptionFilePath() const;
|
||||
void setPeripheralDescriptionFilePath(const QString &path);
|
||||
|
||||
QString qmlsceneCommand() const;
|
||||
void setQmlsceneCommand(const QString &path);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user