Began refactoring target descriptor structs.

This is incomplete - a partial commit of a substantial peice of work
This commit is contained in:
Nav
2024-03-21 15:03:06 +00:00
parent 6c82c4295a
commit 5d63b629e0
10 changed files with 394 additions and 112 deletions

View File

@@ -1,11 +1,14 @@
target_sources( target_sources(
Bloom Bloom
PRIVATE PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/TargetDescription/TargetDescriptionFile.cpp ${CMAKE_CURRENT_SOURCE_DIR}/TargetDescriptor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/TargetAddressSpaceDescriptor.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}/TargetRegisterDescriptor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/TargetMemoryCache.cpp ${CMAKE_CURRENT_SOURCE_DIR}/TargetMemoryCache.cpp
${CMAKE_CURRENT_SOURCE_DIR}/TargetPhysicalInterface.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/Avr8.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Microchip/AVR/AVR8/Avr8TargetConfig.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Microchip/AVR/AVR8/Avr8TargetConfig.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Microchip/AVR/AVR8/TargetDescription/TargetDescriptionFile.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Microchip/AVR/AVR8/TargetDescription/TargetDescriptionFile.cpp

View File

@@ -39,9 +39,11 @@ namespace Targets
struct BreakpointResources struct BreakpointResources
{ {
std::optional<std::uint16_t> maximumHardwareBreakpoints; std::optional<std::uint16_t> maximumHardwareBreakpoints = std::nullopt;
std::optional<std::uint16_t> maximumSoftwareBreakpoints; std::optional<std::uint16_t> maximumSoftwareBreakpoints = std::nullopt;
std::uint16_t reservedHardwareBreakpoints; std::uint16_t reservedHardwareBreakpoints = 0;
BreakpointResources() = default;
BreakpointResources( BreakpointResources(
std::optional<std::uint16_t> maximumHardwareBreakpoints, std::optional<std::uint16_t> maximumHardwareBreakpoints,

View File

@@ -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<std::string, TargetAddressSpaceDescriptor>& addressSpaceDescriptorsByKey,
const std::map<std::string, TargetPeripheralDescriptor>& peripheralDescriptorsByKey,
const std::vector<TargetVariant>& 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<const TargetAddressSpaceDescriptor>
> 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();
}
}

View File

@@ -9,7 +9,8 @@
#include "TargetFamily.hpp" #include "TargetFamily.hpp"
#include "TargetMemory.hpp" #include "TargetMemory.hpp"
#include "TargetRegisterDescriptor.hpp" #include "TargetAddressSpaceDescriptor.hpp"
#include "TargetPeripheralDescriptor.hpp"
#include "TargetVariant.hpp" #include "TargetVariant.hpp"
#include "TargetBreakpoint.hpp" #include "TargetBreakpoint.hpp"
@@ -17,50 +18,31 @@ namespace Targets
{ {
struct TargetDescriptor struct TargetDescriptor
{ {
std::string id;
TargetFamily family;
std::string name; std::string name;
TargetFamily family;
std::string marketId;
std::string vendorName; std::string vendorName;
std::map<TargetMemoryType, TargetMemoryDescriptor> memoryDescriptorsByType; std::map<std::string, TargetAddressSpaceDescriptor> addressSpaceDescriptorsByKey;
std::map<TargetRegisterDescriptorId, TargetRegisterDescriptor> registerDescriptorsById; std::map<std::string, TargetPeripheralDescriptor> peripheralDescriptorsByKey;
BreakpointResources breakpointResources;
std::vector<TargetVariant> variants; std::vector<TargetVariant> variants;
BreakpointResources breakpointResources;
TargetMemoryType programMemoryType;
TargetDescriptor( TargetDescriptor(
const std::string& id,
TargetFamily family,
const std::string& name, const std::string& name,
TargetFamily family,
const std::string& vendorName, const std::string& vendorName,
const std::map<TargetMemoryType, TargetMemoryDescriptor>& memoryDescriptorsByType, const std::string& marketName,
const std::map<TargetRegisterDescriptorId, TargetRegisterDescriptor>& registerDescriptorsById, const std::map<std::string, TargetAddressSpaceDescriptor>& addressSpaceDescriptorsByKey,
const BreakpointResources& breakpointResources, const std::map<std::string, TargetPeripheralDescriptor>& peripheralDescriptorsByKey,
const std::vector<TargetVariant>& variants, const std::vector<TargetVariant>& variants,
TargetMemoryType programMemoryType const BreakpointResources& breakpointResources
) );
: id(id)
, family(family)
, name(name)
, vendorName(vendorName)
, memoryDescriptorsByType(memoryDescriptorsByType)
, registerDescriptorsById(registerDescriptorsById)
, breakpointResources(breakpointResources)
, variants(variants)
, programMemoryType(programMemoryType)
{}
TargetRegisterDescriptorIds registerDescriptorIdsForType(TargetRegisterType type) { std::optional<std::reference_wrapper<const TargetAddressSpaceDescriptor>> tryGetAddressSpaceDescriptor(
auto output = TargetRegisterDescriptorIds(); const std::string& key
) const;
for (const auto& [descriptorId, descriptor] : this->registerDescriptorsById) { const TargetAddressSpaceDescriptor& getAddressSpaceDescriptor(const std::string& key) const;
if (descriptor.type == type) {
output.insert(descriptorId);
}
}
return output;
}
}; };
} }

View File

@@ -0,0 +1,47 @@
#include "TargetPeripheralDescriptor.hpp"
#include <ranges>
#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<std::string, TargetRegisterGroupDescriptor, std::less<void>>& registerGroupDescriptorsByKey
)
: key(key)
, name(name)
, registerGroupDescriptorsByKey(registerGroupDescriptorsByKey)
{}
std::optional<
std::reference_wrapper<const TargetRegisterGroupDescriptor>
> 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();
}
}

