diff --git a/src/DebugToolDrivers/CMakeLists.txt b/src/DebugToolDrivers/CMakeLists.txt index 81856dc0..479fa601 100755 --- a/src/DebugToolDrivers/CMakeLists.txt +++ b/src/DebugToolDrivers/CMakeLists.txt @@ -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 diff --git a/src/DebugToolDrivers/Microchip/Protocols/EDBG/AVR/EdbgAvr8Interface.cpp b/src/DebugToolDrivers/Microchip/Protocols/EDBG/AVR/EdbgAvr8Interface.cpp index df9d44d3..ca3d3625 100644 --- a/src/DebugToolDrivers/Microchip/Protocols/EDBG/AVR/EdbgAvr8Interface.cpp +++ b/src/DebugToolDrivers/Microchip/Protocols/EDBG/AVR/EdbgAvr8Interface.cpp @@ -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(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(1800)); this->setParameter(Avr8EdbgParameters::ENABLE_HIGH_VOLTAGE_UPDI, static_cast(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(200)); @@ -130,17 +125,17 @@ namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr this->setParameter( Avr8EdbgParameters::CONFIG_VARIANT, - static_cast(this->configVariant) + static_cast(this->session.configVariant) ); this->setParameter( Avr8EdbgParameters::CONFIG_FUNCTION, - static_cast(this->configFunction) + static_cast(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 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> - EdbgAvr8Interface::getConfigVariantsByFamilyAndPhysicalInterface() { - return std::map>({ - { - 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& 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(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(this->session.programMemorySegment.pageSize.value()); break; } case Avr8MemoryType::EEPROM_ATOMIC: case Avr8MemoryType::EEPROM_PAGE: { - alignTo = this->targetParameters.eepromPageSize.value(); + alignTo = static_cast(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(this->session.programMemorySegment.pageSize.value()); break; } case Avr8MemoryType::EEPROM_ATOMIC: case Avr8MemoryType::EEPROM_PAGE: { - alignTo = this->targetParameters.eepromPageSize.value(); + alignTo = static_cast(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& 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"); } } diff --git a/src/DebugToolDrivers/Microchip/Protocols/EDBG/AVR/EdbgAvr8Interface.hpp b/src/DebugToolDrivers/Microchip/Protocols/EDBG/AVR/EdbgAvr8Interface.hpp index 62294b11..d994b427 100644 --- a/src/DebugToolDrivers/Microchip/Protocols/EDBG/AVR/EdbgAvr8Interface.hpp +++ b/src/DebugToolDrivers/Microchip/Protocols/EDBG/AVR/EdbgAvr8Interface.hpp @@ -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 - > 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(); diff --git a/src/DebugToolDrivers/Microchip/Protocols/EDBG/AVR/EdbgAvr8Session.cpp b/src/DebugToolDrivers/Microchip/Protocols/EDBG/AVR/EdbgAvr8Session.cpp new file mode 100644 index 00000000..a86c7eb7 --- /dev/null +++ b/src/DebugToolDrivers/Microchip/Protocols/EDBG/AVR/EdbgAvr8Session.cpp @@ -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 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; + } +} diff --git a/src/DebugToolDrivers/Microchip/Protocols/EDBG/AVR/EdbgAvr8Session.hpp b/src/DebugToolDrivers/Microchip/Protocols/EDBG/AVR/EdbgAvr8Session.hpp new file mode 100644 index 00000000..e6a1b5bc --- /dev/null +++ b/src/DebugToolDrivers/Microchip/Protocols/EDBG/AVR/EdbgAvr8Session.hpp @@ -0,0 +1,82 @@ +#pragma once + +#include +#include +#include + +#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 + > programAppSection; + + const std::optional< + std::reference_wrapper + > programBootSection; + + std::optional 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 tryResolveConfigVariant( + Targets::Microchip::Avr::Avr8Bit::Family avrFamily, + Targets::TargetPhysicalInterface physicalInterface + ); + }; +} diff --git a/src/Targets/Microchip/AVR/AVR8/TargetDescriptionFile.cpp b/src/Targets/Microchip/AVR/AVR8/TargetDescriptionFile.cpp index e3f4ed37..defb37ac 100644 --- a/src/Targets/Microchip/AVR/AVR8/TargetDescriptionFile.cpp +++ b/src/Targets/Microchip/AVR/AVR8/TargetDescriptionFile.cpp @@ -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 { diff --git a/src/Targets/Microchip/AVR/AVR8/TargetDescriptionFile.hpp b/src/Targets/Microchip/AVR/AVR8/TargetDescriptionFile.hpp index 5d0c2718..97d334ba 100644 --- a/src/Targets/Microchip/AVR/AVR8/TargetDescriptionFile.hpp +++ b/src/Targets/Microchip/AVR/AVR8/TargetDescriptionFile.hpp @@ -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;