Revisions on Gareth's comments.

o Implemented byte writes to EEPROM now that the emulator has a
  byte-wide target write.
o Added comment describing the reason that mass erase doesn't work.
o Removed all unused code.
o Changed to Linux kernel indent style.
o Changed to Linux kernel function to parenthesis style.
o Stub generation doesn't use Perl, switched to sed.  Also, only
  including the instructions instead of the source and the instructions.
o Handling unaligned destination writes.
This commit is contained in:
Marc Singer 2015-01-24 13:50:59 -08:00
parent e0a8ce5a88
commit bf1cb71eb7
9 changed files with 1098 additions and 1302 deletions

View File

@ -11,3 +11,9 @@ of half-words for inclusion in the target driver. The use of a higher
level language allows more detailed code and for easy revisions. level language allows more detailed code and for easy revisions.
These stubs communicate with the driver through a structure defined in These stubs communicate with the driver through a structure defined in
the src/include/stm32l0-nvm.h header. the src/include/stm32l0-nvm.h header.
The dump-to-array.sh helper script uses sed to transform the output of
'objdump -d' into a half-word array of the instructions that may be
included in C code to declare the stub. FWIW, objcopy doesn't produce
the same output as objdump. It omits some of the instructions,
probably because the object file isn't linked.

View File

@ -1,24 +0,0 @@
#!/usr/bin/perl
#
# Convert the output of objdump to an array of bytes are can include
# into our program.
while (<>) {
if (m/^\s*([0-9a-fA-F]+):\s*([0-9a-fA-F]+)(.*)/) {
my $addr = "0x$1";
my $value = $2;
if (length ($value) == 4) {
print " [$addr/2] = 0x$value, // $_";
}
else {
my $lsb = substr ($value, 4, 4);
my $msb = substr ($value, 0, 4);
print " [$addr/2] = 0x$lsb, // $_";
print " [$addr/2 + 1] = 0x$msb,\n";
}
}
else {
print "// ", $_;
}
}

11
flashstub/dump-to-array.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/sh
#
# Convert the output of objdump to an array of half-words that can be
# included into C code to represent the stub.
#
# Invoke with something like this:
#
# objdump -z -d FILE.o | dump-to-array.sh > FILE.stub
#
sed -E "/^[ ][ ]*[0-9a-fA-F]+:/!d; s/([0-9a-fA-F]+):[ \t]+([0-9a-fA-F]+).*/[0x\1\/2] = 0x\2,/ ; s/0x(....)(....),/0x\2, 0x\1,/"

View File

@ -42,52 +42,52 @@
/* Erase a region of flash. In the event that the erase is misaligned /* Erase a region of flash. In the event that the erase is misaligned
with respect to pages, it will erase the pages that contain the with respect to pages, it will erase the pages that contain the
requested range of bytes. */ requested range of bytes. */
extern "C" void __attribute((naked)) stm32l05x_nvm_prog_erase () { extern "C" void __attribute((naked)) stm32l05x_nvm_prog_erase() {
// Leave room for INFO at second word of routine // Leave room for INFO at second word of routine
__asm volatile ("b 0f\n\t" __asm volatile ("b 0f\n\t"
".align 2\n\t" ".align 2\n\t"
".word 0\n\t" ".word 0\n\t"
".word 0\n\t" ".word 0\n\t"
".word 0\n\t" ".word 0\n\t"
".word 0\n\t" ".word 0\n\t"
".word 0\n\t" ".word 0\n\t"
"0:"); "0:");
auto& nvm = Nvm (Info.nvm); auto& nvm = Nvm (Info.nvm);
// Align to the start of the first page so that we make sure to erase // Align to the start of the first page so that we make sure to erase
// all of the target pages. // all of the target pages.
auto remainder = reinterpret_cast<uint32_t> (Info.destination) auto remainder = reinterpret_cast<uint32_t> (Info.destination)
& (Info.page_size - 1); & (Info.page_size - 1);
Info.size += remainder; Info.size += remainder;
Info.destination -= remainder/sizeof (*Info.destination); Info.destination -= remainder/sizeof (*Info.destination);
if (!unlock (nvm)) if (!unlock(nvm))
goto quit; goto quit;
nvm.sr = STM32Lx_NVM_SR_ERR_M; // Clear errors nvm.sr = STM32Lx_NVM_SR_ERR_M; // Clear errors
// Enable erasing // Enable erasing
nvm.pecr = STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE; nvm.pecr = STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE;
if ((nvm.pecr & (STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE)) if ((nvm.pecr & (STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE))
!= (STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE)) != (STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE))
goto quit; goto quit;
while (Info.size > 0) { while (Info.size > 0) {
*Info.destination = 0; // Initiate erase *Info.destination = 0; // Initiate erase
Info.destination += Info.page_size/sizeof (*Info.destination); Info.destination += Info.page_size/sizeof (*Info.destination);
Info.size -= Info.page_size; Info.size -= Info.page_size;
} }
quit: quit:
lock (nvm); lock(nvm);
__asm volatile ("bkpt"); __asm volatile ("bkpt");
} }
/* /*
Local Variables: Local Variables:
compile-command: "/opt/arm/arm-none-eabi-g++ -mcpu=cortex-m0plus -g -c -std=c++11 -mthumb -o stm32l05x-nvm-prog-erase.o -Os -Wa,-ahndl=stm32l05x-nvm-prog-erase.lst stm32l05x-nvm-prog-erase.cc ; /opt/arm/arm-none-eabi-objdump -S stm32l05x-nvm-prog-erase.o | ./code-to-array.pl > stm32l05x-nvm-prog-erase.stub" compile-command: "/opt/arm/arm-none-eabi-g++ -mcpu=cortex-m0plus -g -c -std=c++11 -mthumb -o stm32l05x-nvm-prog-erase.o -Os -Wa,-ahndl=stm32l05x-nvm-prog-erase.lst stm32l05x-nvm-prog-erase.cc ; /opt/arm/arm-none-eabi-objdump -d -z stm32l05x-nvm-prog-erase.o | ./dump-to-array.sh > stm32l05x-nvm-prog-erase.stub"
End: End:
*/ */

View File

@ -1,159 +1,67 @@
// [0x0/2] = 0xe00a,
// stm32l05x-nvm-prog-erase.o: file format elf32-littlearm [0x2/2] = 0x46c0,
// [0x4/2] = 0x0000, 0x0000,
// [0x8/2] = 0x0000, 0x0000,
// Disassembly of section .text: [0xc/2] = 0x0000, 0x0000,
// [0x10/2] = 0x0000, 0x0000,
// 00000000 <stm32l05x_nvm_prog_erase>: [0x14/2] = 0x0000, 0x0000,
// ".word 0\n\t" [0x18/2] = 0x491a,
// ".word 0\n\t" [0x1a/2] = 0x8a08,
// ".word 0\n\t" [0x1c/2] = 0x680c,
// ".word 0\n\t" [0x1e/2] = 0x684d,
// ".word 0\n\t" [0x20/2] = 0x1e42,
// "0:"); [0x22/2] = 0x4022,
[0x0/2] = 0xe00a, // 0: e00a b.n 18 <stm32l05x_nvm_prog_erase+0x18> [0x24/2] = 0x1955,
[0x2/2] = 0x46c0, // 2: 46c0 nop ; (mov r8, r8) [0x26/2] = 0x0892,
// ... [0x28/2] = 0x0092,
// [0x2a/2] = 0x1aa2,
// auto& nvm = Nvm (Info.nvm); [0x2c/2] = 0x600a,
[0x18/2] = 0x491a, // 18: 491a ldr r1, [pc, #104] ; (84 <stm32l05x_nvm_prog_erase+0x84>) [0x2e/2] = 0x2201,
// [0x30/2] = 0x68cb,
// // Align to the start of the first page so that we make sure to erase [0x32/2] = 0x604d,
// // all of the target pages. [0x34/2] = 0x605a,
// auto remainder = reinterpret_cast<uint32_t> (Info.destination) [0x36/2] = 0x4a14,
// & (Info.page_size - 1); [0x38/2] = 0x60da,
[0x1a/2] = 0x8a08, // 1a: 8a08 ldrh r0, [r1, #16] [0x3a/2] = 0x4a14,
[0x1c/2] = 0x680c, // 1c: 680c ldr r4, [r1, #0] [0x3c/2] = 0x60da,
// Info.size += remainder; [0x3e/2] = 0x4a14,
[0x1e/2] = 0x684d, // 1e: 684d ldr r5, [r1, #4] [0x40/2] = 0x611a,
// auto& nvm = Nvm (Info.nvm); [0x42/2] = 0x4a14,
// [0x44/2] = 0x611a,
// // Align to the start of the first page so that we make sure to erase [0x46/2] = 0x685a,
// // all of the target pages. [0x48/2] = 0x0792,
// auto remainder = reinterpret_cast<uint32_t> (Info.destination) [0x4a/2] = 0xd502,
// & (Info.page_size - 1); [0x4c/2] = 0x2201,
[0x20/2] = 0x1e42, // 20: 1e42 subs r2, r0, #1 [0x4e/2] = 0x605a,
[0x22/2] = 0x4022, // 22: 4022 ands r2, r4 [0x50/2] = 0xbe00,
// Info.size += remainder; [0x52/2] = 0x4a11,
[0x24/2] = 0x1955, // 24: 1955 adds r5, r2, r5 [0x54/2] = 0x619a,
// Info.destination -= remainder/sizeof (*Info.destination); [0x56/2] = 0x2282,
[0x26/2] = 0x0892, // 26: 0892 lsrs r2, r2, #2 [0x58/2] = 0x0092,
[0x28/2] = 0x0092, // 28: 0092 lsls r2, r2, #2 [0x5a/2] = 0x605a,
[0x2a/2] = 0x1aa2, // 2a: 1aa2 subs r2, r4, r2 [0x5c/2] = 0x685c,
[0x2c/2] = 0x600a, // 2c: 600a str r2, [r1, #0] [0x5e/2] = 0x4014,
// #define Nvm(nvm) (*reinterpret_cast<STM32::NVM*>(nvm)) [0x60/2] = 0x4294,
// #define Info (*reinterpret_cast<stm32lx_nvm_stub_info*>(STM32Lx_STUB_INFO_PHYS)) [0x62/2] = 0xd1f3,
// [0x64/2] = 0x0884,
// namespace { [0x66/2] = 0x00a4,
// inline __attribute((always_inline)) bool unlock (STM32::NVM& nvm) { [0x68/2] = 0x684d,
// nvm.pecr = STM32Lx_NVM_PECR_PELOCK; // Lock to guarantee unlock [0x6a/2] = 0x4a06,
[0x2e/2] = 0x2201, // 2e: 2201 movs r2, #1 [0x6c/2] = 0x2d00,
// ".word 0\n\t" [0x6e/2] = 0xdded,
// ".word 0\n\t" [0x70/2] = 0x2600,
// ".word 0\n\t" [0x72/2] = 0x6815,
// "0:"); [0x74/2] = 0x602e,
// [0x76/2] = 0x6815,
// auto& nvm = Nvm (Info.nvm); [0x78/2] = 0x192d,
[0x30/2] = 0x68cb, // 30: 68cb ldr r3, [r1, #12] [0x7a/2] = 0x6015,
// [0x7c/2] = 0x6855,
// // Align to the start of the first page so that we make sure to erase [0x7e/2] = 0x1a2d,
// // all of the target pages. [0x80/2] = 0x6055,
// auto remainder = reinterpret_cast<uint32_t> (Info.destination) [0x82/2] = 0xe7f1,
// & (Info.page_size - 1); [0x84/2] = 0x0004, 0x2000,
// Info.size += remainder; [0x88/2] = 0xcdef, 0x89ab,
[0x32/2] = 0x604d, // 32: 604d str r5, [r1, #4] [0x8c/2] = 0x0405, 0x0203,
[0x34/2] = 0x605a, // 34: 605a str r2, [r3, #4] [0x90/2] = 0xaebf, 0x8c9d,
// nvm.pkeyr = STM32::NVM::PKEY1; [0x94/2] = 0x1516, 0x1314,
[0x36/2] = 0x4a14, // 36: 4a14 ldr r2, [pc, #80] ; (88 <stm32l05x_nvm_prog_erase+0x88>) [0x98/2] = 0x0700, 0x0001,
[0x38/2] = 0x60da, // 38: 60da str r2, [r3, #12]
// nvm.pkeyr = STM32::NVM::PKEY2;
[0x3a/2] = 0x4a14, // 3a: 4a14 ldr r2, [pc, #80] ; (8c <stm32l05x_nvm_prog_erase+0x8c>)
[0x3c/2] = 0x60da, // 3c: 60da str r2, [r3, #12]
// nvm.prgkeyr = STM32::NVM::PRGKEY1;
[0x3e/2] = 0x4a14, // 3e: 4a14 ldr r2, [pc, #80] ; (90 <stm32l05x_nvm_prog_erase+0x90>)
[0x40/2] = 0x611a, // 40: 611a str r2, [r3, #16]
// nvm.prgkeyr = STM32::NVM::PRGKEY2;
[0x42/2] = 0x4a14, // 42: 4a14 ldr r2, [pc, #80] ; (94 <stm32l05x_nvm_prog_erase+0x94>)
[0x44/2] = 0x611a, // 44: 611a str r2, [r3, #16]
// return !(nvm.pecr & STM32Lx_NVM_PECR_PRGLOCK);
[0x46/2] = 0x685a, // 46: 685a ldr r2, [r3, #4]
// Info.destination -= remainder/sizeof (*Info.destination);
//
// if (!unlock (nvm))
[0x48/2] = 0x0792, // 48: 0792 lsls r2, r2, #30
[0x4a/2] = 0xd502, // 4a: d502 bpl.n 52 <stm32l05x_nvm_prog_erase+0x52>
// }
// inline __attribute((always_inline)) void lock (STM32::NVM& nvm) {
// nvm.pecr = STM32Lx_NVM_PECR_PELOCK; }
[0x4c/2] = 0x2201, // 4c: 2201 movs r2, #1
[0x4e/2] = 0x605a, // 4e: 605a str r2, [r3, #4]
// Info.size -= Info.page_size;
// }
//
// quit:
// lock (nvm);
// __asm volatile ("bkpt");
[0x50/2] = 0xbe00, // 50: be00 bkpt 0x0000
// Info.destination -= remainder/sizeof (*Info.destination);
//
// if (!unlock (nvm))
// goto quit;
//
// nvm.sr = STM32Lx_NVM_SR_ERR_M; // Clear errors
[0x52/2] = 0x4a11, // 52: 4a11 ldr r2, [pc, #68] ; (98 <stm32l05x_nvm_prog_erase+0x98>)
[0x54/2] = 0x619a, // 54: 619a str r2, [r3, #24]
//
// // Enable erasing
// nvm.pecr = STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE;
[0x56/2] = 0x2282, // 56: 2282 movs r2, #130 ; 0x82
[0x58/2] = 0x0092, // 58: 0092 lsls r2, r2, #2
[0x5a/2] = 0x605a, // 5a: 605a str r2, [r3, #4]
// if ((nvm.pecr & (STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE))
[0x5c/2] = 0x685c, // 5c: 685c ldr r4, [r3, #4]
[0x5e/2] = 0x4014, // 5e: 4014 ands r4, r2
[0x60/2] = 0x4294, // 60: 4294 cmp r4, r2
[0x62/2] = 0xd1f3, // 62: d1f3 bne.n 4c <stm32l05x_nvm_prog_erase+0x4c>
// goto quit;
//
// while (Info.size > 0) {
// *Info.destination = 0; // Initiate erase
//
// Info.destination += Info.page_size/sizeof (*Info.destination);
[0x64/2] = 0x0884, // 64: 0884 lsrs r4, r0, #2
[0x66/2] = 0x00a4, // 66: 00a4 lsls r4, r4, #2
// nvm.pecr = STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE;
// if ((nvm.pecr & (STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE))
// != (STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE))
// goto quit;
//
// while (Info.size > 0) {
[0x68/2] = 0x684d, // 68: 684d ldr r5, [r1, #4]
[0x6a/2] = 0x4a06, // 6a: 4a06 ldr r2, [pc, #24] ; (84 <stm32l05x_nvm_prog_erase+0x84>)
[0x6c/2] = 0x2d00, // 6c: 2d00 cmp r5, #0
[0x6e/2] = 0xdded, // 6e: dded ble.n 4c <stm32l05x_nvm_prog_erase+0x4c>
// *Info.destination = 0; // Initiate erase
[0x70/2] = 0x2600, // 70: 2600 movs r6, #0
[0x72/2] = 0x6815, // 72: 6815 ldr r5, [r2, #0]
[0x74/2] = 0x602e, // 74: 602e str r6, [r5, #0]
//
// Info.destination += Info.page_size/sizeof (*Info.destination);
[0x76/2] = 0x6815, // 76: 6815 ldr r5, [r2, #0]
[0x78/2] = 0x192d, // 78: 192d adds r5, r5, r4
[0x7a/2] = 0x6015, // 7a: 6015 str r5, [r2, #0]
// Info.size -= Info.page_size;
[0x7c/2] = 0x6855, // 7c: 6855 ldr r5, [r2, #4]
[0x7e/2] = 0x1a2d, // 7e: 1a2d subs r5, r5, r0
[0x80/2] = 0x6055, // 80: 6055 str r5, [r2, #4]
[0x82/2] = 0xe7f1, // 82: e7f1 b.n 68 <stm32l05x_nvm_prog_erase+0x68>
[0x84/2] = 0x0004, // 84: 20000004 .word 0x20000004
[0x84/2 + 1] = 0x2000,
[0x88/2] = 0xcdef, // 88: 89abcdef .word 0x89abcdef
[0x88/2 + 1] = 0x89ab,
[0x8c/2] = 0x0405, // 8c: 02030405 .word 0x02030405
[0x8c/2 + 1] = 0x0203,
[0x90/2] = 0xaebf, // 90: 8c9daebf .word 0x8c9daebf
[0x90/2 + 1] = 0x8c9d,
[0x94/2] = 0x1516, // 94: 13141516 .word 0x13141516
[0x94/2 + 1] = 0x1314,
[0x98/2] = 0x0700, // 98: 00010700 .word 0x00010700
[0x98/2 + 1] = 0x0001,

