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,
};
enum AbstractCommandError: std::uint8_t
enum class AbstractCommandError: std::uint8_t
{
NONE = 0x00,
BUSY = 0x01,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -62,7 +62,6 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
void DebugTranslator::init() {
// No pre-activation initialisation required.
return;
}
void DebugTranslator::activate() {
@@ -126,18 +125,19 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
}
void DebugTranslator::stop() {
auto controlRegister = ControlRegister{};
controlRegister.debugModuleActive = true;
controlRegister.selectedHartIndex = this->selectedHartIndex;
controlRegister.haltRequest = true;
auto controlRegister = ControlRegister{
.debugModuleActive = true,
.selectedHartIndex = this->selectedHartIndex,
.haltRequest = true,
};
this->writeDebugModuleControlRegister(controlRegister);
auto statusRegister = this->readDebugModuleStatusRegister();
for (
auto attempts = 1;
auto attempts = 0;
!statusRegister.allHalted
&& (DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY * attempts) < this->config.targetResponseTimeout;
&& (DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY * attempts) <= this->config.targetResponseTimeout;
++attempts
) {
std::this_thread::sleep_for(DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY);
@@ -153,18 +153,19 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
}
void DebugTranslator::run() {
auto controlRegister = ControlRegister{};
controlRegister.debugModuleActive = true;
controlRegister.selectedHartIndex = this->selectedHartIndex;
controlRegister.resumeRequest = true;
auto controlRegister = ControlRegister{
.debugModuleActive = true,
.selectedHartIndex = this->selectedHartIndex,
.resumeRequest = true,
};
this->writeDebugModuleControlRegister(controlRegister);
auto statusRegister = this->readDebugModuleStatusRegister();
for (
auto attempts = 1;
auto attempts = 0;
!statusRegister.allResumeAcknowledge
&& (DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY * attempts) < this->config.targetResponseTimeout;
&& (DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY * attempts) <= this->config.targetResponseTimeout;
++attempts
) {
std::this_thread::sleep_for(DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY);
@@ -175,6 +176,8 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
this->writeDebugModuleControlRegister(controlRegister);
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"};
}
}
@@ -185,10 +188,11 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
this->writeDebugControlStatusRegister(debugControlStatusRegister);
auto controlRegister = ControlRegister{};
controlRegister.debugModuleActive = true;
controlRegister.selectedHartIndex = this->selectedHartIndex;
controlRegister.resumeRequest = true;
auto controlRegister = ControlRegister{
.debugModuleActive = true,
.selectedHartIndex = this->selectedHartIndex,
.resumeRequest = true,
};
this->writeDebugModuleControlRegister(controlRegister);
@@ -200,12 +204,13 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
}
void DebugTranslator::reset() {
auto controlRegister = ControlRegister{};
controlRegister.debugModuleActive = true;
controlRegister.selectedHartIndex = this->selectedHartIndex;
controlRegister.setResetHaltRequest = true;
controlRegister.haltRequest = true;
controlRegister.ndmReset = true;
auto controlRegister = ControlRegister{
.debugModuleActive = true,
.ndmReset = true,
.setResetHaltRequest = true,
.selectedHartIndex = this->selectedHartIndex,
.haltRequest = true,
};
this->writeDebugModuleControlRegister(controlRegister);
@@ -214,22 +219,21 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
auto statusRegister = this->readDebugModuleStatusRegister();
for (
auto attempts = 1;
auto attempts = 0;
!statusRegister.allHaveReset
&& (DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY * attempts) < this->config.targetResponseTimeout;
&& (DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY * attempts) <= this->config.targetResponseTimeout;
++attempts
) {
std::this_thread::sleep_for(DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY);
statusRegister = this->readDebugModuleStatusRegister();
}
controlRegister = ControlRegister{};
controlRegister.debugModuleActive = true;
controlRegister.selectedHartIndex = this->selectedHartIndex;
controlRegister.clearResetHaltRequest = true;
controlRegister.acknowledgeHaveReset = true;
this->writeDebugModuleControlRegister(controlRegister);
this->writeDebugModuleControlRegister(ControlRegister{
.debugModuleActive = true,
.clearResetHaltRequest = true,
.selectedHartIndex = this->selectedHartIndex,
.acknowledgeHaveReset = true,
});
if (!statusRegister.allHaveReset) {
throw Exceptions::Exception{"Target took too long to reset"};
@@ -258,7 +262,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
const auto& triggerDescriptor = triggerDescriptorOpt->get();
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)
);
@@ -270,16 +274,18 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
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_1,
MatchControl{
.execute = true,
.enabledInUserMode = true,
.enabledInSupervisorMode = true,
.enabledInMachineMode = true,
.action = TriggerModule::TriggerAction::ENTER_DEBUG_MODE,
.accessSize = MatchControl::AccessSize::ANY,
.compareValueType = MatchControl::CompareValueType::ADDRESS,
}.value()
);
this->writeCpuRegister(CpuRegisterNumber::TRIGGER_DATA_2, address);
this->allocatedTriggerIndices.emplace(triggerDescriptor.index);
@@ -305,7 +311,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
void DebugTranslator::clearAllHardwareBreakpoints() {
// 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);
}
@@ -386,13 +392,11 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
this->dtmInterface.writeDebugModuleRegister(RegisterAddress::ABSTRACT_DATA_1, startAddress);
constexpr auto command = AbstractCommandRegister{
MemoryAccessControlField{
false,
true,
MemoryAccessControlField::MemorySize::SIZE_32,
false
.control = MemoryAccessControlField{
.postIncrement = true,
.size = MemoryAccessControlField::MemorySize::SIZE_32,
}.value(),
AbstractCommandRegister::CommandType::MEMORY_ACCESS
.commandType = AbstractCommandRegister::CommandType::MEMORY_ACCESS
};
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);
constexpr auto command = AbstractCommandRegister{
MemoryAccessControlField{
true,
true,
MemoryAccessControlField::MemorySize::SIZE_32,
false
.control = MemoryAccessControlField{
.write = true,
.postIncrement = true,
.size = MemoryAccessControlField::MemorySize::SIZE_32,
}.value(),
AbstractCommandRegister::CommandType::MEMORY_ACCESS
.commandType = AbstractCommandRegister::CommandType::MEMORY_ACCESS
};
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
* read the value back.
*/
auto controlRegister = ControlRegister{};
controlRegister.debugModuleActive = true;
controlRegister.selectedHartIndex = 0xFFFFF;
this->writeDebugModuleControlRegister(
ControlRegister{.debugModuleActive = true, .selectedHartIndex = 0xFFFFF}
);
this->writeDebugModuleControlRegister(controlRegister);
const auto maxHartIndex = this->readDebugModuleControlRegister().selectedHartIndex;
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
* have to test each index until we find one that is non-existent.
*/
auto controlRegister = ControlRegister{};
controlRegister.debugModuleActive = true;
controlRegister.selectedHartIndex = hartIndex;
this->writeDebugModuleControlRegister(controlRegister);
this->writeDebugModuleControlRegister(
ControlRegister{.debugModuleActive = true, .selectedHartIndex = hartIndex}
);
/*
* 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) {
throw Exceptions::Exception{
"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;
}
const auto infoReg = TriggerModule::Registers::TriggerInfo{
const auto infoReg = TriggerModule::Registers::TriggerInfo::fromValue(
this->readCpuRegister(CpuRegisterNumber::TRIGGER_INFO)
};
);
if (infoReg.info == 0x01) {
// Trigger doesn't exist
@@ -564,9 +564,9 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
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{
const auto data1Reg = TriggerModule::Registers::TriggerData1::fromValue(
this->readCpuRegister(CpuRegisterNumber::TRIGGER_DATA_1)
};
);
const auto triggerType = data1Reg.getType();
if (!triggerType.has_value()) {
@@ -584,37 +584,40 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
}
ControlRegister DebugTranslator::readDebugModuleControlRegister() {
return ControlRegister{this->dtmInterface.readDebugModuleRegister(RegisterAddress::CONTROL_REGISTER)};
return ControlRegister::fromValue(
this->dtmInterface.readDebugModuleRegister(RegisterAddress::CONTROL_REGISTER)
);
}
StatusRegister DebugTranslator::readDebugModuleStatusRegister() {
return StatusRegister{this->dtmInterface.readDebugModuleRegister(RegisterAddress::STATUS_REGISTER)};
return StatusRegister::fromValue(this->dtmInterface.readDebugModuleRegister(RegisterAddress::STATUS_REGISTER));
}
AbstractControlStatusRegister DebugTranslator::readDebugModuleAbstractControlStatusRegister() {
return AbstractControlStatusRegister{
return AbstractControlStatusRegister::fromValue(
this->dtmInterface.readDebugModuleRegister(RegisterAddress::ABSTRACT_CONTROL_STATUS_REGISTER)
};
);
}
DebugControlStatusRegister DebugTranslator::readDebugControlStatusRegister() {
return DebugControlStatusRegister{
return DebugControlStatusRegister::fromValue(
this->readCpuRegister(static_cast<RegisterNumber>(CpuRegisterNumber::DEBUG_CONTROL_STATUS_REGISTER))
};
);
}
void DebugTranslator::enableDebugModule() {
auto controlRegister = ControlRegister{};
controlRegister.debugModuleActive = true;
controlRegister.selectedHartIndex = this->selectedHartIndex;
auto controlRegister = ControlRegister{
.debugModuleActive = true,
.selectedHartIndex = this->selectedHartIndex
};
this->writeDebugModuleControlRegister(controlRegister);
controlRegister = this->readDebugModuleControlRegister();
for (
auto attempts = 1;
auto attempts = 0;
!controlRegister.debugModuleActive
&& (DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY * attempts) < this->config.targetResponseTimeout;
&& (DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY * attempts) <= this->config.targetResponseTimeout;
++attempts
) {
std::this_thread::sleep_for(DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY);
@@ -627,17 +630,16 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
}
void DebugTranslator::disableDebugModule() {
auto controlRegister = ControlRegister{};
controlRegister.debugModuleActive = false;
controlRegister.selectedHartIndex = this->selectedHartIndex;
this->writeDebugModuleControlRegister(
ControlRegister{.debugModuleActive = false, .selectedHartIndex = this->selectedHartIndex}
);
this->writeDebugModuleControlRegister(controlRegister);
controlRegister = this->readDebugModuleControlRegister();
auto controlRegister = this->readDebugModuleControlRegister();
for (
auto attempts = 1;
auto attempts = 0;
controlRegister.debugModuleActive
&& (DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY * attempts) < this->config.targetResponseTimeout;
&& (DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY * attempts) <= this->config.targetResponseTimeout;
++attempts
) {
std::this_thread::sleep_for(DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY);
@@ -655,15 +657,12 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
using DebugModule::Registers::RegisterAccessControlField;
const auto commandError = this->tryExecuteAbstractCommand(AbstractCommandRegister{
RegisterAccessControlField{
number,
false,
true,
false,
false,
RegisterAccessControlField::RegisterSize::SIZE_32
.control = RegisterAccessControlField{
.registerNumber = number,
.transfer = true,
.size= RegisterAccessControlField::RegisterSize::SIZE_32
}.value(),
AbstractCommandRegister::CommandType::REGISTER_ACCESS
.commandType = AbstractCommandRegister::CommandType::REGISTER_ACCESS
});
if (commandError != DebugModule::AbstractCommandError::NONE) {
@@ -685,7 +684,8 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
if (!result.hasValue()) {
throw Exceptions::Exception{
"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);
return this->tryExecuteAbstractCommand(AbstractCommandRegister{
RegisterAccessControlField{
number,
true,
true,
false,
false,
RegisterAccessControlField::RegisterSize::SIZE_32
.control = RegisterAccessControlField{
.registerNumber = number,
.write = true,
.transfer = true,
.size = RegisterAccessControlField::RegisterSize::SIZE_32
}.value(),
AbstractCommandRegister::CommandType::REGISTER_ACCESS
.commandType = AbstractCommandRegister::CommandType::REGISTER_ACCESS
});
}
@@ -728,7 +726,8 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
if (commandError != DebugModule::AbstractCommandError::NONE) {
throw Exceptions::Exception{
"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 (
auto attempts = 1;
auto attempts = 0;
abstractStatusRegister.busy
&& (DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY * attempts) < this->config.targetResponseTimeout;
&& (DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY * attempts) <= this->config.targetResponseTimeout;
++attempts
) {
std::this_thread::sleep_for(DebugTranslator::DEBUG_MODULE_RESPONSE_DELAY);
@@ -784,7 +783,8 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
const auto commandError = this->tryExecuteAbstractCommand(abstractCommandRegister);
if (commandError != DebugModule::AbstractCommandError::NONE) {
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 <cstdint>
namespace DebugToolDrivers::Protocols::RiscVDebugSpec
{
DebugTranslatorConfig::DebugTranslatorConfig(const YAML::Node& configNode) {
if (configNode["targetResponseTimeout"]) {
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,
};
PrivilegeMode privilegeMode:2;
bool step:1 = false;
bool nmiPending:1 = false;
bool mprvEnabled:1 = false;
DebugModeCause debugModeCause:3;
bool stopTime:1 = false;
bool stopCount:1 = false;
bool stepInterruptsEnabled:1 = false;
bool breakUMode:1 = false;
bool breakSMode:1 = false;
bool breakMMode:1 = false;
bool breakVUMode:1 = false;
bool breakVSMode:1 = false;
std::uint8_t debugVersion:4 = 0;
PrivilegeMode privilegeMode = PrivilegeMode::USER;
bool step = false;
bool nmiPending = false;
bool mprvEnabled = false;
DebugModeCause debugModeCause = DebugModeCause::BREAK;
bool stopTime = false;
bool stopCount = false;
bool stepInterruptsEnabled = false;
bool breakUMode = false;
bool breakSMode = false;
bool breakMMode = false;
bool breakVUMode = false;
bool breakVSMode = false;
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)
: 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 {
[[nodiscard]] constexpr RegisterValue value() const {
return RegisterValue{0}
| static_cast<RegisterValue>(this->privilegeMode)
| 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->breakVUMode) << 16
| 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
{
U_MODE = 0x00,
S_MODE = 0x01,
M_MODE = 0x03,
USER = 0x00,
SUPERVISOR = 0x01,
MACHINE = 0x03,
};
}

View File

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

View File

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

View File

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

View File

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

View File

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