From ff3fd1c448c263ee07df252251e8f532f1c31021 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Wed, 25 Mar 2026 16:59:53 +0000 Subject: [PATCH 01/12] Improve comments --- src/avr.c | 2 +- src/avrcache.c | 3 ++- src/update.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/avr.c b/src/avr.c index 99f5e786..ed91c17e 100644 --- a/src/avr.c +++ b/src/avr.c @@ -1254,7 +1254,7 @@ int avr_mem_bitmask(const AVRPART *p, const AVRMEM *mem, int addr) { return bitmask; } -// Bitmask for ISP programming (classic parts only) +// Bitmask for verification after ISP programming (classic parts only) static uint8_t get_fuse_bitmask(const AVRMEM *m) { int ret = 0xFF; diff --git a/src/avrcache.c b/src/avrcache.c index 82022c26..37bea64b 100644 --- a/src/avrcache.c +++ b/src/avrcache.c @@ -76,7 +76,7 @@ * avr_chip_erase_cached() erases the chip and discards pending writes() to * flash or EEPROM. It presets the flash cache to all 0xff alleviating the * need to read from the device flash. However, if the programmer serves - * bootloaders is_spm(pgm) then the flash cache is reset + * bootloaders, recognised by is_spm(pgm), then the flash cache is reset * instead, necessitating flash memory be fetched from the device on first * read; the reason for this is that bootloaders emulate chip erase and they * won't overwrite themselves (some bootloaders, eg, optiboot ignore chip @@ -142,6 +142,7 @@ int avr_has_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *me mem->size > 0 && mem->size%mem->page_size == 0 && mem_is_paged_type(mem) && !(p && avr_mem_exclude(pgm, p, mem)); } +// Sanity only: guard against a user setting pgm->xyz_byte to avr_xyz_read_byte_cached (AVRDUDE doesn't) #define fallback_read_byte (pgm->read_byte != avr_read_byte_cached? led_read_byte: avr_read_byte_default) #define fallback_write_byte (pgm->write_byte != avr_write_byte_cached? led_write_byte: avr_write_byte_default) diff --git a/src/update.c b/src/update.c index 0fb5ac2c..d03e0c3f 100644 --- a/src/update.c +++ b/src/update.c @@ -529,7 +529,7 @@ static int update_avr_write(const PROGRAMMER *pgm, const AVRPART *p, const AVRME if(rc < 0) return -1; - // @@@ has there has been output in the meantime to make the ", x bytes written" look out of place? + // @@@ has there been output in the meantime to make the ", x bytes written" look out of place? if(pbar && !(flags & UF_VERIFY)) pmsg_info("%d byte%s of %s written", fs.nbytes, str_plural(fs.nbytes), m_name); else if(!pbar) From 919bb1e83b1f84d6ac87fb28ff1f5b6250e31e30 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Wed, 25 Mar 2026 17:02:36 +0000 Subject: [PATCH 02/12] Improve fallback_read/write_byte() error messaging --- src/avrcache.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/avrcache.c b/src/avrcache.c index 37bea64b..da9b768b 100644 --- a/src/avrcache.c +++ b/src/avrcache.c @@ -142,9 +142,19 @@ int avr_has_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *me mem->size > 0 && mem->size%mem->page_size == 0 && mem_is_paged_type(mem) && !(p && avr_mem_exclude(pgm, p, mem)); } +static int read_byte_error(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, unsigned long addr, uint8_t *value) { + pmsg_error("pgm->read_byte must not be pointing to avr_read_byte_cached()\n"); + return -1; +} + +static int write_byte_error(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, unsigned long addr, uint8_t data) { + pmsg_error("pgm->write_byte must not be pointing to avr_write_byte_cached()\n"); + return -1; +} + // Sanity only: guard against a user setting pgm->xyz_byte to avr_xyz_read_byte_cached (AVRDUDE doesn't) -#define fallback_read_byte (pgm->read_byte != avr_read_byte_cached? led_read_byte: avr_read_byte_default) -#define fallback_write_byte (pgm->write_byte != avr_write_byte_cached? led_write_byte: avr_write_byte_default) +#define fallback_read_byte (pgm->read_byte != avr_read_byte_cached? led_read_byte: read_byte_error) +#define fallback_write_byte (pgm->write_byte != avr_write_byte_cached? led_write_byte: write_byte_error) /* * Read the page containing addr from the device into buf From 7a7b072a9b7593057ea927590f970aae4780e222 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Wed, 25 Mar 2026 17:34:01 +0000 Subject: [PATCH 03/12] Provide avr_can_skip_write_byte() --- src/avr.c | 40 ++++++++++++++++++++++++++++++++++++++++ src/libavrdude.h | 2 ++ 2 files changed, 42 insertions(+) diff --git a/src/avr.c b/src/avr.c index ed91c17e..38706a95 100644 --- a/src/avr.c +++ b/src/avr.c @@ -641,6 +641,46 @@ int avr_bitmask_data(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, return data; } +// Can pgm->write_byte() be skipped, eg, if the wanted data are already there? +int avr_can_skip_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, + unsigned long addr, uint8_t wanted, int *readrc) { + + if(readrc) + *readrc = -99; + + /* + * Check to see if the write is necessary by reading the existing value and + * only write if we are changing the value; we can't use this optimization + * for paged addressing nor for IO memory (as it's not necessarily storage). + * + * For mysterious reasons, on the AT90S1200, this read operation sometimes + * causes the high byte of the same word to be programmed to the value of + * the low byte that has just been programmed before. Avoid that + * optimization on this device. + */ + if(mem->paged || mem_is_io(mem) || (p->flags & AVRPART_IS_AT90S1200)) + return 0; + + // Don't skip write when programming a bootloader + if(is_spm(pgm)) + return 0; + + // Unclear whether this optimisation would work for TPI parts + if(is_tpi(p)) + return 0; + + unsigned char is; + int rc = avr_read_byte_silent(pgm, p, mem, addr, &is); + if(readrc) + *readrc = rc; + if(rc < 0) + return 0; + + int bm = avr_mem_bitmask(p, mem, addr); + + return (is & bm) == (wanted & bm); +} + int avr_write_byte_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, unsigned long addr, unsigned char data) { diff --git a/src/libavrdude.h b/src/libavrdude.h index 2c1e1c6f..37a26437 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -1174,6 +1174,8 @@ extern "C" { unsigned long addr, unsigned char *datap); int avr_bitmask_data(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, unsigned long addr, unsigned char data); + int avr_can_skip_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, + unsigned long addr, uint8_t wanted, int *readrc); int avr_write_byte_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, unsigned long addr, unsigned char data); int avr_write_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, int size, int auto_erase); From 2a5425245df5ce7eaa840d0a76631ec783680486 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Wed, 25 Mar 2026 17:58:00 +0000 Subject: [PATCH 04/12] Utilise avr_can_skip_write_byte() --- src/avr.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/src/avr.c b/src/avr.c index 38706a95..e159a2b7 100644 --- a/src/avr.c +++ b/src/avr.c @@ -693,7 +693,6 @@ int avr_write_byte_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM int ready; int tries; unsigned long start, now; - unsigned char b; unsigned short caddr; OPCODE *writeop; int rc; @@ -770,29 +769,19 @@ int avr_write_byte_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM goto success; } - int bm = avr_mem_bitmask(p, mem, addr); - - if(!mem->paged && (p->flags & AVRPART_IS_AT90S1200) == 0) { - /* - * Check to see if the write is necessary by reading the existing value and - * only write if we are changing the value; we can't use this optimization - * for paged addressing. - * - * For mysterious reasons, on the AT90S1200, this read operation sometimes - * causes the high byte of the same word to be programmed to the value of - * the low byte that has just been programmed before. Avoid that - * optimization on this device. - */ - rc = pgm->read_byte(pgm, p, mem, addr, &b); + // Check to see if writing could be skipped + int rbrc, skip = avr_can_skip_write_byte(pgm, p, mem, addr, data, &rbrc); + if(rbrc != -99) { // read_byte() was executed + rc = rbrc; if(rc != 0) { if(rc != -1) { rc = -2; goto rcerror; } - // Read operation is not support on this memory + // Read operation is not supported on this memory } else { readok = 1; - if((b & bm) == (data & bm)) + if(skip) goto success; } } @@ -836,6 +825,7 @@ int avr_write_byte_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM goto success; } + int bm = avr_mem_bitmask(p, mem, addr); tries = 0; ready = 0; while(!ready) { From f6e2a80379a8761a6bbd7bffdce0b8f38f1c57f8 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Wed, 25 Mar 2026 18:20:52 +0000 Subject: [PATCH 05/12] Remodel avr_write_byte() wrt r/o and w/p memory --- src/avr.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/avr.c b/src/avr.c index e159a2b7..c6d9e342 100644 --- a/src/avr.c +++ b/src/avr.c @@ -919,13 +919,12 @@ int avr_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, pmsg_debug("%s(%s, %s, %s, %s, 0x%02x)\n", __func__, pgmid, p->id, mem->desc, str_ccaddress(addr, mem->size), data); - if(mem_is_readonly(mem)) { - unsigned char is; - - if(pgm->read_byte(pgm, p, mem, addr, &is) >= 0 && is == data) + if(mem_is_readonly(mem) || (pgm->readonly && pgm->readonly(pgm, p, mem, addr))) { + if(avr_can_skip_write_byte(pgm, p, mem, addr, data, NULL)) return 0; - pmsg_error("cannot write to read-only memory %s of %s\n", mem->desc, p->desc); + pmsg_error("cannot write to %s memory %s of %s\n", + mem_is_readonly(mem)? "read-only": "write-protected", mem->desc, p->desc); return -1; } From 5b0d7689d2cbe228d52731ea3314f783c404b45c Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Wed, 25 Mar 2026 18:27:37 +0000 Subject: [PATCH 06/12] Provide avr_update_write_byte() --- src/avr.c | 23 +++++++++++++++++++++++ src/libavrdude.h | 6 ++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/avr.c b/src/avr.c index c6d9e342..780cd7a9 100644 --- a/src/avr.c +++ b/src/avr.c @@ -912,6 +912,29 @@ rcerror: return rc; } +// Update one byte of data at the specified address, ie, write unless already there +int avr_update_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, + unsigned long addr, unsigned char data) { + + pmsg_debug("%s(%s, %s, %s, %s, 0x%02x)\n", __func__, pgmid, p->id, mem->desc, + str_ccaddress(addr, mem->size), data); + + if(avr_can_skip_write_byte(pgm, p, mem, addr, data, NULL)) + return 0; + + if(mem_is_readonly(mem) || (pgm->readonly && pgm->readonly(pgm, p, mem, addr))) { + pmsg_error("cannot write to %s memory %s of %s\n", + mem_is_readonly(mem)? "read-only": "write-protected", mem->desc, p->desc); + return -1; + } + + if(pgm->write_byte != avr_write_byte_default) + if(!(p->prog_modes & (PM_UPDI | PM_aWire))) // Initialise unused bits in classic & XMEGA parts + data = avr_bitmask_data(pgm, p, mem, addr, data); + + return pgm->write_byte(pgm, p, mem, addr, data); +} + // Write a byte of data at the specified address int avr_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, unsigned long addr, unsigned char data) { diff --git a/src/libavrdude.h b/src/libavrdude.h index 37a26437..b18ece38 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -1168,8 +1168,6 @@ extern "C" { uint64_t avr_mstimestamp(void); double avr_timestamp(void); void init_cx(PROGRAMMER *pgm); - int avr_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, - unsigned long addr, unsigned char data); int avr_read_byte_silent(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, unsigned long addr, unsigned char *datap); int avr_bitmask_data(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, @@ -1178,6 +1176,10 @@ extern "C" { unsigned long addr, uint8_t wanted, int *readrc); int avr_write_byte_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, unsigned long addr, unsigned char data); + int avr_update_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, + unsigned long addr, unsigned char data); + int avr_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, + unsigned long addr, unsigned char data); int avr_write_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, int size, int auto_erase); int avr_write(const PROGRAMMER *pgm, const AVRPART *p, const char *memstr, int size, int auto_erase); int avr_signature(const PROGRAMMER *pgm, const AVRPART *p); From 88e05a967347aa2eef7ae9c9d083a224f8ba0123 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Wed, 25 Mar 2026 19:05:14 +0000 Subject: [PATCH 07/12] Remodel led_write_byte() wrt r/o and w/p memory --- src/leds.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/leds.c b/src/leds.c index f63da62d..d7be729f 100644 --- a/src/leds.c +++ b/src/leds.c @@ -199,8 +199,16 @@ int led_chip_erase(const PROGRAMMER *pgm, const AVRPART *p) { // Programmer specific write byte function with ERR/PGM LED info int led_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, unsigned long addr, unsigned char value) { - if(mem_is_readonly(m)) - return pgm->write_byte(pgm, p, m, addr, value); + pmsg_debug("%s(%s, %s, %s, %s, 0x%02x)\n", __func__, pgmid, p->id, m->desc, str_ccaddress(addr, m->size), value); + + if(mem_is_readonly(m) || (pgm->readonly && pgm->readonly(pgm, p, m, addr))) { + if(avr_can_skip_write_byte(pgm, p, m, addr, value, NULL)) + return 0; + + pmsg_error("cannot write to %s memory %s of %s\n", + mem_is_readonly(m)? "read-only": "write-protected", m->desc, p->desc); + return -1; + } led_clr(pgm, LED_ERR); led_set(pgm, LED_PGM); From 70cde43d6664f617300c2e364aa87ff7596f9e9b Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Wed, 25 Mar 2026 19:30:26 +0000 Subject: [PATCH 08/12] Provide led_update_write_byte() --- src/leds.c | 32 +++++++++++++++++++++++++++----- src/libavrdude.h | 6 ++++-- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/leds.c b/src/leds.c index d7be729f..bcd35ccf 100644 --- a/src/leds.c +++ b/src/leds.c @@ -196,9 +196,33 @@ int led_chip_erase(const PROGRAMMER *pgm, const AVRPART *p) { return rc; } +// Programmer specific update byte function with ERR/PGM LED info (ie, only write if data not there) +int led_update_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, unsigned long addr, unsigned char value) { + pmsg_debug("%s(%s, %s, %s, %s, 0x%02x)\n", __func__, pgmid, p->id, m->desc, str_ccaddress(addr, m->size), value); + + if(avr_can_skip_write_byte(pgm, p, m, addr, value, NULL)) + return 0; + + if(mem_is_readonly(m) || (pgm->readonly && pgm->readonly(pgm, p, m, addr))) { + pmsg_error("cannot write to %s memory %s of %s\n", + mem_is_readonly(m)? "read-only": "write-protected", m->desc, p->desc); + return -1; + } + + led_clr(pgm, LED_ERR); + led_set(pgm, LED_PGM); + + int rc = pgm->write_byte(pgm, p, m, addr, value); + + if(rc < 0) + led_set(pgm, LED_ERR); + led_clr(pgm, LED_PGM); + + return rc; +} + // Programmer specific write byte function with ERR/PGM LED info int led_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, unsigned long addr, unsigned char value) { - pmsg_debug("%s(%s, %s, %s, %s, 0x%02x)\n", __func__, pgmid, p->id, m->desc, str_ccaddress(addr, m->size), value); if(mem_is_readonly(m) || (pgm->readonly && pgm->readonly(pgm, p, m, addr))) { @@ -223,13 +247,11 @@ int led_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, uns } // Programmer specific read byte function with ERR/PGM LED info -int led_read_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, - unsigned long addr, unsigned char *valuep) { - +int led_read_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, unsigned long addr, unsigned char *valp) { led_clr(pgm, LED_ERR); led_set(pgm, LED_PGM); - int rc = pgm->read_byte(pgm, p, m, addr, valuep); + int rc = pgm->read_byte(pgm, p, m, addr, valp); if(rc < 0) led_set(pgm, LED_ERR); diff --git a/src/libavrdude.h b/src/libavrdude.h index b18ece38..4be2bfff 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -1051,7 +1051,7 @@ typedef struct programmer { int (*write_byte)(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, unsigned long addr, unsigned char value); int (*read_byte)(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, - unsigned long addr, unsigned char *value); + unsigned long addr, unsigned char *valp); int (*read_sig_bytes)(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m); int (*read_sib)(const PROGRAMMER *pgm, const AVRPART *p, char *sib); int (*read_chip_rev)(const PROGRAMMER *pgm, const AVRPART *p, unsigned char *chip_rev); @@ -1747,10 +1747,12 @@ extern "C" { int led_set(const PROGRAMMER *pgm, int led); int led_clr(const PROGRAMMER *pgm, int led); int led_chip_erase(const PROGRAMMER *pgm, const AVRPART *p); + int led_update_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, + unsigned long addr, unsigned char value); int led_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, unsigned long addr, unsigned char value); int led_read_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, - unsigned long addr, unsigned char *value); + unsigned long addr, unsigned char *valp); int led_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, unsigned int page_size, unsigned int addr, unsigned int n); int led_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, From 76e622599a2b221558bc3d447e62ae3e7dec6998 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Wed, 25 Mar 2026 19:32:59 +0000 Subject: [PATCH 09/12] Initialise unused bits in classic & XMEGA fuses --- src/leds.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/leds.c b/src/leds.c index bcd35ccf..4eaaaa4d 100644 --- a/src/leds.c +++ b/src/leds.c @@ -209,6 +209,10 @@ int led_update_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, un return -1; } + if(pgm->write_byte != avr_write_byte_default) + if(!(p->prog_modes & (PM_UPDI | PM_aWire))) // Initialise unused bits in classic & XMEGA parts + value = avr_bitmask_data(pgm, p, m, addr, value); + led_clr(pgm, LED_ERR); led_set(pgm, LED_PGM); @@ -234,6 +238,10 @@ int led_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, uns return -1; } + if(pgm->write_byte != avr_write_byte_default) + if(!(p->prog_modes & (PM_UPDI | PM_aWire))) // Initialise unused bits in classic & XMEGA parts + value = avr_bitmask_data(pgm, p, m, addr, value); + led_clr(pgm, LED_ERR); led_set(pgm, LED_PGM); From bc0b77910e0dc75dca710887db388a2f0d9fef53 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Wed, 25 Mar 2026 21:18:32 +0000 Subject: [PATCH 10/12] Fix typo --- tools/test8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/test8 b/tools/test8 index e4fa6f8c..71c6d1e9 100755 --- a/tools/test8 +++ b/tools/test8 @@ -14,7 +14,7 @@ Usage() { cat <] Function: test AVRDUDE v 8.0 or later with -c programmer -p part; - also leaves a file bak---.hex for inspection Options: -i Write human-readable contents seeded by to part and exit -r Write random contents seeded by to part and exit From bfba3364d5b83c8a597913a60e884cdcf641c5e6 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Wed, 25 Mar 2026 21:19:31 +0000 Subject: [PATCH 11/12] Utilise avr/led_update_write_byte() functions --- src/avr.c | 2 +- src/avrcache.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/avr.c b/src/avr.c index 780cd7a9..f29d9460 100644 --- a/src/avr.c +++ b/src/avr.c @@ -1234,7 +1234,7 @@ int avr_write_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, int continue; if(do_write) { - if(avr_write_byte(pgm, p, m, i, data)) { + if(avr_update_byte(pgm, p, m, i, data)) { msg_error(" *** failed\n"); led_set(pgm, LED_ERR); goto error; diff --git a/src/avrcache.c b/src/avrcache.c index da9b768b..639108e5 100644 --- a/src/avrcache.c +++ b/src/avrcache.c @@ -155,6 +155,7 @@ static int write_byte_error(const PROGRAMMER *pgm, const AVRPART *p, const AVRME // Sanity only: guard against a user setting pgm->xyz_byte to avr_xyz_read_byte_cached (AVRDUDE doesn't) #define fallback_read_byte (pgm->read_byte != avr_read_byte_cached? led_read_byte: read_byte_error) #define fallback_write_byte (pgm->write_byte != avr_write_byte_cached? led_write_byte: write_byte_error) +#define fallback_update_byte (pgm->write_byte != avr_write_byte_cached? led_update_byte: write_byte_error) /* * Read the page containing addr from the device into buf @@ -681,7 +682,7 @@ int avr_write_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM // Use pgm->write_byte() if not flash/EEPROM/bootrow/usersig or no paged access if(!avr_has_paged_access(pgm, p, mem)) - return fallback_write_byte(pgm, p, mem, addr, data); + return fallback_update_byte(pgm, p, mem, addr, data); // If address is out of range synchronise caches with device and return whether successful if(addr >= (unsigned long) mem->size) From f062636a252b490cb66e895d14eb9dbff6e1cde0 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Wed, 25 Mar 2026 21:30:39 +0000 Subject: [PATCH 12/12] Consider avr_write_byte_default() skips unnecessary writes --- src/avr.c | 8 +++++--- src/leds.c | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/avr.c b/src/avr.c index f29d9460..8f7a0e2b 100644 --- a/src/avr.c +++ b/src/avr.c @@ -916,6 +916,9 @@ rcerror: int avr_update_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, unsigned long addr, unsigned char data) { + if(pgm->write_byte == avr_write_byte_default) // avr_write_byte_default() already updates + return avr_write_byte(pgm, p, mem, addr, data); + pmsg_debug("%s(%s, %s, %s, %s, 0x%02x)\n", __func__, pgmid, p->id, mem->desc, str_ccaddress(addr, mem->size), data); @@ -928,9 +931,8 @@ int avr_update_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, return -1; } - if(pgm->write_byte != avr_write_byte_default) - if(!(p->prog_modes & (PM_UPDI | PM_aWire))) // Initialise unused bits in classic & XMEGA parts - data = avr_bitmask_data(pgm, p, mem, addr, data); + if(!(p->prog_modes & (PM_UPDI | PM_aWire))) // Initialise unused bits in classic & XMEGA parts + data = avr_bitmask_data(pgm, p, mem, addr, data); return pgm->write_byte(pgm, p, mem, addr, data); } diff --git a/src/leds.c b/src/leds.c index 4eaaaa4d..25571f9d 100644 --- a/src/leds.c +++ b/src/leds.c @@ -198,6 +198,9 @@ int led_chip_erase(const PROGRAMMER *pgm, const AVRPART *p) { // Programmer specific update byte function with ERR/PGM LED info (ie, only write if data not there) int led_update_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, unsigned long addr, unsigned char value) { + if(pgm->write_byte == avr_write_byte_default) // avr_write_byte_default() already updates + return led_write_byte(pgm, p, m, addr, value); + pmsg_debug("%s(%s, %s, %s, %s, 0x%02x)\n", __func__, pgmid, p->id, m->desc, str_ccaddress(addr, m->size), value); if(avr_can_skip_write_byte(pgm, p, m, addr, value, NULL)) @@ -209,9 +212,8 @@ int led_update_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, un return -1; } - if(pgm->write_byte != avr_write_byte_default) - if(!(p->prog_modes & (PM_UPDI | PM_aWire))) // Initialise unused bits in classic & XMEGA parts - value = avr_bitmask_data(pgm, p, m, addr, value); + if(!(p->prog_modes & (PM_UPDI | PM_aWire))) // Initialise unused bits in classic & XMEGA parts + value = avr_bitmask_data(pgm, p, m, addr, value); led_clr(pgm, LED_ERR); led_set(pgm, LED_PGM);