View File

@ -43,70 +43,71 @@
/* Write a block of bytes to flash. The called is responsible for /* Write a block of bytes to flash. The called is responsible for
making sure that the address are aligned and that the count is an making sure that the address are aligned and that the count is an
even multiple of words. */ even multiple of words. */
extern "C" void __attribute((naked)) stm32l05x_nvm_prog_write () { extern "C" void __attribute((naked)) stm32l05x_nvm_prog_write() {
// Leave room for INFO at second word of routine // Leave room for INFO at second word of routine
__asm volatile ("b 0f\n\t" __asm volatile ("b 0f\n\t"
".align 2\n\t" ".align 2\n\t"
".word 0\n\t" ".word 0\n\t"
".word 0\n\t" ".word 0\n\t"
".word 0\n\t" ".word 0\n\t"
".word 0\n\t" ".word 0\n\t"
".word 0\n\t" ".word 0\n\t"
"0:"); "0:");
auto& nvm = Nvm (Info.nvm); auto& nvm = Nvm (Info.nvm);
if (!unlock (nvm)) if (!unlock(nvm))
goto quit; goto quit;
nvm.sr = STM32Lx_NVM_SR_ERR_M; // Clear errors nvm.sr = STM32Lx_NVM_SR_ERR_M; // Clear errors
while (Info.size > 0) { while (Info.size > 0) {
// Either we're not half-page aligned or we have less than a half // Either we're not half-page aligned or we have less
// page to write // than a half page to write
if (Info.size < Info.page_size/2 if (Info.size < Info.page_size/2
|| (reinterpret_cast<uint32_t> (Info.destination) || (reinterpret_cast<uint32_t> (Info.destination)
& (Info.page_size/2 - 1))) { & (Info.page_size/2 - 1))) {
nvm.pecr = (Info.options & OPT_STM32L1) ? 0 nvm.pecr = (Info.options & OPT_STM32L1) ? 0
: STM32Lx_NVM_PECR_PROG; // Word programming : STM32Lx_NVM_PECR_PROG; // Word programming
size_t c = Info.page_size/2 size_t c = Info.page_size/2
- (reinterpret_cast<uint32_t> (Info.destination) - (reinterpret_cast<uint32_t> (Info.destination)
& (Info.page_size/2 - 1)); & (Info.page_size/2 - 1));
if (c > Info.size) if (c > Info.size)
c = Info.size; c = Info.size;
Info.size -= c; Info.size -= c;
c /= 4; c /= 4;
while (c--) { while (c--) {
uint32_t v = *Info.source++; uint32_t v = *Info.source++;
*Info.destination++ = v; *Info.destination++ = v;
if (nvm.sr & STM32Lx_NVM_SR_ERR_M) if (nvm.sr & STM32Lx_NVM_SR_ERR_M)
goto quit; goto quit;
} }
} }
// Or we are writing a half-page(s) // Or we are writing a half-page(s)
else { else {
nvm.pecr = STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_FPRG; // Half-page prg nvm.pecr = STM32Lx_NVM_PECR_PROG
size_t c = Info.size & ~(Info.page_size/2 - 1); | STM32Lx_NVM_PECR_FPRG; // Half-page prg
Info.size -= c; size_t c = Info.size & ~(Info.page_size/2 - 1);
c /= 4; Info.size -= c;
while (c--) { c /= 4;
uint32_t v = *Info.source++; while (c--) {
*Info.destination++ = v; uint32_t v = *Info.source++;
} *Info.destination++ = v;
if (nvm.sr & STM32Lx_NVM_SR_ERR_M) }
goto quit; if (nvm.sr & STM32Lx_NVM_SR_ERR_M)
} goto quit;
} }
}
quit: quit:
lock (nvm); lock(nvm);
__asm volatile ("bkpt"); __asm volatile ("bkpt");
} }
/* /*
Local Variables: Local Variables:
compile-command: "/opt/arm/arm-none-eabi-g++ -mcpu=cortex-m0plus -g -c -std=c++11 -mthumb -o stm32l05x-nvm-prog-write.o -Os -Wa,-ahndl=stm32l05x-nvm-prog-write.lst stm32l05x-nvm-prog-write.cc ; /opt/arm/arm-none-eabi-objdump -S stm32l05x-nvm-prog-write.o | ./code-to-array.pl > stm32l05x-nvm-prog-write.stub" compile-command: "/opt/arm/arm-none-eabi-g++ -mcpu=cortex-m0plus -g -c -std=c++11 -mthumb -o stm32l05x-nvm-prog-write.o -Os -Wa,-ahndl=stm32l05x-nvm-prog-write.lst stm32l05x-nvm-prog-write.cc ; /opt/arm/arm-none-eabi-objdump -d -z stm32l05x-nvm-prog-write.o | ./dump-to-array.sh > stm32l05x-nvm-prog-write.stub"
End: End:
*/ */

