From 1f2b5702162ab86341c24d6f9e64235073f649e9 Mon Sep 17 00:00:00 2001
From: MCUdude <hansibull@gmail.com>
Date: Mon, 28 Feb 2022 19:46:47 +0100
Subject: [PATCH 1/9] Support both userrow and usersig names

---
 src/avrdude.conf.in | 12 ++++++------
 src/jtag3.c         | 29 ++++++++++++++++++-----------
 src/jtagmkII.c      | 34 ++++++++++++++++++++--------------
 src/stk500v2.c      | 15 ++++++++++-----
 4 files changed, 54 insertions(+), 36 deletions(-)

diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in
index b362154f..3ba49e6a 100644
--- a/src/avrdude.conf.in
+++ b/src/avrdude.conf.in
@@ -16748,15 +16748,15 @@ part parent    ".avr8x"
     desc		= "AVR8X tiny family common values";
     family_id	= "tinyAVR";
 
-    memory "usersig"
+    memory "userrow"
         size		= 0x20;
         offset		= 0x1300;
         page_size	= 0x20;
         readsize	= 0x100;
     ;
 
-    memory "userrow"
-        alias "usersig";
+    memory "usersig"
+        alias "userrow";
     ;
 ;
 
@@ -16769,15 +16769,15 @@ part parent    ".avr8x"
     desc		= "AVR8X mega family common values";
     family_id	= "megaAVR";
 
-    memory "usersig"
+    memory "userrow"
         size		= 0x40;
         offset		= 0x1300;
         page_size	= 0x40;
         readsize	= 0x100;
     ;
 
-        memory "userrow"
-        alias "usersig";
+    memory "usersig"
+        alias "userrow";
     ;
 ;
 
diff --git a/src/jtag3.c b/src/jtag3.c
index d61f2417..a00a7910 100644
--- a/src/jtag3.c
+++ b/src/jtag3.c
@@ -1174,7 +1174,8 @@ static int jtag3_initialize(PROGRAMMER * pgm, AVRPART * p)
 	u32_to_b4(xd.nvm_fuse_offset, m->offset & ~7);
       } else if (matches(m->desc, "lock")) {
 	u32_to_b4(xd.nvm_lock_offset, m->offset);
-      } else if (strcmp(m->desc, "usersig") == 0) {
+      } else if (strcmp(m->desc, "usersig") == 0 ||
+                 strcmp(m->desc, "userrow") == 0) {
 	u32_to_b4(xd.nvm_user_sig_offset, m->offset);
       } else if (strcmp(m->desc, "prodsig") == 0) {
 	u32_to_b4(xd.nvm_prod_sig_offset, m->offset);
@@ -1225,7 +1226,8 @@ static int jtag3_initialize(PROGRAMMER * pgm, AVRPART * p)
         u16_to_b2(xd.eeprom_bytes, m->size);
         u16_to_b2(xd.eeprom_base, m->offset);
       }
