Created EdbgAvr8Session struct and moved EDBG target info to it

This commit is contained in:
Nav
2024-03-28 21:10:08 +00:00
parent 266cc8f196
commit b9d537e924
7 changed files with 315 additions and 278 deletions

View File

@@ -24,6 +24,7 @@ target_sources(
${CMAKE_CURRENT_SOURCE_DIR}/Microchip/Protocols/EDBG/AVR/Parameters/AVR8Generic/UpdiParameters.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Microchip/Protocols/EDBG/EdbgInterface.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Microchip/Protocols/EDBG/EdbgTargetPowerManagementInterface.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Microchip/Protocols/EDBG/AVR/EdbgAvr8Session.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Microchip/Protocols/EDBG/AVR/EdbgAvr8Interface.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Microchip/Protocols/EDBG/AVR/EdbgAvrIspInterface.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Microchip/EdbgDevice.cpp

View File

@@ -79,6 +79,8 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
using CommandFrames::Avr8Generic::EraseMemory;
using CommandFrames::Avr8Generic::DisableDebugWire;
using Targets::TargetAddressSpaceDescriptor;
using Targets::TargetMemorySegmentType;
using Targets::TargetState;
using Targets::TargetPhysicalInterface;
using Targets::TargetMemoryType;
@@ -90,38 +92,31 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
using Targets::TargetRegisterDescriptors;
using Targets::TargetRegisterDescriptorId;
using Targets::TargetRegisterDescriptorIds;
using Targets::TargetRegisterType;
using Targets::TargetRegisters;
EdbgAvr8Interface::EdbgAvr8Interface(
EdbgInterface* edbgInterface,
const Targets::Microchip::Avr::Avr8Bit::Avr8TargetConfig& targetConfig,
Targets::Microchip::Avr::Avr8Bit::Family targetFamily,
const Targets::Microchip::Avr::Avr8Bit::TargetParameters& targetParameters,
const Targets::TargetRegisterDescriptorMapping& targetRegisterDescriptorsById
const Targets::Microchip::Avr::Avr8Bit::TargetDescriptionFile& targetDescriptionFile,
const Targets::Microchip::Avr::Avr8Bit::Avr8TargetConfig& targetConfig
)
: edbgInterface(edbgInterface)
, targetConfig(targetConfig)
, family(targetFamily)
, configVariant(EdbgAvr8Interface::resolveConfigVariant(targetFamily, targetConfig.physicalInterface))
, targetParameters(targetParameters)
, targetRegisterDescriptorsById(targetRegisterDescriptorsById)
, session(EdbgAvr8Session(targetDescriptionFile, targetConfig))
{}
void EdbgAvr8Interface::init() {
if (this->configVariant == Avr8ConfigVariant::XMEGA) {
if (this->session.configVariant == Avr8ConfigVariant::XMEGA) {
// Default PDI clock to 4MHz
// TODO: Make this adjustable via a target config parameter
this->setParameter(Avr8EdbgParameters::PDI_CLOCK_SPEED, static_cast<std::uint16_t>(4000));
}
if (this->configVariant == Avr8ConfigVariant::UPDI) {
if (this->session.configVariant == Avr8ConfigVariant::UPDI) {
// Default UPDI clock to 1.8MHz
this->setParameter(Avr8EdbgParameters::PDI_CLOCK_SPEED, static_cast<std::uint16_t>(1800));
this->setParameter(Avr8EdbgParameters::ENABLE_HIGH_VOLTAGE_UPDI, static_cast<std::uint8_t>(0));
}
if (this->configVariant == Avr8ConfigVariant::MEGAJTAG) {
if (this->session.configVariant == Avr8ConfigVariant::MEGAJTAG) {
// Default clock value for mega debugging is 200KHz
// TODO: Make this adjustable via a target config parameter
this->setParameter(Avr8EdbgParameters::MEGA_DEBUG_CLOCK, static_cast<std::uint16_t>(200));
@@ -130,17 +125,17 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
this->setParameter(
Avr8EdbgParameters::CONFIG_VARIANT,
static_cast<std::uint8_t>(this->configVariant)
static_cast<std::uint8_t>(this->session.configVariant)
);
this->setParameter(
Avr8EdbgParameters::CONFIG_FUNCTION,
static_cast<std::uint8_t>(this->configFunction)
static_cast<std::uint8_t>(Avr8ConfigFunction::DEBUGGING)
);
this->setParameter(
Avr8EdbgParameters::PHYSICAL_INTERFACE,
getPhysicalInterfaceToAvr8IdMapping().at(this->targetConfig.physicalInterface)
getPhysicalInterfaceToAvr8IdMapping().at(this->session.targetConfig.physicalInterface)
);
this->setTargetParameters();
@@ -232,7 +227,7 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
} catch (const Avr8CommandFailure& activationException) {
if (
this->targetConfig.physicalInterface == TargetPhysicalInterface::DEBUG_WIRE
this->session.targetConfig.physicalInterface == TargetPhysicalInterface::DEBUG_WIRE
&& (
activationException.code == Avr8CommandFailureCode::DEBUGWIRE_PHYSICAL_ERROR
|| activationException.code == Avr8CommandFailureCode::FAILED_TO_ENABLE_OCD
@@ -257,8 +252,8 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
void EdbgAvr8Interface::deactivate() {
if (this->targetAttached) {
if (
this->targetConfig.physicalInterface == TargetPhysicalInterface::DEBUG_WIRE
&& this->targetConfig.disableDebugWireOnDeactivate
this->session.targetConfig.physicalInterface == TargetPhysicalInterface::DEBUG_WIRE
&& this->session.targetConfig.disableDebugWireOnDeactivate
) {
try {
this->disableDebugWire();
@@ -317,7 +312,7 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
}
TargetSignature EdbgAvr8Interface::getDeviceId() {
if (this->configVariant == Avr8ConfigVariant::UPDI) {
if (this->session.configVariant == Avr8ConfigVariant::UPDI) {
/*
* When using the UPDI physical interface, the 'Get device ID' command behaves in an odd manner, where it
* doesn't actually return the target signature, but instead a fixed four byte string reading:
@@ -331,7 +326,7 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
*/
const auto signatureMemory = this->readMemory(
Avr8MemoryType::SRAM,
this->targetParameters.signatureSegmentStartAddress.value(),
this->session.signatureMemorySegment.startAddress,
3
);
@@ -339,7 +334,7 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
throw Exception("Failed to read AVR8 signature from target - unexpected response size");
}
return TargetSignature(signatureMemory[0], signatureMemory[1], signatureMemory[2]);
return {signatureMemory[0], signatureMemory[1], signatureMemory[2]};
}
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
@@ -350,7 +345,7 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
throw Avr8CommandFailure("AVR8 Get device ID command failed", responseFrame);
}
return responseFrame.extractSignature(this->targetConfig.physicalInterface);
return responseFrame.extractSignature(this->session.targetConfig.physicalInterface);
}
void EdbgAvr8Interface::setSoftwareBreakpoint(TargetMemoryAddress address) {
@@ -518,7 +513,7 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
const auto memoryType = (registerType != TargetRegisterType::GENERAL_PURPOSE_REGISTER)
? Avr8MemoryType::SRAM
: (this->configVariant == Avr8ConfigVariant::XMEGA || this->configVariant == Avr8ConfigVariant::UPDI
: (this->session.configVariant == Avr8ConfigVariant::XMEGA || this->session.configVariant == Avr8ConfigVariant::UPDI
? Avr8MemoryType::REGISTER_FILE
: Avr8MemoryType::SRAM);
@@ -622,7 +617,7 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
auto memoryType = Avr8MemoryType::SRAM;
if (
registerDescriptor.type == TargetRegisterType::GENERAL_PURPOSE_REGISTER
&& (this->configVariant == Avr8ConfigVariant::XMEGA || this->configVariant == Avr8ConfigVariant::UPDI)
&& (this->session.configVariant == Avr8ConfigVariant::XMEGA || this->session.configVariant == Avr8ConfigVariant::UPDI)
) {
memoryType = Avr8MemoryType::REGISTER_FILE;
}
@@ -743,14 +738,14 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
}
case TargetMemoryType::FLASH: {
if (
this->configVariant == Avr8ConfigVariant::DEBUG_WIRE
|| this->configVariant == Avr8ConfigVariant::UPDI
|| this->configVariant == Avr8ConfigVariant::MEGAJTAG
this->session.configVariant == Avr8ConfigVariant::DEBUG_WIRE
|| this->session.configVariant == Avr8ConfigVariant::UPDI
|| this->session.configVariant == Avr8ConfigVariant::MEGAJTAG
) {
avr8MemoryType = Avr8MemoryType::FLASH_PAGE;
} else if (this->configVariant == Avr8ConfigVariant::XMEGA) {
const auto bootSectionStartAddress = this->targetParameters.bootSectionStartAddress.value();
} else if (this->session.configVariant == Avr8ConfigVariant::XMEGA) {
const auto bootSectionStartAddress = this->session.programBootSection.value().get().startAddress;
if (startAddress >= bootSectionStartAddress) {
avr8MemoryType = Avr8MemoryType::BOOT_FLASH;
@@ -765,21 +760,21 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
* When using the APPL_FLASH memory type, the address should be relative to the start of the
* application section.
*/
startAddress -= this->targetParameters.appSectionStartAddress.value();
startAddress -= this->session.programAppSection.value().get().startAddress;
avr8MemoryType = Avr8MemoryType::APPL_FLASH;
}
}
break;
}
case TargetMemoryType::EEPROM: {
switch (this->configVariant) {
switch (this->session.configVariant) {
case Avr8ConfigVariant::UPDI:
case Avr8ConfigVariant::XMEGA: {
avr8MemoryType = Avr8MemoryType::EEPROM_ATOMIC;
if (this->configVariant == Avr8ConfigVariant::XMEGA) {
if (this->session.configVariant == Avr8ConfigVariant::XMEGA) {
// EEPROM addresses should be in relative form, for XMEGA (PDI) targets
startAddress -= this->targetParameters.eepromStartAddress.value();
startAddress -= this->session.eepromMemorySegment.startAddress;
}
break;
@@ -810,16 +805,16 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
}
void EdbgAvr8Interface::eraseProgramMemory(std::optional<Avr8Bit::ProgramMemorySection> section) {
if (this->configVariant == Avr8ConfigVariant::DEBUG_WIRE) {
if (this->session.configVariant == Avr8ConfigVariant::DEBUG_WIRE) {
// The EDBG erase command does not work on debugWire targets - we'll just write to the memory instead
return this->writeMemory(
TargetMemoryType::FLASH,
this->targetParameters.flashStartAddress.value(),
TargetMemoryBuffer(this->targetParameters.flashSize.value(), 0xFF)
this->session.programMemorySegment.startAddress,
TargetMemoryBuffer(this->session.programMemorySegment.size, 0xFF)
);
}
if (this->configVariant == Avr8ConfigVariant::XMEGA) {
if (this->session.configVariant == Avr8ConfigVariant::XMEGA) {
// For PDI (XMEGA) targets, we can erase flash memory without erasing EEPROM
if (!section.has_value() || *section == Avr8Bit::ProgramMemorySection::BOOT) {
@@ -908,7 +903,7 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
this->programmingModeEnabled = false;
if (this->configVariant == Avr8ConfigVariant::MEGAJTAG && this->reactivateJtagTargetPostProgrammingMode) {
if (this->session.configVariant == Avr8ConfigVariant::MEGAJTAG && this->reactivateJtagTargetPostProgrammingMode) {
this->deactivatePhysical();
this->targetAttached = false;
this->activate();
@@ -916,23 +911,7 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
}
void EdbgAvr8Interface::setTargetParameters() {
if (!this->targetParameters.stackPointerRegisterLowAddress.has_value()) {
throw DeviceInitializationFailure("Failed to find stack pointer register start address");
}
if (!this->targetParameters.stackPointerRegisterSize.has_value()) {
throw DeviceInitializationFailure("Failed to find stack pointer register size");
}
if (!this->targetParameters.statusRegisterStartAddress.has_value()) {
throw DeviceInitializationFailure("Failed to find status register start address");
}
if (!this->targetParameters.statusRegisterSize.has_value()) {
throw DeviceInitializationFailure("Failed to find status register size");
}
switch (this->configVariant) {
switch (this->session.configVariant) {
case Avr8ConfigVariant::DEBUG_WIRE:
case Avr8ConfigVariant::MEGAJTAG: {
this->setDebugWireAndJtagParameters();
@@ -952,76 +931,6 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
}
}
std::map<Family, std::map<TargetPhysicalInterface, Avr8ConfigVariant>>
EdbgAvr8Interface::getConfigVariantsByFamilyAndPhysicalInterface() {
return std::map<Family, std::map<TargetPhysicalInterface, Avr8ConfigVariant>>({
{
Family::MEGA,
{
{TargetPhysicalInterface::JTAG, Avr8ConfigVariant::MEGAJTAG},
{TargetPhysicalInterface::DEBUG_WIRE, Avr8ConfigVariant::DEBUG_WIRE},
{TargetPhysicalInterface::UPDI, Avr8ConfigVariant::UPDI},
}
},
{
Family::TINY,
{
{TargetPhysicalInterface::JTAG, Avr8ConfigVariant::MEGAJTAG},
{TargetPhysicalInterface::DEBUG_WIRE, Avr8ConfigVariant::DEBUG_WIRE},
{TargetPhysicalInterface::UPDI, Avr8ConfigVariant::UPDI},
}
},
{
Family::XMEGA,
{
{TargetPhysicalInterface::JTAG, Avr8ConfigVariant::XMEGA},
{TargetPhysicalInterface::PDI, Avr8ConfigVariant::XMEGA},
}
},
{
Family::DA,
{
{TargetPhysicalInterface::UPDI, Avr8ConfigVariant::UPDI},
}
},
{
Family::DB,
{
{TargetPhysicalInterface::UPDI, Avr8ConfigVariant::UPDI},
}
},
{
Family::DD,
{
{TargetPhysicalInterface::UPDI, Avr8ConfigVariant::UPDI},
}
},
{
Family::EA,
{
{TargetPhysicalInterface::UPDI, Avr8ConfigVariant::UPDI},
}
},
});
}
Avr8ConfigVariant EdbgAvr8Interface::resolveConfigVariant(
Targets::Microchip::Avr::Avr8Bit::Family targetFamily,
TargetPhysicalInterface physicalInterface
) {
const auto configVariantsByFamily = EdbgAvr8Interface::getConfigVariantsByFamilyAndPhysicalInterface();
const auto configVariantsByPhysicalInterfaceIt = configVariantsByFamily.find(targetFamily);
assert(configVariantsByPhysicalInterfaceIt != configVariantsByFamily.end());
const auto& configVariantsByPhysicalInterface = configVariantsByPhysicalInterfaceIt->second;
const auto configVariantIt = configVariantsByPhysicalInterface.find(physicalInterface);
assert(configVariantIt != configVariantsByPhysicalInterface.end());
return configVariantIt->second;
}
void EdbgAvr8Interface::setParameter(const Avr8EdbgParameter& parameter, const std::vector<unsigned char>& value) {
using Services::StringService;
@@ -1052,7 +961,7 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
}
void EdbgAvr8Interface::setDebugWireAndJtagParameters() {
const auto parameters = Parameters::Avr8Generic::DebugWireJtagParameters(this->targetDescriptionFile);
const auto parameters = Parameters::Avr8Generic::DebugWireJtagParameters(this->session.targetDescriptionFile);
Logger::debug("Setting FLASH_PAGE_SIZE AVR8 device parameter");
this->setParameter(Avr8EdbgParameters::DEVICE_FLASH_PAGE_SIZE, parameters.flashPageSize);
@@ -1103,7 +1012,7 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
}
void EdbgAvr8Interface::setPdiParameters() {
const auto parameters = Parameters::Avr8Generic::PdiParameters(this->targetDescriptionFile);
const auto parameters = Parameters::Avr8Generic::PdiParameters(this->session.targetDescriptionFile);
Logger::debug("Setting APPL_BASE_ADDR AVR8 parameter");
this->setParameter(Avr8EdbgParameters::DEVICE_XMEGA_APPL_BASE_ADDR, parameters.appSectionPdiOffset);
@@ -1152,7 +1061,7 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
}
void EdbgAvr8Interface::setUpdiParameters() {
const auto parameters = Parameters::Avr8Generic::UpdiParameters(this->targetDescriptionFile);
const auto parameters = Parameters::Avr8Generic::UpdiParameters(this->session.targetDescriptionFile);
/*
* The program memory base address field for UPDI sessions (DEVICE_UPDI_PROGMEM_BASE_ADDR) seems to be
@@ -1202,55 +1111,35 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
static_cast<std::uint8_t>(parameters.flashPageSize >> 8)
);
if (this->targetParameters.eepromPageSize.has_value()) {
Logger::debug("Setting UPDI_EEPROM_PAGE_SIZE AVR8 device parameter");
this->setParameter(Avr8EdbgParameters::DEVICE_UPDI_EEPROM_PAGE_SIZE, parameters.eepromPageSize);
}
Logger::debug("Setting UPDI_EEPROM_PAGE_SIZE AVR8 device parameter");
this->setParameter(Avr8EdbgParameters::DEVICE_UPDI_EEPROM_PAGE_SIZE, parameters.eepromPageSize);
if (this->targetParameters.nvmModuleBaseAddress.has_value()) {
Logger::debug("Setting UPDI_NVMCTRL_ADDR AVR8 device parameter");
this->setParameter(Avr8EdbgParameters::DEVICE_UPDI_NVMCTRL_ADDR, parameters.nvmModuleBaseAddress);
}
Logger::debug("Setting UPDI_NVMCTRL_ADDR AVR8 device parameter");
this->setParameter(Avr8EdbgParameters::DEVICE_UPDI_NVMCTRL_ADDR, parameters.nvmModuleBaseAddress);
if (this->targetParameters.ocdModuleAddress.has_value()) {
Logger::debug("Setting UPDI_OCD_ADDR AVR8 device parameter");
this->setParameter(Avr8EdbgParameters::DEVICE_UPDI_OCD_ADDR, parameters.ocdModuleAddress);
}
Logger::debug("Setting UPDI_OCD_ADDR AVR8 device parameter");
this->setParameter(Avr8EdbgParameters::DEVICE_UPDI_OCD_ADDR, parameters.ocdModuleAddress);
if (this->targetParameters.flashSize.has_value()) {
Logger::debug("Setting UPDI_FLASH_SIZE AVR8 device parameter");
this->setParameter(Avr8EdbgParameters::DEVICE_UPDI_FLASH_SIZE, parameters.flashSize);
}
Logger::debug("Setting UPDI_FLASH_SIZE AVR8 device parameter");
this->setParameter(Avr8EdbgParameters::DEVICE_UPDI_FLASH_SIZE, parameters.flashSize);
if (this->targetParameters.eepromSize.has_value()) {
Logger::debug("Setting UPDI_EEPROM_SIZE AVR8 device parameter");
this->setParameter(Avr8EdbgParameters::DEVICE_UPDI_EEPROM_SIZE, parameters.eepromSize);
}
Logger::debug("Setting UPDI_EEPROM_SIZE AVR8 device parameter");
this->setParameter(Avr8EdbgParameters::DEVICE_UPDI_EEPROM_SIZE, parameters.eepromSize);
if (this->targetParameters.eepromStartAddress.has_value()) {
Logger::debug("Setting UPDI_EEPROM_BASE_ADDR AVR8 device parameter");
this->setParameter(Avr8EdbgParameters::DEVICE_UPDI_EEPROM_BASE_ADDR, parameters.eepromStartAddress);
}
Logger::debug("Setting UPDI_EEPROM_BASE_ADDR AVR8 device parameter");
this->setParameter(Avr8EdbgParameters::DEVICE_UPDI_EEPROM_BASE_ADDR, parameters.eepromStartAddress);
if (this->targetParameters.signatureSegmentStartAddress.has_value()) {
Logger::debug("Setting UPDI_SIG_BASE_ADDR AVR8 device parameter");
this->setParameter(Avr8EdbgParameters::DEVICE_UPDI_SIG_BASE_ADDR, parameters.signatureSegmentStartAddress);
}
Logger::debug("Setting UPDI_SIG_BASE_ADDR AVR8 device parameter");
this->setParameter(Avr8EdbgParameters::DEVICE_UPDI_SIG_BASE_ADDR, parameters.signatureSegmentStartAddress);
if (this->targetParameters.fuseSegmentStartAddress.has_value()) {
Logger::debug("Setting UPDI_FUSE_BASE_ADDR AVR8 device parameter");
this->setParameter(Avr8EdbgParameters::DEVICE_UPDI_FUSE_BASE_ADDR, parameters.fuseSegmentStartAddress);
}
Logger::debug("Setting UPDI_FUSE_BASE_ADDR AVR8 device parameter");
this->setParameter(Avr8EdbgParameters::DEVICE_UPDI_FUSE_BASE_ADDR, parameters.fuseSegmentStartAddress);
if (this->targetParameters.fuseSegmentSize.has_value()) {
Logger::debug("Setting UPDI_FUSE_SIZE AVR8 device parameter");
this->setParameter(Avr8EdbgParameters::DEVICE_UPDI_FUSE_SIZE, parameters.fuseSegmentSize);
}
Logger::debug("Setting UPDI_FUSE_SIZE AVR8 device parameter");
this->setParameter(Avr8EdbgParameters::DEVICE_UPDI_FUSE_SIZE, parameters.fuseSegmentSize);
if (this->targetParameters.lockbitsSegmentStartAddress.has_value()) {
Logger::debug("Setting UPDI_LOCK_BASE_ADDR AVR8 device parameter");
this->setParameter(Avr8EdbgParameters::DEVICE_UPDI_LOCK_BASE_ADDR, parameters.lockbitSegmentStartAddress);
}
Logger::debug("Setting UPDI_LOCK_BASE_ADDR AVR8 device parameter");
this->setParameter(Avr8EdbgParameters::DEVICE_UPDI_LOCK_BASE_ADDR, parameters.lockbitSegmentStartAddress);
}
void EdbgAvr8Interface::activatePhysical(bool applyExternalReset) {
@@ -1295,7 +1184,7 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
*/
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
Attach(
this->configVariant != Avr8ConfigVariant::MEGAJTAG
this->session.configVariant != Avr8ConfigVariant::MEGAJTAG
)
);
@@ -1384,12 +1273,12 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
* align them - we've tried only word aligning them - the debug tool reports a "Too many or too few
* bytes" error.
*/
alignTo = this->targetParameters.flashPageSize.value();
alignTo = static_cast<std::uint16_t>(this->session.programMemorySegment.pageSize.value());
break;
}
case Avr8MemoryType::EEPROM_ATOMIC:
case Avr8MemoryType::EEPROM_PAGE: {
alignTo = this->targetParameters.eepromPageSize.value();
alignTo = static_cast<std::uint16_t>(this->session.eepromMemorySegment.pageSize.value());
break;
}
default: {
@@ -1418,12 +1307,12 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
case Avr8MemoryType::APPL_FLASH:
case Avr8MemoryType::BOOT_FLASH: {
// See comment in EdbgAvr8Interface::alignMemoryAddress()
alignTo = this->targetParameters.flashPageSize.value();
alignTo = static_cast<std::uint16_t>(this->session.programMemorySegment.pageSize.value());
break;
}
case Avr8MemoryType::EEPROM_ATOMIC:
case Avr8MemoryType::EEPROM_PAGE: {
alignTo = this->targetParameters.eepromPageSize.value();
alignTo = static_cast<std::uint16_t>(this->session.eepromMemorySegment.pageSize.value());
break;
}
default: {
@@ -1445,10 +1334,10 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
memoryType == Avr8MemoryType::FLASH_PAGE
|| memoryType == Avr8MemoryType::APPL_FLASH
|| memoryType == Avr8MemoryType::BOOT_FLASH
|| (memoryType == Avr8MemoryType::SPM && this->configVariant == Avr8ConfigVariant::MEGAJTAG)
|| (memoryType == Avr8MemoryType::SPM && this->session.configVariant == Avr8ConfigVariant::MEGAJTAG)
) {
// These flash memory types require single page access.
return this->targetParameters.flashPageSize.value();
return this->session.programMemorySegment.pageSize.value();
}
if (
@@ -1456,7 +1345,7 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
|| memoryType == Avr8MemoryType::EEPROM_PAGE
) {
// These EEPROM memory types requires single page access.
return this->targetParameters.eepromPageSize.value();
return this->session.eepromMemorySegment.pageSize.value();
}
if (this->maximumMemoryAccessSizePerRequest.has_value()) {
@@ -1485,7 +1374,7 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
const std::set<TargetMemoryAddress>& excludedAddresses
) {
if (type == Avr8MemoryType::FUSES) {
if (this->configVariant == Avr8ConfigVariant::DEBUG_WIRE) {
if (this->session.configVariant == Avr8ConfigVariant::DEBUG_WIRE) {
throw Exception("Cannot access AVR fuses via the debugWire interface");
}
}
@@ -1618,7 +1507,7 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
const TargetMemoryBuffer& buffer
) {
if (type == Avr8MemoryType::FUSES) {
if (this->configVariant == Avr8ConfigVariant::DEBUG_WIRE) {
if (this->session.configVariant == Avr8ConfigVariant::DEBUG_WIRE) {
throw Exception("Cannot access AVR fuses via the debugWire interface");
}
}

View File

@@ -10,11 +10,13 @@
#include "src/DebugToolDrivers/Microchip/Protocols/EDBG/EdbgInterface.hpp"
#include "Avr8Generic.hpp"
#include "EdbgAvr8Session.hpp"
#include "src/Targets/TargetPhysicalInterface.hpp"
#include "src/Targets/TargetMemory.hpp"
#include "src/Targets/TargetRegisterDescriptor.hpp"
#include "src/Targets/TargetRegister.hpp"
#include "src/Targets/Microchip/AVR/AVR8/TargetDescriptionFile.hpp"
#include "src/Targets/Microchip/AVR/AVR8/Family.hpp"
#include "src/Targets/Microchip/AVR/AVR8/TargetParameters.hpp"
@@ -34,10 +36,8 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
public:
explicit EdbgAvr8Interface(
EdbgInterface* edbgInterface,
const Targets::Microchip::Avr::Avr8Bit::Avr8TargetConfig& targetConfig,
Targets::Microchip::Avr::Avr8Bit::Family targetFamily,
const Targets::Microchip::Avr::Avr8Bit::TargetParameters& targetParameters,
const Targets::TargetRegisterDescriptorMapping& targetRegisterDescriptorsById
const Targets::Microchip::Avr::Avr8Bit::TargetDescriptionFile& targetDescriptionFile,
const Targets::Microchip::Avr::Avr8Bit::Avr8TargetConfig& targetConfig
);
/**
@@ -294,42 +294,9 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
EdbgInterface* edbgInterface = nullptr;
/**
* Project's AVR8 target configuration.
* The active EDBG AVR8 session.
*/
const Targets::Microchip::Avr::Avr8Bit::Avr8TargetConfig& targetConfig;
/**
* 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.
*/
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.
*/
Avr8ConfigFunction configFunction = Avr8ConfigFunction::DEBUGGING;
/**
* Configuring of the AVR8 Generic protocol depends on some characteristics of the target.
* The "AVR8_CONFIG_VARIANT" parameter allows us to determine which target parameters are required by the
* debug tool.
*/
Avr8ConfigVariant configVariant = Avr8ConfigVariant::NONE;
/**
* EDBG-based debug tools require target specific parameters such as memory locations, page sizes and
* register addresses. It is the AVR8 target's responsibility to obtain the required information and pass it
* to the Avr8Interface. See Avr8::getTargetParameters() and Avr8::postPromotionConfigure().
*
* For the EdbgAvr8Interface, we send the required parameters to the debug tool immediately upon receiving
* them. See EdbgAvr8Interface::setTargetParameters().
*/
const Targets::Microchip::Avr::Avr8Bit::TargetParameters& targetParameters;
const Targets::TargetRegisterDescriptorMapping& targetRegisterDescriptorsById;
EdbgAvr8Session session;
/**
* See the comment for EdbgAvr8Interface::setAvoidMaskedMemoryRead().
@@ -379,25 +346,6 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
*/
void setTargetParameters();
/**
* This mapping allows us to determine which config variant to select, based on the target family and the
* selected physical interface.
*/
static std::map<
Targets::Microchip::Avr::Avr8Bit::Family,
std::map<Targets::TargetPhysicalInterface, Avr8ConfigVariant>
> getConfigVariantsByFamilyAndPhysicalInterface();
/**
* Determines the config variant given a target family and physical interface.
*
* @return
*/
static Avr8ConfigVariant resolveConfigVariant(
Targets::Microchip::Avr::Avr8Bit::Family targetFamily,
Targets::TargetPhysicalInterface physicalInterface
);
/**
* Sets an AVR8 parameter on the debug tool. See the Avr8EdbgParameters class and protocol documentation
* for more on available parameters.
@@ -461,17 +409,15 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
* register addresses. These parameters can be sent to the tool before and during a session.
*
* What parameters we need to send depend on the physical interface (and config variant) selected by the user.
* For target parameters, the address (ID) of the parameter also varies across config variants. This is why
* we sometimes have separate parameters for sending the same data, where they differ only in parameter IDs
* (and sometimes size constraints). For example, the Avr8EdbgParameters::FLASH_PAGE_BYTES parameter is used
* to specify the size of a single page in flash memory. The parameter is assigned an address (ID) of 0x00. But
* the Avr8EdbgParameters::DEVICE_XMEGA_FLASH_PAGE_BYTES parameter is used to send the same data (flash page
* size), but only for sessions with the PDI physical interface. The address is 0x26.
* For target parameters, the address (ID) of the parameter also varies across config variants.
*
* - The setDebugWireAndJtagParameters() function sends the required target parameters for debugWire and JTAG
* sessions. Both sessions are covered in a single function because they require the same parameters.
* - The setPdiParameters() function sends the required target parameters for PDI sessions.
* - The setUpdiParameters() function sends the required target parameters for UPDI sessions.
*
* We extract the required parameters from the TDF. See the constructors for the `DebugWireJtagParameters`,
* `PdiParameters` and `UpdiParameters` structs for more.
*/
void setDebugWireAndJtagParameters();
void setPdiParameters();

View File

@@ -0,0 +1,99 @@
#include "EdbgAvr8Session.hpp"
#include "src/Services/StringService.hpp"
#include "src/Exceptions/Exception.hpp"
namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
{
EdbgAvr8Session::EdbgAvr8Session(
const Targets::Microchip::Avr::Avr8Bit::TargetDescriptionFile& targetDescriptionFile,
const Targets::Microchip::Avr::Avr8Bit::Avr8TargetConfig& targetConfig
)
: targetDescriptionFile(targetDescriptionFile)
, targetConfig(targetConfig)
, programAddressSpace(this->targetDescriptionFile.getProgramAddressSpace())
, ramAddressSpace(this->targetDescriptionFile.getRamAddressSpace())
, eepromAddressSpace(this->targetDescriptionFile.getEepromAddressSpace())
, ioAddressSpace(this->targetDescriptionFile.getIoAddressSpace())
, signatureAddressSpace(this->targetDescriptionFile.getSignatureAddressSpace())
, programMemorySegment(this->targetDescriptionFile.getProgramMemorySegment())
, ramMemorySegment(this->targetDescriptionFile.getRamMemorySegment())
, eepromMemorySegment(this->targetDescriptionFile.getEepromMemorySegment())
, ioMemorySegment(this->targetDescriptionFile.getIoMemorySegment())
, signatureMemorySegment(this->targetDescriptionFile.getSignatureMemorySegment())
, programAppSection(this->programMemorySegment.tryGetSection("app_section"))
, programBootSection(this->programMemorySegment.tryGetSection("boot_section"))
{
using Services::StringService;
const auto ocdDataRegisterProperty = this->targetDescriptionFile.tryGetProperty("ocd", "ocd_datareg");
if (ocdDataRegisterProperty.has_value()) {
this->ocdDataRegister = StringService::toUint8(ocdDataRegisterProperty->get().value);
}
const auto resolvedConfigVariant = EdbgAvr8Session::tryResolveConfigVariant(
this->targetDescriptionFile.getAvrFamily(),
this->targetConfig.physicalInterface
);
if (!resolvedConfigVariant.has_value()) {
throw Exceptions::Exception(
"Failed to resolve EDBG config variant from the selected physical interface and the AVR target family"
" - please review the selected physical interface"
);
}
this->configVariant = *resolvedConfigVariant;
}
std::optional<Avr8ConfigVariant> EdbgAvr8Session::tryResolveConfigVariant(
Targets::Microchip::Avr::Avr8Bit::Family avrFamily,
Targets::TargetPhysicalInterface physicalInterface
) {
using Targets::Microchip::Avr::Avr8Bit::Family;
using Targets::TargetPhysicalInterface;
if (avrFamily == Family::MEGA || avrFamily == Family::TINY) {
switch (physicalInterface) {
case TargetPhysicalInterface::JTAG: {
return Avr8ConfigVariant::MEGAJTAG;
}
case TargetPhysicalInterface::DEBUG_WIRE: {
return Avr8ConfigVariant::DEBUG_WIRE;
}
case TargetPhysicalInterface::UPDI: {
return Avr8ConfigVariant::UPDI;
}
default: {
break;
}
}
}
if (avrFamily == Family::XMEGA) {
switch (physicalInterface) {
case TargetPhysicalInterface::JTAG:
case TargetPhysicalInterface::PDI: {
return Avr8ConfigVariant::XMEGA;
}
default: {
break;
}
}
}
if (avrFamily == Family::DA || avrFamily == Family::DB || avrFamily == Family::DD || avrFamily == Family::EA) {
switch (physicalInterface) {
case TargetPhysicalInterface::UPDI: {
return Avr8ConfigVariant::UPDI;
}
default: {
break;
}
}
}
return std::nullopt;
}
}

View File

@@ -0,0 +1,82 @@
#pragma once
#include <cstdint>
#include <optional>
#include <functional>
#include "src/Targets/Microchip/AVR/AVR8/TargetDescriptionFile.hpp"
#include "src/Targets/Microchip/AVR/AVR8/Avr8TargetConfig.hpp"
#include "src/Targets/TargetMemorySegmentDescriptor.hpp"
#include "src/Targets/TargetRegisterDescriptor.hpp"
#include "Avr8Generic.hpp"
namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
{
/**
* This struct holds all required target info for an EDBG AVR8 session.
*/
struct EdbgAvr8Session
{
/**
* AVR8 TDF, from which we extract all target info to configure the EDBG debug tool.
*/
const Targets::Microchip::Avr::Avr8Bit::TargetDescriptionFile& targetDescriptionFile;
/**
* Project's AVR8 target configuration.
*/
const Targets::Microchip::Avr::Avr8Bit::Avr8TargetConfig& targetConfig;
/**
* The EDBG config variant parameter.
*
* See the "AVR8_CONFIG_VARIANT" parameter in section 7.1.3.1 of Microchip's "EDBG-based Tools Protocols"
* document for more.
*/
Avr8ConfigVariant configVariant = Avr8ConfigVariant::NONE;
const Targets::TargetDescription::AddressSpace& programAddressSpace;
const Targets::TargetDescription::AddressSpace& ramAddressSpace;
const Targets::TargetDescription::AddressSpace& eepromAddressSpace;
const Targets::TargetDescription::AddressSpace& ioAddressSpace;
const Targets::TargetDescription::AddressSpace& signatureAddressSpace;
const Targets::TargetDescription::MemorySegment& programMemorySegment;
const Targets::TargetDescription::MemorySegment& ramMemorySegment;
const Targets::TargetDescription::MemorySegment& eepromMemorySegment;
const Targets::TargetDescription::MemorySegment& ioMemorySegment;
const Targets::TargetDescription::MemorySegment& signatureMemorySegment;
const std::optional<
std::reference_wrapper<const Targets::TargetDescription::MemorySegmentSection>
> programAppSection;
const std::optional<
std::reference_wrapper<const Targets::TargetDescription::MemorySegmentSection>
> programBootSection;
std::optional<std::uint8_t> ocdDataRegister;
EdbgAvr8Session(
const Targets::Microchip::Avr::Avr8Bit::TargetDescriptionFile& targetDescriptionFile,
const Targets::Microchip::Avr::Avr8Bit::Avr8TargetConfig& targetConfig
);
private:
/**
* Attempts to determine the EDBG config variant for a given AVR family and physical interface.
*
* See the "AVR8_CONFIG_VARIANT" parameter in section 7.1.3.1 of Microchip's "EDBG-based Tools Protocols"
* document for more.
*
* @return
* The resolved config variant, or std::nullopt if the given AVR family and physical interface do not map to
* any particular EDBG config variant.
*/
static std::optional<Avr8ConfigVariant> tryResolveConfigVariant(
Targets::Microchip::Avr::Avr8Bit::Family avrFamily,
Targets::TargetPhysicalInterface physicalInterface
);
};
}

View File

@@ -50,27 +50,60 @@ namespace Targets::Microchip::Avr::Avr8Bit
return familyIt->second;
}
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");
}
const Targets::TargetDescription::MemorySegment& TargetDescriptionFile::getProgramMemorySegment() const {
return this->getAddressSpace("prog").getMemorySegment("internal_program_memory");
return this->getProgramAddressSpace().getMemorySegment("internal_program_memory");
}
const Targets::TargetDescription::MemorySegment& TargetDescriptionFile::getRamMemorySegment() const {
return this->getAddressSpace("data").getMemorySegment("internal_ram");
return this->getRamAddressSpace().getMemorySegment("internal_ram");
}
const Targets::TargetDescription::MemorySegment& TargetDescriptionFile::getEepromMemorySegment() const {
/*
* The EEPROM segment can sometimes be found within a dedicated address space, or within the data address
* space.
*/
const auto addressSpace = this->tryGetAddressSpace("eeprom");
return addressSpace.has_value()
? addressSpace->get().getMemorySegment("internal_eeprom")
: this->getAddressSpace("data").getMemorySegment("internal_eeprom");
return this->getEepromAddressSpace().getMemorySegment("internal_eeprom");
}
const Targets::TargetDescription::MemorySegment& TargetDescriptionFile::getIoMemorySegment() const {
const auto addressSpace = this->getAddressSpace("data");
const auto addressSpace = this->getIoAddressSpace();
const auto segment = addressSpace.tryGetMemorySegment("io");
return segment.has_value()
? segment->get()
@@ -78,36 +111,15 @@ namespace Targets::Microchip::Avr::Avr8Bit
}
const Targets::TargetDescription::MemorySegment& TargetDescriptionFile::getSignatureMemorySegment() const {
/*
* The signatures segment can sometimes be found within a dedicated address space, or within the data address
* space.
*/
const auto addressSpace = this->tryGetAddressSpace("signatures");
return addressSpace.has_value()
? addressSpace->get().getMemorySegment("signatures")
: this->getAddressSpace("data").getMemorySegment("signatures");
return this->getSignatureAddressSpace().getMemorySegment("signatures");
}
const Targets::TargetDescription::MemorySegment& TargetDescriptionFile::getFuseMemorySegment() const {
/*
* The fuses segment can sometimes be found within a dedicated address space, or within the data address
* space.
*/
const auto addressSpace = this->tryGetAddressSpace("fuses");
return addressSpace.has_value()
? addressSpace->get().getMemorySegment("fuses")
: this->getAddressSpace("data").getMemorySegment("fuses");
return this->getFuseAddressSpace().getMemorySegment("fuses");
}
const Targets::TargetDescription::MemorySegment& TargetDescriptionFile::getLockbitMemorySegment() const {
/*
* The lockbits segment can sometimes be found within a dedicated address space, or within the data address
* space.
*/
const auto addressSpace = this->tryGetAddressSpace("lockbits");
return addressSpace.has_value()
? addressSpace->get().getMemorySegment("lockbits")
: this->getAddressSpace("data").getMemorySegment("lockbits");
return this->getLockbitAddressSpace().getMemorySegment("lockbits");
}
TargetParameters TargetDescriptionFile::getTargetParameters() const {

View File

@@ -54,6 +54,14 @@ namespace Targets::Microchip::Avr::Avr8Bit
*/
[[nodiscard]] Family getAvrFamily() const;
[[nodiscard]] const Targets::TargetDescription::AddressSpace& getProgramAddressSpace() const;
[[nodiscard]] const Targets::TargetDescription::AddressSpace& getRamAddressSpace() const;
[[nodiscard]] const Targets::TargetDescription::AddressSpace& getEepromAddressSpace() const;
[[nodiscard]] const Targets::TargetDescription::AddressSpace& getIoAddressSpace() const;
[[nodiscard]] const Targets::TargetDescription::AddressSpace& getSignatureAddressSpace() const;
[[nodiscard]] const Targets::TargetDescription::AddressSpace& getFuseAddressSpace() const;
[[nodiscard]] const Targets::TargetDescription::AddressSpace& getLockbitAddressSpace() const;
[[nodiscard]] const Targets::TargetDescription::MemorySegment& getProgramMemorySegment() const;
[[nodiscard]] const Targets::TargetDescription::MemorySegment& getRamMemorySegment() const;
[[nodiscard]] const Targets::TargetDescription::MemorySegment& getEepromMemorySegment() const;