Lots of tidying
- Removed generic `avr8` target - Simplified AVR8 target construction - Introduced register descriptor IDs - Simplified GDB register mappings - Simplified target interface contract - Other bits of tidying
This commit is contained in:
@@ -3,6 +3,11 @@
|
||||
#include "TargetInterfaces/TargetPowerManagementInterface.hpp"
|
||||
|
||||
#include "TargetInterfaces/Microchip/AVR/AVR8/Avr8DebugInterface.hpp"
|
||||
#include "src/Targets/Microchip/AVR/AVR8/Avr8TargetConfig.hpp"
|
||||
#include "src/Targets/Microchip/AVR/AVR8/Family.hpp"
|
||||
#include "src/Targets/Microchip/AVR/AVR8/TargetParameters.hpp"
|
||||
#include "src/Targets/TargetRegister.hpp"
|
||||
|
||||
#include "TargetInterfaces/Microchip/AVR/AvrIspInterface.hpp"
|
||||
|
||||
namespace Bloom
|
||||
@@ -67,7 +72,12 @@ namespace Bloom
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
virtual DebugToolDrivers::TargetInterfaces::Microchip::Avr::Avr8::Avr8DebugInterface* getAvr8DebugInterface() {
|
||||
virtual DebugToolDrivers::TargetInterfaces::Microchip::Avr::Avr8::Avr8DebugInterface* getAvr8DebugInterface(
|
||||
const Targets::Microchip::Avr::Avr8Bit::Avr8TargetConfig& targetConfig,
|
||||
Targets::Microchip::Avr::Avr8Bit::Family targetFamily,
|
||||
const Targets::Microchip::Avr::Avr8Bit::TargetParameters& targetParameters,
|
||||
const Targets::TargetRegisterDescriptorMapping& targetRegisterDescriptorsById
|
||||
) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -81,7 +91,9 @@ namespace Bloom
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
virtual DebugToolDrivers::TargetInterfaces::Microchip::Avr::AvrIspInterface* getAvrIspInterface() {
|
||||
virtual DebugToolDrivers::TargetInterfaces::Microchip::Avr::AvrIspInterface* getAvrIspInterface(
|
||||
const Targets::Microchip::Avr::Avr8Bit::Avr8TargetConfig& targetConfig
|
||||
) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,6 @@ namespace Bloom::DebugToolDrivers
|
||||
);
|
||||
}
|
||||
|
||||
this->edbgAvr8Interface = std::make_unique<EdbgAvr8Interface>(this->edbgInterface.get());
|
||||
this->edbgAvrIspInterface = std::make_unique<EdbgAvrIspInterface>(this->edbgInterface.get());
|
||||
|
||||
this->setInitialised(true);
|
||||
@@ -81,6 +80,27 @@ namespace Bloom::DebugToolDrivers
|
||||
UsbDevice::close();
|
||||
}
|
||||
|
||||
TargetInterfaces::Microchip::Avr::Avr8::Avr8DebugInterface* EdbgDevice::getAvr8DebugInterface(
|
||||
const Targets::Microchip::Avr::Avr8Bit::Avr8TargetConfig& targetConfig,
|
||||
Targets::Microchip::Avr::Avr8Bit::Family targetFamily,
|
||||
const Targets::Microchip::Avr::Avr8Bit::TargetParameters& targetParameters,
|
||||
const Targets::TargetRegisterDescriptorMapping& targetRegisterDescriptorsById
|
||||
) {
|
||||
if (this->edbgAvr8Interface == nullptr) {
|
||||
this->edbgAvr8Interface = std::make_unique<EdbgAvr8Interface>(
|
||||
this->edbgInterface.get(),
|
||||
targetConfig,
|
||||
targetFamily,
|
||||
targetParameters,
|
||||
targetRegisterDescriptorsById
|
||||
);
|
||||
|
||||
this->configureAvr8Interface();
|
||||
}
|
||||
|
||||
return this->edbgAvr8Interface.get();
|
||||
}
|
||||
|
||||
std::string EdbgDevice::getSerialNumber() {
|
||||
using namespace CommandFrames::Discovery;
|
||||
using ResponseFrames::Discovery::ResponseId;
|
||||
|
||||
@@ -50,11 +50,16 @@ namespace Bloom::DebugToolDrivers
|
||||
*/
|
||||
void close() override;
|
||||
|
||||
TargetInterfaces::Microchip::Avr::Avr8::Avr8DebugInterface* getAvr8DebugInterface() override {
|
||||
return this->edbgAvr8Interface.get();
|
||||
}
|
||||
TargetInterfaces::Microchip::Avr::Avr8::Avr8DebugInterface* getAvr8DebugInterface(
|
||||
const Targets::Microchip::Avr::Avr8Bit::Avr8TargetConfig& targetConfig,
|
||||
Targets::Microchip::Avr::Avr8Bit::Family targetFamily,
|
||||
const Targets::Microchip::Avr::Avr8Bit::TargetParameters& targetParameters,
|
||||
const Targets::TargetRegisterDescriptorMapping& targetRegisterDescriptorsById
|
||||
) override;
|
||||
|
||||
TargetInterfaces::Microchip::Avr::AvrIspInterface* getAvrIspInterface() override {
|
||||
TargetInterfaces::Microchip::Avr::AvrIspInterface* getAvrIspInterface(
|
||||
const Targets::Microchip::Avr::Avr8Bit::Avr8TargetConfig& targetConfig
|
||||
) override {
|
||||
return this->edbgAvrIspInterface.get();
|
||||
}
|
||||
|
||||
@@ -153,5 +158,9 @@ namespace Bloom::DebugToolDrivers
|
||||
* @return
|
||||
*/
|
||||
std::uint16_t getCmsisHidReportSize();
|
||||
|
||||
virtual void configureAvr8Interface() {
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ namespace Bloom::DebugToolDrivers
|
||||
|
||||
try {
|
||||
EdbgDevice::init();
|
||||
this->edbgAvr8Interface->setReactivateJtagTargetPostProgrammingMode(true);
|
||||
|
||||
} catch (const DeviceNotFound& exception) {
|
||||
/*
|
||||
@@ -40,4 +39,8 @@ namespace Bloom::DebugToolDrivers
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
void MplabPickit4::configureAvr8Interface() {
|
||||
this->edbgAvr8Interface->setReactivateJtagTargetPostProgrammingMode(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,5 +36,8 @@ namespace Bloom::DebugToolDrivers
|
||||
}
|
||||
|
||||
void init() override;
|
||||
|
||||
protected:
|
||||
void configureAvr8Interface() override;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ namespace Bloom::DebugToolDrivers
|
||||
|
||||
try {
|
||||
EdbgDevice::init();
|
||||
this->edbgAvr8Interface->setReactivateJtagTargetPostProgrammingMode(true);
|
||||
|
||||
} catch (const DeviceNotFound& exception) {
|
||||
/*
|
||||
@@ -48,4 +47,8 @@ namespace Bloom::DebugToolDrivers
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
void MplabSnap::configureAvr8Interface() {
|
||||
this->edbgAvr8Interface->setReactivateJtagTargetPostProgrammingMode(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,5 +39,8 @@ namespace Bloom::DebugToolDrivers
|
||||
}
|
||||
|
||||
void init() override;
|
||||
|
||||
protected:
|
||||
void configureAvr8Interface() override;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11,9 +11,7 @@ namespace Bloom::DebugToolDrivers
|
||||
)
|
||||
{}
|
||||
|
||||
void XplainedPro::init() {
|
||||
EdbgDevice::init();
|
||||
|
||||
void XplainedPro::configureAvr8Interface() {
|
||||
this->edbgAvr8Interface->setMaximumMemoryAccessSizePerRequest(256);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ namespace Bloom::DebugToolDrivers
|
||||
return "Xplained Pro";
|
||||
}
|
||||
|
||||
void init() override;
|
||||
protected:
|
||||
void configureAvr8Interface() override;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "EdbgAvr8Interface.hpp"
|
||||
|
||||
#include <thread>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
|
||||
#include "src/Services/PathService.hpp"
|
||||
@@ -80,71 +81,26 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||
using Bloom::Targets::TargetRegister;
|
||||
using Bloom::Targets::TargetRegisterDescriptor;
|
||||
using Bloom::Targets::TargetRegisterDescriptors;
|
||||
using Bloom::Targets::TargetRegisterDescriptorId;
|
||||
using Bloom::Targets::TargetRegisterDescriptorIds;
|
||||
using Bloom::Targets::TargetRegisterType;
|
||||
using Bloom::Targets::TargetRegisters;
|
||||
|
||||
EdbgAvr8Interface::EdbgAvr8Interface(EdbgInterface* edbgInterface)
|
||||
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
|
||||
)
|
||||
: edbgInterface(edbgInterface)
|
||||
, targetConfig(targetConfig)
|
||||
, family(targetFamily)
|
||||
, targetParameters(targetParameters)
|
||||
, targetRegisterDescriptorsById(targetRegisterDescriptorsById)
|
||||
, configVariant(EdbgAvr8Interface::resolveConfigVariant(targetFamily, targetConfig.physicalInterface))
|
||||
{}
|
||||
|
||||
void EdbgAvr8Interface::configure(const Targets::Microchip::Avr::Avr8Bit::Avr8TargetConfig& targetConfig) {
|
||||
this->targetConfig = targetConfig;
|
||||
|
||||
this->configVariant = this->resolveConfigVariant().value_or(Avr8ConfigVariant::NONE);
|
||||
}
|
||||
|
||||
void EdbgAvr8Interface::setTargetParameters(const Avr8Bit::TargetParameters& config) {
|
||||
this->targetParameters = config;
|
||||
|
||||
if (!config.stackPointerRegisterLowAddress.has_value()) {
|
||||
throw DeviceInitializationFailure("Failed to find stack pointer register start address");
|
||||
}
|
||||
|
||||
if (!config.stackPointerRegisterSize.has_value()) {
|
||||
throw DeviceInitializationFailure("Failed to find stack pointer register size");
|
||||
}
|
||||
|
||||
if (!config.statusRegisterStartAddress.has_value()) {
|
||||
throw DeviceInitializationFailure("Failed to find status register start address");
|
||||
}
|
||||
|
||||
if (!config.statusRegisterSize.has_value()) {
|
||||
throw DeviceInitializationFailure("Failed to find status register size");
|
||||
}
|
||||
|
||||
if (this->configVariant == Avr8ConfigVariant::NONE) {
|
||||
auto configVariant = this->resolveConfigVariant();
|
||||
|
||||
if (!configVariant.has_value()) {
|
||||
throw DeviceInitializationFailure("Failed to resolve config variant for the selected "
|
||||
"physical interface and AVR8 family. The selected physical interface is not known to be supported "
|
||||
"by the AVR8 family."
|
||||
);
|
||||
}
|
||||
|
||||
this->configVariant = configVariant.value();
|
||||
}
|
||||
|
||||
switch (this->configVariant) {
|
||||
case Avr8ConfigVariant::DEBUG_WIRE:
|
||||
case Avr8ConfigVariant::MEGAJTAG: {
|
||||
this->setDebugWireAndJtagParameters();
|
||||
break;
|
||||
}
|
||||
case Avr8ConfigVariant::XMEGA: {
|
||||
this->setPdiParameters();
|
||||
break;
|
||||
}
|
||||
case Avr8ConfigVariant::UPDI: {
|
||||
this->setUpdiParameters();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EdbgAvr8Interface::init() {
|
||||
if (this->configVariant == Avr8ConfigVariant::XMEGA) {
|
||||
// Default PDI clock to 4MHz
|
||||
@@ -177,8 +133,10 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||
|
||||
this->setParameter(
|
||||
Avr8EdbgParameters::PHYSICAL_INTERFACE,
|
||||
getAvr8PhysicalInterfaceToIdMapping().at(this->targetConfig->physicalInterface)
|
||||
getAvr8PhysicalInterfaceToIdMapping().at(this->targetConfig.physicalInterface)
|
||||
);
|
||||
|
||||
this->setTargetParameters();
|
||||
}
|
||||
|
||||
void EdbgAvr8Interface::stop() {
|
||||
@@ -267,7 +225,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||
|
||||
} catch (const Avr8CommandFailure& activationException) {
|
||||
if (
|
||||
this->targetConfig->physicalInterface == PhysicalInterface::DEBUG_WIRE
|
||||
this->targetConfig.physicalInterface == PhysicalInterface::DEBUG_WIRE
|
||||
&& (
|
||||
activationException.code == Avr8CommandFailureCode::DEBUGWIRE_PHYSICAL_ERROR
|
||||
|| activationException.code == Avr8CommandFailureCode::FAILED_TO_ENABLE_OCD
|
||||
@@ -292,8 +250,8 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||
void EdbgAvr8Interface::deactivate() {
|
||||
if (this->targetAttached) {
|
||||
if (
|
||||
this->targetConfig->physicalInterface == PhysicalInterface::DEBUG_WIRE
|
||||
&& this->targetConfig->disableDebugWireOnDeactivate
|
||||
this->targetConfig.physicalInterface == PhysicalInterface::DEBUG_WIRE
|
||||
&& this->targetConfig.disableDebugWireOnDeactivate
|
||||
) {
|
||||
try {
|
||||
this->disableDebugWire();
|
||||
@@ -385,7 +343,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||
throw Avr8CommandFailure("AVR8 Get device ID command failed", responseFrame);
|
||||
}
|
||||
|
||||
return responseFrame.extractSignature(this->targetConfig->physicalInterface);
|
||||
return responseFrame.extractSignature(this->targetConfig.physicalInterface);
|
||||
}
|
||||
|
||||
void EdbgAvr8Interface::setBreakpoint(TargetMemoryAddress address) {
|
||||
@@ -418,7 +376,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||
}
|
||||
}
|
||||
|
||||
TargetRegisters EdbgAvr8Interface::readRegisters(const TargetRegisterDescriptors& descriptors) {
|
||||
TargetRegisters EdbgAvr8Interface::readRegisters(const TargetRegisterDescriptorIds& descriptorIds) {
|
||||
/*
|
||||
* This function needs to be fast. Insight eagerly requests the values of all known registers that it can
|
||||
* present to the user. It does this on numerous occasions (target stopped, user clicked refresh, etc). This
|
||||
@@ -439,7 +397,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||
auto output = TargetRegisters();
|
||||
|
||||
// Group descriptors by type and resolve the address range for each type
|
||||
auto descriptorsByType = std::map<TargetRegisterType, std::set<const TargetRegisterDescriptor*>>();
|
||||
auto descriptorIdsByType = std::map<TargetRegisterType, std::set<TargetRegisterDescriptorId>>();
|
||||
|
||||
/*
|
||||
* An address range is just an std::pair of addresses - the first being the start address, the second being
|
||||
@@ -450,7 +408,12 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||
using AddressRange = std::pair<TargetMemoryAddress, TargetMemoryAddress>;
|
||||
auto addressRangeByType = std::map<TargetRegisterType, AddressRange>();
|
||||
|
||||
for (const auto& descriptor : descriptors) {
|
||||
for (const auto& descriptorId : descriptorIds) {
|
||||
const auto descriptorIt = this->targetRegisterDescriptorsById.find(descriptorId);
|
||||
assert(descriptorIt != this->targetRegisterDescriptorsById.end());
|
||||
|
||||
const auto& descriptor = descriptorIt->second;
|
||||
|
||||
if (!descriptor.startAddress.has_value()) {
|
||||
Logger::debug(
|
||||
"Attempted to read register in the absence of a start address - register name: "
|
||||
@@ -459,18 +422,18 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||
continue;
|
||||
}
|
||||
|
||||
descriptorsByType[descriptor.type].insert(&descriptor);
|
||||
descriptorIdsByType[descriptor.type].insert(descriptor.id);
|
||||
|
||||
const auto startAddress = descriptor.startAddress.value();
|
||||
const auto endAddress = startAddress + (descriptor.size - 1);
|
||||
|
||||
const auto addressRangeit = addressRangeByType.find(descriptor.type);
|
||||
const auto addressRangeIt = addressRangeByType.find(descriptor.type);
|
||||
|
||||
if (addressRangeit == addressRangeByType.end()) {
|
||||
if (addressRangeIt == addressRangeByType.end()) {
|
||||
addressRangeByType[descriptor.type] = AddressRange(startAddress, endAddress);
|
||||
|
||||
} else {
|
||||
auto& addressRange = addressRangeit->second;
|
||||
auto& addressRange = addressRangeIt->second;
|
||||
|
||||
if (startAddress < addressRange.first) {
|
||||
addressRange.first = startAddress;
|
||||
@@ -486,16 +449,17 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||
* Now that we have our address ranges and grouped descriptors, we can perform a single read call for each
|
||||
* register type.
|
||||
*/
|
||||
for (const auto&[registerType, descriptors] : descriptorsByType) {
|
||||
for (const auto&[registerType, descriptorIds] : descriptorIdsByType) {
|
||||
const auto& addressRange = addressRangeByType[registerType];
|
||||
const auto startAddress = addressRange.first;
|
||||
const auto endAddress = addressRange.second;
|
||||
const auto bufferSize = (endAddress - startAddress) + 1;
|
||||
const auto readSize = (endAddress - startAddress) + 1;
|
||||
|
||||
const auto memoryType = (registerType != TargetRegisterType::GENERAL_PURPOSE_REGISTER) ?
|
||||
Avr8MemoryType::SRAM
|
||||
const auto memoryType = (registerType != TargetRegisterType::GENERAL_PURPOSE_REGISTER)
|
||||
? Avr8MemoryType::SRAM
|
||||
: (this->configVariant == Avr8ConfigVariant::XMEGA || this->configVariant == Avr8ConfigVariant::UPDI
|
||||
? Avr8MemoryType::REGISTER_FILE : Avr8MemoryType::SRAM);
|
||||
? Avr8MemoryType::REGISTER_FILE
|
||||
: Avr8MemoryType::SRAM);
|
||||
|
||||
/*
|
||||
* When reading the entire range, we must avoid any attempts to access the OCD data register (OCDDR), as
|
||||
@@ -526,37 +490,40 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||
);
|
||||
}
|
||||
|
||||
const auto flatMemoryBuffer = this->readMemory(
|
||||
const auto flatMemoryData = this->readMemory(
|
||||
memoryType,
|
||||
startAddress,
|
||||
bufferSize,
|
||||
readSize,
|
||||
excludedAddresses
|
||||
);
|
||||
|
||||
if (flatMemoryBuffer.size() != bufferSize) {
|
||||
if (flatMemoryData.size() != readSize) {
|
||||
throw Exception(
|
||||
"Failed to read memory within register type address range (" + std::to_string(startAddress)
|
||||
+ " - " + std::to_string(endAddress) + "). Expected " + std::to_string(bufferSize)
|
||||
+ " bytes, got " + std::to_string(flatMemoryBuffer.size())
|
||||
+ " - " + std::to_string(endAddress) + "). Expected " + std::to_string(readSize)
|
||||
+ " bytes, got " + std::to_string(flatMemoryData.size())
|
||||
);
|
||||
}
|
||||
|
||||
// Construct our TargetRegister objects directly from the flat memory buffer
|
||||
for (const auto& descriptor : descriptors) {
|
||||
for (const auto descriptorId : descriptorIds) {
|
||||
const auto descriptorIt = this->targetRegisterDescriptorsById.find(descriptorId);
|
||||
const auto& descriptor = descriptorIt->second;
|
||||
|
||||
/*
|
||||
* Multibyte AVR8 registers are stored in LSB form.
|
||||
*
|
||||
* This is why we use reverse iterators when extracting our data from flatMemoryBuffer. Doing so allows
|
||||
* This is why we use reverse iterators when extracting our data from flatMemoryData. Doing so allows
|
||||
* us to extract the data in MSB form (as is expected for all register values held in TargetRegister
|
||||
* objects).
|
||||
*/
|
||||
const auto bufferStartIt = flatMemoryBuffer.rend() - (descriptor->startAddress.value() - startAddress)
|
||||
- descriptor->size;
|
||||
const auto bufferStartIt = flatMemoryData.rend() - (descriptor.startAddress.value() - startAddress)
|
||||
- descriptor.size;
|
||||
|
||||
output.emplace_back(
|
||||
TargetRegister(
|
||||
*descriptor,
|
||||
TargetMemoryBuffer(bufferStartIt, bufferStartIt + descriptor->size)
|
||||
descriptor.id,
|
||||
TargetMemoryBuffer(bufferStartIt, bufferStartIt + descriptor.size)
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -567,7 +534,10 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||
|
||||
void EdbgAvr8Interface::writeRegisters(const Targets::TargetRegisters& registers) {
|
||||
for (const auto& reg : registers) {
|
||||
const auto& registerDescriptor = reg.descriptor;
|
||||
const auto& registerDescriptorIt = this->targetRegisterDescriptorsById.find(reg.descriptorId);
|
||||
assert(registerDescriptorIt != this->targetRegisterDescriptorsById.end());
|
||||
|
||||
const auto& registerDescriptor = registerDescriptorIt->second;
|
||||
auto registerValue = reg.value;
|
||||
|
||||
if (registerValue.empty()) {
|
||||
@@ -827,7 +797,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||
*/
|
||||
auto eepromSnapshot = std::optional<Targets::TargetMemoryBuffer>();
|
||||
|
||||
if (this->targetConfig->preserveEeprom) {
|
||||
if (this->targetConfig.preserveEeprom) {
|
||||
Logger::debug("Capturing EEPROM data, in preparation for chip erase");
|
||||
eepromSnapshot = this->readMemory(
|
||||
TargetMemoryType::EEPROM,
|
||||
@@ -910,6 +880,43 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::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) {
|
||||
case Avr8ConfigVariant::DEBUG_WIRE:
|
||||
case Avr8ConfigVariant::MEGAJTAG: {
|
||||
this->setDebugWireAndJtagParameters();
|
||||
break;
|
||||
}
|
||||
case Avr8ConfigVariant::XMEGA: {
|
||||
this->setPdiParameters();
|
||||
break;
|
||||
}
|
||||
case Avr8ConfigVariant::UPDI: {
|
||||
this->setUpdiParameters();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::map<Family, std::map<PhysicalInterface, Avr8ConfigVariant>>
|
||||
EdbgAvr8Interface::getConfigVariantsByFamilyAndPhysicalInterface() {
|
||||
return std::map<Family, std::map<PhysicalInterface, Avr8ConfigVariant>>({
|
||||
@@ -963,49 +970,21 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||
});
|
||||
}
|
||||
|
||||
std::optional<Avr8ConfigVariant> EdbgAvr8Interface::resolveConfigVariant() {
|
||||
if (this->family.has_value()) {
|
||||
const auto configVariantsByFamily = EdbgAvr8Interface::getConfigVariantsByFamilyAndPhysicalInterface();
|
||||
const auto configVariantsByPhysicalInterfaceIt = configVariantsByFamily.find(*(this->family));
|
||||
Avr8ConfigVariant EdbgAvr8Interface::resolveConfigVariant(
|
||||
Targets::Microchip::Avr::Avr8Bit::Family targetFamily,
|
||||
Targets::Microchip::Avr::Avr8Bit::PhysicalInterface physicalInterface
|
||||
) {
|
||||
const auto configVariantsByFamily = EdbgAvr8Interface::getConfigVariantsByFamilyAndPhysicalInterface();
|
||||
const auto configVariantsByPhysicalInterfaceIt = configVariantsByFamily.find(targetFamily);
|
||||
|
||||
if (configVariantsByPhysicalInterfaceIt != configVariantsByFamily.end()) {
|
||||
const auto& configVariantsByPhysicalInterface = configVariantsByPhysicalInterfaceIt->second;
|
||||
const auto configVariantIt = configVariantsByPhysicalInterface.find(
|
||||
this->targetConfig->physicalInterface
|
||||
);
|
||||
assert(configVariantsByPhysicalInterfaceIt != configVariantsByFamily.end());
|
||||
|
||||
if (configVariantIt != configVariantsByPhysicalInterface.end()) {
|
||||
return configVariantIt->second;
|
||||
}
|
||||
}
|
||||
const auto& configVariantsByPhysicalInterface = configVariantsByPhysicalInterfaceIt->second;
|
||||
const auto configVariantIt = configVariantsByPhysicalInterface.find(physicalInterface);
|
||||
|
||||
} else {
|
||||
/*
|
||||
* If there is no family set, we may be able to resort to a simpler mapping of physical interfaces
|
||||
* to config variants. But this will only work if the selected physical interface is *NOT* JTAG.
|
||||
*
|
||||
* This is because JTAG is the only physical interface that could map to two different config
|
||||
* variants (MEGAJTAG and XMEGA). The only way we can figure out which config variant to use is if we
|
||||
* know the target family.
|
||||
*
|
||||
* This is why we don't allow users to use ambiguous target names (such as the generic "avr8" target
|
||||
* name), when using the JTAG physical interface. We won't be able to resolve the correct target
|
||||
* variant. Users are required to specify the exact target name in their config, when using the JTAG
|
||||
* physical interface. That way, this->family will be set by the time resolveConfigVariant() is called.
|
||||
*/
|
||||
static const std::map<PhysicalInterface, Avr8ConfigVariant> physicalInterfacesToConfigVariants = {
|
||||
{PhysicalInterface::DEBUG_WIRE, Avr8ConfigVariant::DEBUG_WIRE},
|
||||
{PhysicalInterface::PDI, Avr8ConfigVariant::XMEGA},
|
||||
{PhysicalInterface::UPDI, Avr8ConfigVariant::UPDI},
|
||||
};
|
||||
const auto configVariantIt = physicalInterfacesToConfigVariants.find(this->targetConfig->physicalInterface);
|
||||
assert(configVariantIt != configVariantsByPhysicalInterface.end());
|
||||
|
||||
if (configVariantIt != physicalInterfacesToConfigVariants.end()) {
|
||||
return configVariantIt->second;
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
return configVariantIt->second;
|
||||
}
|
||||
|
||||
void EdbgAvr8Interface::setParameter(const Avr8EdbgParameter& parameter, const std::vector<unsigned char>& value) {
|
||||
|
||||
@@ -10,9 +10,10 @@
|
||||
#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/Avr8Generic.hpp"
|
||||
#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/EdbgInterface.hpp"
|
||||
#include "src/Targets/TargetMemory.hpp"
|
||||
#include "src/Targets/Microchip/AVR/Target.hpp"
|
||||
#include "src/Targets/TargetRegister.hpp"
|
||||
#include "src/Targets/Microchip/AVR/AVR8/Family.hpp"
|
||||
#include "src/Targets/Microchip/AVR/AVR8/PhysicalInterface.hpp"
|
||||
#include "src/Targets/Microchip/AVR/AVR8/TargetParameters.hpp"
|
||||
|
||||
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||
{
|
||||
@@ -28,7 +29,13 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||
class EdbgAvr8Interface: public TargetInterfaces::Microchip::Avr::Avr8::Avr8DebugInterface
|
||||
{
|
||||
public:
|
||||
explicit EdbgAvr8Interface(EdbgInterface* edbgInterface);
|
||||
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
|
||||
);
|
||||
|
||||
/**
|
||||
* Some EDBG devices don't seem to operate correctly when actioning the masked memory read EDBG command. The
|
||||
@@ -83,32 +90,6 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||
* See the comments in that class for more info on the expected behaviour of each method.
|
||||
*/
|
||||
|
||||
/**
|
||||
* As already mentioned in numerous comments above, the EdbgAvr8Interface requires some configuration from
|
||||
* the user. This is supplied via the user's Bloom configuration.
|
||||
*
|
||||
* @param targetConfig
|
||||
*/
|
||||
void configure(const Targets::Microchip::Avr::Avr8Bit::Avr8TargetConfig& targetConfig) override;
|
||||
|
||||
/**
|
||||
* Configures the target family. For some physical interfaces, the target family is required in order
|
||||
* properly configure the EDBG tool. See EdbgAvr8Interface::resolveConfigVariant() for more.
|
||||
*
|
||||
* @param family
|
||||
*/
|
||||
void setFamily(Targets::Microchip::Avr::Avr8Bit::Family family) override {
|
||||
this->family = family;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts target parameters from the AVR8 target instance and sends the necessary target parameters to the
|
||||
* debug tool.
|
||||
*
|
||||
* @param config
|
||||
*/
|
||||
void setTargetParameters(const Targets::Microchip::Avr::Avr8Bit::TargetParameters& config) override;
|
||||
|
||||
/**
|
||||
* Initialises the AVR8 Generic protocol interface by setting the appropriate parameters on the debug tool.
|
||||
*/
|
||||
@@ -207,10 +188,10 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||
/**
|
||||
* Reads registers from the target.
|
||||
*
|
||||
* @param descriptors
|
||||
* @param descriptorIds
|
||||
* @return
|
||||
*/
|
||||
Targets::TargetRegisters readRegisters(const Targets::TargetRegisterDescriptors& descriptors) override;
|
||||
Targets::TargetRegisters readRegisters(const Targets::TargetRegisterDescriptorIds& descriptorIds) override;
|
||||
|
||||
/**
|
||||
* Writes registers to target.
|
||||
@@ -289,7 +270,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||
/**
|
||||
* Project's AVR8 target configuration.
|
||||
*/
|
||||
std::optional<Targets::Microchip::Avr::Avr8Bit::Avr8TargetConfig> targetConfig;
|
||||
const Targets::Microchip::Avr::Avr8Bit::Avr8TargetConfig& targetConfig;
|
||||
|
||||
/**
|
||||
* The target family is taken into account when configuring the AVR8 Generic protocol on the EDBG device.
|
||||
@@ -297,7 +278,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||
* We use this to determine which config variant to select.
|
||||
* See EdbgAvr8Interface::resolveConfigVariant() for more.
|
||||
*/
|
||||
std::optional<Targets::Microchip::Avr::Avr8Bit::Family> family;
|
||||
Targets::Microchip::Avr::Avr8Bit::Family family;
|
||||
|
||||
/**
|
||||
* The AVR8 Generic protocol provides two functions: Debugging and programming. The desired function must be
|
||||
@@ -320,7 +301,9 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||
* For the EdbgAvr8Interface, we send the required parameters to the debug tool immediately upon receiving
|
||||
* them. See EdbgAvr8Interface::setTargetParameters().
|
||||
*/
|
||||
Targets::Microchip::Avr::Avr8Bit::TargetParameters targetParameters;
|
||||
const Targets::Microchip::Avr::Avr8Bit::TargetParameters& targetParameters;
|
||||
|
||||
const Targets::TargetRegisterDescriptorMapping& targetRegisterDescriptorsById;
|
||||
|
||||
/**
|
||||
* See the comment for EdbgAvr8Interface::setAvoidMaskedMemoryRead().
|
||||
@@ -357,6 +340,13 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||
|
||||
bool programmingModeEnabled = false;
|
||||
|
||||
/**
|
||||
* Sends the necessary target parameters to the debug tool.
|
||||
*
|
||||
* @param config
|
||||
*/
|
||||
void setTargetParameters();
|
||||
|
||||
/**
|
||||
* This mapping allows us to determine which config variant to select, based on the target family and the
|
||||
* selected physical interface.
|
||||
@@ -367,11 +357,14 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||
> getConfigVariantsByFamilyAndPhysicalInterface();
|
||||
|
||||
/**
|
||||
* Will attempt to resolve the config variant with the information currently held.
|
||||
* Determines the config variant given a target family and physical interface.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
std::optional<Avr8ConfigVariant> resolveConfigVariant();
|
||||
static Avr8ConfigVariant resolveConfigVariant(
|
||||
Targets::Microchip::Avr::Avr8Bit::Family targetFamily,
|
||||
Targets::Microchip::Avr::Avr8Bit::PhysicalInterface physicalInterface
|
||||
);
|
||||
|
||||
/**
|
||||
* Sets an AVR8 parameter on the debug tool. See the Avr8EdbgParameters class and protocol documentation
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "../../AvrEvent.hpp"
|
||||
#include "src/Targets/Microchip/AVR/Target.hpp"
|
||||
#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/AvrEvent.hpp"
|
||||
#include "src/Targets/TargetBreakpoint.hpp"
|
||||
|
||||
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||
{
|
||||
|
||||
@@ -41,28 +41,6 @@ namespace Bloom::DebugToolDrivers::TargetInterfaces::Microchip::Avr::Avr8
|
||||
Avr8DebugInterface& operator = (const Avr8DebugInterface& other) = default;
|
||||
Avr8DebugInterface& operator = (Avr8DebugInterface&& other) = default;
|
||||
|
||||
/**
|
||||
* Configures the interface. Any debug tool -> target interface specific configuration should take
|
||||
* place here.
|
||||
*
|
||||
* @param targetConfig
|
||||
*/
|
||||
virtual void configure(const Targets::Microchip::Avr::Avr8Bit::Avr8TargetConfig& targetConfig) = 0;
|
||||
|
||||
/**
|
||||
* Sets the target family, independent of other configuration.
|
||||
*
|
||||
* @param family
|
||||
*/
|
||||
virtual void setFamily(Targets::Microchip::Avr::Avr8Bit::Family family) = 0;
|
||||
|
||||
/**
|
||||
* Should accept Avr8 target parameters for configuration of the interface.
|
||||
*
|
||||
* @param config
|
||||
*/
|
||||
virtual void setTargetParameters(const Targets::Microchip::Avr::Avr8Bit::TargetParameters& config) = 0;
|
||||
|
||||
/**
|
||||
* Should initialise the interface between the debug tool and the AVR8 target.
|
||||
*/
|
||||
@@ -153,12 +131,12 @@ namespace Bloom::DebugToolDrivers::TargetInterfaces::Microchip::Avr::Avr8
|
||||
/**
|
||||
* Should read the requested registers from the target.
|
||||
*
|
||||
* @param descriptors
|
||||
* A collection of register descriptors, for the registers to be read.
|
||||
* @param descriptorIds
|
||||
* A collection of register descriptor IDs, for the registers to be read.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
virtual Targets::TargetRegisters readRegisters(const Targets::TargetRegisterDescriptors& descriptors) = 0;
|
||||
virtual Targets::TargetRegisters readRegisters(const Targets::TargetRegisterDescriptorIds& descriptorIds) = 0;
|
||||
|
||||
/**
|
||||
* Should update the value of the given registers.
|
||||
|
||||
Reference in New Issue
Block a user