Triggering a registers written event when a memory range that contains a register is written to.
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "Event.hpp"
|
#include "Event.hpp"
|
||||||
|
#include "src/Targets/TargetRegister.hpp"
|
||||||
|
|
||||||
namespace Bloom::Events
|
namespace Bloom::Events
|
||||||
{
|
{
|
||||||
@@ -12,6 +13,8 @@ namespace Bloom::Events
|
|||||||
static inline EventType type = EventType::REGISTERS_WRITTEN_TO_TARGET;
|
static inline EventType type = EventType::REGISTERS_WRITTEN_TO_TARGET;
|
||||||
static inline const std::string name = "RegistersWrittenToTarget";
|
static inline const std::string name = "RegistersWrittenToTarget";
|
||||||
|
|
||||||
|
Targets::TargetRegisterDescriptors descriptors;
|
||||||
|
|
||||||
[[nodiscard]] EventType getType() const override {
|
[[nodiscard]] EventType getType() const override {
|
||||||
return RegistersWrittenToTarget::type;
|
return RegistersWrittenToTarget::type;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <typeindex>
|
#include <typeindex>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "src/Application.hpp"
|
#include "src/Application.hpp"
|
||||||
#include "src/Helpers/Paths.hpp"
|
#include "src/Helpers/Paths.hpp"
|
||||||
@@ -17,6 +18,9 @@ using namespace Bloom::Targets;
|
|||||||
using namespace Bloom::Events;
|
using namespace Bloom::Events;
|
||||||
using namespace Bloom::Exceptions;
|
using namespace Bloom::Exceptions;
|
||||||
|
|
||||||
|
using Bloom::Targets::TargetRegisterDescriptor;
|
||||||
|
using Bloom::Targets::TargetRegisterDescriptors;
|
||||||
|
|
||||||
void TargetController::run() {
|
void TargetController::run() {
|
||||||
try {
|
try {
|
||||||
this->startup();
|
this->startup();
|
||||||
@@ -170,6 +174,8 @@ void TargetController::suspend() {
|
|||||||
|
|
||||||
this->lastTargetState = TargetState::UNKNOWN;
|
this->lastTargetState = TargetState::UNKNOWN;
|
||||||
this->cachedTargetDescriptor = std::nullopt;
|
this->cachedTargetDescriptor = std::nullopt;
|
||||||
|
this->registerDescriptorsByMemoryType.clear();
|
||||||
|
this->registerAddressRangeByMemoryType.clear();
|
||||||
|
|
||||||
this->state = TargetControllerState::SUSPENDED;
|
this->state = TargetControllerState::SUSPENDED;
|
||||||
this->eventManager.triggerEvent(
|
this->eventManager.triggerEvent(
|
||||||
@@ -181,6 +187,7 @@ void TargetController::suspend() {
|
|||||||
|
|
||||||
void TargetController::resume() {
|
void TargetController::resume() {
|
||||||
this->acquireHardware();
|
this->acquireHardware();
|
||||||
|
this->loadRegisterDescriptors();
|
||||||
|
|
||||||
this->eventListener->registerCallbackForEventType<Events::DebugSessionFinished>(
|
this->eventListener->registerCallbackForEventType<Events::DebugSessionFinished>(
|
||||||
std::bind(&TargetController::onDebugSessionFinishedEvent, this, std::placeholders::_1)
|
std::bind(&TargetController::onDebugSessionFinishedEvent, this, std::placeholders::_1)
|
||||||
@@ -252,6 +259,78 @@ void TargetController::resume() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TargetController::loadRegisterDescriptors() {
|
||||||
|
auto& targetDescriptor = this->getTargetDescriptor();
|
||||||
|
|
||||||
|
for (const auto& [registerType, registerDescriptors] : targetDescriptor.registerDescriptorsByType) {
|
||||||
|
for (const auto& registerDescriptor : registerDescriptors) {
|
||||||
|
auto startAddress = registerDescriptor.startAddress.value_or(0);
|
||||||
|
auto endAddress = startAddress + (registerDescriptor.size - 1);
|
||||||
|
|
||||||
|
if (!this->registerAddressRangeByMemoryType.contains(registerDescriptor.memoryType)) {
|
||||||
|
auto addressRange = TargetMemoryAddressRange();
|
||||||
|
addressRange.startAddress = startAddress;
|
||||||
|
addressRange.endAddress = endAddress;
|
||||||
|
this->registerAddressRangeByMemoryType.insert(
|
||||||
|
std::pair(registerDescriptor.memoryType, addressRange)
|
||||||
|
);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
auto& addressRange = this->registerAddressRangeByMemoryType.at(registerDescriptor.memoryType);
|
||||||
|
|
||||||
|
if (startAddress < addressRange.startAddress) {
|
||||||
|
addressRange.startAddress = startAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endAddress > addressRange.endAddress) {
|
||||||
|
addressRange.endAddress = endAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this->registerDescriptorsByMemoryType[registerDescriptor.memoryType].insert(registerDescriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TargetRegisterDescriptors TargetController::getRegisterDescriptorsWithinAddressRange(
|
||||||
|
std::uint32_t startAddress,
|
||||||
|
std::uint32_t endAddress,
|
||||||
|
Targets::TargetMemoryType memoryType
|
||||||
|
) {
|
||||||
|
auto output = TargetRegisterDescriptors();
|
||||||
|
|
||||||
|
if (this->registerAddressRangeByMemoryType.contains(memoryType)
|
||||||
|
&& this->registerDescriptorsByMemoryType.contains(memoryType)
|
||||||
|
) {
|
||||||
|
auto& registersAddressRange = this->registerAddressRangeByMemoryType.at(memoryType);
|
||||||
|
|
||||||
|
if (
|
||||||
|
(startAddress <= registersAddressRange.startAddress && endAddress >= registersAddressRange.startAddress)
|
||||||
|
|| (startAddress <= registersAddressRange.endAddress && endAddress >= registersAddressRange.startAddress)
|
||||||
|
) {
|
||||||
|
auto& registerDescriptors = this->registerDescriptorsByMemoryType.at(memoryType);
|
||||||
|
|
||||||
|
for (const auto& registerDescriptor : registerDescriptors) {
|
||||||
|
if (!registerDescriptor.startAddress.has_value() || registerDescriptor.size < 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto registerStartAddress = registerDescriptor.startAddress.value();
|
||||||
|
auto registerEndAddress = registerStartAddress + registerDescriptor.size;
|
||||||
|
|
||||||
|
if (
|
||||||
|
(startAddress <= registerStartAddress && endAddress >= registerStartAddress)
|
||||||
|
|| (startAddress <= registerEndAddress && endAddress >= registerStartAddress)
|
||||||
|
) {
|
||||||
|
output.insert(registerDescriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
void TargetController::acquireHardware() {
|
void TargetController::acquireHardware() {
|
||||||
auto debugToolName = this->environmentConfig.debugToolConfig.name;
|
auto debugToolName = this->environmentConfig.debugToolConfig.name;
|
||||||
auto targetName = this->environmentConfig.targetConfig.name;
|
auto targetName = this->environmentConfig.targetConfig.name;
|
||||||
@@ -364,6 +443,14 @@ void TargetController::emitErrorEvent(int correlationId) {
|
|||||||
this->eventManager.triggerEvent(errorEvent);
|
this->eventManager.triggerEvent(errorEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Targets::TargetDescriptor& TargetController::getTargetDescriptor() {
|
||||||
|
if (!this->cachedTargetDescriptor.has_value()) {
|
||||||
|
this->cachedTargetDescriptor = this->target->getDescriptor();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this->cachedTargetDescriptor.value();
|
||||||
|
}
|
||||||
|
|
||||||
void TargetController::onShutdownTargetControllerEvent(const Events::ShutdownTargetController&) {
|
void TargetController::onShutdownTargetControllerEvent(const Events::ShutdownTargetController&) {
|
||||||
this->shutdown();
|
this->shutdown();
|
||||||
}
|
}
|
||||||
@@ -401,12 +488,8 @@ void TargetController::onDebugSessionFinishedEvent(const DebugSessionFinished&)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TargetController::onExtractTargetDescriptor(const Events::ExtractTargetDescriptor& event) {
|
void TargetController::onExtractTargetDescriptor(const Events::ExtractTargetDescriptor& event) {
|
||||||
if (!this->cachedTargetDescriptor.has_value()) {
|
|
||||||
this->cachedTargetDescriptor = this->target->getDescriptor();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto targetDescriptorExtracted = std::make_shared<TargetDescriptorExtracted>();
|
auto targetDescriptorExtracted = std::make_shared<TargetDescriptorExtracted>();
|
||||||
targetDescriptorExtracted->targetDescriptor = this->cachedTargetDescriptor.value();
|
targetDescriptorExtracted->targetDescriptor = this->getTargetDescriptor();
|
||||||
|
|
||||||
targetDescriptorExtracted->correlationId = event.id;
|
targetDescriptorExtracted->correlationId = event.id;
|
||||||
this->eventManager.triggerEvent(targetDescriptorExtracted);
|
this->eventManager.triggerEvent(targetDescriptorExtracted);
|
||||||
@@ -495,6 +578,16 @@ void TargetController::onWriteRegistersEvent(const Events::WriteRegistersToTarge
|
|||||||
|
|
||||||
auto registersWrittenEvent = std::make_shared<Events::RegistersWrittenToTarget>();
|
auto registersWrittenEvent = std::make_shared<Events::RegistersWrittenToTarget>();
|
||||||
registersWrittenEvent->correlationId = event.id;
|
registersWrittenEvent->correlationId = event.id;
|
||||||
|
|
||||||
|
std::transform(
|
||||||
|
event.registers.begin(),
|
||||||
|
event.registers.end(),
|
||||||
|
std::inserter(registersWrittenEvent->descriptors, registersWrittenEvent->descriptors.begin()),
|
||||||
|
[] (const TargetRegister& targetRegister) {
|
||||||
|
return targetRegister.descriptor;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
this->eventManager.triggerEvent(registersWrittenEvent);
|
this->eventManager.triggerEvent(registersWrittenEvent);
|
||||||
|
|
||||||
} catch (const TargetOperationFailure& exception) {
|
} catch (const TargetOperationFailure& exception) {
|
||||||
@@ -525,6 +618,27 @@ void TargetController::onWriteMemoryEvent(const Events::WriteMemoryToTarget& eve
|
|||||||
memoryWrittenEvent->correlationId = event.id;
|
memoryWrittenEvent->correlationId = event.id;
|
||||||
this->eventManager.triggerEvent(memoryWrittenEvent);
|
this->eventManager.triggerEvent(memoryWrittenEvent);
|
||||||
|
|
||||||
|
if (this->registerDescriptorsByMemoryType.contains(event.memoryType)) {
|
||||||
|
/*
|
||||||
|
* The memory type we just wrote to contains some number of registers - if we've written to any address
|
||||||
|
* that is known to store the value of a register, trigger a RegistersWrittenToTarget event
|
||||||
|
*/
|
||||||
|
auto registerDescriptors = this->getRegisterDescriptorsWithinAddressRange(
|
||||||
|
event.startAddress,
|
||||||
|
static_cast<std::uint32_t>(event.startAddress + (event.buffer.size() - 1)),
|
||||||
|
event.memoryType
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!registerDescriptors.empty()) {
|
||||||
|
auto registersWrittenEvent = std::make_shared<Events::RegistersWrittenToTarget>();
|
||||||
|
registersWrittenEvent->correlationId = event.id;
|
||||||
|
registersWrittenEvent->descriptors = registerDescriptors;
|
||||||
|
|
||||||
|
this->eventManager.triggerEvent(registersWrittenEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: REMOVE THIS
|
||||||
if (this->target->memoryAddressRangeClashesWithIoPortRegisters(
|
if (this->target->memoryAddressRangeClashesWithIoPortRegisters(
|
||||||
event.memoryType,
|
event.memoryType,
|
||||||
event.startAddress,
|
event.startAddress,
|
||||||
|
|||||||
@@ -13,6 +13,8 @@
|
|||||||
#include "src/DebugToolDrivers/DebugTools.hpp"
|
#include "src/DebugToolDrivers/DebugTools.hpp"
|
||||||
#include "src/Targets/Target.hpp"
|
#include "src/Targets/Target.hpp"
|
||||||
#include "src/Targets/Targets.hpp"
|
#include "src/Targets/Targets.hpp"
|
||||||
|
#include "src/Targets/TargetRegister.hpp"
|
||||||
|
#include "src/Targets/TargetMemory.hpp"
|
||||||
|
|
||||||
#include "src/EventManager/EventManager.hpp"
|
#include "src/EventManager/EventManager.hpp"
|
||||||
#include "src/EventManager/EventListener.hpp"
|
#include "src/EventManager/EventListener.hpp"
|
||||||
@@ -65,6 +67,16 @@ namespace Bloom
|
|||||||
*/
|
*/
|
||||||
std::optional<Targets::TargetDescriptor> cachedTargetDescriptor;
|
std::optional<Targets::TargetDescriptor> cachedTargetDescriptor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Target register descriptors mapped by the memory type on which the register is stored.
|
||||||
|
*/
|
||||||
|
std::map<Targets::TargetMemoryType, Targets::TargetRegisterDescriptors> registerDescriptorsByMemoryType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Memory address ranges for target registers, mapped by the register memory type.
|
||||||
|
*/
|
||||||
|
std::map<Targets::TargetMemoryType, Targets::TargetMemoryAddressRange> registerAddressRangeByMemoryType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a mapping of supported debug tool names to lambdas. The lambdas should *only* instantiate
|
* Constructs a mapping of supported debug tool names to lambdas. The lambdas should *only* instantiate
|
||||||
* and return an instance to the derived DebugTool class. They should not attempt to establish
|
* and return an instance to the derived DebugTool class. They should not attempt to establish
|
||||||
@@ -210,6 +222,25 @@ namespace Bloom
|
|||||||
*/
|
*/
|
||||||
void resume();
|
void resume();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts address ranges and groups target register descriptors.
|
||||||
|
*/
|
||||||
|
void loadRegisterDescriptors();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves the descriptors of all target registers found within the given address range and memory type.
|
||||||
|
*
|
||||||
|
* @param startAddress
|
||||||
|
* @param endAddress
|
||||||
|
* @param memoryType
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Targets::TargetRegisterDescriptors getRegisterDescriptorsWithinAddressRange(
|
||||||
|
std::uint32_t startAddress,
|
||||||
|
std::uint32_t endAddress,
|
||||||
|
Targets::TargetMemoryType memoryType
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should fire any events queued on the target.
|
* Should fire any events queued on the target.
|
||||||
*/
|
*/
|
||||||
@@ -223,6 +254,8 @@ namespace Bloom
|
|||||||
*/
|
*/
|
||||||
void emitErrorEvent(int correlationId);
|
void emitErrorEvent(int correlationId);
|
||||||
|
|
||||||
|
Targets::TargetDescriptor& getTargetDescriptor();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit TargetController(EventManager& eventManager): eventManager(eventManager) {};
|
explicit TargetController(EventManager& eventManager): eventManager(eventManager) {};
|
||||||
|
|
||||||
|
|||||||
@@ -13,5 +13,11 @@ namespace Bloom::Targets
|
|||||||
OTHER,
|
OTHER,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TargetMemoryAddressRange
|
||||||
|
{
|
||||||
|
std::uint32_t startAddress = 0;
|
||||||
|
std::uint32_t endAddress = 0;
|
||||||
|
};
|
||||||
|
|
||||||
using TargetMemoryBuffer = std::vector<unsigned char>;
|
using TargetMemoryBuffer = std::vector<unsigned char>;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user