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:
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>({
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec::TriggerModule
|
||||
|
||||
enum class TriggerAction: std::uint8_t
|
||||
{
|
||||
RAISE_BREAKPOINT_EXCEPTION = 0x00,
|
||||
ENTER_DEBUG_MODE = 0x01,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user