2024-03-25 19:21:36 +00:00
|
|
|
#include "TargetDescriptionFile.hpp"
|
|
|
|
|
|
|
|
|
|
#include "src/Services/PathService.hpp"
|
|
|
|
|
#include "src/Logger/Logger.hpp"
|
|
|
|
|
|
|
|
|
|
#include "src/Exceptions/Exception.hpp"
|
|
|
|
|
#include "src/Targets/TargetDescription/Exceptions/TargetDescriptionParsingFailureException.hpp"
|
|
|
|
|
|
|
|
|
|
namespace Targets::Microchip::Avr::Avr8Bit
|
|
|
|
|
{
|
|
|
|
|
using namespace Exceptions;
|
|
|
|
|
|
|
|
|
|
using Targets::TargetDescription::RegisterGroup;
|
|
|
|
|
using Targets::TargetDescription::AddressSpace;
|
|
|
|
|
using Targets::TargetDescription::MemorySegment;
|
|
|
|
|
using Targets::TargetDescription::Register;
|
|
|
|
|
using Targets::TargetVariant;
|
|
|
|
|
using Targets::TargetRegisterDescriptor;
|
|
|
|
|
using Services::StringService;
|
|
|
|
|
|
|
|
|
|
TargetDescriptionFile::TargetDescriptionFile(const std::string& xmlFilePath)
|
|
|
|
|
: Targets::TargetDescription::TargetDescriptionFile(xmlFilePath)
|
|
|
|
|
{
|
|
|
|
|
this->loadPadDescriptors();
|
|
|
|
|
this->loadTargetVariants();
|
|
|
|
|
this->loadTargetRegisterDescriptors();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TargetSignature TargetDescriptionFile::getTargetSignature() const {
|
|
|
|
|
const auto& signatureGroup = this->getPropertyGroup("signatures");
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
static_cast<unsigned char>(std::stoul(signatureGroup.getProperty("signature0").value, nullptr, 16)),
|
|
|
|
|
static_cast<unsigned char>(std::stoul(signatureGroup.getProperty("signature1").value, nullptr, 16)),
|
|
|
|
|
static_cast<unsigned char>(std::stoul(signatureGroup.getProperty("signature2").value, nullptr, 16))
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Family TargetDescriptionFile::getAvrFamily() const {
|
|
|
|
|
static const auto targetFamiliesByName = TargetDescriptionFile::getFamilyNameToEnumMapping();
|
|
|
|
|
|
|
|
|
|
const auto familyIt = targetFamiliesByName.find(
|
|
|
|
|
QString::fromStdString(this->getDeviceAttribute("avr-family")).toLower().toStdString()
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (familyIt == targetFamiliesByName.end()) {
|
|
|
|
|
throw Exception("Unknown family name in target description file.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return familyIt->second;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-28 21:10:08 +00:00
|
|
|
const Targets::TargetDescription::AddressSpace& TargetDescriptionFile::getProgramAddressSpace() const {
|
|
|
|
|
return this->getAddressSpace("prog");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Targets::TargetDescription::AddressSpace& TargetDescriptionFile::getRamAddressSpace() const {
|
|
|
|
|
return this->getAddressSpace("data");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Targets::TargetDescription::AddressSpace& TargetDescriptionFile::getEepromAddressSpace() const {
|
|
|
|
|
const auto addressSpace = this->tryGetAddressSpace("eeprom");
|
|
|
|
|
return addressSpace.has_value()
|
|
|
|
|
? addressSpace->get()
|
|
|
|
|
: this->getAddressSpace("data");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Targets::TargetDescription::AddressSpace& TargetDescriptionFile::getIoAddressSpace() const {
|
|
|
|
|
return this->getAddressSpace("data");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Targets::TargetDescription::AddressSpace& TargetDescriptionFile::getSignatureAddressSpace() const {
|
|
|
|
|
const auto addressSpace = this->tryGetAddressSpace("signatures");
|
|
|
|
|
return addressSpace.has_value()
|
|
|
|
|
? addressSpace->get()
|
|
|
|
|
: this->getAddressSpace("data");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Targets::TargetDescription::AddressSpace& TargetDescriptionFile::getFuseAddressSpace() const {
|
|
|
|
|
const auto addressSpace = this->tryGetAddressSpace("fuses");
|
|
|
|
|
return addressSpace.has_value()
|
|
|
|
|
? addressSpace->get()
|
|
|
|
|
: this->getAddressSpace("data");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Targets::TargetDescription::AddressSpace& TargetDescriptionFile::getLockbitAddressSpace() const {
|
|
|
|
|
const auto addressSpace = this->tryGetAddressSpace("lockbits");
|
|
|
|
|
return addressSpace.has_value()
|
|
|
|
|
? addressSpace->get()
|
|
|
|
|
: this->getAddressSpace("data");
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-25 19:21:36 +00:00
|
|
|
const Targets::TargetDescription::MemorySegment& TargetDescriptionFile::getProgramMemorySegment() const {
|
2024-03-28 21:10:08 +00:00
|
|
|
return this->getProgramAddressSpace().getMemorySegment("internal_program_memory");
|
2024-03-25 19:21:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Targets::TargetDescription::MemorySegment& TargetDescriptionFile::getRamMemorySegment() const {
|
2024-03-28 21:10:08 +00:00
|
|
|
return this->getRamAddressSpace().getMemorySegment("internal_ram");
|
2024-03-25 19:21:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Targets::TargetDescription::MemorySegment& TargetDescriptionFile::getEepromMemorySegment() const {
|
2024-03-28 21:10:08 +00:00
|
|
|
return this->getEepromAddressSpace().getMemorySegment("internal_eeprom");
|
2024-03-25 19:21:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Targets::TargetDescription::MemorySegment& TargetDescriptionFile::getIoMemorySegment() const {
|
2024-03-28 21:10:08 +00:00
|
|
|
const auto addressSpace = this->getIoAddressSpace();
|
2024-03-25 19:21:36 +00:00
|
|
|
const auto segment = addressSpace.tryGetMemorySegment("io");
|
|
|
|
|
return segment.has_value()
|
|
|
|
|
? segment->get()
|
|
|
|
|
: addressSpace.getMemorySegment("mapped_io");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Targets::TargetDescription::MemorySegment& TargetDescriptionFile::getSignatureMemorySegment() const {
|
2024-03-28 21:10:08 +00:00
|
|
|
return this->getSignatureAddressSpace().getMemorySegment("signatures");
|
2024-03-25 19:21:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Targets::TargetDescription::MemorySegment& TargetDescriptionFile::getFuseMemorySegment() const {
|
2024-03-28 21:10:08 +00:00
|
|
|
return this->getFuseAddressSpace().getMemorySegment("fuses");
|
2024-03-25 19:21:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Targets::TargetDescription::MemorySegment& TargetDescriptionFile::getLockbitMemorySegment() const {
|
2024-03-28 21:10:08 +00:00
|
|
|
return this->getLockbitAddressSpace().getMemorySegment("lockbits");
|
2024-03-25 19:21:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TargetParameters TargetDescriptionFile::getTargetParameters() const {
|
|
|
|
|
TargetParameters targetParameters;
|
|
|
|
|
|
|
|
|
|
const auto programMemoryAddressSpace = this->getProgramMemoryAddressSpace();
|
|
|
|
|
|
|
|
|
|
if (programMemoryAddressSpace.has_value()) {
|
|
|
|
|
targetParameters.flashSize = programMemoryAddressSpace->size;
|
|
|
|
|
targetParameters.flashStartAddress = programMemoryAddressSpace->startAddress;
|
|
|
|
|
|
|
|
|
|
const auto appMemorySegment = this->getFlashApplicationMemorySegment(programMemoryAddressSpace.value());
|
|
|
|
|
|
|
|
|
|
if (appMemorySegment.has_value()) {
|
|
|
|
|
targetParameters.appSectionStartAddress = appMemorySegment->startAddress;
|
|
|
|
|
targetParameters.appSectionSize = appMemorySegment->size;
|
|
|
|
|
targetParameters.flashPageSize = appMemorySegment->pageSize;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto ramMemorySegment = this->getRamMemorySegment();
|
|
|
|
|
if (ramMemorySegment.has_value()) {
|
|
|
|
|
targetParameters.ramSize = ramMemorySegment->size;
|
|
|
|
|
targetParameters.ramStartAddress = ramMemorySegment->startAddress;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto ioMemorySegment = this->getIoMemorySegment();
|
|
|
|
|
if (ioMemorySegment.has_value()) {
|
|
|
|
|
targetParameters.mappedIoSegmentSize = ioMemorySegment->size;
|
|
|
|
|
targetParameters.mappedIoSegmentStartAddress = ioMemorySegment->startAddress;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto registerMemorySegment = this->getRegisterMemorySegment();
|
|
|
|
|
if (registerMemorySegment.has_value()) {
|
|
|
|
|
targetParameters.gpRegisterSize = registerMemorySegment->size;
|
|
|
|
|
targetParameters.gpRegisterStartAddress = registerMemorySegment->startAddress;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto eepromMemorySegment = this->getEepromMemorySegment();
|
|
|
|
|
if (eepromMemorySegment.has_value()) {
|
|
|
|
|
targetParameters.eepromSize = eepromMemorySegment->size;
|
|
|
|
|
targetParameters.eepromStartAddress = eepromMemorySegment->startAddress;
|
|
|
|
|
|
|
|
|
|
if (eepromMemorySegment->pageSize.has_value()) {
|
|
|
|
|
targetParameters.eepromPageSize = eepromMemorySegment->pageSize.value();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto firstBootSectionMemorySegment = this->getFirstBootSectionMemorySegment();
|
|
|
|
|
if (firstBootSectionMemorySegment.has_value()) {
|
|
|
|
|
targetParameters.bootSectionStartAddress = firstBootSectionMemorySegment->startAddress / 2;
|
|
|
|
|
targetParameters.bootSectionSize = firstBootSectionMemorySegment->size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto cpuRegistersOffset = this->getPeripheralModuleRegisterAddressOffset("cpu", "cpu", "cpu");
|
|
|
|
|
|
|
|
|
|
const auto statusRegister = this->getStatusRegister();
|
|
|
|
|
if (statusRegister.has_value()) {
|
|
|
|
|
targetParameters.statusRegisterStartAddress = cpuRegistersOffset + statusRegister->offset;
|
|
|
|
|
targetParameters.statusRegisterSize = statusRegister->size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto stackPointerRegister = this->getStackPointerRegister();
|
|
|
|
|
if (stackPointerRegister.has_value()) {
|
|
|
|
|
targetParameters.stackPointerRegisterLowAddress = cpuRegistersOffset + stackPointerRegister->offset;
|
|
|
|
|
targetParameters.stackPointerRegisterSize = stackPointerRegister->size;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
// Sometimes the SP register is split into two register nodes, one for low, the other for high
|
|
|
|
|
const auto stackPointerLowRegister = this->getStackPointerLowRegister();
|
|
|
|
|
const auto stackPointerHighRegister = this->getStackPointerHighRegister();
|
|
|
|
|
|
|
|
|
|
if (stackPointerLowRegister.has_value()) {
|
|
|
|
|
targetParameters.stackPointerRegisterLowAddress = cpuRegistersOffset
|
|
|
|
|
+ stackPointerLowRegister->offset;
|
|
|
|
|
targetParameters.stackPointerRegisterSize = stackPointerLowRegister->size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (stackPointerHighRegister.has_value()) {
|
|
|
|
|
targetParameters.stackPointerRegisterSize =
|
|
|
|
|
targetParameters.stackPointerRegisterSize.has_value() ?
|
|
|
|
|
targetParameters.stackPointerRegisterSize.value() + stackPointerHighRegister->size :
|
|
|
|
|
stackPointerHighRegister->size;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// const auto& supportedPhysicalInterfaces = this->getSupportedPhysicalInterfaces();
|
|
|
|
|
//
|
|
|
|
|
// if (
|
|
|
|
|
// supportedPhysicalInterfaces.contains(PhysicalInterface::DEBUG_WIRE)
|
|
|
|
|
// || supportedPhysicalInterfaces.contains(PhysicalInterface::JTAG)
|
|
|
|
|
// ) {
|
|
|
|
|
// this->loadDebugWireAndJtagTargetParameters(targetParameters);
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// if (supportedPhysicalInterfaces.contains(PhysicalInterface::PDI)) {
|
|
|
|
|
// this->loadPdiTargetParameters(targetParameters);
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// if (supportedPhysicalInterfaces.contains(PhysicalInterface::UPDI)) {
|
|
|
|
|
// this->loadUpdiTargetParameters(targetParameters);
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
return targetParameters;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IspParameters TargetDescriptionFile::getIspParameters() const {
|
|
|
|
|
const auto& ispParameterGroup = this->getPropertyGroup("isp_interface");
|
|
|
|
|
auto output = IspParameters();
|
|
|
|
|
|
|
|
|
|
output.programModeTimeout = StringService::toUint8(
|
|
|
|
|
ispParameterGroup.getProperty("ispenterprogmode_timeout").value
|
|
|
|
|
);
|
|
|
|
|
output.programModeStabilizationDelay = StringService::toUint8(
|
|
|
|
|
ispParameterGroup.getProperty("ispenterprogmode_stabdelay").value
|
|
|
|
|
);
|
|
|
|
|
output.programModeCommandExecutionDelay = StringService::toUint8(
|
|
|
|
|
ispParameterGroup.getProperty("ispenterprogmode_cmdexedelay").value
|
|
|
|
|
);
|
|
|
|
|
output.programModeSyncLoops = StringService::toUint8(
|
|
|
|
|
ispParameterGroup.getProperty("ispenterprogmode_synchloops").value
|
|
|
|
|
);
|
|
|
|
|
output.programModeByteDelay = StringService::toUint8(
|
|
|
|
|
ispParameterGroup.getProperty("ispenterprogmode_bytedelay").value
|
|
|
|
|
);
|
|
|
|
|
output.programModePollValue = StringService::toUint8(
|
|
|
|
|
ispParameterGroup.getProperty("ispenterprogmode_pollvalue").value
|
|
|
|
|
);
|
|
|
|
|
output.programModePollIndex = StringService::toUint8(
|
|
|
|
|
ispParameterGroup.getProperty("ispenterprogmode_pollindex").value
|
|
|
|
|
);
|
|
|
|
|
output.programModePreDelay = StringService::toUint8(
|
|
|
|
|
ispParameterGroup.getProperty("ispleaveprogmode_predelay").value
|
|
|
|
|
);
|
|
|
|
|
output.programModePostDelay = StringService::toUint8(
|
|
|
|
|
ispParameterGroup.getProperty("ispleaveprogmode_postdelay").value
|
|
|
|
|
);
|
|
|
|
|
output.readSignaturePollIndex = StringService::toUint8(
|
|
|
|
|
ispParameterGroup.getProperty("ispreadsign_pollindex").value
|
|
|
|
|
);
|
|
|
|
|
output.readFusePollIndex = StringService::toUint8(
|
|
|
|
|
ispParameterGroup.getProperty("ispreadfuse_pollindex").value
|
|
|
|
|
);
|
|
|
|
|
output.readLockPollIndex = StringService::toUint8(
|
|
|
|
|
ispParameterGroup.getProperty("ispreadlock_pollindex").value
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return output;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<FuseEnableStrategy> TargetDescriptionFile::getFuseEnableStrategy() const {
|
|
|
|
|
static const auto fuseEnableStrategies = std::map<std::string, FuseEnableStrategy>({
|
|
|
|
|
{"0", FuseEnableStrategy::CLEAR},
|
|
|
|
|
{"1", FuseEnableStrategy::SET},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const auto programmingInfoPropertyGroupIt = this->propertyGroupsByKey.find("programming_info");
|
|
|
|
|
|
|
|
|
|
if (programmingInfoPropertyGroupIt != this->propertyGroupsByKey.end()) {
|
|
|
|
|
const auto& programmingInfoParamsByName = programmingInfoPropertyGroupIt->second.propertiesByKey;
|
|
|
|
|
const auto fuseEnabledValuePropertyIt = programmingInfoParamsByName.find("fuse_enabled_value");
|
|
|
|
|
|
|
|
|
|
if (fuseEnabledValuePropertyIt != programmingInfoParamsByName.end()) {
|
|
|
|
|
const auto fuseEnableStrategyIt = fuseEnableStrategies.find(
|
|
|
|
|
fuseEnabledValuePropertyIt->second.value
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (fuseEnableStrategyIt != fuseEnableStrategies.end()) {
|
|
|
|
|
return fuseEnableStrategyIt->second;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<FuseBitsDescriptor> TargetDescriptionFile::getDwenFuseBitsDescriptor() const {
|
|
|
|
|
return this->getFuseBitsDescriptorByName("dwen");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<FuseBitsDescriptor> TargetDescriptionFile::getSpienFuseBitsDescriptor() const {
|
|
|
|
|
return this->getFuseBitsDescriptorByName("spien");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<FuseBitsDescriptor> TargetDescriptionFile::getOcdenFuseBitsDescriptor() const {
|
|
|
|
|
return this->getFuseBitsDescriptorByName("ocden");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<FuseBitsDescriptor> TargetDescriptionFile::getJtagenFuseBitsDescriptor() const {
|
|
|
|
|
return this->getFuseBitsDescriptorByName("jtagen");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<FuseBitsDescriptor> TargetDescriptionFile::getEesaveFuseBitsDescriptor() const {
|
|
|
|
|
return this->getFuseBitsDescriptorByName("eesave");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TargetDescriptionFile::loadPadDescriptors() {
|
|
|
|
|
// const auto portModuleIt = this->modulesMappedByName.find("port");
|
|
|
|
|
// const auto portModule = (portModuleIt != this->modulesMappedByName.end())
|
|
|
|
|
// ? std::optional(portModuleIt->second)
|
|
|
|
|
// : std::nullopt;
|
|
|
|
|
//
|
|
|
|
|
// const auto portPeripheralModuleIt = this->peripheralModulesMappedByName.find("port");
|
|
|
|
|
// if (portPeripheralModuleIt == this->peripheralModulesMappedByName.end()) {
|
|
|
|
|
// return;
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// const auto& portPeripheralModule = portPeripheralModuleIt->second;
|
|
|
|
|
|
|
|
|
|
// for (const auto& [instanceName, instance] : portPeripheralModule.instancesMappedByName) {
|
|
|
|
|
// if (instanceName.find("port") != 0) {
|
|
|
|
|
// continue;
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// const auto portRegisterAddressOffset = this->getPeripheralModuleRegisterAddressOffset(
|
|
|
|
|
// portPeripheralModule.name,
|
|
|
|
|
// instanceName,
|
|
|
|
|
// instanceName
|
|
|
|
|
// );
|
|
|
|
|
//
|
|
|
|
|
// for (const auto& signal : instance.instanceSignals) {
|
|
|
|
|
// if (!signal.index.has_value()) {
|
|
|
|
|
// continue;
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// auto& padDescriptor = this->padDescriptorsByName.insert(
|
|
|
|
|
// std::pair(signal.padName, PadDescriptor())
|
|
|
|
|
// ).first->second;
|
|
|
|
|
//
|
|
|
|
|
// padDescriptor.name = signal.padName;
|
|
|
|
|
// padDescriptor.gpioPinNumber = signal.index.value();
|
|
|
|
|
//
|
|
|
|
|
// if (!portModule.has_value()) {
|
|
|
|
|
// continue;
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// const auto instanceRegisterGroupIt = portModule->registerGroupsMappedByName.find(instanceName);
|
|
|
|
|
// if (instanceRegisterGroupIt != portModule->registerGroupsMappedByName.end()) {
|
|
|
|
|
// // We have register information for this port
|
|
|
|
|
// const auto& registerGroup = instanceRegisterGroupIt->second;
|
|
|
|
|
//
|
|
|
|
|
// for (const auto& [registerName, portRegister] : registerGroup.registersMappedByName) {
|
|
|
|
|
// if (registerName.find("port") == 0) {
|
|
|
|
|
// // This is the data register for the port
|
|
|
|
|
// padDescriptor.gpioPortAddress = portRegister.offset;
|
|
|
|
|
// continue;
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// if (registerName.find("pin") == 0) {
|
|
|
|
|
// // This is the input data register for the port
|
|
|
|
|
// padDescriptor.gpioPortInputAddress = portRegister.offset;
|
|
|
|
|
// continue;
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// if (registerName.find("ddr") == 0) {
|
|
|
|
|
// // This is the data direction register for the port
|
|
|
|
|
// padDescriptor.gpioDdrAddress = portRegister.offset;
|
|
|
|
|
// continue;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// continue;
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// const auto portRegisterGroupIt = portModule->registerGroupsMappedByName.find("port");
|
|
|
|
|
// if (portRegisterGroupIt != portModule->registerGroupsMappedByName.end()) {
|
|
|
|
|
// // We have generic register information for all ports on the target
|
|
|
|
|
// const auto& registerGroup = portRegisterGroupIt->second;
|
|
|
|
|
//
|
|
|
|
|
// for (const auto& [registerName, portRegister] : registerGroup.registersMappedByName) {
|
|
|
|
|
// if (registerName == "out") {
|
|
|
|
|
// // Include the port register offset
|
|
|
|
|
// padDescriptor.gpioPortAddress = portRegisterAddressOffset + portRegister.offset;
|
|
|
|
|
// continue;
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// if (registerName == "dir") {
|
|
|
|
|
// padDescriptor.gpioDdrAddress = portRegisterAddressOffset + portRegister.offset;
|
|
|
|
|
// continue;
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// if (registerName == "in") {
|
|
|
|
|
// padDescriptor.gpioPortInputAddress = portRegisterAddressOffset + portRegister.offset;
|
|
|
|
|
// continue;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// continue;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TargetDescriptionFile::loadTargetVariants() {
|
|
|
|
|
// for (const auto& tdVariant : this->variants) {
|
|
|
|
|
// if (tdVariant.disabled) {
|
|
|
|
|
// continue;
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// auto targetVariant = TargetVariant();
|
|
|
|
|
// targetVariant.id = static_cast<int>(this->targetVariantsById.size());
|
|
|
|
|
// targetVariant.name = tdVariant.name;
|
|
|
|
|
// targetVariant.packageName = tdVariant.package;
|
|
|
|
|
//
|
|
|
|
|
// if (tdVariant.package.find("QFP") == 0 || tdVariant.package.find("TQFP") == 0) {
|
|
|
|
|
// targetVariant.package = TargetPackage::QFP;
|
|
|
|
|
//
|
|
|
|
|
// } else if (tdVariant.package.find("PDIP") == 0 || tdVariant.package.find("DIP") == 0) {
|
|
|
|
|
// targetVariant.package = TargetPackage::DIP;
|
|
|
|
|
//
|
|
|
|
|
// } else if (tdVariant.package.find("QFN") == 0 || tdVariant.package.find("VQFN") == 0) {
|
|
|
|
|
// targetVariant.package = TargetPackage::QFN;
|
|
|
|
|
//
|
|
|
|
|
// } else if (tdVariant.package.find("SOIC") == 0) {
|
|
|
|
|
// targetVariant.package = TargetPackage::SOIC;
|
|
|
|
|
//
|
|
|
|
|
// } else if (tdVariant.package.find("SSOP") == 0) {
|
|
|
|
|
// targetVariant.package = TargetPackage::SSOP;
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// const auto tdPinoutIt = this->pinoutsMappedByName.find(tdVariant.pinoutName);
|
|
|
|
|
// if (tdPinoutIt == this->pinoutsMappedByName.end()) {
|
|
|
|
|
// // Missing pinouts in the target description file
|
|
|
|
|
// continue;
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// const auto& tdPinout = tdPinoutIt->second;
|
|
|
|
|
// for (const auto& tdPin : tdPinout.pins) {
|
|
|
|
|
// auto targetPin = TargetPinDescriptor();
|
|
|
|
|
// targetPin.name = tdPin.pad;
|
|
|
|
|
// targetPin.padName = tdPin.pad;
|
|
|
|
|
// targetPin.number = tdPin.position;
|
|
|
|
|
// targetPin.variantId = targetVariant.id;
|
|
|
|
|
//
|
|
|
|
|
// // TODO: REMOVE THIS:
|
|
|
|
|
// if (
|
|
|
|
|
// tdPin.pad.find("vcc") == 0
|
|
|
|
|
// || tdPin.pad.find("avcc") == 0
|
|
|
|
|
// || tdPin.pad.find("aref") == 0
|
|
|
|
|
// || tdPin.pad.find("avdd") == 0
|
|
|
|
|
// || tdPin.pad.find("vdd") == 0
|
|
|
|
|
// ) {
|
|
|
|
|
// targetPin.type = TargetPinType::VCC;
|
|
|
|
|
//
|
|
|
|
|
// } else if (tdPin.pad.find("gnd") == 0) {
|
|
|
|
|
// targetPin.type = TargetPinType::GND;
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// const auto padIt = this->padDescriptorsByName.find(targetPin.padName);
|
|
|
|
|
// if (padIt != this->padDescriptorsByName.end()) {
|
|
|
|
|
// const auto& pad = padIt->second;
|
|
|
|
|
// if (pad.gpioPortAddress.has_value() && pad.gpioDdrAddress.has_value()) {
|
|
|
|
|
// targetPin.type = TargetPinType::GPIO;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// targetVariant.pinDescriptorsByNumber.insert(std::pair(targetPin.number, targetPin));
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// this->targetVariantsById.insert(std::pair(targetVariant.id, targetVariant));
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TargetDescriptionFile::loadTargetRegisterDescriptors() {
|
|
|
|
|
// for (const auto& [moduleName, module] : this->modulesMappedByName) {
|
|
|
|
|
// for (const auto& [registerGroupName, registerGroup] : module.registerGroupsMappedByName) {
|
|
|
|
|
// const auto peripheralRegisterGroupsIt = this->peripheralRegisterGroupsMappedByModuleRegisterGroupName.find(
|
|
|
|
|
// registerGroupName
|
|
|
|
|
// );
|
|
|
|
|
//
|
|
|
|
|
// if (peripheralRegisterGroupsIt != this->peripheralRegisterGroupsMappedByModuleRegisterGroupName.end()) {
|
|
|
|
|
// const auto& peripheralRegisterGroups = peripheralRegisterGroupsIt->second;
|
|
|
|
|
//
|
|
|
|
|
// for (const auto& peripheralRegisterGroup : peripheralRegisterGroups) {
|
|
|
|
|
// if (peripheralRegisterGroup.addressSpaceId.value_or("") != "data") {
|
|
|
|
|
// // Currently, we only deal with registers in the data address space.
|
|
|
|
|
// continue;
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// for (const auto& [moduleRegisterName, moduleRegister] : registerGroup.registersMappedByName) {
|
|
|
|
|
// if (moduleRegister.size < 1) {
|
|
|
|
|
// continue;
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// auto registerDescriptor = TargetRegisterDescriptor(
|
|
|
|
|
// moduleName == "port" ? TargetRegisterType::PORT_REGISTER : TargetRegisterType::OTHER,
|
|
|
|
|
// moduleRegister.offset + peripheralRegisterGroup.offset.value_or(0),
|
|
|
|
|
// moduleRegister.size,
|
|
|
|
|
// TargetMemoryType::RAM,
|
|
|
|
|
// moduleRegisterName,
|
|
|
|
|
// peripheralRegisterGroup.name,
|
|
|
|
|
// moduleRegister.caption.has_value() && !moduleRegister.caption->empty()
|
|
|
|
|
// ? moduleRegister.caption
|
|
|
|
|
// : std::nullopt,
|
|
|
|
|
// moduleRegister.readWriteAccess.has_value()
|
|
|
|
|
// ? TargetRegisterAccess(
|
|
|
|
|
// moduleRegister.readWriteAccess.value().find('r') != std::string::npos,
|
|
|
|
|
// moduleRegister.readWriteAccess.value().find('w') != std::string::npos
|
|
|
|
|
// )
|
|
|
|
|
// : TargetRegisterAccess(true, true)
|
|
|
|
|
// );
|
|
|
|
|
//
|
|
|
|
|
// this->targetRegisterDescriptorsById.emplace(
|
|
|
|
|
// registerDescriptor.id,
|
|
|
|
|
// std::move(registerDescriptor)
|
|
|
|
|
// );
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Targets::TargetMemoryAddress TargetDescriptionFile::getPeripheralModuleRegisterAddressOffset(
|
|
|
|
|
const std::string& moduleName,
|
|
|
|
|
const std::string& instanceName,
|
|
|
|
|
const std::string& registerGroupName
|
|
|
|
|
) const {
|
|
|
|
|
Targets::TargetMemoryAddress addressOffset = 0;
|
|
|
|
|
|
|
|
|
|
// const auto peripheralModuleIt = this->peripheralModulesMappedByName.find(moduleName);
|
|
|
|
|
// if (peripheralModuleIt != this->peripheralModulesMappedByName.end()) {
|
|
|
|
|
// const auto& peripheralModule = peripheralModuleIt->second;
|
|
|
|
|
//
|
|
|
|
|
//// const auto instanceIt = peripheralModule.instancesMappedByName.find(instanceName);
|
|
|
|
|
//// if (instanceIt != peripheralModule.instancesMappedByName.end()) {
|
|
|
|
|
//// const auto& instance = instanceIt->second;
|
|
|
|
|
////
|
|
|
|
|
//// const auto registerGroupIt = instance.registerGroupsMappedByName.find(registerGroupName);
|
|
|
|
|
//// if (registerGroupIt != instance.registerGroupsMappedByName.end()) {
|
|
|
|
|
//// addressOffset = registerGroupIt->second.offset.value_or(0);
|
|
|
|
|
//// }
|
|
|
|
|
//// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
return addressOffset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<FuseBitsDescriptor> TargetDescriptionFile::getFuseBitsDescriptorByName(
|
|
|
|
|
const std::string& fuseBitName
|
|
|
|
|
) const {
|
|
|
|
|
static const auto fuseTypesByName = std::map<std::string, FuseType>({
|
|
|
|
|
{"low", FuseType::LOW},
|
|
|
|
|
{"high", FuseType::HIGH},
|
|
|
|
|
{"extended", FuseType::EXTENDED},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// const auto fuseModuleIt = this->modulesMappedByName.find("fuse");
|
|
|
|
|
//
|
|
|
|
|
// if (fuseModuleIt != this->modulesMappedByName.end()) {
|
|
|
|
|
// const auto& fuseModule = fuseModuleIt->second;
|
|
|
|
|
// auto fuseRegisterGroupIt = fuseModule.registerGroupsMappedByName.find("fuse");
|
|
|
|
|
//
|
|
|
|
|
// if (fuseRegisterGroupIt == fuseModule.registerGroupsMappedByName.end()) {
|
|
|
|
|
// // Try the NVM_FUSES register group
|
|
|
|
|
// fuseRegisterGroupIt = fuseModule.registerGroupsMappedByName.find("nvm_fuses");
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// if (fuseRegisterGroupIt != fuseModule.registerGroupsMappedByName.end()) {
|
|
|
|
|
// const auto& fuseRegisterGroup = fuseRegisterGroupIt->second;
|
|
|
|
|
//
|
|
|
|
|
// for (const auto& [fuseTypeName, fuse] : fuseRegisterGroup.registersMappedByName) {
|
|
|
|
|
// const auto fuseBitFieldIt = fuse.bitFieldsMappedByName.find(fuseBitName);
|
|
|
|
|
//
|
|
|
|
|
// if (fuseBitFieldIt != fuse.bitFieldsMappedByName.end()) {
|
|
|
|
|
// const auto fuseTypeIt = fuseTypesByName.find(fuseTypeName);
|
|
|
|
|
//
|
|
|
|
|
// return FuseBitsDescriptor(
|
|
|
|
|
// this->getPeripheralModuleRegisterAddressOffset("fuse", "fuse", "fuse") + fuse.offset,
|
|
|
|
|
// fuseTypeIt != fuseTypesByName.end() ? fuseTypeIt->second : FuseType::OTHER,
|
|
|
|
|
// fuseBitFieldIt->second.mask
|
|
|
|
|
// );
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// // Try the NVM module
|
|
|
|
|
// const auto nvmModuleIt = this->modulesMappedByName.find("nvm");
|
|
|
|
|
//
|
|
|
|
|
// if (nvmModuleIt != this->modulesMappedByName.end()) {
|
|
|
|
|
// const auto& nvmModule = nvmModuleIt->second;
|
|
|
|
|
// const auto fuseRegisterGroupIt = nvmModule.registerGroupsMappedByName.find("nvm_fuses");
|
|
|
|
|
//
|
|
|
|
|
// if (fuseRegisterGroupIt != nvmModule.registerGroupsMappedByName.end()) {
|
|
|
|
|
// const auto& fuseRegisterGroup = fuseRegisterGroupIt->second;
|
|
|
|
|
//
|
|
|
|
|
// for (const auto& [fuseTypeName, fuse] : fuseRegisterGroup.registersMappedByName) {
|
|
|
|
|
// const auto fuseBitFieldIt = fuse.bitFieldsMappedByName.find(fuseBitName);
|
|
|
|
|
//
|
|
|
|
|
// if (fuseBitFieldIt != fuse.bitFieldsMappedByName.end()) {
|
|
|
|
|
// const auto fuseTypeIt = fuseTypesByName.find(fuseTypeName);
|
|
|
|
|
//
|
|
|
|
|
// return FuseBitsDescriptor(
|
|
|
|
|
// this->getPeripheralModuleRegisterAddressOffset("nvm", "fuse", "fuse") + fuse.offset,
|
|
|
|
|
// fuseTypeIt != fuseTypesByName.end() ? fuseTypeIt->second : FuseType::OTHER,
|
|
|
|
|
// fuseBitFieldIt->second.mask
|
|
|
|
|
// );
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<AddressSpace> TargetDescriptionFile::getProgramMemoryAddressSpace() const {
|
|
|
|
|
// const auto programAddressSpaceIt = this->addressSpacesMappedByKey.find("prog");
|
|
|
|
|
//
|
|
|
|
|
// if (programAddressSpaceIt != this->addressSpacesMappedByKey.end()) {
|
|
|
|
|
// return programAddressSpaceIt->second;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<MemorySegment> TargetDescriptionFile::getFlashApplicationMemorySegment(
|
|
|
|
|
const AddressSpace& programAddressSpace
|
|
|
|
|
) const {
|
|
|
|
|
// const auto& programMemorySegments = programAddressSpace.memorySegmentsByTypeAndName;
|
|
|
|
|
//
|
|
|
|
|
// const auto flashMemorySegmentsIt = programMemorySegments.find(MemorySegmentType::FLASH);
|
|
|
|
|
// if (flashMemorySegmentsIt != programMemorySegments.end()) {
|
|
|
|
|
// const auto& flashMemorySegments = flashMemorySegmentsIt->second;
|
|
|
|
|
//
|
|
|
|
|
// /*
|
|
|
|
|
// * In AVR8 TDFs, flash application memory segments are typically named "APP_SECTION", "PROGMEM" or
|
|
|
|
|
// * "FLASH".
|
|
|
|
|
// */
|
|
|
|
|
// const auto appSectionSegmentIt = flashMemorySegments.find("app_section");
|
|
|
|
|
// if (appSectionSegmentIt != flashMemorySegments.end()) {
|
|
|
|
|
// return appSectionSegmentIt->second;
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// const auto programMemSegmentIt = flashMemorySegments.find("progmem");
|
|
|
|
|
// if (programMemSegmentIt != flashMemorySegments.end()) {
|
|
|
|
|
// return programMemSegmentIt->second;
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// const auto flashSegmentIt = flashMemorySegments.find("flash");
|
|
|
|
|
// if (flashSegmentIt != flashMemorySegments.end()) {
|
|
|
|
|
// return flashSegmentIt->second;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<MemorySegment> TargetDescriptionFile::getRegisterMemorySegment() const {
|
|
|
|
|
// const auto& addressMapping = this->addressSpacesMappedByKey;
|
|
|
|
|
//
|
|
|
|
|
// // Internal RAM ®ister attributes are usually found in the data address space
|
|
|
|
|
// auto dataAddressSpaceIt = addressMapping.find("data");
|
|
|
|
|
//
|
|
|
|
|
// if (dataAddressSpaceIt != addressMapping.end()) {
|
|
|
|
|
// const auto& dataAddressSpace = dataAddressSpaceIt->second;
|
|
|
|
|
// const auto& dataMemorySegments = dataAddressSpace.memorySegmentsByTypeAndName;
|
|
|
|
|
//
|
|
|
|
|
// if (dataMemorySegments.find(MemorySegmentType::REGISTERS) != dataMemorySegments.end()) {
|
|
|
|
|
// const auto& registerMemorySegments = dataMemorySegments.find(MemorySegmentType::REGISTERS)->second;
|
|
|
|
|
// auto registerMemorySegmentIt = registerMemorySegments.begin();
|
|
|
|
|
//
|
|
|
|
|
// if (registerMemorySegmentIt != registerMemorySegments.end()) {
|
|
|
|
|
// return registerMemorySegmentIt->second;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<MemorySegment> TargetDescriptionFile::getFirstBootSectionMemorySegment() const {
|
|
|
|
|
// const auto programAddressSpaceIt = this->addressSpacesMappedByKey.find("prog");
|
|
|
|
|
//
|
|
|
|
|
// if (programAddressSpaceIt != this->addressSpacesMappedByKey.end()) {
|
|
|
|
|
// const auto& programAddressSpace = programAddressSpaceIt->second;
|
|
|
|
|
// const auto& programMemorySegments = programAddressSpace.memorySegmentsByTypeAndName;
|
|
|
|
|
//
|
|
|
|
|
// const auto flashMemorySegmentsit = programMemorySegments.find(MemorySegmentType::FLASH);
|
|
|
|
|
//
|
|
|
|
|
// if (flashMemorySegmentsit != programMemorySegments.end()) {
|
|
|
|
|
// const auto& flashMemorySegments = flashMemorySegmentsit->second;
|
|
|
|
|
//
|
|
|
|
|
// auto bootSectionSegmentIt = flashMemorySegments.find("boot_section_1");
|
|
|
|
|
// if (bootSectionSegmentIt != flashMemorySegments.end()) {
|
|
|
|
|
// return bootSectionSegmentIt->second;
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// bootSectionSegmentIt = flashMemorySegments.find("boot_section");
|
|
|
|
|
// if (bootSectionSegmentIt != flashMemorySegments.end()) {
|
|
|
|
|
// return bootSectionSegmentIt->second;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<RegisterGroup> TargetDescriptionFile::getCpuRegisterGroup() const {
|
|
|
|
|
// const auto& modulesByName = this->modulesMappedByName;
|
|
|
|
|
// const auto cpuModuleIt = modulesByName.find("cpu");
|
|
|
|
|
|
|
|
|
|
// if (cpuModuleIt != modulesByName.end()) {
|
|
|
|
|
// const auto& cpuModule = cpuModuleIt->second;
|
|
|
|
|
// const auto cpuRegisterGroupIt = cpuModule.registerGroupsMappedByName.find("cpu");
|
|
|
|
|
//
|
|
|
|
|
// if (cpuRegisterGroupIt != cpuModule.registerGroupsMappedByName.end()) {
|
|
|
|
|
// return cpuRegisterGroupIt->second;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<RegisterGroup> TargetDescriptionFile::getBootLoadRegisterGroup() const {
|
|
|
|
|
// const auto bootLoadModuleIt = this->modulesMappedByName.find("boot_load");
|
|
|
|
|
|
|
|
|
|
// if (bootLoadModuleIt != this->modulesMappedByName.end()) {
|
|
|
|
|
// const auto& bootLoadModule = bootLoadModuleIt->second;
|
|
|
|
|
// auto bootLoadRegisterGroupIt = bootLoadModule.registerGroupsMappedByName.find("boot_load");
|
|
|
|
|
//
|
|
|
|
|
// if (bootLoadRegisterGroupIt != bootLoadModule.registerGroupsMappedByName.end()) {
|
|
|
|
|
// return bootLoadRegisterGroupIt->second;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<RegisterGroup> TargetDescriptionFile::getEepromRegisterGroup() const {
|
|
|
|
|
// const auto& modulesByName = this->modulesMappedByName;
|
|
|
|
|
|
|
|
|
|
// if (modulesByName.find("eeprom") != modulesByName.end()) {
|
|
|
|
|
// auto eepromModule = modulesByName.find("eeprom")->second;
|
|
|
|
|
// auto eepromRegisterGroupIt = eepromModule.registerGroupsMappedByName.find("eeprom");
|
|
|
|
|
//
|
|
|
|
|
// if (eepromRegisterGroupIt != eepromModule.registerGroupsMappedByName.end()) {
|
|
|
|
|
// return eepromRegisterGroupIt->second;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<Register> TargetDescriptionFile::getStatusRegister() const {
|
|
|
|
|
auto cpuRegisterGroup = this->getCpuRegisterGroup();
|
|
|
|
|
|
|
|
|
|
// if (cpuRegisterGroup.has_value()) {
|
|
|
|
|
// auto statusRegisterIt = cpuRegisterGroup->registersMappedByName.find("sreg");
|
|
|
|
|
//
|
|
|
|
|
// if (statusRegisterIt != cpuRegisterGroup->registersMappedByName.end()) {
|
|
|
|
|
// return statusRegisterIt->second;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<Register> TargetDescriptionFile::getStackPointerRegister() const {
|
|
|
|
|
auto cpuRegisterGroup = this->getCpuRegisterGroup();
|
|
|
|
|
|
|
|
|
|
// if (cpuRegisterGroup.has_value()) {
|
|
|
|
|
// auto stackPointerRegisterIt = cpuRegisterGroup->registersMappedByName.find("sp");
|
|
|
|
|
//
|
|
|
|
|
// if (stackPointerRegisterIt != cpuRegisterGroup->registersMappedByName.end()) {
|
|
|
|
|
// return stackPointerRegisterIt->second;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<Register> TargetDescriptionFile::getStackPointerHighRegister() const {
|
|
|
|
|
auto cpuRegisterGroup = this->getCpuRegisterGroup();
|
|
|
|
|
|
|
|
|
|
// if (cpuRegisterGroup.has_value()) {
|
|
|
|
|
// auto stackPointerHighRegisterIt = cpuRegisterGroup->registersMappedByName.find("sph");
|
|
|
|
|
//
|
|
|
|
|
// if (stackPointerHighRegisterIt != cpuRegisterGroup->registersMappedByName.end()) {
|
|
|
|
|
// return stackPointerHighRegisterIt->second;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<Register> TargetDescriptionFile::getStackPointerLowRegister() const {
|
|
|
|
|
auto cpuRegisterGroup = this->getCpuRegisterGroup();
|
|
|
|
|
|
|
|
|
|
// if (cpuRegisterGroup.has_value()) {
|
|
|
|
|
// auto stackPointerLowRegisterIt = cpuRegisterGroup->registersMappedByName.find("spl");
|
|
|
|
|
//
|
|
|
|
|
// if (stackPointerLowRegisterIt != cpuRegisterGroup->registersMappedByName.end()) {
|
|
|
|
|
// return stackPointerLowRegisterIt->second;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<Register> TargetDescriptionFile::getOscillatorCalibrationRegister() const {
|
|
|
|
|
auto cpuRegisterGroup = this->getCpuRegisterGroup();
|
|
|
|
|
|
|
|
|
|
// if (cpuRegisterGroup.has_value()) {
|
|
|
|
|
// const auto& cpuRegisters = cpuRegisterGroup->registersMappedByName;
|
|
|
|
|
//
|
|
|
|
|
// auto osccalRegisterIt = cpuRegisters.find("osccal");
|
|
|
|
|
// if (osccalRegisterIt != cpuRegisters.end()) {
|
|
|
|
|
// return osccalRegisterIt->second;
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// osccalRegisterIt = cpuRegisters.find("osccal0");
|
|
|
|
|
// if (osccalRegisterIt != cpuRegisters.end()) {
|
|
|
|
|
// return osccalRegisterIt->second;
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// osccalRegisterIt = cpuRegisters.find("osccal1");
|
|
|
|
|
// if (osccalRegisterIt != cpuRegisters.end()) {
|
|
|
|
|
// return osccalRegisterIt->second;
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// osccalRegisterIt = cpuRegisters.find("fosccal");
|
|
|
|
|
// if (osccalRegisterIt != cpuRegisters.end()) {
|
|
|
|
|
// return osccalRegisterIt->second;
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// osccalRegisterIt = cpuRegisters.find("sosccala");
|
|
|
|
|
// if (osccalRegisterIt != cpuRegisters.end()) {
|
|
|
|
|
// return osccalRegisterIt->second;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<Register> TargetDescriptionFile::getSpmcsRegister() const {
|
|
|
|
|
const auto cpuRegisterGroup = this->getCpuRegisterGroup();
|
|
|
|
|
|
|
|
|
|
// if (cpuRegisterGroup.has_value()) {
|
|
|
|
|
// const auto spmcsRegisterIt = cpuRegisterGroup->registersMappedByName.find("spmcsr");
|
|
|
|
|
//
|
|
|
|
|
// if (spmcsRegisterIt != cpuRegisterGroup->registersMappedByName.end()) {
|
|
|
|
|
// return spmcsRegisterIt->second;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// const auto bootLoadRegisterGroup = this->getBootLoadRegisterGroup();
|
|
|
|
|
//
|
|
|
|
|
// if (bootLoadRegisterGroup.has_value()) {
|
|
|
|
|
// const auto spmcsRegisterIt = bootLoadRegisterGroup->registersMappedByName.find("spmcsr");
|
|
|
|
|
//
|
|
|
|
|
// if (spmcsRegisterIt != bootLoadRegisterGroup->registersMappedByName.end()) {
|
|
|
|
|
// return spmcsRegisterIt->second;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<Register> TargetDescriptionFile::getSpmcRegister() const {
|
|
|
|
|
const auto cpuRegisterGroup = this->getCpuRegisterGroup();
|
|
|
|
|
|
|
|
|
|
// if (cpuRegisterGroup.has_value()) {
|
|
|
|
|
// const auto spmcRegisterIt = cpuRegisterGroup->registersMappedByName.find("spmcr");
|
|
|
|
|
//
|
|
|
|
|
// if (spmcRegisterIt != cpuRegisterGroup->registersMappedByName.end()) {
|
|
|
|
|
// return spmcRegisterIt->second;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// const auto bootLoadRegisterGroup = this->getBootLoadRegisterGroup();
|
|
|
|
|
//
|
|
|
|
|
// if (bootLoadRegisterGroup.has_value()) {
|
|
|
|
|
// const auto spmcRegisterIt = bootLoadRegisterGroup->registersMappedByName.find("spmcr");
|
|
|
|
|
//
|
|
|
|
|
// if (spmcRegisterIt != bootLoadRegisterGroup->registersMappedByName.end()) {
|
|
|
|
|
// return spmcRegisterIt->second;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<Register> TargetDescriptionFile::getEepromAddressRegister() const {
|
|
|
|
|
auto eepromRegisterGroup = this->getEepromRegisterGroup();
|
|
|
|
|
|
|
|
|
|
// if (eepromRegisterGroup.has_value()) {
|
|
|
|
|
// auto eepromAddressRegisterIt = eepromRegisterGroup->registersMappedByName.find("eear");
|
|
|
|
|
//
|
|
|
|
|
// if (eepromAddressRegisterIt != eepromRegisterGroup->registersMappedByName.end()) {
|
|
|
|
|
// return eepromAddressRegisterIt->second;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<Register> TargetDescriptionFile::getEepromAddressLowRegister() const {
|
|
|
|
|
auto eepromRegisterGroup = this->getEepromRegisterGroup();
|
|
|
|
|
|
|
|
|
|
// if (eepromRegisterGroup.has_value()) {
|
|
|
|
|
// auto eepromAddressRegisterIt = eepromRegisterGroup->registersMappedByName.find("eearl");
|
|
|
|
|
//
|
|
|
|
|
// if (eepromAddressRegisterIt != eepromRegisterGroup->registersMappedByName.end()) {
|
|
|
|
|
// return eepromAddressRegisterIt->second;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<Register> TargetDescriptionFile::getEepromAddressHighRegister() const {
|
|
|
|
|
auto eepromRegisterGroup = this->getEepromRegisterGroup();
|
|
|
|
|
|
|
|
|
|
// if (eepromRegisterGroup.has_value()) {
|
|
|
|
|
// auto eepromAddressRegisterIt = eepromRegisterGroup->registersMappedByName.find("eearh");
|
|
|
|
|
//
|
|
|
|
|
// if (eepromAddressRegisterIt != eepromRegisterGroup->registersMappedByName.end()) {
|
|
|
|
|
// return eepromAddressRegisterIt->second;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<Register> TargetDescriptionFile::getEepromDataRegister() const {
|
|
|
|
|
auto eepromRegisterGroup = this->getEepromRegisterGroup();
|
|
|
|
|
|
|
|
|
|
// if (eepromRegisterGroup.has_value()) {
|
|
|
|
|
// auto eepromDataRegisterIt = eepromRegisterGroup->registersMappedByName.find("eedr");
|
|
|
|
|
//
|
|
|
|
|
// if (eepromDataRegisterIt != eepromRegisterGroup->registersMappedByName.end()) {
|
|
|
|
|
// return eepromDataRegisterIt->second;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<Register> TargetDescriptionFile::getEepromControlRegister() const {
|
|
|
|
|
auto eepromRegisterGroup = this->getEepromRegisterGroup();
|
|
|
|
|
|
|
|
|
|
// if (eepromRegisterGroup.has_value()) {
|
|
|
|
|
// auto eepromControlRegisterIt = eepromRegisterGroup->registersMappedByName.find("eecr");
|
|
|
|
|
//
|
|
|
|
|
// if (eepromControlRegisterIt != eepromRegisterGroup->registersMappedByName.end()) {
|
|
|
|
|
// return eepromControlRegisterIt->second;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TargetDescriptionFile::loadDebugWireAndJtagTargetParameters(TargetParameters& targetParameters) const {
|
|
|
|
|
// OCD attributes can be found in property groups
|
|
|
|
|
const auto& ocdPropertyGroup = this->getPropertyGroup("ocd");
|
|
|
|
|
targetParameters.ocdRevision = StringService::toUint8(ocdPropertyGroup.getProperty("ocd_revision").value);
|
|
|
|
|
targetParameters.ocdDataRegister = StringService::toUint8(ocdPropertyGroup.getProperty("ocd_datareg").value);
|
|
|
|
|
// const auto ocdPropertyGroupIt = this->propertyGroupsMappedByKey.find("ocd");
|
|
|
|
|
// if (ocdPropertyGroupIt != this->propertyGroupsMappedByKey.end()) {
|
|
|
|
|
// const auto& ocdProperties = ocdPropertyGroupIt->second.propertiesMappedByKey;
|
|
|
|
|
//
|
|
|
|
|
// const auto ocdRevisionPropertyIt = ocdProperties.find("ocd_revision");
|
|
|
|
|
// if (ocdRevisionPropertyIt != ocdProperties.end()) {
|
|
|
|
|
// targetParameters.ocdRevision = ocdRevisionPropertyIt->second.value.toUShort(nullptr, 10);
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// const auto ocdDataRegPropertyIt = ocdProperties.find("ocd_datareg");
|
|
|
|
|
// if (ocdDataRegPropertyIt != ocdProperties.end()) {
|
|
|
|
|
// targetParameters.ocdDataRegister = ocdDataRegPropertyIt->second.value.toUShort(nullptr, 16);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
const auto spmcsRegister = this->getSpmcsRegister();
|
|
|
|
|
if (spmcsRegister.has_value()) {
|
|
|
|
|
targetParameters.spmcRegisterStartAddress = spmcsRegister->offset;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
const auto spmcRegister = this->getSpmcRegister();
|
|
|
|
|
if (spmcRegister.has_value()) {
|
|
|
|
|
targetParameters.spmcRegisterStartAddress = spmcRegister->offset;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto osccalRegister = this->getOscillatorCalibrationRegister();
|
|
|
|
|
if (osccalRegister.has_value()) {
|
|
|
|
|
targetParameters.osccalAddress = osccalRegister->offset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto eepromAddressRegister = this->getEepromAddressRegister();
|
|
|
|
|
if (eepromAddressRegister.has_value()) {
|
|
|
|
|
targetParameters.eepromAddressRegisterLow = eepromAddressRegister->offset;
|
|
|
|
|
targetParameters.eepromAddressRegisterHigh = (eepromAddressRegister->size == 2)
|
|
|
|
|
? eepromAddressRegister->offset + 1 : eepromAddressRegister->offset;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
const auto eepromAddressLowRegister = this->getEepromAddressLowRegister();
|
|
|
|
|
if (eepromAddressLowRegister.has_value()) {
|
|
|
|
|
targetParameters.eepromAddressRegisterLow = eepromAddressLowRegister->offset;
|
|
|
|
|
auto eepromAddressHighRegister = this->getEepromAddressHighRegister();
|
|
|
|
|
|
|
|
|
|
if (eepromAddressHighRegister.has_value()) {
|
|
|
|
|
targetParameters.eepromAddressRegisterHigh = eepromAddressHighRegister->offset;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
targetParameters.eepromAddressRegisterHigh = eepromAddressLowRegister->offset;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto eepromDataRegister = this->getEepromDataRegister();
|
|
|
|
|
if (eepromDataRegister.has_value()) {
|
|
|
|
|
targetParameters.eepromDataRegisterAddress = eepromDataRegister->offset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto eepromControlRegister = this->getEepromControlRegister();
|
|
|
|
|
if (eepromControlRegister.has_value()) {
|
|
|
|
|
targetParameters.eepromControlRegisterAddress = eepromControlRegister->offset;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TargetDescriptionFile::loadPdiTargetParameters(TargetParameters& targetParameters) const {
|
|
|
|
|
const auto pdiPropertyGroupIt = this->propertyGroupsByKey.find("pdi_interface");
|
|
|
|
|
if (pdiPropertyGroupIt == this->propertyGroupsByKey.end()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto& pdiInterfaceProperties = pdiPropertyGroupIt->second.propertiesByKey;
|
|
|
|
|
|
|
|
|
|
// const auto appOffsetPropertyIt = pdiInterfaceProperties.find("app_section_offset");
|
|
|
|
|
// if (appOffsetPropertyIt != pdiInterfaceProperties.end()) {
|
|
|
|
|
// targetParameters.appSectionPdiOffset = appOffsetPropertyIt->second.value.toUInt(nullptr, 16);
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// const auto bootOffsetPropertyIt = pdiInterfaceProperties.find("boot_section_offset");
|
|
|
|
|
// if (bootOffsetPropertyIt != pdiInterfaceProperties.end()) {
|
|
|
|
|
// targetParameters.bootSectionPdiOffset = bootOffsetPropertyIt->second.value.toUInt(nullptr, 16);
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// const auto dataOffsetPropertyIt = pdiInterfaceProperties.find("datamem_offset");
|
|
|
|
|
// if (dataOffsetPropertyIt != pdiInterfaceProperties.end()) {
|
|
|
|
|
// targetParameters.ramPdiOffset = dataOffsetPropertyIt->second.value.toUInt(nullptr, 16);
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// const auto eepromOffsetPropertyIt = pdiInterfaceProperties.find("eeprom_offset");
|
|
|
|
|
// if (eepromOffsetPropertyIt != pdiInterfaceProperties.end()) {
|
|
|
|
|
// targetParameters.eepromPdiOffset = eepromOffsetPropertyIt->second.value.toUInt(nullptr, 16);
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// const auto userSigOffsetPropertyIt = pdiInterfaceProperties.find("user_signatures_offset");
|
|
|
|
|
// if (userSigOffsetPropertyIt != pdiInterfaceProperties.end()) {
|
|
|
|
|
// targetParameters.userSignaturesPdiOffset = userSigOffsetPropertyIt->second.value.toUInt(nullptr, 16);
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// const auto prodSigOffsetPropertyIt = pdiInterfaceProperties.find("prod_signatures_offset");
|
|
|
|
|
// if (prodSigOffsetPropertyIt != pdiInterfaceProperties.end()) {
|
|
|
|
|
// targetParameters.productSignaturesPdiOffset = prodSigOffsetPropertyIt->second.value.toUInt(nullptr, 16);
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// const auto fuseRegOffsetPropertyIt = pdiInterfaceProperties.find("fuse_registers_offset");
|
|
|
|
|
// if (fuseRegOffsetPropertyIt != pdiInterfaceProperties.end()) {
|
|
|
|
|
// targetParameters.fuseRegistersPdiOffset = fuseRegOffsetPropertyIt->second.value.toUInt(nullptr, 16);
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// const auto lockRegOffsetPropertyIt = pdiInterfaceProperties.find("lock_registers_offset");
|
|
|
|
|
// if (lockRegOffsetPropertyIt != pdiInterfaceProperties.end()) {
|
|
|
|
|
// targetParameters.lockRegistersPdiOffset = lockRegOffsetPropertyIt->second.value.toUInt(nullptr, 16);
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
targetParameters.nvmModuleBaseAddress = this->getPeripheralModuleRegisterAddressOffset("nvm", "nvm", "nvm");
|
|
|
|
|
|
|
|
|
|
// TODO: Remove the mcuModuleBaseAddress param - we're not supposed to be using this. We're supposed to using
|
|
|
|
|
// the PDI signature offset, which I have since added to the TDFs (see "pdi_interface.signature_offset" property)
|
|
|
|
|
targetParameters.mcuModuleBaseAddress = this->getPeripheralModuleRegisterAddressOffset("mcu", "mcu", "mcu");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TargetDescriptionFile::loadUpdiTargetParameters(TargetParameters& targetParameters) const {
|
|
|
|
|
targetParameters.nvmModuleBaseAddress = this->getPeripheralModuleRegisterAddressOffset(
|
|
|
|
|
"nvmctrl",
|
|
|
|
|
"nvmctrl",
|
|
|
|
|
"nvmctrl"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const auto updiPropertyGroupIt = this->propertyGroupsByKey.find("updi_interface");
|
|
|
|
|
if (updiPropertyGroupIt != this->propertyGroupsByKey.end()) {
|
|
|
|
|
const auto& updiInterfaceProperties = updiPropertyGroupIt->second.propertiesByKey;
|
|
|
|
|
|
|
|
|
|
// const auto ocdBaseAddressPropertyIt = updiInterfaceProperties.find("ocd_base_addr");
|
|
|
|
|
// if (ocdBaseAddressPropertyIt != updiInterfaceProperties.end()) {
|
|
|
|
|
// targetParameters.ocdModuleAddress = ocdBaseAddressPropertyIt->second.value.toUShort(nullptr, 16);
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// const auto progMemOffsetPropertyIt = updiInterfaceProperties.find("progmem_offset");
|
|
|
|
|
// if (progMemOffsetPropertyIt != updiInterfaceProperties.end()) {
|
|
|
|
|
// targetParameters.programMemoryUpdiStartAddress = progMemOffsetPropertyIt->second.value.toUInt(
|
|
|
|
|
// nullptr,
|
|
|
|
|
// 16
|
|
|
|
|
// );
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto signatureMemorySegment = this->getSignatureMemorySegment();
|
|
|
|
|
if (signatureMemorySegment.has_value()) {
|
|
|
|
|
targetParameters.signatureSegmentStartAddress = signatureMemorySegment->startAddress;
|
|
|
|
|
targetParameters.signatureSegmentSize = signatureMemorySegment->size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto fuseMemorySegment = this->getFuseMemorySegment();
|
|
|
|
|
if (fuseMemorySegment.has_value()) {
|
|
|
|
|
targetParameters.fuseSegmentStartAddress = fuseMemorySegment->startAddress;
|
|
|
|
|
targetParameters.fuseSegmentSize = fuseMemorySegment->size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto lockbitsMemorySegment = this->getLockbitsMemorySegment();
|
|
|
|
|
if (lockbitsMemorySegment.has_value()) {
|
|
|
|
|
targetParameters.lockbitsSegmentStartAddress = lockbitsMemorySegment->startAddress;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|