forked from qt-creator/qt-creator
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:
@@ -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());
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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())
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user