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())
return false;
const FilePath peripheralDescriptionFile = FilePath::fromString(m_deviceSelection.svd);
Runnable inferior;
inferior.executable = bin;
inferior.extraData.insert(Debugger::Constants::kPeripheralDescriptionFile,
peripheralDescriptionFile.toVariant());
inferior.extraData.insert(Debugger::Constants::kUVisionProjectFilePath, projFilePath.toString());
inferior.extraData.insert(Debugger::Constants::kUVisionOptionsFilePath, optFilePath.toString());
inferior.extraData.insert(Debugger::Constants::kUVisionSimulator, isSimulator());

View File

@@ -497,6 +497,14 @@ DeviceSelection DeviceSelectionView::buildSelection(const DeviceSelectionItem *i
break;
}
} 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;
}

View File

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

View File

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

View File

@@ -691,6 +691,41 @@ bool UvscClient::inspectWatcher(const QStringList &expandedWatcherINames,
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)
{
if (!checkConnection())

View File

@@ -87,6 +87,9 @@ public:
bool fetchWatchers(const QStringList &expandedWatcherINames,
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 setRegisterValue(int index, const QString &value);

View File

@@ -32,6 +32,7 @@
#include <debugger/disassemblerlines.h>
#include <debugger/memoryagent.h>
#include <debugger/moduleshandler.h>
#include <debugger/peripheralregisterhandler.h>
#include <debugger/registerhandler.h>
#include <debugger/stackhandler.h>
#include <debugger/threadshandler.h>
@@ -162,6 +163,9 @@ void UvscEngine::setupEngine()
if (!configureProject(rp))
return;
// Reload peripheral register description.
peripheralRegisterHandler()->updateRegisterGroups();
}
void UvscEngine::runEngine()
@@ -231,6 +235,14 @@ void UvscEngine::setRegisterValue(const QString &name, const QString &value)
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)
{
notifyInferiorRunRequested();
@@ -332,6 +344,7 @@ void UvscEngine::activateFrame(int index)
gotoCurrentLocation();
updateLocals();
reloadRegisters();
reloadPeripheralRegisters();
}
bool UvscEngine::stateAcceptsBreakpointChanges() const
@@ -469,6 +482,17 @@ void UvscEngine::reloadRegisters()
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()
{
resetLocation();
@@ -496,6 +520,7 @@ void UvscEngine::updateAll()
handleThreadInfo();
reloadRegisters();
reloadPeripheralRegisters();
updateLocals();
}
@@ -653,6 +678,7 @@ void UvscEngine::handleReloadStack(bool isFull)
if (!m_client->fetchStackFrames(taskId, m_address, data)) {
m_address = 0;
reloadRegisters();
reloadPeripheralRegisters();
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)
{
m_inUpdateLocals = false;

View File

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

View File

@@ -110,6 +110,16 @@ QByteArray encodeAmem(quint64 address, quint32 bytesCount)
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 tval = {};
@@ -238,6 +248,24 @@ QString adjustHexValue(QString hex, const QString &type)
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)
{
return QString::number(varinfo.id);

View File

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