diff --git a/src/avrcache.c b/src/avrcache.c index ea0915771..dbf49201f 100644 --- a/src/avrcache.c +++ b/src/avrcache.c @@ -66,8 +66,8 @@ * 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 + * Usersig is generally unaffected by a chip erase, so will always 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 @@ -90,7 +90,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 bootrow or usersig cache. + * affect the usersig cache. * * The avr_page_erase_cached() function erases a page and synchronises it * with the cache. @@ -689,10 +689,11 @@ int avr_write_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM // Erase the chip and set the cache accordingly int avr_chip_erase_cached(const PROGRAMMER *pgm, const AVRPART *p) { - Cache_desc mems[3] = { + Cache_desc mems[] = { { avr_locate_flash(p), pgm->cp_flash, 1, 0, -1, 0 }, { avr_locate_eeprom(p), pgm->cp_eeprom, 0, 1, -1, 0 }, - // bootrow/usersig is unaffected by CE + { avr_locate_bootrow(p), pgm->cp_bootrow, 0, 0, -1, 0 }, + // usersig is unaffected by CE }; int rc; @@ -718,19 +719,19 @@ int avr_chip_erase_cached(const PROGRAMMER *pgm, const AVRPART *p) { memset(cp->cont, 0xff, cp->size); memset(cp->iscached, 1, cp->size/cp->page_size); } - } else if(mems[i].iseeprom) { // Test whether cached EEPROM pages were zapped - bool erasedee = 0; + } else { // Test whether cached EEPROM/bootrow pages were zapped + bool erased = 0; for(int pgno = 0, n = 0; n < cp->size; pgno++, n += cp->page_size) { if(cp->iscached[pgno]) { - if(!is_memset(cp->copy + n, 0xff, cp->page_size)) { // Page has EEPROM data? + if(!is_memset(cp->copy + n, 0xff, cp->page_size)) { // Page has data? if(avr_read_page_default(pgm, p, mem, n, cp->copy + n) < 0) return LIBAVRDUDE_GENERAL_FAILURE; - erasedee = is_memset(cp->copy + n, 0xff, cp->page_size); + erased = is_memset(cp->copy + n, 0xff, cp->page_size); break; } } } - if(erasedee) { // EEPROM was erased, set cache correspondingly + if(erased) { // Memory was erased, set cache correspondingly memset(cp->copy, 0xff, cp->size); memset(cp->cont, 0xff, cp->size); memset(cp->iscached, 1, cp->size/cp->page_size); diff --git a/src/avrdude.1 b/src/avrdude.1 index 35fce6dd4..28e7b0d7b 100644 --- a/src/avrdude.1 +++ b/src/avrdude.1 @@ -937,10 +937,11 @@ Temperature sensor calibration values .It bootrow Extra page of memory that is only accessible by the MCU in bootloader code; UDPI can read and write this memory only when the device is -unlocked; bootrow is not erased during chip erase +unlocked .It userrow Extra page of EEPROM memory that can be used for firmware settings; this -memory is not erased during a chip erase +memory is not erased during a chip erase; UPDI cannot read this memory +when the device is locked .It sib Special system information block memory with information about AVR family, chip revision etc. .It io @@ -1263,8 +1264,9 @@ command line argument. .Ar verify flushes the cache before verifying memories. .It Ar erase -Perform a chip erase and discard all pending writes to EEPROM and flash. -Note that EEPROM will be preserved if the EESAVE fuse bit is set. +Perform a chip erase and discard all pending writes to flash, EEPROM and bootrow. +Note that EEPROM will be preserved if the EESAVE fuse bit is active, ie, had +a corresponding value at the last reset prior to the operation. .It Ar erase memory Erase the entire specified memory. .It Ar erase memory addr len @@ -1274,8 +1276,8 @@ Synchronise with the device all pending writes to flash, EEPROM, bootrow and usersig. With some programmer and part combinations, flash (and sometimes EEPROM, too) looks like a NOR memory, i.e., 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. When a memory looks like a NOR +erase needs to be issued before writing arbitrary data. Usersig is +unaffected by a chip erase. When a memory looks like a NOR memory, either page erase is deployed (e.g., with parts that have PDI/UPDI interfaces), or if that is not available, both EEPROM and flash caches are fully read in, a chip erase command is issued and both EEPROM and flash diff --git a/src/doc/avrdude.texi b/src/doc/avrdude.texi index 2d1db42de..40746ba45 100644 --- a/src/doc/avrdude.texi +++ b/src/doc/avrdude.texi @@ -981,7 +981,7 @@ Temperature sensor calibration values @item bootrow Extra page of memory that is only accessible by the MCU in bootloader code; UDPI can read and write this memory only when the device is -unlocked; bootrow is not erased during chip erase +unlocked @item userrow Extra page of EEPROM memory that can be used for firmware settings; this memory is not erased during a chip erase @@ -2509,8 +2509,9 @@ comma separated list of memories just as in the @code{-U} command line argument. @code{verify} flushes the cache before verifying memories. @item erase -Perform a chip erase and discard all pending writes to EEPROM and flash. -Note that EEPROM will be preserved if the EESAVE fuse bit is set. +Perform a chip erase and discard all pending writes to flash, EEPROM and bootrow. +Note that EEPROM will be preserved if the EESAVE fuse bit is active, ie, had +a corresponding value at the last reset prior to the operation. @item erase @var{memory} Erase the entire specified memory. @@ -2523,8 +2524,8 @@ Synchronise with the device all pending writes to flash, EEPROM, bootrow and usersig. With some programmer and part combinations, flash (and sometimes EEPROM, too) looks like a NOR memory, i.e., 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. When a memory looks like a NOR +erase needs to be issued before writing arbitrary data. Usersig is +unaffected by a chip erase. When a memory looks like a NOR memory, either page erase is deployed (e.g., with parts that have PDI/UPDI interfaces), or if that is not available, both EEPROM and flash caches are fully read in, a chip erase command is issued and both EEPROM and flash diff --git a/src/dryrun.c b/src/dryrun.c index 94f7d8457..e5c3bbaff 100644 --- a/src/dryrun.c +++ b/src/dryrun.c @@ -62,6 +62,7 @@ typedef struct { int appstart, appsize; // Start and size of application section int datastart, datasize; // Start and size of application data section (if any) int bootstart, bootsize; // Start and size of boot section (if any) + int initialised; // 1 once the part memories are initialised } Dryrun_data; // Use private programmer data as if they were a global structure dry @@ -87,19 +88,40 @@ static int dryrun_read_sig_bytes(const PROGRAMMER *pgm, const AVRPART *p, const } -// Emulate chip erase (only erase flash, pretend EESAVE fuse is active - FIXME: check EESAVE fuse) +// Emulate chip erase static int dryrun_chip_erase(const PROGRAMMER *pgm, const AVRPART *punused) { - AVRMEM *flm; + AVRMEM *mem; pmsg_debug("%s()\n", __func__); if(!dry.dp) Return("no dryrun device?"); - if(!(flm = avr_locate_flash(dry.dp))) + if(!(mem = avr_locate_flash(dry.dp))) Return("cannot locate %s flash memory for chip erase", dry.dp->desc); - if(flm->size < 1) - Return("cannot erase %s flash memory owing to its size %d", dry.dp->desc, flm->size); + if(mem->size < 1) + Return("cannot erase %s flash memory owing to its size %d", dry.dp->desc, mem->size); - memset(flm->buf, 0xff, flm->size); + if(dry.bl) { // Bootloaders won't overwrite themselves + memset(mem->buf + (dry.bl == DRY_TOP? 0: dry.bootsize), 0xff, mem->size-dry.bootsize); + return 0; // Assume that's all a bootloader does + } + + memset(mem->buf, 0xff, mem->size); + + int eesave, bakverb = verbose; + verbose = -123; + if((mem = avr_locate_eeprom(dry.dp))) // Check whether EEPROM needs erasing + if(avr_get_config_value(pgm, dry.dp, "eesave", &eesave) == 0 && eesave == !(dry.dp->prog_modes & PM_UPDI)) + if(mem->size > 0) + memset(mem->buf, 0xff, mem->size); + verbose = bakverb; + + if((mem = avr_locate_bootrow(dry.dp))) // Also erase bootrow if it's there + if(mem->size > 0) + memset(mem->buf, 0xff, mem->size); + + if((mem = avr_locate_lock(dry.dp))) + if(mem->initval != -1 && mem->size > 0 && mem->size <= (int) sizeof(mem->initval)) + memcpy(mem->buf, &mem->initval, mem->size); // FIXME: relying on little endian here return 0; } @@ -124,6 +146,30 @@ static int dryrun_cmd(const PROGRAMMER *pgm, const unsigned char *cmd, unsigned } +static int dryrun_page_erase(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, + unsigned int addr) { + + pmsg_debug("%s(%s, 0x%04x)\n", __func__, m->desc, addr); + if(!dry.dp) + Return("no dryrun device?"); + + AVRMEM *dmem; + if(!(dmem = avr_locate_mem(dry.dp, m->desc))) + Return("cannot locate %s %s memory for paged write", dry.dp->desc, m->desc); + + if(!avr_has_paged_access(pgm, dmem) || addr >= (unsigned) dmem->size) + Return("%s does not support paged access", dmem->desc); + addr &= ~(dmem->page_size-1); + if(addr + dmem->page_size > (unsigned) dmem->size) + Return("%s page erase of %s reaches outside %s?", dmem->desc, + str_ccinterval(addr, addr + dmem->page_size-1), str_ccinterval(0, dmem->size-1)); + + memset(dmem->buf+addr, 0xff, dmem->page_size); + + return 0; +} + + static int dryrun_program_enable(const PROGRAMMER *pgm, const AVRPART *p_unused) { pmsg_debug("%s()\n", __func__); @@ -603,6 +649,10 @@ static void dryrun_enable(PROGRAMMER *pgm, const AVRPART *p) { if((m = avr_locate_flash(q)) && m->size >= 1024 && (pgm->prog_modes & PM_SPM)) dry.bl = (q->prog_modes & PM_UPDI)? DRY_BOTTOM: DRY_TOP; + // So that dryrun can emulate AVRDUDE page erase + if(!(pgm->prog_modes & PM_SPM) && (q->prog_modes & (PM_PDI | PM_UPDI))) + pgm->page_erase = dryrun_page_erase; + if(!dry.random && !dry.init) // OK, no further initialisation needed return; @@ -640,7 +690,12 @@ static void dryrun_enable(PROGRAMMER *pgm, const AVRPART *p) { int ps = flm->page_size; urbtsz = dry.bootsize? dry.bootsize: flm->size > 32768? 512: flm->size < 16384? 256: 384; urbtsz = (urbtsz + ps-1)/ps*ps; - int ubaddr = dry.bootsize? dry.bootstart: flm->size - urbtsz; + if(!dry.bootsize && !dry.datasize) { + dry.bootsize += urbtsz; + dry.appsize -= urbtsz; + dry.bootstart = dry.appsize; + } + int ubaddr = dry.bootstart; putflash(pgm, flm, ubaddr, urbtsz, urbtsz==384? U384: U512); flm->buf[ubaddr] = 0xff; flm->buf[ubaddr+1] = 0xcf; // rjmp .-2 } else if(dry.bootsize) { @@ -666,6 +721,8 @@ static void dryrun_enable(PROGRAMMER *pgm, const AVRPART *p) { putother(pgm, q, m, "The five boxing wizards jump quickly. "); if((m = avr_locate_bootrow(q))) putother(pgm, q, m, "Lorem ipsum dolor sit amet. "); + + dry.initialised = 1; } @@ -942,7 +999,7 @@ static int dryrun_readonly(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM // @@@ check for bootloader write protection - if(mem_is_in_fuses(mem) || mem_is_lock(mem)) + if(dry.initialised && (mem_is_in_fuses(mem) || mem_is_lock(mem))) return 1; return 0; diff --git a/src/term.c b/src/term.c index e56becf79..07ade813d 100644 --- a/src/term.c +++ b/src/term.c @@ -964,7 +964,9 @@ static int cmd_erase(const PROGRAMMER *pgm, const AVRPART *p, int argc, const ch return cmd_write(pgm, p, 6, args); } - term_out("erasing chip ...\n"); + term_out("%s chip erase; discarded pending writes to flash%s\n", + (pgm->prog_modes & PM_SPM)? "asking bootloader to perform": "performing", + avr_locate_bootrow(p)? ", EEPROM and bootrow": avr_locate_eeprom(p)? "and EEPROM": ""); // Erase chip and clear cache int rc = pgm->chip_erase_cached(pgm, p);