From a4c8ac47bb469013a38e67905de898eefae8ec09 Mon Sep 17 00:00:00 2001
From: joerg_wunsch <joerg_wunsch@81a1dc3b-b13d-400b-aceb-764788c761c2>
Date: Mon, 29 Aug 2011 09:25:04 +0000
Subject: [PATCH] bug #34027: avrdude AT90S1200 Problem (part 1 - bitbang
 programmers) * config_gram.y: Introduce new keyword "is_at90s1200". *
 lexer.l: (Ditto.) * avrdude.conf.in: Applew new keyword to the AT90S1200
 device. * avrpart.h: Introduce new flag AVRPART_IS_AT90S1200, reflecting the
 is_at90s1200 configuration keyword. * bitbang.c (bitbang_initialize): Replace
 existing test for AT90S1200 by AVRPART_IS_AT90S1200 * avr.c
 (avr_write_byte_default): Avoid the pre-write reading for the AT90S1200, as
 this appears to sometimes corrupt the high byte by pre-programming the low
 byte just written into it.

git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@1002 81a1dc3b-b13d-400b-aceb-764788c761c2
---
 ChangeLog       | 15 +++++++++++++++
 avr.c           |  8 +++++++-
 avrdude.conf.in |  1 +
 avrpart.h       |  1 +
 bitbang.c       |  2 +-
 config_gram.y   | 13 ++++++++++++-
 lexer.l         |  1 +
 7 files changed, 38 insertions(+), 3 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index e71cecc5..3dc10e57 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2011-08-29  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	bug #34027: avrdude AT90S1200 Problem (part 1 - bitbang
+	programmers)
+	* config_gram.y: Introduce new keyword "is_at90s1200".
+	* lexer.l: (Ditto.)
+	* avrdude.conf.in: Applew new keyword to the AT90S1200 device.
+	* avrpart.h: Introduce new flag AVRPART_IS_AT90S1200, reflecting
+	the is_at90s1200 configuration keyword.
+	* bitbang.c (bitbang_initialize): Replace existing test for
+	AT90S1200 by AVRPART_IS_AT90S1200
+	* avr.c (avr_write_byte_default): Avoid the pre-write reading for
+	the AT90S1200, as this appears to sometimes corrupt the high byte
+	by pre-programming the low byte just written into it.
+
 2011-08-27  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
 
 	* configure.ac: Bump version for post-5.11.
diff --git a/avr.c b/avr.c
index 09dab1fe..961487db 100644
--- a/avr.c
+++ b/avr.c
@@ -443,11 +443,17 @@ int avr_write_byte_default(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
     return 0;
   }
 
-  if (!mem->paged) {
+  if (!mem->paged &&
+      (p->flags & AVRPART_IS_AT90S1200) == 0) {
     /* 
      * check to see if the write is necessary by reading the existing
      * value and only write if we are changing the value; we can't
      * use this optimization for paged addressing.
+     *
+     * For mysterious reasons, on the AT90S1200, this read operation
+     * sometimes causes the high byte of the same word to be
+     * programmed to the value of the low byte that has just been
+     * programmed before.  Avoid that optimization on this device.
      */
     rc = pgm->read_byte(pgm, p, mem, addr, &b);
     if (rc != 0) {
diff --git a/avrdude.conf.in b/avrdude.conf.in
index 39e21568..5d2d2d1a 100644
--- a/avrdude.conf.in
+++ b/avrdude.conf.in
@@ -1523,6 +1523,7 @@ part
 part
     id               = "1200";
     desc             = "AT90S1200";
+    is_at90s1200     = yes;
     stk500_devcode   = 0x33;
     avr910_devcode   = 0x13;
     signature        = 0x1e 0x90 0x01;
diff --git a/avrpart.h b/avrpart.h
index 04334609..f868e948 100644
--- a/avrpart.h
+++ b/avrpart.h
@@ -93,6 +93,7 @@ typedef struct opcode {
 #define AVRPART_INIT_SMC       0x0200  /* part will undergo chip erase */
 #define AVRPART_WRITE          0x0400  /* at least one write operation specified */
 #define AVRPART_HAS_TPI        0x0800  /* part has TPI i/f rather than ISP (ATtiny4/5/9/10) */
+#define AVRPART_IS_AT90S1200   0x1000  /* part is an AT90S1200 (needs special treatment) */
 
 #define AVR_DESCLEN 64
 #define AVR_IDLEN   32
diff --git a/bitbang.c b/bitbang.c
index ada885ac..00eb8277 100644
--- a/bitbang.c
+++ b/bitbang.c
@@ -606,7 +606,7 @@ int bitbang_initialize(PROGRAMMER * pgm, AVRPART * p)
    * order to possibly get back into sync with the chip if we are out
    * of sync.
    */
-  if (strcmp(p->desc, "AT90S1200")==0) {
+  if (p->flags & AVRPART_IS_AT90S1200) {
     pgm->program_enable(pgm, p);
   }
   else {
diff --git a/config_gram.y b/config_gram.y
index 3e10cd46..c676c828 100644
--- a/config_gram.y
+++ b/config_gram.y
@@ -225,6 +225,7 @@ static int parse_cmdbits(OPCODE * op);
 %token K_HAS_PDI                /* MCU has PDI i/f rather than ISP (ATxmega). */
 %token K_HAS_TPI                /* MCU has TPI i/f rather than ISP (ATtiny4/5/9/10). */
 %token K_IDR			/* address of OCD register in IO space */
+%token K_IS_AT90S1200		/* chip is an AT90S1200 (needs special treatment) */
 %token K_IS_AVR32               /* chip is in the avr32 family */
 %token K_RAMPZ			/* address of RAMPZ reg. in IO space */
 %token K_SPMCR			/* address of SPMC[S]R in memory space */
@@ -1166,6 +1167,16 @@ part_parm :
       free_token($3);
     } |
 
+  K_IS_AT90S1200 TKN_EQUAL yesno
+    {
+      if ($3->primary == K_YES)
+        current_part->flags |= AVRPART_IS_AT90S1200;
+      else if ($3->primary == K_NO)
+        current_part->flags &= AVRPART_IS_AT90S1200;
+
+      free_token($3);
+    } |
+
   K_IS_AVR32 TKN_EQUAL yesno
     {
       if ($3->primary == K_YES)
@@ -1175,7 +1186,7 @@ part_parm :
 
       free_token($3);
     } |
-    
+
   K_ALLOWFULLPAGEBITSTREAM TKN_EQUAL yesno
     {
       if ($3->primary == K_YES)
diff --git a/lexer.l b/lexer.l
index 6f1698f8..9870e7c6 100644
--- a/lexer.l
+++ b/lexer.l
@@ -155,6 +155,7 @@ has_pdi          { yylval=NULL; return K_HAS_PDI; }
 has_tpi          { yylval=NULL; return K_HAS_TPI; }
 id               { yylval=NULL; return K_ID; }
 idr              { yylval=NULL; return K_IDR; }
+is_at90s1200     { yylval=NULL; return K_IS_AT90S1200; }
 is_avr32         { yylval=NULL; return K_IS_AVR32; }
 jtagmki          { yylval=NULL; return K_JTAG_MKI; }
 jtagmkii         { yylval=NULL; return K_JTAG_MKII; }