Refactored AVR8 TDF loading
Refactored EDBG AVR8 target parameter uploading Implemented UPDI parameter extraction (from TDF) and uploading to debug tool Introduced supported physical interfaces in AVR8 TDFs
This commit is contained in:
@@ -20,7 +20,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||
constexpr static Avr8EdbgParameter CONFIG_FUNCTION {0x00, 0x01};
|
||||
constexpr static Avr8EdbgParameter PHYSICAL_INTERFACE {0x01, 0x00};
|
||||
constexpr static Avr8EdbgParameter DW_CLOCK_DIVISION_FACTOR {0x01, 0x10};
|
||||
constexpr static Avr8EdbgParameter XMEGA_PDI_CLOCK {0x01, 0x31};
|
||||
constexpr static Avr8EdbgParameter PDI_CLOCK_SPEED {0x01, 0x31};
|
||||
constexpr static Avr8EdbgParameter MEGA_DEBUG_CLOCK {0x01, 0x21};
|
||||
constexpr static Avr8EdbgParameter JTAG_DAISY_CHAIN_SETTINGS {0x01, 0x01};
|
||||
|
||||
@@ -58,7 +58,28 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||
constexpr static Avr8EdbgParameter DEVICE_XMEGA_EEPROM_SIZE {0x02, 0x28};
|
||||
constexpr static Avr8EdbgParameter DEVICE_XMEGA_EEPROM_PAGE_SIZE {0x02, 0x2A};
|
||||
|
||||
// UPDI device parameters
|
||||
constexpr static Avr8EdbgParameter DEVICE_UPDI_PROGMEM_BASE_ADDR {0x02, 0x00};
|
||||
constexpr static Avr8EdbgParameter DEVICE_UPDI_FLASH_PAGE_SIZE {0x02, 0x02};
|
||||
constexpr static Avr8EdbgParameter DEVICE_UPDI_EEPROM_PAGE_SIZE {0x02, 0x03};
|
||||
constexpr static Avr8EdbgParameter DEVICE_UPDI_NVMCTRL_ADDR {0x02, 0x04};
|
||||
constexpr static Avr8EdbgParameter DEVICE_UPDI_OCD_ADDR {0x02, 0x06};
|
||||
constexpr static Avr8EdbgParameter DEVICE_UPDI_FLASH_SIZE {0x02, 0x12};
|
||||
constexpr static Avr8EdbgParameter DEVICE_UPDI_EEPROM_SIZE {0x02, 0x16};
|
||||
constexpr static Avr8EdbgParameter DEVICE_UPDI_USER_SIG_SIZE {0x02, 0x18};
|
||||
constexpr static Avr8EdbgParameter DEVICE_UPDI_FUSE_SIZE {0x02, 0x1A};
|
||||
constexpr static Avr8EdbgParameter DEVICE_UPDI_EEPROM_BASE_ADDR {0x02, 0x20};
|
||||
constexpr static Avr8EdbgParameter DEVICE_UPDI_USER_SIG_BASE_ADDR {0x02, 0x22};
|
||||
constexpr static Avr8EdbgParameter DEVICE_UPDI_SIG_BASE_ADDR {0x02, 0x24};
|
||||
constexpr static Avr8EdbgParameter DEVICE_UPDI_FUSE_BASE_ADDR {0x02, 0x26};
|
||||
constexpr static Avr8EdbgParameter DEVICE_UPDI_LOCK_BASE_ADDR {0x02, 0x28};
|
||||
constexpr static Avr8EdbgParameter DEVICE_UPDI_DEVICE_ID {0x02, 0x2A};
|
||||
constexpr static Avr8EdbgParameter DEVICE_UPDI_PROGMEM_BASE_ADDR_MSB {0x02, 0x2C};
|
||||
constexpr static Avr8EdbgParameter DEVICE_UPDI_FLASH_PAGE_SIZE_MSB {0x02, 0x2D};
|
||||
constexpr static Avr8EdbgParameter DEVICE_UPDI_24_BIT_ADDRESSING_ENABLE {0x02, 0x2E};
|
||||
|
||||
constexpr static Avr8EdbgParameter RUN_TIMERS_WHILST_STOPPED {0x03, 0x00};
|
||||
constexpr static Avr8EdbgParameter ENABLE_HIGH_VOLTAGE_UPDI {0x03, 0x06};
|
||||
};
|
||||
|
||||
enum class Avr8ConfigVariant: unsigned char
|
||||
@@ -148,4 +169,12 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||
DATA = 0x84,
|
||||
FAILED = 0xA0,
|
||||
};
|
||||
|
||||
inline bool operator == (unsigned char rawId, Avr8ResponseId id) {
|
||||
return static_cast<unsigned char>(id) == rawId;
|
||||
}
|
||||
|
||||
inline bool operator == (Avr8ResponseId id, unsigned char rawId) {
|
||||
return rawId == id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,408 @@ std::vector<unsigned char> EdbgAvr8Interface::getParameter(const Avr8EdbgParamet
|
||||
return response.getPayloadData();
|
||||
}
|
||||
|
||||
void EdbgAvr8Interface::setDebugWireAndJtagParameters() {
|
||||
if (this->targetParameters.flashPageSize.has_value()) {
|
||||
Logger::debug("Setting DEVICE_FLASH_PAGE_SIZE AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_FLASH_PAGE_SIZE,
|
||||
this->targetParameters.flashPageSize.value()
|
||||
);
|
||||
}
|
||||
|
||||
if (this->targetParameters.flashSize.has_value()) {
|
||||
Logger::debug("Setting DEVICE_FLASH_SIZE AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_FLASH_SIZE,
|
||||
this->targetParameters.flashSize.value()
|
||||
);
|
||||
}
|
||||
|
||||
if (this->targetParameters.flashStartAddress.has_value()) {
|
||||
Logger::debug("Setting DEVICE_FLASH_BASE AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_FLASH_BASE,
|
||||
this->targetParameters.flashStartAddress.value()
|
||||
);
|
||||
}
|
||||
|
||||
if (this->targetParameters.ramStartAddress.has_value()) {
|
||||
Logger::debug("Setting DEVICE_SRAM_START AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_SRAM_START,
|
||||
this->targetParameters.ramStartAddress.value()
|
||||
);
|
||||
}
|
||||
|
||||
if (this->targetParameters.eepromSize.has_value()) {
|
||||
Logger::debug("Setting DEVICE_EEPROM_SIZE AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_EEPROM_SIZE,
|
||||
this->targetParameters.eepromSize.value()
|
||||
);
|
||||
}
|
||||
|
||||
if (this->targetParameters.eepromPageSize.has_value()) {
|
||||
Logger::debug("Setting DEVICE_EEPROM_PAGE_SIZE AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_EEPROM_PAGE_SIZE,
|
||||
this->targetParameters.eepromPageSize.value()
|
||||
);
|
||||
}
|
||||
|
||||
if (this->targetParameters.ocdRevision.has_value()) {
|
||||
Logger::debug("Setting DEVICE_OCD_REVISION AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_OCD_REVISION,
|
||||
this->targetParameters.ocdRevision.value()
|
||||
);
|
||||
}
|
||||
|
||||
if (this->targetParameters.ocdDataRegister.has_value()) {
|
||||
Logger::debug("Setting DEVICE_OCD_DATA_REGISTER AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_OCD_DATA_REGISTER,
|
||||
this->targetParameters.ocdDataRegister.value()
|
||||
);
|
||||
}
|
||||
|
||||
if (this->targetParameters.spmcRegisterStartAddress.has_value()) {
|
||||
Logger::debug("Setting DEVICE_SPMCR_REGISTER AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_SPMCR_REGISTER,
|
||||
this->targetParameters.spmcRegisterStartAddress.value()
|
||||
);
|
||||
}
|
||||
|
||||
if (this->targetParameters.osccalAddress.has_value()) {
|
||||
Logger::debug("Setting DEVICE_OSCCAL_ADDR AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_OSCCAL_ADDR,
|
||||
this->targetParameters.osccalAddress.value()
|
||||
);
|
||||
}
|
||||
|
||||
if (this->targetParameters.eepromAddressRegisterLow.has_value()) {
|
||||
Logger::debug("Setting DEVICE_EEARL_ADDR AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_EEARL_ADDR,
|
||||
this->targetParameters.eepromAddressRegisterLow.value()
|
||||
);
|
||||
}
|
||||
|
||||
if (this->targetParameters.eepromAddressRegisterHigh.has_value()) {
|
||||
Logger::debug("Setting DEVICE_EEARH_ADDR AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_EEARH_ADDR,
|
||||
this->targetParameters.eepromAddressRegisterHigh.value()
|
||||
);
|
||||
}
|
||||
|
||||
if (this->targetParameters.eepromControlRegisterAddress.has_value()) {
|
||||
Logger::debug("Setting DEVICE_EECR_ADDR AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_EECR_ADDR,
|
||||
this->targetParameters.eepromControlRegisterAddress.value()
|
||||
);
|
||||
}
|
||||
|
||||
if (this->targetParameters.eepromDataRegisterAddress.has_value()) {
|
||||
Logger::debug("Setting DEVICE_EEDR_ADDR AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_EEDR_ADDR,
|
||||
this->targetParameters.eepromDataRegisterAddress.value()
|
||||
);
|
||||
}
|
||||
|
||||
if (this->targetParameters.bootSectionStartAddress.has_value()) {
|
||||
Logger::debug("Setting DEVICE_BOOT_START_ADDR AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_BOOT_START_ADDR,
|
||||
this->targetParameters.bootSectionStartAddress.value()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void EdbgAvr8Interface::setPdiParameters() {
|
||||
if (!this->targetParameters.appSectionPdiOffset.has_value()) {
|
||||
throw Exception("Missing required parameter: APPL_BASE_ADDR");
|
||||
}
|
||||
|
||||
if (!this->targetParameters.bootSectionPdiOffset.has_value()) {
|
||||
throw Exception("Missing required parameter: BOOT_BASE_ADDR");
|
||||
}
|
||||
|
||||
if (!this->targetParameters.bootSectionSize.has_value()) {
|
||||
throw Exception("Missing required parameter: BOOT_BYTES");
|
||||
}
|
||||
|
||||
if (!this->targetParameters.flashSize.has_value()) {
|
||||
throw Exception("Missing required parameter: APPLICATION_BYTES");
|
||||
}
|
||||
|
||||
if (!this->targetParameters.eepromPdiOffset.has_value()) {
|
||||
throw Exception("Missing required parameter: EEPROM_BASE_ADDR");
|
||||
}
|
||||
|
||||
if (!this->targetParameters.fuseRegistersPdiOffset.has_value()) {
|
||||
throw Exception("Missing required parameter: FUSE_BASE_ADDR");
|
||||
}
|
||||
|
||||
if (!this->targetParameters.lockRegistersPdiOffset.has_value()) {
|
||||
throw Exception("Missing required parameter: LOCKBIT_BASE_ADDR");
|
||||
}
|
||||
|
||||
if (!this->targetParameters.userSignaturesPdiOffset.has_value()) {
|
||||
throw Exception("Missing required parameter: USER_SIGN_BASE_ADDR");
|
||||
}
|
||||
|
||||
if (!this->targetParameters.productSignaturesPdiOffset.has_value()) {
|
||||
throw Exception("Missing required parameter: PROD_SIGN_BASE_ADDR");
|
||||
}
|
||||
|
||||
if (!this->targetParameters.ramPdiOffset.has_value()) {
|
||||
throw Exception("Missing required parameter: DATA_BASE_ADDR");
|
||||
}
|
||||
|
||||
if (!this->targetParameters.flashPageSize.has_value()) {
|
||||
throw Exception("Missing required parameter: FLASH_PAGE_BYTES");
|
||||
}
|
||||
|
||||
if (!this->targetParameters.eepromSize.has_value()) {
|
||||
throw Exception("Missing required parameter: EEPROM_SIZE");
|
||||
}
|
||||
|
||||
if (!this->targetParameters.eepromPageSize.has_value()) {
|
||||
throw Exception("Missing required parameter: EEPROM_PAGE_SIZE");
|
||||
}
|
||||
|
||||
if (!this->targetParameters.nvmBaseAddress.has_value()) {
|
||||
throw Exception("Missing required parameter: NVM_BASE");
|
||||
}
|
||||
|
||||
Logger::debug("Setting APPL_BASE_ADDR AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_XMEGA_APPL_BASE_ADDR,
|
||||
this->targetParameters.appSectionPdiOffset.value()
|
||||
);
|
||||
|
||||
Logger::debug("Setting BOOT_BASE_ADDR AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_XMEGA_BOOT_BASE_ADDR,
|
||||
this->targetParameters.bootSectionPdiOffset.value()
|
||||
);
|
||||
|
||||
Logger::debug("Setting EEPROM_BASE_ADDR AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_XMEGA_EEPROM_BASE_ADDR,
|
||||
this->targetParameters.eepromPdiOffset.value()
|
||||
);
|
||||
|
||||
Logger::debug("Setting FUSE_BASE_ADDR AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_XMEGA_FUSE_BASE_ADDR,
|
||||
this->targetParameters.fuseRegistersPdiOffset.value()
|
||||
);
|
||||
|
||||
Logger::debug("Setting LOCKBIT_BASE_ADDR AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_XMEGA_LOCKBIT_BASE_ADDR,
|
||||
this->targetParameters.lockRegistersPdiOffset.value()
|
||||
);
|
||||
|
||||
Logger::debug("Setting USER_SIGN_BASE_ADDR AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_XMEGA_USER_SIGN_BASE_ADDR,
|
||||
this->targetParameters.userSignaturesPdiOffset.value()
|
||||
);
|
||||
|
||||
Logger::debug("Setting PROD_SIGN_BASE_ADDR AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_XMEGA_PROD_SIGN_BASE_ADDR,
|
||||
this->targetParameters.productSignaturesPdiOffset.value()
|
||||
);
|
||||
|
||||
Logger::debug("Setting DATA_BASE_ADDR AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_XMEGA_DATA_BASE_ADDR,
|
||||
this->targetParameters.ramPdiOffset.value()
|
||||
);
|
||||
|
||||
Logger::debug("Setting APPLICATION_BYTES AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_XMEGA_APPLICATION_BYTES,
|
||||
this->targetParameters.flashSize.value()
|
||||
);
|
||||
|
||||
Logger::debug("Setting BOOT_BYTES AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_XMEGA_BOOT_BYTES,
|
||||
this->targetParameters.bootSectionSize.value()
|
||||
);
|
||||
|
||||
Logger::debug("Setting FLASH_PAGE_BYTES AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_XMEGA_FLASH_PAGE_BYTES,
|
||||
this->targetParameters.flashPageSize.value()
|
||||
);
|
||||
|
||||
Logger::debug("Setting EEPROM_SIZE AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_XMEGA_EEPROM_SIZE,
|
||||
this->targetParameters.eepromSize.value()
|
||||
);
|
||||
|
||||
Logger::debug("Setting EEPROM_PAGE_SIZE AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_XMEGA_EEPROM_PAGE_SIZE,
|
||||
static_cast<unsigned char>(this->targetParameters.eepromPageSize.value())
|
||||
);
|
||||
|
||||
Logger::debug("Setting NVM_BASE AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_XMEGA_NVM_BASE,
|
||||
this->targetParameters.nvmBaseAddress.value()
|
||||
);
|
||||
}
|
||||
|
||||
void EdbgAvr8Interface::setUpdiParameters() {
|
||||
if (!this->targetParameters.signatureSegmentStartAddress.has_value()) {
|
||||
throw Exception("Missing required parameter: SIGNATURE BASE ADDRESS");
|
||||
}
|
||||
|
||||
if (this->targetParameters.programMemoryUpdiStartAddress.has_value()) {
|
||||
/*
|
||||
* The program memory base address field for UPDI sessions (DEVICE_UPDI_PROGMEM_BASE_ADDR) seems to be limited
|
||||
* to two bytes in size, as opposed to the four byte size for the debugWire, JTAG and PDI equivalent fields.
|
||||
* This is why, I suspect, another field was required for the most significant byte of the program memory base
|
||||
* address (DEVICE_UPDI_PROGMEM_BASE_ADDR_MSB).
|
||||
*
|
||||
* The additional DEVICE_UPDI_PROGMEM_BASE_ADDR_MSB field is only one byte in size, so it brings the total
|
||||
* capacity for the program memory base address to three bytes. Because of this, we ensure that all TDFs, for
|
||||
* targets that support UPDI, specify an address that does not exceed the maximum value of a 24 bit unsigned
|
||||
* integer. This is done in our TDF validation script (see src/Targets/TargetDescription/README.md for more).
|
||||
*/
|
||||
auto programMemBaseAddress = this->targetParameters.programMemoryUpdiStartAddress.value();
|
||||
Logger::debug("Setting DEVICE_UPDI_PROGMEM_BASE_ADDR AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_UPDI_PROGMEM_BASE_ADDR,
|
||||
static_cast<std::uint16_t>(programMemBaseAddress)
|
||||
);
|
||||
|
||||
Logger::debug("Setting DEVICE_UPDI_PROGMEM_BASE_ADDR_MSB AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_UPDI_PROGMEM_BASE_ADDR_MSB,
|
||||
static_cast<std::uint8_t>(programMemBaseAddress >> 16)
|
||||
);
|
||||
}
|
||||
|
||||
if (this->targetParameters.flashPageSize.has_value()) {
|
||||
/*
|
||||
* See the comment above regarding capacity limitations of the DEVICE_UPDI_PROGMEM_BASE_ADDR field.
|
||||
*
|
||||
* The same applies here, for the flash page size field (DEVICE_UPDI_FLASH_PAGE_SIZE).
|
||||
*/
|
||||
auto flashPageSize = this->targetParameters.flashPageSize.value();
|
||||
Logger::debug("Setting DEVICE_UPDI_FLASH_PAGE_SIZE AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_UPDI_FLASH_PAGE_SIZE,
|
||||
static_cast<std::uint8_t>(flashPageSize)
|
||||
);
|
||||
|
||||
Logger::debug("Setting DEVICE_UPDI_FLASH_PAGE_SIZE_MSB AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_UPDI_FLASH_PAGE_SIZE_MSB,
|
||||
static_cast<std::uint8_t>(flashPageSize >> 8)
|
||||
);
|
||||
}
|
||||
|
||||
if (this->targetParameters.eepromPageSize.has_value()) {
|
||||
Logger::debug("Setting DEVICE_UPDI_EEPROM_PAGE_SIZE AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_UPDI_EEPROM_PAGE_SIZE,
|
||||
this->targetParameters.eepromPageSize.value()
|
||||
);
|
||||
}
|
||||
|
||||
if (this->targetParameters.nvmBaseAddress.has_value()) {
|
||||
Logger::debug("Setting DEVICE_UPDI_NVMCTRL_ADDR AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_UPDI_NVMCTRL_ADDR,
|
||||
this->targetParameters.nvmBaseAddress.value()
|
||||
);
|
||||
}
|
||||
|
||||
if (this->targetParameters.ocdModuleAddress.has_value()) {
|
||||
Logger::debug("Setting DEVICE_UPDI_OCD_ADDR AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_UPDI_OCD_ADDR,
|
||||
this->targetParameters.ocdModuleAddress.value()
|
||||
);
|
||||
}
|
||||
|
||||
if (this->targetParameters.flashSize.has_value()) {
|
||||
Logger::debug("Setting DEVICE_UPDI_FLASH_SIZE AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_UPDI_FLASH_SIZE,
|
||||
this->targetParameters.flashSize.value()
|
||||
);
|
||||
}
|
||||
|
||||
if (this->targetParameters.eepromSize.has_value()) {
|
||||
Logger::debug("Setting DEVICE_UPDI_EEPROM_SIZE AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_UPDI_EEPROM_SIZE,
|
||||
this->targetParameters.eepromSize.value()
|
||||
);
|
||||
}
|
||||
|
||||
if (this->targetParameters.eepromStartAddress.has_value()) {
|
||||
Logger::debug("Setting DEVICE_UPDI_EEPROM_BASE_ADDR AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_UPDI_EEPROM_BASE_ADDR,
|
||||
this->targetParameters.eepromStartAddress.value()
|
||||
);
|
||||
}
|
||||
|
||||
if (this->targetParameters.signatureSegmentStartAddress.has_value()) {
|
||||
Logger::debug("Setting DEVICE_UPDI_SIG_BASE_ADDR AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_UPDI_SIG_BASE_ADDR,
|
||||
this->targetParameters.signatureSegmentStartAddress.value()
|
||||
);
|
||||
}
|
||||
|
||||
if (this->targetParameters.fuseSegmentStartAddress.has_value()) {
|
||||
Logger::debug("Setting DEVICE_UPDI_FUSE_BASE_ADDR AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_UPDI_FUSE_BASE_ADDR,
|
||||
this->targetParameters.fuseSegmentStartAddress.value()
|
||||
);
|
||||
}
|
||||
|
||||
if (this->targetParameters.fuseSegmentSize.has_value()) {
|
||||
Logger::debug("Setting DEVICE_UPDI_FUSE_SIZE AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_UPDI_FUSE_SIZE,
|
||||
this->targetParameters.fuseSegmentSize.value()
|
||||
);
|
||||
}
|
||||
|
||||
if (this->targetParameters.lockbitsSegmentStartAddress.has_value()) {
|
||||
Logger::debug("Setting DEVICE_UPDI_LOCK_BASE_ADDR AVR8 parameter");
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_UPDI_LOCK_BASE_ADDR,
|
||||
this->targetParameters.lockbitsSegmentStartAddress.value()
|
||||
);
|
||||
}
|
||||
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::DEVICE_UPDI_24_BIT_ADDRESSING_ENABLE,
|
||||
this->targetParameters.programMemoryUpdiStartAddress.value_or(0) > 0xFFFF ?
|
||||
static_cast<std::uint8_t>(1) : static_cast<std::uint8_t>(0)
|
||||
);
|
||||
}
|
||||
|
||||
void EdbgAvr8Interface::configure(const TargetConfig& targetConfig) {
|
||||
auto physicalInterface = targetConfig.jsonObject.find("physicalInterface")->toString().toLower().toStdString();
|
||||
|
||||
@@ -124,179 +526,22 @@ void EdbgAvr8Interface::setTargetParameters(const Avr8Bit::TargetParameters& con
|
||||
this->configVariant = configVariant.value();
|
||||
}
|
||||
|
||||
if (this->configVariant == Avr8ConfigVariant::XMEGA) {
|
||||
if (!config.appSectionPdiOffset.has_value()) {
|
||||
throw Exception("Missing required parameter: APPL_BASE_ADDR");
|
||||
switch (this->configVariant) {
|
||||
case Avr8ConfigVariant::DEBUG_WIRE:
|
||||
case Avr8ConfigVariant::MEGAJTAG: {
|
||||
this->setDebugWireAndJtagParameters();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!config.bootSectionPdiOffset.has_value()) {
|
||||
throw Exception("Missing required parameter: BOOT_BASE_ADDR");
|
||||
case Avr8ConfigVariant::XMEGA: {
|
||||
this->setPdiParameters();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!config.bootSectionSize.has_value()) {
|
||||
throw Exception("Missing required parameter: BOOT_BYTES");
|
||||
case Avr8ConfigVariant::UPDI: {
|
||||
this->setUpdiParameters();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!config.flashSize.has_value()) {
|
||||
throw Exception("Missing required parameter: APPLICATION_BYTES");
|
||||
}
|
||||
|
||||
if (!config.eepromPdiOffset.has_value()) {
|
||||
throw Exception("Missing required parameter: EEPROM_BASE_ADDR");
|
||||
}
|
||||
|
||||
if (!config.fuseRegistersPdiOffset.has_value()) {
|
||||
throw Exception("Missing required parameter: FUSE_BASE_ADDR");
|
||||
}
|
||||
|
||||
if (!config.lockRegistersPdiOffset.has_value()) {
|
||||
throw Exception("Missing required parameter: LOCKBIT_BASE_ADDR");
|
||||
}
|
||||
|
||||
if (!config.userSignaturesPdiOffset.has_value()) {
|
||||
throw Exception("Missing required parameter: USER_SIGN_BASE_ADDR");
|
||||
}
|
||||
|
||||
if (!config.productSignaturesPdiOffset.has_value()) {
|
||||
throw Exception("Missing required parameter: PROD_SIGN_BASE_ADDR");
|
||||
}
|
||||
|
||||
if (!config.ramPdiOffset.has_value()) {
|
||||
throw Exception("Missing required parameter: DATA_BASE_ADDR");
|
||||
}
|
||||
|
||||
if (!config.flashPageSize.has_value()) {
|
||||
throw Exception("Missing required parameter: FLASH_PAGE_BYTES");
|
||||
}
|
||||
|
||||
if (!config.eepromSize.has_value()) {
|
||||
throw Exception("Missing required parameter: EEPROM_SIZE");
|
||||
}
|
||||
|
||||
if (!config.eepromPageSize.has_value()) {
|
||||
throw Exception("Missing required parameter: EEPROM_PAGE_SIZE");
|
||||
}
|
||||
|
||||
if (!config.nvmBaseAddress.has_value()) {
|
||||
throw Exception("Missing required parameter: NVM_BASE");
|
||||
}
|
||||
|
||||
Logger::debug("Setting APPL_BASE_ADDR AVR8 parameter");
|
||||
this->setParameter(Avr8EdbgParameters::DEVICE_XMEGA_APPL_BASE_ADDR, config.appSectionPdiOffset.value());
|
||||
|
||||
Logger::debug("Setting BOOT_BASE_ADDR AVR8 parameter");
|
||||
this->setParameter(Avr8EdbgParameters::DEVICE_XMEGA_BOOT_BASE_ADDR, config.bootSectionPdiOffset.value());
|
||||
|
||||
Logger::debug("Setting EEPROM_BASE_ADDR AVR8 parameter");
|
||||
this->setParameter(Avr8EdbgParameters::DEVICE_XMEGA_EEPROM_BASE_ADDR, config.eepromPdiOffset.value());
|
||||
|
||||
Logger::debug("Setting FUSE_BASE_ADDR AVR8 parameter");
|
||||
this->setParameter(Avr8EdbgParameters::DEVICE_XMEGA_FUSE_BASE_ADDR, config.fuseRegistersPdiOffset.value());
|
||||
|
||||
Logger::debug("Setting LOCKBIT_BASE_ADDR AVR8 parameter");
|
||||
this->setParameter(Avr8EdbgParameters::DEVICE_XMEGA_LOCKBIT_BASE_ADDR, config.lockRegistersPdiOffset.value());
|
||||
|
||||
Logger::debug("Setting USER_SIGN_BASE_ADDR AVR8 parameter");
|
||||
this->setParameter(Avr8EdbgParameters::DEVICE_XMEGA_USER_SIGN_BASE_ADDR, config.userSignaturesPdiOffset.value());
|
||||
|
||||
Logger::debug("Setting PROD_SIGN_BASE_ADDR AVR8 parameter");
|
||||
this->setParameter(Avr8EdbgParameters::DEVICE_XMEGA_PROD_SIGN_BASE_ADDR, config.productSignaturesPdiOffset.value());
|
||||
|
||||
Logger::debug("Setting DATA_BASE_ADDR AVR8 parameter");
|
||||
this->setParameter(Avr8EdbgParameters::DEVICE_XMEGA_DATA_BASE_ADDR, config.ramPdiOffset.value());
|
||||
|
||||
Logger::debug("Setting APPLICATION_BYTES AVR8 parameter");
|
||||
this->setParameter(Avr8EdbgParameters::DEVICE_XMEGA_APPLICATION_BYTES, config.flashSize.value());
|
||||
|
||||
Logger::debug("Setting BOOT_BYTES AVR8 parameter");
|
||||
this->setParameter(Avr8EdbgParameters::DEVICE_XMEGA_BOOT_BYTES, config.bootSectionSize.value());
|
||||
|
||||
Logger::debug("Setting FLASH_PAGE_BYTES AVR8 parameter");
|
||||
this->setParameter(Avr8EdbgParameters::DEVICE_XMEGA_FLASH_PAGE_BYTES, config.flashPageSize.value());
|
||||
|
||||
Logger::debug("Setting EEPROM_SIZE AVR8 parameter");
|
||||
this->setParameter(Avr8EdbgParameters::DEVICE_XMEGA_EEPROM_SIZE, config.eepromSize.value());
|
||||
|
||||
Logger::debug("Setting EEPROM_PAGE_SIZE AVR8 parameter");
|
||||
this->setParameter(Avr8EdbgParameters::DEVICE_XMEGA_EEPROM_PAGE_SIZE, static_cast<unsigned char>(config.eepromPageSize.value()));
|
||||
|
||||
Logger::debug("Setting NVM_BASE AVR8 parameter");
|
||||
this->setParameter(Avr8EdbgParameters::DEVICE_XMEGA_NVM_BASE, config.nvmBaseAddress.value());
|
||||
|
||||
} else {
|
||||
if (config.flashPageSize.has_value()) {
|
||||
Logger::debug("Setting DEVICE_FLASH_PAGE_SIZE AVR8 parameter");
|
||||
this->setParameter(Avr8EdbgParameters::DEVICE_FLASH_PAGE_SIZE, config.flashPageSize.value());
|
||||
}
|
||||
|
||||
if (config.flashSize.has_value()) {
|
||||
Logger::debug("Setting DEVICE_FLASH_SIZE AVR8 parameter");
|
||||
this->setParameter(Avr8EdbgParameters::DEVICE_FLASH_SIZE, config.flashSize.value());
|
||||
}
|
||||
|
||||
if (config.flashStartAddress.has_value()) {
|
||||
Logger::debug("Setting DEVICE_FLASH_BASE AVR8 parameter");
|
||||
this->setParameter(Avr8EdbgParameters::DEVICE_FLASH_BASE, config.flashStartAddress.value());
|
||||
}
|
||||
|
||||
if (config.ramStartAddress.has_value()) {
|
||||
Logger::debug("Setting DEVICE_SRAM_START AVR8 parameter");
|
||||
this->setParameter(Avr8EdbgParameters::DEVICE_SRAM_START, config.ramStartAddress.value());
|
||||
}
|
||||
|
||||
if (config.eepromSize.has_value()) {
|
||||
Logger::debug("Setting DEVICE_EEPROM_SIZE AVR8 parameter");
|
||||
this->setParameter(Avr8EdbgParameters::DEVICE_EEPROM_SIZE, config.eepromSize.value());
|
||||
}
|
||||
|
||||
if (config.eepromPageSize.has_value()) {
|
||||
Logger::debug("Setting DEVICE_EEPROM_PAGE_SIZE AVR8 parameter");
|
||||
this->setParameter(Avr8EdbgParameters::DEVICE_EEPROM_PAGE_SIZE, config.eepromPageSize.value());
|
||||
}
|
||||
|
||||
if (config.ocdRevision.has_value()) {
|
||||
Logger::debug("Setting DEVICE_OCD_REVISION AVR8 parameter");
|
||||
this->setParameter(Avr8EdbgParameters::DEVICE_OCD_REVISION, config.ocdRevision.value());
|
||||
}
|
||||
|
||||
if (config.ocdDataRegister.has_value()) {
|
||||
Logger::debug("Setting DEVICE_OCD_DATA_REGISTER AVR8 parameter");
|
||||
this->setParameter(Avr8EdbgParameters::DEVICE_OCD_DATA_REGISTER, config.ocdDataRegister.value());
|
||||
}
|
||||
|
||||
if (config.spmcRegisterStartAddress.has_value()) {
|
||||
Logger::debug("Setting DEVICE_SPMCR_REGISTER AVR8 parameter");
|
||||
this->setParameter(Avr8EdbgParameters::DEVICE_SPMCR_REGISTER, config.spmcRegisterStartAddress.value());
|
||||
}
|
||||
|
||||
if (config.osccalAddress.has_value()) {
|
||||
Logger::debug("Setting DEVICE_OSCCAL_ADDR AVR8 parameter");
|
||||
this->setParameter(Avr8EdbgParameters::DEVICE_OSCCAL_ADDR, config.osccalAddress.value());
|
||||
}
|
||||
|
||||
if (config.eepromAddressRegisterLow.has_value()) {
|
||||
Logger::debug("Setting DEVICE_EEARL_ADDR AVR8 parameter");
|
||||
this->setParameter(Avr8EdbgParameters::DEVICE_EEARL_ADDR, config.eepromAddressRegisterLow.value());
|
||||
}
|
||||
|
||||
if (config.eepromAddressRegisterHigh.has_value()) {
|
||||
Logger::debug("Setting DEVICE_EEARH_ADDR AVR8 parameter");
|
||||
this->setParameter(Avr8EdbgParameters::DEVICE_EEARH_ADDR, config.eepromAddressRegisterHigh.value());
|
||||
}
|
||||
|
||||
if (config.eepromControlRegisterAddress.has_value()) {
|
||||
Logger::debug("Setting DEVICE_EECR_ADDR AVR8 parameter");
|
||||
this->setParameter(Avr8EdbgParameters::DEVICE_EECR_ADDR, config.eepromControlRegisterAddress.value());
|
||||
}
|
||||
|
||||
if (config.eepromDataRegisterAddress.has_value()) {
|
||||
Logger::debug("Setting DEVICE_EEDR_ADDR AVR8 parameter");
|
||||
this->setParameter(Avr8EdbgParameters::DEVICE_EEDR_ADDR, config.eepromDataRegisterAddress.value());
|
||||
}
|
||||
|
||||
if (config.bootSectionStartAddress.has_value()) {
|
||||
Logger::debug("Setting DEVICE_BOOT_START_ADDR AVR8 parameter");
|
||||
this->setParameter(Avr8EdbgParameters::DEVICE_BOOT_START_ADDR, config.bootSectionStartAddress.value());
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -305,7 +550,13 @@ void EdbgAvr8Interface::init() {
|
||||
if (this->configVariant == Avr8ConfigVariant::XMEGA) {
|
||||
// Default PDI clock to 4MHz
|
||||
// TODO: Make this adjustable via a target config parameter
|
||||
this->setParameter(Avr8EdbgParameters::XMEGA_PDI_CLOCK, static_cast<std::uint16_t>(0x0FA0));
|
||||
this->setParameter(Avr8EdbgParameters::PDI_CLOCK_SPEED, static_cast<std::uint16_t>(0x0FA0));
|
||||
}
|
||||
|
||||
if (this->configVariant == Avr8ConfigVariant::UPDI) {
|
||||
// Default UPDI clock to 1.8MHz
|
||||
this->setParameter(Avr8EdbgParameters::PDI_CLOCK_SPEED, static_cast<std::uint16_t>(0x0708));
|
||||
this->setParameter(Avr8EdbgParameters::ENABLE_HIGH_VOLTAGE_UPDI, static_cast<unsigned char>(0x00));
|
||||
}
|
||||
|
||||
if (this->configVariant == Avr8ConfigVariant::MEGAJTAG) {
|
||||
|
||||
@@ -14,14 +14,6 @@
|
||||
|
||||
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||
{
|
||||
inline bool operator==(unsigned char rawId, Avr8ResponseId id) {
|
||||
return static_cast<unsigned char>(id) == rawId;
|
||||
}
|
||||
|
||||
inline bool operator==(Avr8ResponseId id, unsigned char rawId) {
|
||||
return rawId == id;
|
||||
}
|
||||
|
||||
/**
|
||||
* The EdbgAvr8Interface implements the AVR8 Generic EDBG/CMSIS-DAP protocol, as an Avr8Interface.
|
||||
*
|
||||
@@ -291,6 +283,27 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||
*/
|
||||
std::vector<unsigned char> getParameter(const Avr8EdbgParameter& parameter, std::uint8_t size);
|
||||
|
||||
/**
|
||||
* EDBG-based debug tools require target specific parameters such as memory locations, page sizes and
|
||||
* 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.
|
||||
* For example, the Avr8EdbgParameters::DEVICE_FLASH_BASE parameter is used to send the base address for
|
||||
* the target's flash memory segment. The parameter is assigned an address (ID) of 0x06. But the
|
||||
* Avr8EdbgParameters::DEVICE_UPDI_PROG_BASE is used to send the same data (base address of the target's flash
|
||||
* segment), but only for sessions with the UPDI physical interface. The address is 0x00.
|
||||
*
|
||||
* - 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.
|
||||
*/
|
||||
void setDebugWireAndJtagParameters();
|
||||
void setPdiParameters();
|
||||
void setUpdiParameters();
|
||||
|
||||
/**
|
||||
* Sends the "Activate Physical" command to the debug tool, activating the physical interface and thus enabling
|
||||
* communication between the debug tool and the target.
|
||||
|
||||
@@ -24,13 +24,6 @@ using namespace Bloom::Targets::Microchip::Avr;
|
||||
using namespace Bloom::Targets::Microchip::Avr::Avr8Bit;
|
||||
using namespace Exceptions;
|
||||
|
||||
/**
|
||||
* Initialises the target from config parameters extracted from user's config file.
|
||||
*
|
||||
* @see Application::extractConfig(); for more on config extraction.
|
||||
*
|
||||
* @param targetConfig
|
||||
*/
|
||||
void Avr8::preActivationConfigure(const TargetConfig& targetConfig) {
|
||||
Target::preActivationConfigure(targetConfig);
|
||||
|
||||
@@ -44,6 +37,7 @@ void Avr8::preActivationConfigure(const TargetConfig& targetConfig) {
|
||||
void Avr8::postActivationConfigure() {
|
||||
if (!this->targetDescriptionFile.has_value()) {
|
||||
this->loadTargetDescriptionFile();
|
||||
this->initFromTargetDescriptionFile();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -71,27 +65,291 @@ void Avr8::postPromotionConfigure() {
|
||||
}
|
||||
|
||||
this->avr8Interface->setFamily(this->family.value());
|
||||
this->avr8Interface->setTargetParameters(this->getTargetParameters());
|
||||
this->avr8Interface->setTargetParameters(this->targetParameters.value());
|
||||
}
|
||||
|
||||
void Avr8::loadTargetDescriptionFile() {
|
||||
auto targetSignature = this->getId();
|
||||
auto targetDescriptionFile = TargetDescription::TargetDescriptionFile(
|
||||
targetSignature,
|
||||
this->targetDescriptionFile = TargetDescription::TargetDescriptionFile(
|
||||
this->getId(),
|
||||
(!this->name.empty()) ? std::optional(this->name) : std::nullopt
|
||||
);
|
||||
}
|
||||
|
||||
this->targetDescriptionFile = targetDescriptionFile;
|
||||
this->name = targetDescriptionFile.getTargetName();
|
||||
this->family = targetDescriptionFile.getFamily();
|
||||
void Avr8::initFromTargetDescriptionFile() {
|
||||
this->name = this->targetDescriptionFile->getTargetName();
|
||||
this->family = this->targetDescriptionFile->getFamily();
|
||||
|
||||
this->loadTargetParameters();
|
||||
this->loadPadDescriptors();
|
||||
this->loadTargetVariants();
|
||||
}
|
||||
|
||||
void Avr8::loadPadDescriptors() {
|
||||
auto& targetParameters = this->getTargetParameters();
|
||||
void Avr8::loadTargetParameters() {
|
||||
assert(this->targetDescriptionFile.has_value());
|
||||
auto& peripheralModules = this->targetDescriptionFile->getPeripheralModulesMappedByName();
|
||||
this->targetParameters = TargetParameters();
|
||||
auto& propertyGroups = this->targetDescriptionFile->getPropertyGroupsMappedByName();
|
||||
|
||||
auto flashMemorySegment = this->targetDescriptionFile->getFlashMemorySegment();
|
||||
if (flashMemorySegment.has_value()) {
|
||||
this->targetParameters->flashSize = flashMemorySegment->size;
|
||||
this->targetParameters->flashStartAddress = flashMemorySegment->startAddress;
|
||||
|
||||
if (flashMemorySegment->pageSize.has_value()) {
|
||||
this->targetParameters->flashPageSize = flashMemorySegment->pageSize.value();
|
||||
}
|
||||
}
|
||||
|
||||
auto ramMemorySegment = this->targetDescriptionFile->getRamMemorySegment();
|
||||
if (ramMemorySegment.has_value()) {
|
||||
this->targetParameters->ramSize = ramMemorySegment->size;
|
||||
this->targetParameters->ramStartAddress = ramMemorySegment->startAddress;
|
||||
}
|
||||
|
||||
auto registerMemorySegment = this->targetDescriptionFile->getRegisterMemorySegment();
|
||||
if (registerMemorySegment.has_value()) {
|
||||
this->targetParameters->gpRegisterSize = registerMemorySegment->size;
|
||||
this->targetParameters->gpRegisterStartAddress = registerMemorySegment->startAddress;
|
||||
}
|
||||
|
||||
auto eepromMemorySegment = this->targetDescriptionFile->getEepromMemorySegment();
|
||||
if (eepromMemorySegment.has_value()) {
|
||||
this->targetParameters->eepromSize = eepromMemorySegment->size;
|
||||
this->targetParameters->eepromStartAddress = eepromMemorySegment->startAddress;
|
||||
|
||||
if (eepromMemorySegment->pageSize.has_value()) {
|
||||
this->targetParameters->eepromPageSize = eepromMemorySegment->pageSize.value();
|
||||
}
|
||||
}
|
||||
|
||||
auto firstBootSectionMemorySegment = this->targetDescriptionFile->getFirstBootSectionMemorySegment();
|
||||
if (firstBootSectionMemorySegment.has_value()) {
|
||||
this->targetParameters->bootSectionStartAddress = firstBootSectionMemorySegment->startAddress / 2;
|
||||
this->targetParameters->bootSectionSize = firstBootSectionMemorySegment->size;
|
||||
}
|
||||
|
||||
auto statusRegister = this->targetDescriptionFile->getStatusRegister();
|
||||
if (statusRegister.has_value()) {
|
||||
this->targetParameters->statusRegisterStartAddress = statusRegister->offset;
|
||||
this->targetParameters->statusRegisterSize = statusRegister->size;
|
||||
}
|
||||
|
||||
auto stackPointerRegister = this->targetDescriptionFile->getStackPointerRegister();
|
||||
if (stackPointerRegister.has_value()) {
|
||||
this->targetParameters->stackPointerRegisterStartAddress = stackPointerRegister->offset;
|
||||
this->targetParameters->stackPointerRegisterSize = stackPointerRegister->size;
|
||||
|
||||
} else {
|
||||
// Sometimes the SP register is split into two register nodes, one for low, the other for high
|
||||
auto stackPointerLowRegister = this->targetDescriptionFile->getStackPointerLowRegister();
|
||||
auto stackPointerHighRegister = this->targetDescriptionFile->getStackPointerHighRegister();
|
||||
|
||||
if (stackPointerLowRegister.has_value()) {
|
||||
this->targetParameters->stackPointerRegisterStartAddress = stackPointerLowRegister->offset;
|
||||
this->targetParameters->stackPointerRegisterSize = stackPointerLowRegister->size;
|
||||
}
|
||||
|
||||
if (stackPointerHighRegister.has_value()) {
|
||||
this->targetParameters->stackPointerRegisterSize = (this->targetParameters->stackPointerRegisterSize.has_value()) ?
|
||||
this->targetParameters->stackPointerRegisterSize.value() + stackPointerHighRegister->size :
|
||||
stackPointerHighRegister->size;
|
||||
}
|
||||
}
|
||||
|
||||
auto supportedPhysicalInterfaces = this->targetDescriptionFile->getSupportedDebugPhysicalInterfaces();
|
||||
|
||||
if (supportedPhysicalInterfaces.contains(PhysicalInterface::DEBUG_WIRE)
|
||||
|| supportedPhysicalInterfaces.contains(PhysicalInterface::JTAG)) {
|
||||
this->loadDebugWireAndJtagTargetParameters();
|
||||
}
|
||||
|
||||
if (supportedPhysicalInterfaces.contains(PhysicalInterface::PDI)) {
|
||||
this->loadPdiTargetParameters();
|
||||
}
|
||||
|
||||
if (supportedPhysicalInterfaces.contains(PhysicalInterface::UPDI)) {
|
||||
this->loadUpdiTargetParameters();
|
||||
}
|
||||
}
|
||||
|
||||
void Avr8::loadDebugWireAndJtagTargetParameters() {
|
||||
auto& peripheralModules = this->targetDescriptionFile->getPeripheralModulesMappedByName();
|
||||
auto& propertyGroups = this->targetDescriptionFile->getPropertyGroupsMappedByName();
|
||||
|
||||
// OCD attributes can be found in property groups
|
||||
if (propertyGroups.contains("ocd")) {
|
||||
auto& ocdProperties = propertyGroups.at("ocd").propertiesMappedByName;
|
||||
|
||||
if (ocdProperties.find("ocd_revision") != ocdProperties.end()) {
|
||||
this->targetParameters->ocdRevision = ocdProperties.find("ocd_revision")
|
||||
->second.value.toUShort(nullptr, 10);
|
||||
}
|
||||
|
||||
if (ocdProperties.find("ocd_datareg") != ocdProperties.end()) {
|
||||
this->targetParameters->ocdDataRegister = ocdProperties.find("ocd_datareg")
|
||||
->second.value.toUShort(nullptr, 16);
|
||||
}
|
||||
}
|
||||
|
||||
auto spmcsRegister = this->targetDescriptionFile->getSpmcsRegister();
|
||||
if (spmcsRegister.has_value()) {
|
||||
this->targetParameters->spmcRegisterStartAddress = spmcsRegister->offset;
|
||||
|
||||
} else {
|
||||
auto spmcRegister = this->targetDescriptionFile->getSpmcRegister();
|
||||
if (spmcRegister.has_value()) {
|
||||
this->targetParameters->spmcRegisterStartAddress = spmcRegister->offset;
|
||||
}
|
||||
}
|
||||
|
||||
auto osccalRegister = this->targetDescriptionFile->getOscillatorCalibrationRegister();
|
||||
if (osccalRegister.has_value()) {
|
||||
this->targetParameters->osccalAddress = osccalRegister->offset;
|
||||
}
|
||||
|
||||
auto eepromAddressRegister = this->targetDescriptionFile->getEepromAddressRegister();
|
||||
if (eepromAddressRegister.has_value()) {
|
||||
this->targetParameters->eepromAddressRegisterLow = eepromAddressRegister->offset;
|
||||
this->targetParameters->eepromAddressRegisterHigh = (eepromAddressRegister->size == 2)
|
||||
? eepromAddressRegister->offset + 1 : eepromAddressRegister->offset;
|
||||
|
||||
} else {
|
||||
auto eepromAddressLowRegister = this->targetDescriptionFile->getEepromAddressLowRegister();
|
||||
if (eepromAddressLowRegister.has_value()) {
|
||||
this->targetParameters->eepromAddressRegisterLow = eepromAddressLowRegister->offset;
|
||||
auto eepromAddressHighRegister = this->targetDescriptionFile->getEepromAddressHighRegister();
|
||||
|
||||
if (eepromAddressHighRegister.has_value()) {
|
||||
this->targetParameters->eepromAddressRegisterHigh = eepromAddressHighRegister->offset;
|
||||
|
||||
} else {
|
||||
this->targetParameters->eepromAddressRegisterHigh = eepromAddressLowRegister->offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto eepromDataRegister = this->targetDescriptionFile->getEepromDataRegister();
|
||||
if (eepromDataRegister.has_value()) {
|
||||
this->targetParameters->eepromDataRegisterAddress = eepromDataRegister->offset;
|
||||
}
|
||||
|
||||
auto eepromControlRegister = this->targetDescriptionFile->getEepromControlRegister();
|
||||
if (eepromControlRegister.has_value()) {
|
||||
this->targetParameters->eepromControlRegisterAddress = eepromControlRegister->offset;
|
||||
}
|
||||
}
|
||||
|
||||
void Avr8::loadPdiTargetParameters() {
|
||||
auto& peripheralModules = this->targetDescriptionFile->getPeripheralModulesMappedByName();
|
||||
auto& propertyGroups = this->targetDescriptionFile->getPropertyGroupsMappedByName();
|
||||
|
||||
if (propertyGroups.contains("pdi_interface")) {
|
||||
auto& pdiInterfaceProperties = propertyGroups.at("pdi_interface").propertiesMappedByName;
|
||||
|
||||
if (pdiInterfaceProperties.contains("app_section_offset")) {
|
||||
this->targetParameters->appSectionPdiOffset = pdiInterfaceProperties
|
||||
.at("app_section_offset").value.toUInt(nullptr, 16);
|
||||
}
|
||||
|
||||
if (pdiInterfaceProperties.contains("boot_section_offset")) {
|
||||
this->targetParameters->bootSectionPdiOffset = pdiInterfaceProperties
|
||||
.at("boot_section_offset").value.toUInt(nullptr, 16);
|
||||
}
|
||||
|
||||
if (pdiInterfaceProperties.contains("datamem_offset")) {
|
||||
this->targetParameters->ramPdiOffset = pdiInterfaceProperties
|
||||
.at("datamem_offset").value.toUInt(nullptr, 16);
|
||||
}
|
||||
|
||||
if (pdiInterfaceProperties.contains("eeprom_offset")) {
|
||||
this->targetParameters->eepromPdiOffset = pdiInterfaceProperties
|
||||
.at("eeprom_offset").value.toUInt(nullptr, 16);
|
||||
}
|
||||
|
||||
if (pdiInterfaceProperties.contains("user_signatures_offset")) {
|
||||
this->targetParameters->userSignaturesPdiOffset = pdiInterfaceProperties
|
||||
.at("user_signatures_offset").value.toUInt(nullptr, 16);
|
||||
}
|
||||
|
||||
if (pdiInterfaceProperties.contains("prod_signatures_offset")) {
|
||||
this->targetParameters->productSignaturesPdiOffset = pdiInterfaceProperties
|
||||
.at("prod_signatures_offset").value.toUInt(nullptr, 16);
|
||||
}
|
||||
|
||||
if (pdiInterfaceProperties.contains("fuse_registers_offset")) {
|
||||
this->targetParameters->fuseRegistersPdiOffset = pdiInterfaceProperties
|
||||
.at("fuse_registers_offset").value.toUInt(nullptr, 16);
|
||||
}
|
||||
|
||||
if (pdiInterfaceProperties.contains("lock_registers_offset")) {
|
||||
this->targetParameters->lockRegistersPdiOffset = pdiInterfaceProperties
|
||||
.at("lock_registers_offset").value.toUInt(nullptr, 16);
|
||||
}
|
||||
|
||||
if (peripheralModules.contains("nvm")) {
|
||||
auto& nvmModule = peripheralModules.at("nvm");
|
||||
|
||||
if (nvmModule.instancesMappedByName.contains("nvm")) {
|
||||
auto& nvmInstance = nvmModule.instancesMappedByName.at("nvm");
|
||||
|
||||
if (nvmInstance.registerGroupsMappedByName.contains("nvm")) {
|
||||
this->targetParameters->nvmBaseAddress = nvmInstance.registerGroupsMappedByName.at("nvm").offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Avr8::loadUpdiTargetParameters() {
|
||||
auto& propertyGroups = this->targetDescriptionFile->getPropertyGroupsMappedByName();
|
||||
auto& peripheralModules = this->targetDescriptionFile->getPeripheralModulesMappedByName();
|
||||
auto modulesByName = this->targetDescriptionFile->getModulesMappedByName();
|
||||
|
||||
if (peripheralModules.contains("nvmctrl")) {
|
||||
auto& nvmCtrlModule = peripheralModules.at("nvmctrl");
|
||||
|
||||
if (nvmCtrlModule.instancesMappedByName.contains("nvmctrl")) {
|
||||
auto& nvmCtrlInstance = nvmCtrlModule.instancesMappedByName.at("nvmctrl");
|
||||
|
||||
if (nvmCtrlInstance.registerGroupsMappedByName.contains("nvmctrl")) {
|
||||
this->targetParameters->nvmBaseAddress = nvmCtrlInstance.registerGroupsMappedByName.at("nvmctrl").offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (propertyGroups.contains("updi_interface")) {
|
||||
auto& updiInterfaceProperties = propertyGroups.at("updi_interface").propertiesMappedByName;
|
||||
|
||||
if (updiInterfaceProperties.contains("ocd_base_addr")) {
|
||||
this->targetParameters->ocdModuleAddress = updiInterfaceProperties
|
||||
.at("ocd_base_addr").value.toUShort(nullptr, 16);
|
||||
}
|
||||
|
||||
if (updiInterfaceProperties.contains("progmem_offset")) {
|
||||
this->targetParameters->programMemoryUpdiStartAddress = updiInterfaceProperties
|
||||
.at("progmem_offset").value.toUInt(nullptr, 16);
|
||||
}
|
||||
}
|
||||
|
||||
auto signatureMemorySegment = this->targetDescriptionFile->getSignatureMemorySegment();
|
||||
if (signatureMemorySegment.has_value()) {
|
||||
this->targetParameters->signatureSegmentStartAddress = signatureMemorySegment->startAddress;
|
||||
this->targetParameters->signatureSegmentSize = signatureMemorySegment->size;
|
||||
}
|
||||
|
||||
auto fuseMemorySegment = this->targetDescriptionFile->getFuseMemorySegment();
|
||||
if (fuseMemorySegment.has_value()) {
|
||||
this->targetParameters->fuseSegmentStartAddress = fuseMemorySegment->startAddress;
|
||||
this->targetParameters->fuseSegmentSize = fuseMemorySegment->size;
|
||||
}
|
||||
|
||||
auto lockbitsMemorySegment = this->targetDescriptionFile->getLockbitsMemorySegment();
|
||||
if (lockbitsMemorySegment.has_value()) {
|
||||
this->targetParameters->lockbitsSegmentStartAddress = lockbitsMemorySegment->startAddress;
|
||||
}
|
||||
}
|
||||
|
||||
void Avr8::loadPadDescriptors() {
|
||||
/*
|
||||
* Every port address we extract from the target description will be stored in portAddresses, so that
|
||||
* we can extract the start (min) and end (max) for the target's IO port address
|
||||
@@ -215,8 +473,8 @@ void Avr8::loadPadDescriptors() {
|
||||
|
||||
// TODO: Move this into getTargetParameters()
|
||||
if (!portAddresses.empty()) {
|
||||
targetParameters.ioPortAddressRangeStart = *std::min_element(portAddresses.begin(), portAddresses.end());
|
||||
targetParameters.ioPortAddressRangeEnd = *std::max_element(portAddresses.begin(), portAddresses.end());
|
||||
this->targetParameters->ioPortAddressRangeStart = *std::min_element(portAddresses.begin(), portAddresses.end());
|
||||
this->targetParameters->ioPortAddressRangeEnd = *std::max_element(portAddresses.begin(), portAddresses.end());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,198 +548,12 @@ void Avr8::loadTargetVariants() {
|
||||
}
|
||||
}
|
||||
|
||||
TargetParameters& Avr8::getTargetParameters() {
|
||||
if (!this->targetParameters.has_value()) {
|
||||
assert(this->targetDescriptionFile.has_value());
|
||||
auto supportedPhysicalInterfaces = this->targetDescriptionFile->getSupportedDebugPhysicalInterfaces();
|
||||
auto& peripheralModules = this->targetDescriptionFile->getPeripheralModulesMappedByName();
|
||||
this->targetParameters = TargetParameters();
|
||||
auto& propertyGroups = this->targetDescriptionFile->getPropertyGroupsMappedByName();
|
||||
|
||||
auto flashMemorySegment = this->targetDescriptionFile->getFlashMemorySegment();
|
||||
if (flashMemorySegment.has_value()) {
|
||||
this->targetParameters->flashSize = flashMemorySegment->size;
|
||||
this->targetParameters->flashStartAddress = flashMemorySegment->startAddress;
|
||||
|
||||
if (flashMemorySegment->pageSize.has_value()) {
|
||||
this->targetParameters->flashPageSize = flashMemorySegment->pageSize.value();
|
||||
}
|
||||
TargetSignature Avr8::getId() {
|
||||
if (!this->id.has_value()) {
|
||||
this->id = this->avr8Interface->getDeviceId();
|
||||
}
|
||||
|
||||
auto ramMemorySegment = this->targetDescriptionFile->getRamMemorySegment();
|
||||
if (ramMemorySegment.has_value()) {
|
||||
this->targetParameters->ramSize = ramMemorySegment->size;
|
||||
this->targetParameters->ramStartAddress = ramMemorySegment->startAddress;
|
||||
}
|
||||
|
||||
auto registerMemorySegment = this->targetDescriptionFile->getRegisterMemorySegment();
|
||||
if (registerMemorySegment.has_value()) {
|
||||
this->targetParameters->gpRegisterSize = registerMemorySegment->size;
|
||||
this->targetParameters->gpRegisterStartAddress = registerMemorySegment->startAddress;
|
||||
}
|
||||
|
||||
auto eepromMemorySegment = this->targetDescriptionFile->getEepromMemorySegment();
|
||||
if (eepromMemorySegment.has_value()) {
|
||||
this->targetParameters->eepromSize = eepromMemorySegment->size;
|
||||
|
||||
if (eepromMemorySegment->pageSize.has_value()) {
|
||||
this->targetParameters->eepromPageSize = eepromMemorySegment->pageSize.value();
|
||||
}
|
||||
}
|
||||
|
||||
auto firstBootSectionMemorySegment = this->targetDescriptionFile->getFirstBootSectionMemorySegment();
|
||||
if (firstBootSectionMemorySegment.has_value()) {
|
||||
this->targetParameters->bootSectionStartAddress = firstBootSectionMemorySegment->startAddress / 2;
|
||||
this->targetParameters->bootSectionSize = firstBootSectionMemorySegment->size;
|
||||
}
|
||||
|
||||
// OCD attributes can be found in property groups
|
||||
if (propertyGroups.contains("ocd")) {
|
||||
auto& ocdProperties = propertyGroups.at("ocd").propertiesMappedByName;
|
||||
|
||||
if (ocdProperties.find("ocd_revision") != ocdProperties.end()) {
|
||||
this->targetParameters->ocdRevision = ocdProperties.find("ocd_revision")->second.value.toUShort(nullptr, 10);
|
||||
}
|
||||
|
||||
if (ocdProperties.find("ocd_datareg") != ocdProperties.end()) {
|
||||
this->targetParameters->ocdDataRegister = ocdProperties.find("ocd_datareg")->second.value.toUShort(nullptr, 16);
|
||||
}
|
||||
}
|
||||
|
||||
auto statusRegister = this->targetDescriptionFile->getStatusRegister();
|
||||
if (statusRegister.has_value()) {
|
||||
this->targetParameters->statusRegisterStartAddress = statusRegister->offset;
|
||||
this->targetParameters->statusRegisterSize = statusRegister->size;
|
||||
}
|
||||
|
||||
auto stackPointerRegister = this->targetDescriptionFile->getStackPointerRegister();
|
||||
if (stackPointerRegister.has_value()) {
|
||||
this->targetParameters->stackPointerRegisterStartAddress = stackPointerRegister->offset;
|
||||
this->targetParameters->stackPointerRegisterSize = stackPointerRegister->size;
|
||||
|
||||
} else {
|
||||
// Sometimes the SP register is split into two register nodes, one for low, the other for high
|
||||
auto stackPointerLowRegister = this->targetDescriptionFile->getStackPointerLowRegister();
|
||||
auto stackPointerHighRegister = this->targetDescriptionFile->getStackPointerHighRegister();
|
||||
|
||||
if (stackPointerLowRegister.has_value()) {
|
||||
this->targetParameters->stackPointerRegisterStartAddress = stackPointerLowRegister->offset;
|
||||
this->targetParameters->stackPointerRegisterSize = stackPointerLowRegister->size;
|
||||
}
|
||||
|
||||
if (stackPointerHighRegister.has_value()) {
|
||||
this->targetParameters->stackPointerRegisterSize = (this->targetParameters->stackPointerRegisterSize.has_value()) ?
|
||||
this->targetParameters->stackPointerRegisterSize.value() + stackPointerHighRegister->size :
|
||||
stackPointerHighRegister->size;
|
||||
}
|
||||
}
|
||||
|
||||
auto spmcsRegister = this->targetDescriptionFile->getSpmcsRegister();
|
||||
if (spmcsRegister.has_value()) {
|
||||
this->targetParameters->spmcRegisterStartAddress = spmcsRegister->offset;
|
||||
|
||||
} else {
|
||||
auto spmcRegister = this->targetDescriptionFile->getSpmcRegister();
|
||||
if (spmcRegister.has_value()) {
|
||||
this->targetParameters->spmcRegisterStartAddress = spmcRegister->offset;
|
||||
}
|
||||
}
|
||||
|
||||
auto osccalRegister = this->targetDescriptionFile->getOscillatorCalibrationRegister();
|
||||
if (osccalRegister.has_value()) {
|
||||
this->targetParameters->osccalAddress = osccalRegister->offset;
|
||||
}
|
||||
|
||||
auto eepromAddressRegister = this->targetDescriptionFile->getEepromAddressRegister();
|
||||
if (eepromAddressRegister.has_value()) {
|
||||
this->targetParameters->eepromAddressRegisterLow = eepromAddressRegister->offset;
|
||||
this->targetParameters->eepromAddressRegisterHigh = (eepromAddressRegister->size == 2)
|
||||
? eepromAddressRegister->offset + 1 : eepromAddressRegister->offset;
|
||||
|
||||
} else {
|
||||
auto eepromAddressLowRegister = this->targetDescriptionFile->getEepromAddressLowRegister();
|
||||
if (eepromAddressLowRegister.has_value()) {
|
||||
this->targetParameters->eepromAddressRegisterLow = eepromAddressLowRegister->offset;
|
||||
auto eepromAddressHighRegister = this->targetDescriptionFile->getEepromAddressHighRegister();
|
||||
|
||||
if (eepromAddressHighRegister.has_value()) {
|
||||
this->targetParameters->eepromAddressRegisterHigh = eepromAddressHighRegister->offset;
|
||||
|
||||
} else {
|
||||
this->targetParameters->eepromAddressRegisterHigh = eepromAddressLowRegister->offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto eepromDataRegister = this->targetDescriptionFile->getEepromDataRegister();
|
||||
if (eepromDataRegister.has_value()) {
|
||||
this->targetParameters->eepromDataRegisterAddress = eepromDataRegister->offset;
|
||||
}
|
||||
|
||||
auto eepromControlRegister = this->targetDescriptionFile->getEepromControlRegister();
|
||||
if (eepromControlRegister.has_value()) {
|
||||
this->targetParameters->eepromControlRegisterAddress = eepromControlRegister->offset;
|
||||
}
|
||||
|
||||
if (propertyGroups.contains("pdi_interface")) {
|
||||
auto& pdiInterfaceProperties = propertyGroups.at("pdi_interface").propertiesMappedByName;
|
||||
|
||||
if (pdiInterfaceProperties.contains("app_section_offset")) {
|
||||
this->targetParameters->appSectionPdiOffset = pdiInterfaceProperties
|
||||
.at("app_section_offset").value.toUInt(nullptr, 16);
|
||||
}
|
||||
|
||||
if (pdiInterfaceProperties.contains("boot_section_offset")) {
|
||||
this->targetParameters->bootSectionPdiOffset = pdiInterfaceProperties
|
||||
.at("boot_section_offset").value.toUInt(nullptr, 16);
|
||||
}
|
||||
|
||||
if (pdiInterfaceProperties.contains("datamem_offset")) {
|
||||
this->targetParameters->ramPdiOffset = pdiInterfaceProperties
|
||||
.at("datamem_offset").value.toUInt(nullptr, 16);
|
||||
}
|
||||
|
||||
if (pdiInterfaceProperties.contains("eeprom_offset")) {
|
||||
this->targetParameters->eepromPdiOffset = pdiInterfaceProperties
|
||||
.at("eeprom_offset").value.toUInt(nullptr, 16);
|
||||
}
|
||||
|
||||
if (pdiInterfaceProperties.contains("user_signatures_offset")) {
|
||||
this->targetParameters->userSignaturesPdiOffset = pdiInterfaceProperties
|
||||
.at("user_signatures_offset").value.toUInt(nullptr, 16);
|
||||
}
|
||||
|
||||
if (pdiInterfaceProperties.contains("prod_signatures_offset")) {
|
||||
this->targetParameters->productSignaturesPdiOffset = pdiInterfaceProperties
|
||||
.at("prod_signatures_offset").value.toUInt(nullptr, 16);
|
||||
}
|
||||
|
||||
if (pdiInterfaceProperties.contains("fuse_registers_offset")) {
|
||||
this->targetParameters->fuseRegistersPdiOffset = pdiInterfaceProperties
|
||||
.at("fuse_registers_offset").value.toUInt(nullptr, 16);
|
||||
}
|
||||
|
||||
if (pdiInterfaceProperties.contains("lock_registers_offset")) {
|
||||
this->targetParameters->lockRegistersPdiOffset = pdiInterfaceProperties
|
||||
.at("lock_registers_offset").value.toUInt(nullptr, 16);
|
||||
}
|
||||
|
||||
|
||||
if (peripheralModules.contains("nvm")) {
|
||||
auto& nvmModule = peripheralModules.at("nvm");
|
||||
|
||||
if (nvmModule.instancesMappedByName.contains("nvm")) {
|
||||
auto& nvmInstance = nvmModule.instancesMappedByName.at("nvm");
|
||||
|
||||
if (nvmInstance.registerGroupsMappedByName.contains("nvm")) {
|
||||
this->targetParameters->nvmBaseAddress = nvmInstance.registerGroupsMappedByName.at("nvm").offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this->targetParameters.value();
|
||||
return this->id.value();
|
||||
}
|
||||
|
||||
void Avr8::activate() {
|
||||
@@ -492,7 +564,7 @@ void Avr8::activate() {
|
||||
this->avr8Interface->init();
|
||||
|
||||
if (this->targetDescriptionFile.has_value()) {
|
||||
this->avr8Interface->setTargetParameters(this->getTargetParameters());
|
||||
this->avr8Interface->setTargetParameters(this->targetParameters.value());
|
||||
}
|
||||
|
||||
this->avr8Interface->activate();
|
||||
@@ -539,21 +611,11 @@ void Avr8::deactivate() {
|
||||
}
|
||||
}
|
||||
|
||||
TargetSignature Avr8::getId() {
|
||||
if (!this->id.has_value()) {
|
||||
this->id = this->avr8Interface->getDeviceId();
|
||||
}
|
||||
|
||||
return this->id.value();
|
||||
}
|
||||
|
||||
TargetDescriptor Avr8Bit::Avr8::getDescriptor() {
|
||||
auto parameters = this->getTargetParameters();
|
||||
|
||||
auto descriptor = TargetDescriptor();
|
||||
descriptor.id = this->getHumanReadableId();
|
||||
descriptor.name = this->getName();
|
||||
descriptor.ramSize = parameters.ramSize.value_or(0);
|
||||
descriptor.ramSize = this->targetParameters.value().ramSize.value_or(0);
|
||||
|
||||
std::transform(
|
||||
this->targetVariantsById.begin(),
|
||||
@@ -843,6 +905,11 @@ void Avr8::setPinState(int variantId, const TargetPinDescriptor& pinDescriptor,
|
||||
|
||||
if (ioState.has_value()) {
|
||||
auto portSetAddress = padDescriptor.gpioPortSetAddress.value();
|
||||
|
||||
if (ioState == TargetPinState::IoState::HIGH
|
||||
|| !padDescriptor.gpioPortClearAddress.has_value()
|
||||
|| padDescriptor.gpioPortClearAddress == portSetAddress
|
||||
) {
|
||||
auto portSetRegisterValue = this->readMemory(TargetMemoryType::RAM, portSetAddress, 1);
|
||||
|
||||
if (portSetRegisterValue.empty()) {
|
||||
@@ -860,8 +927,16 @@ void Avr8::setPinState(int variantId, const TargetPinDescriptor& pinDescriptor,
|
||||
{static_cast<unsigned char>(portSetBitset.to_ulong())}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (padDescriptor.gpioPortClearAddress.has_value() && padDescriptor.gpioPortClearAddress != portSetAddress) {
|
||||
/*
|
||||
* We only need to update the PORT clear register if the IO state was set to LOW, and the clear register is
|
||||
* not the same register as the set register.
|
||||
*/
|
||||
if (ioState == TargetPinState::IoState::LOW
|
||||
&& padDescriptor.gpioPortClearAddress.has_value()
|
||||
&& padDescriptor.gpioPortClearAddress != portSetAddress
|
||||
) {
|
||||
// We also need to ensure the PORT clear register value is correct
|
||||
auto portClearAddress = padDescriptor.gpioPortClearAddress.value();
|
||||
auto portClearRegisterValue = this->readMemory(TargetMemoryType::RAM, portClearAddress, 1);
|
||||
@@ -886,7 +961,7 @@ void Avr8::setPinState(int variantId, const TargetPinDescriptor& pinDescriptor,
|
||||
}
|
||||
|
||||
bool Avr8::memoryAddressRangeClashesWithIoPortRegisters(TargetMemoryType memoryType, std::uint32_t startAddress, std::uint32_t endAddress) {
|
||||
auto& targetParameters = this->getTargetParameters();
|
||||
auto& targetParameters = this->targetParameters.value();
|
||||
|
||||
/*
|
||||
* We're making an assumption here; that all IO port addresses for all AVR8 targets are aligned. I have no idea
|
||||
|
||||
@@ -31,20 +31,34 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
||||
std::map<int, TargetVariant> targetVariantsById;
|
||||
|
||||
/**
|
||||
* Extracts the ID from the target's memory.
|
||||
*
|
||||
* This function will cache the ID value and use the cached version for any subsequent calls.
|
||||
*
|
||||
* @return
|
||||
* Resolves the appropriate TDF for the AVR8 target and populates this->targetDescriptionFile.
|
||||
*/
|
||||
TargetSignature getId() override;
|
||||
void loadTargetDescriptionFile();
|
||||
|
||||
/**
|
||||
* Extracts the AVR8 target parameters from the loaded target description file.
|
||||
*
|
||||
* @return
|
||||
* Initiates the AVR8 instance from data extracted from the TDF.
|
||||
*/
|
||||
virtual TargetParameters& getTargetParameters();
|
||||
void initFromTargetDescriptionFile();
|
||||
|
||||
/**
|
||||
* Populates this->targetParameters with AVR8 target parameters from the loaded target description file.
|
||||
*/
|
||||
virtual void loadTargetParameters();
|
||||
|
||||
/**
|
||||
* Loads target parameters that are specific to debugWire and mega JTAG sessions.
|
||||
*/
|
||||
virtual void loadDebugWireAndJtagTargetParameters();
|
||||
|
||||
/**
|
||||
* Loads target parameters that are specific to PDI sessions.
|
||||
*/
|
||||
virtual void loadPdiTargetParameters();
|
||||
|
||||
/**
|
||||
* Loads target parameters that are specific to UPDI sessions.
|
||||
*/
|
||||
virtual void loadUpdiTargetParameters();
|
||||
|
||||
/**
|
||||
* Generates a collection of PadDescriptor object from data in the loaded target description file and
|
||||
@@ -57,13 +71,21 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
||||
*/
|
||||
virtual void loadTargetVariants();
|
||||
|
||||
void loadTargetDescriptionFile();
|
||||
/**
|
||||
* Extracts the ID from the target's memory.
|
||||
*
|
||||
* This function will cache the ID value and use the cached version for any subsequent calls.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
TargetSignature getId() override;
|
||||
|
||||
public:
|
||||
explicit Avr8() = default;
|
||||
Avr8(std::string name, const TargetSignature& signature): name(std::move(name)) {
|
||||
this->id = signature;
|
||||
this->loadTargetDescriptionFile();
|
||||
this->initFromTargetDescriptionFile();
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -51,7 +51,7 @@ TargetDescriptionFile::TargetDescriptionFile(
|
||||
+ matchingDescriptionFiles.front().toObject().find("targetDescriptionFilePath")->toString();
|
||||
|
||||
Logger::debug("Loading AVR8 target description file: " + descriptionFilePath.toStdString());
|
||||
this->init(descriptionFilePath);
|
||||
Targets::TargetDescription::TargetDescriptionFile::init(descriptionFilePath);
|
||||
|
||||
} else if (matchingDescriptionFiles.size() > 1) {
|
||||
/*
|
||||
@@ -86,6 +86,27 @@ TargetDescriptionFile::TargetDescriptionFile(
|
||||
}
|
||||
}
|
||||
|
||||
void TargetDescriptionFile::init(const QDomDocument& xml) {
|
||||
Targets::TargetDescription::TargetDescriptionFile::init(xml);
|
||||
|
||||
this->loadDebugPhysicalInterfaces();
|
||||
}
|
||||
|
||||
void TargetDescriptionFile::loadDebugPhysicalInterfaces() {
|
||||
auto interfaceNamesToInterfaces = std::map<std::string, PhysicalInterface>({
|
||||
{"updi", PhysicalInterface::UPDI},
|
||||
{"debugwire", PhysicalInterface::DEBUG_WIRE},
|
||||
{"jtag", PhysicalInterface::DEBUG_WIRE},
|
||||
{"pdi", PhysicalInterface::PDI},
|
||||
});
|
||||
|
||||
for (const auto& [interfaceName, interface]: this->interfacesByName) {
|
||||
if (interfaceNamesToInterfaces.contains(interfaceName)) {
|
||||
this->supportedDebugPhysicalInterfaces.insert(interfaceNamesToInterfaces.at(interfaceName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QJsonObject TargetDescriptionFile::getTargetDescriptionMapping() {
|
||||
auto mappingFile = QFile(
|
||||
QString::fromStdString(Paths::resourcesDirPath() + "/TargetDescriptionFiles/AVR/Mapping.json")
|
||||
@@ -276,6 +297,63 @@ std::optional<MemorySegment> TargetDescriptionFile::getFirstBootSectionMemorySeg
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<MemorySegment> TargetDescriptionFile::getSignatureMemorySegment() const {
|
||||
if (this->addressSpacesMappedById.contains("signatures")) {
|
||||
auto& signaturesAddressSpace = this->addressSpacesMappedById.at("signatures");
|
||||
auto& signaturesAddressSpaceSegments = signaturesAddressSpace.memorySegmentsByTypeAndName;
|
||||
|
||||
if (signaturesAddressSpaceSegments.contains(MemorySegmentType::SIGNATURES)) {
|
||||
return signaturesAddressSpaceSegments.at(MemorySegmentType::SIGNATURES).begin()->second;
|
||||
}
|
||||
|
||||
} else {
|
||||
// The signatures memory segment may be part of the data address space
|
||||
if (this->addressSpacesMappedById.contains("data")) {
|
||||
auto dataAddressSpace = this->addressSpacesMappedById.at("data");
|
||||
|
||||
if (dataAddressSpace.memorySegmentsByTypeAndName.contains(MemorySegmentType::SIGNATURES)) {
|
||||
auto& signatureSegmentsByName = dataAddressSpace.memorySegmentsByTypeAndName.at(
|
||||
MemorySegmentType::SIGNATURES
|
||||
);
|
||||
|
||||
if (signatureSegmentsByName.contains("signatures")) {
|
||||
return signatureSegmentsByName.at("signatures");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<MemorySegment> TargetDescriptionFile::getFuseMemorySegment() const {
|
||||
if (this->addressSpacesMappedById.contains("data")) {
|
||||
auto dataAddressSpace = this->addressSpacesMappedById.at("data");
|
||||
|
||||
if (dataAddressSpace.memorySegmentsByTypeAndName.contains(MemorySegmentType::FUSES)) {
|
||||
return dataAddressSpace.memorySegmentsByTypeAndName.at(
|
||||
MemorySegmentType::SIGNATURES
|
||||
).begin()->second;
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<MemorySegment> TargetDescriptionFile::getLockbitsMemorySegment() const {
|
||||
if (this->addressSpacesMappedById.contains("data")) {
|
||||
auto dataAddressSpace = this->addressSpacesMappedById.at("data");
|
||||
|
||||
if (dataAddressSpace.memorySegmentsByTypeAndName.contains(MemorySegmentType::LOCKBITS)) {
|
||||
return dataAddressSpace.memorySegmentsByTypeAndName.at(
|
||||
MemorySegmentType::LOCKBITS
|
||||
).begin()->second;
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<RegisterGroup> TargetDescriptionFile::getCpuRegisterGroup() const {
|
||||
auto& modulesByName = this->modulesMappedByName;
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "src/Targets/TargetDescription/TargetDescriptionFile.hpp"
|
||||
|
||||
#include "src/Targets/Microchip/AVR/TargetSignature.hpp"
|
||||
#include "src/Targets/Microchip/AVR/AVR8/Family.hpp"
|
||||
#include "src/Targets/Microchip/AVR/AVR8/PhysicalInterface.hpp"
|
||||
|
||||
namespace Bloom::Targets::Microchip::Avr::Avr8Bit::TargetDescription
|
||||
{
|
||||
@@ -44,6 +47,13 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit::TargetDescription
|
||||
};
|
||||
};
|
||||
|
||||
std::set<PhysicalInterface> supportedDebugPhysicalInterfaces;
|
||||
|
||||
/**
|
||||
* Populates this->supportedDebugPhysicalInterfaces with physical interfaces defined in the TDF.
|
||||
*/
|
||||
void loadDebugPhysicalInterfaces();
|
||||
|
||||
public:
|
||||
/**
|
||||
* Will resolve the target description file using the target description JSON mapping and a given target signature.
|
||||
@@ -53,6 +63,14 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit::TargetDescription
|
||||
*/
|
||||
TargetDescriptionFile(const TargetSignature& targetSignature, std::optional<std::string> targetName);
|
||||
|
||||
/**
|
||||
* Extends TDF initialisation to include the loading of physical interfaces for debugging AVR8 targets, among
|
||||
* other things.
|
||||
*
|
||||
* @param xml
|
||||
*/
|
||||
void init(const QDomDocument& xml) override;
|
||||
|
||||
/**
|
||||
* Loads the AVR8 target description JSON mapping file.
|
||||
*
|
||||
@@ -79,6 +97,9 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit::TargetDescription
|
||||
[[nodiscard]] std::optional<Targets::TargetDescription::MemorySegment> getRegisterMemorySegment() const;
|
||||
[[nodiscard]] std::optional<Targets::TargetDescription::MemorySegment> getEepromMemorySegment() const;
|
||||
[[nodiscard]] std::optional<Targets::TargetDescription::MemorySegment> getFirstBootSectionMemorySegment() const;
|
||||
[[nodiscard]] std::optional<Targets::TargetDescription::MemorySegment> getSignatureMemorySegment() const;
|
||||
[[nodiscard]] std::optional<Targets::TargetDescription::MemorySegment> getFuseMemorySegment() const;
|
||||
[[nodiscard]] std::optional<Targets::TargetDescription::MemorySegment> getLockbitsMemorySegment() const;
|
||||
[[nodiscard]] std::optional<Targets::TargetDescription::RegisterGroup> getCpuRegisterGroup() const;
|
||||
[[nodiscard]] std::optional<Targets::TargetDescription::RegisterGroup> getBootLoadRegisterGroup() const;
|
||||
[[nodiscard]] std::optional<Targets::TargetDescription::RegisterGroup> getEepromRegisterGroup() const;
|
||||
@@ -95,5 +116,14 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit::TargetDescription
|
||||
[[nodiscard]] std::optional<Targets::TargetDescription::Register> getEepromAddressHighRegister() const;
|
||||
[[nodiscard]] std::optional<Targets::TargetDescription::Register> getEepromDataRegister() const;
|
||||
[[nodiscard]] std::optional<Targets::TargetDescription::Register> getEepromControlRegister() const;
|
||||
|
||||
/**
|
||||
* Returns a set of all supported physical interfaces for debugging.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
const auto& getSupportedDebugPhysicalInterfaces() {
|
||||
return this->supportedDebugPhysicalInterfaces;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
||||
std::optional<std::uint32_t> flashStartAddress;
|
||||
std::optional<std::uint16_t> ramStartAddress;
|
||||
std::optional<std::uint32_t> ramSize;
|
||||
std::optional<std::uint16_t> eepromStartAddress;
|
||||
std::optional<std::uint16_t> eepromSize;
|
||||
std::optional<std::uint16_t> eepromPageSize;
|
||||
std::optional<std::uint8_t> eepromAddressRegisterHigh;
|
||||
@@ -45,6 +46,17 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
||||
std::optional<std::uint32_t> productSignaturesPdiOffset;
|
||||
std::optional<std::uint16_t> nvmBaseAddress;
|
||||
|
||||
// UPDI specific target params
|
||||
std::optional<std::uint16_t> ocdModuleAddress;
|
||||
std::optional<std::uint32_t> programMemoryUpdiStartAddress;
|
||||
std::optional<std::uint16_t> signatureSegmentStartAddress;
|
||||
std::optional<std::uint16_t> signatureSegmentSize;
|
||||
std::optional<std::uint16_t> userSignatureSegmentStartAddress;
|
||||
std::optional<std::uint16_t> userSignatureSegmentSize;
|
||||
std::optional<std::uint16_t> fuseSegmentStartAddress;
|
||||
std::optional<std::uint16_t> fuseSegmentSize;
|
||||
std::optional<std::uint16_t> lockbitsSegmentStartAddress;
|
||||
|
||||
std::optional<std::uint32_t> ioPortAddressRangeStart;
|
||||
std::optional<std::uint32_t> ioPortAddressRangeEnd;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user