2021-08-15 01:47:48 +01:00
|
|
|
#include "EdbgAvr8Interface.hpp"
|
|
|
|
|
|
2021-04-04 21:04:12 +01:00
|
|
|
#include <thread>
|
2023-05-21 21:08:25 +01:00
|
|
|
#include <cassert>
|
2022-01-16 18:54:58 +00:00
|
|
|
#include <cmath>
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-12-26 21:47:09 +00:00
|
|
|
#include "src/Services/PathService.hpp"
|
2023-01-21 14:27:45 +00:00
|
|
|
#include "src/Services/StringService.hpp"
|
2022-12-26 21:47:09 +00:00
|
|
|
#include "src/Logger/Logger.hpp"
|
2022-03-02 00:56:40 +00:00
|
|
|
|
2023-11-17 22:20:39 +00:00
|
|
|
#include "Exceptions/Avr8CommandFailure.hpp"
|
2021-08-15 01:47:48 +01:00
|
|
|
#include "src/TargetController/Exceptions/DeviceInitializationFailure.hpp"
|
2022-03-02 00:56:40 +00:00
|
|
|
#include "src/Targets/Microchip/AVR/AVR8/Exceptions/DebugWirePhysicalInterfaceError.hpp"
|
2021-04-04 21:04:12 +01:00
|
|
|
|
|
|
|
|
// Command frames
|
2023-11-17 22:20:39 +00:00
|
|
|
#include "CommandFrames/AVR8Generic/SetParameter.hpp"
|
|
|
|
|
#include "CommandFrames/AVR8Generic/GetParameter.hpp"
|
|
|
|
|
#include "CommandFrames/AVR8Generic/ActivatePhysical.hpp"
|
|
|
|
|
#include "CommandFrames/AVR8Generic/DeactivatePhysical.hpp"
|
|
|
|
|
#include "CommandFrames/AVR8Generic/Attach.hpp"
|
|
|
|
|
#include "CommandFrames/AVR8Generic/Detach.hpp"
|
|
|
|
|
#include "CommandFrames/AVR8Generic/Stop.hpp"
|
|
|
|
|
#include "CommandFrames/AVR8Generic/Step.hpp"
|
|
|
|
|
#include "CommandFrames/AVR8Generic/Run.hpp"
|
|
|
|
|
#include "CommandFrames/AVR8Generic/RunTo.hpp"
|
|
|
|
|
#include "CommandFrames/AVR8Generic/GetDeviceId.hpp"
|
|
|
|
|
#include "CommandFrames/AVR8Generic/Reset.hpp"
|
|
|
|
|
#include "CommandFrames/AVR8Generic/ReadMemory.hpp"
|
|
|
|
|
#include "CommandFrames/AVR8Generic/WriteMemory.hpp"
|
|
|
|
|
#include "CommandFrames/AVR8Generic/GetProgramCounter.hpp"
|
|
|
|
|
#include "CommandFrames/AVR8Generic/SetProgramCounter.hpp"
|
|
|
|
|
#include "CommandFrames/AVR8Generic/DisableDebugWire.hpp"
|
|
|
|
|
#include "CommandFrames/AVR8Generic/SetSoftwareBreakpoints.hpp"
|
|
|
|
|
#include "CommandFrames/AVR8Generic/ClearAllSoftwareBreakpoints.hpp"
|
|
|
|
|
#include "CommandFrames/AVR8Generic/ClearSoftwareBreakpoints.hpp"
|
|
|
|
|
#include "CommandFrames/AVR8Generic/SetHardwareBreakpoint.hpp"
|
|
|
|
|
#include "CommandFrames/AVR8Generic/ClearHardwareBreakpoint.hpp"
|
|
|
|
|
#include "CommandFrames/AVR8Generic/EnterProgrammingMode.hpp"
|
|
|
|
|
#include "CommandFrames/AVR8Generic/LeaveProgrammingMode.hpp"
|
|
|
|
|
#include "CommandFrames/AVR8Generic/EraseMemory.hpp"
|
2021-04-04 21:04:12 +01:00
|
|
|
|
|
|
|
|
// AVR events
|
2023-11-17 22:20:39 +00:00
|
|
|
#include "Events/AVR8Generic/BreakEvent.hpp"
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2023-11-17 22:20:39 +00:00
|
|
|
namespace DebugToolDrivers::Microchip::Protocols::Edbg::Avr
|
2022-02-05 15:32:08 +00:00
|
|
|
{
|
2023-08-13 15:47:51 +01:00
|
|
|
using namespace Targets::Microchip::Avr;
|
2022-02-05 15:32:08 +00:00
|
|
|
using namespace Avr8Bit;
|
2023-08-13 15:47:51 +01:00
|
|
|
using namespace Exceptions;
|
2022-02-05 15:32:08 +00:00
|
|
|
|
2022-06-02 23:06:39 +01:00
|
|
|
using CommandFrames::Avr8Generic::Stop;
|
|
|
|
|
using CommandFrames::Avr8Generic::Run;
|
|
|
|
|
using CommandFrames::Avr8Generic::RunTo;
|
|
|
|
|
using CommandFrames::Avr8Generic::Step;
|
|
|
|
|
using CommandFrames::Avr8Generic::Reset;
|
|
|
|
|
using CommandFrames::Avr8Generic::GetProgramCounter;
|
|
|
|
|
using CommandFrames::Avr8Generic::SetProgramCounter;
|
|
|
|
|
using CommandFrames::Avr8Generic::GetDeviceId;
|
|
|
|
|
using CommandFrames::Avr8Generic::SetSoftwareBreakpoints;
|
|
|
|
|
using CommandFrames::Avr8Generic::ClearSoftwareBreakpoints;
|
|
|
|
|
using CommandFrames::Avr8Generic::ClearAllSoftwareBreakpoints;
|
2023-09-20 23:37:54 +01:00
|
|
|
using CommandFrames::Avr8Generic::SetHardwareBreakpoint;
|
|
|
|
|
using CommandFrames::Avr8Generic::ClearHardwareBreakpoint;
|
2022-06-02 23:06:39 +01:00
|
|
|
using CommandFrames::Avr8Generic::ReadMemory;
|
|
|
|
|
using CommandFrames::Avr8Generic::EnterProgrammingMode;
|
|
|
|
|
using CommandFrames::Avr8Generic::LeaveProgrammingMode;
|
|
|
|
|
using CommandFrames::Avr8Generic::SetParameter;
|
|
|
|
|
using CommandFrames::Avr8Generic::GetParameter;
|
|
|
|
|
using CommandFrames::Avr8Generic::ActivatePhysical;
|
|
|
|
|
using CommandFrames::Avr8Generic::DeactivatePhysical;
|
|
|
|
|
using CommandFrames::Avr8Generic::Attach;
|
|
|
|
|
using CommandFrames::Avr8Generic::Detach;
|
|
|
|
|
using CommandFrames::Avr8Generic::ReadMemory;
|
|
|
|
|
using CommandFrames::Avr8Generic::WriteMemory;
|
|
|
|
|
using CommandFrames::Avr8Generic::EraseMemory;
|
|
|
|
|
using CommandFrames::Avr8Generic::DisableDebugWire;
|
|
|
|
|
|
2023-08-13 15:47:51 +01:00
|
|
|
using Targets::TargetState;
|
|
|
|
|
using Targets::TargetMemoryType;
|
|
|
|
|
using Targets::TargetMemoryBuffer;
|
|
|
|
|
using Targets::TargetMemoryAddress;
|
|
|
|
|
using Targets::TargetMemorySize;
|
|
|
|
|
using Targets::TargetRegister;
|
|
|
|
|
using Targets::TargetRegisterDescriptor;
|
|
|
|
|
using Targets::TargetRegisterDescriptors;
|
|
|
|
|
using Targets::TargetRegisterDescriptorId;
|
|
|
|
|
using Targets::TargetRegisterDescriptorIds;
|
|
|
|
|
using Targets::TargetRegisterType;
|
|
|
|
|
using Targets::TargetRegisters;
|
2022-02-05 15:32:08 +00:00
|
|
|
|
2023-05-21 21:08:25 +01:00
|
|
|
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
|
|
|
|
|
)
|
2022-06-02 23:06:39 +01:00
|
|
|
: edbgInterface(edbgInterface)
|
2023-05-21 21:08:25 +01:00
|
|
|
, targetConfig(targetConfig)
|
|
|
|
|
, family(targetFamily)
|
2023-08-19 21:53:00 +01:00
|
|
|
, configVariant(EdbgAvr8Interface::resolveConfigVariant(targetFamily, targetConfig.physicalInterface))
|
2023-05-21 21:08:25 +01:00
|
|
|
, targetParameters(targetParameters)
|
|
|
|
|
, targetRegisterDescriptorsById(targetRegisterDescriptorsById)
|
2022-06-02 23:06:39 +01:00
|
|
|
{}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void EdbgAvr8Interface::init() {
|
|
|
|
|
if (this->configVariant == Avr8ConfigVariant::XMEGA) {
|
|
|
|
|
// Default PDI clock to 4MHz
|
|
|
|
|
// TODO: Make this adjustable via a target config parameter
|
2023-02-20 21:54:28 +00:00
|
|
|
this->setParameter(Avr8EdbgParameters::PDI_CLOCK_SPEED, static_cast<std::uint16_t>(4000));
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
2022-02-05 15:32:08 +00:00
|
|
|
|
|
|
|
|
if (this->configVariant == Avr8ConfigVariant::UPDI) {
|
|
|
|
|
// Default UPDI clock to 1.8MHz
|
2023-02-20 21:54:28 +00:00
|
|
|
this->setParameter(Avr8EdbgParameters::PDI_CLOCK_SPEED, static_cast<std::uint16_t>(1800));
|
|
|
|
|
this->setParameter(Avr8EdbgParameters::ENABLE_HIGH_VOLTAGE_UPDI, static_cast<std::uint8_t>(0));
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
2022-02-05 15:32:08 +00:00
|
|
|
|
|
|
|
|
if (this->configVariant == Avr8ConfigVariant::MEGAJTAG) {
|
2023-02-20 21:54:28 +00:00
|
|
|
// Default clock value for mega debugging is 200KHz
|
2022-02-05 15:32:08 +00:00
|
|
|
// TODO: Make this adjustable via a target config parameter
|
2023-02-20 21:54:28 +00:00
|
|
|
this->setParameter(Avr8EdbgParameters::MEGA_DEBUG_CLOCK, static_cast<std::uint16_t>(200));
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(Avr8EdbgParameters::JTAG_DAISY_CHAIN_SETTINGS, static_cast<std::uint32_t>(0));
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::CONFIG_VARIANT,
|
|
|
|
|
static_cast<std::uint8_t>(this->configVariant)
|
|
|
|
|
);
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::CONFIG_FUNCTION,
|
|
|
|
|
static_cast<std::uint8_t>(this->configFunction)
|
|
|
|
|
);
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::PHYSICAL_INTERFACE,
|
2023-05-21 21:08:25 +01:00
|
|
|
getAvr8PhysicalInterfaceToIdMapping().at(this->targetConfig.physicalInterface)
|
2022-02-05 15:32:08 +00:00
|
|
|
);
|
2023-05-21 21:08:25 +01:00
|
|
|
|
|
|
|
|
this->setTargetParameters();
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void EdbgAvr8Interface::stop() {
|
2022-10-01 20:42:37 +01:00
|
|
|
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
|
2022-06-02 23:06:39 +01:00
|
|
|
Stop()
|
|
|
|
|
);
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
|
|
|
|
throw Avr8CommandFailure("AVR8 Stop target command failed", responseFrame);
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->getTargetState() == TargetState::RUNNING) {
|
|
|
|
|
this->waitForStoppedEvent();
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void EdbgAvr8Interface::run() {
|
|
|
|
|
this->clearEvents();
|
2022-10-01 20:42:37 +01:00
|
|
|
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
|
2022-06-02 23:06:39 +01:00
|
|
|
Run()
|
|
|
|
|
);
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
|
|
|
|
throw Avr8CommandFailure("AVR8 Run command failed", responseFrame);
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->targetState = TargetState::RUNNING;
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
|
2023-04-01 12:40:12 +01:00
|
|
|
void EdbgAvr8Interface::runTo(TargetMemoryAddress address) {
|
2022-02-05 15:32:08 +00:00
|
|
|
this->clearEvents();
|
2022-10-01 20:42:37 +01:00
|
|
|
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
|
2022-06-02 23:06:39 +01:00
|
|
|
RunTo(address)
|
|
|
|
|
);
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
|
|
|
|
throw Avr8CommandFailure("AVR8 Run-to command failed", responseFrame);
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->targetState = TargetState::RUNNING;
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void EdbgAvr8Interface::step() {
|
2022-10-01 20:42:37 +01:00
|
|
|
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
|
2022-06-02 23:06:39 +01:00
|
|
|
Step()
|
|
|
|
|
);
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
|
|
|
|
throw Avr8CommandFailure("AVR8 Step target command failed", responseFrame);
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->targetState = TargetState::RUNNING;
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void EdbgAvr8Interface::reset() {
|
2022-10-01 20:42:37 +01:00
|
|
|
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
|
2022-06-02 23:06:39 +01:00
|
|
|
Reset()
|
|
|
|
|
);
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
|
|
|
|
throw Avr8CommandFailure("AVR8 Reset target command failed", responseFrame);
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2022-04-08 22:16:19 +01:00
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// Wait for stopped event
|
|
|
|
|
this->waitForStoppedEvent();
|
|
|
|
|
|
|
|
|
|
} catch (const Exception& exception) {
|
|
|
|
|
throw Exception("Failed to reset AVR8 target - missing stopped event.");
|
|
|
|
|
}
|
2022-09-24 18:45:45 +01:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Issuing another command immediately after reset sometimes results in an 'illegal target state' error from
|
|
|
|
|
* the EDBG debug tool. Even though we waited for the break event.
|
|
|
|
|
*
|
|
|
|
|
* All we can really do here is introduce a small delay, to ensure that we're not issuing commands too quickly
|
|
|
|
|
* after reset.
|
|
|
|
|
*/
|
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(250));
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void EdbgAvr8Interface::activate() {
|
|
|
|
|
if (!this->physicalInterfaceActivated) {
|
2022-03-02 00:56:40 +00:00
|
|
|
try {
|
|
|
|
|
this->activatePhysical();
|
|
|
|
|
|
|
|
|
|
} catch (const Avr8CommandFailure& activationException) {
|
2023-07-18 21:28:45 +01:00
|
|
|
if (
|
2023-05-21 21:08:25 +01:00
|
|
|
this->targetConfig.physicalInterface == PhysicalInterface::DEBUG_WIRE
|
2023-07-18 21:28:45 +01:00
|
|
|
&& (
|
|
|
|
|
activationException.code == Avr8CommandFailureCode::DEBUGWIRE_PHYSICAL_ERROR
|
|
|
|
|
|| activationException.code == Avr8CommandFailureCode::FAILED_TO_ENABLE_OCD
|
|
|
|
|
)
|
2022-03-02 00:56:40 +00:00
|
|
|
) {
|
|
|
|
|
throw DebugWirePhysicalInterfaceError(
|
|
|
|
|
"Failed to activate the debugWire physical interface - check target connection. "
|
2022-03-05 17:46:08 +00:00
|
|
|
"If the target was recently programmed via ISP, try cycling the target power. See "
|
2022-12-26 21:47:09 +00:00
|
|
|
+ Services::PathService::homeDomainName() + "/docs/debugging-avr-debugwire for more information."
|
2022-03-02 00:56:40 +00:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
throw activationException;
|
|
|
|
|
}
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!this->targetAttached) {
|
|
|
|
|
this->attach();
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void EdbgAvr8Interface::deactivate() {
|
|
|
|
|
if (this->targetAttached) {
|
2022-03-19 13:27:36 +00:00
|
|
|
if (
|
2023-05-21 21:08:25 +01:00
|
|
|
this->targetConfig.physicalInterface == PhysicalInterface::DEBUG_WIRE
|
|
|
|
|
&& this->targetConfig.disableDebugWireOnDeactivate
|
2022-03-19 13:27:36 +00:00
|
|
|
) {
|
2022-02-05 15:32:08 +00:00
|
|
|
try {
|
|
|
|
|
this->disableDebugWire();
|
|
|
|
|
Logger::warning(
|
|
|
|
|
"Successfully disabled debugWire on the AVR8 target - this is only temporary - "
|
2022-03-21 13:05:08 +00:00
|
|
|
"the debugWire module has lost control of the RESET pin. Bloom may no longer be able to "
|
2022-02-05 15:32:08 +00:00
|
|
|
"interface with the target until the next power cycle."
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
} catch (const Exception& exception) {
|
|
|
|
|
// Failing to disable debugWire should never prevent us from proceeding with target deactivation.
|
|
|
|
|
Logger::error(exception.getMessage());
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->detach();
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->physicalInterfaceActivated) {
|
|
|
|
|
this->deactivatePhysical();
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
|
2023-09-21 00:40:30 +01:00
|
|
|
TargetMemoryAddress EdbgAvr8Interface::getProgramCounter() {
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->targetState != TargetState::STOPPED) {
|
|
|
|
|
this->stop();
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
|
2022-06-02 23:06:39 +01:00
|
|
|
GetProgramCounter()
|
|
|
|
|
);
|
|
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
|
|
|
|
throw Avr8CommandFailure("AVR8 Get program counter command failed", responseFrame);
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
return responseFrame.extractProgramCounter();
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
|
2023-09-21 00:40:30 +01:00
|
|
|
void EdbgAvr8Interface::setProgramCounter(TargetMemoryAddress programCounter) {
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->targetState != TargetState::STOPPED) {
|
|
|
|
|
this->stop();
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
|
|
|
|
/*
|
2022-02-05 15:32:08 +00:00
|
|
|
* The program counter will be given in byte address form, but the EDBG tool will be expecting it in word
|
|
|
|
|
* address (16-bit) form. This is why we divide it by 2.
|
2021-10-06 21:12:31 +01:00
|
|
|
*/
|
2022-10-01 20:42:37 +01:00
|
|
|
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
|
2022-06-02 23:06:39 +01:00
|
|
|
SetProgramCounter(programCounter / 2)
|
|
|
|
|
);
|
|
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
|
|
|
|
throw Avr8CommandFailure("AVR8 Set program counter command failed", responseFrame);
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
TargetSignature EdbgAvr8Interface::getDeviceId() {
|
|
|
|
|
if (this->configVariant == Avr8ConfigVariant::UPDI) {
|
|
|
|
|
/*
|
|
|
|
|
* When using the UPDI physical interface, the 'Get device ID' command behaves in an odd manner, where it
|
|
|
|
|
* doesn't actually return the target signature, but instead a fixed four byte string reading:
|
|
|
|
|
* 'A', 'V', 'R' and ' ' (white space).
|
|
|
|
|
*
|
|
|
|
|
* So it appears we cannot use that command for UPDI sessions. As an alternative, we will just read the
|
|
|
|
|
* signature from memory using the signature base address.
|
|
|
|
|
*
|
|
|
|
|
* TODO: Currently, we're assuming the signature will always only ever be three bytes in size, but we may
|
|
|
|
|
* want to consider pulling the size from the TDF.
|
|
|
|
|
*/
|
2022-09-06 17:16:49 +01:00
|
|
|
const auto signatureMemory = this->readMemory(
|
2022-02-05 15:32:08 +00:00
|
|
|
Avr8MemoryType::SRAM,
|
|
|
|
|
this->targetParameters.signatureSegmentStartAddress.value(),
|
|
|
|
|
3
|
|
|
|
|
);
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (signatureMemory.size() != 3) {
|
|
|
|
|
throw Exception("Failed to read AVR8 signature from target - unexpected response size");
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
return TargetSignature(signatureMemory[0], signatureMemory[1], signatureMemory[2]);
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
|
2022-06-02 23:06:39 +01:00
|
|
|
GetDeviceId()
|
|
|
|
|
);
|
2022-02-05 15:32:08 +00:00
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
|
|
|
|
throw Avr8CommandFailure("AVR8 Get device ID command failed", responseFrame);
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2023-05-21 21:08:25 +01:00
|
|
|
return responseFrame.extractSignature(this->targetConfig.physicalInterface);
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
|
2023-09-20 23:37:54 +01:00
|
|
|
void EdbgAvr8Interface::setSoftwareBreakpoint(TargetMemoryAddress address) {
|
2022-10-01 20:42:37 +01:00
|
|
|
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
|
2022-06-02 23:06:39 +01:00
|
|
|
SetSoftwareBreakpoints({address})
|
|
|
|
|
);
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
|
|
|
|
throw Avr8CommandFailure("AVR8 Set software breakpoint command failed", responseFrame);
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
|
2023-09-20 23:37:54 +01:00
|
|
|
void EdbgAvr8Interface::clearSoftwareBreakpoint(TargetMemoryAddress address) {
|
2022-10-01 20:42:37 +01:00
|
|
|
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
|
2022-06-02 23:06:39 +01:00
|
|
|
ClearSoftwareBreakpoints({address})
|
|
|
|
|
);
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
|
|
|
|
throw Avr8CommandFailure("AVR8 Clear software breakpoint command failed", responseFrame);
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
|
2023-09-20 23:37:54 +01:00
|
|
|
void EdbgAvr8Interface::setHardwareBreakpoint(TargetMemoryAddress address) {
|
|
|
|
|
static const auto getAvailableBreakpointNumbers = [this] () {
|
|
|
|
|
auto breakpointNumbers = std::set<std::uint8_t>({1, 2, 3});
|
|
|
|
|
|
|
|
|
|
for (const auto& [address, allocatedNumber] : this->hardwareBreakpointNumbersByAddress) {
|
|
|
|
|
breakpointNumbers.erase(allocatedNumber);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return breakpointNumbers;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const auto availableBreakpointNumbers = getAvailableBreakpointNumbers();
|
|
|
|
|
|
|
|
|
|
if (availableBreakpointNumbers.empty()) {
|
|
|
|
|
throw Exception("Maximum hardware breakpoints have been allocated");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto breakpointNumber = *(availableBreakpointNumbers.begin());
|
|
|
|
|
|
|
|
|
|
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
|
|
|
|
|
SetHardwareBreakpoint(address, breakpointNumber)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
|
|
|
|
throw Avr8CommandFailure("AVR8 Set hardware breakpoint command failed", responseFrame);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->hardwareBreakpointNumbersByAddress.insert(std::pair(address, breakpointNumber));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EdbgAvr8Interface::clearHardwareBreakpoint(TargetMemoryAddress address) {
|
|
|
|
|
const auto breakpointNumberIt = this->hardwareBreakpointNumbersByAddress.find(address);
|
|
|
|
|
|
|
|
|
|
if (breakpointNumberIt == this->hardwareBreakpointNumbersByAddress.end()) {
|
|
|
|
|
Logger::error("No hardware breakpoint at byte address 0x" + Services::StringService::toHex(address));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
|
|
|
|
|
ClearHardwareBreakpoint(breakpointNumberIt->second)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
|
|
|
|
throw Avr8CommandFailure("AVR8 Clear hardware breakpoint command failed", responseFrame);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->hardwareBreakpointNumbersByAddress.erase(address);
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void EdbgAvr8Interface::clearAllBreakpoints() {
|
2022-10-01 20:42:37 +01:00
|
|
|
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
|
2022-06-02 23:06:39 +01:00
|
|
|
ClearAllSoftwareBreakpoints()
|
|
|
|
|
);
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
|
|
|
|
throw Avr8CommandFailure("AVR8 Clear all software breakpoints command failed", responseFrame);
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2023-09-21 01:10:35 +01:00
|
|
|
|
|
|
|
|
// Clear all hardware breakpoints
|
2023-09-22 20:52:17 +01:00
|
|
|
while (!this->hardwareBreakpointNumbersByAddress.empty()) {
|
|
|
|
|
this->clearHardwareBreakpoint(this->hardwareBreakpointNumbersByAddress.begin()->first);
|
2023-09-21 01:10:35 +01:00
|
|
|
}
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2023-05-21 21:08:25 +01:00
|
|
|
TargetRegisters EdbgAvr8Interface::readRegisters(const TargetRegisterDescriptorIds& descriptorIds) {
|
2022-02-05 15:32:08 +00:00
|
|
|
/*
|
|
|
|
|
* 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
|
|
|
|
|
* means we will be frequently loading over 100 register values in a single instance.
|
|
|
|
|
*
|
|
|
|
|
* For the above reason, we do not read each register value individually. That would take far too long if we
|
|
|
|
|
* have over 100 registers to read. Instead, we group the register descriptors into collections by register
|
|
|
|
|
* type, and resolve the address range for each collection. We then perform a single read operation for
|
|
|
|
|
* each collection and hold the memory buffer in a random access container (std::vector). Finally, we extract
|
|
|
|
|
* the data for each register descriptor, from the memory buffer, and construct the relevant TargetRegister
|
|
|
|
|
* object.
|
|
|
|
|
*
|
|
|
|
|
* TODO: We should be grouping the register descriptors by memory type, as opposed to register type. This
|
|
|
|
|
* isn't much of a problem ATM, as currently, we only work with registers that are stored in the data
|
|
|
|
|
* address space or the register file. This will need to be addressed before we can work with any other
|
|
|
|
|
* registers stored elsewhere.
|
|
|
|
|
*/
|
|
|
|
|
auto output = TargetRegisters();
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
// Group descriptors by type and resolve the address range for each type
|
2023-05-21 21:08:25 +01:00
|
|
|
auto descriptorIdsByType = std::map<TargetRegisterType, std::set<TargetRegisterDescriptorId>>();
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
/*
|
2022-09-06 17:16:49 +01:00
|
|
|
* An address range is just an std::pair of addresses - the first being the start address, the second being
|
|
|
|
|
* the end address.
|
|
|
|
|
*
|
|
|
|
|
* TODO: Can't we just use the TargetMemoryAddressRange struct here? Review
|
2022-02-05 15:32:08 +00:00
|
|
|
*/
|
2022-09-06 17:16:49 +01:00
|
|
|
using AddressRange = std::pair<TargetMemoryAddress, TargetMemoryAddress>;
|
2022-02-05 15:32:08 +00:00
|
|
|
auto addressRangeByType = std::map<TargetRegisterType, AddressRange>();
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2023-05-21 21:08:25 +01:00
|
|
|
for (const auto& descriptorId : descriptorIds) {
|
|
|
|
|
const auto descriptorIt = this->targetRegisterDescriptorsById.find(descriptorId);
|
|
|
|
|
assert(descriptorIt != this->targetRegisterDescriptorsById.end());
|
|
|
|
|
|
|
|
|
|
const auto& descriptor = descriptorIt->second;
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!descriptor.startAddress.has_value()) {
|
|
|
|
|
Logger::debug(
|
|
|
|
|
"Attempted to read register in the absence of a start address - register name: "
|
|
|
|
|
+ descriptor.name.value_or("unknown")
|
|
|
|
|
);
|
|
|
|
|
continue;
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
|
2023-05-21 21:08:25 +01:00
|
|
|
descriptorIdsByType[descriptor.type].insert(descriptor.id);
|
2022-02-05 15:32:08 +00:00
|
|
|
|
|
|
|
|
const auto startAddress = descriptor.startAddress.value();
|
|
|
|
|
const auto endAddress = startAddress + (descriptor.size - 1);
|
|
|
|
|
|
2023-05-21 21:08:25 +01:00
|
|
|
const auto addressRangeIt = addressRangeByType.find(descriptor.type);
|
2022-12-03 22:16:21 +00:00
|
|
|
|
2023-05-21 21:08:25 +01:00
|
|
|
if (addressRangeIt == addressRangeByType.end()) {
|
2022-12-03 22:16:21 +00:00
|
|
|
addressRangeByType[descriptor.type] = AddressRange(startAddress, endAddress);
|
2022-02-05 15:32:08 +00:00
|
|
|
|
|
|
|
|
} else {
|
2023-05-21 21:08:25 +01:00
|
|
|
auto& addressRange = addressRangeIt->second;
|
2022-02-05 15:32:08 +00:00
|
|
|
|
|
|
|
|
if (startAddress < addressRange.first) {
|
|
|
|
|
addressRange.first = startAddress;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (endAddress > addressRange.second) {
|
|
|
|
|
addressRange.second = endAddress;
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2022-02-05 15:32:08 +00:00
|
|
|
* Now that we have our address ranges and grouped descriptors, we can perform a single read call for each
|
|
|
|
|
* register type.
|
2021-10-06 21:12:31 +01:00
|
|
|
*/
|
2023-05-21 21:08:25 +01:00
|
|
|
for (const auto&[registerType, descriptorIds] : descriptorIdsByType) {
|
2022-02-05 15:32:08 +00:00
|
|
|
const auto& addressRange = addressRangeByType[registerType];
|
|
|
|
|
const auto startAddress = addressRange.first;
|
|
|
|
|
const auto endAddress = addressRange.second;
|
2023-05-21 21:08:25 +01:00
|
|
|
const auto readSize = (endAddress - startAddress) + 1;
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2023-05-21 21:08:25 +01:00
|
|
|
const auto memoryType = (registerType != TargetRegisterType::GENERAL_PURPOSE_REGISTER)
|
|
|
|
|
? Avr8MemoryType::SRAM
|
2022-02-05 15:32:08 +00:00
|
|
|
: (this->configVariant == Avr8ConfigVariant::XMEGA || this->configVariant == Avr8ConfigVariant::UPDI
|
2023-05-21 21:08:25 +01:00
|
|
|
? Avr8MemoryType::REGISTER_FILE
|
|
|
|
|
: Avr8MemoryType::SRAM);
|
2021-10-06 21:12:31 +01:00
|
|
|
|
|
|
|
|
/*
|
2022-02-05 15:32:08 +00:00
|
|
|
* When reading the entire range, we must avoid any attempts to access the OCD data register (OCDDR), as
|
|
|
|
|
* the debug tool will reject the command and respond with a 0x36 error code (invalid address error).
|
2021-10-06 21:12:31 +01:00
|
|
|
*
|
2022-02-05 15:32:08 +00:00
|
|
|
* For this reason, we specify the OCDDR address as an excluded address. This will mean
|
|
|
|
|
* the EdbgAvr8Interface::readMemory() function will employ the masked read memory command, as opposed to
|
|
|
|
|
* the general read memory command. The masked read memory command allows us to specify which addresses to
|
|
|
|
|
* read and which ones to ignore. For ignored addresses, the debug tool will just return a 0x00 byte.
|
|
|
|
|
* For more info, see section 7.1.22 titled 'Memory Read Masked', in the EDBG protocol document.
|
|
|
|
|
*
|
|
|
|
|
* Interestingly, the masked read memory command doesn't seem to require us to explicitly specify the OCDDR
|
|
|
|
|
* address as an excluded address. It seems to exclude the OCDDR automatically, even if we've not
|
|
|
|
|
* instructed it to do so. This is plausible, as we send the OCDDR address to the debug tool during target
|
|
|
|
|
* initialisation (see EdbgAvr8Interface::setDebugWireAndJtagParameters()). So this means we don't have to
|
|
|
|
|
* specify the OCDDR address as an excluded address, but the EdbgAvr8Interface::readMemory() function will
|
|
|
|
|
* only employ the masked read memory command when we supply at least one excluded address. For this reason,
|
|
|
|
|
* we still pass the OCDDR address to EdbgAvr8Interface::readMemory(), as an excluded address (provided we
|
|
|
|
|
* have it).
|
|
|
|
|
*
|
|
|
|
|
* See CommandFrames::Avr8Generic::ReadMemory(); and the Microchip EDBG documentation for more.
|
2021-10-06 21:12:31 +01:00
|
|
|
*/
|
2022-09-06 17:16:49 +01:00
|
|
|
auto excludedAddresses = std::set<TargetMemoryAddress>();
|
2022-02-05 15:32:08 +00:00
|
|
|
if (memoryType == Avr8MemoryType::SRAM && this->targetParameters.ocdDataRegister.has_value()) {
|
|
|
|
|
excludedAddresses.insert(
|
|
|
|
|
this->targetParameters.ocdDataRegister.value()
|
|
|
|
|
+ this->targetParameters.mappedIoSegmentStartAddress.value_or(0)
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2023-05-21 21:08:25 +01:00
|
|
|
const auto flatMemoryData = this->readMemory(
|
2022-02-05 15:32:08 +00:00
|
|
|
memoryType,
|
|
|
|
|
startAddress,
|
2023-05-21 21:08:25 +01:00
|
|
|
readSize,
|
2022-02-05 15:32:08 +00:00
|
|
|
excludedAddresses
|
2021-10-06 21:12:31 +01:00
|
|
|
);
|
2022-02-05 15:32:08 +00:00
|
|
|
|
2023-05-21 21:08:25 +01:00
|
|
|
if (flatMemoryData.size() != readSize) {
|
2022-02-05 15:32:08 +00:00
|
|
|
throw Exception(
|
|
|
|
|
"Failed to read memory within register type address range (" + std::to_string(startAddress)
|
2023-05-21 21:08:25 +01:00
|
|
|
+ " - " + std::to_string(endAddress) + "). Expected " + std::to_string(readSize)
|
|
|
|
|
+ " bytes, got " + std::to_string(flatMemoryData.size())
|
2022-02-05 15:32:08 +00:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Construct our TargetRegister objects directly from the flat memory buffer
|
2023-05-21 21:08:25 +01:00
|
|
|
for (const auto descriptorId : descriptorIds) {
|
|
|
|
|
const auto descriptorIt = this->targetRegisterDescriptorsById.find(descriptorId);
|
|
|
|
|
const auto& descriptor = descriptorIt->second;
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
/*
|
2022-06-02 23:06:39 +01:00
|
|
|
* Multibyte AVR8 registers are stored in LSB form.
|
2022-02-05 15:32:08 +00:00
|
|
|
*
|
2023-05-21 21:08:25 +01:00
|
|
|
* This is why we use reverse iterators when extracting our data from flatMemoryData. Doing so allows
|
2022-02-05 15:32:08 +00:00
|
|
|
* us to extract the data in MSB form (as is expected for all register values held in TargetRegister
|
|
|
|
|
* objects).
|
|
|
|
|
*/
|
2023-05-21 21:08:25 +01:00
|
|
|
const auto bufferStartIt = flatMemoryData.rend() - (descriptor.startAddress.value() - startAddress)
|
|
|
|
|
- descriptor.size;
|
2022-02-05 15:32:08 +00:00
|
|
|
|
|
|
|
|
output.emplace_back(
|
|
|
|
|
TargetRegister(
|
2023-05-21 21:08:25 +01:00
|
|
|
descriptor.id,
|
|
|
|
|
TargetMemoryBuffer(bufferStartIt, bufferStartIt + descriptor.size)
|
2022-02-05 15:32:08 +00:00
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
2022-02-05 15:32:08 +00:00
|
|
|
|
|
|
|
|
return output;
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void EdbgAvr8Interface::writeRegisters(const Targets::TargetRegisters& registers) {
|
|
|
|
|
for (const auto& reg : registers) {
|
2023-05-21 21:08:25 +01:00
|
|
|
const auto& registerDescriptorIt = this->targetRegisterDescriptorsById.find(reg.descriptorId);
|
|
|
|
|
assert(registerDescriptorIt != this->targetRegisterDescriptorsById.end());
|
|
|
|
|
|
|
|
|
|
const auto& registerDescriptor = registerDescriptorIt->second;
|
2022-02-05 15:32:08 +00:00
|
|
|
auto registerValue = reg.value;
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (registerValue.empty()) {
|
|
|
|
|
throw Exception("Cannot write empty register value");
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (registerValue.size() > registerDescriptor.size) {
|
|
|
|
|
throw Exception("Register value exceeds size specified by register descriptor.");
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (registerValue.size() < registerDescriptor.size) {
|
|
|
|
|
// Fill the missing most-significant bytes with 0x00
|
|
|
|
|
registerValue.insert(registerValue.begin(), registerDescriptor.size - registerValue.size(), 0x00);
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (registerValue.size() > 1) {
|
|
|
|
|
// AVR8 registers are stored in LSB
|
|
|
|
|
std::reverse(registerValue.begin(), registerValue.end());
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
auto memoryType = Avr8MemoryType::SRAM;
|
2022-05-09 22:36:44 +01:00
|
|
|
if (
|
|
|
|
|
registerDescriptor.type == TargetRegisterType::GENERAL_PURPOSE_REGISTER
|
2022-02-05 15:32:08 +00:00
|
|
|
&& (this->configVariant == Avr8ConfigVariant::XMEGA || this->configVariant == Avr8ConfigVariant::UPDI)
|
2022-05-09 22:36:44 +01:00
|
|
|
) {
|
2022-02-05 15:32:08 +00:00
|
|
|
memoryType = Avr8MemoryType::REGISTER_FILE;
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
// TODO: This can be inefficient when updating many registers, maybe do something a little smarter here.
|
|
|
|
|
this->writeMemory(
|
|
|
|
|
memoryType,
|
|
|
|
|
registerDescriptor.startAddress.value(),
|
|
|
|
|
registerValue
|
|
|
|
|
);
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
TargetMemoryBuffer EdbgAvr8Interface::readMemory(
|
|
|
|
|
TargetMemoryType memoryType,
|
2022-09-06 17:16:49 +01:00
|
|
|
TargetMemoryAddress startAddress,
|
|
|
|
|
TargetMemorySize bytes,
|
2022-02-05 15:32:08 +00:00
|
|
|
const std::set<Targets::TargetMemoryAddressRange>& excludedAddressRanges
|
|
|
|
|
) {
|
2022-12-11 23:34:20 +00:00
|
|
|
if (this->programmingModeEnabled && memoryType == TargetMemoryType::RAM) {
|
2023-03-05 23:29:26 +00:00
|
|
|
throw Exception("Cannot access RAM when programming mode is enabled");
|
2022-05-23 23:48:44 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
auto avr8MemoryType = Avr8MemoryType::SRAM;
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
switch (memoryType) {
|
|
|
|
|
case TargetMemoryType::RAM: {
|
|
|
|
|
avr8MemoryType = Avr8MemoryType::SRAM;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case TargetMemoryType::FLASH: {
|
2022-06-04 15:20:02 +01:00
|
|
|
if (
|
|
|
|
|
this->configVariant == Avr8ConfigVariant::DEBUG_WIRE
|
|
|
|
|
|| this->configVariant == Avr8ConfigVariant::UPDI
|
|
|
|
|
) {
|
2022-02-05 15:32:08 +00:00
|
|
|
avr8MemoryType = Avr8MemoryType::FLASH_PAGE;
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-05-23 23:48:44 +01:00
|
|
|
} else if (this->configVariant == Avr8ConfigVariant::MEGAJTAG) {
|
|
|
|
|
avr8MemoryType = this->programmingModeEnabled ? Avr8MemoryType::FLASH_PAGE : Avr8MemoryType::SPM;
|
|
|
|
|
|
2022-06-04 15:20:02 +01:00
|
|
|
} else if (this->configVariant == Avr8ConfigVariant::XMEGA) {
|
|
|
|
|
const auto bootSectionStartAddress = this->targetParameters.bootSectionStartAddress.value();
|
|
|
|
|
if (startAddress >= bootSectionStartAddress) {
|
|
|
|
|
avr8MemoryType = Avr8MemoryType::BOOT_FLASH;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* When using the BOOT_FLASH memory type, the address should be relative to the start of the
|
|
|
|
|
* boot section.
|
|
|
|
|
*/
|
|
|
|
|
startAddress -= bootSectionStartAddress;
|
|
|
|
|
|
|
|
|
|
} else {
|
2022-12-12 01:14:56 +00:00
|
|
|
/*
|
|
|
|
|
* When using the APPL_FLASH memory type, the address should be relative to the start of the
|
|
|
|
|
* application section.
|
|
|
|
|
*/
|
|
|
|
|
startAddress -= this->targetParameters.appSectionStartAddress.value();
|
2022-06-04 15:20:02 +01:00
|
|
|
avr8MemoryType = Avr8MemoryType::APPL_FLASH;
|
|
|
|
|
}
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case TargetMemoryType::EEPROM: {
|
2022-12-11 23:34:20 +00:00
|
|
|
// For JTAG targets, we must use the EEPROM_PAGE memory type when in programming mode.
|
|
|
|
|
avr8MemoryType = (this->configVariant == Avr8ConfigVariant::MEGAJTAG && this->programmingModeEnabled)
|
|
|
|
|
? Avr8MemoryType::EEPROM_PAGE
|
|
|
|
|
: Avr8MemoryType::EEPROM;
|
2022-12-12 01:14:56 +00:00
|
|
|
|
|
|
|
|
if (this->configVariant == Avr8ConfigVariant::XMEGA) {
|
|
|
|
|
// EEPROM addresses should be in relative form, for XMEGA (PDI) targets
|
|
|
|
|
startAddress -= this->targetParameters.eepromStartAddress.value();
|
|
|
|
|
}
|
2023-05-07 16:49:45 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case TargetMemoryType::FUSES: {
|
|
|
|
|
avr8MemoryType = Avr8MemoryType::FUSES;
|
|
|
|
|
break;
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
|
|
|
|
default: {
|
|
|
|
|
break;
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
2021-12-25 20:57:03 +00:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
/*
|
|
|
|
|
* The internal readMemory() function accepts excluded addresses in the form of a set of addresses, as
|
|
|
|
|
* opposed to a set of address ranges.
|
|
|
|
|
*
|
|
|
|
|
* We will perform the conversion here.
|
|
|
|
|
*/
|
2022-09-06 17:16:49 +01:00
|
|
|
auto excludedAddresses = std::set<TargetMemoryAddress>();
|
2022-02-05 15:32:08 +00:00
|
|
|
auto endAddress = startAddress + bytes - 1;
|
2021-12-25 20:57:03 +00:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
for (const auto& addressRange : excludedAddressRanges) {
|
|
|
|
|
if (addressRange.startAddress > endAddress) {
|
|
|
|
|
// This address range is outside of the range from which we will be reading
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2021-12-25 20:57:03 +00:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
for (auto i = addressRange.startAddress; i <= addressRange.endAddress; i++) {
|
|
|
|
|
excludedAddresses.insert(i);
|
|
|
|
|
}
|
2021-12-25 20:57:03 +00:00
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
return this->readMemory(avr8MemoryType, startAddress, bytes, excludedAddresses);
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void EdbgAvr8Interface::writeMemory(
|
|
|
|
|
TargetMemoryType memoryType,
|
2022-09-06 17:16:49 +01:00
|
|
|
TargetMemoryAddress startAddress,
|
2022-02-05 15:32:08 +00:00
|
|
|
const TargetMemoryBuffer& buffer
|
|
|
|
|
) {
|
|
|
|
|
auto avr8MemoryType = Avr8MemoryType::SRAM;
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
switch (memoryType) {
|
|
|
|
|
case TargetMemoryType::RAM: {
|
|
|
|
|
avr8MemoryType = Avr8MemoryType::SRAM;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case TargetMemoryType::FLASH: {
|
2022-06-04 15:20:02 +01:00
|
|
|
if (
|
|
|
|
|
this->configVariant == Avr8ConfigVariant::DEBUG_WIRE
|
|
|
|
|
|| this->configVariant == Avr8ConfigVariant::UPDI
|
2022-06-05 17:49:05 +01:00
|
|
|
|| this->configVariant == Avr8ConfigVariant::MEGAJTAG
|
2022-06-04 15:20:02 +01:00
|
|
|
) {
|
2022-02-05 15:32:08 +00:00
|
|
|
avr8MemoryType = Avr8MemoryType::FLASH_PAGE;
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-06-04 15:20:02 +01:00
|
|
|
} else if (this->configVariant == Avr8ConfigVariant::XMEGA) {
|
2022-06-03 15:45:43 +01:00
|
|
|
const auto bootSectionStartAddress = this->targetParameters.bootSectionStartAddress.value();
|
|
|
|
|
if (startAddress >= bootSectionStartAddress) {
|
|
|
|
|
avr8MemoryType = Avr8MemoryType::BOOT_FLASH;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* When using the BOOT_FLASH memory type, the address should be relative to the start of the
|
|
|
|
|
* boot section.
|
|
|
|
|
*/
|
|
|
|
|
startAddress -= bootSectionStartAddress;
|
|
|
|
|
|
|
|
|
|
} else {
|
2022-12-12 01:14:56 +00:00
|
|
|
/*
|
|
|
|
|
* When using the APPL_FLASH memory type, the address should be relative to the start of the
|
|
|
|
|
* application section.
|
|
|
|
|
*/
|
|
|
|
|
startAddress -= this->targetParameters.appSectionStartAddress.value();
|
2022-06-03 15:45:43 +01:00
|
|
|
avr8MemoryType = Avr8MemoryType::APPL_FLASH;
|
|
|
|
|
}
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case TargetMemoryType::EEPROM: {
|
2022-12-18 19:23:58 +00:00
|
|
|
switch (this->configVariant) {
|
|
|
|
|
case Avr8ConfigVariant::UPDI:
|
|
|
|
|
case Avr8ConfigVariant::XMEGA: {
|
|
|
|
|
avr8MemoryType = Avr8MemoryType::EEPROM_ATOMIC;
|
2022-12-12 01:14:56 +00:00
|
|
|
|
2022-12-18 19:23:58 +00:00
|
|
|
if (this->configVariant == Avr8ConfigVariant::XMEGA) {
|
|
|
|
|
// EEPROM addresses should be in relative form, for XMEGA (PDI) targets
|
|
|
|
|
startAddress -= this->targetParameters.eepromStartAddress.value();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case Avr8ConfigVariant::MEGAJTAG: {
|
|
|
|
|
avr8MemoryType = this->programmingModeEnabled
|
|
|
|
|
? Avr8MemoryType::EEPROM_PAGE
|
|
|
|
|
: Avr8MemoryType::EEPROM;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default: {
|
|
|
|
|
avr8MemoryType = Avr8MemoryType::EEPROM;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2022-12-12 01:14:56 +00:00
|
|
|
}
|
2023-05-07 16:49:45 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case TargetMemoryType::FUSES: {
|
|
|
|
|
avr8MemoryType = Avr8MemoryType::FUSES;
|
|
|
|
|
break;
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
|
|
|
|
default: {
|
|
|
|
|
break;
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
2021-12-25 20:57:03 +00:00
|
|
|
}
|
2022-02-05 15:32:08 +00:00
|
|
|
|
|
|
|
|
return this->writeMemory(avr8MemoryType, startAddress, buffer);
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
|
2022-06-04 15:18:53 +01:00
|
|
|
void EdbgAvr8Interface::eraseProgramMemory(std::optional<Avr8Bit::ProgramMemorySection> section) {
|
|
|
|
|
if (this->configVariant == Avr8ConfigVariant::DEBUG_WIRE) {
|
2022-12-11 23:32:49 +00:00
|
|
|
// The EDBG erase command does not work on debugWire targets - we'll just write to the memory instead
|
|
|
|
|
return this->writeMemory(
|
|
|
|
|
TargetMemoryType::FLASH,
|
|
|
|
|
this->targetParameters.flashStartAddress.value(),
|
|
|
|
|
TargetMemoryBuffer(this->targetParameters.flashSize.value(), 0xFF)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this->configVariant == Avr8ConfigVariant::XMEGA) {
|
|
|
|
|
// For PDI (XMEGA) targets, we can erase flash memory without erasing EEPROM
|
|
|
|
|
|
|
|
|
|
if (!section.has_value() || *section == Avr8Bit::ProgramMemorySection::BOOT) {
|
|
|
|
|
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
|
|
|
|
|
EraseMemory(Avr8EraseMemoryMode::BOOT_SECTION)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
|
|
|
|
throw Avr8CommandFailure("AVR8 erase memory command (for BOOT section) failed", responseFrame);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!section.has_value() || *section == Avr8Bit::ProgramMemorySection::APPLICATION) {
|
|
|
|
|
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
|
|
|
|
|
EraseMemory(Avr8EraseMemoryMode::APPLICATION_SECTION)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
|
|
|
|
throw Avr8CommandFailure(
|
|
|
|
|
"AVR8 erase memory command (for APPLICATION section) failed",
|
|
|
|
|
responseFrame
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
2022-06-03 15:49:12 +01:00
|
|
|
}
|
|
|
|
|
|
2023-05-26 22:45:57 +01:00
|
|
|
throw Exception("JTAG and UPDI targets do not support program memory erase.");
|
|
|
|
|
}
|
2022-12-11 23:32:49 +00:00
|
|
|
|
2023-05-26 22:45:57 +01:00
|
|
|
void EdbgAvr8Interface::eraseChip() {
|
2022-10-01 20:42:37 +01:00
|
|
|
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
|
2022-12-11 23:32:49 +00:00
|
|
|
EraseMemory(Avr8EraseMemoryMode::CHIP)
|
2022-06-03 15:49:12 +01:00
|
|
|
);
|
|
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
|
|
|
|
throw Avr8CommandFailure("AVR8 erase memory command failed", responseFrame);
|
2022-06-03 15:49:12 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
TargetState EdbgAvr8Interface::getTargetState() {
|
|
|
|
|
/*
|
|
|
|
|
* We are not informed when a target goes from a stopped state to a running state, so there is no need
|
|
|
|
|
* to query the tool when we already know the target has stopped.
|
|
|
|
|
*
|
|
|
|
|
* This means we have to rely on the assumption that the target cannot enter a running state without
|
|
|
|
|
* our instruction.
|
|
|
|
|
*/
|
|
|
|
|
if (this->targetState != TargetState::STOPPED) {
|
|
|
|
|
this->refreshTargetState();
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
return this->targetState;
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
|
2022-05-15 17:40:56 +01:00
|
|
|
void EdbgAvr8Interface::enableProgrammingMode() {
|
2022-09-17 20:16:23 +01:00
|
|
|
if (this->programmingModeEnabled) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
|
2022-06-02 23:06:39 +01:00
|
|
|
EnterProgrammingMode()
|
2022-05-15 17:40:56 +01:00
|
|
|
);
|
|
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
|
|
|
|
throw Avr8CommandFailure("Failed to enter programming mode on EDBG debug tool", responseFrame);
|
2022-05-15 17:40:56 +01:00
|
|
|
}
|
2022-05-17 19:45:56 +01:00
|
|
|
|
|
|
|
|
this->programmingModeEnabled = true;
|
2023-09-22 20:51:45 +01:00
|
|
|
this->hardwareBreakpointNumbersByAddress.clear();
|
2022-05-15 17:40:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EdbgAvr8Interface::disableProgrammingMode() {
|
2022-09-17 20:16:23 +01:00
|
|
|
if (!this->programmingModeEnabled) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
|
2022-06-02 23:06:39 +01:00
|
|
|
LeaveProgrammingMode()
|
2022-05-15 17:40:56 +01:00
|
|
|
);
|
|
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
|
|
|
|
throw Avr8CommandFailure("Failed to leave programming mode on EDBG debug tool", responseFrame);
|
2022-05-15 17:40:56 +01:00
|
|
|
}
|
2022-05-17 19:45:30 +01:00
|
|
|
|
2022-05-17 19:45:56 +01:00
|
|
|
this->programmingModeEnabled = false;
|
2023-05-08 02:44:03 +01:00
|
|
|
|
|
|
|
|
if (this->configVariant == Avr8ConfigVariant::MEGAJTAG && this->reactivateJtagTargetPostProgrammingMode) {
|
|
|
|
|
this->deactivatePhysical();
|
|
|
|
|
this->targetAttached = false;
|
|
|
|
|
this->activate();
|
|
|
|
|
}
|
2022-05-17 19:45:56 +01:00
|
|
|
}
|
|
|
|
|
|
2023-05-21 21:08:25 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-17 19:45:30 +01:00
|
|
|
std::map<Family, std::map<PhysicalInterface, Avr8ConfigVariant>>
|
|
|
|
|
EdbgAvr8Interface::getConfigVariantsByFamilyAndPhysicalInterface() {
|
|
|
|
|
return std::map<Family, std::map<PhysicalInterface, Avr8ConfigVariant>>({
|
|
|
|
|
{
|
|
|
|
|
Family::MEGA,
|
|
|
|
|
{
|
|
|
|
|
{PhysicalInterface::JTAG, Avr8ConfigVariant::MEGAJTAG},
|
|
|
|
|
{PhysicalInterface::DEBUG_WIRE, Avr8ConfigVariant::DEBUG_WIRE},
|
|
|
|
|
{PhysicalInterface::UPDI, Avr8ConfigVariant::UPDI},
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
Family::TINY,
|
|
|
|
|
{
|
|
|
|
|
{PhysicalInterface::JTAG, Avr8ConfigVariant::MEGAJTAG},
|
|
|
|
|
{PhysicalInterface::DEBUG_WIRE, Avr8ConfigVariant::DEBUG_WIRE},
|
|
|
|
|
{PhysicalInterface::UPDI, Avr8ConfigVariant::UPDI},
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
Family::XMEGA,
|
|
|
|
|
{
|
|
|
|
|
{PhysicalInterface::JTAG, Avr8ConfigVariant::XMEGA},
|
|
|
|
|
{PhysicalInterface::PDI, Avr8ConfigVariant::XMEGA},
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
Family::DA,
|
|
|
|
|
{
|
|
|
|
|
{PhysicalInterface::UPDI, Avr8ConfigVariant::UPDI},
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
Family::DB,
|
|
|
|
|
{
|
|
|
|
|
{PhysicalInterface::UPDI, Avr8ConfigVariant::UPDI},
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
Family::DD,
|
|
|
|
|
{
|
|
|
|
|
{PhysicalInterface::UPDI, Avr8ConfigVariant::UPDI},
|
|
|
|
|
}
|
2023-05-12 19:08:52 +01:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
Family::EA,
|
|
|
|
|
{
|
|
|
|
|
{PhysicalInterface::UPDI, Avr8ConfigVariant::UPDI},
|
|
|
|
|
}
|
2022-05-17 19:45:30 +01:00
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-21 21:08:25 +01:00
|
|
|
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);
|
2022-05-17 19:45:30 +01:00
|
|
|
|
2023-05-21 21:08:25 +01:00
|
|
|
assert(configVariantsByPhysicalInterfaceIt != configVariantsByFamily.end());
|
2022-05-17 19:45:30 +01:00
|
|
|
|
2023-05-21 21:08:25 +01:00
|
|
|
const auto& configVariantsByPhysicalInterface = configVariantsByPhysicalInterfaceIt->second;
|
|
|
|
|
const auto configVariantIt = configVariantsByPhysicalInterface.find(physicalInterface);
|
2022-05-17 19:45:30 +01:00
|
|
|
|
2023-05-21 21:08:25 +01:00
|
|
|
assert(configVariantIt != configVariantsByPhysicalInterface.end());
|
2022-05-17 19:45:30 +01:00
|
|
|
|
2023-05-21 21:08:25 +01:00
|
|
|
return configVariantIt->second;
|
2022-05-15 17:40:56 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void EdbgAvr8Interface::setParameter(const Avr8EdbgParameter& parameter, const std::vector<unsigned char>& value) {
|
2023-01-21 14:27:45 +00:00
|
|
|
using Services::StringService;
|
|
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
|
2022-06-02 23:06:39 +01:00
|
|
|
SetParameter(parameter, value)
|
|
|
|
|
);
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2023-01-21 13:54:40 +00:00
|
|
|
Logger::debug(
|
2023-01-21 14:27:45 +00:00
|
|
|
"Setting AVR8 EDBG parameter (context: 0x" + StringService::toHex(parameter.context) + ", id: 0x"
|
|
|
|
|
+ StringService::toHex(parameter.id) + ", value: 0x" + StringService::toHex(value) + ")"
|
2023-01-21 13:54:40 +00:00
|
|
|
);
|
|
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
|
|
|
|
throw Avr8CommandFailure("Failed to set parameter on device!", responseFrame);
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
std::vector<unsigned char> EdbgAvr8Interface::getParameter(const Avr8EdbgParameter& parameter, std::uint8_t size) {
|
2022-10-01 20:42:37 +01:00
|
|
|
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
|
2022-06-02 23:06:39 +01:00
|
|
|
GetParameter(parameter, size)
|
|
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
|
|
|
|
throw Avr8CommandFailure("Failed to get parameter from device!", responseFrame);
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
|
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
return responseFrame.getPayloadData();
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void EdbgAvr8Interface::setDebugWireAndJtagParameters() {
|
|
|
|
|
if (this->targetParameters.flashPageSize.has_value()) {
|
2022-12-08 21:18:18 +00:00
|
|
|
Logger::debug("Setting FLASH_PAGE_SIZE AVR8 device parameter");
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_FLASH_PAGE_SIZE,
|
|
|
|
|
this->targetParameters.flashPageSize.value()
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->targetParameters.flashSize.has_value()) {
|
2022-12-08 21:18:18 +00:00
|
|
|
Logger::debug("Setting FLASH_SIZE AVR8 device parameter");
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_FLASH_SIZE,
|
|
|
|
|
this->targetParameters.flashSize.value()
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->targetParameters.flashStartAddress.has_value()) {
|
2022-12-08 21:18:18 +00:00
|
|
|
Logger::debug("Setting FLASH_BASE AVR8 device parameter");
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_FLASH_BASE,
|
|
|
|
|
this->targetParameters.flashStartAddress.value()
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->targetParameters.ramStartAddress.has_value()) {
|
2022-12-08 21:18:18 +00:00
|
|
|
Logger::debug("Setting SRAM_START AVR8 device parameter");
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_SRAM_START,
|
|
|
|
|
this->targetParameters.ramStartAddress.value()
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->targetParameters.eepromSize.has_value()) {
|
2022-12-08 21:18:18 +00:00
|
|
|
Logger::debug("Setting EEPROM_SIZE AVR8 device parameter");
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_EEPROM_SIZE,
|
|
|
|
|
this->targetParameters.eepromSize.value()
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->targetParameters.eepromPageSize.has_value()) {
|
2022-12-08 21:18:18 +00:00
|
|
|
Logger::debug("Setting EEPROM_PAGE_SIZE AVR8 device parameter");
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_EEPROM_PAGE_SIZE,
|
|
|
|
|
this->targetParameters.eepromPageSize.value()
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->targetParameters.ocdRevision.has_value()) {
|
2022-12-08 21:18:18 +00:00
|
|
|
Logger::debug("Setting OCD_REVISION AVR8 device parameter");
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_OCD_REVISION,
|
|
|
|
|
this->targetParameters.ocdRevision.value()
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-06-06 17:44:13 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->targetParameters.ocdDataRegister.has_value()) {
|
2022-12-08 21:18:18 +00:00
|
|
|
Logger::debug("Setting OCD_DATA_REGISTER AVR8 device parameter");
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_OCD_DATA_REGISTER,
|
|
|
|
|
this->targetParameters.ocdDataRegister.value()
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-06-06 17:44:13 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->targetParameters.spmcRegisterStartAddress.has_value()) {
|
2022-12-08 21:18:18 +00:00
|
|
|
Logger::debug("Setting SPMCR_REGISTER AVR8 device parameter");
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_SPMCR_REGISTER,
|
|
|
|
|
this->targetParameters.spmcRegisterStartAddress.value()
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->targetParameters.bootSectionStartAddress.has_value()) {
|
2022-12-08 21:18:18 +00:00
|
|
|
Logger::debug("Setting BOOT_START_ADDR AVR8 device parameter");
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_BOOT_START_ADDR,
|
|
|
|
|
this->targetParameters.bootSectionStartAddress.value()
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
/*
|
|
|
|
|
* All addresses for registers that reside in the mapped IO memory segment include the mapped IO segment offset
|
|
|
|
|
* (start address). But the EDBG protocol requires *some* of these addresses to be stripped of this offset
|
|
|
|
|
* before sending them as target parameters.
|
|
|
|
|
*
|
|
|
|
|
* This applies to the following addresses:
|
|
|
|
|
*
|
|
|
|
|
* - OSCALL Address
|
|
|
|
|
* - EEARL Address
|
|
|
|
|
* - EEARH Address
|
|
|
|
|
* - EECR Address
|
|
|
|
|
* - EEDR Address
|
|
|
|
|
*
|
|
|
|
|
* It *doesn't* seem to apply to the SPMCR or OCDDR address.
|
|
|
|
|
*/
|
|
|
|
|
auto mappedIoStartAddress = this->targetParameters.mappedIoSegmentStartAddress.value_or(0);
|
2021-08-30 22:30:35 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->targetParameters.osccalAddress.has_value()) {
|
2022-12-08 21:18:18 +00:00
|
|
|
Logger::debug("Setting OSCCAL_ADDR AVR8 device parameter");
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_OSCCAL_ADDR,
|
|
|
|
|
static_cast<std::uint8_t>(
|
2021-07-04 00:29:43 +01:00
|
|
|
this->targetParameters.osccalAddress.value() - mappedIoStartAddress
|
|
|
|
|
)
|
2022-02-05 15:32:08 +00:00
|
|
|
);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->targetParameters.eepromAddressRegisterLow.has_value()) {
|
2022-12-08 21:18:18 +00:00
|
|
|
Logger::debug("Setting EEARL_ADDR AVR8 device parameter");
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_EEARL_ADDR,
|
|
|
|
|
static_cast<std::uint8_t>(
|
2021-07-04 00:29:43 +01:00
|
|
|
this->targetParameters.eepromAddressRegisterLow.value() - mappedIoStartAddress
|
|
|
|
|
)
|
2022-02-05 15:32:08 +00:00
|
|
|
);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->targetParameters.eepromAddressRegisterHigh.has_value()) {
|
2022-12-08 21:18:18 +00:00
|
|
|
Logger::debug("Setting EEARH_ADDR AVR8 device parameter");
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_EEARH_ADDR,
|
|
|
|
|
static_cast<std::uint8_t>(
|
2021-07-04 00:29:43 +01:00
|
|
|
this->targetParameters.eepromAddressRegisterHigh.value() - mappedIoStartAddress
|
|
|
|
|
)
|
2022-02-05 15:32:08 +00:00
|
|
|
);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->targetParameters.eepromControlRegisterAddress.has_value()) {
|
2022-12-08 21:18:18 +00:00
|
|
|
Logger::debug("Setting EECR_ADDR AVR8 device parameter");
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_EECR_ADDR,
|
|
|
|
|
static_cast<std::uint8_t>(
|
2021-07-04 00:29:43 +01:00
|
|
|
this->targetParameters.eepromControlRegisterAddress.value() - mappedIoStartAddress
|
|
|
|
|
)
|
2022-02-05 15:32:08 +00:00
|
|
|
);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->targetParameters.eepromDataRegisterAddress.has_value()) {
|
2022-12-08 21:18:18 +00:00
|
|
|
Logger::debug("Setting EEDR_ADDR AVR8 device parameter");
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_EEDR_ADDR,
|
|
|
|
|
static_cast<std::uint8_t>(
|
2021-07-04 00:29:43 +01:00
|
|
|
this->targetParameters.eepromDataRegisterAddress.value() - mappedIoStartAddress
|
|
|
|
|
)
|
2022-02-05 15:32:08 +00:00
|
|
|
);
|
|
|
|
|
}
|
2021-06-27 20:09:15 +01:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void EdbgAvr8Interface::setPdiParameters() {
|
|
|
|
|
if (!this->targetParameters.appSectionPdiOffset.has_value()) {
|
|
|
|
|
throw DeviceInitializationFailure("Missing required parameter: APPL_BASE_ADDR");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!this->targetParameters.bootSectionPdiOffset.has_value()) {
|
|
|
|
|
throw DeviceInitializationFailure("Missing required parameter: BOOT_BASE_ADDR");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-12-12 00:51:45 +00:00
|
|
|
if (!this->targetParameters.appSectionSize.has_value()) {
|
|
|
|
|
throw DeviceInitializationFailure("Missing required parameter: APPLICATION_BYTES");
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-12-12 00:51:45 +00:00
|
|
|
if (!this->targetParameters.bootSectionSize.has_value()) {
|
|
|
|
|
throw DeviceInitializationFailure("Missing required parameter: BOOT_BYTES");
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!this->targetParameters.eepromPdiOffset.has_value()) {
|
|
|
|
|
throw DeviceInitializationFailure("Missing required parameter: EEPROM_BASE_ADDR");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!this->targetParameters.fuseRegistersPdiOffset.has_value()) {
|
|
|
|
|
throw DeviceInitializationFailure("Missing required parameter: FUSE_BASE_ADDR");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!this->targetParameters.lockRegistersPdiOffset.has_value()) {
|
|
|
|
|
throw DeviceInitializationFailure("Missing required parameter: LOCKBIT_BASE_ADDR");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!this->targetParameters.userSignaturesPdiOffset.has_value()) {
|
|
|
|
|
throw DeviceInitializationFailure("Missing required parameter: USER_SIGN_BASE_ADDR");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!this->targetParameters.productSignaturesPdiOffset.has_value()) {
|
|
|
|
|
throw DeviceInitializationFailure("Missing required parameter: PROD_SIGN_BASE_ADDR");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!this->targetParameters.ramPdiOffset.has_value()) {
|
|
|
|
|
throw DeviceInitializationFailure("Missing required parameter: DATA_BASE_ADDR");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!this->targetParameters.flashPageSize.has_value()) {
|
|
|
|
|
throw DeviceInitializationFailure("Missing required parameter: FLASH_PAGE_BYTES");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!this->targetParameters.eepromSize.has_value()) {
|
|
|
|
|
throw DeviceInitializationFailure("Missing required parameter: EEPROM_SIZE");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!this->targetParameters.eepromPageSize.has_value()) {
|
|
|
|
|
throw DeviceInitializationFailure("Missing required parameter: EEPROM_PAGE_SIZE");
|
|
|
|
|
}
|
2021-04-06 23:21:37 +01:00
|
|
|
|
2022-06-02 23:00:27 +01:00
|
|
|
if (!this->targetParameters.nvmModuleBaseAddress.has_value()) {
|
2022-02-05 15:32:08 +00:00
|
|
|
throw DeviceInitializationFailure("Missing required parameter: NVM_BASE");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-06-02 23:05:38 +01:00
|
|
|
if (!this->targetParameters.mcuModuleBaseAddress.has_value()) {
|
|
|
|
|
throw DeviceInitializationFailure("Missing required parameter: SIGNATURE_OFFSET (MCU module base address)");
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::debug("Setting APPL_BASE_ADDR AVR8 parameter");
|
2021-06-27 20:09:15 +01:00
|
|
|
this->setParameter(
|
2022-02-05 15:32:08 +00:00
|
|
|
Avr8EdbgParameters::DEVICE_XMEGA_APPL_BASE_ADDR,
|
|
|
|
|
this->targetParameters.appSectionPdiOffset.value()
|
2021-06-27 20:09:15 +01:00
|
|
|
);
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::debug("Setting BOOT_BASE_ADDR AVR8 parameter");
|
2021-06-27 20:09:15 +01:00
|
|
|
this->setParameter(
|
2022-02-05 15:32:08 +00:00
|
|
|
Avr8EdbgParameters::DEVICE_XMEGA_BOOT_BASE_ADDR,
|
|
|
|
|
this->targetParameters.bootSectionPdiOffset.value()
|
2021-06-27 20:09:15 +01:00
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::debug("Setting EEPROM_BASE_ADDR AVR8 parameter");
|
2021-06-27 20:09:15 +01:00
|
|
|
this->setParameter(
|
2022-02-05 15:32:08 +00:00
|
|
|
Avr8EdbgParameters::DEVICE_XMEGA_EEPROM_BASE_ADDR,
|
|
|
|
|
this->targetParameters.eepromPdiOffset.value()
|
2021-06-27 20:09:15 +01:00
|
|
|
);
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::debug("Setting FUSE_BASE_ADDR AVR8 parameter");
|
2021-06-27 20:09:15 +01:00
|
|
|
this->setParameter(
|
2022-02-05 15:32:08 +00:00
|
|
|
Avr8EdbgParameters::DEVICE_XMEGA_FUSE_BASE_ADDR,
|
|
|
|
|
this->targetParameters.fuseRegistersPdiOffset.value()
|
2021-06-27 20:09:15 +01:00
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::debug("Setting LOCKBIT_BASE_ADDR AVR8 parameter");
|
2021-06-27 20:09:15 +01:00
|
|
|
this->setParameter(
|
2022-02-05 15:32:08 +00:00
|
|
|
Avr8EdbgParameters::DEVICE_XMEGA_LOCKBIT_BASE_ADDR,
|
|
|
|
|
this->targetParameters.lockRegistersPdiOffset.value()
|
2021-06-27 20:09:15 +01:00
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::debug("Setting USER_SIGN_BASE_ADDR AVR8 parameter");
|
2021-06-27 20:09:15 +01:00
|
|
|
this->setParameter(
|
2022-02-05 15:32:08 +00:00
|
|
|
Avr8EdbgParameters::DEVICE_XMEGA_USER_SIGN_BASE_ADDR,
|
|
|
|
|
this->targetParameters.userSignaturesPdiOffset.value()
|
2021-06-27 20:09:15 +01:00
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::debug("Setting PROD_SIGN_BASE_ADDR AVR8 parameter");
|
2021-06-27 20:09:15 +01:00
|
|
|
this->setParameter(
|
2022-02-05 15:32:08 +00:00
|
|
|
Avr8EdbgParameters::DEVICE_XMEGA_PROD_SIGN_BASE_ADDR,
|
|
|
|
|
this->targetParameters.productSignaturesPdiOffset.value()
|
2021-06-27 20:09:15 +01:00
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::debug("Setting DATA_BASE_ADDR AVR8 parameter");
|
2021-06-27 20:09:15 +01:00
|
|
|
this->setParameter(
|
2022-02-05 15:32:08 +00:00
|
|
|
Avr8EdbgParameters::DEVICE_XMEGA_DATA_BASE_ADDR,
|
|
|
|
|
this->targetParameters.ramPdiOffset.value()
|
2021-06-27 20:09:15 +01:00
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::debug("Setting APPLICATION_BYTES AVR8 parameter");
|
2021-06-27 20:09:15 +01:00
|
|
|
this->setParameter(
|
2022-02-05 15:32:08 +00:00
|
|
|
Avr8EdbgParameters::DEVICE_XMEGA_APPLICATION_BYTES,
|
2022-12-12 00:51:45 +00:00
|
|
|
this->targetParameters.appSectionSize.value()
|
2021-06-27 20:09:15 +01:00
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::debug("Setting BOOT_BYTES AVR8 parameter");
|
2021-06-27 20:09:15 +01:00
|
|
|
this->setParameter(
|
2022-02-05 15:32:08 +00:00
|
|
|
Avr8EdbgParameters::DEVICE_XMEGA_BOOT_BYTES,
|
|
|
|
|
this->targetParameters.bootSectionSize.value()
|
2021-06-27 20:09:15 +01:00
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::debug("Setting FLASH_PAGE_BYTES AVR8 parameter");
|
2021-06-27 20:09:15 +01:00
|
|
|
this->setParameter(
|
2022-02-05 15:32:08 +00:00
|
|
|
Avr8EdbgParameters::DEVICE_XMEGA_FLASH_PAGE_BYTES,
|
|
|
|
|
this->targetParameters.flashPageSize.value()
|
2021-06-27 20:09:15 +01:00
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::debug("Setting EEPROM_SIZE AVR8 parameter");
|
2021-06-27 20:09:15 +01:00
|
|
|
this->setParameter(
|
2022-02-05 15:32:08 +00:00
|
|
|
Avr8EdbgParameters::DEVICE_XMEGA_EEPROM_SIZE,
|
|
|
|
|
this->targetParameters.eepromSize.value()
|
2021-06-27 20:09:15 +01:00
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::debug("Setting EEPROM_PAGE_SIZE AVR8 parameter");
|
2021-06-27 20:09:15 +01:00
|
|
|
this->setParameter(
|
2022-02-05 15:32:08 +00:00
|
|
|
Avr8EdbgParameters::DEVICE_XMEGA_EEPROM_PAGE_SIZE,
|
|
|
|
|
static_cast<std::uint8_t>(this->targetParameters.eepromPageSize.value())
|
2021-10-06 21:12:31 +01:00
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::debug("Setting NVM_BASE AVR8 parameter");
|
2021-10-06 21:12:31 +01:00
|
|
|
this->setParameter(
|
2022-02-05 15:32:08 +00:00
|
|
|
Avr8EdbgParameters::DEVICE_XMEGA_NVM_BASE,
|
2022-06-02 23:00:27 +01:00
|
|
|
this->targetParameters.nvmModuleBaseAddress.value()
|
|
|
|
|
);
|
2022-06-02 23:05:38 +01:00
|
|
|
|
|
|
|
|
Logger::debug("Setting SIGNATURE_OFFSET AVR8 parameter");
|
|
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_XMEGA_SIGNATURE_OFFSET,
|
|
|
|
|
this->targetParameters.mcuModuleBaseAddress.value()
|
2021-10-06 21:12:31 +01:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void EdbgAvr8Interface::setUpdiParameters() {
|
|
|
|
|
if (!this->targetParameters.signatureSegmentStartAddress.has_value()) {
|
|
|
|
|
throw DeviceInitializationFailure("Missing required parameter: SIGNATURE BASE ADDRESS");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-12-08 21:08:35 +00:00
|
|
|
if (!this->targetParameters.eepromPageSize.has_value()) {
|
|
|
|
|
throw DeviceInitializationFailure("Missing required parameter: UPDI_EEPROM_PAGE_SIZE");
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
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).
|
|
|
|
|
*/
|
|
|
|
|
const auto programMemBaseAddress = this->targetParameters.programMemoryUpdiStartAddress.value();
|
2022-12-08 21:18:18 +00:00
|
|
|
Logger::debug("Setting UPDI_PROGMEM_BASE_ADDR AVR8 device parameter");
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_UPDI_PROGMEM_BASE_ADDR,
|
|
|
|
|
static_cast<std::uint16_t>(programMemBaseAddress)
|
|
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-12-08 21:18:18 +00:00
|
|
|
Logger::debug("Setting UPDI_PROGMEM_BASE_ADDR_MSB AVR8 device parameter");
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_UPDI_PROGMEM_BASE_ADDR_MSB,
|
|
|
|
|
static_cast<std::uint8_t>(programMemBaseAddress >> 16)
|
|
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
2021-12-25 21:01:58 +00:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
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();
|
2022-12-08 21:18:18 +00:00
|
|
|
Logger::debug("Setting UPDI_FLASH_PAGE_SIZE AVR8 device parameter");
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_UPDI_FLASH_PAGE_SIZE,
|
|
|
|
|
static_cast<std::uint8_t>(flashPageSize)
|
|
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-12-08 21:18:18 +00:00
|
|
|
Logger::debug("Setting UPDI_FLASH_PAGE_SIZE_MSB AVR8 device parameter");
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_UPDI_FLASH_PAGE_SIZE_MSB,
|
|
|
|
|
static_cast<std::uint8_t>(flashPageSize >> 8)
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->targetParameters.eepromPageSize.has_value()) {
|
2022-12-08 21:18:18 +00:00
|
|
|
Logger::debug("Setting UPDI_EEPROM_PAGE_SIZE AVR8 device parameter");
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_UPDI_EEPROM_PAGE_SIZE,
|
|
|
|
|
this->targetParameters.eepromPageSize.value()
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-06-02 23:00:27 +01:00
|
|
|
if (this->targetParameters.nvmModuleBaseAddress.has_value()) {
|
2022-12-08 21:18:18 +00:00
|
|
|
Logger::debug("Setting UPDI_NVMCTRL_ADDR AVR8 device parameter");
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_UPDI_NVMCTRL_ADDR,
|
2022-06-02 23:00:27 +01:00
|
|
|
this->targetParameters.nvmModuleBaseAddress.value()
|
2022-02-05 15:32:08 +00:00
|
|
|
);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->targetParameters.ocdModuleAddress.has_value()) {
|
2022-12-08 21:18:18 +00:00
|
|
|
Logger::debug("Setting UPDI_OCD_ADDR AVR8 device parameter");
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_UPDI_OCD_ADDR,
|
|
|
|
|
this->targetParameters.ocdModuleAddress.value()
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->targetParameters.flashSize.has_value()) {
|
2022-12-08 21:18:18 +00:00
|
|
|
Logger::debug("Setting UPDI_FLASH_SIZE AVR8 device parameter");
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_UPDI_FLASH_SIZE,
|
|
|
|
|
this->targetParameters.flashSize.value()
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this->targetParameters.eepromSize.has_value()) {
|
2022-12-08 21:18:18 +00:00
|
|
|
Logger::debug("Setting UPDI_EEPROM_SIZE AVR8 device parameter");
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_UPDI_EEPROM_SIZE,
|
|
|
|
|
this->targetParameters.eepromSize.value()
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->targetParameters.eepromStartAddress.has_value()) {
|
2022-12-08 21:18:18 +00:00
|
|
|
Logger::debug("Setting UPDI_EEPROM_BASE_ADDR AVR8 device parameter");
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_UPDI_EEPROM_BASE_ADDR,
|
|
|
|
|
this->targetParameters.eepromStartAddress.value()
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->targetParameters.signatureSegmentStartAddress.has_value()) {
|
2022-12-08 21:18:18 +00:00
|
|
|
Logger::debug("Setting UPDI_SIG_BASE_ADDR AVR8 device parameter");
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_UPDI_SIG_BASE_ADDR,
|
|
|
|
|
this->targetParameters.signatureSegmentStartAddress.value()
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-05-02 15:46:18 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->targetParameters.fuseSegmentStartAddress.has_value()) {
|
2022-12-08 21:18:18 +00:00
|
|
|
Logger::debug("Setting UPDI_FUSE_BASE_ADDR AVR8 device parameter");
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_UPDI_FUSE_BASE_ADDR,
|
|
|
|
|
this->targetParameters.fuseSegmentStartAddress.value()
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this->targetParameters.fuseSegmentSize.has_value()) {
|
2022-12-08 21:18:18 +00:00
|
|
|
Logger::debug("Setting UPDI_FUSE_SIZE AVR8 device parameter");
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_UPDI_FUSE_SIZE,
|
|
|
|
|
this->targetParameters.fuseSegmentSize.value()
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->targetParameters.lockbitsSegmentStartAddress.has_value()) {
|
2022-12-08 21:18:18 +00:00
|
|
|
Logger::debug("Setting UPDI_LOCK_BASE_ADDR AVR8 device parameter");
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setParameter(
|
|
|
|
|
Avr8EdbgParameters::DEVICE_UPDI_LOCK_BASE_ADDR,
|
|
|
|
|
this->targetParameters.lockbitsSegmentStartAddress.value()
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
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)
|
|
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void EdbgAvr8Interface::activatePhysical(bool applyExternalReset) {
|
2022-10-01 20:42:37 +01:00
|
|
|
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
|
2022-06-02 23:06:39 +01:00
|
|
|
ActivatePhysical(applyExternalReset)
|
|
|
|
|
);
|
2022-02-05 15:32:08 +00:00
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!applyExternalReset) {
|
|
|
|
|
// Try again with external reset applied
|
|
|
|
|
Logger::debug("Failed to activate physical interface on AVR8 target "
|
|
|
|
|
"- retrying with external reset applied.");
|
|
|
|
|
return this->activatePhysical(true);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
throw Avr8CommandFailure("AVR8 Activate physical interface command failed", responseFrame);
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->physicalInterfaceActivated = true;
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void EdbgAvr8Interface::deactivatePhysical() {
|
2022-10-01 20:42:37 +01:00
|
|
|
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
|
2022-06-02 23:06:39 +01:00
|
|
|
DeactivatePhysical()
|
|
|
|
|
);
|
2022-02-05 15:32:08 +00:00
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
|
|
|
|
throw Avr8CommandFailure("AVR8 Deactivate physical interface command failed", responseFrame);
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->physicalInterfaceActivated = false;
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void EdbgAvr8Interface::attach() {
|
2021-10-04 21:31:31 +01:00
|
|
|
/*
|
2022-02-05 15:32:08 +00:00
|
|
|
* When attaching an ATmega target that is connected via JTAG, we must not set the breakAfterAttach flag, as
|
|
|
|
|
* this results in a timeout.
|
2021-10-04 21:31:31 +01:00
|
|
|
*
|
2022-02-05 15:32:08 +00:00
|
|
|
* However, in this case the attach command seems to _sometimes_ halt the target anyway, regardless of the
|
|
|
|
|
* value of the breakAfterAttach flag. So we still expect a stop event to be received shortly after issuing
|
|
|
|
|
* the attach command.
|
2021-10-04 21:31:31 +01:00
|
|
|
*/
|
2022-10-01 20:42:37 +01:00
|
|
|
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
|
2022-06-02 23:06:39 +01:00
|
|
|
Attach(
|
|
|
|
|
this->configVariant != Avr8ConfigVariant::MEGAJTAG
|
|
|
|
|
)
|
2022-02-05 15:32:08 +00:00
|
|
|
);
|
2021-10-04 21:31:31 +01:00
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
|
|
|
|
throw Avr8CommandFailure("AVR8 Attach command failed", responseFrame);
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-12-25 20:59:29 +00:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->targetAttached = true;
|
2021-10-04 21:31:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
try {
|
|
|
|
|
// Wait for stopped event
|
|
|
|
|
this->waitForStoppedEvent();
|
2021-10-04 21:31:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
} catch (const Exception& exception) {
|
2022-05-03 19:59:38 +01:00
|
|
|
Logger::warning(
|
2022-02-05 15:32:08 +00:00
|
|
|
"Execution on AVR8 target could not be halted post attach - " + exception.getMessage()
|
|
|
|
|
);
|
2021-10-21 19:28:31 +01:00
|
|
|
}
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-10-04 21:31:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void EdbgAvr8Interface::detach() {
|
2022-10-01 20:42:37 +01:00
|
|
|
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
|
2022-06-02 23:06:39 +01:00
|
|
|
Detach()
|
|
|
|
|
);
|
2021-10-21 19:28:31 +01:00
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
|
|
|
|
throw Avr8CommandFailure("AVR8 Detach command failed", responseFrame);
|
2021-10-04 21:31:31 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->targetAttached = false;
|
2021-10-04 21:31:31 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
std::unique_ptr<AvrEvent> EdbgAvr8Interface::getAvrEvent() {
|
2022-10-01 20:42:37 +01:00
|
|
|
auto event = this->edbgInterface->requestAvrEvent();
|
2021-11-22 23:07:18 +00:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!event.has_value()) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
switch (event->eventId.value()) {
|
2022-02-05 15:32:08 +00:00
|
|
|
case AvrEventId::AVR8_BREAK_EVENT: {
|
|
|
|
|
// Break event
|
|
|
|
|
return std::make_unique<BreakEvent>(event.value());
|
|
|
|
|
}
|
|
|
|
|
default: {
|
|
|
|
|
/*
|
|
|
|
|
* TODO: This isn't very nice as we're performing an unnecessary copy. Maybe requestAvrEvents should
|
|
|
|
|
* return a unique_ptr instead?
|
|
|
|
|
*/
|
|
|
|
|
return std::make_unique<AvrEvent>(event.value());
|
|
|
|
|
}
|
2021-04-07 23:30:30 +01:00
|
|
|
}
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EdbgAvr8Interface::clearEvents() {
|
|
|
|
|
while (this->getAvrEvent() != nullptr) {}
|
|
|
|
|
}
|
2021-04-07 23:30:30 +01:00
|
|
|
|
2022-05-28 13:44:10 +01:00
|
|
|
bool EdbgAvr8Interface::alignmentRequired(Avr8MemoryType memoryType) {
|
|
|
|
|
return
|
2022-05-17 19:51:00 +01:00
|
|
|
memoryType == Avr8MemoryType::FLASH_PAGE
|
|
|
|
|
|| memoryType == Avr8MemoryType::SPM
|
2022-06-02 22:20:59 +01:00
|
|
|
|| memoryType == Avr8MemoryType::APPL_FLASH
|
2022-06-03 15:45:43 +01:00
|
|
|
|| memoryType == Avr8MemoryType::BOOT_FLASH
|
2022-12-11 23:34:20 +00:00
|
|
|
|| memoryType == Avr8MemoryType::EEPROM_ATOMIC
|
|
|
|
|
|| memoryType == Avr8MemoryType::EEPROM_PAGE
|
2022-05-28 13:44:10 +01:00
|
|
|
;
|
|
|
|
|
}
|
2022-05-17 19:51:00 +01:00
|
|
|
|
2022-09-06 17:16:49 +01:00
|
|
|
TargetMemoryAddress EdbgAvr8Interface::alignMemoryAddress(
|
|
|
|
|
Avr8MemoryType memoryType,
|
|
|
|
|
TargetMemoryAddress address
|
|
|
|
|
) {
|
2022-05-28 13:44:10 +01:00
|
|
|
std::uint16_t alignTo = 1;
|
|
|
|
|
|
2022-12-11 23:40:37 +00:00
|
|
|
switch (memoryType) {
|
|
|
|
|
case Avr8MemoryType::FLASH_PAGE:
|
|
|
|
|
case Avr8MemoryType::SPM:
|
|
|
|
|
case Avr8MemoryType::APPL_FLASH:
|
|
|
|
|
case Avr8MemoryType::BOOT_FLASH: {
|
2022-12-13 21:12:16 +00:00
|
|
|
/*
|
|
|
|
|
* Although the EDBG documentation claims any number of bytes can be accessed via the FLASH_PAGE mem
|
|
|
|
|
* type, when using the UPDI config variant, this isn't strictly true.
|
|
|
|
|
*
|
|
|
|
|
* When writing to flash on UPDI targets, we MUST page align the write operations. And we cannot word
|
|
|
|
|
* align them - we've tried only word aligning them - the debug tool reports a "Too many or too few
|
|
|
|
|
* bytes" error.
|
|
|
|
|
*/
|
2022-12-11 23:40:37 +00:00
|
|
|
alignTo = this->targetParameters.flashPageSize.value();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case Avr8MemoryType::EEPROM_ATOMIC:
|
|
|
|
|
case Avr8MemoryType::EEPROM_PAGE: {
|
|
|
|
|
alignTo = this->targetParameters.eepromPageSize.value();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default: {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2022-12-11 23:34:20 +00:00
|
|
|
}
|
|
|
|
|
|
2022-05-28 13:44:10 +01:00
|
|
|
if ((address % alignTo) != 0) {
|
2022-09-06 17:16:49 +01:00
|
|
|
return static_cast<TargetMemoryAddress>(std::floor(
|
2022-05-28 13:44:10 +01:00
|
|
|
static_cast<float>(address) / static_cast<float>(alignTo)
|
|
|
|
|
) * alignTo);
|
2022-05-17 19:51:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return address;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-06 17:16:49 +01:00
|
|
|
TargetMemorySize EdbgAvr8Interface::alignMemoryBytes(
|
|
|
|
|
Avr8MemoryType memoryType,
|
|
|
|
|
TargetMemorySize bytes
|
|
|
|
|
) {
|
2022-05-28 13:44:10 +01:00
|
|
|
std::uint16_t alignTo = 1;
|
2022-05-17 19:51:00 +01:00
|
|
|
|
2022-12-11 23:40:37 +00:00
|
|
|
switch (memoryType) {
|
|
|
|
|
case Avr8MemoryType::FLASH_PAGE:
|
|
|
|
|
case Avr8MemoryType::SPM:
|
|
|
|
|
case Avr8MemoryType::APPL_FLASH:
|
|
|
|
|
case Avr8MemoryType::BOOT_FLASH: {
|
2022-12-13 21:12:16 +00:00
|
|
|
// See comment in EdbgAvr8Interface::alignMemoryAddress()
|
2022-12-11 23:40:37 +00:00
|
|
|
alignTo = this->targetParameters.flashPageSize.value();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case Avr8MemoryType::EEPROM_ATOMIC:
|
|
|
|
|
case Avr8MemoryType::EEPROM_PAGE: {
|
|
|
|
|
alignTo = this->targetParameters.eepromPageSize.value();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default: {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2022-12-11 23:34:20 +00:00
|
|
|
}
|
|
|
|
|
|
2022-05-28 13:44:10 +01:00
|
|
|
if ((bytes % alignTo) != 0) {
|
2022-09-06 17:16:49 +01:00
|
|
|
return static_cast<TargetMemorySize>(std::ceil(
|
2022-05-28 13:44:10 +01:00
|
|
|
static_cast<float>(bytes) / static_cast<float>(alignTo)
|
|
|
|
|
) * alignTo);
|
2022-05-17 19:51:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return bytes;
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-08 21:08:35 +00:00
|
|
|
std::optional<Targets::TargetMemorySize> EdbgAvr8Interface::maximumMemoryAccessSize(Avr8MemoryType memoryType) {
|
|
|
|
|
if (
|
|
|
|
|
memoryType == Avr8MemoryType::FLASH_PAGE
|
|
|
|
|
|| memoryType == Avr8MemoryType::APPL_FLASH
|
|
|
|
|
|| memoryType == Avr8MemoryType::BOOT_FLASH
|
|
|
|
|
|| (memoryType == Avr8MemoryType::SPM && this->configVariant == Avr8ConfigVariant::MEGAJTAG)
|
|
|
|
|
) {
|
|
|
|
|
// These flash memory types require single page access.
|
|
|
|
|
return this->targetParameters.flashPageSize.value();
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-11 23:34:20 +00:00
|
|
|
if (
|
|
|
|
|
memoryType == Avr8MemoryType::EEPROM_ATOMIC
|
|
|
|
|
|| memoryType == Avr8MemoryType::EEPROM_PAGE
|
|
|
|
|
) {
|
|
|
|
|
// These EEPROM memory types requires single page access.
|
2022-12-08 21:08:35 +00:00
|
|
|
return this->targetParameters.eepromPageSize.value();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this->maximumMemoryAccessSizePerRequest.has_value()) {
|
|
|
|
|
// There is a memory access size limit for this entire EdbgAvr8Interface instance
|
|
|
|
|
return this->maximumMemoryAccessSizePerRequest;
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-18 19:25:40 +00:00
|
|
|
/*
|
|
|
|
|
* EDBG AVR8 debug tools behave in a really weird way when receiving or responding with more than two packets
|
|
|
|
|
* for a single memory access command. The data they read/write in this case appears to be wrong.
|
|
|
|
|
*
|
|
|
|
|
* To address this, we make sure we only issue memory access commands that will result in no more than two
|
|
|
|
|
* packets being sent to and from the debug tool.
|
|
|
|
|
*
|
|
|
|
|
* The -30 is to accommodate for the bytes in the command that are not part of the main payload of the command.
|
|
|
|
|
*/
|
|
|
|
|
return static_cast<Targets::TargetMemorySize>(
|
|
|
|
|
(this->edbgInterface->getUsbHidInputReportSize() - 30) * 2
|
|
|
|
|
);
|
2022-12-08 21:08:35 +00:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
TargetMemoryBuffer EdbgAvr8Interface::readMemory(
|
|
|
|
|
Avr8MemoryType type,
|
2022-09-06 17:16:49 +01:00
|
|
|
TargetMemoryAddress startAddress,
|
|
|
|
|
TargetMemorySize bytes,
|
|
|
|
|
const std::set<TargetMemoryAddress>& excludedAddresses
|
2022-02-05 15:32:08 +00:00
|
|
|
) {
|
2023-05-07 16:49:45 +01:00
|
|
|
if (type == Avr8MemoryType::FUSES) {
|
|
|
|
|
if (this->configVariant == Avr8ConfigVariant::DEBUG_WIRE) {
|
|
|
|
|
throw Exception("Cannot access AVR fuses via the debugWire interface");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-28 21:27:01 +01:00
|
|
|
const auto managingProgrammingMode = type == Avr8MemoryType::FUSES && !this->programmingModeEnabled;
|
|
|
|
|
if (managingProgrammingMode) {
|
|
|
|
|
this->enableProgrammingMode();
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!excludedAddresses.empty() && (this->avoidMaskedMemoryRead || type != Avr8MemoryType::SRAM)) {
|
2021-04-04 21:04:12 +01:00
|
|
|
/*
|
2022-02-05 15:32:08 +00:00
|
|
|
* Driver-side masked memory read.
|
|
|
|
|
*
|
|
|
|
|
* Split the read into numerous reads, whenever we encounter an excluded address.
|
2021-04-04 21:04:12 +01:00
|
|
|
*
|
2022-02-05 15:32:08 +00:00
|
|
|
* All values for bytes located at excluded addresses will be returned as 0x00 - this mirrors the behaviour
|
|
|
|
|
* of the masked read memory EDBG command.
|
2021-04-04 21:04:12 +01:00
|
|
|
*/
|
2022-02-05 15:32:08 +00:00
|
|
|
auto output = TargetMemoryBuffer();
|
|
|
|
|
output.reserve(bytes);
|
|
|
|
|
|
|
|
|
|
auto segmentStartAddress = startAddress;
|
|
|
|
|
const auto endAddress = startAddress + bytes - 1;
|
|
|
|
|
|
|
|
|
|
for (const auto excludedAddress : excludedAddresses) {
|
|
|
|
|
if (excludedAddress < startAddress || excludedAddress > endAddress) {
|
|
|
|
|
// This excluded address is outside of the range from which we are reading, so it can be ignored.
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto segmentSize = excludedAddress - segmentStartAddress;
|
|
|
|
|
if (segmentSize > 0) {
|
|
|
|
|
auto segmentBuffer = this->readMemory(
|
|
|
|
|
type,
|
|
|
|
|
segmentStartAddress,
|
|
|
|
|
segmentSize
|
|
|
|
|
);
|
|
|
|
|
|
2022-05-23 23:50:10 +01:00
|
|
|
std::move(segmentBuffer.begin(), segmentBuffer.end(), std::back_inserter(output));
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
output.emplace_back(0x00);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
segmentStartAddress = excludedAddress + 1;
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
// Read final segment
|
|
|
|
|
const auto finalReadBytes = (endAddress - segmentStartAddress) + 1;
|
|
|
|
|
if (finalReadBytes > 0) {
|
|
|
|
|
auto segmentBuffer = this->readMemory(
|
|
|
|
|
type,
|
|
|
|
|
segmentStartAddress,
|
|
|
|
|
finalReadBytes
|
|
|
|
|
);
|
|
|
|
|
|
2022-05-23 23:50:10 +01:00
|
|
|
std::move(segmentBuffer.begin(), segmentBuffer.end(), std::back_inserter(output));
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return output;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-28 13:44:10 +01:00
|
|
|
if (this->alignmentRequired(type)) {
|
2022-05-17 19:51:00 +01:00
|
|
|
const auto alignedStartAddress = this->alignMemoryAddress(type, startAddress);
|
|
|
|
|
const auto alignedBytes = this->alignMemoryBytes(type, bytes + (startAddress - alignedStartAddress));
|
2022-02-05 15:32:08 +00:00
|
|
|
|
2022-05-17 19:51:00 +01:00
|
|
|
if (alignedStartAddress != startAddress || alignedBytes != bytes) {
|
2022-05-23 23:50:10 +01:00
|
|
|
auto memoryBuffer = this->readMemory(type, alignedStartAddress, alignedBytes, excludedAddresses);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-05-17 19:51:00 +01:00
|
|
|
const auto offset = memoryBuffer.begin() + (startAddress - alignedStartAddress);
|
2022-05-28 13:29:08 +01:00
|
|
|
auto output = TargetMemoryBuffer();
|
|
|
|
|
output.reserve(bytes);
|
2022-05-23 23:50:10 +01:00
|
|
|
std::move(offset, offset + bytes, std::back_inserter(output));
|
|
|
|
|
|
|
|
|
|
return output;
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
2022-05-28 13:44:10 +01:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-12-08 21:08:35 +00:00
|
|
|
const auto maximumReadSize = this->maximumMemoryAccessSize(type);
|
|
|
|
|
if (maximumReadSize.has_value() && bytes > *maximumReadSize) {
|
2022-09-06 17:16:49 +01:00
|
|
|
auto output = Targets::TargetMemoryBuffer();
|
2022-02-05 15:32:08 +00:00
|
|
|
output.reserve(bytes);
|
2021-04-07 23:30:30 +01:00
|
|
|
|
2022-12-08 21:08:35 +00:00
|
|
|
while (output.size() < bytes) {
|
|
|
|
|
const auto bytesToRead = std::min(
|
|
|
|
|
static_cast<TargetMemorySize>(bytes - output.size()),
|
|
|
|
|
*maximumReadSize
|
2022-05-23 23:50:10 +01:00
|
|
|
);
|
|
|
|
|
|
2021-08-30 22:30:35 +01:00
|
|
|
auto data = this->readMemory(
|
|
|
|
|
type,
|
2022-09-06 17:16:49 +01:00
|
|
|
static_cast<TargetMemoryAddress>(startAddress + output.size()),
|
2021-08-30 22:30:35 +01:00
|
|
|
bytesToRead,
|
|
|
|
|
excludedAddresses
|
|
|
|
|
);
|
2022-12-08 21:08:35 +00:00
|
|
|
std::move(data.begin(), data.end(), std::back_inserter(output));
|
2021-04-07 23:30:30 +01:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2021-04-07 23:30:30 +01:00
|
|
|
return output;
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
|
2022-06-02 23:06:39 +01:00
|
|
|
ReadMemory(
|
|
|
|
|
type,
|
|
|
|
|
startAddress,
|
|
|
|
|
bytes,
|
|
|
|
|
excludedAddresses
|
|
|
|
|
)
|
2022-02-27 20:29:26 +00:00
|
|
|
);
|
2022-06-05 21:03:28 +01:00
|
|
|
|
2023-05-28 21:27:01 +01:00
|
|
|
if (managingProgrammingMode) {
|
|
|
|
|
this->disableProgrammingMode();
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
|
|
|
|
throw Avr8CommandFailure("AVR8 Read memory command failed", responseFrame);
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-12-11 23:40:37 +00:00
|
|
|
const auto data = responseFrame.getMemoryData();
|
2022-12-11 23:38:23 +00:00
|
|
|
|
|
|
|
|
if (data.size() != bytes) {
|
|
|
|
|
throw Avr8CommandFailure("Unexpected number of bytes returned from EDBG debug tool");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return data;
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-09-06 17:16:49 +01:00
|
|
|
void EdbgAvr8Interface::writeMemory(
|
|
|
|
|
Avr8MemoryType type,
|
|
|
|
|
TargetMemoryAddress startAddress,
|
|
|
|
|
const TargetMemoryBuffer& buffer
|
|
|
|
|
) {
|
2023-05-07 16:49:45 +01:00
|
|
|
if (type == Avr8MemoryType::FUSES) {
|
|
|
|
|
if (this->configVariant == Avr8ConfigVariant::DEBUG_WIRE) {
|
|
|
|
|
throw Exception("Cannot access AVR fuses via the debugWire interface");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-28 21:27:01 +01:00
|
|
|
const auto managingProgrammingMode = type == Avr8MemoryType::FUSES && !this->programmingModeEnabled;
|
|
|
|
|
if (managingProgrammingMode) {
|
|
|
|
|
this->enableProgrammingMode();
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-06 17:16:49 +01:00
|
|
|
const auto bytes = static_cast<TargetMemorySize>(buffer.size());
|
2022-05-23 23:49:49 +01:00
|
|
|
|
2022-05-28 13:44:10 +01:00
|
|
|
if (this->alignmentRequired(type)) {
|
2022-05-23 23:49:49 +01:00
|
|
|
const auto alignedStartAddress = this->alignMemoryAddress(type, startAddress);
|
|
|
|
|
const auto alignedBytes = this->alignMemoryBytes(type, bytes + (startAddress - alignedStartAddress));
|
|
|
|
|
|
|
|
|
|
if (alignedStartAddress != startAddress || alignedBytes != bytes) {
|
2022-12-11 23:36:21 +00:00
|
|
|
/*
|
|
|
|
|
* We can't just forward the memory type to readMemory(), because some memory types (such as
|
|
|
|
|
* EEPROM_ATOMIC) can only be used for writing.
|
|
|
|
|
*
|
|
|
|
|
* This nasty hack will have to do for now.
|
|
|
|
|
*/
|
|
|
|
|
const auto readMemoryType = type == Avr8MemoryType::EEPROM_ATOMIC ? Avr8MemoryType::EEPROM : type;
|
|
|
|
|
|
|
|
|
|
auto alignedBuffer = this->readMemory(readMemoryType, alignedStartAddress, alignedBytes);
|
2022-05-23 23:49:49 +01:00
|
|
|
assert(alignedBuffer.size() >= buffer.size());
|
|
|
|
|
|
|
|
|
|
const auto offset = alignedBuffer.begin() + (startAddress - alignedStartAddress);
|
|
|
|
|
std::copy(buffer.begin(), buffer.end(), offset);
|
|
|
|
|
|
|
|
|
|
return this->writeMemory(type, alignedStartAddress, alignedBuffer);
|
|
|
|
|
}
|
2022-05-28 13:44:10 +01:00
|
|
|
}
|
2022-05-23 23:49:49 +01:00
|
|
|
|
2022-12-08 21:08:35 +00:00
|
|
|
const auto maximumWriteSize = this->maximumMemoryAccessSize(type);
|
|
|
|
|
if (maximumWriteSize.has_value() && buffer.size() > *maximumWriteSize) {
|
|
|
|
|
auto bytesWritten = TargetMemorySize(0);
|
2022-05-23 23:49:49 +01:00
|
|
|
|
2022-12-08 21:08:35 +00:00
|
|
|
while (bytesWritten < buffer.size()) {
|
|
|
|
|
const auto chunkSize = std::min(
|
|
|
|
|
static_cast<TargetMemorySize>(buffer.size() - bytesWritten),
|
|
|
|
|
*maximumWriteSize
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
this->writeMemory(
|
|
|
|
|
type,
|
|
|
|
|
startAddress + bytesWritten,
|
|
|
|
|
TargetMemoryBuffer(
|
|
|
|
|
buffer.begin() + bytesWritten,
|
|
|
|
|
buffer.begin() + bytesWritten + chunkSize
|
|
|
|
|
)
|
|
|
|
|
);
|
2022-05-28 13:44:10 +01:00
|
|
|
|
2022-12-08 21:08:35 +00:00
|
|
|
bytesWritten += chunkSize;
|
2022-05-23 23:49:49 +01:00
|
|
|
}
|
2022-12-08 21:08:35 +00:00
|
|
|
|
|
|
|
|
return;
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-08-30 22:30:35 +01:00
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
|
2022-06-02 23:06:39 +01:00
|
|
|
WriteMemory(
|
|
|
|
|
type,
|
|
|
|
|
startAddress,
|
|
|
|
|
buffer
|
|
|
|
|
)
|
2022-02-27 20:29:26 +00:00
|
|
|
);
|
2021-08-07 17:28:54 +01:00
|
|
|
|
2023-05-28 21:27:01 +01:00
|
|
|
|
|
|
|
|
// We must disable and re-enable programming mode, in order for the changes to the fuse bit to take effect.
|
|
|
|
|
if (type == Avr8MemoryType::FUSES) {
|
|
|
|
|
this->disableProgrammingMode();
|
|
|
|
|
|
|
|
|
|
if (!managingProgrammingMode) {
|
|
|
|
|
this->enableProgrammingMode();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
|
|
|
|
throw Avr8CommandFailure("AVR8 Write memory command failed", responseFrame);
|
2021-08-07 17:28:54 +01:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void EdbgAvr8Interface::refreshTargetState() {
|
2022-06-04 15:20:37 +01:00
|
|
|
const auto avrEvent = this->getAvrEvent();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
if (avrEvent != nullptr && avrEvent->eventId == AvrEventId::AVR8_BREAK_EVENT) {
|
2022-02-05 15:32:08 +00:00
|
|
|
auto* breakEvent = dynamic_cast<BreakEvent*>(avrEvent.get());
|
|
|
|
|
|
|
|
|
|
if (breakEvent == nullptr) {
|
|
|
|
|
throw Exception("Failed to process AVR8 break event");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->targetState = TargetState::STOPPED;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->targetState = TargetState::RUNNING;
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void EdbgAvr8Interface::disableDebugWire() {
|
2022-10-01 20:42:37 +01:00
|
|
|
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
|
2022-06-02 23:06:39 +01:00
|
|
|
DisableDebugWire()
|
|
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-10-01 20:42:37 +01:00
|
|
|
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
|
|
|
|
throw Avr8CommandFailure("AVR8 Disable debugWire command failed", responseFrame);
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void EdbgAvr8Interface::waitForStoppedEvent() {
|
|
|
|
|
auto breakEvent = this->waitForAvrEvent<BreakEvent>();
|
|
|
|
|
|
|
|
|
|
if (breakEvent == nullptr) {
|
|
|
|
|
throw Exception("Failed to receive break event for AVR8 target");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->targetState = TargetState::STOPPED;
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|