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())
|
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());
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
@@ -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())
|
||||||
|
@@ -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);
|
||||||
|
@@ -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;
|
||||||
|
@@ -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);
|
||||||
|
@@ -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);
|
||||||
|
@@ -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);
|
||||||
|
Reference in New Issue
Block a user