Added word alignment for flash memory access in UPDI sessions

This commit is contained in:
Nav
2022-05-28 13:44:10 +01:00
parent ae3f83dce7
commit ce33ecba99
2 changed files with 103 additions and 59 deletions

View File

@@ -1344,41 +1344,77 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
while (this->getAvrEvent() != nullptr) {} while (this->getAvrEvent() != nullptr) {}
} }
std::uint32_t EdbgAvr8Interface::alignMemoryAddress(Avr8MemoryType memoryType, std::uint32_t address) { bool EdbgAvr8Interface::alignmentRequired(Avr8MemoryType memoryType) {
std::uint16_t pageSize = ( return
memoryType == Avr8MemoryType::FLASH_PAGE memoryType == Avr8MemoryType::FLASH_PAGE
|| memoryType == Avr8MemoryType::SPM || memoryType == Avr8MemoryType::SPM
) || (memoryType == Avr8MemoryType::APPL_FLASH && this->configVariant == Avr8ConfigVariant::UPDI)
? this->targetParameters.flashPageSize.value() ;
: this->targetParameters.eepromPageSize.value(); }
if (this->maximumMemoryAccessSizePerRequest.has_value() && pageSize > this->maximumMemoryAccessSizePerRequest) { std::uint32_t EdbgAvr8Interface::alignMemoryAddress(Avr8MemoryType memoryType, std::uint32_t address) {
std::uint16_t alignTo = 1;
// We don't have to align to the page size in all cases. We may only need to align to the word size (2 bytes).
switch (memoryType) {
case Avr8MemoryType::FLASH_PAGE:
case Avr8MemoryType::SPM: {
alignTo = this->targetParameters.flashPageSize.value();
break;
}
case Avr8MemoryType::APPL_FLASH: {
if (this->configVariant == Avr8ConfigVariant::UPDI) {
// For UPDI sessions, memory access via the APPL_FLASH must be word aligned.
alignTo = 2;
}
break;
}
default: {
break;
}
}
if (this->maximumMemoryAccessSizePerRequest.has_value() && alignTo > this->maximumMemoryAccessSizePerRequest) {
throw Exception( throw Exception(
"Cannot align memory address - page size exceeds the maximum memory access size per request." "Cannot align memory address - alignment size exceeds the maximum memory access size per request."
); );
} }
if ((address % pageSize) != 0) { if ((address % alignTo) != 0) {
return static_cast<std::uint32_t>(std::floor( return static_cast<std::uint32_t>(std::floor(
static_cast<float>(address) / static_cast<float>(pageSize) static_cast<float>(address) / static_cast<float>(alignTo)
) * pageSize); ) * alignTo);
} }
return address; return address;
} }
std::uint32_t EdbgAvr8Interface::alignMemoryBytes(Avr8MemoryType memoryType, std::uint32_t bytes) { std::uint32_t EdbgAvr8Interface::alignMemoryBytes(Avr8MemoryType memoryType, std::uint32_t bytes) {
std::uint16_t pageSize = ( std::uint16_t alignTo = 1;
memoryType == Avr8MemoryType::FLASH_PAGE
|| memoryType == Avr8MemoryType::SPM
)
? this->targetParameters.flashPageSize.value()
: this->targetParameters.eepromPageSize.value();
if ((bytes % pageSize) != 0) { // We don't have to align to the page size in all cases. We may only need to align to the word size (2 bytes).
switch (memoryType) {
case Avr8MemoryType::FLASH_PAGE:
case Avr8MemoryType::SPM: {
alignTo = this->targetParameters.flashPageSize.value();
break;
}
case Avr8MemoryType::APPL_FLASH: {
if (this->configVariant == Avr8ConfigVariant::UPDI) {
// For UPDI sessions, memory access via the APPL_FLASH must be word aligned.
alignTo = 2;
}
break;
}
default: {
break;
}
}
if ((bytes % alignTo) != 0) {
return static_cast<std::uint32_t>(std::ceil( return static_cast<std::uint32_t>(std::ceil(
static_cast<float>(bytes) / static_cast<float>(pageSize) static_cast<float>(bytes) / static_cast<float>(alignTo)
) * pageSize); ) * alignTo);
} }
return bytes; return bytes;
@@ -1442,7 +1478,7 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
return output; return output;
} }
if (type == Avr8MemoryType::FLASH_PAGE || type == Avr8MemoryType::SPM) { if (this->alignmentRequired(type)) {
const auto alignedStartAddress = this->alignMemoryAddress(type, startAddress); const auto alignedStartAddress = this->alignMemoryAddress(type, startAddress);
const auto alignedBytes = this->alignMemoryBytes(type, bytes + (startAddress - alignedStartAddress)); const auto alignedBytes = this->alignMemoryBytes(type, bytes + (startAddress - alignedStartAddress));
@@ -1456,28 +1492,28 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
return output; return output;
} }
}
if (type == Avr8MemoryType::FLASH_PAGE && this->configVariant == Avr8ConfigVariant::DEBUG_WIRE) { if (type == Avr8MemoryType::FLASH_PAGE) {
// With the FLASH_PAGE memory type, in debugWire sessions, we can only read one page at a time. // With the FLASH_PAGE memory type, we can only read one page at a time.
const auto pageSize = this->targetParameters.flashPageSize.value(); const auto pageSize = this->targetParameters.flashPageSize.value();
if (bytes > pageSize) { if (bytes > pageSize) {
// bytes should always be a multiple of pageSize (given the code above) // bytes should always be a multiple of pageSize (given the code above)
assert(bytes % pageSize == 0); assert(bytes % pageSize == 0);
int pagesRequired = static_cast<int>(bytes / pageSize); int pagesRequired = static_cast<int>(bytes / pageSize);
TargetMemoryBuffer memoryBuffer; TargetMemoryBuffer memoryBuffer;
for (auto i = 0; i < pagesRequired; i++) { for (auto i = 0; i < pagesRequired; i++) {
auto pageBuffer = this->readMemory( auto pageBuffer = this->readMemory(
type, type,
startAddress + static_cast<std::uint32_t>(pageSize * i), startAddress + static_cast<std::uint32_t>(pageSize * i),
pageSize pageSize
); );
std::move(pageBuffer.begin(), pageBuffer.end(), std::back_inserter(memoryBuffer)); std::move(pageBuffer.begin(), pageBuffer.end(), std::back_inserter(memoryBuffer));
}
return memoryBuffer;
} }
return memoryBuffer;
} }
} }
@@ -1569,9 +1605,9 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
} }
void EdbgAvr8Interface::writeMemory(Avr8MemoryType type, std::uint32_t startAddress, const TargetMemoryBuffer& buffer) { void EdbgAvr8Interface::writeMemory(Avr8MemoryType type, std::uint32_t startAddress, const TargetMemoryBuffer& buffer) {
if (type == Avr8MemoryType::FLASH_PAGE || type == Avr8MemoryType::SPM) { const auto bytes = static_cast<std::uint32_t>(buffer.size());
const auto bytes = static_cast<std::uint32_t>(buffer.size());
if (this->alignmentRequired(type)) {
const auto alignedStartAddress = this->alignMemoryAddress(type, startAddress); const auto alignedStartAddress = this->alignMemoryAddress(type, startAddress);
const auto alignedBytes = this->alignMemoryBytes(type, bytes + (startAddress - alignedStartAddress)); const auto alignedBytes = this->alignMemoryBytes(type, bytes + (startAddress - alignedStartAddress));
@@ -1584,30 +1620,30 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
return this->writeMemory(type, alignedStartAddress, alignedBuffer); return this->writeMemory(type, alignedStartAddress, alignedBuffer);
} }
}
if (type == Avr8MemoryType::FLASH_PAGE && this->configVariant == Avr8ConfigVariant::DEBUG_WIRE) { if (type == Avr8MemoryType::FLASH_PAGE) {
// With the FLASH_PAGE memory type, in debugWire sessions, we can only write one page at a time. // With the FLASH_PAGE memory type, we can only write one page at a time.
const auto pageSize = this->targetParameters.flashPageSize.value(); const auto pageSize = this->targetParameters.flashPageSize.value();
if (bytes > pageSize) { if (bytes > pageSize) {
assert(bytes % pageSize == 0); assert(bytes % pageSize == 0);
int pagesRequired = static_cast<int>(bytes / pageSize); int pagesRequired = static_cast<int>(bytes / pageSize);
for (auto i = 0; i < pagesRequired; i++) { for (auto i = 0; i < pagesRequired; i++) {
const auto offset = static_cast<std::uint32_t>(pageSize * i); const auto offset = static_cast<std::uint32_t>(pageSize * i);
auto pageBuffer = TargetMemoryBuffer(); auto pageBuffer = TargetMemoryBuffer();
pageBuffer.reserve(pageSize); pageBuffer.reserve(pageSize);
std::move( std::move(
buffer.begin() + offset, buffer.begin() + offset,
buffer.begin() + offset + pageSize, buffer.begin() + offset + pageSize,
std::back_inserter(pageBuffer) std::back_inserter(pageBuffer)
); );
this->writeMemory(type, startAddress + offset, pageBuffer); this->writeMemory(type, startAddress + offset, pageBuffer);
}
return;
} }
return;
} }
} }

View File

@@ -469,6 +469,14 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
*/ */
void clearEvents(); void clearEvents();
/**
* Checks if alignment is required for memory access via a given Avr8MemoryType.
*
* @param memoryType
* @return
*/
bool alignmentRequired(Avr8MemoryType memoryType);
/** /**
* Aligns a memory address for a given memory type's page size. * Aligns a memory address for a given memory type's page size.
* *