Massive refactor to accommodate RISC-V targets

- Refactored entire codebase (excluding the Insight component) to accommodate multiple target architectures (no longer specific to AVR)
- Deleted 'generate SVD' GDB monitor command - I will eventually move this functionality to the Bloom website
- Added unit size property to address spaces
- Many other changes which I couldn't be bothered to describe here
This commit is contained in:
Nav
2024-07-23 21:14:22 +01:00
parent 2986934485
commit 6cdbfbe950
331 changed files with 8815 additions and 8565 deletions

View File

@@ -3,16 +3,24 @@ target_sources(
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/TargetDescriptor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/TargetAddressSpaceDescriptor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/TargetMemorySegmentDescriptor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/TargetPeripheralDescriptor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/TargetPeripheralSignalDescriptor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/TargetRegisterGroupDescriptor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/TargetRegisterDescriptor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/TargetBitFieldDescriptor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/TargetPinoutDescriptor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/TargetPinDescriptor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/TargetVariantDescriptor.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/TargetDescriptionFile.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Microchip/AVR/AVR8/OpcodeDecoder/Decoder.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Microchip/AVR8/Avr8.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Microchip/AVR8/Avr8TargetConfig.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Microchip/AVR8/TargetDescriptionFile.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Microchip/AVR8/OpcodeDecoder/Decoder.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Microchip/AVR8/IspParameters.cpp
${CMAKE_CURRENT_SOURCE_DIR}/RiscV/RiscV.cpp
${CMAKE_CURRENT_SOURCE_DIR}/RiscV/TargetDescription/TargetDescriptionFile.cpp
${CMAKE_CURRENT_SOURCE_DIR}/RiscV/RiscVTargetConfig.cpp
${CMAKE_CURRENT_SOURCE_DIR}/RiscV/TargetDescriptionFile.cpp
)

File diff suppressed because it is too large Load Diff

View File

@@ -1,220 +0,0 @@
#pragma once
#include <cstdint>
#include <queue>
#include <utility>
#include <optional>
#include "src/Targets/Target.hpp"
#include "src/DebugToolDrivers/DebugTool.hpp"
#include "src/DebugToolDrivers/TargetInterfaces/Microchip/AVR/AVR8/Avr8DebugInterface.hpp"
#include "src/DebugToolDrivers/TargetInterfaces/Microchip/AVR/AvrIspInterface.hpp"
#include "Family.hpp"
#include "TargetParameters.hpp"
#include "PadDescriptor.hpp"
#include "ProgramMemorySection.hpp"
#include "ProgrammingSession.hpp"
#include "src/Targets/Microchip/AVR/Fuse.hpp"
#include "src/Targets/TargetPhysicalInterface.hpp"
#include "src/Targets/TargetRegisterDescriptor.hpp"
#include "src/Targets/TargetBreakpoint.hpp"
#include "TargetDescription/TargetDescriptionFile.hpp"
#include "Avr8TargetConfig.hpp"
namespace Targets::Microchip::Avr::Avr8Bit
{
class Avr8: public Target
{
public:
explicit Avr8(
const TargetConfig& targetConfig,
TargetDescription::TargetDescriptionFile&& targetDescriptionFile
);
/*
* The functions below implement the Target interface for AVR8 targets.
*
* See the Targets::Target abstract class for documentation on the expected behaviour of
* each function.
*/
/**
* All AVR8 compatible debug tools must provide a valid Avr8Interface.
*
* @param debugTool
* @return
*/
bool supportsDebugTool(DebugTool* debugTool) override;
void setDebugTool(DebugTool* debugTool) override;
void activate() override;
void deactivate() override;
TargetDescriptor getDescriptor() override;
void run(std::optional<TargetMemoryAddress> toAddress = std::nullopt) override;
void stop() override;
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 writeRegisters(const TargetRegisters& registers) override;
TargetRegisters readRegisters(const Targets::TargetRegisterDescriptorIds& descriptorIds) override;
TargetMemoryBuffer readMemory(
TargetMemoryType memoryType,
TargetMemoryAddress startAddress,
TargetMemorySize bytes,
const std::set<Targets::TargetMemoryAddressRange>& excludedAddressRanges = {}
) override;
void writeMemory(
TargetMemoryType memoryType,
TargetMemoryAddress startAddress,
const TargetMemoryBuffer& buffer
) override;
void eraseMemory(TargetMemoryType memoryType) override;
TargetState getState() override;
TargetMemoryAddress getProgramCounter() override;
void setProgramCounter(TargetMemoryAddress programCounter) override;
TargetStackPointer getStackPointer() override;
std::map<int, TargetPinState> getPinStates(int variantId) override;
void setPinState(
const TargetPinDescriptor& pinDescriptor,
const TargetPinState& state
) override;
void enableProgrammingMode() override;
void disableProgrammingMode() override;
bool programmingModeEnabled() override;
protected:
DebugToolDrivers::TargetInterfaces::TargetPowerManagementInterface* targetPowerManagementInterface = nullptr;
DebugToolDrivers::TargetInterfaces::Microchip::Avr::Avr8::Avr8DebugInterface* avr8DebugInterface = nullptr;
DebugToolDrivers::TargetInterfaces::Microchip::Avr::AvrIspInterface* avrIspInterface = nullptr;
Avr8TargetConfig targetConfig;
TargetDescription::TargetDescriptionFile targetDescriptionFile;
TargetSignature signature;
std::string name;
Family family;
TargetParameters targetParameters;
std::set<Targets::TargetPhysicalInterface> physicalInterfaces;
std::map<std::string, PadDescriptor> padDescriptorsByName;
std::map<int, TargetVariant> targetVariantsById;
TargetRegisterDescriptor stackPointerRegisterDescriptor;
TargetRegisterDescriptor statusRegisterDescriptor;
/**
* On some AVR8 targets, like the ATmega328P, a cleared fuse bit means the fuse is "programmed" (enabled).
* And a set bit means the fuse is "un-programmed" (disabled). But on others, like the ATmega4809, it's the
* other way around (set bit == enabled, cleared bit == disabled).
*
* The FuseEnableStrategy specifies the strategy of enabling a fuse. It's extracted from the TDF.
* See TargetDescription::getFuseEnableStrategy() for more.
*/
FuseEnableStrategy fuseEnableStrategy;
std::map<TargetRegisterDescriptorId, TargetRegisterDescriptor> targetRegisterDescriptorsById;
std::map<TargetMemoryType, TargetMemoryDescriptor> targetMemoryDescriptorsByType;
std::optional<ProgrammingSession> activeProgrammingSession = std::nullopt;
/**
* Populates this->targetRegisterDescriptorsById with registers extracted from the TDF, as well as general
* purpose and other CPU registers.
*/
void loadTargetRegisterDescriptors();
void loadTargetMemoryDescriptors();
BreakpointResources getBreakpointResources();
/**
* Checks if a particular fuse is enabled in the given fuse byte value. Takes the target's fuse enable strategy
* into account.
*
* @param descriptor
* @param fuseByteValue
*
* @return
*/
bool isFuseEnabled(const FuseBitsDescriptor& descriptor, unsigned char fuseByteValue) const;
/**
* Enables/disables a fuse within the given fuse byte, using the target's fuse enable strategy.
*
* @param descriptor
* @param fuseByteValue
* @param enabled
*
* @return
* The updated fuse byte value.
*/
unsigned char setFuseEnabled(
const FuseBitsDescriptor& descriptor,
unsigned char fuseByteValue,
bool enabled
) const;
/**
* Updates the debugWire enable (DWEN) fuse bit on the AVR target.
*
* @param enable
* True to enable the fuse, false to disable it.
*/
void updateDwenFuseBit(bool enable);
/**
* Updates the On-chip debug enable (OCDEN) fuse bit on the AVR target.
*
* @param enable
* True to enable the fuse, false to disable it.
*/
void updateOcdenFuseBit(bool enable);
/**
* Updates the "Preserve EEPROM" (EESAVE) fuse bit on the AVR target.
*
* @param enable
* True to enable the fuse, false to disable it.
*
* @return
* True if the fuse bit was updated. False if the fuse bit was already set to the desired value.
*/
bool updateEesaveFuseBit(bool enable);
/**
* Resolves the program memory section from a program memory address.
*
* Currently unused, but will be needed soon.
*
* @param address
* @return
*/
ProgramMemorySection getProgramMemorySectionFromAddress(TargetMemoryAddress address);
};
}

View File

