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/RegisterAccessControlField.hpp"
|
||||||
#include "DebugModule/Registers/MemoryAccessControlField.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/Exception.hpp"
|
||||||
#include "src/Exceptions/InvalidConfig.hpp"
|
#include "src/Exceptions/InvalidConfig.hpp"
|
||||||
#include "src/TargetController/Exceptions/DeviceInitializationFailure.hpp"
|
#include "src/TargetController/Exceptions/DeviceInitializationFailure.hpp"
|
||||||
@@ -90,6 +95,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
|
|||||||
|
|
||||||
this->stop();
|
this->stop();
|
||||||
this->reset();
|
this->reset();
|
||||||
|
this->triggerDescriptorsByIndex = this->discoverTriggers();
|
||||||
|
|
||||||
auto debugControlStatusRegister = this->readDebugControlStatusRegister();
|
auto debugControlStatusRegister = this->readDebugControlStatusRegister();
|
||||||
debugControlStatusRegister.breakUMode = true;
|
debugControlStatusRegister.breakUMode = true;
|
||||||
@@ -213,23 +219,76 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DebugTranslator::setSoftwareBreakpoint(TargetMemoryAddress address) {
|
void DebugTranslator::setSoftwareBreakpoint(TargetMemoryAddress address) {
|
||||||
|
throw Exceptions::Exception{"SW breakpoints not supported"};
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugTranslator::clearSoftwareBreakpoint(TargetMemoryAddress address) {
|
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) {
|
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) {
|
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() {
|
void DebugTranslator::clearAllBreakpoints() {
|
||||||
|
for (const auto [triggerIndex, triggerDescriptor] : this->triggerDescriptorsByIndex) {
|
||||||
|
this->clearTrigger(triggerDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->triggerIndicesByBreakpointAddress.clear();
|
||||||
|
this->allocatedTriggerIndices.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
TargetRegisterDescriptorAndValuePairs DebugTranslator::readCpuRegisters(
|
TargetRegisterDescriptorAndValuePairs DebugTranslator::readCpuRegisters(
|
||||||
@@ -445,6 +504,63 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
|
|||||||
return hartIndices;
|
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() {
|
ControlRegister DebugTranslator::readDebugModuleControlRegister() {
|
||||||
return ControlRegister{this->dtmInterface.readDebugModuleRegister(RegisterAddress::CONTROL_REGISTER)};
|
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))
|
std::ceil(static_cast<double>(size) / static_cast<double>(alignTo))
|
||||||
) * 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 <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <optional>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#include "src/DebugToolDrivers/TargetInterfaces/RiscV/RiscVDebugInterface.hpp"
|
#include "src/DebugToolDrivers/TargetInterfaces/RiscV/RiscVDebugInterface.hpp"
|
||||||
|
|
||||||
@@ -20,6 +25,8 @@
|
|||||||
#include "DebugModule/Registers/AbstractControlStatusRegister.hpp"
|
#include "DebugModule/Registers/AbstractControlStatusRegister.hpp"
|
||||||
#include "DebugModule/Registers/AbstractCommandRegister.hpp"
|
#include "DebugModule/Registers/AbstractCommandRegister.hpp"
|
||||||
|
|
||||||
|
#include "TriggerModule/TriggerModule.hpp"
|
||||||
|
#include "TriggerModule/TriggerDescriptor.hpp"
|
||||||
|
|
||||||
#include "src/Helpers/Expected.hpp"
|
#include "src/Helpers/Expected.hpp"
|
||||||
|
|
||||||
@@ -53,6 +60,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
|
|||||||
void setSoftwareBreakpoint(Targets::TargetMemoryAddress address) override;
|
void setSoftwareBreakpoint(Targets::TargetMemoryAddress address) override;
|
||||||
void clearSoftwareBreakpoint(Targets::TargetMemoryAddress address) override;
|
void clearSoftwareBreakpoint(Targets::TargetMemoryAddress address) override;
|
||||||
|
|
||||||
|
std::uint16_t getHardwareBreakpointCount() override;
|
||||||
void setHardwareBreakpoint(Targets::TargetMemoryAddress address) override;
|
void setHardwareBreakpoint(Targets::TargetMemoryAddress address) override;
|
||||||
void clearHardwareBreakpoint(Targets::TargetMemoryAddress address) override;
|
void clearHardwareBreakpoint(Targets::TargetMemoryAddress address) override;
|
||||||
void clearAllBreakpoints() override;
|
void clearAllBreakpoints() override;
|
||||||
@@ -85,7 +93,12 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
|
|||||||
std::vector<DebugModule::HartIndex> hartIndices;
|
std::vector<DebugModule::HartIndex> hartIndices;
|
||||||
DebugModule::HartIndex selectedHartIndex = 0;
|
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::vector<DebugModule::HartIndex> discoverHartIndices();
|
||||||
|
std::unordered_map<TriggerModule::TriggerIndex, TriggerModule::TriggerDescriptor> discoverTriggers();
|
||||||
|
|
||||||
DebugModule::Registers::ControlRegister readDebugModuleControlRegister();
|
DebugModule::Registers::ControlRegister readDebugModuleControlRegister();
|
||||||
DebugModule::Registers::StatusRegister readDebugModuleStatusRegister();
|
DebugModule::Registers::StatusRegister readDebugModuleStatusRegister();
|
||||||
@@ -120,5 +133,8 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
|
|||||||
Targets::TargetMemoryAddress alignTo
|
Targets::TargetMemoryAddress alignTo
|
||||||
);
|
);
|
||||||
Targets::TargetMemorySize alignMemorySize(Targets::TargetMemorySize size, Targets::TargetMemorySize 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
|
enum class CpuRegisterNumber: RegisterNumber
|
||||||
{
|
{
|
||||||
DEBUG_CONTROL_STATUS_REGISTER = 0x07b0,
|
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 setSoftwareBreakpoint(Targets::TargetMemoryAddress address) = 0;
|
||||||
virtual void clearSoftwareBreakpoint(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 setHardwareBreakpoint(Targets::TargetMemoryAddress address) = 0;
|
||||||
virtual void clearHardwareBreakpoint(Targets::TargetMemoryAddress address) = 0;
|
virtual void clearHardwareBreakpoint(Targets::TargetMemoryAddress address) = 0;
|
||||||
virtual void clearAllBreakpoints() = 0;
|
virtual void clearAllBreakpoints() = 0;
|
||||||
|
|||||||
@@ -70,10 +70,14 @@ namespace Targets::RiscV
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RiscV::deactivate() {
|
void RiscV::deactivate() {
|
||||||
if (this->getExecutionState() != TargetExecutionState::RUNNING) {
|
// TODO: Is this "tidy-up" code better placed in the TC? Review after v1.1.0.
|
||||||
this->run();
|
|
||||||
|
if (this->getExecutionState() != TargetExecutionState::STOPPED) {
|
||||||
|
this->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->clearAllBreakpoints();
|
||||||
|
this->run();
|
||||||
this->riscVDebugInterface->deactivate();
|
this->riscVDebugInterface->deactivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +96,11 @@ namespace Targets::RiscV
|
|||||||
this->targetDescriptionFile.targetPadDescriptorsByKey(),
|
this->targetDescriptionFile.targetPadDescriptorsByKey(),
|
||||||
this->targetDescriptionFile.targetPinoutDescriptorsByKey(),
|
this->targetDescriptionFile.targetPinoutDescriptorsByKey(),
|
||||||
this->targetDescriptionFile.targetVariantDescriptorsByKey(),
|
this->targetDescriptionFile.targetVariantDescriptorsByKey(),
|
||||||
{} // TODO: populate this
|
BreakpointResources{
|
||||||
|
this->riscVDebugInterface->getHardwareBreakpointCount(),
|
||||||
|
std::nullopt,
|
||||||
|
static_cast<std::uint16_t>(this->targetConfig.reserveSteppingBreakpoint ? 1 : 0)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Copy the RISC-V CPU register address space and peripheral descriptor
|
// Copy the RISC-V CPU register address space and peripheral descriptor
|
||||||
@@ -126,23 +134,23 @@ namespace Targets::RiscV
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RiscV::setSoftwareBreakpoint(TargetMemoryAddress address) {
|
void RiscV::setSoftwareBreakpoint(TargetMemoryAddress address) {
|
||||||
|
throw Exceptions::Exception{"TARGET - SW breakpoints not supported"};
|
||||||
}
|
}
|
||||||
|
|
||||||
void RiscV::removeSoftwareBreakpoint(TargetMemoryAddress address) {
|
void RiscV::removeSoftwareBreakpoint(TargetMemoryAddress address) {
|
||||||
|
throw Exceptions::Exception{"TARGET - SW breakpoints not supported"};
|
||||||
}
|
}
|
||||||
|
|
||||||
void RiscV::setHardwareBreakpoint(TargetMemoryAddress address) {
|
void RiscV::setHardwareBreakpoint(TargetMemoryAddress address) {
|
||||||
|
this->riscVDebugInterface->setHardwareBreakpoint(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RiscV::removeHardwareBreakpoint(TargetMemoryAddress address) {
|
void RiscV::removeHardwareBreakpoint(TargetMemoryAddress address) {
|
||||||
|
this->riscVDebugInterface->clearHardwareBreakpoint(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RiscV::clearAllBreakpoints() {
|
void RiscV::clearAllBreakpoints() {
|
||||||
|
this->riscVDebugInterface->clearAllBreakpoints();
|
||||||
}
|
}
|
||||||
|
|
||||||
TargetRegisterDescriptorAndValuePairs RiscV::readRegisters(const TargetRegisterDescriptors& descriptors) {
|
TargetRegisterDescriptorAndValuePairs RiscV::readRegisters(const TargetRegisterDescriptors& descriptors) {
|
||||||
|
|||||||
Reference in New Issue
Block a user