From b3cc1535b67a0f86928994284261444f8a14b129 Mon Sep 17 00:00:00 2001
From: bsd <bsd@81a1dc3b-b13d-400b-aceb-764788c761c2>
Date: Sun, 1 Dec 2002 06:35:18 +0000
Subject: [PATCH] Optimize reading and writing for the STK500 programmer if the
 part supports paged reads and writes.  This greatly decreases the
 program/verify time from about 4.5 minutes down to about 10 seconds in a 12K
 program size test case.

Print out the hardware and firmware version for the STK500 if verbose
is enabled.


git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@161 81a1dc3b-b13d-400b-aceb-764788c761c2
---
 avr.c     |  17 +++
 avr.h     |  18 ----
 avrpart.h |  18 ++++
 main.c    |  16 +--
 pgm.c     |  11 ++
 pgm.h     |   4 +
 stk500.c  | 314 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 7 files changed, 370 insertions(+), 28 deletions(-)

diff --git a/avr.c b/avr.c
index 8555ec8d..b1013533 100644
--- a/avr.c
+++ b/avr.c
@@ -374,6 +374,15 @@ int avr_read(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size,
     size = mem->size;
   }
 
+  if (mem->paged && pgm->paged_load != NULL) {
+    /*
+     * the programmer directly supports writing this memory, perhaps
+     * more efficiently than we can from here 
+     */
+    return pgm->paged_load(pgm, p, mem, size);
+  }
+
+
   printed = 0;
 
   for (i=0; i<size; i++) {
@@ -665,6 +674,14 @@ int avr_write(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size,
 
   pgm->err_led(pgm, OFF);
 
+  if (m->paged && pgm->paged_write != NULL) {
+    /*
+     * the programmer directly supports writing this memory, perhaps
+     * more efficiently than we can from here 
+     */
+    return pgm->paged_write(pgm, p, m, size);
+  }
+
   printed = 0;
   werror  = 0;
 
diff --git a/avr.h b/avr.h
index c48f1cfa..7e7ac16d 100644
--- a/avr.h
+++ b/avr.h
@@ -39,24 +39,6 @@
 #include "pgm.h"
 
 
-#define AVR_MEMDESCLEN 64
-typedef struct avrmem {
-  char desc[AVR_MEMDESCLEN];  /* memory description ("flash", "eeprom", etc) */
-  int paged;                  /* page addressed (e.g. ATmega flash) */
-  int size;                   /* total memory size in bytes */
-  int page_size;              /* size of memory page (if page addressed) */
-  int num_pages;              /* number of pages (if page addressed) */
-  int min_write_delay;        /* microseconds */
-  int max_write_delay;        /* microseconds */
-  int pwroff_after_write;     /* after this memory type is written to,
-                                 the device must be powered off and
-                                 back on, see errata
-                                 http://www.atmel.com/atmel/acrobat/doc1280.pdf */
-  unsigned char readback[2];  /* polled read-back values */
-  unsigned char * buf;        /* pointer to memory buffer */
-  OPCODE * op[AVR_OP_MAX];    /* opcodes */
-} AVRMEM;
-
 
 extern struct avrpart parts[];
 
diff --git a/avrpart.h b/avrpart.h
index 3072ca3b..96db5c5a 100644
--- a/avrpart.h
+++ b/avrpart.h
@@ -56,4 +56,22 @@ typedef struct avrpart {
   LISTID        mem;                /* avr memory definitions */
 } AVRPART;
 
+#define AVR_MEMDESCLEN 64
+typedef struct avrmem {
+  char desc[AVR_MEMDESCLEN];  /* memory description ("flash", "eeprom", etc) */
+  int paged;                  /* page addressed (e.g. ATmega flash) */
+  int size;                   /* total memory size in bytes */
+  int page_size;              /* size of memory page (if page addressed) */
+  int num_pages;              /* number of pages (if page addressed) */
+  int min_write_delay;        /* microseconds */
+  int max_write_delay;        /* microseconds */
+  int pwroff_after_write;     /* after this memory type is written to,
+                                 the device must be powered off and
+                                 back on, see errata
+                                 http://www.atmel.com/atmel/acrobat/doc1280.pdf */
+  unsigned char readback[2];  /* polled read-back values */
+  unsigned char * buf;        /* pointer to memory buffer */
+  OPCODE * op[AVR_OP_MAX];    /* opcodes */
+} AVRMEM;
+
 #endif
diff --git a/main.c b/main.c
index 23c83b39..8e0dd9a8 100644
--- a/main.c
+++ b/main.c
@@ -735,14 +735,6 @@ int main(int argc, char * argv [])
   p = avr_dup_part(p);
   v = avr_dup_part(p);
 
-  if (verbose) {
-    avr_display(stderr, p, progbuf, verbose);
-    fprintf(stderr, "\n");
-    pinconfig_display(progbuf);
-  }
-
-  fprintf(stderr, "\n");
-
   if (strcmp(pgm->type, "PPI") == 0) {
     verify_pin_assigned(PIN_AVR_RESET, "AVR RESET");
     verify_pin_assigned(PIN_AVR_SCK,   "AVR SCK");
@@ -755,6 +747,14 @@ int main(int argc, char * argv [])
    */
   pgm->open(pgm, port);
 
+  if (verbose) {
+    avr_display(stderr, p, progbuf, verbose);
+    fprintf(stderr, "\n");
+    pinconfig_display(progbuf);
+  }
+
+  fprintf(stderr, "\n");
+
   exitrc = 0;
 
   rc = pgm->save(pgm);
diff --git a/pgm.c b/pgm.c
index 5d466338..47acf982 100644
--- a/pgm.c
+++ b/pgm.c
@@ -69,6 +69,10 @@ PROGRAMMER * pgm_new(void)
   for (i=0; i<N_PINS; i++)
     pgm->pinno[i] = 0;
 
+  /*
+   * mandatory functions - these are called without checking to see
+   * whether they are assigned or not
+   */
   pgm->rdy_led        = pgm_default_1;
   pgm->err_led        = pgm_default_1;
   pgm->pgm_led        = pgm_default_1;
@@ -87,6 +91,13 @@ PROGRAMMER * pgm_new(void)
   pgm->open           = pgm_default_6;
   pgm->close          = pgm_default_4;
 
+  /*
+   * optional functions - these are checked to make sure they are
+   * assigned before they are called
+   */
+  pgm->paged_write    = NULL;
+  pgm->paged_load     = NULL;
+
   return pgm;
 }
 
diff --git a/pgm.h b/pgm.h
index 3d5f1738..83e8db55 100644
--- a/pgm.h
+++ b/pgm.h
@@ -71,6 +71,10 @@ typedef struct programmer_t {
                           unsigned char res[4]);
   void (*open)           (struct programmer_t * pgm, char * port);
   void (*close)          (struct programmer_t * pgm);
+  int  (*paged_write)    (struct programmer_t * pgm, AVRPART * p, AVRMEM * m, 
+                          int n_bytes);
+  int  (*paged_load)     (struct programmer_t * pgm, AVRPART * p, AVRMEM * m,
+                          int n_bytes);
 } PROGRAMMER;
 
 
diff --git a/stk500.c b/stk500.c
index 24c7ac6f..bd9bd379 100644
--- a/stk500.c
+++ b/stk500.c
@@ -29,6 +29,15 @@
 
 /* $Id$ */
 
+/*
+ * avrprog interface for Atmel STK500 programmer
+ *
+ * Note: most commands use the "universal command" feature of the
+ * programmer in a "pass through" mode, exceptions are "program
+ * enable", "paged read", and "paged write".
+ *
+ */
+
 #include <stdio.h>
 #include <string.h>
 #include <fcntl.h>
@@ -201,8 +210,7 @@ static int getsync(PROGRAMMER * pgm)
   unsigned char buf[32], resp[32];
 
   /*
-   * get in sync
-   */
+   * get in sync */
   buf[0] = Cmnd_STK_GET_SYNC;
   buf[1] = Sync_CRC_EOP;
   send(pgm, buf, 2);
@@ -683,8 +691,301 @@ void stk500_close(PROGRAMMER * pgm)
 }
 
 
