WCH RISC-V software breakpoints, and a few other bits of refactoring/tidying

This commit is contained in:
Nav
2024-12-05 23:09:01 +00:00
parent 966244a01a
commit 33ed399337
55 changed files with 1530 additions and 686 deletions

View File

@@ -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
)
};
}

View File

@@ -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;

View File

@@ -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(),

View File

@@ -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;

View 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>;
}

View File

@@ -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};
}

View 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)
{}
};
}

View File

@@ -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;
}

View File

@@ -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:

View File

@@ -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;
}
}

View File

@@ -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;
};
}

View File

@@ -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.

View File

@@ -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,

View File

@@ -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);

View File

@@ -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;
};
}

View File

@@ -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 {

View File

@@ -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.