Lots of tidying

- Removed generic `avr8` target
- Simplified AVR8 target construction
- Introduced register descriptor IDs
- Simplified GDB register mappings
- Simplified target interface contract
- Other bits of tidying
This commit is contained in:
Nav
2023-05-21 21:08:25 +01:00
parent 5f8242a87a
commit ba03833325
62 changed files with 1304 additions and 1577 deletions

View File

@@ -25,9 +25,6 @@ namespace Bloom::Targets
* All targets supported by Bloom must implement this interface.
*
* A single implementation of this interface can represent a single target, or an entire family of targets.
* For an example, see the Avr8 implementation. The Avr8 target class was written in a way that would allow it to
* work, to *at least* the point of target promotion, for all AVR8 targets. For more on target promotion, see the
* Target::promote() function.
*/
class Target
{
@@ -41,38 +38,27 @@ namespace Bloom::Targets
}
/**
* There are three stages of configuration for targets.
* 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
* exception will be raised and Bloom will shutdown.
*
* preActivationConfigure() - The first stage is just before target activation (Target::activate() being
* called). At this point, we will not have interacted with the target in any way. This function should cover
* any configuration that can be done without the target being activated. It should also cover any configuration
* that is required in order for us to successfully activate the target. For an example, we use this function
* in the Avr8 target class to configure the debug tool with the correct physical interface and config variant
* parameters (taken from the user's settings, via the TargetConfig object). Without these being configured,
* the debug tool would not be able to interface with the AVR8 target, and thus target activation would fail.
* @param debugTool
*
* postActivationConfigure() - The second stage is right after target activation (successful invocation of
* Target::activate()). At this point, we will have established a connection with the target and so interaction
* with the target is permitted here. We use this function in the Avr8 target class to extract the target
* signature from the target's memory, which we then use to find & load the correct target description file.
*
* postPromotionConfigure() - The final stage of configuration occurs just after the target instance has been
* promoted to a different class. See the Target::promote() function for more on this.
*
* If any of the three configuration functions throw an exception, the exception will be treated as a fatal
* error. In response, the TargetController will shutdown, along with the rest of Bloom.
*
* @param targetConfig
* @return
*/
virtual void preActivationConfigure(const TargetConfig& targetConfig) {
this->config = targetConfig;
};
virtual void postActivationConfigure() = 0;
virtual void postPromotionConfigure() = 0;
virtual bool supportsDebugTool(DebugTool* debugTool) = 0;
/**
* Assuming the Target::isDebugToolSupported() check passed, this function will be called shortly after, by the
* TargetController.
*
* @param debugTool
*/
virtual void setDebugTool(DebugTool* debugTool) = 0;
/**
* This function should attempt to establish a connection with the target, and put it in a state where
* debugging can be performed. This function will be called after Target::preActivationConfigure().
* debugging can be performed.
*
* If an exception is thrown from this function, the TargetController will treat it as a fatal error, and thus
* will shutdown, along with the rest of Bloom.
@@ -91,81 +77,6 @@ namespace Bloom::Targets
*/
virtual void deactivate() = 0;
/**
* 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
* exception will be raised and Bloom will shutdown.
*
* For AVR8 targets, we simply check if the debug tool returns a valid Avr8DebugInterface
* (via DebugTool::getAvr8DebugInterface()). If it fails to do so, it would mean that the debug tool, or more
* so our debug tool driver, does not support AVR8 targets.
*
* @param debugTool
*
* @return
*/
virtual bool isDebugToolSupported(DebugTool* debugTool) = 0;
/**
* Assuming the Target::isDebugToolSupported() check passed, this function will be called shortly after, by the
* TargetController.
*
* @param debugTool
*/
virtual void setDebugTool(DebugTool* debugTool) = 0;
/**
* Should indicate whether this target class can be promoted to one that better represents the connected
* target. See Target::promote() for more.
*
* @return
*/
virtual bool supportsPromotion() = 0;
/**
* Bloom allows users to select generic targets within their configuration, but this doesn't have to mean we
* are limited to the generic target class. In some cases, we may want to switch to a target class that is
* more specific to the connected target. We call this "target promotion". See below for an example.
*
* When a user is debugging an AVR8 target, they may not specify the exact name of the target in their project
* configuration file. Instead, they may select the generic 'avr8' target (which maps to the generic Avr8 target
* class). In cases like this, the data we have on the target, at the point of start up, is very limited; all we
* know about the target is that it's part of the AVR8 family. Nothing else. But this is ok, because, when we
* begin the target configuration and activation process, we are able to learn a lot more about the target.
* For AVR8 targets, we extract the target signature shortly after activation, and with that signature we find
* the appropriate target description file, which has all of the information regarding the target that we could
* possibly need. So, by the time we have activated the target, we will know a lot more about it, and it is at
* this point, where we may want to promote it to a more specific target class (from the generic Avr8 target
* class). The generic AVR8 target class will attempt to promote the target to one that is more specific to
* the target's AVR8 family (ATmega, XMega, Tiny, etc). These classes can then also perform promotion of their
* own, if required, where they could promote to a class that's not only specific to an AVR8 family, but to a
* particular target model (for example, a target class that was written specifically for the ATmega328P target).
*
* This function should attempt to promote the current target class to one that is more specific to the
* connected target, with the information it currently holds on the target.
*
* If this function fails to promote the target, it should return an std::unique_ptr(nullptr).
*
* After activating the target, assuming the first call to Target::supportsPromotion() returns true, the
* TargetController will enter a loop, where it will repeatedly call this function and update the target
* instance, until at least one of the following conditions are met:
* - The call to Target::supportsPromotion() on the current target instance returns false
* - The call to Target::promote() on the current target instance returns an std::unique_ptr(nullptr)
* - The call to Target::promote() on the current target instance returns a target class type that is equal
* to the type of the current target instance (promotion failed).
*
* Once at least one of the above conditions are met, the TargetController will break out of the loop and use
* the last promoted target instance from there onwards.
*
* See TargetControllerComponent::acquireHardware() for more on this.
*
* @return
*/
virtual std::unique_ptr<Target> promote() = 0;
virtual std::string getName() const = 0;
virtual std::string getHumanReadableId() = 0;
/**
* Should generate and return a TargetDescriptor for the current target.
*
@@ -230,11 +141,11 @@ namespace Bloom::Targets
/**
* Should read register values of the registers described by the given descriptors.
*
* @param descriptors
* @param descriptorIds
*
* @return
*/
virtual TargetRegisters readRegisters(TargetRegisterDescriptors descriptors) = 0;
virtual TargetRegisters readRegisters(const Targets::TargetRegisterDescriptorIds& descriptorIds) = 0;
/**
* Should read memory from the target.