+ /* flashloaders/stm32f0.s -- thumb1 only, same sequence as for STM32VL, bank ignored */
+ static const uint8_t loader_code_stm32f0[] = {
+#if 1
+ /*
+ * These two NOPs here are a safety precaution, added by Pekka Nikander
+ * while debugging the STM32F05x support. They may not be needed, but
+ * there were strange problems with simpler programs, like a program
+ * that had just a breakpoint or a program that first moved zero to register r2
+ * and then had a breakpoint. So, it appears safest to have these two nops.
+ *
+ * Feel free to remove them, if you dare, but then please do test the result
+ * rigorously. Also, if you remove these, it may be a good idea first to
+ * #if 0 them out, with a comment when these were taken out, and to remove
+ * these only a few months later... But YMMV.
+ */
+ 0x00, 0x30, // nop /* add r0,#0 */
+ 0x00, 0x30, // nop /* add r0,#0 */
+#endif
+ 0x0A, 0x4C, // ldr r4, STM32_FLASH_BASE
+ 0x01, 0x25, // mov r5, #1 /* FLASH_CR_PG, FLASH_SR_BUSY */
+ 0x04, 0x26, // mov r6, #4 /* PGERR */
+ // write_half_word:
+ 0x23, 0x69, // ldr r3, [r4, #16] /* FLASH->CR */
+ 0x2B, 0x43, // orr r3, r5
+ 0x23, 0x61, // str r3, [r4, #16] /* FLASH->CR |= FLASH_CR_PG */
+ 0x03, 0x88, // ldrh r3, [r0] /* r3 = *sram */
+ 0x0B, 0x80, // strh r3, [r1] /* *flash = r3 */
+ // busy:
+ 0xE3, 0x68, // ldr r3, [r4, #12] /* FLASH->SR */
+ 0x2B, 0x42, // tst r3, r5 /* FLASH_SR_BUSY */
+ 0xFC, 0xD0, // beq busy
+
+ 0x33, 0x42, // tst r3, r6 /* PGERR */
+ 0x04, 0xD1, // bne exit
+
+ 0x02, 0x30, // add r0, r0, #2 /* sram += 2 */
+ 0x02, 0x31, // add r1, r1, #2 /* flash += 2 */
+ 0x01, 0x3A, // sub r2, r2, #0x01 /* count-- */
+ 0x00, 0x2A, // cmp r2, #0
+ 0xF0, 0xD1, // bne write_half_word
+ // exit:
+ 0x23, 0x69, // ldr r3, [r4, #16] /* FLASH->CR */
+ 0xAB, 0x43, // bic r3, r5
+ 0x23, 0x61, // str r3, [r4, #16] /* FLASH->CR &= ~FLASH_CR_PG */
+ 0x00, 0xBE, // bkpt #0x00
+ 0x00, 0x20, 0x02, 0x40, /* STM32_FLASH_BASE: .word 0x40022000 */
+ };
+
+ static const uint8_t loader_code_stm32l[] = {
+
+ /* openocd.git/contrib/loaders/flash/stm32lx.S
+ r0, input, dest addr
+ r1, input, source addr
+ r2, input, word count
+ r3, output, word count
+ */
+
+ 0x00, 0x23,
+ 0x04, 0xe0,
+
+ 0x51, 0xf8, 0x04, 0xcb,
+ 0x40, 0xf8, 0x04, 0xcb,
+ 0x01, 0x33,
+
+ 0x93, 0x42,
+ 0xf8, 0xd3,
+ 0x00, 0xbe
+ };
+
+ static const uint8_t loader_code_stm32f4[] = {
+ // flashloaders/stm32f4.s
+
+ 0x07, 0x4b,
+
+ 0x62, 0xb1,
+ 0x04, 0x68,
+ 0x0c, 0x60,
+
+ 0xdc, 0x89,
+ 0x14, 0xf0, 0x01, 0x0f,
+ 0xfb, 0xd1,
+ 0x00, 0xf1, 0x04, 0x00,
+ 0x01, 0xf1, 0x04, 0x01,
+ 0xa2, 0xf1, 0x01, 0x02,
+ 0xf1, 0xe7,
+
+ 0x00, 0xbe,
+
+ 0x00, 0x3c, 0x02, 0x40,
+ };
+
+ const uint8_t* loader_code;
+ size_t loader_size;
+
+ if (sl->chip_id == STM32_CHIPID_L1_MEDIUM) { /* stm32l */
+ loader_code = loader_code_stm32l;
+ loader_size = sizeof(loader_code_stm32l);
+ } else if (sl->core_id == STM32VL_CORE_ID || sl->chip_id == STM32_CHIPID_F3) {
+ loader_code = loader_code_stm32vl;
+ loader_size = sizeof(loader_code_stm32vl);
+ } else if (sl->chip_id == STM32_CHIPID_F2 || sl->chip_id == STM32_CHIPID_F4) {
+ loader_code = loader_code_stm32f4;
+ loader_size = sizeof(loader_code_stm32f4);
+ } else if (sl->chip_id == STM32_CHIPID_F0) {
+ loader_code = loader_code_stm32f0;
+ loader_size = sizeof(loader_code_stm32f0);
+ } else {
+ ELOG("unknown coreid, not sure what flash loader to use, aborting!: %x\n", sl->core_id);
+ return -1;
+ }
+
+ memcpy(sl->q_buf, loader_code, loader_size);
+ stlink_write_mem32(sl, sl->sram_base, loader_size);