View File

@ -1,201 +1,99 @@
// [0x0/2] = 0xe00a,
// stm32l05x-nvm-prog-write.o: file format elf32-littlearm [0x2/2] = 0x46c0,
// [0x4/2] = 0x0000, 0x0000,
// [0x8/2] = 0x0000, 0x0000,
// Disassembly of section .text: [0xc/2] = 0x0000, 0x0000,
// [0x10/2] = 0x0000, 0x0000,
// 00000000 <stm32l05x_nvm_prog_write>: [0x14/2] = 0x0000, 0x0000,
// ".word 0\n\t" [0x18/2] = 0x2201,
// ".word 0\n\t" [0x1a/2] = 0x4b2a,
// ".word 0\n\t" [0x1c/2] = 0x68d9,
// ".word 0\n\t" [0x1e/2] = 0x604a,
// ".word 0\n\t" [0x20/2] = 0x4a29,
// "0:"); [0x22/2] = 0x60ca,
[0x0/2] = 0xe00a, // 0: e00a b.n 18 <stm32l05x_nvm_prog_write+0x18> [0x24/2] = 0x4a29,
[0x2/2] = 0x46c0, // 2: 46c0 nop ; (mov r8, r8) [0x26/2] = 0x60ca,
// ... [0x28/2] = 0x4a29,
// #define Nvm(nvm) (*reinterpret_cast<STM32::NVM*>(nvm)) [0x2a/2] = 0x610a,
// #define Info (*reinterpret_cast<stm32lx_nvm_stub_info*>(STM32Lx_STUB_INFO_PHYS)) [0x2c/2] = 0x4a29,
// [0x2e/2] = 0x610a,
// namespace { [0x30/2] = 0x684a,
// inline __attribute((always_inline)) bool unlock (STM32::NVM& nvm) { [0x32/2] = 0x0792,
// nvm.pecr = STM32Lx_NVM_PECR_PELOCK; // Lock to guarantee unlock [0x34/2] = 0xd502,
[0x18/2] = 0x2201, // 18: 2201 movs r2, #1 [0x36/2] = 0x2301,
// [0x38/2] = 0x604b,
// auto& nvm = Nvm (Info.nvm); [0x3a/2] = 0xbe00,
[0x1a/2] = 0x4b2a, // 1a: 4b2a ldr r3, [pc, #168] ; (c4 <stm32l05x_nvm_prog_write+0xc4>) [0x3c/2] = 0x4826,
[0x1c/2] = 0x68d9, // 1c: 68d9 ldr r1, [r3, #12] [0x3e/2] = 0x6188,
[0x1e/2] = 0x604a, // 1e: 604a str r2, [r1, #4] [0x40/2] = 0x685d,
// nvm.pkeyr = STM32::NVM::PKEY1; [0x42/2] = 0x4e20,
[0x20/2] = 0x4a29, // 20: 4a29 ldr r2, [pc, #164] ; (c8 <stm32l05x_nvm_prog_write+0xc8>) [0x44/2] = 0x2d00,
[0x22/2] = 0x60ca, // 22: 60ca str r2, [r1, #12] [0x46/2] = 0xddf6,
// nvm.pkeyr = STM32::NVM::PKEY2; [0x48/2] = 0x8a32,
[0x24/2] = 0x4a29, // 24: 4a29 ldr r2, [pc, #164] ; (cc <stm32l05x_nvm_prog_write+0xcc>) [0x4a/2] = 0x0852,
[0x26/2] = 0x60ca, // 26: 60ca str r2, [r1, #12] [0x4c/2] = 0x1e54,
// nvm.prgkeyr = STM32::NVM::PRGKEY1; [0x4e/2] = 0x4295,
[0x28/2] = 0x4a29, // 28: 4a29 ldr r2, [pc, #164] ; (d0 <stm32l05x_nvm_prog_write+0xd0>) [0x50/2] = 0xdb02,
[0x2a/2] = 0x610a, // 2a: 610a str r2, [r1, #16] [0x52/2] = 0x6837,
// nvm.prgkeyr = STM32::NVM::PRGKEY2; [0x54/2] = 0x4227,
[0x2c/2] = 0x4a29, // 2c: 4a29 ldr r2, [pc, #164] ; (d4 <stm32l05x_nvm_prog_write+0xd4>) [0x56/2] = 0xd01d,
[0x2e/2] = 0x610a, // 2e: 610a str r2, [r1, #16] [0x58/2] = 0x2602,
// return !(nvm.pecr & STM32Lx_NVM_PECR_PRGLOCK); [0x5a/2] = 0x8a5f,
[0x30/2] = 0x684a, // 30: 684a ldr r2, [r1, #4] [0x5c/2] = 0x4037,
// [0x5e/2] = 0x427e,
// if (!unlock (nvm)) [0x60/2] = 0x417e,
[0x32/2] = 0x0792, // 32: 0792 lsls r2, r2, #30 [0x62/2] = 0x00f6,
[0x34/2] = 0xd502, // 34: d502 bpl.n 3c <stm32l05x_nvm_prog_write+0x3c> [0x64/2] = 0x604e,
// } [0x66/2] = 0x681e,
// inline __attribute((always_inline)) void lock (STM32::NVM& nvm) { [0x68/2] = 0x4034,
// nvm.pecr = STM32Lx_NVM_PECR_PELOCK; } [0x6a/2] = 0x1b12,
[0x36/2] = 0x2301, // 36: 2301 movs r3, #1 [0x6c/2] = 0x42aa,
[0x38/2] = 0x604b, // 38: 604b str r3, [r1, #4] [0x6e/2] = 0xd900,
// } [0x70/2] = 0x1c2a,
// } [0x72/2] = 0x1aad,
// [0x74/2] = 0x605d,
// quit: [0x76/2] = 0x0892,
// lock (nvm); [0x78/2] = 0x3a01,
// __asm volatile ("bkpt"); [0x7a/2] = 0xd3e1,
[0x3a/2] = 0xbe00, // 3a: be00 bkpt 0x0000 [0x7c/2] = 0x689c,
// auto& nvm = Nvm (Info.nvm); [0x7e/2] = 0x1d25,
// [0x80/2] = 0x609d,
// if (!unlock (nvm)) [0x82/2] = 0x6825,
// goto quit; [0x84/2] = 0x681c,
// [0x86/2] = 0x1d26,
// nvm.sr = STM32Lx_NVM_SR_ERR_M; // Clear errors [0x88/2] = 0x601e,
[0x3c/2] = 0x4826, // 3c: 4826 ldr r0, [pc, #152] ; (d8 <stm32l05x_nvm_prog_write+0xd8>) [0x8a/2] = 0x6025,
[0x3e/2] = 0x6188, // 3e: 6188 str r0, [r1, #24] [0x8c/2] = 0x698c,
// [0x8e/2] = 0x4204,
// while (Info.size > 0) { [0x90/2] = 0xd0f2,
[0x40/2] = 0x685d, // 40: 685d ldr r5, [r3, #4] [0x92/2] = 0xe7d0,
[0x42/2] = 0x4e20, // 42: 4e20 ldr r6, [pc, #128] ; (c4 <stm32l05x_nvm_prog_write+0xc4>) [0x94/2] = 0x2481,
[0x44/2] = 0x2d00, // 44: 2d00 cmp r5, #0 [0x96/2] = 0x4252,
[0x46/2] = 0xddf6, // 46: ddf6 ble.n 36 <stm32l05x_nvm_prog_write+0x36> [0x98/2] = 0x402a,
// [0x9a/2] = 0x1aad,
// // Either we're not half-page aligned or we have less than a half [0x9c/2] = 0x00e4,
// // page to write [0x9e/2] = 0x604c,
// if (Info.size < Info.page_size/2 [0xa0/2] = 0x0892,
[0x48/2] = 0x8a32, // 48: 8a32 ldrh r2, [r6, #16] [0xa2/2] = 0x6075,
[0x4a/2] = 0x0852, // 4a: 0852 lsrs r2, r2, #1 [0xa4/2] = 0x3a01,
[0x4c/2] = 0x1e54, // 4c: 1e54 subs r4, r2, #1 [0xa6/2] = 0xd308,
[0x4e/2] = 0x4295, // 4e: 4295 cmp r5, r2 [0xa8/2] = 0x689c,
[0x50/2] = 0xdb02, // 50: db02 blt.n 58 <stm32l05x_nvm_prog_write+0x58> [0xaa/2] = 0x1d25,
// || (reinterpret_cast<uint32_t> (Info.destination) [0xac/2] = 0x609d,
[0x52/2] = 0x6837, // 52: 6837 ldr r7, [r6, #0] [0xae/2] = 0x6825,
[0x54/2] = 0x4227, // 54: 4227 tst r7, r4 [0xb0/2] = 0x681c,
[0x56/2] = 0xd01d, // 56: d01d beq.n 94 <stm32l05x_nvm_prog_write+0x94> [0xb2/2] = 0x1d26,
// & (Info.page_size/2 - 1))) { [0xb4/2] = 0x601e,
// nvm.pecr = (Info.options & OPT_STM32L1) ? 0 [0xb6/2] = 0x6025,
// : STM32Lx_NVM_PECR_PROG; // Word programming [0xb8/2] = 0xe7f4,
[0x58/2] = 0x2602, // 58: 2602 movs r6, #2 [0xba/2] = 0x698a,
// // Either we're not half-page aligned or we have less than a half [0xbc/2] = 0x4202,
// // page to write [0xbe/2] = 0xd0bf,
// if (Info.size < Info.page_size/2 [0xc0/2] = 0xe7b9,
// || (reinterpret_cast<uint32_t> (Info.destination) [0xc2/2] = 0x46c0,
// & (Info.page_size/2 - 1))) { [0xc4/2] = 0x0004, 0x2000,
// nvm.pecr = (Info.options & OPT_STM32L1) ? 0 [0xc8/2] = 0xcdef, 0x89ab,
[0x5a/2] = 0x8a5f, // 5a: 8a5f ldrh r7, [r3, #18] [0xcc/2] = 0x0405, 0x0203,
// : STM32Lx_NVM_PECR_PROG; // Word programming [0xd0/2] = 0xaebf, 0x8c9d,
[0x5c/2] = 0x4037, // 5c: 4037 ands r7, r6 [0xd4/2] = 0x1516, 0x1314,
[0x5e/2] = 0x427e, // 5e: 427e negs r6, r7 [0xd8/2] = 0x0700, 0x0001,
[0x60/2] = 0x417e, // 60: 417e adcs r6, r7
[0x62/2] = 0x00f6, // 62: 00f6 lsls r6, r6, #3
[0x64/2] = 0x604e, // 64: 604e str r6, [r1, #4]
// size_t c = Info.page_size/2
// - (reinterpret_cast<uint32_t> (Info.destination)
// & (Info.page_size/2 - 1));
[0x66/2] = 0x681e, // 66: 681e ldr r6, [r3, #0]
[0x68/2] = 0x4034, // 68: 4034 ands r4, r6
[0x6a/2] = 0x1b12, // 6a: 1b12 subs r2, r2, r4
[0x6c/2] = 0x42aa, // 6c: 42aa cmp r2, r5
[0x6e/2] = 0xd900, // 6e: d900 bls.n 72 <stm32l05x_nvm_prog_write+0x72>
[0x70/2] = 0x1c2a, // 70: 1c2a adds r2, r5, #0
// if (c > Info.size)
// c = Info.size;
// Info.size -= c;
[0x72/2] = 0x1aad, // 72: 1aad subs r5, r5, r2
[0x74/2] = 0x605d, // 74: 605d str r5, [r3, #4]
// c /= 4;
[0x76/2] = 0x0892, // 76: 0892 lsrs r2, r2, #2
// while (c--) {
[0x78/2] = 0x3a01, // 78: 3a01 subs r2, #1
[0x7a/2] = 0xd3e1, // 7a: d3e1 bcc.n 40 <stm32l05x_nvm_prog_write+0x40>
// uint32_t v = *Info.source++;
[0x7c/2] = 0x689c, // 7c: 689c ldr r4, [r3, #8]
[0x7e/2] = 0x1d25, // 7e: 1d25 adds r5, r4, #4
[0x80/2] = 0x609d, // 80: 609d str r5, [r3, #8]
[0x82/2] = 0x6825, // 82: 6825 ldr r5, [r4, #0]
// *Info.destination++ = v;
[0x84/2] = 0x681c, // 84: 681c ldr r4, [r3, #0]
[0x86/2] = 0x1d26, // 86: 1d26 adds r6, r4, #4
[0x88/2] = 0x601e, // 88: 601e str r6, [r3, #0]
[0x8a/2] = 0x6025, // 8a: 6025 str r5, [r4, #0]
// if (nvm.sr & STM32Lx_NVM_SR_ERR_M)
[0x8c/2] = 0x698c, // 8c: 698c ldr r4, [r1, #24]
[0x8e/2] = 0x4204, // 8e: 4204 tst r4, r0
[0x90/2] = 0xd0f2, // 90: d0f2 beq.n 78 <stm32l05x_nvm_prog_write+0x78>
[0x92/2] = 0xe7d0, // 92: e7d0 b.n 36 <stm32l05x_nvm_prog_write+0x36>
// goto quit;
// }
// }
// // Or we are writing a half-page(s)
// else {
// nvm.pecr = STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_FPRG; // Half-page prg
[0x94/2] = 0x2481, // 94: 2481 movs r4, #129 ; 0x81
// size_t c = Info.size & ~(Info.page_size/2 - 1);
[0x96/2] = 0x4252, // 96: 4252 negs r2, r2
[0x98/2] = 0x402a, // 98: 402a ands r2, r5
// Info.size -= c;
[0x9a/2] = 0x1aad, // 9a: 1aad subs r5, r5, r2
// goto quit;
// }
// }
// // Or we are writing a half-page(s)
// else {
// nvm.pecr = STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_FPRG; // Half-page prg
[0x9c/2] = 0x00e4, // 9c: 00e4 lsls r4, r4, #3
[0x9e/2] = 0x604c, // 9e: 604c str r4, [r1, #4]
// size_t c = Info.size & ~(Info.page_size/2 - 1);
// Info.size -= c;
// c /= 4;
[0xa0/2] = 0x0892, // a0: 0892 lsrs r2, r2, #2
// }
// // Or we are writing a half-page(s)
// else {
// nvm.pecr = STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_FPRG; // Half-page prg
// size_t c = Info.size & ~(Info.page_size/2 - 1);
// Info.size -= c;
[0xa2/2] = 0x6075, // a2: 6075 str r5, [r6, #4]
// c /= 4;
// while (c--) {
[0xa4/2] = 0x3a01, // a4: 3a01 subs r2, #1
[0xa6/2] = 0xd308, // a6: d308 bcc.n ba <stm32l05x_nvm_prog_write+0xba>
// uint32_t v = *Info.source++;
[0xa8/2] = 0x689c, // a8: 689c ldr r4, [r3, #8]
[0xaa/2] = 0x1d25, // aa: 1d25 adds r5, r4, #4
[0xac/2] = 0x609d, // ac: 609d str r5, [r3, #8]
[0xae/2] = 0x6825, // ae: 6825 ldr r5, [r4, #0]
// *Info.destination++ = v;
[0xb0/2] = 0x681c, // b0: 681c ldr r4, [r3, #0]
[0xb2/2] = 0x1d26, // b2: 1d26 adds r6, r4, #4
[0xb4/2] = 0x601e, // b4: 601e str r6, [r3, #0]
[0xb6/2] = 0x6025, // b6: 6025 str r5, [r4, #0]
[0xb8/2] = 0xe7f4, // b8: e7f4 b.n a4 <stm32l05x_nvm_prog_write+0xa4>
// }
// if (nvm.sr & STM32Lx_NVM_SR_ERR_M)
[0xba/2] = 0x698a, // ba: 698a ldr r2, [r1, #24]
[0xbc/2] = 0x4202, // bc: 4202 tst r2, r0
[0xbe/2] = 0xd0bf, // be: d0bf beq.n 40 <stm32l05x_nvm_prog_write+0x40>
[0xc0/2] = 0xe7b9, // c0: e7b9 b.n 36 <stm32l05x_nvm_prog_write+0x36>
[0xc2/2] = 0x46c0, // c2: 46c0 nop ; (mov r8, r8)
[0xc4/2] = 0x0004, // c4: 20000004 .word 0x20000004
[0xc4/2 + 1] = 0x2000,
[0xc8/2] = 0xcdef, // c8: 89abcdef .word 0x89abcdef
[0xc8/2 + 1] = 0x89ab,
[0xcc/2] = 0x0405, // cc: 02030405 .word 0x02030405
[0xcc/2 + 1] = 0x0203,
[0xd0/2] = 0xaebf, // d0: 8c9daebf .word 0x8c9daebf
[0xd0/2 + 1] = 0x8c9d,
[0xd4/2] = 0x1516, // d4: 13141516 .word 0x13141516
[0xd4/2 + 1] = 0x1314,
[0xd8/2] = 0x0700, // d8: 00010700 .word 0x00010700
[0xd8/2 + 1] = 0x0001,

