BareMetal: Add support for peripheral registers view using UVSC provider

Now it is possible to use the SVD files to read or write the peripheral
registers of a target device.

By default a paths to the SVD files automatically comes from the installed
"Device Software Pack" database and don't need to be changed by the user.
But, if a user needs to change the SVD file, then it can be done via the
provider's device selection options.

Tested on Windows with Keil MDK-ARM v5.23 using the STM32 NUCLEO-F767ZI
board.

Change-Id: Ia39e8d9a25cd24461804d47830ee9e8f01486108
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Denis Shienkov
2020-03-11 18:05:57 +03:00
parent a92156b08f
commit 818d79b655
10 changed files with 141 additions and 0 deletions

View File

@@ -201,8 +201,12 @@ bool UvscServerProvider::aboutToRun(DebuggerRunTool *runTool, QString &errorMess
if (!optFilePath.exists()) if (!optFilePath.exists())
return false; return false;
const FilePath peripheralDescriptionFile = FilePath::fromString(m_deviceSelection.svd);
Runnable inferior; Runnable inferior;
inferior.executable = bin; inferior.executable = bin;
inferior.extraData.insert(Debugger::Constants::kPeripheralDescriptionFile,
peripheralDescriptionFile.toVariant());
inferior.extraData.insert(Debugger::Constants::kUVisionProjectFilePath, projFilePath.toString()); inferior.extraData.insert(Debugger::Constants::kUVisionProjectFilePath, projFilePath.toString());
inferior.extraData.insert(Debugger::Constants::kUVisionOptionsFilePath, optFilePath.toString()); inferior.extraData.insert(Debugger::Constants::kUVisionOptionsFilePath, optFilePath.toString());
inferior.extraData.insert(Debugger::Constants::kUVisionSimulator, isSimulator()); inferior.extraData.insert(Debugger::Constants::kUVisionSimulator, isSimulator());

View File

@@ -497,6 +497,14 @@ DeviceSelection DeviceSelectionView::buildSelection(const DeviceSelectionItem *i
break; break;
} }
} while ((item = item->parentPackItem())); } while ((item = item->parentPackItem()));
// Fix relative SVD file path to make it as absolute.
const QFileInfo fi(selection.svd);
if (!fi.isAbsolute()) {
const QDir dir(QFileInfo(selection.package.file).path());
selection.svd = QFileInfo(dir, fi.filePath()).absoluteFilePath();
}
return selection; return selection;
} }

View File

@@ -27,6 +27,8 @@
#include "uvtargetdevicemodel.h" #include "uvtargetdevicemodel.h"
#include "uvtargetdeviceviewer.h" #include "uvtargetdeviceviewer.h"
#include <utils/pathchooser.h>
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QFormLayout> #include <QFormLayout>
#include <QHBoxLayout> #include <QHBoxLayout>
@@ -83,6 +85,14 @@ DeviceSelectorDetailsPanel::DeviceSelectorDetailsPanel(DeviceSelection &selectio
layout->addRow(tr("Memory:"), m_memoryView); layout->addRow(tr("Memory:"), m_memoryView);
m_algorithmView = new DeviceSelectionAlgorithmView(m_selection); m_algorithmView = new DeviceSelectionAlgorithmView(m_selection);
layout->addRow(tr("Flash algorithm"), m_algorithmView); layout->addRow(tr("Flash algorithm"), m_algorithmView);
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"));
layout->addRow(tr("Peripheral description file:"),
m_peripheralDescriptionFileChooser);
setLayout(layout); setLayout(layout);
refresh(); refresh();
@@ -95,6 +105,8 @@ DeviceSelectorDetailsPanel::DeviceSelectorDetailsPanel(DeviceSelection &selectio
m_selection.algorithmIndex = index; m_selection.algorithmIndex = index;
emit selectionChanged(); emit selectionChanged();
}); });
connect(m_peripheralDescriptionFileChooser, &Utils::PathChooser::pathChanged,
this, &DeviceSelectorDetailsPanel::selectionChanged);
} }
static QString trimVendor(const QString &vendor) static QString trimVendor(const QString &vendor)
@@ -111,6 +123,7 @@ void DeviceSelectorDetailsPanel::refresh()
m_memoryView->refresh(); m_memoryView->refresh();
m_algorithmView->refresh(); m_algorithmView->refresh();
m_algorithmView->setAlgorithm(m_selection.algorithmIndex); m_algorithmView->setAlgorithm(m_selection.algorithmIndex);
m_peripheralDescriptionFileChooser->setPath(m_selection.svd);
} }
// DeviceSelector // DeviceSelector

