diff --git a/Makefile b/Makefile
index c19bf8d9..0dd87e7e 100644
--- a/Makefile
+++ b/Makefile
@@ -55,6 +55,9 @@ install : dirs                             \
 	  ${CONFIGDIR}/avrprog.conf.sample \
 	  ${CONFIGDIR}/avrprog.conf
 
+config_gram.o : avr.h config.h lists.h pindefs.h
+
+
 dirs :
 	@for dir in ${DIRS}; do \
 	  if [ ! -d $$dir ]; then \
diff --git a/avr.c b/avr.c
index 40e3b1f3..54bf9e5f 100644
--- a/avr.c
+++ b/avr.c
@@ -37,6 +37,7 @@
 
 #include "avr.h"
 #include "config.h"
+#include "lists.h"
 #include "pindefs.h"
 #include "ppi.h"
 
@@ -64,33 +65,82 @@ AVRPART * avr_new_part(void)
   p->id[0]   = 0;
   p->desc[0] = 0;
 
+  p->mem = lcreat(NULL, 0);
+
   return p;
 }
 
 
 
-AVRPART * avr_dup_part(AVRPART * d)
+OPCODE * avr_new_opcode(void)
 {
-  AVRPART * p;
-  int i;
+  OPCODE * m;
 
-  p = (AVRPART *)malloc(sizeof(AVRPART));
-  if (p == NULL) {
-    fprintf(stderr, "avr_dup_part(): out of memory\n");
+  m = (OPCODE *)malloc(sizeof(*m));
+  if (m == NULL) {
+    fprintf(stderr, "avr_new_opcode(): out of memory\n");
     exit(1);
   }
 
+  memset(m, 0, sizeof(*m));
+
+  return m;
+}
+
+
+
+AVRMEM * avr_new_memtype(void)
+{
+  AVRMEM * m;
+
+  m = (AVRMEM *)malloc(sizeof(*m));
+  if (m == NULL) {
+    fprintf(stderr, "avr_new_memtype(): out of memory\n");
+    exit(1);
+  }
+
+  memset(m, 0, sizeof(*m));
+
+  return m;
+}
+
+
+AVRMEM * avr_dup_mem(AVRMEM * m)
+{
+  AVRMEM * n;
+
+  n = avr_new_memtype();
+
+  *n = *m;
+
+  n->buf = (unsigned char *)malloc(n->size);
+  if (n->buf == NULL) {
+    fprintf(stderr, 
+            "avr_dup_mem(): out of memory (memsize=%d)\n", 
+            n->size);
+    exit(1);
+  }
+  memset(n->buf, 0, n->size);
+
+  return n;
+}
+
+
+AVRPART * avr_dup_part(AVRPART * d)
+{
+  AVRPART * p;
+  LISTID save;
+  LNODEID ln;
+
+  p = avr_new_part();
+  save = p->mem;
+
   *p = *d;
 
-  for (i=0; i<AVR_MAXMEMTYPES; i++) {
-    p->mem[i].buf = (unsigned char *)malloc(p->mem[i].size);
-    if (p->mem[i].buf == NULL) {
-      fprintf(stderr, 
-              "avr_dup_part(): out of memory (memsize=%d)\n", 
-              p->mem[i].size);
-      exit(1);
-    }
-    memset(p->mem[i].buf, 0, p->mem[i].size);
+  p->mem = save;
+
+  for (ln=lfirst(d->mem); ln; ln=lnext(ln)) {
+    ladd(p->mem, avr_dup_mem(ldata(ln)));
   }
 
   return p;
@@ -98,6 +148,32 @@ AVRPART * avr_dup_part(AVRPART * d)
 
 
 
+AVRMEM * avr_locate_mem(AVRPART * p, char * desc)
+{
+  AVRMEM * m, * match;
+  LNODEID ln;
+  int matches;
+  int l;
+
+  l = strlen(desc);
+  matches = 0;
+  match = NULL;
+  for (ln=lfirst(p->mem); ln; ln=lnext(ln)) {
+    m = ldata(ln);
+    if (strncmp(desc, m->desc, l) == 0) {
+      match = m;
+      matches++;
+    }
+  }
+
+  if (matches == 1)
+    return match;
+
+  return NULL;
+}
+
+
+
 /*
  * transmit and receive a bit of data to/from the AVR device
  */
@@ -155,132 +231,106 @@ int avr_cmd(int fd, unsigned char cmd[4], unsigned char res[4])
     res[i] = avr_txrx(fd, cmd[i]);
   }
 
-  return 0;
-}
-
-
-/*
- * read a calibration byte
- */
-unsigned char avr_read_calibration(int fd, AVRPART * p)
-{
-  unsigned char cmd[4];
-  unsigned char res[4];
-
-  LED_ON(fd, pgm->pinno[PIN_LED_PGM]);
-  LED_OFF(fd, pgm->pinno[PIN_LED_ERR]);
-
-  cmd[0] = 0x38;
-  cmd[1] = 0x00; /* don't care */
-  cmd[2] = 0x00;
-  cmd[3] = 0x00; /* don't care */
-
-  avr_cmd(fd, cmd, res);
-
-  LED_OFF(fd, pgm->pinno[PIN_LED_PGM]);
-
-  return res[3];    /* calibration byte */
-}
-
-
-/*
- * read a fuse byte
- */
-unsigned char avr_read_fuse(int fd, AVRPART * p, int high)
-{
-  unsigned char cmd[4];
-  unsigned char res[4];
-  static unsigned char cmdbyte1[2] = { 0x50, 0x58 };
-  static unsigned char cmdbyte2[2] = { 0x00, 0x08 };
-
-  LED_ON(fd, pgm->pinno[PIN_LED_PGM]);
-  LED_OFF(fd, pgm->pinno[PIN_LED_ERR]);
-
-  cmd[0] = cmdbyte1[high];
-  cmd[1] = cmdbyte2[high];
-  cmd[2] = 0;               /* don't care */
-  cmd[3] = 0;               /* don't care */
-
-  avr_cmd(fd, cmd, res);
-
-  LED_OFF(fd, pgm->pinno[PIN_LED_PGM]);
-
-  return res[3];    /* fuse bits */
-}
-
-
-/*
- * write a fuse byte
- */
-int avr_write_fuse(int fd, AVRPART * p, int high, unsigned char b)
-{
-  unsigned char cmd[4];
-  unsigned char res[4];
-  static unsigned char cmdbyte[2] = { 0xa0, 0xa8 };
-
-  LED_ON(fd, pgm->pinno[PIN_LED_PGM]);
-  LED_OFF(fd, pgm->pinno[PIN_LED_ERR]);
-
-  cmd[0] = 0xac;
-  cmd[1] = cmdbyte[high];
-  cmd[2] = 0x00;            /* don't care */
-  cmd[3] = b;               /* fuse bits  */
-
-  avr_cmd(fd, cmd, res);
-
-  usleep(2000);
-
-  LED_OFF(fd, pgm->pinno[PIN_LED_PGM]);
+#if 0
+  fprintf(stderr, "avr_cmd(): [ ");
+  for (i=0; i<4; i++)
+    fprintf(stderr, "%02x ", cmd[i]);
+  fprintf(stderr, "] [ ");
+  for (i=0; i<4; i++)
+    fprintf(stderr, "%02x ", res[i]);
+  fprintf(stderr, "]\n");
+#endif
 
   return 0;
 }
 
 
-/*
- * read a lock byte
- */
-unsigned char avr_read_lock(int fd, AVRPART * p)
+int avr_set_bits(OPCODE * op, unsigned char * cmd)
 {
-  unsigned char cmd[4];
-  unsigned char res[4];
+  int i, j, bit;
+  unsigned char mask;
 
-  LED_ON(fd, pgm->pinno[PIN_LED_PGM]);
-  LED_OFF(fd, pgm->pinno[PIN_LED_ERR]);
+  for (i=0; i<32; i++) {
+    if (op->bit[i].type == AVR_CMDBIT_VALUE) {
+      j = 3 - i / 8;
+      bit = i % 8;
+      mask = 1 << bit;
+      if (op->bit[i].value)
+        cmd[j] = cmd[j] | mask;
+      else
+        cmd[j] = cmd[j] & ~mask;
+    }
+  }
 
-  cmd[0] = 0x58;
-  cmd[1] = 0x00;
-  cmd[2] = 0;
-  cmd[3] = 0;               /* don't care */
-
-  avr_cmd(fd, cmd, res);
-
-  LED_OFF(fd, pgm->pinno[PIN_LED_PGM]);
-
-  return res[3];  /* lock bits */
+  return 0;
 }
 
 
-/*
- * write a lock byte
- */
-int avr_write_lock(int fd, AVRPART * p, unsigned char b)
+int avr_set_addr(OPCODE * op, unsigned char * cmd, unsigned long addr)
 {
-  unsigned char cmd[4];
-  unsigned char res[4];
+  int i, j, bit;
+  unsigned long value;
+  unsigned char mask;
 
-  LED_ON(fd, pgm->pinno[PIN_LED_PGM]);
-  LED_OFF(fd, pgm->pinno[PIN_LED_ERR]);
+  for (i=0; i<32; i++) {
+    if (op->bit[i].type == AVR_CMDBIT_ADDRESS) {
+      j = 3 - i / 8;
+      bit = i % 8;
+      mask = 1 << bit;
+      value = addr >> op->bit[i].bitno & 0x01;
+      if (value)
+        cmd[j] = cmd[j] | mask;
+      else
+        cmd[j] = cmd[j] & ~mask;
+    }
+  }
 
-  cmd[0] = 0x5c;
-  cmd[1] = 0xe0;
-  cmd[2] = 0;               /* don't care */
-  cmd[3] = b;               /* lock bits  */
+  return 0;
+}
 
-  avr_cmd(fd, cmd, res);
 
-  usleep(2000);
+int avr_set_input(OPCODE * op, unsigned char * cmd, unsigned char data)
+{
+  int i, j, bit;
+  unsigned char value;
+  unsigned char mask;
 
-  LED_OFF(fd, pgm->pinno[PIN_LED_PGM]);
+  for (i=0; i<32; i++) {
+    if (op->bit[i].type == AVR_CMDBIT_INPUT) {
+      j = 3 - i / 8;
+      bit = i % 8;
+      mask = 1 << bit;
+      value = data >> op->bit[i].bitno & 0x01;
+      if (value)
+        cmd[j] = cmd[j] | mask;
+      else
+        cmd[j] = cmd[j] & ~mask;
+    }
+  }
+
+  return 0;
+}
+
+
+int avr_get_output(OPCODE * op, unsigned char * cmd, unsigned char * data)
+{
+  int i, j, bit;
+  unsigned char value;
+  unsigned char mask;
+
+  for (i=0; i<32; i++) {
+    if (op->bit[i].type == AVR_CMDBIT_OUTPUT) {
+      j = 3 - i / 8;
+      bit = i % 8;
+      mask = 1 << bit;
+      value = ((cmd[j] & mask) >> bit) & 0x01;
+      value = value << op->bit[i].bitno;
+      if (value)
+        *data = *data | value;
+      else
+        *data = *data & ~value;
+    }
+  }
 
   return 0;
 }
@@ -289,60 +339,89 @@ int avr_write_lock(int fd, AVRPART * p, unsigned char b)
 /*
  * read a byte of data from the indicated memory region
  */
-unsigned char avr_read_byte(int fd, AVRPART * p,
-                            int memtype, unsigned long addr)
+int avr_read_byte(int fd, AVRPART * p, AVRMEM * mem, unsigned long addr, 
+                  unsigned char * value)
 {
-  unsigned short offset;
   unsigned char cmd[4];
   unsigned char res[4];
-  /* order here is very important, AVR_EEPROM, AVR_FLASH, AVR_FLASH+1 */
-  static unsigned char cmdbyte[3] = { 0xa0, 0x20, 0x28 };
+  unsigned char data;
+  OPCODE * readop;
 
   LED_ON(fd, pgm->pinno[PIN_LED_PGM]);
   LED_OFF(fd, pgm->pinno[PIN_LED_ERR]);
 
-  offset = 0;
-
-  if (memtype == AVR_M_FLASH) {
-    offset = addr & 0x01;
-    addr   = addr / 2;
+  if (mem->op[AVR_OP_READ_LO]) {
+    if (addr & 0x00000001)
+      readop = mem->op[AVR_OP_READ_HI];
+    else
+      readop = mem->op[AVR_OP_READ_LO];
+    addr = addr / 2;
+  }
+  else {
+    readop = mem->op[AVR_OP_READ];
   }
 
-  cmd[0] = cmdbyte[memtype + offset];
-  cmd[1] = addr >> 8;     /* high order bits of address       */
-  cmd[2] = addr & 0x0ff;  /* low order bits of address        */
-  cmd[3] = 0;             /* don't care                       */
+  if (readop == NULL) {
+    fprintf(stderr, 
+            "avr_read_byte(): operation not supported on memory type \"%s\"\n",
+            p->desc);
+    return -1;
+  }
 
+  memset(cmd, 0, sizeof(cmd));
+
+  avr_set_bits(readop, cmd);
+  avr_set_addr(readop, cmd, addr);
   avr_cmd(fd, cmd, res);
+  data = 0;
+  avr_get_output(readop, res, &data);
 
   LED_OFF(fd, pgm->pinno[PIN_LED_PGM]);
 
-  return res[3];
+  *value = data;
+
+  return 0;
 }
 
 
 /*
  * Read the entirety of the specified memory type into the
  * corresponding buffer of the avrpart pointed to by 'p'.  If size =
- * 0, read the entire contents, otherwize, read 'size' bytes.
+ * 0, read the entire contents, otherwise, read 'size' bytes.
  *
- * Return the number of bytes read, or -1 if an error occurs.  */
-int avr_read(int fd, AVRPART * p, int memtype, int size)
+ * Return the number of bytes read, or -1 if an error occurs.  
+ */
+int avr_read(int fd, AVRPART * p, char * memtype, int size, int verbose)
 {
   unsigned char    rbyte;
   unsigned long    i;
   unsigned char  * buf;
+  AVRMEM * mem;
+  int rc;
 
-  buf  = p->mem[memtype].buf;
+  mem = avr_locate_mem(p, memtype);
+  if (mem == NULL) {
+    fprintf(stderr, "No \"%s\" memory for part %s\n",
+            memtype, p->desc);
+    return -1;
+  }
+
+  buf  = mem->buf;
   if (size == 0) {
-    size = p->mem[memtype].size;
+    size = mem->size;
   }
 
   for (i=0; i<size; i++) {
-    rbyte = avr_read_byte(fd, p, memtype, i);
-    if (i % 16 == 0)
-      fprintf(stderr, "                    \r%4lu  0x%02x", i, rbyte);
+    rc = avr_read_byte(fd, p, mem, i, &rbyte);
+    if (rc != 0) {
+      fprintf(stderr, "avr_read(): error reading address 0x%04lx\n", i);
+      return -2;
+    }
     buf[i] = rbyte;
+    if (verbose) {
+      if (i % 16 == 0)
+        fprintf(stderr, "                    \r%4lu  0x%02x", i, rbyte);
+    }
   }
 
   fprintf(stderr, "\n");
@@ -357,39 +436,38 @@ int avr_read(int fd, AVRPART * p, int memtype, int size)
 /*
  * write a byte of data to the indicated memory region
  */
-int avr_write_page(int fd, AVRPART * p, int memtype, 
-                   unsigned short page)
+int avr_write_page(int fd, AVRPART * p, AVRMEM * mem,
+                   unsigned long addr)
 {
   unsigned char cmd[4];
   unsigned char res[4];
+  OPCODE * wp;
+
+  wp = mem->op[AVR_OP_WRITEPAGE];
+  if (wp == NULL) {
+    fprintf(stderr, 
+            "avr_write_page(): memory \"%s\" not configured for page writes\n",
+            mem->desc);
+    return -1;
+  }
+
+  if (mem->op[AVR_OP_LOADPAGE_LO])
+    addr = addr / 2;
 
   LED_ON(fd, pgm->pinno[PIN_LED_PGM]);
   LED_OFF(fd, pgm->pinno[PIN_LED_ERR]);
 
-  /*
-   * 'page' indicates which page is being programmed: 0 for the first
-   * page_size block, 1 for the second, up to num_pages-1 for the
-   * last.  The MCU actually wants the high-order bits of what would
-   * be the actual address instead, shifted left to the upper most
-   * bits of a 16 bit word.  For a 128K flash, the actual address is a
-   * 17 bits.  To get the right value to send to the MCU, we want to
-   * shift 'page' left by 16 - the number of bits in the page
-   * address.
-   */
-  page = page << p->mem[memtype].pageaddr_shift;
-
-  cmd[0] = 0x4c;
-  cmd[1] = page >> 8;     /* high order bits of address */
-  cmd[2] = page & 0x0ff;  /* low order bits of address  */
-  cmd[3] = 0;             /* these bits are ignored     */
+  memset(cmd, 0, sizeof(cmd));
 
+  avr_set_bits(wp, cmd);
+  avr_set_addr(wp, cmd, addr);
   avr_cmd(fd, cmd, res);
 
   /*
    * since we don't know what voltage the target AVR is powered by, be
    * conservative and delay the max amount the spec says to wait 
    */
-  usleep(p->mem[memtype].max_write_delay);
+  usleep(mem->max_write_delay);
 
   LED_OFF(fd, pgm->pinno[PIN_LED_PGM]);
   return 0;
@@ -399,7 +477,7 @@ int avr_write_page(int fd, AVRPART * p, int memtype,
 /*
  * write a byte of data to the indicated memory region
  */
-int avr_write_byte(int fd, AVRPART * p, int memtype, 
+int avr_write_byte(int fd, AVRPART * p, AVRMEM * mem,
                    unsigned long addr, unsigned char data)
 {
   unsigned char cmd[4];
@@ -408,45 +486,67 @@ int avr_write_byte(int fd, AVRPART * p, int memtype,
   int ready;
   int tries;
   unsigned char b;
-  unsigned short offset;
   unsigned short caddr;
-  /* order here is very important, AVR_M_EEPROM, AVR_M_FLASH, AVR_M_FLASH+1 */
-  static unsigned char cmdbyte[3] = { 0xc0, 0x40, 0x48 };
+  OPCODE * writeop;
+  int rc;
 
-  if (!p->mem[memtype].paged) {
+  if (!mem->paged) {
     /* 
      * 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.
      */
-    b = avr_read_byte(fd, p, memtype, addr);
+    rc = avr_read_byte(fd, p, mem, addr, &b);
+    if (rc != 0)
+      return -1;
+
     if (b == data) {
       return 0;
     }
   }
-  else {
-    addr = addr % p->mem[memtype].page_size;
+
+  /*
+   * determine which memory opcode to use
+   */
+  if (mem->op[AVR_OP_WRITE_LO]) {
+    if (addr & 0x01)
+      writeop = mem->op[AVR_OP_WRITE_HI];
+    else
+      writeop = mem->op[AVR_OP_WRITE_LO];
+    caddr = addr / 2;
   }
+  else if (mem->op[AVR_OP_LOADPAGE_LO]) {
+    if (addr & 0x01)
+      writeop = mem->op[AVR_OP_LOADPAGE_HI];
+    else
+      writeop = mem->op[AVR_OP_LOADPAGE_LO];
+    caddr = addr / 2;
+  }
+  else {
+    writeop = mem->op[AVR_OP_WRITE];
+    caddr = addr;
+  }
+
+  if (writeop == NULL) {
+    fprintf(stderr, 
+            "avr_write_byte(): write not support for memory type \"%s\"\n",
+            mem->desc);
+    exit(1);
+    return -1;
+  }
+
 
   LED_ON(fd, pgm->pinno[PIN_LED_PGM]);
   LED_OFF(fd, pgm->pinno[PIN_LED_ERR]);
 
-  offset = 0;
-
-  caddr = addr;
-  if (memtype == AVR_M_FLASH) {
-    offset = addr & 0x01;
-    caddr  = addr / 2;
-  }
-
-  cmd[0] = cmdbyte[memtype + offset];
-  cmd[1] = caddr >> 8;     /* high order bits of address       */
-  cmd[2] = caddr & 0x0ff;  /* low order bits of address        */
-  cmd[3] = data;           /* data                             */
+  memset(cmd, 0, sizeof(cmd));
 
+  avr_set_bits(writeop, cmd);
+  avr_set_addr(writeop, cmd, caddr);
+  avr_set_input(writeop, cmd, data);
   avr_cmd(fd, cmd, res);
 
-  if (p->mem[memtype].paged) {
+  if (mem->paged) {
     /*
      * in paged addressing, single bytes to written to the memory
      * page complete immediately, we only need to delay when we commit
@@ -459,18 +559,24 @@ int avr_write_byte(int fd, AVRPART * p, int memtype,
   tries = 0;
   ready = 0;
   while (!ready) {
-    usleep(p->mem[memtype].min_write_delay); /* typical write delay */
-    r = avr_read_byte(fd, p, memtype, addr);
-    if ((data == p->mem[memtype].readback[0]) ||
-        (data == p->mem[memtype].readback[1])) {
+    usleep(mem->min_write_delay); /* typical write delay */
+    rc = avr_read_byte(fd, p, mem, addr, &r);
+    if (rc != 0) {
+      return -1;
+    }
+    if ((data == mem->readback[0]) ||
+        (data == mem->readback[1])) {
       /* 
        * use an extra long delay when we happen to be writing values
        * used for polled data read-back.  In this case, polling
        * doesn't work, and we need to delay the worst case write time
        * specified for the chip.
        */
-      usleep(p->mem[memtype].max_write_delay);
-      r = avr_read_byte(fd, p, memtype, addr);
+      usleep(mem->max_write_delay);
+      rc = avr_read_byte(fd, p, mem, addr, &r);
+      if (rc != 0) {
+        return -1;
+      }
     }
 
     if (r == data) {
@@ -504,19 +610,28 @@ int avr_write_byte(int fd, AVRPART * p, int memtype,
  *
  * Return the number of bytes written, or -1 if an error occurs.
  */
-int avr_write(int fd, AVRPART * p, int memtype, int size)
+int avr_write(int fd, AVRPART * p, char * memtype, int size, int verbose)
 {
   int              rc;
   int              wsize;
   unsigned long    i;
   unsigned char    data;
   int              werror;
+  AVRMEM         * m;
+
+  m = avr_locate_mem(p, memtype);
+  if (m == NULL) {
+    fprintf(stderr, "No \"%s\" memory for part %s\n",
+            memtype, p->desc);
+    return -1;
+  }
+
 
   LED_OFF(fd, pgm->pinno[PIN_LED_ERR]);
 
   werror = 0;
 
-  wsize = p->mem[memtype].size;
+  wsize = m->size;
   if (size < wsize) {
     wsize = size;
   }
@@ -530,10 +645,12 @@ int avr_write(int fd, AVRPART * p, int memtype, int size)
 
   for (i=0; i<wsize; i++) {
     /* eeprom or low byte of flash */
-    data = p->mem[memtype].buf[i];
-    rc = avr_write_byte(fd, p, memtype, i, data);
-    if (i % 16 == 0)
-      fprintf(stderr, "                      \r%4lu 0x%02x", i, data);
+    data = m->buf[i];
+    if (verbose) {
+      if (i % 16 == 0)
+        fprintf(stderr, "                      \r%4lu 0x%02x ", i, data);
+    }
+    rc = avr_write_byte(fd, p, m, i, data);
     if (rc) {
       fprintf(stderr, " ***failed;  ");
       fprintf(stderr, "\n");
@@ -541,15 +658,16 @@ int avr_write(int fd, AVRPART * p, int memtype, int size)
       werror = 1;
     }
 
-    if (p->mem[memtype].paged) {
-      if (((i % p->mem[memtype].page_size) == p->mem[memtype].page_size-1) ||
+    if (m->paged) {
+      if (((i % m->page_size) == m->page_size-1) ||
           (i == wsize-1)) {
-        rc = avr_write_page(fd, p, memtype, i/p->mem[memtype].page_size);
+        rc = avr_write_page(fd, p, m, i);
         if (rc) {
           fprintf(stderr,
-                  " *** page %ld (addresses 0x%04lx - 0x%04lx) failed to write\n",
-                  i % p->mem[memtype].page_size, 
-                  i-p->mem[memtype].page_size+1, i);
+                  " *** page %ld (addresses 0x%04lx - 0x%04lx) failed "
+                  "to write\n",
+                  i % m->page_size, 
+                  i - m->page_size + 1, i);
           fprintf(stderr, "\n");
           LED_ON(fd, pgm->pinno[PIN_LED_ERR]);
           werror = 1;
@@ -576,15 +694,23 @@ int avr_write(int fd, AVRPART * p, int memtype, int size)
 /*
  * issue the 'program enable' command to the AVR device
  */
-int avr_program_enable(int fd)
+int avr_program_enable(int fd, AVRPART * p)
 {
-  unsigned char cmd[4] = {0xac, 0x53, 0x00, 0x00};
+  unsigned char cmd[4];
   unsigned char res[4];
 
+  if (p->op[AVR_OP_PGM_ENABLE] == NULL) {
+    fprintf(stderr, "program enable instruction not defined for part \"%s\"\n",
+            p->desc);
+    return -1;
+  }
+
+  memset(cmd, 0, sizeof(cmd));
+  avr_set_bits(p->op[AVR_OP_PGM_ENABLE], cmd);
   avr_cmd(fd, cmd, res);
 
   if (res[2] != cmd[1])
-    return -1;
+    return -2;
 
   return 0;
 }
@@ -595,12 +721,21 @@ int avr_program_enable(int fd)
  */
 int avr_chip_erase(int fd, AVRPART * p)
 {
-  unsigned char data[4] = {0xac, 0x80, 0x00, 0x00};
+  unsigned char cmd[4];
   unsigned char res[4];
 
+  if (p->op[AVR_OP_CHIP_ERASE] == NULL) {
+    fprintf(stderr, "chip erase instruction not defined for part \"%s\"\n",
+            p->desc);
+    return -1;
+  }
+
   LED_ON(fd, pgm->pinno[PIN_LED_PGM]);
 
-  avr_cmd(fd, data, res);
+  memset(cmd, 0, sizeof(cmd));
+
+  avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd);
+  avr_cmd(fd, cmd, res);
   usleep(p->chip_erase_delay);
   avr_initialize(fd, p);
 
@@ -613,16 +748,16 @@ int avr_chip_erase(int fd, AVRPART * p)
 /*
  * read the AVR device's signature bytes
  */
-int avr_signature(int fd, unsigned char sig[4])
+int avr_signature(int fd, AVRPART * p)
 {
-  unsigned char cmd[4] = {0x30, 0x00, 0x00, 0x00};
-  unsigned char res[4];
-  int i;
+  int rc;
 
-  for (i=0; i<4; i++) {
-    cmd[2] = i;
-    avr_cmd(fd, cmd, res);
-    sig[i] = res[3];
+  rc = avr_read(fd, p, "signature", 0, 0);
+  if (rc < 0) {
+    fprintf(stderr, 
+            "%s: error reading signature data for part \"%s\", rc=%d\n",
+            progname, p->desc, rc);
+    return -1;
   }
 
   return 0;
@@ -674,12 +809,12 @@ int avr_initialize(int fd, AVRPART * p)
    * of sync.
    */
   if (strcmp(p->desc, "AT90S1200")==0) {
-    avr_program_enable(fd);
+    avr_program_enable(fd, p);
   }
   else {
     tries = 0;
     do {
-      rc = avr_program_enable(fd);
+      rc = avr_program_enable(fd, p);
       if (rc == 0)
         break;
       ppi_pulsepin(fd, pgm->pinno[PIN_AVR_SCK]);
@@ -700,27 +835,17 @@ int avr_initialize(int fd, AVRPART * p)
 
 
 
-char * avr_memtstr(int memtype)
-{
-  switch (memtype) {
-    case AVR_M_EEPROM : return "eeprom"; break;
-    case AVR_M_FLASH  : return "flash"; break;
-    case AVR_M_FUSE   : return "fuse-bit"; break;
-    case AVR_M_LOCK   : return "fock-bit"; break;
-    default         : return "unknown-memtype"; break;
-  }
-}
-
-
 int avr_initmem(AVRPART * p)
 {
-  int i;
+  LNODEID ln;
+  AVRMEM * m;
 
-  for (i=0; i<AVR_MAXMEMTYPES; i++) {
-    p->mem[i].buf = (unsigned char *) malloc(p->mem[i].size);
-    if (p->mem[i].buf == NULL) {
+  for (ln=lfirst(p->mem); ln; ln=lnext(ln)) {
+    m = ldata(ln);
+    m->buf = (unsigned char *) malloc(m->size);
+    if (m->buf == NULL) {
       fprintf(stderr, "%s: can't alloc buffer for %s size of %d bytes\n",
-              progname, avr_memtstr(i), p->mem[i].size);
+              progname, m->desc, m->size);
       return -1;
     }
   }
@@ -736,15 +861,32 @@ int avr_initmem(AVRPART * p)
  *
  * Return the number of bytes verified, or -1 if they don't match.  
  */
-int avr_verify(AVRPART * p, AVRPART * v, int memtype, int size)
+int avr_verify(AVRPART * p, AVRPART * v, char * memtype, int size)
 {
   int i;
   unsigned char * buf1, * buf2;
   int vsize;
+  AVRMEM * a, * b;
 
-  buf1  = p->mem[memtype].buf;
-  buf2  = v->mem[memtype].buf;
-  vsize = p->mem[memtype].size;
+  a = avr_locate_mem(p, memtype);
+  if (a == NULL) {
+    fprintf(stderr, 
+            "avr_verify(): memory type \"%s\" not defined for part %s\n",
+            memtype, p->desc);
+    return -1;
+  }
+
+  b = avr_locate_mem(v, memtype);
+  if (b == NULL) {
+    fprintf(stderr, 
+            "avr_verify(): memory type \"%s\" not defined for part %s\n",
+            memtype, v->desc);
+    return -1;
+  }
+
+  buf1  = a->buf;
+  buf2  = b->buf;
+  vsize = a->size;
 
   if (vsize < size) {
     fprintf(stderr, 
@@ -752,7 +894,7 @@ int avr_verify(AVRPART * p, AVRPART * v, int memtype, int size)
             "%s%s memory region only contains %d bytes\n"
             "%sOnly %d bytes will be verified.\n",
             progname, size,
-            progbuf, avr_memtstr(memtype), vsize,
+            progbuf, memtype, vsize,
             progbuf, vsize);
     size = vsize;
   }
@@ -777,20 +919,19 @@ void avr_mem_display(char * prefix, FILE * f, AVRMEM * m, int type)
 {
   if (m == NULL) {
     fprintf(f, 
-            "%sMem                  Page        Page                 Polled\n"
-            "%sType   Paged  Size   Size #Pages Shift MinW  MaxW   ReadBack\n"
-            "%s------ ------ ------ ---- ------ ----- ----- ----- ---------\n",
+            "%sMem                       Page                       Polled\n"
+            "%sType        Paged  Size   Size #Pages MinW  MaxW   ReadBack\n"
+            "%s----------- ------ ------ ---- ------ ----- ----- ---------\n",
             prefix, prefix, prefix);
   }
   else {
     fprintf(f,
-            "%s%-6s %-6s %6d %4d %6d %5d %5d %5d 0x%02x 0x%02x\n",
-            prefix, avr_memtstr(type), 
+            "%s%-11s %-6s %6d %4d %5d %5d %5d 0x%02x 0x%02x\n",
+            prefix, m->desc,
             m->paged ? "yes" : "no",
             m->size, 
             m->page_size, 
             m->num_pages, 
-            m->pageaddr_shift, 
             m->min_write_delay, 
             m->max_write_delay,
             m->readback[0], 
@@ -805,6 +946,8 @@ void avr_display(FILE * f, AVRPART * p, char * prefix)
   int i;
   char * buf;
   char * px;
+  LNODEID ln;
+  AVRMEM * m;
 
   fprintf(f, 
           "%sAVR Part         : %s\n"
@@ -827,8 +970,9 @@ void avr_display(FILE * f, AVRPART * p, char * prefix)
   }
   
   avr_mem_display(px, f, NULL, 0);
-  for (i=0; i<AVR_MAXMEMTYPES; i++) {
-    avr_mem_display(px, f, &p->mem[i], i);
+  for (ln=lfirst(p->mem); ln; ln=lnext(ln)) {
+    m = ldata(ln);
+    avr_mem_display(px, f, m, i);
   }
 
   if (buf)
diff --git a/avr.h b/avr.h
index 0ad6e97c..c6a0f42d 100644
--- a/avr.h
+++ b/avr.h
@@ -34,29 +34,62 @@
 
 #include <stdio.h>
 
+#include "lists.h"
+
+
 /*
- * AVR memory designations; the order of these is important, these are
- * used as indexes into statically initialized data, don't change them
- * around.  Specifically, avr_read_byte() and avr_write_byte() rely on
- * the order.
+ * AVR serial programming instructions
  */
-#define AVR_M_EEPROM 0
-#define AVR_M_FLASH  1
-#define AVR_M_FUSE   2
-#define AVR_M_LOCK   3
+enum {
+  AVR_OP_READ,
+  AVR_OP_WRITE,
+  AVR_OP_READ_LO,
+  AVR_OP_READ_HI,
+  AVR_OP_WRITE_LO,
+  AVR_OP_WRITE_HI,
+  AVR_OP_LOADPAGE_LO,
+  AVR_OP_LOADPAGE_HI,
+  AVR_OP_WRITEPAGE,
+  AVR_OP_CHIP_ERASE,
+  AVR_OP_PGM_ENABLE,
+  AVR_OP_MAX
+};
 
-#define AVR_MAXMEMTYPES 2     /* just flash and eeprom */
 
+enum {
+  AVR_CMDBIT_IGNORE,  /* bit is ignored on input and output */
+  AVR_CMDBIT_VALUE,   /* bit is set to 0 or 1 for input or output */
+  AVR_CMDBIT_ADDRESS, /* this bit represents an input address bit */
+  AVR_CMDBIT_INPUT,   /* this bit is an input bit */
+  AVR_CMDBIT_OUTPUT   /* this bit is an output bit */
+};
+
+/*
+ * serial programming instruction bit specifications
+ */
+typedef struct cmdbit {
+  int          type;  /* AVR_CMDBIT_* */
+  int          bitno; /* which input bit to use for this command bit */
+  int          value; /* bit value if type == AVR_CMDBIT_VALUD */
+} CMDBIT;
+
+typedef struct opcode {
+  CMDBIT        bit[32]; /* opcode bit specs */
+} OPCODE;
+
+
+#define AVR_MEMDESCLEN 64
 typedef struct avrmem {
-  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 pageaddr_shift;           /* number of bits in the page address */
-  int min_write_delay;          /* microseconds */
-  int max_write_delay;          /* microseconds */
-  unsigned char readback[2];    /* polled read-back values */
-  unsigned char * buf;          /* pointer to memory buffer */
+  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 */
+  unsigned char readback[2];  /* polled read-back values */
+  unsigned char * buf;        /* pointer to memory buffer */
+  OPCODE * op[AVR_OP_MAX];    /* opcodes */
 } AVRMEM;
 
 
@@ -65,10 +98,10 @@ typedef struct avrmem {
 typedef struct avrpart {
   char          desc[AVR_DESCLEN];  /* long part name */
   char          id[AVR_IDLEN];      /* short part name */
+  int           chip_erase_delay;   /* microseconds */
+  OPCODE      * op[AVR_OP_MAX];     /* opcodes */
 
-  int             chip_erase_delay; /* microseconds */
-
-  AVRMEM          mem[AVR_MAXMEMTYPES];
+  LISTID        mem;                /* avr memory definitions */
 } AVRPART;
 
 
@@ -80,42 +113,38 @@ AVRPART * avr_find_part(char * p);
 
 AVRPART * avr_new_part(void);
 
+OPCODE * avr_new_opcode(void);
+
+AVRMEM * avr_new_memtype(void);
+
 AVRPART * avr_dup_part(AVRPART * d);
 
+AVRMEM * avr_locate_mem(AVRPART * p, char * desc);
+
 int avr_txrx_bit(int fd, int bit);
 
 unsigned char avr_txrx(int fd, unsigned char byte);
 
 int avr_cmd(int fd, unsigned char cmd[4], unsigned char res[4]);
 
-unsigned char avr_read_calibration(int fd, AVRPART * p);
+int avr_read_byte(int fd, AVRPART * p, AVRMEM * mem, unsigned long addr, 
+                  unsigned char * value);
 
-unsigned char avr_read_fuse(int fd, AVRPART * p, int high);
+int avr_read(int fd, AVRPART * p, char * memtype, int size, int verbose);
 
-int avr_write_fuse(int fd, AVRPART * p, int high, unsigned char b);
+int avr_write_page(int fd, AVRPART * p, AVRMEM * mem,
+                   unsigned long addr);
 
-unsigned char avr_read_lock(int fd, AVRPART * p);
-
-int avr_write_lock(int fd, AVRPART * p, unsigned char b);
-
-unsigned char avr_read_byte(int fd, AVRPART * p,
-                            int memtype, unsigned long addr);
-
-int avr_read(int fd, AVRPART * p, int memtype, int size);
-
-int avr_write_bank(int fd, AVRPART * p, int memtype, 
-                   unsigned short bank);
-
-int avr_write_byte(int fd, AVRPART * p, int memtype, 
+int avr_write_byte(int fd, AVRPART * p, AVRMEM * mem,
                    unsigned long addr, unsigned char data);
 
-int avr_write(int fd, AVRPART * p, int memtype, int size);
+int avr_write(int fd, AVRPART * p, char * memtype, int size, int verbose);
 
-int avr_program_enable(int fd);
+int avr_program_enable(int fd, AVRPART * p);
 
 int avr_chip_erase(int fd, AVRPART * p);
 
-int avr_signature(int fd, unsigned char sig[4]);
+int avr_signature(int fd, AVRPART * p);
 
 void avr_powerup(int fd);
 
@@ -127,8 +156,7 @@ char * avr_memtstr(int memtype);
 
 int avr_initmem(AVRPART * p);
 
-int avr_verify(AVRPART * p, AVRPART * v, int memtype, 
-               int size);
+int avr_verify(AVRPART * p, AVRPART * v, char * memtype, int size);
 
 void avr_display(FILE * f, AVRPART * p, char * prefix);
 
diff --git a/avrdude.conf.sample b/avrdude.conf.sample
index d509e21b..00e02897 100644
--- a/avrdude.conf.sample
+++ b/avrdude.conf.sample
@@ -93,7 +93,7 @@ programmer
   vfyled = 17;
 ;
 
-
+/*
 part
     id               = "1200";
     desc             = "AT90S1200";
@@ -335,22 +335,40 @@ part
         readback_p2     = 0xff;
       ;
   ;
+*/
 
 part
     id               = "m163";
     desc             = "ATMEGA163";
+    pgm_enable       = "1", "0", "1", "0",  "1", "1", "0", "0", 
+                       "0", "1", "0", "1",  "0", "0", "1", "1",
+                       "x", "x", "x", "x",  "x", "x", "x", "x", 
+                       "x", "x", "x", "x",  "x", "x", "x", "x";
+
+    chip_erase       = "1", "0", "1", "0",  "1", "1", "0", "0", 
+                       "1", "0", "0", "0",  "0", "0", "0", "0",
+                       "x", "x", "x", "x",  "x", "x", "x", "x", 
+                       "x", "x", "x", "x",  "x", "x", "x", "x";
+
     chip_erase_delay = 32000;
-    eeprom
-        paged           = no;
+    memory "eeprom"
         size            = 512;
-        page_size       = 0;
-        num_pages       = 0;
         min_write_delay = 4000;
         max_write_delay = 4000;
         readback_p1     = 0xff;
         readback_p2     = 0xff;
+
+	read        = "1",   "0",   "1",   "0",    "0",   "0",   "0",   "0",
+                      "x",   "x",   "x",   "x",    "x",   "x",   "x",   "a8",
+                      "a7",  "a6",  "a5",  "a4",   "a3",  "a2",  "a1",  "a0", 
+                      "o",   "o",   "o",   "o",    "o",   "o",   "o",   "o";
+
+	write       = "1",   "1",   "0",   "0",    "0",   "0",   "0",   "0",
+                      "x",   "x",   "x",   "x",    "x",   "x",   "x",   "a8",
+                      "a7",  "a6",  "a5",  "a4",   "a3",  "a2",  "a1",  "a0", 
+                      "i",   "i",   "i",   "i",    "i",   "i",   "i",   "i";
       ;
-    flash
+    memory "flash"
         paged           = yes;
         size            = 16384;
         page_size       = 128;
@@ -359,7 +377,93 @@ part
         max_write_delay = 16000;
         readback_p1     = 0xff;
         readback_p2     = 0xff;
+
+        read_lo     = "0",  "0",  "1",  "0",    "0",   "0",   "0",  "0",
+                      "x",  "x",  "x",  "a12",  "a11", "a10", "a9", "a8",
+                      "a7", "a6", "a5", "a4",   "a3",  "a2",  "a1", "a0",
+                      "o",  "o",  "o",  "o",    "o",   "o",   "o",  "o";
+
+        read_hi     = "0",  "0",  "1",  "0",    "1",   "0",   "0",  "0",
+                      "x",  "x",  "x",  "a12",  "a11", "a10", "a9", "a8",
+                      "a7", "a6", "a5", "a4",   "a3",  "a2",  "a1", "a0",
+                      "o",  "o",  "o",  "o",    "o",   "o",   "o",  "o";
+
+        loadpage_lo = "0",  "1",  "0",  "0",    "0",   "0",   "0",  "0",
+                      "x",  "x",  "x",  "x",    "x",   "x",   "x",  "x",
+                      "x",  "x", "a5", "a4",   "a3",  "a2",  "a1", "a0",
+                      "i",  "i",  "i",  "i",    "i",   "i",   "i",  "i";
+
+        loadpage_hi = "0",  "1",  "0",  "0",    "1",   "0",   "0",  "0",
+                      "x",  "x",  "x",  "x",    "x",   "x",   "x",  "x",
+                      "x",  "x", "a5", "a4",   "a3",  "a2",  "a1", "a0",
+                      "i",  "i",  "i",  "i",    "i",   "i",   "i",  "i";
+
+        writepage   = "0",  "1",  "0",  "0",    "1",   "1",   "0",  "0",
+                      "x",  "x",  "x",  "a12",  "a11", "a10", "a9", "a8",
+                      "a7", "a6", "x",  "x",    "x",   "x",   "x",  "x",
+                      "x",  "x",  "x",  "x",    "x",   "x",   "x",  "x";
       ;
+    memory "lfuse"
+        size            = 1;
+        min_write_delay = 2000;
+        max_write_delay = 2000;
+
+        read        = "0",  "1",  "0",  "1",    "0",   "0",   "0",  "0",
+                      "0",  "0",  "0",  "0",    "0",   "0",   "0",  "0",
+                      "x",  "x",  "x",  "x",    "x",   "x",   "x",  "x",
+                      "o",  "o",  "x",  "x",    "o",   "o",   "o",  "o";
+
+        write       = "1",  "0",  "1",  "0",    "1",   "1",   "0",  "0",
+                      "1",  "0",  "1",  "0",    "0",   "0",   "0",  "0",
+                      "x",  "x",  "x",  "x",    "x",   "x",   "x",  "x",
+                      "i",  "i",  "1",  "1",    "i",   "i",   "i",  "i";
+      ;
+    memory "hfuse"
+        size            = 1;
+        min_write_delay = 2000;
+        max_write_delay = 2000;
+
+        read        = "0",  "1",  "0",  "1",    "1",   "0",   "0",  "0",
+                      "0",  "0",  "0",  "0",    "1",   "0",   "0",  "0",
+                      "x",  "x",  "x",  "x",    "x",   "x",   "x",  "x",
+                      "x",  "x",  "x",  "x",    "1",   "o",   "o",  "o";
+
+        write       = "1",  "0",  "1",  "0",    "1",   "1",   "0",  "0",
+                      "1",  "0",  "1",  "0",    "1",   "0",   "0",  "0",
+                      "x",  "x",  "x",  "x",    "x",   "x",   "x",  "x",
+                      "1",  "1",  "1",  "1",    "1",   "i",   "i",  "i";
+      ;
+    memory "lock"
+        size            = 1;
+        min_write_delay = 2000;
+        max_write_delay = 2000;
+
+        read        = "0",  "1",  "0",  "1",    "1",   "0",   "0",  "0",
+                      "0",  "0",  "0",  "0",    "0",   "0",   "0",  "0",
+                      "x",  "x",  "x",  "x",    "0",   "x",   "x",  "x",
+                      "x",  "x",  "o",  "o",    "o",   "o",   "o",  "o";
+
+        write       = "1",  "0",  "1",  "0",    "1",   "1",   "0",  "0",
+                      "1",  "1",  "1",  "x",    "x",   "x",   "x",  "x",
+                      "x",  "x",  "x",  "x",    "x",   "x",   "x",  "x",
+                      "1",  "1",  "i",  "i",    "i",   "i",   "i",  "i";
+      ;
+    memory "signature"
+        size        = 3;
+
+        read        = "0",  "0",  "1",  "1",    "0",   "0",   "0",  "0",
+                      "x",  "x",  "x",  "x",    "x",   "x",   "x",  "x",
+                      "x",  "x",  "x",  "x",    "x",   "x",   "a1", "a0",
+                      "o",  "o",  "o",  "o",    "o",   "o",   "o",  "o";
+      ;
+    memory "calibration"
+        size        = 1;
+        read        = "0",  "0",  "1",  "1",    "1",   "0",   "0",  "0",
+                      "x",  "x",  "x",  "x",    "x",   "x",   "x",  "x",
+                      "0",  "0",  "0",  "0",    "0",   "0",   "0",  "0",
+                      "o",  "o",  "o",  "o",    "o",   "o",   "o",  "o";
+      ;
+
 /*
     instructions
         instr "pe",   "programming enable"         [ "1010 1100", "0101 0011", "xxxx xxxx", "xxxx xxxx" ];
@@ -381,6 +485,7 @@ part
 */
   ;
 
+/*
 part
     id               = "m8";
     desc             = "ATMEGA8";
@@ -407,3 +512,4 @@ part
       ;
   ;
 
+*/
\ No newline at end of file
diff --git a/config.c b/config.c
index 983f5fc7..a6e9e709 100644
--- a/config.c
+++ b/config.c
@@ -45,7 +45,7 @@ LISTID       string_list;
 LISTID       number_list;
 PROGRAMMER * current_prog;
 AVRPART    * current_part;
-int          current_mem;
+AVRMEM     * current_mem;
 LISTID       part_list;
 LISTID       programmers;
 
diff --git a/config.h b/config.h
index 016910dd..ca4f1a9d 100644
--- a/config.h
+++ b/config.h
@@ -63,7 +63,7 @@ typedef struct programmer_t {
 extern FILE       * yyin;
 extern PROGRAMMER * current_prog;
 extern AVRPART    * current_part;
-extern int          current_mem;
+extern AVRMEM     * current_mem;
 extern LISTID       programmers;
 extern LISTID       part_list;
 extern int          lineno;
diff --git a/config_gram.y b/config_gram.y
index 13bd333f..4645af52 100644
--- a/config_gram.y
+++ b/config_gram.y
@@ -29,8 +29,23 @@
 
 /* $Id$ */
 
+%token K_OP
+%token K_READ
+%token K_WRITE
+%token K_READ_LO
+%token K_READ_HI
+%token K_WRITE_LO
+%token K_WRITE_HI
+%token K_LOADPAGE_LO
+%token K_LOADPAGE_HI
+%token K_WRITEPAGE
+%token K_CHIP_ERASE
+%token K_PGM_ENABLE
+
+%token K_MEMORY
+
 %token K_PAGE_SIZE
-%token K_PAGEED
+%token K_PAGED
 %token K_BUFF
 %token K_CHIP_ERASE_DELAY
 %token K_DESC
@@ -107,7 +122,8 @@ part_def :
     { current_part = avr_new_part(); }
     part_parms 
     { 
-      unsigned int i, j, shift, psize;
+      LNODEID ln;
+      AVRMEM * m;
 
       if (current_part->id[0] == 0) {
         fprintf(stderr,
@@ -121,49 +137,35 @@ part_def :
        * to shift a page for constructing the page address for
        * page-addressed memories.
        */
-      for (i=0; i<AVR_MAXMEMTYPES; i++) {
-        if (current_part->mem[i].paged) {
-          if (!current_part->mem[i].page_size) {
+      for (ln=lfirst(current_part->mem); ln; ln=lnext(ln)) {
+        m = ldata(ln);
+        if (m->paged) {
+          if (m->page_size == 0) {
             fprintf(stderr, 
                     "%s: error at %s:%d: must specify page_size for paged "
                     "memory\n",
                     progname, infile, lineno);
             exit(1);
           }
-          if (!current_part->mem[i].num_pages) {
+          if (m->num_pages == 0) {
             fprintf(stderr, 
                     "%s: error at %s:%d: must specify num_pages for paged "
                     "memory\n",
                     progname, infile, lineno);
             exit(1);
           }
-          if (current_part->mem[i].size != current_part->mem[i].page_size *
-                                             current_part->mem[i].num_pages) {
+          if (m->size != m->page_size * m->num_pages) {
             fprintf(stderr, 
                     "%s: error at %s:%d: page size (%u) * num_pages (%u) = "
                     "%u does not match memory size (%u)\n",
                     progname, infile, lineno,
-                    current_part->mem[i].page_size, 
-                    current_part->mem[i].num_pages, 
-                    current_part->mem[i].page_size * current_part->mem[i].num_pages,
-                    current_part->mem[i].size);
+                    m->page_size, 
+                    m->num_pages, 
+                    m->page_size * m->num_pages,
+                    m->size);
             exit(1);
           }
-          shift = 0;
-          psize = current_part->mem[i].page_size / 2 - 1;
-          for (j=0; j<32 && !shift; j++) {
-            if ((psize >> j) == 0) {
-              shift = j;
-            }
-          }
-          if (!shift) {
-            fprintf(stderr, 
-                    "%s: error at %s:%d: can't determine amount to shift for the page address\n"
-                    "     Are you sure page_size (=%u) is correct?\n",
-                    progname, infile, lineno, current_part->mem[i].page_size);
-            exit(1);
-          }
-          current_part->mem[i].pageaddr_shift = shift;
+
         }
       }
 
@@ -246,6 +248,21 @@ prog_parm :
 ;
 
 
+opcode :
+  K_READ         |
+  K_WRITE        |
+  K_READ_LO      |
+  K_READ_HI      |
+  K_WRITE_LO     |
+  K_WRITE_HI     |
+  K_LOADPAGE_LO  |
+  K_LOADPAGE_HI  |
+  K_WRITEPAGE    |
+  K_CHIP_ERASE   |
+  K_PGM_ENABLE
+;
+
+
 part_parms :
   part_parm TKN_SEMI |
   part_parms part_parm TKN_SEMI
@@ -273,11 +290,46 @@ part_parm :
       free_token($3);
     } |
 
+/*
   K_EEPROM { current_mem = AVR_M_EEPROM; }
     mem_specs |
 
   K_FLASH { current_mem = AVR_M_FLASH; }
-    mem_specs
+    mem_specs | 
+*/
+
+  K_MEMORY TKN_STRING 
+    { 
+      current_mem = avr_new_memtype(); 
+      strcpy(current_mem->desc, strdup($2->value.string)); 
+      free_token($2); 
+    } 
+    mem_specs 
+    { 
+      ladd(current_part->mem, current_mem); 
+      current_mem = NULL; 
+    } |
+
+  opcode TKN_EQUAL string_list {
+    { 
+      int opnum;
+      OPCODE * op;
+
+      if (lsize(string_list) != 32) {
+        fprintf(stderr, 
+                "%s: error at %s:%d: only %d bits specified, need 32\n",
+                progname, infile, lineno, lsize(string_list));
+        exit(1);
+      }
+
+      opnum = which_opcode($1);
+      op = avr_new_opcode();
+      parse_cmdbits(op);
+      current_part->op[opnum] = op;
+
+      free_token($1);
+    }
+  }
 ;
 
 
@@ -295,52 +347,73 @@ mem_specs :
 mem_spec :
   K_PAGED          TKN_EQUAL yesno
     {
-      current_part->mem[current_mem].paged = $3->primary == K_YES ? 1 : 0;
+      current_mem->paged = $3->primary == K_YES ? 1 : 0;
       free_token($3);
     } |
 
   K_SIZE            TKN_EQUAL TKN_NUMBER
     {
-      current_part->mem[current_mem].size = $3->value.number;
+      current_mem->size = $3->value.number;
       free_token($3);
     } |
 
 
   K_PAGE_SIZE       TKN_EQUAL TKN_NUMBER
     {
-      current_part->mem[current_mem].page_size = $3->value.number;
+      current_mem->page_size = $3->value.number;
       free_token($3);
     } |
 
   K_NUM_PAGES       TKN_EQUAL TKN_NUMBER
     {
-      current_part->mem[current_mem].num_pages = $3->value.number;
+      current_mem->num_pages = $3->value.number;
       free_token($3);
     } |
 
   K_MIN_WRITE_DELAY TKN_EQUAL TKN_NUMBER
     {
-      current_part->mem[current_mem].min_write_delay = $3->value.number;
+      current_mem->min_write_delay = $3->value.number;
       free_token($3);
     } |
 
   K_MAX_WRITE_DELAY TKN_EQUAL TKN_NUMBER
     {
-      current_part->mem[current_mem].max_write_delay = $3->value.number;
+      current_mem->max_write_delay = $3->value.number;
       free_token($3);
     } |
 
   K_READBACK_P1     TKN_EQUAL TKN_NUMBER
     {
-      current_part->mem[current_mem].readback[0] = $3->value.number;
+      current_mem->readback[0] = $3->value.number;
       free_token($3);
     } |
 
   K_READBACK_P2     TKN_EQUAL TKN_NUMBER
     {
-      current_part->mem[current_mem].readback[1] = $3->value.number;
+      current_mem->readback[1] = $3->value.number;
       free_token($3);
+    } |
+
+  opcode TKN_EQUAL string_list {
+    { 
+      int opnum;
+      OPCODE * op;
+
+      if (lsize(string_list) != 32) {
+        fprintf(stderr, 
+                "%s: error at %s:%d: only %d bits specified, need 32\n",
+                progname, infile, lineno, lsize(string_list));
+        exit(1);
+      }
+
+      opnum = which_opcode($1);
+      op = avr_new_opcode();
+      parse_cmdbits(op);
+      current_mem->op[opnum] = op;
+
+      free_token($1);
     }
+  }
 ;
 
 
@@ -392,3 +465,123 @@ static int assign_pin(int pinno, TOKEN * v)
   return 0;
 }
 
+
+static int which_opcode(TOKEN * opcode)
+{
+  switch (opcode->primary) {
+    case K_READ        : return AVR_OP_READ; break;
+    case K_WRITE       : return AVR_OP_WRITE; break;
+    case K_READ_LO     : return AVR_OP_READ_LO; break;
+    case K_READ_HI     : return AVR_OP_READ_HI; break;
+    case K_WRITE_LO    : return AVR_OP_WRITE_LO; break;
+    case K_WRITE_HI    : return AVR_OP_WRITE_HI; break;
+    case K_LOADPAGE_LO : return AVR_OP_LOADPAGE_LO; break;
+    case K_LOADPAGE_HI : return AVR_OP_LOADPAGE_HI; break;
+    case K_WRITEPAGE   : return AVR_OP_WRITEPAGE; break;
+    case K_CHIP_ERASE  : return AVR_OP_CHIP_ERASE; break;
+    case K_PGM_ENABLE  : return AVR_OP_PGM_ENABLE; break;
+    default :
+      fprintf(stderr, 
+              "%s: error at %s:%d: invalid opcode\n",
+              progname, infile, lineno);
+      exit(1);
+      break;
+  }
+}
+
+
+static int parse_cmdbits(OPCODE * op)
+{
+  TOKEN * t;
+  int bitno;
+  char ch;
+  char * e;
+  char * q;
+  int len;
+
+  bitno = 31;
+  while (lsize(string_list)) {
+
+    t = lrmv_n(string_list, 1);
+
+    len = strlen(t->value.string);
+
+    if (len == 0) {
+      fprintf(stderr, 
+              "%s: error at %s:%d: invalid bit specifier \"\"\n",
+              progname, infile, lineno);
+      exit(1);
+    }
+
+    ch = t->value.string[0];
+
+    if (len == 1) {
+      switch (ch) {
+        case '1':
+          op->bit[bitno].type  = AVR_CMDBIT_VALUE;
+          op->bit[bitno].value = 1;
+          op->bit[bitno].bitno = bitno % 8;
+          break;
+        case '0':
+          op->bit[bitno].type  = AVR_CMDBIT_VALUE;
+          op->bit[bitno].value = 0;
+          op->bit[bitno].bitno = bitno % 8;
+          break;
+        case 'x':
+          op->bit[bitno].type  = AVR_CMDBIT_IGNORE;
+          op->bit[bitno].value = 0;
+          op->bit[bitno].bitno = bitno % 8;
+          break;
+        case 'a':
+          op->bit[bitno].type  = AVR_CMDBIT_ADDRESS;
+          op->bit[bitno].value = 0;
+          op->bit[bitno].bitno = 8*(bitno/8) + bitno % 8;
+          break;
+        case 'i':
+          op->bit[bitno].type  = AVR_CMDBIT_INPUT;
+          op->bit[bitno].value = 0;
+          op->bit[bitno].bitno = bitno % 8;
+          break;
+        case 'o':
+          op->bit[bitno].type  = AVR_CMDBIT_OUTPUT;
+          op->bit[bitno].value = 0;
+          op->bit[bitno].bitno = bitno % 8;
+          break;
+        default :
+          fprintf(stderr, 
+                  "%s: error at %s:%d: invalid bit specifier '%c'\n",
+                  progname, infile, lineno, ch);
+          exit(1);
+          break;
+      }
+    }
+    else {
+      if (ch == 'a') {
+        q = &t->value.string[1];
+        op->bit[bitno].bitno = strtol(q, &e, 0);
+        if ((e == q)||(*e != 0)) {
+          fprintf(stderr, 
+                  "%s: error at %s:%d: can't parse bit number from \"%s\"\n",
+                  progname, infile, lineno, q);
+          exit(1);
+        }
+        op->bit[bitno].type = AVR_CMDBIT_ADDRESS;
+        op->bit[bitno].value = 0;
+      }
+      else {
+        fprintf(stderr, 
+                "%s: error at %s:%d: invalid bit specifier \"%s\"\n",
+                progname, infile, lineno, t->value.string);
+        exit(1);
+      }
+    }
+
+    free_token(t);    
+    bitno--;
+
+  }  /* while */
+
+  return 0;
+}
+
+
diff --git a/fileio.c b/fileio.c
index cf28033e..a0304e20 100644
--- a/fileio.c
+++ b/fileio.c
@@ -520,7 +520,7 @@ int fmt_autodetect(char * fname)
 
 
 int fileio(int op, char * filename, FILEFMT format, 
-             struct avrpart * p, int memtype, int size)
+             struct avrpart * p, char * memtype, int size)
 {
   int rc;
   FILE * f;
@@ -528,6 +528,15 @@ int fileio(int op, char * filename, FILEFMT format,
   unsigned char * buf;
   struct fioparms fio;
   int i;
+  AVRMEM * mem;
+
+  mem = avr_locate_mem(p, memtype);
+  if (mem == NULL) {
+    fprintf(stderr, 
+            "fileio(): memory type \"%s\" not configured for device \"%s\"\n",
+            memtype, p->desc);
+    return -1;
+  }
 
   rc = fileio_setparms(op, &fio);
   if (rc < 0)
@@ -554,9 +563,9 @@ int fileio(int op, char * filename, FILEFMT format,
   }
 
   /* point at the requested memory buffer */
-  buf = p->mem[memtype].buf;
+  buf = mem->buf;
   if (fio.op == FIO_READ)
-    size = p->mem[memtype].size;
+    size = mem->size;
 
   if (fio.op == FIO_READ) {
     /* 0xff fill unspecified memory */
diff --git a/fileio.h b/fileio.h
index d775b2a9..7c1126f5 100644
--- a/fileio.h
+++ b/fileio.h
@@ -57,6 +57,6 @@ char * fmtstr(FILEFMT format);
 int fileio_setparms(int op, struct fioparms * fp);
 
 int fileio(int op, char * filename, FILEFMT format, 
-             struct avrpart * p, int memtype, int size);
+           struct avrpart * p, char * memtype, int size);
 
 #endif
diff --git a/lexer.l b/lexer.l
index 27487102..ffcd4bd5 100644
--- a/lexer.l
+++ b/lexer.l
@@ -152,6 +152,21 @@ size             { yylval=NULL; return K_SIZE; }
 vcc              { yylval=NULL; return K_VCC; }
 vfyled           { yylval=NULL; return K_VFYLED; }
 
+op               { yylval=NULL; return K_OP; }
+read             { yylval=new_token(K_READ); return K_READ; }
+write            { yylval=new_token(K_WRITE); return K_WRITE; }
+read_lo          { yylval=new_token(K_READ_LO); return K_READ_LO; }
+read_hi          { yylval=new_token(K_READ_HI); return K_READ_HI; }
+write_lo         { yylval=new_token(K_WRITE_LO); return K_WRITE_LO; }
+write_hi         { yylval=new_token(K_WRITE_HI); return K_WRITE_HI; }
+loadpage_lo      { yylval=new_token(K_LOADPAGE_LO); return K_LOADPAGE_LO; }
+loadpage_hi      { yylval=new_token(K_LOADPAGE_HI); return K_LOADPAGE_HI; }
+writepage        { yylval=new_token(K_WRITEPAGE); return K_WRITEPAGE; }
+chip_erase       { yylval=new_token(K_CHIP_ERASE); return K_CHIP_ERASE; }
+pgm_enable       { yylval=new_token(K_PGM_ENABLE); return K_PGM_ENABLE; }
+
+memory           { yylval=NULL; return K_MEMORY; }
+
 no               { yylval=new_token(K_NO); return K_NO; }
 yes              { yylval=new_token(K_YES); return K_YES; }
 
diff --git a/main.c b/main.c
index 070e10ae..7833c452 100644
--- a/main.c
+++ b/main.c
@@ -450,17 +450,16 @@ int main(int argc, char * argv [])
   int              ch;          /* options flag */
   int              size;        /* size of memory region */
   int              len;         /* length for various strings */
-  unsigned char    sig[4];      /* AVR signature bytes */
-  unsigned char    nulldev[4];  /* 0xff signature bytes for comparison */
   struct avrpart * p;           /* which avr part we are programming */
   struct avrpart * v;           /* used for verify */
   int              readorwrite; /* true if a chip read/write op was selected */
   int              ppidata;	/* cached value of the ppi data register */
   int              vsize=-1;    /* number of bytes to verify */
   char             timestamp[64];
+  AVRMEM         * sig;         /* signature data */
 
   /* options / operating mode variables */
-  int     memtype;     /* AVR_FLASH or AVR_EEPROM */
+  char *  memtype;     /* "flash", "eeprom", etc */
   int     doread;      /* 1=reading AVR, 0=writing AVR */
   int     erase;       /* 1=erase chip, 0=don't */
   char  * outputf;     /* output file name */
@@ -493,7 +492,7 @@ int main(int argc, char * argv [])
   outputf       = NULL;
   inputf        = NULL;
   doread        = 1;
-  memtype       = AVR_M_FLASH;
+  memtype       = "flash";
   erase         = 0;
   p             = NULL;
   ovsigck       = 0;
@@ -567,17 +566,14 @@ int main(int argc, char * argv [])
 
       case 'm': /* select memory type to operate on */
         if ((strcasecmp(optarg,"e")==0)||(strcasecmp(optarg,"eeprom")==0)) {
-          memtype = AVR_M_EEPROM;
+          memtype = "eeprom";
         }
         else if ((strcasecmp(optarg,"f")==0)||
                  (strcasecmp(optarg,"flash")==0)) {
-          memtype = AVR_M_FLASH;
+          memtype = "flash";
         }
         else {
-          fprintf(stderr, "%s: invalid memory type \"%s\"\n\n", 
-                  progname, optarg);
-          usage();
-          exit(1);
+          memtype = optarg;
         }
         readorwrite = 1;
         break;
@@ -833,23 +829,43 @@ int main(int argc, char * argv [])
    * against 0xffffffff should ensure that the signature bytes are
    * valid.  
    */
-  avr_signature(fd, sig);
-  fprintf(stderr, "%s: Device signature = 0x", progname);
-  for (i=0; i<4; i++)
-    fprintf(stderr, "%02x", sig[i]);
-  fprintf(stderr, "\n");
+  rc = avr_signature(fd, p);
+  if (rc != 0) {
+    fprintf(stderr, "%s: error reading signature data, rc=%d\n",
+            progname, rc);
+    exit(1);
+  }
 
-  memset(nulldev,0xff,4);
-  if (memcmp(sig,nulldev,4)==0) {
-    fprintf(stderr, 
-            "%s: Yikes!  Invalid device signature.\n", progname);
-    if (!ovsigck) {
-      fprintf(stderr, "%sDouble check connections and try again, "
-              "or use -F to override\n"
-              "%sthis check.\n\n",
-              progbuf, progbuf);
-      exitrc = 1;
-      goto main_exit;
+  sig = avr_locate_mem(p, "signature");
+  if (sig == NULL) {
+    fprintf(stderr,
+            "%s: WARNING: signature data not defined for device \"%s\"\n",
+            progname, p->desc);
+  }   
+
+  if (sig != NULL) {
+    int ff;
+
+    fprintf(stderr, "%s: Device signature = 0x", progname);
+    ff = 1;
+    for (i=0; i<sig->size; i++) {
+      fprintf(stderr, "%02x", sig->buf[i]);
+      if (sig->buf[i] != 0xff)
+        ff = 0;
+    }
+    fprintf(stderr, "\n");
+
+    if (ff) {
+      fprintf(stderr, 
+              "%s: Yikes!  Invalid device signature.\n", progname);
+      if (!ovsigck) {
+        fprintf(stderr, "%sDouble check connections and try again, "
+                "or use -F to override\n"
+                "%sthis check.\n\n",
+                progbuf, progbuf);
+        exitrc = 1;
+        goto main_exit;
+      }
     }
   }
 
@@ -892,11 +908,11 @@ int main(int argc, char * argv [])
      * read out the specified device memory and write it to a file 
      */
     fprintf(stderr, "%s: reading %s memory:\n", 
-            progname, avr_memtstr(memtype));
-    rc = avr_read(fd, p, memtype, 0);
+            progname, memtype);
+    rc = avr_read(fd, p, memtype, 0, 1);
     if (rc < 0) {
       fprintf(stderr, "%s: failed to read all of %s memory, rc=%d\n", 
-              progname, avr_memtstr(memtype), rc);
+              progname, memtype, rc);
       exitrc = 1;
       goto main_exit;
     }
@@ -931,10 +947,10 @@ int main(int argc, char * argv [])
      * write the buffer contents to the selected memory type
      */
     fprintf(stderr, "%s: writing %s:\n", 
-            progname, avr_memtstr(memtype));
+            progname, memtype);
 
     if (!nowrite) {
-      rc = avr_write(fd, p, memtype, size);
+      rc = avr_write(fd, p, memtype, size, 1);
     }
     else {
       /* 
@@ -954,7 +970,7 @@ int main(int argc, char * argv [])
     vsize = rc;
 
     fprintf(stderr, "%s: %d bytes of %s written\n", progname, 
-            vsize, avr_memtstr(memtype));
+            vsize, memtype);
 
   }
 
@@ -966,13 +982,13 @@ int main(int argc, char * argv [])
     LED_ON(fd, pgm->pinno[PIN_LED_VFY]);
 
     fprintf(stderr, "%s: verifying %s memory against %s:\n", 
-            progname, avr_memtstr(memtype), inputf);
+            progname, memtype, inputf);
     fprintf(stderr, "%s: reading on-chip %s data:\n", 
-            progname, avr_memtstr(memtype));
-    rc = avr_read(fd, v, memtype, vsize);
+            progname, memtype);
+    rc = avr_read(fd, v, memtype, vsize, 1);
     if (rc < 0) {
       fprintf(stderr, "%s: failed to read all of %s memory, rc=%d\n", 
-              progname, avr_memtstr(memtype), rc);
+              progname, memtype, rc);
       LED_ON(fd, pgm->pinno[PIN_LED_ERR]);
       exitrc = 1;
       goto main_exit;
@@ -989,7 +1005,7 @@ int main(int argc, char * argv [])
     }
     
     fprintf(stderr, "%s: %d bytes of %s verified\n", 
-            progname, rc, avr_memtstr(memtype));
+            progname, rc, memtype);
 
     LED_OFF(fd, pgm->pinno[PIN_LED_VFY]);
   }
diff --git a/term.c b/term.c
index 814034f9..c99de90d 100644
--- a/term.c
+++ b/term.c
@@ -38,6 +38,7 @@
 
 #include "avr.h"
 #include "config.h"
+#include "lists.h"
 #include "pindefs.h"
 #include "ppi.h"
 
@@ -64,8 +65,6 @@ int cmd_erase (int fd, struct avrpart * p, int argc, char *argv[]);
 
 int cmd_sig   (int fd, struct avrpart * p, int argc, char *argv[]);
 
-int cmd_cal   (int fd, struct avrpart * p, int argc, char *argv[]);
-
 int cmd_part  (int fd, struct avrpart * p, int argc, char *argv[]);
 
 int cmd_help  (int fd, struct avrpart * p, int argc, char *argv[]);
@@ -76,14 +75,13 @@ int cmd_send  (int fd, struct avrpart * p, int argc, char *argv[]);
 
 
 struct command cmd[] = {
-  { "dump",  cmd_dump,  "dump memory  : %s [eeprom|flash] <addr> <N-Bytes>" },
+  { "dump",  cmd_dump,  "dump memory  : %s <memtype> <addr> <N-Bytes>" },
   { "read",  cmd_dump,  "alias for dump" },
-  { "write", cmd_write, "write memory : %s [eeprom|flash] <addr> <b1> <b2> ... <bN>" },
+  { "write", cmd_write, "write memory : %s <memtype> <addr> <b1> <b2> ... <bN>" },
   { "erase", cmd_erase, "perform a chip erase" },
   { "sig",   cmd_sig,   "display device signature bytes" },
-  { "cal",   cmd_cal,   "display device calibration byte" },
-  { "part",  cmd_part,  "display the current part settings" },
-  { "send",  cmd_send,  "send a command : %s <b1> <b2> <b3> <b4>" },
+  { "part",  cmd_part,  "display the current part information" },
+  { "send",  cmd_send,  "send a raw command : %s <b1> <b2> <b3> <b4>" },
   { "help",  cmd_help,  "help" },
   { "?",     cmd_help,  "help" },
   { "quit",  cmd_quit,  "quit" }
@@ -179,7 +177,7 @@ int chardump_line(char * buffer, unsigned char * p, int n, int pad)
 }
 
 
-int hexdump_buf(FILE * f, int startaddr, char * buf, int len)
+int hexdump_buf(FILE * f, int startaddr, unsigned char * buf, int len)
 {
   int addr;
   int i, n;
@@ -209,84 +207,51 @@ int hexdump_buf(FILE * f, int startaddr, char * buf, int len)
 int cmd_dump(int fd, struct avrpart * p, int argc, char * argv[])
 {
   char * e;
-  int i, l;
-  char * buf;
+  unsigned char * buf;
   int maxsize;
-  static int memtype=AVR_M_FLASH;
-  static unsigned short addr=0;
+  unsigned long i;
+  static unsigned long addr=0;
   static int len=64;
+  AVRMEM * mem;
+  char * memtype = NULL;
+  int rc;
 
-  if (argc == 1) {
-    addr += len;
+  if (!((argc == 2) || (argc == 4))) {
+    fprintf(stderr, "Usage: dump <memtype> [<addr> <len>]\n");
+    return -1;
   }
-  else {
-    if (!((argc == 2) || (argc == 4))) {
-      fprintf(stderr, "Usage: dump flash|eeprom|fuse|lock [<addr> <len>]\n");
+
+  memtype = argv[1];
+
+  mem = avr_locate_mem(p, memtype);
+  if (mem == NULL) {
+    fprintf(stderr, "\"%s\" memory type not defined for part \"%s\"\n",
+            memtype, p->desc);
+    return -1;
+  }
+
+  if (argc == 4) {
+    addr = strtoul(argv[2], &e, 0);
+    if (*e || (e == argv[2])) {
+      fprintf(stderr, "%s (dump): can't parse address \"%s\"\n",
+              progname, argv[2]);
       return -1;
     }
 
-    l = strlen(argv[1]);
-    if (strncasecmp(argv[1],"flash",l)==0) {
-      memtype = AVR_M_FLASH;
-    }
-    else if (strncasecmp(argv[1],"eeprom",l)==0) {
-      memtype = AVR_M_EEPROM;
-    }
-    else if ((strncasecmp(argv[1],"fuse",l)==0)||
-             (strncasecmp(argv[1],"fuse-bit",l)==0)) {
-      memtype = AVR_M_FUSE;
-    }
-    else if ((strncasecmp(argv[1],"lock",l)==0)||
-             (strncasecmp(argv[1],"lock-bit",l)==0)) {
-      memtype = AVR_M_LOCK;
-    }
-    else {
-      fprintf(stderr, "%s (dump): invalid memory type \"%s\"\n",
-              progname, argv[1]);
+    len = strtol(argv[3], &e, 0);
+    if (*e || (e == argv[3])) {
+      fprintf(stderr, "%s (dump): can't parse length \"%s\"\n",
+              progname, argv[3]);
       return -1;
     }
-
-    if (argc == 4) {
-      addr = strtoul(argv[2], &e, 0);
-      if (*e || (e == argv[2])) {
-        fprintf(stderr, "%s (dump): can't parse address \"%s\"\n",
-                progname, argv[2]);
-        return -1;
-      }
-
-      len = strtol(argv[3], &e, 0);
-      if (*e || (e == argv[3])) {
-        fprintf(stderr, "%s (dump): can't parse length \"%s\"\n",
-                progname, argv[3]);
-        return -1;
-      }
-    }
   }
 
-  maxsize = 0;
-
-  switch (memtype) {
-    case AVR_M_FLASH:
-    case AVR_M_EEPROM:
-      maxsize = p->mem[memtype].size;
-      break;
-    case AVR_M_FUSE:
-      maxsize = 2;
-      break;
-    case AVR_M_LOCK:
-      maxsize = 1;
-      break;
-  }
-
-  if (argc == 2) {
-    addr = 0;
-    len = maxsize;
-  }
+  maxsize = mem->size;
 
   if (addr > maxsize) {
     fprintf(stderr, 
-            "%s (dump): address 0x%04x is out of range for %s memory\n",
-            progname, addr, avr_memtstr(memtype));
+            "%s (dump): address 0x%05lx is out of range for %s memory\n",
+            progname, addr, mem->desc);
     return -1;
   }
 
@@ -301,17 +266,11 @@ int cmd_dump(int fd, struct avrpart * p, int argc, char * argv[])
   }
 
   for (i=0; i<len; i++) {
-    switch (memtype) {
-      case AVR_M_FLASH:
-      case AVR_M_EEPROM:
-        buf[i] = avr_read_byte(fd, p, memtype, addr+i);
-        break;
-      case AVR_M_FUSE:
-        buf[i] = avr_read_fuse(fd, p, addr+i);
-        break;
-      case AVR_M_LOCK:
-        buf[i] = avr_read_lock(fd, p);
-        break;
+    rc = avr_read_byte(fd, p, mem, addr+i, &buf[i]);
+    if (rc != 0) {
+      fprintf(stderr, "error reading %s address 0x%05lx of part %s\n",
+              mem->desc, addr+i, p->desc);
+      return -1;
     }
   }
 
@@ -321,6 +280,8 @@ int cmd_dump(int fd, struct avrpart * p, int argc, char * argv[])
 
   free(buf);
 
+  addr = addr + len;
+
   return 0;
 }
 
@@ -328,13 +289,13 @@ int cmd_dump(int fd, struct avrpart * p, int argc, char * argv[])
 int cmd_write(int fd, struct avrpart * p, int argc, char * argv[])
 {
   char * e;
-  int i, l;
   int len, maxsize;
-  int memtype;
-  unsigned short addr;
+  char * memtype;
+  unsigned long addr, i;
   char * buf;
   int rc;
   int werror;
+  AVRMEM * mem;
 
   if (argc < 4) {
     fprintf(stderr, "Usage: write flash|eeprom|fuse <addr> <byte1> "
@@ -342,46 +303,16 @@ int cmd_write(int fd, struct avrpart * p, int argc, char * argv[])
     return -1;
   }
 
-  l = strlen(argv[1]);
-  if (strncasecmp(argv[1],"flash",l)==0) {
-    memtype = AVR_M_FLASH;
-  }
-  else if (strncasecmp(argv[1],"eeprom",l)==0) {
-    memtype = AVR_M_EEPROM;
-  }
-  else if ((strncasecmp(argv[1],"fuse",l)==0)||
-           (strncasecmp(argv[1],"fuse-bit",l)==0)) {
-    memtype = AVR_M_FUSE;
-  }
-  else if ((strncasecmp(argv[1],"lock",l)==0)||
-           (strncasecmp(argv[1],"lock-bit",l)==0)) {
-    memtype = AVR_M_LOCK;
-  }
-  else {
-    fprintf(stderr, "%s (write): invalid memory type \"%s\"\n",
-            progname, argv[1]);
+  memtype = argv[1];
+
+  mem = avr_locate_mem(p, memtype);
+  if (mem == NULL) {
+    fprintf(stderr, "\"%s\" memory type not defined for part \"%s\"\n",
+            memtype, p->desc);
     return -1;
   }
 
-  maxsize = 0;
-
-  switch (memtype) {
-    case AVR_M_FLASH:
-    case AVR_M_EEPROM:
-      if (p->mem[memtype].paged) {
-        fprintf(stderr, "%s (write): sorry, interactive write of page "
-                "addressed memory is not supported\n", progname);
-        return -1;
-      }
-      maxsize = p->mem[memtype].size;
-      break;
-    case AVR_M_FUSE:
-      maxsize = 2;
-      break;
-    case AVR_M_LOCK:
-      maxsize = 1;
-      break;
-  }
+  maxsize = mem->size;
 
   addr = strtoul(argv[2], &e, 0);
   if (*e || (e == argv[2])) {
@@ -392,8 +323,8 @@ int cmd_write(int fd, struct avrpart * p, int argc, char * argv[])
 
   if (addr > maxsize) {
     fprintf(stderr, 
-            "%s (write): address 0x%04x is out of range for %s memory\n",
-            progname, addr, avr_memtstr(memtype));
+            "%s (write): address 0x%05lx is out of range for %s memory\n",
+            progname, addr, memtype);
     return -1;
   }
 
@@ -404,7 +335,7 @@ int cmd_write(int fd, struct avrpart * p, int argc, char * argv[])
     fprintf(stderr, 
             "%s (write): selected address and # bytes exceed "
             "range for %s memory\n", 
-            progname, avr_memtstr(memtype));
+            progname, memtype);
     return -1;
   }
 
@@ -427,22 +358,9 @@ int cmd_write(int fd, struct avrpart * p, int argc, char * argv[])
   LED_OFF(fd, pgm->pinno[PIN_LED_ERR]);
   for (werror=0, i=0; i<len; i++) {
 
-    rc = 0;
-    switch (memtype) {
-      case AVR_M_EEPROM:
-      case AVR_M_FLASH:
-        rc = avr_write_byte(fd, p, memtype, addr+i, buf[i]);
-        break;
-      case AVR_M_FUSE:
-        rc = avr_write_fuse(fd, p, addr+i, buf[i]);
-        break;
-      case AVR_M_LOCK:
-        rc = avr_write_lock(fd, p, buf[i]);
-        break;
-    }
-        
+    rc = avr_write_byte(fd, p, mem, addr+i, buf[i]);
     if (rc) {
-      fprintf(stderr, "%s (write): error writing 0x%02x at 0x%04x\n",
+      fprintf(stderr, "%s (write): error writing 0x%02x at 0x%05lx\n",
               progname, buf[i], addr+i);
       werror = 1;
     }
@@ -522,25 +440,28 @@ int cmd_part(int fd, struct avrpart * p, int argc, char * argv[])
 
 int cmd_sig(int fd, struct avrpart * p, int argc, char * argv[])
 {
-  unsigned char sig[4];      /* AVR signature bytes */
   int i;
+  int rc;
+  AVRMEM * m;
 
-  avr_signature(fd, sig);
-  fprintf(stdout, "\nDevice signature = 0x");
-  for (i=0; i<4; i++)
-    fprintf(stdout, "%02x", sig[i]);
-  fprintf(stdout, "\n\n");
+  rc = avr_signature(fd, p);
+  if (rc != 0) {
+    fprintf(stderr, "error reading signature data, rc=%d\n",
+            rc);
+  }
 
-  return 0;
-}
-
-
-int cmd_cal(int fd, struct avrpart * p, int argc, char * argv[])
-{
-  unsigned char byte;
-
-  byte = avr_read_calibration(fd, p);
-  fprintf(stdout, "\nDevice calibration = 0x%02x\n\n", byte);
+  m = avr_locate_mem(p, "signature");
+  if (m == NULL) {
+    fprintf(stderr,
+            "signature data not defined for device \"%s\"\n",
+            p->desc);
+  }
+  else {
+    fprintf(stdout, "Device signature = 0x", progname);
+    for (i=0; i<m->size; i++)
+      fprintf(stdout, "%02x", m->buf[i]);
+    fprintf(stdout, "\n\n");
+  }
 
   return 0;
 }
@@ -562,7 +483,9 @@ int cmd_help(int fd, struct avrpart * p, int argc, char * argv[])
     fprintf(stdout, cmd[i].desc, cmd[i].name);
     fprintf(stdout, "\n");
   }
-  fprintf(stdout, "\n");
+  fprintf(stdout, 
+          "\nUse the 'part' command to display valid memory types for use with the\n"
+          "'dump' and 'write' commands.\n\n");
 
   return 0;
 }