From 5d63b629e0432caf28dbf97264387a1d78008a16 Mon Sep 17 00:00:00 2001 From: Nav Date: Thu, 21 Mar 2024 15:03:06 +0000 Subject: [PATCH] Began refactoring target descriptor structs. This is incomplete - a partial commit of a substantial peice of work --- src/Targets/CMakeLists.txt | 5 +- src/Targets/TargetBreakpoint.hpp | 8 +- src/Targets/TargetDescriptor.cpp | 50 ++++++++ src/Targets/TargetDescriptor.hpp | 52 +++----- src/Targets/TargetPeripheralDescriptor.cpp | 47 ++++++++ src/Targets/TargetPeripheralDescriptor.hpp | 32 +++++ src/Targets/TargetRegisterDescriptor.cpp | 9 -- src/Targets/TargetRegisterDescriptor.hpp | 105 +++++++--------- src/Targets/TargetRegisterGroupDescriptor.cpp | 86 ++++++++++++++ src/Targets/TargetRegisterGroupDescriptor.hpp | 112 ++++++++++++++++++ 10 files changed, 394 insertions(+), 112 deletions(-) create mode 100644 src/Targets/TargetDescriptor.cpp create mode 100644 src/Targets/TargetPeripheralDescriptor.cpp create mode 100644 src/Targets/TargetPeripheralDescriptor.hpp create mode 100644 src/Targets/TargetRegisterGroupDescriptor.cpp create mode 100644 src/Targets/TargetRegisterGroupDescriptor.hpp diff --git a/src/Targets/CMakeLists.txt b/src/Targets/CMakeLists.txt index adf97167..9f179c53 100755 --- a/src/Targets/CMakeLists.txt +++ b/src/Targets/CMakeLists.txt @@ -1,11 +1,14 @@ target_sources( Bloom PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/TargetDescription/TargetDescriptionFile.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/TargetDescriptor.cpp ${CMAKE_CURRENT_SOURCE_DIR}/TargetAddressSpaceDescriptor.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/TargetPeripheralDescriptor.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/TargetRegisterGroupDescriptor.cpp ${CMAKE_CURRENT_SOURCE_DIR}/TargetRegisterDescriptor.cpp ${CMAKE_CURRENT_SOURCE_DIR}/TargetMemoryCache.cpp ${CMAKE_CURRENT_SOURCE_DIR}/TargetPhysicalInterface.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/TargetDescription/TargetDescriptionFile.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Microchip/AVR/AVR8/Avr8.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Microchip/AVR/AVR8/Avr8TargetConfig.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Microchip/AVR/AVR8/TargetDescription/TargetDescriptionFile.cpp diff --git a/src/Targets/TargetBreakpoint.hpp b/src/Targets/TargetBreakpoint.hpp index c6543ed8..999ed93b 100644 --- a/src/Targets/TargetBreakpoint.hpp +++ b/src/Targets/TargetBreakpoint.hpp @@ -39,9 +39,11 @@ namespace Targets struct BreakpointResources { - std::optional maximumHardwareBreakpoints; - std::optional maximumSoftwareBreakpoints; - std::uint16_t reservedHardwareBreakpoints; + std::optional maximumHardwareBreakpoints = std::nullopt; + std::optional maximumSoftwareBreakpoints = std::nullopt; + std::uint16_t reservedHardwareBreakpoints = 0; + + BreakpointResources() = default; BreakpointResources( std::optional maximumHardwareBreakpoints, diff --git a/src/Targets/TargetDescriptor.cpp b/src/Targets/TargetDescriptor.cpp new file mode 100644 index 00000000..f9cd18f9 --- /dev/null +++ b/src/Targets/TargetDescriptor.cpp @@ -0,0 +1,50 @@ +#include "TargetDescriptor.hpp" + +#include "src/Exceptions/InternalFatalErrorException.hpp" + +namespace Targets +{ + TargetDescriptor::TargetDescriptor( + const std::string& name, + TargetFamily family, + const std::string& marketId, + const std::string& vendorName, + const std::map& addressSpaceDescriptorsByKey, + const std::map& peripheralDescriptorsByKey, + const std::vector& variants, + const BreakpointResources& breakpointResources + ) + : name(name) + , family(family) + , marketId(marketId) + , vendorName(vendorName) + , addressSpaceDescriptorsByKey(addressSpaceDescriptorsByKey) + , peripheralDescriptorsByKey(peripheralDescriptorsByKey) + , variants(variants) + , breakpointResources(breakpointResources) + {} + + std::optional< + std::reference_wrapper + > TargetDescriptor::tryGetAddressSpaceDescriptor(const std::string& key) const { + const auto descriptorIt = this->addressSpaceDescriptorsByKey.find(key); + + if (descriptorIt == this->addressSpaceDescriptorsByKey.end()) { + return std::nullopt; + } + + return std::cref(descriptorIt->second); + } + + const TargetAddressSpaceDescriptor& TargetDescriptor::getAddressSpaceDescriptor(const std::string& key) const { + const auto descriptor = this->tryGetAddressSpaceDescriptor(key); + if (!descriptor.has_value()) { + throw Exceptions::InternalFatalErrorException( + "Failed to get address space descriptor \"" + std::string(key) + + "\" from target descriptor - descriptor not found" + ); + } + + return descriptor->get(); + } +} diff --git a/src/Targets/TargetDescriptor.hpp b/src/Targets/TargetDescriptor.hpp index a6c43b1d..a476db03 100644 --- a/src/Targets/TargetDescriptor.hpp +++ b/src/Targets/TargetDescriptor.hpp @@ -9,7 +9,8 @@ #include "TargetFamily.hpp" #include "TargetMemory.hpp" -#include "TargetRegisterDescriptor.hpp" +#include "TargetAddressSpaceDescriptor.hpp" +#include "TargetPeripheralDescriptor.hpp" #include "TargetVariant.hpp" #include "TargetBreakpoint.hpp" @@ -17,50 +18,31 @@ namespace Targets { struct TargetDescriptor { - std::string id; - TargetFamily family; std::string name; + TargetFamily family; + std::string marketId; std::string vendorName; - std::map memoryDescriptorsByType; - std::map registerDescriptorsById; - BreakpointResources breakpointResources; + std::map addressSpaceDescriptorsByKey; + std::map peripheralDescriptorsByKey; std::vector variants; - - TargetMemoryType programMemoryType; + BreakpointResources breakpointResources; TargetDescriptor( - const std::string& id, - TargetFamily family, const std::string& name, + TargetFamily family, const std::string& vendorName, - const std::map& memoryDescriptorsByType, - const std::map& registerDescriptorsById, - const BreakpointResources& breakpointResources, + const std::string& marketName, + const std::map& addressSpaceDescriptorsByKey, + const std::map& peripheralDescriptorsByKey, const std::vector& variants, - TargetMemoryType programMemoryType - ) - : id(id) - , family(family) - , name(name) - , vendorName(vendorName) - , memoryDescriptorsByType(memoryDescriptorsByType) - , registerDescriptorsById(registerDescriptorsById) - , breakpointResources(breakpointResources) - , variants(variants) - , programMemoryType(programMemoryType) - {} + const BreakpointResources& breakpointResources + ); - TargetRegisterDescriptorIds registerDescriptorIdsForType(TargetRegisterType type) { - auto output = TargetRegisterDescriptorIds(); + std::optional> tryGetAddressSpaceDescriptor( + const std::string& key + ) const; - for (const auto& [descriptorId, descriptor] : this->registerDescriptorsById) { - if (descriptor.type == type) { - output.insert(descriptorId); - } - } - - return output; - } + const TargetAddressSpaceDescriptor& getAddressSpaceDescriptor(const std::string& key) const; }; } diff --git a/src/Targets/TargetPeripheralDescriptor.cpp b/src/Targets/TargetPeripheralDescriptor.cpp new file mode 100644 index 00000000..e8019638 --- /dev/null +++ b/src/Targets/TargetPeripheralDescriptor.cpp @@ -0,0 +1,47 @@ +#include "TargetPeripheralDescriptor.hpp" + +#include + +#include "src/Services/StringService.hpp" + +#include "src/Exceptions/InternalFatalErrorException.hpp" + +namespace Targets +{ + TargetPeripheralDescriptor::TargetPeripheralDescriptor( + const std::string& key, + const std::string& name, + const std::map>& registerGroupDescriptorsByKey + ) + : key(key) + , name(name) + , registerGroupDescriptorsByKey(registerGroupDescriptorsByKey) + {} + + std::optional< + std::reference_wrapper + > TargetPeripheralDescriptor::tryGetRegisterGroupDescriptor(std::string_view keyStr) const { + const auto keys = Services::StringService::split(keyStr, '.'); + + const auto firstGroupIt = this->registerGroupDescriptorsByKey.find(*keys.begin()); + return firstGroupIt != this->registerGroupDescriptorsByKey.end() + ? keys.size() > 1 + ? firstGroupIt->second.tryGetSubgroupDescriptor(keys | std::ranges::views::drop(1)) + : std::optional(std::cref(firstGroupIt->second)) + : std::nullopt; + } + + const TargetRegisterGroupDescriptor& TargetPeripheralDescriptor::getRegisterGroupDescriptor( + std::string_view key + ) const { + const auto descriptor = this->tryGetRegisterGroupDescriptor(key); + if (!descriptor.has_value()) { + throw Exceptions::InternalFatalErrorException( + "Failed to get register group descriptor \"" + std::string(key) + + "\" from peripheral \"" + this->key + "\" - register group descriptor not found" + ); + } + + return descriptor->get(); + } +} diff --git a/src/Targets/TargetPeripheralDescriptor.hpp b/src/Targets/TargetPeripheralDescriptor.hpp new file mode 100644 index 00000000..cd7f00f0 --- /dev/null +++ b/src/Targets/TargetPeripheralDescriptor.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "TargetRegisterGroupDescriptor.hpp" + +namespace Targets +{ + struct TargetPeripheralDescriptor + { + public: + std::string key; + std::string name; + std::map> registerGroupDescriptorsByKey; + + TargetPeripheralDescriptor( + const std::string& key, + const std::string& name, + const std::map>& registerGroupDescriptorsByKey + ); + + std::optional> tryGetRegisterGroupDescriptor( + std::string_view keyStr + ) const; + + const TargetRegisterGroupDescriptor& getRegisterGroupDescriptor(std::string_view key) const; + }; +} diff --git a/src/Targets/TargetRegisterDescriptor.cpp b/src/Targets/TargetRegisterDescriptor.cpp index ee3ddb47..19b18844 100644 --- a/src/Targets/TargetRegisterDescriptor.cpp +++ b/src/Targets/TargetRegisterDescriptor.cpp @@ -2,14 +2,5 @@ namespace Targets { - std::size_t TargetRegisterDescriptor::getHash() const { - if (!this->cachedHash.has_value()) { - auto stringHasher = std::hash(); - this->cachedHash = stringHasher(std::to_string(this->startAddress.value_or(0)) - + "_" + std::to_string(static_cast(this->type))); - } - - return this->cachedHash.value(); - } } diff --git a/src/Targets/TargetRegisterDescriptor.hpp b/src/Targets/TargetRegisterDescriptor.hpp index c656c72b..dc216bd9 100644 --- a/src/Targets/TargetRegisterDescriptor.hpp +++ b/src/Targets/TargetRegisterDescriptor.hpp @@ -9,22 +9,13 @@ #include #include "TargetMemory.hpp" +#include "TargetAddressSpaceDescriptor.hpp" namespace Targets { using TargetRegisterDescriptorId = std::uint32_t; using TargetRegisterDescriptorIds = std::set; - enum class TargetRegisterType: std::uint8_t - { - GENERAL_PURPOSE_REGISTER, - PROGRAM_COUNTER, - STACK_POINTER, - STATUS_REGISTER, - PORT_REGISTER, - OTHER, - }; - struct TargetRegisterAccess { bool readable = false; @@ -37,89 +28,75 @@ namespace Targets : readable(readable) , writable(writable) {} + + bool operator == (const TargetRegisterAccess& other) const { + return this->readable == other.readable + && this->writable == other.writable + ; + } }; struct TargetRegisterDescriptor { public: - TargetRegisterDescriptorId id; - TargetRegisterType type; - std::optional startAddress; + const TargetRegisterDescriptorId id; + std::string key; + std::string name; + std::string addressSpaceKey; + const TargetAddressSpaceDescriptorId addressSpaceDescriptorId; + TargetMemoryAddress startAddress; TargetMemorySize size; - TargetMemoryType memoryType; - - std::optional name; - std::optional groupName; + TargetRegisterAccess access; std::optional description; - TargetRegisterAccess access; - TargetRegisterDescriptor( - TargetRegisterType type, - std::optional startAddress, + const std::string& key, + const std::string& name, + const std::string& addressSpaceKey, + TargetAddressSpaceDescriptorId addressSpaceDescriptorId, + TargetMemoryAddress startAddress, TargetMemorySize size, - TargetMemoryType memoryType, - std::optional name, - std::optional groupName, - std::optional description, - TargetRegisterAccess access + TargetRegisterAccess access, + std::optional description ) : id(++(TargetRegisterDescriptor::lastRegisterDescriptorId)) - , type(type) + , key(key) + , name(name) + , addressSpaceKey(addressSpaceKey) + , addressSpaceDescriptorId(addressSpaceDescriptorId) , startAddress(startAddress) , size(size) - , memoryType(memoryType) - , name(name) - , groupName(groupName) - , description(description) , access(access) + , description(description) {}; bool operator == (const TargetRegisterDescriptor& other) const { - return this->getHash() == other.getHash(); + return this->key == other.key + && this->name == other.name + && this->addressSpaceDescriptorId == other.addressSpaceDescriptorId + && this->startAddress == other.startAddress + && this->size == other.size + && this->access == other.access + && this->description == other.description + ; } bool operator < (const TargetRegisterDescriptor& other) const { - if (this->type == other.type) { - return this->startAddress.has_value() && other.startAddress.has_value() - ? this->startAddress < other.startAddress - : this->name < other.name - ; + if (this->addressSpaceDescriptorId != other.addressSpaceDescriptorId) { + /* + * If the registers are within different address spaces, there is no meaningful way to sort them, so + * we just sort by name. + */ + return this->name < other.name; } - /* - * If the registers are of different type, there is no meaningful way to sort them, so we just use - * the unique hash. - */ - return this->getHash() < other.getHash(); + return this->startAddress < other.startAddress; } private: - mutable std::optional cachedHash; static inline std::atomic lastRegisterDescriptorId = 0; - std::size_t getHash() const; - - friend std::hash; }; using TargetRegisterDescriptors = std::set; using TargetRegisterDescriptorMapping = std::map; } - -namespace std -{ - /** - * Hashing function for TargetRegisterDescriptor type. - * - * This is required in order to use TargetRegisterDescriptor as a key in an std::unordered_map (see the BiMap - * class) - */ - template<> - class hash - { - public: - std::size_t operator()(const Targets::TargetRegisterDescriptor& descriptor) const { - return descriptor.getHash(); - } - }; -} diff --git a/src/Targets/TargetRegisterGroupDescriptor.cpp b/src/Targets/TargetRegisterGroupDescriptor.cpp new file mode 100644 index 00000000..cb8c478f --- /dev/null +++ b/src/Targets/TargetRegisterGroupDescriptor.cpp @@ -0,0 +1,86 @@ +#include "TargetRegisterGroupDescriptor.hpp" + +#include +#include + +#include "src/Services/StringService.hpp" +#include "src/Exceptions/InternalFatalErrorException.hpp" + +namespace Targets +{ + TargetRegisterGroupDescriptor::TargetRegisterGroupDescriptor( + const std::string& key, + const std::string& name, + const std::string& addressSpaceKey, + TargetAddressSpaceDescriptorId addressSpaceDescriptorId, + const std::optional& description, + const std::map& registerDescriptorsByKey, + const std::map>& subgroupDescriptorsByKey + ) + : key(key) + , name(name) + , addressSpaceKey(addressSpaceKey) + , addressSpaceDescriptorId(addressSpaceDescriptorId) + , description(description) + , registerDescriptorsByKey(registerDescriptorsByKey) + , subgroupDescriptorsByKey(subgroupDescriptorsByKey) + {} + + TargetMemoryAddress TargetRegisterGroupDescriptor::startAddress() const { + assert(!this->registerDescriptorsByKey.empty() || !this->subgroupDescriptorsByKey.empty()); + + auto startAddress = TargetMemoryAddress{0}; + + for (const auto& [key, registerDescriptor] : this->registerDescriptorsByKey) { + if (registerDescriptor.startAddress < startAddress) { + startAddress = registerDescriptor.startAddress; + } + } + + for (const auto& [key, groupDescriptor] : this->subgroupDescriptorsByKey) { + const auto groupStartAddress = groupDescriptor.startAddress(); + if (groupStartAddress < startAddress) { + startAddress = groupStartAddress; + } + } + + return startAddress; + } + + TargetMemorySize TargetRegisterGroupDescriptor::size() const { + return std::accumulate( + this->registerDescriptorsByKey.begin(), + this->registerDescriptorsByKey.end(), + TargetMemorySize{0}, + [] (TargetMemorySize size, const decltype(this->registerDescriptorsByKey)::value_type& pair) { + return size + pair.second.size; + } + ) + std::accumulate( + this->subgroupDescriptorsByKey.begin(), + this->subgroupDescriptorsByKey.end(), + TargetMemorySize{0}, + [] (TargetMemorySize size, const decltype(this->subgroupDescriptorsByKey)::value_type& pair) { + return size + pair.second.size(); + } + ); + } + + std::optional< + std::reference_wrapper + > TargetRegisterGroupDescriptor::tryGetSubgroupDescriptor(std::string_view keyStr) const { + return this->tryGetSubgroupDescriptor(Services::StringService::split(keyStr, '.')); + } + + const TargetRegisterGroupDescriptor& TargetRegisterGroupDescriptor::getSubgroupDescriptor( + std::string_view keyStr + ) const { + const auto subgroup = this->tryGetSubgroupDescriptor(keyStr); + if (!subgroup.has_value()) { + throw Exceptions::InternalFatalErrorException( + "Failed to get subgroup \"" + std::string(keyStr) + "\" from register group - subgroup not found" + ); + } + + return subgroup->get(); + } +} diff --git a/src/Targets/TargetRegisterGroupDescriptor.hpp b/src/Targets/TargetRegisterGroupDescriptor.hpp new file mode 100644 index 00000000..786d0ecb --- /dev/null +++ b/src/Targets/TargetRegisterGroupDescriptor.hpp @@ -0,0 +1,112 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "TargetMemory.hpp" +#include "TargetAddressSpaceDescriptor.hpp" +#include "TargetRegisterDescriptor.hpp" + +namespace Targets +{ + struct TargetRegisterGroupDescriptor + { + public: + std::string key; + std::string name; + std::string addressSpaceKey; + const TargetAddressSpaceDescriptorId addressSpaceDescriptorId; + std::optional description; + std::map registerDescriptorsByKey; + std::map> subgroupDescriptorsByKey; + + TargetRegisterGroupDescriptor( + const std::string& key, + const std::string& name, + const std::string& addressSpaceKey, + TargetAddressSpaceDescriptorId addressSpaceDescriptorId, + const std::optional& description, + const std::map& registerDescriptorsByKey, + const std::map>& subgroupDescriptorsByKey + ); + + /** + * Calculates the start address of the register group. + * + * Excessive calls to this function is discouraged, as the implementation is quite slow. + * + * @return + */ + TargetMemoryAddress startAddress() const; + + /** + * Calculates the size of this register group. + * + * Excessive calls to this function is discouraged, as the implementation is quite slow. + * + * @return + */ + TargetMemorySize size() const; + + /** + * Attempts to fetch a subgroup with a set of keys. + * + * @tparam KeysType + * @param keys + * @return + */ + template + requires + std::ranges::sized_range + std::optional> tryGetSubgroupDescriptor( + KeysType keys + ) const { + auto firstSubgroupIt = this->subgroupDescriptorsByKey.find(*(keys.begin())); + if (firstSubgroupIt == this->subgroupDescriptorsByKey.end()) { + return std::nullopt; + } + + auto subgroup = std::optional(std::cref(firstSubgroupIt->second)); + for (const auto key : keys | std::ranges::views::drop(1)) { + subgroup = subgroup->get().tryGetSubgroupDescriptor(key); + + if (!subgroup.has_value()) { + break; + } + } + + return subgroup; + } + + /** + * Attempts to fetch a subgroup with a set of keys in the form of a string in "dot notation". + * + * @param keyStr + * A string in "dot notation", containing each key seperated with a period/dot character (e.g. + * "parent.child.grandchild"). + * + * @return + */ + std::optional> tryGetSubgroupDescriptor( + std::string_view keyStr + ) const; + + /** + * Fetches a subgroup with a set of keys in the form of a string in "dot notation". If the subgroup is not + * found, an InternalFatalErrorException is thrown. + * + * @param keyStr + * A string in "dot notation", containing each key seperated with a period/dot character (e.g. + * "parent.child.grandchild"). + * + * @return + */ + const TargetRegisterGroupDescriptor& getSubgroupDescriptor(std::string_view keyStr) const; + }; +}