Add mem->type to encode memory types and attributes

This commit is contained in:
Stefan Rueger
2023-10-25 12:13:36 +01:00
parent 26aedba188
commit 6e2a7a88a6
5 changed files with 153 additions and 35 deletions

View File

@@ -1459,29 +1459,65 @@ char *avr_prog_modes(int pm) {
// Typical order in which memories show in avrdude.conf, runtime adds unknown ones (if any)
const char *avr_mem_order[100] = {
"eeprom", "flash", "application", "apptable",
"boot", "lfuse", "hfuse", "efuse",
"fuse", "fuse0", "wdtcfg", "fuse1",
"bodcfg", "fuse2", "osccfg", "fuse3",
"fuse4", "tcd0cfg", "fuse5", "syscfg0",
"fuse6", "syscfg1", "fuse7", "append",
"codesize", "fuse8", "fuse9", "bootend",
"bootsize", "fusea", "pdicfg", "fuses",
"lock", "lockbits", "prodsig", "sigrow",
"signature", "calibration", "tempsense", "sernum",
"osccal16", "osccal20", "osc16err", "osc20err",
"bootrow", "usersig", "userrow", "data",
"io", "sib",
memtable_t avr_mem_order[100] = {
{"eeprom", MEM_EEPROM},
{"flash", MEM_FLASH | MEM_IN_FLASH},
{"application", MEM_APPLICATION | MEM_IN_FLASH},
{"apptable", MEM_APPTABLE | MEM_IN_FLASH},
{"boot", MEM_BOOT | MEM_IN_FLASH},
{"fuses", MEM_FUSES},
{"lfuse", MEM_FUSE0 | MEM_IS_A_FUSE},
{"hfuse", MEM_FUSE1 | MEM_IS_A_FUSE},
{"efuse", MEM_FUSE2 | MEM_IS_A_FUSE},
{"fuse", MEM_FUSE0 | MEM_IS_A_FUSE},
{"fuse0", MEM_FUSE0 | MEM_IS_A_FUSE},
{"wdtcfg", MEM_FUSE0 | MEM_IS_A_FUSE},
{"fuse1", MEM_FUSE1 | MEM_IS_A_FUSE},
{"bodcfg", MEM_FUSE1 | MEM_IS_A_FUSE},
{"fuse2", MEM_FUSE2 | MEM_IS_A_FUSE},
{"osccfg", MEM_FUSE2 | MEM_IS_A_FUSE},
{"fuse4", MEM_FUSE4 | MEM_IS_A_FUSE},
{"tcd0cfg", MEM_FUSE4 | MEM_IS_A_FUSE},
{"fuse5", MEM_FUSE5 | MEM_IS_A_FUSE},
{"syscfg0", MEM_FUSE5 | MEM_IS_A_FUSE},
{"fuse6", MEM_FUSE6 | MEM_IS_A_FUSE},
{"syscfg1", MEM_FUSE6 | MEM_IS_A_FUSE},
{"fuse7", MEM_FUSE7 | MEM_IS_A_FUSE},
{"append", MEM_FUSE7 | MEM_IS_A_FUSE},
{"codesize", MEM_FUSE7 | MEM_IS_A_FUSE},
{"fuse8", MEM_FUSE8 | MEM_IS_A_FUSE},
{"bootend", MEM_FUSE8 | MEM_IS_A_FUSE},
{"bootsize", MEM_FUSE8 | MEM_IS_A_FUSE},
{"fusea", MEM_FUSEA | MEM_IS_A_FUSE},
{"pdicfg", MEM_FUSEA | MEM_IS_A_FUSE},
{"lock", MEM_LOCK},
{"lockbits", MEM_LOCK},
{"prodsig", MEM_SIGROW | MEM_IN_SIGROW | MEM_READONLY},
{"sigrow", MEM_SIGROW | MEM_IN_SIGROW | MEM_READONLY},
{"signature", MEM_SIGNATURE | MEM_IN_SIGROW | MEM_READONLY},
{"calibration", MEM_CALIBRATION | MEM_IN_SIGROW | MEM_READONLY},
{"tempsense", MEM_TEMPSENSE | MEM_IN_SIGROW | MEM_READONLY},
{"sernum", MEM_SERNUM | MEM_IN_SIGROW | MEM_READONLY},
{"osccal16", MEM_OSCCAL16 | MEM_IN_SIGROW | MEM_READONLY},
{"osccal20", MEM_OSCCAL20 | MEM_IN_SIGROW | MEM_READONLY},
{"osc16err", MEM_OSC16ERR | MEM_IN_SIGROW | MEM_READONLY},
{"osc20err", MEM_OSC20ERR | MEM_IN_SIGROW | MEM_READONLY},
{"bootrow", MEM_BOOTROW | MEM_USER_TYPE},
{"usersig", MEM_USERROW | MEM_USER_TYPE},
{"userrow", MEM_USERROW | MEM_USER_TYPE},
{"data", MEM_SRAM},
{"io", MEM_IO},
{"sib", MEM_SIB | MEM_READONLY},
};
void avr_add_mem_order(const char *str) {
int avr_get_mem_type(const char *str) {
for(size_t i=0; i < sizeof avr_mem_order/sizeof *avr_mem_order; i++) {
if(avr_mem_order[i] && str_eq(avr_mem_order[i], str))
return;
if(!avr_mem_order[i]) {
avr_mem_order[i] = cfg_strdup("avr_mem_order()", str);
return;
if(avr_mem_order[i].str && str_eq(avr_mem_order[i].str, str))
return avr_mem_order[i].type;
if(!avr_mem_order[i].str) {
pmsg_warning("avr_mem_order[] does not know %s; add to array and recompile\n", str);
avr_mem_order[i].str = cfg_strdup(__func__, str);
return avr_mem_order[i].type;
}
}
pmsg_error("avr_mem_order[] under-dimensioned in avr.c; increase and recompile\n");
@@ -1519,7 +1555,7 @@ int avr_mem_is_usersig_type(const AVRMEM *mem) {
int avr_mem_is_known(const char *str) {
if(str && *str)
for(size_t i=0; i < sizeof avr_mem_order/sizeof *avr_mem_order; i++)
if(avr_mem_order[i] && str_eq(avr_mem_order[i], str))
if(avr_mem_order[i].str && str_eq(avr_mem_order[i].str, str))
return 1;
return 0;
}
@@ -1527,7 +1563,7 @@ int avr_mem_is_known(const char *str) {
int avr_mem_might_be_known(const char *str) {
if(str && *str)
for(size_t i=0; i < sizeof avr_mem_order/sizeof *avr_mem_order; i++)
if(avr_mem_order[i] && str_starts(avr_mem_order[i], str))
if(avr_mem_order[i].str && str_starts(avr_mem_order[i].str, str))
return 1;
return 0;
}

View File

@@ -991,8 +991,8 @@ part_parm :
mem = avr_new_mem();
mem->desc = cache_string($2->value.string);
ladd(current_part->mem, mem);
mem->type = avr_get_mem_type($2->value.string);
}
avr_add_mem_order($2->value.string);
current_mem = mem;
free_token($2);
}

View File

@@ -492,8 +492,8 @@ static int avrpart_deep_copy(AVRPARTdeep *d, const AVRPART *p) {
// Fill in all memories we got in defined order
di = 0;
for(size_t mi=0; mi < sizeof avr_mem_order/sizeof *avr_mem_order && avr_mem_order[mi]; mi++) {
m = dev_locate_mem(p, avr_mem_order[mi]);
for(size_t mi=0; mi < sizeof avr_mem_order/sizeof *avr_mem_order && avr_mem_order[mi].str; mi++) {
m = dev_locate_mem(p, avr_mem_order[mi].str);
if(m) {
if(di >= sizeof d->mems/sizeof *d->mems) {
pmsg_error("ran out of mems[] space, increase size in AVRMEMdeep of developer_opts.c and recompile\n");
@@ -730,11 +730,11 @@ static void dev_part_strct(const AVRPART *p, bool tsv, const AVRPART *base, bool
if(!base || opcodecmp(p->op[i], base->op[i], i))
dev_part_strct_entry(tsv, ".ptop", p->desc, "part", opcodename(i), opcode2str(p->op[i], i, !tsv), p->comments);
for(size_t mi=0; mi < sizeof avr_mem_order/sizeof *avr_mem_order && avr_mem_order[mi]; mi++) {
for(size_t mi=0; mi < sizeof avr_mem_order/sizeof *avr_mem_order && avr_mem_order[mi].str; mi++) {
AVRMEM *m, *bm;
m = dev_locate_mem(p, avr_mem_order[mi]);
bm = base? dev_locate_mem(base, avr_mem_order[mi]): NULL;
m = dev_locate_mem(p, avr_mem_order[mi].str);
bm = base? dev_locate_mem(base, avr_mem_order[mi].str): NULL;
if(!m && bm && !tsv)
dev_info("\n memory \"%s\" %*s= NULL;\n", bm->desc, 13 > strlen(bm->desc)? 13-strlen(bm->desc): 0, "");
@@ -941,12 +941,12 @@ void dev_output_part_defs(char *partdesc) {
AVRPART *p = ldata(ln1);
if(p->mem)
for(LNODEID lnm=lfirst(p->mem); lnm; lnm=lnext(lnm))
avr_add_mem_order(((AVRMEM *) ldata(lnm))->desc);
avr_get_mem_type(((AVRMEM *) ldata(lnm))->desc);
// Same for aliased memories (though probably not needed)
if(p->mem_alias)
for(LNODEID lnm=lfirst(p->mem_alias); lnm; lnm=lnext(lnm))
avr_add_mem_order(((AVRMEM_ALIAS *) ldata(lnm))->desc);
avr_get_mem_type(((AVRMEM_ALIAS *) ldata(lnm))->desc);
}
if((nprinted = dev_nprinted)) {

View File

@@ -3116,7 +3116,7 @@ part
# parameters for bootloaders
autobaud_sync = <num> ; # autobaud detection byte, default 0x30
memory <memory>
memory <memstr>
paged = <yes/no> ; # yes/no (flash only, do not use for EEPROM)
offset = <num> ; # memory offset
size = <num> ; # bytes

View File

@@ -322,10 +322,92 @@ typedef struct avrpart {
int lineno; /* config file line number */
} AVRPART;
typedef unsigned int memtype_t;
typedef struct {
const char *str;
memtype_t type;
} memtable_t;
// The least significant 4 bits of type are the offset of a fuse in fuses mem
#define MEM_FUSEOFF_MASK 15 // Mask for offset
#define MEM_FUSE0 0 // fuse lfuse fuse0 wdtcfg
#define MEM_FUSE1 1 // hfuse fuse1 bodcfg
#define MEM_FUSE2 2 // efuse fuse2 osccfg
#define MEM_FUSE4 4 // fuse4 tcd0cfg
#define MEM_FUSE5 5 // fuse5 syscfg0
#define MEM_FUSE6 6 // fuse6 syscfg1
#define MEM_FUSE7 7 // fuse7 append codesize
#define MEM_FUSE8 8 // fuse8 bootend bootsize
#define MEM_FUSEA 10 // fusea pdicfg
// Individual memories that may have different names in different parts
#define MEM_EEPROM (1<< 4) // eeprom
#define MEM_FLASH (1<< 5) // flash
#define MEM_APPLICATION (1<< 6) // application
#define MEM_APPTABLE (1<< 7) // apptable
#define MEM_BOOT (1<< 8) // boot
#define MEM_FUSES (1<< 9) // fuses
#define MEM_LOCK (1<<10) // lock lockbits
#define MEM_SIGROW (1<<11) // prodsig sigrow
#define MEM_SIGNATURE (1<<12) // signature
#define MEM_CALIBRATION (1<<13) // calibration
#define MEM_TEMPSENSE (1<<14) // tempsense
#define MEM_SERNUM (1<<15) // sernum
#define MEM_OSCCAL16 (1<<16) // osccal16
#define MEM_OSCCAL20 (1<<17) // osccal20
#define MEM_OSC16ERR (1<<18) // osc16err
#define MEM_OSC20ERR (1<<19) // osc20err
#define MEM_BOOTROW (1<<20) // bootrow
#define MEM_USERROW (1<<21) // userrow usersig
#define MEM_SRAM (1<<22) // data
#define MEM_IO (1<<23) // io
#define MEM_SIB (1<<24) // sib
// Attributes
#define MEM_IN_FLASH (1<<27) // flash application apptable boot
#define MEM_IS_A_FUSE (1<<28) // fuse [elh]fuse fuseN wdtcfg bodcfg osccfg tcd0cfg syscfg0 syscfg1 append codesize bootend bootsize pdicfg
#define MEM_USER_TYPE (1<<29) // userrow usersig bootrow
#define MEM_IN_SIGROW (1<<30) // prodsig sigrow signature calibration sernum tempsense osccal16 osccal20 osc16err osc20err
#define MEM_READONLY (1U<<31) // sib prodsig sigrow signature sernum tempsense calibration osccal16 osccal20 osc16err osc20err
// Fuse offset and memory type/attribute macros
#define mem_is_eeprom(mem) (!!((mem)->type & MEM_EEPROM))
#define mem_is_flash(mem) (!!((mem)->type & MEM_FLASH))
#define mem_is_application(mem) (!!((mem)->type & MEM_APPLICATION))
#define mem_is_apptable(mem) (!!((mem)->type & MEM_APPTABLE))
#define mem_is_boot(mem) (!!((mem)->type & MEM_BOOT))
#define mem_is_fuses(mem) (!!((mem)->type & MEM_FUSES))
#define mem_is_lock(mem) (!!((mem)->type & MEM_LOCK))
#define mem_is_sigrow(mem) (!!((mem)->type & MEM_SIGROW))
#define mem_is_signature(mem) (!!((mem)->type & MEM_SIGNATURE))
#define mem_is_calibration(mem) (!!((mem)->type & MEM_CALIBRATION))
#define mem_is_tempsense(mem) (!!((mem)->type & MEM_TEMPSENSE))
#define mem_is_sernum(mem) (!!((mem)->type & MEM_SERNUM))
#define mem_is_osccal16(mem) (!!((mem)->type & MEM_OSCCAL16))
#define mem_is_osccal20(mem) (!!((mem)->type & MEM_OSCCAL20))
#define mem_is_osc16err(mem) (!!((mem)->type & MEM_OSC16ERR))
#define mem_is_osc20err(mem) (!!((mem)->type & MEM_OSC20ERR))
#define mem_is_bootrow(mem) (!!((mem)->type & MEM_BOOTROW))
#define mem_is_userrow(mem) (!!((mem)->type & MEM_USERROW))
#define mem_is_sram(mem) (!!((mem)->type & MEM_SRAM))
#define mem_is_io(mem) (!!((mem)->type & MEM_IO))
#define mem_is_sib(mem) (!!((mem)->type & MEM_SIB))
#define mem_is_in_flash(mem) (!!((mem)->type & MEM_IN_FLASH))
#define mem_is_a_fuse(mem) (!!((mem)->type & MEM_IS_A_FUSE))
#define mem_is_in_fuses(mem) (!!((mem)->type & (MEM_FUSES | MEM_IS_A_FUSE))) // If fuses exists, that is
#define mem_is_user_type(mem) (!!((mem)->type & MEM_USER_TYPE))
#define mem_is_in_sigrow(mem) (!!((mem)->type & MEM_IN_SIGROW)) // If sigrow exists, that is
#define mem_is_readonly(mem) (!!((mem)->type & MEM_READONLY))
#define mem_fuse_offset(mem) ((mem)->type & MEM_FUSEOFF_MASK) // Valid if mem_is_a_fuse(mem)
typedef struct avrmem {
const char *desc; /* memory description ("flash", "eeprom", etc) */
memtype_t type; /* internally used type, cannot be set in conf files */
LISTID comments; // Used by developer options -p*/[ASsr...]
int paged; /* page addressed (e.g. ATmega flash) */
int paged; /* 16-bit page addressed, e.g., ATmega flash but not EEPROM */
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) */
@@ -335,7 +417,7 @@ typedef struct avrmem {
unsigned int offset; /* offset in IO memory (ATxmega) */
int min_write_delay; /* microseconds */
int max_write_delay; /* microseconds */
int pwroff_after_write; /* after this memory type is written to,
int pwroff_after_write; /* after this memory is written to,
the device must be powered off and
back on, see errata
https://www.microchip.com/content/dam/mchp/documents/OTH/ProductDocuments/DataSheets/doc1042.pdf */
@@ -921,7 +1003,7 @@ void sort_programmers(LISTID programmers);
typedef void (*FP_UpdateProgress)(int percent, double etime, const char *hdr, int finish);
extern struct avrpart parts[];
extern const char *avr_mem_order[100];
extern memtable_t avr_mem_order[100];
extern FP_UpdateProgress update_progress;
@@ -976,7 +1058,7 @@ int avr_put_cycle_count(const PROGRAMMER *pgm, const AVRPART *p, int cycles);
char *avr_prog_modes(int pm);
void avr_add_mem_order(const char *str);
int avr_get_mem_type(const char *str);
int avr_memstr_is_flash_type(const char *mem);