View File

@@ -0,0 +1,32 @@
#pragma once
#include <string>
#include <map>
#include <optional>
#include <functional>
#include <string_view>
#include "TargetRegisterGroupDescriptor.hpp"
namespace Targets
{
struct TargetPeripheralDescriptor
{
public:
std::string key;
std::string name;
std::map<std::string, TargetRegisterGroupDescriptor, std::less<void>> registerGroupDescriptorsByKey;
TargetPeripheralDescriptor(
const std::string& key,
const std::string& name,
const std::map<std::string, TargetRegisterGroupDescriptor, std::less<void>>& registerGroupDescriptorsByKey
);
std::optional<std::reference_wrapper<const TargetRegisterGroupDescriptor>> tryGetRegisterGroupDescriptor(
std::string_view keyStr
) const;
const TargetRegisterGroupDescriptor& getRegisterGroupDescriptor(std::string_view key) const;
};
}

View File

@@ -2,14 +2,5 @@
namespace Targets namespace Targets
{ {
std::size_t TargetRegisterDescriptor::getHash() const {
if (!this->cachedHash.has_value()) {
auto stringHasher = std::hash<std::string>();
this->cachedHash = stringHasher(std::to_string(this->startAddress.value_or(0))
+ "_" + std::to_string(static_cast<std::uint8_t>(this->type)));
}
return this->cachedHash.value();
}
} }

View File

