Debugger: Improve parsing of SVD file

The previous implementation was done in a hurry and a bit
overcomplicated for maintenance.

Now it is simplified and a common code moved to a separate functions.

Change-Id: I86e9131e08154ec24bb7778c3a7d4c3d6b042751
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Denis Shienkov
2020-01-30 17:07:48 +03:00
parent c50e928e76
commit d5fd6a83d8

View File

@@ -52,6 +52,8 @@ constexpr char kBitRange[] = "bitRange";
constexpr char kBitWidth[] = "bitWidth"; constexpr char kBitWidth[] = "bitWidth";
constexpr char kDerivedFrom[] = "derivedFrom"; constexpr char kDerivedFrom[] = "derivedFrom";
constexpr char kDescription[] = "description"; constexpr char kDescription[] = "description";
constexpr char kDevice[] = "device";
constexpr char kDisplayName[] = "displayName";
constexpr char kField[] = "field"; constexpr char kField[] = "field";
constexpr char kFields[] = "fields"; constexpr char kFields[] = "fields";
constexpr char kGroupName[] = "groupName"; constexpr char kGroupName[] = "groupName";
@@ -559,135 +561,141 @@ PeripheralRegisterHandler::PeripheralRegisterHandler(DebuggerEngine *engine)
setHeader({tr("Name"), tr("Value"), tr("Access")}); setHeader({tr("Name"), tr("Value"), tr("Access")});
} }
static PeripheralRegisterGroups availablePeripheralRegisterGroups( static void handleField(QXmlStreamReader &in, PeripheralRegister &reg)
const QString &filePath) {
PeripheralRegisterField fld;
while (in.readNextStartElement()) {
const auto elementName = in.name();
if (elementName == kName) {
fld.name = in.readElementText();
} else if (elementName == kDescription) {
fld.description = in.readElementText();
} else if (elementName == kAccess) {
fld.access = decodeAccess(in.readElementText());
} else if (elementName == 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 == kBitOffset) {
fld.bitOffset = int(decodeNumeric(in.readElementText()));
} else if (elementName == kBitWidth) {
fld.bitWidth = int(decodeNumeric(in.readElementText()));
} else {
in.skipCurrentElement();
}
}
reg.fields.push_back(fld);
}
static void handleRegister(QXmlStreamReader &in, PeripheralRegisterGroup &group)
{
PeripheralRegister reg;
while (in.readNextStartElement()) {
const auto elementName = in.name();
if (elementName == kName) {
reg.name = in.readElementText();
} else if (elementName == kDisplayName) {
reg.displayName = in.readElementText();
} else if (elementName == kDescription) {
reg.description = in.readElementText();
} else if (elementName == kAddressOffset) {
reg.addressOffset = decodeNumeric(in.readElementText());
} else if (elementName == kSize) {
reg.size = int(decodeNumeric(in.readElementText()));
} else if (elementName == kAccess) {
reg.access = decodeAccess(in.readElementText());
} else if (elementName == kResetvalue) {
reg.resetValue = decodeNumeric(in.readElementText());
} else if (elementName == kFields) {
while (in.readNextStartElement()) {
const auto elementName = in.name();
if (elementName == kField)
handleField(in, reg);
else
in.skipCurrentElement();
}
} else {
in.skipCurrentElement();
}
}
group.registers.push_back(reg);
}
static void handleGroup(QXmlStreamReader &in, PeripheralRegisterGroups &groups)
{
PeripheralRegisterGroup group;
const auto fromGroupName = in.attributes().value(kDerivedFrom);
if (!fromGroupName.isEmpty()) {
const auto groupEnd = groups.cend();
const auto groupIt = std::find_if(groups.cbegin(), groupEnd,
[fromGroupName](const PeripheralRegisterGroup &group) {
return fromGroupName == group.name;
});
if (groupIt != groupEnd)
group = *groupIt;
}
while (in.readNextStartElement()) {
const auto elementName = in.name();
if (elementName == kName) {
group.name = in.readElementText();
} else if (elementName == kDescription) {
group.description = in.readElementText();
} else if (elementName == kGroupName) {
group.displayName = in.readElementText();
} else if (elementName == kBaseAddress) {
group.baseAddress = decodeNumeric(in.readElementText());
} else if (elementName == kSize) {
group.size = int(decodeNumeric(in.readElementText()));
} else if (elementName == kAccess) {
group.access = decodeAccess(in.readElementText());
} else if (elementName == kRegisters) {
while (in.readNextStartElement()) {
const auto elementName = in.name();
if (elementName == kRegister)
handleRegister(in, group);
else
in.skipCurrentElement();
}
} else {
in.skipCurrentElement();
}
}
groups.push_back(group);
}
static PeripheralRegisterGroups availablePeripheralRegisterGroups(const QString &filePath)
{ {
QFile f(filePath); QFile f(filePath);
if (!f.open(QIODevice::ReadOnly)) if (!f.open(QIODevice::ReadOnly))
return {}; return {};
QXmlStreamReader in(&f); QXmlStreamReader in(&f);
PeripheralRegisterGroups groups;
PeripheralRegisterGroups foundGroups; while (in.readNextStartElement()) {
const auto elementName = in.name();
while (!in.atEnd()) { if (elementName == kDevice) {
const auto token = in.readNext(); while (in.readNextStartElement()) {
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(); const auto elementName = in.name();
if (elementName == QLatin1String(kName)) { if (elementName == kPeripherals) {
group.name = in.readElementText(); while (in.readNextStartElement()) {
} else if (elementName == QLatin1String(kDescription)) { const auto elementName = in.name();
group.description = in.readElementText(); if (elementName == kPeripheral)
} else if (elementName == QLatin1String(kGroupName)) { handleGroup(in, groups);
group.displayName = in.readElementText(); else
} else if (elementName == QLatin1String(kBaseAddress)) { in.skipCurrentElement();
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 { } else {
in.skipCurrentElement(); in.skipCurrentElement();
@@ -695,8 +703,7 @@ static PeripheralRegisterGroups availablePeripheralRegisterGroups(
} }
} }
} }
return groups;
return foundGroups;
} }
void PeripheralRegisterHandler::updateRegisterGroups() void PeripheralRegisterHandler::updateRegisterGroups()