Consider bootrow and pdicfg for terminal cache and dryrun

This commit is contained in:
Stefan Rueger
2023-08-15 20:21:24 +01:00
parent 9e22afae7c
commit 161d5aa4a4
6 changed files with 86 additions and 69 deletions

View File

@@ -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) {

View File

@@ -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];

View File

@@ -29,6 +29,7 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <unistd.h>
#include <stdarg.h>
#include <time.h>
@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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);