diff --git a/src/avr.c b/src/avr.c index 8cf3f6f1..46ca112e 100644 --- a/src/avr.c +++ b/src/avr.c @@ -1165,10 +1165,10 @@ int avr_signature(const PROGRAMMER *pgm, const AVRPART *p) { int avr_mem_bitmask(const AVRPART *p, const AVRMEM *mem, int addr) { int bitmask = mem->bitmask; // Collective memory fuses will have a different bitmask for each address (ie, fuse) - if(str_eq(mem->desc, "fuses") && addr < 10) { // Get right fuse in fuses memory + if(str_eq(mem->desc, "fuses") && addr >=0 && addr < 16) { // Get right fuse in fuses memory char memtype[64]; AVRMEM *dfuse; - sprintf(memtype, "fuse%d", addr); + sprintf(memtype, "fuse%x", addr); if((dfuse = avr_locate_mem(p, memtype)) && dfuse->size == 1) bitmask = dfuse->bitmask; } @@ -1401,11 +1401,12 @@ const char *avr_mem_order[100] = { "fuse4", "tcd0cfg", "fuse5", "syscfg0", "fuse6", "syscfg1", "fuse7", "append", "codesize", "fuse8", "fuse9", "bootend", - "bootsize", "fuses", "lock", "lockbits", - "tempsense", "signature", "prodsig", "sernum", - "calibration", "osccal16", "osccal20", "osc16err", - "osc20err", "usersig", "userrow", "data", - "io", "sib", + "bootsize", "fusea" "pdicfg", "fuses", + "lock", "lockbits", "tempsense", "signature", + "prodsig", "sernum", "calibration", "osccal16", + "osccal20", "osc16err", "osc20err", "bootrow", + "usersig", "userrow", "data", "io", + "sib", }; void avr_add_mem_order(const char *str) { @@ -1441,8 +1442,8 @@ int avr_mem_is_eeprom_type(const AVRMEM *mem) { return avr_memtype_is_eeprom_type(mem->desc); } -int avr_memtype_is_usersig_type(const char *memtype) { - return memtype && (str_eq(memtype, "usersig") || str_eq(memtype, "userrow")); +int avr_memtype_is_usersig_type(const char *memtype) { // Bootrow is subsumed under usersig type + return memtype && (str_eq(memtype, "bootrow") || str_eq(memtype, "usersig") || str_eq(memtype, "userrow")); } int avr_mem_is_usersig_type(const AVRMEM *mem) { diff --git a/src/avrcache.c b/src/avrcache.c index 1cb4c580..129ea13e 100644 --- a/src/avrcache.c +++ b/src/avrcache.c @@ -50,30 +50,31 @@ * int avr_reset_cache(const PROGRAMMER *pgm, const AVRPART *p); * * avr_read_byte_cached() and avr_write_byte_cached() use a cache if paged - * routines are available and if the device memory type is flash, EEPROM or - * usersig. The AVRXMEGA memories application, apptable and boot are subsumed - * under flash. Userrow is subsumed under usersig provided avrdude.conf has a - * memory alias from usersig to userrow. In all other cases the cached - * read/write functions fall back to pgm->read_byte() and pgm->write_byte(), - * respectively. Bytewise cached read always gets its data from the cache, - * possibly after reading a page from the device memory. Bytewise cached - * write with an address in memory range only ever modifies the cache. Any - * modifications are written to the device after calling avr_flush_cache() or - * when attempting to read or write from a location outside the address range - * of the device memory. + * routines are available and if the device memory type is flash, EEPROM, + * bootrow or usersig. The AVRXMEGA memories application, apptable and boot + * are subsumed under flash. Userrow is subsumed under usersig provided + * avrdude.conf has a memory alias from usersig to userrow. In all other + * cases the cached read/write functions fall back to pgm->read_byte() and + * pgm->write_byte(), respectively. Bytewise cached read always gets its data + * from the cache, possibly after reading a page from the device memory. + * Bytewise cached write with an address in memory range only ever modifies + * the cache. Any modifications are written to the device after calling + * avr_flush_cache() or when attempting to read or write from a location + * outside the address range of the device memory. * - * avr_flush_cache() synchronises pending writes to flash, EEPROM and usersig - * with the device. With some programmer and part combinations, flash (and - * sometimes EEPROM, too) looks like a NOR memory, ie, a write can only clear - * bits, never set them. For NOR memories a page erase or, if not available, - * a chip erase needs to be issued before writing arbitrary data. Usersig is - * generally unaffected by a chip erase, so will need a page erase. When a - * memory looks like a NOR memory, either page erase is deployed (eg, with - * parts that have PDI/UPDI interfaces), or if that is not available, both - * EEPROM and flash caches are fully read in, a pgm->chip_erase() command is - * issued and both EEPROM and flash are written back to the device. Hence, it - * can take minutes to ensure that a single previously cleared bit is set - * and, therefore, this routine should be called sparingly. + * avr_flush_cache() synchronises pending writes to flash, EEPROM, bootrow + * and usersig with the device. With some programmer and part combinations, + * flash (and sometimes EEPROM, too) looks like a NOR memory, ie, a write can + * only clear bits, never set them. For NOR memories a page erase or, if not + * available, a chip erase needs to be issued before writing arbitrary data. + * Bootrow and usersig are generally unaffected by a chip erase, so will need + * a page erase. When a memory looks like a NOR memory, either page erase is + * deployed (eg, with parts that have PDI/UPDI interfaces), or if that is not + * available, both EEPROM and flash caches are fully read in, a + * pgm->chip_erase() command is issued and both EEPROM and flash are written + * back to the device. Hence, it can take minutes to ensure that a single + * previously cleared bit is set and, therefore, this routine should be + * called sparingly. * * avr_chip_erase_cached() erases the chip and discards pending writes() to * flash or EEPROM. It presets the flash cache to all 0xff alleviating the @@ -90,7 +91,7 @@ * has these clear bits on the device. Only with this evidence is the EEPROM * cache preset to all 0xff otherwise the cache discards all pending writes * to EEPROM and is left unchanged otherwise. avr_chip_erase_cached() does not - * affect the usersig cache. + * affect the bootrow or usersig cache. * * The avr_page_erase_cached() function erases a page and synchronises it * with the cache. @@ -120,7 +121,7 @@ * - Programmer must have paged routines * - Memory has positive page size, which is a power of two * - Memory has positive size, which is a multiple of the page size - * - Memory is flash, EEPROM or usersig type + * - Memory is flash, EEPROM, bootrow or usersig type * * Note that in this definition the page size can be 1 */ @@ -256,7 +257,7 @@ static int loadCachePage(AVR_Cache *cp, const PROGRAMMER *pgm, const AVRPART *p, static int initCache(AVR_Cache *cp, const PROGRAMMER *pgm, const AVRPART *p) { AVRMEM *basemem = avr_locate_mem(p, - cp == pgm->cp_flash? "flash": cp == pgm->cp_eeprom? "eeprom": "usersig"); + cp == pgm->cp_flash? "flash": cp == pgm->cp_eeprom? "eeprom": cp == pgm->cp_bootrow? "bootrow": "usersig"); if(!basemem || !avr_has_paged_access(pgm, basemem)) return LIBAVRDUDE_GENERAL_FAILURE; @@ -357,11 +358,12 @@ typedef struct { } CacheDesc_t; -// Write flash, EEPROM and usersig caches to device and free them +// Write flash, EEPROM, bootrow and usersig caches to device and free them int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) { - CacheDesc_t mems[3] = { + CacheDesc_t mems[] = { { avr_locate_mem(p, "flash"), pgm->cp_flash, 1, 0, -1, 0 }, { avr_locate_mem(p, "eeprom"), pgm->cp_eeprom, 0, 1, -1, 0 }, + { avr_locate_mem(p, "bootrow"), pgm->cp_bootrow, 0, 0, -1, 0 }, { avr_locate_mem(p, "usersig"), pgm->cp_usersig, 0, 0, -1, 0 }, }; @@ -453,7 +455,7 @@ int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) { AVR_Cache *cp = mems[i].cp; if(!mem) continue; - if(avr_mem_is_usersig_type(mem)) // CE does not affect usersig + if(avr_mem_is_usersig_type(mem)) // CE does not affect bootrow/usersig continue; for(int pgno = 0, n = 0; n < cp->size; pgno++, n += cp->page_size) @@ -469,7 +471,7 @@ int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) { AVR_Cache *cp = mems[i].cp; if(!mem) continue; - if(avr_mem_is_usersig_type(mem)) // CE does not affect usersig + if(avr_mem_is_usersig_type(mem)) // CE does not affect bootrow/usersig continue; for(int ird = 0, pgno = 0, n = 0; n < cp->size; pgno++, n += cp->page_size) { @@ -498,7 +500,7 @@ int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) { AVR_Cache *cp = mems[i].cp; if(!mem) continue; - if(avr_mem_is_usersig_type(mem)) // CE does not affect usersig + if(avr_mem_is_usersig_type(mem)) // CE does not affect bootrow/usersig continue; if(mems[i].isflash) { @@ -590,7 +592,7 @@ int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) { /* * Read byte via a read/write cache - * - Used if paged routines available and if memory is flash, EEPROM or usersig + * - Used if paged routines available and if memory is flash, EEPROM, bootrow or usersig * - Otherwise fall back to pgm->read_byte() * - Out of memory addr: synchronise cache and, if successful, pretend reading a zero * - Cache is automagically created and initialised if needed @@ -598,7 +600,7 @@ int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) { int avr_read_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, unsigned long addr, unsigned char *value) { - // Use pgm->read_byte() if not flash/EEPROM/usersig or no paged access + // Use pgm->read_byte() if not flash/EEPROM/bootrow/usersig or no paged access if(!avr_has_paged_access(pgm, mem)) return fallback_read_byte(pgm, p, mem, addr, value); @@ -611,7 +613,8 @@ int avr_read_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM * } AVR_Cache *cp = avr_mem_is_eeprom_type(mem)? pgm->cp_eeprom: - avr_mem_is_usersig_type(mem)? pgm->cp_usersig: pgm->cp_flash; + avr_mem_is_flash_type(mem)? pgm->cp_flash: + str_eq(mem->desc, "bootrow")? pgm->cp_bootrow: pgm->cp_usersig; if(!cp->cont) // Init cache if needed if(initCache(cp, pgm, p) < 0) @@ -633,7 +636,7 @@ int avr_read_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM * /* * Write byte via a read/write cache - * - Used if paged routines available and if memory is flash, EEPROM or usersig + * - Used if paged routines available and if memory is flash, EEPROM, bootrow or usersig * - Otherwise fall back to pgm->write_byte() * - Out of memory addr: synchronise cache with device and return whether successful * - If programmer indicates a readonly spot, return LIBAVRDUDE_SOFTFAIL @@ -642,7 +645,7 @@ int avr_read_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM * int avr_write_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, unsigned long addr, unsigned char data) { - // Use pgm->write_byte() if not flash/EEPROM/usersig or no paged access + // Use pgm->write_byte() if not flash/EEPROM/bootrow/usersig or no paged access if(!avr_has_paged_access(pgm, mem)) return fallback_write_byte(pgm, p, mem, addr, data); @@ -651,7 +654,8 @@ int avr_write_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM return avr_flush_cache(pgm, p); AVR_Cache *cp = avr_mem_is_eeprom_type(mem)? pgm->cp_eeprom: - avr_mem_is_usersig_type(mem)? pgm->cp_usersig: pgm->cp_flash; + avr_mem_is_flash_type(mem)? pgm->cp_flash: + str_eq(mem->desc, "bootrow")? pgm->cp_bootrow: pgm->cp_usersig; if(!cp->cont) // Init cache if needed if(initCache(cp, pgm, p) < 0) @@ -682,7 +686,7 @@ int avr_chip_erase_cached(const PROGRAMMER *pgm, const AVRPART *p) { CacheDesc_t mems[3] = { { avr_locate_mem(p, "flash"), pgm->cp_flash, 1, 0, -1, 0 }, { avr_locate_mem(p, "eeprom"), pgm->cp_eeprom, 0, 1, -1, 0 }, - // usersig is unaffected by CE + // bootrow/usersig is unaffected by CE }; int rc; @@ -754,7 +758,8 @@ int avr_page_erase_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM } AVR_Cache *cp = avr_mem_is_eeprom_type(mem)? pgm->cp_eeprom: - avr_mem_is_usersig_type(mem)? pgm->cp_usersig: pgm->cp_flash; + avr_mem_is_flash_type(mem)? pgm->cp_flash: + str_eq(mem->desc, "bootrow")? pgm->cp_bootrow: pgm->cp_usersig; if(!cp->cont) // Init cache if needed if(initCache(cp, pgm, p) < 0) @@ -780,7 +785,7 @@ int avr_page_erase_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM // Free cache(s) discarding any pending writes int avr_reset_cache(const PROGRAMMER *pgm, const AVRPART *p_unused) { - AVR_Cache *mems[3] = { pgm->cp_flash, pgm->cp_eeprom, pgm->cp_usersig }; + AVR_Cache *mems[] = { pgm->cp_flash, pgm->cp_eeprom, pgm->cp_bootrow, pgm->cp_usersig }; for(size_t i = 0; i < sizeof mems/sizeof*mems; i++) { AVR_Cache *cp = mems[i]; diff --git a/src/dryrun.c b/src/dryrun.c index 88ed5479..797c343f 100644 --- a/src/dryrun.c +++ b/src/dryrun.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -113,7 +114,7 @@ static void dryrun_enable(PROGRAMMER *pgm, const AVRPART *p) { pmsg_debug("%s()\n", __func__); if(!dry.dp) { - unsigned char inifuses[10]; // For fuses, which is made up from fuse0, fuse1, ... + unsigned char inifuses[16]; // For fuses, which is made up from fuse0, fuse1, ... AVRMEM *fusesm = NULL; dry.dp = avr_dup_part(p); // Allocate dryrun part @@ -126,13 +127,14 @@ static void dryrun_enable(PROGRAMMER *pgm, const AVRPART *p) { } else if(str_eq(m->desc, "fuses")) { fusesm = m; } else if(str_contains(m->desc, "fuse") || str_contains(m->desc, "lock")) { - // Lock can have 4 bytes: still allow initialisation from initval + // Lock, eg, can have 4 bytes: still allow initialisation from initval if(m->initval != -1 && m->size >=1 && m->size <= (int) sizeof(m->initval)) { memcpy(m->buf, &m->initval, m->size); // FIXME: relying on little endian here - if(str_starts(m->desc, "fuse") && m->desc[4] && m->size == 1) { - int fno = m->desc[4]-'0'; - if(fno >= 0 && fno < (int) sizeof inifuses) - inifuses[fno] = m->initval; + if(str_starts(m->desc, "fuse") && m->desc[4] && isxdigit(0xff & m->desc[4]) && !m->desc[5]) { + int fno = strtol(m->desc+4, NULL, 16); + if(fno >= 0) + for(int i = 0; i < m->size && fno+i < (int) sizeof inifuses; i++) + inifuses[fno+i] = m->initval >> 8*i; } } else { memset(m->buf, 0xff, m->size); @@ -333,16 +335,22 @@ int dryrun_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, dmem->buf[addr] = data; - if(str_eq(dmem->desc, "fuses") && addr < 10) { // Copy the byte to corresponding fuse[0-9] + if(str_eq(dmem->desc, "fuses") && addr < 16) { // Copy the byte to corresponding fuse[0-9a-f] char memtype[64]; - sprintf(memtype, "fuse%ld", addr); - if((dfuse = avr_locate_mem(dry.dp, memtype)) && dfuse->size == 1) + sprintf(memtype, "fuse%lx", addr); + if((dfuse = avr_locate_mem(dry.dp, memtype))) dfuse->buf[0] = data; - } else if(str_starts(m->desc, "fuse")) { // Copy fuseN byte into fuses memory - int fno = m->desc[4]-'0'; - if(fno >= 0 && fno < 10) - if((dfuse = avr_locate_mem(dry.dp, "fuses")) && dfuse->size > fno) - dfuse->buf[fno] = data; + else if(addr > 0) { // Could be high byte of two-byte fuse + sprintf(memtype, "fuse%lx", addr-1); + if((dfuse = avr_locate_mem(dry.dp, memtype))) + dfuse->buf[1] = data; + } + } else if(str_starts(m->desc, "fuse") && m->desc[4] && isxdigit(0xff & m->desc[4]) && !m->desc[5]) { + // Copy fuseX byte into fuses memory + int fno = strtol(m->desc+4, NULL, 16); + if(fno >= 0) + if((dfuse = avr_locate_mem(dry.dp, "fuses")) && (int) (fno+addr) < dfuse->size) + dfuse->buf[fno+addr] = data; } return 0; diff --git a/src/fileio.c b/src/fileio.c index fed7751e..4d42a1eb 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -782,7 +782,7 @@ static int elf_mem_limits(const AVRMEM *mem, const AVRPART *p, *lowbound = 0x810000; *highbound = 0x81ffff; // Max 64 KiB *fileoff = 0; - } else if (str_eq(mem->desc, "lfuse") || str_eq(mem->desc, "fuses")) { + } else if (str_eq(mem->desc, "lfuse") || str_eq(mem->desc, "fuse") || str_eq(mem->desc, "fuses")) { *lowbound = 0x820000; *highbound = 0x82ffff; *fileoff = 0; @@ -795,11 +795,11 @@ static int elf_mem_limits(const AVRMEM *mem, const AVRPART *p, *highbound = 0x82ffff; *fileoff = 2; } else if (str_starts(mem->desc, "fuse") && - (mem->desc[4] >= '0' && mem->desc[4] <= '9')) { - /* Xmega fuseN */ + mem->desc[4] && isxdigit(0xff & mem->desc[4]) && ¬mem->desc[5]) { + /* Xmega or modern AVR fuseX */ *lowbound = 0x820000; *highbound = 0x82ffff; - *fileoff = mem->desc[4] - '0'; + *fileoff = strtol(mem->desc+4, NULL, 16); } else if (str_starts(mem->desc, "lock")) { // Lock or lockbits *lowbound = 0x830000; *highbound = 0x83ffff; diff --git a/src/libavrdude.h b/src/libavrdude.h index 272dfa31..cabd276c 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -843,7 +843,7 @@ typedef struct programmer_t { unsigned int addr); int (*flush_cache) (const struct programmer_t *pgm, const AVRPART *p); int (*reset_cache) (const struct programmer_t *pgm, const AVRPART *p); - AVR_Cache *cp_flash, *cp_eeprom, *cp_usersig; + AVR_Cache *cp_flash, *cp_eeprom, *cp_bootrow, *cp_usersig; const char *config_file; // Config file where defined int lineno; // Config file line number diff --git a/src/pgm.c b/src/pgm.c index d95d6f33..8e4ab69b 100644 --- a/src/pgm.c +++ b/src/pgm.c @@ -81,6 +81,7 @@ PROGRAMMER *pgm_new(void) { // Allocate cache structures for flash and EEPROM, *do not* free in pgm_free() pgm->cp_flash = cfg_malloc("pgm_new()", sizeof(AVR_Cache)); pgm->cp_eeprom = cfg_malloc("pgm_new()", sizeof(AVR_Cache)); + pgm->cp_bootrow = cfg_malloc("pgm_new()", sizeof(AVR_Cache)); pgm->cp_usersig = cfg_malloc("pgm_new()", sizeof(AVR_Cache)); // Default values @@ -180,7 +181,7 @@ void pgm_free(PROGRAMMER *p) { } // Never free const char *, eg, p->desc, which are set by cache_string() // p->cookie is freed by pgm_teardown - // Never free cp_flash, cp_eeprom or cp_usersig cache structures + // Never free cp_flash, cp_eeprom, cp_bootrow or cp_usersig cache structures free(p); } } @@ -197,6 +198,8 @@ PROGRAMMER *pgm_dup(const PROGRAMMER *src) { free(pgm->cp_flash); if(pgm->cp_eeprom) free(pgm->cp_eeprom); + if(pgm->cp_bootrow) + free(pgm->cp_bootrow); if(pgm->cp_usersig) free(pgm->cp_usersig);