- Refactored AVR8 constructor, moving TDF construction to the TargetControllerComponent

- The `TargetControllerComponent` now resolves the target via the new generated mapping approach
- Added `TargetDescriptionFile` derived class
- Removed obsolete JSON map processing code
- Other bits of refactoring and tidying
This commit is contained in:
Nav
2023-12-17 18:12:53 +00:00
parent 866cdbdcc5
commit 66cbd89051
14 changed files with 161 additions and 119 deletions

View File

@@ -51,6 +51,15 @@ namespace Services
return PathService::projectDirPath() + "/.bloom";
}
/**
* Returns the path to the directory containing Bloom's target description files.
*
* @return
*/
static std::string targetDescriptionDirPath() {
return PathService::resourcesDirPath() + "/TargetDescriptionFiles";
}
/**
* Returns the path to the current project's settings file.
*

View File

@@ -4,8 +4,12 @@
#include <typeindex>
#include <algorithm>
#include "src/Targets/Microchip/AVR/AVR8/TargetDescription/TargetDescriptionFile.hpp"
#include "src/Targets/RiscV/TargetDescription/TargetDescriptionFile.hpp"
#include "Responses/Error.hpp"
#include "src/Services/PathService.hpp"
#include "src/Services/ProcessService.hpp"
#include "src/Services/StringService.hpp"
#include "src/Logger/Logger.hpp"
@@ -371,32 +375,30 @@ namespace TargetController
};
}
std::map<
std::string,
std::function<std::unique_ptr<Targets::Target>(const TargetConfig&)>
> TargetControllerComponent::getSupportedTargets() {
using Avr8TargetDescriptionFile = Targets::Microchip::Avr::Avr8Bit::TargetDescription::TargetDescriptionFile;
std::unique_ptr<Targets::Target> TargetControllerComponent::constructTargetFromBrief(
const TargetDescription::GeneratedMapping::BriefTargetDescriptor &targetBrief
) {
using Services::PathService;
auto mapping = std::map<std::string, std::function<std::unique_ptr<Targets::Target>(const TargetConfig&)>>();
// Include all targets from AVR8 target description files
const auto avr8PdMapping = Avr8TargetDescriptionFile::getTargetDescriptionMapping();
for (auto mapIt = avr8PdMapping.begin(); mapIt != avr8PdMapping.end(); ++mapIt) {
const auto mappingObject = mapIt.value().toObject();
const auto targetName = mappingObject.find("name").value().toString().toLower().toStdString();
if (!mapping.contains(targetName)) {
mapping.insert({
targetName,
[targetName] (const TargetConfig& targetConfig) {
return std::make_unique<Targets::Microchip::Avr::Avr8Bit::Avr8>(targetConfig);
}
});
}
if (targetBrief.targetFamily == TargetFamily::AVR_8) {
return std::make_unique<Microchip::Avr::Avr8Bit::Avr8>(
this->environmentConfig.targetConfig,
Microchip::Avr::Avr8Bit::TargetDescription::TargetDescriptionFile(
PathService::targetDescriptionDirPath() + "/" + targetBrief.relativeTdfPath
)
);
}
return mapping;
if (targetBrief.targetFamily == TargetFamily::RISC_V) {
return std::make_unique<RiscV::RiscV>(
this->environmentConfig.targetConfig,
RiscV::TargetDescription::TargetDescriptionFile(
PathService::targetDescriptionDirPath() + "/" + targetBrief.relativeTdfPath
)
);
}
throw Exception("Cannot construct target instance - invalid target family in BriefTargetDescriptor");
}
void TargetControllerComponent::processQueuedCommands() {
@@ -468,10 +470,10 @@ namespace TargetController
const auto& targetName = this->environmentConfig.targetConfig.name;
static const auto supportedDebugTools = this->getSupportedDebugTools();
static const auto supportedTargets = this->getSupportedTargets();
static const auto targetsByConfigValue = TargetDescription::TargetDescriptionFile::mapping();
const auto debugToolIt = supportedDebugTools.find(debugToolName);
const auto targetIt = supportedTargets.find(targetName);
const auto targetBriefIt = targetsByConfigValue.find(targetName);
if (debugToolIt == supportedDebugTools.end()) {
throw Exceptions::InvalidConfig(
@@ -479,7 +481,7 @@ namespace TargetController
);
}
if (targetIt == supportedTargets.end()) {
if (targetBriefIt == targetsByConfigValue.end()) {
throw Exceptions::InvalidConfig(
"Target name (\"" + targetName + "\") not recognised. Please check your configuration!"
);
@@ -495,7 +497,7 @@ namespace TargetController
Logger::info("Debug tool serial: " + this->debugTool->getSerialNumber());
Logger::info("Debug tool firmware version: " + this->debugTool->getFirmwareVersionString());
this->target = targetIt->second(this->environmentConfig.targetConfig);
this->target = this->constructTargetFromBrief(targetBriefIt->second);
const auto& targetDescriptor = this->getTargetDescriptor();
if (!this->target->supportsDebugTool(this->debugTool.get())) {

View File

@@ -246,12 +246,14 @@ namespace TargetController
std::map<std::string, std::function<std::unique_ptr<DebugTool>()>> getSupportedDebugTools();
/**
* Constructs a mapping of supported target names to lambdas. The lambdas should instantiate and return an
* instance to the appropriate Target class.
* Constructs a Target instance from a BriefTargetDescriptor object.
*
* @param targetBrief
* @return
*/
std::map<std::string, std::function<std::unique_ptr<Targets::Target>(const TargetConfig&)>> getSupportedTargets();
std::unique_ptr<Targets::Target> constructTargetFromBrief(
const Targets::TargetDescription::GeneratedMapping::BriefTargetDescriptor& targetBrief
);
/**
* Processes any pending commands in the queue.

View File

@@ -10,4 +10,5 @@ target_sources(
${CMAKE_CURRENT_SOURCE_DIR}/Microchip/AVR/AVR8/TargetDescription/TargetDescriptionFile.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Microchip/AVR/AVR8/OpcodeDecoder/Decoder.cpp
${CMAKE_CURRENT_SOURCE_DIR}/RiscV/RiscV.cpp
${CMAKE_CURRENT_SOURCE_DIR}/RiscV/TargetDescription/TargetDescriptionFile.cpp
)

View File

@@ -18,9 +18,9 @@ namespace Targets::Microchip::Avr::Avr8Bit
{
using namespace Exceptions;
Avr8::Avr8(const TargetConfig& targetConfig)
Avr8::Avr8(const TargetConfig& targetConfig, TargetDescription::TargetDescriptionFile&& targetDescriptionFile)
: targetConfig(Avr8TargetConfig(targetConfig))
, targetDescriptionFile(TargetDescription::TargetDescriptionFile(this->targetConfig.name))
, targetDescriptionFile(std::move(targetDescriptionFile))
, signature(this->targetDescriptionFile.getTargetSignature())
, name(this->targetDescriptionFile.getTargetName())
, family(this->targetDescriptionFile.getAvrFamily())

View File

@@ -30,7 +30,10 @@ namespace Targets::Microchip::Avr::Avr8Bit
class Avr8: public Target
{
public:
explicit Avr8(const TargetConfig& targetConfig);
explicit Avr8(
const TargetConfig& targetConfig,
TargetDescription::TargetDescriptionFile&& targetDescriptionFile
);
/*
* The functions below implement the Target interface for AVR8 targets.

View File

@@ -1,9 +1,5 @@
#include "TargetDescriptionFile.hpp"
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include "src/Services/PathService.hpp"
#include "src/Logger/Logger.hpp"
@@ -22,54 +18,15 @@ namespace Targets::Microchip::Avr::Avr8Bit::TargetDescription
using Targets::TargetVariant;
using Targets::TargetRegisterDescriptor;
TargetDescriptionFile::TargetDescriptionFile(const std::string& targetName) {
const auto mapping = TargetDescriptionFile::getTargetDescriptionMapping();
const auto descriptionFileObjectIt = mapping.find(QString::fromStdString(targetName).toLower());
if (descriptionFileObjectIt == mapping.end()) {
throw Exception(
"Failed to resolve target description file for target \"" + targetName + "\" - unknown target name."
);
}
const auto descriptionFileObject = descriptionFileObjectIt.value().toObject();
const auto descriptionFilePath = QString::fromStdString(
Services::PathService::resourcesDirPath()) + "/" + descriptionFileObject.find("tdfPath")->toString();
Logger::debug("Loading AVR8 target description file: " + descriptionFilePath.toStdString());
Targets::TargetDescription::TargetDescriptionFile::init(descriptionFilePath);
}
void TargetDescriptionFile::init(const QDomDocument& document) {
Targets::TargetDescription::TargetDescriptionFile::init(document);
const auto device = document.elementsByTagName("device").item(0).toElement();
if (!device.isElement()) {
throw TargetDescriptionParsingFailureException("Device element not found.");
}
this->avrFamilyName = device.attributes().namedItem("avr-family").nodeValue().toLower().toStdString();
TargetDescriptionFile::TargetDescriptionFile(const std::string& xmlFilePath)
: Targets::TargetDescription::TargetDescriptionFile(xmlFilePath)
{
this->loadSupportedPhysicalInterfaces();
this->loadPadDescriptors();
this->loadTargetVariants();
this->loadTargetRegisterDescriptors();
}
QJsonObject TargetDescriptionFile::getTargetDescriptionMapping() {
auto mappingFile = QFile(
QString::fromStdString(Services::PathService::resourcesDirPath() + "/TargetDescriptionFiles/AVR/Mapping.json")
);
if (!mappingFile.exists()) {
throw Exception("Failed to load AVR target description mapping - mapping file not found");
}
mappingFile.open(QIODevice::ReadOnly);
return QJsonDocument::fromJson(mappingFile.readAll()).object();
}
TargetSignature TargetDescriptionFile::getTargetSignature() const {
const auto& propertyGroups = this->propertyGroupsMappedByName;
@@ -110,11 +67,9 @@ namespace Targets::Microchip::Avr::Avr8Bit::TargetDescription
Family TargetDescriptionFile::getAvrFamily() const {
static const auto targetFamiliesByName = TargetDescriptionFile::getFamilyNameToEnumMapping();
if (this->avrFamilyName.empty()) {
throw Exception("Could not find target family name in target description file.");
}
const auto familyIt = targetFamiliesByName.find(this->avrFamilyName);
const auto familyIt = targetFamiliesByName.find(
QString::fromStdString(this->deviceAttribute("avr-family")).toLower().toStdString()
);
if (familyIt == targetFamiliesByName.end()) {
throw Exception("Unknown family name in target description file.");

View File

@@ -33,27 +33,13 @@ namespace Targets::Microchip::Avr::Avr8Bit::TargetDescription
class TargetDescriptionFile: public Targets::TargetDescription::TargetDescriptionFile
{
public:
/**
* Will resolve the target description file using the target description JSON mapping and a given target name.
*
* @param targetName
*/
TargetDescriptionFile(const std::string& targetName);
/**
* Extends TDF initialisation to include the loading of physical interfaces for debugging AVR8 targets, among
* other things.
*
* @param xml
*/
void init(const QDomDocument& document) override;
/**
* Loads the AVR8 target description JSON mapping file.
*
* @return
*/
static QJsonObject getTargetDescriptionMapping();
explicit TargetDescriptionFile(const std::string& xmlFilePath);
/**
* Extracts the AVR8 target signature from the TDF.

View File

@@ -27,8 +27,11 @@ namespace Targets::RiscV
using DebugModule::Registers::AbstractControlStatusRegister;
using DebugModule::Registers::AbstractCommandRegister;
RiscV::RiscV(const TargetConfig& targetConfig)
: name("CH32X035C8T6") // TODO: TDF
RiscV::RiscV(
const TargetConfig& targetConfig,
TargetDescription::TargetDescriptionFile&& targetDescriptionFile
)
: targetDescriptionFile(targetDescriptionFile)
, stackPointerRegisterDescriptor(
RiscVRegisterDescriptor(
TargetRegisterType::STACK_POINTER,
@@ -107,10 +110,10 @@ namespace Targets::RiscV
TargetDescriptor RiscV::getDescriptor() {
return TargetDescriptor(
"TDF ID",
this->targetDescriptionFile.getTargetId(),
TargetFamily::RISC_V,
this->name,
"TDF VENDOR NAME",
this->targetDescriptionFile.getTargetName(),
this->targetDescriptionFile.getVendorName(),
{
{
Targets::TargetMemoryType::FLASH,

View File

@@ -7,6 +7,8 @@
#include "src/Targets/Target.hpp"
#include "src/DebugToolDrivers/DebugTool.hpp"
#include "TargetDescription/TargetDescriptionFile.hpp"
#include "src/DebugToolDrivers/TargetInterfaces/RiscV/RiscVDebugInterface.hpp"
#include "src/DebugToolDrivers/TargetInterfaces/RiscV/RiscVProgramInterface.hpp"
@@ -27,7 +29,10 @@ namespace Targets::RiscV
class RiscV: public Target
{
public:
explicit RiscV(const TargetConfig& targetConfig);
explicit RiscV(
const TargetConfig& targetConfig,
TargetDescription::TargetDescriptionFile&& targetDescriptionFile
);
/*
* The functions below implement the Target interface for RISC-V targets.
@@ -99,7 +104,8 @@ namespace Targets::RiscV
bool programmingModeEnabled() override;
protected:
std::string name;
TargetDescription::TargetDescriptionFile targetDescriptionFile;
std::map<TargetRegisterDescriptorId, RiscVRegisterDescriptor> registerDescriptorsById;
RiscVRegisterDescriptor stackPointerRegisterDescriptor;

View File

@@ -0,0 +1,18 @@
#include "TargetDescriptionFile.hpp"
#include <QString>
namespace Targets::RiscV::TargetDescription
{
TargetDescriptionFile::TargetDescriptionFile(const std::string& xmlFilePath)
: Targets::TargetDescription::TargetDescriptionFile(xmlFilePath)
{}
std::string TargetDescriptionFile::getTargetId() const {
return this->deviceAttribute("id");
}
std::string TargetDescriptionFile::getVendorName() const {
return this->deviceAttribute("vendor");
}
}

View File

@@ -0,0 +1,33 @@
#pragma once
#include "src/Targets/TargetDescription/TargetDescriptionFile.hpp"
#include "src/Targets/RiscV/RiscVGeneric.hpp"
namespace Targets::RiscV::TargetDescription
{
/**
* Represents an RISC-V TDF.
*
* For more information of TDFs, see src/Targets/TargetDescription/README.md
*/
class TargetDescriptionFile: public Targets::TargetDescription::TargetDescriptionFile
{
public:
explicit TargetDescriptionFile(const std::string& xmlFilePath);
/**
* Returns the RISC-V target ID from the TDF.
*
* @return
*/
[[nodiscard]] std::string getTargetId() const;
/**
* Returns the RISC-V vendor name from the TDF.
*
* @return
*/
[[nodiscard]] std::string getVendorName() const;
};
}

