Tidying RISC-V register structs

- Removed unnecessary bit fields
- Added default values to members
- Removed all user-defined constructors to make the structs aggregate, replacing the from-value constructor with a `fromValue()` status member function.
- Made use of designated initialisation
- Changed unscoped enums to scoped
- Other small bits of tidying
This commit is contained in:
Nav
2024-10-16 21:22:16 +01:00
parent 17b90e3c08
commit 348ec19c1b
16 changed files with 338 additions and 378 deletions

View File

@@ -22,7 +22,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec::DebugModule
BUSY = 0x03, BUSY = 0x03,
}; };
enum AbstractCommandError: std::uint8_t enum class AbstractCommandError: std::uint8_t
{ {
NONE = 0x00, NONE = 0x00,
BUSY = 0x01, BUSY = 0x01,

View File

@@ -9,7 +9,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec::DebugModule::Registers
{ {
struct AbstractCommandRegister struct AbstractCommandRegister
{ {
enum CommandType: std::uint8_t enum class CommandType: std::uint8_t
{ {
REGISTER_ACCESS = 0x00, REGISTER_ACCESS = 0x00,
QUICK_ACCESS = 0x01, QUICK_ACCESS = 0x01,
@@ -19,15 +19,12 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec::DebugModule::Registers
std::uint32_t control; std::uint32_t control;
CommandType commandType; CommandType commandType;
constexpr AbstractCommandRegister(std::uint32_t control, CommandType commandType) static constexpr AbstractCommandRegister fromValue(RegisterValue value) {
: control(control) return {
, commandType(commandType) .control = static_cast<std::uint32_t>(value & 0x00FFFFFF),
{} .commandType = static_cast<CommandType>((value >> 24) & 0xFF),
};
constexpr explicit AbstractCommandRegister(RegisterValue registerValue) }
: control(static_cast<std::uint32_t>(registerValue & 0x00FFFFFF))
, commandType(static_cast<CommandType>((registerValue >> 24) & 0xFF))
{}
[[nodiscard]] constexpr RegisterValue value() const { [[nodiscard]] constexpr RegisterValue value() const {
assert(this->control <= 0x00FFFFFF); assert(this->control <= 0x00FFFFFF);

View File

@@ -8,27 +8,29 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec::DebugModule::Registers
{ {
struct AbstractControlStatusRegister struct AbstractControlStatusRegister
{ {
std::uint8_t dataCount:4; std::uint8_t dataCount = 0;
AbstractCommandError commandError:3; AbstractCommandError commandError = AbstractCommandError::NONE;
bool relaxedPrivilege:1; bool relaxedPrivilege = false;
bool busy:1; bool busy = false;
std::uint8_t programBufferSize:5; std::uint8_t programBufferSize = 0;
constexpr explicit AbstractControlStatusRegister(RegisterValue registerValue) static constexpr AbstractControlStatusRegister fromValue(RegisterValue value) {
: dataCount(static_cast<std::uint8_t>(registerValue & 0x0F)) return {
, commandError(static_cast<AbstractCommandError>((registerValue >> 8) & 0x07)) .dataCount = static_cast<std::uint8_t>(value & 0x0F),
, relaxedPrivilege(static_cast<bool>(registerValue & (0x01 << 11))) .commandError = static_cast<AbstractCommandError>((value >> 8) & 0x07),
, busy(static_cast<bool>(registerValue & (0x01 << 12))) .relaxedPrivilege = static_cast<bool>(value & (0x01 << 11)),
, programBufferSize(static_cast<std::uint8_t>((registerValue >> 24) & 0x1F)) .busy = static_cast<bool>(value & (0x01 << 12)),
{} .programBufferSize = static_cast<std::uint8_t>((value >> 24) & 0x1F),
};
}
[[nodiscard]] constexpr RegisterValue value() const { [[nodiscard]] constexpr RegisterValue value() const {
return RegisterValue{0} return RegisterValue{0}
| static_cast<RegisterValue>(this->dataCount) | static_cast<RegisterValue>(this->dataCount & 0x0F)
| static_cast<RegisterValue>(this->commandError) << 8 | static_cast<RegisterValue>(this->commandError) << 8
| static_cast<RegisterValue>(this->relaxedPrivilege) << 11 | static_cast<RegisterValue>(this->relaxedPrivilege) << 11
| static_cast<RegisterValue>(this->busy) << 12 | static_cast<RegisterValue>(this->busy) << 12
| static_cast<RegisterValue>(this->programBufferSize) << 24 | static_cast<RegisterValue>(this->programBufferSize & 0x1F) << 24
; ;
} }

View File

@@ -9,43 +9,50 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec::DebugModule::Registers
{ {
struct ControlRegister struct ControlRegister
{ {
enum HartSelectionMode: std::uint8_t enum class HartSelectionMode: std::uint8_t
{ {
SINGLE = 0x00, SINGLE = 0x00,
MULTI = 0x01, MULTI = 0x01,
}; };
bool debugModuleActive:1 = false; bool debugModuleActive = false;
bool ndmReset:1 = false; bool ndmReset = false;
bool clearResetHaltRequest:1 = false; bool clearResetHaltRequest = false;
bool setResetHaltRequest:1 = false; bool setResetHaltRequest = false;
bool clearKeepAlive:1 = false; bool clearKeepAlive = false;
bool setKeepAlive:1 = false; bool setKeepAlive = false;
HartIndex selectedHartIndex = 0; HartIndex selectedHartIndex = 0;
HartSelectionMode hartSelectionMode:1 = HartSelectionMode::SINGLE; HartSelectionMode hartSelectionMode = HartSelectionMode::SINGLE;
bool acknowledgeUnavailableHarts:1 = false; bool acknowledgeUnavailableHarts = false;
bool acknowledgeHaveReset:1 = false; bool acknowledgeHaveReset = false;
bool hartReset:1 = false; bool hartReset = false;
bool resumeRequest:1 = false; bool resumeRequest = false;
bool haltRequest:1 = false; bool haltRequest = false;
ControlRegister() = default; /**
* These `fromValue()` functions cannot be constructors because we'd lose designated initialisation (as the
constexpr explicit ControlRegister(RegisterValue registerValue) * structs would no longer be aggregates - structs with user-defined constructors cannot be aggregates).
: debugModuleActive(static_cast<bool>(registerValue & 0x01)) *
, ndmReset(static_cast<bool>(registerValue & (0x01 << 1))) * @param value
, clearResetHaltRequest(static_cast<bool>(registerValue & (0x01 << 2))) * @return
, setResetHaltRequest(static_cast<bool>(registerValue & (0x01 << 3))) */
, clearKeepAlive(static_cast<bool>(registerValue & (0x01 << 4))) static constexpr auto fromValue(RegisterValue value) {
, setKeepAlive(static_cast<bool>(registerValue & (0x01 << 5))) return ControlRegister{
, selectedHartIndex((((registerValue >> 6) & 0x3FF) << 10) | ((registerValue >> 16) & 0x3FF)) .debugModuleActive = static_cast<bool>(value & 0x01),
, hartSelectionMode(static_cast<HartSelectionMode>(registerValue & (0x01 << 26))) .ndmReset = static_cast<bool>(value & (0x01 << 1)),
, acknowledgeUnavailableHarts(static_cast<bool>(registerValue & (0x01 << 27))) .clearResetHaltRequest = static_cast<bool>(value & (0x01 << 2)),
, acknowledgeHaveReset(static_cast<bool>(registerValue & (0x01 << 28))) .setResetHaltRequest = static_cast<bool>(value & (0x01 << 3)),
, hartReset(static_cast<bool>(registerValue & (0x01 << 29))) .clearKeepAlive = static_cast<bool>(value & (0x01 << 4)),
, resumeRequest(static_cast<bool>(registerValue & (0x01 << 30))) .setKeepAlive = static_cast<bool>(value & (0x01 << 5)),
, haltRequest(static_cast<bool>(registerValue & static_cast<std::uint32_t>(0x01 << 31))) .selectedHartIndex = (((value >> 6) & 0x3FF) << 10) | ((value >> 16) & 0x3FF),
{} .hartSelectionMode = static_cast<HartSelectionMode>(value & (0x01 << 26)),
.acknowledgeUnavailableHarts = static_cast<bool>(value & (0x01 << 27)),
.acknowledgeHaveReset = static_cast<bool>(value & (0x01 << 28)),
.hartReset = static_cast<bool>(value & (0x01 << 29)),
.resumeRequest = static_cast<bool>(value & (0x01 << 30)),
.haltRequest = static_cast<bool>(value & static_cast<std::uint32_t>(0x01 << 31)),
};
}
[[nodiscard]] constexpr RegisterValue value() const { [[nodiscard]] constexpr RegisterValue value() const {
assert(this->selectedHartIndex <= 0xFFFFF); assert(this->selectedHartIndex <= 0xFFFFF);

View File

@@ -17,29 +17,19 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec::DebugModule::Registers
SIZE_128 = 0x04, SIZE_128 = 0x04,
}; };
bool write:1; bool write = false;
bool postIncrement:1; bool postIncrement = false;
MemorySize size:3; MemorySize size = MemorySize::SIZE_8;
bool virtualAddress:1; bool virtualAddress = false;
constexpr MemoryAccessControlField( static constexpr auto fromValue(std::uint32_t value) {
bool write, return MemoryAccessControlField{
bool postIncrement, .write = static_cast<bool>(value & (0x01 << 16)),
MemorySize size, .postIncrement = static_cast<bool>(value & (0x01 << 19)),
bool virtualAddress .size = static_cast<MemorySize>((value >> 20) & 0x07),
) .virtualAddress = static_cast<bool>(value & (0x01 << 23)),
: write(write) };
, postIncrement(postIncrement) }
, size(size)
, virtualAddress(virtualAddress)
{}
constexpr explicit MemoryAccessControlField(std::uint32_t controlValue)
: write(static_cast<bool>(controlValue & (0x01 << 16)))
, postIncrement(static_cast<bool>(controlValue & (0x01 << 19)))
, size(static_cast<MemorySize>((controlValue >> 20) & 0x07))
, virtualAddress(static_cast<bool>(controlValue & (0x01 << 23)))
{}
[[nodiscard]] constexpr std::uint32_t value() const { [[nodiscard]] constexpr std::uint32_t value() const {
return std::uint32_t{0} return std::uint32_t{0}

View File

@@ -15,37 +15,23 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec::DebugModule::Registers
SIZE_128 = 0x04, SIZE_128 = 0x04,
}; };
RegisterNumber registerNumber; RegisterNumber registerNumber = 0;
bool write:1; bool write = false;
bool transfer:1; bool transfer = false;
bool postExecute:1; bool postExecute = false;
bool postIncrement:1; bool postIncrement = false;
RegisterSize size:3; RegisterSize size = RegisterSize::SIZE_32;
RegisterAccessControlField( static constexpr auto fromValue(std::uint32_t value) {
RegisterNumber registerNumber, return RegisterAccessControlField{
bool write, .registerNumber = static_cast<RegisterNumber>(value & 0xFFFF),
bool transfer, .write = static_cast<bool>(value & (0x01 << 16)),
bool postExecute, .transfer = static_cast<bool>(value & (0x01 << 17)),
bool postIncrement, .postExecute = static_cast<bool>(value & (0x01 << 18)),
RegisterSize size .postIncrement = static_cast<bool>(value & (0x01 << 19)),
) .size = static_cast<RegisterSize>((value >> 20) & 0x07),
: registerNumber(registerNumber) };
, write(write) }
, transfer(transfer)
, postExecute(postExecute)
, postIncrement(postIncrement)
, size(size)
{}
constexpr explicit RegisterAccessControlField(std::uint32_t controlValue)
: registerNumber(static_cast<RegisterNumber>(controlValue & 0xFFFF))
, write(static_cast<bool>(controlValue & (0x01 << 16)))
, transfer(static_cast<bool>(controlValue & (0x01 << 17)))
, postExecute(static_cast<bool>(controlValue & (0x01 << 18)))
, postIncrement(static_cast<bool>(controlValue & (0x01 << 19)))
, size(static_cast<RegisterSize>((controlValue >> 20) & 0x07))
{}
[[nodiscard]] constexpr std::uint32_t value() const { [[nodiscard]] constexpr std::uint32_t value() const {
return std::uint32_t{0} return std::uint32_t{0}

View File

@@ -8,53 +8,55 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec::DebugModule::Registers
{ {
struct StatusRegister struct StatusRegister
{ {
std::uint8_t version:4; std::uint8_t version = 0;
bool validConfigStructurePointer:1; bool validConfigStructurePointer = false;
bool supportsResetHalt:1; bool supportsResetHalt = false;
bool authBusy:1; bool authBusy = false;
bool authenticated:1; bool authenticated = false;
bool anyHalted:1; bool anyHalted = false;
bool allHalted:1; bool allHalted = false;
bool anyRunning:1; bool anyRunning = false;
bool allRunning:1; bool allRunning = false;
bool anyUnavailable:1; bool anyUnavailable = false;
bool allUnavailable:1; bool allUnavailable = false;
bool anyNonExistent:1; bool anyNonExistent = false;
bool allNonExistent:1; bool allNonExistent = false;
bool anyResumeAcknowledge:1; bool anyResumeAcknowledge = false;
bool allResumeAcknowledge:1; bool allResumeAcknowledge = false;
bool anyHaveReset:1; bool anyHaveReset = false;
bool allHaveReset:1; bool allHaveReset = false;
bool implicitBreak:1; bool implicitBreak = false;
bool stickyUnavailableBits:1; bool stickyUnavailableBits = false;
bool ndmResetPending:1; bool ndmResetPending = false;
constexpr explicit StatusRegister(RegisterValue registerValue) static constexpr StatusRegister fromValue(RegisterValue value) {
: version(static_cast<std::uint8_t>(registerValue & 0x0F)) return {
, validConfigStructurePointer(static_cast<bool>(registerValue & (0x01 << 4))) .version = static_cast<std::uint8_t>(value & 0x0F),
, supportsResetHalt(static_cast<bool>(registerValue & (0x01 << 5))) .validConfigStructurePointer = static_cast<bool>(value & (0x01 << 4)),
, authBusy(static_cast<bool>(registerValue & (0x01 << 6))) .supportsResetHalt = static_cast<bool>(value & (0x01 << 5)),
, authenticated(static_cast<bool>(registerValue & (0x01 << 7))) .authBusy = static_cast<bool>(value & (0x01 << 6)),
, anyHalted(static_cast<bool>(registerValue & (0x01 << 8))) .authenticated = static_cast<bool>(value & (0x01 << 7)),
, allHalted(static_cast<bool>(registerValue & (0x01 << 9))) .anyHalted = static_cast<bool>(value & (0x01 << 8)),
, anyRunning(static_cast<bool>(registerValue & (0x01 << 10))) .allHalted = static_cast<bool>(value & (0x01 << 9)),
, allRunning(static_cast<bool>(registerValue & (0x01 << 11))) .anyRunning = static_cast<bool>(value & (0x01 << 10)),
, anyUnavailable(static_cast<bool>(registerValue & (0x01 << 12))) .allRunning = static_cast<bool>(value & (0x01 << 11)),
, allUnavailable(static_cast<bool>(registerValue & (0x01 << 13))) .anyUnavailable = static_cast<bool>(value & (0x01 << 12)),
, anyNonExistent(static_cast<bool>(registerValue & (0x01 << 14))) .allUnavailable = static_cast<bool>(value & (0x01 << 13)),
, allNonExistent(static_cast<bool>(registerValue & (0x01 << 15))) .anyNonExistent = static_cast<bool>(value & (0x01 << 14)),
, anyResumeAcknowledge(static_cast<bool>(registerValue & (0x01 << 16))) .allNonExistent = static_cast<bool>(value & (0x01 << 15)),
, allResumeAcknowledge(static_cast<bool>(registerValue & (0x01 << 17))) .anyResumeAcknowledge = static_cast<bool>(value & (0x01 << 16)),
, anyHaveReset(static_cast<bool>(registerValue & (0x01 << 18))) .allResumeAcknowledge = static_cast<bool>(value & (0x01 << 17)),
, allHaveReset(static_cast<bool>(registerValue & (0x01 << 19))) .anyHaveReset = static_cast<bool>(value & (0x01 << 18)),
, implicitBreak(static_cast<bool>(registerValue & (0x01 << 22))) .allHaveReset = static_cast<bool>(value & (0x01 << 19)),
, stickyUnavailableBits(static_cast<bool>(registerValue & (0x01 << 23))) .implicitBreak = static_cast<bool>(value & (0x01 << 22)),
, ndmResetPending(static_cast<bool>(registerValue & (0x01 << 24))) .stickyUnavailableBits = static_cast<bool>(value & (0x01 << 23)),
{} .ndmResetPending = static_cast<bool>(value & (0x01 << 24)),
};
}
[[nodiscard]] constexpr RegisterValue value() const { [[nodiscard]] constexpr RegisterValue value() const {
return RegisterValue{0} return RegisterValue{0}
| static_cast<RegisterValue>(this->version) | static_cast<RegisterValue>(this->version & 0x0F)
| static_cast<RegisterValue>(this->validConfigStructurePointer) << 4 | static_cast<RegisterValue>(this->validConfigStructurePointer) << 4
| static_cast<RegisterValue>(this->supportsResetHalt) << 5 | static_cast<RegisterValue>(this->supportsResetHalt) << 5
| static_cast<RegisterValue>(this->authBusy) << 6 | static_cast<RegisterValue>(this->authBusy) << 6

View File

@@ -62,7 +62,6 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
void DebugTranslator::init() { void DebugTranslator::init() {
// No pre-activation initialisation required. // No pre-activation initialisation required.
return;
} }
void DebugTranslator::activate() { void DebugTranslator::activate() {
@@ -126,18 +125,19 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
} }
void DebugTranslator::stop() { void DebugTranslator::stop() {
auto controlRegister = ControlRegister{}; auto controlRegister = ControlRegister{
controlRegister.debugModuleActive = true; .debugModuleActive = true,
controlRegister.selectedHartIndex = this->selectedHartIndex; .selectedHartIndex = this->selectedHartIndex,
controlRegister.haltRequest = true; .haltRequest = true,
};
this->writeDebugModuleControlRegister(controlRegister); this->writeDebugModuleControlRegister(controlRegister);
auto statusRegister = this->readDebugModuleStatusRegister(); auto statusRegister = this->readDebugModuleStatusRegister();
for ( for (
auto attempts = 1; auto attempts = 0;
!statusRegister.allHalted !statusRegister.allHalted
&& (DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY * attempts) < this->config.targetResponseTimeout; && (DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY * attempts) <= this->config.targetResponseTimeout;
++attempts ++attempts
) { ) {
std::this_thread::sleep_for(DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY); std::this_thread::sleep_for(DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY);
@@ -153,18 +153,19 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
} }
void DebugTranslator::run() { void DebugTranslator::run() {
auto controlRegister = ControlRegister{}; auto controlRegister = ControlRegister{
controlRegister.debugModuleActive = true; .debugModuleActive = true,
controlRegister.selectedHartIndex = this->selectedHartIndex; .selectedHartIndex = this->selectedHartIndex,
controlRegister.resumeRequest = true; .resumeRequest = true,
};
this->writeDebugModuleControlRegister(controlRegister); this->writeDebugModuleControlRegister(controlRegister);
auto statusRegister = this->readDebugModuleStatusRegister(); auto statusRegister = this->readDebugModuleStatusRegister();
for ( for (
auto attempts = 1; auto attempts = 0;
!statusRegister.allResumeAcknowledge !statusRegister.allResumeAcknowledge
&& (DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY * attempts) < this->config.targetResponseTimeout; && (DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY * attempts) <= this->config.targetResponseTimeout;
++attempts ++attempts
) { ) {
std::this_thread::sleep_for(DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY); std::this_thread::sleep_for(DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY);
@@ -175,6 +176,8 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
this->writeDebugModuleControlRegister(controlRegister); this->writeDebugModuleControlRegister(controlRegister);
if (!statusRegister.allResumeAcknowledge) { if (!statusRegister.allResumeAcknowledge) {
Logger::debug("Failed to resume target execution - stopping target");
this->stop();
throw Exceptions::Exception{"Target took too long to acknowledge resume request"}; throw Exceptions::Exception{"Target took too long to acknowledge resume request"};
} }
} }
@@ -185,10 +188,11 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
this->writeDebugControlStatusRegister(debugControlStatusRegister); this->writeDebugControlStatusRegister(debugControlStatusRegister);
auto controlRegister = ControlRegister{}; auto controlRegister = ControlRegister{
controlRegister.debugModuleActive = true; .debugModuleActive = true,
controlRegister.selectedHartIndex = this->selectedHartIndex; .selectedHartIndex = this->selectedHartIndex,
controlRegister.resumeRequest = true; .resumeRequest = true,
};
this->writeDebugModuleControlRegister(controlRegister); this->writeDebugModuleControlRegister(controlRegister);
@@ -200,12 +204,13 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
} }
void DebugTranslator::reset() { void DebugTranslator::reset() {
auto controlRegister = ControlRegister{}; auto controlRegister = ControlRegister{
controlRegister.debugModuleActive = true; .debugModuleActive = true,
controlRegister.selectedHartIndex = this->selectedHartIndex; .ndmReset = true,
controlRegister.setResetHaltRequest = true; .setResetHaltRequest = true,
controlRegister.haltRequest = true; .selectedHartIndex = this->selectedHartIndex,
controlRegister.ndmReset = true; .haltRequest = true,
};
this->writeDebugModuleControlRegister(controlRegister); this->writeDebugModuleControlRegister(controlRegister);
@@ -214,22 +219,21 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
auto statusRegister = this->readDebugModuleStatusRegister(); auto statusRegister = this->readDebugModuleStatusRegister();
for ( for (
auto attempts = 1; auto attempts = 0;
!statusRegister.allHaveReset !statusRegister.allHaveReset
&& (DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY * attempts) < this->config.targetResponseTimeout; && (DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY * attempts) <= this->config.targetResponseTimeout;
++attempts ++attempts
) { ) {
std::this_thread::sleep_for(DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY); std::this_thread::sleep_for(DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY);
statusRegister = this->readDebugModuleStatusRegister(); statusRegister = this->readDebugModuleStatusRegister();
} }
controlRegister = ControlRegister{}; this->writeDebugModuleControlRegister(ControlRegister{
controlRegister.debugModuleActive = true; .debugModuleActive = true,
controlRegister.selectedHartIndex = this->selectedHartIndex; .clearResetHaltRequest = true,
controlRegister.clearResetHaltRequest = true; .selectedHartIndex = this->selectedHartIndex,
controlRegister.acknowledgeHaveReset = true; .acknowledgeHaveReset = true,
});
this->writeDebugModuleControlRegister(controlRegister);
if (!statusRegister.allHaveReset) { if (!statusRegister.allHaveReset) {
throw Exceptions::Exception{"Target took too long to reset"}; throw Exceptions::Exception{"Target took too long to reset"};
@@ -258,7 +262,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
const auto& triggerDescriptor = triggerDescriptorOpt->get(); const auto& triggerDescriptor = triggerDescriptorOpt->get();
Logger::debug( Logger::debug(
"Installing hardware BP at address " + Services::StringService::toHex(address) + " with trigger index " "Installing hardware BP at address 0x" + Services::StringService::toHex(address) + " with trigger index "
+ std::to_string(triggerDescriptor.index) + std::to_string(triggerDescriptor.index)
); );
@@ -270,16 +274,18 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
TriggerModule::Registers::TriggerSelect{triggerDescriptor.index}.value() TriggerModule::Registers::TriggerSelect{triggerDescriptor.index}.value()
); );
auto matchControlRegister = MatchControl{}; this->writeCpuRegister(
matchControlRegister.execute = true; CpuRegisterNumber::TRIGGER_DATA_1,
matchControlRegister.enabledInUserMode = true; MatchControl{
matchControlRegister.enabledInSupervisorMode = true; .execute = true,
matchControlRegister.enabledInMachineMode = true; .enabledInUserMode = true,
matchControlRegister.action = TriggerModule::TriggerAction::ENTER_DEBUG_MODE; .enabledInSupervisorMode = true,
matchControlRegister.accessSize = MatchControl::AccessSize::ANY; .enabledInMachineMode = true,
matchControlRegister.compareValueType = MatchControl::CompareValueType::ADDRESS; .action = TriggerModule::TriggerAction::ENTER_DEBUG_MODE,
.accessSize = MatchControl::AccessSize::ANY,
this->writeCpuRegister(CpuRegisterNumber::TRIGGER_DATA_1, matchControlRegister.value()); .compareValueType = MatchControl::CompareValueType::ADDRESS,
}.value()
);
this->writeCpuRegister(CpuRegisterNumber::TRIGGER_DATA_2, address); this->writeCpuRegister(CpuRegisterNumber::TRIGGER_DATA_2, address);
this->allocatedTriggerIndices.emplace(triggerDescriptor.index); this->allocatedTriggerIndices.emplace(triggerDescriptor.index);
@@ -305,7 +311,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
void DebugTranslator::clearAllHardwareBreakpoints() { void DebugTranslator::clearAllHardwareBreakpoints() {
// To ensure that any untracked breakpoints are cleared, we clear all triggers on the target. // To ensure that any untracked breakpoints are cleared, we clear all triggers on the target.
for (const auto [triggerIndex, triggerDescriptor] : this->triggerDescriptorsByIndex) { for (const auto& [triggerIndex, triggerDescriptor] : this->triggerDescriptorsByIndex) {
this->clearTrigger(triggerDescriptor); this->clearTrigger(triggerDescriptor);
} }
@@ -386,13 +392,11 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
this->dtmInterface.writeDebugModuleRegister(RegisterAddress::ABSTRACT_DATA_1, startAddress); this->dtmInterface.writeDebugModuleRegister(RegisterAddress::ABSTRACT_DATA_1, startAddress);
constexpr auto command = AbstractCommandRegister{ constexpr auto command = AbstractCommandRegister{
MemoryAccessControlField{ .control = MemoryAccessControlField{
false, .postIncrement = true,
true, .size = MemoryAccessControlField::MemorySize::SIZE_32,
MemoryAccessControlField::MemorySize::SIZE_32,
false
}.value(), }.value(),
AbstractCommandRegister::CommandType::MEMORY_ACCESS .commandType = AbstractCommandRegister::CommandType::MEMORY_ACCESS
}; };
for (auto address = startAddress; address <= (startAddress + bytes - 1); address += 4) { for (auto address = startAddress; address <= (startAddress + bytes - 1); address += 4) {
@@ -460,13 +464,12 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
this->dtmInterface.writeDebugModuleRegister(RegisterAddress::ABSTRACT_DATA_1, startAddress); this->dtmInterface.writeDebugModuleRegister(RegisterAddress::ABSTRACT_DATA_1, startAddress);
constexpr auto command = AbstractCommandRegister{ constexpr auto command = AbstractCommandRegister{
MemoryAccessControlField{ .control = MemoryAccessControlField{
true, .write = true,
true, .postIncrement = true,
MemoryAccessControlField::MemorySize::SIZE_32, .size = MemoryAccessControlField::MemorySize::SIZE_32,
false
}.value(), }.value(),
AbstractCommandRegister::CommandType::MEMORY_ACCESS .commandType = AbstractCommandRegister::CommandType::MEMORY_ACCESS
}; };
for (TargetMemoryAddress offset = 0; offset < buffer.size(); offset += 4) { for (TargetMemoryAddress offset = 0; offset < buffer.size(); offset += 4) {
@@ -491,11 +494,10 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
* We can obtain the maximum hart index by setting all of the hartsel bits in the control register and then * We can obtain the maximum hart index by setting all of the hartsel bits in the control register and then
* read the value back. * read the value back.
*/ */
auto controlRegister = ControlRegister{}; this->writeDebugModuleControlRegister(
controlRegister.debugModuleActive = true; ControlRegister{.debugModuleActive = true, .selectedHartIndex = 0xFFFFF}
controlRegister.selectedHartIndex = 0xFFFFF; );
this->writeDebugModuleControlRegister(controlRegister);
const auto maxHartIndex = this->readDebugModuleControlRegister().selectedHartIndex; const auto maxHartIndex = this->readDebugModuleControlRegister().selectedHartIndex;
for (auto hartIndex = DebugModule::HartIndex{0}; hartIndex <= maxHartIndex; ++hartIndex) { for (auto hartIndex = DebugModule::HartIndex{0}; hartIndex <= maxHartIndex; ++hartIndex) {
@@ -503,11 +505,9 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
* We can't just assume that everything between 0 and the maximum hart index are valid hart indices. We * We can't just assume that everything between 0 and the maximum hart index are valid hart indices. We
* have to test each index until we find one that is non-existent. * have to test each index until we find one that is non-existent.
*/ */
auto controlRegister = ControlRegister{}; this->writeDebugModuleControlRegister(
controlRegister.debugModuleActive = true; ControlRegister{.debugModuleActive = true, .selectedHartIndex = hartIndex}
controlRegister.selectedHartIndex = hartIndex; );
this->writeDebugModuleControlRegister(controlRegister);
/* /*
* It's worth noting that some RISC-V targets **do not** set the non-existent flags. I'm not sure why. * It's worth noting that some RISC-V targets **do not** set the non-existent flags. I'm not sure why.
@@ -544,7 +544,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
if (writeSelectError != DebugModule::AbstractCommandError::NONE) { if (writeSelectError != DebugModule::AbstractCommandError::NONE) {
throw Exceptions::Exception{ throw Exceptions::Exception{
"Failed to write to TRIGGER_SELECT register - abstract command error: 0x" "Failed to write to TRIGGER_SELECT register - abstract command error: 0x"
+ Services::StringService::toHex(writeSelectError) + Services::StringService::toHex(static_cast<std::uint8_t>(writeSelectError))
}; };
} }
@@ -552,9 +552,9 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
break; break;
} }
const auto infoReg = TriggerModule::Registers::TriggerInfo{ const auto infoReg = TriggerModule::Registers::TriggerInfo::fromValue(
this->readCpuRegister(CpuRegisterNumber::TRIGGER_INFO) this->readCpuRegister(CpuRegisterNumber::TRIGGER_INFO)
}; );
if (infoReg.info == 0x01) { if (infoReg.info == 0x01) {
// Trigger doesn't exist // Trigger doesn't exist
@@ -564,9 +564,9 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
auto supportedTypes = infoReg.getSupportedTriggerTypes(); auto supportedTypes = infoReg.getSupportedTriggerTypes();
if (supportedTypes.empty()) { if (supportedTypes.empty()) {
// The trigger info register has no trigger type info. Try the data1 register. // The trigger info register has no trigger type info. Try the data1 register.
const auto data1Reg = TriggerModule::Registers::TriggerData1{ const auto data1Reg = TriggerModule::Registers::TriggerData1::fromValue(
this->readCpuRegister(CpuRegisterNumber::TRIGGER_DATA_1) this->readCpuRegister(CpuRegisterNumber::TRIGGER_DATA_1)
}; );
const auto triggerType = data1Reg.getType(); const auto triggerType = data1Reg.getType();
if (!triggerType.has_value()) { if (!triggerType.has_value()) {
@@ -584,37 +584,40 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
} }
ControlRegister DebugTranslator::readDebugModuleControlRegister() { ControlRegister DebugTranslator::readDebugModuleControlRegister() {
return ControlRegister{this->dtmInterface.readDebugModuleRegister(RegisterAddress::CONTROL_REGISTER)}; return ControlRegister::fromValue(
this->dtmInterface.readDebugModuleRegister(RegisterAddress::CONTROL_REGISTER)
);
} }
StatusRegister DebugTranslator::readDebugModuleStatusRegister() { StatusRegister DebugTranslator::readDebugModuleStatusRegister() {
return StatusRegister{this->dtmInterface.readDebugModuleRegister(RegisterAddress::STATUS_REGISTER)}; return StatusRegister::fromValue(this->dtmInterface.readDebugModuleRegister(RegisterAddress::STATUS_REGISTER));
} }
AbstractControlStatusRegister DebugTranslator::readDebugModuleAbstractControlStatusRegister() { AbstractControlStatusRegister DebugTranslator::readDebugModuleAbstractControlStatusRegister() {
return AbstractControlStatusRegister{ return AbstractControlStatusRegister::fromValue(
this->dtmInterface.readDebugModuleRegister(RegisterAddress::ABSTRACT_CONTROL_STATUS_REGISTER) this->dtmInterface.readDebugModuleRegister(RegisterAddress::ABSTRACT_CONTROL_STATUS_REGISTER)
}; );
} }
DebugControlStatusRegister DebugTranslator::readDebugControlStatusRegister() { DebugControlStatusRegister DebugTranslator::readDebugControlStatusRegister() {
return DebugControlStatusRegister{ return DebugControlStatusRegister::fromValue(
this->readCpuRegister(static_cast<RegisterNumber>(CpuRegisterNumber::DEBUG_CONTROL_STATUS_REGISTER)) this->readCpuRegister(static_cast<RegisterNumber>(CpuRegisterNumber::DEBUG_CONTROL_STATUS_REGISTER))
}; );
} }
void DebugTranslator::enableDebugModule() { void DebugTranslator::enableDebugModule() {
auto controlRegister = ControlRegister{}; auto controlRegister = ControlRegister{
controlRegister.debugModuleActive = true; .debugModuleActive = true,
controlRegister.selectedHartIndex = this->selectedHartIndex; .selectedHartIndex = this->selectedHartIndex
};
this->writeDebugModuleControlRegister(controlRegister); this->writeDebugModuleControlRegister(controlRegister);
controlRegister = this->readDebugModuleControlRegister(); controlRegister = this->readDebugModuleControlRegister();
for ( for (
auto attempts = 1; auto attempts = 0;
!controlRegister.debugModuleActive !controlRegister.debugModuleActive
&& (DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY * attempts) < this->config.targetResponseTimeout; && (DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY * attempts) <= this->config.targetResponseTimeout;
++attempts ++attempts
) { ) {
std::this_thread::sleep_for(DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY); std::this_thread::sleep_for(DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY);
@@ -627,17 +630,16 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
} }
void DebugTranslator::disableDebugModule() { void DebugTranslator::disableDebugModule() {
auto controlRegister = ControlRegister{}; this->writeDebugModuleControlRegister(
controlRegister.debugModuleActive = false; ControlRegister{.debugModuleActive = false, .selectedHartIndex = this->selectedHartIndex}
controlRegister.selectedHartIndex = this->selectedHartIndex; );
this->writeDebugModuleControlRegister(controlRegister); auto controlRegister = this->readDebugModuleControlRegister();
controlRegister = this->readDebugModuleControlRegister();
for ( for (
auto attempts = 1; auto attempts = 0;
controlRegister.debugModuleActive controlRegister.debugModuleActive
&& (DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY * attempts) < this->config.targetResponseTimeout; && (DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY * attempts) <= this->config.targetResponseTimeout;
++attempts ++attempts
) { ) {
std::this_thread::sleep_for(DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY); std::this_thread::sleep_for(DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY);
@@ -655,15 +657,12 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
using DebugModule::Registers::RegisterAccessControlField; using DebugModule::Registers::RegisterAccessControlField;
const auto commandError = this->tryExecuteAbstractCommand(AbstractCommandRegister{ const auto commandError = this->tryExecuteAbstractCommand(AbstractCommandRegister{
RegisterAccessControlField{ .control = RegisterAccessControlField{
number, .registerNumber = number,
false, .transfer = true,
true, .size= RegisterAccessControlField::RegisterSize::SIZE_32
false,
false,
RegisterAccessControlField::RegisterSize::SIZE_32
}.value(), }.value(),
AbstractCommandRegister::CommandType::REGISTER_ACCESS .commandType = AbstractCommandRegister::CommandType::REGISTER_ACCESS
}); });
if (commandError != DebugModule::AbstractCommandError::NONE) { if (commandError != DebugModule::AbstractCommandError::NONE) {
@@ -685,7 +684,8 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
if (!result.hasValue()) { if (!result.hasValue()) {
throw Exceptions::Exception{ throw Exceptions::Exception{
"Failed to read CPU register (number: 0x" + Services::StringService::toHex(number) "Failed to read CPU register (number: 0x" + Services::StringService::toHex(number)
+ ") - abstract command error: 0x" + Services::StringService::toHex(result.error()) + ") - abstract command error: 0x"
+ Services::StringService::toHex(static_cast<std::uint8_t>(result.error()))
}; };
} }
@@ -704,15 +704,13 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
this->dtmInterface.writeDebugModuleRegister(RegisterAddress::ABSTRACT_DATA_0, value); this->dtmInterface.writeDebugModuleRegister(RegisterAddress::ABSTRACT_DATA_0, value);
return this->tryExecuteAbstractCommand(AbstractCommandRegister{ return this->tryExecuteAbstractCommand(AbstractCommandRegister{
RegisterAccessControlField{ .control = RegisterAccessControlField{
number, .registerNumber = number,
true, .write = true,
true, .transfer = true,
false, .size = RegisterAccessControlField::RegisterSize::SIZE_32
false,
RegisterAccessControlField::RegisterSize::SIZE_32
}.value(), }.value(),
AbstractCommandRegister::CommandType::REGISTER_ACCESS .commandType = AbstractCommandRegister::CommandType::REGISTER_ACCESS
}); });
} }
@@ -728,7 +726,8 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
if (commandError != DebugModule::AbstractCommandError::NONE) { if (commandError != DebugModule::AbstractCommandError::NONE) {
throw Exceptions::Exception{ throw Exceptions::Exception{
"Failed to write to CPU register (number: 0x" + Services::StringService::toHex(number) "Failed to write to CPU register (number: 0x" + Services::StringService::toHex(number)
+ ") - abstract command error: 0x" + Services::StringService::toHex(commandError) + ") - abstract command error: 0x"
+ Services::StringService::toHex(static_cast<std::uint8_t>(commandError))
}; };
} }
} }
@@ -762,9 +761,9 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
} }
for ( for (
auto attempts = 1; auto attempts = 0;
abstractStatusRegister.busy abstractStatusRegister.busy
&& (DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY * attempts) < this->config.targetResponseTimeout; && (DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY * attempts) <= this->config.targetResponseTimeout;
++attempts ++attempts
) { ) {
std::this_thread::sleep_for(DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY); std::this_thread::sleep_for(DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY);
@@ -784,7 +783,8 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
const auto commandError = this->tryExecuteAbstractCommand(abstractCommandRegister); const auto commandError = this->tryExecuteAbstractCommand(abstractCommandRegister);
if (commandError != DebugModule::AbstractCommandError::NONE) { if (commandError != DebugModule::AbstractCommandError::NONE) {
throw Exceptions::Exception{ throw Exceptions::Exception{
"Failed to execute abstract command - error: 0x" + Services::StringService::toHex(commandError) "Failed to execute abstract command - error: 0x"
+ Services::StringService::toHex(static_cast<std::uint8_t>(commandError))
}; };
} }
} }

View File

@@ -1,11 +1,13 @@
#include "DebugTranslatorConfig.hpp" #include "DebugTranslatorConfig.hpp"
#include <cstdint>
namespace DebugToolDrivers::Protocols::RiscVDebugSpec namespace DebugToolDrivers::Protocols::RiscVDebugSpec
{ {
DebugTranslatorConfig::DebugTranslatorConfig(const YAML::Node& configNode) { DebugTranslatorConfig::DebugTranslatorConfig(const YAML::Node& configNode) {
if (configNode["targetResponseTimeout"]) { if (configNode["targetResponseTimeout"]) {
this->targetResponseTimeout = std::chrono::microseconds{ this->targetResponseTimeout = std::chrono::microseconds{
configNode["targetResponseTimeout"].as<int>(this->targetResponseTimeout.count()) configNode["targetResponseTimeout"].as<std::int64_t>(this->targetResponseTimeout.count())
}; };
} }
} }

View File

@@ -18,41 +18,41 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec::Registers
GROUP = 0x06, GROUP = 0x06,
}; };
PrivilegeMode privilegeMode:2; PrivilegeMode privilegeMode = PrivilegeMode::USER;
bool step:1 = false; bool step = false;
bool nmiPending:1 = false; bool nmiPending = false;
bool mprvEnabled:1 = false; bool mprvEnabled = false;
DebugModeCause debugModeCause:3; DebugModeCause debugModeCause = DebugModeCause::BREAK;
bool stopTime:1 = false; bool stopTime = false;
bool stopCount:1 = false; bool stopCount = false;
bool stepInterruptsEnabled:1 = false; bool stepInterruptsEnabled = false;
bool breakUMode:1 = false; bool breakUMode = false;
bool breakSMode:1 = false; bool breakSMode = false;
bool breakMMode:1 = false; bool breakMMode = false;
bool breakVUMode:1 = false; bool breakVUMode = false;
bool breakVSMode:1 = false; bool breakVSMode = false;
std::uint8_t debugVersion:4 = 0; std::uint8_t debugVersion = 0;
DebugControlStatusRegister() = default; static constexpr auto fromValue(RegisterValue value) {
return DebugControlStatusRegister{
.privilegeMode = static_cast<PrivilegeMode>(value & 0x03),
.step = static_cast<bool>(value & (0x01 << 2)),
.nmiPending = static_cast<bool>(value & (0x01 << 3)),
.mprvEnabled = static_cast<bool>(value & (0x01 << 4)),
.debugModeCause = static_cast<DebugModeCause>((value >> 6) & 0x07),
.stopTime = static_cast<bool>(value & (0x01 << 9)),
.stopCount = static_cast<bool>(value & (0x01 << 10)),
.stepInterruptsEnabled = static_cast<bool>(value & (0x01 << 11)),
.breakUMode = static_cast<bool>(value & (0x01 << 12)),
.breakSMode = static_cast<bool>(value & (0x01 << 13)),
.breakMMode = static_cast<bool>(value & (0x01 << 15)),
.breakVUMode = static_cast<bool>(value & (0x01 << 16)),
.breakVSMode = static_cast<bool>(value & (0x01 << 17)),
.debugVersion = static_cast<std::uint8_t>((value >> 28) & 0x0F)
};
}
constexpr explicit DebugControlStatusRegister(RegisterValue registerValue) [[nodiscard]] constexpr RegisterValue value() const {
: privilegeMode(static_cast<PrivilegeMode>(registerValue & 0x03))
, step(static_cast<bool>(registerValue & (0x01 << 2)))
, nmiPending(static_cast<bool>(registerValue & (0x01 << 3)))
, mprvEnabled(static_cast<bool>(registerValue & (0x01 << 4)))
, debugModeCause(static_cast<DebugModeCause>((registerValue >> 6) & 0x07))
, stopTime(static_cast<bool>(registerValue & (0x01 << 9)))
, stopCount(static_cast<bool>(registerValue & (0x01 << 10)))
, stepInterruptsEnabled(static_cast<bool>(registerValue & (0x01 << 11)))
, breakUMode(static_cast<bool>(registerValue & (0x01 << 12)))
, breakSMode(static_cast<bool>(registerValue & (0x01 << 13)))
, breakMMode(static_cast<bool>(registerValue & (0x01 << 15)))
, breakVUMode(static_cast<bool>(registerValue & (0x01 << 16)))
, breakVSMode(static_cast<bool>(registerValue & (0x01 << 17)))
, debugVersion(static_cast<std::uint8_t>(registerValue >> 28) & 0x0F)
{}
constexpr RegisterValue value() const {
return RegisterValue{0} return RegisterValue{0}
| static_cast<RegisterValue>(this->privilegeMode) | static_cast<RegisterValue>(this->privilegeMode)
| static_cast<RegisterValue>(this->step) << 2 | static_cast<RegisterValue>(this->step) << 2
@@ -67,7 +67,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec::Registers
| static_cast<RegisterValue>(this->breakMMode) << 15 | static_cast<RegisterValue>(this->breakMMode) << 15
| static_cast<RegisterValue>(this->breakVUMode) << 16 | static_cast<RegisterValue>(this->breakVUMode) << 16
| static_cast<RegisterValue>(this->breakVSMode) << 17 | static_cast<RegisterValue>(this->breakVSMode) << 17
| static_cast<RegisterValue>(this->debugVersion) << 28 | static_cast<RegisterValue>(this->debugVersion & 0x0F) << 28
; ;
} }
}; };

View File

@@ -9,8 +9,8 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
enum class PrivilegeMode: std::uint8_t enum class PrivilegeMode: std::uint8_t
{ {
U_MODE = 0x00, USER = 0x00,
S_MODE = 0x01, SUPERVISOR = 0x01,
M_MODE = 0x03, MACHINE = 0x03,
}; };
} }

View File

@@ -37,71 +37,39 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec::TriggerModule::Registers
DATA = 0x01, DATA = 0x01,
}; };
bool load:1 = false; bool load = false;
bool store:1 = false; bool store = false;
bool execute:1 = false; bool execute = false;
bool enabledInUserMode:1 = false; bool enabledInUserMode = false;
bool enabledInSupervisorMode:1 = false; bool enabledInSupervisorMode = false;
bool enabledInMachineMode:1 = false; bool enabledInMachineMode = false;
MatchMode matchMode:4 = MatchMode::EQUAL; MatchMode matchMode = MatchMode::EQUAL;
bool chain:1 = false; // TODO: Consider making this an enum bool chain = false; // TODO: Consider making this an enum
TriggerAction action:4 = TriggerAction::ENTER_DEBUG_MODE; TriggerAction action = TriggerAction::RAISE_BREAKPOINT_EXCEPTION;
AccessSize accessSize = AccessSize::ANY; AccessSize accessSize = AccessSize::ANY;
bool timing:1 = false; // TODO: Consider making this an enum bool timing = false; // TODO: Consider making this an enum
CompareValueType compareValueType:1 = CompareValueType::ADDRESS; CompareValueType compareValueType = CompareValueType::ADDRESS;
bool hit:1 = false; bool hit = false;
MatchControl() = default; static constexpr auto fromValue(RegisterValue value) {
return MatchControl{
constexpr explicit MatchControl( .load = static_cast<bool>(value & 0x01),
bool load, .store = static_cast<bool>(value & (0x01 << 1)),
bool store, .execute = static_cast<bool>(value & (0x01 << 2)),
bool execute, .enabledInUserMode = static_cast<bool>(value & (0x01 << 3)),
bool enabledInUserMode, .enabledInSupervisorMode = static_cast<bool>(value & (0x01 << 4)),
bool enabledInSupervisorMode, .enabledInMachineMode = static_cast<bool>(value & (0x01 << 6)),
bool enabledInMachineMode, .matchMode = static_cast<MatchMode>((value >> 7) & 0x0F),
MatchMode matchMode, .chain = static_cast<bool>(value & (0x01 << 11)),
bool chain, .action = static_cast<TriggerAction>((value >> 12) & 0x0F),
TriggerAction action, .accessSize = static_cast<AccessSize>(
AccessSize accessSize, (((value >> 21) & 0x03) << 2) | ((value >> 16) & 0x03)
bool timing, ),
CompareValueType compareValueType, .timing = static_cast<bool>(value & (0x01 << 18)),
bool hit .compareValueType = static_cast<CompareValueType>((value >> 19) & 0x01),
) .hit = static_cast<bool>(value & (0x01 << 20)),
: 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 { [[nodiscard]] constexpr RegisterValue value() const {
return RegisterValue{0} return RegisterValue{0}

View File

@@ -9,27 +9,27 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec::TriggerModule::Registers
{ {
struct TriggerData1 struct TriggerData1
{ {
std::uint32_t data:27; std::uint32_t data;
bool debugModeOnly:1; bool debugModeOnly;
std::uint8_t type:4; std::uint8_t type;
TriggerData1() = default; static constexpr auto fromValue(RegisterValue value) {
return TriggerData1{
constexpr explicit TriggerData1(RegisterValue registerValue) .data = value & 0x07FFFFFF,
: data(registerValue & 0x07FFFFFF) .debugModeOnly = static_cast<bool>(value & (0x01 << 27)),
, debugModeOnly(static_cast<bool>(registerValue & (0x01 << 27))) .type = static_cast<std::uint8_t>((value >> 28) & 0x0F),
, type(static_cast<std::uint8_t>(registerValue >> 28) & 0x0F) };
{} }
[[nodiscard]] constexpr RegisterValue value() const { [[nodiscard]] constexpr RegisterValue value() const {
return RegisterValue{0} return RegisterValue{0}
| static_cast<RegisterValue>(this->data) | static_cast<RegisterValue>(this->data & 0x07FFFFFF)
| static_cast<RegisterValue>(this->debugModeOnly) << 27 | static_cast<RegisterValue>(this->debugModeOnly) << 27
| static_cast<RegisterValue>(this->type) << 28 | static_cast<RegisterValue>(this->type & 0x0F) << 28
; ;
} }
std::optional<TriggerType> getType() const { [[nodiscard]] std::optional<TriggerType> getType() const {
return (this->type >= 0x01 && this->type <= 0x07) return (this->type >= 0x01 && this->type <= 0x07)
? std::optional{static_cast<TriggerType>(this->type)} ? std::optional{static_cast<TriggerType>(this->type)}
: std::nullopt; : std::nullopt;

View File

@@ -13,10 +13,12 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec::TriggerModule::Registers
std::uint16_t info; std::uint16_t info;
std::uint8_t version; std::uint8_t version;
constexpr explicit TriggerInfo(RegisterValue registerValue) static constexpr auto fromValue(RegisterValue value) {
: info(registerValue & 0xFFFF) return TriggerInfo{
, version(static_cast<std::uint8_t>(registerValue >> 24)) .info = static_cast<std::uint16_t>(value & 0xFFFF),
{} .version = static_cast<std::uint8_t>(value >> 24),
};
}
[[nodiscard]] constexpr RegisterValue value() const { [[nodiscard]] constexpr RegisterValue value() const {
return RegisterValue{0} return RegisterValue{0}
@@ -25,7 +27,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec::TriggerModule::Registers
; ;
} }
std::set<TriggerType> getSupportedTriggerTypes() const { [[nodiscard]] std::set<TriggerType> getSupportedTriggerTypes() const {
auto output = std::set<TriggerType>{}; auto output = std::set<TriggerType>{};
static constexpr auto types = std::to_array<TriggerType>({ static constexpr auto types = std::to_array<TriggerType>({

View File

@@ -6,6 +6,9 @@
namespace DebugToolDrivers::Protocols::RiscVDebugSpec::TriggerModule::Registers namespace DebugToolDrivers::Protocols::RiscVDebugSpec::TriggerModule::Registers
{ {
/**
* TODO: Given the single, full width bit field, is this struct really necessary? Review.
*/
struct TriggerSelect struct TriggerSelect
{ {
TriggerIndex index; TriggerIndex index;

View File

@@ -22,6 +22,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec::TriggerModule
enum class TriggerAction: std::uint8_t enum class TriggerAction: std::uint8_t
{ {
RAISE_BREAKPOINT_EXCEPTION = 0x00,
ENTER_DEBUG_MODE = 0x01, ENTER_DEBUG_MODE = 0x01,
}; };
} }