WCH RISC-V software breakpoints, and a few other bits of refactoring/tidying
This commit is contained in:
@@ -25,8 +25,10 @@ namespace Targets::Microchip::Avr8
|
||||
Avr8::Avr8(const TargetConfig& targetConfig, TargetDescriptionFile&& targetDescriptionFile)
|
||||
: targetConfig(Avr8TargetConfig{targetConfig})
|
||||
, targetDescriptionFile(std::move(targetDescriptionFile))
|
||||
, programAddressSpaceDescriptor(this->targetDescriptionFile.getProgramAddressSpaceDescriptor())
|
||||
, dataAddressSpaceDescriptor(this->targetDescriptionFile.getDataAddressSpaceDescriptor())
|
||||
, fuseAddressSpaceDescriptor(this->targetDescriptionFile.getFuseAddressSpaceDescriptor())
|
||||
, programMemorySegmentDescriptor(this->targetDescriptionFile.getProgramMemorySegmentDescriptor())
|
||||
, ramMemorySegmentDescriptor(this->targetDescriptionFile.getRamMemorySegmentDescriptor())
|
||||
, ioMemorySegmentDescriptor(this->targetDescriptionFile.getIoMemorySegmentDescriptor())
|
||||
, fuseMemorySegmentDescriptor(this->targetDescriptionFile.getFuseMemorySegmentDescriptor())
|
||||
@@ -234,7 +236,6 @@ namespace Targets::Microchip::Avr8
|
||||
}
|
||||
|
||||
this->stop();
|
||||
this->clearAllBreakpoints();
|
||||
|
||||
if (
|
||||
this->targetConfig.physicalInterface == TargetPhysicalInterface::JTAG
|
||||
@@ -357,24 +358,30 @@ namespace Targets::Microchip::Avr8
|
||||
this->avr8DebugInterface->reset();
|
||||
}
|
||||
|
||||
void Avr8::setSoftwareBreakpoint(TargetMemoryAddress address) {
|
||||
this->avr8DebugInterface->setSoftwareBreakpoint(address);
|
||||
void Avr8::setProgramBreakpoint(const TargetProgramBreakpoint& breakpoint) {
|
||||
if (breakpoint.addressSpaceDescriptor != this->programAddressSpaceDescriptor) {
|
||||
throw Exception{"Unexpected address space descriptor"};
|
||||
}
|
||||
|
||||
if (breakpoint.type == TargetProgramBreakpoint::Type::HARDWARE) {
|
||||
this->avr8DebugInterface->setHardwareBreakpoint(breakpoint.address);
|
||||
|
||||
} else {
|
||||
this->avr8DebugInterface->setSoftwareBreakpoint(breakpoint.address);
|
||||
}
|
||||
}
|
||||
|
||||
void Avr8::removeSoftwareBreakpoint(TargetMemoryAddress address) {
|
||||
this->avr8DebugInterface->clearSoftwareBreakpoint(address);
|
||||
}
|
||||
void Avr8::removeProgramBreakpoint(const TargetProgramBreakpoint& breakpoint) {
|
||||
if (breakpoint.addressSpaceDescriptor != this->programAddressSpaceDescriptor) {
|
||||
throw Exception{"Unexpected address space descriptor"};
|
||||
}
|
||||
|
||||
void Avr8::setHardwareBreakpoint(TargetMemoryAddress address) {
|
||||
this->avr8DebugInterface->setHardwareBreakpoint(address);
|
||||
}
|
||||
if (breakpoint.type == TargetProgramBreakpoint::Type::HARDWARE) {
|
||||
this->avr8DebugInterface->clearHardwareBreakpoint(breakpoint.address);
|
||||
|
||||
void Avr8::removeHardwareBreakpoint(TargetMemoryAddress address) {
|
||||
this->avr8DebugInterface->clearHardwareBreakpoint(address);
|
||||
}
|
||||
|
||||
void Avr8::clearAllBreakpoints() {
|
||||
this->avr8DebugInterface->clearAllBreakpoints();
|
||||
} else {
|
||||
this->avr8DebugInterface->clearSoftwareBreakpoint(breakpoint.address);
|
||||
}
|
||||
}
|
||||
|
||||
TargetRegisterDescriptorAndValuePairs Avr8::readRegisters(const Targets::TargetRegisterDescriptors& descriptors) {
|
||||
@@ -795,19 +802,19 @@ namespace Targets::Microchip::Avr8
|
||||
}
|
||||
|
||||
BreakpointResources Avr8::getBreakpointResources() {
|
||||
auto maxHardwareBreakpoints = std::uint16_t{0};
|
||||
auto hardwareBreakpoints = std::uint32_t{0};
|
||||
|
||||
switch (this->targetConfig.physicalInterface) {
|
||||
case TargetPhysicalInterface::JTAG: {
|
||||
maxHardwareBreakpoints = this->family == Family::XMEGA ? 2 : 3;
|
||||
hardwareBreakpoints = this->family == Family::XMEGA ? 2 : 3;
|
||||
break;
|
||||
}
|
||||
case TargetPhysicalInterface::PDI: {
|
||||
maxHardwareBreakpoints = 2;
|
||||
hardwareBreakpoints = 2;
|
||||
break;
|
||||
}
|
||||
case TargetPhysicalInterface::UPDI: {
|
||||
maxHardwareBreakpoints = 1;
|
||||
hardwareBreakpoints = 1;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -816,11 +823,15 @@ namespace Targets::Microchip::Avr8
|
||||
}
|
||||
|
||||
return BreakpointResources{
|
||||
maxHardwareBreakpoints,
|
||||
std::nullopt,
|
||||
hardwareBreakpoints,
|
||||
/*
|
||||
* AVR targets have unlimited SW breakpoints, so we just use the program memory size divided by the
|
||||
* breakpoint ("BREAK") opcode (byte) size, to determine the limit.
|
||||
*/
|
||||
this->programMemorySegmentDescriptor.size() / 2,
|
||||
std::min(
|
||||
static_cast<std::uint16_t>(this->targetConfig.reserveSteppingBreakpoint.value_or(true) ? 1 : 0),
|
||||
maxHardwareBreakpoints
|
||||
static_cast<std::uint32_t>(this->targetConfig.reserveSteppingBreakpoint.value_or(true) ? 1 : 0),
|
||||
hardwareBreakpoints
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -63,12 +63,8 @@ namespace Targets::Microchip::Avr8
|
||||
void step() override;
|
||||
void reset() override;
|
||||
|
||||
void setSoftwareBreakpoint(TargetMemoryAddress address) override;
|
||||
void removeSoftwareBreakpoint(TargetMemoryAddress address) override;
|
||||
|
||||
void setHardwareBreakpoint(TargetMemoryAddress address) override;
|
||||
void removeHardwareBreakpoint(TargetMemoryAddress address) override;
|
||||
void clearAllBreakpoints() override;
|
||||
void setProgramBreakpoint(const TargetProgramBreakpoint& breakpoint) override;
|
||||
void removeProgramBreakpoint(const TargetProgramBreakpoint& breakpoint) override;
|
||||
|
||||
TargetRegisterDescriptorAndValuePairs readRegisters(const TargetRegisterDescriptors& descriptors) override;
|
||||
void writeRegisters(const TargetRegisterDescriptorAndValuePairs& registers) override;
|
||||
@@ -122,9 +118,11 @@ namespace Targets::Microchip::Avr8
|
||||
Avr8TargetConfig targetConfig;
|
||||
TargetDescriptionFile targetDescriptionFile;
|
||||
|
||||
TargetAddressSpaceDescriptor programAddressSpaceDescriptor;
|
||||
TargetAddressSpaceDescriptor dataAddressSpaceDescriptor;
|
||||
TargetAddressSpaceDescriptor fuseAddressSpaceDescriptor;
|
||||
|
||||
TargetMemorySegmentDescriptor programMemorySegmentDescriptor;
|
||||
TargetMemorySegmentDescriptor ramMemorySegmentDescriptor;
|
||||
TargetMemorySegmentDescriptor ioMemorySegmentDescriptor;
|
||||
TargetMemorySegmentDescriptor fuseMemorySegmentDescriptor;
|
||||
|
||||
@@ -133,6 +133,10 @@ namespace Targets::Microchip::Avr8
|
||||
return this->getLockbitAddressSpace().getMemorySegment("lockbits");
|
||||
}
|
||||
|
||||
TargetAddressSpaceDescriptor TargetDescriptionFile::getProgramAddressSpaceDescriptor() const {
|
||||
return this->targetAddressSpaceDescriptorFromAddressSpace(this->getProgramAddressSpace());
|
||||
}
|
||||
|
||||
TargetAddressSpaceDescriptor TargetDescriptionFile::getDataAddressSpaceDescriptor() const {
|
||||
return this->targetAddressSpaceDescriptorFromAddressSpace(this->getDataAddressSpace());
|
||||
}
|
||||
@@ -141,6 +145,13 @@ namespace Targets::Microchip::Avr8
|
||||
return this->targetAddressSpaceDescriptorFromAddressSpace(this->getFuseAddressSpace());
|
||||
}
|
||||
|
||||
TargetMemorySegmentDescriptor TargetDescriptionFile::getProgramMemorySegmentDescriptor() const {
|
||||
return this->targetMemorySegmentDescriptorFromMemorySegment(
|
||||
this->getProgramMemorySegment(),
|
||||
this->getProgramAddressSpace()
|
||||
);
|
||||
}
|
||||
|
||||
TargetMemorySegmentDescriptor TargetDescriptionFile::getRamMemorySegmentDescriptor() const {
|
||||
return this->targetMemorySegmentDescriptorFromMemorySegment(
|
||||
this->getRamMemorySegment(),
|
||||
|
||||
@@ -61,9 +61,11 @@ namespace Targets::Microchip::Avr8
|
||||
[[nodiscard]] const TargetDescription::MemorySegment& getFuseMemorySegment() const;
|
||||
[[nodiscard]] const TargetDescription::MemorySegment& getLockbitMemorySegment() const;
|
||||
|
||||
[[nodiscard]] TargetAddressSpaceDescriptor getProgramAddressSpaceDescriptor() const;
|
||||
[[nodiscard]] TargetAddressSpaceDescriptor getDataAddressSpaceDescriptor() const;
|
||||
[[nodiscard]] TargetAddressSpaceDescriptor getFuseAddressSpaceDescriptor() const;
|
||||
|
||||
[[nodiscard]] TargetMemorySegmentDescriptor getProgramMemorySegmentDescriptor() const;
|
||||
[[nodiscard]] TargetMemorySegmentDescriptor getRamMemorySegmentDescriptor() const;
|
||||
[[nodiscard]] TargetMemorySegmentDescriptor getFuseMemorySegmentDescriptor() const;
|
||||
[[nodiscard]] TargetMemorySegmentDescriptor getIoMemorySegmentDescriptor() const;
|
||||
|
||||
112
src/Targets/ProgramBreakpointRegistry.hpp
Normal file
112
src/Targets/ProgramBreakpointRegistry.hpp
Normal file
@@ -0,0 +1,112 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <unordered_map>
|
||||
#include <optional>
|
||||
#include <functional>
|
||||
#include <numeric>
|
||||
|
||||
#include "TargetBreakpoint.hpp"
|
||||
#include "TargetMemory.hpp"
|
||||
|
||||
namespace Targets
|
||||
{
|
||||
/**
|
||||
* Bookkeeping for program breakpoints.
|
||||
*
|
||||
* This template class will accept any type derived from the TargetProgramBreakpoint struct, to accommodate
|
||||
* additional context-specific breakpoint data.
|
||||
*/
|
||||
template <typename BreakpointType>
|
||||
requires std::is_base_of_v<TargetProgramBreakpoint, BreakpointType>
|
||||
class ProgramBreakpointRegistryGeneric
|
||||
{
|
||||
public:
|
||||
std::unordered_map<TargetAddressSpaceId, std::unordered_map<TargetMemoryAddress, BreakpointType>> mapping;
|
||||
|
||||
void insert(const BreakpointType& breakpoint) {
|
||||
this->mapping[breakpoint.addressSpaceDescriptor.id].emplace(breakpoint.address, breakpoint);
|
||||
}
|
||||
|
||||
void remove(TargetAddressSpaceId addressSpaceId, TargetMemoryAddress address) {
|
||||
const auto addressMappingIt = this->mapping.find(addressSpaceId);
|
||||
if (addressMappingIt == this->mapping.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
addressMappingIt->second.erase(address);
|
||||
}
|
||||
|
||||
void remove(const TargetProgramBreakpoint& breakpoint) {
|
||||
this->remove(breakpoint.addressSpaceDescriptor.id, breakpoint.address);
|
||||
}
|
||||
|
||||
std::optional<std::reference_wrapper<const BreakpointType>> find(
|
||||
TargetAddressSpaceId addressSpaceId,
|
||||
TargetMemoryAddress address
|
||||
) const {
|
||||
const auto addressMappingIt = this->mapping.find(addressSpaceId);
|
||||
if (addressMappingIt == this->mapping.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const auto& addressMapping = addressMappingIt->second;
|
||||
const auto breakpointIt = addressMapping.find(address);
|
||||
if (breakpointIt == addressMapping.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return std::cref(breakpointIt->second);
|
||||
}
|
||||
|
||||
std::optional<std::reference_wrapper<const BreakpointType>> find(
|
||||
const TargetProgramBreakpoint& breakpoint
|
||||
) const {
|
||||
return this->find(breakpoint.addressSpaceDescriptor.id, breakpoint.address);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool contains(TargetAddressSpaceId addressSpaceId, TargetMemoryAddress address) const {
|
||||
const auto addressMappingIt = this->mapping.find(addressSpaceId);
|
||||
if (addressMappingIt == this->mapping.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& addressMapping = addressMappingIt->second;
|
||||
const auto breakpointIt = addressMapping.find(address);
|
||||
if (breakpointIt == addressMapping.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool contains(const BreakpointType& breakpoint) const {
|
||||
return this->contains(breakpoint.addressSpaceDescriptor.id, breakpoint.address);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::size_t size() const {
|
||||
return std::accumulate(
|
||||
this->mapping.begin(),
|
||||
this->mapping.end(),
|
||||
std::size_t{0},
|
||||
[] (std::size_t accumulatedSize, const decltype(this->mapping)::value_type& addressMappingPair) {
|
||||
return accumulatedSize + addressMappingPair.second.size();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
decltype(ProgramBreakpointRegistryGeneric::mapping)::const_iterator begin() const noexcept {
|
||||
return this->mapping.begin();
|
||||
}
|
||||
|
||||
decltype(ProgramBreakpointRegistryGeneric::mapping)::const_iterator end() const noexcept {
|
||||
return this->mapping.end();
|
||||
}
|
||||
|
||||
void clear() {
|
||||
this->mapping.clear();
|
||||
}
|
||||
};
|
||||
|
||||
using ProgramBreakpointRegistry = ProgramBreakpointRegistryGeneric<TargetProgramBreakpoint>;
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
namespace Targets::RiscV::Opcodes
|
||||
{
|
||||
using Opcode = std::uint32_t;
|
||||
using OpcodeCompressed = std::uint16_t;
|
||||
|
||||
enum class GprNumber: std::uint8_t
|
||||
{
|
||||
@@ -14,4 +15,8 @@ namespace Targets::RiscV::Opcodes
|
||||
};
|
||||
|
||||
static constexpr auto Ebreak = Opcode{0x00100073};
|
||||
static constexpr auto EbreakCompressed = OpcodeCompressed{0x9002};
|
||||
|
||||
static constexpr auto Fence = Opcode{0x0000000f};
|
||||
static constexpr auto FenceI = Opcode{0x0000100f};
|
||||
}
|
||||
|
||||
23
src/Targets/RiscV/ProgramBreakpoint.hpp
Normal file
23
src/Targets/RiscV/ProgramBreakpoint.hpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "src/Targets/TargetBreakpoint.hpp"
|
||||
#include "Opcodes/Opcode.hpp"
|
||||
|
||||
namespace Targets::RiscV
|
||||
{
|
||||
struct ProgramBreakpoint: TargetProgramBreakpoint
|
||||
{
|
||||
std::optional<Opcodes::Opcode> originalInstruction = std::nullopt;
|
||||
|
||||
explicit ProgramBreakpoint(const TargetProgramBreakpoint& breakpoint)
|
||||
: TargetProgramBreakpoint(breakpoint)
|
||||
{}
|
||||
|
||||
explicit ProgramBreakpoint(const TargetProgramBreakpoint& breakpoint, Opcodes::Opcode originalInstruction)
|
||||
: TargetProgramBreakpoint(breakpoint)
|
||||
, originalInstruction(originalInstruction)
|
||||
{}
|
||||
};
|
||||
}
|
||||
@@ -59,8 +59,6 @@ namespace Targets::RiscV
|
||||
this->stop();
|
||||
}
|
||||
|
||||
this->clearAllBreakpoints();
|
||||
this->run();
|
||||
this->riscVDebugInterface->deactivate();
|
||||
}
|
||||
|
||||
@@ -80,26 +78,6 @@ namespace Targets::RiscV
|
||||
this->riscVDebugInterface->reset();
|
||||
}
|
||||
|
||||
void RiscV::setSoftwareBreakpoint(TargetMemoryAddress address) {
|
||||
throw Exceptions::Exception{"TARGET - SW breakpoints not supported"};
|
||||
}
|
||||
|
||||
void RiscV::removeSoftwareBreakpoint(TargetMemoryAddress address) {
|
||||
throw Exceptions::Exception{"TARGET - SW breakpoints not supported"};
|
||||
}
|
||||
|
||||
void RiscV::setHardwareBreakpoint(TargetMemoryAddress address) {
|
||||
this->riscVDebugInterface->setHardwareBreakpoint(address);
|
||||
}
|
||||
|
||||
void RiscV::removeHardwareBreakpoint(TargetMemoryAddress address) {
|
||||
this->riscVDebugInterface->clearHardwareBreakpoint(address);
|
||||
}
|
||||
|
||||
void RiscV::clearAllBreakpoints() {
|
||||
this->riscVDebugInterface->clearAllHardwareBreakpoints();
|
||||
}
|
||||
|
||||
TargetRegisterDescriptorAndValuePairs RiscV::readRegisters(const TargetRegisterDescriptors& descriptors) {
|
||||
auto output = TargetRegisterDescriptorAndValuePairs{};
|
||||
|
||||
@@ -316,10 +294,12 @@ namespace Targets::RiscV
|
||||
}
|
||||
|
||||
void RiscV::enableProgrammingMode() {
|
||||
this->riscVDebugInterface->enableProgrammingMode();
|
||||
this->programmingMode = true;
|
||||
}
|
||||
|
||||
void RiscV::disableProgrammingMode() {
|
||||
this->riscVDebugInterface->disableProgrammingMode();
|
||||
this->programmingMode = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,13 +38,6 @@ namespace Targets::RiscV
|
||||
void step() override;
|
||||
void reset() override;
|
||||
|
||||
void setSoftwareBreakpoint(TargetMemoryAddress address) override;
|
||||
void removeSoftwareBreakpoint(TargetMemoryAddress address) override;
|
||||
|
||||
void setHardwareBreakpoint(TargetMemoryAddress address) override;
|
||||
void removeHardwareBreakpoint(TargetMemoryAddress address) override;
|
||||
void clearAllBreakpoints() override;
|
||||
|
||||
TargetRegisterDescriptorAndValuePairs readRegisters(const TargetRegisterDescriptors& descriptors) override;
|
||||
void writeRegisters(const TargetRegisterDescriptorAndValuePairs& registers) override;
|
||||
|
||||
@@ -84,9 +77,7 @@ namespace Targets::RiscV
|
||||
void setGpioPadState(const TargetPadDescriptor& padDescriptor, const TargetGpioPadState& state) override;
|
||||
|
||||
void enableProgrammingMode() override;
|
||||
|
||||
void disableProgrammingMode() override;
|
||||
|
||||
bool programmingModeEnabled() override;
|
||||
|
||||
protected:
|
||||
|
||||
@@ -47,8 +47,6 @@ namespace Targets::RiscV::Wch
|
||||
}
|
||||
|
||||
TargetDescriptor WchRiscV::targetDescriptor() {
|
||||
const auto hardwareBreakpointCount = this->riscVDebugInterface->getHardwareBreakpointCount();
|
||||
|
||||
auto descriptor = TargetDescriptor{
|
||||
this->targetDescriptionFile.getName(),
|
||||
this->targetDescriptionFile.getFamily(),
|
||||
@@ -59,15 +57,16 @@ namespace Targets::RiscV::Wch
|
||||
this->targetDescriptionFile.targetPadDescriptorsByKey(),
|
||||
this->targetDescriptionFile.targetPinoutDescriptorsByKey(),
|
||||
this->targetDescriptionFile.targetVariantDescriptorsByKey(),
|
||||
BreakpointResources{
|
||||
hardwareBreakpointCount,
|
||||
std::nullopt,
|
||||
static_cast<std::uint16_t>(
|
||||
this->targetConfig.reserveSteppingBreakpoint.value_or(false) && hardwareBreakpointCount > 0 ? 1 : 0
|
||||
)
|
||||
}
|
||||
this->riscVDebugInterface->getBreakpointResources()
|
||||
};
|
||||
|
||||
if (
|
||||
this->targetConfig.reserveSteppingBreakpoint.value_or(false)
|
||||
&& descriptor.breakpointResources.hardwareBreakpoints > 0
|
||||
) {
|
||||
descriptor.breakpointResources.reservedHardwareBreakpoints = 1;
|
||||
}
|
||||
|
||||
// Copy the RISC-V CPU register address space and peripheral descriptor
|
||||
descriptor.addressSpaceDescriptorsByKey.emplace(
|
||||
this->cpuRegisterAddressSpaceDescriptor.key,
|
||||
@@ -100,6 +99,44 @@ namespace Targets::RiscV::Wch
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
void WchRiscV::setProgramBreakpoint(const TargetProgramBreakpoint& breakpoint) {
|
||||
if (
|
||||
breakpoint.type == TargetProgramBreakpoint::Type::SOFTWARE
|
||||
&& breakpoint.memorySegmentDescriptor == this->mappedProgramMemorySegmentDescriptor
|
||||
) {
|
||||
this->riscVDebugInterface->setProgramBreakpoint(TargetProgramBreakpoint{
|
||||
.addressSpaceDescriptor = this->sysAddressSpaceDescriptor,
|
||||
.memorySegmentDescriptor = this->getDestinationProgramMemorySegmentDescriptor(),
|
||||
.address = this->transformAliasedProgramMemoryAddress(breakpoint.address),
|
||||
.size = breakpoint.size,
|
||||
.type = breakpoint.type
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this->riscVDebugInterface->setProgramBreakpoint(breakpoint);
|
||||
}
|
||||
|
||||
void WchRiscV::removeProgramBreakpoint(const TargetProgramBreakpoint& breakpoint) {
|
||||
if (
|
||||
breakpoint.type == TargetProgramBreakpoint::Type::SOFTWARE
|
||||
&& breakpoint.memorySegmentDescriptor == this->mappedProgramMemorySegmentDescriptor
|
||||
) {
|
||||
this->riscVDebugInterface->removeProgramBreakpoint(TargetProgramBreakpoint{
|
||||
.addressSpaceDescriptor = this->sysAddressSpaceDescriptor,
|
||||
.memorySegmentDescriptor = this->getDestinationProgramMemorySegmentDescriptor(),
|
||||
.address = this->transformAliasedProgramMemoryAddress(breakpoint.address),
|
||||
.size = breakpoint.size,
|
||||
.type = breakpoint.type
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this->riscVDebugInterface->removeProgramBreakpoint(breakpoint);
|
||||
}
|
||||
|
||||
void WchRiscV::writeMemory(
|
||||
const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
|
||||
const TargetMemorySegmentDescriptor& memorySegmentDescriptor,
|
||||
@@ -119,13 +156,35 @@ namespace Targets::RiscV::Wch
|
||||
* before v2.0.0.
|
||||
*/
|
||||
if (memorySegmentDescriptor == this->mappedProgramMemorySegmentDescriptor) {
|
||||
const auto newAddress = startAddress - this->mappedProgramMemorySegmentDescriptor.addressRange.startAddress
|
||||
+ this->programMemorySegmentDescriptor.addressRange.startAddress;
|
||||
assert(this->programMemorySegmentDescriptor.addressRange.contains(newAddress));
|
||||
const auto transformedAddress = this->transformAliasedProgramMemoryAddress(startAddress);
|
||||
assert(this->programMemorySegmentDescriptor.addressRange.contains(transformedAddress));
|
||||
|
||||
return RiscV::writeMemory(addressSpaceDescriptor, this->programMemorySegmentDescriptor, newAddress, buffer);
|
||||
return RiscV::writeMemory(
|
||||
addressSpaceDescriptor,
|
||||
this->programMemorySegmentDescriptor,
|
||||
transformedAddress,
|
||||
buffer
|
||||
);
|
||||
}
|
||||
|
||||
return RiscV::writeMemory(addressSpaceDescriptor, memorySegmentDescriptor, startAddress, buffer);
|
||||
}
|
||||
|
||||
const TargetMemorySegmentDescriptor& WchRiscV::getDestinationProgramMemorySegmentDescriptor() {
|
||||
return this->programMemorySegmentDescriptor;
|
||||
}
|
||||
|
||||
TargetMemoryAddress WchRiscV::transformAliasedProgramMemoryAddress(TargetMemoryAddress address) const {
|
||||
using Services::StringService;
|
||||
|
||||
const auto transformedAddress = address - this->mappedProgramMemorySegmentDescriptor.addressRange.startAddress
|
||||
+ this->programMemorySegmentDescriptor.addressRange.startAddress;
|
||||
|
||||
Logger::debug(
|
||||
"Transformed mapped program memory address 0x" + StringService::toHex(address) + " to 0x"
|
||||
+ StringService::toHex(transformedAddress)
|
||||
);
|
||||
|
||||
return transformedAddress;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,9 @@ namespace Targets::RiscV::Wch
|
||||
void postActivate() override;
|
||||
TargetDescriptor targetDescriptor() override;
|
||||
|
||||
void setProgramBreakpoint(const TargetProgramBreakpoint& breakpoint) override;
|
||||
void removeProgramBreakpoint(const TargetProgramBreakpoint& breakpoint) override;
|
||||
|
||||
void writeMemory(
|
||||
const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
|
||||
const TargetMemorySegmentDescriptor& memorySegmentDescriptor,
|
||||
@@ -31,6 +34,10 @@ namespace Targets::RiscV::Wch
|
||||
std::optional<std::reference_wrapper<const TargetDescription::Variant>> variant = std::nullopt;
|
||||
|
||||
const TargetMemorySegmentDescriptor& programMemorySegmentDescriptor;
|
||||
const TargetMemorySegmentDescriptor& bootProgramMemorySegmentDescriptor;
|
||||
const TargetMemorySegmentDescriptor& mappedProgramMemorySegmentDescriptor;
|
||||
|
||||
const TargetMemorySegmentDescriptor& getDestinationProgramMemorySegmentDescriptor();
|
||||
TargetMemoryAddress transformAliasedProgramMemoryAddress(TargetMemoryAddress address) const;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -116,40 +116,8 @@ namespace Targets
|
||||
*/
|
||||
virtual void reset() = 0;
|
||||
|
||||
/**
|
||||
* Should set a software breakpoint on the target, at the given address.
|
||||
*
|
||||
* @param address
|
||||
*/
|
||||
virtual void setSoftwareBreakpoint(TargetMemoryAddress address) = 0;
|
||||
|
||||
/**
|
||||
* Should remove a software breakpoint at the given address.
|
||||
*
|
||||
* @param address
|
||||
*/
|
||||
virtual void removeSoftwareBreakpoint(TargetMemoryAddress address) = 0;
|
||||
|
||||
/**
|
||||
* Should set a hardware breakpoint on the target, at the given address.
|
||||
*
|
||||
* @param address
|
||||
*/
|
||||
virtual void setHardwareBreakpoint(TargetMemoryAddress address) = 0;
|
||||
|
||||
/**
|
||||
* Should remove a hardware breakpoint at the given address.
|
||||
*
|
||||
* @param address
|
||||
*/
|
||||
virtual void removeHardwareBreakpoint(TargetMemoryAddress address) = 0;
|
||||
|
||||
/**
|
||||
* Should clear all breakpoints on the target.
|
||||
*
|
||||
* @TODO: is this still needed? Review
|
||||
*/
|
||||
virtual void clearAllBreakpoints() = 0;
|
||||
virtual void setProgramBreakpoint(const TargetProgramBreakpoint& breakpoint) = 0;
|
||||
virtual void removeProgramBreakpoint(const TargetProgramBreakpoint& breakpoint) = 0;
|
||||
|
||||
/**
|
||||
* Should read register values of the registers described by the given descriptors.
|
||||
|
||||
@@ -85,6 +85,18 @@ namespace Targets
|
||||
return output;
|
||||
}
|
||||
|
||||
std::optional<
|
||||
std::reference_wrapper<const TargetMemorySegmentDescriptor>
|
||||
> TargetAddressSpaceDescriptor::getContainingMemorySegmentDescriptor(const TargetMemoryAddress& address) const {
|
||||
for (const auto& [key, segmentDescriptor] : this->segmentDescriptorsByKey) {
|
||||
if (segmentDescriptor.addressRange.contains(address)) {
|
||||
return std::cref(segmentDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
TargetAddressSpaceDescriptor TargetAddressSpaceDescriptor::clone() const {
|
||||
auto output = TargetAddressSpaceDescriptor{
|
||||
this->key,
|
||||
|
||||
@@ -92,6 +92,18 @@ namespace Targets
|
||||
const TargetMemoryAddressRange& addressRange
|
||||
) const;
|
||||
|
||||
/**
|
||||
* Fetches the memory segment which contains the given address.
|
||||
*
|
||||
* @param address
|
||||
*
|
||||
* @return
|
||||
* The containing memory segment descriptor, or std::nullopt of no segments contain the address.
|
||||
*/
|
||||
[[nodiscard]] std::optional<
|
||||
std::reference_wrapper<const TargetMemorySegmentDescriptor>
|
||||
> getContainingMemorySegmentDescriptor(const TargetMemoryAddress& address) const;
|
||||
|
||||
[[nodiscard]] TargetAddressSpaceDescriptor clone() const;
|
||||
|
||||
static TargetAddressSpaceId generateId(const std::string& addressSpaceKey);
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include <cassert>
|
||||
|
||||
#include "TargetMemory.hpp"
|
||||
#include "TargetAddressSpaceDescriptor.hpp"
|
||||
#include "TargetMemorySegmentDescriptor.hpp"
|
||||
|
||||
namespace Targets
|
||||
{
|
||||
@@ -14,7 +16,7 @@ namespace Targets
|
||||
UNKNOWN,
|
||||
};
|
||||
|
||||
struct TargetBreakpoint
|
||||
struct TargetProgramBreakpoint
|
||||
{
|
||||
enum class Type: std::uint8_t
|
||||
{
|
||||
@@ -22,42 +24,17 @@ namespace Targets
|
||||
SOFTWARE,
|
||||
};
|
||||
|
||||
/**
|
||||
* Byte address of the breakpoint.
|
||||
*/
|
||||
TargetMemoryAddress address = 0;
|
||||
|
||||
Type type = Type::SOFTWARE;
|
||||
|
||||
TargetBreakpoint() = default;
|
||||
|
||||
explicit TargetBreakpoint(TargetMemoryAddress address, Type type = Type::SOFTWARE)
|
||||
: address(address)
|
||||
, type(type)
|
||||
{};
|
||||
const TargetAddressSpaceDescriptor& addressSpaceDescriptor;
|
||||
const TargetMemorySegmentDescriptor& memorySegmentDescriptor;
|
||||
TargetMemoryAddress address;
|
||||
TargetMemorySize size;
|
||||
Type type;
|
||||
};
|
||||
|
||||
struct BreakpointResources
|
||||
{
|
||||
std::optional<std::uint16_t> maximumHardwareBreakpoints = std::nullopt;
|
||||
std::optional<std::uint16_t> maximumSoftwareBreakpoints = std::nullopt;
|
||||
std::uint16_t reservedHardwareBreakpoints = 0;
|
||||
|
||||
BreakpointResources() = default;
|
||||
|
||||
BreakpointResources(
|
||||
std::optional<std::uint16_t> maximumHardwareBreakpoints,
|
||||
std::optional<std::uint16_t> maximumSoftwareBreakpoints,
|
||||
std::uint16_t reservedHardwareBreakpoints
|
||||
)
|
||||
: maximumHardwareBreakpoints(maximumHardwareBreakpoints)
|
||||
, maximumSoftwareBreakpoints(maximumSoftwareBreakpoints)
|
||||
, reservedHardwareBreakpoints(reservedHardwareBreakpoints)
|
||||
{
|
||||
assert(
|
||||
!this->maximumHardwareBreakpoints.has_value()
|
||||
|| this->maximumHardwareBreakpoints >= this->reservedHardwareBreakpoints
|
||||
);
|
||||
}
|
||||
std::uint32_t hardwareBreakpoints = 0;
|
||||
std::uint32_t softwareBreakpoints = 0;
|
||||
std::uint32_t reservedHardwareBreakpoints = 0;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -42,6 +42,18 @@ namespace Targets
|
||||
return std::cref(descriptorIt->second);
|
||||
}
|
||||
|
||||
std::optional<
|
||||
std::reference_wrapper<TargetAddressSpaceDescriptor>
|
||||
> TargetDescriptor::tryGetAddressSpaceDescriptor(const std::string& key) {
|
||||
const auto descriptorIt = this->addressSpaceDescriptorsByKey.find(key);
|
||||
|
||||
if (descriptorIt == this->addressSpaceDescriptorsByKey.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return std::ref(descriptorIt->second);
|
||||
}
|
||||
|
||||
const TargetAddressSpaceDescriptor& TargetDescriptor::getAddressSpaceDescriptor(const std::string& key) const {
|
||||
const auto descriptor = this->tryGetAddressSpaceDescriptor(key);
|
||||
if (!descriptor.has_value()) {
|
||||
@@ -54,6 +66,28 @@ namespace Targets
|
||||
return descriptor->get();
|
||||
}
|
||||
|
||||
TargetAddressSpaceDescriptor& TargetDescriptor::getAddressSpaceDescriptor(const std::string& key) {
|
||||
return const_cast<TargetAddressSpaceDescriptor&>(
|
||||
const_cast<const TargetDescriptor*>(this)->getAddressSpaceDescriptor(key)
|
||||
);
|
||||
}
|
||||
|
||||
const TargetMemorySegmentDescriptor& TargetDescriptor::getMemorySegmentDescriptor(
|
||||
const std::string& addressSpaceKey,
|
||||
const std::string& segmentKey
|
||||
) const {
|
||||
return this->getAddressSpaceDescriptor(addressSpaceKey).getMemorySegmentDescriptor(segmentKey);
|
||||
}
|
||||
|
||||
TargetMemorySegmentDescriptor& TargetDescriptor::getMemorySegmentDescriptor(
|
||||
const std::string& addressSpaceKey,
|
||||
const std::string& segmentKey
|
||||
) {
|
||||
return const_cast<TargetMemorySegmentDescriptor&>(
|
||||
const_cast<const TargetDescriptor*>(this)->getMemorySegmentDescriptor(addressSpaceKey, segmentKey)
|
||||
);
|
||||
}
|
||||
|
||||
const TargetAddressSpaceDescriptor& TargetDescriptor::getFirstAddressSpaceDescriptorContainingMemorySegment(
|
||||
const std::string& memorySegmentKey
|
||||
) const {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
#include <QMetaType>
|
||||
|
||||
@@ -53,8 +54,21 @@ namespace Targets
|
||||
std::optional<std::reference_wrapper<const TargetAddressSpaceDescriptor>> tryGetAddressSpaceDescriptor(
|
||||
const std::string& key
|
||||
) const;
|
||||
std::optional<std::reference_wrapper<TargetAddressSpaceDescriptor>> tryGetAddressSpaceDescriptor(
|
||||
const std::string& key
|
||||
);
|
||||
|
||||
const TargetAddressSpaceDescriptor& getAddressSpaceDescriptor(const std::string& key) const;
|
||||
TargetAddressSpaceDescriptor& getAddressSpaceDescriptor(const std::string& key);
|
||||
|
||||
const TargetMemorySegmentDescriptor& getMemorySegmentDescriptor(
|
||||
const std::string& addressSpaceKey,
|
||||
const std::string& segmentKey
|
||||
) const;
|
||||
TargetMemorySegmentDescriptor& getMemorySegmentDescriptor(
|
||||
const std::string& addressSpaceKey,
|
||||
const std::string& segmentKey
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns the descriptor for the first address space that contains the given memory segment.
|
||||
|
||||
Reference in New Issue
Block a user