View File

@@ -38,6 +38,8 @@ class QLineEdit;
class QPlainTextEdit; class QPlainTextEdit;
QT_END_NAMESPACE QT_END_NAMESPACE
namespace Utils { class PathChooser; }
namespace BareMetal { namespace BareMetal {
namespace Internal { namespace Internal {
namespace Uv { namespace Uv {
@@ -107,6 +109,7 @@ private:
QPlainTextEdit *m_descEdit = nullptr; QPlainTextEdit *m_descEdit = nullptr;
DeviceSelectionMemoryView *m_memoryView = nullptr; DeviceSelectionMemoryView *m_memoryView = nullptr;
DeviceSelectionAlgorithmView *m_algorithmView = nullptr; DeviceSelectionAlgorithmView *m_algorithmView = nullptr;
Utils::PathChooser *m_peripheralDescriptionFileChooser = nullptr;
}; };
// DeviceSelectionDialog // DeviceSelectionDialog

View File

@@ -691,6 +691,41 @@ bool UvscClient::inspectWatcher(const QStringList &expandedWatcherINames,
return true; return true;
} }
bool UvscClient::fetchMemory(quint64 address, QByteArray &data)
{
if (data.isEmpty())
data.resize(sizeof(quint8));
QByteArray amem = UvscUtils::encodeAmem(address, data);
const auto amemPtr = reinterpret_cast<AMEM *>(amem.data());
const UVSC_STATUS st = ::UVSC_DBG_MEM_READ(m_descriptor, amemPtr, amem.size());
if (st != UVSC_STATUS_SUCCESS) {
setError(RuntimeError);
return false;
}
data = QByteArray(reinterpret_cast<char *>(&amemPtr->bytes),
amemPtr->bytesCount);
return true;
}
bool UvscClient::changeMemory(quint64 address, const QByteArray &data)
{
if (data.isEmpty()) {
setError(RuntimeError);
return false;
}
QByteArray amem = UvscUtils::encodeAmem(address, data);
const auto amemPtr = reinterpret_cast<AMEM *>(amem.data());
const UVSC_STATUS st = ::UVSC_DBG_MEM_WRITE(m_descriptor, amemPtr, amem.size());
if (st != UVSC_STATUS_SUCCESS) {
setError(RuntimeError);
return false;
}
return true;
}
bool UvscClient::disassemblyAddress(quint64 address, QByteArray &result) bool UvscClient::disassemblyAddress(quint64 address, QByteArray &result)
{ {
if (!checkConnection()) if (!checkConnection())

View File

@@ -87,6 +87,9 @@ public:
bool fetchWatchers(const QStringList &expandedWatcherINames, bool fetchWatchers(const QStringList &expandedWatcherINames,
const std::vector<std::pair<QString, QString>> &rootWatchers, GdbMi &data); const std::vector<std::pair<QString, QString>> &rootWatchers, GdbMi &data);
bool fetchMemory(quint64 address, QByteArray &data);
bool changeMemory(quint64 address, const QByteArray &data);
bool disassemblyAddress(quint64 address, QByteArray &result); bool disassemblyAddress(quint64 address, QByteArray &result);
bool setRegisterValue(int index, const QString &value); bool setRegisterValue(int index, const QString &value);

View File

@@ -32,6 +32,7 @@
#include <debugger/disassemblerlines.h> #include <debugger/disassemblerlines.h>
#include <debugger/memoryagent.h> #include <debugger/memoryagent.h>
#include <debugger/moduleshandler.h> #include <debugger/moduleshandler.h>
#include <debugger/peripheralregisterhandler.h>
#include <debugger/registerhandler.h> #include <debugger/registerhandler.h>
#include <debugger/stackhandler.h> #include <debugger/stackhandler.h>
#include <debugger/threadshandler.h> #include <debugger/threadshandler.h>
@@ -162,6 +163,9 @@ void UvscEngine::setupEngine()
if (!configureProject(rp)) if (!configureProject(rp))
return; return;
// Reload peripheral register description.
peripheralRegisterHandler()->updateRegisterGroups();
} }
void UvscEngine::runEngine() void UvscEngine::runEngine()
@@ -231,6 +235,14 @@ void UvscEngine::setRegisterValue(const QString &name, const QString &value)
reloadRegisters(); reloadRegisters();
} }
void UvscEngine::setPeripheralRegisterValue(quint64 address, quint64 value)
{
const QByteArray data = UvscUtils::encodeU32(value);
if (!m_client->changeMemory(address, data))
return;
reloadPeripheralRegisters();
}
void UvscEngine::executeStepOver(bool byInstruction) void UvscEngine::executeStepOver(bool byInstruction)
{ {
notifyInferiorRunRequested(); notifyInferiorRunRequested();
@@ -332,6 +344,7 @@ void UvscEngine::activateFrame(int index)
gotoCurrentLocation(); gotoCurrentLocation();
updateLocals(); updateLocals();
reloadRegisters(); reloadRegisters();
reloadPeripheralRegisters();
} }
bool UvscEngine::stateAcceptsBreakpointChanges() const bool UvscEngine::stateAcceptsBreakpointChanges() const
@@ -469,6 +482,17 @@ void UvscEngine::reloadRegisters()
handleReloadRegisters(); handleReloadRegisters();
} }
void UvscEngine::reloadPeripheralRegisters()
{
if (!isPeripheralRegistersWindowVisible())
return;
const QList<quint64> addresses = peripheralRegisterHandler()->activeRegisters();
if (addresses.isEmpty())
return; // Nothing to update.
handleReloadPeripheralRegisters(addresses);
}
void UvscEngine::reloadFullStack() void UvscEngine::reloadFullStack()
{ {
resetLocation(); resetLocation();
@@ -496,6 +520,7 @@ void UvscEngine::updateAll()
handleThreadInfo(); handleThreadInfo();
reloadRegisters(); reloadRegisters();
reloadPeripheralRegisters();
updateLocals(); updateLocals();
} }
@@ -653,6 +678,7 @@ void UvscEngine::handleReloadStack(bool isFull)
if (!m_client->fetchStackFrames(taskId, m_address, data)) { if (!m_client->fetchStackFrames(taskId, m_address, data)) {
m_address = 0; m_address = 0;
reloadRegisters(); reloadRegisters();
reloadPeripheralRegisters();
return; return;
} }
@@ -678,6 +704,19 @@ void UvscEngine::handleReloadRegisters()
} }
} }
void UvscEngine::handleReloadPeripheralRegisters(const QList<quint64> &addresses)
{
for (const quint64 address : addresses) {
QByteArray data = UvscUtils::encodeU32(0);
if (!m_client->fetchMemory(address, data)) {
showMessage(tr("UVSC: Fetching peripheral register failed"), LogMisc);
} else {
const quint32 value = UvscUtils::decodeU32(data);
peripheralRegisterHandler()->updateRegister(address, value);
}
}
}
void UvscEngine::handleUpdateLocals(bool partial) void UvscEngine::handleUpdateLocals(bool partial)
{ {
m_inUpdateLocals = false; m_inUpdateLocals = false;

View File

@@ -49,6 +49,7 @@ public:
bool hasCapability(unsigned cap) const final; bool hasCapability(unsigned cap) const final;
void setRegisterValue(const QString &name, const QString &value) final; void setRegisterValue(const QString &name, const QString &value) final;
void setPeripheralRegisterValue(quint64 address, quint64 value) final;
void executeStepOver(bool byInstruction) final; void executeStepOver(bool byInstruction) final;
void executeStepIn(bool byInstruction) final; void executeStepIn(bool byInstruction) final;
@@ -72,6 +73,8 @@ public:
void fetchDisassembler(DisassemblerAgent *agent) final; void fetchDisassembler(DisassemblerAgent *agent) final;
void reloadRegisters() final; void reloadRegisters() final;
void reloadPeripheralRegisters() final;
void reloadFullStack() final; void reloadFullStack() final;
private slots: private slots:
@@ -84,6 +87,7 @@ private slots:
void handleThreadInfo(); void handleThreadInfo();
void handleReloadStack(bool isFull); void handleReloadStack(bool isFull);
void handleReloadRegisters(); void handleReloadRegisters();
void handleReloadPeripheralRegisters(const QList<quint64> &addresses);
void handleUpdateLocals(bool partial); void handleUpdateLocals(bool partial);
void handleInsertBreakpoint(const QString &exp, const Breakpoint &bp); void handleInsertBreakpoint(const QString &exp, const Breakpoint &bp);
void handleRemoveBreakpoint(const Breakpoint &bp); void handleRemoveBreakpoint(const Breakpoint &bp);

View File

@@ -110,6 +110,16 @@ QByteArray encodeAmem(quint64 address, quint32 bytesCount)
return buffer; return buffer;
} }
QByteArray encodeAmem(quint64 address, const QByteArray &data)
{
QByteArray buffer(sizeof(AMEM) - 1, 0);
buffer.append(data);
const auto amem = reinterpret_cast<AMEM *>(buffer.data());
amem->address = address;
amem->bytesCount = data.size();
return buffer;
}
TVAL encodeVoidTval() TVAL encodeVoidTval()
{ {
TVAL tval = {}; TVAL tval = {};
@@ -238,6 +248,24 @@ QString adjustHexValue(QString hex, const QString &type)
return {}; return {};
} }
QByteArray encodeU32(quint32 value)
{
QByteArray data;
QDataStream out(&data, QIODevice::WriteOnly);
out.setByteOrder(QDataStream::LittleEndian);
out << value;
return data;
}
quint32 decodeU32(const QByteArray &data)
{
QDataStream in(data);
in.setByteOrder(QDataStream::LittleEndian);
quint32 value = 0;
in >> value;
return value;
}
QString buildLocalId(const VARINFO &varinfo) QString buildLocalId(const VARINFO &varinfo)
{ {
return QString::number(varinfo.id); return QString::number(varinfo.id);

View File

@@ -56,6 +56,7 @@ QString decodeAscii(const qint8 *ascii);
QByteArray encodeProjectData(const QStringList &someNames); QByteArray encodeProjectData(const QStringList &someNames);
QByteArray encodeBreakPoint(BKTYPE type, const QString &exp, const QString &cmd = QString()); QByteArray encodeBreakPoint(BKTYPE type, const QString &exp, const QString &cmd = QString());
QByteArray encodeAmem(quint64 address, quint32 bytesCount); QByteArray encodeAmem(quint64 address, quint32 bytesCount);
QByteArray encodeAmem(quint64 address, const QByteArray &data);
TVAL encodeVoidTval(); TVAL encodeVoidTval();
TVAL encodeIntTval(int value); TVAL encodeIntTval(int value);
TVAL encodeU64Tval(quint64 value); TVAL encodeU64Tval(quint64 value);
@@ -65,6 +66,9 @@ VSET encodeU64Vset(quint64 index, const QString &value);
bool isKnownRegister(int type); bool isKnownRegister(int type);
QString adjustHexValue(QString hex, const QString &type); QString adjustHexValue(QString hex, const QString &type);
QByteArray encodeU32(quint32 value);
quint32 decodeU32(const QByteArray &data);
QString buildLocalId(const VARINFO &varinfo); QString buildLocalId(const VARINFO &varinfo);
QString buildLocalEditable(const VARINFO &varinfo); QString buildLocalEditable(const VARINFO &varinfo);
QString buildLocalNumchild(const VARINFO &varinfo); QString buildLocalNumchild(const VARINFO &varinfo);