diff --git a/src/DebugToolDrivers/Protocols/RiscVDebugSpec/DebugTranslator.cpp b/src/DebugToolDrivers/Protocols/RiscVDebugSpec/DebugTranslator.cpp index 1c18a0ef..62e35636 100644 --- a/src/DebugToolDrivers/Protocols/RiscVDebugSpec/DebugTranslator.cpp +++ b/src/DebugToolDrivers/Protocols/RiscVDebugSpec/DebugTranslator.cpp @@ -11,6 +11,11 @@ #include "DebugModule/Registers/RegisterAccessControlField.hpp" #include "DebugModule/Registers/MemoryAccessControlField.hpp" +#include "TriggerModule/Registers/TriggerSelect.hpp" +#include "TriggerModule/Registers/TriggerInfo.hpp" +#include "TriggerModule/Registers/TriggerData1.hpp" +#include "TriggerModule/Registers/MatchControl.hpp" + #include "src/Exceptions/Exception.hpp" #include "src/Exceptions/InvalidConfig.hpp" #include "src/TargetController/Exceptions/DeviceInitializationFailure.hpp" @@ -90,6 +95,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec this->stop(); this->reset(); + this->triggerDescriptorsByIndex = this->discoverTriggers(); auto debugControlStatusRegister = this->readDebugControlStatusRegister(); debugControlStatusRegister.breakUMode = true; @@ -213,23 +219,76 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec } void DebugTranslator::setSoftwareBreakpoint(TargetMemoryAddress address) { - + throw Exceptions::Exception{"SW breakpoints not supported"}; } void DebugTranslator::clearSoftwareBreakpoint(TargetMemoryAddress address) { + throw Exceptions::Exception{"SW breakpoints not supported"}; + } + std::uint16_t DebugTranslator::getHardwareBreakpointCount() { + return static_cast(this->triggerDescriptorsByIndex.size()); } void DebugTranslator::setHardwareBreakpoint(TargetMemoryAddress address) { + using TriggerModule::TriggerType; + const auto triggerDescriptorOpt = this->getAvailableTrigger(); + if (!triggerDescriptorOpt.has_value()) { + throw Exceptions::Exception{"Insufficient resources - no available trigger"}; + } + + const auto& triggerDescriptor = triggerDescriptorOpt->get(); + Logger::debug("Installing hardware BP at address " + Services::StringService::toHex(address) + " with index " + std::to_string(triggerDescriptor.index)); + + if (triggerDescriptor.supportedTypes.contains(TriggerType::MATCH_CONTROL)) { + using TriggerModule::Registers::MatchControl; + + this->writeCpuRegister( + CpuRegisterNumber::TRIGGER_SELECT, + TriggerModule::Registers::TriggerSelect{triggerDescriptor.index}.value() + ); + + auto matchControlRegister = MatchControl{}; + matchControlRegister.execute = true; + matchControlRegister.enabledInUserMode = true; + matchControlRegister.enabledInSupervisorMode = true; + matchControlRegister.enabledInMachineMode = true; + matchControlRegister.action = TriggerModule::TriggerAction::ENTER_DEBUG_MODE; + matchControlRegister.accessSize = MatchControl::AccessSize::ANY; + matchControlRegister.compareValueType = MatchControl::CompareValueType::ADDRESS; + + this->writeCpuRegister(CpuRegisterNumber::TRIGGER_DATA_1, matchControlRegister.value()); + this->writeCpuRegister(CpuRegisterNumber::TRIGGER_DATA_2, address); + + this->allocatedTriggerIndices.emplace(triggerDescriptor.index); + this->triggerIndicesByBreakpointAddress.emplace(address, triggerDescriptor.index); + return; + } + + throw Exceptions::Exception{"Unsupported trigger"}; } void DebugTranslator::clearHardwareBreakpoint(TargetMemoryAddress address) { + const auto triggerIndexIt = this->triggerIndicesByBreakpointAddress.find(address); + if (triggerIndexIt == this->triggerIndicesByBreakpointAddress.end()) { + throw Exceptions::Exception{"Unknown hardware breakpoint"}; + } + const auto& triggerDescriptor = this->triggerDescriptorsByIndex.at(triggerIndexIt->second); + + this->clearTrigger(triggerDescriptor); + this->triggerIndicesByBreakpointAddress.erase(address); + this->allocatedTriggerIndices.erase(triggerDescriptor.index); } void DebugTranslator::clearAllBreakpoints() { + for (const auto [triggerIndex, triggerDescriptor] : this->triggerDescriptorsByIndex) { + this->clearTrigger(triggerDescriptor); + } + this->triggerIndicesByBreakpointAddress.clear(); + this->allocatedTriggerIndices.clear(); } TargetRegisterDescriptorAndValuePairs DebugTranslator::readCpuRegisters( @@ -445,6 +504,63 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec return hartIndices; } + std::unordered_map< + TriggerModule::TriggerIndex, + TriggerModule::TriggerDescriptor + > DebugTranslator::discoverTriggers() { + auto output = std::unordered_map{}; + + constexpr auto MAX_TRIGGER_INDEX = 10; + for (auto triggerIndex = TriggerModule::TriggerIndex{0}; triggerIndex <= MAX_TRIGGER_INDEX; ++triggerIndex) { + const auto selectRegValue = TriggerModule::Registers::TriggerSelect{triggerIndex}.value(); + + const auto writeSelectError = this->tryWriteCpuRegister(CpuRegisterNumber::TRIGGER_SELECT, selectRegValue); + if (writeSelectError == DebugModule::AbstractCommandError::EXCEPTION) { + break; + } + + if (writeSelectError != DebugModule::AbstractCommandError::NONE) { + throw Exceptions::Exception{ + "Failed to write to TRIGGER_SELECT register - abstract command error: 0x" + + Services::StringService::toHex(writeSelectError) + }; + } + + if (this->readCpuRegister(CpuRegisterNumber::TRIGGER_SELECT) != selectRegValue) { + break; + } + + const auto infoReg = TriggerModule::Registers::TriggerInfo{ + this->readCpuRegister(CpuRegisterNumber::TRIGGER_INFO) + }; + + if (infoReg.info == 0x01) { + // Trigger doesn't exist + break; + } + + auto supportedTypes = infoReg.getSupportedTriggerTypes(); + if (supportedTypes.empty()) { + // The trigger info register has no trigger type info. Try the data1 register. + const auto data1Reg = TriggerModule::Registers::TriggerData1{ + this->readCpuRegister(CpuRegisterNumber::TRIGGER_DATA_1) + }; + + const auto triggerType = data1Reg.getType(); + if (!triggerType.has_value()) { + // Trigger data1 register also lacks type info. Assume the trigger doesn't exist + break; + } + + supportedTypes.insert(*triggerType); + } + + output.emplace(triggerIndex, TriggerModule::TriggerDescriptor{triggerIndex, supportedTypes}); + } + + return output; + } + ControlRegister DebugTranslator::readDebugModuleControlRegister() { return ControlRegister{this->dtmInterface.readDebugModuleRegister(RegisterAddress::CONTROL_REGISTER)}; } @@ -650,4 +766,38 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec std::ceil(static_cast(size) / static_cast(alignTo)) ) * alignTo; } + + std::optional< + std::reference_wrapper + > DebugTranslator::getAvailableTrigger() { + for (const auto& [index, descriptor] : this->triggerDescriptorsByIndex) { + if (this->allocatedTriggerIndices.contains(index)) { + continue; + } + + return descriptor; + } + + return std::nullopt; + } + + void DebugTranslator::clearTrigger(const TriggerModule::TriggerDescriptor& triggerDescriptor) { + using TriggerModule::TriggerType; + + Logger::debug("Clearing trigger " + std::to_string(triggerDescriptor.index)); // TODO: keep this, but reword it + + if (triggerDescriptor.supportedTypes.contains(TriggerType::MATCH_CONTROL)) { + using TriggerModule::Registers::MatchControl; + + this->writeCpuRegister( + CpuRegisterNumber::TRIGGER_SELECT, + TriggerModule::Registers::TriggerSelect{triggerDescriptor.index}.value() + ); + + this->writeCpuRegister(CpuRegisterNumber::TRIGGER_DATA_1, MatchControl{}.value()); + return; + } + + throw Exceptions::Exception{"Unsupported trigger"}; + } } diff --git a/src/DebugToolDrivers/Protocols/RiscVDebugSpec/DebugTranslator.hpp b/src/DebugToolDrivers/Protocols/RiscVDebugSpec/DebugTranslator.hpp index 9b012d06..9cd02337 100644 --- a/src/DebugToolDrivers/Protocols/RiscVDebugSpec/DebugTranslator.hpp +++ b/src/DebugToolDrivers/Protocols/RiscVDebugSpec/DebugTranslator.hpp @@ -2,6 +2,11 @@ #include #include +#include +#include +#include +#include +#include #include "src/DebugToolDrivers/TargetInterfaces/RiscV/RiscVDebugInterface.hpp" @@ -20,6 +25,8 @@ #include "DebugModule/Registers/AbstractControlStatusRegister.hpp" #include "DebugModule/Registers/AbstractCommandRegister.hpp" +#include "TriggerModule/TriggerModule.hpp" +#include "TriggerModule/TriggerDescriptor.hpp" #include "src/Helpers/Expected.hpp" @@ -53,6 +60,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec void setSoftwareBreakpoint(Targets::TargetMemoryAddress address) override; void clearSoftwareBreakpoint(Targets::TargetMemoryAddress address) override; + std::uint16_t getHardwareBreakpointCount() override; void setHardwareBreakpoint(Targets::TargetMemoryAddress address) override; void clearHardwareBreakpoint(Targets::TargetMemoryAddress address) override; void clearAllBreakpoints() override; @@ -85,7 +93,12 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec std::vector hartIndices; DebugModule::HartIndex selectedHartIndex = 0; + std::unordered_map triggerDescriptorsByIndex; + std::unordered_set allocatedTriggerIndices; + std::unordered_map triggerIndicesByBreakpointAddress; + std::vector discoverHartIndices(); + std::unordered_map discoverTriggers(); DebugModule::Registers::ControlRegister readDebugModuleControlRegister(); DebugModule::Registers::StatusRegister readDebugModuleStatusRegister(); @@ -120,5 +133,8 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec Targets::TargetMemoryAddress alignTo ); Targets::TargetMemorySize alignMemorySize(Targets::TargetMemorySize size, Targets::TargetMemorySize alignTo); + + std::optional> getAvailableTrigger(); + void clearTrigger(const TriggerModule::TriggerDescriptor& triggerDescriptor); }; } diff --git a/src/DebugToolDrivers/Protocols/RiscVDebugSpec/Registers/CpuRegisterNumbers.hpp b/src/DebugToolDrivers/Protocols/RiscVDebugSpec/Registers/CpuRegisterNumbers.hpp index d69ccd08..1df04d69 100644 --- a/src/DebugToolDrivers/Protocols/RiscVDebugSpec/Registers/CpuRegisterNumbers.hpp +++ b/src/DebugToolDrivers/Protocols/RiscVDebugSpec/Registers/CpuRegisterNumbers.hpp @@ -7,5 +7,10 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec::Registers enum class CpuRegisterNumber: RegisterNumber { DEBUG_CONTROL_STATUS_REGISTER = 0x07b0, + TRIGGER_SELECT = 0x07a0, + TRIGGER_DATA_1 = 0x07a1, + TRIGGER_DATA_2 = 0x07a2, + TRIGGER_DATA_3 = 0x07a3, + TRIGGER_INFO = 0x07a4, }; } diff --git a/src/DebugToolDrivers/Protocols/RiscVDebugSpec/TriggerModule/Registers/MatchControl.hpp b/src/DebugToolDrivers/Protocols/RiscVDebugSpec/TriggerModule/Registers/MatchControl.hpp new file mode 100644 index 00000000..15fb5790 --- /dev/null +++ b/src/DebugToolDrivers/Protocols/RiscVDebugSpec/TriggerModule/Registers/MatchControl.hpp @@ -0,0 +1,125 @@ +#pragma once + +#include +#include + +#include "src/DebugToolDrivers/Protocols/RiscVDebugSpec/TriggerModule/TriggerModule.hpp" + +namespace DebugToolDrivers::Protocols::RiscVDebugSpec::TriggerModule::Registers +{ + struct MatchControl + { + enum class MatchMode: std::uint8_t + { + EQUAL = 0x00, + TOP_BITS = 0x01, + GREATER_THAN = 0x02, + LESS_THAN = 0x03, + MASK_LOW = 0x04, + MASK_HIGH = 0x05, + NOT_EQUAL = 0x08, + NOT_TOP_BITS = 0x09, + NOT_MASK_LOW = 0x0C, + NOT_MASK_HIGH = 0x0D, + }; + + enum class AccessSize: std::uint8_t + { + ANY = 0x00, + SIZE_8 = 0x01, + SIZE_16 = 0x02, + SIZE_32 = 0x03, + }; + + enum class CompareValueType: std::uint8_t + { + ADDRESS = 0x00, + DATA = 0x01, + }; + + bool load:1 = false; + bool store:1 = false; + bool execute:1 = false; + bool enabledInUserMode:1 = false; + bool enabledInSupervisorMode:1 = false; + bool enabledInMachineMode:1 = false; + MatchMode matchMode:4 = MatchMode::EQUAL; + bool chain:1 = false; // TODO: Consider making this an enum + TriggerAction action:4 = TriggerAction::ENTER_DEBUG_MODE; + AccessSize accessSize = AccessSize::ANY; + bool timing:1 = false; // TODO: Consider making this an enum + CompareValueType compareValueType:1 = CompareValueType::ADDRESS; + bool hit:1 = false; + + MatchControl() = default; + + constexpr explicit MatchControl( + bool load, + bool store, + bool execute, + bool enabledInUserMode, + bool enabledInSupervisorMode, + bool enabledInMachineMode, + MatchMode matchMode, + bool chain, + TriggerAction action, + AccessSize accessSize, + bool timing, + CompareValueType compareValueType, + bool hit + ) + : load(load) + , store(store) + , execute(execute) + , enabledInUserMode(enabledInUserMode) + , enabledInSupervisorMode(enabledInSupervisorMode) + , enabledInMachineMode(enabledInMachineMode) + , matchMode(matchMode) + , chain(chain) + , action(action) + , accessSize(accessSize) + , timing(timing) + , compareValueType(compareValueType) + , hit(hit) + {} + + constexpr explicit MatchControl(RegisterValue registerValue) + : load(static_cast(registerValue & 0x01)) + , store(static_cast(registerValue & (0x01 << 1))) + , execute(static_cast(registerValue & (0x01 << 2))) + , enabledInUserMode(static_cast(registerValue & (0x01 << 3))) + , enabledInSupervisorMode(static_cast(registerValue & (0x01 << 4))) + , enabledInMachineMode(static_cast(registerValue & (0x01 << 6))) + , matchMode(static_cast((registerValue >> 7) & 0x0F)) + , chain(static_cast(registerValue & (0x01 << 11))) + , action(static_cast((registerValue >> 12) & 0x0F)) + , accessSize( + static_cast( + (((registerValue >> 21) & 0x03) << 2) | ((registerValue >> 16) & 0x03) + ) + ) + , timing(static_cast(registerValue & (0x01 << 18))) + , compareValueType(static_cast((registerValue >> 19) & 0x01)) + , hit(static_cast(registerValue & (0x01 << 20))) + {} + + [[nodiscard]] constexpr RegisterValue value() const { + return RegisterValue{0} + | static_cast(this->load) + | static_cast(this->store) << 1 + | static_cast(this->execute) << 2 + | static_cast(this->enabledInUserMode) << 3 + | static_cast(this->enabledInSupervisorMode) << 4 + | static_cast(this->enabledInMachineMode) << 6 + | static_cast(this->matchMode) << 7 + | static_cast(this->chain) << 11 + | static_cast(this->action) << 12 + | (static_cast(this->accessSize) & 0x03) << 16 + | static_cast(this->timing) << 18 + | static_cast(this->compareValueType) << 19 + | static_cast(this->hit) << 20 + | (static_cast(this->accessSize) >> 2) << 21 + ; + } + }; +} diff --git a/src/DebugToolDrivers/Protocols/RiscVDebugSpec/TriggerModule/Registers/TriggerData1.hpp b/src/DebugToolDrivers/Protocols/RiscVDebugSpec/TriggerModule/Registers/TriggerData1.hpp new file mode 100644 index 00000000..48314c93 --- /dev/null +++ b/src/DebugToolDrivers/Protocols/RiscVDebugSpec/TriggerModule/Registers/TriggerData1.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include +#include + +#include "src/DebugToolDrivers/Protocols/RiscVDebugSpec/TriggerModule/TriggerModule.hpp" + +namespace DebugToolDrivers::Protocols::RiscVDebugSpec::TriggerModule::Registers +{ + struct TriggerData1 + { + std::uint32_t data:27; + bool debugModeOnly:1; + std::uint8_t type:4; + + TriggerData1() = default; + + constexpr explicit TriggerData1(RegisterValue registerValue) + : data(registerValue & 0x07FFFFFF) + , debugModeOnly(static_cast(registerValue & (0x01 << 27))) + , type(static_cast(registerValue >> 28) & 0x0F) + {} + + [[nodiscard]] constexpr RegisterValue value() const { + return RegisterValue{0} + | static_cast(this->data) + | static_cast(this->debugModeOnly) << 27 + | static_cast(this->type) << 28 + ; + } + + std::optional getType() const { + return (this->type >= 0x01 && this->type <= 0x07) + ? std::optional{static_cast(this->type)} + : std::nullopt; + } + }; +} diff --git a/src/DebugToolDrivers/Protocols/RiscVDebugSpec/TriggerModule/Registers/TriggerInfo.hpp b/src/DebugToolDrivers/Protocols/RiscVDebugSpec/TriggerModule/Registers/TriggerInfo.hpp new file mode 100644 index 00000000..a9488835 --- /dev/null +++ b/src/DebugToolDrivers/Protocols/RiscVDebugSpec/TriggerModule/Registers/TriggerInfo.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include +#include +#include + +#include "src/DebugToolDrivers/Protocols/RiscVDebugSpec/TriggerModule/TriggerModule.hpp" + +namespace DebugToolDrivers::Protocols::RiscVDebugSpec::TriggerModule::Registers +{ + struct TriggerInfo + { + std::uint16_t info; + std::uint8_t version; + + constexpr explicit TriggerInfo(RegisterValue registerValue) + : info(registerValue & 0xFFFF) + , version(static_cast(registerValue >> 24)) + {} + + [[nodiscard]] constexpr RegisterValue value() const { + return RegisterValue{0} + | static_cast(this->info) + | static_cast(this->version) << 24 + ; + } + + std::set getSupportedTriggerTypes() const { + auto output = std::set{}; + + static constexpr auto types = std::to_array({ + TriggerType::LEGACY, + TriggerType::MATCH_CONTROL, + TriggerType::INSTRUCTION_COUNT, + TriggerType::INTERRUPT_TRIGGER, + TriggerType::EXCEPTION_TRIGGER, + TriggerType::MATCH_CONTROL_TYPE_6, + TriggerType::EXTERNAL, + }); + + for (const auto& type : types) { + if (this->info & (0x01 << static_cast(type))) { + output.insert(type); + } + } + + return output; + } + }; +} diff --git a/src/DebugToolDrivers/Protocols/RiscVDebugSpec/TriggerModule/Registers/TriggerSelect.hpp b/src/DebugToolDrivers/Protocols/RiscVDebugSpec/TriggerModule/Registers/TriggerSelect.hpp new file mode 100644 index 00000000..57a98d75 --- /dev/null +++ b/src/DebugToolDrivers/Protocols/RiscVDebugSpec/TriggerModule/Registers/TriggerSelect.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include + +#include "src/DebugToolDrivers/Protocols/RiscVDebugSpec/TriggerModule/TriggerModule.hpp" + +namespace DebugToolDrivers::Protocols::RiscVDebugSpec::TriggerModule::Registers +{ + struct TriggerSelect + { + TriggerIndex index; + + constexpr explicit TriggerSelect(TriggerIndex index) + : index(index) + {} + + [[nodiscard]] constexpr RegisterValue value() const { + return static_cast(this->index); + } + }; +} diff --git a/src/DebugToolDrivers/Protocols/RiscVDebugSpec/TriggerModule/TriggerDescriptor.hpp b/src/DebugToolDrivers/Protocols/RiscVDebugSpec/TriggerModule/TriggerDescriptor.hpp new file mode 100644 index 00000000..9065d300 --- /dev/null +++ b/src/DebugToolDrivers/Protocols/RiscVDebugSpec/TriggerModule/TriggerDescriptor.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +#include "TriggerModule.hpp" + +namespace DebugToolDrivers::Protocols::RiscVDebugSpec::TriggerModule +{ + struct TriggerDescriptor + { + TriggerIndex index; + std::set supportedTypes; + + TriggerDescriptor(TriggerIndex index, const std::set& supportedTypes) + : index(index) + , supportedTypes(supportedTypes) + {} + }; +} diff --git a/src/DebugToolDrivers/Protocols/RiscVDebugSpec/TriggerModule/TriggerModule.hpp b/src/DebugToolDrivers/Protocols/RiscVDebugSpec/TriggerModule/TriggerModule.hpp new file mode 100644 index 00000000..71d13e76 --- /dev/null +++ b/src/DebugToolDrivers/Protocols/RiscVDebugSpec/TriggerModule/TriggerModule.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include + +namespace DebugToolDrivers::Protocols::RiscVDebugSpec::TriggerModule +{ + using RegisterValue = std::uint32_t; + using TriggerIndex = std::uint32_t; + + enum class TriggerType: std::uint8_t + { + NONE = 0x00, + LEGACY = 0x01, + MATCH_CONTROL = 0x02, + INSTRUCTION_COUNT = 0x03, + INTERRUPT_TRIGGER = 0x04, + EXCEPTION_TRIGGER = 0x05, + MATCH_CONTROL_TYPE_6 = 0x06, + EXTERNAL = 0x07, + DISABLED = 0x0F, + }; + + enum class TriggerAction: std::uint8_t + { + ENTER_DEBUG_MODE = 0x01, + }; +} diff --git a/src/DebugToolDrivers/TargetInterfaces/RiscV/RiscVDebugInterface.hpp b/src/DebugToolDrivers/TargetInterfaces/RiscV/RiscVDebugInterface.hpp index 392d706c..3c5bc6a3 100644 --- a/src/DebugToolDrivers/TargetInterfaces/RiscV/RiscVDebugInterface.hpp +++ b/src/DebugToolDrivers/TargetInterfaces/RiscV/RiscVDebugInterface.hpp @@ -31,6 +31,7 @@ namespace DebugToolDrivers::TargetInterfaces::RiscV virtual void setSoftwareBreakpoint(Targets::TargetMemoryAddress address) = 0; virtual void clearSoftwareBreakpoint(Targets::TargetMemoryAddress address) = 0; + virtual std::uint16_t getHardwareBreakpointCount() = 0; virtual void setHardwareBreakpoint(Targets::TargetMemoryAddress address) = 0; virtual void clearHardwareBreakpoint(Targets::TargetMemoryAddress address) = 0; virtual void clearAllBreakpoints() = 0; diff --git a/src/Targets/RiscV/RiscV.cpp b/src/Targets/RiscV/RiscV.cpp index 549e00ad..215d6c7e 100644 --- a/src/Targets/RiscV/RiscV.cpp +++ b/src/Targets/RiscV/RiscV.cpp @@ -70,10 +70,14 @@ namespace Targets::RiscV } void RiscV::deactivate() { - if (this->getExecutionState() != TargetExecutionState::RUNNING) { - this->run(); + // TODO: Is this "tidy-up" code better placed in the TC? Review after v1.1.0. + + if (this->getExecutionState() != TargetExecutionState::STOPPED) { + this->stop(); } + this->clearAllBreakpoints(); + this->run(); this->riscVDebugInterface->deactivate(); } @@ -92,7 +96,11 @@ namespace Targets::RiscV this->targetDescriptionFile.targetPadDescriptorsByKey(), this->targetDescriptionFile.targetPinoutDescriptorsByKey(), this->targetDescriptionFile.targetVariantDescriptorsByKey(), - {} // TODO: populate this + BreakpointResources{ + this->riscVDebugInterface->getHardwareBreakpointCount(), + std::nullopt, + static_cast(this->targetConfig.reserveSteppingBreakpoint ? 1 : 0) + } }; // Copy the RISC-V CPU register address space and peripheral descriptor @@ -126,23 +134,23 @@ namespace Targets::RiscV } void RiscV::setSoftwareBreakpoint(TargetMemoryAddress address) { - + throw Exceptions::Exception{"TARGET - SW breakpoints not supported"}; } void RiscV::removeSoftwareBreakpoint(TargetMemoryAddress address) { - + throw Exceptions::Exception{"TARGET - SW breakpoints not supported"}; } void RiscV::setHardwareBreakpoint(TargetMemoryAddress address) { - + this->riscVDebugInterface->setHardwareBreakpoint(address); } void RiscV::removeHardwareBreakpoint(TargetMemoryAddress address) { - + this->riscVDebugInterface->clearHardwareBreakpoint(address); } void RiscV::clearAllBreakpoints() { - + this->riscVDebugInterface->clearAllBreakpoints(); } TargetRegisterDescriptorAndValuePairs RiscV::readRegisters(const TargetRegisterDescriptors& descriptors) {