@@ -9,22 +9,13 @@
#include <set> #include <set>
#include "TargetMemory.hpp" #include "TargetMemory.hpp"
#include "TargetAddressSpaceDescriptor.hpp"
namespace Targets namespace Targets
{ {
using TargetRegisterDescriptorId = std::uint32_t; using TargetRegisterDescriptorId = std::uint32_t;
using TargetRegisterDescriptorIds = std::set<Targets::TargetRegisterDescriptorId>; using TargetRegisterDescriptorIds = std::set<Targets::TargetRegisterDescriptorId>;
enum class TargetRegisterType: std::uint8_t
{
GENERAL_PURPOSE_REGISTER,
PROGRAM_COUNTER,
STACK_POINTER,
STATUS_REGISTER,
PORT_REGISTER,
OTHER,
};
struct TargetRegisterAccess struct TargetRegisterAccess
{ {
bool readable = false; bool readable = false;
@@ -37,89 +28,75 @@ namespace Targets
: readable(readable) : readable(readable)
, writable(writable) , writable(writable)
{} {}
bool operator == (const TargetRegisterAccess& other) const {
return this->readable == other.readable
&& this->writable == other.writable
;
}
}; };
struct TargetRegisterDescriptor struct TargetRegisterDescriptor
{ {
public: public:
TargetRegisterDescriptorId id; const TargetRegisterDescriptorId id;
TargetRegisterType type; std::string key;
std::optional<TargetMemoryAddress> startAddress; std::string name;
std::string addressSpaceKey;
const TargetAddressSpaceDescriptorId addressSpaceDescriptorId;
TargetMemoryAddress startAddress;
TargetMemorySize size; TargetMemorySize size;
TargetMemoryType memoryType; TargetRegisterAccess access;
std::optional<std::string> name;
std::optional<std::string> groupName;
std::optional<std::string> description; std::optional<std::string> description;
TargetRegisterAccess access;
TargetRegisterDescriptor( TargetRegisterDescriptor(
TargetRegisterType type, const std::string& key,
std::optional<TargetMemoryAddress> startAddress, const std::string& name,
const std::string& addressSpaceKey,
TargetAddressSpaceDescriptorId addressSpaceDescriptorId,
TargetMemoryAddress startAddress,
TargetMemorySize size, TargetMemorySize size,
TargetMemoryType memoryType, TargetRegisterAccess access,
std::optional<std::string> name, std::optional<std::string> description
std::optional<std::string> groupName,
std::optional<std::string> description,
TargetRegisterAccess access
) )
: id(++(TargetRegisterDescriptor::lastRegisterDescriptorId)) : id(++(TargetRegisterDescriptor::lastRegisterDescriptorId))
, type(type) , key(key)
, name(name)
, addressSpaceKey(addressSpaceKey)
, addressSpaceDescriptorId(addressSpaceDescriptorId)
, startAddress(startAddress) , startAddress(startAddress)
, size(size) , size(size)
, memoryType(memoryType)
, name(name)
, groupName(groupName)
, description(description)
, access(access) , access(access)
, description(description)
{}; {};
bool operator == (const TargetRegisterDescriptor& other) const { 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 { bool operator < (const TargetRegisterDescriptor& other) const {
if (this->type == other.type) { if (this->addressSpaceDescriptorId != other.addressSpaceDescriptorId) {
return this->startAddress.has_value() && other.startAddress.has_value() /*
? this->startAddress < other.startAddress * If the registers are within different address spaces, there is no meaningful way to sort them, so
: this->name < other.name * we just sort by name.
; */
return this->name < other.name;
} }
/* return this->startAddress < other.startAddress;
* 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();
} }
private: private:
mutable std::optional<std::size_t> cachedHash;
static inline std::atomic<TargetRegisterDescriptorId> lastRegisterDescriptorId = 0; static inline std::atomic<TargetRegisterDescriptorId> lastRegisterDescriptorId = 0;
std::size_t getHash() const;
friend std::hash<Targets::TargetRegisterDescriptor>;
}; };
using TargetRegisterDescriptors = std::set<TargetRegisterDescriptor>; using TargetRegisterDescriptors = std::set<TargetRegisterDescriptor>;
using TargetRegisterDescriptorMapping = std::map<TargetRegisterDescriptorId, TargetRegisterDescriptor>; using TargetRegisterDescriptorMapping = std::map<TargetRegisterDescriptorId, TargetRegisterDescriptor>;
} }
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<Targets::TargetRegisterDescriptor>
{
public:
std::size_t operator()(const Targets::TargetRegisterDescriptor& descriptor) const {
return descriptor.getHash();
}
};
}

View File

@@ -0,0 +1,86 @@
#include "TargetRegisterGroupDescriptor.hpp"
#include <cassert>
#include <numeric>
#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<std::string>& description,
const std::map<std::string, TargetRegisterDescriptor>& registerDescriptorsByKey,
const std::map<std::string, TargetRegisterGroupDescriptor, std::less<void>>& 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<const TargetRegisterGroupDescriptor>
> 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();
}
}

View File

@@ -0,0 +1,112 @@
#pragma once
#include <cstdint>
#include <string>
#include <map>
#include <functional>
#include <optional>
#include <string_view>
#include <ranges>
#include <concepts>
#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<std::string> description;
std::map<std::string, TargetRegisterDescriptor> registerDescriptorsByKey;
std::map<std::string, TargetRegisterGroupDescriptor, std::less<void>> subgroupDescriptorsByKey;
TargetRegisterGroupDescriptor(
const std::string& key,
const std::string& name,
const std::string& addressSpaceKey,
TargetAddressSpaceDescriptorId addressSpaceDescriptorId,
const std::optional<std::string>& description,
const std::map<std::string, TargetRegisterDescriptor>& registerDescriptorsByKey,
const std::map<std::string, TargetRegisterGroupDescriptor, std::less<void>>& 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 <typename KeysType>
requires
std::ranges::sized_range<KeysType>
std::optional<std::reference_wrapper<const TargetRegisterGroupDescriptor>> 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<std::reference_wrapper<const TargetRegisterGroupDescriptor>> 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;
};
}