2021-10-02 17:39:27 +01:00
|
|
|
#include "TargetDescriptionFile.hpp"
|
|
|
|
|
|
2021-05-30 19:05:18 +01:00
|
|
|
#include <QJsonDocument>
|
|
|
|
|
#include <QJsonArray>
|
|
|
|
|
|
2022-12-26 21:47:09 +00:00
|
|
|
#include "src/Services/PathService.hpp"
|
2024-02-12 19:23:00 +00:00
|
|
|
#include "src/Services/StringService.hpp"
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-02-13 20:22:18 +00:00
|
|
|
#include "src/Targets/TargetMemory.hpp"
|
2024-03-09 01:49:04 +00:00
|
|
|
#include "src/Targets/TargetPinoutDescriptor.hpp"
|
2024-02-13 20:22:18 +00:00
|
|
|
#include "src/Helpers/BiMap.hpp"
|
|
|
|
|
#include "src/Logger/Logger.hpp"
|
|
|
|
|
|
|
|
|
|
#include "Exceptions/TargetDescriptionParsingFailureException.hpp"
|
2024-03-09 01:49:04 +00:00
|
|
|
#include "Exceptions/InvalidTargetDescriptionDataException.hpp"
|
2024-02-13 20:22:18 +00: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;
|
2024-02-13 20:48:06 +00:00
|
|
|
using namespace ::Exceptions;
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-02-12 19:23:00 +00:00
|
|
|
using Services::StringService;
|
|
|
|
|
|
2023-12-17 18:12:53 +00:00
|
|
|
TargetDescriptionFile::TargetDescriptionFile(const std::string& xmlFilePath) {
|
2023-12-12 23:19:21 +00:00
|
|
|
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 {
|
2023-12-17 18:12:53 +00:00
|
|
|
return this->deviceAttribute("name");
|
2023-03-05 23:30:42 +00:00
|
|
|
}
|
|
|
|
|
|
2023-12-13 00:50:10 +00:00
|
|
|
TargetFamily TargetDescriptionFile::getFamily() const {
|
2024-02-26 19:29:53 +00:00
|
|
|
const auto& family = this->deviceAttribute("family");
|
2023-12-13 00:50:10 +00:00
|
|
|
|
2024-02-26 19:29:53 +00:00
|
|
|
if (family == "AVR8") {
|
|
|
|
|
return TargetFamily::AVR_8;
|
|
|
|
|
}
|
2023-12-13 00:50:10 +00:00
|
|
|
|
2024-02-26 19:29:53 +00:00
|
|
|
if (family == "RISCV") {
|
|
|
|
|
return TargetFamily::RISC_V;
|
2023-12-13 00:50:10 +00:00
|
|
|
}
|
|
|
|
|
|
2024-02-26 19:29:53 +00:00
|
|
|
throw InvalidTargetDescriptionDataException("Failed to resolve target family - invalid family name");
|
2021-06-08 00:43:45 +01:00
|
|
|
}
|
|
|
|
|
|
2024-02-12 19:23:00 +00:00
|
|
|
std::optional<std::reference_wrapper<const PropertyGroup>> TargetDescriptionFile::tryGetPropertyGroup(
|
|
|
|
|
std::string_view keyStr
|
|
|
|
|
) const {
|
2024-02-13 20:24:52 +00:00
|
|
|
const auto keys = StringService::split(keyStr, '.');
|
2024-02-12 19:23:00 +00:00
|
|
|
|
2024-02-13 20:24:52 +00:00
|
|
|
const auto firstSubgroupIt = this->propertyGroupsByKey.find(*keys.begin());
|
|
|
|
|
return firstSubgroupIt != this->propertyGroupsByKey.end()
|
2024-02-12 19:23:00 +00:00
|
|
|
? keys.size() > 1
|
2024-02-12 19:39:21 +00:00
|
|
|
? firstSubgroupIt->second.tryGetSubgroup(keys | std::ranges::views::drop(1))
|
|
|
|
|
: std::optional(std::cref(firstSubgroupIt->second))
|
2024-02-12 19:23:00 +00:00
|
|
|
: std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const PropertyGroup& TargetDescriptionFile::getPropertyGroup(std::string_view keyStr) const {
|
|
|
|
|
const auto propertyGroup = this->tryGetPropertyGroup(keyStr);
|
|
|
|
|
|
|
|
|
|
if (!propertyGroup.has_value()) {
|
2024-02-26 19:28:18 +00:00
|
|
|
throw InvalidTargetDescriptionDataException(
|
2024-02-12 19:23:00 +00:00
|
|
|
"Failed to get property group \"" + std::string(keyStr) + "\" from TDF - property group not found"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return propertyGroup->get();
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-13 20:22:18 +00:00
|
|
|
std::optional<std::reference_wrapper<const AddressSpace>> TargetDescriptionFile::tryGetAddressSpace(
|
|
|
|
|
std::string_view key
|
|
|
|
|
) const {
|
|
|
|
|
const auto addressSpaceIt = this->addressSpacesByKey.find(key);
|
|
|
|
|
return addressSpaceIt != this->addressSpacesByKey.end()
|
|
|
|
|
? std::optional(std::cref(addressSpaceIt->second))
|
|
|
|
|
: std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-15 21:25:32 +00:00
|
|
|
const AddressSpace& TargetDescriptionFile::getAddressSpace(std::string_view key) const {
|
2024-02-13 20:22:18 +00:00
|
|
|
const auto addressSpace = this->tryGetAddressSpace(key);
|
|
|
|
|
|
|
|
|
|
if (!addressSpace.has_value()) {
|
2024-02-26 19:28:18 +00:00
|
|
|
throw InvalidTargetDescriptionDataException(
|
2024-02-13 20:22:18 +00:00
|
|
|
"Failed to get address space \"" + std::string(key) + "\" from TDF - address space not found"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return addressSpace->get();
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-15 21:24:41 +00:00
|
|
|
std::set<TargetPhysicalInterface> TargetDescriptionFile::getPhysicalInterfaces() const {
|
|
|
|
|
static const auto physicalInterfacesByName = BiMap<std::string, TargetPhysicalInterface>({
|
|
|
|
|
{"updi", TargetPhysicalInterface::UPDI},
|
|
|
|
|
{"debugwire", TargetPhysicalInterface::DEBUG_WIRE},
|
|
|
|
|
{"jtag", TargetPhysicalInterface::JTAG},
|
|
|
|
|
{"pdi", TargetPhysicalInterface::PDI},
|
|
|
|
|
{"isp", TargetPhysicalInterface::ISP},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
auto output = std::set<TargetPhysicalInterface>();
|
|
|
|
|
|
|
|
|
|
for (const auto& physicalInterface : this->physicalInterfaces) {
|
|
|
|
|
const auto interface = physicalInterfacesByName.valueAt(
|
|
|
|
|
StringService::asciiToLower(physicalInterface.name)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (interface.has_value()) {
|
|
|
|
|
output.insert(*interface);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return output;
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-26 19:27:36 +00:00
|
|
|
std::optional<std::reference_wrapper<const Module>> TargetDescriptionFile::tryGetModule(
|
|
|
|
|
std::string_view key
|
|
|
|
|
) const {
|
|
|
|
|
const auto moduleIt = this->modulesByKey.find(key);
|
|
|
|
|
return moduleIt != this->modulesByKey.end()
|
|
|
|
|
? std::optional(std::cref(moduleIt->second))
|
|
|
|
|
: std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Module& TargetDescriptionFile::getModule(std::string_view key) const {
|
|
|
|
|
const auto module = this->tryGetModule(key);
|
|
|
|
|
|
|
|
|
|
if (!module.has_value()) {
|
|
|
|
|
throw InvalidTargetDescriptionDataException(
|
|
|
|
|
"Failed to get module \"" + std::string(key) + "\" from TDF - module not found"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return module->get();
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-27 21:01:36 +00:00
|
|
|
std::optional<std::reference_wrapper<const Peripheral>> TargetDescriptionFile::tryGetPeripheral(
|
|
|
|
|
std::string_view key
|
|
|
|
|
) const {
|
|
|
|
|
const auto peripheralIt = this->peripheralsByKey.find(key);
|
|
|
|
|
return peripheralIt != this->peripheralsByKey.end()
|
|
|
|
|
? std::optional(std::cref(peripheralIt->second))
|
|
|
|
|
: std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Peripheral& TargetDescriptionFile::getPeripheral(std::string_view key) const {
|
|
|
|
|
const auto peripheral = this->tryGetPeripheral(key);
|
|
|
|
|
|
|
|
|
|
if (!peripheral.has_value()) {
|
|
|
|
|
throw InvalidTargetDescriptionDataException(
|
|
|
|
|
"Failed to get peripheral \"" + std::string(key) + "\" from TDF - peripheral not found"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return peripheral->get();
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-17 18:12:53 +00:00
|
|
|
void TargetDescriptionFile::init(const std::string& xmlFilePath) {
|
|
|
|
|
auto file = QFile(QString::fromStdString(xmlFilePath));
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!file.exists()) {
|
2024-03-09 01:56:43 +00:00
|
|
|
throw InternalFatalErrorException("Failed to load target description file - file not found");
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
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())) {
|
2024-03-09 01:56:43 +00:00
|
|
|
throw TargetDescriptionParsingFailureException();
|
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) {
|
2024-02-12 19:23:00 +00:00
|
|
|
const auto deviceElement = document.documentElement();
|
|
|
|
|
if (deviceElement.nodeName() != "device") {
|
|
|
|
|
throw TargetDescriptionParsingFailureException("Root \"device\" element not found.");
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-02-12 19:23:00 +00:00
|
|
|
const auto deviceAttributes = deviceElement.attributes();
|
2023-12-17 18:12:53 +00:00
|
|
|
for (auto i = 0; i < deviceAttributes.length(); ++i) {
|
|
|
|
|
const auto deviceAttribute = deviceAttributes.item(i);
|
|
|
|
|
this->deviceAttributesByName.insert(
|
|
|
|
|
std::pair(
|
|
|
|
|
deviceAttribute.nodeName().toStdString(),
|
|
|
|
|
deviceAttribute.nodeValue().toStdString()
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
}
|
2022-02-05 15:32:08 +00:00
|
|
|
|
2024-02-12 19:23:00 +00:00
|
|
|
for (
|
|
|
|
|
auto element = deviceElement.firstChildElement("property-groups").firstChildElement("property-group");
|
|
|
|
|
!element.isNull();
|
|
|
|
|
element = element.nextSiblingElement("property-group")
|
|
|
|
|
) {
|
|
|
|
|
auto propertyGroup = TargetDescriptionFile::propertyGroupFromXml(element);
|
2024-02-13 20:24:52 +00:00
|
|
|
this->propertyGroupsByKey.insert(
|
2024-02-12 19:23:00 +00:00
|
|
|
std::pair(propertyGroup.key, std::move(propertyGroup))
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-13 20:22:18 +00:00
|
|
|
for (
|
|
|
|
|
auto element = deviceElement.firstChildElement("address-spaces").firstChildElement("address-space");
|
|
|
|
|
!element.isNull();
|
|
|
|
|
element = element.nextSiblingElement("address-space")
|
|
|
|
|
) {
|
|
|
|
|
auto addressSpace = TargetDescriptionFile::addressSpaceFromXml(element);
|
|
|
|
|
this->addressSpacesByKey.insert(
|
|
|
|
|
std::pair(addressSpace.key, std::move(addressSpace))
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-15 19:40:22 +00:00
|
|
|
for (
|
|
|
|
|
auto element = deviceElement.firstChildElement("physical-interfaces")
|
|
|
|
|
.firstChildElement("physical-interface");
|
|
|
|
|
!element.isNull();
|
|
|
|
|
element = element.nextSiblingElement("physical-interface")
|
|
|
|
|
) {
|
|
|
|
|
this->physicalInterfaces.emplace_back(
|
|
|
|
|
TargetDescriptionFile::physicalInterfaceFromXml(element)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-26 19:27:36 +00:00
|
|
|
for (
|
|
|
|
|
auto element = deviceElement.firstChildElement("modules").firstChildElement("module");
|
|
|
|
|
!element.isNull();
|
|
|
|
|
element = element.nextSiblingElement("module")
|
|
|
|
|
) {
|
|
|
|
|
auto module = TargetDescriptionFile::moduleFromXml(element);
|
|
|
|
|
this->modulesByKey.insert(
|
|
|
|
|
std::pair(module.key, std::move(module))
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-27 21:01:36 +00:00
|
|
|
for (
|
|
|
|
|
auto element = deviceElement.firstChildElement("peripherals").firstChildElement("peripheral");
|
|
|
|
|
!element.isNull();
|
|
|
|
|
element = element.nextSiblingElement("peripheral")
|
|
|
|
|
) {
|
|
|
|
|
auto peripheral = TargetDescriptionFile::peripheralFromXml(element);
|
|
|
|
|
this->peripheralsByKey.insert(
|
|
|
|
|
std::pair(peripheral.key, std::move(peripheral))
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-09 01:49:04 +00:00
|
|
|
for (
|
|
|
|
|
auto element = deviceElement.firstChildElement("pinouts").firstChildElement("pinout");
|
|
|
|
|
!element.isNull();
|
|
|
|
|
element = element.nextSiblingElement("pinout")
|
|
|
|
|
) {
|
|
|
|
|
auto pinout = TargetDescriptionFile::pinoutFromXml(element);
|
|
|
|
|
this->pinoutsByKey.insert(
|
|
|
|
|
std::pair(pinout.key, std::move(pinout))
|
|
|
|
|
);
|
|
|
|
|
}
|
2024-03-09 15:40:05 +00:00
|
|
|
|
|
|
|
|
for (
|
|
|
|
|
auto element = deviceElement.firstChildElement("variants").firstChildElement("variant");
|
|
|
|
|
!element.isNull();
|
|
|
|
|
element = element.nextSiblingElement("variant")
|
|
|
|
|
) {
|
|
|
|
|
this->variants.emplace_back(TargetDescriptionFile::variantFromXml(element));
|
|
|
|
|
}
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
|
|
|
|
|
2024-02-27 21:27:41 +00:00
|
|
|
const std::string& TargetDescriptionFile::deviceAttribute(const std::string& attributeName) const {
|
|
|
|
|
const auto attributeIt = this->deviceAttributesByName.find(attributeName);
|
|
|
|
|
|
|
|
|
|
if (attributeIt == this->deviceAttributesByName.end()) {
|
2024-03-09 01:56:43 +00:00
|
|
|
throw InvalidTargetDescriptionDataException("Missing target device attribute (\"" + attributeName + "\")");
|
2024-02-27 21:27:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return attributeIt->second;
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-12 19:23:00 +00:00
|
|
|
std::optional<std::string> TargetDescriptionFile::tryGetAttribute(
|
|
|
|
|
const QDomElement& element,
|
|
|
|
|
const QString& attributeName
|
|
|
|
|
) {
|
|
|
|
|
return element.hasAttribute(attributeName)
|
|
|
|
|
? std::optional(element.attribute(attributeName).toStdString())
|
|
|
|
|
: std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string TargetDescriptionFile::getAttribute(const QDomElement& element, const QString& attributeName) {
|
|
|
|
|
const auto attribute = TargetDescriptionFile::tryGetAttribute(element, attributeName);
|
|
|
|
|
|
|
|
|
|
if (!attribute.has_value()) {
|
2024-03-09 01:56:43 +00:00
|
|
|
throw InvalidTargetDescriptionDataException(
|
2024-02-12 19:23:00 +00:00
|
|
|
"Failed to fetch attribute from TDF element \"" + element.nodeName().toStdString()
|
|
|
|
|
+ "\" - attribute \"" + attributeName.toStdString() + "\" not found"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return *attribute;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PropertyGroup TargetDescriptionFile::propertyGroupFromXml(const QDomElement& xmlElement) {
|
|
|
|
|
auto output = PropertyGroup(TargetDescriptionFile::getAttribute(xmlElement, "key"), {}, {});
|
|
|
|
|
|
|
|
|
|
for (
|
|
|
|
|
auto element = xmlElement.firstChildElement("property");
|
|
|
|
|
!element.isNull();
|
|
|
|
|
element = element.nextSiblingElement("property")
|
|
|
|
|
) {
|
|
|
|
|
auto property = TargetDescriptionFile::propertyFromXml(element);
|
2024-02-13 20:24:52 +00:00
|
|
|
output.propertiesByKey.insert(std::pair(property.key, std::move(property)));
|
2024-02-12 19:23:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (
|
|
|
|
|
auto element = xmlElement.firstChildElement("property-group");
|
|
|
|
|
!element.isNull();
|
|
|
|
|
element = element.nextSiblingElement("property-group")
|
|
|
|
|
) {
|
2024-02-12 19:39:21 +00:00
|
|
|
auto subgroup = TargetDescriptionFile::propertyGroupFromXml(element);
|
2024-02-25 16:41:57 +00:00
|
|
|
output.subgroupsByKey.insert(std::pair(subgroup.key, std::move(subgroup)));
|
2024-02-12 19:23:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return output;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Property TargetDescriptionFile::propertyFromXml(const QDomElement& xmlElement) {
|
|
|
|
|
return Property(
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "key"),
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "value")
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-26 19:29:53 +00:00
|
|
|
AddressSpace TargetDescriptionFile::addressSpaceFromXml(const QDomElement& xmlElement) {
|
2024-02-13 20:22:18 +00:00
|
|
|
static const auto endiannessByName = BiMap<std::string, TargetMemoryEndianness>({
|
|
|
|
|
{"big", TargetMemoryEndianness::BIG},
|
|
|
|
|
{"little", TargetMemoryEndianness::LITTLE},
|
|
|
|
|
});
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-02-13 20:22:18 +00:00
|
|
|
const auto endiannessName = TargetDescriptionFile::tryGetAttribute(xmlElement, "endianness");
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-02-13 20:22:18 +00:00
|
|
|
auto endianness = std::optional<TargetMemoryEndianness>();
|
|
|
|
|
if (endiannessName.has_value()) {
|
|
|
|
|
endianness = endiannessByName.valueAt(*endiannessName);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-02-13 20:22:18 +00:00
|
|
|
if (!endianness.has_value()) {
|
2024-03-09 01:56:43 +00:00
|
|
|
throw InvalidTargetDescriptionDataException(
|
2024-02-13 20:22:18 +00:00
|
|
|
"Failed to extract address space from TDF - invalid endianness name \"" + *endiannessName + "\""
|
2022-02-05 15:32:08 +00:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-02-13 20:22:18 +00:00
|
|
|
auto output = AddressSpace(
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "key"),
|
|
|
|
|
StringService::toUint32(TargetDescriptionFile::getAttribute(xmlElement, "start")),
|
|
|
|
|
StringService::toUint32(TargetDescriptionFile::getAttribute(xmlElement, "size")),
|
|
|
|
|
endianness,
|
|
|
|
|
{}
|
|
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-02-13 20:22:18 +00:00
|
|
|
for (
|
|
|
|
|
auto element = xmlElement.firstChildElement("memory-segment");
|
|
|
|
|
!element.isNull();
|
|
|
|
|
element = element.nextSiblingElement("memory-segment")
|
2022-02-05 15:32:08 +00:00
|
|
|
) {
|
2024-02-13 20:22:18 +00:00
|
|
|
auto section = TargetDescriptionFile::memorySegmentFromXml(element);
|
|
|
|
|
output.memorySegmentsByKey.insert(std::pair(section.key, std::move(section)));
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-02-13 20:22:18 +00:00
|
|
|
return output;
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-02-13 20:22:18 +00:00
|
|
|
MemorySegment TargetDescriptionFile::memorySegmentFromXml(const QDomElement& xmlElement) {
|
|
|
|
|
static const auto typesByName = BiMap<std::string, MemorySegmentType>({
|
|
|
|
|
{"aliased", MemorySegmentType::ALIASED},
|
|
|
|
|
{"regs", MemorySegmentType::REGISTERS},
|
|
|
|
|
{"eeprom", MemorySegmentType::EEPROM},
|
|
|
|
|
{"flash", MemorySegmentType::FLASH},
|
|
|
|
|
{"fuses", MemorySegmentType::FUSES},
|
|
|
|
|
{"io", MemorySegmentType::IO},
|
|
|
|
|
{"ram", MemorySegmentType::RAM},
|
|
|
|
|
{"lockbits", MemorySegmentType::LOCKBITS},
|
|
|
|
|
{"osccal", MemorySegmentType::OSCCAL},
|
|
|
|
|
{"production_signatures", MemorySegmentType::PRODUCTION_SIGNATURES},
|
|
|
|
|
{"signatures", MemorySegmentType::SIGNATURES},
|
|
|
|
|
{"user_signatures", MemorySegmentType::USER_SIGNATURES},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const auto typeName = TargetDescriptionFile::getAttribute(xmlElement, "type");
|
|
|
|
|
|
|
|
|
|
const auto type = typesByName.valueAt(typeName);
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!type.has_value()) {
|
2024-03-09 01:56:43 +00:00
|
|
|
throw InvalidTargetDescriptionDataException(
|
2024-02-13 20:22:18 +00:00
|
|
|
"Failed to extract memory segment from TDF - invalid memory segment type name \"" + typeName + "\""
|
|
|
|
|
);
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-02-13 20:22:18 +00:00
|
|
|
const auto pageSize = TargetDescriptionFile::tryGetAttribute(xmlElement, "page-size");
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-02-13 20:22:18 +00:00
|
|
|
auto output = MemorySegment(
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "key"),
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "name"),
|
|
|
|
|
*type,
|
|
|
|
|
StringService::toUint32(TargetDescriptionFile::getAttribute(xmlElement, "start")),
|
|
|
|
|
StringService::toUint32(TargetDescriptionFile::getAttribute(xmlElement, "size")),
|
|
|
|
|
pageSize.has_value()
|
|
|
|
|
? std::optional(StringService::toUint16(*pageSize))
|
|
|
|
|
: std::nullopt,
|
|
|
|
|
{}
|
|
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-02-13 20:22:18 +00:00
|
|
|
for (
|
|
|
|
|
auto element = xmlElement.firstChildElement("section");
|
|
|
|
|
!element.isNull();
|
|
|
|
|
element = element.nextSiblingElement("section")
|
|
|
|
|
) {
|
|
|
|
|
auto section = TargetDescriptionFile::memorySegmentSectionFromXml(element);
|
|
|
|
|
output.sectionsByKey.insert(std::pair(section.key, std::move(section)));
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-02-13 20:22:18 +00:00
|
|
|
return output;
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-02-13 20:22:18 +00:00
|
|
|
MemorySegmentSection TargetDescriptionFile::memorySegmentSectionFromXml(const QDomElement& xmlElement) {
|
|
|
|
|
auto output = MemorySegmentSection(
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "key"),
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "name"),
|
|
|
|
|
StringService::toUint32(TargetDescriptionFile::getAttribute(xmlElement, "start")),
|
|
|
|
|
StringService::toUint32(TargetDescriptionFile::getAttribute(xmlElement, "size")),
|
|
|
|
|
{}
|
|
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-02-13 20:22:18 +00:00
|
|
|
for (
|
|
|
|
|
auto element = xmlElement.firstChildElement("section");
|
|
|
|
|
!element.isNull();
|
|
|
|
|
element = element.nextSiblingElement("section")
|
|
|
|
|
) {
|
|
|
|
|
auto section = TargetDescriptionFile::memorySegmentSectionFromXml(element);
|
|
|
|
|
output.subSectionsByKey.insert(std::pair(section.key, std::move(section)));
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-02-13 20:22:18 +00:00
|
|
|
return output;
|
2021-08-27 23:51:21 +01:00
|
|
|
}
|
2021-08-07 17:15:48 +01:00
|
|
|
|
2024-02-15 19:40:22 +00:00
|
|
|
PhysicalInterface TargetDescriptionFile::physicalInterfaceFromXml(const QDomElement& xmlElement) {
|
|
|
|
|
return PhysicalInterface(
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "name"),
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "type")
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-26 19:27:36 +00:00
|
|
|
Module TargetDescriptionFile::moduleFromXml(const QDomElement& xmlElement) {
|
|
|
|
|
auto output = Module(
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "key"),
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "name"),
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "description"),
|
|
|
|
|
{}
|
|
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-02-26 19:27:36 +00:00
|
|
|
for (
|
|
|
|
|
auto element = xmlElement.firstChildElement("register-group");
|
|
|
|
|
!element.isNull();
|
|
|
|
|
element = element.nextSiblingElement("register-group")
|
|
|
|
|
) {
|
|
|
|
|
auto registerGroup = TargetDescriptionFile::registerGroupFromXml(element);
|
|
|
|
|
output.registerGroupsByKey.insert(std::pair(registerGroup.key, std::move(registerGroup)));
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-02-26 19:27:36 +00:00
|
|
|
return output;
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-02-26 19:27:36 +00:00
|
|
|
RegisterGroup TargetDescriptionFile::registerGroupFromXml(const QDomElement& xmlElement) {
|
|
|
|
|
const auto offset = TargetDescriptionFile::tryGetAttribute(xmlElement, "offset");
|
2021-08-07 17:15:48 +01:00
|
|
|
|
2024-02-26 19:27:36 +00:00
|
|
|
auto output = RegisterGroup(
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "key"),
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "name"),
|
|
|
|
|
offset.has_value() ? std::optional(StringService::toUint32(*offset)) : std::nullopt,
|
|
|
|
|
{},
|
|
|
|
|
{},
|
|
|
|
|
{}
|
|
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-02-26 19:27:36 +00:00
|
|
|
for (
|
|
|
|
|
auto element = xmlElement.firstChildElement("register");
|
|
|
|
|
!element.isNull();
|
|
|
|
|
element = element.nextSiblingElement("register")
|
2022-02-05 15:32:08 +00:00
|
|
|
) {
|
2024-02-26 19:27:36 +00:00
|
|
|
auto reg = TargetDescriptionFile::registerFromXml(element);
|
|
|
|
|
output.registersByKey.insert(std::pair(reg.key, std::move(reg)));
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-08-30 22:32:40 +01:00
|
|
|
|
2024-02-26 19:27:36 +00:00
|
|
|
for (
|
|
|
|
|
auto element = xmlElement.firstChildElement("register-group");
|
|
|
|
|
!element.isNull();
|
|
|
|
|
element = element.nextSiblingElement("register-group")
|
|
|
|
|
) {
|
|
|
|
|
auto registerGroup = TargetDescriptionFile::registerGroupFromXml(element);
|
|
|
|
|
output.subgroupsByKey.insert(std::pair(registerGroup.key, std::move(registerGroup)));
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-02-26 19:27:36 +00:00
|
|
|
for (
|
|
|
|
|
auto element = xmlElement.firstChildElement("register-group-reference");
|
|
|
|
|
!element.isNull();
|
|
|
|
|
element = element.nextSiblingElement("register-group-reference")
|
|
|
|
|
) {
|
|
|
|
|
auto registerGroupReference = TargetDescriptionFile::registerGroupReferenceFromXml(element);
|
|
|
|
|
output.subgroupReferencesByKey.insert(
|
|
|
|
|
std::pair(registerGroupReference.key, std::move(registerGroupReference))
|
|
|
|
|
);
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-02-26 19:27:36 +00:00
|
|
|
return output;
|
|
|
|
|
}
|
2021-06-06 20:06:43 +01:00
|
|
|
|
2024-02-26 19:27:36 +00:00
|
|
|
RegisterGroupReference TargetDescriptionFile::registerGroupReferenceFromXml(const QDomElement& xmlElement) {
|
|
|
|
|
return RegisterGroupReference(
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "key"),
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "name"),
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "register-group-key"),
|
|
|
|
|
StringService::toUint32(TargetDescriptionFile::getAttribute(xmlElement, "offset")),
|
|
|
|
|
TargetDescriptionFile::tryGetAttribute(xmlElement, "description")
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-06-06 20:06:43 +01:00
|
|
|
|
2024-02-26 19:27:36 +00:00
|
|
|
Register TargetDescriptionFile::registerFromXml(const QDomElement& xmlElement) {
|
|
|
|
|
const auto initialValue = TargetDescriptionFile::tryGetAttribute(xmlElement, "initial-value");
|
|
|
|
|
const auto alternative = TargetDescriptionFile::tryGetAttribute(xmlElement, "alternative");
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-02-26 19:27:36 +00:00
|
|
|
auto output = Register(
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "key"),
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "name"),
|
|
|
|
|
TargetDescriptionFile::tryGetAttribute(xmlElement, "description"),
|
|
|
|
|
StringService::toUint32(TargetDescriptionFile::getAttribute(xmlElement, "offset")),
|
|
|
|
|
StringService::toUint16(TargetDescriptionFile::getAttribute(xmlElement, "size")),
|
|
|
|
|
initialValue.has_value() ? std::optional(StringService::toUint64(*initialValue)) : std::nullopt,
|
|
|
|
|
TargetDescriptionFile::tryGetAttribute(xmlElement, "access"),
|
|
|
|
|
alternative.has_value() ? std::optional(*alternative == "true") : std::nullopt,
|
|
|
|
|
{}
|
|
|
|
|
);
|
2022-03-04 15:33:31 +00:00
|
|
|
|
2024-02-26 19:27:36 +00:00
|
|
|
for (
|
|
|
|
|
auto element = xmlElement.firstChildElement("bit-field");
|
|
|
|
|
!element.isNull();
|
|
|
|
|
element = element.nextSiblingElement("bit-field")
|
|
|
|
|
) {
|
|
|
|
|
auto bitField = TargetDescriptionFile::bitFieldFromXml(element);
|
|
|
|
|
output.bitFieldsByKey.insert(std::pair(bitField.key, std::move(bitField)));
|
2022-03-04 15:33:31 +00:00
|
|
|
}
|
|
|
|
|
|
2024-02-26 19:27:36 +00:00
|
|
|
return output;
|
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) {
|
2024-02-26 19:27:36 +00:00
|
|
|
return BitField(
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "key"),
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "name"),
|
|
|
|
|
TargetDescriptionFile::tryGetAttribute(xmlElement, "description"),
|
|
|
|
|
StringService::toUint64(TargetDescriptionFile::getAttribute(xmlElement, "mask")),
|
|
|
|
|
TargetDescriptionFile::tryGetAttribute(xmlElement, "access")
|
2022-03-04 15:33:31 +00:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-27 21:01:36 +00:00
|
|
|
Peripheral TargetDescriptionFile::peripheralFromXml(const QDomElement& xmlElement) {
|
|
|
|
|
const auto offset = TargetDescriptionFile::tryGetAttribute(xmlElement, "offset");
|
|
|
|
|
|
|
|
|
|
auto output = Peripheral(
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "key"),
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "name"),
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "module-key"),
|
|
|
|
|
{},
|
|
|
|
|
{}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
for (
|
|
|
|
|
auto element = xmlElement.firstChildElement("register-group-instance");
|
|
|
|
|
!element.isNull();
|
|
|
|
|
element = element.nextSiblingElement("register-group-instance")
|
|
|
|
|
) {
|
|
|
|
|
auto registerGroupInstance = TargetDescriptionFile::registerGroupInstanceFromXml(element);
|
|
|
|
|
output.registerGroupInstancesByKey.insert(
|
|
|
|
|
std::pair(registerGroupInstance.key, std::move(registerGroupInstance))
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (
|
|
|
|
|
auto element = xmlElement.firstChildElement("signals").firstChildElement("signal");
|
|
|
|
|
!element.isNull();
|
|
|
|
|
element = element.nextSiblingElement("signal")
|
|
|
|
|
) {
|
|
|
|
|
output.sigs.emplace_back(TargetDescriptionFile::signalFromXml(element));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return output;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RegisterGroupInstance TargetDescriptionFile::registerGroupInstanceFromXml(const QDomElement& xmlElement) {
|
|
|
|
|
return RegisterGroupInstance(
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "key"),
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "name"),
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "register-group-key"),
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "address-space-key"),
|
|
|
|
|
StringService::toUint32(TargetDescriptionFile::getAttribute(xmlElement, "offset")),
|
|
|
|
|
TargetDescriptionFile::tryGetAttribute(xmlElement, "description")
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Signal TargetDescriptionFile::signalFromXml(const QDomElement& xmlElement) {
|
|
|
|
|
const auto index = TargetDescriptionFile::tryGetAttribute(xmlElement, "index");
|
|
|
|
|
|
|
|
|
|
return Signal(
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "pad-id"),
|
|
|
|
|
index.has_value() ? std::optional(StringService::toUint64(*index)) : std::nullopt,
|
|
|
|
|
TargetDescriptionFile::tryGetAttribute(xmlElement, "function"),
|
|
|
|
|
TargetDescriptionFile::tryGetAttribute(xmlElement, "group"),
|
|
|
|
|
TargetDescriptionFile::tryGetAttribute(xmlElement, "field")
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-09 01:49:04 +00:00
|
|
|
Pinout TargetDescriptionFile::pinoutFromXml(const QDomElement& xmlElement) {
|
|
|
|
|
static const auto typesByName = BiMap<std::string, PinoutType>({
|
|
|
|
|
{"soic", PinoutType::SOIC},
|
|
|
|
|
{"ssop", PinoutType::SSOP},
|
|
|
|
|
{"dip", PinoutType::DIP},
|
|
|
|
|
{"qfn", PinoutType::QFN},
|
|
|
|
|
{"mlf", PinoutType::MLF},
|
|
|
|
|
{"drqfn", PinoutType::DUAL_ROW_QFN},
|
|
|
|
|
{"qfp", PinoutType::QFP},
|
|
|
|
|
{"bga", PinoutType::BGA},
|
|
|
|
|
});
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-03-09 01:49:04 +00:00
|
|
|
const auto typeName = TargetDescriptionFile::getAttribute(xmlElement, "type");
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-03-09 01:49:04 +00:00
|
|
|
const auto type = typesByName.valueAt(typeName);
|
|
|
|
|
if (!type.has_value()) {
|
|
|
|
|
throw InvalidTargetDescriptionDataException(
|
|
|
|
|
"Failed to extract pinout from TDF - invalid pinout type name \"" + typeName + "\""
|
|
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2024-03-09 01:49:04 +00:00
|
|
|
auto output = Pinout(
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "key"),
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "name"),
|
|
|
|
|
*type,
|
|
|
|
|
TargetDescriptionFile::tryGetAttribute(xmlElement, "function"),
|
|
|
|
|
{}
|
|
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-03-09 01:49:04 +00:00
|
|
|
for (
|
|
|
|
|
auto element = xmlElement.firstChildElement("pin");
|
|
|
|
|
!element.isNull();
|
|
|
|
|
element = element.nextSiblingElement("pin")
|
|
|
|
|
) {
|
2024-03-09 15:20:55 +00:00
|
|
|
output.pins.emplace_back(TargetDescriptionFile::pinFromXml(element));
|
2024-03-09 01:49:04 +00:00
|
|
|
}
|
2021-06-06 20:06:43 +01:00
|
|
|
|
2024-03-09 01:49:04 +00:00
|
|
|
return output;
|
|
|
|
|
}
|
2021-06-06 20:06:43 +01:00
|
|
|
|
2024-03-09 01:49:04 +00:00
|
|
|
Pin TargetDescriptionFile::pinFromXml(const QDomElement& xmlElement) {
|
|
|
|
|
return Pin(
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "position"),
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "pad")
|
|
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
2024-03-09 15:40:05 +00:00
|
|
|
|
|
|
|
|
Variant TargetDescriptionFile::variantFromXml(const QDomElement& xmlElement) {
|
|
|
|
|
return Variant(
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "name"),
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "pinout-key"),
|
|
|
|
|
TargetDescriptionFile::getAttribute(xmlElement, "package")
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-06-26 03:47:23 +01:00
|
|
|
}
|