Flash programming support for WCH-LinkE tool

This commit is contained in:
Nav
2024-11-16 20:05:26 +00:00
parent 0118306e30
commit 07283a2dc7
24 changed files with 638 additions and 53 deletions

View File

@@ -3,6 +3,7 @@
#include <cassert>
#include <cmath>
#include <iterator>
#include <algorithm>
#include "src/Helpers/Pair.hpp"
#include "src/Services/StringService.hpp"
@@ -40,6 +41,7 @@ namespace Targets::RiscV
bool RiscV::supportsDebugTool(DebugTool* debugTool) {
return
debugTool->getRiscVDebugInterface(this->targetDescriptionFile, this->targetConfig) != nullptr
&& debugTool->getRiscVProgramInterface(this->targetDescriptionFile, this->targetConfig) != nullptr
&& debugTool->getRiscVIdentificationInterface(this->targetDescriptionFile, this->targetConfig) != nullptr
;
}
@@ -247,8 +249,76 @@ namespace Targets::RiscV
static_cast<TargetMemoryAddress>(startAddress + buffer.size()) - 1)
);
if (memorySegmentDescriptor.type == TargetMemorySegmentType::FLASH && this->riscVProgramInterface) {
return this->riscVProgramInterface->writeFlashMemory(startAddress, buffer);
if (
memorySegmentDescriptor.type == TargetMemorySegmentType::FLASH
&& this->isProgramMemory(
addressSpaceDescriptor,
memorySegmentDescriptor,
startAddress,
static_cast<TargetMemorySize>(buffer.size())
)
) {
const auto alignmentSize = this->riscVProgramInterface->alignmentSize(
addressSpaceDescriptor,
memorySegmentDescriptor,
startAddress,
static_cast<TargetMemorySize>(buffer.size())
);
if (alignmentSize.has_value()) {
const auto bufferSize = static_cast<TargetMemorySize>(buffer.size());
const auto alignedStartAddress = (startAddress / *alignmentSize) * *alignmentSize;
const auto alignedBufferSize = static_cast<TargetMemorySize>(std::ceil(
static_cast<double>(bufferSize) / static_cast<double>(*alignmentSize)
) * *alignmentSize);
if (alignedStartAddress != startAddress || alignedBufferSize != bufferSize) {
auto alignedBuffer = (alignedStartAddress < startAddress)
? this->readMemory(
addressSpaceDescriptor,
memorySegmentDescriptor,
alignedStartAddress,
(startAddress - alignedStartAddress),
{}
)
: TargetMemoryBuffer{};
alignedBuffer.resize(alignedBufferSize);
std::copy(
buffer.begin(),
buffer.end(),
alignedBuffer.begin() + (startAddress - alignedStartAddress)
);
const auto dataBack = this->readMemory(
addressSpaceDescriptor,
memorySegmentDescriptor,
startAddress + bufferSize,
alignedBufferSize - bufferSize - (startAddress - alignedStartAddress),
{}
);
std::copy(
dataBack.begin(),
dataBack.end(),
alignedBuffer.begin() + (startAddress - alignedStartAddress) + bufferSize
);
return this->riscVProgramInterface->writeProgramMemory(
addressSpaceDescriptor,
memorySegmentDescriptor,
alignedStartAddress,
alignedBuffer
);
}
}
return this->riscVProgramInterface->writeProgramMemory(
addressSpaceDescriptor,
memorySegmentDescriptor,
startAddress,
buffer
);
}
return this->riscVDebugInterface->writeMemory(
@@ -272,7 +342,7 @@ namespace Targets::RiscV
const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
const TargetMemorySegmentDescriptor& memorySegmentDescriptor
) {
this->riscVProgramInterface->eraseProgramMemory(addressSpaceDescriptor, memorySegmentDescriptor);
}
TargetExecutionState RiscV::getExecutionState() {
@@ -333,15 +403,15 @@ namespace Targets::RiscV
}
void RiscV::enableProgrammingMode() {
this->programmingMode = true;
}
void RiscV::disableProgrammingMode() {
this->programmingMode = false;
}
bool RiscV::programmingModeEnabled() {
return false;
return this->programmingMode;
}
const TargetMemorySegmentDescriptor& RiscV::resolveRegisterMemorySegmentDescriptor(

View File

@@ -130,6 +130,8 @@ namespace Targets::RiscV
*/
TargetAddressSpaceDescriptor sysAddressSpaceDescriptor;
bool programmingMode = false;
const TargetMemorySegmentDescriptor& resolveRegisterMemorySegmentDescriptor(
const TargetRegisterDescriptor& regDescriptor,
const TargetAddressSpaceDescriptor& addressSpaceDescriptor

View File

@@ -6,7 +6,11 @@ namespace Targets::RiscV
: Targets::TargetDescription::TargetDescriptionFile(xmlFilePath)
{}
const TargetDescription::AddressSpace& TargetDescriptionFile::getSystemAddressSpace() const {
return this->getAddressSpace("system");
}
TargetAddressSpaceDescriptor TargetDescriptionFile::getSystemAddressSpaceDescriptor() const {
return this->targetAddressSpaceDescriptorFromAddressSpace(this->getAddressSpace("system"));
return this->targetAddressSpaceDescriptorFromAddressSpace(this->getSystemAddressSpace());
}
}

View File

@@ -14,6 +14,8 @@ namespace Targets::RiscV
public:
explicit TargetDescriptionFile(const std::string& xmlFilePath);
[[nodiscard]] const TargetDescription::AddressSpace& getSystemAddressSpace() const;
[[nodiscard]] TargetAddressSpaceDescriptor getSystemAddressSpaceDescriptor() const;
};
}

