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:
@@ -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
@@ -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);
|
||||
};
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
@@ -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)
|
||||
{}
|
||||
};
|
||||
}
|
||||
1154
src/Targets/Microchip/AVR8/Avr8.cpp
Normal file
1154
src/Targets/Microchip/AVR8/Avr8.cpp
Normal file
File diff suppressed because it is too large
Load Diff
232
src/Targets/Microchip/AVR8/Avr8.hpp
Normal file
232
src/Targets/Microchip/AVR8/Avr8.hpp
Normal 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);
|
||||
};
|
||||
}
|
||||
@@ -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"]) {
|
||||
@@ -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
|
||||
@@ -10,9 +10,5 @@ namespace Exceptions
|
||||
explicit DebugWirePhysicalInterfaceError(const std::string& message)
|
||||
: TargetOperationFailure(message)
|
||||
{}
|
||||
|
||||
explicit DebugWirePhysicalInterfaceError(const char* message)
|
||||
: TargetOperationFailure(message)
|
||||
{}
|
||||
};
|
||||
}
|
||||
@@ -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,
|
||||
};
|
||||
24
src/Targets/Microchip/AVR8/Fuse.hpp
Normal file
24
src/Targets/Microchip/AVR8/Fuse.hpp
Normal 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,
|
||||
};
|
||||
}
|
||||
34
src/Targets/Microchip/AVR8/GpioPadDescriptor.hpp
Normal file
34
src/Targets/Microchip/AVR8/GpioPadDescriptor.hpp
Normal 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)
|
||||
{}
|
||||
};
|
||||
}
|
||||
29
src/Targets/Microchip/AVR8/IspParameters.cpp
Normal file
29
src/Targets/Microchip/AVR8/IspParameters.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
@@ -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),
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include "src/Targets/TargetMemory.hpp"
|
||||
|
||||
namespace Targets::Microchip::Avr::Avr8Bit::OpcodeDecoder
|
||||
namespace Targets::Microchip::Avr8::OpcodeDecoder
|
||||
{
|
||||
struct Instruction
|
||||
{
|
||||
@@ -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;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Targets::Microchip::Avr::Avr8Bit
|
||||
namespace Targets::Microchip::Avr8
|
||||
{
|
||||
enum class ProgramMemorySection: std::uint8_t
|
||||
{
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Targets::Microchip::Avr::Avr8Bit
|
||||
namespace Targets::Microchip::Avr8
|
||||
{
|
||||
/**
|
||||
* Information relating to a specific AVR8 programming session.
|
||||
195
src/Targets/Microchip/AVR8/TargetDescriptionFile.cpp
Normal file
195
src/Targets/Microchip/AVR8/TargetDescriptionFile.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
85
src/Targets/Microchip/AVR8/TargetDescriptionFile.hpp
Normal file
85
src/Targets/Microchip/AVR8/TargetDescriptionFile.hpp
Normal 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;
|
||||
};
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
@@ -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
|
||||
;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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
|
||||
;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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
|
||||
;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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
|
||||
;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
@@ -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
|
||||
;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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
|
||||
;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
@@ -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)
|
||||
{}
|
||||
};
|
||||
}
|
||||
8
src/Targets/RiscV/RiscVTargetConfig.cpp
Normal file
8
src/Targets/RiscV/RiscVTargetConfig.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
#include "RiscVTargetConfig.hpp"
|
||||
|
||||
namespace Targets::RiscV
|
||||
{
|
||||
RiscVTargetConfig::RiscVTargetConfig(const TargetConfig& targetConfig)
|
||||
: TargetConfig(targetConfig)
|
||||
{}
|
||||
}
|
||||
15
src/Targets/RiscV/RiscVTargetConfig.hpp
Normal file
15
src/Targets/RiscV/RiscVTargetConfig.hpp
Normal 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);
|
||||
};
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
16
src/Targets/RiscV/TargetDescriptionFile.cpp
Normal file
16
src/Targets/RiscV/TargetDescriptionFile.cpp
Normal 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"));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "src/Targets/TargetMemory.hpp"
|
||||
|
||||
namespace Targets::RiscV
|
||||
{
|
||||
struct TargetParameters
|
||||
{};
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
20
src/Targets/TargetBitFieldDescriptor.cpp
Normal file
20
src/Targets/TargetBitFieldDescriptor.cpp
Normal 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};
|
||||
}
|
||||
}
|
||||
36
src/Targets/TargetBitFieldDescriptor.hpp
Normal file
36
src/Targets/TargetBitFieldDescriptor.hpp
Normal 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;
|
||||
};
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
{}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
40
src/Targets/TargetGpioPinState.hpp
Normal file
40
src/Targets/TargetGpioPinState.hpp
Normal 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)
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
46
src/Targets/TargetMemorySegmentDescriptor.cpp
Normal file
46
src/Targets/TargetMemorySegmentDescriptor.cpp
Normal 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};
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace Targets
|
||||
{
|
||||
enum class TargetMemorySegmentType: std::uint8_t
|
||||
{
|
||||
GENERAL_PURPOSE_REGISTERS,
|
||||
ALIASED,
|
||||
REGISTERS,
|
||||
EEPROM,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
19
src/Targets/TargetPeripheralSignalDescriptor.cpp
Normal file
19
src/Targets/TargetPeripheralSignalDescriptor.cpp
Normal 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
|
||||
};
|
||||
}
|
||||
}
|
||||
28
src/Targets/TargetPeripheralSignalDescriptor.hpp
Normal file
28
src/Targets/TargetPeripheralSignalDescriptor.hpp
Normal 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;
|
||||
};
|
||||
}
|
||||
@@ -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"},
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
14
src/Targets/TargetPinDescriptor.cpp
Normal file
14
src/Targets/TargetPinDescriptor.cpp
Normal 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)
|
||||
{}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
22
src/Targets/TargetPinoutDescriptor.cpp
Normal file
22
src/Targets/TargetPinoutDescriptor.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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>;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
14
src/Targets/TargetVariantDescriptor.cpp
Normal file
14
src/Targets/TargetVariantDescriptor.cpp
Normal 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)
|
||||
{}
|
||||
}
|
||||
24
src/Targets/TargetVariantDescriptor.hpp
Normal file
24
src/Targets/TargetVariantDescriptor.hpp
Normal 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;
|
||||
};
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user