aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--flashstub/Makefile41
-rw-r--r--flashstub/lmi.stub1
-rw-r--r--flashstub/nrf51.stub1
-rw-r--r--flashstub/stm32.s43
-rw-r--r--flashstub/stm32f1.c40
-rw-r--r--flashstub/stm32f1.stub1
-rw-r--r--flashstub/stm32f4.c40
-rw-r--r--flashstub/stm32f4.s44
-rw-r--r--flashstub/stm32f4.stub1
-rw-r--r--flashstub/stub.h30
-rw-r--r--src/Makefile9
-rw-r--r--src/adiv5.c344
-rw-r--r--src/adiv5_jtagdp.c47
-rw-r--r--src/adiv5_swdp.c48
-rw-r--r--src/arm7tdmi.c295
-rw-r--r--src/command.c36
-rw-r--r--src/cortexm.c399
-rw-r--r--src/crc32.c13
-rw-r--r--src/exception.c39
-rw-r--r--src/gdb_main.c52
-rw-r--r--src/gdb_packet.c3
-rw-r--r--src/include/adiv5.h71
-rw-r--r--src/include/cortexm.h8
-rw-r--r--src/include/crc32.h2
-rw-r--r--src/include/exception.h74
-rw-r--r--src/include/general.h4
-rw-r--r--src/include/target.h154
-rw-r--r--src/jtag_scan.c3
-rw-r--r--src/kinetis.c27
-rw-r--r--src/lmi.c137
-rw-r--r--src/lpc11xx.c78
-rw-r--r--src/lpc43xx.c137
-rw-r--r--src/main.c16
-rw-r--r--src/nrf51.c146
-rw-r--r--src/platforms/f4discovery/platform.h14
-rw-r--r--src/platforms/launchpad-icdi/platform.c15
-rw-r--r--src/platforms/launchpad-icdi/platform.h15
-rw-r--r--src/platforms/libftdi/platform.c19
-rw-r--r--src/platforms/libftdi/platform.h3
-rw-r--r--src/platforms/native/platform.c2
-rw-r--r--src/platforms/native/platform.h16
-rw-r--r--src/platforms/stlink/Makefile.inc1
-rw-r--r--src/platforms/stlink/platform.c2
-rw-r--r--src/platforms/stlink/platform.h14
-rw-r--r--src/platforms/stm32/timing.c1
-rw-r--r--src/platforms/swlink/Makefile.inc1
-rw-r--r--src/platforms/swlink/platform.c2
-rw-r--r--src/platforms/swlink/platform.h14
-rw-r--r--src/sam3x.c170
-rw-r--r--src/samd.c407
-rw-r--r--src/stm32f1.c221
-rw-r--r--src/stm32f4.c154
-rw-r--r--src/stm32l0.c374
-rw-r--r--src/stm32l1.c231
54 files changed, 1648 insertions, 2412 deletions
diff --git a/flashstub/Makefile b/flashstub/Makefile
new file mode 100644
index 0000000..c955ca8
--- /dev/null
+++ b/flashstub/Makefile
@@ -0,0 +1,41 @@
+CROSS_COMPILE ?= arm-none-eabi-
+AS = $(CROSS_COMPILE)as
+CC = $(CROSS_COMPILE)gcc
+OBJCOPY = $(CROSS_COMPILE)objcopy
+HEXDUMP = hexdump
+
+ifneq ($(V), 1)
+Q = @
+endif
+
+CFLAGS=-Os -std=gnu99 -mcpu=cortex-m3 -mthumb -I../libopencm3/include
+ASFLAGS=-mcpu=cortex-m3 -mthumb
+
+all: lmi.stub stm32f4.stub nrf51.stub stm32f1.stub
+
+stm32f1.o: stm32f1.c
+ $(Q)echo " CC $<"
+ $(Q)$(CC) $(CFLAGS) -DSTM32F1 -o $@ -c $<
+
+stm32f4.o: stm32f4.c
+ $(Q)echo " CC $<"
+ $(Q)$(CC) $(CFLAGS) -DSTM32F4 -o $@ -c $<
+
+%.o: %.s
+ $(Q)echo " AS $<"
+ $(Q)$(AS) $(ASFLAGS) -o $@ $<
+
+%.bin: %.o
+ $(Q)echo " OBJCOPY $@"
+ $(Q)$(OBJCOPY) -O binary $< $@
+
+%.stub: %.bin
+ $(Q)echo " HEXDUMP $@"
+ $(Q)$(HEXDUMP) -v -e '/2 "0x%04X, "' $< > $@
+
+.PHONY: clean
+
+clean:
+ $(Q)echo " CLEAN"
+ -$(Q)rm -f *.o *.bin *.stub
+
diff --git a/flashstub/lmi.stub b/flashstub/lmi.stub
new file mode 100644
index 0000000..afaf939
--- /dev/null
+++ b/flashstub/lmi.stub
@@ -0,0 +1 @@
+0x4809, 0x490B, 0x467A, 0x3230, 0x4B0A, 0x4D08, 0xB15B, 0x6001, 0x6814, 0x6044, 0x6085, 0x6884, 0x2601, 0x4234, 0xD1FB, 0x3B01, 0x3104, 0x3204, 0xE7F2, 0xBE00, 0xD000, 0x400F, 0x0001, 0xA442, 0x0000, 0x0000, 0x0004, 0x0000, 0x6548, 0x6C6C, 0x206F, 0x6F57, 0x6C72, 0x2164, 0x000A, 0x0000, 0x0000,
diff --git a/flashstub/nrf51.stub b/flashstub/nrf51.stub
new file mode 100644
index 0000000..6c12fa4
--- /dev/null
+++ b/flashstub/nrf51.stub
@@ -0,0 +1 @@
+0x4808, 0x4909, 0x467A, 0x3228, 0x4B08, 0x2B00, 0xD009, 0x6814, 0x600C, 0x6804, 0x2601, 0x4234, 0xD0FB, 0x3B04, 0x3104, 0x3204, 0xE7F3, 0xBE00, 0xE400, 0x4001, 0x0000, 0x0000, 0x000C, 0x0000, 0xAAAA, 0xAAAA, 0xBBBB, 0xBBBB, 0xCCCC, 0xCCCC,
diff --git a/flashstub/stm32.s b/flashstub/stm32.s
deleted file mode 100644
index 8a9cb54..0000000
--- a/flashstub/stm32.s
+++ /dev/null
@@ -1,43 +0,0 @@
-.global _start
-
-_start:
- ldr r0, _flashbase
- ldr r1, _addr
- mov r2, pc
- add r2, #(_data - . - 2)
- ldr r3, _size
- mov r5, #1
-_next:
- cmp r3, #0
- beq _done
- @ Write PG command to FLASH_CR
- str r5, [r0, #0x10]
- @ Write data to flash (half-word)
- ldrh r4, [r2]
- strh r4, [r1]
-
-_wait: @ Wait for BSY bit to clear
- ldr r4, [r0, #0x0C]
- mov r6, #1
- tst r4, r6
- bne _wait
-
- sub r3, #2
- add r1, #2
- add r2, #2
- b _next
-_done:
- bkpt
-
-@.align 4
-.org 0x28
-_flashbase:
- .word 0x40022000
-_addr:
- .word 0
-_size:
- .word 12
-_data:
- .word 0xAAAAAAAA
- .word 0xBBBBBBBB
- .word 0xCCCCCCCC
diff --git a/flashstub/stm32f1.c b/flashstub/stm32f1.c
new file mode 100644
index 0000000..f9ba0a1
--- /dev/null
+++ b/flashstub/stm32f1.c
@@ -0,0 +1,40 @@
+/*
+ * This file is part of the Black Magic Debug project.
+ *
+ * Copyright (C) 2015 Black Sphere Technologies Ltd.
+ * Written by Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "libopencm3/stm32/flash.h"
+#include "stub.h"
+
+#define SR_ERROR_MASK 0x14
+
+void __attribute__((naked))
+stm32f1_flash_write_stub(uint16_t *dest, uint16_t *src, uint32_t size)
+{
+ for (int i; i < size; i += 2) {
+ FLASH_CR = FLASH_CR_PG;
+ *dest++ = *src++;
+ while (FLASH_SR & FLASH_SR_BSY)
+ ;
+ }
+
+ if (FLASH_SR & SR_ERROR_MASK)
+ stub_exit(1);
+
+ stub_exit(0);
+}
+
diff --git a/flashstub/stm32f1.stub b/flashstub/stm32f1.stub
new file mode 100644
index 0000000..7f2914c
--- /dev/null
+++ b/flashstub/stm32f1.stub
@@ -0,0 +1 @@
+0x2300, 0x4293, 0x4C09, 0xD20A, 0x4D09, 0x2601, 0x602E, 0x5ACD, 0x52C5, 0x6825, 0xF015, 0x0F01, 0xD1FB, 0x3302, 0xE7F1, 0x6823, 0xF013, 0x0F14, 0xD000, 0xBE01, 0xBE00, 0xBF00, 0x200C, 0x4002, 0x2010, 0x4002, \ No newline at end of file
diff --git a/flashstub/stm32f4.c b/flashstub/stm32f4.c
new file mode 100644
index 0000000..6732897
--- /dev/null
+++ b/flashstub/stm32f4.c
@@ -0,0 +1,40 @@
+/*
+ * This file is part of the Black Magic Debug project.
+ *
+ * Copyright (C) 2015 Black Sphere Technologies Ltd.
+ * Written by Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "libopencm3/stm32/flash.h"
+#include "stub.h"
+
+#define SR_ERROR_MASK 0xF2
+
+void __attribute__((naked))
+stm32f4_flash_write_stub(uint32_t *dest, uint32_t *src, uint32_t size)
+{
+ for (int i = 0; i < size; i += 4) {
+ FLASH_CR = FLASH_CR_PROGRAM_X32 | FLASH_CR_PG;
+ *dest++ = *src++;
+ while (FLASH_SR & FLASH_SR_BSY)
+ ;
+ }
+
+ if (FLASH_SR & SR_ERROR_MASK)
+ stub_exit(1);
+
+ stub_exit(0);
+}
+
diff --git a/flashstub/stm32f4.s b/flashstub/stm32f4.s
deleted file mode 100644
index fa3fda0..0000000
--- a/flashstub/stm32f4.s
+++ /dev/null
@@ -1,44 +0,0 @@
-.global _start
-
-_start:
- ldr r0, _flashbase
- ldr r1, _addr
- mov r2, pc
- add r2, #(_data - . - 2)
- ldr r3, _size
- ldr r5, _cr
-_next:
- cbz r3, _done
- @ Write PG command to FLASH_CR
- str r5, [r0, #0x10]
- @ Write data to flash (word)
- ldr r4, [r2]
- str r4, [r1]
-
-_wait: @ Wait for BSY bit to clear
- ldrh r4, [r0, #0x0E]
- mov r6, #1
- tst r4, r6
- bne _wait
-
- sub r3, #4
- add r1, #4
- add r2, #4
- b _next
-_done:
- bkpt
-
-@.align 4
-.org 0x28
-_cr:
- .word 0x00000201
-_flashbase:
- .word 0x40023C00
-_addr:
- .word 0x0800bf78
-_size:
- .word 8
-_data:
- .word 0xAAAAAAAA
- .word 0xBBBBBBBB
- .word 0xCCCCCCCC
diff --git a/flashstub/stm32f4.stub b/flashstub/stm32f4.stub
new file mode 100644
index 0000000..25b5d9a
--- /dev/null
+++ b/flashstub/stm32f4.stub
@@ -0,0 +1 @@
+0x2300, 0x4293, 0x4C09, 0xD20B, 0x4D09, 0xF240, 0x2601, 0x602E, 0x58CD, 0x50C5, 0x6825, 0xF415, 0x3F80, 0xD1FB, 0x3304, 0xE7F0, 0x6823, 0xF013, 0x0FF2, 0xD000, 0xBE01, 0xBE00, 0x3C0C, 0x4002, 0x3C10, 0x4002, \ No newline at end of file
diff --git a/flashstub/stub.h b/flashstub/stub.h
new file mode 100644
index 0000000..b837bae
--- /dev/null
+++ b/flashstub/stub.h
@@ -0,0 +1,30 @@
+/*
+ * This file is part of the Black Magic Debug project.
+ *
+ * Copyright (C) 2015 Black Sphere Technologies Ltd.
+ * Written by Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __STUB_H
+#define __STUB_H
+
+static inline void __attribute__((always_inline))
+stub_exit(const int code)
+{
+ asm("bkpt %0"::"i"(code));
+}
+
+#endif
+
diff --git a/src/Makefile b/src/Makefile
index d1dc7f9..3d879ef 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -7,18 +7,20 @@ MAKEFLAGS += --no-print-dir
Q := @
endif
-CFLAGS += -Wall -Wextra -Wno-char-subscripts\
- -O2 -std=gnu99 -g3 -MD \
+OPT_FLAGS ?= -O2
+
+CFLAGS += -Wall -Wextra -Werror -Wno-char-subscripts\
+ $(OPT_FLAGS) -std=gnu99 -g3 -MD \
-I. -Iinclude -Iplatforms/common -I$(PLATFORM_DIR) \
SRC = \
adiv5.c \
adiv5_jtagdp.c \
adiv5_swdp.c \
- arm7tdmi.c \
command.c \
cortexm.c \
crc32.c \
+ exception.c \
gdb_if.c \
gdb_main.c \
gdb_packet.c \
@@ -38,7 +40,6 @@ SRC = \
stm32f1.c \
stm32f4.c \
stm32l0.c \
- stm32l1.c \
swdptap.c \
target.c \
diff --git a/src/adiv5.c b/src/adiv5.c
index 361cd75..4bc64bb 100644
--- a/src/adiv5.c
+++ b/src/adiv5.c
@@ -1,7 +1,7 @@
/*
* This file is part of the Black Magic Debug project.
*
- * Copyright (C) 2011 Black Sphere Technologies Ltd.
+ * Copyright (C) 2015 Black Sphere Technologies Ltd.
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
*
* This program is free software: you can redistribute it and/or modify
@@ -37,14 +37,10 @@
static const char adiv5_driver_str[] = "ARM ADIv5 MEM-AP";
-static int ap_check_error(struct target_s *target);
+static bool ap_check_error(target *t);
-static int ap_mem_read_words(struct target_s *target, uint32_t *dest, uint32_t src, int len);
-static int ap_mem_write_words(struct target_s *target, uint32_t dest, const uint32_t *src, int len);
-static int ap_mem_read_halfwords(struct target_s *target, uint16_t *dest, uint32_t src, int len);
-static int ap_mem_write_halfwords(struct target_s *target, uint32_t dest, const uint16_t *src, int len);
-static int ap_mem_read_bytes(struct target_s *target, uint8_t *dest, uint32_t src, int len);
-static int ap_mem_write_bytes(struct target_s *target, uint32_t dest, const uint8_t *src, int len);
+static void ap_mem_read(target *t, void *dest, uint32_t src, size_t len);
+static void ap_mem_write(target *t, uint32_t dest, const void *src, size_t len);
void adiv5_dp_ref(ADIv5_DP_t *dp)
{
@@ -72,6 +68,11 @@ void adiv5_ap_unref(ADIv5_AP_t *ap)
}
}
+void adiv5_dp_write(ADIv5_DP_t *dp, uint16_t addr, uint32_t value)
+{
+ dp->low_access(dp, ADIV5_LOW_WRITE, addr, value);
+}
+
void adiv5_dp_init(ADIv5_DP_t *dp)
{
uint32_t ctrlstat;
@@ -147,12 +148,8 @@ void adiv5_dp_init(ADIv5_DP_t *dp)
t->driver = adiv5_driver_str;
t->check_error = ap_check_error;
- t->mem_read_words = ap_mem_read_words;
- t->mem_write_words = ap_mem_write_words;
- t->mem_read_halfwords = ap_mem_read_halfwords;
- t->mem_write_halfwords = ap_mem_write_halfwords;
- t->mem_read_bytes = ap_mem_read_bytes;
- t->mem_write_bytes = ap_mem_write_bytes;
+ t->mem_read = ap_mem_read;
+ t->mem_write = ap_mem_write;
/* The rest sould only be added after checking ROM table */
cortexm_probe(t);
@@ -160,288 +157,135 @@ void adiv5_dp_init(ADIv5_DP_t *dp)
adiv5_dp_unref(dp);
}
-void adiv5_dp_write_ap(ADIv5_DP_t *dp, uint8_t addr, uint32_t value)
-{
- adiv5_dp_low_access(dp, ADIV5_LOW_AP, ADIV5_LOW_WRITE, addr, value);
-}
-
-uint32_t adiv5_dp_read_ap(ADIv5_DP_t *dp, uint8_t addr)
+static bool ap_check_error(target *t)
{
- uint32_t ret;
-
- adiv5_dp_low_access(dp, ADIV5_LOW_AP, ADIV5_LOW_READ, addr, 0);
- ret = adiv5_dp_low_access(dp, ADIV5_LOW_DP, ADIV5_LOW_READ,
- ADIV5_DP_RDBUFF, 0);
-
- return ret;
+ ADIv5_AP_t *ap = adiv5_target_ap(t);
+ return adiv5_dp_error(ap->dp) != 0;
}
+enum align {
+ ALIGN_BYTE = 0,
+ ALIGN_HALFWORD = 1,
+ ALIGN_WORD = 2
+};
+#define ALIGNOF(x) (((x) & 3) == 0 ? ALIGN_WORD : \
+ (((x) & 1) == 0 ? ALIGN_HALFWORD : ALIGN_BYTE))
-static int
-ap_check_error(struct target_s *target)
+/* Program the CSW and TAR for sequencial access at a given width */
+static void ap_mem_access_setup(ADIv5_AP_t *ap, uint32_t addr, enum align align)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
- return adiv5_dp_error(ap->dp);
-}
-
-static int
-ap_mem_read_words(struct target_s *target, uint32_t *dest, uint32_t src, int len)
-{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
- uint32_t osrc = src;
-
- len >>= 2;
-
- adiv5_ap_write(ap, ADIV5_AP_CSW, ap->csw |
- ADIV5_AP_CSW_SIZE_WORD | ADIV5_AP_CSW_ADDRINC_SINGLE);
- adiv5_dp_low_access(ap->dp, ADIV5_LOW_AP, ADIV5_LOW_WRITE,
- ADIV5_AP_TAR, src);
- adiv5_dp_low_access(ap->dp, ADIV5_LOW_AP, ADIV5_LOW_READ,
- ADIV5_AP_DRW, 0);
- while(--len) {
- *dest++ = adiv5_dp_low_access(ap->dp, ADIV5_LOW_AP,
- ADIV5_LOW_READ, ADIV5_AP_DRW, 0);
- src += 4;
- /* Check for 10 bit address overflow */
- if ((src ^ osrc) & 0xfffffc00) {
- osrc = src;
- adiv5_dp_low_access(ap->dp, ADIV5_LOW_AP,
- ADIV5_LOW_WRITE, ADIV5_AP_TAR, src);
- adiv5_dp_low_access(ap->dp, ADIV5_LOW_AP,
- ADIV5_LOW_READ, ADIV5_AP_DRW, 0);
- }
-
+ uint32_t csw = ap->csw | ADIV5_AP_CSW_ADDRINC_SINGLE;
+
+ switch (align) {
+ case ALIGN_BYTE:
+ csw |= ADIV5_AP_CSW_SIZE_BYTE;
+ break;
+ case ALIGN_HALFWORD:
+ csw |= ADIV5_AP_CSW_SIZE_HALFWORD;
+ break;
+ case ALIGN_WORD:
+ csw |= ADIV5_AP_CSW_SIZE_WORD;
+ break;
}
- *dest++ = adiv5_dp_low_access(ap->dp, ADIV5_LOW_DP, ADIV5_LOW_READ,
- ADIV5_DP_RDBUFF, 0);
-
- return 0;
+ adiv5_ap_write(ap, ADIV5_AP_CSW, csw);
+ adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, ADIV5_AP_TAR, addr);
}
-static int
-ap_mem_read_halfwords(struct target_s *target, uint16_t *dest, uint32_t src, int len)
+/* Extract read data from data lane based on align and src address */
+static void * extract(void *dest, uint32_t src, uint32_t val, enum align align)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
- uint32_t tmp;
- uint32_t osrc = src;
-
- len >>= 1;
-
- adiv5_ap_write(ap, ADIV5_AP_CSW, ap->csw |
- ADIV5_AP_CSW_SIZE_HALFWORD | ADIV5_AP_CSW_ADDRINC_SINGLE);
- adiv5_dp_low_access(ap->dp, ADIV5_LOW_AP, ADIV5_LOW_WRITE,
- ADIV5_AP_TAR, src);
- adiv5_dp_low_access(ap->dp, ADIV5_LOW_AP, ADIV5_LOW_READ,
- ADIV5_AP_DRW, 0);
- while(--len) {
- tmp = adiv5_dp_low_access(ap->dp, ADIV5_LOW_AP, ADIV5_LOW_READ,
- ADIV5_AP_DRW, 0);
- *dest++ = (tmp >> ((src & 0x2) << 3) & 0xFFFF);
-
- src += 2;
- /* Check for 10 bit address overflow */
- if ((src ^ osrc) & 0xfffffc00) {
- osrc = src;
- adiv5_dp_low_access(ap->dp, ADIV5_LOW_AP,
- ADIV5_LOW_WRITE, ADIV5_AP_TAR, src);
- adiv5_dp_low_access(ap->dp, ADIV5_LOW_AP,
- ADIV5_LOW_READ, ADIV5_AP_DRW, 0);
- }
+ switch (align) {
+ case ALIGN_BYTE:
+ *(uint8_t *)dest = (val >> ((src & 0x3) << 3) & 0xFF);
+ break;
+ case ALIGN_HALFWORD:
+ *(uint16_t *)dest = (val >> ((src & 0x2) << 3) & 0xFFFF);
+ break;
+ case ALIGN_WORD:
+ *(uint32_t *)dest = val;
+ break;
}
- tmp = adiv5_dp_low_access(ap->dp, 0, 1, ADIV5_DP_RDBUFF, 0);
- *dest++ = (tmp >> ((src & 0x2) << 3) & 0xFFFF);
-
- return 0;
+ return (uint8_t *)dest + (1 << align);
}
-static int
-ap_mem_read_bytes(struct target_s *target, uint8_t *dest, uint32_t src, int len)
+static void
+ap_mem_read(target *t, void *dest, uint32_t src, size_t len)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
+ ADIv5_AP_t *ap = adiv5_target_ap(t);
uint32_t tmp;
uint32_t osrc = src;
+ enum align align = MIN(ALIGNOF(src), ALIGNOF(len));
- adiv5_ap_write(ap, ADIV5_AP_CSW, ap->csw |
- ADIV5_AP_CSW_SIZE_BYTE | ADIV5_AP_CSW_ADDRINC_SINGLE);
- adiv5_dp_low_access(ap->dp, ADIV5_LOW_AP, ADIV5_LOW_WRITE,
- ADIV5_AP_TAR, src);
- adiv5_dp_low_access(ap->dp, ADIV5_LOW_AP, ADIV5_LOW_READ,
- ADIV5_AP_DRW, 0);
- while(--len) {
- tmp = adiv5_dp_low_access(ap->dp, 1, 1, ADIV5_AP_DRW, 0);
- *dest++ = (tmp >> ((src & 0x3) << 3) & 0xFF);
-
- src++;
+ len >>= align;
+ ap_mem_access_setup(ap, src, align);
+ adiv5_dp_low_access(ap->dp, ADIV5_LOW_READ, ADIV5_AP_DRW, 0);
+ while (--len) {
+ tmp = adiv5_dp_low_access(ap->dp, ADIV5_LOW_READ, ADIV5_AP_DRW, 0);
+ dest = extract(dest, src, tmp, align);
+
+ src += (1 << align);
/* Check for 10 bit address overflow */
if ((src ^ osrc) & 0xfffffc00) {
osrc = src;
- adiv5_dp_low_access(ap->dp, ADIV5_LOW_AP,
+ adiv5_dp_low_access(ap->dp,
ADIV5_LOW_WRITE, ADIV5_AP_TAR, src);
- adiv5_dp_low_access(ap->dp, ADIV5_LOW_AP,
+ adiv5_dp_low_access(ap->dp,
ADIV5_LOW_READ, ADIV5_AP_DRW, 0);
}
}
- tmp = adiv5_dp_low_access(ap->dp, 0, 1, ADIV5_DP_RDBUFF, 0);
- *dest++ = (tmp >> ((src++ & 0x3) << 3) & 0xFF);
-
- return 0;
+ tmp = adiv5_dp_low_access(ap->dp, ADIV5_LOW_READ, ADIV5_DP_RDBUFF, 0);
+ extract(dest, src, tmp, align);
}
-
-static int
-ap_mem_write_words(struct target_s *target, uint32_t dest, const uint32_t *src, int len)
+static void
+ap_mem_write(target *t, uint32_t dest, const void *src, size_t len)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
+ ADIv5_AP_t *ap = adiv5_target_ap(t);
uint32_t odest = dest;
-
- len >>= 2;
-
- adiv5_ap_write(ap, ADIV5_AP_CSW, ap->csw |
- ADIV5_AP_CSW_SIZE_WORD | ADIV5_AP_CSW_ADDRINC_SINGLE);
- adiv5_dp_low_access(ap->dp, ADIV5_LOW_AP, ADIV5_LOW_WRITE,
- ADIV5_AP_TAR, dest);
- while(len--) {
- adiv5_dp_low_access(ap->dp, ADIV5_LOW_AP, ADIV5_LOW_WRITE,
- ADIV5_AP_DRW, *src++);
- dest += 4;
- /* Check for 10 bit address overflow */
- if ((dest ^ odest) & 0xfffffc00) {
- odest = dest;
- adiv5_dp_low_access(ap->dp, ADIV5_LOW_AP,
- ADIV5_LOW_WRITE, ADIV5_AP_TAR, dest);
- }
- }
-
- return 0;
-}
-
-static int
-ap_mem_write_halfwords(struct target_s *target, uint32_t dest, const uint16_t *src, int len)
-{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
- uint32_t odest = dest;
-
- len >>= 1;
-
- adiv5_ap_write(ap, ADIV5_AP_CSW, ap->csw |
- ADIV5_AP_CSW_SIZE_HALFWORD | ADIV5_AP_CSW_ADDRINC_SINGLE);
- adiv5_dp_low_access(ap->dp, ADIV5_LOW_AP, ADIV5_LOW_WRITE,
- ADIV5_AP_TAR, dest);
- while(len--) {
- uint32_t tmp = (uint32_t)*src++ << ((dest & 2) << 3);
- adiv5_dp_low_access(ap->dp, ADIV5_LOW_AP, ADIV5_LOW_WRITE,
- ADIV5_AP_DRW, tmp);
- dest += 2;
- /* Check for 10 bit address overflow */
- if ((dest ^ odest) & 0xfffffc00) {
- odest = dest;
- adiv5_dp_low_access(ap->dp, ADIV5_LOW_AP,
- ADIV5_LOW_WRITE, ADIV5_AP_TAR, dest);
+ enum align align = MIN(ALIGNOF(dest), ALIGNOF(len));
+
+ len >>= align;
+ ap_mem_access_setup(ap, dest, align);
+ while (len--) {
+ uint32_t tmp = 0;
+ /* Pack data into correct data lane */
+ switch (align) {
+ case ALIGN_BYTE:
+ tmp = ((uint32_t)*(uint8_t *)src) << ((dest & 3) << 3);
+ break;
+ case ALIGN_HALFWORD:
+ tmp = ((uint32_t)*(uint16_t *)src) << ((dest & 2) << 3);
+ break;
+ case ALIGN_WORD:
+ tmp = *(uint32_t *)src;
+ break;
}
- }
- return 0;
-}
-
-static int
-ap_mem_write_bytes(struct target_s *target, uint32_t dest, const uint8_t *src, int len)
-{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
- uint32_t odest = dest;
-
- adiv5_ap_write(ap, ADIV5_AP_CSW, ap->csw |
- ADIV5_AP_CSW_SIZE_BYTE | ADIV5_AP_CSW_ADDRINC_SINGLE);
- adiv5_dp_low_access(ap->dp, ADIV5_LOW_AP, ADIV5_LOW_WRITE,
- ADIV5_AP_TAR, dest);
- while(len--) {
- uint32_t tmp = (uint32_t)*src++ << ((dest++ & 3) << 3);
- adiv5_dp_low_access(ap->dp, ADIV5_LOW_AP, ADIV5_LOW_WRITE,
- ADIV5_AP_DRW, tmp);
+ src = (uint8_t *)src + (1 << align);
+ dest += (1 << align);
+ adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, ADIV5_AP_DRW, tmp);
/* Check for 10 bit address overflow */
if ((dest ^ odest) & 0xfffffc00) {
odest = dest;
- adiv5_dp_low_access(ap->dp, ADIV5_LOW_AP,
+ adiv5_dp_low_access(ap->dp,
ADIV5_LOW_WRITE, ADIV5_AP_TAR, dest);
}
}
- return 0;
-}
-
-
-
-uint32_t adiv5_ap_mem_read(ADIv5_AP_t *ap, uint32_t addr)
-{
- adiv5_ap_write(ap, ADIV5_AP_CSW, ap->csw |
- ADIV5_AP_CSW_SIZE_WORD | ADIV5_AP_CSW_ADDRINC_SINGLE);
- adiv5_ap_write(ap, ADIV5_AP_TAR, addr);
- return adiv5_ap_read(ap, ADIV5_AP_DRW);
-}
-
-void adiv5_ap_mem_write(ADIv5_AP_t *ap, uint32_t addr, uint32_t value)
-{
- adiv5_ap_write(ap, ADIV5_AP_CSW, ap->csw |
- ADIV5_AP_CSW_SIZE_WORD | ADIV5_AP_CSW_ADDRINC_SINGLE);
- adiv5_ap_write(ap, ADIV5_AP_TAR, addr);
- adiv5_ap_write(ap, ADIV5_AP_DRW, value);
-}
-
-uint16_t adiv5_ap_mem_read_halfword(ADIv5_AP_t *ap, uint32_t addr)
-{
- adiv5_ap_write(ap, ADIV5_AP_CSW, ap->csw |
- ADIV5_AP_CSW_SIZE_HALFWORD | ADIV5_AP_CSW_ADDRINC_SINGLE);
- adiv5_ap_write(ap, ADIV5_AP_TAR, addr);
- uint32_t v = adiv5_ap_read(ap, ADIV5_AP_DRW);
- if (addr & 2)
- return v >> 16;
- else
- return v & 0xFFFF;
-}
-
-void adiv5_ap_mem_write_halfword(ADIv5_AP_t *ap, uint32_t addr, uint16_t value)
-{
- uint32_t v = value;
- if (addr & 2)
- v <<= 16;
-
- adiv5_ap_write(ap, ADIV5_AP_CSW, ap->csw |
- ADIV5_AP_CSW_SIZE_HALFWORD | ADIV5_AP_CSW_ADDRINC_SINGLE);
- adiv5_ap_write(ap, ADIV5_AP_TAR, addr);
- adiv5_ap_write(ap, ADIV5_AP_DRW, v);
-}
-
-uint8_t adiv5_ap_mem_read_byte(ADIv5_AP_t *ap, uint32_t addr)
-{
- adiv5_ap_write(ap, ADIV5_AP_CSW, ap->csw |
- ADIV5_AP_CSW_SIZE_BYTE | ADIV5_AP_CSW_ADDRINC_SINGLE);
- adiv5_ap_write(ap, ADIV5_AP_TAR, addr);
- uint32_t v = adiv5_ap_read(ap, ADIV5_AP_DRW);
-
- return v >> ((addr & 3) * 8);
-}
-
-void adiv5_ap_mem_write_byte(ADIv5_AP_t *ap, uint32_t addr, uint8_t value)
-{
- uint32_t v = value << ((addr & 3) * 8);
-
- adiv5_ap_write(ap, ADIV5_AP_CSW, ap->csw |
- ADIV5_AP_CSW_SIZE_BYTE | ADIV5_AP_CSW_ADDRINC_SINGLE);
- adiv5_ap_write(ap, ADIV5_AP_TAR, addr);
- adiv5_ap_write(ap, ADIV5_AP_DRW, v);
}
-void adiv5_ap_write(ADIv5_AP_t *ap, uint8_t addr, uint32_t value)
+void adiv5_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value)
{
adiv5_dp_write(ap->dp, ADIV5_DP_SELECT,
((uint32_t)ap->apsel << 24)|(addr & 0xF0));
- adiv5_dp_write_ap(ap->dp, addr, value);
+ adiv5_dp_write(ap->dp, addr, value);
}
-uint32_t adiv5_ap_read(ADIv5_AP_t *ap, uint8_t addr)
+uint32_t adiv5_ap_read(ADIv5_AP_t *ap, uint16_t addr)
{
uint32_t ret;
adiv5_dp_write(ap->dp, ADIV5_DP_SELECT,
((uint32_t)ap->apsel << 24)|(addr & 0xF0));
- ret = adiv5_dp_read_ap(ap->dp, addr);
+ ret = adiv5_dp_read(ap->dp, addr);
return ret;
}
diff --git a/src/adiv5_jtagdp.c b/src/adiv5_jtagdp.c
index 8f62a11..d97bc99 100644
--- a/src/adiv5_jtagdp.c
+++ b/src/adiv5_jtagdp.c
@@ -23,6 +23,7 @@
*/
#include "general.h"
+#include "exception.h"
#include "adiv5.h"
#include "jtag_scan.h"
#include "jtagtap.h"
@@ -36,13 +37,12 @@
#define IR_DPACC 0xA
#define IR_APACC 0xB
-static void adiv5_jtagdp_write(ADIv5_DP_t *dp, uint8_t addr, uint32_t value);
-static uint32_t adiv5_jtagdp_read(ADIv5_DP_t *dp, uint8_t addr);
+static uint32_t adiv5_jtagdp_read(ADIv5_DP_t *dp, uint16_t addr);
static uint32_t adiv5_jtagdp_error(ADIv5_DP_t *dp);
-static uint32_t adiv5_jtagdp_low_access(ADIv5_DP_t *dp, uint8_t APnDP, uint8_t RnW,
- uint8_t addr, uint32_t value);
+static uint32_t adiv5_jtagdp_low_access(ADIv5_DP_t *dp, uint8_t RnW,
+ uint16_t addr, uint32_t value);
void adiv5_jtag_dp_handler(jtag_dev_t *dev)
@@ -52,7 +52,6 @@ void adiv5_jtag_dp_handler(jtag_dev_t *dev)
dp->dev = dev;
dp->idcode = dev->idcode;
- dp->dp_write = adiv5_jtagdp_write;
dp->dp_read = adiv5_jtagdp_read;
dp->error = adiv5_jtagdp_error;
dp->low_access = adiv5_jtagdp_low_access;
@@ -60,49 +59,43 @@ void adiv5_jtag_dp_handler(jtag_dev_t *dev)
adiv5_dp_init(dp);
}
-static void adiv5_jtagdp_write(ADIv5_DP_t *dp, uint8_t addr, uint32_t value)
+static uint32_t adiv5_jtagdp_read(ADIv5_DP_t *dp, uint16_t addr)
{
- adiv5_jtagdp_low_access(dp, ADIV5_LOW_DP, ADIV5_LOW_WRITE, addr, value);
-}
-
-static uint32_t adiv5_jtagdp_read(ADIv5_DP_t *dp, uint8_t addr)
-{
- adiv5_jtagdp_low_access(dp, ADIV5_LOW_DP, ADIV5_LOW_READ, addr, 0);
- return adiv5_jtagdp_low_access(dp, ADIV5_LOW_DP, ADIV5_LOW_READ,
+ adiv5_jtagdp_low_access(dp, ADIV5_LOW_READ, addr, 0);
+ return adiv5_jtagdp_low_access(dp, ADIV5_LOW_READ,
ADIV5_DP_RDBUFF, 0);
}
static uint32_t adiv5_jtagdp_error(ADIv5_DP_t *dp)
{
- adiv5_jtagdp_low_access(dp, ADIV5_LOW_DP, ADIV5_LOW_READ,
- ADIV5_DP_CTRLSTAT, 0);
- return adiv5_jtagdp_low_access(dp, ADIV5_LOW_DP, ADIV5_LOW_WRITE,
+ adiv5_jtagdp_low_access(dp, ADIV5_LOW_READ, ADIV5_DP_CTRLSTAT, 0);
+ return adiv5_jtagdp_low_access(dp, ADIV5_LOW_WRITE,
ADIV5_DP_CTRLSTAT, 0xF0000032) & 0x32;
}
-static uint32_t adiv5_jtagdp_low_access(ADIv5_DP_t *dp, uint8_t APnDP, uint8_t RnW,
- uint8_t addr, uint32_t value)
+static uint32_t adiv5_jtagdp_low_access(ADIv5_DP_t *dp, uint8_t RnW,
+ uint16_t addr, uint32_t value)
{
+ bool APnDP = addr & ADIV5_APnDP;
+ addr &= 0xff;
uint64_t request, response;
uint8_t ack;
request = ((uint64_t)value << 3) | ((addr >> 1) & 0x06) | (RnW?1:0);
- jtag_dev_write_ir(dp->dev, APnDP?IR_APACC:IR_DPACC);
+ jtag_dev_write_ir(dp->dev, APnDP ? IR_APACC : IR_DPACC);
- int tries = 1000;
+ platform_timeout_set(2000);
do {
jtag_dev_shift_dr(dp->dev, (uint8_t*)&response, (uint8_t*)&request, 35);
ack = response & 0x07;
- } while(--tries && (ack == JTAGDP_ACK_WAIT));
+ } while(!platform_timeout_is_expired() && (ack == JTAGDP_ACK_WAIT));
- if (dp->allow_timeout && (ack == JTAGDP_ACK_WAIT))
- return 0;
+ if (ack == JTAGDP_ACK_WAIT)
+ raise_exception(EXCEPTION_TIMEOUT, "JTAG-DP ACK timeout");
- if((ack != JTAGDP_ACK_OK)) {
- /* Fatal error if invalid ACK response */
- PLATFORM_FATAL_ERROR(1);
- }
+ if((ack != JTAGDP_ACK_OK))
+ raise_exception(EXCEPTION_ERROR, "JTAG-DP invalid ACK");
return (uint32_t)(response >> 3);
}
diff --git a/src/adiv5_swdp.c b/src/adiv5_swdp.c
index 9df362f..b53fcb5 100644
--- a/src/adiv5_swdp.c
+++ b/src/adiv5_swdp.c
@@ -23,6 +23,7 @@
*/
#include "general.h"
+#include "exception.h"
#include "adiv5.h"
#include "swdptap.h"
#include "jtagtap.h"
@@ -33,13 +34,12 @@
#define SWDP_ACK_WAIT 0x02
#define SWDP_ACK_FAULT 0x04
-static void adiv5_swdp_write(ADIv5_DP_t *dp, uint8_t addr, uint32_t value);
-static uint32_t adiv5_swdp_read(ADIv5_DP_t *dp, uint8_t addr);
+static uint32_t adiv5_swdp_read(ADIv5_DP_t *dp, uint16_t addr);
static uint32_t adiv5_swdp_error(ADIv5_DP_t *dp);
-static uint32_t adiv5_swdp_low_access(ADIv5_DP_t *dp, uint8_t APnDP, uint8_t RnW,
- uint8_t addr, uint32_t value);
+static uint32_t adiv5_swdp_low_access(ADIv5_DP_t *dp, uint8_t RnW,
+ uint16_t addr, uint32_t value);
int adiv5_swdp_scan(void)
@@ -64,7 +64,6 @@ int adiv5_swdp_scan(void)
return -1;
}
- dp->dp_write = adiv5_swdp_write;
dp->dp_read = adiv5_swdp_read;
dp->error = adiv5_swdp_error;
dp->low_access = adiv5_swdp_low_access;
@@ -78,14 +77,15 @@ int adiv5_swdp_scan(void)
return target_list?1:0;
}
-static void adiv5_swdp_write(ADIv5_DP_t *dp, uint8_t addr, uint32_t value)
+static uint32_t adiv5_swdp_read(ADIv5_DP_t *dp, uint16_t addr)
{
- adiv5_swdp_low_access(dp, ADIV5_LOW_DP, ADIV5_LOW_WRITE, addr, value);
-}
-
-static uint32_t adiv5_swdp_read(ADIv5_DP_t *dp, uint8_t addr)
-{
- return adiv5_swdp_low_access(dp, ADIV5_LOW_DP, ADIV5_LOW_READ, addr, 0);
+ if (addr & ADIV5_APnDP) {
+ adiv5_dp_low_access(dp, ADIV5_LOW_READ, addr, 0);
+ return adiv5_dp_low_access(dp, ADIV5_LOW_READ,
+ ADIV5_DP_RDBUFF, 0);
+ } else {
+ return adiv5_swdp_low_access(dp, ADIV5_LOW_READ, addr, 0);
+ }
}
static uint32_t adiv5_swdp_error(ADIv5_DP_t *dp)
@@ -105,15 +105,17 @@ static uint32_t adiv5_swdp_error(ADIv5_DP_t *dp)
if(err & ADIV5_DP_CTRLSTAT_WDATAERR)
clr |= ADIV5_DP_ABORT_WDERRCLR;
- adiv5_swdp_write(dp, ADIV5_DP_ABORT, clr);
+ adiv5_dp_write(dp, ADIV5_DP_ABORT, clr);
dp->fault = 0;
return err;
}
-static uint32_t adiv5_swdp_low_access(ADIv5_DP_t *dp, uint8_t APnDP, uint8_t RnW,
- uint8_t addr, uint32_t value)
+static uint32_t adiv5_swdp_low_access(ADIv5_DP_t *dp, uint8_t RnW,
+ uint16_t addr, uint32_t value)
{
+ bool APnDP = addr & ADIV5_APnDP;
+ addr &= 0xff;
uint8_t request = 0x81;
uint32_t response;
uint8_t ack;
@@ -128,28 +130,26 @@ static uint32_t adiv5_swdp_low_access(ADIv5_DP_t *dp, uint8_t APnDP, uint8_t RnW
if((addr == 4) || (addr == 8))
request ^= 0x20;
- size_t tries = 1000;
+ platform_timeout_set(2000);
do {
swdptap_seq_out(request, 8);
ack = swdptap_seq_in(3);
- } while(--tries && ack == SWDP_ACK_WAIT);
+ } while (!platform_timeout_is_expired() && ack == SWDP_ACK_WAIT);
- if (dp->allow_timeout && (ack == SWDP_ACK_WAIT))
- return 0;
+ if (ack == SWDP_ACK_WAIT)
+ raise_exception(EXCEPTION_TIMEOUT, "SWDP ACK timeout");
if(ack == SWDP_ACK_FAULT) {
dp->fault = 1;
return 0;
}
- if(ack != SWDP_ACK_OK) {
- /* Fatal error if invalid ACK response */
- PLATFORM_FATAL_ERROR(1);
- }
+ if(ack != SWDP_ACK_OK)
+ raise_exception(EXCEPTION_ERROR, "SWDP invalid ACK");
if(RnW) {
if(swdptap_seq_in_parity(&response, 32)) /* Give up on parity error */
- PLATFORM_FATAL_ERROR(1);
+ raise_exception(EXCEPTION_ERROR, "SWDP Parity error");
} else {
swdptap_seq_out_parity(value, 32);
}
diff --git a/src/arm7tdmi.c b/src/arm7tdmi.c
deleted file mode 100644
index 1721787..0000000
--- a/src/arm7tdmi.c
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * This file is part of the Black Magic Debug project.
- *
- * Copyright (C) 2011 Black Sphere Technologies Ltd.
- * Written by Gareth McMullin <gareth@blacksphere.co.nz>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/* This file implements the ARM7TDMI target support using the JTAG
- * interface as described in ARM7TDMI Technical Reference Manual,
- * ARM Document DDI 0210C
- */
-
-#include "general.h"
-#include "target.h"
-#include "jtag_scan.h"
-#include "jtagtap.h"
-
-/* TODO:
- * Skeleton target.
- * EmbeddedICE registers, halt/resume target.
- * Check target mode on halt, switch to ARM if needed.
- * Read registers on halt, restore on resume. Give GDB cached copy.
- * System speed access, read/write memory.
- * Misaligned/byte memory access.
- * Breakpoint support.
- * Watchpoint support.
- * Funnies: abort on breakpointed instruction, etc.
- * Flash programming for STR73x and LPC2xxx.
- */
-static const char arm7_driver_str[] = "ARM7TDMI";
-
-/* ARM7 JTAG IR values */
-#define ARM7_IR_EXTEST 0x0
-#define ARM7_IR_SCAN_N 0x2
-#define ARM7_IR_SAMPLE_PRELOAD 0x3
-#define ARM7_IR_RESTART 0x4
-#define ARM7_IR_CLAMP 0x5
-#define ARM7_IR_HIGHZ 0x7
-#define ARM7_IR_CLAMPZ 0x9
-#define ARM7_IR_INTEST 0xC
-#define ARM7_IR_IDCODE 0xE
-#define ARM7_IR_BYPASS 0xF
-
-/* ARM7 SCAN_N scan chain values */
-#define ARM7_SCANN_BOUNDARY 0
-#define ARM7_SCANN_DBUS 1
-#define ARM7_SCANN_EICE 2
-
-/* EmbeddedICE-RT Register addresses */
-#define ARM7_EICE_DEBUG_CTRL 0x00
-#define ARM7_EICE_DEBUG_STAT 0x01
-#define ARM7_EICE_ABORT_STAT 0x02
-#define ARM7_EICE_COMMS_CTRL 0x04
-#define ARM7_EICE_COMMS_DATA 0x05
-#define ARM7_EICE_WATCH_ADDR(x) (0x08 + (8 * (x))
-#define ARM7_EICE_WATCH_ADDR_MASK(x) (0x09 + (8 * (x))
-#define ARM7_EICE_WATCH_DATA(x) (0x0A + (8 * (x))
-#define ARM7_EICE_WATCH_DATA_MASK(x) (0x0B + (8 * (x))
-#define ARM7_EICE_WATCH_CTRL(x) (0x0C + (8 * (x))
-#define ARM7_EICE_WATCH_CTRL_MASK(x) (0x0D + (8 * (x))
-
-/* Read/write bit in EmbeddedICE-RT scan chain */
-#define ARM7_EICE_READ (0uLL << 37)
-#define ARM7_EICE_WRITE (1uLL << 37)
-
-/* Debug Control Register bits */
-#define ARM7_EICE_DEBUG_CTRL_EICE_DISABLE (1 << 5)
-#define ARM7_EICE_DEBUG_CTRL_MONITOR (1 << 4)
-/* Bit 3 - Reserved */
-#define ARM7_EICE_DEBUG_CTRL_INTDIS (1 << 2)
-#define ARM7_EICE_DEBUG_CTRL_DBGRQ (1 << 1)
-#define ARM7_EICE_DEBUG_CTRL_DBGACK (1 << 0)
-
-/* Debug Status Register bits */
-#define ARM7_EICE_DEBUG_STAT_TBIT (1 << 4)
-#define ARM7_EICE_DEBUG_STAT_NMREQ (1 << 3)
-#define ARM7_EICE_DEBUG_STAT_INTDIS (1 << 2)
-#define ARM7_EICE_DEBUG_STAT_DBGRQ (1 << 1)
-#define ARM7_EICE_DEBUG_STAT_DBGACK (1 << 0)
-
-#define ARM7_OP_NOP 0xE1A00000
-
-struct target_arm7_s {
- target t;
- jtag_dev_t *jtag;
- uint32_t reg_cache[16];
-};
-
-/* FIXME: Remove: */
-static void do_nothing(void)
-{
-}
-
-static bool arm7_attach(struct target_s *target);
-static int arm7_regs_read(struct target_s *target, void *data);
-static int arm7_regs_write(struct target_s *target, const void *data);
-static void arm7_halt_request(struct target_s *target);
-static int arm7_halt_wait(struct target_s *target);
-static void arm7_halt_resume(struct target_s *target, bool step);
-
-void arm7tdmi_jtag_handler(jtag_dev_t *dev)
-{
- struct target_arm7_s *tj = (void*)target_new(sizeof(*tj));
- target *t = (target *)tj;
-
- t->driver = arm7_driver_str;
- tj->jtag = dev;
-
- /* Setup mandatory virtual methods */
- t->attach = arm7_attach;
- t->detach = (void *)do_nothing;
- t->check_error = (void *)do_nothing;
- t->mem_read_words = (void *)do_nothing;
- t->mem_write_words = (void *)do_nothing;
- t->mem_read_halfwords = (void *)do_nothing;
- t->mem_write_halfwords = (void *)do_nothing;
- t->mem_read_bytes = (void *)do_nothing;
- t->mem_write_bytes = (void *)do_nothing;
- t->regs_size = 16 * sizeof(uint32_t);
- t->regs_read = (void *)arm7_regs_read;
- t->regs_write = (void *)arm7_regs_write;
- t->pc_write = (void *)do_nothing;
- t->reset = (void *)do_nothing;
- t->halt_request = arm7_halt_request;
- t->halt_wait = arm7_halt_wait;
- t->halt_resume = arm7_halt_resume;
-
- /* TODO: Breakpoint and watchpoint functions. */
- /* TODO: Fault unwinder. */
- /* TODO: Memory map / Flash programming. */
-}
-
-static void arm7_select_scanchain(struct target_arm7_s *target, uint8_t chain)
-{
- jtag_dev_write_ir(target->jtag, ARM7_IR_SCAN_N);
- jtag_dev_shift_dr(target->jtag, NULL, &chain, 4);
- jtag_dev_write_ir(target->jtag, ARM7_IR_INTEST);
-}
-
-static void arm7_eice_write(struct target_arm7_s *target,
- uint8_t addr, uint32_t value)
-{
- uint64_t val = ((uint64_t)addr << 32) | value | ARM7_EICE_WRITE;
-
- arm7_select_scanchain(target, ARM7_SCANN_EICE);
- jtag_dev_shift_dr(target->jtag, NULL, (uint8_t *)&val, 38);
- DEBUG("eice_write(%d, 0x%08X)\n", addr, value);
-}
-
-static uint32_t arm7_eice_read(struct target_arm7_s *target, uint8_t addr)
-{
- uint64_t val = ((uint64_t)addr << 32) | ARM7_EICE_READ;
-
- arm7_select_scanchain(target, ARM7_SCANN_EICE);
- jtag_dev_shift_dr(target->jtag, NULL, (uint8_t *)&val, 38);
- jtag_dev_shift_dr(target->jtag, (uint8_t *)&val, (uint8_t *)&val, 38);
- DEBUG("eice_read(%d, 0x%08X)\n", addr, (uint32_t)val);
-
- return (uint32_t)val;
-}
-
-/* Execute a single instruction at debug speed.
- * Performs datalen data bus accesses after the op to capture data.
- */
-static void arm7_op_debug(struct target_arm7_s *t, uint32_t op, uint32_t *data,
- int datalen)
-{
- uint64_t tmp;
- /* FIXME: This routine is broken.
- * This process isn't very well documented. Maybe NOPs need to
- * be shifted into pipeline before data is read out.
- */
- DEBUG("op_debug(0x%08X)\n", op);
- arm7_select_scanchain(t, ARM7_SCANN_DBUS);
- tmp = op;
- jtag_dev_shift_dr(t->jtag, NULL, (const uint8_t*)&tmp, 33);
- while(datalen--) {
- tmp = *data;
- jtag_dev_shift_dr(t->jtag, (uint8_t*)&tmp, (uint8_t*)&tmp, 33);
- *data = (uint32_t)tmp;
- DEBUG("\t0x%08X\n", *data);
- data++;
- }
-}
-
-/* Execute a single instruction at system speed. */
-static void arm7_op_system(struct target_arm7_s *t, uint32_t op)
-{
- uint64_t tmp;
- arm7_select_scanchain(t, ARM7_SCANN_DBUS);
- tmp = op | (1uLL << 32);
- jtag_dev_shift_dr(t->jtag, NULL, (const uint8_t*)&tmp, 33);
-}
-
-static void arm7_halt_request(struct target_s *target)
-{
- struct target_arm7_s *t = (struct target_arm7_s *)target;
-
- arm7_eice_write(t, ARM7_EICE_DEBUG_CTRL, ARM7_EICE_DEBUG_CTRL_DBGRQ);
-}
-
-static int arm7_halt_wait(struct target_s *target)
-{
- struct target_arm7_s *t = (struct target_arm7_s *)target;
- int stat = arm7_eice_read(t, ARM7_EICE_DEBUG_STAT);
-
- if(!(stat & ARM7_EICE_DEBUG_STAT_DBGACK))
- return 0;
-
- /* We are halted, so switch to ARM mode if needed. */
- if(stat & ARM7_EICE_DEBUG_STAT_TBIT) {
- /* This sequence switches to ARM mode:
- * 6000 STR R0, [R0] ; Save R0 before use
- * 4678 MOV R0, PC ; Copy PC into R0
- * 6000 STR R0, [R0] ; Now save the PC in R0
- * 4778 BX PC ; Jump into ARM state
- * 46c0 MOV R8, R8 ; NOP
- * 46c0 MOV R8, R8 ; NOP
- */
- /* FIXME: Switch to ARM mode. */
- }
-
- /* Fetch core register values */
- /* E880FFFF STM R0, {R0-R15} */
- arm7_op_debug(t, 0xE880FFFF, t->reg_cache, 16);
-
- return 1;
-}
-
-static void arm7_halt_resume(struct target_s *target, bool step)
-{
- struct target_arm7_s *t = (struct target_arm7_s *)target;
-
- if(step) {
- /* FIXME: Set breakpoint on any instruction to single step. */
- }
-
- /* Restore core registers. */
- /* E890FFFF LDM R0, {R0-R15} */
- arm7_op_debug(t, 0xE890FFFF, t->reg_cache, 16);
-
- /* Release DBGRQ */
- arm7_eice_write(t, ARM7_EICE_DEBUG_CTRL, 0);
- /* This sequence restores PC if no other instructions issued in
- * debug mode...
- * 0 E1A00000; MOV R0, R0
- * 1 E1A00000; MOV R0, R0
- * 0 EAFFFFFA; B -6
- * FIXME: Add adjustment for other opcodes.
- */
- arm7_op_debug(t, ARM7_OP_NOP, NULL, 0);
- arm7_op_system(t, ARM7_OP_NOP);
- arm7_op_debug(t, 0xEAFFFFF8, NULL, 0);
-
- jtag_dev_write_ir(t->jtag, ARM7_IR_RESTART);
-}
-
-static bool arm7_attach(struct target_s *target)
-{
- int tries = 0;
- target_halt_request(target);
- while(!target_halt_wait(target) && --tries)
- platform_delay(2);
- if(!tries)
- return false;
- return true;
-}
-
-static int arm7_regs_read(struct target_s *target, void *data)
-{
- struct target_arm7_s *t = (struct target_arm7_s *)target;
- memcpy(data, t->reg_cache, target->regs_size);
- return 0;
-}
-
-static int arm7_regs_write(struct target_s *target, const void *data)
-{
- struct target_arm7_s *t = (struct target_arm7_s *)target;
- memcpy(t->reg_cache, data, target->regs_size);
- return 0;
-}
-
diff --git a/src/command.c b/src/command.c
index 64e4ed6..8e20960 100644
--- a/src/command.c
+++ b/src/command.c
@@ -23,6 +23,7 @@
*/
#include "general.h"
+#include "exception.h"
#include "command.h"
#include "gdb_packet.h"
#include "jtag_scan.h"
@@ -139,19 +140,30 @@ bool cmd_help(target *t)
static bool cmd_jtag_scan(target *t, int argc, char **argv)
{
(void)t;
- uint8_t *irlens = NULL;
+ uint8_t irlens[argc];
gdb_outf("Target voltage: %s\n", platform_target_voltage());
if (argc > 1) {
/* Accept a list of IR lengths on command line */
- irlens = alloca(argc);
for (int i = 1; i < argc; i++)
irlens[i-1] = atoi(argv[i]);
irlens[argc-1] = 0;
}
- int devs = jtag_scan(irlens);
+ int devs = -1;
+ volatile struct exception e;
+ TRY_CATCH (e, EXCEPTION_ALL) {
+ devs = jtag_scan(argc > 1 ? irlens : NULL);
+ }
+ switch (e.type) {
+ case EXCEPTION_TIMEOUT:
+ gdb_outf("Timeout during scan. Is target stuck in WFI?\n");
+ break;
+ case EXCEPTION_ERROR:
+ gdb_outf("Exception: %s\n", e.msg);
+ break;
+ }
if(devs < 0) {
gdb_out("JTAG device scan failed!\n");
@@ -175,13 +187,25 @@ bool cmd_swdp_scan(void)
{
gdb_outf("Target voltage: %s\n", platform_target_voltage());
- if(adiv5_swdp_scan() < 0) {
+ int devs = -1;
+ volatile struct exception e;
+ TRY_CATCH (e, EXCEPTION_ALL) {
+ devs = adiv5_swdp_scan();
+ }
+ switch (e.type) {
+ case EXCEPTION_TIMEOUT:
+ gdb_outf("Timeout during scan. Is target stuck in WFI?\n");
+ break;
+ case EXCEPTION_ERROR:
+ gdb_outf("Exception: %s\n", e.msg);
+ break;
+ }
+
+ if(devs < 0) {
gdb_out("SW-DP scan failed!\n");
return false;
}
- //gdb_outf("SW-DP detected IDCODE: 0x%08X\n", adiv5_dp_list->idcode);
-
cmd_targets(NULL);
return true;
diff --git a/src/cortexm.c b/src/cortexm.c
index b1d3569..ae1c59d 100644
--- a/src/cortexm.c
+++ b/src/cortexm.c
@@ -24,11 +24,9 @@
* ARM doc DDI0403C.
*
* Also supports Cortex-M0 / ARMv6-M
- *
- * Issues:
- * There are way too many magic numbers used here.
*/
#include "general.h"
+#include "exception.h"
#include "jtagtap.h"
#include "jtag_scan.h"
#include "adiv5.h"
@@ -36,6 +34,7 @@
#include "command.h"
#include "gdb_packet.h"
#include "cortexm.h"
+#include "morse.h"
#include <unistd.h>
@@ -56,23 +55,24 @@ const struct command_s cortexm_cmd_list[] = {
#define SIGINT 2
#define SIGTRAP 5
#define SIGSEGV 11
+#define SIGLOST 29
-static int cortexm_regs_read(struct target_s *target, void *data);
-static int cortexm_regs_write(struct target_s *target, const void *data);
-static int cortexm_pc_write(struct target_s *target, const uint32_t val);
+static void cortexm_regs_read(target *t, void *data);
+static void cortexm_regs_write(target *t, const void *data);
+static uint32_t cortexm_pc_read(target *t);
-static void cortexm_reset(struct target_s *target);
-static int cortexm_halt_wait(struct target_s *target);
-static void cortexm_halt_request(struct target_s *target);
-static int cortexm_fault_unwind(struct target_s *target);
+static void cortexm_reset(target *t);
+static int cortexm_halt_wait(target *t);
+static void cortexm_halt_request(target *t);
+static int cortexm_fault_unwind(target *t);
-static int cortexm_set_hw_bp(struct target_s *target, uint32_t addr);
-static int cortexm_clear_hw_bp(struct target_s *target, uint32_t addr);
+static int cortexm_set_hw_bp(target *t, uint32_t addr);
+static int cortexm_clear_hw_bp(target *t, uint32_t addr);
-static int cortexm_set_hw_wp(struct target_s *target, uint8_t type, uint32_t addr, uint8_t len);
-static int cortexm_clear_hw_wp(struct target_s *target, uint8_t type, uint32_t addr, uint8_t len);
+static int cortexm_set_hw_wp(target *t, uint8_t type, uint32_t addr, uint8_t len);
+static int cortexm_clear_hw_wp(target *t, uint8_t type, uint32_t addr, uint8_t len);
-static int cortexm_check_hw_wp(struct target_s *target, uint32_t *addr);
+static int cortexm_check_hw_wp(target *t, uint32_t *addr);
#define CORTEXM_MAX_WATCHPOINTS 4 /* architecture says up to 15, no implementation has > 4 */
#define CORTEXM_MAX_BREAKPOINTS 6 /* architecture says up to 127, no implementation has > 6 */
@@ -203,41 +203,39 @@ static const char tdesc_cortex_mf[] =
#define REG_PSP 18
#define REG_SPECIAL 19
-bool
-cortexm_probe(struct target_s *target)
+bool cortexm_probe(target *t)
{
- target->driver = cortexm_driver_str;
+ t->driver = cortexm_driver_str;
- target->attach = cortexm_attach;
- target->detach = cortexm_detach;
+ t->attach = cortexm_attach;
+ t->detach = cortexm_detach;
/* Should probe here to make sure it's Cortex-M3 */
- target->tdesc = tdesc_cortex_m;
- target->regs_read = cortexm_regs_read;
- target->regs_write = cortexm_regs_write;
- target->pc_write = cortexm_pc_write;
+ t->tdesc = tdesc_cortex_m;
+ t->regs_read = cortexm_regs_read;
+ t->regs_write = cortexm_regs_write;
- target->reset = cortexm_reset;
- target->halt_request = cortexm_halt_request;
- target->halt_wait = cortexm_halt_wait;
- target->halt_resume = cortexm_halt_resume;
- target->regs_size = sizeof(regnum_cortex_m);
+ t->reset = cortexm_reset;
+ t->halt_request = cortexm_halt_request;
+ t->halt_wait = cortexm_halt_wait;
+ t->halt_resume = cortexm_halt_resume;
+ t->regs_size = sizeof(regnum_cortex_m);
- target->hostio_reply = cortexm_hostio_reply;
+ t->hostio_reply = cortexm_hostio_reply;
- target_add_commands(target, cortexm_cmd_list, cortexm_driver_str);
+ target_add_commands(t, cortexm_cmd_list, cortexm_driver_str);
/* Probe for FP extension */
- ADIv5_AP_t *ap = adiv5_target_ap(target);
- uint32_t cpacr = adiv5_ap_mem_read(ap, CORTEXM_CPACR);
+ uint32_t cpacr = target_mem_read32(t, CORTEXM_CPACR);
cpacr |= 0x00F00000; /* CP10 = 0b11, CP11 = 0b11 */
- adiv5_ap_mem_write(ap, CORTEXM_CPACR, cpacr);
- if (adiv5_ap_mem_read(ap, CORTEXM_CPACR) == cpacr) {
- target->target_options |= TOPT_FLAVOUR_V7MF;
- target->regs_size += sizeof(regnum_cortex_mf);
- target->tdesc = tdesc_cortex_mf;
+ target_mem_write32(t, CORTEXM_CPACR, cpacr);
+ if (target_mem_read32(t, CORTEXM_CPACR) == cpacr) {
+ t->target_options |= TOPT_FLAVOUR_V7MF;
+ t->regs_size += sizeof(regnum_cortex_mf);
+ t->tdesc = tdesc_cortex_mf;
}
+ ADIv5_AP_t *ap = adiv5_target_ap(t);
struct cortexm_priv *priv = calloc(1, sizeof(*priv));
ap->priv = priv;
ap->priv_free = free;
@@ -247,12 +245,11 @@ cortexm_probe(struct target_s *target)
CORTEXM_DEMCR_VC_CORERESET;
#define PROBE(x) \
- do { if ((x)(target)) return true; else target_check_error(target); } while (0)
+ do { if ((x)(t)) return true; else target_check_error(t); } while (0)
PROBE(stm32f1_probe);
PROBE(stm32f4_probe);
PROBE(stm32l0_probe); /* STM32L0xx & STM32L1xx */
- PROBE(stm32l1_probe);
PROBE(lpc11xx_probe);
PROBE(lpc43xx_probe);
PROBE(sam3x_probe);
@@ -265,62 +262,62 @@ cortexm_probe(struct target_s *target)
return true;
}
-bool cortexm_attach(struct target_s *target)
+bool cortexm_attach(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
+ ADIv5_AP_t *ap = adiv5_target_ap(t);
struct cortexm_priv *priv = ap->priv;
unsigned i;
uint32_t r;
int tries;
/* Clear any pending fault condition */
- target_check_error(target);
+ target_check_error(t);
- target_halt_request(target);
+ target_halt_request(t);
tries = 10;
- while(!connect_assert_srst && !target_halt_wait(target) && --tries)
+ while(!connect_assert_srst && !target_halt_wait(t) && --tries)
platform_delay(2);
if(!tries)
return false;
/* Request halt on reset */
- adiv5_ap_mem_write(ap, CORTEXM_DEMCR, priv->demcr);
+ target_mem_write32(t, CORTEXM_DEMCR, priv->demcr);
/* Reset DFSR flags */
- adiv5_ap_mem_write(ap, CORTEXM_DFSR, CORTEXM_DFSR_RESETALL);
+ target_mem_write32(t, CORTEXM_DFSR, CORTEXM_DFSR_RESETALL);
/* size the break/watchpoint units */
priv->hw_breakpoint_max = CORTEXM_MAX_BREAKPOINTS;
- r = adiv5_ap_mem_read(ap, CORTEXM_FPB_CTRL);
+ r = target_mem_read32(t, CORTEXM_FPB_CTRL);
if (((r >> 4) & 0xf) < priv->hw_breakpoint_max) /* only look at NUM_COMP1 */
priv->hw_breakpoint_max = (r >> 4) & 0xf;
priv->hw_watchpoint_max = CORTEXM_MAX_WATCHPOINTS;
- r = adiv5_ap_mem_read(ap, CORTEXM_DWT_CTRL);
+ r = target_mem_read32(t, CORTEXM_DWT_CTRL);
if ((r >> 28) > priv->hw_watchpoint_max)
priv->hw_watchpoint_max = r >> 28;
/* Clear any stale breakpoints */
for(i = 0; i < priv->hw_breakpoint_max; i++) {
- adiv5_ap_mem_write(ap, CORTEXM_FPB_COMP(i), 0);
+ target_mem_write32(t, CORTEXM_FPB_COMP(i), 0);
priv->hw_breakpoint[i] = 0;
}
/* Clear any stale watchpoints */
for(i = 0; i < priv->hw_watchpoint_max; i++) {
- adiv5_ap_mem_write(ap, CORTEXM_DWT_FUNC(i), 0);
+ target_mem_write32(t, CORTEXM_DWT_FUNC(i), 0);
priv->hw_watchpoint[i].type = 0;
}
/* Flash Patch Control Register: set ENABLE */
- adiv5_ap_mem_write(ap, CORTEXM_FPB_CTRL,
+ target_mem_write32(t, CORTEXM_FPB_CTRL,
CORTEXM_FPB_CTRL_KEY | CORTEXM_FPB_CTRL_ENABLE);
- target->set_hw_bp = cortexm_set_hw_bp;
- target->clear_hw_bp = cortexm_clear_hw_bp;
+ t->set_hw_bp = cortexm_set_hw_bp;
+ t->clear_hw_bp = cortexm_clear_hw_bp;
/* Data Watchpoint and Trace */
- target->set_hw_wp = cortexm_set_hw_wp;
- target->clear_hw_wp = cortexm_clear_hw_wp;
- target->check_hw_wp = cortexm_check_hw_wp;
+ t->set_hw_wp = cortexm_set_hw_wp;
+ t->clear_hw_wp = cortexm_clear_hw_wp;
+ t->check_hw_wp = cortexm_check_hw_wp;
if(connect_assert_srst)
jtagtap_srst(false);
@@ -328,164 +325,171 @@ bool cortexm_attach(struct target_s *target)
return true;
}
-void cortexm_detach(struct target_s *target)
+void cortexm_detach(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
+ ADIv5_AP_t *ap = adiv5_target_ap(t);
struct cortexm_priv *priv = ap->priv;
unsigned i;
/* Clear any stale breakpoints */
for(i = 0; i < priv->hw_breakpoint_max; i++)
- adiv5_ap_mem_write(ap, CORTEXM_FPB_COMP(i), 0);
+ target_mem_write32(t, CORTEXM_FPB_COMP(i), 0);
/* Clear any stale watchpoints */
for(i = 0; i < priv->hw_watchpoint_max; i++)
- adiv5_ap_mem_write(ap, CORTEXM_DWT_FUNC(i), 0);
+ target_mem_write32(t, CORTEXM_DWT_FUNC(i), 0);
/* Disable debug */
- adiv5_ap_mem_write(ap, CORTEXM_DHCSR, CORTEXM_DHCSR_DBGKEY);
+ target_mem_write32(t, CORTEXM_DHCSR, CORTEXM_DHCSR_DBGKEY);
}
-static int
-cortexm_regs_read(struct target_s *target, void *data)
+enum { DB_DHCSR, DB_DCRSR, DB_DCRDR, DB_DEMCR };
+
+static void cortexm_regs_read(target *t, void *data)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
+ ADIv5_AP_t *ap = adiv5_target_ap(t);
uint32_t *regs = data;
unsigned i;
/* FIXME: Describe what's really going on here */
- adiv5_ap_write(ap, ADIV5_AP_CSW, ap->csw |
- ADIV5_AP_CSW_SIZE_WORD | ADIV5_AP_CSW_ADDRINC_SINGLE);
+ adiv5_ap_write(ap, ADIV5_AP_CSW, ap->csw | ADIV5_AP_CSW_SIZE_WORD);
/* Map the banked data registers (0x10-0x1c) to the
* debug registers DHCSR, DCRSR, DCRDR and DEMCR respectively */
- adiv5_dp_low_access(ap->dp, 1, 0, ADIV5_AP_TAR, CORTEXM_DHCSR);
+ adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, ADIV5_AP_TAR, CORTEXM_DHCSR);
/* Walk the regnum_cortex_m array, reading the registers it
* calls out. */
- adiv5_ap_write(ap, ADIV5_AP_DB(1), regnum_cortex_m[0]); /* Required to switch banks */
- *regs++ = adiv5_dp_read_ap(ap->dp, ADIV5_AP_DB(2));
+ adiv5_ap_write(ap, ADIV5_AP_DB(DB_DCRSR), regnum_cortex_m[0]); /* Required to switch banks */
+ *regs++ = adiv5_dp_read(ap->dp, ADIV5_AP_DB(DB_DCRDR));
for(i = 1; i < sizeof(regnum_cortex_m) / 4; i++) {
- adiv5_dp_low_access(ap->dp, 1, 0, ADIV5_AP_DB(1), regnum_cortex_m[i]);
- *regs++ = adiv5_dp_read_ap(ap->dp, ADIV5_AP_DB(2));
+ adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, ADIV5_AP_DB(DB_DCRSR),
+ regnum_cortex_m[i]);
+ *regs++ = adiv5_dp_read(ap->dp, ADIV5_AP_DB(DB_DCRDR));
}
- if (target->target_options & TOPT_FLAVOUR_V7MF)
+ if (t->target_options & TOPT_FLAVOUR_V7MF)
for(i = 0; i < sizeof(regnum_cortex_mf) / 4; i++) {
- adiv5_dp_low_access(ap->dp, 1, 0, ADIV5_AP_DB(1), regnum_cortex_mf[i]);
- *regs++ = adiv5_dp_read_ap(ap->dp, ADIV5_AP_DB(2));
+ adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE,
+ ADIV5_AP_DB(DB_DCRSR),
+ regnum_cortex_mf[i]);
+ *regs++ = adiv5_dp_read(ap->dp, ADIV5_AP_DB(DB_DCRDR));
}
-
- return 0;
}
-static int
-cortexm_regs_write(struct target_s *target, const void *data)
+static void cortexm_regs_write(target *t, const void *data)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
+ ADIv5_AP_t *ap = adiv5_target_ap(t);
const uint32_t *regs = data;
unsigned i;
/* FIXME: Describe what's really going on here */
- adiv5_ap_write(ap, ADIV5_AP_CSW, ap->csw |
- ADIV5_AP_CSW_SIZE_WORD | ADIV5_AP_CSW_ADDRINC_SINGLE);
+ adiv5_ap_write(ap, ADIV5_AP_CSW, ap->csw | ADIV5_AP_CSW_SIZE_WORD);
/* Map the banked data registers (0x10-0x1c) to the
* debug registers DHCSR, DCRSR, DCRDR and DEMCR respectively */
- adiv5_dp_low_access(ap->dp, 1, 0, ADIV5_AP_TAR, CORTEXM_DHCSR);
+ adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, ADIV5_AP_TAR, CORTEXM_DHCSR);
/* Walk the regnum_cortex_m array, writing the registers it
* calls out. */
- adiv5_ap_write(ap, ADIV5_AP_DB(2), *regs++); /* Required to switch banks */
- adiv5_dp_low_access(ap->dp, 1, 0, ADIV5_AP_DB(1), 0x10000 | regnum_cortex_m[0]);
+ adiv5_ap_write(ap, ADIV5_AP_DB(DB_DCRDR), *regs++); /* Required to switch banks */
+ adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, ADIV5_AP_DB(DB_DCRSR),
+ 0x10000 | regnum_cortex_m[0]);
for(i = 1; i < sizeof(regnum_cortex_m) / 4; i++) {
- adiv5_dp_low_access(ap->dp, 1, 0, ADIV5_AP_DB(2), *regs++);
- adiv5_dp_low_access(ap->dp, 1, 0, ADIV5_AP_DB(1),
- 0x10000 | regnum_cortex_m[i]);
+ adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE,
+ ADIV5_AP_DB(DB_DCRDR), *regs++);
+ adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, ADIV5_AP_DB(DB_DCRSR),
+ 0x10000 | regnum_cortex_m[i]);
}
- if (target->target_options & TOPT_FLAVOUR_V7MF)
+ if (t->target_options & TOPT_FLAVOUR_V7MF)
for(i = 0; i < sizeof(regnum_cortex_mf) / 4; i++) {
- adiv5_dp_low_access(ap->dp, 1, 0, ADIV5_AP_DB(2), *regs++);
- adiv5_dp_low_access(ap->dp, 1, 0, ADIV5_AP_DB(1),
- 0x10000 | regnum_cortex_mf[i]);
+ adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE,
+ ADIV5_AP_DB(DB_DCRDR), *regs++);
+ adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE,
+ ADIV5_AP_DB(DB_DCRSR),
+ 0x10000 | regnum_cortex_mf[i]);
}
-
- return 0;
}
-static uint32_t
-cortexm_pc_read(struct target_s *target)
+static uint32_t cortexm_pc_read(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
-
- adiv5_ap_mem_write(ap, CORTEXM_DCRSR, 0x0F);
- return adiv5_ap_mem_read(ap, CORTEXM_DCRDR);
-
- return 0;
+ target_mem_write32(t, CORTEXM_DCRSR, 0x0F);
+ return target_mem_read32(t, CORTEXM_DCRDR);
}
-static int
-cortexm_pc_write(struct target_s *target, const uint32_t val)
+static void cortexm_pc_write(target *t, const uint32_t val)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
-
- adiv5_ap_mem_write(ap, CORTEXM_DCRDR, val);
- adiv5_ap_mem_write(ap, CORTEXM_DCRSR, CORTEXM_DCRSR_REGWnR | 0x0F);
-
- return 0;
+ target_mem_write32(t, CORTEXM_DCRDR, val);
+ target_mem_write32(t, CORTEXM_DCRSR, CORTEXM_DCRSR_REGWnR | 0x0F);
}
/* The following three routines implement target halt/resume
* using the core debug registers in the NVIC. */
-static void
-cortexm_reset(struct target_s *target)
+static void cortexm_reset(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
-
jtagtap_srst(true);
jtagtap_srst(false);
/* Read DHCSR here to clear S_RESET_ST bit before reset */
- adiv5_ap_mem_read(ap, CORTEXM_DHCSR);
+ target_mem_read32(t, CORTEXM_DHCSR);
/* Request system reset from NVIC: SRST doesn't work correctly */
/* This could be VECTRESET: 0x05FA0001 (reset only core)
* or SYSRESETREQ: 0x05FA0004 (system reset)
*/
- adiv5_ap_mem_write(ap, CORTEXM_AIRCR,
- CORTEXM_AIRCR_VECTKEY | CORTEXM_AIRCR_SYSRESETREQ);
+ target_mem_write32(t, CORTEXM_AIRCR,
+ CORTEXM_AIRCR_VECTKEY | CORTEXM_AIRCR_SYSRESETREQ);
/* Poll for release from reset */
- while(adiv5_ap_mem_read(ap, CORTEXM_DHCSR) & CORTEXM_DHCSR_S_RESET_ST);
+ while (target_mem_read32(t, CORTEXM_DHCSR) & CORTEXM_DHCSR_S_RESET_ST);
/* Reset DFSR flags */
- adiv5_ap_mem_write(ap, CORTEXM_DFSR, CORTEXM_DFSR_RESETALL);
+ target_mem_write32(t, CORTEXM_DFSR, CORTEXM_DFSR_RESETALL);
}
-static void
-cortexm_halt_request(struct target_s *target)
+static void cortexm_halt_request(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
-
- ap->dp->allow_timeout = false;
- adiv5_ap_mem_write(ap, CORTEXM_DHCSR,
- CORTEXM_DHCSR_DBGKEY | CORTEXM_DHCSR_C_HALT | CORTEXM_DHCSR_C_DEBUGEN);
+ volatile struct exception e;
+ TRY_CATCH (e, EXCEPTION_TIMEOUT) {
+ target_mem_write32(t, CORTEXM_DHCSR, CORTEXM_DHCSR_DBGKEY |
+ CORTEXM_DHCSR_C_HALT |
+ CORTEXM_DHCSR_C_DEBUGEN);
+ }
+ if (e.type) {
+ gdb_out("Timeout sending interrupt, is target in WFI?\n");
+ }
}
-static int
-cortexm_halt_wait(struct target_s *target)
+static int cortexm_halt_wait(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
+ ADIv5_AP_t *ap = adiv5_target_ap(t);
struct cortexm_priv *priv = ap->priv;
- if (!(adiv5_ap_mem_read(ap, CORTEXM_DHCSR) & CORTEXM_DHCSR_S_HALT))
+
+ volatile uint32_t dhcsr = 0;
+ volatile struct exception e;
+ TRY_CATCH (e, EXCEPTION_ALL) {
+ /* If this times out because the target is in WFI then
+ * the target is still running. */
+ dhcsr = target_mem_read32(t, CORTEXM_DHCSR);
+ }
+ switch (e.type) {
+ case EXCEPTION_ERROR:
+ /* Oh crap, there's no recovery from this... */
+ target_list_free();
+ morse("TARGET LOST.", 1);
+ return SIGLOST;
+ case EXCEPTION_TIMEOUT:
+ /* Timeout isn't a problem, target could be in WFI */
return 0;
+ }
- ap->dp->allow_timeout = false;
+ if (!(dhcsr & CORTEXM_DHCSR_S_HALT))
+ return 0;
/* We've halted. Let's find out why. */
- uint32_t dfsr = adiv5_ap_mem_read(ap, CORTEXM_DFSR);
- adiv5_ap_mem_write(ap, CORTEXM_DFSR, dfsr); /* write back to reset */
+ uint32_t dfsr = target_mem_read32(t, CORTEXM_DFSR);
+ target_mem_write32(t, CORTEXM_DFSR, dfsr); /* write back to reset */
- if ((dfsr & CORTEXM_DFSR_VCATCH) && cortexm_fault_unwind(target))
+ if ((dfsr & CORTEXM_DFSR_VCATCH) && cortexm_fault_unwind(t))
return SIGSEGV;
/* Remember if we stopped on a breakpoint */
@@ -493,13 +497,13 @@ cortexm_halt_wait(struct target_s *target)
if (priv->on_bkpt) {
/* If we've hit a programmed breakpoint, check for semihosting
* call. */
- uint32_t pc = cortexm_pc_read(target);
+ uint32_t pc = cortexm_pc_read(t);
uint16_t bkpt_instr;
- target_mem_read_bytes(target, (uint8_t *)&bkpt_instr, pc, 2);
+ bkpt_instr = target_mem_read16(t, pc);
if (bkpt_instr == 0xBEAB) {
- int n = cortexm_hostio_request(target);
+ int n = cortexm_hostio_request(t);
if (n > 0) {
- target_halt_resume(target, priv->stepping);
+ target_halt_resume(t, priv->stepping);
return 0;
} else if (n < 0) {
return -1;
@@ -517,9 +521,9 @@ cortexm_halt_wait(struct target_s *target)
}
-void cortexm_halt_resume(struct target_s *target, bool step)
+void cortexm_halt_resume(target *t, bool step)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
+ ADIv5_AP_t *ap = adiv5_target_ap(t);
struct cortexm_priv *priv = ap->priv;
uint32_t dhcsr = CORTEXM_DHCSR_DBGKEY | CORTEXM_DHCSR_C_DEBUGEN;
@@ -528,44 +532,42 @@ void cortexm_halt_resume(struct target_s *target, bool step)
/* Disable interrupts while single stepping... */
if(step != priv->stepping) {
- adiv5_ap_mem_write(ap, CORTEXM_DHCSR, dhcsr | CORTEXM_DHCSR_C_HALT);
+ target_mem_write32(t, CORTEXM_DHCSR, dhcsr | CORTEXM_DHCSR_C_HALT);
priv->stepping = step;
}
if (priv->on_bkpt) {
- uint32_t pc = cortexm_pc_read(target);
- if ((adiv5_ap_mem_read_halfword(ap, pc) & 0xFF00) == 0xBE00)
- cortexm_pc_write(target, pc + 2);
+ uint32_t pc = cortexm_pc_read(t);
+ if ((target_mem_read16(t, pc) & 0xFF00) == 0xBE00)
+ cortexm_pc_write(t, pc + 2);
}
- adiv5_ap_mem_write(ap, CORTEXM_DHCSR, dhcsr);
- ap->dp->allow_timeout = true;
+ target_mem_write32(t, CORTEXM_DHCSR, dhcsr);
}
-static int cortexm_fault_unwind(struct target_s *target)
+static int cortexm_fault_unwind(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
- uint32_t hfsr = adiv5_ap_mem_read(ap, CORTEXM_HFSR);
- uint32_t cfsr = adiv5_ap_mem_read(ap, CORTEXM_CFSR);
- adiv5_ap_mem_write(ap, CORTEXM_HFSR, hfsr);/* write back to reset */
- adiv5_ap_mem_write(ap, CORTEXM_CFSR, cfsr);/* write back to reset */
+ uint32_t hfsr = target_mem_read32(t, CORTEXM_HFSR);
+ uint32_t cfsr = target_mem_read32(t, CORTEXM_CFSR);
+ target_mem_write32(t, CORTEXM_HFSR, hfsr);/* write back to reset */
+ target_mem_write32(t, CORTEXM_CFSR, cfsr);/* write back to reset */
/* We check for FORCED in the HardFault Status Register or
* for a configurable fault to avoid catching core resets */
if((hfsr & CORTEXM_HFSR_FORCED) || cfsr) {
/* Unwind exception */
- uint32_t regs[target->regs_size / 4];
+ uint32_t regs[t->regs_size / 4];
uint32_t stack[8];
uint32_t retcode, framesize;
/* Read registers for post-exception stack pointer */
- target_regs_read(target, regs);
+ target_regs_read(t, regs);
/* save retcode currently in lr */
retcode = regs[REG_LR];
bool spsel = retcode & (1<<2);
bool fpca = !(retcode & (1<<4));
/* Read stack for pre-exception registers */
uint32_t sp = spsel ? regs[REG_PSP] : regs[REG_MSP];
- target_mem_read_words(target, stack, sp, sizeof(stack));
- if (target_check_error(target))
+ target_mem_read(t, stack, sp, sizeof(stack));
+ if (target_check_error(t))
return 0;
regs[REG_LR] = stack[5]; /* restore LR to pre-exception state */
regs[REG_PC] = stack[6]; /* restore PC to pre-exception state */
@@ -591,24 +593,55 @@ static int cortexm_fault_unwind(struct target_s *target)
/* Reset exception state to allow resuming from restored
* state.
*/
- adiv5_ap_mem_write(ap, CORTEXM_AIRCR,
+ target_mem_write32(t, CORTEXM_AIRCR,
CORTEXM_AIRCR_VECTKEY | CORTEXM_AIRCR_VECTCLRACTIVE);
/* Write pre-exception registers back to core */
- target_regs_write(target, regs);
+ target_regs_write(t, regs);
return 1;
}
return 0;
}
+int cortexm_run_stub(target *t, uint32_t loadaddr,
+ uint32_t r0, uint32_t r1, uint32_t r2, uint32_t r3)
+{
+ uint32_t regs[t->regs_size / 4];
+
+ memset(regs, 0, sizeof(regs));
+ regs[0] = r0;
+ regs[1] = r1;
+ regs[2] = r2;
+ regs[3] = r3;
+ regs[15] = loadaddr;
+ regs[16] = 0x1000000;
+ regs[19] = 0;
+
+ cortexm_regs_write(t, regs);
+
+ if (target_check_error(t))
+ return -1;
+
+ /* Execute the stub */
+ cortexm_halt_resume(t, 0);
+ while (!cortexm_halt_wait(t))
+ ;
+
+ uint32_t pc = cortexm_pc_read(t);
+ uint16_t bkpt_instr = target_mem_read16(t, pc);
+ if (bkpt_instr >> 8 != 0xbe)
+ return -2;
+
+ return bkpt_instr & 0xff;
+}
+
/* The following routines implement hardware breakpoints.
* The Flash Patch and Breakpoint (FPB) system is used. */
-static int
-cortexm_set_hw_bp(struct target_s *target, uint32_t addr)
+static int cortexm_set_hw_bp(target *t, uint32_t addr)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
+ ADIv5_AP_t *ap = adiv5_target_ap(t);
struct cortexm_priv *priv = ap->priv;
uint32_t val = addr & 0x1FFFFFFC;
unsigned i;
@@ -623,15 +656,14 @@ cortexm_set_hw_bp(struct target_s *target, uint32_t addr)
priv->hw_breakpoint[i] = addr | 1;
- adiv5_ap_mem_write(ap, CORTEXM_FPB_COMP(i), val);
+ target_mem_write32(t, CORTEXM_FPB_COMP(i), val);
return 0;
}
-static int
-cortexm_clear_hw_bp(struct target_s *target, uint32_t addr)
+static int cortexm_clear_hw_bp(target *t, uint32_t addr)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
+ ADIv5_AP_t *ap = adiv5_target_ap(t);
struct cortexm_priv *priv = ap->priv;
unsigned i;
@@ -642,19 +674,18 @@ cortexm_clear_hw_bp(struct target_s *target, uint32_t addr)
priv->hw_breakpoint[i] = 0;
- adiv5_ap_mem_write(ap, CORTEXM_FPB_COMP(i), 0);
+ target_mem_write32(t, CORTEXM_FPB_COMP(i), 0);
return 0;
}
-
/* The following routines implement hardware watchpoints.
* The Data Watch and Trace (DWT) system is used. */
static int
-cortexm_set_hw_wp(struct target_s *target, uint8_t type, uint32_t addr, uint8_t len)
+cortexm_set_hw_wp(target *t, uint8_t type, uint32_t addr, uint8_t len)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
+ ADIv5_AP_t *ap = adiv5_target_ap(t);
struct cortexm_priv *priv = ap->priv;
unsigned i;
@@ -676,7 +707,7 @@ cortexm_set_hw_wp(struct target_s *target, uint8_t type, uint32_t addr, uint8_t
for(i = 0; i < priv->hw_watchpoint_max; i++)
if((priv->hw_watchpoint[i].type == 0) &&
- ((adiv5_ap_mem_read(ap, CORTEXM_DWT_FUNC(i)) & 0xF) == 0))
+ ((target_mem_read32(t, CORTEXM_DWT_FUNC(i)) & 0xF) == 0))
break;
if(i == priv->hw_watchpoint_max) return -2;
@@ -685,18 +716,18 @@ cortexm_set_hw_wp(struct target_s *target, uint8_t type, uint32_t addr, uint8_t
priv->hw_watchpoint[i].addr = addr;
priv->hw_watchpoint[i].size = len;
- adiv5_ap_mem_write(ap, CORTEXM_DWT_COMP(i), addr);
- adiv5_ap_mem_write(ap, CORTEXM_DWT_MASK(i), len);
- adiv5_ap_mem_write(ap, CORTEXM_DWT_FUNC(i), type |
- ((target->target_options & TOPT_FLAVOUR_V6M) ? 0: CORTEXM_DWT_FUNC_DATAVSIZE_WORD));
+ target_mem_write32(t, CORTEXM_DWT_COMP(i), addr);
+ target_mem_write32(t, CORTEXM_DWT_MASK(i), len);
+ target_mem_write32(t, CORTEXM_DWT_FUNC(i), type |
+ ((t->target_options & TOPT_FLAVOUR_V6M) ? 0: CORTEXM_DWT_FUNC_DATAVSIZE_WORD));
return 0;
}
static int
-cortexm_clear_hw_wp(struct target_s *target, uint8_t type, uint32_t addr, uint8_t len)
+cortexm_clear_hw_wp(target *t, uint8_t type, uint32_t addr, uint8_t len)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
+ ADIv5_AP_t *ap = adiv5_target_ap(t);
struct cortexm_priv *priv = ap->priv;
unsigned i;
@@ -725,22 +756,21 @@ cortexm_clear_hw_wp(struct target_s *target, uint8_t type, uint32_t addr, uint8_
priv->hw_watchpoint[i].type = 0;
- adiv5_ap_mem_write(ap, CORTEXM_DWT_FUNC(i), 0);
+ target_mem_write32(t, CORTEXM_DWT_FUNC(i), 0);
return 0;
}
-static int
-cortexm_check_hw_wp(struct target_s *target, uint32_t *addr)
+static int cortexm_check_hw_wp(target *t, uint32_t *addr)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
+ ADIv5_AP_t *ap = adiv5_target_ap(t);
struct cortexm_priv *priv = ap->priv;
unsigned i;
for(i = 0; i < priv->hw_watchpoint_max; i++)
/* if SET and MATCHED then break */
if(priv->hw_watchpoint[i].type &&
- (adiv5_ap_mem_read(ap, CORTEXM_DWT_FUNC(i)) &
+ (target_mem_read32(t, CORTEXM_DWT_FUNC(i)) &
CORTEXM_DWT_FUNC_MATCHED))
break;
@@ -774,7 +804,7 @@ static bool cortexm_vector_catch(target *t, int argc, char *argv[])
else
priv->demcr &= ~tmp;
- adiv5_ap_mem_write(ap, CORTEXM_DEMCR, priv->demcr);
+ target_mem_write32(t, CORTEXM_DEMCR, priv->demcr);
}
gdb_out("Catching vectors: ");
@@ -833,7 +863,7 @@ static int cortexm_hostio_request(target *t)
uint32_t params[4];
target_regs_read(t, arm_regs);
- target_mem_read_words(t, params, arm_regs[1], sizeof(params));
+ target_mem_read(t, params, arm_regs[1], sizeof(params));
priv->syscall = arm_regs[0];
DEBUG("syscall 0x%x (%x %x %x %x)\n", priv->syscall,
@@ -853,8 +883,7 @@ static int cortexm_hostio_request(target *t)
uint32_t pflag = flags[params[1] >> 1];
char filename[4];
- target_mem_read_bytes(t, (uint8_t *)filename,
- params[0], sizeof(filename));
+ target_mem_read(t, filename, params[0], sizeof(filename));
/* handle requests for console i/o */
if (!strcmp(filename, ":tt")) {
if (pflag == FILEIO_O_RDONLY)
diff --git a/src/crc32.c b/src/crc32.c
index 42d1d48..6f1c0e3 100644
--- a/src/crc32.c
+++ b/src/crc32.c
@@ -94,14 +94,13 @@ uint32_t crc32_calc(uint32_t crc, uint8_t data)
return (crc << 8) ^ crc32_table[((crc >> 24) ^ data) & 255];
}
-uint32_t generic_crc32(struct target_s *target, uint32_t base, int len)
+uint32_t generic_crc32(target *t, uint32_t base, int len)
{
uint32_t crc = -1;
uint8_t byte;
while (len--) {
- if (target_mem_read_bytes(target, &byte, base, 1) != 0)
- return -1;
+ byte = target_mem_read8(t, base);
crc = crc32_calc(crc, byte);
base++;
@@ -110,7 +109,7 @@ uint32_t generic_crc32(struct target_s *target, uint32_t base, int len)
}
#else
#include <libopencm3/stm32/crc.h>
-uint32_t generic_crc32(struct target_s *target, uint32_t base, int len)
+uint32_t generic_crc32(target *t, uint32_t base, int len)
{
uint32_t data;
uint32_t crc;
@@ -119,8 +118,7 @@ uint32_t generic_crc32(struct target_s *target, uint32_t base, int len)
CRC_CR |= CRC_CR_RESET;
while (len > 3) {
- if (target_mem_read_words(target, &data, base, 4) != 0)
- return -1;
+ data = target_mem_read32(t, base);
CRC_DR = __builtin_bswap32(data);
base += 4;
@@ -130,8 +128,7 @@ uint32_t generic_crc32(struct target_s *target, uint32_t base, int len)
crc = CRC_DR;
while (len--) {
- if (target_mem_read_bytes(target, (uint8_t *)&data, base++, 1) != 0)
- return -1;
+ data = target_mem_read8(t, base++);
crc ^= data << 24;
for (i = 0; i < 8; i++) {
diff --git a/src/exception.c b/src/exception.c
new file mode 100644
index 0000000..3d43f99
--- /dev/null
+++ b/src/exception.c
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the Black Magic Debug project.
+ *
+ * Copyright (C) 2015 Black Sphere Technologies Ltd.
+ * Written by Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "general.h"
+#include "exception.h"
+
+struct exception *innermost_exception;
+
+void raise_exception(uint32_t type, const char *msg)
+{
+ struct exception *e;
+ for (e = innermost_exception; e; e = e->outer) {
+ if (e->mask & type) {
+ e->type = type;
+ e->msg = msg;
+ innermost_exception = e->outer;
+ longjmp(e->jmpbuf, type);
+ }
+ }
+ abort();
+}
+
diff --git a/src/gdb_main.c b/src/gdb_main.c
index ab4fc8a..6b2059f 100644
--- a/src/gdb_main.c
+++ b/src/gdb_main.c
@@ -77,9 +77,10 @@ gdb_main(void)
/* Implementation of these is mandatory! */
case 'g': { /* 'g': Read general registers */
ERROR_IF_NO_TARGET();
- uint8_t arm_regs[cur_target->regs_size];
+ uint8_t arm_regs[target_regs_size(cur_target)];
target_regs_read(cur_target, arm_regs);
- gdb_putpacket(hexify(pbuf, (void*)arm_regs, cur_target->regs_size), cur_target->regs_size * 2);
+ gdb_putpacket(hexify(pbuf, arm_regs, sizeof(arm_regs)),
+ sizeof(arm_regs) * 2);
break;
}
case 'm': { /* 'm addr,len': Read len bytes from addr */
@@ -88,12 +89,7 @@ gdb_main(void)
sscanf(pbuf, "m%" SCNx32 ",%" SCNx32, &addr, &len);
DEBUG("m packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", addr, len);
uint8_t mem[len];
- if(((addr & 3) == 0) && ((len & 3) == 0))
- target_mem_read_words(cur_target, (void*)mem, addr, len);
- else if(((addr & 1) == 0) && ((len & 1) == 0))
- target_mem_read_halfwords(cur_target, (void*)mem, addr, len);
- else
- target_mem_read_bytes(cur_target, (void*)mem, addr, len);
+ target_mem_read(cur_target, mem, addr, len);
if(target_check_error(cur_target))
gdb_putpacketz("E01");
else
@@ -102,8 +98,8 @@ gdb_main(void)
}
case 'G': { /* 'G XX': Write general registers */
ERROR_IF_NO_TARGET();
- uint8_t arm_regs[cur_target->regs_size];
- unhexify(arm_regs, &pbuf[1], cur_target->regs_size);
+ uint8_t arm_regs[target_regs_size(cur_target)];
+ unhexify(arm_regs, &pbuf[1], sizeof(arm_regs));
target_regs_write(cur_target, arm_regs);
gdb_putpacketz("OK");
break;
@@ -116,12 +112,7 @@ gdb_main(void)
DEBUG("M packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", addr, len);
uint8_t mem[len];
unhexify(mem, pbuf + hex, len);
- if(((addr & 3) == 0) && ((len & 3) == 0))
- target_mem_write_words(cur_target, addr, (void*)mem, len);
- else if(((addr & 1) == 0) && ((len & 1) == 0))
- target_mem_write_halfwords(cur_target, addr, (void*)mem, len);
- else
- target_mem_write_bytes(cur_target, addr, (void*)mem, len);
+ target_mem_write(cur_target, addr, mem, len);
if(target_check_error(cur_target))
gdb_putpacketz("E01");
else
@@ -168,6 +159,12 @@ gdb_main(void)
if (sig < 0)
break;
+ /* Target disappeared */
+ if (cur_target == NULL) {
+ gdb_putpacket_f("X%02X", sig);
+ break;
+ }
+
/* Report reason for halt */
if(target_check_hw_wp(cur_target, &watch_addr)) {
/* Watchpoint hit */
@@ -244,10 +241,7 @@ gdb_main(void)
ERROR_IF_NO_TARGET();
sscanf(pbuf, "X%" SCNx32 ",%" SCNx32 ":%n", &addr, &len, &bin);
DEBUG("X packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", addr, len);
- if(((addr & 3) == 0) && ((len & 3) == 0))
- target_mem_write_words(cur_target, addr, (void*)pbuf+bin, len);
- else
- target_mem_write_bytes(cur_target, addr, (void*)pbuf+bin, len);
+ target_mem_write(cur_target, addr, pbuf+bin, len);
if(target_check_error(cur_target))
gdb_putpacketz("E01");
else
@@ -334,11 +328,11 @@ handle_q_packet(char *packet, int len)
cur_target = target_attach(last_target,
gdb_target_destroy_callback);
}
- if((!cur_target) || (!cur_target->xml_mem_map)) {
+ if (!cur_target) {
gdb_putpacketz("E01");
return;
}
- handle_q_string_reply(cur_target->xml_mem_map, packet + 23);
+ handle_q_string_reply(target_mem_map(cur_target), packet + 23);
} else if (strncmp (packet, "qXfer:features:read:target.xml:", 31) == 0) {
/* Read target description */
@@ -347,11 +341,11 @@ handle_q_packet(char *packet, int len)
cur_target = target_attach(last_target,
gdb_target_destroy_callback);
}
- if((!cur_target) || (!cur_target->tdesc)) {
+ if (!cur_target) {
gdb_putpacketz("E01");
return;
}
- handle_q_string_reply(cur_target->tdesc, packet + 31);
+ handle_q_string_reply(target_tdesc(cur_target), packet + 31);
} else if (sscanf(packet, "qCRC:%" PRIx32 ",%" PRIx32, &addr, &alen) == 2) {
if(!cur_target) {
gdb_putpacketz("E01");
@@ -431,7 +425,7 @@ handle_v_packet(char *packet, int plen)
} else if (!strcmp(packet, "vFlashDone")) {
/* Commit flash operations. */
- gdb_putpacketz("OK");
+ gdb_putpacketz(target_flash_done(cur_target) ? "EFF" : "OK");
flash_mode = 0;
} else {
@@ -457,10 +451,6 @@ handle_z_packet(char *packet, int plen)
sscanf(packet + 2, ",%" PRIx32 ",%d", &addr, &len);
switch(type) {
case 1: /* Hardware breakpoint */
- if(!cur_target->set_hw_bp) { /* Not supported */
- gdb_putpacketz("");
- return;
- }
if(set)
ret = target_set_hw_bp(cur_target, addr);
else
@@ -470,10 +460,6 @@ handle_z_packet(char *packet, int plen)
case 2:
case 3:
case 4:
- if(!cur_target->set_hw_wp) { /* Not supported */
- gdb_putpacketz("");
- return;
- }
if(set)
ret = target_set_hw_wp(cur_target, type, addr, len);
else
diff --git a/src/gdb_packet.c b/src/gdb_packet.c
index fb3335e..9ce63f2 100644
--- a/src/gdb_packet.c
+++ b/src/gdb_packet.c
@@ -159,7 +159,8 @@ void gdb_outf(const char *fmt, ...)
char *buf;
va_start(ap, fmt);
- vasprintf(&buf, fmt, ap);
+ if (vasprintf(&buf, fmt, ap) < 0)
+ return;
gdb_out(buf);
free(buf);
va_end(ap);
diff --git a/src/include/adiv5.h b/src/include/adiv5.h
index e0ce9cf..12d3bf4 100644
--- a/src/include/adiv5.h
+++ b/src/include/adiv5.h
@@ -24,12 +24,16 @@
#include "jtag_scan.h"
#include "target.h"
+#define ADIV5_APnDP 0x100
+#define ADIV5_DP_REG(x) (x)
+#define ADIV5_AP_REG(x) (ADIV5_APnDP | (x))
+
/* ADIv5 DP Register addresses */
-#define ADIV5_DP_IDCODE 0x0
-#define ADIV5_DP_ABORT 0x0
-#define ADIV5_DP_CTRLSTAT 0x4
-#define ADIV5_DP_SELECT 0x8
-#define ADIV5_DP_RDBUFF 0xC
+#define ADIV5_DP_IDCODE ADIV5_DP_REG(0x0)
+#define ADIV5_DP_ABORT ADIV5_DP_REG(0x0)
+#define ADIV5_DP_CTRLSTAT ADIV5_DP_REG(0x4)
+#define ADIV5_DP_SELECT ADIV5_DP_REG(0x8)
+#define ADIV5_DP_RDBUFF ADIV5_DP_REG(0xC)
/* AP Abort Register (ABORT) */
/* Bits 31:5 - Reserved */
@@ -63,15 +67,15 @@
/* ADIv5 MEM-AP Registers */
-#define ADIV5_AP_CSW 0x00
-#define ADIV5_AP_TAR 0x04
+#define ADIV5_AP_CSW ADIV5_AP_REG(0x00)
+#define ADIV5_AP_TAR ADIV5_AP_REG(0x04)
/* 0x08 - Reserved */
-#define ADIV5_AP_DRW 0x0C
-#define ADIV5_AP_DB(x) (0x10 + (4*(x)))
+#define ADIV5_AP_DRW ADIV5_AP_REG(0x0C)
+#define ADIV5_AP_DB(x) ADIV5_AP_REG(0x10 + (4*(x)))
/* 0x20:0xF0 - Reserved */
-#define ADIV5_AP_CFG 0xF4
-#define ADIV5_AP_BASE 0xF8
-#define ADIV5_AP_IDR 0xFC
+#define ADIV5_AP_CFG ADIV5_AP_REG(0xF4)
+#define ADIV5_AP_BASE ADIV5_AP_REG(0xF8)
+#define ADIV5_AP_IDR ADIV5_AP_REG(0xFC)
/* AP Control and Status Word (CSW) */
#define ADIV5_AP_CSW_DBGSWENABLE (1u << 31)
@@ -93,11 +97,9 @@
#define ADIV5_AP_CSW_SIZE_WORD (2u << 0)
#define ADIV5_AP_CSW_SIZE_MASK (7u << 0)
-/* Constants to make RnW and APnDP parameters more clear in code */
+/* Constants to make RnW parameters more clear in code */
#define ADIV5_LOW_WRITE 0
#define ADIV5_LOW_READ 1
-#define ADIV5_LOW_DP 0
-#define ADIV5_LOW_AP 1
/* Try to keep this somewhat absract for later adding SW-DP */
typedef struct ADIv5_DP_s {
@@ -105,15 +107,10 @@ typedef struct ADIv5_DP_s {
uint32_t idcode;
- bool allow_timeout;
-
- void (*dp_write)(struct ADIv5_DP_s *dp, uint8_t addr, uint32_t value);
- uint32_t (*dp_read)(struct ADIv5_DP_s *dp, uint8_t addr);
-
+ uint32_t (*dp_read)(struct ADIv5_DP_s *dp, uint16_t addr);
uint32_t (*error)(struct ADIv5_DP_s *dp);
-
- uint32_t (*low_access)(struct ADIv5_DP_s *dp, uint8_t APnDP, uint8_t RnW,
- uint8_t addr, uint32_t value);
+ uint32_t (*low_access)(struct ADIv5_DP_s *dp, uint8_t RnW,
+ uint16_t addr, uint32_t value);
union {
jtag_dev_t *dev;
@@ -121,12 +118,7 @@ typedef struct ADIv5_DP_s {
};
} ADIv5_DP_t;
-static inline void adiv5_dp_write(ADIv5_DP_t *dp, uint8_t addr, uint32_t value)
-{
- dp->dp_write(dp, addr, value);
-}
-
-static inline uint32_t adiv5_dp_read(ADIv5_DP_t *dp, uint8_t addr)
+static inline uint32_t adiv5_dp_read(ADIv5_DP_t *dp, uint16_t addr)
{
return dp->dp_read(dp, addr);
}
@@ -136,10 +128,10 @@ static inline uint32_t adiv5_dp_error(ADIv5_DP_t *dp)
return dp->error(dp);
}
-static inline uint32_t adiv5_dp_low_access(struct ADIv5_DP_s *dp, uint8_t APnDP,
- uint8_t RnW, uint8_t addr, uint32_t value)
+static inline uint32_t adiv5_dp_low_access(struct ADIv5_DP_s *dp, uint8_t RnW,
+ uint16_t addr, uint32_t value)
{
- return dp->low_access(dp, APnDP, RnW, addr, value);
+ return dp->low_access(dp, RnW, addr, value);
}
typedef struct ADIv5_AP_s {
@@ -158,24 +150,15 @@ typedef struct ADIv5_AP_s {
} ADIv5_AP_t;
void adiv5_dp_init(ADIv5_DP_t *dp);
+void adiv5_dp_write(ADIv5_DP_t *dp, uint16_t addr, uint32_t value);
void adiv5_dp_ref(ADIv5_DP_t *dp);
void adiv5_ap_ref(ADIv5_AP_t *ap);
void adiv5_dp_unref(ADIv5_DP_t *dp);
void adiv5_ap_unref(ADIv5_AP_t *ap);
-void adiv5_dp_write_ap(ADIv5_DP_t *dp, uint8_t addr, uint32_t value);
-uint32_t adiv5_dp_read_ap(ADIv5_DP_t *dp, uint8_t addr);
-
-uint32_t adiv5_ap_mem_read(ADIv5_AP_t *ap, uint32_t addr);
-void adiv5_ap_mem_write(ADIv5_AP_t *ap, uint32_t addr, uint32_t value);
-uint16_t adiv5_ap_mem_read_halfword(ADIv5_AP_t *ap, uint32_t addr);
-void adiv5_ap_mem_write_halfword(ADIv5_AP_t *ap, uint32_t addr, uint16_t value);
-uint8_t adiv5_ap_mem_read_byte(ADIv5_AP_t *ap, uint32_t addr);
-void adiv5_ap_mem_write_byte(ADIv5_AP_t *ap, uint32_t addr, uint8_t value);
-
-void adiv5_ap_write(ADIv5_AP_t *ap, uint8_t addr, uint32_t value);
-uint32_t adiv5_ap_read(ADIv5_AP_t *ap, uint8_t addr);
+void adiv5_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value);
+uint32_t adiv5_ap_read(ADIv5_AP_t *ap, uint16_t addr);
void adiv5_jtag_dp_handler(jtag_dev_t *dev);
int adiv5_swdp_scan(void);
diff --git a/src/include/cortexm.h b/src/include/cortexm.h
index 1fd77e6..f7396bf 100644
--- a/src/include/cortexm.h
+++ b/src/include/cortexm.h
@@ -143,9 +143,11 @@
#define CORTEXM_DWT_FUNC_FUNC_WRITE (6 << 0)
#define CORTEXM_DWT_FUNC_FUNC_ACCESS (7 << 0)
-bool cortexm_attach(struct target_s *target);
-void cortexm_detach(struct target_s *target);
-void cortexm_halt_resume(struct target_s *target, bool step);
+bool cortexm_attach(target *t);
+void cortexm_detach(target *t);
+void cortexm_halt_resume(target *t, bool step);
+int cortexm_run_stub(target *t, uint32_t loadaddr,
+ uint32_t r0, uint32_t r1, uint32_t r2, uint32_t r3);
#endif
diff --git a/src/include/crc32.h b/src/include/crc32.h
index 9966d8d..bd8d5c4 100644
--- a/src/include/crc32.h
+++ b/src/include/crc32.h
@@ -22,6 +22,6 @@
#define __CRC32_H
uint32_t crc32_calc(uint32_t crc, uint8_t data);
-uint32_t generic_crc32(struct target_s *target, uint32_t base, int len);
+uint32_t generic_crc32(target *t, uint32_t base, int len);
#endif
diff --git a/src/include/exception.h b/src/include/exception.h
new file mode 100644
index 0000000..180398d
--- /dev/null
+++ b/src/include/exception.h
@@ -0,0 +1,74 @@
+/*
+ * This file is part of the Black Magic Debug project.
+ *
+ * Copyright (C) 2015 Black Sphere Technologies Ltd.
+ * Written by Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Exception handling to escape deep nesting.
+ * Used for the case of communicaiton failure and timeouts.
+ */
+
+/* Example usage:
+ *
+ * volatile struct exception e;
+ * TRY_CATCH (e, EXCEPTION_TIMEOUT) {
+ * ...
+ * raise_exception(EXCEPTION_TIMEOUT, "Timeout occurred");
+ * ...
+ * }
+ * if (e.type == EXCEPTION_TIMEOUT) {
+ * printf("timeout: %s\n", e.msg);
+ * }
+ */
+
+/* Limitations:
+ * Can't use break, return, goto, etc from inside the TRY_CATCH block.
+ */
+
+#ifndef __EXCEPTION_H
+#define __EXCEPTION_H
+
+#include <setjmp.h>
+#include <stdint.h>
+
+#define EXCEPTION_ERROR 0x01
+#define EXCEPTION_TIMEOUT 0x02
+#define EXCEPTION_ALL -1
+
+struct exception {
+ uint32_t type;
+ const char *msg;
+ /* private */
+ uint32_t mask;
+ jmp_buf jmpbuf;
+ struct exception *outer;
+};
+
+extern struct exception *innermost_exception;
+
+#define TRY_CATCH(e, type_mask) \
+ (e).type = 0; \
+ (e).mask = (type_mask); \
+ (e).outer = innermost_exception; \
+ innermost_exception = (void*)&(e); \
+ if (setjmp(innermost_exception->jmpbuf) == 0) \
+ for (;innermost_exception == &(e); innermost_exception = (e).outer)
+
+void raise_exception(uint32_t type, const char *msg);
+
+#endif
+
diff --git a/src/include/general.h b/src/include/general.h
index 2cb4bd9..c82c750 100644
--- a/src/include/general.h
+++ b/src/include/general.h
@@ -38,5 +38,9 @@
#define DEBUG printf
#endif
+#define ALIGN(x, n) (((x) + (n) - 1) & ~((n) - 1))
+#undef MIN
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+
#endif
diff --git a/src/include/target.h b/src/include/target.h
index 5db79a7..940a360 100644
--- a/src/include/target.h
+++ b/src/include/target.h
@@ -48,24 +48,11 @@ target *target_attach(target *t, target_destroy_callback destroy_cb);
(target)->check_error(target)
/* Memory access functions */
-#define target_mem_read_words(target, dest, src, len) \
- (target)->mem_read_words((target), (dest), (src), (len))
-
-#define target_mem_write_words(target, dest, src, len) \
- (target)->mem_write_words((target), (dest), (src), (len))
-
-#define target_mem_read_halfwords(target, dest, src, len) \
- (target)->mem_read_halfwords((target), (dest), (src), (len))
-
-#define target_mem_write_halfwords(target, dest, src, len) \
- (target)->mem_write_halfwords((target), (dest), (src), (len))
-
-#define target_mem_read_bytes(target, dest, src, len) \
- (target)->mem_read_bytes((target), (dest), (src), (len))
-
-#define target_mem_write_bytes(target, dest, src, len) \
- (target)->mem_write_bytes((target), (dest), (src), (len))
+#define target_mem_read(target, dest, src, len) \
+ (target)->mem_read((target), (dest), (src), (len))
+#define target_mem_write(target, dest, src, len) \
+ (target)->mem_write((target), (dest), (src), (len))
/* Register access functions */
#define target_regs_read(target, data) \
@@ -74,12 +61,6 @@ target *target_attach(target *t, target_destroy_callback destroy_cb);
#define target_regs_write(target, data) \
(target)->regs_write((target), (data))
-#define target_pc_read(target) \
- (target)->pc_read((target))
-
-#define target_pc_write(target, val) \
- (target)->pc_write((target), (val))
-
/* Halt/resume functions */
#define target_reset(target) \
@@ -120,59 +101,58 @@ target *target_attach(target *t, target_destroy_callback destroy_cb);
#define target_flash_write(target, dest, src, len) \
(target)->flash_write((target), (dest), (src), (len))
+#define target_flash_done(target) \
+ ((target)->flash_done ? (target)->flash_done(target) : 0)
+
/* Host I/O */
#define target_hostio_reply(target, recode, errcode) \
(target)->hostio_reply((target), (retcode), (errcode))
+/* Accessor functions */
+#define target_regs_size(target) \
+ ((target)->regs_size)
+
+#define target_mem_map(target) \
+ ((target)->xml_mem_map ? (target)->xml_mem_map : "")
+
+#define target_tdesc(target) \
+ ((target)->tdesc ? (target)->tdesc : "")
struct target_s {
/* Notify controlling debugger if target is lost */
target_destroy_callback destroy_callback;
/* Attach/Detach funcitons */
- bool (*attach)(struct target_s *target);
- void (*detach)(struct target_s *target);
- int (*check_error)(struct target_s *target);
+ bool (*attach)(target *t);
+ void (*detach)(target *t);
+ bool (*check_error)(target *t);
/* Memory access functions */
- int (*mem_read_words)(struct target_s *target, uint32_t *dest, uint32_t src,
- int len);
- int (*mem_write_words)(struct target_s *target, uint32_t dest,
- const uint32_t *src, int len);
-
- int (*mem_read_halfwords)(struct target_s *target, uint16_t *dest, uint32_t src,
- int len);
- int (*mem_write_halfwords)(struct target_s *target, uint32_t dest,
- const uint16_t *src, int len);
-
- int (*mem_read_bytes)(struct target_s *target, uint8_t *dest, uint32_t src,
- int len);
- int (*mem_write_bytes)(struct target_s *target, uint32_t dest,
- const uint8_t *src, int len);
+ void (*mem_read)(target *t, void *dest, uint32_t src,
+ size_t len);
+ void (*mem_write)(target *t, uint32_t dest,
+ const void *src, size_t len);
/* Register access functions */
int regs_size;
const char *tdesc;
- int (*regs_read)(struct target_s *target, void *data);
- int (*regs_write)(struct target_s *target, const void *data);
-
- uint32_t (*pc_read)(struct target_s *target);
- int (*pc_write)(struct target_s *target, const uint32_t val);
+ void (*regs_read)(target *t, void *data);
+ void (*regs_write)(target *t, const void *data);
/* Halt/resume functions */
- void (*reset)(struct target_s *target);
- void (*halt_request)(struct target_s *target);
- int (*halt_wait)(struct target_s *target);
- void (*halt_resume)(struct target_s *target, bool step);
+ void (*reset)(target *t);
+ void (*halt_request)(target *t);
+ int (*halt_wait)(target *t);
+ void (*halt_resume)(target *t, bool step);
/* Break-/watchpoint functions */
- int (*set_hw_bp)(struct target_s *target, uint32_t addr);
- int (*clear_hw_bp)(struct target_s *target, uint32_t addr);
+ int (*set_hw_bp)(target *t, uint32_t addr);
+ int (*clear_hw_bp)(target *t, uint32_t addr);
- int (*set_hw_wp)(struct target_s *target, uint8_t type, uint32_t addr, uint8_t len);
- int (*clear_hw_wp)(struct target_s *target, uint8_t type, uint32_t addr, uint8_t len);
+ int (*set_hw_wp)(target *t, uint8_t type, uint32_t addr, uint8_t len);
+ int (*clear_hw_wp)(target *t, uint8_t type, uint32_t addr, uint8_t len);
- int (*check_hw_wp)(struct target_s *target, uint32_t *addr);
+ int (*check_hw_wp)(target *t, uint32_t *addr);
/* target-defined options */
unsigned target_options;
@@ -180,9 +160,10 @@ struct target_s {
/* Flash memory access functions */
const char *xml_mem_map;
- int (*flash_erase)(struct target_s *target, uint32_t addr, size_t len);
- int (*flash_write)(struct target_s *target, uint32_t dest,
+ int (*flash_erase)(target *t, uint32_t addr, size_t len);
+ int (*flash_write)(target *t, uint32_t dest,
const uint8_t *src, size_t len);
+ int (*flash_done)(target *t);
/* Host I/O support */
void (*hostio_reply)(target *t, int32_t retcode, uint32_t errcode);
@@ -210,21 +191,58 @@ target *target_new(unsigned size);
void target_list_free(void);
void target_add_commands(target *t, const struct command_s *cmds, const char *name);
+static inline uint32_t target_mem_read32(target *t, uint32_t addr)
+{
+ uint32_t ret;
+ target_mem_read(t, &ret, addr, sizeof(ret));
+ return ret;
+}
+
+static inline void target_mem_write32(target *t, uint32_t addr, uint32_t value)
+{
+ target_mem_write(t, addr, &value, sizeof(value));
+}
+
+static inline uint16_t target_mem_read16(target *t, uint32_t addr)
+{
+ uint16_t ret;
+ target_mem_read(t, &ret, addr, sizeof(ret));
+ return ret;
+}
+
+static inline void target_mem_write16(target *t, uint32_t addr, uint16_t value)
+{
+ target_mem_write(t, addr, &value, sizeof(value));
+}
+
+static inline uint8_t target_mem_read8(target *t, uint32_t addr)
+{
+ uint8_t ret;
+ target_mem_read(t, &ret, addr, sizeof(ret));
+ return ret;
+}
+
+static inline void target_mem_write8(target *t, uint32_t addr, uint8_t value)
+{
+ target_mem_write(t, addr, &value, sizeof(value));
+}
+
+
/* Probe for various targets.
* Actual functions implemented in their respective drivers.
*/
-bool cortexm_probe(struct target_s *target);
-bool stm32f1_probe(struct target_s *target);
-bool stm32f4_probe(struct target_s *target);
-bool stm32l0_probe(struct target_s *target);
-bool stm32l1_probe(struct target_s *target);
-bool lmi_probe(struct target_s *target);
-bool lpc11xx_probe(struct target_s *target);
-bool lpc43xx_probe(struct target_s *target);
-bool sam3x_probe(struct target_s *target);
-bool nrf51_probe(struct target_s *target);
-bool samd_probe(struct target_s *target);
-bool kinetis_probe(struct target_s *target);
+bool cortexm_probe(target *t);
+bool stm32f1_probe(target *t);
+bool stm32f4_probe(target *t);
+bool stm32l0_probe(target *t);
+bool stm32l1_probe(target *t);
+bool lmi_probe(target *t);
+bool lpc11xx_probe(target *t);
+bool lpc43xx_probe(target *t);
+bool sam3x_probe(target *t);
+bool nrf51_probe(target *t);
+bool samd_probe(target *t);
+bool kinetis_probe(target *t);
#endif
diff --git a/src/jtag_scan.c b/src/jtag_scan.c
index c4e80cf..f46a148 100644
--- a/src/jtag_scan.c
+++ b/src/jtag_scan.c
@@ -43,9 +43,6 @@ static struct jtag_dev_descr_s {
{.idcode = 0x0BA00477, .idmask = 0x0FFF0FFF,
.descr = "ARM Limited: ADIv5 JTAG-DP port.",
.handler = adiv5_jtag_dp_handler},
- {.idcode = 0x3F0F0F0F, .idmask = 0xFFFFFFFF,
- .descr = "ST Microelectronics: STR730",
- .handler = arm7tdmi_jtag_handler},
{.idcode = 0x06410041, .idmask = 0x0FFFFFFF,
.descr = "ST Microelectronics: STM32, Medium density."},
{.idcode = 0x06412041, .idmask = 0x0FFFFFFF,
diff --git a/src/kinetis.c b/src/kinetis.c
index b260d2a..7ccb28d 100644
--- a/src/kinetis.c
+++ b/src/kinetis.c
@@ -54,8 +54,8 @@
#define KL25_PAGESIZE 0x400
-static int kl25_flash_erase(struct target_s *target, uint32_t addr, size_t len);
-static int kl25_flash_write(struct target_s *target, uint32_t dest,
+static int kl25_flash_erase(target *t, uint32_t addr, size_t len);
+static int kl25_flash_write(target *t, uint32_t dest,
const uint8_t *src, size_t len);
static const char kl25_xml_memory_map[] = "<?xml version=\"1.0\"?>"
@@ -70,9 +70,9 @@ static const char kl25_xml_memory_map[] = "<?xml version=\"1.0\"?>"
" <memory type=\"ram\" start=\"0x20000000\" length=\"0x3000\"/>"
"</memory-map>";
-bool kinetis_probe(struct target_s *t)
+bool kinetis_probe(target *t)
{
- uint32_t sdid = adiv5_ap_mem_read(adiv5_target_ap(t), SIM_SDID);
+ uint32_t sdid = target_mem_read32(t, SIM_SDID);
switch (sdid >> 20) {
case 0x251:
t->driver = "KL25";
@@ -85,14 +85,13 @@ bool kinetis_probe(struct target_s *t)
}
static bool
-kl25_command(struct target_s *t, uint8_t cmd, uint32_t addr, const uint8_t data[8])
+kl25_command(target *t, uint8_t cmd, uint32_t addr, const uint8_t data[8])
{
- ADIv5_AP_t *ap = adiv5_target_ap(t);
uint8_t fstat;
/* Wait for CCIF to be high */
do {
- fstat = adiv5_ap_mem_read_byte(ap, FTFA_FSTAT);
+ fstat = target_mem_read8(t, FTFA_FSTAT);
/* Check ACCERR and FPVIOL are zero in FSTAT */
if (fstat & (FTFA_FSTAT_ACCERR | FTFA_FSTAT_FPVIOL))
return false;
@@ -101,18 +100,18 @@ kl25_command(struct target_s *t, uint8_t cmd, uint32_t addr, const uint8_t data[
/* Write command to FCCOB */
addr &= 0xffffff;
addr |= (uint32_t)cmd << 24;
- adiv5_ap_mem_write(ap, FTFA_FCCOB(0), addr);
+ target_mem_write32(t, FTFA_FCCOB(0), addr);
if (data) {
- adiv5_ap_mem_write(ap, FTFA_FCCOB(4), *(uint32_t*)&data[0]);
- adiv5_ap_mem_write(ap, FTFA_FCCOB(8), *(uint32_t*)&data[4]);
+ target_mem_write32(t, FTFA_FCCOB(4), *(uint32_t*)&data[0]);
+ target_mem_write32(t, FTFA_FCCOB(8), *(uint32_t*)&data[4]);
}
/* Enable execution by clearing CCIF */
- adiv5_ap_mem_write_byte(ap, FTFA_FSTAT, FTFA_FSTAT_CCIF);
+ target_mem_write8(t, FTFA_FSTAT, FTFA_FSTAT_CCIF);
/* Wait for execution to complete */
do {
- fstat = adiv5_ap_mem_read_byte(ap, FTFA_FSTAT);
+ fstat = target_mem_read8(t, FTFA_FSTAT);
/* Check ACCERR and FPVIOL are zero in FSTAT */
if (fstat & (FTFA_FSTAT_ACCERR | FTFA_FSTAT_FPVIOL))
return false;
@@ -121,7 +120,7 @@ kl25_command(struct target_s *t, uint8_t cmd, uint32_t addr, const uint8_t data[
return true;
}
-static int kl25_flash_erase(struct target_s *t, uint32_t addr, size_t len)
+static int kl25_flash_erase(target *t, uint32_t addr, size_t len)
{
addr &= ~(KL25_PAGESIZE - 1);
len = (len + KL25_PAGESIZE - 1) & ~(KL25_PAGESIZE - 1);
@@ -134,7 +133,7 @@ static int kl25_flash_erase(struct target_s *t, uint32_t addr, size_t len)
return 0;
}
-static int kl25_flash_write(struct target_s *t, uint32_t dest,
+static int kl25_flash_write(target *t, uint32_t dest,
const uint8_t *src, size_t len)
{
/* FIXME handle misaligned start and end of sections */
diff --git a/src/lmi.c b/src/lmi.c
index 0f16db4..fb425a2 100644
--- a/src/lmi.c
+++ b/src/lmi.c
@@ -21,18 +21,33 @@
/* This file implements TI/LMI LM3S target specific functions providing
* the XML memory map and Flash memory programming.
*
- * Issues:
- * No detection of the target device.
- * Add reference to documentation.
- * Flash erase is very slow.
+ * According to: TivaTM TM4C123GH6PM Microcontroller Datasheet
*/
#include "general.h"
-#include "adiv5.h"
#include "target.h"
+#include "cortexm.h"
-static int lmi_flash_erase(struct target_s *target, uint32_t addr, size_t len);
-static int lmi_flash_write(struct target_s *target, uint32_t dest,
+#define SRAM_BASE 0x20000000
+#define STUB_BUFFER_BASE (SRAM_BASE + 0x30)
+
+#define BLOCK_SIZE 0x400
+
+#define LMI_SCB_BASE 0x400FE000
+#define LMI_SCB_DID1 (LMI_SCB_BASE + 0x004)
+
+#define LMI_FLASH_BASE 0x400FD000
+#define LMI_FLASH_FMA (LMI_FLASH_BASE + 0x000)
+#define LMI_FLASH_FMC (LMI_FLASH_BASE + 0x008)
+
+#define LMI_FLASH_FMC_WRITE (1 << 0)
+#define LMI_FLASH_FMC_ERASE (1 << 1)
+#define LMI_FLASH_FMC_MERASE (1 << 2)
+#define LMI_FLASH_FMC_COMT (1 << 3)
+#define LMI_FLASH_FMC_WRKEY 0xA4420000
+
+static int lmi_flash_erase(target *t, uint32_t addr, size_t len);
+static int lmi_flash_write(target *t, uint32_t dest,
const uint8_t *src, size_t len);
static const char lmi_driver_str[] = "TI Stellaris/Tiva";
@@ -61,112 +76,58 @@ static const char tm4c123gh6pm_xml_memory_map[] = "<?xml version=\"1.0\"?>"
static const uint16_t lmi_flash_write_stub[] = {
-// _start:
- 0x4809, // ldr r0, [pc, #36] // _flashbase
- 0x490b, // ldr r1, [pc, #44] // _addr
- 0x467a, // mov r2, pc
- 0x3230, // adds r2, #48
- 0x4b0a, // ldr r3, [pc, #40] // _size
- 0x4d08, // ldr r5, [pc, #32] // _flash_write_cmd
-// _next:
- 0xb15b, // cbz r3, _done
- 0x6001, // str r1, [r0, #0]
- 0x6814, // ldr r4, [r2]
- 0x6044, // str r4, [r0, #4]
- 0x6085, // str r5, [r0, #8]
-// _wait:
- 0x6884, // ldr r4, [r0, #8]
- 0x2601, // movs r6, #1
- 0x4234, // tst r4, r6
- 0xd1fb, // bne _wait
-
- 0x3b01, // subs r3, #1
- 0x3104, // adds r1, #4
- 0x3204, // adds r2, #4
- 0xe7f2, // b _next
-// _done:
- 0xbe00, // bkpt
-// _flashbase:
- 0xd000, 0x400f, // .word 0x400fd000
-// _flash_write_cmd:
- 0x0001, 0xa442, // .word 0xa4420001
-// _addr:
-// 0x0000, 0x0000,
-// _size:
-// 0x0000, 0x0000,
-// _data:
-// ...
+#include "../flashstub/lmi.stub"
};
-bool lmi_probe(struct target_s *target)
+bool lmi_probe(target *t)
{
- uint32_t did1 = adiv5_ap_mem_read(adiv5_target_ap(target), 0x400FE004);
+ uint32_t did1 = target_mem_read32(t, LMI_SCB_DID1);
switch (did1 >> 16) {
case 0x1049: /* LM3S3748 */
- target->driver = lmi_driver_str;
- target->xml_mem_map = lmi_xml_memory_map;
- target->flash_erase = lmi_flash_erase;
- target->flash_write = lmi_flash_write;
+ t->driver = lmi_driver_str;
+ t->xml_mem_map = lmi_xml_memory_map;
+ t->flash_erase = lmi_flash_erase;
+ t->flash_write = lmi_flash_write;
return true;
case 0x10A1: /* TM4C123GH6PM */
- target->driver = lmi_driver_str;
- target->xml_mem_map = tm4c123gh6pm_xml_memory_map;
- target->flash_erase = lmi_flash_erase;
- target->flash_write = lmi_flash_write;
+ t->driver = lmi_driver_str;
+ t->xml_mem_map = tm4c123gh6pm_xml_memory_map;
+ t->flash_erase = lmi_flash_erase;
+ t->flash_write = lmi_flash_write;
return true;
}
return false;
}
-int lmi_flash_erase(struct target_s *target, uint32_t addr, size_t len)
+int lmi_flash_erase(target *t, uint32_t addr, size_t len)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
- uint32_t tmp;
-
- addr &= 0xFFFFFC00;
- len &= 0xFFFFFC00;
-
- /* setup word access */
- adiv5_ap_write(ap, 0x00, 0xA2000052);
-
- /* select Flash Control */
- adiv5_dp_low_access(ap->dp, 1, 0, 0x04, 0x400FD000);
+ addr &= ~(BLOCK_SIZE - 1);
+ len &= ~(BLOCK_SIZE - 1);
while(len) {
- /* write address to FMA */
- adiv5_ap_write(ap, 0x10, addr); /* Required to switch banks */
- /* set ERASE bit in FMC */
- adiv5_dp_low_access(ap->dp, 1, 0, 0x08, 0xA4420002);
- /* Read FMC to poll for ERASE bit */
- adiv5_dp_low_access(ap->dp, 1, 1, 0x08, 0);
- do {
- tmp = adiv5_dp_low_access(ap->dp, 1, 1, 0x08, 0);
- } while (tmp & 2);
-
- len -= 0x400;
- addr += 0x400;
+ target_mem_write32(t, LMI_FLASH_FMA, addr);
+ target_mem_write32(t, LMI_FLASH_FMC,
+ LMI_FLASH_FMC_WRKEY | LMI_FLASH_FMC_ERASE);
+ while (target_mem_read32(t, LMI_FLASH_FMC) &
+ LMI_FLASH_FMC_ERASE);
+
+ len -= BLOCK_SIZE;
+ addr += BLOCK_SIZE;
}
return 0;
}
-int lmi_flash_write(struct target_s *target, uint32_t dest,
- const uint8_t *src, size_t len)
+int lmi_flash_write(target *t, uint32_t dest, const uint8_t *src, size_t len)
{
uint32_t data[(len>>2)+2];
data[0] = dest;
data[1] = len >> 2;
memcpy(&data[2], src, len);
- DEBUG("Sending stub\n");
- target_mem_write_words(target, 0x20000000, (void*)lmi_flash_write_stub, 0x30);
- DEBUG("Sending data\n");
- target_mem_write_words(target, 0x20000030, data, len + 8);
- DEBUG("Running stub\n");
- target_pc_write(target, 0x20000000);
- target_halt_resume(target, 0);
- DEBUG("Waiting for halt\n");
- while(!target_halt_wait(target));
- return 0;
+ target_mem_write(t, SRAM_BASE, lmi_flash_write_stub,
+ sizeof(lmi_flash_write_stub));
+ target_mem_write(t, STUB_BUFFER_BASE, data, len + 8);
+ return cortexm_run_stub(t, SRAM_BASE, 0, 0, 0, 0);
}
diff --git a/src/lpc11xx.c b/src/lpc11xx.c
index b6309c2..3a85ded 100644
--- a/src/lpc11xx.c
+++ b/src/lpc11xx.c
@@ -61,10 +61,10 @@ static struct flash_program flash_pgm;
static const char lpc8xx_driver[] = "lpc8xx";
static const char lpc11xx_driver[] = "lpc11xx";
-static void lpc11x_iap_call(struct target_s *target, struct flash_param *param, unsigned param_len);
-static int lpc11xx_flash_prepare(struct target_s *target, uint32_t addr, int len);
-static int lpc11xx_flash_erase(struct target_s *target, uint32_t addr, size_t len);
-static int lpc11xx_flash_write(struct target_s *target, uint32_t dest, const uint8_t *src,
+static void lpc11x_iap_call(target *t, struct flash_param *param, unsigned param_len);
+static int lpc11xx_flash_prepare(target *t, uint32_t addr, int len);
+static int lpc11xx_flash_erase(target *t, uint32_t addr, size_t len);
+static int lpc11xx_flash_write(target *t, uint32_t dest, const uint8_t *src,
size_t len);
/*
@@ -103,12 +103,12 @@ static const char lpc8xx_xml_memory_map[] = "<?xml version=\"1.0\"?>"
"</memory-map>";
bool
-lpc11xx_probe(struct target_s *target)
+lpc11xx_probe(target *t)
{
uint32_t idcode;
/* read the device ID register */
- idcode = adiv5_ap_mem_read(adiv5_target_ap(target), 0x400483F4);
+ idcode = target_mem_read32(t, 0x400483F4);
switch (idcode) {
@@ -143,18 +143,18 @@ lpc11xx_probe(struct target_s *target)
case 0x2972402B: /* lpc11u23/301 */
case 0x2988402B: /* lpc11u24x/301 */
case 0x2980002B: /* lpc11u24x/401 */
- target->driver = lpc11xx_driver;
- target->xml_mem_map = lpc11xx_xml_memory_map;
- target->flash_erase = lpc11xx_flash_erase;
- target->flash_write = lpc11xx_flash_write;
+ t->driver = lpc11xx_driver;
+ t->xml_mem_map = lpc11xx_xml_memory_map;
+ t->flash_erase = lpc11xx_flash_erase;
+ t->flash_write = lpc11xx_flash_write;
return true;
case 0x1812202b: /* LPC812M101FDH20 */
- target->driver = lpc8xx_driver;
- target->xml_mem_map = lpc8xx_xml_memory_map;
- target->flash_erase = lpc11xx_flash_erase;
- target->flash_write = lpc11xx_flash_write;
+ t->driver = lpc8xx_driver;
+ t->xml_mem_map = lpc8xx_xml_memory_map;
+ t->flash_erase = lpc11xx_flash_erase;
+ t->flash_write = lpc11xx_flash_write;
return true;
}
@@ -163,55 +163,55 @@ lpc11xx_probe(struct target_s *target)
}
static void
-lpc11x_iap_call(struct target_s *target, struct flash_param *param, unsigned param_len)
+lpc11x_iap_call(target *t, struct flash_param *param, unsigned param_len)
{
- uint32_t regs[target->regs_size / sizeof(uint32_t)];
+ uint32_t regs[t->regs_size / sizeof(uint32_t)];
/* fill out the remainder of the parameters and copy the structure to RAM */
param->opcodes[0] = 0xbe00;
param->opcodes[1] = 0x0000;
- target_mem_write_words(target, IAP_RAM_BASE, (void *)param, param_len);
+ target_mem_write(t, IAP_RAM_BASE, param, param_len);
/* set up for the call to the IAP ROM */
- target_regs_read(target, regs);
+ target_regs_read(t, regs);
regs[0] = IAP_RAM_BASE + offsetof(struct flash_param, command);
regs[1] = IAP_RAM_BASE + offsetof(struct flash_param, result);
// stack pointer - top of the smallest ram less 32 for IAP usage
- if (target->driver == lpc8xx_driver)
+ if (t->driver == lpc8xx_driver)
regs[MSP] = IAP_RAM_BASE + MIN_RAM_SIZE_FOR_LPC8xx - RAM_USAGE_FOR_IAP_ROUTINES;
else
regs[MSP] = IAP_RAM_BASE + MIN_RAM_SIZE_FOR_LPC1xxx - RAM_USAGE_FOR_IAP_ROUTINES;
regs[14] = IAP_RAM_BASE | 1;
regs[15] = IAP_ENTRYPOINT;
- target_regs_write(target, regs);
+ target_regs_write(t, regs);
/* start the target and wait for it to halt again */
- target_halt_resume(target, 0);
- while (!target_halt_wait(target));
+ target_halt_resume(t, 0);
+ while (!target_halt_wait(t));
/* copy back just the parameters structure */
- target_mem_read_words(target, (void *)param, IAP_RAM_BASE, sizeof(struct flash_param));
+ target_mem_read(t, param, IAP_RAM_BASE, sizeof(struct flash_param));
}
-static int flash_page_size(struct target_s *target)
+static int flash_page_size(target *t)
{
- if (target->driver == lpc8xx_driver)
+ if (t->driver == lpc8xx_driver)
return 1024;
else
return 4096;
}
static int
-lpc11xx_flash_prepare(struct target_s *target, uint32_t addr, int len)
+lpc11xx_flash_prepare(target *t, uint32_t addr, int len)
{
/* prepare the sector(s) to be erased */
memset(&flash_pgm.p, 0, sizeof(flash_pgm.p));
flash_pgm.p.command[0] = IAP_CMD_PREPARE;
- flash_pgm.p.command[1] = addr / flash_page_size(target);
- flash_pgm.p.command[2] = (addr + len - 1) / flash_page_size(target);
+ flash_pgm.p.command[1] = addr / flash_page_size(t);
+ flash_pgm.p.command[2] = (addr + len - 1) / flash_page_size(t);
- lpc11x_iap_call(target, &flash_pgm.p, sizeof(flash_pgm.p));
+ lpc11x_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p));
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
return -1;
}
@@ -220,27 +220,27 @@ lpc11xx_flash_prepare(struct target_s *target, uint32_t addr, int len)
}
static int
-lpc11xx_flash_erase(struct target_s *target, uint32_t addr, size_t len)
+lpc11xx_flash_erase(target *t, uint32_t addr, size_t len)
{
- if (addr % flash_page_size(target))
+ if (addr % flash_page_size(t))
return -1;
/* prepare... */
- if (lpc11xx_flash_prepare(target, addr, len))
+ if (lpc11xx_flash_prepare(t, addr, len))
return -1;
/* and now erase them */
flash_pgm.p.command[0] = IAP_CMD_ERASE;
- flash_pgm.p.command[1] = addr / flash_page_size(target);
- flash_pgm.p.command[2] = (addr + len - 1) / flash_page_size(target);
+ flash_pgm.p.command[1] = addr / flash_page_size(t);
+ flash_pgm.p.command[2] = (addr + len - 1) / flash_page_size(t);
flash_pgm.p.command[3] = 12000; /* XXX safe to assume this? */
- lpc11x_iap_call(target, &flash_pgm.p, sizeof(flash_pgm.p));
+ lpc11x_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p));
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
return -1;
}
flash_pgm.p.command[0] = IAP_CMD_BLANKCHECK;
- lpc11x_iap_call(target, &flash_pgm.p, sizeof(flash_pgm.p));
+ lpc11x_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p));
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
return -1;
}
@@ -249,7 +249,7 @@ lpc11xx_flash_erase(struct target_s *target, uint32_t addr, size_t len)
}
static int
-lpc11xx_flash_write(struct target_s *target, uint32_t dest, const uint8_t *src, size_t len)
+lpc11xx_flash_write(target *t, uint32_t dest, const uint8_t *src, size_t len)
{
unsigned first_chunk = dest / IAP_PGM_CHUNKSIZE;
unsigned last_chunk = (dest + len - 1) / IAP_PGM_CHUNKSIZE;
@@ -300,7 +300,7 @@ lpc11xx_flash_write(struct target_s *target, uint32_t dest, const uint8_t *src,
}
/* prepare... */
- if (lpc11xx_flash_prepare(target, chunk * IAP_PGM_CHUNKSIZE, IAP_PGM_CHUNKSIZE))
+ if (lpc11xx_flash_prepare(t, chunk * IAP_PGM_CHUNKSIZE, IAP_PGM_CHUNKSIZE))
return -1;
/* set the destination address and program */
@@ -310,7 +310,7 @@ lpc11xx_flash_write(struct target_s *target, uint32_t dest, const uint8_t *src,
flash_pgm.p.command[3] = IAP_PGM_CHUNKSIZE;
/* assuming we are running off IRC - safe lower bound */
flash_pgm.p.command[4] = 12000; /* XXX safe to presume this? */
- lpc11x_iap_call(target, &flash_pgm.p, sizeof(flash_pgm));
+ lpc11x_iap_call(t, &flash_pgm.p, sizeof(flash_pgm));
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
return -1;
}
diff --git a/src/lpc43xx.c b/src/lpc43xx.c
index eca7338..1519306 100644
--- a/src/lpc43xx.c
+++ b/src/lpc43xx.c
@@ -119,20 +119,20 @@ struct flash_program {
uint8_t data[IAP_PGM_CHUNKSIZE];
};
-static bool lpc43xx_cmd_erase(target *target, int argc, const char *argv[]);
-static bool lpc43xx_cmd_reset(target *target, int argc, const char *argv[]);
-static bool lpc43xx_cmd_mkboot(target *target, int argc, const char *argv[]);
-static int lpc43xx_flash_init(struct target_s *target);
-static void lpc43xx_iap_call(struct target_s *target, struct flash_param *param,
+static bool lpc43xx_cmd_erase(target *t, int argc, const char *argv[]);
+static bool lpc43xx_cmd_reset(target *t, int argc, const char *argv[]);
+static bool lpc43xx_cmd_mkboot(target *t, int argc, const char *argv[]);
+static int lpc43xx_flash_init(target *t);
+static void lpc43xx_iap_call(target *t, struct flash_param *param,
unsigned param_len);
-static int lpc43xx_flash_prepare(struct target_s *target,
+static int lpc43xx_flash_prepare(target *t,
uint32_t addr, int len);
-static int lpc43xx_flash_erase(struct target_s *target, uint32_t addr, size_t len);
-static int lpc43xx_flash_write(struct target_s *target,
+static int lpc43xx_flash_erase(target *t, uint32_t addr, size_t len);
+static int lpc43xx_flash_write(target *t,
uint32_t dest, const uint8_t *src, size_t len);
-static void lpc43xx_set_internal_clock(struct target_s *target);
-static void lpc43xx_wdt_set_period(struct target_s *target);
-static void lpc43xx_wdt_pet(struct target_s *target);
+static void lpc43xx_set_internal_clock(target *t);
+static void lpc43xx_wdt_set_period(target *t);
+static void lpc43xx_wdt_pet(target *t);
const struct command_s lpc43xx_cmd_list[] = {
{"erase_mass", lpc43xx_cmd_erase, "Erase entire flash memory"},
@@ -166,45 +166,45 @@ static const char lpc4337_xml_memory_map[] = "<?xml version=\"1.0\"?>"
" <memory type=\"ram\" start=\"0x1B080000\" length=\"0xE4F80000\"/>"
"</memory-map>";
-bool lpc43xx_probe(struct target_s *target)
+bool lpc43xx_probe(target *t)
{
uint32_t chipid, cpuid;
- chipid = adiv5_ap_mem_read(adiv5_target_ap(target), LPC43XX_CHIPID);
- cpuid = adiv5_ap_mem_read(adiv5_target_ap(target), ARM_CPUID);
+ chipid = target_mem_read32(t, LPC43XX_CHIPID);
+ cpuid = target_mem_read32(t, ARM_CPUID);
switch(chipid) {
case 0x4906002B: /* Parts with on-chip flash */
switch (cpuid & 0xFF00FFF0) {
case 0x4100C240:
- target->driver = "LPC43xx Cortex-M4";
+ t->driver = "LPC43xx Cortex-M4";
if (cpuid == 0x410FC241)
{
/* LPC4337 */
- target->xml_mem_map = lpc4337_xml_memory_map;
- target->flash_erase = lpc43xx_flash_erase;
- target->flash_write = lpc43xx_flash_write;
- target_add_commands(target, lpc43xx_cmd_list, "LPC43xx");
+ t->xml_mem_map = lpc4337_xml_memory_map;
+ t->flash_erase = lpc43xx_flash_erase;
+ t->flash_write = lpc43xx_flash_write;
+ target_add_commands(t, lpc43xx_cmd_list, "LPC43xx");
}
break;
case 0x4100C200:
- target->driver = "LPC43xx Cortex-M0";
+ t->driver = "LPC43xx Cortex-M0";
break;
default:
- target->driver = "LPC43xx <Unknown>";
+ t->driver = "LPC43xx <Unknown>";
}
return true;
case 0x5906002B: /* Flashless parts */
case 0x6906002B:
switch (cpuid & 0xFF00FFF0) {
case 0x4100C240:
- target->driver = "LPC43xx Cortex-M4";
+ t->driver = "LPC43xx Cortex-M4";
break;
case 0x4100C200:
- target->driver = "LPC43xx Cortex-M0";
+ t->driver = "LPC43xx Cortex-M0";
break;
default:
- target->driver = "LPC43xx <Unknown>";
+ t->driver = "LPC43xx <Unknown>";
}
return true;
}
@@ -213,7 +213,7 @@ bool lpc43xx_probe(struct target_s *target)
}
/* Reset all major systems _except_ debug */
-static bool lpc43xx_cmd_reset(target *target, int argc, const char *argv[])
+static bool lpc43xx_cmd_reset(target *t, int argc, const char *argv[])
{
(void)argc;
(void)argv;
@@ -224,12 +224,12 @@ static bool lpc43xx_cmd_reset(target *target, int argc, const char *argv[])
static const uint32_t reset_val = 0x05FA0004;
/* System reset on target */
- target_mem_write_words(target, AIRCR, &reset_val, sizeof(reset_val));
+ target_mem_write(t, AIRCR, &reset_val, sizeof(reset_val));
return true;
}
-static bool lpc43xx_cmd_erase(target *target, int argc, const char *argv[])
+static bool lpc43xx_cmd_erase(target *t, int argc, const char *argv[])
{
(void)argc;
(void)argv;
@@ -237,7 +237,7 @@ static bool lpc43xx_cmd_erase(target *target, int argc, const char *argv[])
uint32_t bank = 0;
struct flash_program flash_pgm;
- lpc43xx_flash_init(target);
+ lpc43xx_flash_init(t);
for (bank = 0; bank < FLASH_NUM_BANK; bank++)
{
@@ -246,7 +246,7 @@ static bool lpc43xx_cmd_erase(target *target, int argc, const char *argv[])
flash_pgm.p.params.prepare.end_sector = FLASH_NUM_SECTOR-1;
flash_pgm.p.params.prepare.flash_bank = bank;
flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS;
- lpc43xx_iap_call(target, &flash_pgm.p, sizeof(flash_pgm.p));
+ lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p));
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
return false;
}
@@ -257,7 +257,7 @@ static bool lpc43xx_cmd_erase(target *target, int argc, const char *argv[])
flash_pgm.p.params.erase.cpu_clk_khz = CPU_CLK_KHZ;
flash_pgm.p.params.erase.flash_bank = bank;
flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS;
- lpc43xx_iap_call(target, &flash_pgm.p, sizeof(flash_pgm.p));
+ lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p));
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS)
{
return false;
@@ -269,20 +269,20 @@ static bool lpc43xx_cmd_erase(target *target, int argc, const char *argv[])
return true;
}
-static int lpc43xx_flash_init(struct target_s *target)
+static int lpc43xx_flash_init(target *t)
{
/* Deal with WDT */
- lpc43xx_wdt_set_period(target);
+ lpc43xx_wdt_set_period(t);
/* Force internal clock */
- lpc43xx_set_internal_clock(target);
+ lpc43xx_set_internal_clock(t);
struct flash_program flash_pgm;
/* Initialize flash IAP */
flash_pgm.p.command = IAP_CMD_INIT;
flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS;
- lpc43xx_iap_call(target, &flash_pgm.p, sizeof(flash_pgm.p));
+ lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p));
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS)
return -1;
@@ -332,40 +332,40 @@ static int32_t sector_number(uint32_t addr)
}
}
-static void lpc43xx_iap_call(struct target_s *target, struct flash_param *param, unsigned param_len)
+static void lpc43xx_iap_call(target *t, struct flash_param *param, unsigned param_len)
{
- uint32_t regs[target->regs_size / sizeof(uint32_t)];
+ uint32_t regs[t->regs_size / sizeof(uint32_t)];
uint32_t iap_entry;
/* Pet WDT before each IAP call, if it is on */
- lpc43xx_wdt_pet(target);
+ lpc43xx_wdt_pet(t);
- target_mem_read_words(target, &iap_entry, IAP_ENTRYPOINT_LOCATION, sizeof(iap_entry));
+ target_mem_read(t, &iap_entry, IAP_ENTRYPOINT_LOCATION, sizeof(iap_entry));
/* fill out the remainder of the parameters and copy the structure to RAM */
param->opcode = ARM_THUMB_BREAKPOINT; /* breakpoint */
param->pad0 = 0x0000; /* pad */
- target_mem_write_words(target, IAP_RAM_BASE, (void *)param, param_len);
+ target_mem_write(t, IAP_RAM_BASE, param, param_len);
/* set up for the call to the IAP ROM */
- target_regs_read(target, regs);
+ target_regs_read(t, regs);
regs[0] = IAP_RAM_BASE + offsetof(struct flash_param, command);
regs[1] = IAP_RAM_BASE + offsetof(struct flash_param, result);
regs[R_MSP] = IAP_RAM_BASE + IAP_RAM_SIZE;
regs[R_LR] = IAP_RAM_BASE | 1;
regs[R_PC] = iap_entry;
- target_regs_write(target, regs);
+ target_regs_write(t, regs);
/* start the target and wait for it to halt again */
- target_halt_resume(target, 0);
- while (!target_halt_wait(target));
+ target_halt_resume(t, 0);
+ while (!target_halt_wait(t));
/* copy back just the parameters structure */
- target_mem_read_words(target, (void *)param, IAP_RAM_BASE, sizeof(struct flash_param));
+ target_mem_read(t, param, IAP_RAM_BASE, sizeof(struct flash_param));
}
-static int lpc43xx_flash_prepare(struct target_s *target, uint32_t addr, int len)
+static int lpc43xx_flash_prepare(target *t, uint32_t addr, int len)
{
struct flash_program flash_pgm;
@@ -376,7 +376,7 @@ static int lpc43xx_flash_prepare(struct target_s *target, uint32_t addr, int len
flash_pgm.p.params.prepare.flash_bank = flash_bank(addr);
flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS;
- lpc43xx_iap_call(target, &flash_pgm.p, sizeof(flash_pgm.p));
+ lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p));
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
return -1;
}
@@ -384,7 +384,7 @@ static int lpc43xx_flash_prepare(struct target_s *target, uint32_t addr, int len
return 0;
}
-static int lpc43xx_flash_erase(struct target_s *target, uint32_t addr, size_t len)
+static int lpc43xx_flash_erase(target *t, uint32_t addr, size_t len)
{
struct flash_program flash_pgm;
@@ -393,11 +393,11 @@ static int lpc43xx_flash_erase(struct target_s *target, uint32_t addr, size_t le
return -1;
/* init */
- if (lpc43xx_flash_init(target))
+ if (lpc43xx_flash_init(t))
return -1;
/* prepare... */
- if (lpc43xx_flash_prepare(target, addr, len))
+ if (lpc43xx_flash_prepare(t, addr, len))
return -1;
/* and now erase them */
@@ -407,7 +407,7 @@ static int lpc43xx_flash_erase(struct target_s *target, uint32_t addr, size_t le
flash_pgm.p.params.erase.cpu_clk_khz = CPU_CLK_KHZ;
flash_pgm.p.params.erase.flash_bank = flash_bank(addr);
flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS;
- lpc43xx_iap_call(target, &flash_pgm.p, sizeof(flash_pgm.p));
+ lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p));
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
return -1;
}
@@ -418,7 +418,7 @@ static int lpc43xx_flash_erase(struct target_s *target, uint32_t addr, size_t le
flash_pgm.p.params.blank_check.end_sector = sector_number(addr+len);
flash_pgm.p.params.blank_check.flash_bank = flash_bank(addr);
flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS;
- lpc43xx_iap_call(target, &flash_pgm.p, sizeof(flash_pgm.p));
+ lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p));
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
return -1;
}
@@ -426,13 +426,13 @@ static int lpc43xx_flash_erase(struct target_s *target, uint32_t addr, size_t le
return 0;
}
-static void lpc43xx_set_internal_clock(struct target_s *target)
+static void lpc43xx_set_internal_clock(target *t)
{
const uint32_t val2 = (1 << 11) | (1 << 24);
- target_mem_write_words(target, 0x40050000 + 0x06C, &val2, sizeof(val2));
+ target_mem_write(t, 0x40050000 + 0x06C, &val2, sizeof(val2));
}
-static int lpc43xx_flash_write(struct target_s *target,
+static int lpc43xx_flash_write(target *t,
uint32_t dest, const uint8_t *src, size_t len)
{
unsigned first_chunk = dest / IAP_PGM_CHUNKSIZE;
@@ -472,14 +472,14 @@ static int lpc43xx_flash_write(struct target_s *target,
}
/* prepare... */
- if (lpc43xx_flash_prepare(target, chunk * IAP_PGM_CHUNKSIZE, IAP_PGM_CHUNKSIZE)) {
+ if (lpc43xx_flash_prepare(t, chunk * IAP_PGM_CHUNKSIZE, IAP_PGM_CHUNKSIZE)) {
return -1;
}
/* copy buffer into target memory */
- target_mem_write_words(target,
+ target_mem_write(t,
IAP_RAM_BASE + offsetof(struct flash_program, data),
- (uint32_t*)flash_pgm.data, sizeof(flash_pgm.data));
+ flash_pgm.data, sizeof(flash_pgm.data));
/* set the destination address and program */
flash_pgm.p.command = IAP_CMD_PROGRAM;
@@ -488,7 +488,7 @@ static int lpc43xx_flash_write(struct target_s *target,
flash_pgm.p.params.program.byte_count = IAP_PGM_CHUNKSIZE;
flash_pgm.p.params.program.cpu_clk_khz = CPU_CLK_KHZ;
flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS;
- lpc43xx_iap_call(target, &flash_pgm.p, sizeof(flash_pgm));
+ lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm));
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
return -1;
}
@@ -504,7 +504,7 @@ static int lpc43xx_flash_write(struct target_s *target,
* This is done indepently of writing to give the user a chance to verify flash
* before changing it.
*/
-static bool lpc43xx_cmd_mkboot(target *target, int argc, const char *argv[])
+static bool lpc43xx_cmd_mkboot(target *t, int argc, const char *argv[])
{
/* Usage: mkboot 0 or mkboot 1 */
if (argc != 2) {
@@ -519,7 +519,7 @@ static bool lpc43xx_cmd_mkboot(target *target, int argc, const char *argv[])
return false;
}
- lpc43xx_flash_init(target);
+ lpc43xx_flash_init(t);
struct flash_program flash_pgm;
/* special command to compute/write magic vector for signature */
@@ -527,7 +527,7 @@ static bool lpc43xx_cmd_mkboot(target *target, int argc, const char *argv[])
flash_pgm.p.params.make_active.flash_bank = bank;
flash_pgm.p.params.make_active.cpu_clk_khz = CPU_CLK_KHZ;
flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS;
- lpc43xx_iap_call(target, &flash_pgm.p, sizeof(flash_pgm));
+ lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm));
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
gdb_outf("Set bootable failed.\n");
return false;
@@ -537,11 +537,11 @@ static bool lpc43xx_cmd_mkboot(target *target, int argc, const char *argv[])
return true;
}
-static void lpc43xx_wdt_set_period(struct target_s *target)
+static void lpc43xx_wdt_set_period(target *t)
{
uint32_t wdt_mode = 0;
/* Check if WDT is on */
- target_mem_read_words(target, &wdt_mode, LPC43XX_WDT_MODE, sizeof(wdt_mode));
+ target_mem_read(t, &wdt_mode, LPC43XX_WDT_MODE, sizeof(wdt_mode));
/* If WDT on, we can't disable it, but we may be able to set a long period */
if (wdt_mode && !(wdt_mode & LPC43XX_WDT_PROTECT))
@@ -549,15 +549,15 @@ static void lpc43xx_wdt_set_period(struct target_s *target)
const uint32_t wdt_period = LPC43XX_WDT_PERIOD_MAX;
- target_mem_write_words(target, LPC43XX_WDT_CNT, &wdt_period, sizeof(wdt_period));
+ target_mem_write(t, LPC43XX_WDT_CNT, &wdt_period, sizeof(wdt_period));
}
}
-static void lpc43xx_wdt_pet(struct target_s *target)
+static void lpc43xx_wdt_pet(target *t)
{
uint32_t wdt_mode = 0;
/* Check if WDT is on */
- target_mem_read_words(target, &wdt_mode, LPC43XX_WDT_MODE, sizeof(wdt_mode));
+ target_mem_read(t, &wdt_mode, LPC43XX_WDT_MODE, sizeof(wdt_mode));
/* If WDT on, pet */
if (wdt_mode)
@@ -565,8 +565,7 @@ static void lpc43xx_wdt_pet(struct target_s *target)
const uint32_t feed1 = 0xAA;;
const uint32_t feed2 = 0x55;;
-
- target_mem_write_words(target, LPC43XX_WDT_FEED, &feed1, sizeof(feed1));
- target_mem_write_words(target, LPC43XX_WDT_FEED, &feed2, sizeof(feed2));
+ target_mem_write(t, LPC43XX_WDT_FEED, &feed1, sizeof(feed1));
+ target_mem_write(t, LPC43XX_WDT_FEED, &feed2, sizeof(feed2));
}
}
diff --git a/src/main.c b/src/main.c
index 60db15c..9f37107 100644
--- a/src/main.c
+++ b/src/main.c
@@ -28,6 +28,9 @@
#include "jtagtap.h"
#include "jtag_scan.h"
#include "target.h"
+#include "exception.h"
+#include "gdb_packet.h"
+#include "morse.h"
int
main(int argc, char **argv)
@@ -39,9 +42,18 @@ main(int argc, char **argv)
(void) argv;
platform_init();
#endif
- PLATFORM_SET_FATAL_ERROR_RECOVERY();
- gdb_main();
+ while (true) {
+ volatile struct exception e;
+ TRY_CATCH(e, EXCEPTION_ALL) {
+ gdb_main();
+ }
+ if (e.type) {
+ gdb_putpacketz("EFF");
+ target_list_free();
+ morse("TARGET LOST.", 1);
+ }
+ }
/* Should never get here */
return 0;
diff --git a/src/nrf51.c b/src/nrf51.c
index 55c9a58..e302de7 100644
--- a/src/nrf51.c
+++ b/src/nrf51.c
@@ -26,9 +26,10 @@
#include "target.h"
#include "command.h"
#include "gdb_packet.h"
+#include "cortexm.h"
-static int nrf51_flash_erase(struct target_s *target, uint32_t addr, size_t len);
-static int nrf51_flash_write(struct target_s *target, uint32_t dest,
+static int nrf51_flash_erase(target *t, uint32_t addr, size_t len);
+static int nrf51_flash_write(target *t, uint32_t dest,
const uint8_t *src, size_t len);
static bool nrf51_cmd_erase_all(target *t);
@@ -95,52 +96,18 @@ static const char nrf51_xml_memory_map[] = "<?xml version=\"1.0\"?>"
#define NRF51_PAGE_SIZE 1024
-static const uint16_t nrf51_flash_write_stub[] = {
-// _start:
- 0x4808, // ldr r0, [pc, #32] ; (24 <_ready>)
- 0x4909, // ldr r1, [pc, #36] ; (28 <_addr>)
- 0x467a, // mov r2, pc
- 0x3228, // adds r2, #40 ; 0x28
- 0x4b08, // ldr r3, [pc, #32] ; (2c <_size>)
-
-// next:
- 0x2b00, // cmp r3, #0
- 0xd009, // beq.n 22 <_done>
- 0x6814, // ldr r4, [r2, #0]
- 0x600c, // str r4, [r1, #0]
-
-// wait:
- 0x6804, // ldr r4, [r0, #0]
- 0x2601, // movs r6, #1
- 0x4234, // tst r4, r6
- 0xd0fb, // beq.n 12 <_wait>
-
- 0x3b04, // subs r3, #4
- 0x3104, // adds r1, #4
- 0x3204, // adds r2, #4
- 0xe7f3, // b.n a <_next>
-
-// done:
- 0xbe00, // bkpt 0x0000
-
-// ready:
- 0xe400, 0x4001 // .word 0x4001e400
-// addr:
-// 0x0000, 0x0000
-// size:
-// 0x0000, 0x0000
-// data:
-// ...
+#define SRAM_BASE 0x20000000
+#define STUB_BUFFER_BASE (SRAM_BASE + 0x28)
+static const uint16_t nrf51_flash_write_stub[] = {
+#include "../flashstub/nrf51.stub"
};
-bool nrf51_probe(struct target_s *target)
+bool nrf51_probe(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
+ t->idcode = target_mem_read32(t, NRF51_FICR_CONFIGID) & 0xFFFF;
- target->idcode = adiv5_ap_mem_read(ap, NRF51_FICR_CONFIGID) & 0xFFFF;
-
- switch (target->idcode) {
+ switch (t->idcode) {
case 0x001D:
case 0x002A:
case 0x0044:
@@ -152,46 +119,43 @@ bool nrf51_probe(struct target_s *target)
case 0x004D:
case 0x0026:
case 0x004C:
- target->driver = "Nordic nRF51";
- target->xml_mem_map = nrf51_xml_memory_map;
- target->flash_erase = nrf51_flash_erase;
- target->flash_write = nrf51_flash_write;
- target_add_commands(target, nrf51_cmd_list, "nRF51");
+ t->driver = "Nordic nRF51";
+ t->xml_mem_map = nrf51_xml_memory_map;
+ t->flash_erase = nrf51_flash_erase;
+ t->flash_write = nrf51_flash_write;
+ target_add_commands(t, nrf51_cmd_list, "nRF51");
return true;
}
return false;
}
-static int nrf51_flash_erase(struct target_s *target, uint32_t addr, size_t len)
+static int nrf51_flash_erase(target *t, uint32_t addr, size_t len)
{
-
- ADIv5_AP_t *ap = adiv5_target_ap(target);
-
addr &= ~(NRF51_PAGE_SIZE - 1);
len &= ~(NRF51_PAGE_SIZE - 1);
/* Enable erase */
- adiv5_ap_mem_write(ap, NRF51_NVMC_CONFIG, NRF51_NVMC_CONFIG_EEN);
+ target_mem_write32(t, NRF51_NVMC_CONFIG, NRF51_NVMC_CONFIG_EEN);
/* Poll for NVMC_READY */
- while(adiv5_ap_mem_read(ap, NRF51_NVMC_READY) == 0)
- if(target_check_error(target))
+ while (target_mem_read32(t, NRF51_NVMC_READY) == 0)
+ if(target_check_error(t))
return -1;
while (len) {
if (addr == NRF51_UICR) { // Special Case
/* Write to the ERASE_UICR register to erase */
- adiv5_ap_mem_write(ap, NRF51_NVMC_ERASEUICR, 0x1);
+ target_mem_write32(t, NRF51_NVMC_ERASEUICR, 0x1);
} else { // Standard Flash Page
/* Write address of first word in page to erase it */
- adiv5_ap_mem_write(ap, NRF51_NVMC_ERASEPAGE, addr);
+ target_mem_write32(t, NRF51_NVMC_ERASEPAGE, addr);
}
/* Poll for NVMC_READY */
- while(adiv5_ap_mem_read(ap, NRF51_NVMC_READY) == 0)
- if(target_check_error(target))
+ while (target_mem_read32(t, NRF51_NVMC_READY) == 0)
+ if(target_check_error(t))
return -1;
addr += NRF51_PAGE_SIZE;
@@ -199,20 +163,19 @@ static int nrf51_flash_erase(struct target_s *target, uint32_t addr, size_t len)
}
/* Return to read-only */
- adiv5_ap_mem_write(ap, NRF51_NVMC_CONFIG, NRF51_NVMC_CONFIG_REN);
+ target_mem_write32(t, NRF51_NVMC_CONFIG, NRF51_NVMC_CONFIG_REN);
/* Poll for NVMC_READY */
- while(adiv5_ap_mem_read(ap, NRF51_NVMC_READY) == 0)
- if(target_check_error(target))
+ while (target_mem_read32(t, NRF51_NVMC_READY) == 0)
+ if(target_check_error(t))
return -1;
return 0;
}
-static int nrf51_flash_write(struct target_s *target, uint32_t dest,
+static int nrf51_flash_write(target *t, uint32_t dest,
const uint8_t *src, size_t len)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
uint32_t offset = dest % 4;
uint32_t words = (offset + len + 3) / 4;
uint32_t data[2 + words];
@@ -225,49 +188,42 @@ static int nrf51_flash_write(struct target_s *target, uint32_t dest,
memcpy((uint8_t *)&data[2] + offset, src, len);
/* Enable write */
- adiv5_ap_mem_write(ap, NRF51_NVMC_CONFIG, NRF51_NVMC_CONFIG_WEN);
+ target_mem_write32(t, NRF51_NVMC_CONFIG, NRF51_NVMC_CONFIG_WEN);
/* Poll for NVMC_READY */
- while(adiv5_ap_mem_read(ap, NRF51_NVMC_READY) == 0)
- if(target_check_error(target))
+ while (target_mem_read32(t, NRF51_NVMC_READY) == 0)
+ if(target_check_error(t))
return -1;
- /* Write stub and data to target ram and set PC */
- target_mem_write_words(target, 0x20000000, (void*)nrf51_flash_write_stub, 0x28);
- target_mem_write_words(target, 0x20000028, data, len + 8);
- target_pc_write(target, 0x20000000);
- if(target_check_error(target))
- return -1;
-
- /* Execute the stub */
- target_halt_resume(target, 0);
- while(!target_halt_wait(target));
+ /* Write stub and data to target ram and call stub */
+ target_mem_write(t, SRAM_BASE, nrf51_flash_write_stub,
+ sizeof(nrf51_flash_write_stub));
+ target_mem_write(t, STUB_BUFFER_BASE, data, len + 8);
+ cortexm_run_stub(t, SRAM_BASE, 0, 0, 0, 0);
/* Return to read-only */
- adiv5_ap_mem_write(ap, NRF51_NVMC_CONFIG, NRF51_NVMC_CONFIG_REN);
+ target_mem_write32(t, NRF51_NVMC_CONFIG, NRF51_NVMC_CONFIG_REN);
return 0;
}
static bool nrf51_cmd_erase_all(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(t);
-
gdb_out("erase..\n");
/* Enable erase */
- adiv5_ap_mem_write(ap, NRF51_NVMC_CONFIG, NRF51_NVMC_CONFIG_EEN);
+ target_mem_write32(t, NRF51_NVMC_CONFIG, NRF51_NVMC_CONFIG_EEN);
/* Poll for NVMC_READY */
- while(adiv5_ap_mem_read(ap, NRF51_NVMC_READY) == 0)
+ while (target_mem_read32(t, NRF51_NVMC_READY) == 0)
if(target_check_error(t))
return false;
/* Erase all */
- adiv5_ap_mem_write(ap, NRF51_NVMC_ERASEALL, 1);
+ target_mem_write32(t, NRF51_NVMC_ERASEALL, 1);
/* Poll for NVMC_READY */
- while(adiv5_ap_mem_read(ap, NRF51_NVMC_READY) == 0)
+ while (target_mem_read32(t, NRF51_NVMC_READY) == 0)
if(target_check_error(t))
return false;
@@ -276,28 +232,22 @@ static bool nrf51_cmd_erase_all(target *t)
static bool nrf51_cmd_read_hwid(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(t);
-
- uint32_t hwid = adiv5_ap_mem_read(ap, NRF51_FICR_CONFIGID) & 0xFFFF;
+ uint32_t hwid = target_mem_read32(t, NRF51_FICR_CONFIGID) & 0xFFFF;
gdb_outf("Hardware ID: 0x%04X\n", hwid);
return true;
}
static bool nrf51_cmd_read_fwid(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(t);
-
- uint32_t fwid = (adiv5_ap_mem_read(ap, NRF51_FICR_CONFIGID) >> 16) & 0xFFFF;
+ uint32_t fwid = (target_mem_read32(t, NRF51_FICR_CONFIGID) >> 16) & 0xFFFF;
gdb_outf("Firmware ID: 0x%04X\n", fwid);
return true;
}
static bool nrf51_cmd_read_deviceid(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(t);
-
- uint32_t deviceid_low = adiv5_ap_mem_read(ap, NRF51_FICR_DEVICEID_LOW);
- uint32_t deviceid_high = adiv5_ap_mem_read(ap, NRF51_FICR_DEVICEID_HIGH);
+ uint32_t deviceid_low = target_mem_read32(t, NRF51_FICR_DEVICEID_LOW);
+ uint32_t deviceid_high = target_mem_read32(t, NRF51_FICR_DEVICEID_HIGH);
gdb_outf("Device ID: 0x%08X%08X\n", deviceid_high, deviceid_low);
@@ -305,11 +255,9 @@ static bool nrf51_cmd_read_deviceid(target *t)
}
static bool nrf51_cmd_read_deviceaddr(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(t);
-
- uint32_t addr_type = adiv5_ap_mem_read(ap, NRF51_FICR_DEVICEADDRTYPE);
- uint32_t addr_low = adiv5_ap_mem_read(ap, NRF51_FICR_DEVICEADDR_LOW);
- uint32_t addr_high = adiv5_ap_mem_read(ap, NRF51_FICR_DEVICEADDR_HIGH) & 0xFFFF;
+ uint32_t addr_type = target_mem_read32(t, NRF51_FICR_DEVICEADDRTYPE);
+ uint32_t addr_low = target_mem_read32(t, NRF51_FICR_DEVICEADDR_LOW);
+ uint32_t addr_high = target_mem_read32(t, NRF51_FICR_DEVICEADDR_HIGH) & 0xFFFF;
if ((addr_type & 1) == 0) {
gdb_outf("Publicly Listed Address: 0x%04X%08X\n", addr_high, addr_low);
diff --git a/src/platforms/f4discovery/platform.h b/src/platforms/f4discovery/platform.h
index 300a3c1..16bd169 100644
--- a/src/platforms/f4discovery/platform.h
+++ b/src/platforms/f4discovery/platform.h
@@ -24,9 +24,7 @@
#ifndef __PLATFORM_H
#define __PLATFORM_H
-#include "gdb_packet.h"
#include "gpio.h"
-#include "morse.h"
#include "timing.h"
#include "version.h"
@@ -142,8 +140,6 @@
#define DEBUG(...)
-extern jmp_buf fatal_error_jmpbuf;
-
#define gpio_set_val(port, pin, val) do { \
if(val) \
gpio_set((port), (pin)); \
@@ -155,16 +151,6 @@ extern jmp_buf fatal_error_jmpbuf;
#define SET_IDLE_STATE(state) {gpio_set_val(LED_PORT, LED_IDLE_RUN, state);}
#define SET_ERROR_STATE(state) {gpio_set_val(LED_PORT, LED_ERROR, state);}
-#define PLATFORM_SET_FATAL_ERROR_RECOVERY() {setjmp(fatal_error_jmpbuf);}
-#define PLATFORM_FATAL_ERROR(error) { \
- if(running_status) gdb_putpacketz("X1D"); \
- else gdb_putpacketz("EFF"); \
- running_status = 0; \
- target_list_free(); \
- morse("TARGET LOST.", 1); \
- longjmp(fatal_error_jmpbuf, (error)); \
-}
-
static inline int platform_hwversion(void)
{
return 0;
diff --git a/src/platforms/launchpad-icdi/platform.c b/src/platforms/launchpad-icdi/platform.c
index e689f0c..ff67fa0 100644
--- a/src/platforms/launchpad-icdi/platform.c
+++ b/src/platforms/launchpad-icdi/platform.c
@@ -33,7 +33,6 @@
extern void trace_tick(void);
-jmp_buf fatal_error_jmpbuf;
uint8_t running_status;
volatile uint32_t timeout_counter;
@@ -86,10 +85,20 @@ platform_init(void)
cdcacm_init();
}
+void platform_timeout_set(uint32_t ms)
+{
+ timeout_counter = ms / 10;
+}
+
+bool platform_timeout_is_expired(void)
+{
+ return timeout_counter == 0;
+}
+
void platform_delay(uint32_t delay)
{
- timeout_counter = delay * 10;
- while(timeout_counter);
+ platform_timeout_set(delay);
+ while (platform_timeout_is_expired());
}
const char *platform_target_voltage(void)
diff --git a/src/platforms/launchpad-icdi/platform.h b/src/platforms/launchpad-icdi/platform.h
index dc2efcf..52b963e 100644
--- a/src/platforms/launchpad-icdi/platform.h
+++ b/src/platforms/launchpad-icdi/platform.h
@@ -17,10 +17,6 @@
#ifndef __PLATFORM_H
#define __PLATFORM_H
-#include "gdb_packet.h"
-
-#include <setjmp.h>
-
#include <libopencm3/lm4f/gpio.h>
#include <libopencm3/usb/usbd.h>
@@ -31,7 +27,6 @@
#define DFU_IDENT "Black Magic Firmware Upgrade (Launchpad)"
#define DFU_IFACE_STRING "lolwut"
-extern jmp_buf fatal_error_jmpbuf;
extern uint8_t running_status;
extern volatile uint32_t timeout_counter;
@@ -108,16 +103,6 @@ extern usbd_driver lm4f_usb_driver;
#define SET_IDLE_STATE(state) {}
#define SET_ERROR_STATE(state) SET_IDLE_STATE(state)
-#define PLATFORM_SET_FATAL_ERROR_RECOVERY() {setjmp(fatal_error_jmpbuf);}
-#define PLATFORM_FATAL_ERROR(error) { \
- if( running_status ) gdb_putpacketz("X1D"); \
- else gdb_putpacketz("EFF"); \
- running_status = 0; \
- target_list_free(); \
- morse("TARGET LOST.", 1); \
- longjmp(fatal_error_jmpbuf, (error)); \
-}
-
#define PLATFORM_HAS_TRACESWO
inline static void gpio_set_val(uint32_t port, uint8_t pin, uint8_t val) {
diff --git a/src/platforms/libftdi/platform.c b/src/platforms/libftdi/platform.c
index 0f16263..37f876b 100644
--- a/src/platforms/libftdi/platform.c
+++ b/src/platforms/libftdi/platform.c
@@ -22,6 +22,7 @@
#include "version.h"
#include <assert.h>
+#include <sys/time.h>
struct ftdi_context *ftdic;
@@ -264,3 +265,21 @@ void platform_delay(uint32_t delay)
usleep(delay * 100000);
}
+static uint32_t timeout_time;
+static uint32_t time_ms(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
+}
+
+void platform_timeout_set(uint32_t ms)
+{
+ timeout_time = time_ms() + ms;
+}
+
+bool platform_timeout_is_expired(void)
+{
+ return time_ms() > timeout_time;
+}
+
diff --git a/src/platforms/libftdi/platform.h b/src/platforms/libftdi/platform.h
index 135b2e3..8611674 100644
--- a/src/platforms/libftdi/platform.h
+++ b/src/platforms/libftdi/platform.h
@@ -36,9 +36,6 @@
#define SET_IDLE_STATE(state)
#define SET_ERROR_STATE(state)
-#define PLATFORM_FATAL_ERROR(error) abort()
-#define PLATFORM_SET_FATAL_ERROR_RECOVERY()
-
extern struct ftdi_context *ftdic;
void platform_buffer_flush(void);
diff --git a/src/platforms/native/platform.c b/src/platforms/native/platform.c
index ac54b4b..babb498 100644
--- a/src/platforms/native/platform.c
+++ b/src/platforms/native/platform.c
@@ -35,8 +35,6 @@
#include <libopencm3/usb/usbd.h>
#include <libopencm3/stm32/f1/adc.h>
-jmp_buf fatal_error_jmpbuf;
-
static void adc_init(void);
static void setup_vbus_irq(void);
diff --git a/src/platforms/native/platform.h b/src/platforms/native/platform.h
index ae9bcef..6958585 100644
--- a/src/platforms/native/platform.h
+++ b/src/platforms/native/platform.h
@@ -24,13 +24,9 @@
#ifndef __PLATFORM_H
#define __PLATFORM_H
-#include "gdb_packet.h"
#include "gpio.h"
-#include "morse.h"
#include "timing.h"
-#include <setjmp.h>
-
#define PLATFORM_HAS_TRACESWO
#define PLATFORM_HAS_POWER_SWITCH
#define BOARD_IDENT "Black Magic Probe"
@@ -147,22 +143,10 @@
#define DEBUG(...)
-extern jmp_buf fatal_error_jmpbuf;
-
#define SET_RUN_STATE(state) {running_status = (state);}
#define SET_IDLE_STATE(state) {gpio_set_val(LED_PORT, LED_IDLE_RUN, state);}
#define SET_ERROR_STATE(state) {gpio_set_val(LED_PORT, LED_ERROR, state);}
-#define PLATFORM_SET_FATAL_ERROR_RECOVERY() {setjmp(fatal_error_jmpbuf);}
-#define PLATFORM_FATAL_ERROR(error) do { \
- if(running_status) gdb_putpacketz("X1D"); \
- else gdb_putpacketz("EFF"); \
- running_status = 0; \
- target_list_free(); \
- morse("TARGET LOST.", 1); \
- longjmp(fatal_error_jmpbuf, (error)); \
-} while (0)
-
/* Use newlib provided integer only stdio functions */
#define sscanf siscanf
#define sprintf siprintf
diff --git a/src/platforms/stlink/Makefile.inc b/src/platforms/stlink/Makefile.inc
index dd1ab41..fdee700 100644
--- a/src/platforms/stlink/Makefile.inc
+++ b/src/platforms/stlink/Makefile.inc
@@ -2,6 +2,7 @@ CROSS_COMPILE ?= arm-none-eabi-
CC = $(CROSS_COMPILE)gcc
OBJCOPY = $(CROSS_COMPILE)objcopy
+OPT_FLAGS = -Os
CFLAGS += -mcpu=cortex-m3 -mthumb \
-DSTM32F1 -DDISCOVERY_STLINK -I../libopencm3/include \
-I platforms/stm32
diff --git a/src/platforms/stlink/platform.c b/src/platforms/stlink/platform.c
index fb10faa..dd501a4 100644
--- a/src/platforms/stlink/platform.c
+++ b/src/platforms/stlink/platform.c
@@ -36,8 +36,6 @@
uint8_t running_status;
volatile uint32_t timeout_counter;
-jmp_buf fatal_error_jmpbuf;
-
uint16_t led_idle_run;
/* Pins PC[14:13] are used to detect hardware revision. Read
* 11 for STLink V1 e.g. on VL Discovery, tag as hwversion 0
diff --git a/src/platforms/stlink/platform.h b/src/platforms/stlink/platform.h
index c304db2..498e512 100644
--- a/src/platforms/stlink/platform.h
+++ b/src/platforms/stlink/platform.h
@@ -24,7 +24,6 @@
#ifndef __PLATFORM_H
#define __PLATFORM_H
-#include "gdb_packet.h"
#include "gpio.h"
#include "timing.h"
#include "version.h"
@@ -33,8 +32,6 @@
#include <libopencm3/stm32/f1/memorymap.h>
#include <libopencm3/usb/usbd.h>
-#include <setjmp.h>
-
#define BOARD_IDENT "Black Magic Probe (STLINK), (Firmware " FIRMWARE_VERSION ")"
#define BOARD_IDENT_DFU "Black Magic (Upgrade) for STLink/Discovery, (Firmware " FIRMWARE_VERSION ")"
#define BOARD_IDENT_UPD "Black Magic (DFU Upgrade) for STLink/Discovery, (Firmware " FIRMWARE_VERSION ")"
@@ -131,23 +128,12 @@
#define DEBUG(...)
-extern jmp_buf fatal_error_jmpbuf;
-
extern uint16_t led_idle_run;
#define LED_IDLE_RUN led_idle_run
#define SET_RUN_STATE(state) {running_status = (state);}
#define SET_IDLE_STATE(state) {gpio_set_val(LED_PORT, led_idle_run, state);}
#define SET_ERROR_STATE(x)
-#define PLATFORM_SET_FATAL_ERROR_RECOVERY() {setjmp(fatal_error_jmpbuf);}
-#define PLATFORM_FATAL_ERROR(error) do { \
- if(running_status) gdb_putpacketz("X1D"); \
- else gdb_putpacketz("EFF"); \
- running_status = 0; \
- target_list_free(); \
- longjmp(fatal_error_jmpbuf, (error)); \
-} while (0)
-
/* Use newlib provided integer only stdio functions */
#define sscanf siscanf
#define sprintf siprintf
diff --git a/src/platforms/stm32/timing.c b/src/platforms/stm32/timing.c
index cac22ca..55a217a 100644
--- a/src/platforms/stm32/timing.c
+++ b/src/platforms/stm32/timing.c
@@ -17,6 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "general.h"
+#include "morse.h"
#include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/scb.h>
diff --git a/src/platforms/swlink/Makefile.inc b/src/platforms/swlink/Makefile.inc
index 8899471..62f90bb 100644
--- a/src/platforms/swlink/Makefile.inc
+++ b/src/platforms/swlink/Makefile.inc
@@ -2,6 +2,7 @@ CROSS_COMPILE ?= arm-none-eabi-
CC = $(CROSS_COMPILE)gcc
OBJCOPY = $(CROSS_COMPILE)objcopy
+OPT_FLAGS = -Os
CFLAGS += -mcpu=cortex-m3 -mthumb \
-DSTM32F1 -DDISCOVERY_SWLINK -I../libopencm3/include \
-I platforms/stm32
diff --git a/src/platforms/swlink/platform.c b/src/platforms/swlink/platform.c
index cbdae0c..02cde19 100644
--- a/src/platforms/swlink/platform.c
+++ b/src/platforms/swlink/platform.c
@@ -33,8 +33,6 @@
#include <libopencm3/usb/usbd.h>
#include <libopencm3/stm32/f1/adc.h>
-jmp_buf fatal_error_jmpbuf;
-
void platform_init(void)
{
uint32_t data;
diff --git a/src/platforms/swlink/platform.h b/src/platforms/swlink/platform.h
index ffa35cf..e31f543 100644
--- a/src/platforms/swlink/platform.h
+++ b/src/platforms/swlink/platform.h
@@ -24,13 +24,10 @@
#ifndef __PLATFORM_H
#define __PLATFORM_H
-#include "gdb_packet.h"
#include "gpio.h"
#include "timing.h"
#include "version.h"
-#include <setjmp.h>
-
#define BOARD_IDENT "Black Magic Probe (SWLINK), (Firmware " FIRMWARE_VERSION ")"
#define BOARD_IDENT_DFU "Black Magic (Upgrade), STM8S Discovery, (Firmware " FIRMWARE_VERSION ")"
#define BOARD_IDENT_UPD "Black Magic (DFU Upgrade), STM8S Discovery, (Firmware " FIRMWARE_VERSION ")"
@@ -126,21 +123,10 @@
#define DEBUG(...)
-extern jmp_buf fatal_error_jmpbuf;
-
#define SET_RUN_STATE(state) {running_status = (state);}
#define SET_IDLE_STATE(state) {gpio_set_val(LED_PORT, LED_IDLE_RUN, state);}
#define SET_ERROR_STATE(x)
-#define PLATFORM_SET_FATAL_ERROR_RECOVERY() {setjmp(fatal_error_jmpbuf);}
-#define PLATFORM_FATAL_ERROR(error) { \
- if(running_status) gdb_putpacketz("X1D"); \
- else gdb_putpacketz("EFF"); \
- running_status = 0; \
- target_list_free(); \
- longjmp(fatal_error_jmpbuf, (error)); \
-}
-
/* Use newlib provided integer only stdio functions */
#define sscanf siscanf
#define sprintf siprintf
diff --git a/src/sam3x.c b/src/sam3x.c
index 7141cb5..0566718 100644
--- a/src/sam3x.c
+++ b/src/sam3x.c
@@ -28,8 +28,8 @@
#include "command.h"
#include "gdb_packet.h"
-static int sam3x_flash_erase(struct target_s *target, uint32_t addr, size_t len);
-static int sam3x_flash_write(struct target_s *target, uint32_t dest,
+static int sam3x_flash_erase(target *t, uint32_t addr, size_t len);
+static int sam3x_flash_write(target *t, uint32_t dest,
const uint8_t *src, size_t len);
static bool sam3x_cmd_gpnvm_get(target *t);
@@ -65,6 +65,18 @@ static const char sam3n_xml_memory_map[] = "<?xml version=\"1.0\"?>"
" <memory type=\"ram\" start=\"0x20000000\" length=\"0x200000\"/>"
"</memory-map>";
+static const char sam3u_xml_memory_map[] = "<?xml version=\"1.0\"?>"
+/* "<!DOCTYPE memory-map "
+ " PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
+ " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"*/
+ "<memory-map>"
+ " <memory type=\"flash\" start=\"0x80000\" length=\"0x100000\">"
+ " <property name=\"blocksize\">0x100</property>"
+ " </memory>"
+ " <memory type=\"rom\" start=\"0x180000\" length=\"0x200000\"/>"
+ " <memory type=\"ram\" start=\"0x20000000\" length=\"0x200000\"/>"
+ "</memory-map>";
+
static const char sam4s_xml_memory_map[] = "<?xml version=\"1.0\"?>"
/* "<!DOCTYPE memory-map "
" PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
@@ -80,6 +92,7 @@ static const char sam4s_xml_memory_map[] = "<?xml version=\"1.0\"?>"
/* Enhanced Embedded Flash Controller (EEFC) Register Map */
#define SAM3N_EEFC_BASE 0x400E0A00
#define SAM3X_EEFC_BASE(x) (0x400E0A00+((x)*0x400))
+#define SAM3U_EEFC_BASE(x) (0x400E0800+((x)*0x200))
#define SAM4S_EEFC_BASE(x) (0x400E0A00+((x)*0x200))
#define EEFC_FMR(base) ((base)+0x00)
#define EEFC_FCR(base) ((base)+0x04)
@@ -111,6 +124,7 @@ static const char sam4s_xml_memory_map[] = "<?xml version=\"1.0\"?>"
#define SAM3X_CHIPID_CIDR 0x400E0940
#define SAM3N_CHIPID_CIDR 0x400E0740
#define SAM3S_CHIPID_CIDR 0x400E0740
+#define SAM3U_CHIPID_CIDR 0x400E0740
#define SAM4S_CHIPID_CIDR 0x400E0740
#define CHIPID_CIDR_VERSION_MASK (0x1F << 0)
@@ -126,6 +140,8 @@ static const char sam4s_xml_memory_map[] = "<?xml version=\"1.0\"?>"
#define CHIPID_CIDR_NVPSIZ2_MASK (0x0F << 12)
#define CHIPID_CIDR_SRAMSIZ_MASK (0x0F << 16)
#define CHIPID_CIDR_ARCH_MASK (0xFF << 20)
+#define CHIPID_CIDR_ARCH_SAM3UxC (0x80 << 20)
+#define CHIPID_CIDR_ARCH_SAM3UxE (0x81 << 20)
#define CHIPID_CIDR_ARCH_SAM3XxC (0x84 << 20)
#define CHIPID_CIDR_ARCH_SAM3XxE (0x85 << 20)
#define CHIPID_CIDR_ARCH_SAM3XxG (0x86 << 20)
@@ -146,61 +162,71 @@ static const char sam4s_xml_memory_map[] = "<?xml version=\"1.0\"?>"
#define SAM3_PAGE_SIZE 256
#define SAM4_PAGE_SIZE 512
-bool sam3x_probe(struct target_s *target)
+bool sam3x_probe(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
-
- target->idcode = adiv5_ap_mem_read(ap, SAM3X_CHIPID_CIDR);
+ t->idcode = target_mem_read32(t, SAM3X_CHIPID_CIDR);
/* FIXME: Check for all variants with similar flash interface */
- switch (target->idcode & (CHIPID_CIDR_ARCH_MASK | CHIPID_CIDR_EPROC_MASK)) {
+ switch (t->idcode & (CHIPID_CIDR_ARCH_MASK | CHIPID_CIDR_EPROC_MASK)) {
case CHIPID_CIDR_ARCH_SAM3XxC | CHIPID_CIDR_EPROC_CM3:
case CHIPID_CIDR_ARCH_SAM3XxE | CHIPID_CIDR_EPROC_CM3:
case CHIPID_CIDR_ARCH_SAM3XxG | CHIPID_CIDR_EPROC_CM3:
- target->driver = "Atmel SAM3X";
- target->xml_mem_map = sam3x_xml_memory_map;
- target->flash_erase = sam3x_flash_erase;
- target->flash_write = sam3x_flash_write;
- target_add_commands(target, sam3x_cmd_list, "SAM3X");
+ t->driver = "Atmel SAM3X";
+ t->xml_mem_map = sam3x_xml_memory_map;
+ t->flash_erase = sam3x_flash_erase;
+ t->flash_write = sam3x_flash_write;
+ target_add_commands(t, sam3x_cmd_list, "SAM3X");
return true;
}
- target->idcode = adiv5_ap_mem_read(ap, SAM3N_CHIPID_CIDR);
- switch (target->idcode & (CHIPID_CIDR_ARCH_MASK | CHIPID_CIDR_EPROC_MASK)) {
+ t->idcode = target_mem_read32(t, SAM3N_CHIPID_CIDR);
+ switch (t->idcode & (CHIPID_CIDR_ARCH_MASK | CHIPID_CIDR_EPROC_MASK)) {
case CHIPID_CIDR_ARCH_SAM3NxA | CHIPID_CIDR_EPROC_CM3:
case CHIPID_CIDR_ARCH_SAM3NxB | CHIPID_CIDR_EPROC_CM3:
case CHIPID_CIDR_ARCH_SAM3NxC | CHIPID_CIDR_EPROC_CM3:
- target->driver = "Atmel SAM3N";
- target->xml_mem_map = sam3n_xml_memory_map;
- target->flash_erase = sam3x_flash_erase;
- target->flash_write = sam3x_flash_write;
- target_add_commands(target, sam3x_cmd_list, "SAM3N");
+ t->driver = "Atmel SAM3N";
+ t->xml_mem_map = sam3n_xml_memory_map;
+ t->flash_erase = sam3x_flash_erase;
+ t->flash_write = sam3x_flash_write;
+ target_add_commands(t, sam3x_cmd_list, "SAM3N");
+ return true;
+ }
+
+ t->idcode = target_mem_read32(t, SAM3S_CHIPID_CIDR);
+ switch (t->idcode & (CHIPID_CIDR_ARCH_MASK | CHIPID_CIDR_EPROC_MASK)) {
+ case CHIPID_CIDR_ARCH_SAM3SxA | CHIPID_CIDR_EPROC_CM3:
+ case CHIPID_CIDR_ARCH_SAM3SxB | CHIPID_CIDR_EPROC_CM3:
+ case CHIPID_CIDR_ARCH_SAM3SxC | CHIPID_CIDR_EPROC_CM3:
+ t->driver = "Atmel SAM3S";
+ t->xml_mem_map = sam3n_xml_memory_map;
+ t->flash_erase = sam3x_flash_erase;
+ t->flash_write = sam3x_flash_write;
+ target_add_commands(t, sam3x_cmd_list, "SAM3S");
return true;
}
-
- target->idcode = adiv5_ap_mem_read(ap, SAM3S_CHIPID_CIDR);
- switch (target->idcode & (CHIPID_CIDR_ARCH_MASK | CHIPID_CIDR_EPROC_MASK)) {
- case CHIPID_CIDR_ARCH_SAM3SxA | CHIPID_CIDR_EPROC_CM3:
- case CHIPID_CIDR_ARCH_SAM3SxB | CHIPID_CIDR_EPROC_CM3:
- case CHIPID_CIDR_ARCH_SAM3SxC | CHIPID_CIDR_EPROC_CM3:
- target->driver = "Atmel SAM3S";
- target->xml_mem_map = sam3n_xml_memory_map;
- target->flash_erase = sam3x_flash_erase;
- target->flash_write = sam3x_flash_write;
- target_add_commands(target, sam3x_cmd_list, "SAM3S");
- return true;
- }
-
- target->idcode = adiv5_ap_mem_read(ap, SAM4S_CHIPID_CIDR);
- switch (target->idcode & (CHIPID_CIDR_ARCH_MASK | CHIPID_CIDR_EPROC_MASK)) {
+
+ t->idcode = target_mem_read32(t, SAM3U_CHIPID_CIDR);
+ switch (t->idcode & (CHIPID_CIDR_ARCH_MASK | CHIPID_CIDR_EPROC_MASK)) {
+ case CHIPID_CIDR_ARCH_SAM3UxC | CHIPID_CIDR_EPROC_CM3:
+ case CHIPID_CIDR_ARCH_SAM3UxE | CHIPID_CIDR_EPROC_CM3:
+ t->driver = "Atmel SAM3U";
+ t->xml_mem_map = sam3u_xml_memory_map;
+ t->flash_erase = sam3x_flash_erase;
+ t->flash_write = sam3x_flash_write;
+ target_add_commands(t, sam3x_cmd_list, "SAM3U");
+ return true;
+ }
+
+ t->idcode = target_mem_read32(t, SAM4S_CHIPID_CIDR);
+ switch (t->idcode & (CHIPID_CIDR_ARCH_MASK | CHIPID_CIDR_EPROC_MASK)) {
case CHIPID_CIDR_ARCH_SAM4SxA | CHIPID_CIDR_EPROC_CM4:
case CHIPID_CIDR_ARCH_SAM4SxB | CHIPID_CIDR_EPROC_CM4:
case CHIPID_CIDR_ARCH_SAM4SxC | CHIPID_CIDR_EPROC_CM4:
- target->driver = "Atmel SAM4S";
- target->xml_mem_map = sam4s_xml_memory_map;
- target->flash_erase = sam3x_flash_erase;
- target->flash_write = sam3x_flash_write;
- target_add_commands(target, sam3x_cmd_list, "SAM4S");
+ t->driver = "Atmel SAM4S";
+ t->xml_mem_map = sam4s_xml_memory_map;
+ t->flash_erase = sam3x_flash_erase;
+ t->flash_write = sam3x_flash_write;
+ target_add_commands(t, sam3x_cmd_list, "SAM4S");
return true;
}
@@ -208,29 +234,27 @@ bool sam3x_probe(struct target_s *target)
}
static int
-sam3x_flash_cmd(struct target_s *target, uint32_t base, uint8_t cmd, uint16_t arg)
+sam3x_flash_cmd(target *t, uint32_t base, uint8_t cmd, uint16_t arg)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
-
DEBUG("%s: base = 0x%08x cmd = 0x%02X, arg = 0x%06X\n",
__func__, base, cmd, arg);
- adiv5_ap_mem_write(ap, EEFC_FCR(base),
- EEFC_FCR_FKEY | cmd | ((uint32_t)arg << 8));
+ target_mem_write32(t, EEFC_FCR(base),
+ EEFC_FCR_FKEY | cmd | ((uint32_t)arg << 8));
- while(!(adiv5_ap_mem_read(ap, EEFC_FSR(base)) & EEFC_FSR_FRDY))
- if(target_check_error(target))
+ while (!(target_mem_read32(t, EEFC_FSR(base)) & EEFC_FSR_FRDY))
+ if(target_check_error(t))
return -1;
- uint32_t sr = adiv5_ap_mem_read(ap, EEFC_FSR(base));
+ uint32_t sr = target_mem_read32(t, EEFC_FSR(base));
return sr & EEFC_FSR_ERROR;
}
static uint32_t
-sam3x_flash_base(struct target_s *target, uint32_t addr, uint32_t *offset)
+sam3x_flash_base(target *t, uint32_t addr, uint32_t *offset)
{
- if (strcmp(target->driver, "Atmel SAM3X") == 0) {
+ if (strcmp(t->driver, "Atmel SAM3X") == 0) {
uint32_t half = -1;
- switch (target->idcode & CHIPID_CIDR_NVPSIZ_MASK) {
+ switch (t->idcode & CHIPID_CIDR_NVPSIZ_MASK) {
case CHIPID_CIDR_NVPSIZ_128K:
half = 0x00090000;
break;
@@ -252,9 +276,24 @@ sam3x_flash_base(struct target_s *target, uint32_t addr, uint32_t *offset)
}
}
- if (strcmp(target->driver, "Atmel SAM4S") == 0) {
+ /* The SAM3U has a constant split between both banks */
+ if (strcmp(t->driver, "Atmel SAM3U") == 0) {
+ if (addr >= 0x100000) {
+ if(offset)
+ *offset = addr - 0x100000;
+
+ return SAM3U_EEFC_BASE(1);
+ } else {
+ if(offset)
+ *offset = addr - 0x80000;
+
+ return SAM3U_EEFC_BASE(0);
+ }
+ }
+
+ if (strcmp(t->driver, "Atmel SAM4S") == 0) {
uint32_t half = -1;
- switch (target->idcode & CHIPID_CIDR_NVPSIZ_MASK) {
+ switch (t->idcode & CHIPID_CIDR_NVPSIZ_MASK) {
case CHIPID_CIDR_NVPSIZ_128K:
case CHIPID_CIDR_NVPSIZ_256K:
case CHIPID_CIDR_NVPSIZ_512K:
@@ -285,16 +324,16 @@ sam3x_flash_base(struct target_s *target, uint32_t addr, uint32_t *offset)
return SAM3N_EEFC_BASE;
}
-static int sam3x_flash_erase(struct target_s *target, uint32_t addr, size_t len)
+static int sam3x_flash_erase(target *t, uint32_t addr, size_t len)
{
uint32_t offset;
- uint32_t base = sam3x_flash_base(target, addr, &offset);
+ uint32_t base = sam3x_flash_base(t, addr, &offset);
/* The SAM4S is the only supported device with a page erase command.
* Erasing is done in 8-page chunks. arg[15:2] contains the page
* number and arg[1:0] contains 0x1, indicating 8-page chunks.
*/
- if (strcmp(target->driver, "Atmel SAM4S") == 0) {
+ if (strcmp(t->driver, "Atmel SAM4S") == 0) {
unsigned chunk = offset / SAM4_PAGE_SIZE;
/* Fail if the start address is not 8-page-aligned. */
@@ -306,7 +345,7 @@ static int sam3x_flash_erase(struct target_s *target, uint32_t addr, size_t len)
*/
while (len > 0) {
int16_t arg = chunk | 0x1;
- if(sam3x_flash_cmd(target, base, EEFC_FCR_FCMD_EPA, arg))
+ if(sam3x_flash_cmd(t, base, EEFC_FCR_FCMD_EPA, arg))
return -1;
len -= SAM4_PAGE_SIZE * 8;
@@ -326,10 +365,10 @@ static int sam3x_flash_erase(struct target_s *target, uint32_t addr, size_t len)
memset(buf, 0xff, sizeof(buf));
/* Only do this once, since it doesn't change. */
- target_mem_write_words(target, addr, (void*)buf, SAM3_PAGE_SIZE);
+ target_mem_write(t, addr, buf, SAM3_PAGE_SIZE);
while (len) {
- if(sam3x_flash_cmd(target, base, EEFC_FCR_FCMD_EWP, chunk))
+ if(sam3x_flash_cmd(t, base, EEFC_FCR_FCMD_EWP, chunk))
return -1;
len -= SAM3_PAGE_SIZE;
@@ -340,17 +379,17 @@ static int sam3x_flash_erase(struct target_s *target, uint32_t addr, size_t len)
return 0;
}
-static int sam3x_flash_write(struct target_s *target, uint32_t dest,
+static int sam3x_flash_write(target *t, uint32_t dest,
const uint8_t *src, size_t len)
{
unsigned page_size;
- if (strcmp(target->driver, "Atmel SAM4S") == 0) {
+ if (strcmp(t->driver, "Atmel SAM4S") == 0) {
page_size = SAM4_PAGE_SIZE;
} else {
page_size = SAM3_PAGE_SIZE;
}
uint32_t offset;
- uint32_t base = sam3x_flash_base(target, dest, &offset);
+ uint32_t base = sam3x_flash_base(t, dest, &offset);
uint8_t buf[page_size];
unsigned first_chunk = offset / page_size;
unsigned last_chunk = (offset + len - 1) / page_size;
@@ -384,8 +423,8 @@ static int sam3x_flash_write(struct target_s *target, uint32_t dest,
src += page_size;
}
- target_mem_write_words(target, dest, (void*)buf, page_size);
- if(sam3x_flash_cmd(target, base, EEFC_FCR_FCMD_WP, chunk))
+ target_mem_write(t, dest, buf, page_size);
+ if(sam3x_flash_cmd(t, base, EEFC_FCR_FCMD_WP, chunk))
return -1;
}
@@ -394,11 +433,10 @@ static int sam3x_flash_write(struct target_s *target, uint32_t dest,
static bool sam3x_cmd_gpnvm_get(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(t);
uint32_t base = sam3x_flash_base(t, 0, NULL);
sam3x_flash_cmd(t, base, EEFC_FCR_FCMD_GGPB, 0);
- gdb_outf("GPNVM: 0x%08X\n", adiv5_ap_mem_read(ap, EEFC_FRR(base)));
+ gdb_outf("GPNVM: 0x%08X\n", target_mem_read32(t, EEFC_FRR(base)));
return true;
}
diff --git a/src/samd.c b/src/samd.c
index 6f73956..c8517aa 100644
--- a/src/samd.c
+++ b/src/samd.c
@@ -40,8 +40,8 @@
#include "gdb_packet.h"
#include "cortexm.h"
-static int samd_flash_erase(struct target_s *target, uint32_t addr, size_t len);
-static int samd_flash_write(struct target_s *target, uint32_t dest,
+static int samd_flash_erase(target *t, uint32_t addr, size_t len);
+static int samd_flash_write(target *t, uint32_t dest,
const uint8_t *src, size_t len);
static bool samd_cmd_erase_all(target *t);
@@ -59,7 +59,7 @@ const struct command_s samd_cmd_list[] = {
{"user_row", (cmd_handler)samd_cmd_read_userrow, "Prints user row from flash"},
{"serial", (cmd_handler)samd_cmd_serial, "Prints serial number"},
{"mbist", (cmd_handler)samd_cmd_mbist, "Runs the built-in memory test"},
- {"set_security_bit", (cmd_handler)samd_cmd_ssb, "Sets the Security Bit"},
+ {"set_security_bit", (cmd_handler)samd_cmd_ssb, "Sets the Security Bit"},
{NULL, NULL, NULL}
};
@@ -159,36 +159,31 @@ static const char samd_xml_memory_map[] = "<?xml version=\"1.0\"?>"
/* Component ID */
#define SAMD_CID_VALUE 0xB105100D
-/* Utility */
-#define MINIMUM(a,b) ((a < b) ? a : b)
-
/**
* Reads the SAM D20 Peripheral ID
*/
-uint64_t samd_read_pid(struct target_s *target)
+uint64_t samd_read_pid(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
uint64_t pid = 0;
uint8_t i, j;
/* Five PID registers to read LSB first */
for (i = 0, j = 0; i < 5; i++, j += 8)
- pid |= (adiv5_ap_mem_read(ap, SAMD_DSU_PID(i)) & 0xFF) << j;
+ pid |= (target_mem_read32(t, SAMD_DSU_PID(i)) & 0xFF) << j;
return pid;
}
/**
* Reads the SAM D20 Component ID
*/
-uint32_t samd_read_cid(struct target_s *target)
+uint32_t samd_read_cid(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
uint64_t cid = 0;
uint8_t i, j;
/* Four CID registers to read LSB first */
for (i = 0, j = 0; i < 4; i++, j += 8)
- cid |= (adiv5_ap_mem_read(ap, SAMD_DSU_CID(i)) & 0xFF) << j;
+ cid |= (target_mem_read32(t, SAMD_DSU_CID(i)) & 0xFF) << j;
return cid;
}
@@ -198,10 +193,8 @@ uint32_t samd_read_cid(struct target_s *target)
* removes the target from extended reset where required.
*/
static void
-samd_reset(struct target_s *target)
+samd_reset(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
-
/**
* SRST is not asserted here as it appears to reset the adiv5
* logic, meaning that subsequent adiv5_* calls PLATFORM_FATAL_ERROR.
@@ -219,31 +212,30 @@ samd_reset(struct target_s *target)
*/
/* Read DHCSR here to clear S_RESET_ST bit before reset */
- adiv5_ap_mem_read(ap, CORTEXM_DHCSR);
+ target_mem_read32(t, CORTEXM_DHCSR);
/* Request system reset from NVIC: SRST doesn't work correctly */
/* This could be VECTRESET: 0x05FA0001 (reset only core)
* or SYSRESETREQ: 0x05FA0004 (system reset)
*/
- adiv5_ap_mem_write(ap, CORTEXM_AIRCR,
- CORTEXM_AIRCR_VECTKEY | CORTEXM_AIRCR_SYSRESETREQ);
+ target_mem_write32(t, CORTEXM_AIRCR,
+ CORTEXM_AIRCR_VECTKEY | CORTEXM_AIRCR_SYSRESETREQ);
/* Exit extended reset */
- if (adiv5_ap_mem_read(ap, SAMD_DSU_CTRLSTAT) &
+ if (target_mem_read32(t, SAMD_DSU_CTRLSTAT) &
SAMD_STATUSA_CRSTEXT) {
/* Write bit to clear from extended reset */
- adiv5_ap_mem_write(ap, SAMD_DSU_CTRLSTAT,
- SAMD_STATUSA_CRSTEXT);
+ target_mem_write32(t, SAMD_DSU_CTRLSTAT, SAMD_STATUSA_CRSTEXT);
}
/* Poll for release from reset */
- while(adiv5_ap_mem_read(ap, CORTEXM_DHCSR) & CORTEXM_DHCSR_S_RESET_ST);
+ while (target_mem_read32(t, CORTEXM_DHCSR) & CORTEXM_DHCSR_S_RESET_ST);
/* Reset DFSR flags */
- adiv5_ap_mem_write(ap, CORTEXM_DFSR, CORTEXM_DFSR_RESETALL);
+ target_mem_write32(t, CORTEXM_DFSR, CORTEXM_DFSR_RESETALL);
/* Clear any target errors */
- target_check_error(target);
+ target_check_error(t);
}
/**
@@ -253,18 +245,17 @@ samd_reset(struct target_s *target)
* Only required for SAM D20 _Revision B_ Silicon
*/
static void
-samd20_revB_detach(struct target_s *target)
+samd20_revB_detach(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
- cortexm_detach(target);
+ cortexm_detach(t);
/* ---- Additional ---- */
/* Exit extended reset */
- if (adiv5_ap_mem_read(ap, SAMD_DSU_CTRLSTAT) &
+ if (target_mem_read32(t, SAMD_DSU_CTRLSTAT) &
SAMD_STATUSA_CRSTEXT) {
/* Write bit to clear from extended reset */
- adiv5_ap_mem_write(ap, SAMD_DSU_CTRLSTAT,
- SAMD_STATUSA_CRSTEXT);
+ target_mem_write32(t, SAMD_DSU_CTRLSTAT,
+ SAMD_STATUSA_CRSTEXT);
}
}
@@ -275,18 +266,16 @@ samd20_revB_detach(struct target_s *target)
* Only required for SAM D20 _Revision B_ Silicon
*/
static void
-samd20_revB_halt_resume(struct target_s *target, bool step)
+samd20_revB_halt_resume(target *t, bool step)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
- cortexm_halt_resume(target, step);
+ cortexm_halt_resume(t, step);
/* ---- Additional ---- */
/* Exit extended reset */
- if (adiv5_ap_mem_read(ap, SAMD_DSU_CTRLSTAT) &
- SAMD_STATUSA_CRSTEXT) {
+ if (target_mem_read32(t, SAMD_DSU_CTRLSTAT) & SAMD_STATUSA_CRSTEXT) {
/* Write bit to clear from extended reset */
- adiv5_ap_mem_write(ap, SAMD_DSU_CTRLSTAT,
- SAMD_STATUSA_CRSTEXT);
+ target_mem_write32(t, SAMD_DSU_CTRLSTAT,
+ SAMD_STATUSA_CRSTEXT);
}
}
@@ -299,7 +288,7 @@ samd20_revB_halt_resume(struct target_s *target, bool step)
* rescue the device.
*/
static bool
-samd_protected_attach(struct target_s *target)
+samd_protected_attach(target *t)
{
/**
* TODO: Notify the user that we're not really attached and
@@ -307,10 +296,10 @@ samd_protected_attach(struct target_s *target)
* regain access to the chip.
*/
- /* Patch back in the normal cortexm attach for next time */
- target->attach = cortexm_attach;
+ /* Patch back in the normal cortexm attach for next time */
+ t->attach = cortexm_attach;
- /* Allow attach this time */
+ /* Allow attach this time */
return true;
}
@@ -374,135 +363,129 @@ struct samd_descr samd_parse_device_id(uint32_t did)
char variant_string[40];
-bool samd_probe(struct target_s *target)
+bool samd_probe(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
- uint32_t cid = samd_read_cid(target);
- uint32_t pid = samd_read_pid(target);
+ uint32_t cid = samd_read_cid(t);
+ uint32_t pid = samd_read_pid(t);
/* Check the ARM Coresight Component and Perhiperal IDs */
- if (cid == SAMD_CID_VALUE &&
- (pid & SAMD_PID_MASK) == SAMD_PID_CONST_VALUE) {
-
- /* Read the Device ID */
- uint32_t did = adiv5_ap_mem_read(ap, SAMD_DSU_DID);
-
- /* If the Device ID matches */
- if ((did & SAMD_DID_MASK) == SAMD_DID_CONST_VALUE) {
-
- uint32_t ctrlstat = adiv5_ap_mem_read(ap, SAMD_DSU_CTRLSTAT);
- struct samd_descr samd = samd_parse_device_id(did);
-
- /* Protected? */
- int protected = (ctrlstat & SAMD_STATUSB_PROT);
-
- /* Part String */
- if (protected) {
- sprintf(variant_string,
- "Atmel SAMD%d%c%dA%s (rev %c) (PROT=1)",
- samd.series, samd.pin, samd.mem,
- samd.package, samd.revision);
- } else {
- sprintf(variant_string,
- "Atmel SAMD%d%c%dA%s (rev %c)",
- samd.series, samd.pin, samd.mem,
- samd.package, samd.revision);
- }
-
- /* Setup Target */
- target->driver = variant_string;
- target->reset = samd_reset;
-
- if (samd.series == 20 && samd.revision == 'B') {
- /**
- * These functions check for and
- * extended reset. Appears to be
- * related to Errata 35.4.1 ref 12015
- */
- target->detach = samd20_revB_detach;
- target->halt_resume = samd20_revB_halt_resume;
- }
- if (protected) {
- /**
- * Overload the default cortexm attach
- * for when the samd is protected.
- * This function allows users to
- * attach on a temporary basis so they
- * can rescue the device.
- */
- target->attach = samd_protected_attach;
- }
-
- target->xml_mem_map = samd_xml_memory_map;
- target->flash_erase = samd_flash_erase;
- target->flash_write = samd_flash_write;
- target_add_commands(target, samd_cmd_list, "SAMD");
-
- /* If we're not in reset here */
- if (!connect_assert_srst) {
- /* We'll have to release the target from
- * extended reset to make attach possible */
- if (adiv5_ap_mem_read(ap, SAMD_DSU_CTRLSTAT) &
- SAMD_STATUSA_CRSTEXT) {
-
- /* Write bit to clear from extended reset */
- adiv5_ap_mem_write(ap, SAMD_DSU_CTRLSTAT,
- SAMD_STATUSA_CRSTEXT);
- }
- }
-
- return true;
+ if ((cid != SAMD_CID_VALUE) ||
+ ((pid & SAMD_PID_MASK) != SAMD_PID_CONST_VALUE))
+ return false;
+
+ /* Read the Device ID */
+ uint32_t did = target_mem_read32(t, SAMD_DSU_DID);
+
+ /* If the Device ID matches */
+ if ((did & SAMD_DID_MASK) != SAMD_DID_CONST_VALUE)
+ return false;
+
+ uint32_t ctrlstat = target_mem_read32(t, SAMD_DSU_CTRLSTAT);
+ struct samd_descr samd = samd_parse_device_id(did);
+
+ /* Protected? */
+ bool protected = (ctrlstat & SAMD_STATUSB_PROT);
+
+ /* Part String */
+ if (protected) {
+ sprintf(variant_string,
+ "Atmel SAMD%d%c%dA%s (rev %c) (PROT=1)",
+ samd.series, samd.pin, samd.mem,
+ samd.package, samd.revision);
+ } else {
+ sprintf(variant_string,
+ "Atmel SAMD%d%c%dA%s (rev %c)",
+ samd.series, samd.pin, samd.mem,
+ samd.package, samd.revision);
+ }
+
+ /* Setup Target */
+ t->driver = variant_string;
+ t->reset = samd_reset;
+
+ if (samd.series == 20 && samd.revision == 'B') {
+ /**
+ * These functions check for and
+ * extended reset. Appears to be
+ * related to Errata 35.4.1 ref 12015
+ */
+ t->detach = samd20_revB_detach;
+ t->halt_resume = samd20_revB_halt_resume;
+ }
+ if (protected) {
+ /**
+ * Overload the default cortexm attach
+ * for when the samd is protected.
+ * This function allows users to
+ * attach on a temporary basis so they
+ * can rescue the device.
+ */
+ t->attach = samd_protected_attach;
+ }
+
+ t->xml_mem_map = samd_xml_memory_map;
+ t->flash_erase = samd_flash_erase;
+ t->flash_write = samd_flash_write;
+ target_add_commands(t, samd_cmd_list, "SAMD");
+
+ /* If we're not in reset here */
+ if (!connect_assert_srst) {
+ /* We'll have to release the target from
+ * extended reset to make attach possible */
+ if (target_mem_read32(t, SAMD_DSU_CTRLSTAT) &
+ SAMD_STATUSA_CRSTEXT) {
+
+ /* Write bit to clear from extended reset */
+ target_mem_write32(t, SAMD_DSU_CTRLSTAT,
+ SAMD_STATUSA_CRSTEXT);
}
}
- return false;
+ return true;
}
/**
* Temporary (until next reset) flash memory locking / unlocking
*/
-static void samd_lock_current_address(struct target_s *target)
+static void samd_lock_current_address(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
-
/* Issue the unlock command */
- adiv5_ap_mem_write(ap, SAMD_NVMC_CTRLA, SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_LOCK);
+ target_mem_write32(t, SAMD_NVMC_CTRLA,
+ SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_LOCK);
}
-static void samd_unlock_current_address(struct target_s *target)
+static void samd_unlock_current_address(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
-
/* Issue the unlock command */
- adiv5_ap_mem_write(ap, SAMD_NVMC_CTRLA, SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_UNLOCK);
+ target_mem_write32(t, SAMD_NVMC_CTRLA,
+ SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_UNLOCK);
}
/**
* Erase flash row by row
*/
-static int samd_flash_erase(struct target_s *target, uint32_t addr, size_t len)
+static int samd_flash_erase(target *t, uint32_t addr, size_t len)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
-
addr &= ~(SAMD_ROW_SIZE - 1);
len &= ~(SAMD_ROW_SIZE - 1);
while (len) {
/* Write address of first word in row to erase it */
/* Must be shifted right for 16-bit address, see Datasheet §20.8.8 Address */
- adiv5_ap_mem_write(ap, SAMD_NVMC_ADDRESS, addr >> 1);
+ target_mem_write32(t, SAMD_NVMC_ADDRESS, addr >> 1);
/* Unlock */
- samd_unlock_current_address(target);
+ samd_unlock_current_address(t);
/* Issue the erase command */
- adiv5_ap_mem_write(ap, SAMD_NVMC_CTRLA, SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_ERASEROW);
+ target_mem_write32(t, SAMD_NVMC_CTRLA,
+ SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_ERASEROW);
/* Poll for NVM Ready */
- while ((adiv5_ap_mem_read(ap, SAMD_NVMC_INTFLAG) & SAMD_NVMC_READY) == 0)
- if(target_check_error(target))
+ while ((target_mem_read32(t, SAMD_NVMC_INTFLAG) & SAMD_NVMC_READY) == 0)
+ if (target_check_error(t))
return -1;
/* Lock */
- samd_lock_current_address(target);
+ samd_lock_current_address(t);
addr += SAMD_ROW_SIZE;
len -= SAMD_ROW_SIZE;
@@ -514,11 +497,9 @@ static int samd_flash_erase(struct target_s *target, uint32_t addr, size_t len)
/**
* Write flash page by page
*/
-static int samd_flash_write(struct target_s *target, uint32_t dest,
+static int samd_flash_write(target *t, uint32_t dest,
const uint8_t *src, size_t len)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
-
/* Find the size of our 32-bit data buffer */
uint32_t offset = dest % 4;
uint32_t words = (offset + len + 3) / 4;
@@ -537,58 +518,34 @@ static int samd_flash_write(struct target_s *target, uint32_t dest,
uint32_t first_page = dest & ~(SAMD_PAGE_SIZE - 1);
/* The start address of the last page involved in the write */
uint32_t last_page = (dest + len - 1) & ~(SAMD_PAGE_SIZE - 1);
- uint32_t end_of_this_page;
-
+ uint32_t next_page;
+ uint32_t length;
for (uint32_t page = first_page; page <= last_page; page += SAMD_PAGE_SIZE) {
- end_of_this_page = page + (SAMD_PAGE_SIZE - 4);
-
- if (addr > page || (page == last_page && end < end_of_this_page)) {
- /* Setup write */
- adiv5_ap_write(ap, ADIV5_AP_CSW, ap->csw |
- ADIV5_AP_CSW_SIZE_WORD | ADIV5_AP_CSW_ADDRINC_SINGLE);
- adiv5_ap_write(ap, ADIV5_AP_TAR, addr);
- adiv5_dp_write(ap->dp, ADIV5_DP_SELECT,
- ((uint32_t)ap->apsel << 24)|(ADIV5_AP_DRW & 0xF0));
-
- /* Partial, manual page write */
- for (; addr <= MINIMUM(end, end_of_this_page); addr += 4, i++) {
- adiv5_dp_write_ap(ap->dp, ADIV5_AP_DRW, data[i]);
- }
-
- /* Unlock */
- samd_unlock_current_address(target);
-
- /* Issue the write page command */
- adiv5_ap_mem_write(ap, SAMD_NVMC_CTRLA,
- SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_WRITEPAGE);
- } else {
- /* Write first word to set address */
- adiv5_ap_mem_write(ap, addr, data[i]); addr += 4; i++;
-
- /* Unlock */
- samd_unlock_current_address(target);
-
- /* Set up write */
- adiv5_ap_write(ap, ADIV5_AP_CSW, ap->csw |
- ADIV5_AP_CSW_SIZE_WORD | ADIV5_AP_CSW_ADDRINC_SINGLE);
- adiv5_ap_write(ap, ADIV5_AP_TAR, addr);
- adiv5_dp_write(ap->dp, ADIV5_DP_SELECT,
- ((uint32_t)ap->apsel << 24)|(ADIV5_AP_DRW & 0xF0));
-
- /* Full, automatic page write */
- for (; addr < page + SAMD_PAGE_SIZE; addr += 4, i++) {
- adiv5_dp_write_ap(ap->dp, ADIV5_AP_DRW, data[i]);
- }
- }
+ next_page = page + SAMD_PAGE_SIZE;
+ length = MIN(end + 4, next_page) - addr;
+
+ /* Write within a single page. This may be part or all of the page */
+ target_mem_write(t, addr, &data[i], length);
+ addr += length; i += (length >> 2);
+
+ /* If MANW=0 (default) we may have triggered an automatic
+ * write. Ignore this */
+
+ /* Unlock */
+ samd_unlock_current_address(t);
+
+ /* Issue the write page command */
+ target_mem_write32(t, SAMD_NVMC_CTRLA,
+ SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_WRITEPAGE);
/* Poll for NVM Ready */
- while ((adiv5_ap_mem_read(ap, SAMD_NVMC_INTFLAG) & SAMD_NVMC_READY) == 0)
- if(target_check_error(target))
+ while ((target_mem_read32(t, SAMD_NVMC_INTFLAG) & SAMD_NVMC_READY) == 0)
+ if (target_check_error(t))
return -1;
/* Lock */
- samd_lock_current_address(target);
+ samd_lock_current_address(t);
}
return 0;
@@ -599,20 +556,19 @@ static int samd_flash_write(struct target_s *target, uint32_t dest,
*/
static bool samd_cmd_erase_all(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(t);
-
/* Clear the DSU status bits */
- adiv5_ap_mem_write(ap, SAMD_DSU_CTRLSTAT,
- (SAMD_STATUSA_DONE | SAMD_STATUSA_PERR | SAMD_STATUSA_FAIL));
+ target_mem_write32(t, SAMD_DSU_CTRLSTAT,
+ SAMD_STATUSA_DONE | SAMD_STATUSA_PERR |
+ SAMD_STATUSA_FAIL);
/* Erase all */
- adiv5_ap_mem_write(ap, SAMD_DSU_CTRLSTAT, SAMD_CTRL_CHIP_ERASE);
+ target_mem_write32(t, SAMD_DSU_CTRLSTAT, SAMD_CTRL_CHIP_ERASE);
/* Poll for DSU Ready */
uint32_t status;
- while (((status = adiv5_ap_mem_read(ap, SAMD_DSU_CTRLSTAT)) &
+ while (((status = target_mem_read32(t, SAMD_DSU_CTRLSTAT)) &
(SAMD_STATUSA_DONE | SAMD_STATUSA_PERR | SAMD_STATUSA_FAIL)) == 0)
- if(target_check_error(t))
+ if (target_check_error(t))
return false;
/* Test the protection error bit in Status A */
@@ -641,80 +597,78 @@ static bool samd_cmd_erase_all(target *t)
*/
static bool samd_set_flashlock(target *t, uint16_t value)
{
- ADIv5_AP_t *ap = adiv5_target_ap(t);
-
- uint32_t high = adiv5_ap_mem_read(ap, SAMD_NVM_USER_ROW_HIGH);
- uint32_t low = adiv5_ap_mem_read(ap, SAMD_NVM_USER_ROW_LOW);
+ uint32_t high = target_mem_read32(t, SAMD_NVM_USER_ROW_HIGH);
+ uint32_t low = target_mem_read32(t, SAMD_NVM_USER_ROW_LOW);
/* Write address of a word in the row to erase it */
/* Must be shifted right for 16-bit address, see Datasheet §20.8.8 Address */
- adiv5_ap_mem_write(ap, SAMD_NVMC_ADDRESS, SAMD_NVM_USER_ROW_LOW >> 1);
+ target_mem_write32(t, SAMD_NVMC_ADDRESS, SAMD_NVM_USER_ROW_LOW >> 1);
/* Issue the erase command */
- adiv5_ap_mem_write(ap, SAMD_NVMC_CTRLA, SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_ERASEAUXROW);
+ target_mem_write32(t, SAMD_NVMC_CTRLA,
+ SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_ERASEAUXROW);
/* Poll for NVM Ready */
- while ((adiv5_ap_mem_read(ap, SAMD_NVMC_INTFLAG) & SAMD_NVMC_READY) == 0)
- if(target_check_error(t))
+ while ((target_mem_read32(t, SAMD_NVMC_INTFLAG) & SAMD_NVMC_READY) == 0)
+ if (target_check_error(t))
return -1;
/* Modify the high byte of the user row */
high = (high & 0x0000FFFF) | ((value << 16) & 0xFFFF0000);
/* Write back */
- adiv5_ap_mem_write(ap, SAMD_NVM_USER_ROW_LOW, low);
- adiv5_ap_mem_write(ap, SAMD_NVM_USER_ROW_HIGH, high);
+ target_mem_write32(t, SAMD_NVM_USER_ROW_LOW, low);
+ target_mem_write32(t, SAMD_NVM_USER_ROW_HIGH, high);
/* Issue the page write command */
- adiv5_ap_mem_write(ap, SAMD_NVMC_CTRLA,
- SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_WRITEAUXPAGE);
+ target_mem_write32(t, SAMD_NVMC_CTRLA,
+ SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_WRITEAUXPAGE);
- return true;
+ return true;
}
+
static bool samd_cmd_lock_flash(target *t)
{
return samd_set_flashlock(t, 0x0000);
}
+
static bool samd_cmd_unlock_flash(target *t)
{
return samd_set_flashlock(t, 0xFFFF);
}
+
static bool samd_cmd_read_userrow(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(t);
-
gdb_outf("User Row: 0x%08x%08x\n",
- adiv5_ap_mem_read(ap, SAMD_NVM_USER_ROW_HIGH),
- adiv5_ap_mem_read(ap, SAMD_NVM_USER_ROW_LOW));
+ target_mem_read32(t, SAMD_NVM_USER_ROW_HIGH),
+ target_mem_read32(t, SAMD_NVM_USER_ROW_LOW));
return true;
}
+
/**
* Reads the 128-bit serial number from the NVM
*/
static bool samd_cmd_serial(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(t);
-
gdb_outf("Serial Number: 0x");
for (uint32_t i = 0; i < 4; i++) {
- gdb_outf("%08x", adiv5_ap_mem_read(ap, SAMD_NVM_SERIAL(i)));
+ gdb_outf("%08x", target_mem_read32(t, SAMD_NVM_SERIAL(i)));
}
gdb_outf("\n");
return true;
}
+
/**
* Returns the size (in bytes) of the current SAM D20's flash memory.
*/
static uint32_t samd_flash_size(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(t);
-
/* Read the Device ID */
- uint32_t did = adiv5_ap_mem_read(ap, SAMD_DSU_DID);
+ uint32_t did = target_mem_read32(t, SAMD_DSU_DID);
/* Mask off the device select bits */
uint8_t devsel = did & SAMD_DID_DEVSEL_MASK;
@@ -722,28 +676,27 @@ static uint32_t samd_flash_size(target *t)
/* Shift the maximum flash size (256KB) down as appropriate */
return (0x40000 >> (devsel % 5));
}
+
/**
* Runs the Memory Built In Self Test (MBIST)
*/
static bool samd_cmd_mbist(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(t);
-
/* Write the memory parameters to the DSU */
- adiv5_ap_mem_write(ap, SAMD_DSU_ADDRESS, 0);
- adiv5_ap_mem_write(ap, SAMD_DSU_LENGTH, samd_flash_size(t));
+ target_mem_write32(t, SAMD_DSU_ADDRESS, 0);
+ target_mem_write32(t, SAMD_DSU_LENGTH, samd_flash_size(t));
/* Clear the fail bit */
- adiv5_ap_mem_write(ap, SAMD_DSU_CTRLSTAT, SAMD_STATUSA_FAIL);
+ target_mem_write32(t, SAMD_DSU_CTRLSTAT, SAMD_STATUSA_FAIL);
/* Write the MBIST command */
- adiv5_ap_mem_write(ap, SAMD_DSU_CTRLSTAT, SAMD_CTRL_MBIST);
+ target_mem_write32(t, SAMD_DSU_CTRLSTAT, SAMD_CTRL_MBIST);
/* Poll for DSU Ready */
uint32_t status;
- while (((status = adiv5_ap_mem_read(ap, SAMD_DSU_CTRLSTAT)) &
+ while (((status = target_mem_read32(t, SAMD_DSU_CTRLSTAT)) &
(SAMD_STATUSA_DONE | SAMD_STATUSA_PERR | SAMD_STATUSA_FAIL)) == 0)
- if(target_check_error(t))
+ if (target_check_error(t))
return false;
/* Test the protection error bit in Status A */
@@ -755,7 +708,7 @@ static bool samd_cmd_mbist(target *t)
/* Test the fail bit in Status A */
if (status & SAMD_STATUSA_FAIL) {
gdb_outf("MBIST Fail @ 0x%08x\n",
- adiv5_ap_mem_read(ap, SAMD_DSU_ADDRESS));
+ target_mem_read32(t, SAMD_DSU_ADDRESS));
} else {
gdb_outf("MBIST Passed!\n");
}
@@ -767,14 +720,13 @@ static bool samd_cmd_mbist(target *t)
*/
static bool samd_cmd_ssb(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(t);
-
/* Issue the ssb command */
- adiv5_ap_mem_write(ap, SAMD_NVMC_CTRLA, SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_SSB);
+ target_mem_write32(t, SAMD_NVMC_CTRLA,
+ SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_SSB);
- /* Poll for NVM Ready */
- while ((adiv5_ap_mem_read(ap, SAMD_NVMC_INTFLAG) & SAMD_NVMC_READY) == 0)
- if(target_check_error(t))
+ /* Poll for NVM Ready */
+ while ((target_mem_read32(t, SAMD_NVMC_INTFLAG) & SAMD_NVMC_READY) == 0)
+ if (target_check_error(t))
return -1;
gdb_outf("Set the security bit! "
@@ -782,3 +734,4 @@ static bool samd_cmd_ssb(target *t)
return true;
}
+
diff --git a/src/stm32f1.c b/src/stm32f1.c
index 405bc1a..459c159 100644
--- a/src/stm32f1.c
+++ b/src/stm32f1.c
@@ -32,6 +32,7 @@
#include "general.h"
#include "adiv5.h"
#include "target.h"
+#include "cortexm.h"
#include "command.h"
#include "gdb_packet.h"
@@ -45,11 +46,11 @@ const struct command_s stm32f1_cmd_list[] = {
};
-static int stm32md_flash_erase(struct target_s *target, uint32_t addr, size_t len);
-static int stm32hd_flash_erase(struct target_s *target, uint32_t addr, size_t len);
-static int stm32f1_flash_erase(struct target_s *target, uint32_t addr, size_t len,
+static int stm32md_flash_erase(target *t, uint32_t addr, size_t len);
+static int stm32hd_flash_erase(target *t, uint32_t addr, size_t len);
+static int stm32f1_flash_erase(target *t, uint32_t addr, size_t len,
uint32_t pagesize);
-static int stm32f1_flash_write(struct target_s *target, uint32_t dest,
+static int stm32f1_flash_write(target *t, uint32_t dest,
const uint8_t *src, size_t len);
static const char stm32f1_driver_str[] = "STM32, Medium density.";
@@ -120,137 +121,105 @@ static const char stm32hd_xml_memory_map[] = "<?xml version=\"1.0\"?>"
#define DBGMCU_IDCODE_F0 0x40015800
static const uint16_t stm32f1_flash_write_stub[] = {
-// _start:
- 0x4809, // ldr r0, [pc, #36] // _flashbase
- 0x490a, // ldr r1, [pc, #40] // _addr
- 0x467a, // mov r2, pc
- 0x322c, // adds r2, #44
- 0x4b09, // ldr r3, [pc, #36] // _size
- 0x2501, // movs r5, #1
-// _next:
- 0x2b00, // cmp r3, #0
- 0xd00a, // beq _done
- 0x6105, // str r5, [r0, #16]
- 0x8814, // ldrh r4, [r2]
- 0x800c, // strh r4, [r1]
-// _wait:
- 0x68c4, // ldr r4, [r0, #12]
- 0x2601, // movs r6, #1
- 0x4234, // tst r4, r6
- 0xd1fb, // bne _wait
-
- 0x3b02, // subs r3, #2
- 0x3102, // adds r1, #2
- 0x3202, // adds r2, #2
- 0xe7f2, // b _next
-// _done:
- 0xbe00, // bkpt
-// .org 0x28
-// _flashbase:
- 0x2000, 0x4002, // .word 0x40022000 (FPEC_BASE)
-// _addr:
-// 0x0000, 0x0000,
-// _size:
-// 0x0000, 0x0000,
-// _data:
-// ...
+#include "../flashstub/stm32f1.stub"
};
-bool stm32f1_probe(struct target_s *target)
-{
+#define SRAM_BASE 0x20000000
+#define STUB_BUFFER_BASE ALIGN(SRAM_BASE + sizeof(stm32f1_flash_write_stub), 4)
- target->idcode = adiv5_ap_mem_read(adiv5_target_ap(target), DBGMCU_IDCODE) & 0xfff;
- switch(target->idcode) {
+bool stm32f1_probe(target *t)
+{
+ t->idcode = target_mem_read32(t, DBGMCU_IDCODE) & 0xfff;
+ switch(t->idcode) {
case 0x410: /* Medium density */
case 0x412: /* Low denisty */
case 0x420: /* Value Line, Low-/Medium density */
- target->driver = stm32f1_driver_str;
- target->xml_mem_map = stm32f1_xml_memory_map;
- target->flash_erase = stm32md_flash_erase;
- target->flash_write = stm32f1_flash_write;
- target_add_commands(target, stm32f1_cmd_list, "STM32 LD/MD");
+ t->driver = stm32f1_driver_str;
+ t->xml_mem_map = stm32f1_xml_memory_map;
+ t->flash_erase = stm32md_flash_erase;
+ t->flash_write = stm32f1_flash_write;
+ target_add_commands(t, stm32f1_cmd_list, "STM32 LD/MD");
return true;
case 0x414: /* High density */
case 0x418: /* Connectivity Line */
case 0x428: /* Value Line, High Density */
- target->driver = stm32hd_driver_str;
- target->xml_mem_map = stm32hd_xml_memory_map;
- target->flash_erase = stm32hd_flash_erase;
- target->flash_write = stm32f1_flash_write;
- target_add_commands(target, stm32f1_cmd_list, "STM32 HD/CL");
+ t->driver = stm32hd_driver_str;
+ t->xml_mem_map = stm32hd_xml_memory_map;
+ t->flash_erase = stm32hd_flash_erase;
+ t->flash_write = stm32f1_flash_write;
+ target_add_commands(t, stm32f1_cmd_list, "STM32 HD/CL");
return true;
case 0x422: /* STM32F30x */
case 0x432: /* STM32F37x */
- target->driver = stm32f3_driver_str;
- target->xml_mem_map = stm32hd_xml_memory_map;
- target->flash_erase = stm32hd_flash_erase;
- target->flash_write = stm32f1_flash_write;
- target_add_commands(target, stm32f1_cmd_list, "STM32F3");
+ t->driver = stm32f3_driver_str;
+ t->xml_mem_map = stm32hd_xml_memory_map;
+ t->flash_erase = stm32hd_flash_erase;
+ t->flash_write = stm32f1_flash_write;
+ target_add_commands(t, stm32f1_cmd_list, "STM32F3");
return true;
}
- target->idcode = adiv5_ap_mem_read(adiv5_target_ap(target), DBGMCU_IDCODE_F0) & 0xfff;
- switch(target->idcode) {
+ t->idcode = target_mem_read32(t, DBGMCU_IDCODE_F0) & 0xfff;
+ switch(t->idcode) {
case 0x444: /* STM32F03 RM0091 Rev.7 */
case 0x445: /* STM32F04 RM0091 Rev.7 */
case 0x440: /* STM32F05 RM0091 Rev.7 */
case 0x448: /* STM32F07 RM0091 Rev.7 */
case 0x442: /* STM32F09 RM0091 Rev.7 */
- switch(target->idcode) {
+ switch(t->idcode) {
case 0x444: /* STM32F03 */
- target->driver = stm32f03_driver_str;
+ t->driver = stm32f03_driver_str;
break;
case 0x445: /* STM32F04 */
- target->driver = stm32f04_driver_str;
+ t->driver = stm32f04_driver_str;
break;
case 0x440: /* STM32F05 */
- target->driver = stm32f05_driver_str;
+ t->driver = stm32f05_driver_str;
break;
case 0x448: /* STM32F07 */
- target->driver = stm32f07_driver_str;
+ t->driver = stm32f07_driver_str;
break;
case 0x442: /* STM32F09 */
- target->driver = stm32f09_driver_str;
+ t->driver = stm32f09_driver_str;
break;
}
- target->xml_mem_map = stm32f1_xml_memory_map;
- target->flash_erase = stm32md_flash_erase;
- target->flash_write = stm32f1_flash_write;
- target_add_commands(target, stm32f1_cmd_list, "STM32F0");
+ t->xml_mem_map = stm32f1_xml_memory_map;
+ t->flash_erase = stm32md_flash_erase;
+ t->flash_write = stm32f1_flash_write;
+ target_add_commands(t, stm32f1_cmd_list, "STM32F0");
return true;
}
return false;
}
-static void stm32f1_flash_unlock(ADIv5_AP_t *ap)
+static void stm32f1_flash_unlock(target *t)
{
- adiv5_ap_mem_write(ap, FLASH_KEYR, KEY1);
- adiv5_ap_mem_write(ap, FLASH_KEYR, KEY2);
+ target_mem_write32(t, FLASH_KEYR, KEY1);
+ target_mem_write32(t, FLASH_KEYR, KEY2);
}
-static int stm32f1_flash_erase(struct target_s *target, uint32_t addr,
+static int stm32f1_flash_erase(target *t, uint32_t addr,
size_t len, uint32_t pagesize)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
uint16_t sr;
addr &= ~(pagesize - 1);
len = (len + pagesize - 1) & ~(pagesize - 1);
- stm32f1_flash_unlock(ap);
+ stm32f1_flash_unlock(t);
while(len) {
/* Flash page erase instruction */
- adiv5_ap_mem_write(ap, FLASH_CR, FLASH_CR_PER);
+ target_mem_write32(t, FLASH_CR, FLASH_CR_PER);
/* write address to FMA */
- adiv5_ap_mem_write(ap, FLASH_AR, addr);
+ target_mem_write32(t, FLASH_AR, addr);
/* Flash page erase start instruction */
- adiv5_ap_mem_write(ap, FLASH_CR, FLASH_CR_STRT | FLASH_CR_PER);
+ target_mem_write32(t, FLASH_CR, FLASH_CR_STRT | FLASH_CR_PER);
/* Read FLASH_SR to poll for BSY bit */
- while(adiv5_ap_mem_read(ap, FLASH_SR) & FLASH_SR_BSY)
- if(target_check_error(target))
+ while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY)
+ if(target_check_error(t))
return -1;
len -= pagesize;
@@ -258,75 +227,57 @@ static int stm32f1_flash_erase(struct target_s *target, uint32_t addr,
}
/* Check for error */
- sr = adiv5_ap_mem_read(ap, FLASH_SR);
+ sr = target_mem_read32(t, FLASH_SR);
if ((sr & SR_ERROR_MASK) || !(sr & SR_EOP))
return -1;
return 0;
}
-static int stm32hd_flash_erase(struct target_s *target, uint32_t addr, size_t len)
+static int stm32hd_flash_erase(target *t, uint32_t addr, size_t len)
{
- return stm32f1_flash_erase(target, addr, len, 0x800);
+ return stm32f1_flash_erase(t, addr, len, 0x800);
}
-static int stm32md_flash_erase(struct target_s *target, uint32_t addr, size_t len)
+static int stm32md_flash_erase(target *t, uint32_t addr, size_t len)
{
- return stm32f1_flash_erase(target, addr, len, 0x400);
+ return stm32f1_flash_erase(t, addr, len, 0x400);
}
-static int stm32f1_flash_write(struct target_s *target, uint32_t dest,
+static int stm32f1_flash_write(target *t, uint32_t dest,
const uint8_t *src, size_t len)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
uint32_t offset = dest % 4;
- uint32_t words = (offset + len + 3) / 4;
- if (words > 256)
- return -1;
- uint32_t data[2 + words];
+ uint8_t data[ALIGN(offset + len, 4)];
/* Construct data buffer used by stub */
- data[0] = dest - offset;
- data[1] = words * 4; /* length must always be a multiple of 4 */
- data[2] = 0xFFFFFFFF; /* pad partial words with all 1s to avoid */
- data[words + 1] = 0xFFFFFFFF; /* damaging overlapping areas */
- memcpy((uint8_t *)&data[2] + offset, src, len);
+ /* pad partial words with all 1s to avoid damaging overlapping areas */
+ memset(data, 0xff, sizeof(data));
+ memcpy((uint8_t *)data + offset, src, len);
/* Write stub and data to target ram and set PC */
- target_mem_write_words(target, 0x20000000, (void*)stm32f1_flash_write_stub, 0x2C);
- target_mem_write_words(target, 0x2000002C, data, sizeof(data));
- target_pc_write(target, 0x20000000);
- if(target_check_error(target))
- return -1;
-
- /* Execute the stub */
- target_halt_resume(target, 0);
- while(!target_halt_wait(target));
-
- /* Check for error */
- if (adiv5_ap_mem_read(ap, FLASH_SR) & SR_ERROR_MASK)
- return -1;
-
- return 0;
+ target_mem_write(t, SRAM_BASE, stm32f1_flash_write_stub,
+ sizeof(stm32f1_flash_write_stub));
+ target_mem_write(t, STUB_BUFFER_BASE, data, sizeof(data));
+ return cortexm_run_stub(t, SRAM_BASE, dest - offset,
+ STUB_BUFFER_BASE, sizeof(data), 0);
}
static bool stm32f1_cmd_erase_mass(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(t);
-
- stm32f1_flash_unlock(ap);
+ stm32f1_flash_unlock(t);
/* Flash mass erase start instruction */
- adiv5_ap_mem_write(ap, FLASH_CR, FLASH_CR_MER);
- adiv5_ap_mem_write(ap, FLASH_CR, FLASH_CR_STRT | FLASH_CR_MER);
+ target_mem_write32(t, FLASH_CR, FLASH_CR_MER);
+ target_mem_write32(t, FLASH_CR, FLASH_CR_STRT | FLASH_CR_MER);
/* Read FLASH_SR to poll for BSY bit */
- while(adiv5_ap_mem_read(ap, FLASH_SR) & FLASH_SR_BSY)
+ while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY)
if(target_check_error(t))
return false;
/* Check for error */
- uint16_t sr = adiv5_ap_mem_read(ap, FLASH_SR);
+ uint16_t sr = target_mem_read32(t, FLASH_SR);
if ((sr & SR_ERROR_MASK) || !(sr & SR_EOP))
return false;
@@ -335,14 +286,12 @@ static bool stm32f1_cmd_erase_mass(target *t)
static bool stm32f1_option_erase(target *t)
{
- ADIv5_AP_t *ap = adiv5_target_ap(t);
-
/* Erase option bytes instruction */
- adiv5_ap_mem_write(ap, FLASH_CR, FLASH_CR_OPTER | FLASH_CR_OPTWRE);
- adiv5_ap_mem_write(ap, FLASH_CR,
- FLASH_CR_STRT | FLASH_CR_OPTER | FLASH_CR_OPTWRE);
+ target_mem_write32(t, FLASH_CR, FLASH_CR_OPTER | FLASH_CR_OPTWRE);
+ target_mem_write32(t, FLASH_CR,
+ FLASH_CR_STRT | FLASH_CR_OPTER | FLASH_CR_OPTWRE);
/* Read FLASH_SR to poll for BSY bit */
- while(adiv5_ap_mem_read(ap, FLASH_SR) & FLASH_SR_BSY)
+ while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY)
if(target_check_error(t))
return false;
return true;
@@ -350,15 +299,13 @@ static bool stm32f1_option_erase(target *t)
static bool stm32f1_option_write_erased(target *t, uint32_t addr, uint16_t value)
{
- ADIv5_AP_t *ap = adiv5_target_ap(t);
-
if (value == 0xffff)
return true;
/* Erase option bytes instruction */
- adiv5_ap_mem_write(ap, FLASH_CR, FLASH_CR_OPTPG | FLASH_CR_OPTWRE);
- adiv5_ap_mem_write_halfword(ap, addr, value);
+ target_mem_write32(t, FLASH_CR, FLASH_CR_OPTPG | FLASH_CR_OPTWRE);
+ target_mem_write16(t, addr, value);
/* Read FLASH_SR to poll for BSY bit */
- while(adiv5_ap_mem_read(ap, FLASH_SR) & FLASH_SR_BSY)
+ while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY)
if(target_check_error(t))
return false;
return true;
@@ -366,7 +313,6 @@ static bool stm32f1_option_write_erased(target *t, uint32_t addr, uint16_t value
static bool stm32f1_option_write(target *t, uint32_t addr, uint16_t value)
{
- ADIv5_AP_t *ap = adiv5_target_ap(t);
uint16_t opt_val[8];
int i, index;
@@ -375,7 +321,7 @@ static bool stm32f1_option_write(target *t, uint32_t addr, uint16_t value)
return false;
/* Retrieve old values */
for (i = 0; i < 16; i = i +4) {
- uint32_t val = adiv5_ap_mem_read(ap, FLASH_OBP_RDP + i);
+ uint32_t val = target_mem_read32(t, FLASH_OBP_RDP + i);
opt_val[i/2] = val & 0xffff;
opt_val[i/2 +1] = val >> 16;
}
@@ -398,7 +344,6 @@ static bool stm32f1_cmd_option(target *t, int argc, char *argv[])
{
uint32_t addr, val;
uint32_t flash_obp_rdp_key;
- ADIv5_AP_t *ap = adiv5_target_ap(t);
uint32_t rdprt;
switch(t->idcode) {
@@ -409,10 +354,10 @@ static bool stm32f1_cmd_option(target *t, int argc, char *argv[])
break;
default: flash_obp_rdp_key = FLASH_OBP_RDP_KEY;
}
- rdprt = (adiv5_ap_mem_read(ap, FLASH_OBR) & FLASH_OBR_RDPRT);
- stm32f1_flash_unlock(ap);
- adiv5_ap_mem_write(ap, FLASH_OPTKEYR, KEY1);
- adiv5_ap_mem_write(ap, FLASH_OPTKEYR, KEY2);
+ rdprt = target_mem_read32(t, FLASH_OBR) & FLASH_OBR_RDPRT;
+ stm32f1_flash_unlock(t);
+ target_mem_write32(t, FLASH_OPTKEYR, KEY1);
+ target_mem_write32(t, FLASH_OPTKEYR, KEY2);
if ((argc == 2) && !strcmp(argv[1], "erase")) {
stm32f1_option_erase(t);
@@ -432,7 +377,7 @@ static bool stm32f1_cmd_option(target *t, int argc, char *argv[])
if (0 && flash_obp_rdp_key == FLASH_OBP_RDP_KEY_F3) {
/* Reload option bytes on F0 and F3*/
- val = adiv5_ap_mem_read(ap, FLASH_CR);
+ val = target_mem_read32(t, FLASH_CR);
val |= FLASH_CR_OBL_LAUNCH;
stm32f1_option_write(t, FLASH_CR, val);
val &= ~FLASH_CR_OBL_LAUNCH;
@@ -441,7 +386,7 @@ static bool stm32f1_cmd_option(target *t, int argc, char *argv[])
for (int i = 0; i < 0xf; i += 4) {
addr = 0x1ffff800 + i;
- val = adiv5_ap_mem_read(ap, addr);
+ val = target_mem_read32(t, addr);
gdb_outf("0x%08X: 0x%04X\n", addr, val & 0xFFFF);
gdb_outf("0x%08X: 0x%04X\n", addr + 2, val >> 16);
}
diff --git a/src/stm32f4.c b/src/stm32f4.c
index fac097a..03a33f0 100644
--- a/src/stm32f4.c
+++ b/src/stm32f4.c
@@ -33,6 +33,7 @@
#include "general.h"
#include "adiv5.h"
#include "target.h"
+#include "cortexm.h"
#include "command.h"
#include "gdb_packet.h"
@@ -46,8 +47,8 @@ const struct command_s stm32f4_cmd_list[] = {
};
-static int stm32f4_flash_erase(struct target_s *target, uint32_t addr, size_t len);
-static int stm32f4_flash_write(struct target_s *target, uint32_t dest,
+static int stm32f4_flash_erase(target *t, uint32_t addr, size_t len);
+static int stm32f4_flash_write(target *t, uint32_t dest,
const uint8_t *src, size_t len);
static const char stm32f4_driver_str[] = "STM32F4xx";
@@ -120,49 +121,17 @@ static const char stm32f4_xml_memory_map[] = "<?xml version=\"1.0\"?>"
/* This routine is uses word access. Only usable on target voltage >2.7V */
static const uint16_t stm32f4_flash_write_stub[] = {
-// _start:
- 0x480a, // ldr r0, [pc, #40] // _flashbase
- 0x490b, // ldr r1, [pc, #44] // _addr
- 0x467a, // mov r2, pc
- 0x3230, // adds r2, #48
- 0x4b0a, // ldr r3, [pc, #36] // _size
- 0x4d07, // ldr r5, [pc, #28] // _cr
-// _next:
- 0xb153, // cbz r3, _done
- 0x6105, // str r5, [r0, #16]
- 0x6814, // ldr r4, [r2]
- 0x600c, // str r4, [r1]
-// _wait:
- 0x89c4, // ldrb r4, [r0, #14]
- 0x2601, // movs r6, #1
- 0x4234, // tst r4, r6
- 0xd1fb, // bne _wait
-
- 0x3b04, // subs r3, #4
- 0x3104, // adds r1, #4
- 0x3204, // adds r2, #4
- 0xe7f3, // b _next
-// _done:
- 0xbe00, // bkpt
- 0x0000,
-// .org 0x28
-//_cr:
- 0x0201, 0x0000, //.word 0x00000201 (Value to write to FLASH_CR) */
-// _flashbase:
- 0x3c00, 0x4002, // .word 0x40023c00 (FPEC_BASE)
-// _addr:
-// 0x0000, 0x0000,
-// _size:
-// 0x0000, 0x0000,
-// _data:
-// ...
+#include "../flashstub/stm32f4.stub"
};
-bool stm32f4_probe(struct target_s *target)
+#define SRAM_BASE 0x20000000
+#define STUB_BUFFER_BASE ALIGN(SRAM_BASE + sizeof(stm32f4_flash_write_stub), 4)
+
+bool stm32f4_probe(target *t)
{
uint32_t idcode;
- idcode = adiv5_ap_mem_read(adiv5_target_ap(target), DBGMCU_IDCODE);
+ idcode = target_mem_read32(t, DBGMCU_IDCODE);
switch(idcode & 0xFFF) {
case 0x411: /* Documented to be 0x413! This is what I read... */
case 0x413: /* F407VGT6 */
@@ -170,35 +139,34 @@ bool stm32f4_probe(struct target_s *target)
case 0x423: /* F401 B/C RM0368 Rev.3 */
case 0x431: /* F411 RM0383 Rev.4 */
case 0x433: /* F401 D/E RM0368 Rev.3 */
- target->xml_mem_map = stm32f4_xml_memory_map;
- target->driver = stm32f4_driver_str;
- target->flash_erase = stm32f4_flash_erase;
- target->flash_write = stm32f4_flash_write;
- target_add_commands(target, stm32f4_cmd_list, "STM32F4");
+ t->xml_mem_map = stm32f4_xml_memory_map;
+ t->driver = stm32f4_driver_str;
+ t->flash_erase = stm32f4_flash_erase;
+ t->flash_write = stm32f4_flash_write;
+ target_add_commands(t, stm32f4_cmd_list, "STM32F4");
return true;
}
return false;
}
-static void stm32f4_flash_unlock(ADIv5_AP_t *ap)
+static void stm32f4_flash_unlock(target *t)
{
- if (adiv5_ap_mem_read(ap, FLASH_CR) & FLASH_CR_LOCK) {
+ if (target_mem_read32(t, FLASH_CR) & FLASH_CR_LOCK) {
/* Enable FPEC controller access */
- adiv5_ap_mem_write(ap, FLASH_KEYR, KEY1);
- adiv5_ap_mem_write(ap, FLASH_KEYR, KEY2);
+ target_mem_write32(t, FLASH_KEYR, KEY1);
+ target_mem_write32(t, FLASH_KEYR, KEY2);
}
}
-static int stm32f4_flash_erase(struct target_s *target, uint32_t addr, size_t len)
+static int stm32f4_flash_erase(target *t, uint32_t addr, size_t len)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
uint16_t sr;
uint32_t cr;
uint32_t pagesize;
addr &= 0x07FFC000;
- stm32f4_flash_unlock(ap);
+ stm32f4_flash_unlock(t);
while(len) {
if (addr < 0x10000) { /* Sector 0..3 */
@@ -215,13 +183,13 @@ static int stm32f4_flash_erase(struct target_s *target, uint32_t addr, size_t le
}
cr |= FLASH_CR_EOPIE | FLASH_CR_ERRIE | FLASH_CR_SER;
/* Flash page erase instruction */
- adiv5_ap_mem_write(ap, FLASH_CR, cr);
+ target_mem_write32(t, FLASH_CR, cr);
/* write address to FMA */
- adiv5_ap_mem_write(ap, FLASH_CR, cr | FLASH_CR_STRT);
+ target_mem_write32(t, FLASH_CR, cr | FLASH_CR_STRT);
/* Read FLASH_SR to poll for BSY bit */
- while(adiv5_ap_mem_read(ap, FLASH_SR) & FLASH_SR_BSY)
- if(target_check_error(target))
+ while(target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY)
+ if(target_check_error(t))
return -1;
len -= pagesize;
@@ -229,46 +197,30 @@ static int stm32f4_flash_erase(struct target_s *target, uint32_t addr, size_t le
}
/* Check for error */
- sr = adiv5_ap_mem_read(ap, FLASH_SR);
+ sr = target_mem_read32(t, FLASH_SR);
if(sr & SR_ERROR_MASK)
return -1;
return 0;
}
-static int stm32f4_flash_write(struct target_s *target, uint32_t dest,
+static int stm32f4_flash_write(target *t, uint32_t dest,
const uint8_t *src, size_t len)
{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
uint32_t offset = dest % 4;
- uint32_t words = (offset + len + 3) / 4;
- uint32_t data[2 + words];
- uint16_t sr;
+ uint8_t data[ALIGN(offset + len, 4)];
/* Construct data buffer used by stub */
- data[0] = dest - offset;
- data[1] = words * 4; /* length must always be a multiple of 4 */
- data[2] = 0xFFFFFFFF; /* pad partial words with all 1s to avoid */
- data[words + 1] = 0xFFFFFFFF; /* damaging overlapping areas */
- memcpy((uint8_t *)&data[2] + offset, src, len);
-
- /* Write stub and data to target ram and set PC */
- target_mem_write_words(target, 0x20000000, (void*)stm32f4_flash_write_stub, 0x30);
- target_mem_write_words(target, 0x20000030, data, sizeof(data));
- target_pc_write(target, 0x20000000);
- if(target_check_error(target))
- return -1;
-
- /* Execute the stub */
- target_halt_resume(target, 0);
- while(!target_halt_wait(target));
-
- /* Check for error */
- sr = adiv5_ap_mem_read(ap, FLASH_SR);
- if(sr & SR_ERROR_MASK)
- return -1;
-
- return 0;
+ /* pad partial words with all 1s to avoid damaging overlapping areas */
+ memset(data, 0xff, sizeof(data));
+ memcpy((uint8_t *)data + offset, src, len);
+
+ /* Write buffer to target ram call stub */
+ target_mem_write(t, SRAM_BASE, stm32f4_flash_write_stub,
+ sizeof(stm32f4_flash_write_stub));
+ target_mem_write(t, STUB_BUFFER_BASE, data, sizeof(data));
+ return cortexm_run_stub(t, SRAM_BASE, dest - offset,
+ STUB_BUFFER_BASE, sizeof(data), 0);
}
static bool stm32f4_cmd_erase_mass(target *t)
@@ -276,17 +228,15 @@ static bool stm32f4_cmd_erase_mass(target *t)
const char spinner[] = "|/-\\";
int spinindex = 0;
- ADIv5_AP_t *ap = adiv5_target_ap(t);
-
gdb_out("Erasing flash... This may take a few seconds. ");
- stm32f4_flash_unlock(ap);
+ stm32f4_flash_unlock(t);
/* Flash mass erase start instruction */
- adiv5_ap_mem_write(ap, FLASH_CR, FLASH_CR_MER);
- adiv5_ap_mem_write(ap, FLASH_CR, FLASH_CR_STRT | FLASH_CR_MER);
+ target_mem_write32(t, FLASH_CR, FLASH_CR_MER);
+ target_mem_write32(t, FLASH_CR, FLASH_CR_STRT | FLASH_CR_MER);
/* Read FLASH_SR to poll for BSY bit */
- while(adiv5_ap_mem_read(ap, FLASH_SR) & FLASH_SR_BSY) {
+ while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY) {
gdb_outf("\b%c", spinner[spinindex++ % 4]);
if(target_check_error(t)) {
gdb_out("\n");
@@ -296,7 +246,7 @@ static bool stm32f4_cmd_erase_mass(target *t)
gdb_out("\n");
/* Check for error */
- uint16_t sr = adiv5_ap_mem_read(ap, FLASH_SR);
+ uint16_t sr = target_mem_read32(t, FLASH_SR);
if ((sr & SR_ERROR_MASK) || !(sr & SR_EOP))
return false;
@@ -305,23 +255,21 @@ static bool stm32f4_cmd_erase_mass(target *t)
static bool stm32f4_option_write(target *t, uint32_t value)
{
- ADIv5_AP_t *ap = adiv5_target_ap(t);
-
- adiv5_ap_mem_write(ap, FLASH_OPTKEYR, OPTKEY1);
- adiv5_ap_mem_write(ap, FLASH_OPTKEYR, OPTKEY2);
+ target_mem_write32(t, FLASH_OPTKEYR, OPTKEY1);
+ target_mem_write32(t, FLASH_OPTKEYR, OPTKEY2);
value &= ~FLASH_OPTCR_RESERVED;
- while(adiv5_ap_mem_read(ap, FLASH_SR) & FLASH_SR_BSY)
+ while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY)
if(target_check_error(t))
return -1;
/* WRITE option bytes instruction */
- adiv5_ap_mem_write(ap, FLASH_OPTCR, value);
- adiv5_ap_mem_write(ap, FLASH_OPTCR, value | FLASH_OPTCR_OPTSTRT);
+ target_mem_write32(t, FLASH_OPTCR, value);
+ target_mem_write32(t, FLASH_OPTCR, value | FLASH_OPTCR_OPTSTRT);
/* Read FLASH_SR to poll for BSY bit */
- while(adiv5_ap_mem_read(ap, FLASH_SR) & FLASH_SR_BSY)
+ while(target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY)
if(target_check_error(t))
return false;
- adiv5_ap_mem_write(ap, FLASH_OPTCR, value | FLASH_OPTCR_OPTLOCK);
+ target_mem_write32(t, FLASH_OPTCR, value | FLASH_OPTCR_OPTLOCK);
return true;
}
@@ -329,8 +277,6 @@ static bool stm32f4_cmd_option(target *t, int argc, char *argv[])
{
uint32_t addr, val;
- ADIv5_AP_t *ap = adiv5_target_ap(t);
-
if ((argc == 2) && !strcmp(argv[1], "erase")) {
stm32f4_option_write(t, 0x0fffaaed);
}
@@ -344,7 +290,7 @@ static bool stm32f4_cmd_option(target *t, int argc, char *argv[])
for (int i = 0; i < 0xf; i += 8) {
addr = 0x1fffC000 + i;
- val = adiv5_ap_mem_read(ap, addr);
+ val = target_mem_read32(t, addr);
gdb_outf("0x%08X: 0x%04X\n", addr, val & 0xFFFF);
}
return true;
diff --git a/src/stm32l0.c b/src/stm32l0.c
index 2e30035..8193b12 100644
--- a/src/stm32l0.c
+++ b/src/stm32l0.c
@@ -72,13 +72,13 @@
to regain control of the target after the option byte reload.
stm32l0_option_write(t, 0x1ff80000, 0xffff0000);
- adiv5_ap_mem_write(ap, STM32L0_NVM_PECR, STM32L0_NVM_PECR_OBL_LAUNCH);
+ target_mem_write32(target, STM32L0_NVM_PECR, STM32L0_NVM_PECR_OBL_LAUNCH);
stm32l0_option_write(t, 0x1ff80000, 0xff5500aa);
- adiv5_ap_mem_write(ap, STM32L0_NVM_PECR, STM32L0_NVM_PECR_OBL_LAUNCH);
+ target_mem_write32(target, STM32L0_NVM_PECR, STM32L0_NVM_PECR_OBL_LAUNCH);
uint32_t sr;
do {
- sr = adiv5_ap_mem_read(ap, STM32L0_NVM_SR);
+ sr = target_mem_read32(target, STM32L0_NVM_SR);
} while (sr & STM32L0_NVM_SR_BSY);
o Errors. We probably should clear SR errors immediately after
@@ -112,49 +112,36 @@
*/
-#define CONFIG_STM32L1 /* Include support for STM32L1 */
-
#include "general.h"
#include "adiv5.h"
#include "target.h"
#include "command.h"
#include "gdb_packet.h"
+#include "cortexm.h"
#include "stm32lx-nvm.h"
static int inhibit_stubs; /* Local option to force non-stub flash IO */
-static int stm32lx_nvm_erase(struct target_s* target,
- uint32_t addr, size_t len);
-static int stm32lx_nvm_write(struct target_s* target,
- uint32_t destination,
- const uint8_t* source,
+static int stm32lx_nvm_erase(target *t, uint32_t addr, size_t len);
+static int stm32lx_nvm_write(target *t, uint32_t dest, const uint8_t* src,
size_t size);
-static int stm32lx_nvm_prog_erase(struct target_s* target,
- uint32_t addr, size_t len);
-static int stm32lx_nvm_prog_write(struct target_s* target,
- uint32_t destination,
- const uint8_t* source,
+static int stm32lx_nvm_prog_erase(target *t, uint32_t addr, size_t len);
+static int stm32lx_nvm_prog_write(target *t, uint32_t dest, const uint8_t* src,
size_t size);
-static int stm32lx_nvm_prog_erase_stubbed(struct target_s* target,
- uint32_t addr, size_t len);
-static int stm32lx_nvm_prog_write_stubbed(struct target_s* target,
- uint32_t destination,
- const uint8_t* source,
- size_t size);
+static int stm32lx_nvm_prog_erase_stubbed(target *t, uint32_t addr, size_t len);
+static int stm32lx_nvm_prog_write_stubbed(target *t, uint32_t dest,
+ const uint8_t* src, size_t size);
-static int stm32lx_nvm_data_erase(struct target_s* target,
- uint32_t addr, size_t len);
-static int stm32lx_nvm_data_write(struct target_s* target,
- uint32_t destination,
- const uint8_t* source,
- size_t size);
+static int stm32lx_nvm_data_erase(target *t, uint32_t addr, size_t len);
+static int stm32lx_nvm_data_write(target *t, uint32_t dest,
+ const uint8_t* src, size_t size);
-static bool stm32lx_cmd_option (target* t, int argc, char** argv);
-static bool stm32lx_cmd_eeprom (target* t, int argc, char** argv);
-static bool stm32lx_cmd_stubs (target* t, int argc, char** argv);
+static bool stm32lx_cmd_option(target* t, int argc, char** argv);
+static bool stm32lx_cmd_eeprom(target* t, int argc, char** argv);
+static bool stm32lx_cmd_stubs(target* t, int argc, char** argv);
static const struct command_s stm32lx_cmd_list[] = {
{ "stubs", (cmd_handler) stm32lx_cmd_stubs,
@@ -190,7 +177,6 @@ static const char stm32l0_xml_memory_map[] = "<?xml version=\"1.0\"?>"
" <memory type=\"ram\" start=\"0x20000000\" length=\"0x2000\"/>"
"</memory-map>";
-#if defined(CONFIG_STM32L1)
static const char stm32l1_driver_str[] = "STM32L1xx";
static const char stm32l1_xml_memory_map[] = "<?xml version=\"1.0\"?>"
@@ -209,7 +195,6 @@ static const char stm32l1_xml_memory_map[] = "<?xml version=\"1.0\"?>"
/* SRAM; ranges from 4KiB to 80KiB(0x14000). */
" <memory type=\"ram\" start=\"0x20000000\" length=\"0x14000\"/>"
"</memory-map>";
-#endif
static const uint16_t stm32l0_nvm_prog_write_stub [] = {
#include "../flashstub/stm32l05x-nvm-prog-write.stub"
@@ -219,9 +204,9 @@ static const uint16_t stm32l0_nvm_prog_erase_stub [] = {
#include "../flashstub/stm32l05x-nvm-prog-erase.stub"
};
-static uint32_t stm32lx_nvm_prog_page_size(struct target_s* target)
+static uint32_t stm32lx_nvm_prog_page_size(target *t)
{
- switch (target->idcode) {
+ switch (t->idcode) {
case 0x417: /* STM32L0xx */
return STM32L0_NVM_PROG_PAGE_SIZE;
default: /* STM32L1xx */
@@ -229,9 +214,9 @@ static uint32_t stm32lx_nvm_prog_page_size(struct target_s* target)
}
}
-static bool stm32lx_is_stm32l1(struct target_s* target)
+static bool stm32lx_is_stm32l1(target *t)
{
- switch (target->idcode) {
+ switch (t->idcode) {
case 0x417: /* STM32L0xx */
return false;
default: /* STM32L1xx */
@@ -239,9 +224,9 @@ static bool stm32lx_is_stm32l1(struct target_s* target)
}
}
-static uint32_t stm32lx_nvm_eeprom_size(struct target_s* target)
+static uint32_t stm32lx_nvm_eeprom_size(target *t)
{
- switch (target->idcode) {
+ switch (t->idcode) {
case 0x417: /* STM32L0xx */
return STM32L0_NVM_EEPROM_SIZE;
default: /* STM32L1xx */
@@ -249,9 +234,9 @@ static uint32_t stm32lx_nvm_eeprom_size(struct target_s* target)
}
}
-static uint32_t stm32lx_nvm_phys(struct target_s* target)
+static uint32_t stm32lx_nvm_phys(target *t)
{
- switch (target->idcode) {
+ switch (t->idcode) {
case 0x417: /* STM32L0xx */
return STM32L0_NVM_PHYS;
default: /* STM32L1xx */
@@ -259,9 +244,9 @@ static uint32_t stm32lx_nvm_phys(struct target_s* target)
}
}
-static uint32_t stm32lx_nvm_data_page_size(struct target_s* target)
+static uint32_t stm32lx_nvm_data_page_size(target *t)
{
- switch (target->idcode) {
+ switch (t->idcode) {
case 0x417: /* STM32L0xx */
return STM32L0_NVM_DATA_PAGE_SIZE;
default: /* STM32L1xx */
@@ -269,9 +254,9 @@ static uint32_t stm32lx_nvm_data_page_size(struct target_s* target)
}
}
-static uint32_t stm32lx_nvm_option_size(struct target_s* target)
+static uint32_t stm32lx_nvm_option_size(target *t)
{
- switch (target->idcode) {
+ switch (t->idcode) {
case 0x417: /* STM32L0xx */
return STM32L0_NVM_OPT_SIZE;
default: /* STM32L1xx */
@@ -282,43 +267,38 @@ static uint32_t stm32lx_nvm_option_size(struct target_s* target)
/** Query MCU memory for an indication as to whether or not the
currently attached target is served by this module. We detect the
STM32L0xx parts as well as the STM32L1xx's. */
-bool stm32l0_probe(struct target_s* target)
+bool stm32l0_probe(target *t)
{
uint32_t idcode;
-#if defined(CONFIG_STM32L1)
-
- idcode = adiv5_ap_mem_read(adiv5_target_ap(target),
- STM32L1_DBGMCU_IDCODE_PHYS) & 0xfff;
+ idcode = target_mem_read32(t, STM32L1_DBGMCU_IDCODE_PHYS) & 0xfff;
switch (idcode) {
case 0x416: /* CAT. 1 device */
case 0x429: /* CAT. 2 device */
case 0x427: /* CAT. 3 device */
case 0x436: /* CAT. 4 device */
case 0x437: /* CAT. 5 device */
- target->idcode = idcode;
- target->driver = stm32l1_driver_str;
- target->xml_mem_map = stm32l1_xml_memory_map;
- target->flash_erase = stm32lx_nvm_erase;
- target->flash_write = stm32lx_nvm_write;
- target_add_commands(target, stm32lx_cmd_list, "STM32L1x");
+ t->idcode = idcode;
+ t->driver = stm32l1_driver_str;
+ t->xml_mem_map = stm32l1_xml_memory_map;
+ t->flash_erase = stm32lx_nvm_erase;
+ t->flash_write = stm32lx_nvm_write;
+ target_add_commands(t, stm32lx_cmd_list, "STM32L1x");
return true;
}
-#endif
- idcode = adiv5_ap_mem_read(adiv5_target_ap(target),
- STM32L0_DBGMCU_IDCODE_PHYS) & 0xfff;
+ idcode = target_mem_read32(t, STM32L0_DBGMCU_IDCODE_PHYS) & 0xfff;
switch (idcode) {
default:
break;
case 0x417: /* STM32L0x[123] & probably others */
- target->idcode = idcode;
- target->driver = stm32l0_driver_str;
- target->xml_mem_map = stm32l0_xml_memory_map;
- target->flash_erase = stm32lx_nvm_erase;
- target->flash_write = stm32lx_nvm_write;
- target_add_commands(target, stm32lx_cmd_list, "STM32L0x");
+ t->idcode = idcode;
+ t->driver = stm32l0_driver_str;
+ t->xml_mem_map = stm32l0_xml_memory_map;
+ t->flash_erase = stm32lx_nvm_erase;
+ t->flash_write = stm32lx_nvm_write;
+ target_add_commands(t, stm32lx_cmd_list, "STM32L0x");
return true;
}
@@ -327,42 +307,42 @@ bool stm32l0_probe(struct target_s* target)
/** Lock the NVM control registers preventing writes or erases. */
-static void stm32lx_nvm_lock(ADIv5_AP_t* ap, uint32_t nvm)
+static void stm32lx_nvm_lock(target *t, uint32_t nvm)
{
- adiv5_ap_mem_write(ap, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_PELOCK);
+ target_mem_write32(t, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_PELOCK);
}
/** Unlock the NVM control registers for modifying program or
data flash. Returns true if the unlock succeeds. */
-static bool stm32lx_nvm_prog_data_unlock(ADIv5_AP_t* ap, uint32_t nvm)
+static bool stm32lx_nvm_prog_data_unlock(target* t, uint32_t nvm)
{
/* Always lock first because that's the only way to know that the
unlock can succeed on the STM32L0's. */
- adiv5_ap_mem_write(ap, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_PELOCK);
- adiv5_ap_mem_write(ap, STM32Lx_NVM_PEKEYR(nvm), STM32Lx_NVM_PEKEY1);
- adiv5_ap_mem_write(ap, STM32Lx_NVM_PEKEYR(nvm), STM32Lx_NVM_PEKEY2);
- adiv5_ap_mem_write(ap, STM32Lx_NVM_PRGKEYR(nvm), STM32Lx_NVM_PRGKEY1);
- adiv5_ap_mem_write(ap, STM32Lx_NVM_PRGKEYR(nvm), STM32Lx_NVM_PRGKEY2);
+ target_mem_write32(t, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_PELOCK);
+ target_mem_write32(t, STM32Lx_NVM_PEKEYR(nvm), STM32Lx_NVM_PEKEY1);
+ target_mem_write32(t, STM32Lx_NVM_PEKEYR(nvm), STM32Lx_NVM_PEKEY2);
+ target_mem_write32(t, STM32Lx_NVM_PRGKEYR(nvm), STM32Lx_NVM_PRGKEY1);
+ target_mem_write32(t, STM32Lx_NVM_PRGKEYR(nvm), STM32Lx_NVM_PRGKEY2);
- return !(adiv5_ap_mem_read(ap, STM32Lx_NVM_PECR(nvm))
+ return !(target_mem_read32(t, STM32Lx_NVM_PECR(nvm))
& STM32Lx_NVM_PECR_PRGLOCK);
}
/** Unlock the NVM control registers for modifying option bytes.
Returns true if the unlock succeeds. */
-static bool stm32lx_nvm_opt_unlock(ADIv5_AP_t* ap, uint32_t nvm)
+static bool stm32lx_nvm_opt_unlock(target *t, uint32_t nvm)
{
/* Always lock first because that's the only way to know that the
unlock can succeed on the STM32L0's. */
- adiv5_ap_mem_write(ap, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_PELOCK);
- adiv5_ap_mem_write(ap, STM32Lx_NVM_PEKEYR(nvm), STM32Lx_NVM_PEKEY1);
- adiv5_ap_mem_write(ap, STM32Lx_NVM_PEKEYR(nvm), STM32Lx_NVM_PEKEY2);
- adiv5_ap_mem_write(ap, STM32Lx_NVM_OPTKEYR(nvm), STM32Lx_NVM_OPTKEY1);
- adiv5_ap_mem_write(ap, STM32Lx_NVM_OPTKEYR(nvm), STM32Lx_NVM_OPTKEY2);
+ target_mem_write32(t, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_PELOCK);
+ target_mem_write32(t, STM32Lx_NVM_PEKEYR(nvm), STM32Lx_NVM_PEKEY1);
+ target_mem_write32(t, STM32Lx_NVM_PEKEYR(nvm), STM32Lx_NVM_PEKEY2);
+ target_mem_write32(t, STM32Lx_NVM_OPTKEYR(nvm), STM32Lx_NVM_OPTKEY1);
+ target_mem_write32(t, STM32Lx_NVM_OPTKEYR(nvm), STM32Lx_NVM_OPTKEY2);
- return !(adiv5_ap_mem_read(ap, STM32Lx_NVM_PECR(nvm))
+ return !(target_mem_read32(t, STM32Lx_NVM_PECR(nvm))
& STM32Lx_NVM_PECR_OPTLOCK);
}
@@ -370,41 +350,34 @@ static bool stm32lx_nvm_opt_unlock(ADIv5_AP_t* ap, uint32_t nvm)
/** Erase a region of flash using a stub function. This only works
when the MCU hasn't entered a fault state(see NOTES). The flash
array is erased for all pages from addr to addr+len inclusive. */
-static int stm32lx_nvm_prog_erase_stubbed(struct target_s* target,
+static int stm32lx_nvm_prog_erase_stubbed(target *t,
uint32_t addr, size_t size)
{
struct stm32lx_nvm_stub_info info;
- const uint32_t nvm = stm32lx_nvm_phys(target);
+ const uint32_t nvm = stm32lx_nvm_phys(t);
info.nvm = nvm;
- info.page_size = stm32lx_nvm_prog_page_size(target);
+ info.page_size = stm32lx_nvm_prog_page_size(t);
/* Load the stub */
- target_mem_write_words(target, STM32Lx_STUB_PHYS,
- (void*) &stm32l0_nvm_prog_erase_stub[0],
- sizeof(stm32l0_nvm_prog_erase_stub));
+ target_mem_write(t, STM32Lx_STUB_PHYS,
+ &stm32l0_nvm_prog_erase_stub[0],
+ sizeof(stm32l0_nvm_prog_erase_stub));
/* Setup parameters */
info.destination = addr;
info.size = size;
/* Copy parameters */
- target_mem_write_words(target, STM32Lx_STUB_INFO_PHYS,
- (void*) &info, sizeof(info));
+ target_mem_write(t, STM32Lx_STUB_INFO_PHYS, &info, sizeof(info));
/* Execute stub */
- target_pc_write(target, STM32Lx_STUB_PHYS);
- if (target_check_error(target))
- return -1;
- target_halt_resume(target, 0);
- while (!target_halt_wait(target))
- ;
- {
- ADIv5_AP_t* ap = adiv5_target_ap(target);
- if (adiv5_ap_mem_read(ap, STM32Lx_NVM_SR(nvm))
- & STM32Lx_NVM_SR_ERR_M)
- return -1;
- }
+ cortexm_run_stub(t, STM32Lx_STUB_PHYS, 0, 0, 0, 0);
+
+ if (target_mem_read32(t, STM32Lx_NVM_SR(nvm))
+ & STM32Lx_NVM_SR_ERR_M)
+ return -1;
+
return 0;
}
@@ -414,14 +387,14 @@ static int stm32lx_nvm_prog_erase_stubbed(struct target_s* target,
when the MCU hasn't entered a fault state. Once the MCU faults,
this function will not succeed because the MCU will fault before
executing a single instruction in the stub. */
-static int stm32lx_nvm_prog_write_stubbed(struct target_s* target,
+static int stm32lx_nvm_prog_write_stubbed(target *t,
uint32_t destination,
const uint8_t* source,
size_t size)
{
struct stm32lx_nvm_stub_info info;
- const uint32_t nvm = stm32lx_nvm_phys(target);
- const size_t page_size = stm32lx_nvm_prog_page_size(target);
+ const uint32_t nvm = stm32lx_nvm_phys(t);
+ const size_t page_size = stm32lx_nvm_prog_page_size(t);
/* We can only handle word aligned writes and even
word-multiple ranges. The stm32lx's cannot perform
@@ -434,9 +407,9 @@ static int stm32lx_nvm_prog_write_stubbed(struct target_s* target,
info.page_size = page_size;
/* Load the stub */
- target_mem_write_words(target, STM32Lx_STUB_PHYS,
- (void*) &stm32l0_nvm_prog_write_stub[0],
- sizeof(stm32l0_nvm_prog_write_stub));
+ target_mem_write(t, STM32Lx_STUB_PHYS,
+ &stm32l0_nvm_prog_write_stub[0],
+ sizeof(stm32l0_nvm_prog_write_stub));
while (size > 0) {
@@ -458,8 +431,7 @@ static int stm32lx_nvm_prog_write_stubbed(struct target_s* target,
info.size = cb;
/* Copy data to write to flash */
- target_mem_write_words(target, info.source, (void*) source,
- info.size);
+ target_mem_write(t, info.source, source, info.size);
/* Move pointers early */
destination += cb;
@@ -467,19 +439,13 @@ static int stm32lx_nvm_prog_write_stubbed(struct target_s* target,
size -= cb;
/* Copy parameters */
- target_mem_write_words(target, STM32Lx_STUB_INFO_PHYS,
- (void*) &info, sizeof(info));
+ target_mem_write(t, STM32Lx_STUB_INFO_PHYS,
+ &info, sizeof(info));
/* Execute stub */
- target_pc_write(target, STM32Lx_STUB_PHYS);
- if (target_check_error(target))
- return -1;
- target_halt_resume(target, 0);
- while (!target_halt_wait(target))
- ;
+ cortexm_run_stub(t, STM32Lx_STUB_PHYS, 0, 0, 0, 0);
- if (adiv5_ap_mem_read(adiv5_target_ap(target),
- STM32Lx_NVM_SR(nvm))
+ if (target_mem_read32(t, STM32Lx_NVM_SR(nvm))
& STM32Lx_NVM_SR_ERR_M)
return -1;
}
@@ -491,19 +457,19 @@ static int stm32lx_nvm_prog_write_stubbed(struct target_s* target,
/** Erase a region of NVM for STM32Lx. This is the lead function and
it will invoke an implementation, stubbed or not depending on the
options and the range of addresses. */
-static int stm32lx_nvm_erase(struct target_s* target, uint32_t addr, size_t size)
+static int stm32lx_nvm_erase(target *t, uint32_t addr, size_t size)
{
if (addr >= STM32Lx_NVM_EEPROM_PHYS)
- return stm32lx_nvm_data_erase(target, addr, size);
+ return stm32lx_nvm_data_erase(t, addr, size);
/* Use stub if not inhibited, the MCU is in a non-exceptonal state
and there is stub. */
volatile uint32_t regs[20];
- target_regs_read(target, &regs);
+ target_regs_read(t, &regs);
if (inhibit_stubs || (regs[16] & 0xf))
- return stm32lx_nvm_prog_erase(target, addr, size);
+ return stm32lx_nvm_prog_erase(t, addr, size);
- return stm32lx_nvm_prog_erase_stubbed(target, addr, size);
+ return stm32lx_nvm_prog_erase_stubbed(t, addr, size);
}
@@ -512,13 +478,13 @@ static int stm32lx_nvm_erase(struct target_s* target, uint32_t addr, size_t size
the options and the range of addresses. Data (EEPROM) writes
don't have to care about alignment, but the program flash does.
There is a fixup for unaligned program flash writes. */
-static int stm32lx_nvm_write(struct target_s* target,
+static int stm32lx_nvm_write(target *t,
uint32_t destination,
const uint8_t* source,
size_t size)
{
if (destination >= STM32Lx_NVM_EEPROM_PHYS)
- return stm32lx_nvm_data_write(target, destination, source,
+ return stm32lx_nvm_data_write(t, destination, source,
size);
/* Unaligned destinations. To make this feature simple to
@@ -541,12 +507,12 @@ static int stm32lx_nvm_write(struct target_s* target,
/* Skip stub if the MCU is in a questionable state, or if the
user asks us to avoid stubs. */
volatile uint32_t regs[20];
- target_regs_read(target, &regs);
+ target_regs_read(t, &regs);
if (inhibit_stubs || (regs[16] & 0xf))
- return stm32lx_nvm_prog_write(target, destination, source,
+ return stm32lx_nvm_prog_write(t, destination, source,
size);
- return stm32lx_nvm_prog_write_stubbed(target, destination, source,
+ return stm32lx_nvm_prog_write_stubbed(t, destination, source,
size);
}
@@ -555,50 +521,46 @@ static int stm32lx_nvm_write(struct target_s* target,
interface. This is slower than stubbed versions(see NOTES). The
flash array is erased for all pages from addr to addr+len
inclusive. NVM register file address chosen from target. */
-static int stm32lx_nvm_prog_erase(struct target_s* target,
- uint32_t addr, size_t len)
+static int stm32lx_nvm_prog_erase(target *t, uint32_t addr, size_t len)
{
- ADIv5_AP_t* ap = adiv5_target_ap(target);
- const size_t page_size = stm32lx_nvm_prog_page_size(target);
- const uint32_t nvm = stm32lx_nvm_phys(target);
+ const size_t page_size = stm32lx_nvm_prog_page_size(t);
+ const uint32_t nvm = stm32lx_nvm_phys(t);
/* Word align */
len += (addr & 3);
addr &= ~3;
- if (!stm32lx_nvm_prog_data_unlock(ap, nvm))
+ if (!stm32lx_nvm_prog_data_unlock(t, nvm))
return -1;
/* Flash page erase instruction */
- adiv5_ap_mem_write(ap, STM32Lx_NVM_PECR(nvm),
+ target_mem_write32(t, STM32Lx_NVM_PECR(nvm),
STM32Lx_NVM_PECR_ERASE | STM32Lx_NVM_PECR_PROG);
- {
- uint32_t pecr = adiv5_ap_mem_read(ap, STM32Lx_NVM_PECR(nvm));
- if ((pecr & (STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE))
- != (STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE))
- return -1;
- }
+ uint32_t pecr = target_mem_read32(t, STM32Lx_NVM_PECR(nvm));
+ if ((pecr & (STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE))
+ != (STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE))
+ return -1;
/* Clear errors. Note that this only works when we wait for the NVM
block to complete the last operation. */
- adiv5_ap_mem_write(ap, STM32Lx_NVM_SR(nvm), STM32Lx_NVM_SR_ERR_M);
+ target_mem_write32(t, STM32Lx_NVM_SR(nvm), STM32Lx_NVM_SR_ERR_M);
while (len > 0) {
/* Write first word of page to 0 */
- adiv5_ap_mem_write(ap, addr, 0);
+ target_mem_write32(t, addr, 0);
len -= page_size;
addr += page_size;
}
/* Disable further programming by locking PECR */
- stm32lx_nvm_lock(ap, nvm);
+ stm32lx_nvm_lock(t, nvm);
/* Wait for completion or an error */
while (1) {
- uint32_t sr = adiv5_ap_mem_read(ap, STM32Lx_NVM_SR(nvm));
- if (target_check_error(target))
+ uint32_t sr = target_mem_read32(t, STM32Lx_NVM_SR(nvm));
+ if (target_check_error(t))
return -1;
if (sr & STM32Lx_NVM_SR_BSY)
continue;
@@ -614,14 +576,13 @@ static int stm32lx_nvm_prog_erase(struct target_s* target,
/** Write to program flash using operations through the debug
interface. This is slower than the stubbed write(see NOTES).
NVM register file address chosen from target. */
-static int stm32lx_nvm_prog_write(struct target_s* target,
+static int stm32lx_nvm_prog_write(target *t,
uint32_t destination,
const uint8_t* source_8,
size_t size)
{
- ADIv5_AP_t* ap = adiv5_target_ap(target);
- const uint32_t nvm = stm32lx_nvm_phys(target);
- const bool is_stm32l1 = stm32lx_is_stm32l1(target);
+ const uint32_t nvm = stm32lx_nvm_phys(t);
+ const bool is_stm32l1 = stm32lx_is_stm32l1(t);
/* We can only handle word aligned writes and even
word-multiple ranges. The stm32lx's cannot perform
@@ -630,19 +591,19 @@ static int stm32lx_nvm_prog_write(struct target_s* target,
if ((destination & 3) || (size & 3))
return -1;
- if (!stm32lx_nvm_prog_data_unlock(ap, nvm))
+ if (!stm32lx_nvm_prog_data_unlock(t, nvm))
return -1;
- const size_t half_page_size = stm32lx_nvm_prog_page_size(target)/2;
+ const size_t half_page_size = stm32lx_nvm_prog_page_size(t)/2;
uint32_t* source = (uint32_t*) source_8;
while (size > 0) {
/* Wait for BSY to clear because we cannot write the PECR until
the previous operation completes on STM32Lxxx. */
- while (adiv5_ap_mem_read(ap, STM32Lx_NVM_SR(nvm))
+ while (target_mem_read32(t, STM32Lx_NVM_SR(nvm))
& STM32Lx_NVM_SR_BSY)
- if (target_check_error(target)) {
+ if (target_check_error(t)) {
return -1;
}
@@ -650,7 +611,7 @@ static int stm32lx_nvm_prog_write(struct target_s* target,
// than a half page to write
if (size < half_page_size
|| (destination & (half_page_size - 1))) {
- adiv5_ap_mem_write(ap, STM32Lx_NVM_PECR(nvm),
+ target_mem_write32(t, STM32Lx_NVM_PECR(nvm),
is_stm32l1
? 0
: STM32Lx_NVM_PECR_PROG);
@@ -661,31 +622,31 @@ static int stm32lx_nvm_prog_write(struct target_s* target,
c = size;
size -= c;
- target_mem_write_words(target, destination, source, c);
+ target_mem_write(t, destination, source, c);
source += c/4;
destination += c;
}
// Or we are writing a half-page(s)
else {
- adiv5_ap_mem_write(ap, STM32Lx_NVM_PECR(nvm),
+ target_mem_write32(t, STM32Lx_NVM_PECR(nvm),
STM32Lx_NVM_PECR_PROG
| STM32Lx_NVM_PECR_FPRG);
size_t c = size & ~(half_page_size - 1);
size -= c;
- target_mem_write_words(target, destination, source, c);
+ target_mem_write(t, destination, source, c);
source += c/4;
destination += c;
}
}
/* Disable further programming by locking PECR */
- stm32lx_nvm_lock(ap, nvm);
+ stm32lx_nvm_lock(t, nvm);
/* Wait for completion or an error */
while (1) {
- uint32_t sr = adiv5_ap_mem_read(ap, STM32Lx_NVM_SR(nvm));
- if (target_check_error(target)) {
+ uint32_t sr = target_mem_read32(t, STM32Lx_NVM_SR(nvm));
+ if (target_check_error(t)) {
return -1;
}
if (sr & STM32Lx_NVM_SR_BSY)
@@ -704,46 +665,43 @@ static int stm32lx_nvm_prog_write(struct target_s* target,
interface . The flash is erased for all pages from addr to
addr+len, inclusive, on a word boundary. NVM register file
address chosen from target. */
-static int stm32lx_nvm_data_erase(struct target_s* target,
+static int stm32lx_nvm_data_erase(target *t,
uint32_t addr, size_t len)
{
- ADIv5_AP_t* ap = adiv5_target_ap(target);
- const size_t page_size = stm32lx_nvm_data_page_size(target);
- const uint32_t nvm = stm32lx_nvm_phys(target);
+ const size_t page_size = stm32lx_nvm_data_page_size(t);
+ const uint32_t nvm = stm32lx_nvm_phys(t);
/* Word align */
len += (addr & 3);
addr &= ~3;
- if (!stm32lx_nvm_prog_data_unlock(ap, nvm))
+ if (!stm32lx_nvm_prog_data_unlock(t, nvm))
return -1;
/* Flash data erase instruction */
- adiv5_ap_mem_write(ap, STM32Lx_NVM_PECR(nvm),
+ target_mem_write32(t, STM32Lx_NVM_PECR(nvm),
STM32Lx_NVM_PECR_ERASE | STM32Lx_NVM_PECR_DATA);
- {
- uint32_t pecr = adiv5_ap_mem_read(ap, STM32Lx_NVM_PECR(nvm));
- if ((pecr & (STM32Lx_NVM_PECR_ERASE | STM32Lx_NVM_PECR_DATA))
- != (STM32Lx_NVM_PECR_ERASE | STM32Lx_NVM_PECR_DATA))
- return -1;
- }
+ uint32_t pecr = target_mem_read32(t, STM32Lx_NVM_PECR(nvm));
+ if ((pecr & (STM32Lx_NVM_PECR_ERASE | STM32Lx_NVM_PECR_DATA))
+ != (STM32Lx_NVM_PECR_ERASE | STM32Lx_NVM_PECR_DATA))
+ return -1;
while (len > 0) {
/* Write first word of page to 0 */
- adiv5_ap_mem_write(ap, addr, 0);
+ target_mem_write32(t, addr, 0);
len -= page_size;
addr += page_size;
}
/* Disable further programming by locking PECR */
- stm32lx_nvm_lock(ap, nvm);
+ stm32lx_nvm_lock(t, nvm);
/* Wait for completion or an error */
while (1) {
- uint32_t sr = adiv5_ap_mem_read(ap, STM32Lx_NVM_SR(nvm));
- if (target_check_error(target))
+ uint32_t sr = target_mem_read32(t, STM32Lx_NVM_SR(nvm));
+ if (target_check_error(t))
return -1;
if (sr & STM32Lx_NVM_SR_BSY)
continue;
@@ -760,40 +718,38 @@ static int stm32lx_nvm_data_erase(struct target_s* target,
NVM register file address chosen from target. Unaligned
destination writes are supported (though unaligned sources are
not). */
-static int stm32lx_nvm_data_write(struct target_s* target,
+static int stm32lx_nvm_data_write(target *t,
uint32_t destination,
const uint8_t* source_8,
size_t size)
{
- ADIv5_AP_t* ap = adiv5_target_ap(target);
- const uint32_t nvm = stm32lx_nvm_phys(target);
- const bool is_stm32l1 = stm32lx_is_stm32l1(target);
- uint32_t* source = (uint32_t*) source_8;
+ const uint32_t nvm = stm32lx_nvm_phys(t);
+ const bool is_stm32l1 = stm32lx_is_stm32l1(t);
+ uint32_t* source = (uint32_t*) source_8;
- if (!stm32lx_nvm_prog_data_unlock(ap, nvm))
+ if (!stm32lx_nvm_prog_data_unlock(t, nvm))
return -1;
-
- adiv5_ap_mem_write(ap, STM32Lx_NVM_PECR(nvm),
+ target_mem_write32(t, STM32Lx_NVM_PECR(nvm),
is_stm32l1 ? 0 : STM32Lx_NVM_PECR_DATA);
while (size) {
size -= 4;
uint32_t v = *source++;
- adiv5_ap_mem_write(ap, destination, v);
+ target_mem_write32(t, destination, v);
destination += 4;
- if (target_check_error(target))
+ if (target_check_error(t))
return -1;
}
/* Disable further programming by locking PECR */
- stm32lx_nvm_lock(ap, nvm);
+ stm32lx_nvm_lock(t, nvm);
/* Wait for completion or an error */
while (1) {
- uint32_t sr = adiv5_ap_mem_read(ap, STM32Lx_NVM_SR(nvm));
- if (target_check_error(target))
+ uint32_t sr = target_mem_read32(t, STM32Lx_NVM_SR(nvm));
+ if (target_check_error(t))
return -1;
if (sr & STM32Lx_NVM_SR_BSY)
continue;
@@ -814,16 +770,15 @@ static int stm32lx_nvm_data_write(struct target_s* target,
The return value is true if the write succeeded. */
static bool stm32lx_option_write(target *t, uint32_t address, uint32_t value)
{
- ADIv5_AP_t* ap = adiv5_target_ap(t);
const uint32_t nvm = stm32lx_nvm_phys(t);
/* Erase and program option in one go. */
- adiv5_ap_mem_write(ap, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_FIX);
- adiv5_ap_mem_write(ap, address, value);
+ target_mem_write32(t, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_FIX);
+ target_mem_write32(t, address, value);
uint32_t sr;
do {
- sr = adiv5_ap_mem_read(ap, STM32Lx_NVM_SR(nvm));
+ sr = target_mem_read32(t, STM32Lx_NVM_SR(nvm));
} while (sr & STM32Lx_NVM_SR_BSY);
return !(sr & STM32Lx_NVM_SR_ERR_M);
@@ -840,29 +795,28 @@ static bool stm32lx_option_write(target *t, uint32_t address, uint32_t value)
static bool stm32lx_eeprom_write(target *t, uint32_t address,
size_t cb, uint32_t value)
{
- ADIv5_AP_t* ap = adiv5_target_ap(t);
const uint32_t nvm = stm32lx_nvm_phys(t);
const bool is_stm32l1 = stm32lx_is_stm32l1(t);
/* Clear errors. */
- adiv5_ap_mem_write(ap, STM32Lx_NVM_SR(nvm), STM32Lx_NVM_SR_ERR_M);
+ target_mem_write32(t, STM32Lx_NVM_SR(nvm), STM32Lx_NVM_SR_ERR_M);
/* Erase and program option in one go. */
- adiv5_ap_mem_write(ap, STM32Lx_NVM_PECR(nvm),
+ target_mem_write32(t, STM32Lx_NVM_PECR(nvm),
(is_stm32l1 ? 0 : STM32Lx_NVM_PECR_DATA)
| STM32Lx_NVM_PECR_FIX);
if (cb == 4)
- adiv5_ap_mem_write(ap, address, value);
+ target_mem_write32(t, address, value);
else if (cb == 2)
- adiv5_ap_mem_write_halfword(ap, address, value);
+ target_mem_write16(t, address, value);
else if (cb == 1)
- adiv5_ap_mem_write_byte(ap, address, value);
+ target_mem_write8(t, address, value);
else
return false;
uint32_t sr;
do {
- sr = adiv5_ap_mem_read(ap, STM32Lx_NVM_SR(nvm));
+ sr = target_mem_read32(t, STM32Lx_NVM_SR(nvm));
} while (sr & STM32Lx_NVM_SR_BSY);
return !(sr & STM32Lx_NVM_SR_ERR_M);
@@ -889,11 +843,10 @@ static bool stm32lx_cmd_stubs(target* t,
static bool stm32lx_cmd_option(target* t, int argc, char** argv)
{
- ADIv5_AP_t* ap = adiv5_target_ap(t);
const uint32_t nvm = stm32lx_nvm_phys(t);
const size_t opt_size = stm32lx_nvm_option_size(t);
- if (!stm32lx_nvm_opt_unlock(ap, nvm)) {
+ if (!stm32lx_nvm_opt_unlock(t, nvm)) {
gdb_out("unable to unlock NVM option bytes\n");
return true;
}
@@ -901,7 +854,7 @@ static bool stm32lx_cmd_option(target* t, int argc, char** argv)
size_t cb = strlen(argv[1]);
if (argc == 2 && !strncasecmp(argv[1], "obl_launch", cb)) {
- adiv5_ap_mem_write(ap, STM32Lx_NVM_PECR(nvm),
+ target_mem_write32(t, STM32Lx_NVM_PECR(nvm),
STM32Lx_NVM_PECR_OBL_LAUNCH);
}
else if (argc == 4 && !strncasecmp(argv[1], "raw", cb)) {
@@ -935,7 +888,7 @@ static bool stm32lx_cmd_option(target* t, int argc, char** argv)
/* Report the current option values */
for(unsigned i = 0; i < opt_size; i += sizeof(uint32_t)) {
uint32_t addr = STM32Lx_NVM_OPT_PHYS + i;
- uint32_t val = adiv5_ap_mem_read(ap, addr);
+ uint32_t val = target_mem_read32(t, addr);
gdb_outf("0x%08x: 0x%04x 0x%04x %s\n",
addr, val & 0xffff, (val >> 16) & 0xffff,
((val & 0xffff) == ((~val >> 16) & 0xffff))
@@ -943,7 +896,7 @@ static bool stm32lx_cmd_option(target* t, int argc, char** argv)
}
if (stm32lx_is_stm32l1(t)) {
- uint32_t optr = adiv5_ap_mem_read(ap, STM32Lx_NVM_OPTR(nvm));
+ uint32_t optr = target_mem_read32(t, STM32Lx_NVM_OPTR(nvm));
uint8_t rdprot = (optr >> STM32L1_NVM_OPTR_RDPROT_S)
& STM32L1_NVM_OPTR_RDPROT_M;
if (rdprot == STM32L1_NVM_OPTR_RDPROT_0)
@@ -965,7 +918,7 @@ static bool stm32lx_cmd_option(target* t, int argc, char** argv)
(optr & STM32L1_NVM_OPTR_nBFB2) ? 1 : 0);
}
else {
- uint32_t optr = adiv5_ap_mem_read(ap, STM32Lx_NVM_OPTR(nvm));
+ uint32_t optr = target_mem_read32(t, STM32Lx_NVM_OPTR(nvm));
uint8_t rdprot = (optr >> STM32L0_NVM_OPTR_RDPROT_S)
& STM32L0_NVM_OPTR_RDPROT_M;
if (rdprot == STM32L0_NVM_OPTR_RDPROT_0)
@@ -998,17 +951,16 @@ usage:
STM32Lx_NVM_OPT_PHYS + opt_size - sizeof(uint32_t));
done:
- stm32lx_nvm_lock(ap, nvm);
+ stm32lx_nvm_lock(t, nvm);
return true;
}
static bool stm32lx_cmd_eeprom(target* t, int argc, char** argv)
{
- ADIv5_AP_t* ap = adiv5_target_ap(t);
const uint32_t nvm = stm32lx_nvm_phys(t);
- if (!stm32lx_nvm_prog_data_unlock(ap, nvm)) {
+ if (!stm32lx_nvm_prog_data_unlock(t, nvm)) {
gdb_out("unable to unlock EEPROM\n");
return true;
}
@@ -1062,6 +1014,6 @@ usage:
+ stm32lx_nvm_eeprom_size(t));
done:
- stm32lx_nvm_lock(ap, nvm);
+ stm32lx_nvm_lock(t, nvm);
return true;
}
diff --git a/src/stm32l1.c b/src/stm32l1.c
deleted file mode 100644
index 86298e5..0000000
--- a/src/stm32l1.c
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * This file is part of the Black Magic Debug project.
- *
- * Copyright (C) 2012 Vegard Storheil Eriksen <zyp@jvnv.net>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/* This file implements STM32L1 target specific functions for detecting
- * the device, providing the XML memory map and Flash memory programming.
- *
- * Refereces:
- * ST doc - RM0038
- * Reference manual - STM32L151xx, STM32L152xx and STM32L162xx
- * advanced ARM-based 32-bit MCUs
- * ST doc - PM0062
- * Programming manual - STM32L151xx, STM32L152xx and STM32L162xx
- * Flash and EEPROM programming
- */
-
-#include "general.h"
-#include "adiv5.h"
-#include "target.h"
-#include "command.h"
-#include "gdb_packet.h"
-
-static int stm32l1_flash_erase(struct target_s *target, uint32_t addr,
- size_t len);
-static int stm32l1_flash_write(struct target_s *target, uint32_t dest,
- const uint8_t *src, size_t len);
-
-static const char stm32l1_driver_str[] = "STM32L1xx";
-
-static const char stm32l1_xml_memory_map[] = "<?xml version=\"1.0\"?>"
-/* "<!DOCTYPE memory-map "
- " PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
- " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"*/
- "<memory-map>"
- " <memory type=\"flash\" start=\"0x8000000\" length=\"0x80000\">"
- " <property name=\"blocksize\">0x100</property>"
- " </memory>"
- " <memory type=\"ram\" start=\"0x20000000\" length=\"0x5000\"/>"
- "</memory-map>";
-
-/* Flash Controller Register Map */
-#define STM32L1_FLASH_BASE 0x40023C00
-#define STM32L1_FLASH_ACR (STM32L1_FLASH_BASE + 0x00)
-#define STM32L1_FLASH_PECR (STM32L1_FLASH_BASE + 0x04)
-#define STM32L1_FLASH_PDKEYR (STM32L1_FLASH_BASE + 0x08)
-#define STM32L1_FLASH_PEKEYR (STM32L1_FLASH_BASE + 0x0C)
-#define STM32L1_FLASH_PRGKEYR (STM32L1_FLASH_BASE + 0x10)
-#define STM32L1_FLASH_OPTKEYR (STM32L1_FLASH_BASE + 0x14)
-#define STM32L1_FLASH_SR (STM32L1_FLASH_BASE + 0x18)
-#define STM32L1_FLASH_OBR (STM32L1_FLASH_BASE + 0x1C)
-#define STM32L1_FLASH_WRPR1 (STM32L1_FLASH_BASE + 0x20)
-#define STM32L1_FLASH_WRPR2 (STM32L1_FLASH_BASE + 0x80)
-#define STM32L1_FLASH_WRPR3 (STM32L1_FLASH_BASE + 0x84)
-
-#define STM32L1_FLASH_PECR_FPRG (1 << 10)
-#define STM32L1_FLASH_PECR_ERASE (1 << 9)
-#define STM32L1_FLASH_PECR_PROG (1 << 3)
-
-#define STM32L1_FLASH_SR_BSY (1 << 0)
-#define STM32L1_FLASH_SR_EOP (1 << 1)
-
-#define STM32L1_FLASH_SR_ERROR_MASK (0x1f << 8)
-
-#define STM32L1_PEKEY1 0x89ABCDEF
-#define STM32L1_PEKEY2 0x02030405
-#define STM32L1_PRGKEY1 0x8C9DAEBF
-#define STM32L1_PRGKEY2 0x13141516
-
-#define STM32L1_DBGMCU_IDCODE 0xE0042000
-
-bool stm32l1_probe(struct target_s *target)
-{
- uint32_t idcode;
-
- idcode = adiv5_ap_mem_read(adiv5_target_ap(target), STM32L1_DBGMCU_IDCODE);
- switch(idcode & 0xFFF) {
- case 0x416: /* CAT. 1 device */
- case 0x429: /* CAT. 2 device */
- case 0x427: /* CAT. 3 device */
- case 0x436: /* CAT. 4 device */
- case 0x437: /* CAT. 5 device */
- target->idcode = idcode & 0xFFF;
- target->driver = stm32l1_driver_str;
- target->xml_mem_map = stm32l1_xml_memory_map;
- target->flash_erase = stm32l1_flash_erase;
- target->flash_write = stm32l1_flash_write;
- return true;
- }
-
- return false;
-}
-
-static void stm32l1_flash_unlock(ADIv5_AP_t *ap)
-{
- adiv5_ap_mem_write(ap, STM32L1_FLASH_PEKEYR, STM32L1_PEKEY1);
- adiv5_ap_mem_write(ap, STM32L1_FLASH_PEKEYR, STM32L1_PEKEY2);
- adiv5_ap_mem_write(ap, STM32L1_FLASH_PRGKEYR, STM32L1_PRGKEY1);
- adiv5_ap_mem_write(ap, STM32L1_FLASH_PRGKEYR, STM32L1_PRGKEY2);
-}
-
-static int stm32l1_flash_erase(struct target_s *target, uint32_t addr, size_t len)
-{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
- uint16_t sr;
-
- addr &= ~255;
- len &= ~255;
-
- stm32l1_flash_unlock(ap);
-
- /* Flash page erase instruction */
- adiv5_ap_mem_write(ap, STM32L1_FLASH_PECR, STM32L1_FLASH_PECR_ERASE | STM32L1_FLASH_PECR_PROG);
-
- /* Read FLASH_SR to poll for BSY bit */
- while(adiv5_ap_mem_read(ap, STM32L1_FLASH_SR) & STM32L1_FLASH_SR_BSY)
- if(target_check_error(target))
- return -1;
-
- while(len) {
- /* Write first word of page to 0 */
- adiv5_ap_mem_write(ap, addr, 0);
-
- len -= 256;
- addr += 256;
- }
-
- /* Disable programming mode */
- adiv5_ap_mem_write(ap, STM32L1_FLASH_PECR, 0);
-
- /* Check for error */
- sr = adiv5_ap_mem_read(ap, STM32L1_FLASH_SR);
- if ((sr & STM32L1_FLASH_SR_ERROR_MASK) || !(sr & STM32L1_FLASH_SR_EOP))
- return -1;
-
- return 0;
-}
-
-static int stm32l1_flash_write(struct target_s *target, uint32_t dest,
- const uint8_t *src, size_t len)
-{
- ADIv5_AP_t *ap = adiv5_target_ap(target);
- uint16_t sr;
-
- /* Handle non word-aligned start */
- if(dest & 3) {
- uint32_t data = 0;
- uint32_t wlen = 4 - (dest & 3);
- if(wlen > len)
- wlen = len;
-
- memcpy((uint8_t *)&data + (dest & 3), src, wlen);
- adiv5_ap_mem_write(ap, dest & ~3, data);
- src += wlen;
- dest += wlen;
- len -= wlen;
- }
-
- /* Handle non half-page-aligned start */
- if(dest & 127 && len >= 4) {
- uint32_t xlen = 128 - (dest & 127);
- if(xlen > len)
- xlen = len & ~3;
-
- target_mem_write_words(target, dest, (uint32_t*)src, xlen);
- src += xlen;
- dest += xlen;
- len -= xlen;
- }
-
- /* Write half-pages */
- if(len > 128) {
- /* Enable half page mode */
- adiv5_ap_mem_write(ap, STM32L1_FLASH_PECR, STM32L1_FLASH_PECR_FPRG | STM32L1_FLASH_PECR_PROG);
-
- /* Read FLASH_SR to poll for BSY bit */
- while(adiv5_ap_mem_read(ap, STM32L1_FLASH_SR) & STM32L1_FLASH_SR_BSY)
- if(target_check_error(target))
- return -1;
-
- target_mem_write_words(target, dest, (uint32_t*)src, len & ~127);
- src += len & ~127;
- dest += len & ~127;
- len -= len & ~127;
-
- /* Disable half page mode */
- adiv5_ap_mem_write(ap, STM32L1_FLASH_PECR, 0);
-
- /* Read FLASH_SR to poll for BSY bit */
- while(adiv5_ap_mem_read(ap, STM32L1_FLASH_SR) & STM32L1_FLASH_SR_BSY)
- if(target_check_error(target))
- return -1;
- }
-
- /* Handle non-full page at the end */
- if(len >= 4) {
- target_mem_write_words(target, dest, (uint32_t*)src, len & ~3);
- src += len & ~3;
- dest += len & ~3;
- len -= len & ~3;
- }
-
- /* Handle non-full word at the end */
- if(len) {
- uint32_t data = 0;
-
- memcpy((uint8_t *)&data, src, len);
- adiv5_ap_mem_write(ap, dest, data);
- }
-
- /* Check for error */
- sr = adiv5_ap_mem_read(ap, STM32L1_FLASH_SR);
- if ((sr & STM32L1_FLASH_SR_ERROR_MASK) || !(sr & STM32L1_FLASH_SR_EOP))
- return -1;
-
- return 0;
-}