View File

@@ -14,6 +14,8 @@ namespace Targets::RiscV::Wch
)
: RiscV(targetConfig, targetDescriptionFile)
, targetDescriptionFile(std::move(targetDescriptionFile))
, programMemorySegmentDescriptor(this->sysAddressSpaceDescriptor.getMemorySegmentDescriptor("internal_program_memory"))
, mappedProgramMemorySegmentDescriptor(this->sysAddressSpaceDescriptor.getMemorySegmentDescriptor("mapped_progmem"))
{}
void WchRiscV::activate() {
@@ -85,4 +87,29 @@ namespace Targets::RiscV::Wch
return descriptor;
}
void WchRiscV::writeMemory(
const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
const TargetMemorySegmentDescriptor& memorySegmentDescriptor,
TargetMemoryAddress startAddress,
const TargetMemoryBuffer& buffer
) {
/*
* WCH targets have a memory segment that maps to either the program memory segment or the boot program
* memory segment.
*
* Reading directly from the mapped memory segment is fine, but we cannot write to it - the operation just
* fails silently. We handle this by altering the write operation so that we write to the appropriate,
* non-mapped segment.
*/
if (memorySegmentDescriptor == this->mappedProgramMemorySegmentDescriptor) {
const auto newAddress = startAddress - this->mappedProgramMemorySegmentDescriptor.addressRange.startAddress
+ this->programMemorySegmentDescriptor.addressRange.startAddress;
assert(this->programMemorySegmentDescriptor.addressRange.contains(newAddress));
return RiscV::writeMemory(addressSpaceDescriptor, this->programMemorySegmentDescriptor, newAddress, buffer);
}
return RiscV::writeMemory(addressSpaceDescriptor, memorySegmentDescriptor, startAddress, buffer);
}
}

View File

@@ -10,7 +10,7 @@
namespace Targets::RiscV::Wch
{
class WchRiscV: public ::Targets::RiscV::RiscV
class WchRiscV: public ::Targets::RiscV::RiscV
{
public:
WchRiscV(const TargetConfig& targetConfig, TargetDescriptionFile&& targetDescriptionFile);
@@ -19,8 +19,18 @@ class WchRiscV: public ::Targets::RiscV::RiscV
void postActivate() override;
TargetDescriptor targetDescriptor() override;
void writeMemory(
const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
const TargetMemorySegmentDescriptor& memorySegmentDescriptor,
TargetMemoryAddress startAddress,
const TargetMemoryBuffer& buffer
) override;
protected:
TargetDescriptionFile targetDescriptionFile;
std::optional<std::reference_wrapper<const TargetDescription::Variant>> variant = std::nullopt;
const TargetMemorySegmentDescriptor& programMemorySegmentDescriptor;
const TargetMemorySegmentDescriptor& mappedProgramMemorySegmentDescriptor;
};
}