From 6e2a7a88a680dae21101cbcdaca2a3ef261af809 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Wed, 25 Oct 2023 12:13:36 +0100 Subject: [PATCH] Add mem->type to encode memory types and attributes --- src/avr.c | 80 ++++++++++++++++++++++++++++----------- src/config_gram.y | 2 +- src/developer_opts.c | 14 +++---- src/doc/avrdude.texi | 2 +- src/libavrdude.h | 90 ++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 153 insertions(+), 35 deletions(-) diff --git a/src/avr.c b/src/avr.c index afc591f2..61710a08 100644 --- a/src/avr.c +++ b/src/avr.c @@ -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; } diff --git a/src/config_gram.y b/src/config_gram.y index f33ca6e6..41798692 100644 --- a/src/config_gram.y +++ b/src/config_gram.y @@ -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); } diff --git a/src/developer_opts.c b/src/developer_opts.c index cf41629f..5b32f3da 100644 --- a/src/developer_opts.c +++ b/src/developer_opts.c @@ -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)) { diff --git a/src/doc/avrdude.texi b/src/doc/avrdude.texi index 4a17f009..6f84f07b 100644 --- a/src/doc/avrdude.texi +++ b/src/doc/avrdude.texi @@ -3116,7 +3116,7 @@ part # parameters for bootloaders autobaud_sync = ; # autobaud detection byte, default 0x30 - memory + memory paged = ; # yes/no (flash only, do not use for EEPROM) offset = ; # memory offset size = ; # bytes diff --git a/src/libavrdude.h b/src/libavrdude.h index aa5f718d..3036f494 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -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);