+static int loadaddr(PROGRAMMER * pgm, uint16_t addr)
+{
+  unsigned char buf[16];
+  int tries;
+
+  tries = 0;
+ retry:
+  tries++;
+  buf[0] = Cmnd_STK_LOAD_ADDRESS;
+  buf[1] = addr & 0xff;
+  buf[2] = (addr >> 8) & 0xff;
+  buf[3] = Sync_CRC_EOP;
+
+  send(pgm, buf, 4);
+
+  recv(pgm, buf, 1);
+  if (buf[0] == Resp_STK_NOSYNC) {
+    if (tries > 33) {
+      fprintf(stderr, "%s: loadaddr(): can't get into sync\n",
+              progname);
+      return -1;
+    }
+    getsync(pgm);
+    goto retry;
+  }
+  else if (buf[0] != Resp_STK_INSYNC) {
+    fprintf(stderr,
+            "%s: loadaddr(): (a) protocol error, "
+            "expect=0x%02x, resp=0x%02x\n", 
+            progname, Resp_STK_INSYNC, buf[0]);
+    return -1;
+  }
+
+  recv(pgm, buf, 1);
+  if (buf[0] == Resp_STK_OK) {
+    return 0;
+  }
+
+  fprintf(stderr,
+          "%s: loadaddr(): (a) protocol error, "
+          "expect=0x%02x, resp=0x%02x\n", 
+          progname, Resp_STK_INSYNC, buf[0]);
+  return -1;
+}
+
+
+int stk500_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, int n_bytes)
+{
+  unsigned char buf[16];
+  int memtype;
+  unsigned int addr;
+  int a_div;
+  int i;
+  int tries;
+  unsigned int n;
+
+  if (!m->paged)
+    return -1;
+
+  if (strcmp(m->desc, "flash") == 0) {
+    memtype = 'F';
+  }
+  else if (strcmp(m->desc, "flash") == 0) {
+    memtype = 'E';
+  }
+  else {
+    return -2;
+  }
+
+  if (m->op[AVR_OP_LOADPAGE_LO])
+    a_div = 2;
+  else
+    a_div = 1;
+
+  if (n_bytes > m->size) {
+    n_bytes = m->size;
+    n = m->size;
+  }
+  else {
+    if ((n_bytes % m->page_size) != 0) {
+      n = n_bytes + m->page_size - (n_bytes % m->page_size);
+    }
+    else {
+      n = n_bytes;
+    }
+  }
+
+  for (addr = 0; addr < n; addr += m->page_size) {
+    fprintf(stderr, "\r      \r%6u", addr);
+    tries = 0;
+  retry:
+    tries++;
+    loadaddr(pgm, addr/a_div);
+    buf[0] = Cmnd_STK_PROG_PAGE;
+    buf[1] = (m->page_size >> 8) & 0xff;
+    buf[2] = m->page_size & 0xff;
+    buf[3] = memtype;
+    send(pgm, buf, 4);
+    for (i=0; i<m->page_size; i++) {
+      buf[0] = m->buf[addr + i];
+      send(pgm, buf, 1);
+    }
+    buf[0] = Sync_CRC_EOP;
+    send(pgm, buf, 1);
+
+    recv(pgm, buf, 1);
+    if (buf[0] == Resp_STK_NOSYNC) {
+      if (tries > 33) {
+        fprintf(stderr, "\n%s: stk500_paged_write(): can't get into sync\n",
+                progname);
+        return -3;
+      }
+      getsync(pgm);
+      goto retry;
+    }
+    else if (buf[0] != Resp_STK_INSYNC) {
+      fprintf(stderr,
+              "\n%s: stk500_paged_write(): (a) protocol error, "
+              "expect=0x%02x, resp=0x%02x\n", 
+              progname, Resp_STK_INSYNC, buf[0]);
+      return -4;
+    }
+    
+    recv(pgm, buf, 1);
+    if (buf[0] != Resp_STK_OK) {
+      fprintf(stderr,
+              "\n%s: stk500_paged_write(): (a) protocol error, "
+              "expect=0x%02x, resp=0x%02x\n", 
+              progname, Resp_STK_INSYNC, buf[0]);
+      return -5;
+    }
+  }
+  fprintf(stderr, "\r      \r%6u", addr-1);
+  fprintf(stderr, "\n");
+
+  return n;
+}
+
+
+int stk500_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, int n_bytes)
+{
+  unsigned char buf[16];
+  int memtype;
+  unsigned int addr;
+  int a_div;
+  int tries;
+  unsigned int n;
+
+  if (!m->paged)
+    return -1;
+
+  if (strcmp(m->desc, "flash") == 0) {
+    memtype = 'F';
+  }
+  else if (strcmp(m->desc, "flash") == 0) {
+    memtype = 'E';
+  }
+  else {
+    return -2;
+  }
+
+  if (m->op[AVR_OP_LOADPAGE_LO])
+    a_div = 2;
+  else
+    a_div = 1;
+
+  if (n_bytes > m->size) {
+    n_bytes = m->size;
+    n = m->size;
+  }
+  else {
+    if ((n_bytes % m->page_size) != 0) {
+      n = n_bytes + m->page_size - (n_bytes % m->page_size);
+    }
+    else {
+      n = n_bytes;
+    }
+  }
+
+  for (addr = 0; addr < n; addr += m->page_size) {
+    fprintf(stderr, "\r      \r%6u", addr);
+    tries = 0;
+  retry:
+    tries++;
+    loadaddr(pgm, addr/a_div);
+    buf[0] = Cmnd_STK_READ_PAGE;
+    buf[1] = (m->page_size >> 8) & 0xff;
+    buf[2] = m->page_size & 0xff;
+    buf[3] = memtype;
+    buf[4] = Sync_CRC_EOP;
+    send(pgm, buf, 5);
+
+    recv(pgm, buf, 1);
+    if (buf[0] == Resp_STK_NOSYNC) {
+      if (tries > 33) {
+        fprintf(stderr, "\n%s: stk500_paged_load(): can't get into sync\n",
+                progname);
+        return -3;
+      }
+      getsync(pgm);
+      goto retry;
+    }
+    else if (buf[0] != Resp_STK_INSYNC) {
+      fprintf(stderr,
+              "\n%s: stk500_paged_load(): (a) protocol error, "
+              "expect=0x%02x, resp=0x%02x\n", 
+              progname, Resp_STK_INSYNC, buf[0]);
+      return -4;
+    }
+
+    recv(pgm, &m->buf[addr], m->page_size);
+
+    recv(pgm, buf, 1);
+    if (buf[0] != Resp_STK_OK) {
+      fprintf(stderr,
+              "\n%s: stk500_paged_load(): (a) protocol error, "
+              "expect=0x%02x, resp=0x%02x\n", 
+              progname, Resp_STK_INSYNC, buf[0]);
+      return -5;
+    }
+  }
+  fprintf(stderr, "\r      \r%6u", addr-1);
+  fprintf(stderr, "\n");
+
+  return n;
+}
+
+
+static int getparm(PROGRAMMER * pgm, unsigned parm, unsigned * value)
+{
+  unsigned char buf[16];
+  unsigned v;
+  int tries = 0;
+
+ retry:
+  tries++;
+  buf[0] = Cmnd_STK_GET_PARAMETER;
+  buf[1] = parm;
+  buf[2] = Sync_CRC_EOP;
+
+  send(pgm, buf, 3);
+
+  recv(pgm, buf, 1);
+  if (buf[0] == Resp_STK_NOSYNC) {
+    if (tries > 33) {
+      fprintf(stderr, "\n%s: getparm(): can't get into sync\n",
+              progname);
+      return -1;
+    }
+    getsync(pgm);
+    goto retry;
+  }
+  else if (buf[0] != Resp_STK_INSYNC) {
+    fprintf(stderr,
+            "\n%s: getparm(): (a) protocol error, "
+            "expect=0x%02x, resp=0x%02x\n", 
+            progname, Resp_STK_INSYNC, buf[0]);
+    return -2;
+  }
+
+  recv(pgm, buf, 1);
+  v = buf[0];
+
+  recv(pgm, buf, 1);
+  if (buf[0] == Resp_STK_FAILED) {
+    fprintf(stderr,
+            "\n%s: getparm(): parameter 0x%02x failed\n",
+            progname, v);
+    return -3;
+  }
+  else if (buf[0] != Resp_STK_OK) {
+    fprintf(stderr,
+            "\n%s: getparm(): (a) protocol error, "
+            "expect=0x%02x, resp=0x%02x\n", 
+            progname, Resp_STK_INSYNC, buf[0]);
+    return -3;
+  }
+
+  *value = v;
+
+  return 0;
+}
+
+  
 void stk500_display(PROGRAMMER * pgm, char * p)
 {
+  unsigned maj, min, hdw;
+
+  getparm(pgm, Parm_STK_HW_VER, &hdw);
+  getparm(pgm, Parm_STK_SW_MAJOR, &maj);
+  getparm(pgm, Parm_STK_SW_MINOR, &min);
+
+  fprintf(stderr, "%sHardware Version: %d\n", p, hdw);
+  fprintf(stderr, "%sFirmware Version: %d.%d\n", p, maj, min);
+
   return;
 }
 
@@ -693,6 +994,9 @@ void stk500_initpgm(PROGRAMMER * pgm)
 {
   strcpy(pgm->type, "STK500");
 
+  /*
+   * mandatory functions
+   */
   pgm->rdy_led        = stk500_rdy_led;
   pgm->err_led        = stk500_err_led;
   pgm->pgm_led        = stk500_pgm_led;
@@ -710,6 +1014,12 @@ void stk500_initpgm(PROGRAMMER * pgm)
   pgm->cmd            = stk500_cmd;
   pgm->open           = stk500_open;
   pgm->close          = stk500_close;
+
+  /*
+   * optional functions
+   */
+  pgm->paged_write    = stk500_paged_write;
+  pgm->paged_load     = stk500_paged_load;
 }