757 lines
27 KiB
C++
757 lines
27 KiB
C++
#include "RiscV.hpp"
|
|
|
|
#include <cassert>
|
|
#include <cmath>
|
|
#include <iterator>
|
|
#include <algorithm>
|
|
|
|
#include "src/Helpers/Pair.hpp"
|
|
#include "src/Services/StringService.hpp"
|
|
#include "src/Logger/Logger.hpp"
|
|
|
|
#include "Exceptions/IllegalMemoryAccess.hpp"
|
|
|
|
#include "src/Exceptions/Exception.hpp"
|
|
#include "src/Exceptions/InvalidConfig.hpp"
|
|
#include "src/TargetController/Exceptions/TargetOperationFailure.hpp"
|
|
|
|
namespace Targets::RiscV
|
|
{
|
|
RiscV::RiscV(
|
|
const TargetConfig& targetConfig,
|
|
const TargetDescriptionFile& targetDescriptionFile
|
|
)
|
|
: targetConfig(RiscVTargetConfig{targetConfig})
|
|
, targetDescriptionFile(targetDescriptionFile)
|
|
, isaDescriptor(this->targetDescriptionFile.getIsaDescriptor())
|
|
, cpuRegisterAddressSpaceDescriptor(RiscV::generateCpuRegisterAddressSpaceDescriptor())
|
|
, csrMemorySegmentDescriptor(this->cpuRegisterAddressSpaceDescriptor.getMemorySegmentDescriptor("cs_registers"))
|
|
, gprMemorySegmentDescriptor(this->cpuRegisterAddressSpaceDescriptor.getMemorySegmentDescriptor("gp_registers"))
|
|
, cpuPeripheralDescriptor(
|
|
RiscV::generateCpuPeripheralDescriptor(
|
|
this->isaDescriptor,
|
|
this->cpuRegisterAddressSpaceDescriptor,
|
|
this->csrMemorySegmentDescriptor,
|
|
this->gprMemorySegmentDescriptor
|
|
)
|
|
)
|
|
, csrGroupDescriptor(this->cpuPeripheralDescriptor.getRegisterGroupDescriptor("csr"))
|
|
, gprGroupDescriptor(this->cpuPeripheralDescriptor.getRegisterGroupDescriptor("gpr"))
|
|
, pcRegisterDescriptor(this->csrGroupDescriptor.getRegisterDescriptor("dpc"))
|
|
, spRegisterDescriptor(this->gprGroupDescriptor.getRegisterDescriptor("x2"))
|
|
, sysAddressSpaceDescriptor(this->targetDescriptionFile.getSystemAddressSpaceDescriptor())
|
|
{}
|
|
|
|
bool RiscV::supportsDebugTool(DebugTool* debugTool) {
|
|
return debugTool->getRiscVDebugInterface(this->targetDescriptionFile, this->targetConfig) != nullptr;
|
|
}
|
|
|
|
void RiscV::setDebugTool(DebugTool* debugTool) {
|
|
this->riscVDebugInterface = debugTool->getRiscVDebugInterface(this->targetDescriptionFile, this->targetConfig);
|
|
}
|
|
|
|
void RiscV::activate() {
|
|
this->riscVDebugInterface->activate();
|
|
}
|
|
|
|
void RiscV::deactivate() {
|
|
// TODO: Is this "tidy-up" code better placed in the TC? Review after v2.0.0.
|
|
|
|
if (this->getExecutionState() != TargetExecutionState::STOPPED) {
|
|
this->stop();
|
|
}
|
|
|
|
this->riscVDebugInterface->deactivate();
|
|
}
|
|
|
|
void RiscV::run(std::optional<TargetMemoryAddress> toAddress) {
|
|
this->riscVDebugInterface->run();
|
|
}
|
|
|
|
void RiscV::stop() {
|
|
this->riscVDebugInterface->stop();
|
|
}
|
|
|
|
void RiscV::step() {
|
|
this->riscVDebugInterface->step();
|
|
}
|
|
|
|
void RiscV::reset() {
|
|
this->riscVDebugInterface->reset();
|
|
}
|
|
|
|
TargetRegisterDescriptorAndValuePairs RiscV::readRegisters(const TargetRegisterDescriptors& descriptors) {
|
|
auto output = TargetRegisterDescriptorAndValuePairs{};
|
|
|
|
/*
|
|
* A "system register" is simply a register that we can access via the system address space.
|
|
*
|
|
* CPU registers (GPRs, CSRs, etc) cannot be accessed via the system address space, so we separate them from
|
|
* system registers, in order to access them separately.
|
|
*/
|
|
auto cpuRegisterDescriptors = TargetRegisterDescriptors{};
|
|
|
|
for (const auto& descriptor : descriptors) {
|
|
if (descriptor->addressSpaceId == this->cpuRegisterAddressSpaceDescriptor.id) {
|
|
if (
|
|
!this->csrMemorySegmentDescriptor.addressRange.contains(descriptor->startAddress)
|
|
&& !this->gprMemorySegmentDescriptor.addressRange.contains(descriptor->startAddress)
|
|
) {
|
|
throw Exceptions::Exception{
|
|
"Cannot access CPU register \"" + descriptor->key + "\" - unknown memory segment"
|
|
};
|
|
}
|
|
|
|
cpuRegisterDescriptors.emplace_back(descriptor);
|
|
continue;
|
|
}
|
|
|
|
if (descriptor->addressSpaceId != this->sysAddressSpaceDescriptor.id) {
|
|
throw Exceptions::Exception{
|
|
"Cannot access register \"" + descriptor->key + "\" - unknown address space"
|
|
};
|
|
}
|
|
|
|
auto value = this->riscVDebugInterface->readMemory(
|
|
this->sysAddressSpaceDescriptor,
|
|
this->resolveRegisterMemorySegmentDescriptor(*descriptor, this->sysAddressSpaceDescriptor),
|
|
descriptor->startAddress,
|
|
descriptor->size
|
|
);
|
|
|
|
if (value.size() > 1 && this->sysAddressSpaceDescriptor.endianness == TargetMemoryEndianness::LITTLE) {
|
|
// LSB to MSB
|
|
std::reverse(value.begin(), value.end());
|
|
}
|
|
|
|
output.emplace_back(*descriptor, std::move(value));
|
|
}
|
|
|
|
if (!cpuRegisterDescriptors.empty()) {
|
|
auto cpuRegisterValues = this->riscVDebugInterface->readCpuRegisters(cpuRegisterDescriptors);
|
|
std::move(cpuRegisterValues.begin(), cpuRegisterValues.end(), std::back_inserter(output));
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
void RiscV::writeRegisters(const TargetRegisterDescriptorAndValuePairs& registers) {
|
|
for (const auto& pair : registers) {
|
|
const auto& descriptor = pair.first;
|
|
|
|
if (descriptor.addressSpaceId == this->cpuRegisterAddressSpaceDescriptor.id) {
|
|
if (
|
|
!this->csrMemorySegmentDescriptor.addressRange.contains(descriptor.startAddress)
|
|
&& !this->gprMemorySegmentDescriptor.addressRange.contains(descriptor.startAddress)
|
|
) {
|
|
throw Exceptions::Exception{"Cannot access CPU register - unknown memory segment"};
|
|
}
|
|
|
|
this->riscVDebugInterface->writeCpuRegisters({pair});
|
|
continue;
|
|
}
|
|
|
|
if (descriptor.addressSpaceId != this->sysAddressSpaceDescriptor.id) {
|
|
throw Exceptions::Exception{
|
|
"Cannot access register \"" + descriptor.key + "\" - unknown address space"
|
|
};
|
|
}
|
|
|
|
auto value = pair.second;
|
|
|
|
if (value.size() > 1 && this->sysAddressSpaceDescriptor.endianness == TargetMemoryEndianness::LITTLE) {
|
|
// MSB to LSB
|
|
std::reverse(value.begin(), value.end());
|
|
}
|
|
|
|
this->riscVDebugInterface->writeMemory(
|
|
this->sysAddressSpaceDescriptor,
|
|
this->resolveRegisterMemorySegmentDescriptor(descriptor, this->sysAddressSpaceDescriptor),
|
|
descriptor.startAddress,
|
|
value
|
|
);
|
|
}
|
|
}
|
|
|
|
TargetMemoryBuffer RiscV::readMemory(
|
|
const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
|
|
const TargetMemorySegmentDescriptor& memorySegmentDescriptor,
|
|
TargetMemoryAddress startAddress,
|
|
TargetMemorySize bytes,
|
|
const std::set<TargetMemoryAddressRange>& excludedAddressRanges
|
|
) {
|
|
assert(bytes > 0);
|
|
|
|
assert(addressSpaceDescriptor.addressRange.contains(startAddress));
|
|
assert(addressSpaceDescriptor.addressRange.contains(startAddress + bytes - 1));
|
|
|
|
assert(memorySegmentDescriptor.addressRange.contains(startAddress));
|
|
assert(memorySegmentDescriptor.addressRange.contains(startAddress + bytes - 1));
|
|
|
|
return this->riscVDebugInterface->readMemory(
|
|
addressSpaceDescriptor,
|
|
memorySegmentDescriptor,
|
|
startAddress,
|
|
bytes,
|
|
excludedAddressRanges
|
|
);
|
|
}
|
|
|
|
void RiscV::writeMemory(
|
|
const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
|
|
const TargetMemorySegmentDescriptor& memorySegmentDescriptor,
|
|
TargetMemoryAddress startAddress,
|
|
TargetMemoryBufferSpan buffer
|
|
) {
|
|
assert(!buffer.empty());
|
|
|
|
assert(addressSpaceDescriptor.addressRange.contains(startAddress));
|
|
assert(addressSpaceDescriptor.addressRange.contains(
|
|
static_cast<TargetMemoryAddress>(startAddress + buffer.size()) - 1)
|
|
);
|
|
|
|
assert(memorySegmentDescriptor.addressRange.contains(startAddress));
|
|
assert(memorySegmentDescriptor.addressRange.contains(
|
|
static_cast<TargetMemoryAddress>(startAddress + buffer.size()) - 1)
|
|
);
|
|
|
|
return this->riscVDebugInterface->writeMemory(
|
|
addressSpaceDescriptor,
|
|
memorySegmentDescriptor,
|
|
startAddress,
|
|
buffer
|
|
);
|
|
}
|
|
|
|
bool RiscV::isProgramMemory(
|
|
const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
|
|
const TargetMemorySegmentDescriptor& memorySegmentDescriptor,
|
|
TargetMemoryAddress startAddress,
|
|
TargetMemorySize size
|
|
) {
|
|
return memorySegmentDescriptor.executable;
|
|
}
|
|
|
|
void RiscV::eraseMemory(
|
|
const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
|
|
const TargetMemorySegmentDescriptor& memorySegmentDescriptor
|
|
) {
|
|
this->riscVDebugInterface->eraseMemory(addressSpaceDescriptor, memorySegmentDescriptor);
|
|
}
|
|
|
|
TargetExecutionState RiscV::getExecutionState() {
|
|
return this->riscVDebugInterface->getExecutionState();
|
|
}
|
|
|
|
TargetMemoryAddress RiscV::getProgramCounter() {
|
|
const auto value = this->riscVDebugInterface->readCpuRegisters({&(this->pcRegisterDescriptor)}).at(0).second;
|
|
assert(value.size() == 4);
|
|
return static_cast<TargetMemoryAddress>(
|
|
(value[0] << 24) | (value[1] << 16) | (value[2] << 8) | (value[3])
|
|
);
|
|
}
|
|
|
|
void RiscV::setProgramCounter(TargetMemoryAddress programCounter) {
|
|
this->riscVDebugInterface->writeCpuRegisters({
|
|
{
|
|
this->pcRegisterDescriptor,
|
|
TargetMemoryBuffer{
|
|
static_cast<unsigned char>(programCounter >> 24),
|
|
static_cast<unsigned char>(programCounter >> 16),
|
|
static_cast<unsigned char>(programCounter >> 8),
|
|
static_cast<unsigned char>(programCounter)
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
TargetStackPointer RiscV::getStackPointer() {
|
|
const auto value = this->riscVDebugInterface->readCpuRegisters({&(this->spRegisterDescriptor)}).at(0).second;
|
|
assert(value.size() == 4);
|
|
return static_cast<TargetStackPointer>(
|
|
(value[0] << 24) | (value[1] << 16) | (value[2] << 8) | (value[3])
|
|
);
|
|
}
|
|
|
|
void RiscV::setStackPointer(TargetStackPointer stackPointer) {
|
|
this->riscVDebugInterface->writeCpuRegisters({
|
|
{
|
|
this->spRegisterDescriptor,
|
|
TargetMemoryBuffer{
|
|
static_cast<unsigned char>(stackPointer >> 24),
|
|
static_cast<unsigned char>(stackPointer >> 16),
|
|
static_cast<unsigned char>(stackPointer >> 8),
|
|
static_cast<unsigned char>(stackPointer)
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
TargetGpioPadDescriptorAndStatePairs RiscV::getGpioPadStates(const TargetPadDescriptors& padDescriptors) {
|
|
return {};
|
|
}
|
|
|
|
void RiscV::setGpioPadState(const TargetPadDescriptor& padDescriptor, const TargetGpioPadState& state) {
|
|
|
|
}
|
|
|
|
void RiscV::enableProgrammingMode() {
|
|
this->riscVDebugInterface->enableProgrammingMode();
|
|
this->programmingMode = true;
|
|
}
|
|
|
|
void RiscV::disableProgrammingMode() {
|
|
this->riscVDebugInterface->disableProgrammingMode();
|
|
this->programmingMode = false;
|
|
}
|
|
|
|
bool RiscV::programmingModeEnabled() {
|
|
return this->programmingMode;
|
|
}
|
|
|
|
TargetMemoryBuffer RiscV::readRegister(const TargetRegisterDescriptor& descriptor) {
|
|
return this->readRegisters({&descriptor}).front().second;
|
|
}
|
|
|
|
DynamicRegisterValue RiscV::readRegisterDynamicValue(const TargetRegisterDescriptor& descriptor) {
|
|
return DynamicRegisterValue{descriptor, this->readRegister(descriptor)};
|
|
}
|
|
|
|
void RiscV::writeRegister(const TargetRegisterDescriptor& descriptor, TargetMemoryBufferSpan value) {
|
|
this->writeRegisters({{descriptor, TargetMemoryBuffer{value.begin(), value.end()}}});
|
|
}
|
|
|
|
void RiscV::writeRegister(const TargetRegisterDescriptor& descriptor, std::uint64_t value) {
|
|
auto data = TargetMemoryBuffer(descriptor.size, 0x00);
|
|
|
|
for (auto i = TargetMemorySize{0}; i < descriptor.size; ++i) {
|
|
data[i] = static_cast<unsigned char>(value >> ((descriptor.size - i - 1) * 8));
|
|
}
|
|
|
|
this->writeRegister(descriptor, data);
|
|
}
|
|
|
|
bool RiscV::probeMemory(
|
|
const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
|
|
const TargetMemorySegmentDescriptor& memorySegmentDescriptor,
|
|
Targets::TargetMemoryAddress address
|
|
) {
|
|
try {
|
|
this->riscVDebugInterface->readMemory(addressSpaceDescriptor, memorySegmentDescriptor, address, 4, {});
|
|
return true;
|
|
|
|
} catch (const Exceptions::IllegalMemoryAccess&) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void RiscV::applyDebugInterfaceAccessRestrictions(TargetAddressSpaceDescriptor& addressSpaceDescriptor) {
|
|
for (auto& [segmentKey, segmentDescriptor] : addressSpaceDescriptor.segmentDescriptorsByKey) {
|
|
this->riscVDebugInterface->applyAccessRestrictions(segmentDescriptor);
|
|
}
|
|
}
|
|
|
|
void RiscV::applyDebugInterfaceAccessRestrictions(TargetRegisterGroupDescriptor& registerGroupDescriptor) {
|
|
for (auto& [registerKey, registerDescriptor] : registerGroupDescriptor.registerDescriptorsByKey) {
|
|
this->riscVDebugInterface->applyAccessRestrictions(registerDescriptor);
|
|
}
|
|
|
|
for (auto& [subgroupKey, subgroupDescriptor] : registerGroupDescriptor.subgroupDescriptorsByKey) {
|
|
this->applyDebugInterfaceAccessRestrictions(subgroupDescriptor);
|
|
}
|
|
}
|
|
|
|
const TargetMemorySegmentDescriptor& RiscV::resolveRegisterMemorySegmentDescriptor(
|
|
const TargetRegisterDescriptor& regDescriptor,
|
|
const TargetAddressSpaceDescriptor& addressSpaceDescriptor
|
|
) {
|
|
const auto segmentDescriptors = addressSpaceDescriptor.getIntersectingMemorySegmentDescriptors(
|
|
TargetMemoryAddressRange{
|
|
regDescriptor.startAddress,
|
|
(regDescriptor.startAddress + (regDescriptor.size / addressSpaceDescriptor.unitSize) - 1)
|
|
}
|
|
);
|
|
|
|
if (segmentDescriptors.empty()) {
|
|
throw Exceptions::Exception{
|
|
"Cannot access system register \"" + regDescriptor.key + "\" - unknown memory segment"
|
|
};
|
|
}
|
|
|
|
if (segmentDescriptors.size() != 1) {
|
|
throw Exceptions::Exception{
|
|
"Cannot access system register \"" + regDescriptor.key
|
|
+ "\" - register spans multiple memory segments"
|
|
};
|
|
}
|
|
|
|
return *(segmentDescriptors.front());
|
|
}
|
|
|
|
TargetAddressSpaceDescriptor RiscV::generateCpuRegisterAddressSpaceDescriptor() {
|
|
auto addressSpace = TargetAddressSpaceDescriptor{
|
|
"debug_module",
|
|
{0x0000, 0xFFFF},
|
|
TargetMemoryEndianness::LITTLE,
|
|
{},
|
|
4
|
|
};
|
|
|
|
addressSpace.segmentDescriptorsByKey.emplace(
|
|
"cs_registers",
|
|
TargetMemorySegmentDescriptor{
|
|
addressSpace.key,
|
|
"cs_registers",
|
|
"Control Status Registers",
|
|
TargetMemorySegmentType::REGISTERS,
|
|
{0x0000, 0x0FFF},
|
|
addressSpace.unitSize,
|
|
false,
|
|
{true, true},
|
|
{false, false},
|
|
false,
|
|
std::nullopt
|
|
}
|
|
);
|
|
|
|
addressSpace.segmentDescriptorsByKey.emplace(
|
|
"gp_registers",
|
|
TargetMemorySegmentDescriptor{
|
|
addressSpace.key,
|
|
"gp_registers",
|
|
"General Purpose Registers",
|
|
TargetMemorySegmentType::GENERAL_PURPOSE_REGISTERS,
|
|
{0x1000, 0x101F},
|
|
addressSpace.unitSize,
|
|
false,
|
|
{true, true},
|
|
{false, false},
|
|
false,
|
|
std::nullopt
|
|
}
|
|
);
|
|
|
|
return addressSpace;
|
|
}
|
|
|
|
TargetPeripheralDescriptor RiscV::generateCpuPeripheralDescriptor(
|
|
const IsaDescriptor& isaDescriptor,
|
|
const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
|
|
const TargetMemorySegmentDescriptor& csrMemorySegmentDescriptor,
|
|
const TargetMemorySegmentDescriptor& gprMemorySegmentDescriptor
|
|
) {
|
|
auto cpuPeripheralDescriptor = TargetPeripheralDescriptor{
|
|
"cpu",
|
|
"CPU",
|
|
"RISC-V GPRs and CSRs",
|
|
{},
|
|
{}
|
|
};
|
|
|
|
auto& gprGroup = cpuPeripheralDescriptor.registerGroupDescriptorsByKey.emplace(
|
|
"gpr",
|
|
TargetRegisterGroupDescriptor{
|
|
"gpr",
|
|
"gpr",
|
|
"General Purpose Registers",
|
|
cpuPeripheralDescriptor.key,
|
|
addressSpaceDescriptor.key,
|
|
std::nullopt,
|
|
{},
|
|
{}
|
|
}
|
|
).first->second;
|
|
|
|
for (auto i = std::uint8_t{0}; i <= static_cast<std::uint8_t>(isaDescriptor.isReduced() ? 15 : 31); ++i) {
|
|
const auto key = "x" + std::to_string(i);
|
|
gprGroup.registerDescriptorsByKey.emplace(
|
|
key,
|
|
TargetRegisterDescriptor{
|
|
key,
|
|
"X" + std::to_string(i),
|
|
gprGroup.absoluteKey,
|
|
cpuPeripheralDescriptor.key,
|
|
addressSpaceDescriptor.key,
|
|
gprMemorySegmentDescriptor.addressRange.startAddress + i,
|
|
4,
|
|
TargetRegisterType::GENERAL_PURPOSE_REGISTER,
|
|
TargetRegisterAccess(true, true),
|
|
std::nullopt,
|
|
{}
|
|
}
|
|
);
|
|
}
|
|
|
|
auto& csrGroup = cpuPeripheralDescriptor.registerGroupDescriptorsByKey.emplace(
|
|
"csr",
|
|
TargetRegisterGroupDescriptor{
|
|
"csr",
|
|
"csr",
|
|
"Control Status Registers",
|
|
cpuPeripheralDescriptor.key,
|
|
addressSpaceDescriptor.key,
|
|
std::nullopt,
|
|
{},
|
|
{}
|
|
}
|
|
).first->second;
|
|
|
|
csrGroup.registerDescriptorsByKey.emplace(
|
|
"marchid",
|
|
TargetRegisterDescriptor{
|
|
"marchid",
|
|
"MARCHID",
|
|
csrGroup.absoluteKey,
|
|
cpuPeripheralDescriptor.key,
|
|
addressSpaceDescriptor.key,
|
|
csrMemorySegmentDescriptor.addressRange.startAddress + 0xF12,
|
|
4,
|
|
TargetRegisterType::OTHER,
|
|
TargetRegisterAccess(true, false),
|
|
"Architecture ID",
|
|
{}
|
|
}
|
|
);
|
|
|
|
csrGroup.registerDescriptorsByKey.emplace(
|
|
"mimpid",
|
|
TargetRegisterDescriptor{
|
|
"mimpid",
|
|
"MIMPID",
|
|
csrGroup.absoluteKey,
|
|
cpuPeripheralDescriptor.key,
|
|
addressSpaceDescriptor.key,
|
|
csrMemorySegmentDescriptor.addressRange.startAddress + 0xF13,
|
|
4,
|
|
TargetRegisterType::OTHER,
|
|
TargetRegisterAccess(true, false),
|
|
"Implementation ID",
|
|
{}
|
|
}
|
|
);
|
|
|
|
csrGroup.registerDescriptorsByKey.emplace(
|
|
"mstatus",
|
|
TargetRegisterDescriptor{
|
|
"mstatus",
|
|
"MSTATUS",
|
|
csrGroup.absoluteKey,
|
|
cpuPeripheralDescriptor.key,
|
|
addressSpaceDescriptor.key,
|
|
csrMemorySegmentDescriptor.addressRange.startAddress + 0x300,
|
|
4,
|
|
TargetRegisterType::OTHER,
|
|
TargetRegisterAccess(true, true),
|
|
"Machine status",
|
|
{}
|
|
}
|
|
);
|
|
|
|
csrGroup.registerDescriptorsByKey.emplace(
|
|
"misa",
|
|
TargetRegisterDescriptor{
|
|
"misa",
|
|
"MISA",
|
|
csrGroup.absoluteKey,
|
|
cpuPeripheralDescriptor.key,
|
|
addressSpaceDescriptor.key,
|
|
csrMemorySegmentDescriptor.addressRange.startAddress + 0x301,
|
|
4,
|
|
TargetRegisterType::OTHER,
|
|
TargetRegisterAccess(true, true),
|
|
"ISA and extensions",
|
|
{}
|
|
}
|
|
);
|
|
|
|
csrGroup.registerDescriptorsByKey.emplace(
|
|
"mtvec",
|
|
TargetRegisterDescriptor{
|
|
"mtvec",
|
|
"MTVEC",
|
|
csrGroup.absoluteKey,
|
|
cpuPeripheralDescriptor.key,
|
|
addressSpaceDescriptor.key,
|
|
csrMemorySegmentDescriptor.addressRange.startAddress + 0x305,
|
|
4,
|
|
TargetRegisterType::OTHER,
|
|
TargetRegisterAccess(true, true),
|
|
"Machine trap-handler base address",
|
|
{}
|
|
}
|
|
);
|
|
|
|
csrGroup.registerDescriptorsByKey.emplace(
|
|
"mcounteren",
|
|
TargetRegisterDescriptor{
|
|
"mcounteren",
|
|
"MCOUNTEREN",
|
|
csrGroup.absoluteKey,
|
|
cpuPeripheralDescriptor.key,
|
|
addressSpaceDescriptor.key,
|
|
csrMemorySegmentDescriptor.addressRange.startAddress + 0x306,
|
|
4,
|
|
TargetRegisterType::OTHER,
|
|
TargetRegisterAccess(true, true),
|
|
"Machine counter enable",
|
|
{}
|
|
}
|
|
);
|
|
|
|
csrGroup.registerDescriptorsByKey.emplace(
|
|
"mscratch",
|
|
TargetRegisterDescriptor{
|
|
"mscratch",
|
|
"MSCRATCH",
|
|
csrGroup.absoluteKey,
|
|
cpuPeripheralDescriptor.key,
|
|
addressSpaceDescriptor.key,
|
|
csrMemorySegmentDescriptor.addressRange.startAddress + 0x340,
|
|
4,
|
|
TargetRegisterType::OTHER,
|
|
TargetRegisterAccess(true, true),
|
|
"Scratch register for machine trap handlers",
|
|
{}
|
|
}
|
|
);
|
|
|
|
csrGroup.registerDescriptorsByKey.emplace(
|
|
"mepc",
|
|
TargetRegisterDescriptor{
|
|
"mepc",
|
|
"MEPC",
|
|
csrGroup.absoluteKey,
|
|
cpuPeripheralDescriptor.key,
|
|
addressSpaceDescriptor.key,
|
|
csrMemorySegmentDescriptor.addressRange.startAddress + 0x341,
|
|
4,
|
|
TargetRegisterType::OTHER,
|
|
TargetRegisterAccess(true, true),
|
|
"Machine exception program counter",
|
|
{}
|
|
}
|
|
);
|
|
|
|
csrGroup.registerDescriptorsByKey.emplace(
|
|
"mcause",
|
|
TargetRegisterDescriptor{
|
|
"mcause",
|
|
"MCAUSE",
|
|
csrGroup.absoluteKey,
|
|
cpuPeripheralDescriptor.key,
|
|
addressSpaceDescriptor.key,
|
|
csrMemorySegmentDescriptor.addressRange.startAddress + 0x342,
|
|
4,
|
|
TargetRegisterType::OTHER,
|
|
TargetRegisterAccess(true, true),
|
|
"Machine trap cause",
|
|
{}
|
|
}
|
|
);
|
|
|
|
csrGroup.registerDescriptorsByKey.emplace(
|
|
"mtval",
|
|
TargetRegisterDescriptor{
|
|
"mtval",
|
|
"MTVAL",
|
|
csrGroup.absoluteKey,
|
|
cpuPeripheralDescriptor.key,
|
|
addressSpaceDescriptor.key,
|
|
csrMemorySegmentDescriptor.addressRange.startAddress + 0x343,
|
|
4,
|
|
TargetRegisterType::OTHER,
|
|
TargetRegisterAccess(true, true),
|
|
"Machine bad address or instruction",
|
|
{}
|
|
}
|
|
);
|
|
|
|
csrGroup.registerDescriptorsByKey.emplace(
|
|
"mip",
|
|
TargetRegisterDescriptor{
|
|
"mip",
|
|
"MIP",
|
|
csrGroup.absoluteKey,
|
|
cpuPeripheralDescriptor.key,
|
|
addressSpaceDescriptor.key,
|
|
csrMemorySegmentDescriptor.addressRange.startAddress + 0x344,
|
|
4,
|
|
TargetRegisterType::OTHER,
|
|
TargetRegisterAccess(true, true),
|
|
"Machine interrupt pending",
|
|
{}
|
|
}
|
|
);
|
|
|
|
csrGroup.registerDescriptorsByKey.emplace(
|
|
"dcsr",
|
|
TargetRegisterDescriptor{
|
|
"dcsr",
|
|
"DCSR",
|
|
csrGroup.absoluteKey,
|
|
cpuPeripheralDescriptor.key,
|
|
addressSpaceDescriptor.key,
|
|
csrMemorySegmentDescriptor.addressRange.startAddress + 0x7B0,
|
|
4,
|
|
TargetRegisterType::OTHER,
|
|
TargetRegisterAccess(true, true),
|
|
"Debug control and status",
|
|
{}
|
|
}
|
|
);
|
|
|
|
csrGroup.registerDescriptorsByKey.emplace(
|
|
"dpc",
|
|
TargetRegisterDescriptor{
|
|
"dpc",
|
|
"DPC",
|
|
csrGroup.absoluteKey,
|
|
cpuPeripheralDescriptor.key,
|
|
addressSpaceDescriptor.key,
|
|
csrMemorySegmentDescriptor.addressRange.startAddress + 0x7B1,
|
|
4,
|
|
TargetRegisterType::OTHER,
|
|
TargetRegisterAccess(true, true),
|
|
"Debug program counter",
|
|
{}
|
|
}
|
|
);
|
|
|
|
csrGroup.registerDescriptorsByKey.emplace(
|
|
"dscratch0",
|
|
TargetRegisterDescriptor{
|
|
"dscratch0",
|
|
"DSCRATCH0",
|
|
csrGroup.absoluteKey,
|
|
cpuPeripheralDescriptor.key,
|
|
addressSpaceDescriptor.key,
|
|
csrMemorySegmentDescriptor.addressRange.startAddress + 0x7B2,
|
|
4,
|
|
TargetRegisterType::OTHER,
|
|
TargetRegisterAccess(true, true),
|
|
"Debug scratch 0",
|
|
{}
|
|
}
|
|
);
|
|
|
|
csrGroup.registerDescriptorsByKey.emplace(
|
|
"dscratch1",
|
|
TargetRegisterDescriptor{
|
|
"dscratch1",
|
|
"DSCRATCH1",
|
|
csrGroup.absoluteKey,
|
|
cpuPeripheralDescriptor.key,
|
|
addressSpaceDescriptor.key,
|
|
csrMemorySegmentDescriptor.addressRange.startAddress + 0x7B3,
|
|
4,
|
|
TargetRegisterType::OTHER,
|
|
TargetRegisterAccess(true, true),
|
|
"Debug scratch 1",
|
|
{}
|
|
}
|
|
);
|
|
|
|
return cpuPeripheralDescriptor;
|
|
}
|
|
}
|