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(
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

View File

@@ -39,9 +39,11 @@ namespace Targets
struct BreakpointResources
{
std::optional<std::uint16_t> maximumHardwareBreakpoints;
std::optional<std::uint16_t> maximumSoftwareBreakpoints;
std::uint16_t reservedHardwareBreakpoints;
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,

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 "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<TargetMemoryType, TargetMemoryDescriptor> memoryDescriptorsByType;
std::map<TargetRegisterDescriptorId, TargetRegisterDescriptor> registerDescriptorsById;
BreakpointResources breakpointResources;
std::map<std::string, TargetAddressSpaceDescriptor> addressSpaceDescriptorsByKey;
std::map<std::string, TargetPeripheralDescriptor> peripheralDescriptorsByKey;
std::vector<TargetVariant> 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<TargetMemoryType, TargetMemoryDescriptor>& memoryDescriptorsByType,
const std::map<TargetRegisterDescriptorId, TargetRegisterDescriptor>& registerDescriptorsById,
const BreakpointResources& breakpointResources,
const std::string& marketName,
const std::map<std::string, TargetAddressSpaceDescriptor>& addressSpaceDescriptorsByKey,
const std::map<std::string, TargetPeripheralDescriptor>& peripheralDescriptorsByKey,
const std::vector<TargetVariant>& 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<std::reference_wrapper<const TargetAddressSpaceDescriptor>> 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;
};
}

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
{
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 "TargetMemory.hpp"
#include "TargetAddressSpaceDescriptor.hpp"
namespace Targets
{
using TargetRegisterDescriptorId = std::uint32_t;
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
{
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<TargetMemoryAddress> startAddress;
const TargetRegisterDescriptorId id;
std::string key;
std::string name;
std::string addressSpaceKey;
const TargetAddressSpaceDescriptorId addressSpaceDescriptorId;
TargetMemoryAddress startAddress;
TargetMemorySize size;
TargetMemoryType memoryType;
std::optional<std::string> name;
std::optional<std::string> groupName;
TargetRegisterAccess access;
std::optional<std::string> description;
TargetRegisterAccess access;
TargetRegisterDescriptor(
TargetRegisterType type,
std::optional<TargetMemoryAddress> startAddress,
const std::string& key,
const std::string& name,
const std::string& addressSpaceKey,
TargetAddressSpaceDescriptorId addressSpaceDescriptorId,
TargetMemoryAddress startAddress,
TargetMemorySize size,
TargetMemoryType memoryType,
std::optional<std::string> name,
std::optional<std::string> groupName,
std::optional<std::string> description,
TargetRegisterAccess access
TargetRegisterAccess access,
std::optional<std::string> 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();
}
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
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->addressSpaceDescriptorId != other.addressSpaceDescriptorId) {
/*
* If the registers are of different type, there is no meaningful way to sort them, so we just use
* the unique hash.
* If the registers are within different address spaces, there is no meaningful way to sort them, so
* we just sort by name.
*/
return this->getHash() < other.getHash();
return this->name < other.name;
}
return this->startAddress < other.startAddress;
}
private:
mutable std::optional<std::size_t> cachedHash;
static inline std::atomic<TargetRegisterDescriptorId> lastRegisterDescriptorId = 0;
std::size_t getHash() const;
friend std::hash<Targets::TargetRegisterDescriptor>;
};
using TargetRegisterDescriptors = std::set<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;
};
}