View File

@ -31,108 +31,108 @@
/* ----- Types */ /* ----- Types */
enum { enum {
STM32Lx_STUB_PHYS = 0x20000000ul, STM32Lx_STUB_PHYS = 0x20000000ul,
STM32Lx_STUB_INFO_PHYS = 0x20000004ul, STM32Lx_STUB_INFO_PHYS = 0x20000004ul,
STM32Lx_STUB_DATA_PHYS = (0x20000000ul + 1024), STM32Lx_STUB_DATA_PHYS = (0x20000000ul + 1024),
STM32Lx_STUB_DATA_MAX = 2048, STM32Lx_STUB_DATA_MAX = 2048,
STM32Lx_NVM_OPT_PHYS = 0x1ff80000ul, STM32Lx_NVM_OPT_PHYS = 0x1ff80000ul,
STM32Lx_NVM_EEPROM_PHYS = 0x08080000ul, STM32Lx_NVM_EEPROM_PHYS = 0x08080000ul,
STM32L0_NVM_PHYS = 0x40022000ul, STM32L0_NVM_PHYS = 0x40022000ul,
STM32L0_NVM_PROG_PAGE_SIZE = 128, STM32L0_NVM_PROG_PAGE_SIZE = 128,
STM32L0_NVM_DATA_PAGE_SIZE = 4, STM32L0_NVM_DATA_PAGE_SIZE = 4,
STM32L0_NVM_OPT_SIZE = 12, STM32L0_NVM_OPT_SIZE = 12,
STM32L0_NVM_EEPROM_SIZE = 2*1024, STM32L0_NVM_EEPROM_SIZE = 2*1024,
STM32L1_NVM_PHYS = 0x40023c00ul, STM32L1_NVM_PHYS = 0x40023c00ul,
STM32L1_NVM_PROG_PAGE_SIZE = 256, STM32L1_NVM_PROG_PAGE_SIZE = 256,
STM32L1_NVM_DATA_PAGE_SIZE = 4, STM32L1_NVM_DATA_PAGE_SIZE = 4,
STM32L1_NVM_OPT_SIZE = 32, STM32L1_NVM_OPT_SIZE = 32,
STM32L1_NVM_EEPROM_SIZE = 16*1024, STM32L1_NVM_EEPROM_SIZE = 16*1024,
STM32Lx_NVM_PEKEY1 = 0x89abcdeful, STM32Lx_NVM_PEKEY1 = 0x89abcdeful,
STM32Lx_NVM_PEKEY2 = 0x02030405ul, STM32Lx_NVM_PEKEY2 = 0x02030405ul,
STM32Lx_NVM_PRGKEY1 = 0x8c9daebful, STM32Lx_NVM_PRGKEY1 = 0x8c9daebful,
STM32Lx_NVM_PRGKEY2 = 0x13141516ul, STM32Lx_NVM_PRGKEY2 = 0x13141516ul,
STM32Lx_NVM_OPTKEY1 = 0xfbead9c8ul, STM32Lx_NVM_OPTKEY1 = 0xfbead9c8ul,
STM32Lx_NVM_OPTKEY2 = 0x24252627ul, STM32Lx_NVM_OPTKEY2 = 0x24252627ul,
STM32Lx_NVM_PECR_OBL_LAUNCH = (1<<18), STM32Lx_NVM_PECR_OBL_LAUNCH = (1<<18),
STM32Lx_NVM_PECR_ERRIE = (1<<17), STM32Lx_NVM_PECR_ERRIE = (1<<17),
STM32Lx_NVM_PECR_EOPIE = (1<<16), STM32Lx_NVM_PECR_EOPIE = (1<<16),
STM32Lx_NVM_PECR_FPRG = (1<<10), STM32Lx_NVM_PECR_FPRG = (1<<10),
STM32Lx_NVM_PECR_ERASE = (1<< 9), STM32Lx_NVM_PECR_ERASE = (1<< 9),
STM32Lx_NVM_PECR_FIX = (1<< 8), /* FTDW */ STM32Lx_NVM_PECR_FIX = (1<< 8), /* FTDW */
STM32Lx_NVM_PECR_DATA = (1<< 4), STM32Lx_NVM_PECR_DATA = (1<< 4),
STM32Lx_NVM_PECR_PROG = (1<< 3), STM32Lx_NVM_PECR_PROG = (1<< 3),
STM32Lx_NVM_PECR_OPTLOCK = (1<< 2), STM32Lx_NVM_PECR_OPTLOCK = (1<< 2),
STM32Lx_NVM_PECR_PRGLOCK = (1<< 1), STM32Lx_NVM_PECR_PRGLOCK = (1<< 1),
STM32Lx_NVM_PECR_PELOCK = (1<< 0), STM32Lx_NVM_PECR_PELOCK = (1<< 0),
STM32Lx_NVM_SR_FWWERR = (1<<17), STM32Lx_NVM_SR_FWWERR = (1<<17),
STM32Lx_NVM_SR_NOTZEROERR = (1<<16), STM32Lx_NVM_SR_NOTZEROERR = (1<<16),
STM32Lx_NVM_SR_RDERR = (1<<13), STM32Lx_NVM_SR_RDERR = (1<<13),
STM32Lx_NVM_SR_OPTVER = (1<<11), STM32Lx_NVM_SR_OPTVER = (1<<11),
STM32Lx_NVM_SR_SIZERR = (1<<10), STM32Lx_NVM_SR_SIZERR = (1<<10),
STM32Lx_NVM_SR_PGAERR = (1<<9), STM32Lx_NVM_SR_PGAERR = (1<<9),
STM32Lx_NVM_SR_WRPERR = (1<<8), STM32Lx_NVM_SR_WRPERR = (1<<8),
STM32Lx_NVM_SR_READY = (1<<3), STM32Lx_NVM_SR_READY = (1<<3),
STM32Lx_NVM_SR_HWOFF = (1<<2), STM32Lx_NVM_SR_HWOFF = (1<<2),
STM32Lx_NVM_SR_EOP = (1<<1), STM32Lx_NVM_SR_EOP = (1<<1),
STM32Lx_NVM_SR_BSY = (1<<0), STM32Lx_NVM_SR_BSY = (1<<0),
STM32Lx_NVM_SR_ERR_M = ( STM32Lx_NVM_SR_WRPERR STM32Lx_NVM_SR_ERR_M = ( STM32Lx_NVM_SR_WRPERR
| STM32Lx_NVM_SR_PGAERR | STM32Lx_NVM_SR_PGAERR
| STM32Lx_NVM_SR_SIZERR | STM32Lx_NVM_SR_SIZERR
| STM32Lx_NVM_SR_NOTZEROERR), | STM32Lx_NVM_SR_NOTZEROERR),
STM32L0_NVM_OPTR_BOOT1 = (1<<31), STM32L0_NVM_OPTR_BOOT1 = (1<<31),
STM32L0_NVM_OPTR_WDG_SW = (1<<20), STM32L0_NVM_OPTR_WDG_SW = (1<<20),
STM32L0_NVM_OPTR_WPRMOD = (1<<8), STM32L0_NVM_OPTR_WPRMOD = (1<<8),
STM32L0_NVM_OPTR_RDPROT_S = (0), STM32L0_NVM_OPTR_RDPROT_S = (0),
STM32L0_NVM_OPTR_RDPROT_M = (0xff), STM32L0_NVM_OPTR_RDPROT_M = (0xff),
STM32L0_NVM_OPTR_RDPROT_0 = (0xaa), STM32L0_NVM_OPTR_RDPROT_0 = (0xaa),
STM32L0_NVM_OPTR_RDPROT_2 = (0xcc), STM32L0_NVM_OPTR_RDPROT_2 = (0xcc),
STM32L1_NVM_OPTR_nBFB2 = (1<<23), STM32L1_NVM_OPTR_nBFB2 = (1<<23),
STM32L1_NVM_OPTR_nRST_STDBY = (1<<22), STM32L1_NVM_OPTR_nRST_STDBY = (1<<22),
STM32L1_NVM_OPTR_nRST_STOP = (1<<21), STM32L1_NVM_OPTR_nRST_STOP = (1<<21),
STM32L1_NVM_OPTR_WDG_SW = (1<<20), STM32L1_NVM_OPTR_WDG_SW = (1<<20),
STM32L1_NVM_OPTR_BOR_LEV_S = (16), STM32L1_NVM_OPTR_BOR_LEV_S = (16),
STM32L1_NVM_OPTR_BOR_LEV_M = (0xf), STM32L1_NVM_OPTR_BOR_LEV_M = (0xf),
STM32L1_NVM_OPTR_SPRMOD = (1<<8), STM32L1_NVM_OPTR_SPRMOD = (1<<8),
STM32L1_NVM_OPTR_RDPROT_S = (0), STM32L1_NVM_OPTR_RDPROT_S = (0),
STM32L1_NVM_OPTR_RDPROT_M = (0xff), STM32L1_NVM_OPTR_RDPROT_M = (0xff),
STM32L1_NVM_OPTR_RDPROT_0 = (0xaa), STM32L1_NVM_OPTR_RDPROT_0 = (0xaa),
STM32L1_NVM_OPTR_RDPROT_2 = (0xcc), STM32L1_NVM_OPTR_RDPROT_2 = (0xcc),
}; };
#if defined (__cplusplus) #if defined (__cplusplus)
namespace STM32 { namespace STM32 {
struct NVM { struct NVM {
volatile uint32_t acr; volatile uint32_t acr;
volatile uint32_t pecr; volatile uint32_t pecr;
volatile uint32_t pdkeyr; volatile uint32_t pdkeyr;
volatile uint32_t pkeyr; volatile uint32_t pkeyr;
volatile uint32_t prgkeyr; volatile uint32_t prgkeyr;
volatile uint32_t optkeyr; volatile uint32_t optkeyr;
volatile uint32_t sr; volatile uint32_t sr;
volatile uint32_t optr; volatile uint32_t optr;
volatile uint32_t wrprot; volatile uint32_t wrprot;
static constexpr uint32_t PKEY1 = 0x89abcdef; static constexpr uint32_t PKEY1 = 0x89abcdef;
static constexpr uint32_t PKEY2 = 0x02030405; static constexpr uint32_t PKEY2 = 0x02030405;
static constexpr uint32_t PRGKEY1 = 0x8c9daebf; static constexpr uint32_t PRGKEY1 = 0x8c9daebf;
static constexpr uint32_t PRGKEY2 = 0x13141516; static constexpr uint32_t PRGKEY2 = 0x13141516;
static constexpr uint32_t OPTKEY1 = 0xfbead9c8; static constexpr uint32_t OPTKEY1 = 0xfbead9c8;
static constexpr uint32_t OPTKEY2 = 0x24252627; static constexpr uint32_t OPTKEY2 = 0x24252627;
static constexpr uint32_t PDKEY1 = 0x04152637; static constexpr uint32_t PDKEY1 = 0x04152637;
static constexpr uint32_t PDKEY2 = 0xfafbfcfd; static constexpr uint32_t PDKEY2 = 0xfafbfcfd;
}; };
static_assert(sizeof (NVM) == 9*4, "NVM size error"); static_assert(sizeof (NVM) == 9*4, "NVM size error");
} }
using stm32lx_stub_pointer_t = uint32_t*; using stm32lx_stub_pointer_t = uint32_t*;
@ -140,16 +140,18 @@ using stm32lx_stub_pointer_t = uint32_t*;
#define Info (*reinterpret_cast<stm32lx_nvm_stub_info*>(STM32Lx_STUB_INFO_PHYS)) #define Info (*reinterpret_cast<stm32lx_nvm_stub_info*>(STM32Lx_STUB_INFO_PHYS))
namespace { namespace {
inline __attribute((always_inline)) bool unlock (STM32::NVM& nvm) { inline __attribute((always_inline)) bool unlock (STM32::NVM& nvm) {
nvm.pecr = STM32Lx_NVM_PECR_PELOCK; // Lock to guarantee unlock // Lock guarantees unlock
nvm.pkeyr = STM32::NVM::PKEY1; nvm.pecr = STM32Lx_NVM_PECR_PELOCK;
nvm.pkeyr = STM32::NVM::PKEY2;
nvm.prgkeyr = STM32::NVM::PRGKEY1; nvm.pkeyr = STM32::NVM::PKEY1;
nvm.prgkeyr = STM32::NVM::PRGKEY2; nvm.pkeyr = STM32::NVM::PKEY2;
return !(nvm.pecr & STM32Lx_NVM_PECR_PRGLOCK); nvm.prgkeyr = STM32::NVM::PRGKEY1;
} nvm.prgkeyr = STM32::NVM::PRGKEY2;
inline __attribute((always_inline)) void lock (STM32::NVM& nvm) { return !(nvm.pecr & STM32Lx_NVM_PECR_PRGLOCK);
nvm.pecr = STM32Lx_NVM_PECR_PELOCK; } }
inline __attribute((always_inline)) void lock (STM32::NVM& nvm) {
nvm.pecr = STM32Lx_NVM_PECR_PELOCK; }
} }
@ -158,15 +160,15 @@ namespace {
typedef uint32_t stm32lx_stub_pointer_t; typedef uint32_t stm32lx_stub_pointer_t;
struct stm32lx_nvm { struct stm32lx_nvm {
volatile uint32_t acr; volatile uint32_t acr;
volatile uint32_t pecr; volatile uint32_t pecr;
volatile uint32_t pdkeyr; volatile uint32_t pdkeyr;
volatile uint32_t pekeyr; volatile uint32_t pekeyr;
volatile uint32_t prgkeyr; volatile uint32_t prgkeyr;
volatile uint32_t optkeyr; volatile uint32_t optkeyr;
volatile uint32_t sr; volatile uint32_t sr;
volatile uint32_t optr; /* or obr */ volatile uint32_t optr; /* or obr */
volatile uint32_t wrprot; /* or wprot1 */ volatile uint32_t wrprot; /* or wprot1 */
}; };
#define STM32Lx_NVM(p) (*(struct stm32lx_nvm*) (p)) #define STM32Lx_NVM(p) (*(struct stm32lx_nvm*) (p))
@ -180,16 +182,16 @@ struct stm32lx_nvm {
#endif #endif
enum { enum {
OPT_STM32L1 = 1<<1, OPT_STM32L1 = 1<<1,
}; };
struct stm32lx_nvm_stub_info { struct stm32lx_nvm_stub_info {
stm32lx_stub_pointer_t destination; stm32lx_stub_pointer_t destination;
int32_t size; int32_t size;
stm32lx_stub_pointer_t source; stm32lx_stub_pointer_t source;
uint32_t nvm; uint32_t nvm;
uint16_t page_size; uint16_t page_size;
uint16_t options; uint16_t options;
} __attribute__((packed)); } __attribute__((packed));
/* ----- Globals */ /* ----- Globals */

File diff suppressed because it is too large Load Diff