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

@@ -88,7 +88,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
enum class Avr8MemoryType: unsigned char
{
/**
* The SRAM memory type can be used to read &write to internal memory on the target.
* The SRAM memory type can be used to read & write to internal memory on the target.
*
* It's available with all of the config variants in debugging mode.
*/
@@ -144,5 +144,4 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
DATA = 0x84,
FAILED = 0xA0,
};
}
}

View File

@@ -69,7 +69,6 @@ void EdbgAvr8Interface::configure(const TargetConfig& targetConfig) {
auto physicalInterface = targetConfig.jsonObject.find("physicalInterface")->toString().toLower().toStdString();
auto availablePhysicalInterfaces = EdbgAvr8Interface::physicalInterfacesByName;
auto availableConfigVariants = EdbgAvr8Interface::configVariantsByPhysicalInterface;
if (physicalInterface.empty()
|| availablePhysicalInterfaces.find(physicalInterface) == availablePhysicalInterfaces.end()
@@ -79,16 +78,18 @@ void EdbgAvr8Interface::configure(const TargetConfig& targetConfig) {
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) {
Logger::warning("AVR8 debugWire interface selected - the DWEN fuse will need to be enabled");
}
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) {
@@ -110,6 +111,18 @@ void EdbgAvr8Interface::setTargetParameters(const Avr8Bit::TargetParameters& con
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 (!config.appSectionPdiOffset.has_value()) {
throw Exception("Missing required parameter: APPL_BASE_ADDR");
@@ -850,7 +863,7 @@ TargetRegisters EdbgAvr8Interface::readGeneralPurposeRegisters(std::set<std::siz
auto output = TargetRegisters();
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.gpRegisterSize.value_or(32)
);

View File

@@ -41,6 +41,14 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
*/
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
* 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
* debug tool.
*/
Avr8ConfigVariant configVariant;
Avr8ConfigVariant configVariant = Avr8ConfigVariant::NONE;
/**
* 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.
*/
Avr8PhysicalInterface physicalInterface;
Avr8PhysicalInterface physicalInterface = Avr8PhysicalInterface::NONE;
/**
* 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 selected physical
* interface.
* This mapping allows us to determine which config variant to select, based on the target family and the
* selected physical interface.
*/
static inline std::map<Avr8PhysicalInterface, Avr8ConfigVariant> configVariantsByPhysicalInterface = {
{Avr8PhysicalInterface::DEBUG_WIRE, Avr8ConfigVariant::DEBUG_WIRE},
{Avr8PhysicalInterface::PDI, Avr8ConfigVariant::XMEGA},
{Avr8PhysicalInterface::JTAG, Avr8ConfigVariant::MEGAJTAG},
{Avr8PhysicalInterface::PDI_1W, Avr8ConfigVariant::UPDI},
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::PDI, Avr8ConfigVariant::XMEGA},
{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
* for more on available parameters.
@@ -338,6 +429,16 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
*/
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
* debug tool.
@@ -522,4 +623,4 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
*/
virtual Targets::TargetState getTargetState() override;
};
}
}