From 2a385e716ee3ca36b4fbef841e009b852b8a0acc Mon Sep 17 00:00:00 2001 From: dragonmux Date: Fri, 10 Dec 2021 14:46:12 -0500 Subject: [PATCH 01/56] avr: Added stub support for the AVR JTAG-PDI scan --- src/Makefile | 3 +++ src/platforms/hosted/platform.c | 5 +++++ src/target/atxmega.c | 0 src/target/avr.h | 19 +++++++++++++++++++ src/target/avr_jtagdp.c | 22 ++++++++++++++++++++++ src/target/avr_pdi.c | 16 ++++++++++++++++ src/target/jtag_devs.c | 4 ++++ 7 files changed, 69 insertions(+) create mode 100644 src/target/atxmega.c create mode 100644 src/target/avr.h create mode 100644 src/target/avr_jtagdp.c create mode 100644 src/target/avr_pdi.c diff --git a/src/Makefile b/src/Makefile index b618bfc4a7e..97f1d54b697 100644 --- a/src/Makefile +++ b/src/Makefile @@ -20,6 +20,9 @@ SRC = \ adiv5.c \ adiv5_jtagdp.c \ adiv5_swdp.c \ + atxmega.c \ + avr_jtagdp.c \ + avr_pdi.c \ command.c \ cortexa.c \ cortexm.c \ diff --git a/src/platforms/hosted/platform.c b/src/platforms/hosted/platform.c index ff6865a3e29..813e6777ca0 100644 --- a/src/platforms/hosted/platform.c +++ b/src/platforms/hosted/platform.c @@ -252,6 +252,11 @@ int platform_jtag_dp_init(ADIv5_DP_t *dp) return 0; } +int platform_avr_jtag_dp_init(AVR_DP_t *dp) +{ + return 0; +} + char *platform_ident(void) { switch (info.bmp_type) { diff --git a/src/target/atxmega.c b/src/target/atxmega.c new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/target/avr.h b/src/target/avr.h new file mode 100644 index 00000000000..335b239a3bb --- /dev/null +++ b/src/target/avr.h @@ -0,0 +1,19 @@ +#ifndef ATMEL___H +#define ATMEL___H + +#include "jtag_scan.h" + +typedef struct Atmel_DP_s { + int refcnt; + + uint32_t idcode; + + uint8_t dp_jd_index; +} AVR_DP_t; + +void avr_dp_init(AVR_DP_t *dp); + +void avr_jtag_dp_handler(uint8_t jd_index, uint32_t j_idcode); +int platform_avr_jtag_dp_init(AVR_DP_t *dp); + +#endif /*ATMEL___H*/ diff --git a/src/target/avr_jtagdp.c b/src/target/avr_jtagdp.c new file mode 100644 index 00000000000..841f0135a06 --- /dev/null +++ b/src/target/avr_jtagdp.c @@ -0,0 +1,22 @@ +#include "general.h" +#include "exception.h" +#include "avr.h" +#include "jtag_scan.h" +#include "jtagtap.h" +#include "gdb_packet.h" + +void avr_jtag_dp_handler(uint8_t jd_index, uint32_t j_idcode) +{ + AVR_DP_t *dp = calloc(1, sizeof(*dp)); + if (!dp) { /* calloc failed: heap exhaustion */ + DEBUG_WARN("calloc: failed in %s\n", __func__); + return; + } + + dp->dp_jd_index = jd_index; + dp->idcode = j_idcode; + if ((PC_HOSTED == 0) || (!platform_avr_jtag_dp_init(dp))) { + // + } + avr_dp_init(dp); +} diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c new file mode 100644 index 00000000000..adb44276537 --- /dev/null +++ b/src/target/avr_pdi.c @@ -0,0 +1,16 @@ +#include "general.h" +#include "target.h" +#include "target_internal.h" +#include "avr.h" +#include "exception.h" + +static void avr_dp_unref(AVR_DP_t *dp) +{ + if (--(dp->refcnt) == 0) + free(dp); +} + +void avr_dp_init(AVR_DP_t *dp) +{ + (void)dp; +} diff --git a/src/target/jtag_devs.c b/src/target/jtag_devs.c index f0ddea43df6..f881ad53048 100644 --- a/src/target/jtag_devs.c +++ b/src/target/jtag_devs.c @@ -22,6 +22,7 @@ #include "general.h" #include "jtag_scan.h" #include "adiv5.h" +#include "avr.h" #include "jtag_devs.h" jtag_dev_descr_t dev_descr[] = { @@ -62,6 +63,9 @@ jtag_dev_descr_t dev_descr[] = { .descr = "Xambala: RVDBG013."}, {.idcode = 0x000007A3, .idmask = 0x00000FFF, .descr = "Gigadevice BSD."}, + {.idcode = 0x0000003F, .idmask = 0x00000FFF, + .descr = "Atmel Limited: AVR JTAG-PDI port.", + .handler = avr_jtag_dp_handler}, /* Just for fun, unsupported */ {.idcode = 0x8940303F, .idmask = 0xFFFFFFFF, .descr = "ATMega16."}, {.idcode = 0x0792603F, .idmask = 0xFFFFFFFF, .descr = "AT91SAM9261."}, From 1df92b8a25500924196735981eeeb442a4d680a9 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Fri, 10 Dec 2021 16:09:07 -0500 Subject: [PATCH 02/56] hosted: Fixed an error + warning the platform AVR support introduced --- src/platforms/hosted/platform.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/platforms/hosted/platform.c b/src/platforms/hosted/platform.c index 813e6777ca0..2a179964029 100644 --- a/src/platforms/hosted/platform.c +++ b/src/platforms/hosted/platform.c @@ -25,6 +25,7 @@ #include "target.h" #include "target_internal.h" #include "adiv5.h" +#include "avr.h" #include "timing.h" #include "cl_utils.h" #include "gdb_if.h" @@ -254,6 +255,7 @@ int platform_jtag_dp_init(ADIv5_DP_t *dp) int platform_avr_jtag_dp_init(AVR_DP_t *dp) { + (void)dp; return 0; } From 67d3a58ceba8d41427de7a5ba40327d08264469d Mon Sep 17 00:00:00 2001 From: dragonmux Date: Fri, 10 Dec 2021 16:10:38 -0500 Subject: [PATCH 03/56] jtag_scan: Added some brackets that were missing --- src/target/jtag_scan.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/target/jtag_scan.c b/src/target/jtag_scan.c index 4addc4921e3..fd9b9f5e026 100644 --- a/src/target/jtag_scan.c +++ b/src/target/jtag_scan.c @@ -207,8 +207,8 @@ int jtag_scan(const uint8_t *irlens) #endif /* Check for known devices and handle accordingly */ - for(i = 0; i < jtag_dev_count; i++) - for(j = 0; dev_descr[j].idcode; j++) + for(i = 0; i < jtag_dev_count; i++) { + for(j = 0; dev_descr[j].idcode; j++) { if((jtag_devs[i].jd_idcode & dev_descr[j].idmask) == dev_descr[j].idcode) { jtag_devs[i].current_ir = -1; @@ -219,6 +219,8 @@ int jtag_scan(const uint8_t *irlens) dev_descr[j].handler(i); break; } + } + } return jtag_dev_count; } From acb1425c69ddcf5dcc68e8c17ba71cc432ef7e0c Mon Sep 17 00:00:00 2001 From: dragonmux Date: Fri, 10 Dec 2021 16:11:52 -0500 Subject: [PATCH 04/56] adi: Fixed a couple of UB bitwise operations --- src/target/adiv5.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/target/adiv5.c b/src/target/adiv5.c index af6251a7612..89c11c6a18c 100644 --- a/src/target/adiv5.c +++ b/src/target/adiv5.c @@ -683,9 +683,8 @@ void adiv5_dp_init(ADIv5_DP_t *dp) return; } DEBUG_INFO("DPIDR 0x%08" PRIx32 " (v%d %srev%d)\n", dp->idcode, - (uint8_t)((dp->idcode >> 12) & 0xf), - (dp->idcode & ADIV5_MINDP) ? "MINDP " : "", - (uint16_t)(dp->idcode >> 28)); + (uint8_t)((dp->idcode >> 12U) & 0xfU), + (dp->idcode & ADIV5_MINDP) ? "MINDP " : "", (uint16_t)(dp->idcode >> 28U)); volatile uint32_t ctrlstat = 0; #if PC_HOSTED == 1 platform_adiv5_dp_defaults(dp); From 4928aad59b8f0b7b51852d2c6769f4fa5805b0c3 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Fri, 10 Dec 2021 16:45:58 -0500 Subject: [PATCH 05/56] avr: Begun implementing the PDI-specific JTAG IO routines --- src/target/avr.h | 5 ++- src/target/avr_jtagdp.c | 1 - src/target/avr_pdi.c | 68 +++++++++++++++++++++++++++++++++++++++-- src/target/jtag_scan.c | 2 +- src/target/jtag_scan.h | 1 + 5 files changed, 72 insertions(+), 5 deletions(-) diff --git a/src/target/avr.h b/src/target/avr.h index 335b239a3bb..b54f67f7c9d 100644 --- a/src/target/avr.h +++ b/src/target/avr.h @@ -11,9 +11,12 @@ typedef struct Atmel_DP_s { uint8_t dp_jd_index; } AVR_DP_t; -void avr_dp_init(AVR_DP_t *dp); +bool avr_dp_init(AVR_DP_t *dp); void avr_jtag_dp_handler(uint8_t jd_index, uint32_t j_idcode); int platform_avr_jtag_dp_init(AVR_DP_t *dp); +bool avr_pdi_reg_write(AVR_DP_t *dp, uint8_t reg, uint8_t value); +uint8_t avr_pdi_reg_read(AVR_DP_t *dp, uint8_t reg); + #endif /*ATMEL___H*/ diff --git a/src/target/avr_jtagdp.c b/src/target/avr_jtagdp.c index 841f0135a06..af8fa5c7002 100644 --- a/src/target/avr_jtagdp.c +++ b/src/target/avr_jtagdp.c @@ -3,7 +3,6 @@ #include "avr.h" #include "jtag_scan.h" #include "jtagtap.h" -#include "gdb_packet.h" void avr_jtag_dp_handler(uint8_t jd_index, uint32_t j_idcode) { diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index adb44276537..2c694f9214b 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -4,13 +4,77 @@ #include "avr.h" #include "exception.h" +#define IR_PDI 0x7U +#define PDI_BREAK 0xBBU +#define PDI_DELAY 0xDBU +#define PDI_EMPTY 0xEBU + +#define PDI_LDCS 0x80U +#define PDI_STCS 0xC0U + static void avr_dp_unref(AVR_DP_t *dp) { if (--(dp->refcnt) == 0) free(dp); } -void avr_dp_init(AVR_DP_t *dp) +bool avr_dp_init(AVR_DP_t *dp) +{ + /* Check for a valid part number in the IDCode */ + if ((dp->idcode & 0x0FFFF000) == 0) { + DEBUG_WARN("Invalid DP idcode %08" PRIx32 "\n", dp->idcode); + free(dp); + return false; + } + DEBUG_INFO("AVR ID 0x%08" PRIx32 " (v%d)\n", dp->idcode, + (uint8_t)((dp->idcode >> 28U) & 0xfU)); + jtag_dev_write_ir(&jtag_proc, dp->dp_jd_index, IR_PDI); + return true; +} + +static bool avr_dev_shift_dr(jtag_proc_t *jp, uint8_t jd_index, uint8_t *dout, const uint8_t din) +{ + jtag_dev_t *d = &jtag_devs[jd_index]; + uint8_t result = 0; + uint16_t request = 0, response = 0; + uint8_t *data = (uint8_t *)&request; + if (!dout) + return false; + jtagtap_shift_dr(); + jp->jtagtap_tdi_seq(0, ones, d->dr_prescan); + data[0] = din; + // Calculate the parity bit + for (uint8_t i = 0; i < 8; ++i) + data[1] ^= (din >> i) & 1U; + jp->jtagtap_tdi_tdo_seq((uint8_t *)&response, 1, (uint8_t *)&request, 9); + jp->jtagtap_tdi_seq(1, ones, d->dr_postscan); + jtagtap_return_idle(); + data = (uint8_t *)&response; + // Calculate the parity bit + for (uint8_t i = 0; i < 8; ++i) + result ^= (data[0] >> i) & 1U; + *dout = data[0]; + return result == data[1]; +} + +bool avr_pdi_reg_write(AVR_DP_t *dp, uint8_t reg, uint8_t value) +{ + uint8_t result = 0, command = PDI_STCS | reg; + if (reg >= 16 || + avr_dev_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || + result != PDI_EMPTY || + avr_dev_shift_dr(&jtag_proc, dp->dp_jd_index, &result, value)) + return false; + return result == PDI_EMPTY; +} + +uint8_t avr_pdi_reg_read(AVR_DP_t *dp, uint8_t reg) { - (void)dp; + uint8_t result = 0, command = PDI_LDCS | reg; + if (reg >= 16 || + avr_dev_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || + result != PDI_EMPTY || + !avr_dev_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command)) + return 0xFFU; // TODO - figure out a better way to indicate failure. + return result; } diff --git a/src/target/jtag_scan.c b/src/target/jtag_scan.c index fd9b9f5e026..42966c15c39 100644 --- a/src/target/jtag_scan.c +++ b/src/target/jtag_scan.c @@ -35,7 +35,7 @@ struct jtag_dev_s jtag_devs[JTAG_MAX_DEVS+1]; int jtag_dev_count; /* bucket of ones for don't care TDI */ -static const uint8_t ones[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; +const uint8_t ones[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; #if PC_HOSTED == 0 void jtag_add_device(const int dev_index, const jtag_dev_t *jtag_dev) diff --git a/src/target/jtag_scan.h b/src/target/jtag_scan.h index cc6d361a2c2..67449dd0eee 100644 --- a/src/target/jtag_scan.h +++ b/src/target/jtag_scan.h @@ -42,6 +42,7 @@ typedef struct jtag_dev_s { extern struct jtag_dev_s jtag_devs[JTAG_MAX_DEVS+1]; extern int jtag_dev_count; +extern const uint8_t ones[9]; void jtag_dev_write_ir(jtag_proc_t *jp, uint8_t jd_index, uint32_t ir); void jtag_dev_shift_dr(jtag_proc_t *jp, uint8_t jd_index, uint8_t *dout, const uint8_t *din, int ticks); From 52b6112485fb22aad6c68347b2f1e20e0d515ab6 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 11 Dec 2021 14:12:08 -0500 Subject: [PATCH 06/56] atxmega: Created a probing routine for the ATXMega series linup to correctly add Flash and SRAM regions for the devices --- src/target/atxmega.c | 19 +++++++++++++++++++ src/target/avr.h | 2 ++ src/target/avr_pdi.c | 15 +++++++++++++++ src/target/target_internal.h | 2 ++ 4 files changed, 38 insertions(+) diff --git a/src/target/atxmega.c b/src/target/atxmega.c index e69de29bb2d..4c89e6a0edf 100644 --- a/src/target/atxmega.c +++ b/src/target/atxmega.c @@ -0,0 +1,19 @@ +#include "general.h" +#include "target.h" +#include "target_internal.h" +#include "avr.h" + +#define IDCODE_XMEGA256A3U 0x9842U + +bool atxmega_probe(target *t) +{ + switch (t->idcode) { + case IDCODE_XMEGA256A3U: + t->core = "ATXMega256A3U"; + target_add_ram(t, 0x01002000, 0x01002800); + avr_add_flash(t, 0x00800000, 0x40000); + avr_add_flash(t, 0x00840000, 0x2000); + return true; + } + return false; +} diff --git a/src/target/avr.h b/src/target/avr.h index b54f67f7c9d..9354aa9c969 100644 --- a/src/target/avr.h +++ b/src/target/avr.h @@ -2,6 +2,7 @@ #define ATMEL___H #include "jtag_scan.h" +#include "target.h" typedef struct Atmel_DP_s { int refcnt; @@ -15,6 +16,7 @@ bool avr_dp_init(AVR_DP_t *dp); void avr_jtag_dp_handler(uint8_t jd_index, uint32_t j_idcode); int platform_avr_jtag_dp_init(AVR_DP_t *dp); +void avr_add_flash(target *t, uint32_t start, size_t length); bool avr_pdi_reg_write(AVR_DP_t *dp, uint8_t reg, uint8_t value); uint8_t avr_pdi_reg_read(AVR_DP_t *dp, uint8_t reg); diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index 2c694f9214b..8b8eebe2972 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -32,6 +32,21 @@ bool avr_dp_init(AVR_DP_t *dp) return true; } +void avr_add_flash(target *t, uint32_t start, size_t length) +{ + struct target_flash *f = calloc(1, sizeof(*f)); + if (!f) { /* calloc failed: heap exhaustion */ + DEBUG_WARN("calloc: failed in %s\n", __func__); + return; + } + + f->start = start; + f->length = length; + f->blocksize = 0x100; + f->erased = 0xff; + target_add_flash(t, f); +} + static bool avr_dev_shift_dr(jtag_proc_t *jp, uint8_t jd_index, uint8_t *dout, const uint8_t din) { jtag_dev_t *d = &jtag_devs[jd_index]; diff --git a/src/target/target_internal.h b/src/target/target_internal.h index 883d3b57313..b2c65d0d818 100644 --- a/src/target/target_internal.h +++ b/src/target/target_internal.h @@ -201,4 +201,6 @@ bool efm32_probe(target *t); bool msp432_probe(target *t); bool ke04_probe(target *t); bool rp_probe(target *t); + +bool atxmega_probe(target *t); #endif From 38889a1c14d30cddb74ad3314043e72f96643a25 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 11 Dec 2021 14:12:53 -0500 Subject: [PATCH 07/56] avr_pdi: Enabled the creation of a valid target to attach to in the JTAG-PDI logic --- src/target/avr_pdi.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index 8b8eebe2972..ecaf46e2a53 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -3,6 +3,7 @@ #include "target_internal.h" #include "avr.h" #include "exception.h" +#include "gdb_packet.h" #define IR_PDI 0x7U #define PDI_BREAK 0xBBU @@ -12,6 +13,11 @@ #define PDI_LDCS 0x80U #define PDI_STCS 0xC0U +static void avr_dp_ref(AVR_DP_t *dp) +{ + dp->refcnt++; +} + static void avr_dp_unref(AVR_DP_t *dp) { if (--(dp->refcnt) == 0) @@ -20,6 +26,8 @@ static void avr_dp_unref(AVR_DP_t *dp) bool avr_dp_init(AVR_DP_t *dp) { + target *t; + /* Check for a valid part number in the IDCode */ if ((dp->idcode & 0x0FFFF000) == 0) { DEBUG_WARN("Invalid DP idcode %08" PRIx32 "\n", dp->idcode); @@ -29,6 +37,19 @@ bool avr_dp_init(AVR_DP_t *dp) DEBUG_INFO("AVR ID 0x%08" PRIx32 " (v%d)\n", dp->idcode, (uint8_t)((dp->idcode >> 28U) & 0xfU)); jtag_dev_write_ir(&jtag_proc, dp->dp_jd_index, IR_PDI); + + t = target_new(); + if (!t) + return false; + avr_dp_ref(dp); + + t->cpuid = dp->idcode; + t->idcode = (dp->idcode >> 12) & 0xFFFFU; + t->priv = dp; + t->driver = "Atmel AVR"; + t->core = "AVR"; + if (atxmega_probe(t)) + return true; return true; } From f2c63845b0b9eacc968b2b8305241ababdc6ed02 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 11 Dec 2021 14:14:19 -0500 Subject: [PATCH 08/56] jtag-pdi: Fixed an issue the way the JTAG handlers are called with the masked ID code causes for the AVR logic --- src/target/avr_jtagdp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/target/avr_jtagdp.c b/src/target/avr_jtagdp.c index af8fa5c7002..5f6d790eb5f 100644 --- a/src/target/avr_jtagdp.c +++ b/src/target/avr_jtagdp.c @@ -11,9 +11,10 @@ void avr_jtag_dp_handler(uint8_t jd_index, uint32_t j_idcode) DEBUG_WARN("calloc: failed in %s\n", __func__); return; } + (void)j_idcode; dp->dp_jd_index = jd_index; - dp->idcode = j_idcode; + dp->idcode = jtag_devs[jd_index].jd_idcode; if ((PC_HOSTED == 0) || (!platform_avr_jtag_dp_init(dp))) { // } From 39964b6e4a5956942c18a3ebf7493ed1d2b0f75e Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 11 Dec 2021 14:17:35 -0500 Subject: [PATCH 09/56] avr_pdi: Done some reorganisation to make the layout of the AVR targeting logic make a bit more sense --- src/target/avr.h | 1 + src/target/avr_jtagdp.c | 25 +++++++++++++++++++++++++ src/target/avr_pdi.c | 33 ++++----------------------------- 3 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/target/avr.h b/src/target/avr.h index 9354aa9c969..c010cae4b5c 100644 --- a/src/target/avr.h +++ b/src/target/avr.h @@ -18,6 +18,7 @@ void avr_jtag_dp_handler(uint8_t jd_index, uint32_t j_idcode); int platform_avr_jtag_dp_init(AVR_DP_t *dp); void avr_add_flash(target *t, uint32_t start, size_t length); +bool avr_jtag_shift_dr(jtag_proc_t *jp, uint8_t jd_index, uint8_t *dout, const uint8_t din); bool avr_pdi_reg_write(AVR_DP_t *dp, uint8_t reg, uint8_t value); uint8_t avr_pdi_reg_read(AVR_DP_t *dp, uint8_t reg); diff --git a/src/target/avr_jtagdp.c b/src/target/avr_jtagdp.c index 5f6d790eb5f..f9f99d140a0 100644 --- a/src/target/avr_jtagdp.c +++ b/src/target/avr_jtagdp.c @@ -20,3 +20,28 @@ void avr_jtag_dp_handler(uint8_t jd_index, uint32_t j_idcode) } avr_dp_init(dp); } + +bool avr_jtag_shift_dr(jtag_proc_t *jp, uint8_t jd_index, uint8_t *dout, const uint8_t din) +{ + jtag_dev_t *d = &jtag_devs[jd_index]; + uint8_t result = 0; + uint16_t request = 0, response = 0; + uint8_t *data = (uint8_t *)&request; + if (!dout) + return false; + jtagtap_shift_dr(); + jp->jtagtap_tdi_seq(0, ones, d->dr_prescan); + data[0] = din; + // Calculate the parity bit + for (uint8_t i = 0; i < 8; ++i) + data[1] ^= (din >> i) & 1U; + jp->jtagtap_tdi_tdo_seq((uint8_t *)&response, 1, (uint8_t *)&request, 9); + jp->jtagtap_tdi_seq(1, ones, d->dr_postscan); + jtagtap_return_idle(); + data = (uint8_t *)&response; + // Calculate the parity bit + for (uint8_t i = 0; i < 8; ++i) + result ^= (data[0] >> i) & 1U; + *dout = data[0]; + return result == data[1]; +} diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index ecaf46e2a53..0ddd61c8e54 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -68,38 +68,13 @@ void avr_add_flash(target *t, uint32_t start, size_t length) target_add_flash(t, f); } -static bool avr_dev_shift_dr(jtag_proc_t *jp, uint8_t jd_index, uint8_t *dout, const uint8_t din) -{ - jtag_dev_t *d = &jtag_devs[jd_index]; - uint8_t result = 0; - uint16_t request = 0, response = 0; - uint8_t *data = (uint8_t *)&request; - if (!dout) - return false; - jtagtap_shift_dr(); - jp->jtagtap_tdi_seq(0, ones, d->dr_prescan); - data[0] = din; - // Calculate the parity bit - for (uint8_t i = 0; i < 8; ++i) - data[1] ^= (din >> i) & 1U; - jp->jtagtap_tdi_tdo_seq((uint8_t *)&response, 1, (uint8_t *)&request, 9); - jp->jtagtap_tdi_seq(1, ones, d->dr_postscan); - jtagtap_return_idle(); - data = (uint8_t *)&response; - // Calculate the parity bit - for (uint8_t i = 0; i < 8; ++i) - result ^= (data[0] >> i) & 1U; - *dout = data[0]; - return result == data[1]; -} - bool avr_pdi_reg_write(AVR_DP_t *dp, uint8_t reg, uint8_t value) { uint8_t result = 0, command = PDI_STCS | reg; if (reg >= 16 || - avr_dev_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || result != PDI_EMPTY || - avr_dev_shift_dr(&jtag_proc, dp->dp_jd_index, &result, value)) + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, value)) return false; return result == PDI_EMPTY; } @@ -108,9 +83,9 @@ uint8_t avr_pdi_reg_read(AVR_DP_t *dp, uint8_t reg) { uint8_t result = 0, command = PDI_LDCS | reg; if (reg >= 16 || - avr_dev_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || result != PDI_EMPTY || - !avr_dev_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command)) + !avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command)) return 0xFFU; // TODO - figure out a better way to indicate failure. return result; } From d6f6ba568166be50a13b2494e13dac6fc1ddf8c3 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 11 Dec 2021 14:21:43 -0500 Subject: [PATCH 10/56] avr: Moved some code around and begun implementing the attach and detach phases to see if we can make scanning reliable --- src/target/avr.h | 5 ++++- src/target/avr_pdi.c | 52 ++++++++++++++++++++++++++++++-------------- 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/src/target/avr.h b/src/target/avr.h index c010cae4b5c..9fd8dbe147d 100644 --- a/src/target/avr.h +++ b/src/target/avr.h @@ -16,10 +16,13 @@ bool avr_dp_init(AVR_DP_t *dp); void avr_jtag_dp_handler(uint8_t jd_index, uint32_t j_idcode); int platform_avr_jtag_dp_init(AVR_DP_t *dp); -void avr_add_flash(target *t, uint32_t start, size_t length); bool avr_jtag_shift_dr(jtag_proc_t *jp, uint8_t jd_index, uint8_t *dout, const uint8_t din); bool avr_pdi_reg_write(AVR_DP_t *dp, uint8_t reg, uint8_t value); uint8_t avr_pdi_reg_read(AVR_DP_t *dp, uint8_t reg); +bool avr_attach(target *t); +void avr_detach(target *t); +void avr_add_flash(target *t, uint32_t start, size_t length); + #endif /*ATMEL___H*/ diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index 0ddd61c8e54..686b1aa3992 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -6,6 +6,8 @@ #include "gdb_packet.h" #define IR_PDI 0x7U +#define IR_BYPASS 0xFU + #define PDI_BREAK 0xBBU #define PDI_DELAY 0xDBU #define PDI_EMPTY 0xEBU @@ -36,7 +38,7 @@ bool avr_dp_init(AVR_DP_t *dp) } DEBUG_INFO("AVR ID 0x%08" PRIx32 " (v%d)\n", dp->idcode, (uint8_t)((dp->idcode >> 28U) & 0xfU)); - jtag_dev_write_ir(&jtag_proc, dp->dp_jd_index, IR_PDI); + jtag_dev_write_ir(&jtag_proc, dp->dp_jd_index, IR_BYPASS); t = target_new(); if (!t) @@ -48,26 +50,15 @@ bool avr_dp_init(AVR_DP_t *dp) t->priv = dp; t->driver = "Atmel AVR"; t->core = "AVR"; + + t->attach = avr_attach; + t->detach = avr_detach; + if (atxmega_probe(t)) return true; return true; } -void avr_add_flash(target *t, uint32_t start, size_t length) -{ - struct target_flash *f = calloc(1, sizeof(*f)); - if (!f) { /* calloc failed: heap exhaustion */ - DEBUG_WARN("calloc: failed in %s\n", __func__); - return; - } - - f->start = start; - f->length = length; - f->blocksize = 0x100; - f->erased = 0xff; - target_add_flash(t, f); -} - bool avr_pdi_reg_write(AVR_DP_t *dp, uint8_t reg, uint8_t value) { uint8_t result = 0, command = PDI_STCS | reg; @@ -89,3 +80,32 @@ uint8_t avr_pdi_reg_read(AVR_DP_t *dp, uint8_t reg) return 0xFFU; // TODO - figure out a better way to indicate failure. return result; } + +void avr_add_flash(target *t, uint32_t start, size_t length) +{ + struct target_flash *f = calloc(1, sizeof(*f)); + if (!f) { /* calloc failed: heap exhaustion */ + DEBUG_WARN("calloc: failed in %s\n", __func__); + return; + } + + f->start = start; + f->length = length; + f->blocksize = 0x100; + f->erased = 0xff; + target_add_flash(t, f); +} + +bool avr_attach(target *t) +{ + AVR_DP_t *dp = t->priv; + jtag_dev_write_ir(&jtag_proc, dp->dp_jd_index, IR_PDI); + + return true; +} + +void avr_detach(target *t) +{ + AVR_DP_t *dp = t->priv; + jtag_dev_write_ir(&jtag_proc, dp->dp_jd_index, IR_BYPASS); +} From c98ed53607995e5a05e74824d4fc74d6475749ab Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 18 Dec 2021 17:03:53 -0500 Subject: [PATCH 11/56] avr: Added support for target_halt_poll --- src/target/avr.h | 1 + src/target/avr_pdi.c | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/src/target/avr.h b/src/target/avr.h index 9fd8dbe147d..8a471f9b972 100644 --- a/src/target/avr.h +++ b/src/target/avr.h @@ -10,6 +10,7 @@ typedef struct Atmel_DP_s { uint32_t idcode; uint8_t dp_jd_index; + enum target_halt_reason halt_reason; } AVR_DP_t; bool avr_dp_init(AVR_DP_t *dp); diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index 686b1aa3992..6d6b2be7673 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -15,6 +15,8 @@ #define PDI_LDCS 0x80U #define PDI_STCS 0xC0U +static enum target_halt_reason avr_halt_poll(target *t, target_addr *watch); + static void avr_dp_ref(AVR_DP_t *dp) { dp->refcnt++; @@ -53,9 +55,11 @@ bool avr_dp_init(AVR_DP_t *dp) t->attach = avr_attach; t->detach = avr_detach; + t->halt_poll = avr_halt_poll; if (atxmega_probe(t)) return true; + dp->halt_reason = TARGET_HALT_RUNNING; return true; } @@ -109,3 +113,10 @@ void avr_detach(target *t) AVR_DP_t *dp = t->priv; jtag_dev_write_ir(&jtag_proc, dp->dp_jd_index, IR_BYPASS); } + +static enum target_halt_reason avr_halt_poll(target *t, target_addr *watch) +{ + AVR_DP_t *dp = t->priv; + (void)watch; + return dp->halt_reason; +} From 18971f59549644331c8b5960f484c54b227087cf Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 18 Dec 2021 17:04:46 -0500 Subject: [PATCH 12/56] avr: Added support for target_reset --- src/target/avr_pdi.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index 6d6b2be7673..51ff701838a 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -15,6 +15,15 @@ #define PDI_LDCS 0x80U #define PDI_STCS 0xC0U +#define PDI_REG_STATUS 0U +#define PDI_REG_RESET 1U +#define PDI_REG_CTRL 2U +#define PDI_REG_R3 3U +#define PDI_REG_R4 4U + +#define PDI_RESET 0x59U + +static void avr_reset(target *t); static enum target_halt_reason avr_halt_poll(target *t, target_addr *watch); static void avr_dp_ref(AVR_DP_t *dp) @@ -114,6 +123,14 @@ void avr_detach(target *t) jtag_dev_write_ir(&jtag_proc, dp->dp_jd_index, IR_BYPASS); } +static void avr_reset(target *t) +{ + AVR_DP_t *dp = t->priv; + if (!avr_pdi_reg_write(dp, PDI_REG_RESET, PDI_RESET) || + avr_pdi_reg_read(dp, PDI_REG_STATUS) != 0x00) + raise_exception(EXCEPTION_ERROR, "Error resetting device, device in incorrect state\n"); +} + static enum target_halt_reason avr_halt_poll(target *t, target_addr *watch) { AVR_DP_t *dp = t->priv; From 211ead12fc1aa0ed51b0d1595da7e17922b65aa0 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 18 Dec 2021 17:06:07 -0500 Subject: [PATCH 13/56] avr: Added support for target_halt_request --- src/target/avr_pdi.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index 51ff701838a..7770c00a01b 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -24,6 +24,7 @@ #define PDI_RESET 0x59U static void avr_reset(target *t); +static void avr_halt_request(target *t); static enum target_halt_reason avr_halt_poll(target *t, target_addr *watch); static void avr_dp_ref(AVR_DP_t *dp) @@ -64,6 +65,8 @@ bool avr_dp_init(AVR_DP_t *dp) t->attach = avr_attach; t->detach = avr_detach; + t->reset = avr_reset; + t->halt_request = avr_halt_request; t->halt_poll = avr_halt_poll; if (atxmega_probe(t)) @@ -131,6 +134,26 @@ static void avr_reset(target *t) raise_exception(EXCEPTION_ERROR, "Error resetting device, device in incorrect state\n"); } +static void avr_halt_request(target *t) +{ + AVR_DP_t *dp = t->priv; + /* To halt the processor we go through a few really specific steps: + * Write r4 to 1 to indicate we want to put the processor into debug-based pause + * Read r3 and check it's 0x10 which indicates the processor is held in reset and no debugging is active + * Releae reset + * Read r3 twice more, the first time should respond 0x14 to indicate the processor is still reset + * but that debug pause is requested, and the second should respond 0x04 to indicate the processor is now + * in debug pause state (halted) + */ + if (!avr_pdi_reg_write(dp, PDI_REG_R4, 1) || + avr_pdi_reg_read(dp, PDI_REG_R3) != 0x10U || + !avr_pdi_reg_write(dp, PDI_REG_RESET, 0) || + avr_pdi_reg_read(dp, PDI_REG_R3) != 0x14U || + avr_pdi_reg_read(dp, PDI_REG_R3) != 0x04U) + raise_exception(EXCEPTION_ERROR, "Error halting device, device in incorrect state\n"); + dp->halt_reason = TARGET_HALT_REQUEST; +} + static enum target_halt_reason avr_halt_poll(target *t, target_addr *watch) { AVR_DP_t *dp = t->priv; From a248d44f85f28579cb1eb78b667278ef9bbee76e Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 18 Dec 2021 17:06:45 -0500 Subject: [PATCH 14/56] avr: Added support for enabling/disabling the debug and programming states of the PDI controller --- src/target/avr_pdi.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index 7770c00a01b..58de9b5b956 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -14,6 +14,7 @@ #define PDI_LDCS 0x80U #define PDI_STCS 0xC0U +#define PDI_KEY 0xE0U #define PDI_REG_STATUS 0U #define PDI_REG_RESET 1U @@ -23,6 +24,15 @@ #define PDI_RESET 0x59U +typedef enum +{ + PDI_PROG = 0x02U, + PDI_DEBUG = 0x04U, +} pdi_key_e; + +static const char pdi_key_prog[] = {0xff, 0x88, 0xd8, 0xcd, 0x45, 0xab, 0x89, 0x12}; +static const char pdi_key_debug[] = {0x21, 0x81, 0x7c, 0x9f, 0xd4, 0x2d, 0x21, 0x3a}; + static void avr_reset(target *t); static void avr_halt_request(target *t); static enum target_halt_reason avr_halt_poll(target *t, target_addr *watch); @@ -97,6 +107,27 @@ uint8_t avr_pdi_reg_read(AVR_DP_t *dp, uint8_t reg) return result; } +bool avr_enable(AVR_DP_t *dp, pdi_key_e what) +{ + const char *const key = what == PDI_DEBUG ? pdi_key_debug : pdi_key_prog; + uint8_t result = 0; + if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, PDI_KEY) || + result != PDI_EMPTY) + return false; + for (uint8_t i = 0; i < 8; ++i) + { + if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, key[i]) || + result != PDI_EMPTY) + return false; + } + return (avr_pdi_reg_read(dp, PDI_REG_STATUS) & what) == what; +} + +bool avr_disable(AVR_DP_t *dp, pdi_key_e what) +{ + return avr_pdi_reg_write(dp, PDI_REG_STATUS, ~what); +} + void avr_add_flash(target *t, uint32_t start, size_t length) { struct target_flash *f = calloc(1, sizeof(*f)); From 0a4832b36a59c8e5513a05569575a95bc2d940b5 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 18 Dec 2021 17:06:56 -0500 Subject: [PATCH 15/56] avr: Begun fleshing out attach/detach --- src/target/avr_pdi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index 58de9b5b956..87e16fe90b3 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -147,6 +147,9 @@ bool avr_attach(target *t) { AVR_DP_t *dp = t->priv; jtag_dev_write_ir(&jtag_proc, dp->dp_jd_index, IR_PDI); + target_reset(t); + avr_enable(dp, PDI_DEBUG); + target_halt_request(t); return true; } @@ -154,6 +157,8 @@ bool avr_attach(target *t) void avr_detach(target *t) { AVR_DP_t *dp = t->priv; + + avr_disable(dp, PDI_DEBUG); jtag_dev_write_ir(&jtag_proc, dp->dp_jd_index, IR_BYPASS); } From dcf006c94badccb9aeb96846295c30267735cb5b Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 18 Dec 2021 19:27:17 -0500 Subject: [PATCH 16/56] avr: Fixed the avr_attach error handling --- src/target/avr_pdi.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index 87e16fe90b3..49baf2e1c39 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -75,6 +75,7 @@ bool avr_dp_init(AVR_DP_t *dp) t->attach = avr_attach; t->detach = avr_detach; + t->reset = avr_reset; t->halt_request = avr_halt_request; t->halt_poll = avr_halt_poll; @@ -102,7 +103,7 @@ uint8_t avr_pdi_reg_read(AVR_DP_t *dp, uint8_t reg) if (reg >= 16 || avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || result != PDI_EMPTY || - !avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command)) + !avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, 0)) return 0xFFU; // TODO - figure out a better way to indicate failure. return result; } @@ -146,12 +147,16 @@ void avr_add_flash(target *t, uint32_t start, size_t length) bool avr_attach(target *t) { AVR_DP_t *dp = t->priv; + volatile struct exception e; jtag_dev_write_ir(&jtag_proc, dp->dp_jd_index, IR_PDI); - target_reset(t); - avr_enable(dp, PDI_DEBUG); - target_halt_request(t); - return true; + TRY_CATCH (e, EXCEPTION_ALL) { + target_reset(t); + if (!avr_enable(dp, PDI_DEBUG)) + return false; + target_halt_request(t); + } + return !e.type; } void avr_detach(target *t) @@ -167,7 +172,7 @@ static void avr_reset(target *t) AVR_DP_t *dp = t->priv; if (!avr_pdi_reg_write(dp, PDI_REG_RESET, PDI_RESET) || avr_pdi_reg_read(dp, PDI_REG_STATUS) != 0x00) - raise_exception(EXCEPTION_ERROR, "Error resetting device, device in incorrect state\n"); + raise_exception(EXCEPTION_ERROR, "Error resetting device, device in incorrect state"); } static void avr_halt_request(target *t) @@ -186,7 +191,7 @@ static void avr_halt_request(target *t) !avr_pdi_reg_write(dp, PDI_REG_RESET, 0) || avr_pdi_reg_read(dp, PDI_REG_R3) != 0x14U || avr_pdi_reg_read(dp, PDI_REG_R3) != 0x04U) - raise_exception(EXCEPTION_ERROR, "Error halting device, device in incorrect state\n"); + raise_exception(EXCEPTION_ERROR, "Error halting device, device in incorrect state"); dp->halt_reason = TARGET_HALT_REQUEST; } From d3a8156efc238c26671a44513c2d90e2b71cf335 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 18 Dec 2021 19:28:25 -0500 Subject: [PATCH 17/56] avr: Added debug logging to avr_jtag_shift_dr --- src/target/avr_jtagdp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/target/avr_jtagdp.c b/src/target/avr_jtagdp.c index f9f99d140a0..a76930edd81 100644 --- a/src/target/avr_jtagdp.c +++ b/src/target/avr_jtagdp.c @@ -43,5 +43,6 @@ bool avr_jtag_shift_dr(jtag_proc_t *jp, uint8_t jd_index, uint8_t *dout, const u for (uint8_t i = 0; i < 8; ++i) result ^= (data[0] >> i) & 1U; *dout = data[0]; + DEBUG_INFO("Sent 0x%x to target, response was 0x%x (0x%x)\n", din, data[0], data[1]); return result == data[1]; } From 6357a9d6ae730ec7fba7b076d3367ec4222e4d3c Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 18 Dec 2021 19:29:07 -0500 Subject: [PATCH 18/56] avr: Added the register size descriptor --- src/target/avr_pdi.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index 49baf2e1c39..1c96bcd29eb 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -37,6 +37,14 @@ static void avr_reset(target *t); static void avr_halt_request(target *t); static enum target_halt_reason avr_halt_poll(target *t, target_addr *watch); +static const uint32_t regnum_avr[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // r0-r15 + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, // r16-31 + 32, // SREG + 33, // SP + 34, // PC +}; + static void avr_dp_ref(AVR_DP_t *dp) { dp->refcnt++; @@ -79,6 +87,7 @@ bool avr_dp_init(AVR_DP_t *dp) t->reset = avr_reset; t->halt_request = avr_halt_request; t->halt_poll = avr_halt_poll; + t->regs_size = sizeof(regnum_avr); if (atxmega_probe(t)) return true; From 7fe0dc6ff4287ade300238c7627b695bd8bc3a44 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 18 Dec 2021 21:40:00 -0500 Subject: [PATCH 19/56] atxmega: Added register definitions for the xmega6 lineup --- src/target/atxmega.c | 45 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/target/atxmega.c b/src/target/atxmega.c index 4c89e6a0edf..e47d783ad5d 100644 --- a/src/target/atxmega.c +++ b/src/target/atxmega.c @@ -5,6 +5,50 @@ #define IDCODE_XMEGA256A3U 0x9842U +static const char tdesc_xmega6[] = + "" + "" + "" + " avr:106" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; + bool atxmega_probe(target *t) { switch (t->idcode) { @@ -13,6 +57,7 @@ bool atxmega_probe(target *t) target_add_ram(t, 0x01002000, 0x01002800); avr_add_flash(t, 0x00800000, 0x40000); avr_add_flash(t, 0x00840000, 0x2000); + t->tdesc = tdesc_xmega6; return true; } return false; From c01f72578c5de0ebd3f3928beb5f0a9746ddf491 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 18 Dec 2021 21:40:58 -0500 Subject: [PATCH 20/56] avr: Corrected the target register count field for the actual length of the registers block --- src/target/avr_pdi.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index 1c96bcd29eb..ec235dd18fb 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -37,13 +37,13 @@ static void avr_reset(target *t); static void avr_halt_request(target *t); static enum target_halt_reason avr_halt_poll(target *t, target_addr *watch); -static const uint32_t regnum_avr[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // r0-r15 - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, // r16-31 - 32, // SREG - 33, // SP - 34, // PC -}; +typedef struct __attribute__((packed)) +{ + uint8_t general[32]; // r0-r31 + uint8_t sreg; // r32 + uint16_t sp; // r33 + uint32_t pc; // r34 +} avr_regs; static void avr_dp_ref(AVR_DP_t *dp) { @@ -87,7 +87,9 @@ bool avr_dp_init(AVR_DP_t *dp) t->reset = avr_reset; t->halt_request = avr_halt_request; t->halt_poll = avr_halt_poll; - t->regs_size = sizeof(regnum_avr); + // Unlike on an ARM processor, where this is the length of a table, here we return the size of + // a suitable registers structure. + t->regs_size = sizeof(avr_regs); if (atxmega_probe(t)) return true; From 6ef59e9f56be98ef820235eead0a233a00d51518 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 18 Dec 2021 21:42:46 -0500 Subject: [PATCH 21/56] avr: Created a first-pass at routines for reading/writing the AVR address space --- src/target/avr_pdi.c | 119 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 109 insertions(+), 10 deletions(-) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index ec235dd18fb..f79d48e95bd 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -12,9 +12,23 @@ #define PDI_DELAY 0xDBU #define PDI_EMPTY 0xEBU +#define PDI_LDS 0x00U +#define PDI_LD 0x20U +#define PDI_STS 0x40U +#define PDI_ST 0x60U #define PDI_LDCS 0x80U -#define PDI_STCS 0xC0U -#define PDI_KEY 0xE0U +#define PDI_STCS 0xc0U +#define PDI_KEY 0xe0U + +#define PDI_DATA_8 0x00U +#define PDI_DATA_16 0x01U +#define PDI_DATA_24 0x02U +#define PDI_DATA_32 0x03U + +#define PDI_ADDR_8 0x00U +#define PDI_ADDR_16 0x04U +#define PDI_ADDR_24 0x08U +#define PDI_ADDR_32 0x0cU #define PDI_REG_STATUS 0U #define PDI_REG_RESET 1U @@ -101,8 +115,7 @@ bool avr_pdi_reg_write(AVR_DP_t *dp, uint8_t reg, uint8_t value) { uint8_t result = 0, command = PDI_STCS | reg; if (reg >= 16 || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || - result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || result != PDI_EMPTY || avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, value)) return false; return result == PDI_EMPTY; @@ -112,24 +125,110 @@ uint8_t avr_pdi_reg_read(AVR_DP_t *dp, uint8_t reg) { uint8_t result = 0, command = PDI_LDCS | reg; if (reg >= 16 || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || - result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || result != PDI_EMPTY || !avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, 0)) return 0xFFU; // TODO - figure out a better way to indicate failure. return result; } +bool avr_pdi_st8(AVR_DP_t *dp, uint32_t reg, uint8_t data) +{ + uint8_t result = 0, command = PDI_STS | PDI_ADDR_32 | PDI_DATA_8; + if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, reg & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 8U) & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 16U) & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 24U) & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, data)) + return false; + return result == PDI_EMPTY; +} + +uint8_t avr_pdi_ld8(AVR_DP_t *dp, uint32_t reg) +{ + uint8_t result = 0, command = PDI_LDS | PDI_ADDR_32 | PDI_DATA_8; + uint8_t data[1]; + if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, reg & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 8U) & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 16U) & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 24U) & 0xffU) || result != PDI_EMPTY || + !avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, data, 0)) + return 0xFFU; // TODO - figure out a better way to indicate failure. + return data[0]; +} + +bool avr_pdi_st16(AVR_DP_t *dp, uint32_t reg, uint16_t data) +{ + uint8_t result = 0, command = PDI_STS | PDI_ADDR_32 | PDI_DATA_16; + if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, reg & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 8U) & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 16U) & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 24U) & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, data & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (data >> 8U) & 0xffU)) + return false; + return result == PDI_EMPTY; +} + +uint16_t avr_pdi_ld16(AVR_DP_t *dp, uint32_t reg) +{ + uint8_t result = 0, command = PDI_LDS | PDI_ADDR_32 | PDI_DATA_16; + uint8_t data[2]; + if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, reg & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 8U) & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 16U) & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 24U) & 0xffU) || result != PDI_EMPTY || + !avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, data + 0, 0) || + !avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, data + 1, 0)) + return 0xFFFFU; // TODO - figure out a better way to indicate failure. + return data[0] | (data[1] << 8U); +} + +bool avr_pdi_st32(AVR_DP_t *dp, uint32_t reg, uint32_t data) +{ + uint8_t result = 0, command = PDI_STS | PDI_ADDR_32 | PDI_DATA_32; + if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, reg & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 8U) & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 16U) & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 24U) & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, data & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (data >> 8U) & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (data >> 16U) & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (data >> 24U) & 0xffU)) + return false; + return result == PDI_EMPTY; +} + +uint32_t avr_pdi_ld32(AVR_DP_t *dp, uint32_t reg) +{ + uint8_t result = 0, command = PDI_LDS | PDI_ADDR_32 | PDI_DATA_32; + uint8_t data[4]; + if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, reg & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 8U) & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 16U) & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 24U) & 0xffU) || result != PDI_EMPTY || + !avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, data + 0, 0) || + !avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, data + 1, 0) || + !avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, data + 2, 0) || + !avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, data + 3, 0)) + return 0xFFFFU; // TODO - figure out a better way to indicate failure. + return data[0] | (data[1] << 8U) | (data[2] << 16U) | (data[3] << 24U); +} + bool avr_enable(AVR_DP_t *dp, pdi_key_e what) { const char *const key = what == PDI_DEBUG ? pdi_key_debug : pdi_key_prog; uint8_t result = 0; - if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, PDI_KEY) || - result != PDI_EMPTY) + if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, PDI_KEY) || result != PDI_EMPTY) return false; for (uint8_t i = 0; i < 8; ++i) { - if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, key[i]) || - result != PDI_EMPTY) + if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, key[i]) || result != PDI_EMPTY) return false; } return (avr_pdi_reg_read(dp, PDI_REG_STATUS) & what) == what; From 06767bf2549e6bedc3ea77f0e77c283ede53fcdd Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 18 Dec 2021 21:44:09 -0500 Subject: [PATCH 22/56] avr: Implemented arbitrary processor-space memory block reading --- src/target/avr_pdi.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index f79d48e95bd..7e72e49cd22 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -17,6 +17,7 @@ #define PDI_STS 0x40U #define PDI_ST 0x60U #define PDI_LDCS 0x80U +#define PDI_REPEAT 0xa0U #define PDI_STCS 0xc0U #define PDI_KEY 0xe0U @@ -30,6 +31,12 @@ #define PDI_ADDR_24 0x08U #define PDI_ADDR_32 0x0cU +#define PDI_MODE_IND_PTR 0x00U +#define PDI_MODE_IND_INCPTR 0x04U +#define PDI_MODE_DIR_PTR 0x08U +#define PDI_MODE_DIR_INCPTR 0x0cU // "Reserved" +#define PDI_MODE_MASK 0xf3U + #define PDI_REG_STATUS 0U #define PDI_REG_RESET 1U #define PDI_REG_CTRL 2U @@ -220,6 +227,41 @@ uint32_t avr_pdi_ld32(AVR_DP_t *dp, uint32_t reg) return data[0] | (data[1] << 8U) | (data[2] << 16U) | (data[3] << 24U); } +bool avr_pdi_read(AVR_DP_t *dp, uint32_t addr, uint8_t ptr_mode, void *dst, uint32_t count) +{ + const uint32_t repeat = count - 1U; + uint8_t result = 0, command; + uint8_t *data = (uint8_t *)dst; + if ((ptr_mode & PDI_MODE_MASK) || !count) + return false; + // Run `st ptr ` + command = PDI_ST | PDI_MODE_DIR_PTR | PDI_DATA_32; + if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, addr & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (addr >> 8U) & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (addr >> 16U) & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (addr >> 24U) & 0xffU) || result != PDI_EMPTY) + return false; + // Run `repeat ` + command = PDI_REPEAT | PDI_DATA_32; + if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, repeat & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (repeat >> 8U) & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (repeat >> 16U) & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (repeat >> 24U) & 0xffU) || result != PDI_EMPTY) + return false; + // Run `ld ` + command = PDI_LD | ptr_mode; + if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || result != PDI_EMPTY) + return false; + for (uint32_t i = 0; i < count; ++i) + { + if (!avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &data[i], 0)) + return false; + } + return true; +} + bool avr_enable(AVR_DP_t *dp, pdi_key_e what) { const char *const key = what == PDI_DEBUG ? pdi_key_debug : pdi_key_prog; From 51977166253cafdc76cae0ef2c5279f718ac5883 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 18 Dec 2021 21:45:04 -0500 Subject: [PATCH 23/56] avr_pdi: Done a first pass at reading the AVR registers --- src/target/avr_pdi.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index 7e72e49cd22..1422c6ebf0d 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -45,6 +45,18 @@ #define PDI_RESET 0x59U +#define AVR_ADDR_DBG_CTR 0x00000000U +#define AVR_ADDR_DBG_PC 0x00000004U +#define AVR_ADDR_DBG_CTRL 0x0000000aU +#define AVR_ADDR_DBG_SPECIAL 0x0000000cU + +#define AVR_DBG_READ_REGS 0x11U +#define AVR_NUM_REGS 32 + +#define AVR_ADDR_CPU 0x01000030U +#define AVR_ADDR_CPU_SPL 0xDU +#define AVR_ADDR_CPU_SREG 0xFU + typedef enum { PDI_PROG = 0x02U, @@ -58,6 +70,8 @@ static void avr_reset(target *t); static void avr_halt_request(target *t); static enum target_halt_reason avr_halt_poll(target *t, target_addr *watch); +static void avr_regs_read(target *t, void *data); + typedef struct __attribute__((packed)) { uint8_t general[32]; // r0-r31 @@ -353,3 +367,18 @@ static enum target_halt_reason avr_halt_poll(target *t, target_addr *watch) (void)watch; return dp->halt_reason; } + +static void avr_regs_read(target *t, void *data) +{ + AVR_DP_t *dp = t->priv; + avr_regs *regs = (avr_regs *)data; + regs->pc = avr_pdi_ld32(dp, AVR_ADDR_DBG_PC); + regs->sp = avr_pdi_ld16(dp, AVR_ADDR_CPU | AVR_ADDR_CPU_SPL); + regs->sreg = avr_pdi_ld16(dp, AVR_ADDR_CPU | AVR_ADDR_CPU_SREG); + + if (!avr_pdi_st8(dp, AVR_ADDR_DBG_CTRL, AVR_DBG_READ_REGS) || + !avr_pdi_st32(dp, AVR_ADDR_DBG_CTR, AVR_NUM_REGS) || + !avr_pdi_reg_write(dp, PDI_REG_R4, 1) || + !avr_pdi_read(dp, AVR_ADDR_DBG_SPECIAL, PDI_MODE_IND_PTR, regs->general, 32)) + raise_exception(EXCEPTION_ERROR, "Error reading registers"); +} From 8f5a51ac20e2b33b282e229166e1b2b2851d4155 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sun, 19 Dec 2021 05:46:26 -0500 Subject: [PATCH 24/56] avr: Rewrote the processor space load/store routines --- src/target/avr_pdi.c | 143 +++++++++++++++++++++---------------------- 1 file changed, 69 insertions(+), 74 deletions(-) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index 1422c6ebf0d..7d0d91c1b99 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -152,96 +152,85 @@ uint8_t avr_pdi_reg_read(AVR_DP_t *dp, uint8_t reg) return result; } -bool avr_pdi_st8(AVR_DP_t *dp, uint32_t reg, uint8_t data) +static bool avr_pdi_write(AVR_DP_t *dp, uint8_t bytes, uint32_t reg, uint32_t value) { - uint8_t result = 0, command = PDI_STS | PDI_ADDR_32 | PDI_DATA_8; - if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, reg & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 8U) & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 16U) & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 24U) & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, data)) - return false; - return result == PDI_EMPTY; -} + uint8_t result = 0; + uint8_t command = PDI_STS | PDI_ADDR_32 | bytes; + uint8_t data_bytes[4] = { + value & 0xffU, + (value >> 8U) & 0xffU, + (value >> 16U) & 0xffU, + (value >> 24U) & 0xffU + }; -uint8_t avr_pdi_ld8(AVR_DP_t *dp, uint32_t reg) -{ - uint8_t result = 0, command = PDI_LDS | PDI_ADDR_32 | PDI_DATA_8; - uint8_t data[1]; if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || result != PDI_EMPTY || avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, reg & 0xffU) || result != PDI_EMPTY || avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 8U) & 0xffU) || result != PDI_EMPTY || avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 16U) & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 24U) & 0xffU) || result != PDI_EMPTY || - !avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, data, 0)) - return 0xFFU; // TODO - figure out a better way to indicate failure. - return data[0]; + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 24U) & 0xffU) || result != PDI_EMPTY) + return false; + // This is intentionally <= to avoid `bytes + 1` silliness + for (uint8_t i = 0; i <= bytes; ++i) + { + if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, data_bytes[i]) || result != PDI_EMPTY) + return false; + } + return true; } -bool avr_pdi_st16(AVR_DP_t *dp, uint32_t reg, uint16_t data) +static bool avr_pdi_read(AVR_DP_t *dp, uint8_t bytes, uint32_t reg, uint32_t *value) { - uint8_t result = 0, command = PDI_STS | PDI_ADDR_32 | PDI_DATA_16; + uint8_t result = 0; + uint8_t command = PDI_LDS | PDI_ADDR_32 | bytes; + uint8_t data_bytes[4]; + uint32_t data = 0xffffffffU; if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || result != PDI_EMPTY || avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, reg & 0xffU) || result != PDI_EMPTY || avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 8U) & 0xffU) || result != PDI_EMPTY || avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 16U) & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 24U) & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, data & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (data >> 8U) & 0xffU)) + avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 24U) & 0xffU) || result != PDI_EMPTY) return false; - return result == PDI_EMPTY; + for (uint8_t i = 0; i <= bytes; ++i) + { + if (!avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &data_bytes[i], 0)) + return false; + } + data = data_bytes[0]; + if (bytes > PDI_DATA_8) + data |= data_bytes[1] << 8U; + if (bytes > PDI_DATA_16) + data |= data_bytes[2] << 16U; + if (bytes > PDI_DATA_24) + data |= data_bytes[3] << 24U; + *value = data; + return true; } -uint16_t avr_pdi_ld16(AVR_DP_t *dp, uint32_t reg) +static inline bool avr_pdi_read8(AVR_DP_t *dp, uint32_t reg, uint8_t *value) { - uint8_t result = 0, command = PDI_LDS | PDI_ADDR_32 | PDI_DATA_16; - uint8_t data[2]; - if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, reg & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 8U) & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 16U) & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 24U) & 0xffU) || result != PDI_EMPTY || - !avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, data + 0, 0) || - !avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, data + 1, 0)) - return 0xFFFFU; // TODO - figure out a better way to indicate failure. - return data[0] | (data[1] << 8U); + uint32_t data; + const bool result = avr_pdi_read(dp, PDI_DATA_8, reg, &data); + if (result) + *value = data; + return result; } -bool avr_pdi_st32(AVR_DP_t *dp, uint32_t reg, uint32_t data) +static inline bool avr_pdi_read16(AVR_DP_t *dp, uint32_t reg, uint16_t *value) { - uint8_t result = 0, command = PDI_STS | PDI_ADDR_32 | PDI_DATA_32; - if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, reg & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 8U) & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 16U) & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 24U) & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, data & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (data >> 8U) & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (data >> 16U) & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (data >> 24U) & 0xffU)) - return false; - return result == PDI_EMPTY; + uint32_t data; + const bool result = avr_pdi_read(dp, PDI_DATA_16, reg, &data); + if (result) + *value = data; + return result; } -uint32_t avr_pdi_ld32(AVR_DP_t *dp, uint32_t reg) -{ - uint8_t result = 0, command = PDI_LDS | PDI_ADDR_32 | PDI_DATA_32; - uint8_t data[4]; - if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, reg & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 8U) & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 16U) & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 24U) & 0xffU) || result != PDI_EMPTY || - !avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, data + 0, 0) || - !avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, data + 1, 0) || - !avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, data + 2, 0) || - !avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, data + 3, 0)) - return 0xFFFFU; // TODO - figure out a better way to indicate failure. - return data[0] | (data[1] << 8U) | (data[2] << 16U) | (data[3] << 24U); -} +static inline bool avr_pdi_read24(AVR_DP_t *dp, uint32_t reg, uint32_t *value) + { return avr_pdi_read(dp, PDI_DATA_24, reg, value); } -bool avr_pdi_read(AVR_DP_t *dp, uint32_t addr, uint8_t ptr_mode, void *dst, uint32_t count) +static inline bool avr_pdi_read32(AVR_DP_t *dp, uint32_t reg, uint32_t *value) + { return avr_pdi_read(dp, PDI_DATA_32, reg, value); } + +static bool avr_pdi_read_ind(AVR_DP_t *dp, uint32_t addr, uint8_t ptr_mode, void *dst, uint32_t count) { const uint32_t repeat = count - 1U; uint8_t result = 0, command; @@ -372,13 +361,19 @@ static void avr_regs_read(target *t, void *data) { AVR_DP_t *dp = t->priv; avr_regs *regs = (avr_regs *)data; - regs->pc = avr_pdi_ld32(dp, AVR_ADDR_DBG_PC); - regs->sp = avr_pdi_ld16(dp, AVR_ADDR_CPU | AVR_ADDR_CPU_SPL); - regs->sreg = avr_pdi_ld16(dp, AVR_ADDR_CPU | AVR_ADDR_CPU_SREG); - - if (!avr_pdi_st8(dp, AVR_ADDR_DBG_CTRL, AVR_DBG_READ_REGS) || - !avr_pdi_st32(dp, AVR_ADDR_DBG_CTR, AVR_NUM_REGS) || + uint32_t pc = 0; + uint16_t sp = 0; + if (!avr_pdi_read32(dp, AVR_ADDR_DBG_PC, &pc) || + !avr_pdi_read16(dp, AVR_ADDR_CPU | AVR_ADDR_CPU_SPL, &sp) || + !avr_pdi_read8(dp, AVR_ADDR_CPU | AVR_ADDR_CPU_SREG, ®s->sreg) || + !avr_pdi_write(dp, PDI_DATA_8, AVR_ADDR_DBG_CTRL, AVR_DBG_READ_REGS) || + !avr_pdi_write(dp, PDI_DATA_32, AVR_ADDR_DBG_CTR, AVR_NUM_REGS) || !avr_pdi_reg_write(dp, PDI_REG_R4, 1) || - !avr_pdi_read(dp, AVR_ADDR_DBG_SPECIAL, PDI_MODE_IND_PTR, regs->general, 32)) + !avr_pdi_read_ind(dp, AVR_ADDR_DBG_SPECIAL, PDI_MODE_IND_PTR, regs->general, 32)) raise_exception(EXCEPTION_ERROR, "Error reading registers"); + // These aren't in the reads above because regs is a packed struct, which results in compiler errors + // Additionally, the program counter is stored in words and points to the next instruction to be executed + // So we substract 1 and double. + regs->pc = (pc - 1) << 1; + regs->sp = sp; } From f7e8e19d903f46a2f59bdf78de680293c64922e9 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sun, 19 Dec 2021 05:48:22 -0500 Subject: [PATCH 25/56] avr: Static-correctness and added avr_regs_read to the target function pointers --- src/target/avr_pdi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index 7d0d91c1b99..32cf48c08f6 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -119,6 +119,8 @@ bool avr_dp_init(AVR_DP_t *dp) t->attach = avr_attach; t->detach = avr_detach; + t->regs_read = avr_regs_read; + t->reset = avr_reset; t->halt_request = avr_halt_request; t->halt_poll = avr_halt_poll; @@ -265,7 +267,7 @@ static bool avr_pdi_read_ind(AVR_DP_t *dp, uint32_t addr, uint8_t ptr_mode, void return true; } -bool avr_enable(AVR_DP_t *dp, pdi_key_e what) +static bool avr_enable(AVR_DP_t *dp, pdi_key_e what) { const char *const key = what == PDI_DEBUG ? pdi_key_debug : pdi_key_prog; uint8_t result = 0; @@ -279,7 +281,7 @@ bool avr_enable(AVR_DP_t *dp, pdi_key_e what) return (avr_pdi_reg_read(dp, PDI_REG_STATUS) & what) == what; } -bool avr_disable(AVR_DP_t *dp, pdi_key_e what) +static bool avr_disable(AVR_DP_t *dp, pdi_key_e what) { return avr_pdi_reg_write(dp, PDI_REG_STATUS, ~what); } From f47da90f5f066ec7eeda1dcdb1bcd74b26bf36fa Mon Sep 17 00:00:00 2001 From: dragonmux Date: Tue, 21 Dec 2021 17:55:57 -0500 Subject: [PATCH 26/56] avr: Fixed the warning that was being generated by our target description --- src/target/atxmega.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/target/atxmega.c b/src/target/atxmega.c index e47d783ad5d..772f21e3628 100644 --- a/src/target/atxmega.c +++ b/src/target/atxmega.c @@ -10,6 +10,8 @@ static const char tdesc_xmega6[] = "" "" " avr:106" + /* As it turns out, GDB doesn't acctually support this (despite asking for it!) yet */ +#if 0 " " " " " " @@ -47,6 +49,7 @@ static const char tdesc_xmega6[] = " " " " " " +#endif ""; bool atxmega_probe(target *t) @@ -54,7 +57,7 @@ bool atxmega_probe(target *t) switch (t->idcode) { case IDCODE_XMEGA256A3U: t->core = "ATXMega256A3U"; - target_add_ram(t, 0x01002000, 0x01002800); + target_add_ram(t, 0x01002000, 0x800); avr_add_flash(t, 0x00800000, 0x40000); avr_add_flash(t, 0x00840000, 0x2000); t->tdesc = tdesc_xmega6; From 85878c0cd38c80f317f7368a4701931881e532f6 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Tue, 18 Jan 2022 08:40:12 -0500 Subject: [PATCH 27/56] avr: Removed the needless refcounting and added a target private free function --- src/target/avr.h | 2 -- src/target/avr_pdi.c | 15 ++------------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/src/target/avr.h b/src/target/avr.h index 8a471f9b972..cc837da38d8 100644 --- a/src/target/avr.h +++ b/src/target/avr.h @@ -5,8 +5,6 @@ #include "target.h" typedef struct Atmel_DP_s { - int refcnt; - uint32_t idcode; uint8_t dp_jd_index; diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index 32cf48c08f6..a148729514f 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -80,17 +80,6 @@ typedef struct __attribute__((packed)) uint32_t pc; // r34 } avr_regs; -static void avr_dp_ref(AVR_DP_t *dp) -{ - dp->refcnt++; -} - -static void avr_dp_unref(AVR_DP_t *dp) -{ - if (--(dp->refcnt) == 0) - free(dp); -} - bool avr_dp_init(AVR_DP_t *dp) { target *t; @@ -108,13 +97,13 @@ bool avr_dp_init(AVR_DP_t *dp) t = target_new(); if (!t) return false; - avr_dp_ref(dp); t->cpuid = dp->idcode; t->idcode = (dp->idcode >> 12) & 0xFFFFU; - t->priv = dp; t->driver = "Atmel AVR"; t->core = "AVR"; + t->priv = dp; + t->priv_free = free; t->attach = avr_attach; t->detach = avr_detach; From e2b9f995d10de6352527cfdf0ee55c5d54dc4707 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Fri, 21 Jan 2022 15:13:42 -0500 Subject: [PATCH 28/56] avr: Implemented handling for DELAY packets as we run so fast the PDI controller generates them --- src/target/avr_jtagdp.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/target/avr_jtagdp.c b/src/target/avr_jtagdp.c index a76930edd81..2d497e52f8f 100644 --- a/src/target/avr_jtagdp.c +++ b/src/target/avr_jtagdp.c @@ -4,6 +4,8 @@ #include "jtag_scan.h" #include "jtagtap.h" +#define PDI_DELAY 0xDBU + void avr_jtag_dp_handler(uint8_t jd_index, uint32_t j_idcode) { AVR_DP_t *dp = calloc(1, sizeof(*dp)); @@ -26,19 +28,24 @@ bool avr_jtag_shift_dr(jtag_proc_t *jp, uint8_t jd_index, uint8_t *dout, const u jtag_dev_t *d = &jtag_devs[jd_index]; uint8_t result = 0; uint16_t request = 0, response = 0; - uint8_t *data = (uint8_t *)&request; + uint8_t *data; if (!dout) return false; - jtagtap_shift_dr(); - jp->jtagtap_tdi_seq(0, ones, d->dr_prescan); - data[0] = din; - // Calculate the parity bit - for (uint8_t i = 0; i < 8; ++i) - data[1] ^= (din >> i) & 1U; - jp->jtagtap_tdi_tdo_seq((uint8_t *)&response, 1, (uint8_t *)&request, 9); - jp->jtagtap_tdi_seq(1, ones, d->dr_postscan); - jtagtap_return_idle(); - data = (uint8_t *)&response; + do + { + data = (uint8_t *)&request; + jtagtap_shift_dr(); + jp->jtagtap_tdi_seq(0, ones, d->dr_prescan); + data[0] = din; + // Calculate the parity bit + for (uint8_t i = 0; i < 8; ++i) + data[1] ^= (din >> i) & 1U; + jp->jtagtap_tdi_tdo_seq((uint8_t *)&response, 1, (uint8_t *)&request, 9); + jp->jtagtap_tdi_seq(1, ones, d->dr_postscan); + jtagtap_return_idle(); + data = (uint8_t *)&response; + } + while (data[0] == PDI_DELAY && data[1] == 1); // Calculate the parity bit for (uint8_t i = 0; i < 8; ++i) result ^= (data[0] >> i) & 1U; From 42b6d2a06f07495a4091c56e8ce04959cd98744b Mon Sep 17 00:00:00 2001 From: dragonmux Date: Fri, 21 Jan 2022 15:14:49 -0500 Subject: [PATCH 29/56] avr: Turns out a 16-bit read of an 8-bit register address does not read it and the next register, breaking readout of the stack pointer --- src/target/avr_pdi.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index a148729514f..f1cd98f07b6 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -53,9 +53,7 @@ #define AVR_DBG_READ_REGS 0x11U #define AVR_NUM_REGS 32 -#define AVR_ADDR_CPU 0x01000030U -#define AVR_ADDR_CPU_SPL 0xDU -#define AVR_ADDR_CPU_SREG 0xFU +#define AVR_ADDR_CPU_SPL 0x0100003DU typedef enum { @@ -352,11 +350,10 @@ static void avr_regs_read(target *t, void *data) { AVR_DP_t *dp = t->priv; avr_regs *regs = (avr_regs *)data; + uint8_t status[3]; uint32_t pc = 0; - uint16_t sp = 0; if (!avr_pdi_read32(dp, AVR_ADDR_DBG_PC, &pc) || - !avr_pdi_read16(dp, AVR_ADDR_CPU | AVR_ADDR_CPU_SPL, &sp) || - !avr_pdi_read8(dp, AVR_ADDR_CPU | AVR_ADDR_CPU_SREG, ®s->sreg) || + !avr_pdi_read_ind(dp, AVR_ADDR_CPU_SPL, PDI_MODE_IND_INCPTR, status, 3) || !avr_pdi_write(dp, PDI_DATA_8, AVR_ADDR_DBG_CTRL, AVR_DBG_READ_REGS) || !avr_pdi_write(dp, PDI_DATA_32, AVR_ADDR_DBG_CTR, AVR_NUM_REGS) || !avr_pdi_reg_write(dp, PDI_REG_R4, 1) || @@ -366,5 +363,6 @@ static void avr_regs_read(target *t, void *data) // Additionally, the program counter is stored in words and points to the next instruction to be executed // So we substract 1 and double. regs->pc = (pc - 1) << 1; - regs->sp = sp; + regs->sp = status[0] | (status[1] << 8); + regs->sreg = status[2]; } From cff5fdd0b1483a8766355f8c61f6a8fe386f5658 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Fri, 21 Jan 2022 15:15:26 -0500 Subject: [PATCH 30/56] avr: Cleanup in avr_pdi_read_ind() --- src/target/avr_pdi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index f1cd98f07b6..4dd9f12370d 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -219,7 +219,8 @@ static inline bool avr_pdi_read24(AVR_DP_t *dp, uint32_t reg, uint32_t *value) static inline bool avr_pdi_read32(AVR_DP_t *dp, uint32_t reg, uint32_t *value) { return avr_pdi_read(dp, PDI_DATA_32, reg, value); } -static bool avr_pdi_read_ind(AVR_DP_t *dp, uint32_t addr, uint8_t ptr_mode, void *dst, uint32_t count) +static bool avr_pdi_read_ind(const AVR_DP_t *const dp, const uint32_t addr, const uint8_t ptr_mode, + void *const dst, const uint32_t count) { const uint32_t repeat = count - 1U; uint8_t result = 0, command; @@ -248,7 +249,7 @@ static bool avr_pdi_read_ind(AVR_DP_t *dp, uint32_t addr, uint8_t ptr_mode, void return false; for (uint32_t i = 0; i < count; ++i) { - if (!avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &data[i], 0)) + if (!avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, data + i, 0)) return false; } return true; From 350ad30d0a90d32baa9121a1aa96223486bcd9fa Mon Sep 17 00:00:00 2001 From: dragonmux Date: Fri, 21 Jan 2022 15:16:22 -0500 Subject: [PATCH 31/56] avr: Cleanup in avr_enable() --- src/target/avr_pdi.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index 4dd9f12370d..200e8e18868 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -57,11 +57,11 @@ typedef enum { - PDI_PROG = 0x02U, + PDI_NVM = 0x02U, PDI_DEBUG = 0x04U, } pdi_key_e; -static const char pdi_key_prog[] = {0xff, 0x88, 0xd8, 0xcd, 0x45, 0xab, 0x89, 0x12}; +static const char pdi_key_nvm[] = {0xff, 0x88, 0xd8, 0xcd, 0x45, 0xab, 0x89, 0x12}; static const char pdi_key_debug[] = {0x21, 0x81, 0x7c, 0x9f, 0xd4, 0x2d, 0x21, 0x3a}; static void avr_reset(target *t); @@ -257,7 +257,7 @@ static bool avr_pdi_read_ind(const AVR_DP_t *const dp, const uint32_t addr, cons static bool avr_enable(AVR_DP_t *dp, pdi_key_e what) { - const char *const key = what == PDI_DEBUG ? pdi_key_debug : pdi_key_prog; + const char *const key = what == PDI_DEBUG ? pdi_key_debug : pdi_key_nvm; uint8_t result = 0; if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, PDI_KEY) || result != PDI_EMPTY) return false; @@ -266,7 +266,14 @@ static bool avr_enable(AVR_DP_t *dp, pdi_key_e what) if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, key[i]) || result != PDI_EMPTY) return false; } - return (avr_pdi_reg_read(dp, PDI_REG_STATUS) & what) == what; + if (what == PDI_NVM) + { + while ((avr_pdi_reg_read(dp, PDI_REG_STATUS) & what) != what) + continue; + return true; + } + else + return (avr_pdi_reg_read(dp, PDI_REG_STATUS) & what) == what; } static bool avr_disable(AVR_DP_t *dp, pdi_key_e what) From b6ae147c54f6fc8408816462f3b682e924f9f0f2 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Fri, 21 Jan 2022 15:16:45 -0500 Subject: [PATCH 32/56] avr: Made sure to enable NVM access during attach and disable it during detach --- src/target/avr_pdi.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index 200e8e18868..974bf16ac1d 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -55,6 +55,13 @@ #define AVR_ADDR_CPU_SPL 0x0100003DU +#define AVR_ADDR_NVM 0x010001C0U +#define AVR_ADDR_NVM_DATA 0x010001C4U +#define AVR_ADDR_NVM_CMD 0x010001CAU + +#define AVR_NVM_CMD_NOP 0x00U +#define AVR_NVM_CMD_READ_NVM 0x43U + typedef enum { PDI_NVM = 0x02U, @@ -296,6 +303,12 @@ void avr_add_flash(target *t, uint32_t start, size_t length) target_add_flash(t, f); } +bool avr_ensure_nvm_idle(AVR_DP_t *dp) +{ + return avr_pdi_write(dp, PDI_DATA_8, AVR_ADDR_NVM_CMD, 0) && + avr_pdi_write(dp, PDI_DATA_8, AVR_ADDR_NVM_DATA, 0xFFU); +} + bool avr_attach(target *t) { AVR_DP_t *dp = t->priv; @@ -307,6 +320,9 @@ bool avr_attach(target *t) if (!avr_enable(dp, PDI_DEBUG)) return false; target_halt_request(t); + if (!avr_enable(dp, PDI_NVM) || + !avr_ensure_nvm_idle(dp)) + return false; } return !e.type; } @@ -315,6 +331,7 @@ void avr_detach(target *t) { AVR_DP_t *dp = t->priv; + avr_disable(dp, PDI_NVM); avr_disable(dp, PDI_DEBUG); jtag_dev_write_ir(&jtag_proc, dp->dp_jd_index, IR_BYPASS); } From 470186fe7bd8aa338152367255809dc0db980464 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Fri, 21 Jan 2022 15:18:11 -0500 Subject: [PATCH 33/56] avr: Improved the reset code so the status register not being the expected value doesn't cause problems --- src/target/avr_pdi.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index 974bf16ac1d..0176b97de93 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -339,9 +339,13 @@ void avr_detach(target *t) static void avr_reset(target *t) { AVR_DP_t *dp = t->priv; - if (!avr_pdi_reg_write(dp, PDI_REG_RESET, PDI_RESET) || - avr_pdi_reg_read(dp, PDI_REG_STATUS) != 0x00) + if (!avr_pdi_reg_write(dp, PDI_REG_RESET, PDI_RESET)) raise_exception(EXCEPTION_ERROR, "Error resetting device, device in incorrect state"); + if (avr_pdi_reg_read(dp, PDI_REG_STATUS) != 0x00) + { + avr_disable(dp, PDI_NVM); + avr_disable(dp, PDI_DEBUG); + } } static void avr_halt_request(target *t) From 58d5430482225438295e6ac3442d9b85c825e44a Mon Sep 17 00:00:00 2001 From: dragonmux Date: Fri, 21 Jan 2022 15:21:29 -0500 Subject: [PATCH 34/56] avr: Added preliminary read memory support (only supports Flash addresses) --- src/target/atxmega.c | 6 ++++-- src/target/avr_pdi.c | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/target/atxmega.c b/src/target/atxmega.c index 772f21e3628..999d145ce49 100644 --- a/src/target/atxmega.c +++ b/src/target/atxmega.c @@ -58,8 +58,10 @@ bool atxmega_probe(target *t) case IDCODE_XMEGA256A3U: t->core = "ATXMega256A3U"; target_add_ram(t, 0x01002000, 0x800); - avr_add_flash(t, 0x00800000, 0x40000); - avr_add_flash(t, 0x00840000, 0x2000); + // These are mapped here to make things make sense to GDB + // - internally we add 0x00800000 to get to the PDI mapped address. + avr_add_flash(t, 0x00000000, 0x40000); + avr_add_flash(t, 0x00040000, 0x2000); t->tdesc = tdesc_xmega6; return true; } diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index 0176b97de93..fceaa56d9d3 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -45,6 +45,8 @@ #define PDI_RESET 0x59U +#define PDI_FLASH_OFFSET 0x00800000U + #define AVR_ADDR_DBG_CTR 0x00000000U #define AVR_ADDR_DBG_PC 0x00000004U #define AVR_ADDR_DBG_CTRL 0x0000000aU @@ -75,6 +77,9 @@ static void avr_reset(target *t); static void avr_halt_request(target *t); static enum target_halt_reason avr_halt_poll(target *t, target_addr *watch); +static bool avr_check_error(target *t); +static void avr_mem_read(target *t, void *dest, target_addr src, size_t len); + static void avr_regs_read(target *t, void *data); typedef struct __attribute__((packed)) @@ -113,6 +118,9 @@ bool avr_dp_init(AVR_DP_t *dp) t->attach = avr_attach; t->detach = avr_detach; + t->check_error = avr_check_error; + t->mem_read = avr_mem_read; + t->regs_read = avr_regs_read; t->reset = avr_reset; @@ -375,6 +383,23 @@ static enum target_halt_reason avr_halt_poll(target *t, target_addr *watch) return dp->halt_reason; } +static bool avr_check_error(target *t) +{ + AVR_DP_t *dp = t->priv; + (void)dp; + return false; +} + +static void avr_mem_read(target *t, void *dest, target_addr src, size_t len) +{ + AVR_DP_t *dp = t->priv; + // This presently assumes src is a Flash address. + if (!avr_pdi_write(dp, PDI_DATA_8, AVR_ADDR_NVM_CMD, AVR_NVM_CMD_READ_NVM) || + !avr_pdi_read_ind(dp, src | PDI_FLASH_OFFSET, PDI_MODE_IND_INCPTR, dest, len) || + !avr_ensure_nvm_idle(dp)) + return; // TODO: set an error indicator for avr_check_error. +} + static void avr_regs_read(target *t, void *data) { AVR_DP_t *dp = t->priv; From 24104235a6b24d2e0ac806f59321b79a63f06dc1 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Fri, 21 Jan 2022 15:22:22 -0500 Subject: [PATCH 35/56] avr: Unified the case of all the top of file constantsin avr_pdi.c --- src/target/avr_pdi.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index fceaa56d9d3..3636b9a984c 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -17,9 +17,9 @@ #define PDI_STS 0x40U #define PDI_ST 0x60U #define PDI_LDCS 0x80U -#define PDI_REPEAT 0xa0U -#define PDI_STCS 0xc0U -#define PDI_KEY 0xe0U +#define PDI_REPEAT 0xA0U +#define PDI_STCS 0xC0U +#define PDI_KEY 0xE0U #define PDI_DATA_8 0x00U #define PDI_DATA_16 0x01U @@ -29,13 +29,13 @@ #define PDI_ADDR_8 0x00U #define PDI_ADDR_16 0x04U #define PDI_ADDR_24 0x08U -#define PDI_ADDR_32 0x0cU +#define PDI_ADDR_32 0x0CU #define PDI_MODE_IND_PTR 0x00U #define PDI_MODE_IND_INCPTR 0x04U #define PDI_MODE_DIR_PTR 0x08U -#define PDI_MODE_DIR_INCPTR 0x0cU // "Reserved" -#define PDI_MODE_MASK 0xf3U +#define PDI_MODE_DIR_INCPTR 0x0CU // "Reserved" +#define PDI_MODE_MASK 0xF3U #define PDI_REG_STATUS 0U #define PDI_REG_RESET 1U @@ -49,11 +49,11 @@ #define AVR_ADDR_DBG_CTR 0x00000000U #define AVR_ADDR_DBG_PC 0x00000004U -#define AVR_ADDR_DBG_CTRL 0x0000000aU -#define AVR_ADDR_DBG_SPECIAL 0x0000000cU +#define AVR_ADDR_DBG_CTRL 0x0000000AU +#define AVR_ADDR_DBG_SPECIAL 0x0000000CU -#define AVR_DBG_READ_REGS 0x11U -#define AVR_NUM_REGS 32 +#define AVR_DBG_READ_REGS 0x11U +#define AVR_NUM_REGS 32 #define AVR_ADDR_CPU_SPL 0x0100003DU From d2ccf869715d4674144c35eea633d8f0fab3fc6f Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 17 Feb 2022 11:25:58 -0500 Subject: [PATCH 36/56] target: Made target_flash_for_addr() available as a target internal --- src/target/target.c | 6 +++--- src/target/target_internal.h | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/target/target.c b/src/target/target.c index dd4208a85f7..eae1b5bbdb4 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -239,7 +239,7 @@ bool target_mem_map(target *t, char *tmp, size_t len) return true; } -static struct target_flash *flash_for_addr(target *t, uint32_t addr) +struct target_flash *target_flash_for_addr(target *t, uint32_t addr) { for (struct target_flash *f = t->flash; f; f = f->next) if ((f->start <= addr) && @@ -252,7 +252,7 @@ int target_flash_erase(target *t, target_addr addr, size_t len) { int ret = 0; while (len) { - struct target_flash *f = flash_for_addr(t, addr); + struct target_flash *f = target_flash_for_addr(t, addr); if (!f) { DEBUG_WARN("Erase stopped at 0x%06" PRIx32 "\n", addr); return ret; @@ -271,7 +271,7 @@ int target_flash_write(target *t, { int ret = 0; while (len) { - struct target_flash *f = flash_for_addr(t, dest); + struct target_flash *f = target_flash_for_addr(t, dest); if (!f) return 1; size_t tmptarget = MIN(dest + len, f->start + f->length); diff --git a/src/target/target_internal.h b/src/target/target_internal.h index b2c65d0d818..bb9eab2abc7 100644 --- a/src/target/target_internal.h +++ b/src/target/target_internal.h @@ -143,6 +143,8 @@ void target_add_commands(target *t, const struct command_s *cmds, const char *na void target_add_ram(target *t, target_addr start, uint32_t len); void target_add_flash(target *t, struct target_flash *f); +struct target_flash *target_flash_for_addr(target *t, uint32_t addr); + /* Convenience function for MMIO access */ uint32_t target_mem_read32(target *t, uint32_t addr); uint16_t target_mem_read16(target *t, uint32_t addr); From 532da486fd636a11c443add55945010ac9b45fa4 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 17 Feb 2022 11:26:42 -0500 Subject: [PATCH 37/56] avr: Implemented PDI error tracking --- src/target/avr.h | 7 +++++++ src/target/avr_jtagdp.c | 1 + src/target/avr_pdi.c | 3 +-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/target/avr.h b/src/target/avr.h index cc837da38d8..ff9c3cd7742 100644 --- a/src/target/avr.h +++ b/src/target/avr.h @@ -4,11 +4,18 @@ #include "jtag_scan.h" #include "target.h" +enum avr_error_e +{ + pdi_ok, + pdi_failure, +}; + typedef struct Atmel_DP_s { uint32_t idcode; uint8_t dp_jd_index; enum target_halt_reason halt_reason; + enum avr_error_e error_state; } AVR_DP_t; bool avr_dp_init(AVR_DP_t *dp); diff --git a/src/target/avr_jtagdp.c b/src/target/avr_jtagdp.c index 2d497e52f8f..068d6026fa2 100644 --- a/src/target/avr_jtagdp.c +++ b/src/target/avr_jtagdp.c @@ -17,6 +17,7 @@ void avr_jtag_dp_handler(uint8_t jd_index, uint32_t j_idcode) dp->dp_jd_index = jd_index; dp->idcode = jtag_devs[jd_index].jd_idcode; + dp->error_state = pdi_ok; if ((PC_HOSTED == 0) || (!platform_avr_jtag_dp_init(dp))) { // } diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index 3636b9a984c..a5faa4c9e71 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -386,8 +386,7 @@ static enum target_halt_reason avr_halt_poll(target *t, target_addr *watch) static bool avr_check_error(target *t) { AVR_DP_t *dp = t->priv; - (void)dp; - return false; + return dp->error_state != pdi_ok; } static void avr_mem_read(target *t, void *dest, target_addr src, size_t len) From b0a59d1b9abe3167c5f65eb415aefd0dc6774aac Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 17 Feb 2022 11:26:59 -0500 Subject: [PATCH 38/56] atxmega: Fixed the memory map for the RAM --- src/target/atxmega.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/target/atxmega.c b/src/target/atxmega.c index 999d145ce49..5abc9dcab9b 100644 --- a/src/target/atxmega.c +++ b/src/target/atxmega.c @@ -57,7 +57,9 @@ bool atxmega_probe(target *t) switch (t->idcode) { case IDCODE_XMEGA256A3U: t->core = "ATXMega256A3U"; - target_add_ram(t, 0x01002000, 0x800); + // RAM is actually at 0x01002000, but this is done to keep things right for GDB + // - internally we add 0x00800000 to get to the PDI mapped address. + target_add_ram(t, 0x00802000, 0x800); // These are mapped here to make things make sense to GDB // - internally we add 0x00800000 to get to the PDI mapped address. avr_add_flash(t, 0x00000000, 0x40000); From 7325d71c18c0f6df3d5f65a8752b58f68271c2ce Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 17 Feb 2022 11:27:32 -0500 Subject: [PATCH 39/56] avr: Implemented read-out of RAM regions --- src/target/avr_pdi.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index a5faa4c9e71..cded49868de 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -392,11 +392,19 @@ static bool avr_check_error(target *t) static void avr_mem_read(target *t, void *dest, target_addr src, size_t len) { AVR_DP_t *dp = t->priv; - // This presently assumes src is a Flash address. - if (!avr_pdi_write(dp, PDI_DATA_8, AVR_ADDR_NVM_CMD, AVR_NVM_CMD_READ_NVM) || - !avr_pdi_read_ind(dp, src | PDI_FLASH_OFFSET, PDI_MODE_IND_INCPTR, dest, len) || - !avr_ensure_nvm_idle(dp)) - return; // TODO: set an error indicator for avr_check_error. + if (target_flash_for_addr(t, src) != NULL) + { + // This presently assumes src is a Flash address. + if (!avr_pdi_write(dp, PDI_DATA_8, AVR_ADDR_NVM_CMD, AVR_NVM_CMD_READ_NVM) || + !avr_pdi_read_ind(dp, src | PDI_FLASH_OFFSET, PDI_MODE_IND_INCPTR, dest, len) || + !avr_ensure_nvm_idle(dp)) + dp->error_state = pdi_failure; + } + else if (src >= 0x00800000U) + { + if (!avr_pdi_read_ind(dp, src + 0x00800000U, PDI_MODE_IND_INCPTR, dest, len)) + dp->error_state = pdi_failure; + } } static void avr_regs_read(target *t, void *data) From fd009579c2e7e624f9eec0011ad973ce961cf46d Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 17 Feb 2022 11:48:41 -0500 Subject: [PATCH 40/56] avr: Fixed the naming of the JTAG PDI functions and types, dropping the early 'PD' naming we had going on --- src/platforms/hosted/platform.c | 2 +- src/target/avr.h | 12 +- src/target/avr_jtagdp.c | 16 +-- src/target/avr_pdi.c | 202 ++++++++++++++++---------------- src/target/jtag_devs.c | 2 +- 5 files changed, 117 insertions(+), 117 deletions(-) diff --git a/src/platforms/hosted/platform.c b/src/platforms/hosted/platform.c index 2a179964029..4ac09997930 100644 --- a/src/platforms/hosted/platform.c +++ b/src/platforms/hosted/platform.c @@ -253,7 +253,7 @@ int platform_jtag_dp_init(ADIv5_DP_t *dp) return 0; } -int platform_avr_jtag_dp_init(AVR_DP_t *dp) +int platform_avr_jtag_pdi_init(avr_pdi_t *pdi) { (void)dp; return 0; diff --git a/src/target/avr.h b/src/target/avr.h index ff9c3cd7742..dfec001f280 100644 --- a/src/target/avr.h +++ b/src/target/avr.h @@ -16,16 +16,16 @@ typedef struct Atmel_DP_s { uint8_t dp_jd_index; enum target_halt_reason halt_reason; enum avr_error_e error_state; -} AVR_DP_t; +} avr_pdi_t; -bool avr_dp_init(AVR_DP_t *dp); +bool avr_pdi_init(avr_pdi_t *pdi); -void avr_jtag_dp_handler(uint8_t jd_index, uint32_t j_idcode); -int platform_avr_jtag_dp_init(AVR_DP_t *dp); +void avr_jtag_pdi_handler(uint8_t jd_index, uint32_t j_idcode); +int platform_avr_jtag_pdi_init(avr_pdi_t *pdi); bool avr_jtag_shift_dr(jtag_proc_t *jp, uint8_t jd_index, uint8_t *dout, const uint8_t din); -bool avr_pdi_reg_write(AVR_DP_t *dp, uint8_t reg, uint8_t value); -uint8_t avr_pdi_reg_read(AVR_DP_t *dp, uint8_t reg); +bool avr_pdi_reg_write(avr_pdi_t *pdi, uint8_t reg, uint8_t value); +uint8_t avr_pdi_reg_read(avr_pdi_t *pdi, uint8_t reg); bool avr_attach(target *t); void avr_detach(target *t); diff --git a/src/target/avr_jtagdp.c b/src/target/avr_jtagdp.c index 068d6026fa2..e3d303aeb3f 100644 --- a/src/target/avr_jtagdp.c +++ b/src/target/avr_jtagdp.c @@ -6,22 +6,22 @@ #define PDI_DELAY 0xDBU -void avr_jtag_dp_handler(uint8_t jd_index, uint32_t j_idcode) +void avr_jtag_pdi_handler(uint8_t jd_index, uint32_t j_idcode) { - AVR_DP_t *dp = calloc(1, sizeof(*dp)); - if (!dp) { /* calloc failed: heap exhaustion */ + avr_pdi_t *pdi = calloc(1, sizeof(*pdi)); + if (!pdi) { /* calloc failed: heap exhaustion */ DEBUG_WARN("calloc: failed in %s\n", __func__); return; } (void)j_idcode; - dp->dp_jd_index = jd_index; - dp->idcode = jtag_devs[jd_index].jd_idcode; - dp->error_state = pdi_ok; - if ((PC_HOSTED == 0) || (!platform_avr_jtag_dp_init(dp))) { + pdi->dp_jd_index = jd_index; + pdi->idcode = jtag_devs[jd_index].jd_idcode; + pdi->error_state = pdi_ok; + if ((PC_HOSTED == 0) || (!platform_avr_jtag_pdi_init(pdi))) { // } - avr_dp_init(dp); + avr_pdi_init(pdi); } bool avr_jtag_shift_dr(jtag_proc_t *jp, uint8_t jd_index, uint8_t *dout, const uint8_t din) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index cded49868de..eb9fc901bd0 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -90,29 +90,29 @@ typedef struct __attribute__((packed)) uint32_t pc; // r34 } avr_regs; -bool avr_dp_init(AVR_DP_t *dp) +bool avr_pdi_init(avr_pdi_t *pdi) { target *t; /* Check for a valid part number in the IDCode */ - if ((dp->idcode & 0x0FFFF000) == 0) { - DEBUG_WARN("Invalid DP idcode %08" PRIx32 "\n", dp->idcode); - free(dp); + if ((pdi->idcode & 0x0FFFF000) == 0) { + DEBUG_WARN("Invalid PDI idcode %08" PRIx32 "\n", pdi->idcode); + free(pdi); return false; } - DEBUG_INFO("AVR ID 0x%08" PRIx32 " (v%d)\n", dp->idcode, - (uint8_t)((dp->idcode >> 28U) & 0xfU)); - jtag_dev_write_ir(&jtag_proc, dp->dp_jd_index, IR_BYPASS); + DEBUG_INFO("AVR ID 0x%08" PRIx32 " (v%d)\n", pdi->idcode, + (uint8_t)((pdi->idcode >> 28U) & 0xfU)); + jtag_dev_write_ir(&jtag_proc, pdi->dp_jd_index, IR_BYPASS); t = target_new(); if (!t) return false; - t->cpuid = dp->idcode; - t->idcode = (dp->idcode >> 12) & 0xFFFFU; + t->cpuid = pdi->idcode; + t->idcode = (pdi->idcode >> 12) & 0xFFFFU; t->driver = "Atmel AVR"; t->core = "AVR"; - t->priv = dp; + t->priv = pdi; t->priv_free = free; t->attach = avr_attach; @@ -132,31 +132,31 @@ bool avr_dp_init(AVR_DP_t *dp) if (atxmega_probe(t)) return true; - dp->halt_reason = TARGET_HALT_RUNNING; + pdi->halt_reason = TARGET_HALT_RUNNING; return true; } -bool avr_pdi_reg_write(AVR_DP_t *dp, uint8_t reg, uint8_t value) +bool avr_pdi_reg_write(avr_pdi_t *pdi, uint8_t reg, uint8_t value) { uint8_t result = 0, command = PDI_STCS | reg; if (reg >= 16 || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, value)) + avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, command) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, value)) return false; return result == PDI_EMPTY; } -uint8_t avr_pdi_reg_read(AVR_DP_t *dp, uint8_t reg) +uint8_t avr_pdi_reg_read(avr_pdi_t *pdi, uint8_t reg) { uint8_t result = 0, command = PDI_LDCS | reg; if (reg >= 16 || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || result != PDI_EMPTY || - !avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, 0)) + avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, command) || result != PDI_EMPTY || + !avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, 0)) return 0xFFU; // TODO - figure out a better way to indicate failure. return result; } -static bool avr_pdi_write(AVR_DP_t *dp, uint8_t bytes, uint32_t reg, uint32_t value) +static bool avr_pdi_write(avr_pdi_t *pdi, uint8_t bytes, uint32_t reg, uint32_t value) { uint8_t result = 0; uint8_t command = PDI_STS | PDI_ADDR_32 | bytes; @@ -167,36 +167,36 @@ static bool avr_pdi_write(AVR_DP_t *dp, uint8_t bytes, uint32_t reg, uint32_t va (value >> 24U) & 0xffU }; - if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, reg & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 8U) & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 16U) & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 24U) & 0xffU) || result != PDI_EMPTY) + if (avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, command) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, reg & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, (reg >> 8U) & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, (reg >> 16U) & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, (reg >> 24U) & 0xffU) || result != PDI_EMPTY) return false; // This is intentionally <= to avoid `bytes + 1` silliness for (uint8_t i = 0; i <= bytes; ++i) { - if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, data_bytes[i]) || result != PDI_EMPTY) + if (avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, data_bytes[i]) || result != PDI_EMPTY) return false; } return true; } -static bool avr_pdi_read(AVR_DP_t *dp, uint8_t bytes, uint32_t reg, uint32_t *value) +static bool avr_pdi_read(avr_pdi_t *pdi, uint8_t bytes, uint32_t reg, uint32_t *value) { uint8_t result = 0; uint8_t command = PDI_LDS | PDI_ADDR_32 | bytes; uint8_t data_bytes[4]; uint32_t data = 0xffffffffU; - if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, reg & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 8U) & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 16U) & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (reg >> 24U) & 0xffU) || result != PDI_EMPTY) + if (avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, command) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, reg & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, (reg >> 8U) & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, (reg >> 16U) & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, (reg >> 24U) & 0xffU) || result != PDI_EMPTY) return false; for (uint8_t i = 0; i <= bytes; ++i) { - if (!avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &data_bytes[i], 0)) + if (!avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &data_bytes[i], 0)) return false; } data = data_bytes[0]; @@ -210,31 +210,31 @@ static bool avr_pdi_read(AVR_DP_t *dp, uint8_t bytes, uint32_t reg, uint32_t *va return true; } -static inline bool avr_pdi_read8(AVR_DP_t *dp, uint32_t reg, uint8_t *value) +static inline bool avr_pdi_read8(avr_pdi_t *pdi, uint32_t reg, uint8_t *value) { uint32_t data; - const bool result = avr_pdi_read(dp, PDI_DATA_8, reg, &data); + const bool result = avr_pdi_read(pdi, PDI_DATA_8, reg, &data); if (result) *value = data; return result; } -static inline bool avr_pdi_read16(AVR_DP_t *dp, uint32_t reg, uint16_t *value) +static inline bool avr_pdi_read16(avr_pdi_t *pdi, uint32_t reg, uint16_t *value) { uint32_t data; - const bool result = avr_pdi_read(dp, PDI_DATA_16, reg, &data); + const bool result = avr_pdi_read(pdi, PDI_DATA_16, reg, &data); if (result) *value = data; return result; } -static inline bool avr_pdi_read24(AVR_DP_t *dp, uint32_t reg, uint32_t *value) - { return avr_pdi_read(dp, PDI_DATA_24, reg, value); } +static inline bool avr_pdi_read24(avr_pdi_t *pdi, uint32_t reg, uint32_t *value) + { return avr_pdi_read(pdi, PDI_DATA_24, reg, value); } -static inline bool avr_pdi_read32(AVR_DP_t *dp, uint32_t reg, uint32_t *value) - { return avr_pdi_read(dp, PDI_DATA_32, reg, value); } +static inline bool avr_pdi_read32(avr_pdi_t *pdi, uint32_t reg, uint32_t *value) + { return avr_pdi_read(pdi, PDI_DATA_32, reg, value); } -static bool avr_pdi_read_ind(const AVR_DP_t *const dp, const uint32_t addr, const uint8_t ptr_mode, +static bool avr_pdi_read_ind(const avr_pdi_t *const pdi, const uint32_t addr, const uint8_t ptr_mode, void *const dst, const uint32_t count) { const uint32_t repeat = count - 1U; @@ -244,56 +244,56 @@ static bool avr_pdi_read_ind(const AVR_DP_t *const dp, const uint32_t addr, cons return false; // Run `st ptr ` command = PDI_ST | PDI_MODE_DIR_PTR | PDI_DATA_32; - if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, addr & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (addr >> 8U) & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (addr >> 16U) & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (addr >> 24U) & 0xffU) || result != PDI_EMPTY) + if (avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, command) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, addr & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, (addr >> 8U) & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, (addr >> 16U) & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, (addr >> 24U) & 0xffU) || result != PDI_EMPTY) return false; // Run `repeat ` command = PDI_REPEAT | PDI_DATA_32; - if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, repeat & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (repeat >> 8U) & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (repeat >> 16U) & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, (repeat >> 24U) & 0xffU) || result != PDI_EMPTY) + if (avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, command) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, repeat & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, (repeat >> 8U) & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, (repeat >> 16U) & 0xffU) || result != PDI_EMPTY || + avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, (repeat >> 24U) & 0xffU) || result != PDI_EMPTY) return false; // Run `ld ` command = PDI_LD | ptr_mode; - if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, command) || result != PDI_EMPTY) + if (avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, command) || result != PDI_EMPTY) return false; for (uint32_t i = 0; i < count; ++i) { - if (!avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, data + i, 0)) + if (!avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, data + i, 0)) return false; } return true; } -static bool avr_enable(AVR_DP_t *dp, pdi_key_e what) +static bool avr_enable(avr_pdi_t *pdi, pdi_key_e what) { const char *const key = what == PDI_DEBUG ? pdi_key_debug : pdi_key_nvm; uint8_t result = 0; - if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, PDI_KEY) || result != PDI_EMPTY) + if (avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, PDI_KEY) || result != PDI_EMPTY) return false; for (uint8_t i = 0; i < 8; ++i) { - if (avr_jtag_shift_dr(&jtag_proc, dp->dp_jd_index, &result, key[i]) || result != PDI_EMPTY) + if (avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, key[i]) || result != PDI_EMPTY) return false; } if (what == PDI_NVM) { - while ((avr_pdi_reg_read(dp, PDI_REG_STATUS) & what) != what) + while ((avr_pdi_reg_read(pdi, PDI_REG_STATUS) & what) != what) continue; return true; } else - return (avr_pdi_reg_read(dp, PDI_REG_STATUS) & what) == what; + return (avr_pdi_reg_read(pdi, PDI_REG_STATUS) & what) == what; } -static bool avr_disable(AVR_DP_t *dp, pdi_key_e what) +static bool avr_disable(avr_pdi_t *pdi, pdi_key_e what) { - return avr_pdi_reg_write(dp, PDI_REG_STATUS, ~what); + return avr_pdi_reg_write(pdi, PDI_REG_STATUS, ~what); } void avr_add_flash(target *t, uint32_t start, size_t length) @@ -311,25 +311,25 @@ void avr_add_flash(target *t, uint32_t start, size_t length) target_add_flash(t, f); } -bool avr_ensure_nvm_idle(AVR_DP_t *dp) +bool avr_ensure_nvm_idle(avr_pdi_t *pdi) { - return avr_pdi_write(dp, PDI_DATA_8, AVR_ADDR_NVM_CMD, 0) && - avr_pdi_write(dp, PDI_DATA_8, AVR_ADDR_NVM_DATA, 0xFFU); + return avr_pdi_write(pdi, PDI_DATA_8, AVR_ADDR_NVM_CMD, 0) && + avr_pdi_write(pdi, PDI_DATA_8, AVR_ADDR_NVM_DATA, 0xFFU); } bool avr_attach(target *t) { - AVR_DP_t *dp = t->priv; + avr_pdi_t *pdi = t->priv; volatile struct exception e; - jtag_dev_write_ir(&jtag_proc, dp->dp_jd_index, IR_PDI); + jtag_dev_write_ir(&jtag_proc, pdi->dp_jd_index, IR_PDI); TRY_CATCH (e, EXCEPTION_ALL) { target_reset(t); - if (!avr_enable(dp, PDI_DEBUG)) + if (!avr_enable(pdi, PDI_DEBUG)) return false; target_halt_request(t); - if (!avr_enable(dp, PDI_NVM) || - !avr_ensure_nvm_idle(dp)) + if (!avr_enable(pdi, PDI_NVM) || + !avr_ensure_nvm_idle(pdi)) return false; } return !e.type; @@ -337,28 +337,28 @@ bool avr_attach(target *t) void avr_detach(target *t) { - AVR_DP_t *dp = t->priv; + avr_pdi_t *pdi = t->priv; - avr_disable(dp, PDI_NVM); - avr_disable(dp, PDI_DEBUG); - jtag_dev_write_ir(&jtag_proc, dp->dp_jd_index, IR_BYPASS); + avr_disable(pdi, PDI_NVM); + avr_disable(pdi, PDI_DEBUG); + jtag_dev_write_ir(&jtag_proc, pdi->dp_jd_index, IR_BYPASS); } static void avr_reset(target *t) { - AVR_DP_t *dp = t->priv; - if (!avr_pdi_reg_write(dp, PDI_REG_RESET, PDI_RESET)) + avr_pdi_t *pdi = t->priv; + if (!avr_pdi_reg_write(pdi, PDI_REG_RESET, PDI_RESET)) raise_exception(EXCEPTION_ERROR, "Error resetting device, device in incorrect state"); - if (avr_pdi_reg_read(dp, PDI_REG_STATUS) != 0x00) + if (avr_pdi_reg_read(pdi, PDI_REG_STATUS) != 0x00) { - avr_disable(dp, PDI_NVM); - avr_disable(dp, PDI_DEBUG); + avr_disable(pdi, PDI_NVM); + avr_disable(pdi, PDI_DEBUG); } } static void avr_halt_request(target *t) { - AVR_DP_t *dp = t->priv; + avr_pdi_t *pdi = t->priv; /* To halt the processor we go through a few really specific steps: * Write r4 to 1 to indicate we want to put the processor into debug-based pause * Read r3 and check it's 0x10 which indicates the processor is held in reset and no debugging is active @@ -367,58 +367,58 @@ static void avr_halt_request(target *t) * but that debug pause is requested, and the second should respond 0x04 to indicate the processor is now * in debug pause state (halted) */ - if (!avr_pdi_reg_write(dp, PDI_REG_R4, 1) || - avr_pdi_reg_read(dp, PDI_REG_R3) != 0x10U || - !avr_pdi_reg_write(dp, PDI_REG_RESET, 0) || - avr_pdi_reg_read(dp, PDI_REG_R3) != 0x14U || - avr_pdi_reg_read(dp, PDI_REG_R3) != 0x04U) + if (!avr_pdi_reg_write(pdi, PDI_REG_R4, 1) || + avr_pdi_reg_read(pdi, PDI_REG_R3) != 0x10U || + !avr_pdi_reg_write(pdi, PDI_REG_RESET, 0) || + avr_pdi_reg_read(pdi, PDI_REG_R3) != 0x14U || + avr_pdi_reg_read(pdi, PDI_REG_R3) != 0x04U) raise_exception(EXCEPTION_ERROR, "Error halting device, device in incorrect state"); - dp->halt_reason = TARGET_HALT_REQUEST; + pdi->halt_reason = TARGET_HALT_REQUEST; } static enum target_halt_reason avr_halt_poll(target *t, target_addr *watch) { - AVR_DP_t *dp = t->priv; + avr_pdi_t *pdi = t->priv; (void)watch; - return dp->halt_reason; + return pdi->halt_reason; } static bool avr_check_error(target *t) { - AVR_DP_t *dp = t->priv; - return dp->error_state != pdi_ok; + avr_pdi_t *pdi = t->priv; + return pdi->error_state != pdi_ok; } static void avr_mem_read(target *t, void *dest, target_addr src, size_t len) { - AVR_DP_t *dp = t->priv; + avr_pdi_t *pdi = t->priv; if (target_flash_for_addr(t, src) != NULL) { // This presently assumes src is a Flash address. - if (!avr_pdi_write(dp, PDI_DATA_8, AVR_ADDR_NVM_CMD, AVR_NVM_CMD_READ_NVM) || - !avr_pdi_read_ind(dp, src | PDI_FLASH_OFFSET, PDI_MODE_IND_INCPTR, dest, len) || - !avr_ensure_nvm_idle(dp)) - dp->error_state = pdi_failure; + if (!avr_pdi_write(pdi, PDI_DATA_8, AVR_ADDR_NVM_CMD, AVR_NVM_CMD_READ_NVM) || + !avr_pdi_read_ind(pdi, src | PDI_FLASH_OFFSET, PDI_MODE_IND_INCPTR, dest, len) || + !avr_ensure_nvm_idle(pdi)) + pdi->error_state = pdi_failure; } else if (src >= 0x00800000U) { - if (!avr_pdi_read_ind(dp, src + 0x00800000U, PDI_MODE_IND_INCPTR, dest, len)) - dp->error_state = pdi_failure; + if (!avr_pdi_read_ind(pdi, src + 0x00800000U, PDI_MODE_IND_INCPTR, dest, len)) + pdi->error_state = pdi_failure; } } static void avr_regs_read(target *t, void *data) { - AVR_DP_t *dp = t->priv; + avr_pdi_t *pdi = t->priv; avr_regs *regs = (avr_regs *)data; uint8_t status[3]; uint32_t pc = 0; - if (!avr_pdi_read32(dp, AVR_ADDR_DBG_PC, &pc) || - !avr_pdi_read_ind(dp, AVR_ADDR_CPU_SPL, PDI_MODE_IND_INCPTR, status, 3) || - !avr_pdi_write(dp, PDI_DATA_8, AVR_ADDR_DBG_CTRL, AVR_DBG_READ_REGS) || - !avr_pdi_write(dp, PDI_DATA_32, AVR_ADDR_DBG_CTR, AVR_NUM_REGS) || - !avr_pdi_reg_write(dp, PDI_REG_R4, 1) || - !avr_pdi_read_ind(dp, AVR_ADDR_DBG_SPECIAL, PDI_MODE_IND_PTR, regs->general, 32)) + if (!avr_pdi_read32(pdi, AVR_ADDR_DBG_PC, &pc) || + !avr_pdi_read_ind(pdi, AVR_ADDR_CPU_SPL, PDI_MODE_IND_INCPTR, status, 3) || + !avr_pdi_write(pdi, PDI_DATA_8, AVR_ADDR_DBG_CTRL, AVR_DBG_READ_REGS) || + !avr_pdi_write(pdi, PDI_DATA_32, AVR_ADDR_DBG_CTR, AVR_NUM_REGS) || + !avr_pdi_reg_write(pdi, PDI_REG_R4, 1) || + !avr_pdi_read_ind(pdi, AVR_ADDR_DBG_SPECIAL, PDI_MODE_IND_PTR, regs->general, 32)) raise_exception(EXCEPTION_ERROR, "Error reading registers"); // These aren't in the reads above because regs is a packed struct, which results in compiler errors // Additionally, the program counter is stored in words and points to the next instruction to be executed diff --git a/src/target/jtag_devs.c b/src/target/jtag_devs.c index f881ad53048..d3fdb4b4540 100644 --- a/src/target/jtag_devs.c +++ b/src/target/jtag_devs.c @@ -65,7 +65,7 @@ jtag_dev_descr_t dev_descr[] = { .descr = "Gigadevice BSD."}, {.idcode = 0x0000003F, .idmask = 0x00000FFF, .descr = "Atmel Limited: AVR JTAG-PDI port.", - .handler = avr_jtag_dp_handler}, + .handler = avr_jtag_pdi_handler}, /* Just for fun, unsupported */ {.idcode = 0x8940303F, .idmask = 0xFFFFFFFF, .descr = "ATMega16."}, {.idcode = 0x0792603F, .idmask = 0xFFFFFFFF, .descr = "AT91SAM9261."}, From c50575a70d952804c8c08ca46098ef61c0ad59a9 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 17 Feb 2022 12:54:17 -0500 Subject: [PATCH 41/56] avr: Refactored out avr_pdi_write_ptr() and avr_pdi_repeat() from avr_pdi_read_ind() --- src/target/avr_pdi.c | 52 ++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index eb9fc901bd0..d3aafbdca17 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -234,32 +234,42 @@ static inline bool avr_pdi_read24(avr_pdi_t *pdi, uint32_t reg, uint32_t *value) static inline bool avr_pdi_read32(avr_pdi_t *pdi, uint32_t reg, uint32_t *value) { return avr_pdi_read(pdi, PDI_DATA_32, reg, value); } +// Runs `st ptr ` +static bool avr_pdi_write_ptr(const avr_pdi_t *const pdi, const uint32_t addr) +{ + const uint8_t command = PDI_ST | PDI_MODE_DIR_PTR | PDI_DATA_32; + uint8_t result = 0; + return !avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, command) && result == PDI_EMPTY && + !avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, addr & 0xffU) && result == PDI_EMPTY && + !avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, (addr >> 8U) & 0xffU) && result == PDI_EMPTY && + !avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, (addr >> 16U) & 0xffU) && result == PDI_EMPTY && + !avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, (addr >> 24U) & 0xffU) && result == PDI_EMPTY; +} + +// Runs `repeat ` +static bool avr_pdi_repeat(const avr_pdi_t *const pdi, const uint32_t count) +{ + const uint32_t repeat = count - 1U; + const uint8_t command = PDI_REPEAT | PDI_DATA_32; + uint8_t result = 0; + return !avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, command) && result == PDI_EMPTY && + !avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, repeat & 0xffU) && result == PDI_EMPTY && + !avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, (repeat >> 8U) & 0xffU) && result == PDI_EMPTY && + !avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, (repeat >> 16U) & 0xffU) && result == PDI_EMPTY && + !avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, (repeat >> 24U) & 0xffU) && result == PDI_EMPTY; +} + static bool avr_pdi_read_ind(const avr_pdi_t *const pdi, const uint32_t addr, const uint8_t ptr_mode, void *const dst, const uint32_t count) { - const uint32_t repeat = count - 1U; - uint8_t result = 0, command; - uint8_t *data = (uint8_t *)dst; - if ((ptr_mode & PDI_MODE_MASK) || !count) - return false; - // Run `st ptr ` - command = PDI_ST | PDI_MODE_DIR_PTR | PDI_DATA_32; - if (avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, command) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, addr & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, (addr >> 8U) & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, (addr >> 16U) & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, (addr >> 24U) & 0xffU) || result != PDI_EMPTY) - return false; - // Run `repeat ` - command = PDI_REPEAT | PDI_DATA_32; - if (avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, command) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, repeat & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, (repeat >> 8U) & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, (repeat >> 16U) & 0xffU) || result != PDI_EMPTY || - avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, (repeat >> 24U) & 0xffU) || result != PDI_EMPTY) + const uint8_t command = PDI_LD | ptr_mode; + uint8_t result = 0; + uint8_t *const data = (uint8_t *)dst; + if ((ptr_mode & PDI_MODE_MASK) || !count || + !avr_pdi_write_ptr(pdi, addr) || + !avr_pdi_repeat(pdi, count)) return false; // Run `ld ` - command = PDI_LD | ptr_mode; if (avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, command) || result != PDI_EMPTY) return false; for (uint32_t i = 0; i < count; ++i) From ed84ae40329a8c6e0667cd921a746d060bc61c1b Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 17 Feb 2022 12:54:29 -0500 Subject: [PATCH 42/56] avr: Implemented avr_pdi_write_ind() --- src/target/avr_pdi.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index d3aafbdca17..7753e232bd6 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -280,6 +280,27 @@ static bool avr_pdi_read_ind(const avr_pdi_t *const pdi, const uint32_t addr, co return true; } +static bool avr_pdi_write_ind(const avr_pdi_t *const pdi, const uint32_t addr, const uint8_t ptr_mode, + const void *const src, const uint32_t count) +{ + const uint8_t command = PDI_ST | ptr_mode; + uint8_t result = 0; + const uint8_t *const data = (const uint8_t *)src; + if ((ptr_mode & PDI_MODE_MASK) || !count || + !avr_pdi_write_ptr(pdi, addr) || + !avr_pdi_repeat(pdi, count)) + return false; + // Run `st ` + if (avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, command) || result != PDI_EMPTY) + return false; + for (uint32_t i = 0; i < count; ++i) + { + if (avr_jtag_shift_dr(&jtag_proc, pdi->dp_jd_index, &result, data[i]) || result != PDI_EMPTY) + return false; + } + return true; +} + static bool avr_enable(avr_pdi_t *pdi, pdi_key_e what) { const char *const key = what == PDI_DEBUG ? pdi_key_debug : pdi_key_nvm; From e4e3c45cb16313cda73b4ca6571b01114d35f9a7 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 17 Feb 2022 12:55:24 -0500 Subject: [PATCH 43/56] avr: Implemented Flash erase and write routines --- src/target/avr_pdi.c | 66 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index 7753e232bd6..ac66aee56f5 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -60,9 +60,17 @@ #define AVR_ADDR_NVM 0x010001C0U #define AVR_ADDR_NVM_DATA 0x010001C4U #define AVR_ADDR_NVM_CMD 0x010001CAU +#define AVR_ADDR_NVM_STATUS 0x010001CFU -#define AVR_NVM_CMD_NOP 0x00U -#define AVR_NVM_CMD_READ_NVM 0x43U +#define AVR_NVM_CMD_NOP 0x00U +#define AVR_NVM_CMD_ERASE_FLASH_BUFFER 0x26U +#define AVR_NVM_CMD_WRITE_FLASH_BUFFER 0x23U +#define AVR_NVM_CMD_ERASE_FLASH_PAGE 0x2BU +#define AVR_NVM_CMD_WRITE_FLASH_PAGE 0x2EU +#define AVR_NVM_CMD_READ_NVM 0x43U + +#define AVR_NVM_BUSY 0x80U +#define AVR_NVM_FBUSY 0x40U typedef enum { @@ -82,6 +90,9 @@ static void avr_mem_read(target *t, void *dest, target_addr src, size_t len); static void avr_regs_read(target *t, void *data); +static int avr_flash_erase(struct target_flash *f, target_addr addr, size_t len); +static int avr_flash_write(struct target_flash *f, target_addr dest, const void *src, size_t len); + typedef struct __attribute__((packed)) { uint8_t general[32]; // r0-r31 @@ -338,6 +349,8 @@ void avr_add_flash(target *t, uint32_t start, size_t length) f->start = start; f->length = length; f->blocksize = 0x100; + f->erase = avr_flash_erase; + f->write = avr_flash_write; f->erased = 0xff; target_add_flash(t, f); } @@ -458,3 +471,52 @@ static void avr_regs_read(target *t, void *data) regs->sp = status[0] | (status[1] << 8); regs->sreg = status[2]; } + +static int avr_flash_erase(struct target_flash *f, target_addr addr, size_t len) +{ + avr_pdi_t *pdi = f->t->priv; + for (size_t i = 0; i < len; i += f->blocksize) + { + uint8_t status = 0; + if (!avr_pdi_write(pdi, PDI_DATA_8, AVR_ADDR_NVM_CMD, AVR_NVM_CMD_ERASE_FLASH_PAGE) || + !avr_pdi_write(pdi, PDI_DATA_8, (addr + i) | PDI_FLASH_OFFSET, 0x55U)) + return 1; + + while (avr_pdi_read8(pdi, AVR_ADDR_NVM_STATUS, &status) && + (status & (AVR_NVM_BUSY | AVR_NVM_FBUSY)) == (AVR_NVM_BUSY | AVR_NVM_FBUSY)) + continue; + + if (!avr_ensure_nvm_idle(pdi) || + // This can only happen if the read failed. + (status & (AVR_NVM_BUSY | AVR_NVM_FBUSY)) != 0) + return 1; + } + return 0; +} + +static int avr_flash_write(struct target_flash *f, target_addr dest, const void *src, size_t len) +{ + avr_pdi_t *pdi = f->t->priv; + const uint8_t *const buffer = (const uint8_t *)src; + for (size_t i = 0; i < len; i += f->blocksize) + { + uint8_t status = 0; + const size_t amount = MIN(f->blocksize, len - i); + const uint32_t addr = (dest + i) | PDI_FLASH_OFFSET; + if (!avr_pdi_write(pdi, PDI_DATA_8, AVR_ADDR_NVM_CMD, AVR_NVM_CMD_WRITE_FLASH_BUFFER) || + !avr_pdi_write_ind(pdi, addr, PDI_MODE_IND_INCPTR, buffer + i, amount) || + !avr_pdi_write(pdi, PDI_DATA_8, AVR_ADDR_NVM_CMD, AVR_NVM_CMD_WRITE_FLASH_PAGE) || + !avr_pdi_write(pdi, PDI_DATA_8, addr, 0xFFU)) + return 1; + + while (avr_pdi_read8(pdi, AVR_ADDR_NVM_STATUS, &status) && + (status & (AVR_NVM_BUSY | AVR_NVM_FBUSY)) == (AVR_NVM_BUSY | AVR_NVM_FBUSY)) + continue; + + if (!avr_ensure_nvm_idle(pdi) || + // This can only happen if the read failed. + (status & (AVR_NVM_BUSY | AVR_NVM_FBUSY)) != 0) + return 1; + } + return 0; +} From a75d1ca64ded86b0e9b6f6dbb559cbfd853217f7 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 17 Feb 2022 14:24:44 -0500 Subject: [PATCH 44/56] avr: Added a guard to stop the processor getting spuriously extra reset --- src/target/avr_pdi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index ac66aee56f5..e6b7acdd831 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -391,6 +391,9 @@ void avr_detach(target *t) static void avr_reset(target *t) { avr_pdi_t *pdi = t->priv; + // We only actually want to do this if the target is not presently attached as this resets the NVM and debug enables + if (target_attached(t)) + return; if (!avr_pdi_reg_write(pdi, PDI_REG_RESET, PDI_RESET)) raise_exception(EXCEPTION_ERROR, "Error resetting device, device in incorrect state"); if (avr_pdi_reg_read(pdi, PDI_REG_STATUS) != 0x00) From 486a4a1016e70f52d7d65f714c45eb2eb8fc0918 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 19 Feb 2022 20:26:21 -0500 Subject: [PATCH 45/56] avr: Implemented an erase command to clean out Flash --- src/target/avr_pdi.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index e6b7acdd831..f67131ca7a7 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -81,6 +81,13 @@ typedef enum static const char pdi_key_nvm[] = {0xff, 0x88, 0xd8, 0xcd, 0x45, 0xab, 0x89, 0x12}; static const char pdi_key_debug[] = {0x21, 0x81, 0x7c, 0x9f, 0xd4, 0x2d, 0x21, 0x3a}; +static bool avr_erase(target *t, int argc, char **argv); + +const struct command_s avr_cmd_list[] = { + {"erase", (cmd_handler)avr_erase, "Erase (part of) a device"}, + {NULL, NULL, NULL} +}; + static void avr_reset(target *t); static void avr_halt_request(target *t); static enum target_halt_reason avr_halt_poll(target *t, target_addr *watch); @@ -141,6 +148,8 @@ bool avr_pdi_init(avr_pdi_t *pdi) // a suitable registers structure. t->regs_size = sizeof(avr_regs); + target_add_commands(t, avr_cmd_list, "Atmel AVR"); + if (atxmega_probe(t)) return true; pdi->halt_reason = TARGET_HALT_RUNNING; @@ -523,3 +532,23 @@ static int avr_flash_write(struct target_flash *f, target_addr dest, const void } return 0; } + +static bool avr_erase(target *t, int argc, char **argv) +{ + if (argc < 2) + tc_printf(t, "usage: monitor erase () \n"); + else + { + target_addr begin = 0; + size_t length = 0; + if (argc >= 3) + { + begin = atol(argv[1]); + length = atol(argv[2]); + } + else + length = atol(argv[1]); + target_flash_erase(t, begin, length); + } + return true; +} From e6a27a95bf36c95f55a30f120829d22dbb4bf805 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sun, 20 Feb 2022 00:24:22 -0500 Subject: [PATCH 46/56] hosted: Fixed an error introduced by the avr_pdi_t refactor --- src/platforms/hosted/platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platforms/hosted/platform.c b/src/platforms/hosted/platform.c index 4ac09997930..c10666963dc 100644 --- a/src/platforms/hosted/platform.c +++ b/src/platforms/hosted/platform.c @@ -255,7 +255,7 @@ int platform_jtag_dp_init(ADIv5_DP_t *dp) int platform_avr_jtag_pdi_init(avr_pdi_t *pdi) { - (void)dp; + (void)pdi; return 0; } From 2de8dab6f43495aa5b0e8607c1b0efd315365e8f Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sun, 20 Feb 2022 00:25:41 -0500 Subject: [PATCH 47/56] avr: Added support in avr_pdi_s for breakpoints and storing the program counter --- src/target/avr.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/target/avr.h b/src/target/avr.h index dfec001f280..787e71fe662 100644 --- a/src/target/avr.h +++ b/src/target/avr.h @@ -10,12 +10,18 @@ enum avr_error_e pdi_failure, }; -typedef struct Atmel_DP_s { +#define AVR_MAX_BREAKPOINTS 2 + +typedef struct avr_pdi_s { uint32_t idcode; uint8_t dp_jd_index; enum target_halt_reason halt_reason; enum avr_error_e error_state; + target_addr programCounter; + + bool hw_breakpoint[AVR_MAX_BREAKPOINTS]; + uint8_t hw_breakpoint_max; } avr_pdi_t; bool avr_pdi_init(avr_pdi_t *pdi); From d20d8f63afa3f565034fff38f047954e395ae160 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sun, 20 Feb 2022 00:26:24 -0500 Subject: [PATCH 48/56] avr_pdi: Cleaned up the debug print in avr_jtag_shift_dr() to always emit 2 nibbles --- src/target/avr_jtagdp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/avr_jtagdp.c b/src/target/avr_jtagdp.c index e3d303aeb3f..77b1ff6b30c 100644 --- a/src/target/avr_jtagdp.c +++ b/src/target/avr_jtagdp.c @@ -51,6 +51,6 @@ bool avr_jtag_shift_dr(jtag_proc_t *jp, uint8_t jd_index, uint8_t *dout, const u for (uint8_t i = 0; i < 8; ++i) result ^= (data[0] >> i) & 1U; *dout = data[0]; - DEBUG_INFO("Sent 0x%x to target, response was 0x%x (0x%x)\n", din, data[0], data[1]); + DEBUG_INFO("Sent 0x%02x to target, response was 0x%02x (0x%x)\n", din, data[0], data[1]); return result == data[1]; } From ddafc2c9dfbd76f2da3f5cb6ec64f61619263871 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sun, 20 Feb 2022 00:27:49 -0500 Subject: [PATCH 49/56] avr: Added some additional r3 (debug status) checks to attach and regs_read, and fixed the order of operations in regs_read --- src/target/avr_pdi.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index f67131ca7a7..e385b6866f8 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -382,7 +382,8 @@ bool avr_attach(target *t) return false; target_halt_request(t); if (!avr_enable(pdi, PDI_NVM) || - !avr_ensure_nvm_idle(pdi)) + !avr_ensure_nvm_idle(pdi) || + avr_pdi_reg_read(pdi, PDI_REG_R3) != 0x04U) return false; } return !e.type; @@ -410,6 +411,7 @@ static void avr_reset(target *t) avr_disable(pdi, PDI_NVM); avr_disable(pdi, PDI_DEBUG); } + pdi->programCounter = 0; } static void avr_halt_request(target *t) @@ -471,10 +473,12 @@ static void avr_regs_read(target *t, void *data) uint32_t pc = 0; if (!avr_pdi_read32(pdi, AVR_ADDR_DBG_PC, &pc) || !avr_pdi_read_ind(pdi, AVR_ADDR_CPU_SPL, PDI_MODE_IND_INCPTR, status, 3) || - !avr_pdi_write(pdi, PDI_DATA_8, AVR_ADDR_DBG_CTRL, AVR_DBG_READ_REGS) || + !avr_pdi_write(pdi, PDI_DATA_32, AVR_ADDR_DBG_PC, 0) || !avr_pdi_write(pdi, PDI_DATA_32, AVR_ADDR_DBG_CTR, AVR_NUM_REGS) || + !avr_pdi_write(pdi, PDI_DATA_8, AVR_ADDR_DBG_CTRL, AVR_DBG_READ_REGS) || !avr_pdi_reg_write(pdi, PDI_REG_R4, 1) || - !avr_pdi_read_ind(pdi, AVR_ADDR_DBG_SPECIAL, PDI_MODE_IND_PTR, regs->general, 32)) + !avr_pdi_read_ind(pdi, AVR_ADDR_DBG_SPECIAL, PDI_MODE_IND_PTR, regs->general, 32) || + avr_pdi_reg_read(pdi, PDI_REG_R3) != 0x04U) raise_exception(EXCEPTION_ERROR, "Error reading registers"); // These aren't in the reads above because regs is a packed struct, which results in compiler errors // Additionally, the program counter is stored in words and points to the next instruction to be executed @@ -482,6 +486,7 @@ static void avr_regs_read(target *t, void *data) regs->pc = (pc - 1) << 1; regs->sp = status[0] | (status[1] << 8); regs->sreg = status[2]; + pdi->programCounter = pc - 1; } static int avr_flash_erase(struct target_flash *f, target_addr addr, size_t len) From 3779f89da7eeeda2240a91194ee20ba2c56f23b4 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sun, 20 Feb 2022 00:30:14 -0500 Subject: [PATCH 50/56] atxmega: Added configuration to set the max breakpoints on each target --- src/target/atxmega.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/target/atxmega.c b/src/target/atxmega.c index 5abc9dcab9b..69202bee9de 100644 --- a/src/target/atxmega.c +++ b/src/target/atxmega.c @@ -54,6 +54,8 @@ static const char tdesc_xmega6[] = bool atxmega_probe(target *t) { + avr_pdi_t *pdi = t->priv; + switch (t->idcode) { case IDCODE_XMEGA256A3U: t->core = "ATXMega256A3U"; @@ -65,6 +67,7 @@ bool atxmega_probe(target *t) avr_add_flash(t, 0x00000000, 0x40000); avr_add_flash(t, 0x00040000, 0x2000); t->tdesc = tdesc_xmega6; + pdi->hw_breakpoint_max = 2; return true; } return false; From d5747e28f43a3c19fe7dc930e5e07a974f67b5be Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sun, 20 Feb 2022 04:31:17 -0500 Subject: [PATCH 51/56] avr: Implemented support for setting and clearing breakpoints --- src/target/avr.h | 3 +- src/target/avr_jtagdp.c | 1 + src/target/avr_pdi.c | 61 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/src/target/avr.h b/src/target/avr.h index 787e71fe662..b2173ef7bcc 100644 --- a/src/target/avr.h +++ b/src/target/avr.h @@ -20,7 +20,8 @@ typedef struct avr_pdi_s { enum avr_error_e error_state; target_addr programCounter; - bool hw_breakpoint[AVR_MAX_BREAKPOINTS]; + target_addr hw_breakpoint[AVR_MAX_BREAKPOINTS]; + uint8_t hw_breakpoint_enabled; uint8_t hw_breakpoint_max; } avr_pdi_t; diff --git a/src/target/avr_jtagdp.c b/src/target/avr_jtagdp.c index 77b1ff6b30c..149d3195c0c 100644 --- a/src/target/avr_jtagdp.c +++ b/src/target/avr_jtagdp.c @@ -18,6 +18,7 @@ void avr_jtag_pdi_handler(uint8_t jd_index, uint32_t j_idcode) pdi->dp_jd_index = jd_index; pdi->idcode = jtag_devs[jd_index].jd_idcode; pdi->error_state = pdi_ok; + pdi->hw_breakpoint_enabled = 0; if ((PC_HOSTED == 0) || (!platform_avr_jtag_pdi_init(pdi))) { // } diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index e385b6866f8..c028311bd42 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -52,6 +52,9 @@ #define AVR_ADDR_DBG_CTRL 0x0000000AU #define AVR_ADDR_DBG_SPECIAL 0x0000000CU +#define AVR_DBG_BREAK_ENABLED 0x80000000U +#define AVR_DBG_BREAK_MASK 0x00FFFFFFU + #define AVR_DBG_READ_REGS 0x11U #define AVR_NUM_REGS 32 @@ -100,6 +103,9 @@ static void avr_regs_read(target *t, void *data); static int avr_flash_erase(struct target_flash *f, target_addr addr, size_t len); static int avr_flash_write(struct target_flash *f, target_addr dest, const void *src, size_t len); +static int avr_breakwatch_set(target *t, struct breakwatch *bw); +static int avr_breakwatch_clear(target *t, struct breakwatch *bw); + typedef struct __attribute__((packed)) { uint8_t general[32]; // r0-r31 @@ -143,11 +149,15 @@ bool avr_pdi_init(avr_pdi_t *pdi) t->reset = avr_reset; t->halt_request = avr_halt_request; + t->halt_resume = avr_halt_resume; t->halt_poll = avr_halt_poll; // Unlike on an ARM processor, where this is the length of a table, here we return the size of // a suitable registers structure. t->regs_size = sizeof(avr_regs); + t->breakwatch_set = avr_breakwatch_set; + t->breakwatch_clear = avr_breakwatch_clear; + target_add_commands(t, avr_cmd_list, "Atmel AVR"); if (atxmega_probe(t)) @@ -538,6 +548,57 @@ static int avr_flash_write(struct target_flash *f, target_addr dest, const void return 0; } +static int avr_breakwatch_set(target *t, struct breakwatch *bw) +{ + avr_pdi_t *pdi = t->priv; + switch (bw->type) + { + case TARGET_BREAK_HARD: + { + const uint8_t bp = pdi->hw_breakpoint_enabled; + if (bp == pdi->hw_breakpoint_max) + return -1; + pdi->hw_breakpoint[bp] = AVR_DBG_BREAK_ENABLED | bw->addr; + bw->reserved[0] = pdi->hw_breakpoint[bp]; + ++pdi->hw_breakpoint_enabled; + return 0; + } + default: + return 1; + } +} + +static int avr_breakwatch_clear(target *t, struct breakwatch *bw) +{ + avr_pdi_t *pdi = t->priv; + switch (bw->type) + { + case TARGET_BREAK_HARD: + { + uint8_t bp = 0; + // Locate the breakpoint + for (; bp < pdi->hw_breakpoint_max; ++bp) + { + if (pdi->hw_breakpoint[bp] == bw->reserved[0]) + break; + } + // Fail if we cannot find it + if (bp == pdi->hw_breakpoint_max) + return -1; + // Shuffle the remaining breakpoints. + for (; bp < (pdi->hw_breakpoint_enabled - 1U); ++bp) + pdi->hw_breakpoint[bp] = pdi->hw_breakpoint[bp + 1]; + // Cleanup by disabling the breakpoint and fixing the count + pdi->hw_breakpoint[bp] = 0; + bw->reserved[0] = 0; + --pdi->hw_breakpoint_enabled; + return 0; + } + default: + return 1; + } +} + static bool avr_erase(target *t, int argc, char **argv) { if (argc < 2) From 50df05e139912a7aeb9c2dc6d4b89270ef3f4ac9 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sun, 20 Feb 2022 04:32:05 -0500 Subject: [PATCH 52/56] avr: Implemented the code required to write the current breakpoint configuration out to the target --- src/target/avr_pdi.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index c028311bd42..af80a4c7da4 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -52,6 +52,11 @@ #define AVR_ADDR_DBG_CTRL 0x0000000AU #define AVR_ADDR_DBG_SPECIAL 0x0000000CU +#define AVR_ADDR_DBG_BREAK_BASE 0x00000020U +#define AVR_ADDR_DBG_BREAK_UNK1 0x00000040U +#define AVR_ADDR_DBG_BREAK_UNK2 0x00000044U +#define AVR_ADDR_DBG_BREAK_UNK3 0x00000048U + #define AVR_DBG_BREAK_ENABLED 0x80000000U #define AVR_DBG_BREAK_MASK 0x00FFFFFFU @@ -380,6 +385,24 @@ bool avr_ensure_nvm_idle(avr_pdi_t *pdi) avr_pdi_write(pdi, PDI_DATA_8, AVR_ADDR_NVM_DATA, 0xFFU); } +static bool avr_config_breakpoints(avr_pdi_t *pdi) +{ + const uint32_t addr_breakpoint_counter = AVR_ADDR_DBG_BREAK_BASE + (pdi->hw_breakpoint_max * 4); + const uint16_t breakpoint_count = pdi->hw_breakpoint_enabled << 8U; + for (uint8_t i = 0; i < pdi->hw_breakpoint_max; ++i) + { + if (!avr_pdi_write(pdi, PDI_DATA_32, AVR_ADDR_DBG_BREAK_BASE + (i * 4), + pdi->hw_breakpoint[i] & AVR_DBG_BREAK_MASK)) + return false; + } + if (!avr_pdi_write(pdi, PDI_DATA_8, AVR_ADDR_DBG_BREAK_UNK1, 0) || + !avr_pdi_write(pdi, PDI_DATA_8, AVR_ADDR_DBG_BREAK_UNK2, 0) || + !avr_pdi_write(pdi, PDI_DATA_16, addr_breakpoint_counter, breakpoint_count) || + !avr_pdi_write(pdi, PDI_DATA_8, AVR_ADDR_DBG_BREAK_UNK3, 0)) + return false; + return true; +} + bool avr_attach(target *t) { avr_pdi_t *pdi = t->priv; From 91aa86b1e048fe313facdeb12e25e73b4b89d75c Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sun, 20 Feb 2022 04:34:31 -0500 Subject: [PATCH 53/56] avr: Implemented halt_resume and proper detection for running vs breakpoint hit --- src/target/avr_pdi.c | 46 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index af80a4c7da4..0e03d439161 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -98,6 +98,7 @@ const struct command_s avr_cmd_list[] = { static void avr_reset(target *t); static void avr_halt_request(target *t); +static void avr_halt_resume(target *t, bool step); static enum target_halt_reason avr_halt_poll(target *t, target_addr *watch); static bool avr_check_error(target *t); @@ -467,9 +468,54 @@ static void avr_halt_request(target *t) pdi->halt_reason = TARGET_HALT_REQUEST; } +static void avr_halt_resume(target *t, bool step) +{ + avr_pdi_t *pdi = t->priv; + if (step) + { + const target_addr currentPC = pdi->programCounter; + const target_addr nextPC = currentPC + 1U; + /* To do a single step, we run the following steps: + * Write the debug control register to 4, which puts the processor in a temporary breakpoint mode + * Write the debug counter register with the address to stop execution on + * Write the program counter with the address to resume execution on + */ + if (avr_pdi_reg_read(pdi, PDI_REG_R3) != 0x04U || + !avr_pdi_write(pdi, PDI_DATA_8, AVR_ADDR_DBG_CTRL, 4) || + !avr_pdi_write(pdi, PDI_DATA_32, AVR_ADDR_DBG_CTR, nextPC) || + !avr_pdi_write(pdi, PDI_DATA_32, AVR_ADDR_DBG_PC, currentPC) || + !avr_pdi_reg_write(pdi, PDI_REG_R4, 1) || + avr_pdi_reg_read(pdi, PDI_REG_R3) != 0x04U || + avr_pdi_reg_read(pdi, PDI_REG_STATUS) != 0x06U) + raise_exception(EXCEPTION_ERROR, "Error resuming device, device in incorrect state"); + pdi->halt_reason = TARGET_HALT_STEPPING; + } + else + { + /* To resume the processor we go through the following specific steps: + * Write the program counter to ensure we start where we expect + * Then we release the externally (PDI) applied reset + * We then poke the debug control register to indicate debug-supervised run + * Ensure that PDI is still in debug mode (r4 = 1) + * Read r3 to see that the processor is resuming + */ + if (avr_pdi_reg_read(pdi, PDI_REG_R3) != 0x04U || + !avr_config_breakpoints(pdi) || + !avr_pdi_write(pdi, PDI_DATA_32, AVR_ADDR_DBG_PC, pdi->programCounter) || + !avr_pdi_reg_write(pdi, PDI_REG_RESET, 0) || + !avr_pdi_write(pdi, PDI_DATA_8, AVR_ADDR_DBG_CTRL, 0) || + !avr_pdi_reg_write(pdi, PDI_REG_R4, 1)) + raise_exception(EXCEPTION_ERROR, "Error resuming device, device in incorrect state"); + pdi->halt_reason = TARGET_HALT_RUNNING; + } +} + static enum target_halt_reason avr_halt_poll(target *t, target_addr *watch) { avr_pdi_t *pdi = t->priv; + if (pdi->halt_reason == TARGET_HALT_RUNNING && + avr_pdi_reg_read(pdi, PDI_REG_R3) == 0x04U) + pdi->halt_reason = TARGET_HALT_BREAKPOINT; (void)watch; return pdi->halt_reason; } From 0e2b322448846ee0c7a1f9f8b2ff0a89c007b47a Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sun, 20 Feb 2022 04:34:57 -0500 Subject: [PATCH 54/56] avr: const and static correctness improvements --- src/target/avr_pdi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index 0e03d439161..c8462fa5689 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -380,7 +380,7 @@ void avr_add_flash(target *t, uint32_t start, size_t length) target_add_flash(t, f); } -bool avr_ensure_nvm_idle(avr_pdi_t *pdi) +static bool avr_ensure_nvm_idle(avr_pdi_t *pdi) { return avr_pdi_write(pdi, PDI_DATA_8, AVR_ADDR_NVM_CMD, 0) && avr_pdi_write(pdi, PDI_DATA_8, AVR_ADDR_NVM_DATA, 0xFFU); @@ -468,7 +468,7 @@ static void avr_halt_request(target *t) pdi->halt_reason = TARGET_HALT_REQUEST; } -static void avr_halt_resume(target *t, bool step) +static void avr_halt_resume(target *t, const bool step) { avr_pdi_t *pdi = t->priv; if (step) From dd941193a61723b18a1b76d4611c558c82f2dc0d Mon Sep 17 00:00:00 2001 From: dragonmux Date: Tue, 15 Mar 2022 08:58:11 -0400 Subject: [PATCH 55/56] avr_jtagdp: Fixed the signature of avr_jtag_pdi_handler to match with the change in #978 --- src/target/avr.h | 2 +- src/target/avr_jtagdp.c | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/target/avr.h b/src/target/avr.h index b2173ef7bcc..b43dd51bac1 100644 --- a/src/target/avr.h +++ b/src/target/avr.h @@ -27,7 +27,7 @@ typedef struct avr_pdi_s { bool avr_pdi_init(avr_pdi_t *pdi); -void avr_jtag_pdi_handler(uint8_t jd_index, uint32_t j_idcode); +void avr_jtag_pdi_handler(uint8_t jd_index); int platform_avr_jtag_pdi_init(avr_pdi_t *pdi); bool avr_jtag_shift_dr(jtag_proc_t *jp, uint8_t jd_index, uint8_t *dout, const uint8_t din); diff --git a/src/target/avr_jtagdp.c b/src/target/avr_jtagdp.c index 149d3195c0c..1fc093285f0 100644 --- a/src/target/avr_jtagdp.c +++ b/src/target/avr_jtagdp.c @@ -6,15 +6,13 @@ #define PDI_DELAY 0xDBU -void avr_jtag_pdi_handler(uint8_t jd_index, uint32_t j_idcode) +void avr_jtag_pdi_handler(uint8_t jd_index) { avr_pdi_t *pdi = calloc(1, sizeof(*pdi)); if (!pdi) { /* calloc failed: heap exhaustion */ DEBUG_WARN("calloc: failed in %s\n", __func__); return; } - (void)j_idcode; - pdi->dp_jd_index = jd_index; pdi->idcode = jtag_devs[jd_index].jd_idcode; pdi->error_state = pdi_ok; From ee3e2b00d91fbf5aeb6039332b94faf814ab9af7 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 19 Mar 2022 00:23:14 -0400 Subject: [PATCH 56/56] avr: Cleaned up the breakpoint configuration code, making it more robust --- src/target/atxmega.c | 2 +- src/target/avr.h | 4 ++-- src/target/avr_jtagdp.c | 2 +- src/target/avr_pdi.c | 44 ++++++++++++++++++++++++++--------------- 4 files changed, 32 insertions(+), 20 deletions(-) diff --git a/src/target/atxmega.c b/src/target/atxmega.c index 69202bee9de..8131fc254fe 100644 --- a/src/target/atxmega.c +++ b/src/target/atxmega.c @@ -67,7 +67,7 @@ bool atxmega_probe(target *t) avr_add_flash(t, 0x00000000, 0x40000); avr_add_flash(t, 0x00040000, 0x2000); t->tdesc = tdesc_xmega6; - pdi->hw_breakpoint_max = 2; + pdi->hw_breakpoints_max = 2; return true; } return false; diff --git a/src/target/avr.h b/src/target/avr.h index b43dd51bac1..c23675c41f8 100644 --- a/src/target/avr.h +++ b/src/target/avr.h @@ -21,8 +21,8 @@ typedef struct avr_pdi_s { target_addr programCounter; target_addr hw_breakpoint[AVR_MAX_BREAKPOINTS]; - uint8_t hw_breakpoint_enabled; - uint8_t hw_breakpoint_max; + uint32_t hw_breakpoints_enabled; + uint32_t hw_breakpoints_max; } avr_pdi_t; bool avr_pdi_init(avr_pdi_t *pdi); diff --git a/src/target/avr_jtagdp.c b/src/target/avr_jtagdp.c index 1fc093285f0..a762522cebc 100644 --- a/src/target/avr_jtagdp.c +++ b/src/target/avr_jtagdp.c @@ -16,7 +16,7 @@ void avr_jtag_pdi_handler(uint8_t jd_index) pdi->dp_jd_index = jd_index; pdi->idcode = jtag_devs[jd_index].jd_idcode; pdi->error_state = pdi_ok; - pdi->hw_breakpoint_enabled = 0; + pdi->hw_breakpoints_enabled = 0; if ((PC_HOSTED == 0) || (!platform_avr_jtag_pdi_init(pdi))) { // } diff --git a/src/target/avr_pdi.c b/src/target/avr_pdi.c index c8462fa5689..55c87e15f47 100644 --- a/src/target/avr_pdi.c +++ b/src/target/avr_pdi.c @@ -386,15 +386,26 @@ static bool avr_ensure_nvm_idle(avr_pdi_t *pdi) avr_pdi_write(pdi, PDI_DATA_8, AVR_ADDR_NVM_DATA, 0xFFU); } -static bool avr_config_breakpoints(avr_pdi_t *pdi) +static bool avr_config_breakpoints(avr_pdi_t *pdi, const bool step) { - const uint32_t addr_breakpoint_counter = AVR_ADDR_DBG_BREAK_BASE + (pdi->hw_breakpoint_max * 4); - const uint16_t breakpoint_count = pdi->hw_breakpoint_enabled << 8U; - for (uint8_t i = 0; i < pdi->hw_breakpoint_max; ++i) + const uint32_t addr_breakpoint_counter = AVR_ADDR_DBG_BREAK_BASE + (pdi->hw_breakpoints_max * 4); + const uint16_t breakpoint_count = step ? 0U : (pdi->hw_breakpoints_enabled << 8U); + if (step) { - if (!avr_pdi_write(pdi, PDI_DATA_32, AVR_ADDR_DBG_BREAK_BASE + (i * 4), - pdi->hw_breakpoint[i] & AVR_DBG_BREAK_MASK)) - return false; + for (uint8_t i = 0; i < pdi->hw_breakpoints_max; ++i) + { + if (!avr_pdi_write(pdi, PDI_DATA_32, AVR_ADDR_DBG_BREAK_BASE + (i * 4), 0U)) + return false; + } + } + else + { + for (uint8_t i = 0; i < pdi->hw_breakpoints_max; ++i) + { + if (!avr_pdi_write(pdi, PDI_DATA_32, AVR_ADDR_DBG_BREAK_BASE + (i * 4), + pdi->hw_breakpoint[i] & AVR_DBG_BREAK_MASK)) + return false; + } } if (!avr_pdi_write(pdi, PDI_DATA_8, AVR_ADDR_DBG_BREAK_UNK1, 0) || !avr_pdi_write(pdi, PDI_DATA_8, AVR_ADDR_DBG_BREAK_UNK2, 0) || @@ -481,13 +492,14 @@ static void avr_halt_resume(target *t, const bool step) * Write the program counter with the address to resume execution on */ if (avr_pdi_reg_read(pdi, PDI_REG_R3) != 0x04U || + !avr_config_breakpoints(pdi, step) || !avr_pdi_write(pdi, PDI_DATA_8, AVR_ADDR_DBG_CTRL, 4) || !avr_pdi_write(pdi, PDI_DATA_32, AVR_ADDR_DBG_CTR, nextPC) || !avr_pdi_write(pdi, PDI_DATA_32, AVR_ADDR_DBG_PC, currentPC) || !avr_pdi_reg_write(pdi, PDI_REG_R4, 1) || avr_pdi_reg_read(pdi, PDI_REG_R3) != 0x04U || avr_pdi_reg_read(pdi, PDI_REG_STATUS) != 0x06U) - raise_exception(EXCEPTION_ERROR, "Error resuming device, device in incorrect state"); + raise_exception(EXCEPTION_ERROR, "Error stepping device, device in incorrect state"); pdi->halt_reason = TARGET_HALT_STEPPING; } else @@ -500,7 +512,7 @@ static void avr_halt_resume(target *t, const bool step) * Read r3 to see that the processor is resuming */ if (avr_pdi_reg_read(pdi, PDI_REG_R3) != 0x04U || - !avr_config_breakpoints(pdi) || + !avr_config_breakpoints(pdi, step) || !avr_pdi_write(pdi, PDI_DATA_32, AVR_ADDR_DBG_PC, pdi->programCounter) || !avr_pdi_reg_write(pdi, PDI_REG_RESET, 0) || !avr_pdi_write(pdi, PDI_DATA_8, AVR_ADDR_DBG_CTRL, 0) || @@ -624,12 +636,12 @@ static int avr_breakwatch_set(target *t, struct breakwatch *bw) { case TARGET_BREAK_HARD: { - const uint8_t bp = pdi->hw_breakpoint_enabled; - if (bp == pdi->hw_breakpoint_max) + const uint8_t bp = pdi->hw_breakpoints_enabled; + if (bp == pdi->hw_breakpoints_max) return -1; pdi->hw_breakpoint[bp] = AVR_DBG_BREAK_ENABLED | bw->addr; bw->reserved[0] = pdi->hw_breakpoint[bp]; - ++pdi->hw_breakpoint_enabled; + ++pdi->hw_breakpoints_enabled; return 0; } default: @@ -646,21 +658,21 @@ static int avr_breakwatch_clear(target *t, struct breakwatch *bw) { uint8_t bp = 0; // Locate the breakpoint - for (; bp < pdi->hw_breakpoint_max; ++bp) + for (; bp < pdi->hw_breakpoints_max; ++bp) { if (pdi->hw_breakpoint[bp] == bw->reserved[0]) break; } // Fail if we cannot find it - if (bp == pdi->hw_breakpoint_max) + if (bp == pdi->hw_breakpoints_max) return -1; // Shuffle the remaining breakpoints. - for (; bp < (pdi->hw_breakpoint_enabled - 1U); ++bp) + for (; bp < (pdi->hw_breakpoints_enabled - 1U); ++bp) pdi->hw_breakpoint[bp] = pdi->hw_breakpoint[bp + 1]; // Cleanup by disabling the breakpoint and fixing the count pdi->hw_breakpoint[bp] = 0; bw->reserved[0] = 0; - --pdi->hw_breakpoint_enabled; + --pdi->hw_breakpoints_enabled; return 0; } default: