Flash programming support for WCH-LinkE tool
This commit is contained in:
@@ -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(
|
||||
|
||||
@@ -130,6 +130,8 @@ namespace Targets::RiscV
|
||||
*/
|
||||
TargetAddressSpaceDescriptor sysAddressSpaceDescriptor;
|
||||
|
||||
bool programmingMode = false;
|
||||
|
||||
const TargetMemorySegmentDescriptor& resolveRegisterMemorySegmentDescriptor(
|
||||
const TargetRegisterDescriptor& regDescriptor,
|
||||
const TargetAddressSpaceDescriptor& addressSpaceDescriptor
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ namespace Targets::RiscV
|
||||
public:
|
||||
explicit TargetDescriptionFile(const std::string& xmlFilePath);
|
||||
|
||||
[[nodiscard]] const TargetDescription::AddressSpace& getSystemAddressSpace() const;
|
||||
|
||||
[[nodiscard]] TargetAddressSpaceDescriptor getSystemAddressSpaceDescriptor() const;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user