Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce memory types in lieu of string comparisons with memory names #1538

Merged
merged 23 commits into from
Nov 3, 2023
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
26aedba
Rename memtype to memstr, memchr or mtype
stefanrueger Oct 24, 2023
6e2a7a8
Add mem->type to encode memory types and attributes
stefanrueger Oct 25, 2023
872fb9d
Replace and remove avr_memstr_is_...() functions
stefanrueger Oct 25, 2023
7bdd610
Replace avr_mem_is_...() functions with macros
stefanrueger Oct 25, 2023
cd53766
Replace str_eq(m->desc, "...") with mem_is_...(m)
stefanrueger Oct 25, 2023
c8d11f6
Replace str_eq(m->desc, "(usersig|userrow|prodsig|sigrow") with macros
stefanrueger Oct 25, 2023
03db6e5
Use memory type for fuse memories instead of fuse names
stefanrueger Oct 26, 2023
2be7f7e
Refer to memory rather than memory type
stefanrueger Oct 26, 2023
54eacc5
Convert avr_locate_mem(p, string) to avr_locate_mem_by_type()
stefanrueger Oct 30, 2023
d6f4cdd
Show parameter that could not be set
stefanrueger Oct 30, 2023
af4614e
Handle sigrow sub-memories in jtagmkII_read_byte()
stefanrueger Oct 30, 2023
dab5904
Review and fix fuses r/w for jtag3
stefanrueger Oct 30, 2023
566cfad
Review and fix single fuse r/w for jtag2/jtag3
stefanrueger Oct 31, 2023
4622a6d
Add sigrow sub-memories to jtagmkII_read_byte()
stefanrueger Oct 31, 2023
c9eb065
Suggest -xrestore when flash overlaps the bootloader in -c urclock
stefanrueger Oct 31, 2023
76cbf91
Add notice2() messages for sigrow access
stefanrueger Oct 31, 2023
0fc5749
Merge branch 'avrdudes:main' into memory-types
stefanrueger Nov 2, 2023
124fcc8
Unify communication traces using trace_buffer() or trace2_buffer()
stefanrueger Nov 2, 2023
37df346
Fix usbdev_recv_frame communication trace
stefanrueger Nov 2, 2023
528b56b
Use __func__ in calls of trace_buffer()
stefanrueger Nov 2, 2023
9c894e1
Set readsize and page_size of UPDI fuses to 1 ...
stefanrueger Nov 2, 2023
291f9ff
Remove unused variables
stefanrueger Nov 3, 2023
f9920fc
Treat chip_rev as unsigned char
stefanrueger Nov 3, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 98 additions & 72 deletions src/avr.c
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ int avr_read_byte_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM

if (readop == NULL) {
#if DEBUG
pmsg_error("operation not supported on memory type %s\n", mem->desc);
pmsg_error("operation not supported on memory %s\n", mem->desc);
#endif
goto error;
}
Expand Down Expand Up @@ -302,7 +302,7 @@ int avr_mem_hiaddr(const AVRMEM * mem)
return mem->size;

/* if the memory is not a flash-type memory do not remove trailing 0xff */
if(!avr_mem_is_flash_type(mem))
if(!mem_is_in_flash(mem))
return mem->size;