@@ -1,28 +0,0 @@
#pragma once
#include <string>
#include <cstdint>
#include <optional>
namespace Targets::Microchip::Avr::Avr8Bit
{
/**
* Pin configurations for AVR8 targets may vary across target variants. This is why we must differentiate a pin
* to a pad. A pin is mapped to a pad, but this mapping is variant specific. For example, pin 4 on
* the ATmega328P-PN (DIP variant) is mapped to a GPIO pad (PORTD/PIN2), but on the QFN variant (ATmega328P-MN),
* pin 4 is mapped to a GND pad.
*
* PadDescriptor describes a single pad on an AVR8 target. On target configuration, PadDescriptors are
* generated from the AVR8 target description file. These descriptors are mapped to pad names.
* See Avr8::loadPadDescriptors() for more.
*/
struct PadDescriptor
{
std::string name;
std::optional<std::uint8_t> gpioPinNumber;
std::optional<std::uint16_t> gpioPortAddress;
std::optional<std::uint16_t> gpioPortInputAddress;
std::optional<std::uint16_t> gpioDdrAddress;
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,282 +0,0 @@
#pragma once
#include <set>
#include <optional>
#include "src/Targets/TargetDescription/TargetDescriptionFile.hpp"
#include "src/Targets/TargetVariant.hpp"
#include "src/Targets/TargetRegisterDescriptor.hpp"
#include "src/Targets/Microchip/AVR/TargetSignature.hpp"
#include "src/Targets/Microchip/AVR/IspParameters.hpp"
#include "src/Targets/Microchip/AVR/Fuse.hpp"
#include "src/Targets/Microchip/AVR/AVR8/Family.hpp"
#include "src/Targets/Microchip/AVR/AVR8/TargetParameters.hpp"
#include "src/Targets/Microchip/AVR/AVR8/PadDescriptor.hpp"
namespace Targets::Microchip::Avr::Avr8Bit
{
/**
* Represents an AVR8 TDF. See the Targets::TargetDescription::TargetDescriptionFile close for more on TDFs.
*
* During the build process, we generate a JSON file containing a mapping of AVR8 target signatures to target
* description file paths. Bloom uses this mapping to find a particular target description file, for AVR8 targets,
* given a target signature. See directory "build/resources/TargetDescriptionFiles".
* The generation of the JSON mapping, is done by a PHP script:
* "build/scripts/CopyAvrPartFilesAndCreateMapping.php". This script is invoked via a custom command, at build time.
*
* For more information of TDFs, see src/Targets/TargetDescription/README.md
*/
class TargetDescriptionFile: public Targets::TargetDescription::TargetDescriptionFile
{
public:
/**
* Extends TDF initialisation to include the loading of physical interfaces for debugging AVR8 targets, among
* other things.
*
* @param xml
*/
explicit TargetDescriptionFile(const std::string& xmlFilePath);
/**
* Extracts the AVR8 target signature from the TDF.
*
* @return
*/
[[nodiscard]] TargetSignature getTargetSignature() const;
/**
* Extracts the AVR8 target family from the TDF.
*
* @return
*/
[[nodiscard]] Family getAvrFamily() const;
[[nodiscard]] const Targets::TargetDescription::AddressSpace& getProgramAddressSpace() const;
[[nodiscard]] const Targets::TargetDescription::AddressSpace& getRamAddressSpace() const;
[[nodiscard]] const Targets::TargetDescription::AddressSpace& getEepromAddressSpace() const;
[[nodiscard]] const Targets::TargetDescription::AddressSpace& getIoAddressSpace() const;
[[nodiscard]] const Targets::TargetDescription::AddressSpace& getSignatureAddressSpace() const;
[[nodiscard]] const Targets::TargetDescription::AddressSpace& getFuseAddressSpace() const;
[[nodiscard]] const Targets::TargetDescription::AddressSpace& getLockbitAddressSpace() const;
[[nodiscard]] const Targets::TargetDescription::MemorySegment& getProgramMemorySegment() const;
[[nodiscard]] const Targets::TargetDescription::MemorySegment& getRamMemorySegment() const;
[[nodiscard]] const Targets::TargetDescription::MemorySegment& getEepromMemorySegment() const;
[[nodiscard]] const Targets::TargetDescription::MemorySegment& getIoMemorySegment() const;
[[nodiscard]] const Targets::TargetDescription::MemorySegment& getSignatureMemorySegment() const;
[[nodiscard]] const Targets::TargetDescription::MemorySegment& getFuseMemorySegment() const;
[[nodiscard]] const Targets::TargetDescription::MemorySegment& getLockbitMemorySegment() const;
/**
* Constructs an instance of TargetParameters, for the AVR8 target, with data from the TDF.
*
* @return
*/
[[nodiscard]] TargetParameters getTargetParameters() const;
/**
* Extracts the target's ISP parameters from the TDF.
*
* @return
*/
[[nodiscard]] IspParameters getIspParameters() const;
/**
* Extracts the target's fuse enable strategy.
*
* @return
* std::nullopt if the TDF doesn't contain a fuse enable strategy.
*/
[[nodiscard]] std::optional<FuseEnableStrategy> getFuseEnableStrategy() const;
/**
* Constructs a FuseBitDescriptor for the debugWire enable (DWEN) fuse bit, with information extracted from
* the TDF.
*
* @return
* std::nullopt if the DWEN bit field could not be found in the TDF.
*/
[[nodiscard]] std::optional<FuseBitsDescriptor> getDwenFuseBitsDescriptor() const;
/**
* Constructs a FuseBitDescriptor for the SPI enable (SPIEN) fuse bit, with information extracted from
* the TDF.
*
* @return
* std::nullopt if the SPIEN bit field could not be found in the TDF.
*/
[[nodiscard]] std::optional<FuseBitsDescriptor> getSpienFuseBitsDescriptor() const;
/**
* Constructs a FuseBitDescriptor for the OCD enable (OCDEN) fuse bit, with information extracted from
* the TDF.
*
* @return
* std::nullopt if the OCDEN bit field could not be found in the TDF.
*/
[[nodiscard]] std::optional<FuseBitsDescriptor> getOcdenFuseBitsDescriptor() const;
/**
* Constructs a FuseBitDescriptor for the JTAG enable (JTAGEN) fuse bit, with information extracted from
* the TDF.
*
* @return
* std::nullopt if the JTAGEN bit field could not be found in the TDF.
*/
[[nodiscard]] std::optional<FuseBitsDescriptor> getJtagenFuseBitsDescriptor() const;
/**
* Constructs a FuseBitDescriptor for the "Preserve EEPROM" (EESAVE) fuse bit, with information extracted from
* the TDF.
*
* @return
* std::nullopt if the EESAVE bit field could not be found in the TDF.
*/
[[nodiscard]] std::optional<FuseBitsDescriptor> getEesaveFuseBitsDescriptor() const;
/**
* Returns a mapping of all pad descriptors extracted from TDF, mapped by name.
*
* @return
*/
[[nodiscard]] const auto& getPadDescriptorsMappedByName() const {
return this->padDescriptorsByName;
}
/**
* Returns a mapping of all target variants extracted from the TDF, mapped by ID.
*
* @return
*/
[[nodiscard]] const auto& getVariantsMappedById() const {
return this->targetVariantsById;
}
/**
* Returns a mapping of all target register descriptors extracted from the TDF, by ID.
*
* @return
*/
[[nodiscard]] const auto& getRegisterDescriptorsMappedById() const {
return this->targetRegisterDescriptorsById;
}
private:
/**`
* AVR8 target description files include the target family name. This method returns a mapping of part
* description family name strings to Family enum values.
*
* TODO: the difference in AVR8 family variations, like "tinyAVR" and "tinyAVR 2" may require attention.
*
* @return
*/
static inline auto getFamilyNameToEnumMapping() {
// All keys should be lower-case.
return std::map<std::string, Family> {
{"megaavr", Family::MEGA},
{"avr mega", Family::MEGA},
{"avr xmega", Family::XMEGA},
{"avr tiny", Family::TINY},
{"tinyavr", Family::TINY},
{"tinyavr 2", Family::TINY},
{"avr da", Family::DA},
{"avr db", Family::DB},
{"avr dd", Family::DD},
{"avr ea", Family::EA},
};
};
std::string avrFamilyName;
std::map<std::string, PadDescriptor> padDescriptorsByName;
std::map<int, TargetVariant> targetVariantsById;
std::map<TargetRegisterDescriptorId, TargetRegisterDescriptor> targetRegisterDescriptorsById;
/**
* Populates this->supportedPhysicalInterfaces with physical interfaces defined in the TDF.
*/
void loadSupportedPhysicalInterfaces();
/**
* Generates a collection of PadDescriptor objects from data in the TDF and populates this->padDescriptorsByName.
*/
void loadPadDescriptors();
/**
* Loads all variants for the AVR8 target, from the TDF, and populates this->targetVariantsById.
*/
void loadTargetVariants();
/**
* Loads all register descriptors from the TDF, and populates this->targetRegisterDescriptorsById.
*/
void loadTargetRegisterDescriptors();
/**
* Gets the register address offset for a specific peripheral module.
*
* @param moduleName
* @param instanceName
* @param registerGroupName
* @return
*/
Targets::TargetMemoryAddress getPeripheralModuleRegisterAddressOffset(
const std::string& moduleName,
const std::string& instanceName,
const std::string& registerGroupName
) const;
[[nodiscard]] std::optional<FuseBitsDescriptor> getFuseBitsDescriptorByName(
const std::string& fuseBitName
) const;
[[nodiscard]] std::optional<Targets::TargetDescription::AddressSpace> getProgramMemoryAddressSpace() const;
[[nodiscard]] std::optional<Targets::TargetDescription::MemorySegment> getFlashApplicationMemorySegment(
const Targets::TargetDescription::AddressSpace& programAddressSpace
) const;
[[nodiscard]] std::optional<Targets::TargetDescription::MemorySegment> getRegisterMemorySegment() const;
[[nodiscard]] std::optional<Targets::TargetDescription::MemorySegment> getFirstBootSectionMemorySegment() const;
[[nodiscard]] std::optional<Targets::TargetDescription::MemorySegment> getLockbitsMemorySegment() const;
[[nodiscard]] std::optional<Targets::TargetDescription::RegisterGroup> getCpuRegisterGroup() const;
[[nodiscard]] std::optional<Targets::TargetDescription::RegisterGroup> getBootLoadRegisterGroup() const;
[[nodiscard]] std::optional<Targets::TargetDescription::RegisterGroup> getEepromRegisterGroup() const;
[[nodiscard]] std::optional<Targets::TargetDescription::Register> getStatusRegister() const;
[[nodiscard]] std::optional<Targets::TargetDescription::Register> getStackPointerRegister() const;
[[nodiscard]] std::optional<Targets::TargetDescription::Register> getStackPointerHighRegister() const;
[[nodiscard]] std::optional<Targets::TargetDescription::Register> getStackPointerLowRegister() const;
[[nodiscard]] std::optional<Targets::TargetDescription::Register> getOscillatorCalibrationRegister() const;
[[nodiscard]] std::optional<Targets::TargetDescription::Register> getSpmcsRegister() const;
[[nodiscard]] std::optional<Targets::TargetDescription::Register> getSpmcRegister() const;
[[nodiscard]] std::optional<Targets::TargetDescription::Register> getEepromAddressRegister() const;
[[nodiscard]] std::optional<Targets::TargetDescription::Register> getEepromAddressLowRegister() const;
[[nodiscard]] std::optional<Targets::TargetDescription::Register> getEepromAddressHighRegister() const;
[[nodiscard]] std::optional<Targets::TargetDescription::Register> getEepromDataRegister() const;
[[nodiscard]] std::optional<Targets::TargetDescription::Register> getEepromControlRegister() const;
/**
* Loads target parameters that are specific to debugWire and mega JTAG sessions.
*
* @param targetParameters
*/
virtual void loadDebugWireAndJtagTargetParameters(TargetParameters& targetParameters) const;
/**
* Loads target parameters that are specific to PDI sessions.
*
* @param targetParameters
*/
virtual void loadPdiTargetParameters(TargetParameters& targetParameters) const;
/**
* Loads target parameters that are specific to UPDI sessions.
*
* @param targetParameters
*/
virtual void loadUpdiTargetParameters(TargetParameters& targetParameters) const;
};
}

View File

@@ -1,69 +0,0 @@
#pragma once
#include <cstdint>
#include <optional>
#include "../TargetSignature.hpp"
#include "Family.hpp"
namespace Targets::Microchip::Avr::Avr8Bit
{
/**
* Holds all parameters that would be required for configuring a debug tool, for an AVR8 target.
*
* This can usually be extracted from the AVR8 TDF.
* See Targets::Microchip::Avr::Avr8Bit::TargetDescription::TargetDescriptionFile::getTargetParameters();
*/
struct TargetParameters
{
std::optional<std::uint32_t> mappedIoSegmentStartAddress;
std::optional<std::uint16_t> mappedIoSegmentSize;
std::optional<std::uint32_t> bootSectionStartAddress;
std::optional<std::uint32_t> gpRegisterStartAddress;
std::optional<std::uint32_t> gpRegisterSize;
std::optional<std::uint16_t> flashPageSize;
std::optional<std::uint32_t> flashSize;
std::optional<std::uint32_t> flashStartAddress;
std::optional<std::uint16_t> ramStartAddress;
std::optional<std::uint32_t> ramSize;
std::optional<std::uint16_t> eepromStartAddress;
std::optional<std::uint16_t> eepromSize;
std::optional<std::uint8_t> eepromPageSize;
std::optional<std::uint8_t> eepromAddressRegisterHigh;
std::optional<std::uint8_t> eepromAddressRegisterLow;
std::optional<std::uint8_t> eepromDataRegisterAddress;
std::optional<std::uint8_t> eepromControlRegisterAddress;
std::optional<std::uint8_t> ocdRevision;
std::optional<std::uint8_t> ocdDataRegister;
std::optional<std::uint16_t> statusRegisterStartAddress;
std::optional<std::uint16_t> statusRegisterSize;
std::optional<std::uint16_t> stackPointerRegisterLowAddress;
std::optional<std::uint16_t> stackPointerRegisterSize;
std::optional<std::uint8_t> spmcRegisterStartAddress;
std::optional<std::uint8_t> osccalAddress;
// XMega/PDI/UPDI specific target params
std::optional<std::uint32_t> appSectionPdiOffset;
std::optional<std::uint32_t> appSectionStartAddress;
std::optional<std::uint32_t> appSectionSize;
std::optional<std::uint16_t> bootSectionSize;
std::optional<std::uint32_t> bootSectionPdiOffset;
std::optional<std::uint32_t> eepromPdiOffset;
std::optional<std::uint32_t> ramPdiOffset;
std::optional<std::uint32_t> fuseRegistersPdiOffset;
std::optional<std::uint32_t> lockRegistersPdiOffset;
std::optional<std::uint32_t> userSignaturesPdiOffset;
std::optional<std::uint32_t> productSignaturesPdiOffset;
std::optional<std::uint16_t> nvmModuleBaseAddress;
std::optional<std::uint16_t> mcuModuleBaseAddress;
// UPDI specific target params
std::optional<std::uint16_t> ocdModuleAddress;
std::optional<std::uint32_t> programMemoryUpdiStartAddress;
std::optional<std::uint16_t> signatureSegmentStartAddress;
std::optional<std::uint16_t> signatureSegmentSize;
std::optional<std::uint16_t> fuseSegmentStartAddress;
std::optional<std::uint16_t> fuseSegmentSize;
std::optional<std::uint16_t> lockbitsSegmentStartAddress;
};
}

View File

@@ -1,54 +0,0 @@
#pragma once
#include <cstdint>
#include "src/Targets/TargetMemory.hpp"
namespace Targets::Microchip::Avr
{
enum class FuseType: std::uint8_t
{
LOW,
HIGH,
EXTENDED,
OTHER,
};
enum class FuseEnableStrategy: std::uint8_t
{
CLEAR,
SET,
};
struct Fuse
{
FuseType type;
std::uint8_t value;
Fuse(FuseType type, std::uint8_t value)
: type(type)
, value(value)
{}
};
struct FuseBitsDescriptor
{
TargetMemoryAddress byteAddress;
/**
* The type of the fuse byte in which the fuse bits resides.
*/
FuseType fuseType;
/**
* Fuse bits mask
*/
std::uint8_t bitMask;
FuseBitsDescriptor(TargetMemoryAddress byteAddress, FuseType fuseType, std::uint8_t bitMask)
: byteAddress(byteAddress)
, fuseType(fuseType)
, bitMask(bitMask)
{}
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,232 @@
#pragma once
#include <cstdint>
#include <queue>
#include <utility>
#include <optional>
#include "src/Targets/Target.hpp"
#include "src/DebugToolDrivers/DebugTool.hpp"
#include "src/DebugToolDrivers/TargetInterfaces/Microchip/AVR8/Avr8DebugInterface.hpp"
#include "src/DebugToolDrivers/TargetInterfaces/Microchip/AVR8/AvrIspInterface.hpp"
#include "Family.hpp"
#include "GpioPadDescriptor.hpp"
#include "ProgramMemorySection.hpp"
#include "ProgrammingSession.hpp"
#include "src/Targets/Microchip/AVR8/Fuse.hpp"
#include "src/Targets/TargetPhysicalInterface.hpp"
#include "src/Targets/TargetRegisterDescriptor.hpp"
#include "src/Targets/TargetBitFieldDescriptor.hpp"
#include "src/Targets/TargetBreakpoint.hpp"
#include "TargetDescriptionFile.hpp"
#include "Avr8TargetConfig.hpp"
namespace Targets::Microchip::Avr8
{
class Avr8: public Target
{
public:
explicit Avr8(const TargetConfig& targetConfig, TargetDescriptionFile&& targetDescriptionFile);
/*
* The functions below implement the Target interface for AVR8 targets.
*
* See the Targets::Target abstract class for documentation on the expected behaviour of
* each function.
*/
/**
* All AVR8 compatible debug tools must provide a valid Avr8Interface.
*
* @param debugTool
* @return
*/
bool supportsDebugTool(DebugTool* debugTool) override;
void setDebugTool(DebugTool* debugTool) override;
void activate() override;
void deactivate() override;
TargetDescriptor targetDescriptor() override;
void run(std::optional<TargetMemoryAddress> toAddress) override;
void stop() override;
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;
TargetMemoryBuffer readMemory(
const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
const TargetMemorySegmentDescriptor& memorySegmentDescriptor,
TargetMemoryAddress startAddress,
TargetMemorySize bytes,
const std::set<TargetMemoryAddressRange>& excludedAddressRanges
) override;
void writeMemory(
const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
const TargetMemorySegmentDescriptor& memorySegmentDescriptor,
TargetMemoryAddress startAddress,
const TargetMemoryBuffer& buffer
) override;
bool isProgramMemory(
const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
const TargetMemorySegmentDescriptor& memorySegmentDescriptor,
TargetMemoryAddress startAddress,
TargetMemorySize size
) override;
void eraseMemory(
const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
const TargetMemorySegmentDescriptor& memorySegmentDescriptor
) override;
TargetExecutionState getExecutionState() override;
TargetMemoryAddress getProgramCounter() override;
void setProgramCounter(TargetMemoryAddress programCounter) override;
TargetStackPointer getStackPointer() override;
void setStackPointer(TargetStackPointer stackPointer) override;
TargetGpioPinDescriptorAndStatePairs getGpioPinStates(const TargetPinoutDescriptor& pinoutDescriptor) override;
void setGpioPinState(const TargetPinDescriptor& pinDescriptor, const TargetGpioPinState& state) override;
void enableProgrammingMode() override;
void disableProgrammingMode() override;
bool programmingModeEnabled() override;
protected:
DebugToolDrivers::TargetInterfaces::TargetPowerManagementInterface* targetPowerManagementInterface = nullptr;
DebugToolDrivers::TargetInterfaces::Microchip::Avr8::Avr8DebugInterface* avr8DebugInterface = nullptr;
DebugToolDrivers::TargetInterfaces::Microchip::Avr8::AvrIspInterface* avrIspInterface = nullptr;
Avr8TargetConfig targetConfig;
TargetDescriptionFile targetDescriptionFile;
TargetAddressSpaceDescriptor dataAddressSpaceDescriptor;
TargetAddressSpaceDescriptor fuseAddressSpaceDescriptor;
TargetMemorySegmentDescriptor ramMemorySegmentDescriptor;
TargetMemorySegmentDescriptor ioMemorySegmentDescriptor;
TargetMemorySegmentDescriptor fuseMemorySegmentDescriptor;
TargetSignature signature;
Family family;
bool activated = false;
std::set<TargetPhysicalInterface> physicalInterfaces;
std::vector<TargetPeripheralDescriptor> gpioPortPeripheralDescriptors;
std::map<std::string, GpioPadDescriptor> gpioPadDescriptorsByPadName;
/**
* The stack pointer register on AVR8 targets can take several forms:
*
* 1. A single 8 or 16-bit register in the CPU peripheral, with key "sp"
* 2. Two 8-bit registers for high and low bytes in a 16-bit stack pointer, in the CPU peripheral, with keys
* "spl" and "sph"
* 3. A single 8-bit low byte register for an 8-bit stack pointer, in the CPU peripheral. This is similar
* to 1, but with key "spl"
*/
std::optional<TargetRegisterDescriptor> spRegisterDescriptor;
std::optional<TargetRegisterDescriptor> spLowRegisterDescriptor;
std::optional<TargetRegisterDescriptor> spHighRegisterDescriptor;
/**
* On some AVR8 targets, like the ATmega328P, a cleared fuse bit means the fuse is "programmed" (enabled).
* And a set bit means the fuse is "un-programmed" (disabled). But on others, like the ATmega4809, it's the
* other way around (set bit == enabled, cleared bit == disabled).
*
* The FuseEnableStrategy specifies the strategy of enabling a fuse. It's extracted from the TDF.
* See TargetDescription::getFuseEnableStrategy() for more.
*/
FuseEnableStrategy fuseEnableStrategy;
std::optional<ProgrammingSession> activeProgrammingSession = std::nullopt;
static std::map<std::string, GpioPadDescriptor> generateGpioPadDescriptorMapping(
const std::vector<TargetPeripheralDescriptor>& portPeripheralDescriptors
);
TargetMemoryBuffer readRegister(const TargetRegisterDescriptor& descriptor);
void writeRegister(const TargetRegisterDescriptor& descriptor, const TargetMemoryBuffer& value) ;
void applyDebugInterfaceRegisterAccessRestrictions(
TargetRegisterGroupDescriptor& groupDescriptor,
const TargetAddressSpaceDescriptor& addressSpaceDescriptor
);
BreakpointResources getBreakpointResources();
/**
* Checks if a particular fuse is enabled in the given fuse byte value. Takes the target's fuse enable strategy
* into account.
*
* @param bitFieldDescriptor
* @param value
*
* @return
*/
bool isFuseEnabled(const TargetBitFieldDescriptor& bitFieldDescriptor, FuseValue value) const;
/**
* Enables/disables a fuse within the given fuse byte, using the target's fuse enable strategy.
*
* @param bitFieldDescriptor
* @param value
* @param enabled
*
* @return
* The updated fuse byte value.
*/
FuseValue setFuseEnabled(
const TargetBitFieldDescriptor& bitFieldDescriptor,
FuseValue value,
bool enabled
) const;
/**
* Updates the debugWIRE enable (DWEN) fuse bit on the AVR target.
*
* @param enable
* True to enable the fuse, false to disable it.
*/
void updateDwenFuseBit(bool enable);
/**
* Updates the On-chip debug enable (OCDEN) fuse bit on the AVR target.
*
* @param enable
* True to enable the fuse, false to disable it.
*/
void updateOcdenFuseBit(bool enable);
/**
* Updates the "Preserve EEPROM" (EESAVE) fuse bit on the AVR target.
*
* @param enable
* True to enable the fuse, false to disable it.
*
* @return
* True if the fuse bit was updated. False if the fuse bit was already set to the desired value.
*/
bool updateEesaveFuseBit(bool enable);
};
}

View File

@@ -1,17 +1,10 @@
#include "Avr8TargetConfig.hpp"
#include "src/Services/PathService.hpp"
#include "src/Services/StringService.hpp"
#include "src/Exceptions/InvalidConfig.hpp"
namespace Targets::Microchip::Avr::Avr8Bit
namespace Targets::Microchip::Avr8
{
Avr8TargetConfig::Avr8TargetConfig(const TargetConfig& targetConfig)
: TargetConfig(targetConfig)
{
using Exceptions::InvalidConfig;
const auto& targetNode = targetConfig.targetNode;
// The 'manageDwenFuseBit' param used to be 'updateDwenFuseBit' - we still support the old, for now.
@@ -40,9 +33,9 @@ namespace Targets::Microchip::Avr::Avr8Bit
}
if (targetNode["targetPowerCycleDelay"]) {
this->targetPowerCycleDelay = std::chrono::milliseconds(targetNode["targetPowerCycleDelay"].as<int>(
this->targetPowerCycleDelay = std::chrono::milliseconds{targetNode["targetPowerCycleDelay"].as<int>(
this->targetPowerCycleDelay.count()
));
)};
}
if (targetNode["manageOcdenFuseBit"]) {

View File

@@ -6,7 +6,7 @@
#include "src/ProjectConfig.hpp"
namespace Targets::Microchip::Avr::Avr8Bit
namespace Targets::Microchip::Avr8
{
/**
* Extending the generic TargetConfig struct to accommodate AVR8 target configuration parameters.
@@ -15,15 +15,15 @@ namespace Targets::Microchip::Avr::Avr8Bit
{
public:
/**
* Because the debugWire module requires control of the reset pin on the target, enabling this module will
* Because the debugWIRE module requires control of the reset pin on the target, enabling this module will
* effectively mean losing control of the reset pin. This means users won't be able to use other
* interfaces that require access to the reset pin, such as ISP, until the debugWire module is disabled.
* interfaces that require access to the reset pin, such as ISP, until the debugWIRE module is disabled.
*
* The EdbgAvr8Interface provides a function for temporarily disabling the debugWire module on the target.
* This doesn't change the DWEN fuse and its affect is only temporary - the debugWire module will be
* The EdbgAvr8Interface provides a function for temporarily disabling the debugWIRE module on the target.
* This doesn't change the DWEN fuse and its affect is only temporary - the debugWIRE module will be
* reactivated upon the user cycling the power to the target.
*
* Bloom is able to temporarily disable the debugWire module, automatically, upon deactivating of the
* Bloom is able to temporarily disable the debugWIRE module, automatically, upon deactivating of the
* target (which usually occurs after a debug session has ended). This allows users to program the target via
* ISP, after they've finished a debug session. After programming the target, the user will need to cycle the
* target power before Bloom can gain access for another debug session. This flag control this function.
@@ -35,7 +35,7 @@ namespace Targets::Microchip::Avr::Avr8Bit
bool disableDebugWireOnDeactivate = false;
/**
* The manageDwenFuseBit flag determines if Bloom should manage the DWEN fuse bit, for debugWire sessions.
* The manageDwenFuseBit flag determines if Bloom should manage the DWEN fuse bit, for debugWIRE sessions.
*
* This parameter is optional, and the function is disabled by default. Users must explicitly enable it in
* their target configuration.
@@ -44,7 +44,7 @@ namespace Targets::Microchip::Avr::Avr8Bit
/**
* For debug tools that provide target power management functions (such as some evaluation boards), Bloom can
* automatically cycle the target power after updating the DWEN fuse bit, for debugWire sessions. This parameter
* automatically cycle the target power after updating the DWEN fuse bit, for debugWIRE sessions. This parameter
* controls this function.
*
* This parameter is optional. The function is enabled by default.
@@ -57,7 +57,7 @@ namespace Targets::Microchip::Avr::Avr8Bit
*
* This parameter determines how long we wait.
*/
std::chrono::milliseconds targetPowerCycleDelay = std::chrono::milliseconds(250);
std::chrono::milliseconds targetPowerCycleDelay = std::chrono::milliseconds{250};
/**
* The manageOcdenFuseBit flag determines if Bloom should manage the OCDEN fuse but on JTAG-enabled AVR

View File

@@ -10,9 +10,5 @@ namespace Exceptions
explicit DebugWirePhysicalInterfaceError(const std::string& message)
: TargetOperationFailure(message)
{}
explicit DebugWirePhysicalInterfaceError(const char* message)
: TargetOperationFailure(message)
{}
};
}

View File

@@ -1,14 +1,14 @@
#pragma once
namespace Targets::Microchip::Avr::Avr8Bit
namespace Targets::Microchip::Avr8
{
enum class Family: int
{
MEGA,
XMEGA,
TINY,
DB,
DA,
DB,
DD,
EA,
};

View File

@@ -0,0 +1,24 @@
#pragma once
#include <cstdint>
#include "src/Targets/TargetMemory.hpp"
namespace Targets::Microchip::Avr8
{
using FuseValue = std::uint8_t;
enum class FuseType: std::uint8_t
{
LOW,
HIGH,
EXTENDED,
OTHER,
};
enum class FuseEnableStrategy: std::uint8_t
{
CLEAR,
SET,
};
}

View File

@@ -0,0 +1,34 @@
#pragma once
#include <cstdint>
#include "src/Targets/TargetRegisterDescriptor.hpp"
namespace Targets::Microchip::Avr8
{
/**
* This struct contains all of the relevant GPIO register descriptors for a particular pad, on an AVR8 target.
*
* We use this to read and manipulate the state of GPIO pins.
*/
struct GpioPadDescriptor
{
std::uint8_t registerMask;
const TargetRegisterDescriptor& dataDirectionRegisterDescriptor;
const TargetRegisterDescriptor& inputRegisterDescriptor;
const TargetRegisterDescriptor& outputRegisterDescriptor;
GpioPadDescriptor(
std::uint8_t registerMask,
const TargetRegisterDescriptor& dataDirectionRegisterDescriptor,
const TargetRegisterDescriptor& inputRegisterDescriptor,
const TargetRegisterDescriptor& outputRegisterDescriptor
)
: registerMask(registerMask)
, dataDirectionRegisterDescriptor(dataDirectionRegisterDescriptor)
, inputRegisterDescriptor(inputRegisterDescriptor)
, outputRegisterDescriptor(outputRegisterDescriptor)
{}
};
}

View File

@@ -0,0 +1,29 @@
#include "IspParameters.hpp"
#include "src/Services/StringService.hpp"
namespace Targets::Microchip::Avr8
{
IspParameters::IspParameters(const TargetDescriptionFile& targetDescriptionFile) {
using Services::StringService;
const auto& ispGroup = targetDescriptionFile.getPropertyGroup("isp_interface");
this->programModeTimeout = StringService::toUint8(ispGroup.getProperty("ispenterprogmode_timeout").value);
this->programModeStabilizationDelay = StringService::toUint8(
ispGroup.getProperty("ispenterprogmode_stabdelay").value
);
this->programModeCommandExecutionDelay = StringService::toUint8(
ispGroup.getProperty("ispenterprogmode_cmdexedelay").value
);
this->programModeSyncLoops = StringService::toUint8(ispGroup.getProperty("ispenterprogmode_synchloops").value);
this->programModeByteDelay = StringService::toUint8(ispGroup.getProperty("ispenterprogmode_bytedelay").value);
this->programModePollValue = StringService::toUint8(ispGroup.getProperty("ispenterprogmode_pollvalue").value);
this->programModePollIndex = StringService::toUint8(ispGroup.getProperty("ispenterprogmode_pollindex").value);
this->programModePreDelay = StringService::toUint8(ispGroup.getProperty("ispleaveprogmode_predelay").value);
this->programModePostDelay = StringService::toUint8(ispGroup.getProperty("ispleaveprogmode_postdelay").value);
this->readSignaturePollIndex = StringService::toUint8(ispGroup.getProperty("ispreadsign_pollindex").value);
this->readFusePollIndex = StringService::toUint8(ispGroup.getProperty("ispreadfuse_pollindex").value);
this->readLockPollIndex = StringService::toUint8(ispGroup.getProperty("ispreadlock_pollindex").value);
}
}

View File

@@ -2,10 +2,15 @@
#include <cstdint>
namespace Targets::Microchip::Avr
#include "TargetDescriptionFile.hpp"
namespace Targets::Microchip::Avr8
{
/**
* These parameters are required by the ISP interface. They can be extracted from the target's TDF.
* These parameters are required by ISP interfaces, to enter programming mode.
*
* These parameters are not specific to the EDBG protocol, which is why they do not reside in the EDBG protocol
* directory.
*/
struct IspParameters
{
@@ -18,9 +23,10 @@ namespace Targets::Microchip::Avr
std::uint8_t programModePollIndex;
std::uint8_t programModePreDelay;
std::uint8_t programModePostDelay;
std::uint8_t readSignaturePollIndex;
std::uint8_t readFusePollIndex;
std::uint8_t readLockPollIndex;
explicit IspParameters(const TargetDescriptionFile& targetDescriptionFile);
};
}

View File

@@ -6,14 +6,14 @@
#include "Exceptions/DecodeFailure.hpp"
namespace Targets::Microchip::Avr::Avr8Bit::OpcodeDecoder
namespace Targets::Microchip::Avr8::OpcodeDecoder
{
Decoder::InstructionMapping Decoder::decode(
Targets::TargetMemoryAddress startByteAddress,
const TargetMemoryBuffer& data,
bool throwOnFailure
) {
auto output = Decoder::InstructionMapping();
auto output = Decoder::InstructionMapping{};
static const auto decoders = Decoder::opcodeDecoders();
@@ -29,7 +29,7 @@ namespace Targets::Microchip::Avr::Avr8Bit::OpcodeDecoder
if (instruction.has_value()) {
const auto instructionSize = instruction->byteSize;
output.insert(std::pair(instructionByteAddress, std::move(*instruction)));
output.emplace(instructionByteAddress, std::move(*instruction));
dataIt += instructionSize;
instructionByteAddress += instructionSize;
@@ -40,13 +40,13 @@ namespace Targets::Microchip::Avr::Avr8Bit::OpcodeDecoder
if (!opcodeMatched) {
if (throwOnFailure) {
throw Exceptions::DecodeFailure(
throw Exceptions::DecodeFailure{
instructionByteAddress,
static_cast<std::uint32_t>(*(dataIt + 1) << 8) | *dataIt
);
};
}
output.insert(std::pair(instructionByteAddress, std::nullopt));
output.emplace(instructionByteAddress, std::nullopt);
dataIt += 2;
instructionByteAddress += 2;
@@ -62,7 +62,7 @@ namespace Targets::Microchip::Avr::Avr8Bit::OpcodeDecoder
*
* I've used the same order that is used in the AVR implementation of GDB.
*/
return Decoder::OpcodeDecoders({
return Decoder::OpcodeDecoders{
std::bind(&Opcodes::UndefinedOrErased::decode, std::placeholders::_1, std::placeholders::_2),
std::bind(&Opcodes::Clc::decode, std::placeholders::_1, std::placeholders::_2),
std::bind(&Opcodes::Clh::decode, std::placeholders::_1, std::placeholders::_2),
@@ -208,6 +208,6 @@ namespace Targets::Microchip::Avr::Avr8Bit::OpcodeDecoder
std::bind(&Opcodes::Eicall::decode, std::placeholders::_1, std::placeholders::_2),
std::bind(&Opcodes::Eijmp::decode, std::placeholders::_1, std::placeholders::_2),
std::bind(&Opcodes::Des::decode, std::placeholders::_1, std::placeholders::_2),
});
};
}
}

View File

@@ -11,7 +11,7 @@
#include "src/Targets/TargetMemory.hpp"
#include "src/Services/BitsetService.hpp"
namespace Targets::Microchip::Avr::Avr8Bit::OpcodeDecoder
namespace Targets::Microchip::Avr8::OpcodeDecoder
{
class Decoder
{

View File

@@ -6,7 +6,7 @@
#include "src/Targets/TargetMemory.hpp"
namespace Targets::Microchip::Avr::Avr8Bit::OpcodeDecoder::Exceptions
namespace Targets::Microchip::Avr8::OpcodeDecoder::Exceptions
{
class DecodeFailure: public ::Exceptions::Exception
{

View File

@@ -6,7 +6,7 @@
#include "src/Targets/TargetMemory.hpp"
namespace Targets::Microchip::Avr::Avr8Bit::OpcodeDecoder
namespace Targets::Microchip::Avr8::OpcodeDecoder
{
struct Instruction
{

View File

@@ -13,7 +13,7 @@
#include "src/Targets/TargetMemory.hpp"
#include "src/Services/BitsetService.hpp"
namespace Targets::Microchip::Avr::Avr8Bit::OpcodeDecoder
namespace Targets::Microchip::Avr8::OpcodeDecoder
{
struct InstructionParameterBase
{};
@@ -520,13 +520,13 @@ namespace Targets::Microchip::Avr::Avr8Bit::OpcodeDecoder
return std::nullopt;
}
auto output = Instruction(
auto output = Instruction{
SelfType::name,
opcode,
byteSize,
mnemonic,
canChangeProgramFlow
);
};
if constexpr (decltype(sourceRegisterParameter)::hasValue()) {
constexpr auto param = sourceRegisterParameter.value;

View File

@@ -2,7 +2,7 @@
#include <cstdint>
namespace Targets::Microchip::Avr::Avr8Bit
namespace Targets::Microchip::Avr8
{
enum class ProgramMemorySection: std::uint8_t
{

View File

@@ -2,7 +2,7 @@
#include <cstdint>
namespace Targets::Microchip::Avr::Avr8Bit
namespace Targets::Microchip::Avr8
{
/**
* Information relating to a specific AVR8 programming session.

View File

@@ -0,0 +1,195 @@
#include "TargetDescriptionFile.hpp"
#include "src/Services/PathService.hpp"
#include "src/Services/StringService.hpp"
#include "src/Logger/Logger.hpp"
#include "src/Exceptions/Exception.hpp"
#include "src/Targets/TargetDescription/Exceptions/TargetDescriptionParsingFailureException.hpp"
namespace Targets::Microchip::Avr8
{
using Targets::TargetDescription::RegisterGroup;
using Targets::TargetDescription::AddressSpace;
using Targets::TargetDescription::MemorySegment;
using Targets::TargetDescription::Register;
using Targets::TargetDescription::Exceptions::InvalidTargetDescriptionDataException;
using Targets::TargetRegisterDescriptor;
using Services::StringService;
TargetDescriptionFile::TargetDescriptionFile(const std::string& xmlFilePath)
: Targets::TargetDescription::TargetDescriptionFile(xmlFilePath)
{}
TargetSignature TargetDescriptionFile::getTargetSignature() const {
const auto& signatureGroup = this->getPropertyGroup("signatures");
return {
StringService::toUint8(signatureGroup.getProperty("signature0").value, 16),
StringService::toUint8(signatureGroup.getProperty("signature1").value, 16),
StringService::toUint8(signatureGroup.getProperty("signature2").value, 16)
};
}
Family TargetDescriptionFile::getAvrFamily() const {
static const auto targetFamiliesByName = std::map<std::string, Family>{
{"MEGA", Family::MEGA},
{"XMEGA", Family::XMEGA},
{"TINY", Family::TINY},
{"DA", Family::DA},
{"DB", Family::DB},
{"DD", Family::DD},
{"EA", Family::EA},
};
const auto familyIt = targetFamiliesByName.find(this->getDeviceAttribute("avr-family"));
if (familyIt == targetFamiliesByName.end()) {
throw InvalidTargetDescriptionDataException{"Unknown AVR family name in target description file"};
}
return familyIt->second;
}
const TargetDescription::AddressSpace& TargetDescriptionFile::getRegisterFileAddressSpace() const {
/*
* On some AVRs, the register file is accessible via the data address space. On the newer UPDI and PDI AVRs,
* it has a dedicated address space.
*/
const auto addressSpace = this->tryGetAddressSpace("register_file");
return addressSpace.has_value()
? addressSpace->get()
: this->getAddressSpace("data");
}
const TargetDescription::AddressSpace& TargetDescriptionFile::getProgramAddressSpace() const {
return this->getAddressSpace("prog");
}
const TargetDescription::AddressSpace& TargetDescriptionFile::getDataAddressSpace() const {
return this->getAddressSpace("data");
}
const TargetDescription::AddressSpace& TargetDescriptionFile::getEepromAddressSpace() const {
const auto addressSpace = this->tryGetAddressSpace("eeprom");
return addressSpace.has_value()
? addressSpace->get()
: this->getAddressSpace("data");
}
const TargetDescription::AddressSpace& TargetDescriptionFile::getIoAddressSpace() const {
return this->getAddressSpace("data");
}
const TargetDescription::AddressSpace& TargetDescriptionFile::getSignatureAddressSpace() const {
const auto addressSpace = this->tryGetAddressSpace("signatures");
return addressSpace.has_value()
? addressSpace->get()
: this->getAddressSpace("data");
}
const TargetDescription::AddressSpace& TargetDescriptionFile::getFuseAddressSpace() const {
const auto addressSpace = this->tryGetAddressSpace("fuses");
return addressSpace.has_value()
? addressSpace->get()
: this->getAddressSpace("data");
}
const TargetDescription::AddressSpace& TargetDescriptionFile::getLockbitAddressSpace() const {
const auto addressSpace = this->tryGetAddressSpace("lockbits");
return addressSpace.has_value()
? addressSpace->get()
: this->getAddressSpace("data");
}
const TargetDescription::MemorySegment& TargetDescriptionFile::getProgramMemorySegment() const {
return this->getProgramAddressSpace().getMemorySegment("internal_program_memory");
}
const TargetDescription::MemorySegment& TargetDescriptionFile::getRamMemorySegment() const {
return this->getDataAddressSpace().getMemorySegment("internal_ram");
}
const TargetDescription::MemorySegment& TargetDescriptionFile::getEepromMemorySegment() const {
return this->getEepromAddressSpace().getMemorySegment("internal_eeprom");
}
const TargetDescription::MemorySegment& TargetDescriptionFile::getIoMemorySegment() const {
const auto addressSpace = this->getIoAddressSpace();
const auto segment = addressSpace.tryGetMemorySegment("io");
return segment.has_value()
? segment->get()
: addressSpace.getMemorySegment("mapped_io");
}
const TargetDescription::MemorySegment& TargetDescriptionFile::getSignatureMemorySegment() const {
return this->getSignatureAddressSpace().getMemorySegment("signatures");
}
const TargetDescription::MemorySegment& TargetDescriptionFile::getFuseMemorySegment() const {
return this->getFuseAddressSpace().getMemorySegment("fuses");
}
const TargetDescription::MemorySegment& TargetDescriptionFile::getLockbitMemorySegment() const {
return this->getLockbitAddressSpace().getMemorySegment("lockbits");
}
TargetAddressSpaceDescriptor TargetDescriptionFile::getDataAddressSpaceDescriptor() const {
return this->targetAddressSpaceDescriptorFromAddressSpace(this->getDataAddressSpace());
}
TargetAddressSpaceDescriptor TargetDescriptionFile::getFuseAddressSpaceDescriptor() const {
return this->targetAddressSpaceDescriptorFromAddressSpace(this->getFuseAddressSpace());
}
TargetMemorySegmentDescriptor TargetDescriptionFile::getRamMemorySegmentDescriptor() const {
return this->targetMemorySegmentDescriptorFromMemorySegment(
this->getRamMemorySegment(),
this->getDataAddressSpace()
);
}
TargetMemorySegmentDescriptor TargetDescriptionFile::getFuseMemorySegmentDescriptor() const {
return this->targetMemorySegmentDescriptorFromMemorySegment(
this->getFuseMemorySegment(),
this->getFuseAddressSpace()
);
}
TargetMemorySegmentDescriptor TargetDescriptionFile::getIoMemorySegmentDescriptor() const {
return this->targetMemorySegmentDescriptorFromMemorySegment(
this->getIoMemorySegment(),
this->getIoAddressSpace()
);
}
TargetPeripheralDescriptor TargetDescriptionFile::getFuseTargetPeripheralDescriptor() const {
return this->getTargetPeripheralDescriptor("fuse");
}
Pair<
TargetRegisterDescriptor,
TargetBitFieldDescriptor
> TargetDescriptionFile::getFuseRegisterBitFieldDescriptorPair(const std::string& fuseBitFieldKey) const {
const auto peripheralDescriptor = this->getFuseTargetPeripheralDescriptor();
const auto pair = peripheralDescriptor.getRegisterGroupDescriptor("fuse").getRegisterBitFieldDescriptorPair(
fuseBitFieldKey
);
return {pair.first.clone(), pair.second.clone()};
}
std::optional<FuseEnableStrategy> TargetDescriptionFile::getFuseEnableStrategy() const {
const auto fuseEnabledValueProperty = this->tryGetProperty("programming_info", "fuse_enabled_value");
if (fuseEnabledValueProperty.has_value()) {
if (fuseEnabledValueProperty->get().value == "0") {
return FuseEnableStrategy::CLEAR;
}
if (fuseEnabledValueProperty->get().value == "1") {
return FuseEnableStrategy::SET;
}
}
return std::nullopt;
}
}

View File

@@ -0,0 +1,85 @@
#pragma once
#include <set>
#include <optional>
#include "src/Targets/TargetDescription/TargetDescriptionFile.hpp"
#include "src/Targets/TargetRegisterDescriptor.hpp"
#include "src/Targets/Microchip/AVR8/TargetSignature.hpp"
#include "src/Targets/Microchip/AVR8/Fuse.hpp"
#include "src/Targets/Microchip/AVR8/Family.hpp"
namespace Targets::Microchip::Avr8
{
/**
* AVR8 TDF
*
* For more information of TDFs, see src/Targets/TargetDescription/README.md
*/
class TargetDescriptionFile: public TargetDescription::TargetDescriptionFile
{
public:
/**
* Extends TDF initialisation to include the loading of physical interfaces for debugging AVR8 targets, among
* other things.
*
* @param xml
*/
explicit TargetDescriptionFile(const std::string& xmlFilePath);
/**
* Extracts the AVR8 target signature from the TDF.
*
* @return
*/
[[nodiscard]] TargetSignature getTargetSignature() const;
/**
* Extracts the AVR8 target family from the TDF.
*
* @return
*/
[[nodiscard]] Family getAvrFamily() const;
[[nodiscard]] const TargetDescription::AddressSpace& getRegisterFileAddressSpace() const;
[[nodiscard]] const TargetDescription::AddressSpace& getProgramAddressSpace() const;
[[nodiscard]] const TargetDescription::AddressSpace& getDataAddressSpace() const;
[[nodiscard]] const TargetDescription::AddressSpace& getEepromAddressSpace() const;
[[nodiscard]] const TargetDescription::AddressSpace& getIoAddressSpace() const;
[[nodiscard]] const TargetDescription::AddressSpace& getSignatureAddressSpace() const;
[[nodiscard]] const TargetDescription::AddressSpace& getFuseAddressSpace() const;
[[nodiscard]] const TargetDescription::AddressSpace& getLockbitAddressSpace() const;
[[nodiscard]] const TargetDescription::MemorySegment& getProgramMemorySegment() const;
[[nodiscard]] const TargetDescription::MemorySegment& getRamMemorySegment() const;
[[nodiscard]] const TargetDescription::MemorySegment& getEepromMemorySegment() const;
[[nodiscard]] const TargetDescription::MemorySegment& getIoMemorySegment() const;
[[nodiscard]] const TargetDescription::MemorySegment& getSignatureMemorySegment() const;
[[nodiscard]] const TargetDescription::MemorySegment& getFuseMemorySegment() const;
[[nodiscard]] const TargetDescription::MemorySegment& getLockbitMemorySegment() const;
[[nodiscard]] TargetAddressSpaceDescriptor getDataAddressSpaceDescriptor() const;
[[nodiscard]] TargetAddressSpaceDescriptor getFuseAddressSpaceDescriptor() const;
[[nodiscard]] TargetMemorySegmentDescriptor getRamMemorySegmentDescriptor() const;
[[nodiscard]] TargetMemorySegmentDescriptor getFuseMemorySegmentDescriptor() const;
[[nodiscard]] TargetMemorySegmentDescriptor getIoMemorySegmentDescriptor() const;
[[nodiscard]] TargetPeripheralDescriptor getFuseTargetPeripheralDescriptor() const;
[[nodiscard]] Pair<
TargetRegisterDescriptor,
TargetBitFieldDescriptor
> getFuseRegisterBitFieldDescriptorPair(const std::string& fuseBitFieldKey) const;
/**
* Extracts the target's fuse enable strategy.
*
* @return
* std::nullopt if the TDF doesn't contain a fuse enable strategy.
*/
[[nodiscard]] std::optional<FuseEnableStrategy> getFuseEnableStrategy() const;
};
}

View File

@@ -4,10 +4,12 @@
#include <sstream>
#include <iomanip>
namespace Targets::Microchip::Avr
#include "src/Services/StringService.hpp"
namespace Targets::Microchip::Avr8
{
/**
* All AVR targets carry a three-byte signature that is *usually* unique to the target.
* All AVR8 targets carry a three-byte signature that is *usually* unique to the target.
*
* The AVR target signature consists of three bytes: 0xAABBCC
* Byte AA (byteZero) identifies the manufacture of the target (usually 1E for Atmel/Microchip)
@@ -15,11 +17,7 @@ namespace Targets::Microchip::Avr
* Byte CC (byteTwo) identifies the target
*
* Some AVR targets have been found to carry identical signatures. For example, the AT90PWM1, AT90PWM2B
* and the AT90PWM3B all carry a signature of 0x1E9383. Although these devices may not differ in
* significant ways, Bloom does still take duplicate signatures into account, to ensure that the correct
* target description file is used.
*
* This class represents an AVR target signature.
* and the AT90PWM3B all carry a signature of 0x1E9383.
*/
struct TargetSignature
{
@@ -35,7 +33,7 @@ namespace Targets::Microchip::Avr
{};
explicit TargetSignature(const std::string& hex) {
const auto signature = static_cast<std::uint32_t>(std::stoul(hex, nullptr, 16));
const auto signature = Services::StringService::toUint32(hex, 16);
this->byteZero = static_cast<unsigned char>(signature >> 16);
this->byteOne = static_cast<unsigned char>(signature >> 8);
@@ -43,7 +41,7 @@ namespace Targets::Microchip::Avr
}
[[nodiscard]] std::string toHex() const {
std::stringstream stream;
auto stream = std::stringstream{};
stream << std::hex << std::setfill('0');
stream << std::setw(2) << static_cast<unsigned int>(this->byteZero);
stream << std::setw(2) << static_cast<unsigned int>(this->byteOne);

View File

@@ -1,27 +0,0 @@
#pragma once
#include <cstdint>
#include <vector>
#include <set>
#include <optional>
namespace Targets::RiscV::DebugModule
{
using RegisterAddress = std::uint8_t;
using RegisterValue = std::uint32_t;
using HartIndex = std::uint32_t;
enum class DmiOperation: std::uint8_t
{
IGNORE = 0x00,
READ = 0x01,
WRITE = 0x02,
};
enum class DmiOperationStatus: std::uint8_t
{
SUCCESS = 0x00,
FAILED = 0x02,
BUSY = 0x03,
};
}

View File

@@ -1,38 +0,0 @@
#pragma once
#include <cstdint>
#include <cassert>
#include "src/Targets/RiscV/DebugModule/DebugModule.hpp"
namespace Targets::RiscV::DebugModule::Registers
{
struct AbstractCommandRegister
{
enum CommandType: std::uint8_t
{
REGISTER_ACCESS = 0x00,
QUICK_ACCESS = 0x01,
MEMORY_ACCESS = 0x02,
};
std::uint32_t control = 0;
CommandType commandType = CommandType::REGISTER_ACCESS;
AbstractCommandRegister() = default;
constexpr explicit AbstractCommandRegister(RegisterValue registerValue)
: control(static_cast<std::uint32_t>(registerValue & 0x00FFFFFF))
, commandType(static_cast<CommandType>((registerValue >> 24) & 0xFF))
{}
[[nodiscard]] constexpr RegisterValue value() const {
assert(this->control <= 0x00FFFFFF);
return RegisterValue{0}
| static_cast<RegisterValue>(this->control & 0x00FFFFFF)
| static_cast<RegisterValue>(this->commandType) << 24
;
}
};
}

View File

@@ -1,53 +0,0 @@
#pragma once
#include <cstdint>
#include "src/Targets/RiscV/DebugModule/DebugModule.hpp"
namespace Targets::RiscV::DebugModule::Registers
{
struct AbstractControlStatusRegister
{
enum CommandError: std::uint8_t
{
NONE = 0x00,
BUSY = 0x01,
NOT_SUPPORTED = 0x02,
EXCEPTION = 0x03,
HALT_RESUME = 0x04,
BUS = 0x05,
OTHER = 0x07,
};
std::uint8_t dataCount:4 = 0;
CommandError commandError:3 = CommandError::NONE;
bool relaxedPrivilege:1 = false;
bool busy:1 = false;
std::uint8_t programBufferSize:5 = 0;
AbstractControlStatusRegister() = default;
constexpr explicit AbstractControlStatusRegister(RegisterValue registerValue)
: dataCount(static_cast<std::uint8_t>(registerValue & 0x0F))
, commandError(static_cast<CommandError>((registerValue >> 8) & 0x07))
, relaxedPrivilege(static_cast<bool>(registerValue & (0x01 << 11)))
, busy(static_cast<bool>(registerValue & (0x01 << 12)))
, programBufferSize(static_cast<std::uint8_t>((registerValue >> 24) & 0x1F))
{}
[[nodiscard]] constexpr RegisterValue value() const {
return RegisterValue{0}
| static_cast<RegisterValue>(this->dataCount)
| static_cast<RegisterValue>(this->commandError) << 8
| static_cast<RegisterValue>(this->relaxedPrivilege) << 11
| static_cast<RegisterValue>(this->busy) << 12
| static_cast<RegisterValue>(this->programBufferSize) << 24
;
}
constexpr void clearCommandError() {
// Setting all of the bits will clear the field
this->commandError = CommandError::OTHER;
}
};
}

View File

@@ -1,71 +0,0 @@
#pragma once
#include <cstdint>
#include <cassert>
#include "src/Targets/RiscV/DebugModule/DebugModule.hpp"
namespace Targets::RiscV::DebugModule::Registers
{
struct ControlRegister
{
enum HartSelectionMode: std::uint8_t
{
SINGLE = 0x00,
MULTI = 0x01,
};
bool debugModuleActive:1 = false;
bool ndmReset:1 = false;
bool clearResetHaltRequest:1 = false;
bool setResetHaltRequest:1 = false;
bool clearKeepAlive:1 = false;
bool setKeepAlive:1 = false;
HartIndex selectedHartIndex = 0;
HartSelectionMode hartSelectionMode:1 = HartSelectionMode::SINGLE;
bool acknowledgeUnavailableHarts:1 = false;
bool acknowledgeHaveReset:1 = false;
bool hartReset:1 = false;
bool resumeRequest:1 = false;
bool haltRequest:1 = false;
ControlRegister() = default;
constexpr explicit ControlRegister(RegisterValue registerValue)
: debugModuleActive(static_cast<bool>(registerValue & 0x01))
, ndmReset(static_cast<bool>(registerValue & (0x01 << 1)))
, clearResetHaltRequest(static_cast<bool>(registerValue & (0x01 << 2)))
, setResetHaltRequest(static_cast<bool>(registerValue & (0x01 << 3)))
, clearKeepAlive(static_cast<bool>(registerValue & (0x01 << 4)))
, setKeepAlive(static_cast<bool>(registerValue & (0x01 << 5)))
, selectedHartIndex((((registerValue >> 6) & 0x3FF) << 10) | ((registerValue >> 16) & 0x3FF))
, hartSelectionMode(static_cast<HartSelectionMode>(registerValue & (0x01 << 26)))
, acknowledgeUnavailableHarts(static_cast<bool>(registerValue & (0x01 << 27)))
, acknowledgeHaveReset(static_cast<bool>(registerValue & (0x01 << 28)))
, hartReset(static_cast<bool>(registerValue & (0x01 << 29)))
, resumeRequest(static_cast<bool>(registerValue & (0x01 << 30)))
, haltRequest(static_cast<bool>(registerValue & static_cast<std::uint32_t>(0x01 << 31)))
{}
[[nodiscard]] constexpr RegisterValue value() const {
assert(this->selectedHartIndex <= 0xFFFFF);
return RegisterValue{0}
| static_cast<RegisterValue>(this->debugModuleActive)
| static_cast<RegisterValue>(this->ndmReset) << 1
| static_cast<RegisterValue>(this->clearResetHaltRequest) << 2
| static_cast<RegisterValue>(this->setResetHaltRequest) << 3
| static_cast<RegisterValue>(this->clearKeepAlive) << 4
| static_cast<RegisterValue>(this->setKeepAlive) << 5
| static_cast<RegisterValue>((this->selectedHartIndex & 0xFFFFF) >> 10) << 6
| static_cast<RegisterValue>(this->selectedHartIndex & 0x3FF) << 16
| static_cast<RegisterValue>(this->hartSelectionMode) << 26
| static_cast<RegisterValue>(this->acknowledgeUnavailableHarts) << 27
| static_cast<RegisterValue>(this->acknowledgeHaveReset) << 28
| static_cast<RegisterValue>(this->hartReset) << 29
| static_cast<RegisterValue>(this->resumeRequest) << 30
| static_cast<RegisterValue>(this->haltRequest) << 31
;
}
};
}

View File

@@ -1,55 +0,0 @@
#pragma once
#include <cstdint>
#include "src/Targets/RiscV/RiscVGeneric.hpp"
namespace Targets::RiscV::DebugModule::Registers
{
struct MemoryAccessControlField
{
enum class MemorySize: std::uint8_t
{
SIZE_8 = 0x00,
SIZE_16 = 0x01,
SIZE_32 = 0x02,
SIZE_64 = 0x03,
SIZE_128 = 0x04,
};
bool write:1 = false;
bool postIncrement:1 = false;
MemorySize size:3 = MemorySize::SIZE_32;
bool virtualAddress:1 = false;
MemoryAccessControlField() = default;
MemoryAccessControlField(
bool write,
bool postIncrement,
MemorySize size,
bool virtualAddress
)
: write(write)
, postIncrement(postIncrement)
, size(size)
, virtualAddress(virtualAddress)
{}
constexpr explicit MemoryAccessControlField(std::uint32_t controlValue)
: write(static_cast<bool>(controlValue & (0x01 << 16)))
, postIncrement(static_cast<bool>(controlValue & (0x01 << 19)))
, size(static_cast<MemorySize>((controlValue >> 20) & 0x07))
, virtualAddress(static_cast<bool>(controlValue & (0x01 << 23)))
{}
[[nodiscard]] constexpr std::uint32_t value() const {
return std::uint32_t{0}
| static_cast<std::uint32_t>(this->write) << 16
| static_cast<std::uint32_t>(this->postIncrement) << 19
| static_cast<std::uint32_t>(this->size) << 20
| static_cast<std::uint32_t>(this->virtualAddress) << 23
;
}
};
}

View File

@@ -1,61 +0,0 @@
#pragma once
#include <cstdint>
#include "src/Targets/RiscV/RiscVGeneric.hpp"
namespace Targets::RiscV::DebugModule::Registers
{
struct RegisterAccessControlField
{
enum class RegisterSize: std::uint8_t
{
SIZE_32 = 0x02,
SIZE_64 = 0x03,
SIZE_128 = 0x04,
};
RegisterNumber registerNumber;
bool write:1 = false;
bool transfer:1 = false;
bool postExecute:1 = false;
bool postIncrement:1 = false;
RegisterSize size:3 = RegisterSize::SIZE_32;
RegisterAccessControlField(
RegisterNumber registerNumber,
bool write,
bool transfer,
bool postExecute,
bool postIncrement,
RegisterSize size
)
: registerNumber(registerNumber)
, write(write)
, transfer(transfer)
, postExecute(postExecute)
, postIncrement(postIncrement)
, size(size)
{}
constexpr explicit RegisterAccessControlField(std::uint32_t controlValue)
: registerNumber(static_cast<RegisterNumber>(controlValue & 0xFFFF))
, write(static_cast<bool>(controlValue & (0x01 << 16)))
, transfer(static_cast<bool>(controlValue & (0x01 << 17)))
, postExecute(static_cast<bool>(controlValue & (0x01 << 18)))
, postIncrement(static_cast<bool>(controlValue & (0x01 << 19)))
, size(static_cast<RegisterSize>((controlValue >> 20) & 0x07))
{}
[[nodiscard]] constexpr std::uint32_t value() const {
return std::uint32_t{0}
| static_cast<std::uint32_t>(this->registerNumber)
| static_cast<std::uint32_t>(this->write) << 16
| static_cast<std::uint32_t>(this->transfer) << 17
| static_cast<std::uint32_t>(this->postExecute) << 18
| static_cast<std::uint32_t>(this->postIncrement) << 19
| static_cast<std::uint32_t>(this->size) << 20
;
}
};
}

View File

@@ -1,23 +0,0 @@
#pragma once
#include <cstdint>
#include "src/Targets/RiscV/DebugModule/DebugModule.hpp"
namespace Targets::RiscV::DebugModule::Registers
{
enum class RegisterAddress: ::Targets::RiscV::DebugModule::RegisterAddress
{
ABSTRACT_DATA_0 = 0x04,
ABSTRACT_DATA_1 = 0x05,
ABSTRACT_DATA_2 = 0x06,
ABSTRACT_DATA_3 = 0x07,
ABSTRACT_DATA_4 = 0x08,
ABSTRACT_DATA_5 = 0x09,
ABSTRACT_DATA_6 = 0x0a,
CONTROL_REGISTER = 0x10,
STATUS_REGISTER = 0x11,
ABSTRACT_CONTROL_STATUS_REGISTER = 0x16,
ABSTRACT_COMMAND_REGISTER = 0x17,
};
}

View File

@@ -1,80 +0,0 @@
#pragma once
#include <cstdint>
#include "src/Targets/RiscV/DebugModule/DebugModule.hpp"
namespace Targets::RiscV::DebugModule::Registers
{
struct StatusRegister
{
std::uint8_t version:4 = 0;
bool validConfigStructurePointer:1 = false;
bool supportsResetHalt:1 = false;
bool authBusy:1 = false;
bool authenticated:1 = false;
bool anyHalted:1 = false;
bool allHalted:1 = false;
bool anyRunning:1 = false;
bool allRunning:1 = false;
bool anyUnavailable:1 = false;
bool allUnavailable:1 = false;
bool anyNonExistent:1 = false;
bool allNonExistent:1 = false;
bool anyResumeAcknowledge:1 = false;
bool allResumeAcknowledge:1 = false;
bool anyHaveReset:1 = false;
bool allHaveReset:1 = false;
bool implicitBreak:1 = false;
bool stickyUnavailableBits:1 = false;
bool ndmResetPending:1 = false;
constexpr explicit StatusRegister(RegisterValue registerValue)
: version(static_cast<std::uint8_t>(registerValue & 0x0F))
, validConfigStructurePointer(static_cast<bool>(registerValue & (0x01 << 4)))
, supportsResetHalt(static_cast<bool>(registerValue & (0x01 << 5)))
, authBusy(static_cast<bool>(registerValue & (0x01 << 6)))
, authenticated(static_cast<bool>(registerValue & (0x01 << 7)))
, anyHalted(static_cast<bool>(registerValue & (0x01 << 8)))
, allHalted(static_cast<bool>(registerValue & (0x01 << 9)))
, anyRunning(static_cast<bool>(registerValue & (0x01 << 10)))
, allRunning(static_cast<bool>(registerValue & (0x01 << 11)))
, anyUnavailable(static_cast<bool>(registerValue & (0x01 << 12)))
, allUnavailable(static_cast<bool>(registerValue & (0x01 << 13)))
, anyNonExistent(static_cast<bool>(registerValue & (0x01 << 14)))
, allNonExistent(static_cast<bool>(registerValue & (0x01 << 15)))
, anyResumeAcknowledge(static_cast<bool>(registerValue & (0x01 << 16)))
, allResumeAcknowledge(static_cast<bool>(registerValue & (0x01 << 17)))
, anyHaveReset(static_cast<bool>(registerValue & (0x01 << 18)))
, allHaveReset(static_cast<bool>(registerValue & (0x01 << 19)))
, implicitBreak(static_cast<bool>(registerValue & (0x01 << 22)))
, stickyUnavailableBits(static_cast<bool>(registerValue & (0x01 << 23)))
, ndmResetPending(static_cast<bool>(registerValue & (0x01 << 24)))
{}
[[nodiscard]] constexpr RegisterValue value() const {
return RegisterValue{0}
| static_cast<RegisterValue>(this->version)
| static_cast<RegisterValue>(this->validConfigStructurePointer) << 4
| static_cast<RegisterValue>(this->supportsResetHalt) << 5
| static_cast<RegisterValue>(this->authBusy) << 6
| static_cast<RegisterValue>(this->authenticated) << 7
| static_cast<RegisterValue>(this->anyHalted) << 8
| static_cast<RegisterValue>(this->allHalted) << 9
| static_cast<RegisterValue>(this->anyRunning) << 10
| static_cast<RegisterValue>(this->allRunning) << 11
| static_cast<RegisterValue>(this->anyUnavailable) << 12
| static_cast<RegisterValue>(this->allUnavailable) << 13
| static_cast<RegisterValue>(this->anyNonExistent) << 14
| static_cast<RegisterValue>(this->allNonExistent) << 15
| static_cast<RegisterValue>(this->anyResumeAcknowledge) << 16
| static_cast<RegisterValue>(this->allResumeAcknowledge) << 17
| static_cast<RegisterValue>(this->anyHaveReset) << 18
| static_cast<RegisterValue>(this->allHaveReset) << 19
| static_cast<RegisterValue>(this->implicitBreak) << 22
| static_cast<RegisterValue>(this->stickyUnavailableBits) << 23
| static_cast<RegisterValue>(this->ndmResetPending) << 24
;
}
};
}

View File

@@ -1,74 +0,0 @@
#pragma once
#include <cstdint>
#include "src/Targets/RiscV/RiscVGeneric.hpp"
namespace Targets::RiscV::Registers
{
struct DebugControlStatusRegister
{
enum class DebugModeCause: std::uint8_t
{
BREAK = 0x01,
TRIGGER = 0x02,
HALT_REQUEST = 0x03,
STEP = 0x04,
RESET_HALT_REQUEST = 0x05,
GROUP = 0x06,
};
PrivilegeMode privilegeMode:2;
bool step:1 = false;
bool nmiPending:1 = false;
bool mprvEnabled:1 = false;
DebugModeCause debugModeCause:3;
bool stopTime:1 = false;
bool stopCount:1 = false;
bool stepInterruptsEnabled:1 = false;
bool breakUMode:1 = false;
bool breakSMode:1 = false;
bool breakMMode:1 = false;
bool breakVUMode:1 = false;
bool breakVSMode:1 = false;
std::uint8_t debugVersion:4 = 0;
DebugControlStatusRegister() = default;
constexpr explicit DebugControlStatusRegister(RegisterValue registerValue)
: privilegeMode(static_cast<PrivilegeMode>(registerValue & 0x03))
, step(static_cast<bool>(registerValue & (0x01 << 2)))
, nmiPending(static_cast<bool>(registerValue & (0x01 << 3)))
, mprvEnabled(static_cast<bool>(registerValue & (0x01 << 4)))
, debugModeCause(static_cast<DebugModeCause>((registerValue >> 6) & 0x07))
, stopTime(static_cast<bool>(registerValue & (0x01 << 9)))
, stopCount(static_cast<bool>(registerValue & (0x01 << 10)))
, stepInterruptsEnabled(static_cast<bool>(registerValue & (0x01 << 11)))
, breakUMode(static_cast<bool>(registerValue & (0x01 << 12)))
, breakSMode(static_cast<bool>(registerValue & (0x01 << 13)))
, breakMMode(static_cast<bool>(registerValue & (0x01 << 15)))
, breakVUMode(static_cast<bool>(registerValue & (0x01 << 16)))
, breakVSMode(static_cast<bool>(registerValue & (0x01 << 17)))
, debugVersion(static_cast<std::uint8_t>(registerValue >> 28) & 0x0F)
{}
constexpr RegisterValue value() const {
return RegisterValue{0}
| static_cast<RegisterValue>(this->privilegeMode)
| static_cast<RegisterValue>(this->step) << 2
| static_cast<RegisterValue>(this->nmiPending) << 3
| static_cast<RegisterValue>(this->mprvEnabled) << 4
| static_cast<RegisterValue>(this->debugModeCause) << 6
| static_cast<RegisterValue>(this->stopTime) << 9
| static_cast<RegisterValue>(this->stopCount) << 10
| static_cast<RegisterValue>(this->stepInterruptsEnabled) << 11
| static_cast<RegisterValue>(this->breakUMode) << 12
| static_cast<RegisterValue>(this->breakSMode) << 13
| static_cast<RegisterValue>(this->breakMMode) << 15
| static_cast<RegisterValue>(this->breakVUMode) << 16
| static_cast<RegisterValue>(this->breakVSMode) << 17
| static_cast<RegisterValue>(this->debugVersion) << 28
;
}
};
}

View File

@@ -1,23 +0,0 @@
#pragma once
#include <cstdint>
#include "src/Targets/RiscV/RiscVGeneric.hpp"
namespace Targets::RiscV::Registers
{
enum class RegisterNumberBase: ::Targets::RiscV::RegisterNumber
{
CSR = 0x0000,
GPR = 0x1000,
FPR = 0x1020,
OTHER = 0xc000,
};
enum class RegisterNumber: ::Targets::RiscV::RegisterNumber
{
DEBUG_CONTROL_STATUS_REGISTER = 0x07b0,
DEBUG_PROGRAM_COUNTER_REGISTER = 0x07b1,
STACK_POINTER_X2 = 0x1002,
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -7,32 +7,19 @@
#include "src/Targets/Target.hpp"
#include "src/DebugToolDrivers/DebugTool.hpp"
#include "TargetDescription/TargetDescriptionFile.hpp"
#include "RiscVTargetConfig.hpp"
#include "TargetDescriptionFile.hpp"
#include "src/DebugToolDrivers/TargetInterfaces/RiscV/RiscVDebugInterface.hpp"
#include "src/DebugToolDrivers/TargetInterfaces/RiscV/RiscVProgramInterface.hpp"
#include "src/Targets/RiscV/RiscVGeneric.hpp"
#include "src/Targets/RiscV/Registers/RegisterNumbers.hpp"
#include "src/Targets/RiscV/Registers/DebugControlStatusRegister.hpp"
#include "src/Targets/RiscV/DebugModule/DebugModule.hpp"
#include "src/Targets/RiscV/DebugModule/Registers/ControlRegister.hpp"
#include "src/Targets/RiscV/DebugModule/Registers/StatusRegister.hpp"
#include "src/Targets/RiscV/DebugModule/Registers/AbstractControlStatusRegister.hpp"
#include "src/Targets/RiscV/DebugModule/Registers/AbstractCommandRegister.hpp"
#include "RiscVRegisterDescriptor.hpp"
#include "src/DebugToolDrivers/TargetInterfaces/RiscV/RiscVIdentificationInterface.hpp"
namespace Targets::RiscV
{
class RiscV: public Target
{
public:
explicit RiscV(
const TargetConfig& targetConfig,
TargetDescription::TargetDescriptionFile&& targetDescriptionFile
);
RiscV(const TargetConfig& targetConfig, TargetDescriptionFile&& targetDescriptionFile);
/*
* The functions below implement the Target interface for RISC-V targets.
@@ -41,20 +28,13 @@ namespace Targets::RiscV
* each function.
*/
/**
* All RISC-V compatible debug tools must provide a valid RiscVDebugInterface.
*
* @param debugTool
* @return
*/
bool supportsDebugTool(DebugTool* debugTool) override;
void setDebugTool(DebugTool* debugTool) override;
void activate() override;
void deactivate() override;
TargetDescriptor getDescriptor() override;
TargetDescriptor targetDescriptor() override;
void run(std::optional<TargetMemoryAddress> toAddress = std::nullopt) override;
void stop() override;
@@ -68,34 +48,45 @@ namespace Targets::RiscV
void removeHardwareBreakpoint(TargetMemoryAddress address) override;
void clearAllBreakpoints() override;
TargetRegisters readRegisters(const TargetRegisterDescriptorIds& descriptorIds) override;
void writeRegisters(const TargetRegisters& registers) override;
TargetRegisterDescriptorAndValuePairs readRegisters(const TargetRegisterDescriptors& descriptors) override;
void writeRegisters(const TargetRegisterDescriptorAndValuePairs& registers) override;
TargetMemoryBuffer readMemory(
TargetMemoryType memoryType,
const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
const TargetMemorySegmentDescriptor& memorySegmentDescriptor,
TargetMemoryAddress startAddress,
TargetMemorySize bytes,
const std::set<TargetMemoryAddressRange>& excludedAddressRanges = {}
) override;
void writeMemory(
TargetMemoryType memoryType,
const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
const TargetMemorySegmentDescriptor& memorySegmentDescriptor,
TargetMemoryAddress startAddress,
const TargetMemoryBuffer& buffer
) override;
void eraseMemory(TargetMemoryType memoryType) override;
bool isProgramMemory(
const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
const TargetMemorySegmentDescriptor& memorySegmentDescriptor,
TargetMemoryAddress startAddress,
TargetMemorySize size
) override;
void eraseMemory(
const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
const TargetMemorySegmentDescriptor& memorySegmentDescriptor
) override;
TargetState getState() override;
TargetExecutionState getExecutionState() override;
TargetMemoryAddress getProgramCounter() override;
void setProgramCounter(TargetMemoryAddress programCounter) override;
TargetStackPointer getStackPointer() override;
void setStackPointer(TargetStackPointer stackPointer) override;
std::map<int, TargetPinState> getPinStates(int variantId) override;
void setPinState(
const TargetPinDescriptor& pinDescriptor,
const TargetPinState& state
TargetGpioPinDescriptorAndStatePairs getGpioPinStates(
const TargetPinoutDescriptor& pinoutDescriptor
) override;
void setGpioPinState(const TargetPinDescriptor& pinDescriptor, const TargetGpioPinState& state) override;
void enableProgrammingMode() override;
@@ -104,43 +95,53 @@ namespace Targets::RiscV
bool programmingModeEnabled() override;
protected:
TargetDescription::TargetDescriptionFile targetDescriptionFile;
std::map<TargetRegisterDescriptorId, RiscVRegisterDescriptor> registerDescriptorsById;
RiscVRegisterDescriptor stackPointerRegisterDescriptor;
RiscVTargetConfig targetConfig;
TargetDescriptionFile targetDescriptionFile;
DebugToolDrivers::TargetInterfaces::RiscV::RiscVDebugInterface* riscVDebugInterface = nullptr;
DebugToolDrivers::TargetInterfaces::RiscV::RiscVProgramInterface* riscVProgramInterface = nullptr;
DebugToolDrivers::TargetInterfaces::RiscV::RiscVIdentificationInterface* riscVIdInterface = nullptr;
std::set<DebugModule::HartIndex> hartIndices;
DebugModule::HartIndex selectedHartIndex = 0;
/*
* On RISC-V targets, CPU registers are typically only accessible via the debug module (we can't access them
* via the system address space). So we use abstract commands to access these registers. This means we have to
* address these registers via their register numbers, as defined in the RISC-V debug spec.
*
* We effectively treat register numbers as a separate address space, with an addressable unit size of 4 bytes.
* The `cpuRegisterAddressSpaceDescriptor` member holds the descriptor for this address space.
*
* TODO: review this. This address space is specific to the RISC-V debug spec, but some debug tools may
* implement their own debug translator in firmware, and then provide a higher-level API to access the
* same registers. In that case, this address space may not be relevant. This may need to be moved.
* ATM all RISC-V debug tools supported by Bloom provide a DTM interface, so we use our own debug
* translator driver and this address space is, in fact, relevant. I will deal with this when it
* becomes a problem.
*/
TargetAddressSpaceDescriptor cpuRegisterAddressSpaceDescriptor;
const TargetMemorySegmentDescriptor& csrMemorySegmentDescriptor;
const TargetMemorySegmentDescriptor& gprMemorySegmentDescriptor;
void loadRegisterDescriptors();
TargetPeripheralDescriptor cpuPeripheralDescriptor;
const TargetRegisterGroupDescriptor& csrGroupDescriptor;
const TargetRegisterGroupDescriptor& gprGroupDescriptor;
const TargetRegisterDescriptor& pcRegisterDescriptor;
const TargetRegisterDescriptor& spRegisterDescriptor;
std::set<DebugModule::HartIndex> discoverHartIndices();
/*
* The "system" address space is the main address space on RISC-V targets.
*/
TargetAddressSpaceDescriptor sysAddressSpaceDescriptor;
DebugModule::Registers::ControlRegister readDebugModuleControlRegister();
DebugModule::Registers::StatusRegister readDebugModuleStatusRegister();
DebugModule::Registers::AbstractControlStatusRegister readDebugModuleAbstractControlStatusRegister();
const TargetMemorySegmentDescriptor& resolveRegisterMemorySegmentDescriptor(
const TargetRegisterDescriptor& regDescriptor,
const TargetAddressSpaceDescriptor& addressSpaceDescriptor
);
Registers::DebugControlStatusRegister readDebugControlStatusRegister();
void enableDebugModule();
void disableDebugModule();
RegisterValue readRegister(RegisterNumber number);
RegisterValue readRegister(Registers::RegisterNumber number);
void writeRegister(RegisterNumber number, RegisterValue value);
void writeRegister(Registers::RegisterNumber number, RegisterValue value);
void writeDebugModuleControlRegister(const DebugModule::Registers::ControlRegister& controlRegister);
void writeDebugControlStatusRegister(const Registers::DebugControlStatusRegister& controlRegister);
void executeAbstractCommand(const DebugModule::Registers::AbstractCommandRegister& abstractCommandRegister);
TargetMemoryAddress alignMemoryAddress(TargetMemoryAddress address, TargetMemoryAddress alignTo);
TargetMemorySize alignMemorySize(TargetMemorySize size, TargetMemorySize alignTo);
static TargetAddressSpaceDescriptor generateCpuRegisterAddressSpaceDescriptor();
static TargetPeripheralDescriptor generateCpuPeripheralDescriptor(
const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
const TargetMemorySegmentDescriptor& csrMemorySegmentDescriptor,
const TargetMemorySegmentDescriptor& gprMemorySegmentDescriptor
);
};
}

View File

@@ -1,16 +0,0 @@
#pragma once
#include <cstdint>
namespace Targets::RiscV
{
using RegisterValue = std::uint32_t;
using RegisterNumber = std::uint16_t;
enum class PrivilegeMode: std::uint8_t
{
U_MODE = 0x00,
S_MODE = 0x01,
M_MODE = 0x03,
};
}

View File

@@ -1,38 +0,0 @@
#pragma once
#include <cstdint>
#include "src/Targets/TargetRegisterDescriptor.hpp"
#include "RiscVGeneric.hpp"
namespace Targets::RiscV
{
struct RiscVRegisterDescriptor: public ::Targets::TargetRegisterDescriptor
{
RegisterNumber number;
RiscVRegisterDescriptor(
TargetRegisterType type,
RegisterNumber number,
TargetMemorySize size,
TargetMemoryType memoryType,
std::optional<std::string> name,
std::optional<std::string> groupName,
std::optional<std::string> description,
TargetRegisterAccess access
)
: ::Targets::TargetRegisterDescriptor(
type,
std::nullopt,
size,
memoryType,
name,
groupName,
description,
access
)
, number(number)
{}
};
}

View File

@@ -0,0 +1,8 @@
#include "RiscVTargetConfig.hpp"
namespace Targets::RiscV
{
RiscVTargetConfig::RiscVTargetConfig(const TargetConfig& targetConfig)
: TargetConfig(targetConfig)
{}
}

View File

@@ -0,0 +1,15 @@
#pragma once
#include "src/ProjectConfig.hpp"
namespace Targets::RiscV
{
/**
* Extending the generic TargetConfig struct to accommodate RISC-V target configuration parameters.
*/
struct RiscVTargetConfig: public TargetConfig
{
public:
explicit RiscVTargetConfig(const TargetConfig& targetConfig);
};
}

View File

@@ -1,18 +0,0 @@
#include "TargetDescriptionFile.hpp"
#include <QString>
namespace Targets::RiscV::TargetDescription
{
TargetDescriptionFile::TargetDescriptionFile(const std::string& xmlFilePath)
: Targets::TargetDescription::TargetDescriptionFile(xmlFilePath)
{}
std::string TargetDescriptionFile::getTargetId() const {
return this->deviceAttribute("id");
}
std::string TargetDescriptionFile::getVendorName() const {
return this->deviceAttribute("vendor");
}
}

View File

@@ -0,0 +1,16 @@
#include "TargetDescriptionFile.hpp"
namespace Targets::RiscV
{
TargetDescriptionFile::TargetDescriptionFile(const std::string& xmlFilePath)
: Targets::TargetDescription::TargetDescriptionFile(xmlFilePath)
{}
std::string TargetDescriptionFile::getTargetId() const {
return this->getProperty("vendor", "target_id").value;
}
TargetAddressSpaceDescriptor TargetDescriptionFile::getSystemAddressSpaceDescriptor() const {
return this->targetAddressSpaceDescriptorFromAddressSpace(this->getAddressSpace("system"));
}
}

View File

@@ -2,9 +2,7 @@
#include "src/Targets/TargetDescription/TargetDescriptionFile.hpp"
#include "src/Targets/RiscV/RiscVGeneric.hpp"
namespace Targets::RiscV::TargetDescription
namespace Targets::RiscV
{
/**
* Represents an RISC-V TDF.
@@ -23,11 +21,6 @@ namespace Targets::RiscV::TargetDescription
*/
[[nodiscard]] std::string getTargetId() const;
/**
* Returns the RISC-V vendor name from the TDF.
*
* @return
*/
[[nodiscard]] std::string getVendorName() const;
[[nodiscard]] TargetAddressSpaceDescriptor getSystemAddressSpaceDescriptor() const;
};
}

View File

@@ -1,11 +0,0 @@
#pragma once
#include <cstdint>
#include "src/Targets/TargetMemory.hpp"
namespace Targets::RiscV
{
struct TargetParameters
{};
}

View File

@@ -10,11 +10,15 @@
#include "src/ProjectConfig.hpp"
#include "TargetDescriptor.hpp"
#include "TargetAddressSpaceDescriptor.hpp"
#include "TargetMemorySegmentDescriptor.hpp"
#include "TargetState.hpp"
#include "TargetRegisterDescriptor.hpp"
#include "TargetRegister.hpp"
#include "TargetMemory.hpp"
#include "TargetBreakpoint.hpp"
#include "TargetPinoutDescriptor.hpp"
#include "TargetPinDescriptor.hpp"
#include "TargetGpioPinState.hpp"
#include "src/DebugToolDrivers/DebugTool.hpp"
@@ -34,10 +38,6 @@ namespace Targets
virtual ~Target() = default;
bool isActivated() const {
return this->activated;
}
/**
* Should check if the given debugTool is compatible with the target. Returning false in this function will
* prevent Bloom from attempting to use the selected debug tool with the selected target. An InvalidConfig
@@ -79,22 +79,18 @@ namespace Targets
virtual void deactivate() = 0;
/**
* Should generate and return a TargetDescriptor for the current target.
*
* This is called when a component within Bloom requests the TargetDescriptor from the TargetController.
* The TargetController will cache this upon the first request. Subsequent requests will be serviced with the
* cached value.
* Should generate a TargetDescriptor for the current target.
*
* @return
*/
virtual TargetDescriptor getDescriptor() = 0;
virtual TargetDescriptor targetDescriptor() = 0;
/**
* Should resume execution on the target.
*
* @param toAddress
*/
virtual void run(std::optional<TargetMemoryAddress> toAddress = std::nullopt) = 0;
virtual void run(std::optional<TargetMemoryAddress> toAddress) = 0;
/**
* Should halt execution on the target.
@@ -149,23 +145,24 @@ namespace Targets
/**
* Should read register values of the registers described by the given descriptors.
*
* @param descriptorIds
* @param descriptors
*
* @return
*/
virtual TargetRegisters readRegisters(const Targets::TargetRegisterDescriptorIds& descriptorIds) = 0;
virtual TargetRegisterDescriptorAndValuePairs readRegisters(const TargetRegisterDescriptors& descriptors) = 0;
/**
* Should update the value of the given registers.
*
* @param registers
*/
virtual void writeRegisters(const TargetRegisters& registers) = 0;
virtual void writeRegisters(const TargetRegisterDescriptorAndValuePairs& registers) = 0;
/**
* Should read memory from the target.
*
* @param memoryType
* @param addressSpaceDescriptor
* @param memorySegmentDescriptor
* @param startAddress
* @param bytes
* @param excludedAddressRanges
@@ -173,38 +170,65 @@ namespace Targets
* @return
*/
virtual TargetMemoryBuffer readMemory(
TargetMemoryType memoryType,
const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
const TargetMemorySegmentDescriptor& memorySegmentDescriptor,
TargetMemoryAddress startAddress,
TargetMemorySize bytes,
const std::set<Targets::TargetMemoryAddressRange>& excludedAddressRanges = {}
const std::set<TargetMemoryAddressRange>& excludedAddressRanges
) = 0;
/**
* Should write memory to the target.
*
* @param memoryType
* @param addressSpaceDescriptor
* @param memorySegmentDescriptor
* @param startAddress
* @param buffer
*/
virtual void writeMemory(
TargetMemoryType memoryType,
const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
const TargetMemorySegmentDescriptor& memorySegmentDescriptor,
TargetMemoryAddress startAddress,
const TargetMemoryBuffer& buffer
) = 0;
/**
* Should check if the given memory is program memory.
*
* The TargetMemorySegmentDescriptor::executable flag specifies whether any part of the segment is executable,
* but this member function allows for a more granular check.
*
* @param addressSpaceDescriptor
* @param memorySegmentDescriptor
* @param startAddress
* @param size
*
* @return
*/
virtual bool isProgramMemory(
const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
const TargetMemorySegmentDescriptor& memorySegmentDescriptor,
TargetMemoryAddress startAddress,
TargetMemorySize size
) = 0;
/**
* Should erase the entire address range of a given memory type.
*
* @param memoryType
* @param addressSpaceDescriptor
* @param memorySegmentDescriptor
*/
virtual void eraseMemory(TargetMemoryType memoryType) = 0;
virtual void eraseMemory(
const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
const TargetMemorySegmentDescriptor& memorySegmentDescriptor
) = 0;
/**
* Should return the current state of the target.
*
* @return
*/
virtual TargetState getState() = 0;
virtual TargetExecutionState getExecutionState() = 0;
/**
* Should fetch the current program counter value.
@@ -228,24 +252,30 @@ namespace Targets
virtual TargetStackPointer getStackPointer() = 0;
/**
* Should get the current pin states for each pin on the target, mapped by pin number
* Should update the stack pointer value on the target.
*
* @param variantId
* @param stackPointer
*/
virtual void setStackPointer(TargetStackPointer stackPointer) = 0;
/**
* Should get the current state of each GPIO pin on the target
*
* @param pinoutDescriptor
*
* @return
*/
virtual std::map<int, TargetPinState> getPinStates(int variantId) = 0;
virtual TargetGpioPinDescriptorAndStatePairs getGpioPinStates(
const TargetPinoutDescriptor& pinoutDescriptor
) = 0;
/**
* Should update the pin state for the given pin, with the given state.
* Should update the pin state for the given GPIO pin, with the given state.
*
* @param pinDescriptor
* @param state
*/
virtual void setPinState(
const TargetPinDescriptor& pinDescriptor,
const TargetPinState& state
) = 0;
virtual void setGpioPinState(const TargetPinDescriptor& pinDescriptor, const TargetGpioPinState& state) = 0;
/**
* Should prepare the target for programming.
@@ -263,14 +293,5 @@ namespace Targets
* @return
*/
virtual bool programmingModeEnabled() = 0;
protected:
/**
* Target related configuration provided by the user. This is passed in via the first stage of target
* configuration. See Target::preActivationConfigure() for more.
*/
TargetConfig config;
bool activated = false;
};
}

View File

@@ -1,5 +1,9 @@
#include "TargetAddressSpaceDescriptor.hpp"
#include <utility>
#include <algorithm>
#include "src/Services/StringService.hpp"
#include "src/Exceptions/InternalFatalErrorException.hpp"
namespace Targets
@@ -8,17 +12,27 @@ namespace Targets
const std::string& key,
const TargetMemoryAddressRange& addressRange,
TargetMemoryEndianness endianness,
const std::map<std::string, TargetMemorySegmentDescriptor>& segmentDescriptorsByKey
std::map<std::string, TargetMemorySegmentDescriptor>&& segmentDescriptorsByKey,
std::uint8_t unitSize
)
: id(++(TargetAddressSpaceDescriptor::lastAddressSpaceDescriptorId))
: id(TargetAddressSpaceDescriptor::generateId(key))
, key(key)
, addressRange(addressRange)
, endianness(endianness)
, segmentDescriptorsByKey(segmentDescriptorsByKey)
, segmentDescriptorsByKey(std::move(segmentDescriptorsByKey))
, unitSize(unitSize)
{}
bool TargetAddressSpaceDescriptor::operator == (const TargetAddressSpaceDescriptor& other) const {
return this->id == other.id;
}
bool TargetAddressSpaceDescriptor::operator != (const TargetAddressSpaceDescriptor& other) const {
return !(*this == other);
}
TargetMemorySize TargetAddressSpaceDescriptor::size() const {
return this->addressRange.size();
return this->addressRange.size() * this->unitSize;
}
std::optional<
@@ -38,10 +52,10 @@ namespace Targets
) const {
const auto segment = this->tryGetMemorySegmentDescriptor(key);
if (!segment.has_value()) {
throw Exceptions::InternalFatalErrorException(
throw Exceptions::InternalFatalErrorException{
"Failed to get memory segment descriptor \"" + key + "\" from address space \"" + this->key
+ "\" - segment not found"
);
};
}
return segment->get();
@@ -52,7 +66,7 @@ namespace Targets
> TargetAddressSpaceDescriptor::getIntersectingMemorySegmentDescriptors(
const TargetMemoryAddressRange& addressRange
) const {
auto output = std::vector<const TargetMemorySegmentDescriptor*>();
auto output = std::vector<const TargetMemorySegmentDescriptor*>{};
for (const auto& [key, segmentDescriptor] : this->segmentDescriptorsByKey) {
if (segmentDescriptor.addressRange.intersectsWith(addressRange)) {
@@ -60,6 +74,34 @@ namespace Targets
}
}
std::sort(
output.begin(),
output.end(),
[] (const TargetMemorySegmentDescriptor* descA, const TargetMemorySegmentDescriptor* descB) {
return descA->addressRange.startAddress < descB->addressRange.startAddress;
}
);
return output;
}
TargetAddressSpaceDescriptor TargetAddressSpaceDescriptor::clone() const {
auto output = TargetAddressSpaceDescriptor{
this->key,
this->addressRange,
this->endianness,
{},
this->unitSize
};
for (const auto& [key, descriptor] : this->segmentDescriptorsByKey) {
output.segmentDescriptorsByKey.emplace(key, descriptor.clone());
}
return output;
}
TargetAddressSpaceId TargetAddressSpaceDescriptor::generateId(const std::string& addressSpaceKey) {
return static_cast<TargetAddressSpaceId>(Services::StringService::hash(addressSpaceKey));
}
}

View File

@@ -11,24 +11,47 @@
namespace Targets
{
using TargetAddressSpaceDescriptorId = std::uint8_t;
struct TargetAddressSpaceDescriptor
{
public:
const TargetAddressSpaceDescriptorId id;
std::string key;
/*
* The ID of an address space is just a hash of the address space key, which is unique. We use the ID for
* cheap equality checks.
*
* See TargetAddressSpaceDescriptor::generateId() for more.
*/
const TargetAddressSpaceId id;
const std::string key;
TargetMemoryAddressRange addressRange;
TargetMemoryEndianness endianness;
std::map<std::string, TargetMemorySegmentDescriptor> segmentDescriptorsByKey;
/*
* In Bloom, a byte is always considered to be 8 bits in width.
*
* Not all address spaces are byte-addressable. TargetAddressSpaceDescriptor::unitSize holds the number of
* bytes within a single addressable unit.
*
* This is also available in segment descriptors, via TargetMemorySegmentDescriptor::addressSpaceUnitSize.
*/
std::uint8_t unitSize;
TargetAddressSpaceDescriptor(
const std::string& key,
const TargetMemoryAddressRange& addressRange,
TargetMemoryEndianness endianness,
const std::map<std::string, TargetMemorySegmentDescriptor>& segmentDescriptorsByKey
std::map<std::string, TargetMemorySegmentDescriptor>&& segmentDescriptorsByKey,
std::uint8_t unitSize = 1
);
TargetAddressSpaceDescriptor(const TargetAddressSpaceDescriptor& other) = delete;
TargetAddressSpaceDescriptor& operator = (const TargetAddressSpaceDescriptor& other) = delete;
TargetAddressSpaceDescriptor(TargetAddressSpaceDescriptor&& other) noexcept = default;
bool operator == (const TargetAddressSpaceDescriptor& other) const;
bool operator != (const TargetAddressSpaceDescriptor& other) const;
TargetMemorySize size() const;
/**
@@ -69,7 +92,8 @@ namespace Targets
const TargetMemoryAddressRange& addressRange
) const;
private:
static inline std::atomic<TargetAddressSpaceDescriptorId> lastAddressSpaceDescriptorId = 0;
[[nodiscard]] TargetAddressSpaceDescriptor clone() const;
static TargetAddressSpaceId generateId(const std::string& addressSpaceKey);
};
}

View File

@@ -0,0 +1,20 @@
#include "TargetBitFieldDescriptor.hpp"
namespace Targets
{
TargetBitFieldDescriptor::TargetBitFieldDescriptor(
const std::string& key,
const std::string& name,
std::uint64_t mask,
std::optional<std::string> description
)
: key(key)
, name(name)
, mask(mask)
, description(description)
{}
TargetBitFieldDescriptor TargetBitFieldDescriptor::clone() const {
return {*this};
}
}

View File

@@ -0,0 +1,36 @@
#pragma once
#include <cstdint>
#include <string>
#include <optional>
#include "src/Helpers/Pair.hpp"
namespace Targets
{
struct TargetBitFieldDescriptor
{
public:
std::string key;
std::string name;
std::uint64_t mask;
std::optional<std::string> description;
TargetBitFieldDescriptor(
const std::string& key,
const std::string& name,
std::uint64_t mask,
std::optional<std::string> description
);
TargetBitFieldDescriptor& operator = (const TargetBitFieldDescriptor& other) = delete;
TargetBitFieldDescriptor(TargetBitFieldDescriptor&& other) noexcept = default;
TargetBitFieldDescriptor& operator = (TargetBitFieldDescriptor&& other) = default;
[[nodiscard]] TargetBitFieldDescriptor clone() const;
private:
TargetBitFieldDescriptor(const TargetBitFieldDescriptor& other) = default;
};
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include <string>
#include <cstdint>
#include <optional>
#include <map>
@@ -16,6 +17,7 @@ namespace Targets::TargetDescription
std::string key;
TargetMemoryAddress startAddress;
TargetMemorySize size;
std::uint8_t unitSize;
std::optional<TargetMemoryEndianness> endianness;
std::map<std::string, MemorySegment, std::less<void>> memorySegmentsByKey;
@@ -23,12 +25,14 @@ namespace Targets::TargetDescription
const std::string& key,
TargetMemoryAddress startAddress,
TargetMemorySize size,
std::uint8_t unitSize,
const std::optional<TargetMemoryEndianness>& endianness,
const std::map<std::string, MemorySegment, std::less<void>>& memorySegmentsByKey
)
: key(key)
, startAddress(startAddress)
, size(size)
, unitSize(unitSize)
, endianness(endianness)
, memorySegmentsByKey(memorySegmentsByKey)
{}
@@ -46,10 +50,10 @@ namespace Targets::TargetDescription
const MemorySegment& getMemorySegment(std::string_view key) const {
const auto segment = this->tryGetMemorySegment(key);
if (!segment.has_value()) {
throw Exceptions::InvalidTargetDescriptionDataException(
"Failed to get memory segment \"" + std::string(key)
throw Exceptions::InvalidTargetDescriptionDataException{
"Failed to get memory segment \"" + std::string{key}
+ "\" from address space in TDF - segment not found"
);
};
}
return segment->get();

View File

@@ -55,17 +55,17 @@ namespace Targets::TargetDescription
return firstSubgroupIt != this->sectionsByKey.end()
? keys.size() > 1
? firstSubgroupIt->second.tryGetSubSection(keys | std::ranges::views::drop(1))
: std::optional(std::cref(firstSubgroupIt->second))
: std::optional{std::cref(firstSubgroupIt->second)}
: std::nullopt;
}
const MemorySegmentSection& getSection(std::string_view keyStr) const {
const auto propertyGroup = this->tryGetSection(keyStr);
if (!propertyGroup.has_value()) {
throw Exceptions::InvalidTargetDescriptionDataException(
"Failed to get memory segment section \"" + std::string(keyStr)
throw Exceptions::InvalidTargetDescriptionDataException{
"Failed to get memory segment section \"" + std::string{keyStr}
+ "\" from memory segment in TDF - section not found"
);
};
}
return propertyGroup->get();

View File

@@ -66,10 +66,10 @@ namespace Targets::TargetDescription
const MemorySegmentSection& getSubSection(std::string_view keyStr) const {
const auto propertyGroup = this->tryGetSubSection(keyStr);
if (!propertyGroup.has_value()) {
throw Exceptions::InvalidTargetDescriptionDataException(
"Failed to get memory segment sub-section \"" + std::string(keyStr)
throw Exceptions::InvalidTargetDescriptionDataException{
"Failed to get memory segment sub-section \"" + std::string{keyStr}
+ "\" from memory segment in TDF - sub-section not found"
);
};
}
return propertyGroup->get();

View File

@@ -40,17 +40,17 @@ namespace Targets::TargetDescription
return firstGroupIt != this->registerGroupsByKey.end()
? keys.size() > 1
? firstGroupIt->second.tryGetSubgroup(keys | std::ranges::views::drop(1))
: std::optional(std::cref(firstGroupIt->second))
: std::optional{std::cref(firstGroupIt->second)}
: std::nullopt;
}
const RegisterGroup& getRegisterGroup(std::string_view keyStr) const {
const auto group = this->tryGetRegisterGroup(keyStr);
if (!group.has_value()) {
throw Exceptions::InvalidTargetDescriptionDataException(
"Failed to get register group \"" + std::string(keyStr)
throw Exceptions::InvalidTargetDescriptionDataException{
"Failed to get register group \"" + std::string{keyStr}
+ "\" from module in TDF - register group not found"
);
};
}
return group->get();

View File

@@ -51,10 +51,10 @@ namespace Targets::TargetDescription
const RegisterGroupInstance& getRegisterGroupInstance(std::string_view key) const {
const auto instance = this->tryGetRegisterGroupInstance(key);
if (!instance.has_value()) {
throw Exceptions::InvalidTargetDescriptionDataException(
"Failed to get register group instance \"" + std::string(key)
throw Exceptions::InvalidTargetDescriptionDataException{
"Failed to get register group instance \"" + std::string{key}
+ "\" from peripheral in TDF - register group instance not found"
);
};
}
return instance->get();

View File

@@ -1,21 +1,15 @@
#pragma once
#include <cstdint>
#include <string>
namespace Targets::TargetDescription
{
struct PhysicalInterface
{
std::string name;
std::string type;
std::string value;
PhysicalInterface(
const std::string& name,
const std::string& type
)
: name(name)
, type(type)
PhysicalInterface(const std::string& value)
: value(value)
{}
};
}

View File

@@ -14,14 +14,14 @@ namespace Targets::TargetDescription
{
std::string key;
std::string name;
::Targets::PinoutType type;
::Targets::TargetPinoutType type;
std::optional<std::string> function;
std::vector<Pin> pins;
Pinout(
const std::string& key,
const std::string& name,
::Targets::PinoutType type,
::Targets::TargetPinoutType type,
const std::optional<std::string>& function,
const std::vector<Pin>& pins
)

View File

@@ -49,7 +49,7 @@ namespace Targets::TargetDescription
return std::nullopt;
}
auto subgroup = std::optional(std::cref(firstSubgroupIt->second));
auto subgroup = std::optional{std::cref(firstSubgroupIt->second)};
for (const auto key : keys | std::ranges::views::drop(1)) {
subgroup = subgroup->get().tryGetSubgroup(key);
@@ -68,10 +68,10 @@ namespace Targets::TargetDescription
const PropertyGroup& getSubgroup(std::string_view keyStr) const {
const auto propertyGroup = this->tryGetSubgroup(keyStr);
if (!propertyGroup.has_value()) {
throw Exceptions::InvalidTargetDescriptionDataException(
"Failed to get subgroup \"" + std::string(keyStr)
throw Exceptions::InvalidTargetDescriptionDataException{
"Failed to get subgroup \"" + std::string{keyStr}
+ "\" from property group in TDF - subgroup not found"
);
};
}
return propertyGroup->get();
@@ -90,9 +90,10 @@ namespace Targets::TargetDescription
const Property& getProperty(std::string_view key) const {
const auto property = this->tryGetProperty(key);
if (!property.has_value()) {
throw Exceptions::InvalidTargetDescriptionDataException(
"Failed to get property \"" + std::string(key) + "\" from property group in TDF - property not found"
);
throw Exceptions::InvalidTargetDescriptionDataException{
"Failed to get property \"" + std::string{key}
+ "\" from property group in TDF - property not found"
};
}
return property->get();

View File

@@ -3,25 +3,25 @@
A target description file (TDF) is an XML file that describes a particular target. All targets that are supported by
Bloom will have an associated TDF in Bloom's codebase. They can be found in `src/Targets/TargetDescriptionFiles`.
The data held by TDFs is fundamental to Bloom's operation. The following is an incomplete list of the data extracted
from TDFs:
The data held by TDFs is fundamental to Bloom's operation. The following is an incomplete list of the data contained
within Bloom's TDFs:
- Memory address space descriptions (including sections, offsets and sizes)
- Register descriptions (including offsets and sizes)
- Parameters for debug interfaces
- Memory address spaces, segments and sections
- Peripherals register groups, registers and signals
- Debug interface parameters
- Target signatures
- Package variant descriptions
- Package pinouts
Given that Bloom currently only supports AVR8 targets, we only possess TDFs for AVR8 targets.
TDFs are distributed with Bloom. They are copied to the build directory
(`${CMAKE_BINARY_DIR}/resources/TargetDescriptionFiles/`) at build time and included in the distributed packages (DEB,
RPM, etc). Upon copying the TDFs, we also generate a JSON mapping of AVR8 target IDs to TDF file paths. This
RPM, etc).
Upon copying the TDFs, we also generate a JSON mapping of AVR8 target IDs to TDF file paths. This
mapping is also distributed with Bloom and can be found in the `${CMAKE_BINARY_DIR}/resources/TargetDescriptionFiles/AVR`
directory, with the name `Mapping.json`. The mapping is used by Bloom, at runtime, to resolve the appropriate TDF from
an AVR8 target signature. The TDF file paths in the mapping are relative to Bloom's resource directory.
See the [`Avr8::Avr8(...)`](../../Targets/Microchip/AVR/AVR8/Avr8.cpp) constructor for more.
See the [`Avr8::Avr8(...)`](../../Targets/Microchip/AVR8/Avr8.cpp) constructor for more.
See `build/scripts/Avr8TargetDescriptionFiles.php` for the script that performs the copying and generation of the JSON
mapping.
@@ -44,7 +44,7 @@ AVR8 TDFs describe certain constructs in a way that **may** not be employed by o
AVR8 PORT registers are described in a `<module>` node of the TDF. This method is currently considered to be specific
to AVR8 TDFs. For that reason, we extend the `Targets::TargetDescription::TargetDescriptionFile` class to better
represent TDFs for particular target families or architectures. For AVR8 targets, we use the
`Targets::Microchip::Avr::Avr8Bit::TargetDescription::TargetDescriptionFile` class to represent AVR8 TDFs.
`Targets::Microchip::Avr8::TargetDescription::TargetDescriptionFile` class to represent AVR8 TDFs.
It would be good to keep in mind that as and when support for other target families and architectures is implemented,
we may use the constructs that were initially specific to AVR8 TDFs, in other TDFs. In this case, those constructs will

View File

@@ -60,9 +60,9 @@ namespace Targets::TargetDescription
const BitField& getBitField(std::string_view key) const {
const auto bitField = this->tryGetBitField(key);
if (!bitField.has_value()) {
throw Exceptions::InvalidTargetDescriptionDataException(
"Failed to get bit field \"" + std::string(key) + "\" from register in TDF - bit field not found"
);
throw Exceptions::InvalidTargetDescriptionDataException{
"Failed to get bit field \"" + std::string{key} + "\" from register in TDF - bit field not found"
};
}
return bitField->get();

View File

@@ -67,10 +67,10 @@ namespace Targets::TargetDescription
const RegisterGroup& getSubgroup(std::string_view keyStr) const {
const auto subgroup = this->tryGetSubgroup(keyStr);
if (!subgroup.has_value()) {
throw Exceptions::InvalidTargetDescriptionDataException(
"Failed to get subgroup \"" + std::string(keyStr)
throw Exceptions::InvalidTargetDescriptionDataException{
"Failed to get subgroup \"" + std::string{keyStr}
+ "\" from register group in TDF - subgroup not found"
);
};
}
return subgroup->get();
@@ -89,10 +89,10 @@ namespace Targets::TargetDescription
const Register& getRegister(std::string_view key) const {
const auto reg = this->tryGetRegister(key);
if (!reg.has_value()) {
throw Exceptions::InvalidTargetDescriptionDataException(
"Failed to get register \"" + std::string(key) + "\" from register group in TDF - register "
throw Exceptions::InvalidTargetDescriptionDataException{
"Failed to get register \"" + std::string{key} + "\" from register group in TDF - register "
"not found"
);
};
}
return reg->get();

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,5 @@
#pragma once
#include <QFile>
#include <QDomDocument>
#include <QDomElement>
#include <string>
@@ -30,8 +29,13 @@
#include "src/Targets/TargetAddressSpaceDescriptor.hpp"
#include "src/Targets/TargetMemorySegmentDescriptor.hpp"
#include "src/Targets/TargetPeripheralDescriptor.hpp"
#include "src/Targets/TargetPeripheralSignalDescriptor.hpp"
#include "src/Targets/TargetRegisterGroupDescriptor.hpp"
#include "src/Targets/TargetRegisterDescriptor.hpp"
#include "src/Targets/TargetBitFieldDescriptor.hpp"
#include "src/Targets/TargetPinoutDescriptor.hpp"
#include "src/Targets/TargetPinDescriptor.hpp"
#include "src/Targets/TargetVariantDescriptor.hpp"
#include "src/Targets/TargetPhysicalInterface.hpp"
namespace Targets::TargetDescription
@@ -46,12 +50,10 @@ namespace Targets::TargetDescription
* During the build process, all target description files are copied to the distribution directory, ready
* to be shipped with the Bloom binary.
*
* Processing of target description files is done in this class.
*
* This class may be extended to further reflect a TDF that is specific to a particular target, target architecture
* or target family. For example, the Targets::Microchip::Avr::Avr8Bit::TargetDescription::TargetDescriptionFile
* class inherits from this class, to represent TDFs for AVR8 targets. The derived class provides access to
* additional data that is only found in AVR8 TDFs (such as AVR target signature, AVR Family, etc).
* or target family. For example, the Targets::Microchip::Avr8::TargetDescriptionFile class inherits from this
* class, to represent TDFs for AVR8 targets. The derived class provides access to additional data that is only
* found in AVR8 TDFs (such as AVR target signature, AVR Family, etc).
*
* For more information of TDFs, see src/Targets/TargetDescription/README.md
*/
@@ -78,7 +80,7 @@ namespace Targets::TargetDescription
*
* @return
*/
[[nodiscard]] const std::string& getTargetName() const;
[[nodiscard]] const std::string& getName() const;
/**
* Returns the target family extracted from the TDF.
@@ -87,16 +89,35 @@ namespace Targets::TargetDescription
*/
[[nodiscard]] TargetFamily getFamily() const;
[[nodiscard]] std::optional<std::string> tryGetVendorName() const;
[[nodiscard]] const std::string& getVendorName() const;
[[nodiscard]] std::optional<std::reference_wrapper<const PropertyGroup>> tryGetPropertyGroup(
std::string_view keyStr
) const;
[[nodiscard]] const PropertyGroup& getPropertyGroup(std::string_view keyStr) const;
[[nodiscard]] std::optional<std::reference_wrapper<const Property>> tryGetProperty(
std::string_view groupKey,
std::string_view propertyKey
) const;
[[nodiscard]] const Property& getProperty(std::string_view groupKey, std::string_view propertyKey) const;
[[nodiscard]] std::optional<std::reference_wrapper<const AddressSpace>> tryGetAddressSpace(
std::string_view key
) const;
[[nodiscard]] const AddressSpace& getAddressSpace(std::string_view key) const;
[[nodiscard]] std::optional<std::reference_wrapper<const MemorySegment>> tryGetMemorySegment(
std::string_view addressSpaceKey,
std::string_view segmentKey
) const;
[[nodiscard]] const MemorySegment& getMemorySegment(
std::string_view addressSpaceKey,
std::string_view segmentKey
) const;
[[nodiscard]] std::set<Targets::TargetPhysicalInterface> getPhysicalInterfaces() const;
[[nodiscard]] std::optional<std::reference_wrapper<const Module>> tryGetModule(
@@ -109,8 +130,25 @@ namespace Targets::TargetDescription
) const;
[[nodiscard]] const Peripheral& getPeripheral(std::string_view key) const;
TargetDescriptor targetDescriptor() const;
std::map<TargetAddressSpaceDescriptorId, TargetAddressSpaceDescriptor> targetAddressSpaceDescriptorsById() const;
[[nodiscard]] std::optional<TargetMemorySegmentDescriptor> tryGetTargetMemorySegmentDescriptor(
std::string_view addressSpaceKey,
std::string_view segmentKey
) const;
[[nodiscard]] TargetMemorySegmentDescriptor getTargetMemorySegmentDescriptor(
std::string_view addressSpaceKey,
std::string_view segmentKey
) const;
[[nodiscard]] std::optional<TargetPeripheralDescriptor> tryGetTargetPeripheralDescriptor(
std::string_view key
) const;
[[nodiscard]] TargetPeripheralDescriptor getTargetPeripheralDescriptor(std::string_view key) const;
[[nodiscard]] std::map<std::string, TargetAddressSpaceDescriptor> targetAddressSpaceDescriptorsByKey() const;
[[nodiscard]] std::map<std::string, TargetPeripheralDescriptor> targetPeripheralDescriptorsByKey() const;
[[nodiscard]] std::map<std::string, TargetPinoutDescriptor> targetPinoutDescriptorsByKey() const;
[[nodiscard]] std::vector<TargetVariantDescriptor> targetVariantDescriptors() const;
[[nodiscard]] std::vector<TargetPeripheralDescriptor> gpioPortPeripheralDescriptors() const;
protected:
std::map<std::string, std::string> deviceAttributesByName;
@@ -165,25 +203,38 @@ namespace Targets::TargetDescription
);
static TargetMemorySegmentDescriptor targetMemorySegmentDescriptorFromMemorySegment(
const MemorySegment& memorySegment
const MemorySegment& memorySegment,
const AddressSpace& addressSpace
);
static TargetPeripheralDescriptor targetPeripheralDescriptorFromPeripheral(
const Peripheral& peripheral,
const Module& peripheralModule
);
static TargetPeripheralSignalDescriptor targetPeripheralSignalDescriptorFromSignal(const Signal& signal);
static TargetRegisterGroupDescriptor targetRegisterGroupDescriptorFromRegisterGroup(
const RegisterGroup& registerGroup,
const Module& peripheralModule,
TargetMemoryAddress baseAddress,
const std::string& addressSpaceKey,
TargetAddressSpaceDescriptorId addressSpaceDescriptorId,
const std::string& key,
const std::string& name,
const std::optional<std::string>& description
const std::string& addressSpaceKey,
const std::optional<std::string>& description,
const RegisterGroup& registerGroup,
const Module& peripheralModule,
TargetMemoryAddress baseAddress
);
static TargetRegisterDescriptor targetRegisterDescriptorFromRegister(
const Register& reg,
const std::string& addressSpaceKey,
TargetAddressSpaceDescriptorId addressSpaceDescriptorId,
TargetMemoryAddress baseAddress
);
static TargetBitFieldDescriptor targetBitFieldDescriptorFromBitField(const BitField& bitField);
static TargetPinoutDescriptor targetPinoutDescriptorFromPinout(const Pinout& pinout);
static TargetPinDescriptor targetPinDescriptorFromPin(const Pin& pin);
static TargetVariantDescriptor targetVariantDescriptorFromVariant(const Variant& variant);
};
}

View File

@@ -1,5 +1,7 @@
#include "TargetDescriptor.hpp"
#include <utility>
#include "src/Exceptions/InternalFatalErrorException.hpp"
namespace Targets
@@ -9,18 +11,20 @@ namespace Targets
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,
std::map<std::string, TargetAddressSpaceDescriptor>&& addressSpaceDescriptorsByKey,
std::map<std::string, TargetPeripheralDescriptor>&& peripheralDescriptorsByKey,
std::map<std::string, TargetPinoutDescriptor>&& pinoutDescriptorsByKey,
std::vector<TargetVariantDescriptor>&& variantDescriptors,
const BreakpointResources& breakpointResources
)
: name(name)
, family(family)
, marketId(marketId)
, vendorName(vendorName)
, addressSpaceDescriptorsByKey(addressSpaceDescriptorsByKey)
, peripheralDescriptorsByKey(peripheralDescriptorsByKey)
, variants(variants)
, addressSpaceDescriptorsByKey(std::move(addressSpaceDescriptorsByKey))
, peripheralDescriptorsByKey(std::move(peripheralDescriptorsByKey))
, pinoutDescriptorsByKey(std::move(pinoutDescriptorsByKey))
, variantDescriptors(std::move(variantDescriptors))
, breakpointResources(breakpointResources)
{}
@@ -39,10 +43,74 @@ namespace Targets
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)
throw Exceptions::InternalFatalErrorException{
"Failed to get address space descriptor \"" + std::string{key}
+ "\" from target descriptor - descriptor not found"
);
};
}
return descriptor->get();
}
const TargetAddressSpaceDescriptor& TargetDescriptor::getFirstAddressSpaceDescriptorContainingMemorySegment(
const std::string& memorySegmentKey
) const {
for (const auto& [key, addressSpaceDescriptor] : this->addressSpaceDescriptorsByKey) {
const auto segmentDescriptor = addressSpaceDescriptor.tryGetMemorySegmentDescriptor(memorySegmentKey);
if (segmentDescriptor.has_value()) {
return addressSpaceDescriptor;
}
}
throw Exceptions::InternalFatalErrorException{
"Failed to get address space descriptor from target descriptor - descriptor containing memory segment \""
+ memorySegmentKey + "\" not found"
};
}
std::optional<
std::reference_wrapper<const TargetPeripheralDescriptor>
> TargetDescriptor::tryGetPeripheralDescriptor(const std::string& key) const {
const auto descriptorIt = this->peripheralDescriptorsByKey.find(key);
if (descriptorIt == this->peripheralDescriptorsByKey.end()) {
return std::nullopt;
}
return std::cref(descriptorIt->second);
}
const TargetPeripheralDescriptor& TargetDescriptor::getPeripheralDescriptor(const std::string& key) const {
const auto descriptor = this->tryGetPeripheralDescriptor(key);
if (!descriptor.has_value()) {
throw Exceptions::InternalFatalErrorException{
"Failed to get peripheral descriptor \"" + std::string{key}
+ "\" from target descriptor - descriptor not found"
};
}
return descriptor->get();
}
std::optional<
std::reference_wrapper<const TargetPinoutDescriptor>
> TargetDescriptor::tryGetPinoutDescriptor(const std::string& key) const {
const auto descriptorIt = this->pinoutDescriptorsByKey.find(key);
if (descriptorIt == this->pinoutDescriptorsByKey.end()) {
return std::nullopt;
}
return std::cref(descriptorIt->second);
}
const TargetPinoutDescriptor& TargetDescriptor::getPinoutDescriptor(const std::string& key) const {
const auto descriptor = this->tryGetPinoutDescriptor(key);
if (!descriptor.has_value()) {
throw Exceptions::InternalFatalErrorException{
"Failed to get pinout descriptor \"" + std::string{key}
+ "\" from target descriptor - descriptor not found"
};
}
return descriptor->get();

View File

@@ -11,7 +11,8 @@
#include "TargetMemory.hpp"
#include "TargetAddressSpaceDescriptor.hpp"
#include "TargetPeripheralDescriptor.hpp"
#include "TargetVariant.hpp"
#include "TargetPinoutDescriptor.hpp"
#include "TargetVariantDescriptor.hpp"
#include "TargetBreakpoint.hpp"
namespace Targets
@@ -24,26 +25,56 @@ namespace Targets
std::string vendorName;
std::map<std::string, TargetAddressSpaceDescriptor> addressSpaceDescriptorsByKey;
std::map<std::string, TargetPeripheralDescriptor> peripheralDescriptorsByKey;
std::vector<TargetVariant> variants;
std::map<std::string, TargetPinoutDescriptor> pinoutDescriptorsByKey;
std::vector<TargetVariantDescriptor> variantDescriptors;
BreakpointResources breakpointResources;
TargetDescriptor(
const std::string& name,
TargetFamily family,
const std::string& marketId,
const std::string& vendorName,
const std::string& marketName,
const std::map<std::string, TargetAddressSpaceDescriptor>& addressSpaceDescriptorsByKey,
const std::map<std::string, TargetPeripheralDescriptor>& peripheralDescriptorsByKey,
const std::vector<TargetVariant>& variants,
std::map<std::string, TargetAddressSpaceDescriptor>&& addressSpaceDescriptorsByKey,
std::map<std::string, TargetPeripheralDescriptor>&& peripheralDescriptorsByKey,
std::map<std::string, TargetPinoutDescriptor>&& pinoutDescriptorsByKey,
std::vector<TargetVariantDescriptor>&& variantDescriptors,
const BreakpointResources& breakpointResources
);
TargetDescriptor(const TargetDescriptor& other) = delete;
TargetDescriptor& operator = (const TargetDescriptor& other) = delete;
TargetDescriptor(TargetDescriptor&& other) noexcept = default;
TargetDescriptor& operator = (TargetDescriptor&& other) = default;
std::optional<std::reference_wrapper<const TargetAddressSpaceDescriptor>> tryGetAddressSpaceDescriptor(
const std::string& key
) const;
const TargetAddressSpaceDescriptor& getAddressSpaceDescriptor(const std::string& key) const;
/**
* Returns the descriptor for the first address space that contains the given memory segment.
*
* @param memorySegmentKey
* Key of the memory segment that should be contained within the address space.
*
* @return
*/
const TargetAddressSpaceDescriptor& getFirstAddressSpaceDescriptorContainingMemorySegment(
const std::string& memorySegmentKey
) const;
std::optional<std::reference_wrapper<const TargetPeripheralDescriptor>> tryGetPeripheralDescriptor(
const std::string& key
) const;
const TargetPeripheralDescriptor& getPeripheralDescriptor(const std::string& key) const;
std::optional<std::reference_wrapper<const TargetPinoutDescriptor>> tryGetPinoutDescriptor(
const std::string& key
) const;
const TargetPinoutDescriptor& getPinoutDescriptor(const std::string& key) const;
};
}
Q_DECLARE_METATYPE(Targets::TargetDescriptor)

View File

@@ -0,0 +1,40 @@
#pragma once
#include <cstdint>
#include <QMetaType>
#include "TargetPinDescriptor.hpp"
namespace Targets
{
struct TargetGpioPinState
{
enum class State: std::uint8_t
{
HIGH,
LOW,
};
enum class DataDirection: std::uint8_t
{
INPUT,
OUTPUT,
};
State value;
DataDirection direction;
TargetGpioPinState(
State value,
DataDirection direction
)
: value(value)
, direction(direction)
{}
};
using TargetGpioPinDescriptorAndStatePair = Pair<const TargetPinDescriptor&, TargetGpioPinState>;
using TargetGpioPinDescriptorAndStatePairs = std::vector<TargetGpioPinDescriptorAndStatePair>;
}
Q_DECLARE_METATYPE(Targets::TargetGpioPinState)

View File

@@ -1,9 +1,11 @@
#pragma once
#include <cstdint>
#include <algorithm>
#include <vector>
#include <set>
#include <optional>
#include <cassert>
namespace Targets
{
@@ -12,21 +14,15 @@ namespace Targets
using TargetStackPointer = TargetMemoryAddress;
using TargetMemoryBuffer = std::vector<unsigned char>;
using TargetAddressSpaceId = std::size_t;
using TargetMemorySegmentId = std::size_t;
enum class TargetMemoryEndianness: std::uint8_t
{
BIG,
LITTLE,
};
enum class TargetMemoryType: std::uint8_t
{
FLASH,
RAM,
EEPROM,
FUSES,
OTHER,
};
struct TargetMemoryAddressRange
{
TargetMemoryAddress startAddress = 0;
@@ -36,7 +32,9 @@ namespace Targets
TargetMemoryAddressRange(TargetMemoryAddress startAddress, TargetMemoryAddress endAddress)
: startAddress(startAddress)
, endAddress(endAddress)
{}
{
assert(this->startAddress <= this->endAddress);
}
bool operator == (const TargetMemoryAddressRange& rhs) const {
return this->startAddress == rhs.startAddress && this->endAddress == rhs.endAddress;
@@ -46,27 +44,67 @@ namespace Targets
return this->startAddress < rhs.startAddress;
}
TargetMemorySize size() const {
/**
* Returns the number of addresses in the range.
*
* Keep in mind that the number of addresses may not be equal to the number of bytes in the range. It depends
* on whether the address space is byte-addressable. See TargetAddressSpaceDescriptor::unitSize for more.
*
* @return
*/
[[nodiscard]] TargetMemorySize size() const {
return this->endAddress - this->startAddress + 1;
}
[[nodiscard]] bool intersectsWith(const TargetMemoryAddressRange& other) const {
return
(other.startAddress <= this->startAddress && other.endAddress >= this->startAddress)
|| (other.startAddress >= this->startAddress && other.startAddress <= this->endAddress)
;
/**
* Checks if this range intersects with the given range.
*
* @param other
* @return
*/
[[nodiscard]] bool intersectsWith(const TargetMemoryAddressRange& other) const noexcept {
return this->startAddress <= other.endAddress && other.startAddress <= this->endAddress;
}
[[nodiscard]] bool contains(TargetMemoryAddress address) const {
/**
* Returns the number of addresses in this range that intersect with the given range.
*
* @param other
* @return
*/
[[nodiscard]] TargetMemorySize intersectingSize(const TargetMemoryAddressRange& other) const noexcept {
return this->intersectsWith(other)
? std::min(this->endAddress, other.endAddress) - std::max(this->startAddress, other.startAddress) + 1
: 0;
}
/**
* Checks if the given address is contained within this range.
*
* @param address
* @return
*/
[[nodiscard]] bool contains(TargetMemoryAddress address) const noexcept {
return address >= this->startAddress && address <= this->endAddress;
}
[[nodiscard]] bool contains(const TargetMemoryAddressRange& addressRange) const {
/**
* Checks if the given range is completely contained within this range.
*
* @param addressRange
* @return
*/
[[nodiscard]] bool contains(const TargetMemoryAddressRange& addressRange) const noexcept {
return this->startAddress <= addressRange.startAddress && this->endAddress >= addressRange.endAddress;
}
std::set<Targets::TargetMemoryAddress> addresses() const {
auto addresses = std::set<Targets::TargetMemoryAddress>();
/**
* Returns a set of all addresses within this range.
*
* @return
*/
std::set<Targets::TargetMemoryAddress> addresses() const noexcept {
auto addresses = std::set<Targets::TargetMemoryAddress>{};
auto addressesIt = addresses.end();
for (auto i = this->startAddress; i <= this->endAddress; ++i) {
@@ -81,44 +119,13 @@ namespace Targets
{
bool readable = false;
bool writeable = false;
bool writeableDuringDebugSession = false;
TargetMemoryAccess(
bool readable,
bool writeable,
bool writeableDuringDebugSession
bool writeable
)
: readable(readable)
, writeable(writeable)
, writeableDuringDebugSession(writeableDuringDebugSession)
{}
};
struct TargetMemoryDescriptor
{
TargetMemoryType type;
TargetMemoryAddressRange addressRange;
TargetMemoryAccess access;
std::optional<TargetMemorySize> pageSize;
TargetMemoryDescriptor(
TargetMemoryType type,
TargetMemoryAddressRange addressRange,
TargetMemoryAccess access,
std::optional<TargetMemorySize> pageSize = std::nullopt
)
: type(type)
, addressRange(addressRange)
, access(access)
, pageSize(pageSize)
{}
bool operator == (const TargetMemoryDescriptor& rhs) const {
return this->type == rhs.type && this->addressRange == rhs.addressRange;
}
[[nodiscard]] TargetMemorySize size() const {
return (this->addressRange.endAddress - this->addressRange.startAddress) + 1;
}
};
}

View File

@@ -6,22 +6,22 @@
namespace Targets
{
TargetMemoryCache::TargetMemoryCache(const TargetMemoryDescriptor& memoryDescriptor)
: memoryDescriptor(memoryDescriptor)
, data(TargetMemoryBuffer(memoryDescriptor.size(), 0x00))
TargetMemoryCache::TargetMemoryCache(const TargetAddressSpaceDescriptor& addressSpaceDescriptor)
: addressSpaceDescriptor(addressSpaceDescriptor)
, data(TargetMemoryBuffer(addressSpaceDescriptor.size(), 0x00))
{}
TargetMemoryBuffer TargetMemoryCache::fetch(TargetMemoryAddress startAddress, TargetMemorySize bytes) const {
const auto startIndex = startAddress - this->memoryDescriptor.addressRange.startAddress;
const auto startIndex = startAddress - this->addressSpaceDescriptor.addressRange.startAddress;
if (
startAddress < this->memoryDescriptor.addressRange.startAddress
startAddress < this->addressSpaceDescriptor.addressRange.startAddress
|| (startIndex + bytes) > this->data.size()
) {
throw Exceptions::Exception("Invalid cache access");
throw Exceptions::Exception{"Invalid cache access"};
}
return TargetMemoryBuffer(this->data.begin() + startIndex, this->data.begin() + startIndex + bytes);
return TargetMemoryBuffer{this->data.begin() + startIndex, this->data.begin() + startIndex + bytes};
}
bool TargetMemoryCache::contains(TargetMemoryAddress startAddress, TargetMemorySize bytes) const {
@@ -34,7 +34,7 @@ namespace Targets
}
void TargetMemoryCache::insert(TargetMemoryAddress startAddress, const TargetMemoryBuffer& data) {
const auto startIndex = startAddress - this->memoryDescriptor.addressRange.startAddress;
const auto startIndex = startAddress - this->addressSpaceDescriptor.addressRange.startAddress;
std::copy(data.begin(), data.end(), this->data.begin() + startIndex);
@@ -47,7 +47,7 @@ namespace Targets
intersectingStartSegmentIt == this->populatedSegments.end()
&& intersectingEndSegmentIt == this->populatedSegments.end()
) {
this->populatedSegments.insert(std::pair(startAddress, endAddress));
this->populatedSegments.emplace(startAddress, endAddress);
return;
}
@@ -56,8 +56,8 @@ namespace Targets
return;
}
auto newStartSegment = std::optional<decltype(this->populatedSegments)::value_type>();
auto newEndSegment = std::optional<decltype(this->populatedSegments)::value_type>();
auto newStartSegment = std::optional<decltype(this->populatedSegments)::value_type>{};
auto newEndSegment = std::optional<decltype(this->populatedSegments)::value_type>{};
if (intersectingStartSegmentIt != this->populatedSegments.end()) {
newStartSegment.emplace(intersectingStartSegmentIt->first, endAddress);

View File

@@ -3,6 +3,7 @@
#include <cstdint>
#include <map>
#include "TargetAddressSpaceDescriptor.hpp"
#include "TargetMemory.hpp"
namespace Targets
@@ -10,7 +11,7 @@ namespace Targets
class TargetMemoryCache
{
public:
TargetMemoryCache(const TargetMemoryDescriptor& memoryDescriptor);
TargetMemoryCache(const TargetAddressSpaceDescriptor& addressSpaceDescriptor);
/**
* Fetches data from the cache.
@@ -46,7 +47,7 @@ namespace Targets
void clear();
private:
const TargetMemoryDescriptor& memoryDescriptor;
const TargetAddressSpaceDescriptor& addressSpaceDescriptor;
TargetMemoryBuffer data;
/**

View File

@@ -0,0 +1,46 @@
#include "TargetMemorySegmentDescriptor.hpp"
#include "src/Services/StringService.hpp"
namespace Targets
{
TargetMemorySegmentDescriptor::TargetMemorySegmentDescriptor(
const std::string& addressSpaceKey,
const std::string& key,
const std::string& name,
TargetMemorySegmentType type,
const TargetMemoryAddressRange& addressRange,
std::uint8_t addressSpaceUnitSize,
bool executable,
const TargetMemoryAccess& debugModeAccess,
const TargetMemoryAccess& programmingModeAccess,
std::optional<TargetMemorySize> pageSize
)
: id(static_cast<TargetMemorySegmentId>(Services::StringService::hash(addressSpaceKey + key)))
, key(key)
, name(name)
, type(type)
, addressRange(addressRange)
, addressSpaceUnitSize(addressSpaceUnitSize)
, executable(executable)
, debugModeAccess(debugModeAccess)
, programmingModeAccess(programmingModeAccess)
, pageSize(pageSize)
{}
bool TargetMemorySegmentDescriptor::operator == (const TargetMemorySegmentDescriptor& other) const {
return this->id == other.id;
}
bool TargetMemorySegmentDescriptor::operator != (const TargetMemorySegmentDescriptor& other) const {
return !(*this == other);
}
TargetMemorySize TargetMemorySegmentDescriptor::size() const {
return this->addressRange.size() * this->addressSpaceUnitSize;
}
TargetMemorySegmentDescriptor TargetMemorySegmentDescriptor::clone() const {
return {*this};
}
}

View File

@@ -1,7 +1,9 @@
#pragma once
#include <string>
#include <cstdint>
#include <optional>
#include <utility>
#include "TargetMemory.hpp"
#include "TargetMemorySegmentType.hpp"
@@ -11,34 +13,48 @@ namespace Targets
struct TargetMemorySegmentDescriptor
{
public:
std::string key;
/*
* The ID of a memory segment is just a hash of the address space key and the memory segment key, concatenated,
* which will be unique.
*
* We use the ID for cheap equality checks.
*/
const TargetMemorySegmentId id;
const std::string key;
std::string name;
TargetMemorySegmentType type;
TargetMemoryAddressRange addressRange;
std::uint8_t addressSpaceUnitSize;
bool executable;
TargetMemoryAccess debugModeAccess;
TargetMemoryAccess programmingModeAccess;
std::optional<TargetMemorySize> pageSize;
TargetMemorySegmentDescriptor(
const std::string& addressSpaceKey,
const std::string& key,
const std::string& name,
TargetMemorySegmentType type,
const TargetMemoryAddressRange& addressRange,
std::uint8_t addressSpaceUnitSize,
bool executable,
const TargetMemoryAccess& debugModeAccess,
const TargetMemoryAccess& programmingModeAccess,
std::optional<TargetMemorySize> pageSize
)
: key(key)
, name(name)
, type(type)
, addressRange(addressRange)
, debugModeAccess(debugModeAccess)
, programmingModeAccess(programmingModeAccess)
, pageSize(pageSize)
{};
);
TargetMemorySize size() const {
return this->addressRange.size();
}
TargetMemorySegmentDescriptor& operator = (const TargetMemorySegmentDescriptor& other) = delete;
TargetMemorySegmentDescriptor(TargetMemorySegmentDescriptor&& other) noexcept = default;
bool operator == (const TargetMemorySegmentDescriptor& other) const;
bool operator != (const TargetMemorySegmentDescriptor& other) const;
TargetMemorySize size() const;
[[nodiscard]] TargetMemorySegmentDescriptor clone() const;
private:
TargetMemorySegmentDescriptor(const TargetMemorySegmentDescriptor& other) = default;
};
}

View File

@@ -6,6 +6,7 @@ namespace Targets
{
enum class TargetMemorySegmentType: std::uint8_t
{
GENERAL_PURPOSE_REGISTERS,
ALIASED,
REGISTERS,
EEPROM,

View File

@@ -1,6 +1,7 @@
#include "TargetPeripheralDescriptor.hpp"
#include <ranges>
#include <utility>
#include "src/Services/StringService.hpp"
@@ -11,11 +12,13 @@ namespace Targets
TargetPeripheralDescriptor::TargetPeripheralDescriptor(
const std::string& key,
const std::string& name,
const std::map<std::string, TargetRegisterGroupDescriptor, std::less<void>>& registerGroupDescriptorsByKey
std::map<std::string, TargetRegisterGroupDescriptor, std::less<void>>&& registerGroupDescriptorsByKey,
std::vector<TargetPeripheralSignalDescriptor>&& signalDescriptors
)
: key(key)
, name(name)
, registerGroupDescriptorsByKey(registerGroupDescriptorsByKey)
, registerGroupDescriptorsByKey(std::move(registerGroupDescriptorsByKey))
, signalDescriptors(std::move(signalDescriptors))
{}
std::optional<
@@ -27,7 +30,7 @@ namespace Targets
return firstGroupIt != this->registerGroupDescriptorsByKey.end()
? keys.size() > 1
? firstGroupIt->second.tryGetSubgroupDescriptor(keys | std::ranges::views::drop(1))
: std::optional(std::cref(firstGroupIt->second))
: std::optional{std::cref(firstGroupIt->second)}
: std::nullopt;
}
@@ -36,12 +39,38 @@ namespace Targets
) const {
const auto descriptor = this->tryGetRegisterGroupDescriptor(key);
if (!descriptor.has_value()) {
throw Exceptions::InternalFatalErrorException(
"Failed to get register group descriptor \"" + std::string(key)
throw Exceptions::InternalFatalErrorException{
"Failed to get register group descriptor \"" + std::string{key}
+ "\" from peripheral \"" + this->key + "\" - register group descriptor not found"
);
};
}
return descriptor->get();
}
const TargetRegisterDescriptor& TargetPeripheralDescriptor::getRegisterDescriptor(
std::string_view groupKey,
const std::string& registerKey
) const {
return this->getRegisterGroupDescriptor(groupKey).getRegisterDescriptor(registerKey);
}
TargetPeripheralDescriptor TargetPeripheralDescriptor::clone() const {
auto output = TargetPeripheralDescriptor{
this->key,
this->name,
{},
{}
};
for (const auto& [key, descriptor] : this->registerGroupDescriptorsByKey) {
output.registerGroupDescriptorsByKey.emplace(key, descriptor.clone());
}
for (const auto& descriptor : this->signalDescriptors) {
output.signalDescriptors.emplace_back(descriptor.clone());
}
return output;
}
}

View File

@@ -2,11 +2,14 @@
#include <string>
#include <map>
#include <vector>
#include <optional>
#include <functional>
#include <string_view>
#include "TargetRegisterGroupDescriptor.hpp"
#include "TargetRegisterDescriptor.hpp"
#include "TargetPeripheralSignalDescriptor.hpp"
namespace Targets
{
@@ -16,17 +19,32 @@ namespace Targets
std::string key;
std::string name;
std::map<std::string, TargetRegisterGroupDescriptor, std::less<void>> registerGroupDescriptorsByKey;
std::vector<TargetPeripheralSignalDescriptor> signalDescriptors;
TargetPeripheralDescriptor(
const std::string& key,
const std::string& name,
const std::map<std::string, TargetRegisterGroupDescriptor, std::less<void>>& registerGroupDescriptorsByKey
std::map<std::string, TargetRegisterGroupDescriptor, std::less<void>>&& registerGroupDescriptorsByKey,
std::vector<TargetPeripheralSignalDescriptor>&& signalDescriptors
);
std::optional<std::reference_wrapper<const TargetRegisterGroupDescriptor>> tryGetRegisterGroupDescriptor(
std::string_view keyStr
TargetPeripheralDescriptor(const TargetPeripheralDescriptor& other) = delete;
TargetPeripheralDescriptor& operator = (const TargetPeripheralDescriptor& other) = delete;
TargetPeripheralDescriptor(TargetPeripheralDescriptor&& other) noexcept = default;
TargetPeripheralDescriptor& operator = (TargetPeripheralDescriptor&& other) = default;
[[nodiscard]] std::optional<
std::reference_wrapper<const TargetRegisterGroupDescriptor>
> tryGetRegisterGroupDescriptor(std::string_view keyStr) const;
[[nodiscard]] const TargetRegisterGroupDescriptor& getRegisterGroupDescriptor(std::string_view key) const;
[[nodiscard]] const TargetRegisterDescriptor& getRegisterDescriptor(
std::string_view groupKey,
const std::string& registerKey
) const;
const TargetRegisterGroupDescriptor& getRegisterGroupDescriptor(std::string_view key) const;
[[nodiscard]] TargetPeripheralDescriptor clone() const;
};
}

View File

@@ -0,0 +1,19 @@
#include "TargetPeripheralSignalDescriptor.hpp"
namespace Targets
{
TargetPeripheralSignalDescriptor::TargetPeripheralSignalDescriptor(
const std::string& padName,
const std::optional<std::uint16_t>& index
)
: padName(padName)
, index(index)
{}
TargetPeripheralSignalDescriptor TargetPeripheralSignalDescriptor::clone() const {
return {
this->padName,
this->index
};
}
}

View File

@@ -0,0 +1,28 @@
#pragma once
#include <cstdint>
#include <string>
#include <optional>
namespace Targets
{
struct TargetPeripheralSignalDescriptor
{
public:
std::string padName;
std::optional<std::uint16_t> index;
TargetPeripheralSignalDescriptor(
const std::string& padName,
const std::optional<std::uint16_t>& index
);
TargetPeripheralSignalDescriptor(const TargetPeripheralSignalDescriptor& other) = delete;
TargetPeripheralSignalDescriptor& operator = (const TargetPeripheralSignalDescriptor& other) = delete;
TargetPeripheralSignalDescriptor(TargetPeripheralSignalDescriptor&& other) noexcept = default;
TargetPeripheralSignalDescriptor& operator = (TargetPeripheralSignalDescriptor&& other) = default;
[[nodiscard]] TargetPeripheralSignalDescriptor clone() const;
};
}

View File

@@ -3,12 +3,12 @@
namespace Targets
{
std::map<TargetPhysicalInterface, std::string> getPhysicalInterfaceNames() {
return std::map<TargetPhysicalInterface, std::string>({
return std::map<TargetPhysicalInterface, std::string>{
{TargetPhysicalInterface::ISP, "ISP"},
{TargetPhysicalInterface::DEBUG_WIRE, "debugWire"},
{TargetPhysicalInterface::DEBUG_WIRE, "debugWIRE"},
{TargetPhysicalInterface::PDI, "PDI"},
{TargetPhysicalInterface::JTAG, "JTAG"},
{TargetPhysicalInterface::UPDI, "UPDI"},
});
};
}
}

View File

@@ -0,0 +1,14 @@
#include "TargetPinDescriptor.hpp"
namespace Targets
{
TargetPinDescriptor::TargetPinDescriptor(
const std::string& padName,
const std::string& position,
TargetPinType type
)
: padName(padName)
, position(position)
, type(type)
{}
}

View File

@@ -1,65 +1,35 @@
#pragma once
#include <string>
#include <cstdint>
#include <vector>
#include <optional>
#include <map>
#include <QMetaType>
#include <string>
namespace Targets
{
enum class TargetPinType: std::uint8_t
{
UNKNOWN,
GPIO,
GND,
VCC,
OTHER,
};
struct TargetPinDescriptor
{
int number;
int variantId;
bool supportsGpio = false;
std::string name;
public:
std::string padName;
std::vector<std::string> functions;
std::string position;
TargetPinType type = TargetPinType::OTHER;
TargetPinType type = TargetPinType::UNKNOWN;
TargetPinDescriptor(
const std::string& padName,
const std::string& position,
TargetPinType type
);
bool operator == (const TargetPinDescriptor& pinDescriptor) const {
return this->number == pinDescriptor.number
&& this->supportsGpio == pinDescriptor.supportsGpio
&& this->name == pinDescriptor.name
&& this->padName == pinDescriptor.padName
&& this->functions == pinDescriptor.functions
&& this->type == pinDescriptor.type
;
}
TargetPinDescriptor(const TargetPinDescriptor& other) = delete;
TargetPinDescriptor& operator = (const TargetPinDescriptor& other) = delete;
TargetPinDescriptor(TargetPinDescriptor&& other) noexcept = default;
TargetPinDescriptor& operator = (TargetPinDescriptor&& other) = default;
};
struct TargetPinState
{
enum class IoState: std::uint8_t
{
HIGH,
LOW,
};
enum class IoDirection: std::uint8_t
{
INPUT,
OUTPUT,
};
std::optional<IoState> ioState;
std::optional<IoDirection> ioDirection;
};
using TargetPinStateMapping = std::map<int, Targets::TargetPinState>;
}
Q_DECLARE_METATYPE(Targets::TargetPinDescriptor)
Q_DECLARE_METATYPE(Targets::TargetPinState)
Q_DECLARE_METATYPE(Targets::TargetPinStateMapping)

View File

@@ -0,0 +1,22 @@
#include "TargetPinoutDescriptor.hpp"
#include <utility>
namespace Targets
{
TargetPinoutDescriptor::TargetPinoutDescriptor(
const std::string& key,
const std::string& name,
TargetPinoutType type,
std::vector<TargetPinDescriptor>&& pinDescriptors
)
: key(key)
, name(name)
, type(type)
, pinDescriptors(std::move(pinDescriptors))
{}
bool TargetPinoutDescriptor::operator == (const TargetPinoutDescriptor& other) const {
return this->key == other.key;
}
}

View File

@@ -1,10 +1,14 @@
#pragma once
#include <cstdint>
#include <string>
#include <vector>
#include "TargetPinDescriptor.hpp"
namespace Targets
{
enum class PinoutType: std::uint8_t
enum class TargetPinoutType: std::uint8_t
{
SOIC,
SSOP,
@@ -15,4 +19,28 @@ namespace Targets
MLF,
BGA,
};
struct TargetPinoutDescriptor
{
public:
std::string key;
std::string name;
TargetPinoutType type;
std::vector<TargetPinDescriptor> pinDescriptors;
TargetPinoutDescriptor(
const std::string& key,
const std::string& name,
TargetPinoutType type,
std::vector<TargetPinDescriptor>&& pinDescriptors
);
TargetPinoutDescriptor(const TargetPinoutDescriptor& other) = delete;
TargetPinoutDescriptor& operator = (const TargetPinoutDescriptor& other) = delete;
TargetPinoutDescriptor(TargetPinoutDescriptor&& other) noexcept = default;
TargetPinoutDescriptor& operator = (TargetPinoutDescriptor&& other) = default;
bool operator == (const TargetPinoutDescriptor& other) const;
};
}

View File

@@ -1,32 +0,0 @@
#pragma once
#include <cstdint>
#include <utility>
#include <vector>
#include "TargetRegisterDescriptor.hpp"
#include "TargetMemory.hpp"
namespace Targets
{
struct TargetRegister
{
TargetRegisterDescriptorId descriptorId;
/**
* Register values should be in MSB form
*/
TargetMemoryBuffer value;
TargetRegister(TargetRegisterDescriptorId descriptorId, TargetMemoryBuffer value)
: descriptorId(descriptorId)
, value(std::move(value))
{};
[[nodiscard]] std::size_t size() const {
return this->value.size();
}
};
using TargetRegisters = std::vector<TargetRegister>;
}

View File

@@ -1,6 +1,99 @@
#include "TargetRegisterDescriptor.hpp"
#include "TargetAddressSpaceDescriptor.hpp"
#include "src/Exceptions/InternalFatalErrorException.hpp"
namespace Targets
{
TargetRegisterDescriptor::TargetRegisterDescriptor(
const std::string& key,
const std::string& name,
const std::string& addressSpaceKey,
TargetMemoryAddress startAddress,
TargetMemorySize size,
TargetRegisterType type,
TargetRegisterAccess access,
std::optional<std::string> description,
std::map<std::string, TargetBitFieldDescriptor>&& bitFieldDescriptorsByKey
)
: key(key)
, name(name)
, addressSpaceId(TargetAddressSpaceDescriptor::generateId(addressSpaceKey))
, addressSpaceKey(addressSpaceKey)
, startAddress(startAddress)
, size(size)
, type(type)
, access(access)
, description(description)
, bitFieldDescriptorsByKey(std::move(bitFieldDescriptorsByKey))
{}
bool TargetRegisterDescriptor::operator == (const TargetRegisterDescriptor& other) const {
return this->key == other.key
&& this->name == other.name
&& this->addressSpaceKey == other.addressSpaceKey
&& this->startAddress == other.startAddress
&& this->size == other.size
&& this->type == other.type
&& this->access == other.access
&& this->description == other.description
;
}
bool TargetRegisterDescriptor::operator < (const TargetRegisterDescriptor& other) const {
if (this->addressSpaceKey != other.addressSpaceKey) {
/*
* 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;
}
return this->startAddress < other.startAddress;
}
[[nodiscard]] std::optional<
std::reference_wrapper<const TargetBitFieldDescriptor>
> TargetRegisterDescriptor::tryGetBitFieldDescriptor(const std::string& key) const {
const auto bitFieldIt = this->bitFieldDescriptorsByKey.find(key);
if (bitFieldIt == this->bitFieldDescriptorsByKey.end()) {
return std::nullopt;
}
return std::cref(bitFieldIt->second);
}
[[nodiscard]] const TargetBitFieldDescriptor& TargetRegisterDescriptor::getBitFieldDescriptor(
const std::string& key
) const {
const auto bitField = this->tryGetBitFieldDescriptor(key);
if (!bitField.has_value()) {
throw Exceptions::InternalFatalErrorException{
"Failed to get bit field descriptor \"" + std::string{key} + "\" from register - bit field not found"
};
}
return bitField->get();
}
TargetRegisterDescriptor TargetRegisterDescriptor::clone() const {
auto output = TargetRegisterDescriptor{
this->key,
this->name,
this->addressSpaceKey,
this->startAddress,
this->size,
this->type,
this->access,
this->description,
{}
};
for (const auto& [key, descriptor] : this->bitFieldDescriptorsByKey) {
output.bitFieldDescriptorsByKey.emplace(key, descriptor.clone());
}
return output;
}
}

View File

@@ -1,21 +1,29 @@
#pragma once
#include <cstdint>
#include <atomic>
#include <string>
#include <optional>
#include <utility>
#include <map>
#include <set>
#include <vector>
#include "TargetMemory.hpp"
#include "TargetAddressSpaceDescriptor.hpp"
#include "TargetBitFieldDescriptor.hpp"
#include "src/Helpers/Pair.hpp"
namespace Targets
{
using TargetRegisterDescriptorId = std::uint32_t;
using TargetRegisterDescriptorIds = std::set<Targets::TargetRegisterDescriptorId>;
enum class TargetRegisterType: std::uint8_t
{
GENERAL_PURPOSE_REGISTER,
OTHER,
};
struct TargetRegisterAccess
{
bool readable = false;
@@ -39,64 +47,47 @@ namespace Targets
struct TargetRegisterDescriptor
{
public:
const TargetRegisterDescriptorId id;
std::string key;
std::string name;
TargetAddressSpaceId addressSpaceId;
std::string addressSpaceKey;
const TargetAddressSpaceDescriptorId addressSpaceDescriptorId;
TargetMemoryAddress startAddress;
TargetMemorySize size;
TargetRegisterType type;
TargetRegisterAccess access;
std::optional<std::string> description;
std::map<std::string, TargetBitFieldDescriptor> bitFieldDescriptorsByKey;
TargetRegisterDescriptor(
const std::string& key,
const std::string& name,
const std::string& addressSpaceKey,
TargetAddressSpaceDescriptorId addressSpaceDescriptorId,
TargetMemoryAddress startAddress,
TargetMemorySize size,
TargetRegisterType type,
TargetRegisterAccess access,
std::optional<std::string> description
)
: id(++(TargetRegisterDescriptor::lastRegisterDescriptorId))
, key(key)
, name(name)
, addressSpaceKey(addressSpaceKey)
, addressSpaceDescriptorId(addressSpaceDescriptorId)
, startAddress(startAddress)
, size(size)
, access(access)
, description(description)
{};
std::optional<std::string> description,
std::map<std::string, TargetBitFieldDescriptor>&& bitFieldDescriptorsByKey
);
bool operator == (const TargetRegisterDescriptor& other) const {
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
;
}
TargetRegisterDescriptor(const TargetRegisterDescriptor& other) = delete;
TargetRegisterDescriptor& operator = (const TargetRegisterDescriptor& other) = delete;
bool operator < (const TargetRegisterDescriptor& other) const {
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;
}
TargetRegisterDescriptor(TargetRegisterDescriptor&& other) noexcept = default;
TargetRegisterDescriptor& operator = (TargetRegisterDescriptor&& other) = default;
return this->startAddress < other.startAddress;
}
bool operator == (const TargetRegisterDescriptor& other) const;
bool operator < (const TargetRegisterDescriptor& other) const;
private:
static inline std::atomic<TargetRegisterDescriptorId> lastRegisterDescriptorId = 0;
[[nodiscard]] std::optional<std::reference_wrapper<const TargetBitFieldDescriptor>> tryGetBitFieldDescriptor(
const std::string& key
) const;
[[nodiscard]] const TargetBitFieldDescriptor& getBitFieldDescriptor(const std::string& key) const;
[[nodiscard]] TargetRegisterDescriptor clone() const;
};
using TargetRegisterDescriptors = std::set<TargetRegisterDescriptor>;
using TargetRegisterDescriptorMapping = std::map<TargetRegisterDescriptorId, TargetRegisterDescriptor>;
using TargetRegisterDescriptors = std::vector<const TargetRegisterDescriptor*>;
using TargetRegisterDescriptorAndValuePair = Pair<const TargetRegisterDescriptor&, TargetMemoryBuffer>;
using TargetRegisterDescriptorAndValuePairs = std::vector<TargetRegisterDescriptorAndValuePair>;
}

View File

@@ -12,24 +12,22 @@ namespace Targets
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
std::map<std::string, TargetRegisterDescriptor, std::less<void>>&& registerDescriptorsByKey,
std::map<std::string, TargetRegisterGroupDescriptor, std::less<void>>&& subgroupDescriptorsByKey
)
: key(key)
, name(name)
, addressSpaceKey(addressSpaceKey)
, addressSpaceDescriptorId(addressSpaceDescriptorId)
, description(description)
, registerDescriptorsByKey(registerDescriptorsByKey)
, subgroupDescriptorsByKey(subgroupDescriptorsByKey)
, registerDescriptorsByKey(std::move(registerDescriptorsByKey))
, subgroupDescriptorsByKey(std::move(subgroupDescriptorsByKey))
{}
TargetMemoryAddress TargetRegisterGroupDescriptor::startAddress() const {
assert(!this->registerDescriptorsByKey.empty() || !this->subgroupDescriptorsByKey.empty());
auto startAddress = TargetMemoryAddress{0};
auto startAddress = TargetMemoryAddress{-1U};
for (const auto& [key, registerDescriptor] : this->registerDescriptorsByKey) {
if (registerDescriptor.startAddress < startAddress) {
@@ -76,11 +74,87 @@ namespace Targets
) 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"
);
throw Exceptions::InternalFatalErrorException{
"Failed to get subgroup \"" + std::string{keyStr} + "\" from register group - subgroup not found"
};
}
return subgroup->get();
}
[[nodiscard]] std::optional<
std::reference_wrapper<const TargetRegisterDescriptor>
> TargetRegisterGroupDescriptor::tryGetRegisterDescriptor(const std::string& key) const {
const auto registerIt = this->registerDescriptorsByKey.find(key);
if (registerIt == this->registerDescriptorsByKey.end()) {
return std::nullopt;
}
return std::cref(registerIt->second);
}
std::optional<
std::reference_wrapper<const TargetRegisterDescriptor>
> TargetRegisterGroupDescriptor::tryGetFirstRegisterDescriptor(std::initializer_list<std::string>&& keys) const {
for (const auto& key : keys) {
auto descriptor = this->tryGetRegisterDescriptor(key);
if (descriptor.has_value()) {
return descriptor;
}
}
return std::nullopt;
}
[[nodiscard]] const TargetRegisterDescriptor& TargetRegisterGroupDescriptor::getRegisterDescriptor(
const std::string& key
) const {
const auto reg = this->tryGetRegisterDescriptor(key);
if (!reg.has_value()) {
throw Exceptions::InternalFatalErrorException{
"Failed to get register descriptor \"" + std::string{key} + "\" from register group - register "
"descriptor not found"
};
}
return reg->get();
}
Pair<
const TargetRegisterDescriptor&,
const TargetBitFieldDescriptor&
> TargetRegisterGroupDescriptor::getRegisterBitFieldDescriptorPair(const std::string& bitFieldKey) const {
for (const auto& [regKey, regDescriptor] : this->registerDescriptorsByKey) {
const auto bitFieldDescriptor = regDescriptor.tryGetBitFieldDescriptor(bitFieldKey);
if (bitFieldDescriptor.has_value()) {
return {regDescriptor, bitFieldDescriptor->get()};
}
}
throw Exceptions::InternalFatalErrorException{
"Failed to find bit field \"" + std::string{bitFieldKey} + "\" within register group"
};
}
TargetRegisterGroupDescriptor TargetRegisterGroupDescriptor::clone() const {
auto output = TargetRegisterGroupDescriptor{
this->key,
this->name,
this->addressSpaceKey,
this->description,
{},
{}
};
for (const auto& [key, descriptor] : this->subgroupDescriptorsByKey) {
output.subgroupDescriptorsByKey.emplace(key, descriptor.clone());
}
for (const auto& [key, descriptor] : this->registerDescriptorsByKey) {
output.registerDescriptorsByKey.emplace(key, descriptor.clone());
}
return output;
}
}

View File

@@ -6,12 +6,12 @@
#include <functional>
#include <optional>
#include <string_view>
#include <initializer_list>
#include <ranges>
#include <concepts>
#include "TargetMemory.hpp"
#include "TargetAddressSpaceDescriptor.hpp"
#include "TargetRegisterDescriptor.hpp"
#include "src/Helpers/Pair.hpp"
namespace Targets
{
@@ -21,21 +21,25 @@ namespace Targets
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, TargetRegisterDescriptor, std::less<void>> 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
std::map<std::string, TargetRegisterDescriptor, std::less<void>>&& registerDescriptorsByKey,
std::map<std::string, TargetRegisterGroupDescriptor, std::less<void>>&& subgroupDescriptorsByKey
);
TargetRegisterGroupDescriptor(const TargetRegisterGroupDescriptor& other) = delete;
TargetRegisterGroupDescriptor& operator = (const TargetRegisterGroupDescriptor& other) = delete;
TargetRegisterGroupDescriptor(TargetRegisterGroupDescriptor&& other) noexcept = default;
TargetRegisterGroupDescriptor& operator = (TargetRegisterGroupDescriptor&& other) = default;
/**
* Calculates the start address of the register group.
*
@@ -43,7 +47,7 @@ namespace Targets
*
* @return
*/
TargetMemoryAddress startAddress() const;
[[nodiscard]] TargetMemoryAddress startAddress() const;
/**
* Calculates the size of this register group.
@@ -52,7 +56,7 @@ namespace Targets
*
* @return
*/
TargetMemorySize size() const;
[[nodiscard]] TargetMemorySize size() const;
/**
* Attempts to fetch a subgroup with a set of keys.
@@ -89,13 +93,13 @@ namespace Targets
*
* @param keyStr
* A string in "dot notation", containing each key seperated with a period/dot character (e.g.
* "parent.child.grandchild").
* "grandchild.parent.child").
*
* @return
*/
std::optional<std::reference_wrapper<const TargetRegisterGroupDescriptor>> tryGetSubgroupDescriptor(
std::string_view keyStr
) const;
[[nodiscard]] 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
@@ -103,10 +107,55 @@ namespace Targets
*
* @param keyStr
* A string in "dot notation", containing each key seperated with a period/dot character (e.g.
* "parent.child.grandchild").
* "grandchild.parent.child").
*
* @return
*/
const TargetRegisterGroupDescriptor& getSubgroupDescriptor(std::string_view keyStr) const;
[[nodiscard]] const TargetRegisterGroupDescriptor& getSubgroupDescriptor(std::string_view keyStr) const;
/**
* Register descriptor lookup by key.
*
* @param key
*
* @return
* The register descriptor matching the given key, if it exists. Otherwise, std::nullopt.
*/
[[nodiscard]] std::optional<std::reference_wrapper<const TargetRegisterDescriptor>> tryGetRegisterDescriptor(
const std::string& key
) const;
/**
* Performs a lookup of each key in the given set of keys, and returns the first matching register descriptor.
*
* @param keys
*
* @return
* std::nullopt if all keys do not map to any register descriptors.
*/
[[nodiscard]] std::optional<
std::reference_wrapper<const TargetRegisterDescriptor>
> tryGetFirstRegisterDescriptor(std::initializer_list<std::string>&& keys) const;
[[nodiscard]] const TargetRegisterDescriptor& getRegisterDescriptor(const std::string& key) const;
/**
* Finds the first register descriptor containing the bit field with the given key.
*
* This function will throw an InternalFatalErrorException if the bit field was not found in any of the
* registers within this register group.
*
* @param bitFieldKey
*
* @return
* A Pair object with Pair::first being the register descriptor in which the bit field was found, and
* Pair::second being the bit field descriptor.
*/
[[nodiscard]] Pair<
const TargetRegisterDescriptor&,
const TargetBitFieldDescriptor&
> getRegisterBitFieldDescriptorPair(const std::string& bitFieldKey) const;
[[nodiscard]] TargetRegisterGroupDescriptor clone() const;
};
}

View File

@@ -1,15 +1,77 @@
#pragma once
#include <QMetaType>
#include <cstdint>
#include <atomic>
#include <optional>
#include "TargetMemory.hpp"
namespace Targets
{
enum class TargetState: std::uint8_t
enum class TargetExecutionState: std::uint8_t
{
UNKNOWN,
STOPPED,
RUNNING,
STEPPING,
};
enum class TargetMode: std::uint8_t
{
DEBUGGING,
PROGRAMMING,
};
static_assert(std::atomic<TargetExecutionState>::is_always_lock_free);
static_assert(std::atomic<TargetMode>::is_always_lock_free);
static_assert(std::atomic<std::optional<TargetMemoryAddress>>::is_always_lock_free);
struct TargetState
{
std::atomic<TargetExecutionState> executionState = TargetExecutionState::UNKNOWN;
std::atomic<TargetMode> mode = TargetMode::DEBUGGING;
/**
* Current program counter - only populated when TargetState::executionState == TargetExecutionState::STOPPED
*/
std::atomic<std::optional<TargetMemoryAddress>> programCounter = {};
TargetState() = default;
TargetState(
TargetExecutionState executionState,
TargetMode mode,
std::optional<TargetMemoryAddress> programCounter = std::nullopt
)
: executionState(executionState)
, mode(mode)
, programCounter(programCounter)
{}
TargetState(const TargetState& other)
: executionState(other.executionState.load())
, mode(other.mode.load())
, programCounter(other.programCounter.load())
{}
TargetState& operator = (const TargetState& other) {
this->executionState = other.executionState.load();
this->mode = other.mode.load();
this->programCounter = other.programCounter.load();
return *this;
}
bool operator == (const TargetState& other) const {
return
this->executionState.load() == other.executionState.load()
&& this->mode.load() == other.mode.load()
&& this->programCounter.load() == other.programCounter.load()
;
}
bool operator != (const TargetState& other) const {
return !(*this == other);
}
};
}
Q_DECLARE_METATYPE(Targets::TargetState)

View File

@@ -1,64 +0,0 @@
#pragma once
#include <cstdint>
#include <string>
#include <map>
#include "TargetPinDescriptor.hpp"
namespace Targets
{
enum class TargetPackage: std::uint8_t
{
UNKNOWN,
/**
* Quad flat package (QFP)
*/
QFP,
/**
* Dual inline package (DIP)
*/
DIP,
/**
* "Small outline integrated circuit" package (SOIC).
*
* Because of the similarities between SOIC and DIP, Insight treats SOIC packages as DIP packages. That is,
* it uses the same package widget.
*/
SOIC,
/**
* "Shrink small outline" package (SSOP)
*
* Because of the similarities between this and DIP, Insight treats SSOP packages as DIP packages. That is,
* it uses the same package widget.
*/
SSOP,
/**
* Quad flat no-lead (QFN) package
*
* Because of the similarities between this and QFP, Insight treats QFN packages as QFP.
*/
QFN,
};
struct TargetVariant
{
int id;
std::string name;
std::string packageName;
TargetPackage package = TargetPackage::UNKNOWN;
std::map<int, TargetPinDescriptor> pinDescriptorsByNumber;
bool operator == (const TargetVariant& variant) const {
return this->name == variant.name
&& this->packageName == variant.packageName
&& this->package == variant.package
&& this->pinDescriptorsByNumber == variant.pinDescriptorsByNumber;
}
};
}

View File

@@ -0,0 +1,14 @@
#include "TargetVariantDescriptor.hpp"
#include <utility>
namespace Targets
{
TargetVariantDescriptor::TargetVariantDescriptor(
const std::string& name,
const std::string& pinoutKey
)
: name(name)
, pinoutKey(pinoutKey)
{}
}

View File

@@ -0,0 +1,24 @@
#pragma once
#include <string>
namespace Targets
{
struct TargetVariantDescriptor
{
public:
std::string name;
std::string pinoutKey;
TargetVariantDescriptor(
const std::string& name,
const std::string& pinoutKey
);
TargetVariantDescriptor(const TargetVariantDescriptor& other) = delete;
TargetVariantDescriptor& operator = (const TargetVariantDescriptor& other) = delete;
TargetVariantDescriptor(TargetVariantDescriptor&& other) noexcept = default;
TargetVariantDescriptor& operator = (TargetVariantDescriptor&& other) noexcept = default;
};
}

View File

@@ -1,5 +1,5 @@
#pragma once
#include "src/Targets/Target.hpp"
#include "src/Targets/Microchip/AVR/AVR8/Avr8.hpp"
#include "src/Targets/Microchip/AVR8/Avr8.hpp"
#include "src/Targets/RiscV/RiscV.hpp"