Fixed issue with automatic config variant selection, where we were not properly handling XMEGA targets with the JTAG physical interface.

Also introduced new AVR8 families, for D series targets.
Also moved AVR family param outside of TargetParameters struct
This commit is contained in:
Nav
2021-06-06 17:44:13 +01:00
parent 5ba95e6967
commit 3f1247ce74
11 changed files with 178 additions and 28 deletions

View File

@@ -10,6 +10,9 @@ class Avr8TargetDescriptionFile extends TargetDescriptionFile
const AVR8_FAMILY_MEGA = 'MEGA'; const AVR8_FAMILY_MEGA = 'MEGA';
const AVR8_FAMILY_TINY = 'TINY'; const AVR8_FAMILY_TINY = 'TINY';
const AVR8_FAMILY_XMEGA = 'XMEGA'; const AVR8_FAMILY_XMEGA = 'XMEGA';
const AVR8_FAMILY_DB = 'DB';
const AVR8_FAMILY_DA = 'DA';
const AVR8_FAMILY_DD = 'DD';
const AVR8_FAMILY_OTHER = 'OTHER'; const AVR8_FAMILY_OTHER = 'OTHER';
const AVR8_PHYSICAL_INTERFACE_JTAG = 'JTAG'; const AVR8_PHYSICAL_INTERFACE_JTAG = 'JTAG';
@@ -77,6 +80,15 @@ class Avr8TargetDescriptionFile extends TargetDescriptionFile
} else if (stristr($deviceAttributes['family'], 'mega') !== false) { } else if (stristr($deviceAttributes['family'], 'mega') !== false) {
$this->family = self::AVR8_FAMILY_MEGA; $this->family = self::AVR8_FAMILY_MEGA;
} else if (strtolower(trim($deviceAttributes['family'])) == 'avr da') {
$this->family = self::AVR8_FAMILY_DA;
} else if (strtolower(trim($deviceAttributes['family'])) == 'avr db') {
$this->family = self::AVR8_FAMILY_DB;
} else if (strtolower(trim($deviceAttributes['family'])) == 'avr dd') {
$this->family = self::AVR8_FAMILY_DD;
} else { } else {
$this->family = self::AVR8_FAMILY_OTHER; $this->family = self::AVR8_FAMILY_OTHER;
} }
@@ -338,6 +350,10 @@ class Avr8TargetDescriptionFile extends TargetDescriptionFile
return $failures; return $failures;
} }
if (is_null($this->family) || $this->family == self::AVR8_FAMILY_OTHER) {
$failures[] = 'Unknown AVR8 family';
}
if (is_null($this->stackPointerRegisterStartAddress)) { if (is_null($this->stackPointerRegisterStartAddress)) {
$failures[] = 'Missing stack pointer register start address.'; $failures[] = 'Missing stack pointer register start address.';
} }

View File

@@ -144,5 +144,4 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
DATA = 0x84, DATA = 0x84,
FAILED = 0xA0, FAILED = 0xA0,
}; };
} }

View File