-      else if (strcmp(m->desc, "usersig") == 0)
+      else if (strcmp(m->desc, "usersig") == 0 ||
+               strcmp(m->desc, "userrow") == 0)
       {
         u16_to_b2(xd.user_sig_bytes, m->size);
         u16_to_b2(xd.user_sig_base, m->offset);
@@ -1686,9 +1688,10 @@ static int jtag3_page_erase(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
       cmd[3] = XMEGA_ERASE_BOOT_PAGE;
   } else if (strcmp(m->desc, "eeprom") == 0) {
     cmd[3] = XMEGA_ERASE_EEPROM_PAGE;
-  } else if ( ( strcmp(m->desc, "usersig") == 0 ) ) {
+  } else if (strcmp(m->desc, "usersig") == 0 ||
+             strcmp(m->desc, "userrow") == 0) {
     cmd[3] = XMEGA_ERASE_USERSIG;
-  } else if ( ( strcmp(m->desc, "boot") == 0 ) ) {
+  } else if (strcmp(m->desc, "boot") == 0) {
     cmd[3] = XMEGA_ERASE_BOOT_PAGE;
   } else {
     cmd[3] = XMEGA_ERASE_APP_PAGE;
@@ -1760,9 +1763,10 @@ static int jtag3_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
     }
     cmd[3] = ( p->flags & AVRPART_HAS_PDI ) ? MTYPE_EEPROM_XMEGA : MTYPE_EEPROM_PAGE;
     PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L;
-  } else if ( ( strcmp(m->desc, "usersig") == 0 ) ) {
+  } else if (strcmp(m->desc, "usersig") == 0 ||
+             strcmp(m->desc, "userrow") == 0) {
     cmd[3] = MTYPE_USERSIG;
-  } else if ( ( strcmp(m->desc, "boot") == 0 ) ) {
+  } else if (strcmp(m->desc, "boot") == 0) {
     cmd[3] = MTYPE_BOOT_FLASH;
   } else if ( p->flags & AVRPART_HAS_PDI || p->flags & AVRPART_HAS_UPDI ) {
     cmd[3] = MTYPE_FLASH;
@@ -1849,11 +1853,12 @@ static int jtag3_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
     cmd[3] = ( p->flags & AVRPART_HAS_PDI || p->flags & AVRPART_HAS_UPDI ) ? MTYPE_EEPROM : MTYPE_EEPROM_PAGE;
     if (pgm->flag & PGM_FL_IS_DW)
       return -1;
-  } else if ( ( strcmp(m->desc, "prodsig") == 0 ) ) {
+  } else if (strcmp(m->desc, "prodsig") == 0) {
     cmd[3] = MTYPE_PRODSIG;
-  } else if ( ( strcmp(m->desc, "usersig") == 0 ) ) {
+  } else if (strcmp(m->desc, "usersig") == 0 ||
+             strcmp(m->desc, "userrow") == 0) {
     cmd[3] = MTYPE_USERSIG;
-  } else if ( ( strcmp(m->desc, "boot") == 0 ) ) {
+  } else if (strcmp(m->desc, "boot") == 0) {
     cmd[3] = MTYPE_BOOT_FLASH;
   } else if ( p->flags & AVRPART_HAS_PDI ) {
     cmd[3] = MTYPE_FLASH;
@@ -1965,7 +1970,8 @@ static int jtag3_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
     cmd[3] = MTYPE_FUSE_BITS;
     if (!(p->flags & AVRPART_HAS_UPDI))
       addr = mem->offset & 7;
-  } else if (strcmp(mem->desc, "usersig") == 0) {
+  } else if (strcmp(mem->desc, "usersig") == 0 ||
+             strcmp(mem->desc, "userrow") == 0) {
     cmd[3] = MTYPE_USERSIG;
   } else if (strcmp(mem->desc, "prodsig") == 0) {
     cmd[3] = MTYPE_PRODSIG;
@@ -2126,7 +2132,8 @@ static int jtag3_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
     cmd[3] = MTYPE_FUSE_BITS;
     if (!(p->flags & AVRPART_HAS_UPDI))
       addr = mem->offset & 7;
-  } else if (strcmp(mem->desc, "usersig") == 0) {
+  } else if (strcmp(mem->desc, "usersig") == 0 ||
+             strcmp(mem->desc, "userrow") == 0) {
     cmd[3] = MTYPE_USERSIG;
   } else if (strcmp(mem->desc, "prodsig") == 0) {
     cmd[3] = MTYPE_PRODSIG;
diff --git a/src/jtagmkII.c b/src/jtagmkII.c
index eeab8e92..fc06301c 100644
--- a/src/jtagmkII.c
+++ b/src/jtagmkII.c
@@ -1056,7 +1056,8 @@ static void jtagmkII_set_xmega_params(PROGRAMMER * pgm, AVRPART * p)
       u32_to_b4(sendbuf.dd.nvm_fuse_offset, m->offset & ~7);
     } else if (strncmp(m->desc, "lock", 4) == 0) {
       u32_to_b4(sendbuf.dd.nvm_lock_offset, m->offset);
-    } else if (strcmp(m->desc, "usersig") == 0) {
+    } else if (strcmp(m->desc, "usersig") == 0 ||
+               strcmp(m->desc, "userrow") == 0) {
       u32_to_b4(sendbuf.dd.nvm_user_sig_offset, m->offset);
     } else if (strcmp(m->desc, "prodsig") == 0) {
       u32_to_b4(sendbuf.dd.nvm_prod_sig_offset, m->offset);
@@ -1933,9 +1934,10 @@ static int jtagmkII_page_erase(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
       cmd[1] = XMEGA_ERASE_BOOT_PAGE;
   } else if (strcmp(m->desc, "eeprom") == 0) {
     cmd[1] = XMEGA_ERASE_EEPROM_PAGE;
-  } else if ( ( strcmp(m->desc, "usersig") == 0 ) ) {
+  } else if (strcmp(m->desc, "usersig") == 0 ||
+             strcmp(m->desc, "userrow") == 0) {
     cmd[1] = XMEGA_ERASE_USERSIG;
-  } else if ( ( strcmp(m->desc, "boot") == 0 ) ) {
+  } else if (strcmp(m->desc, "boot") == 0) {
     cmd[1] = XMEGA_ERASE_BOOT_PAGE;
   } else {
     cmd[1] = XMEGA_ERASE_APP_PAGE;
@@ -2044,13 +2046,14 @@ static int jtagmkII_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
       free(cmd);
       return n_bytes;
     }
-    cmd[1] = ( p->flags & (AVRPART_HAS_PDI | AVRPART_HAS_UPDI) ) ? MTYPE_EEPROM : MTYPE_EEPROM_PAGE;
+    cmd[1] = (p->flags & (AVRPART_HAS_PDI | AVRPART_HAS_UPDI)) ? MTYPE_EEPROM : MTYPE_EEPROM_PAGE;
     PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L;
-  } else if ( ( strcmp(m->desc, "usersig") == 0 ) ) {
+  } else if (strcmp(m->desc, "usersig") == 0 ||
+             strcmp(m->desc, "userrow") == 0) {
     cmd[1] = MTYPE_USERSIG;
-  } else if ( ( strcmp(m->desc, "boot") == 0 ) ) {
+  } else if (strcmp(m->desc, "boot") == 0) {
     cmd[1] = MTYPE_BOOT_FLASH;
-  } else if ( p->flags & (AVRPART_HAS_PDI | AVRPART_HAS_UPDI) ) {
+  } else if (p->flags & (AVRPART_HAS_PDI | AVRPART_HAS_UPDI)) {
     cmd[1] = MTYPE_FLASH;
   } else {
     cmd[1] = MTYPE_SPM;
@@ -2156,16 +2159,17 @@ static int jtagmkII_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
       /* dynamically decide between flash/boot memtype */
       dynamic_memtype = 1;
   } else if (strcmp(m->desc, "eeprom") == 0) {
-    cmd[1] = ( p->flags & (AVRPART_HAS_PDI | AVRPART_HAS_UPDI) ) ? MTYPE_EEPROM : MTYPE_EEPROM_PAGE;
+    cmd[1] = (p->flags & (AVRPART_HAS_PDI | AVRPART_HAS_UPDI)) ? MTYPE_EEPROM : MTYPE_EEPROM_PAGE;
     if (pgm->flag & PGM_FL_IS_DW)
       return -1;
-  } else if ( ( strcmp(m->desc, "prodsig") == 0 ) ) {
+  } else if (strcmp(m->desc, "prodsig") == 0) {
     cmd[1] = MTYPE_PRODSIG;
-  } else if ( ( strcmp(m->desc, "usersig") == 0 ) ) {
+  } else if (strcmp(m->desc, "usersig") == 0 ||
+             strcmp(m->desc, "userrow") == 0) {
     cmd[1] = MTYPE_USERSIG;
-  } else if ( ( strcmp(m->desc, "boot") == 0 ) ) {
+  } else if (strcmp(m->desc, "boot") == 0) {
     cmd[1] = MTYPE_BOOT_FLASH;
-  } else if ( p->flags & (AVRPART_HAS_PDI | AVRPART_HAS_UPDI) ) {
+  } else if (p->flags & (AVRPART_HAS_PDI | AVRPART_HAS_UPDI)) {
     cmd[1] = MTYPE_FLASH;
   } else {
     cmd[1] = MTYPE_SPM;
@@ -2291,7 +2295,8 @@ static int jtagmkII_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
       unsupp = 1;
   } else if (strncmp(mem->desc, "fuse", strlen("fuse")) == 0) {
     cmd[1] = MTYPE_FUSE_BITS;
-  } else if (strcmp(mem->desc, "usersig") == 0) {
+  } else if (strcmp(mem->desc, "usersig") == 0 ||
+             strcmp(mem->desc, "userrow") == 0) {
     cmd[1] = MTYPE_USERSIG;
   } else if (strcmp(mem->desc, "prodsig") == 0) {
     cmd[1] = MTYPE_PRODSIG;
@@ -2460,7 +2465,8 @@ static int jtagmkII_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
       unsupp = 1;
   } else if (strncmp(mem->desc, "fuse", strlen("fuse")) == 0) {
     cmd[1] = MTYPE_FUSE_BITS;
-  } else if (strcmp(mem->desc, "usersig") == 0) {
+  } else if (strcmp(mem->desc, "usersig") == 0 ||
+             strcmp(mem->desc, "userrow") == 0) {
     cmd[1] = MTYPE_USERSIG;
   } else if (strcmp(mem->desc, "prodsig") == 0) {
     cmd[1] = MTYPE_PRODSIG;
diff --git a/src/stk500v2.c b/src/stk500v2.c
index 92e59516..523d6539 100644
--- a/src/stk500v2.c
+++ b/src/stk500v2.c
@@ -3869,7 +3869,8 @@ static int stk600_xprog_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
              * fuses.
              */
             need_erase = 1;
-    } else if (strcmp(mem->desc, "usersig") == 0) {
+    } else if (strcmp(mem->desc, "usersig") == 0 ||
+               strcmp(mem->desc, "userrow") == 0) {
         memcode = XPRG_MEM_TYPE_USERSIG;
     } else {
         avrdude_message(MSG_INFO, "%s: stk600_xprog_write_byte(): unknown memory \"%s\"\n",
@@ -3944,7 +3945,8 @@ static int stk600_xprog_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
     } else if (strcmp(mem->desc, "calibration") == 0 ||
                strcmp(mem->desc, "prodsig") == 0) {
         b[1] = XPRG_MEM_TYPE_FACTORY_CALIBRATION;
-    } else if (strcmp(mem->desc, "usersig") == 0) {
+    } else if (strcmp(mem->desc, "usersig") == 0 ||
+               strcmp(mem->desc, "userrow") == 0) {
         b[1] = XPRG_MEM_TYPE_USERSIG;
     } else {
         avrdude_message(MSG_INFO, "%s: stk600_xprog_read_byte(): unknown memory \"%s\"\n",
@@ -4019,7 +4021,8 @@ static int stk600_xprog_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
     } else if (strcmp(mem->desc, "calibration") == 0 ||
                strcmp(mem->desc, "prodsig") == 0) {
         memtype = XPRG_MEM_TYPE_FACTORY_CALIBRATION;
-    } else if (strcmp(mem->desc, "usersig") == 0) {
+    } else if (strcmp(mem->desc, "usersig") == 0 ||
+               strcmp(mem->desc, "userrow") == 0) {
         memtype = XPRG_MEM_TYPE_USERSIG;
     } else {
         avrdude_message(MSG_INFO, "%s: stk600_xprog_paged_load(): unknown paged memory \"%s\"\n",
@@ -4132,7 +4135,8 @@ static int stk600_xprog_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
     } else if (strcmp(mem->desc, "calibration") == 0) {
         memtype = XPRG_MEM_TYPE_FACTORY_CALIBRATION;
         writemode = (1 << XPRG_MEM_WRITE_WRITE);
-    } else if (strcmp(mem->desc, "usersig") == 0) {
+    } else if (strcmp(mem->desc, "usersig") == 0 ||
+               strcmp(mem->desc, "userrow") == 0) {
         memtype = XPRG_MEM_TYPE_USERSIG;
         writemode = (1 << XPRG_MEM_WRITE_WRITE);
     } else {
@@ -4290,7 +4294,8 @@ static int stk600_xprog_page_erase(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
       b[1] = XPRG_ERASE_BOOT_PAGE;
     } else if (strcmp(m->desc, "eeprom") == 0) {
       b[1] = XPRG_ERASE_EEPROM_PAGE;
-    } else if (strcmp(m->desc, "usersig") == 0) {
+    } else if (strcmp(m->desc, "usersig") == 0 ||
+               strcmp(m->desc, "userrow") == 0) {
       b[1] = XPRG_ERASE_USERSIG;
     } else {
       avrdude_message(MSG_INFO, "%s: stk600_xprog_page_erase(): unknown paged memory \"%s\"\n",

From d89f695c31c2833b9edcd3077ecc152256151c1b Mon Sep 17 00:00:00 2001
From: MCUdude <hansibull@gmail.com>
Date: Mon, 28 Feb 2022 20:39:55 +0100
Subject: [PATCH 2/9] Incread default read size to 256 bytes

---
 src/term.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/term.c b/src/term.c
index 7051503a..eff75841 100644
--- a/src/term.c
+++ b/src/term.c
@@ -250,7 +250,7 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p,
 
   if (strncmp(prevmem, memtype, strlen(memtype)) != 0) {
     addr = 0;
-    len  = 64;
+    len  = 256;
     strncpy(prevmem, memtype, sizeof(prevmem)-1);
     prevmem[sizeof(prevmem)-1] = 0;
   }

From b688b1f601a9868dbfd688c893e78553330fa8a8 Mon Sep 17 00:00:00 2001
From: MCUdude <hansibull@gmail.com>
Date: Mon, 28 Feb 2022 22:40:17 +0100
Subject: [PATCH 3/9] Add support for read with ... "operator" This means that
 you can use ... to read the "rest" of the memory. $ read eeprom ...   will
 dump the entire memory $ read eeorm 0x80 ...   will dump the memory from
 address 0x80 to the end address

---
 src/term.c | 125 ++++++++++++++++++++++++++---------------------------
 1 file changed, 62 insertions(+), 63 deletions(-)

diff --git a/src/term.c b/src/term.c
index eff75841..b01acd46 100644
--- a/src/term.c
+++ b/src/term.c
@@ -149,12 +149,10 @@ static int nexttok(char * buf, char ** tok, char ** next)
 static int hexdump_line(char * buffer, unsigned char * p, int n, int pad)
 {
   char * hexdata = "0123456789abcdef";
-  char * b;
-  int i, j;
+  char * b = buffer;
+  int32_t i = 0;
+  int32_t j = 0;
 
-  b = buffer;
-
-  j = 0;
   for (i=0; i<n; i++) {
     if (i && ((i % 8) == 0))
       b[j++] = ' ';
@@ -183,7 +181,7 @@ static int chardump_line(char * buffer, unsigned char * p, int n, int pad)
   int i;
   char b [ 128 ];
 
-  for (i=0; i<n; i++) {
+  for (int32_t i = 0; i < n; i++) {
     memcpy(b, p, n);
     buffer[i] = '.';
     if (isalpha((int)(b[i])) || isdigit((int)(b[i])) || ispunct((int)(b[i])))
@@ -192,7 +190,7 @@ static int chardump_line(char * buffer, unsigned char * p, int n, int pad)
       buffer[i] = ' ';
   }
 
-  for (i=n; i<pad; i++)
+  for (i = n; i < pad; i++)
     buffer[i] = ' ';
 
   buffer[i] = 0;
@@ -203,16 +201,13 @@ static int chardump_line(char * buffer, unsigned char * p, int n, int pad)
 
 static int hexdump_buf(FILE * f, int startaddr, unsigned char * buf, int len)
 {
-  int addr;
-  int n;
-  unsigned char * p;
   char dst1[80];
   char dst2[80];
 
-  addr = startaddr;
-  p = (unsigned char *)buf;
+  int32_t addr = startaddr;
+  unsigned char * p = (unsigned char *)buf;
   while (len) {
-    n = 16;
+    int32_t n = 16;
     if (n > len)
       n = len;
     hexdump_line(dst1, p, n, 48);
@@ -230,83 +225,88 @@ static int hexdump_buf(FILE * f, int startaddr, unsigned char * buf, int len)
 static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p,
 		    int argc, char * argv[])
 {
-  static char prevmem[128] = {0};
-  char * e;
-  unsigned char * buf;
-  int maxsize;
-  unsigned long i;
-  static unsigned long addr=0;
-  static int len=64;
-  AVRMEM * mem;
-  char * memtype = NULL;
-  int rc;
-
-  if (!((argc == 2) || (argc == 4))) {
-    avrdude_message(MSG_INFO, "Usage: dump <memtype> [<addr> <len>]\n");
-    return -1;
+  if (argc < 2) {
+  avrdude_message(MSG_INFO, "Usage: %s <memtype> [<start addr> <len>]\n"
+                            "       %s <memtype> [<start addr> <...>]\n"
+                            "       %s <memtype> <...>\n"
+                            "       %s <memtype>\n",
+                            argv[0], argv[0], argv[0], argv[0]);
+  return -1;
   }
 
-  memtype = argv[1];
-
-  if (strncmp(prevmem, memtype, strlen(memtype)) != 0) {
-    addr = 0;
-    len  = 256;
-    strncpy(prevmem, memtype, sizeof(prevmem)-1);
-    prevmem[sizeof(prevmem)-1] = 0;
-  }
-
-  mem = avr_locate_mem(p, memtype);
+  enum { read_size = 256 };
+  static char prevmem[128] = {0x00};
+  char * memtype = argv[1];
+  AVRMEM * mem = avr_locate_mem(p, memtype);
   if (mem == NULL) {
     avrdude_message(MSG_INFO, "\"%s\" memory type not defined for part \"%s\"\n",
             memtype, p->desc);
     return -1;
   }
+  uint32_t maxsize = mem->size;
 
+  // Get start address if present
+  char * end_ptr;
+  static uint32_t addr = 0;
   if (argc == 4) {
-    addr = strtoul(argv[2], &e, 0);
-    if (*e || (e == argv[2])) {
-      avrdude_message(MSG_INFO, "%s (dump): can't parse address \"%s\"\n",
-              progname, argv[2]);
+    addr = strtoul(argv[2], &end_ptr, 0);
+    if (*end_ptr || (end_ptr == argv[2])) {
+      avrdude_message(MSG_INFO, "%s (%s): can't parse address \"%s\"\n",
+              progname, argv[0], argv[2]);
       return -1;
-    }
-
-    len = strtol(argv[3], &e, 0);
-    if (*e || (e == argv[3])) {
-      avrdude_message(MSG_INFO, "%s (dump): can't parse length \"%s\"\n",
-              progname, argv[3]);
+    } else if (addr >= maxsize) {
+      avrdude_message(MSG_INFO, "%s (%s): address 0x%05lx is out of range for %s memory\n",
+                      progname, argv[0], addr, mem->desc);
       return -1;
     }
   }
 
-  maxsize = mem->size;
-
-  if (addr >= maxsize) {
-    if (argc == 2) {
-      /* wrap around */
+  // Get no. bytes to read if present
+  static int32_t len = read_size;
+  if (argc >= 3) {
+    memset(prevmem, 0x00, sizeof(prevmem));
+    if (strcmp(argv[argc - 1], "...") == 0) {
+      if (argc == 3)
+        addr = 0;
+      len = maxsize - addr;
+    } else if (argc == 4) {
+      len = strtol(argv[3], &end_ptr, 0);
+      if (*end_ptr || (end_ptr == argv[3])) {
+        avrdude_message(MSG_INFO, "%s (%s): can't parse length \"%s\"\n",
+              progname, argv[0], argv[3]);
+        return -1;
+      }
+    } else {
+      len = read_size;
+    }
+  }
+  // No address or length specified
+  else if (argc == 2) {
+    if (strncmp(prevmem, memtype, strlen(memtype)) != 0) {
       addr = 0;
+      len  = read_size;
+      strncpy(prevmem, memtype, sizeof(prevmem) - 1);
+      prevmem[sizeof(prevmem) - 1] = 0;
     }
-    else {
-      avrdude_message(MSG_INFO, "%s (dump): address 0x%05lx is out of range for %s memory\n",
-                      progname, addr, mem->desc);
-      return -1;
-    }
+    if (addr >= maxsize)
+      addr = 0; // Wrap around
   }
 
-  /* trim len if nessary to not read past the end of memory */
+  // Trim len if nessary to not read past the end of memory
   if ((addr + len) > maxsize)
     len = maxsize - addr;
 
-  buf = malloc(len);
+  uint8_t * buf = malloc(len);
   if (buf == NULL) {
     avrdude_message(MSG_INFO, "%s (dump): out of memory\n", progname);
     return -1;
   }
 
-  for (i=0; i<len; i++) {
-    rc = pgm->read_byte(pgm, p, mem, addr+i, &buf[i]);
+  for (uint32_t i = 0; i < len; i++) {
+    int32_t rc = pgm->read_byte(pgm, p, mem, addr + i, &buf[i]);
     if (rc != 0) {
       avrdude_message(MSG_INFO, "error reading %s address 0x%05lx of part %s\n",
-              mem->desc, addr+i, p->desc);
+              mem->desc, addr + i, p->desc);
       if (rc == -1)
         avrdude_message(MSG_INFO, "read operation not supported on memory type \"%s\"\n",
                 mem->desc);
@@ -315,7 +315,6 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p,
   }
 
   hexdump_buf(stdout, addr, buf, len);
-
   fprintf(stdout, "\n");
 
   free(buf);

From df6e2eea127837f356349ddf59365ec42dcd0e54 Mon Sep 17 00:00:00 2001
From: MCUdude <hansibull@gmail.com>
Date: Wed, 2 Mar 2022 20:09:59 +0100
Subject: [PATCH 4/9] Fix terminal write bug Wouldn't write data properly after
 an integer >= 2 bytes was written

---
 src/term.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/term.c b/src/term.c
index 7051503a..281a1f70 100644
--- a/src/term.c
+++ b/src/term.c
@@ -410,7 +410,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
     };
   } data = {.bytes_grown = 0, .size = 0, .is_float = false, .ll = 0, .is_signed = false};
 
-  for (i = start_offset; i < len + start_offset - data.bytes_grown; i++) {
+  for (i = start_offset; i < len + start_offset; i++) {
     data.is_float = false;
     data.size = 0;
 

From c7174d767889e7ee279b0f6dc561176cb741668a Mon Sep 17 00:00:00 2001
From: MCUdude <hansibull@gmail.com>
Date: Wed, 2 Mar 2022 20:24:51 +0100
Subject: [PATCH 5/9] Update description

---
 src/term.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/term.c b/src/term.c
index 281a1f70..fc1b1069 100644
--- a/src/term.c
+++ b/src/term.c
@@ -334,7 +334,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
       "Usage: write <memtype> <start addr> <data1> <data2> <dataN>\n"
       "       write <memtype> <start addr> <no. bytes> <data1> <dataN> <...>\n\n"
       "       Add a suffix to manually specify the size for each field:\n"
-      "       H/h/S/s: 16-bit, L/l: 32-bit, LL/ll: 6-bit, F/f: 32-bit float\n");
+      "       HH/hh: 8-bit, H/h/S/s: 16-bit, L/l: 32-bit, LL/ll: 64-bit, F/f: 32-bit float\n");
     return -1;
   }
 

From d9c52249a9822333dba5cb3db701dceeb174ee1e Mon Sep 17 00:00:00 2001
From: MCUdude <hansibull@gmail.com>
Date: Thu, 3 Mar 2022 19:37:42 +0100
Subject: [PATCH 6/9] Restructure "write mode" code

---
 src/term.c | 26 +++++++++-----------------
 1 file changed, 9 insertions(+), 17 deletions(-)

diff --git a/src/term.c b/src/term.c
index fc1b1069..d98f0207 100644
--- a/src/term.c
+++ b/src/term.c
@@ -365,9 +365,16 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
     return -1;
   }
 
-  // Figure out how many bytes there is to write to memory
+  uint8_t * buf = malloc(mem->size);
+  if (buf == NULL) {
+    avrdude_message(MSG_INFO, "%s (write): out of memory\n", progname);
+    return -1;
+  }
+
+  // Find the first argument to write to flash and how many arguments to parse and write
   if (strcmp(argv[argc - 1], "...") == 0) {
     write_mode = WRITE_MODE_FILL;
+    start_offset = 4;
     len = strtoul(argv[3], &end_ptr, 0);
     if (*end_ptr || (end_ptr == argv[3])) {
       avrdude_message(MSG_INFO, "%s (write ...): can't parse address \"%s\"\n",
@@ -376,23 +383,8 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
     }
   } else {
     write_mode = WRITE_MODE_STANDARD;
-  }
-
-  uint8_t * buf = malloc(mem->size);
-  if (buf == NULL) {
-    avrdude_message(MSG_INFO, "%s (write): out of memory\n", progname);
-    return -1;
-  }
-
-  if (write_mode == WRITE_MODE_STANDARD) {
-    start_offset = 3; // Argument number where data to write starts
+    start_offset = 3;
     len = argc - start_offset;
-  } else if (write_mode == WRITE_MODE_FILL)
-    start_offset = 4;
-  else {
-    avrdude_message(MSG_INFO, "%s (write): invalid write mode %d\n",
-                    progname, write_mode);
-    return -1;
   }
 
   // Structure related to data that is being written to memory

From 5cbc9c37fc71c424e99bdcc00bb910fd581c2676 Mon Sep 17 00:00:00 2001
From: Joerg Wunsch <j@uriah.heep.sax.de>
Date: Thu, 3 Mar 2022 23:15:20 +0100
Subject: [PATCH 7/9] Mention PRs #893, #894, #896, bug #889

---
 NEWS | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/NEWS b/NEWS
index 3ede3e9f..1e00e48f 100644
--- a/NEWS
+++ b/NEWS
@@ -72,6 +72,7 @@ Changes since version 6.4:
     - Rework HID support for Windows #881
     - List of signing keys? #884
     - Pickit4 UPDI is writing at offset 0x4000 into flash instead of 0x0000. #892
+    - SerialUPDI programmer can't write to usersig/userrow in terminal mode #889
 
   * Pull requests:
 
@@ -144,6 +145,9 @@ Changes since version 6.4:
     - Avrdude terminal write improvements #880
     - Add userrow and usersig aliases #888
     - For UPDI devices do not add offset when accessing flash. #895
+    - Support both userrow and usersig names #893
+    - Fix ugly terminal write bug #896
+    - Improve terminal read functionality #894
 
   * Internals:
 

From 34168759b0b01691c29140b9768e3d65b7bbbf06 Mon Sep 17 00:00:00 2001
From: Joerg Wunsch <j@uriah.heep.sax.de>
Date: Mon, 7 Mar 2022 22:52:14 +0100
Subject: [PATCH 8/9] Fix a one-bit error in ATmega165* signature read command.

---
 NEWS                | 1 +
 src/avrdude.conf.in | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/NEWS b/NEWS
index 1e00e48f..c33142d1 100644
--- a/NEWS
+++ b/NEWS
@@ -73,6 +73,7 @@ Changes since version 6.4:
     - List of signing keys? #884
     - Pickit4 UPDI is writing at offset 0x4000 into flash instead of 0x0000. #892
     - SerialUPDI programmer can't write to usersig/userrow in terminal mode #889
+    - Signature read command for ATmega165* was wrong (no-id)
 
   * Pull requests:
 
diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in
index 3ba49e6a..6366de5c 100644
--- a/src/avrdude.conf.in
+++ b/src/avrdude.conf.in
@@ -14437,7 +14437,7 @@ part
 
     memory "signature"
         size            = 3;
-        read            = "0  0  1  1   1  0  0  0   0  0  0  0   0  0  0  0",
+        read            = "0  0  1  1   0  0  0  0   0  0  0  0   0  0  0  0",
                           "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
       ;
 

From 416c465ec08c8e6525df1d47706ab41f24fc546f Mon Sep 17 00:00:00 2001
From: Joerg Wunsch <j@uriah.heep.sax.de>
Date: Sun, 13 Mar 2022 00:13:29 +0100
Subject: [PATCH 9/9] Bring the texinfo doc up to date

* remove copyright years; they are not meaningful anyway
* reflect the project move from Savannah to Github
---
 src/doc/avrdude.texi | 26 +++++++++++---------------
 1 file changed, 11 insertions(+), 15 deletions(-)

diff --git a/src/doc/avrdude.texi b/src/doc/avrdude.texi
index 0364a296..68769ec6 100644
--- a/src/doc/avrdude.texi
+++ b/src/doc/avrdude.texi
@@ -28,9 +28,7 @@ This file documents the avrdude program.
 
 For avrdude version @value{VERSION}, @value{UPDATED}.
 
-Copyright @copyright{} 2003, 2005 Brian Dean
-
-Copyright @copyright{} 2006 - 2021 J@"org Wunsch
+Copyright @copyright{} Brian Dean, J@"org Wunsch
 
 Permission is granted to make and distribute verbatim copies of
 this manual provided the copyright notice and this permission notice
@@ -66,11 +64,9 @@ the terms of the GNU Free Documentation License (FDL), version 1.3.
 @page
 Send comments on AVRDUDE to @w{@email{avrdude-dev@@nongnu.org}}.
 
-Use @uref{http://savannah.nongnu.org/bugs/?group=avrdude} to report bugs.
+Use @uref{https://github.com/avrdudes/avrdude/issues} to report bugs.
 
-Copyright @copyright{} 2003,2005 Brian S. Dean
-
-Copyright @copyright{} 2006 - 2013 J@"org Wunsch
+Copyright @copyright{} Brian S. Dean, J@"org Wunsch
 @sp 2
 
 Permission is granted to make and distribute verbatim copies of
@@ -104,11 +100,9 @@ For avrdude version @value{VERSION}, @value{UPDATED}.
 
 Send comments on AVRDUDE to @w{@email{avrdude-dev@@nongnu.org}}.
 
-Use @uref{http://savannah.nongnu.org/bugs/?group=avrdude} to report bugs.
+Use @uref{https://github.com/avrdudes/avrdude/issues} to report bugs.
 
-Copyright @copyright{} 2003,2005 Brian S. Dean
-
-Copyright @copyright{} 2006 J@"org Wunsch
+Copyright @copyright{} Brian S. Dean, J@"org Wunsch
 @end ifinfo
 
 @menu
@@ -353,13 +347,15 @@ AVRDUDE when interest grew in a Windows port of the software so that the
 name did not conflict with AVRPROG.EXE which is the name of Atmel's
 Windows programming software.
 
-The AVRDUDE source now resides in the public CVS repository on
-savannah.gnu.org (@url{http://savannah.gnu.org/projects/avrdude/}),
-where it continues to be enhanced and ported to other systems.  In
+For many years, the AVRDUDE source resided in public repositories on
+savannah.nongnu.org,
+where it continued to be enhanced and ported to other systems.  In
 addition to FreeBSD, AVRDUDE now runs on Linux and Windows.  The
 developers behind the porting effort primarily were Ted Roth, Eric
 Weddington, and Joerg Wunsch.
 
+In 2022, the project moved to Github (@url{https://github.com/avrdudes/avrdude/}).
+
 And in the spirit of many open source projects, this manual also draws
 on the work of others.  The initial revision was composed of parts of
 the original Unix manual page written by Joerg Wunsch, the original web
@@ -2446,7 +2442,7 @@ such as @option{--prefix} and @option{--datadir}.
 @noindent
 In general, please report any bugs encountered via
 @*
-@url{http://savannah.nongnu.org/bugs/?group=avrdude}.
+@url{https://github.com/avrdudes/avrdude/issues}.
 
 
 @itemize @bullet