/* return the highest non-0xff address regardless of how much
Expand All @@ -322,17 +322,17 @@ int avr_mem_hiaddr(const AVRMEM * mem)


/*
* Read the entirety of the specified memory type into the corresponding
* Read the entirety of the specified memory into the corresponding
* buffer of the avrpart pointed to by p. If v is non-NULL, verify against
* v's memory area, only those cells that are tagged TAG_ALLOCATED are
* verified.
*
* Return the number of bytes read, or < 0 if an error occurs.
*/
int avr_read(const PROGRAMMER *pgm, const AVRPART *p, const char *memtype, const AVRPART *v) {
AVRMEM *mem = avr_locate_mem(p, memtype);
int avr_read(const PROGRAMMER *pgm, const AVRPART *p, const char *memstr, const AVRPART *v) {
AVRMEM *mem = avr_locate_mem(p, memstr);
if (mem == NULL) {
pmsg_error("no %s memory for part %s\n", memtype, p->desc);
pmsg_error("no %s memory for part %s\n", memstr, p->desc);
return LIBAVRDUDE_GENERAL_FAILURE;
}

Expand Down Expand Up @@ -467,7 +467,7 @@ int avr_read_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, con
/* else: fall back to byte-at-a-time read, for historical reasons */
}

if (str_eq(mem->desc, "signature")) {
if (mem_is_signature(mem)) {
if (pgm->read_sig_bytes) {
int rc = pgm->read_sig_bytes(pgm, p, mem);
if (rc < 0)
Expand Down Expand Up @@ -663,7 +663,7 @@ int avr_write_byte_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM
goto error;
}

if (str_eq(mem->desc, "flash")) {
if (mem_is_flash(mem)) {
pmsg_error("writing a byte to flash is not supported for %s\n", p->desc);
goto error;
} else if ((mem->offset + addr) & 1) {
Expand All @@ -675,7 +675,7 @@ int avr_write_byte_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM
continue;

/* must erase fuse first */
if (str_eq(mem->desc, "fuse")) {
if (mem_is_a_fuse(mem)) { // TPI parts only have one fuse
/* setup for SECTION_ERASE (high byte) */
avr_tpi_setup_rw(pgm, mem, addr | 1, TPI_NVMCMD_SECTION_ERASE);

Expand Down Expand Up @@ -725,7 +725,7 @@ int avr_write_byte_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM
rc = -2;
goto rcerror;
}
// Read operation is not support on this memory type
// Read operation is not support on this memory
}
else {
readok = 1;
Expand Down Expand Up @@ -758,7 +758,7 @@ int avr_write_byte_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM

if (writeop == NULL) {
#if DEBUG
pmsg_error("write not supported for memory type %s\n", mem->desc);
pmsg_error("write not supported for memory %s\n", mem->desc);
#endif
goto error;
}
Expand All @@ -782,7 +782,7 @@ int avr_write_byte_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM

if (readok == 0) {
/*
* read operation not supported for this memory type, just wait
* read operation not supported for this memory, just wait
* the max programming time and then return
*/
usleep(mem->max_write_delay); /* maximum write delay */
Expand Down Expand Up @@ -833,7 +833,7 @@ int avr_write_byte_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM
else if (mem->pwroff_after_write) {
/*
* The device has been flagged as power-off after write to this
* memory type. The reason we don't just blindly follow the
* memory. The reason we don't just blindly follow the
* flag is that the power-off advice may only apply to some
* memory bits but not all. We only actually power-off the
* device if the data read back does not match what we wrote.
Expand Down Expand Up @@ -907,10 +907,10 @@ int avr_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem,
*
* Return the number of bytes written, or LIBAVRDUDE_GENERAL_FAILURE on error.
*/
int avr_write(const PROGRAMMER *pgm, const AVRPART *p, const char *memtype, int size, int auto_erase) {
AVRMEM *m = avr_locate_mem(p, memtype);
int avr_write(const PROGRAMMER *pgm, const AVRPART *p, const char *memstr, int size, int auto_erase) {
AVRMEM *m = avr_locate_mem(p, memstr);
if (m == NULL) {
pmsg_error("no %s memory for part %s\n", memtype, p->desc);
pmsg_error("no %s memory for part %s\n", memstr, p->desc);
return LIBAVRDUDE_GENERAL_FAILURE;
}

Expand Down Expand Up @@ -1154,7 +1154,7 @@ int avr_write_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, int

int page_tainted = 0;
int flush_page = 0;
int paged = avr_mem_is_flash_type(m) && m->paged;
int paged = mem_is_in_flash(m) && m->paged;

if(paged)
wsize = (wsize+1)/2*2; // Round up write size for word boundary
Expand Down Expand Up @@ -1230,13 +1230,19 @@ int avr_signature(const PROGRAMMER *pgm, const AVRPART *p) {
// Obtain bitmask for byte in memory (classic, TPI, PDI and UPDI parts)
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 >=0 && addr < 16) { // Get right fuse in fuses memory
char memtype[64];
AVRMEM *dfuse;
sprintf(memtype, "fuse%x", addr);
if((dfuse = avr_locate_mem(p, memtype)) && dfuse->size == 1)
if(mem_is_fuses(mem) && addr >=0 && addr < 16) { // Get right fuse in fuses memory
AVRMEM *dfuse = avr_locate_fuse_by_offset(p, addr);
if(dfuse) {
bitmask = dfuse->bitmask;
if(dfuse->size == 2 && addr == (int) mem_fuse_offset(dfuse)+1) // High byte of 2-byte fuse
bitmask >>= 8;
}
} else if(mem_is_a_fuse(mem) && mem->size == 2 && addr == 1) {
bitmask >>= 8;
} else if(mem_is_lock(mem) && mem->size > 1 && mem->size <= 4 && addr >= 0 && addr < mem->size) {
bitmask >>= (8*addr);
}

return bitmask & 0xff;
Expand Down Expand Up @@ -1281,21 +1287,21 @@ int compare_memory_masked(AVRMEM * m, uint8_t b1, uint8_t b2) {
*
* Return the number of bytes verified, or -1 if they don't match.
*/
int avr_verify(const PROGRAMMER *pgm, const AVRPART *p, const AVRPART *v, const char *memtype, int size) {
int avr_verify(const PROGRAMMER *pgm, const AVRPART *p, const AVRPART *v, const char *memstr, int size) {
int i;
unsigned char * buf1, * buf2;
int vsize;
AVRMEM * a, * b;

a = avr_locate_mem(p, memtype);
a = avr_locate_mem(p, memstr);
if (a == NULL) {
pmsg_error("memory type %s not defined for part %s\n", memtype, p->desc);
pmsg_error("memory %s not defined for part %s\n", memstr, p->desc);
return -1;
}

b = avr_locate_mem(v, memtype);
b = avr_locate_mem(v, memstr);
if (b == NULL) {
pmsg_error("memory type %s not defined for part %s\n", memtype, v->desc);
pmsg_error("memory %s not defined for part %s\n", memstr, v->desc);
return -1;
}

Expand All @@ -1305,7 +1311,7 @@ int avr_verify(const PROGRAMMER *pgm, const AVRPART *p, const AVRPART *v, const

if (vsize < size) {
pmsg_warning("requested verification for %d bytes\n", size);
imsg_warning("%s memory region only contains %d bytes\n", memtype, vsize);
imsg_warning("%s memory region only contains %d bytes\n", memstr, vsize);
imsg_warning("only %d bytes will be verified\n", vsize);
size = vsize;
}
Expand All @@ -1319,7 +1325,7 @@ int avr_verify(const PROGRAMMER *pgm, const AVRPART *p, const AVRPART *v, const
if(vroerror < 10) {
if(!(verror + vroerror))
pmsg_warning("verification mismatch%s\n",
avr_mem_is_flash_type(a)? " in r/o areas, expected for vectors and/or bootloader": "");
mem_is_in_flash(a)? " in r/o areas, expected for vectors and/or bootloader": "");
imsg_warning("device 0x%02x != input 0x%02x at addr 0x%04x (read only location)\n",
buf1[i], buf2[i], i);
} else if(vroerror == 10)
Expand All @@ -1342,12 +1348,12 @@ int avr_verify(const PROGRAMMER *pgm, const AVRPART *p, const AVRPART *v, const
// Mismatch is only in unused bits
if ((buf1[i] | bitmask) != 0xff) {
// Programmer returned unused bits as 0, must be the part/programmer
pmsg_warning("ignoring mismatch in unused bits of %s\n", memtype);
pmsg_warning("ignoring mismatch in unused bits of %s\n", memstr);
imsg_warning("(device 0x%02x != input 0x%02x); to prevent this warning fix\n", buf1[i], buf2[i]);
imsg_warning("the part or programmer definition in the config file\n");
} else {
// Programmer returned unused bits as 1, must be the user
pmsg_warning("ignoring mismatch in unused bits of %s\n", memtype);
pmsg_warning("ignoring mismatch in unused bits of %s\n", memstr);
imsg_warning("(device 0x%02x != input 0x%02x); to prevent this warning set\n", buf1[i], buf2[i]);
imsg_warning("unused bits to 1 when writing (double check with datasheet)\n");
}
Expand Down Expand Up @@ -1459,75 +1465,95 @@ 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},
{"fuse", MEM_FUSE0 | MEM_IS_A_FUSE},
{"lfuse", MEM_FUSE0 | MEM_IS_A_FUSE},
{"hfuse", MEM_FUSE1 | MEM_IS_A_FUSE},
{"efuse", MEM_FUSE2 | 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");
exit(1);
}

int avr_memtype_is_flash_type(const char *memtype) {
return memtype && (
str_eq(memtype, "flash") ||
str_eq(memtype, "application") ||
str_eq(memtype, "apptable") ||
str_eq(memtype, "boot"));
}

int avr_mem_is_flash_type(const AVRMEM *mem) {
return avr_memtype_is_flash_type(mem->desc);
}

int avr_memtype_is_eeprom_type(const char *memtype) {
return memtype && str_eq(memtype, "eeprom");
return mem_is_in_flash(mem);
}

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) { // Bootrow is subsumed under usersig type
return memtype && (str_eq(memtype, "bootrow") || str_eq(memtype, "usersig") || str_eq(memtype, "userrow"));
return mem_is_eeprom(mem);
}

int avr_mem_is_usersig_type(const AVRMEM *mem) {
return avr_memtype_is_usersig_type(mem->desc);
return mem_is_user_type(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;
}

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;
}
Expand Down
Loading