@@ -69,7 +69,6 @@ void EdbgAvr8Interface::configure(const TargetConfig& targetConfig) {
auto physicalInterface = targetConfig.jsonObject.find("physicalInterface")->toString().toLower().toStdString(); auto physicalInterface = targetConfig.jsonObject.find("physicalInterface")->toString().toLower().toStdString();
auto availablePhysicalInterfaces = EdbgAvr8Interface::physicalInterfacesByName; auto availablePhysicalInterfaces = EdbgAvr8Interface::physicalInterfacesByName;
auto availableConfigVariants = EdbgAvr8Interface::configVariantsByPhysicalInterface;
if (physicalInterface.empty() if (physicalInterface.empty()
|| availablePhysicalInterfaces.find(physicalInterface) == availablePhysicalInterfaces.end() || availablePhysicalInterfaces.find(physicalInterface) == availablePhysicalInterfaces.end()
@@ -79,16 +78,18 @@ void EdbgAvr8Interface::configure(const TargetConfig& targetConfig) {
auto selectedPhysicalInterface = availablePhysicalInterfaces.find(physicalInterface)->second; auto selectedPhysicalInterface = availablePhysicalInterfaces.find(physicalInterface)->second;
if (availableConfigVariants.find(selectedPhysicalInterface) == availableConfigVariants.end()) {
throw InvalidConfig("Invalid config variant deduced from physical interface.");
}
if (selectedPhysicalInterface == Avr8PhysicalInterface::DEBUG_WIRE) { if (selectedPhysicalInterface == Avr8PhysicalInterface::DEBUG_WIRE) {
Logger::warning("AVR8 debugWire interface selected - the DWEN fuse will need to be enabled"); Logger::warning("AVR8 debugWire interface selected - the DWEN fuse will need to be enabled");
} }
this->physicalInterface = selectedPhysicalInterface; this->physicalInterface = selectedPhysicalInterface;
this->configVariant = availableConfigVariants.find(selectedPhysicalInterface)->second;
if (this->physicalInterface == Avr8PhysicalInterface::JTAG && !this->family.has_value()) {
throw InvalidConfig("Cannot use JTAG physical interface with ambiguous target name - please specify the"
" exact name of the target in your configuration file. See https://bloom.oscillate.io/docs/supported-targets");
}
this->configVariant = this->resolveConfigVariant().value_or(Avr8ConfigVariant::NONE);
} }
void EdbgAvr8Interface::setTargetParameters(const Avr8Bit::TargetParameters& config) { void EdbgAvr8Interface::setTargetParameters(const Avr8Bit::TargetParameters& config) {
@@ -110,6 +111,18 @@ void EdbgAvr8Interface::setTargetParameters(const Avr8Bit::TargetParameters& con
throw Exception("Failed to find status register size"); throw Exception("Failed to find status register size");
} }
if (this->configVariant == Avr8ConfigVariant::NONE) {
auto configVariant = this->resolveConfigVariant();
if (!configVariant.has_value()) {
throw Exception("Failed to resolve config variant for the selected "
"physical interface and AVR8 family. The selected physical interface is not known to be supported "
"by the AVR8 family.");
}
this->configVariant = configVariant.value();
}
if (this->configVariant == Avr8ConfigVariant::XMEGA) { if (this->configVariant == Avr8ConfigVariant::XMEGA) {
if (!config.appSectionPdiOffset.has_value()) { if (!config.appSectionPdiOffset.has_value()) {
throw Exception("Missing required parameter: APPL_BASE_ADDR"); throw Exception("Missing required parameter: APPL_BASE_ADDR");
@@ -850,7 +863,7 @@ TargetRegisters EdbgAvr8Interface::readGeneralPurposeRegisters(std::set<std::siz
auto output = TargetRegisters(); auto output = TargetRegisters();
auto registers = this->readMemory( auto registers = this->readMemory(
this->targetParameters.family == Family::XMEGA ? Avr8MemoryType::REGISTER_FILE : Avr8MemoryType::SRAM, this->family == Family::XMEGA ? Avr8MemoryType::REGISTER_FILE : Avr8MemoryType::SRAM,
this->targetParameters.gpRegisterStartAddress.value_or(0x00), this->targetParameters.gpRegisterStartAddress.value_or(0x00),
this->targetParameters.gpRegisterSize.value_or(32) this->targetParameters.gpRegisterSize.value_or(32)
); );

View File

@@ -41,6 +41,14 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
*/ */
EdbgInterface& edbgInterface; EdbgInterface& edbgInterface;
/**
* The target family is taken into account when configuring the AVR8 Generic protocol on the EDBG device.
*
* We use this to determine which config variant to select.
* See EdbgAvr8Interface::resolveConfigVariant() for more.
*/
std::optional<Targets::Microchip::Avr::Avr8Bit::Family> family;
/** /**
* The AVR8 Generic protocol provides two functions: Debugging and programming. The desired function must be * The AVR8 Generic protocol provides two functions: Debugging and programming. The desired function must be
* configured via the setting of the "AVR8_CONFIG_FUNCTION" parameter. * configured via the setting of the "AVR8_CONFIG_FUNCTION" parameter.
@@ -52,13 +60,13 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
* The "AVR8_CONFIG_VARIANT" parameter allows us to determine which target parameters are required by the * The "AVR8_CONFIG_VARIANT" parameter allows us to determine which target parameters are required by the
* debug tool. * debug tool.
*/ */
Avr8ConfigVariant configVariant; Avr8ConfigVariant configVariant = Avr8ConfigVariant::NONE;
/** /**
* Currently, the AVR8 Generic protocol supports 4 physical interfaces: debugWire, JTAG, PDI and UPDI. * Currently, the AVR8 Generic protocol supports 4 physical interfaces: debugWire, JTAG, PDI and UPDI.
* The desired physical interface must be selected by setting the "AVR8_PHY_PHYSICAL" parameter. * The desired physical interface must be selected by setting the "AVR8_PHY_PHYSICAL" parameter.
*/ */
Avr8PhysicalInterface physicalInterface; Avr8PhysicalInterface physicalInterface = Avr8PhysicalInterface::NONE;
/** /**
* EDBG-based debug tools require target specific parameters such as memory locations, page sizes and * EDBG-based debug tools require target specific parameters such as memory locations, page sizes and
@@ -123,17 +131,100 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
}; };
/** /**
* Although users can supply the desired config variant via their Bloom configuration, this is not required. * This mapping allows us to determine which config variant to select, based on the target family and the
* This mapping allows us to determine which config variant to select, based on the selected physical * selected physical interface.
* interface.
*/ */
static inline std::map<Avr8PhysicalInterface, Avr8ConfigVariant> configVariantsByPhysicalInterface = { static inline auto getConfigVariantsByFamilyAndPhysicalInterface() {
using Targets::Microchip::Avr::Avr8Bit::Family;
return std::map<Family, std::map<Avr8PhysicalInterface, Avr8ConfigVariant>>({
{
Family::MEGA,
{
{Avr8PhysicalInterface::JTAG, Avr8ConfigVariant::MEGAJTAG},
{Avr8PhysicalInterface::DEBUG_WIRE, Avr8ConfigVariant::DEBUG_WIRE},
}
},
{
Family::TINY,
{
{Avr8PhysicalInterface::JTAG, Avr8ConfigVariant::MEGAJTAG},
{Avr8PhysicalInterface::DEBUG_WIRE, Avr8ConfigVariant::DEBUG_WIRE},
}
},
{
Family::XMEGA,
{
{Avr8PhysicalInterface::JTAG, Avr8ConfigVariant::XMEGA},
{Avr8PhysicalInterface::PDI, Avr8ConfigVariant::XMEGA},
}
},
{
Family::DA,
{
{Avr8PhysicalInterface::PDI_1W, Avr8ConfigVariant::UPDI},
}
},
{
Family::DB,
{
{Avr8PhysicalInterface::PDI_1W, Avr8ConfigVariant::UPDI},
}
},
{
Family::DD,
{
{Avr8PhysicalInterface::PDI_1W, Avr8ConfigVariant::UPDI},
}
},
});
};
/**
* Will attempt to resolve the config variant with the information currently held.
*
* @return
*/
std::optional<Avr8ConfigVariant> resolveConfigVariant() {
if (this->family.has_value()) {
auto configVariantsByFamily = EdbgAvr8Interface::getConfigVariantsByFamilyAndPhysicalInterface();
if (configVariantsByFamily.contains(this->family.value())) {
auto configVariantsByPhysicalInterface = configVariantsByFamily
.at(this->family.value());
if (configVariantsByPhysicalInterface.contains(this->physicalInterface)) {
return configVariantsByPhysicalInterface.at(this->physicalInterface);
}
}
} else {
/*
* If there is no family set, we may be able to resort to a simpler mapping of physical interfaces
* to config variants. But this will only work if the selected physical interface is *NOT* JTAG.
*
* This is because JTAG is the only physical interface that could map to two different config
* variants (MEGAJTAG and XMEGA). The only way we can figure out which config variant to use is if we
* know the target family.
*
* This is why we don't allow users to use ambiguous target names (such as the generic "avr8" target
* name), when using the JTAG physical interface. We won't be able to resolve the correct target
* variant. Users are required to specify the exact target name in their config, when using the JTAG
* physical interface. That way, this->family will be set by the time resolveConfigVariant() is called.
*/
static std::map<Avr8PhysicalInterface, Avr8ConfigVariant> physicalInterfacesToConfigVariants = {
{Avr8PhysicalInterface::DEBUG_WIRE, Avr8ConfigVariant::DEBUG_WIRE}, {Avr8PhysicalInterface::DEBUG_WIRE, Avr8ConfigVariant::DEBUG_WIRE},
{Avr8PhysicalInterface::PDI, Avr8ConfigVariant::XMEGA}, {Avr8PhysicalInterface::PDI, Avr8ConfigVariant::XMEGA},
{Avr8PhysicalInterface::JTAG, Avr8ConfigVariant::MEGAJTAG},
{Avr8PhysicalInterface::PDI_1W, Avr8ConfigVariant::UPDI}, {Avr8PhysicalInterface::PDI_1W, Avr8ConfigVariant::UPDI},
}; };
if (physicalInterfacesToConfigVariants.contains(this->physicalInterface)) {
return physicalInterfacesToConfigVariants.at(this->physicalInterface);
}
}
return std::nullopt;
}
/** /**
* Sets an AVR8 parameter on the debug tool. See the Avr8EdbgParameters class and protocol documentation * Sets an AVR8 parameter on the debug tool. See the Avr8EdbgParameters class and protocol documentation
* for more on available parameters. * for more on available parameters.
@@ -338,6 +429,16 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
*/ */
virtual void configure(const TargetConfig& targetConfig) override; virtual void configure(const TargetConfig& targetConfig) override;
/**
* Configures the target family. For some physical interfaces, the target family is required in order
* properly configure the EDBG tool. See EdbgAvr8Interface::resolveConfigVariant() for more.
*
* @param family
*/
void setFamily(Targets::Microchip::Avr::Avr8Bit::Family family) override {
this->family = family;
}
/** /**
* Accepts target parameters from the AVR8 target instance and sends the necessary target parameters to the * Accepts target parameters from the AVR8 target instance and sends the necessary target parameters to the
* debug tool. * debug tool.

View File

@@ -5,6 +5,7 @@
#include "src/Targets/Microchip/AVR/TargetSignature.hpp" #include "src/Targets/Microchip/AVR/TargetSignature.hpp"
#include "src/Targets/Microchip/AVR/AVR8/TargetParameters.hpp" #include "src/Targets/Microchip/AVR/AVR8/TargetParameters.hpp"
#include "src/Targets/Microchip/AVR/AVR8/Family.hpp"
#include "src/Targets/TargetState.hpp" #include "src/Targets/TargetState.hpp"
#include "src/Targets/TargetRegister.hpp" #include "src/Targets/TargetRegister.hpp"
#include "src/Targets/TargetMemory.hpp" #include "src/Targets/TargetMemory.hpp"
@@ -36,6 +37,13 @@ namespace Bloom::DebugToolDrivers::TargetInterfaces::Microchip::Avr::Avr8
*/ */
virtual void configure(const TargetConfig& targetConfig) = 0; virtual void configure(const TargetConfig& targetConfig) = 0;
/**
* Sets the target family, independent of other configuration.
*
* @param family
*/
virtual void setFamily(Targets::Microchip::Avr::Avr8Bit::Family family) = 0;
/** /**
* Should accept Avr8 target parameters for configuration of the interface. * Should accept Avr8 target parameters for configuration of the interface.
* *

View File

@@ -33,6 +33,10 @@ using namespace Exceptions;
void Avr8::preActivationConfigure(const TargetConfig& targetConfig) { void Avr8::preActivationConfigure(const TargetConfig& targetConfig) {
Target::preActivationConfigure(targetConfig); Target::preActivationConfigure(targetConfig);
if (this->family.has_value()) {
this->avr8Interface->setFamily(this->family.value());
}
this->avr8Interface->configure(targetConfig); this->avr8Interface->configure(targetConfig);
} }
@@ -61,6 +65,11 @@ void Avr8::postActivationConfigure() {
} }
void Avr8::postPromotionConfigure() { void Avr8::postPromotionConfigure() {
if (!this->family.has_value()) {
throw Exception("Failed to resolve AVR8 family");
}
this->avr8Interface->setFamily(this->family.value());
this->avr8Interface->setTargetParameters(this->getTargetParameters()); this->avr8Interface->setTargetParameters(this->getTargetParameters());
} }
@@ -276,7 +285,6 @@ TargetParameters& Avr8::getTargetParameters() {
if (!this->targetParameters.has_value()) { if (!this->targetParameters.has_value()) {
assert(this->targetDescriptionFile.has_value()); assert(this->targetDescriptionFile.has_value());
this->targetParameters = TargetParameters(); this->targetParameters = TargetParameters();
this->targetParameters->family = this->family;
auto& propertyGroups = this->targetDescriptionFile->getPropertyGroupsMappedByName(); auto& propertyGroups = this->targetDescriptionFile->getPropertyGroupsMappedByName();
auto flashMemorySegment = this->targetDescriptionFile->getFlashMemorySegment(); auto flashMemorySegment = this->targetDescriptionFile->getFlashMemorySegment();

View File

@@ -62,6 +62,7 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
explicit Avr8() = default; explicit Avr8() = default;
Avr8(const std::string& name, const TargetSignature& signature): name(name) { Avr8(const std::string& name, const TargetSignature& signature): name(name) {
this->id = signature; this->id = signature;
this->loadTargetDescriptionFile();
}; };
/* /*

View File

@@ -7,5 +7,8 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
MEGA, MEGA,
XMEGA, XMEGA,
TINY, TINY,
DB,
DA,
DD,
}; };
} }

View File

@@ -141,9 +141,9 @@ Family TargetDescriptionFile::getFamily() const {
throw Exception("Could not find target family name in target description file."); throw Exception("Could not find target family name in target description file.");
} }
if (familyNameToEnums.find(familyName) == familyNameToEnums.end()) { if (!familyNameToEnums.contains(familyName)) {
throw Exception("Unknown family name in target description file."); throw Exception("Unknown family name in target description file.");
} }
return familyNameToEnums.find(familyName)->second; return familyNameToEnums.at(familyName);
} }

View File

@@ -36,6 +36,9 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit::TargetDescription
{"avr tiny", Family::TINY}, {"avr tiny", Family::TINY},
{"tinyavr", Family::TINY}, {"tinyavr", Family::TINY},
{"tinyavr 2", Family::TINY}, {"tinyavr 2", Family::TINY},
{"avr da", Family::DA},
{"avr db", Family::DB},
{"avr dd", Family::DD},
}; };
}; };

View File

@@ -10,8 +10,6 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
{ {
struct TargetParameters struct TargetParameters
{ {
std::optional<Family> family;
std::optional<std::uint32_t> bootSectionStartAddress; std::optional<std::uint32_t> bootSectionStartAddress;
std::optional<std::uint32_t> gpRegisterStartAddress; std::optional<std::uint32_t> gpRegisterStartAddress;
std::optional<std::uint32_t> gpRegisterSize; std::optional<std::uint32_t> gpRegisterSize;