2021-10-02 17:39:27 +01:00
|
|
|
#include "TargetDescriptionFile.hpp"
|
|
|
|
|
|
2021-05-30 19:05:18 +01:00
|
|
|
#include <QJsonDocument>
|
|
|
|
|
#include <QJsonArray>
|
|
|
|
|
|
2021-05-31 01:01:14 +01:00
|
|
|
#include "Exceptions/TargetDescriptionParsingFailureException.hpp"
|
2021-04-04 21:04:12 +01:00
|
|
|
#include "src/Logger/Logger.hpp"
|
2022-12-26 21:47:09 +00:00
|
|
|
#include "src/Services/PathService.hpp"
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2023-08-13 15:47:51 +01:00
|
|
|
namespace Targets::TargetDescription
|
2022-02-05 15:32:08 +00:00
|
|
|
{
|
2023-08-13 15:47:51 +01:00
|
|
|
using namespace Exceptions;
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2023-12-12 23:19:21 +00:00
|
|
|
const std::map<std::string, GeneratedMapping::BriefTargetDescriptor>& TargetDescriptionFile::mapping() {
|
|
|
|
|
return GeneratedMapping::map;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TargetDescriptionFile::TargetDescriptionFile(const QString& xmlFilePath) {
|
|
|
|
|
this->init(xmlFilePath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TargetDescriptionFile::TargetDescriptionFile(const QDomDocument& xml) {
|
|
|
|
|
this->init(xml);
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-05 23:30:42 +00:00
|
|
|
const std::string& TargetDescriptionFile::getTargetName() const {
|
|
|
|
|
return this->targetName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const std::string& TargetDescriptionFile::getFamilyName() const {
|
|
|
|
|
return this->familyName;
|
2021-06-08 00:43:45 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void TargetDescriptionFile::init(const QString& xmlFilePath) {
|
|
|
|
|
auto file = QFile(xmlFilePath);
|
|
|
|
|
if (!file.exists()) {
|
|
|
|
|
// This can happen if someone has been messing with the Resources directory.
|
|
|
|
|
throw Exception("Failed to load target description file - file not found");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
file.open(QIODevice::ReadOnly);
|
2023-03-05 23:30:42 +00:00
|
|
|
auto document = QDomDocument();
|
|
|
|
|
if (!document.setContent(file.readAll())) {
|
2022-02-05 15:32:08 +00:00
|
|
|
throw Exception("Failed to parse target description file - please report this error "
|
2022-12-26 21:47:09 +00:00
|
|
|
"to Bloom developers via " + Services::PathService::homeDomainName() + "/report-issue");
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2023-03-05 23:30:42 +00:00
|
|
|
this->init(document);
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2023-03-05 23:30:42 +00:00
|
|
|
void TargetDescriptionFile::init(const QDomDocument& document) {
|
|
|
|
|
const auto device = document.elementsByTagName("device").item(0).toElement();
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!device.isElement()) {
|
|
|
|
|
throw TargetDescriptionParsingFailureException("Device element not found.");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2023-03-05 23:30:42 +00:00
|
|
|
this->targetName = device.attributes().namedItem("name").nodeValue().toStdString();
|
|
|
|
|
this->familyName = device.attributes().namedItem("family").nodeValue().toLower().toStdString();
|
2022-02-05 15:32:08 +00:00
|
|
|
|
2023-03-05 23:30:42 +00:00
|
|
|
this->loadAddressSpaces(document);
|
|
|
|
|
this->loadPropertyGroups(document);
|
|
|
|
|
this->loadModules(document);
|
|
|
|
|
this->loadPeripheralModules(document);
|
|
|
|
|
this->loadVariants(document);
|
|
|
|
|
this->loadPinouts(document);
|
|
|
|
|
this->loadInterfaces(document);
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
|
|
|
|
|
2023-12-10 13:04:05 +00:00
|
|
|
AddressSpace TargetDescriptionFile::addressSpaceFromXml(const QDomElement& xmlElement) {
|
2022-02-05 15:32:08 +00:00
|
|
|
if (
|
|
|
|
|
!xmlElement.hasAttribute("id")
|
|
|
|
|
|| !xmlElement.hasAttribute("name")
|
|
|
|
|
|| !xmlElement.hasAttribute("size")
|
|
|
|
|
|| !xmlElement.hasAttribute("start")
|
|
|
|
|
) {
|
|
|
|
|
throw Exception("Address space element missing id/name/size/start attributes.");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
auto addressSpace = AddressSpace();
|
|
|
|
|
addressSpace.name = xmlElement.attribute("name").toStdString();
|
|
|
|
|
addressSpace.id = xmlElement.attribute("id").toStdString();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
bool conversionStatus;
|
|
|
|
|
addressSpace.startAddress = xmlElement.attribute("start").toUInt(&conversionStatus, 16);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!conversionStatus) {
|
|
|
|
|
throw Exception("Failed to convert start address hex value to integer.");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
addressSpace.size = xmlElement.attribute("size").toUInt(&conversionStatus, 16);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!conversionStatus) {
|
|
|
|
|
throw Exception("Failed to convert size hex value to integer.");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (xmlElement.hasAttribute("endianness")) {
|
|
|
|
|
addressSpace.littleEndian = (xmlElement.attribute("endianness").toStdString() == "little");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
// Create memory segment objects and add them to the mapping.
|
|
|
|
|
auto segmentNodes = xmlElement.elementsByTagName("memory-segment");
|
|
|
|
|
auto& memorySegments = addressSpace.memorySegmentsByTypeAndName;
|
|
|
|
|
for (int segmentIndex = 0; segmentIndex < segmentNodes.count(); segmentIndex++) {
|
|
|
|
|
try {
|
2023-12-10 13:04:05 +00:00
|
|
|
auto segment = TargetDescriptionFile::memorySegmentFromXml(
|
2022-02-05 15:32:08 +00:00
|
|
|
segmentNodes.item(segmentIndex).toElement()
|
|
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!memorySegments.contains(segment.type)) {
|
|
|
|
|
memorySegments.insert(
|
|
|
|
|
std::pair<
|
|
|
|
|
MemorySegmentType,
|
|
|
|
|
decltype(addressSpace.memorySegmentsByTypeAndName)::mapped_type
|
|
|
|
|
>(segment.type, {}));
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
memorySegments.find(segment.type)->second.insert(std::pair(segment.name, segment));
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
} catch (const Exception& exception) {
|
|
|
|
|
Logger::debug("Failed to extract memory segment from target description element - "
|
|
|
|
|
+ exception.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
return addressSpace;
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2023-12-10 13:04:05 +00:00
|
|
|
MemorySegment TargetDescriptionFile::memorySegmentFromXml(const QDomElement& xmlElement) {
|
2022-02-05 15:32:08 +00:00
|
|
|
if (
|
|
|
|
|
!xmlElement.hasAttribute("type")
|
|
|
|
|
|| !xmlElement.hasAttribute("name")
|
|
|
|
|
|| !xmlElement.hasAttribute("size")
|
|
|
|
|
|| !xmlElement.hasAttribute("start")
|
|
|
|
|
) {
|
|
|
|
|
throw Exception("Missing type/name/size/start attributes");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
auto segment = MemorySegment();
|
|
|
|
|
auto typeName = xmlElement.attribute("type").toStdString();
|
|
|
|
|
auto type = MemorySegment::typesMappedByName.valueAt(typeName);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!type.has_value()) {
|
|
|
|
|
throw Exception("Unknown type: \"" + typeName + "\"");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
segment.type = type.value();
|
|
|
|
|
segment.name = xmlElement.attribute("name").toLower().toStdString();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
bool conversionStatus = false;
|
|
|
|
|
segment.startAddress = xmlElement.attribute("start").toUInt(&conversionStatus, 16);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!conversionStatus) {
|
|
|
|
|
// Failed to convert startAddress hex value as string to uint16_t
|
|
|
|
|
throw Exception("Invalid start address");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
segment.size = xmlElement.attribute("size").toUInt(&conversionStatus, 16);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
|
|
|
|
if (!conversionStatus) {
|
|
|
|
|
// Failed to convert size hex value as string to uint16_t
|
|
|
|
|
throw Exception("Invalid size");
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (xmlElement.hasAttribute("pagesize")) {
|
|
|
|
|
// The page size can be in single byte hexadecimal form ("0x01"), or it can be in plain integer form!
|
|
|
|
|
auto pageSize = xmlElement.attribute("pagesize");
|
|
|
|
|
segment.pageSize = pageSize.toUInt(&conversionStatus, pageSize.contains("0x") ? 16 : 10);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!conversionStatus) {
|
|
|
|
|
// Failed to convert size hex value as string to uint16_t
|
|
|
|
|
throw Exception("Invalid size");
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
return segment;
|
2021-08-27 23:51:21 +01:00
|
|
|
}
|
2021-08-07 17:15:48 +01:00
|
|
|
|
2023-12-10 13:04:05 +00:00
|
|
|
RegisterGroup TargetDescriptionFile::registerGroupFromXml(const QDomElement& xmlElement) {
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!xmlElement.hasAttribute("name")) {
|
|
|
|
|
throw Exception("Missing register group name attribute");
|
|
|
|
|
}
|
2021-08-30 22:31:44 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
auto registerGroup = RegisterGroup();
|
|
|
|
|
registerGroup.name = xmlElement.attribute("name").toLower().toStdString();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (registerGroup.name.empty()) {
|
|
|
|
|
throw Exception("Empty register group name");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (xmlElement.hasAttribute("name-in-module")) {
|
|
|
|
|
registerGroup.moduleName = xmlElement.attribute("name-in-module").toLower().toStdString();
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (xmlElement.hasAttribute("address-space")) {
|
|
|
|
|
registerGroup.addressSpaceId = xmlElement.attribute("address-space").toLower().toStdString();
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (xmlElement.hasAttribute("offset")) {
|
|
|
|
|
registerGroup.offset = xmlElement.attribute("offset").toInt(nullptr, 16);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
auto& registers = registerGroup.registersMappedByName;
|
|
|
|
|
auto registerNodes = xmlElement.elementsByTagName("register");
|
|
|
|
|
for (int registerIndex = 0; registerIndex < registerNodes.count(); registerIndex++) {
|
|
|
|
|
try {
|
2023-12-10 13:04:05 +00:00
|
|
|
auto reg = TargetDescriptionFile::registerFromXml(
|
2022-02-05 15:32:08 +00:00
|
|
|
registerNodes.item(registerIndex).toElement()
|
|
|
|
|
);
|
|
|
|
|
registers.insert(std::pair(reg.name, reg));
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
} catch (const Exception& exception) {
|
|
|
|
|
Logger::debug("Failed to extract register from register group target description element - "
|
|
|
|
|
+ exception.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-08-07 17:15:48 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
return registerGroup;
|
2021-08-07 17:15:48 +01:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2023-12-10 13:04:05 +00:00
|
|
|
Register TargetDescriptionFile::registerFromXml(const QDomElement& xmlElement) {
|
2022-02-05 15:32:08 +00:00
|
|
|
if (
|
|
|
|
|
!xmlElement.hasAttribute("name")
|
|
|
|
|
|| !xmlElement.hasAttribute("offset")
|
|
|
|
|
|| !xmlElement.hasAttribute("size")
|
|
|
|
|
) {
|
|
|
|
|
throw Exception("Missing register name/offset/size attribute");
|
|
|
|
|
}
|
2021-08-30 22:32:40 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
auto reg = Register();
|
|
|
|
|
reg.name = xmlElement.attribute("name").toLower().toStdString();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (reg.name.empty()) {
|
|
|
|
|
throw Exception("Empty register name");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (xmlElement.hasAttribute("caption")) {
|
|
|
|
|
reg.caption = xmlElement.attribute("caption").toStdString();
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (xmlElement.hasAttribute("ocd-rw")) {
|
|
|
|
|
reg.readWriteAccess = xmlElement.attribute("ocd-rw").toLower().toStdString();
|
2021-06-06 20:06:43 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
} else if (xmlElement.hasAttribute("rw")) {
|
|
|
|
|
reg.readWriteAccess = xmlElement.attribute("rw").toLower().toStdString();
|
|
|
|
|
}
|
2021-06-06 20:06:43 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
bool conversionStatus = false;
|
|
|
|
|
reg.size = xmlElement.attribute("size").toUShort(nullptr, 10);
|
|
|
|
|
reg.offset = xmlElement.attribute("offset").toUShort(&conversionStatus, 16);
|
2021-06-06 20:06:43 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!conversionStatus) {
|
|
|
|
|
// Failed to convert offset hex value as string to uint16_t
|
|
|
|
|
throw Exception("Invalid register offset");
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-03-04 15:33:31 +00:00
|
|
|
auto& bitFields = reg.bitFieldsMappedByName;
|
|
|
|
|
auto bitFieldNodes = xmlElement.elementsByTagName("bitfield");
|
|
|
|
|
for (int bitFieldIndex = 0; bitFieldIndex < bitFieldNodes.count(); bitFieldIndex++) {
|
|
|
|
|
try {
|
2023-12-10 13:04:05 +00:00
|
|
|
auto bitField = TargetDescriptionFile::bitFieldFromXml(
|
2022-03-04 15:33:31 +00:00
|
|
|
bitFieldNodes.item(bitFieldIndex).toElement()
|
|
|
|
|
);
|
|
|
|
|
bitFields.insert(std::pair(bitField.name, bitField));
|
|
|
|
|
|
|
|
|
|
} catch (const Exception& exception) {
|
|
|
|
|
Logger::debug("Failed to extract bit field from register target description element - "
|
|
|
|
|
+ exception.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
return reg;
|
2021-06-06 20:06:43 +01:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2023-12-10 13:04:05 +00:00
|
|
|
BitField TargetDescriptionFile::bitFieldFromXml(const QDomElement& xmlElement) {
|
2022-03-04 15:33:31 +00:00
|
|
|
if (!xmlElement.hasAttribute("name") || !xmlElement.hasAttribute("mask")) {
|
|
|
|
|
throw Exception("Missing bit field name/mask attribute");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto bitField = BitField();
|
|
|
|
|
bitField.name = xmlElement.attribute("name").toLower().toStdString();
|
|
|
|
|
|
|
|
|
|
auto maskConversion = false;
|
|
|
|
|
bitField.mask = static_cast<std::uint8_t>(
|
|
|
|
|
xmlElement.attribute("mask").toUShort(&maskConversion, 16)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (!maskConversion) {
|
|
|
|
|
throw Exception("Failed to convert bit field mask to integer (from hex string)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bitField.name.empty()) {
|
|
|
|
|
throw Exception("Empty bit field name");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return bitField;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-05 23:30:42 +00:00
|
|
|
void TargetDescriptionFile::loadAddressSpaces(const QDomDocument& document) {
|
|
|
|
|
const auto deviceElement = document.elementsByTagName("device").item(0).toElement();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2023-03-05 23:30:42 +00:00
|
|
|
auto addressSpaceNodes = deviceElement.elementsByTagName("address-spaces").item(0).toElement()
|
2022-02-05 15:32:08 +00:00
|
|
|
.elementsByTagName("address-space");
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
for (int addressSpaceIndex = 0; addressSpaceIndex < addressSpaceNodes.count(); addressSpaceIndex++) {
|
|
|
|
|
try {
|
2023-12-10 13:04:05 +00:00
|
|
|
auto addressSpace = TargetDescriptionFile::addressSpaceFromXml(
|
2022-02-05 15:32:08 +00:00
|
|
|
addressSpaceNodes.item(addressSpaceIndex).toElement()
|
|
|
|
|
);
|
|
|
|
|
this->addressSpacesMappedById.insert(std::pair(addressSpace.id, addressSpace));
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
} catch (const Exception& exception) {
|
|
|
|
|
Logger::debug(
|
|
|
|
|
"Failed to extract address space from target description element - "
|
|
|
|
|
+ exception.getMessage()
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2023-03-05 23:30:42 +00:00
|
|
|
void TargetDescriptionFile::loadPropertyGroups(const QDomDocument& document) {
|
|
|
|
|
const auto deviceElement = document.elementsByTagName("device").item(0).toElement();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2023-03-05 23:30:42 +00:00
|
|
|
auto propertyGroupNodes = deviceElement.elementsByTagName("property-groups").item(0).toElement()
|
2022-02-05 15:32:08 +00:00
|
|
|
.elementsByTagName("property-group");
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
for (int propertyGroupIndex = 0; propertyGroupIndex < propertyGroupNodes.count(); propertyGroupIndex++) {
|
|
|
|
|
auto propertyGroupElement = propertyGroupNodes.item(propertyGroupIndex).toElement();
|
|
|
|
|
auto propertyGroupName = propertyGroupElement.attributes().namedItem(
|
|
|
|
|
"name"
|
|
|
|
|
).nodeValue().toLower().toStdString();
|
|
|
|
|
PropertyGroup propertyGroup;
|
|
|
|
|
propertyGroup.name = propertyGroupName;
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
auto propertyNodes = propertyGroupElement.elementsByTagName("property");
|
|
|
|
|
for (int propertyIndex = 0; propertyIndex < propertyNodes.count(); propertyIndex++) {
|
|
|
|
|
auto propertyElement = propertyNodes.item(propertyIndex).toElement();
|
|
|
|
|
auto propertyName = propertyElement.attributes().namedItem("name").nodeValue();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
Property property;
|
|
|
|
|
property.name = propertyName.toStdString();
|
|
|
|
|
property.value = propertyElement.attributes().namedItem("value").nodeValue();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
propertyGroup.propertiesMappedByName.insert(
|
|
|
|
|
std::pair(propertyName.toLower().toStdString(), property)
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->propertyGroupsMappedByName.insert(std::pair(propertyGroup.name, propertyGroup));
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2023-03-05 23:30:42 +00:00
|
|
|
void TargetDescriptionFile::loadModules(const QDomDocument& document) {
|
|
|
|
|
const auto deviceElement = document.elementsByTagName("device").item(0).toElement();
|
|
|
|
|
|
|
|
|
|
auto moduleNodes = document.elementsByTagName("modules").item(0).toElement()
|
2022-02-05 15:32:08 +00:00
|
|
|
.elementsByTagName("module");
|
2021-06-06 20:06:43 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
for (int moduleIndex = 0; moduleIndex < moduleNodes.count(); moduleIndex++) {
|
|
|
|
|
auto moduleElement = moduleNodes.item(moduleIndex).toElement();
|
|
|
|
|
auto moduleName = moduleElement.attributes().namedItem("name").nodeValue().toLower().toStdString();
|
|
|
|
|
Module module;
|
|
|
|
|
module.name = moduleName;
|
2021-06-06 20:06:43 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
auto registerGroupNodes = moduleElement.elementsByTagName("register-group");
|
|
|
|
|
for (int registerGroupIndex = 0; registerGroupIndex < registerGroupNodes.count(); registerGroupIndex++) {
|
2023-12-10 13:04:05 +00:00
|
|
|
auto registerGroup = TargetDescriptionFile::registerGroupFromXml(
|
2022-02-05 15:32:08 +00:00
|
|
|
registerGroupNodes.item(registerGroupIndex).toElement()
|
|
|
|
|
);
|
2021-08-27 23:51:21 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
module.registerGroupsMappedByName.insert(std::pair(registerGroup.name, registerGroup));
|
2021-08-27 23:51:21 +01:00
|
|
|
}
|
2022-02-05 15:32:08 +00:00
|
|
|
|
|
|
|
|
this->modulesMappedByName.insert(std::pair(module.name, module));
|
2021-06-06 20:06:43 +01:00
|
|
|
}
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
|
|
|
|
|
2023-03-05 23:30:42 +00:00
|
|
|
void TargetDescriptionFile::loadPeripheralModules(const QDomDocument& document) {
|
|
|
|
|
const auto deviceElement = document.elementsByTagName("device").item(0).toElement();
|
|
|
|
|
|
|
|
|
|
auto moduleNodes = deviceElement.elementsByTagName("peripherals").item(0).toElement()
|
2022-02-05 15:32:08 +00:00
|
|
|
.elementsByTagName("module");
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
for (int moduleIndex = 0; moduleIndex < moduleNodes.count(); moduleIndex++) {
|
|
|
|
|
auto moduleElement = moduleNodes.item(moduleIndex).toElement();
|
|
|
|
|
auto moduleName = moduleElement.attributes().namedItem("name").nodeValue().toLower().toStdString();
|
|
|
|
|
Module module;
|
|
|
|
|
module.name = moduleName;
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
auto registerGroupNodes = moduleElement.elementsByTagName("register-group");
|
2021-04-04 21:04:12 +01:00
|
|
|
for (int registerGroupIndex = 0; registerGroupIndex < registerGroupNodes.count(); registerGroupIndex++) {
|
2023-12-10 13:04:05 +00:00
|
|
|
auto registerGroup = TargetDescriptionFile::registerGroupFromXml(
|
2021-06-06 19:14:36 +01:00
|
|
|
registerGroupNodes.item(registerGroupIndex).toElement()
|
|
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
module.registerGroupsMappedByName.insert(std::pair(registerGroup.name, registerGroup));
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (registerGroup.moduleName.has_value()) {
|
|
|
|
|
this->peripheralRegisterGroupsMappedByModuleRegisterGroupName[registerGroup.moduleName.value()]
|
|
|
|
|
.emplace_back(registerGroup);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
auto instanceNodes = moduleElement.elementsByTagName("instance");
|
|
|
|
|
for (int instanceIndex = 0; instanceIndex < instanceNodes.count(); instanceIndex++) {
|
|
|
|
|
auto instanceXml = instanceNodes.item(instanceIndex).toElement();
|
|
|
|
|
auto instance = ModuleInstance();
|
|
|
|
|
instance.name = instanceXml.attribute("name").toLower().toStdString();
|
|
|
|
|
|
|
|
|
|
auto registerGroupNodes = instanceXml.elementsByTagName("register-group");
|
|
|
|
|
for (
|
|
|
|
|
int registerGroupIndex = 0;
|
|
|
|
|
registerGroupIndex < registerGroupNodes.count();
|
|
|
|
|
registerGroupIndex++
|
|
|
|
|
) {
|
2023-12-10 13:04:05 +00:00
|
|
|
auto registerGroup = TargetDescriptionFile::registerGroupFromXml(
|
2022-02-05 15:32:08 +00:00
|
|
|
registerGroupNodes.item(registerGroupIndex).toElement()
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
instance.registerGroupsMappedByName.insert(std::pair(registerGroup.name, registerGroup));
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
auto signalNodes = instanceXml.elementsByTagName("signals").item(0).toElement()
|
|
|
|
|
.elementsByTagName("signal");
|
|
|
|
|
for (int signalIndex = 0; signalIndex < signalNodes.count(); signalIndex++) {
|
|
|
|
|
auto signalXml = signalNodes.item(signalIndex).toElement();
|
|
|
|
|
auto signal = Signal();
|
|
|
|
|
|
|
|
|
|
if (!signalXml.hasAttribute("pad")) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
signal.padName = signalXml.attribute("pad").toLower().toStdString();
|
|
|
|
|
signal.function = signalXml.attribute("function").toStdString();
|
|
|
|
|
signal.group = signalXml.attribute("group").toStdString();
|
|
|
|
|
auto indexAttribute = signalXml.attribute("index");
|
|
|
|
|
bool indexValid = false;
|
|
|
|
|
auto indexValue = indexAttribute.toInt(&indexValid, 10);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!indexAttribute.isEmpty() && indexValid) {
|
|
|
|
|
signal.index = indexValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
instance.instanceSignals.emplace_back(signal);
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
module.instancesMappedByName.insert(std::pair(instance.name, instance));
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->peripheralModulesMappedByName.insert(std::pair(module.name, module));
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-05 23:30:42 +00:00
|
|
|
void TargetDescriptionFile::loadVariants(const QDomDocument& document) {
|
|
|
|
|
const auto deviceElement = document.elementsByTagName("device").item(0).toElement();
|
|
|
|
|
|
|
|
|
|
auto variantNodes = document.elementsByTagName("variants").item(0).toElement()
|
2022-02-05 15:32:08 +00:00
|
|
|
.elementsByTagName("variant");
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
for (int variantIndex = 0; variantIndex < variantNodes.count(); variantIndex++) {
|
|
|
|
|
try {
|
|
|
|
|
auto variantXml = variantNodes.item(variantIndex).toElement();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!variantXml.hasAttribute("ordercode")) {
|
|
|
|
|
throw Exception("Missing ordercode attribute");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!variantXml.hasAttribute("package")) {
|
|
|
|
|
throw Exception("Missing package attribute");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!variantXml.hasAttribute("pinout")) {
|
|
|
|
|
throw Exception("Missing pinout attribute");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
auto variant = Variant();
|
|
|
|
|
variant.name = variantXml.attribute("ordercode").toStdString();
|
|
|
|
|
variant.pinoutName = variantXml.attribute("pinout").toLower().toStdString();
|
|
|
|
|
variant.package = variantXml.attribute("package").toUpper().toStdString();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (variantXml.hasAttribute("disabled")) {
|
|
|
|
|
variant.disabled = (variantXml.attribute("disabled") == "1");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->variants.push_back(variant);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
} catch (const Exception& exception) {
|
|
|
|
|
Logger::debug(
|
|
|
|
|
"Failed to extract variant from target description element - " + exception.getMessage()
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-05 23:30:42 +00:00
|
|
|
void TargetDescriptionFile::loadPinouts(const QDomDocument& document) {
|
|
|
|
|
const auto deviceElement = document.elementsByTagName("device").item(0).toElement();
|
|
|
|
|
|
|
|
|
|
auto pinoutNodes = document.elementsByTagName("pinouts").item(0).toElement()
|
2022-02-05 15:32:08 +00:00
|
|
|
.elementsByTagName("pinout");
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
for (int pinoutIndex = 0; pinoutIndex < pinoutNodes.count(); pinoutIndex++) {
|
|
|
|
|
try {
|
|
|
|
|
auto pinoutXml = pinoutNodes.item(pinoutIndex).toElement();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!pinoutXml.hasAttribute("name")) {
|
|
|
|
|
throw Exception("Missing name attribute");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
auto pinout = Pinout();
|
|
|
|
|
pinout.name = pinoutXml.attribute("name").toLower().toStdString();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
auto pinNodes = pinoutXml.elementsByTagName("pin");
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
for (int pinIndex = 0; pinIndex < pinNodes.count(); pinIndex++) {
|
|
|
|
|
auto pinXml = pinNodes.item(pinIndex).toElement();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!pinXml.hasAttribute("position")) {
|
|
|
|
|
throw Exception(
|
|
|
|
|
"Missing position attribute on pin element " + std::to_string(pinIndex)
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!pinXml.hasAttribute("pad")) {
|
|
|
|
|
throw Exception("Missing pad attribute on pin element " + std::to_string(pinIndex));
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
auto pin = Pin();
|
|
|
|
|
bool positionConversionSucceeded = true;
|
|
|
|
|
pin.position = pinXml.attribute("position").toInt(&positionConversionSucceeded, 10);
|
|
|
|
|
pin.pad = pinXml.attribute("pad").toLower().toStdString();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!positionConversionSucceeded) {
|
|
|
|
|
throw Exception("Failed to convert position attribute value to integer on pin element "
|
|
|
|
|
+ std::to_string(pinIndex));
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
pinout.pins.push_back(pin);
|
|
|
|
|
}
|
2021-06-06 20:06:43 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->pinoutsMappedByName.insert(std::pair(pinout.name, pinout));
|
2021-06-06 20:06:43 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
} catch (const Exception& exception) {
|
|
|
|
|
Logger::debug(
|
|
|
|
|
"Failed to extract pinout from target description element - " + exception.getMessage()
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
}
|
2021-06-26 03:47:23 +01:00
|
|
|
|
2023-03-05 23:30:42 +00:00
|
|
|
void TargetDescriptionFile::loadInterfaces(const QDomDocument& document) {
|
|
|
|
|
const auto deviceElement = document.elementsByTagName("device").item(0).toElement();
|
|
|
|
|
|
|
|
|
|
auto interfaceNodes = deviceElement.elementsByTagName("interfaces").item(0).toElement()
|
2022-02-05 15:32:08 +00:00
|
|
|
.elementsByTagName("interface");
|
2021-06-26 03:47:23 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
for (int interfaceIndex = 0; interfaceIndex < interfaceNodes.count(); interfaceIndex++) {
|
|
|
|
|
try {
|
|
|
|
|
auto interfaceXml = interfaceNodes.item(interfaceIndex).toElement();
|
2021-06-26 03:47:23 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!interfaceXml.hasAttribute("name")) {
|
|
|
|
|
throw Exception("Missing name attribute");
|
|
|
|
|
}
|
2021-06-26 03:47:23 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
auto interface = Interface();
|
|
|
|
|
interface.name = interfaceXml.attribute("name").toLower().toStdString();
|
2021-06-26 03:47:23 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (interfaceXml.hasAttribute("type")) {
|
|
|
|
|
interface.type = interfaceXml.attribute("type").toStdString();
|
|
|
|
|
}
|
2021-06-26 03:47:23 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->interfacesByName.insert(std::pair(interface.name, interface));
|
2021-06-26 03:47:23 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
} catch (const Exception& exception) {
|
|
|
|
|
Logger::debug(
|
|
|
|
|
"Failed to extract interface from target description element - " + exception.getMessage()
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-06-26 03:47:23 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|