View File

@@ -15,7 +15,7 @@ namespace Targets::TargetDescription
return GeneratedMapping::map;
}
TargetDescriptionFile::TargetDescriptionFile(const QString& xmlFilePath) {
TargetDescriptionFile::TargetDescriptionFile(const std::string& xmlFilePath) {
this->init(xmlFilePath);
}
@@ -24,7 +24,7 @@ namespace Targets::TargetDescription
}
const std::string& TargetDescriptionFile::getTargetName() const {
return this->targetName;
return this->deviceAttribute("name");
}
TargetFamily TargetDescriptionFile::getFamily() const {
@@ -33,7 +33,7 @@ namespace Targets::TargetDescription
{"RISCV", TargetFamily::RISC_V},
};
const auto familyIt = familiesByName.find(this->familyName);
const auto familyIt = familiesByName.find(this->deviceAttribute("family"));
if (familyIt == familiesByName.end()) {
throw Exception("Failed to resolve target family - invalid family name");
@@ -42,8 +42,8 @@ namespace Targets::TargetDescription
return familyIt->second;
}
void TargetDescriptionFile::init(const QString& xmlFilePath) {
auto file = QFile(xmlFilePath);
void TargetDescriptionFile::init(const std::string& xmlFilePath) {
auto file = QFile(QString::fromStdString(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");
@@ -65,8 +65,16 @@ namespace Targets::TargetDescription
throw TargetDescriptionParsingFailureException("Device element not found.");
}
this->targetName = device.attributes().namedItem("name").nodeValue().toStdString();
this->familyName = device.attributes().namedItem("family").nodeValue().toLower().toStdString();
const auto deviceAttributes = device.attributes();
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()
)
);
}
this->loadAddressSpaces(document);
this->loadPropertyGroups(document);
@@ -306,6 +314,16 @@ namespace Targets::TargetDescription
return bitField;
}
const std::string& TargetDescriptionFile::deviceAttribute(const std::string& attributeName) const {
const auto attributeIt = this->deviceAttributesByName.find(attributeName);
if (attributeIt == this->deviceAttributesByName.end()) {
throw Exception("Missing target device attribute (\"" + attributeName + "\")");
}
return attributeIt->second;
}
void TargetDescriptionFile::loadAddressSpaces(const QDomDocument& document) {
const auto deviceElement = document.elementsByTagName("device").item(0).toElement();

View File

@@ -59,7 +59,7 @@ namespace Targets::TargetDescription
*
* @param xmlFilePath
*/
explicit TargetDescriptionFile(const QString& xmlFilePath);
explicit TargetDescriptionFile(const std::string& xmlFilePath);
/**
* Will construct a TargetDescriptionFile instance from pre-loaded XML.
@@ -83,9 +83,7 @@ namespace Targets::TargetDescription
[[nodiscard]] TargetFamily getFamily() const;
protected:
std::string targetName;
std::string familyName;
std::map<std::string, std::string> deviceAttributesByName;
std::map<std::string, AddressSpace> addressSpacesMappedById;
std::map<std::string, PropertyGroup> propertyGroupsMappedByName;
std::map<std::string, Module> modulesMappedByName;
@@ -104,8 +102,8 @@ namespace Targets::TargetDescription
TargetDescriptionFile& operator = (const TargetDescriptionFile& other) = default;
TargetDescriptionFile& operator = (TargetDescriptionFile&& other) = default;
virtual void init(const QDomDocument& document);
void init(const QString& xmlFilePath);
void init(const std::string& xmlFilePath);
void init(const QDomDocument& document);
/**
* Constructs an AddressSpace object from an XML element.
@@ -147,6 +145,14 @@ namespace Targets::TargetDescription
*/
static BitField bitFieldFromXml(const QDomElement& xmlElement);
/**
* Fetches a device attribute value by name. Throws an exception if the attribute is not found.
*
* @param attributeName
* @return
*/
const std::string& deviceAttribute(const std::string& attributeName) const;
/**
* Extracts all address spaces and loads them into this->addressSpacesMappedById.
*/