First pass at RISC-V hardware breakpoints (Trigger module)
This commit is contained in:
@@ -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<std::uint16_t>(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<TriggerModule::TriggerIndex, TriggerModule::TriggerDescriptor>{};
|
||||
|
||||
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<double>(size) / static_cast<double>(alignTo))
|
||||
) * alignTo;
|
||||
}
|
||||
|
||||
std::optional<
|
||||
std::reference_wrapper<const TriggerModule::TriggerDescriptor>
|
||||
> 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"};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <optional>
|
||||
#include <functional>
|
||||
|
||||
#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<DebugModule::HartIndex> hartIndices;
|
||||
DebugModule::HartIndex selectedHartIndex = 0;
|
||||
|
||||
std::unordered_map<TriggerModule::TriggerIndex, TriggerModule::TriggerDescriptor> triggerDescriptorsByIndex;
|
||||
std::unordered_set<TriggerModule::TriggerIndex> allocatedTriggerIndices;
|
||||
std::unordered_map<Targets::TargetMemoryAddress, TriggerModule::TriggerIndex> triggerIndicesByBreakpointAddress;
|
||||
|
||||
std::vector<DebugModule::HartIndex> discoverHartIndices();
|
||||
std::unordered_map<TriggerModule::TriggerIndex, TriggerModule::TriggerDescriptor> 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<std::reference_wrapper<const TriggerModule::TriggerDescriptor>> getAvailableTrigger();
|
||||
void clearTrigger(const TriggerModule::TriggerDescriptor& triggerDescriptor);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
#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<bool>(registerValue & 0x01))
|
||||
, store(static_cast<bool>(registerValue & (0x01 << 1)))
|
||||
, execute(static_cast<bool>(registerValue & (0x01 << 2)))
|
||||
, enabledInUserMode(static_cast<bool>(registerValue & (0x01 << 3)))
|
||||
, enabledInSupervisorMode(static_cast<bool>(registerValue & (0x01 << 4)))
|
||||
, enabledInMachineMode(static_cast<bool>(registerValue & (0x01 << 6)))
|
||||
, matchMode(static_cast<MatchMode>((registerValue >> 7) & 0x0F))
|
||||
, chain(static_cast<bool>(registerValue & (0x01 << 11)))
|
||||
, action(static_cast<TriggerAction>((registerValue >> 12) & 0x0F))
|
||||
, accessSize(
|
||||
static_cast<AccessSize>(
|
||||
(((registerValue >> 21) & 0x03) << 2) | ((registerValue >> 16) & 0x03)
|
||||
)
|
||||
)
|
||||
, timing(static_cast<bool>(registerValue & (0x01 << 18)))
|
||||
, compareValueType(static_cast<CompareValueType>((registerValue >> 19) & 0x01))
|
||||
, hit(static_cast<bool>(registerValue & (0x01 << 20)))
|
||||
{}
|
||||
|
||||
[[nodiscard]] constexpr RegisterValue value() const {
|
||||
return RegisterValue{0}
|
||||
| static_cast<RegisterValue>(this->load)
|
||||
| static_cast<RegisterValue>(this->store) << 1
|
||||
| static_cast<RegisterValue>(this->execute) << 2
|
||||
| static_cast<RegisterValue>(this->enabledInUserMode) << 3
|
||||
| static_cast<RegisterValue>(this->enabledInSupervisorMode) << 4
|
||||
| static_cast<RegisterValue>(this->enabledInMachineMode) << 6
|
||||
| static_cast<RegisterValue>(this->matchMode) << 7
|
||||
| static_cast<RegisterValue>(this->chain) << 11
|
||||
| static_cast<RegisterValue>(this->action) << 12
|
||||
| (static_cast<RegisterValue>(this->accessSize) & 0x03) << 16
|
||||
| static_cast<RegisterValue>(this->timing) << 18
|
||||
| static_cast<RegisterValue>(this->compareValueType) << 19
|
||||
| static_cast<RegisterValue>(this->hit) << 20
|
||||
| (static_cast<RegisterValue>(this->accessSize) >> 2) << 21
|
||||
;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
#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<bool>(registerValue & (0x01 << 27)))
|
||||
, type(static_cast<std::uint8_t>(registerValue >> 28) & 0x0F)
|
||||
{}
|
||||
|
||||
[[nodiscard]] constexpr RegisterValue value() const {
|
||||
return RegisterValue{0}
|
||||
| static_cast<RegisterValue>(this->data)
|
||||
| static_cast<RegisterValue>(this->debugModeOnly) << 27
|
||||
| static_cast<RegisterValue>(this->type) << 28
|
||||
;
|
||||
}
|
||||
|
||||
std::optional<TriggerType> getType() const {
|
||||
return (this->type >= 0x01 && this->type <= 0x07)
|
||||
? std::optional{static_cast<TriggerType>(this->type)}
|
||||
: std::nullopt;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <set>
|
||||
#include <array>
|
||||
|
||||
#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<std::uint8_t>(registerValue >> 24))
|
||||
{}
|
||||
|
||||
[[nodiscard]] constexpr RegisterValue value() const {
|
||||
return RegisterValue{0}
|
||||
| static_cast<RegisterValue>(this->info)
|
||||
| static_cast<RegisterValue>(this->version) << 24
|
||||
;
|
||||
}
|
||||
|
||||
std::set<TriggerType> getSupportedTriggerTypes() const {
|
||||
auto output = std::set<TriggerType>{};
|
||||
|
||||
static constexpr auto types = std::to_array<TriggerType>({
|
||||
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<std::uint8_t>(type))) {
|
||||
output.insert(type);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#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<RegisterValue>(this->index);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <set>
|
||||
|
||||
#include "TriggerModule.hpp"
|
||||
|
||||
namespace DebugToolDrivers::Protocols::RiscVDebugSpec::TriggerModule
|
||||
{
|
||||
struct TriggerDescriptor
|
||||
{
|
||||
TriggerIndex index;
|
||||
std::set<TriggerType> supportedTypes;
|
||||
|
||||
TriggerDescriptor(TriggerIndex index, const std::set<TriggerType>& supportedTypes)
|
||||
: index(index)
|
||||
, supportedTypes(supportedTypes)
|
||||
{}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
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,
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user