From d134dc8ffff40127cb294706ddaa78e84da432ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Wunsch?= Date: Thu, 10 Feb 2022 20:39:19 +0100 Subject: [PATCH] Alias keyword (#868) Implementation for an "alias" keyword. By now, only applied inside memory descriptions. * Make "mem_alias" a separate nonterminal. The previous implementation attempt caused a syntax error in yacc code, and separating mem_alias on the same level as mem_spec appears to be the cleaner solution anyway. * Maintain real memory aliases. Instead of duplicating the aliased memory with a new name, maintain a second list of memory aliases (per device) that contains a pointer to the memory area it is aliased to. That way, a memory name can be clearly distinguished between the canonical one and any aliases. * Check p->mem_alias != NULL before touching it * Add avr_find_memalias() This takes a memory region as input, and searches whether an alias can be found for it. * We need to add a list structure for the mem_alias list, always. By that means, mem_alias won't ever be NULL, so no need to check later. Also, in avr_dup_part(), duplicate the alias list. * In a memory alias, actually remember the current name. * In avr_dup_part(), adjust pointers of aliased memories While walking the list of memories, for each entry, see if there is an alias pointing to it. If so, allocate a duplicated one, and fix its aliased_mem pointer to point to the duplicated memory region instead of the original one. * Add avr_locate_mem_noalias() When looking whether any memory region has already been defined for the current part while parsing the config file, only non-aliased names must be considered. Otherwise, a newly defined alias would kick out the memory definition it is being aliased to. * When defining a mem_alias, drop any existing one of that name. * Actually use avr_find_memalias() to find aliases * Add declaration for avr_find_memalias() * When defining a memory, also search for an existing alias If the newly defined name has the same as an existing alias, the alias can be removed. Note that we do explicitly *not* remove any memory by the same name of a later defined alias, as this might invalidate another alias'es pointer. If someone defines that, the alias name just won't ever be found by avr_locate_mem(). --- src/avrpart.c | 144 ++++++++++++++++++++++++++++++++++++++++------ src/config.c | 2 + src/config.h | 1 + src/config_gram.y | 55 +++++++++++++++++- src/lexer.l | 1 + src/libavrdude.h | 11 ++++ 6 files changed, 193 insertions(+), 21 deletions(-) diff --git a/src/avrpart.c b/src/avrpart.c index 13b89e2d..dc6def44 100644 --- a/src/avrpart.c +++ b/src/avrpart.c @@ -260,6 +260,21 @@ AVRMEM * avr_new_memtype(void) return m; } +AVRMEM_ALIAS * avr_new_memalias(void) +{ + AVRMEM_ALIAS * m; + + m = (AVRMEM_ALIAS *)malloc(sizeof(*m)); + if (m == NULL) { + avrdude_message(MSG_INFO, "avr_new_memalias(): out of memory\n"); + exit(1); + } + + memset(m, 0, sizeof(*m)); + + return m; +} + /* * Allocate and initialize memory buffers for each of the device's @@ -326,6 +341,17 @@ AVRMEM * avr_dup_mem(AVRMEM * m) return n; } +AVRMEM_ALIAS * avr_dup_memalias(AVRMEM_ALIAS * m) +{ + AVRMEM_ALIAS * n; + + n = avr_new_memalias(); + + *n = *m; + + return n; +} + void avr_free_mem(AVRMEM * m) { int i; @@ -348,7 +374,36 @@ void avr_free_mem(AVRMEM * m) free(m); } -AVRMEM * avr_locate_mem(AVRPART * p, char * desc) +void avr_free_memalias(AVRMEM_ALIAS * m) +{ + free(m); +} + +AVRMEM_ALIAS * avr_locate_memalias(AVRPART * p, char * desc) +{ + AVRMEM_ALIAS * m, * match; + LNODEID ln; + int matches; + int l; + + l = strlen(desc); + matches = 0; + match = NULL; + for (ln=lfirst(p->mem_alias); ln; ln=lnext(ln)) { + m = ldata(ln); + if (strncmp(desc, m->desc, l) == 0) { + match = m; + matches++; + } + } + + if (matches == 1) + return match; + + return NULL; +} + +AVRMEM * avr_locate_mem_noalias(AVRPART * p, char * desc) { AVRMEM * m, * match; LNODEID ln; @@ -373,11 +428,54 @@ AVRMEM * avr_locate_mem(AVRPART * p, char * desc) } +AVRMEM * avr_locate_mem(AVRPART * p, char * desc) +{ + AVRMEM * m, * match; + AVRMEM_ALIAS * alias; + LNODEID ln; + int matches; + int l; + + l = strlen(desc); + matches = 0; + match = NULL; + for (ln=lfirst(p->mem); ln; ln=lnext(ln)) { + m = ldata(ln); + if (strncmp(desc, m->desc, l) == 0) { + match = m; + matches++; + } + } + + if (matches == 1) + return match; + + /* not yet found: look for matching alias name */ + alias = avr_locate_memalias(p, desc); + if (alias != NULL) + return alias->aliased_mem; + + return NULL; +} + +AVRMEM_ALIAS * avr_find_memalias(AVRPART * p, AVRMEM * m_orig) +{ + AVRMEM_ALIAS * m; + LNODEID ln; + + for (ln=lfirst(p->mem_alias); ln; ln=lnext(ln)) { + m = ldata(ln); + if (m->aliased_mem == m_orig) + return m; + } + + return NULL; +} + + void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, AVRPART * p, int type, int verbose) { - static LNODEID ln; - static AVRMEM * n; static unsigned int prev_mem_offset, prev_mem_size; int i, j; char * optr; @@ -398,25 +496,14 @@ void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, AVRPART * p, prefix, prefix, prefix); } - // Get the next memory section, and stop before going out of band - if (ln == NULL) - ln = lnext(lfirst(p->mem)); - else - ln = lnext(ln); - if (ln != NULL) - n = ldata(ln); - // Only print memory section if the previous section printed isn't identical if(prev_mem_offset != m->offset || prev_mem_size != m->size || (strcmp(p->family_id, "") == 0)) { prev_mem_offset = m->offset; prev_mem_size = m->size; + AVRMEM_ALIAS *ap = avr_find_memalias(p, m); /* Show alias if the current and the next memory section has the same offset and size, we're not out of band and a family_id is present */ - char * mem_desc_alias = m->offset == n->offset && \ - m->size == n->size && \ - ln != NULL && \ - strcmp(p->family_id, "") != 0 ? - n->desc : ""; + char * mem_desc_alias = ap? ap->desc: ""; fprintf(f, "%s%-11s %-8s %4d %5d %5d %4d %-6s %6d %4d %6d %5d %5d 0x%02x 0x%02x\n", prefix, @@ -488,6 +575,7 @@ AVRPART * avr_new_part(void) p->ocdrev = -1; p->mem = lcreat(NULL, 0); + p->mem_alias = lcreat(NULL, 0); return p; } @@ -496,19 +584,35 @@ AVRPART * avr_new_part(void) AVRPART * avr_dup_part(AVRPART * d) { AVRPART * p; - LISTID save; - LNODEID ln; + LISTID save, save2; + LNODEID ln, ln2; int i; p = avr_new_part(); save = p->mem; + save2 = p->mem_alias; *p = *d; p->mem = save; + p->mem_alias = save2; for (ln=lfirst(d->mem); ln; ln=lnext(ln)) { - ladd(p->mem, avr_dup_mem(ldata(ln))); + AVRMEM *m = ldata(ln); + AVRMEM *m2 = avr_dup_mem(m); + ladd(p->mem, m2); + // see if there is any alias for it + for (ln2=lfirst(d->mem_alias); ln2; ln2=lnext(ln2)) { + AVRMEM_ALIAS *a = ldata(ln2); + if (a->aliased_mem == m) { + // yes, duplicate it + AVRMEM_ALIAS *a2 = avr_dup_memalias(a); + // ... adjust the pointer ... + a2->aliased_mem = m2; + // ... and add to new list + ladd(p->mem_alias, a2); + } + } } for (i = 0; i < AVR_OP_MAX; i++) { @@ -523,6 +627,8 @@ void avr_free_part(AVRPART * d) int i; ldestroy_cb(d->mem, (void(*)(void *))avr_free_mem); d->mem = NULL; + ldestroy_cb(d->mem_alias, (void(*)(void *))avr_free_memalias); + d->mem_alias = NULL; for(i=0;iop)/sizeof(d->op[0]);i++) { if (d->op[i] != NULL) diff --git a/src/config.c b/src/config.c index a384f50f..3d8a760e 100644 --- a/src/config.c +++ b/src/config.c @@ -47,6 +47,7 @@ AVRPART * current_part; AVRMEM * current_mem; LISTID part_list; LISTID programmers; +bool is_alias; int lineno; const char * infile; @@ -72,6 +73,7 @@ int init_config(void) current_mem = NULL; part_list = lcreat(NULL, 0); programmers = lcreat(NULL, 0); + is_alias = false; lineno = 1; infile = NULL; diff --git a/src/config.h b/src/config.h index d0d65ae2..914dda54 100644 --- a/src/config.h +++ b/src/config.h @@ -54,6 +54,7 @@ extern int lineno; extern const char * infile; extern LISTID string_list; extern LISTID number_list; +extern bool is_alias; // current entry is alias #if !defined(HAS_YYSTYPE) diff --git a/src/config_gram.y b/src/config_gram.y index d04e84f5..8b31519a 100644 --- a/src/config_gram.y +++ b/src/config_gram.y @@ -68,6 +68,7 @@ static int pin_name; %token K_PAGE_SIZE %token K_PAGED +%token K_ALIAS %token K_BAUDRATE %token K_BS2 %token K_BUFF @@ -1238,13 +1239,24 @@ part_parm : mem_specs { AVRMEM * existing_mem; + AVRMEM_ALIAS * existing_alias; - existing_mem = avr_locate_mem(current_part, current_mem->desc); + existing_mem = avr_locate_mem_noalias(current_part, current_mem->desc); if (existing_mem != NULL) { lrmv_d(current_part->mem, existing_mem); avr_free_mem(existing_mem); } - ladd(current_part->mem, current_mem); + existing_alias = avr_locate_memalias(current_part, current_mem->desc); + if (existing_alias != NULL) { + lrmv_d(current_part->mem_alias, existing_alias); + avr_free_memalias(existing_alias); + } + if (is_alias) { + avr_free_mem(current_mem); // alias mem has been already entered below + is_alias = false; + } else { + ladd(current_part->mem, current_mem); + } current_mem = NULL; } | @@ -1281,6 +1293,7 @@ yesno : mem_specs : mem_spec TKN_SEMI | + mem_alias TKN_SEMI | mem_specs mem_spec TKN_SEMI ; @@ -1410,6 +1423,44 @@ mem_spec : } ; +mem_alias : + K_ALIAS TKN_STRING + { + AVRMEM * existing_mem; + + existing_mem = avr_locate_mem(current_part, $2->value.string); + if (existing_mem == NULL) { + yyerror("%s alias to non-existent memory %s", + current_mem->desc, $2->value.string); + free_token($2); + YYABORT; + } + + // if this alias does already exist, drop the old one + AVRMEM_ALIAS * alias = avr_locate_memalias(current_part, current_mem->desc); + if (alias) { + lrmv_d(current_part->mem_alias, alias); + avr_free_memalias(alias); + } + // NB: we do *not* check whether any non-alias region of the + // same name does already exist, as that one could be pointed to + // by an(other) alias as well. If we destroyed it, the alias + // pointer would get stale. In case someone defines the same + // name both as a regular memory as well as an alias, the + // regular one will always be found first by avr_locate_mem(). + + is_alias = true; + alias = avr_new_memalias(); + + // alias->desc and current_mem->desc have the same length + // definition, thus no need to check for length here + strcpy(alias->desc, current_mem->desc); + alias->aliased_mem = existing_mem; + ladd(current_part->mem_alias, alias); + + free_token($2); + } +; %% diff --git a/src/lexer.l b/src/lexer.l index 9aab9d4a..0b31eb21 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -117,6 +117,7 @@ SIGN [+-] \n { yyerror("unterminated character constant"); return YYERRCODE; } +alias { yylval=NULL; return K_ALIAS; } allowfullpagebitstream { yylval=NULL; return K_ALLOWFULLPAGEBITSTREAM; } avr910_devcode { yylval=NULL; return K_AVR910_DEVCODE; } bank_size { yylval=NULL; return K_PAGE_SIZE; } diff --git a/src/libavrdude.h b/src/libavrdude.h index e44e5f48..ddb72b48 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -261,6 +261,7 @@ typedef struct avrpart { OPCODE * op[AVR_OP_MAX]; /* opcodes */ LISTID mem; /* avr memory definitions */ + LISTID mem_alias; /* memory alias definitions */ char config_file[PATH_MAX]; /* config file where defined */ int lineno; /* config file line number */ } AVRPART; @@ -292,6 +293,11 @@ typedef struct avrmem { OPCODE * op[AVR_OP_MAX]; /* opcodes */ } AVRMEM; +typedef struct avrmem_alias { + char desc[AVR_MEMDESCLEN]; /* alias name ("syscfg0" etc.) */ + AVRMEM *aliased_mem; +} AVRMEM_ALIAS; + #ifdef __cplusplus extern "C" { #endif @@ -307,10 +313,15 @@ int avr_get_output_index(OPCODE * op); /* Functions for AVRMEM structures */ AVRMEM * avr_new_memtype(void); +AVRMEM_ALIAS * avr_new_memalias(void); int avr_initmem(AVRPART * p); AVRMEM * avr_dup_mem(AVRMEM * m); void avr_free_mem(AVRMEM * m); +void avr_free_memalias(AVRMEM_ALIAS * m); AVRMEM * avr_locate_mem(AVRPART * p, char * desc); +AVRMEM * avr_locate_mem_noalias(AVRPART * p, char * desc); +AVRMEM_ALIAS * avr_locate_memalias(AVRPART * p, char * desc); +AVRMEM_ALIAS * avr_find_memalias(AVRPART * p, AVRMEM * m_orig); void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, AVRPART * p, int type, int verbose);