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().
This commit is contained in:
parent
ba314f23e9
commit
d134dc8fff
144
src/avrpart.c
144
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;i<sizeof(d->op)/sizeof(d->op[0]);i++)
|
||||
{
|
||||
if (d->op[i] != NULL)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
|
|
|
@ -117,6 +117,7 @@ SIGN [+-]
|
|||
<strng>\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; }
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue