Added AVR8 fuse enable strategy
This commit is contained in:
@@ -14,8 +14,6 @@
|
||||
#include "Exceptions/DebugWirePhysicalInterfaceError.hpp"
|
||||
#include "src/Targets/TargetRegister.hpp"
|
||||
|
||||
#include "src/Targets/Microchip/AVR/Fuse.hpp"
|
||||
|
||||
namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
||||
{
|
||||
using namespace Exceptions;
|
||||
@@ -54,6 +52,7 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
||||
TargetRegisterAccess(true, true)
|
||||
)
|
||||
)
|
||||
, fuseEnableStrategy(this->targetDescriptionFile.getFuseEnableStrategy().value_or(FuseEnableStrategy::CLEAR))
|
||||
{
|
||||
if (!this->supportedPhysicalInterfaces.contains(this->targetConfig.physicalInterface)) {
|
||||
/*
|
||||
@@ -648,6 +647,28 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
||||
}
|
||||
}
|
||||
|
||||
bool Avr8::isFuseEnabled(const FuseBitsDescriptor& descriptor, unsigned char fuseByteValue) const {
|
||||
const auto programmedValue = static_cast<unsigned char>(
|
||||
this->fuseEnableStrategy == FuseEnableStrategy::SET
|
||||
? (0xFF & descriptor.bitMask)
|
||||
: 0
|
||||
);
|
||||
|
||||
return (fuseByteValue & descriptor.bitMask) == programmedValue;
|
||||
}
|
||||
|
||||
unsigned char Avr8::setFuseEnabled(
|
||||
const FuseBitsDescriptor& descriptor,
|
||||
unsigned char fuseByteValue,
|
||||
bool enabled
|
||||
) const {
|
||||
return static_cast<unsigned char>(
|
||||
this->fuseEnableStrategy == FuseEnableStrategy::SET
|
||||
? enabled ? (fuseByteValue | descriptor.bitMask) : fuseByteValue & ~(descriptor.bitMask)
|
||||
: enabled ? fuseByteValue & ~(descriptor.bitMask) : (fuseByteValue | descriptor.bitMask)
|
||||
);
|
||||
}
|
||||
|
||||
void Avr8::updateDwenFuseBit(bool enable) {
|
||||
if (this->avrIspInterface == nullptr) {
|
||||
throw Exception(
|
||||
@@ -750,7 +771,7 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
||||
* cleared bit (0b0), means the fuse/lock is set.
|
||||
*/
|
||||
|
||||
if ((spienFuseByte & spienFuseBitsDescriptor->bitMask) != 0) {
|
||||
if (!this->isFuseEnabled(*spienFuseBitsDescriptor, spienFuseByte)) {
|
||||
/*
|
||||
* If we get here, something is very wrong. The SPIEN (SPI enable) fuse bit appears to be cleared, but
|
||||
* this is not possible because we're connected to the target via the SPI (the ISP interface uses a
|
||||
@@ -771,7 +792,7 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
||||
|
||||
Logger::info("Current SPIEN fuse bit value confirmed");
|
||||
|
||||
if (!static_cast<bool>(dwenFuseByte & dwenFuseBitsDescriptor->bitMask) == enable) {
|
||||
if (this->isFuseEnabled(*dwenFuseBitsDescriptor, dwenFuseByte) == enable) {
|
||||
/*
|
||||
* The DWEN fuse appears to already be set to the desired value. This may be a result of incorrect data
|
||||
* in the TDF, but we're not taking any chances.
|
||||
@@ -801,8 +822,7 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
||||
|
||||
const auto newFuse = Fuse(
|
||||
dwenFuseBitsDescriptor->fuseType,
|
||||
(enable) ? static_cast<unsigned char>(dwenFuseByte & ~(dwenFuseBitsDescriptor->bitMask))
|
||||
: static_cast<unsigned char>(dwenFuseByte | dwenFuseBitsDescriptor->bitMask)
|
||||
this->setFuseEnabled(*dwenFuseBitsDescriptor, dwenFuseByte, enable)
|
||||
);
|
||||
|
||||
Logger::warning("Updating DWEN fuse bit");
|
||||
@@ -876,7 +896,7 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
||||
|
||||
Logger::debug("OCDEN fuse byte value (before update): 0x" + StringService::toHex(ocdenFuseByteValue));
|
||||
|
||||
if ((jtagenFuseByteValue & jtagenFuseBitsDescriptor->bitMask) != 0) {
|
||||
if (!this->isFuseEnabled(*jtagenFuseBitsDescriptor, jtagenFuseByteValue)) {
|
||||
/*
|
||||
* If we get here, something has gone wrong. The JTAGEN fuse should always be programmed by this point.
|
||||
* We wouldn't have been able to activate the JTAG physical interface if the fuse wasn't programmed.
|
||||
@@ -890,16 +910,14 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
||||
);
|
||||
}
|
||||
|
||||
if (!static_cast<bool>(ocdenFuseByteValue & ocdenFuseBitsDescriptor->bitMask) == enable) {
|
||||
if (this->isFuseEnabled(*ocdenFuseBitsDescriptor, ocdenFuseByteValue) == enable) {
|
||||
Logger::debug("OCDEN fuse bit already set to desired value - aborting update operation");
|
||||
|
||||
this->disableProgrammingMode();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto newValue = (enable)
|
||||
? static_cast<unsigned char>(ocdenFuseByteValue & ~(ocdenFuseBitsDescriptor->bitMask))
|
||||
: static_cast<unsigned char>(ocdenFuseByteValue | ocdenFuseBitsDescriptor->bitMask);
|
||||
const auto newValue = this->setFuseEnabled(*ocdenFuseBitsDescriptor, ocdenFuseByteValue, enable);
|
||||
|
||||
Logger::debug("New OCDEN fuse byte value (to be written): 0x" + StringService::toHex(newValue));
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include "TargetParameters.hpp"
|
||||
#include "PadDescriptor.hpp"
|
||||
#include "ProgramMemorySection.hpp"
|
||||
|
||||
#include "src/Targets/Microchip/AVR/Fuse.hpp"
|
||||
#include "src/Targets/TargetRegister.hpp"
|
||||
|
||||
#include "TargetDescription/TargetDescriptionFile.hpp"
|
||||
@@ -116,6 +118,16 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
||||
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;
|
||||
@@ -130,6 +142,33 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
||||
|
||||
void loadTargetMemoryDescriptors();
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
||||
@@ -339,6 +339,32 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit::TargetDescription
|
||||
return output;
|
||||
}
|
||||
|
||||
std::optional<FuseEnableStrategy> TargetDescriptionFile::getFuseEnableStrategy() const {
|
||||
static const auto fuseEnableStrategies = std::map<std::string, FuseEnableStrategy>({
|
||||
{"0", FuseEnableStrategy::CLEAR},
|
||||
{"1", FuseEnableStrategy::SET},
|
||||
});
|
||||
|
||||
const auto programmingInfoPropertyGroupIt = this->propertyGroupsMappedByName.find("programming_info");
|
||||
|
||||
if (programmingInfoPropertyGroupIt != this->propertyGroupsMappedByName.end()) {
|
||||
const auto& programmingInfoParamsByName = programmingInfoPropertyGroupIt->second.propertiesMappedByName;
|
||||
const auto fuseEnabledValuePropertyIt = programmingInfoParamsByName.find("fuse_enabled_value");
|
||||
|
||||
if (fuseEnabledValuePropertyIt != programmingInfoParamsByName.end()) {
|
||||
const auto fuseEnableStrategyIt = fuseEnableStrategies.find(
|
||||
fuseEnabledValuePropertyIt->second.value.toStdString()
|
||||
);
|
||||
|
||||
if (fuseEnableStrategyIt != fuseEnableStrategies.end()) {
|
||||
return fuseEnableStrategyIt->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<FuseBitsDescriptor> TargetDescriptionFile::getDwenFuseBitsDescriptor() const {
|
||||
return this->getFuseBitsDescriptorByName("dwen");
|
||||
}
|
||||
|
||||
@@ -83,6 +83,14 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit::TargetDescription
|
||||
*/
|
||||
[[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.
|
||||
|
||||
@@ -13,6 +13,12 @@ namespace Bloom::Targets::Microchip::Avr
|
||||
EXTENDED,
|
||||
};
|
||||
|
||||
enum class FuseEnableStrategy: std::uint8_t
|
||||
{
|
||||
CLEAR,
|
||||
SET,
|
||||
};
|
||||
|
||||
struct Fuse
|
||||
{
|
||||
FuseType type;
|
||||
|
||||
Reference in New Issue
Block a user