2001-10-15 02:49:10 +00:00
|
|
|
/*
|
2003-02-08 04:17:25 +00:00
|
|
|
* avrdude - A Downloader/Uploader for AVR device programmers
|
2004-12-22 01:52:45 +00:00
|
|
|
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
|
2001-10-15 02:49:10 +00:00
|
|
|
*
|
2003-02-06 19:08:33 +00:00
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
2001-10-15 02:49:10 +00:00
|
|
|
*
|
2003-02-06 19:08:33 +00:00
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
2001-10-15 02:49:10 +00:00
|
|
|
*
|
2003-02-06 19:08:33 +00:00
|
|
|
* You should have received a copy of the GNU General Public License
|
2012-11-20 14:03:50 +00:00
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2001-10-15 02:49:10 +00:00
|
|
|
*/
|
|
|
|
|
2001-10-14 23:17:26 +00:00
|
|
|
/* $Id$ */
|
|
|
|
|
2003-02-14 20:34:03 +00:00
|
|
|
#include "ac_cfg.h"
|
|
|
|
|
2007-01-24 22:43:46 +00:00
|
|
|
#include <errno.h>
|
2001-10-14 23:17:26 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdarg.h>
|
Prepare for new components in avrdude.conf incl prog_modes
- Add prog_modes to part and programmer definitions; prog_mode is a bitwise
or of programming modes
+ PM_SPM: Bootloaders, self-programming with SPM/NVM Controllers
+ PM_TPI: t4, t5, t9, t10, t20, t40, t102, t104
+ PM_ISP: SPI programming for In-System Programming (typ classic parts)
+ PM_PDI: Program and Debug Interface (xmega parts)
+ PM_UPDI: Unified Program and Debug Interface
+ PM_HVSP: High Voltage Serial Programming (some classic parts)
+ PM_HVPP: High Voltage Parallel Programming (most non-HVSP classic parts)
+ PM_debugWIRE: Simpler alternative to JTAG (a subset of HVPP/HVSP parts)
+ PM_JTAG: some classic parts, some xmega
+ PM_aWire: AVR32 parts
- Add mcuid, a unique id in 0..2039, to part definition for urclock programmer
- Add n_interrupts, the number of interrupts, to part definition
- Add n_page_erase to part definition (# of pages erased during NVM erase)
- Implement a simple calculator in config_gram.y so numeric values can be
expressed as simple expressions such as PM_SPM | PM_UPDI
- Introduce a new method of assigning simple components to the grammar without
touching config_gram.y via an eligible-component list in config.c; numeric
expressions on the rhs of an assignment resolve to integer values
- Update documentation in avrdude.conf.in and avrdude.texi
2022-08-30 01:08:15 +00:00
|
|
|
#include <stddef.h>
|
2001-10-14 23:17:26 +00:00
|
|
|
#include <string.h>
|
2022-08-09 20:20:44 +00:00
|
|
|
#include <ctype.h>
|
2001-10-14 23:17:26 +00:00
|
|
|
|
2007-01-24 22:43:46 +00:00
|
|
|
#include "avrdude.h"
|
2014-05-19 10:01:59 +00:00
|
|
|
#include "libavrdude.h"
|
2014-06-17 20:08:28 +00:00
|
|
|
#include "config.h"
|
2022-08-30 18:48:17 +00:00
|
|
|
#include "avrintel.h"
|
2014-05-19 10:01:59 +00:00
|
|
|
|
2003-02-14 20:34:03 +00:00
|
|
|
#include "config_gram.h"
|
2001-10-14 23:17:26 +00:00
|
|
|
|
2022-08-09 20:45:04 +00:00
|
|
|
const char *default_programmer;
|
|
|
|
const char *default_parallel;
|
|
|
|
const char *default_serial;
|
|
|
|
const char *default_spi;
|
2011-08-26 20:30:26 +00:00
|
|
|
double default_bitclock;
|
2003-02-21 18:46:51 +00:00
|
|
|
|
2001-10-14 23:17:26 +00:00
|
|
|
LISTID string_list;
|
|
|
|
LISTID number_list;
|
|
|
|
PROGRAMMER * current_prog;
|
|
|
|
AVRPART * current_part;
|
2001-11-21 02:46:55 +00:00
|
|
|
AVRMEM * current_mem;
|
Prepare for new components in avrdude.conf incl prog_modes
- Add prog_modes to part and programmer definitions; prog_mode is a bitwise
or of programming modes
+ PM_SPM: Bootloaders, self-programming with SPM/NVM Controllers
+ PM_TPI: t4, t5, t9, t10, t20, t40, t102, t104
+ PM_ISP: SPI programming for In-System Programming (typ classic parts)
+ PM_PDI: Program and Debug Interface (xmega parts)
+ PM_UPDI: Unified Program and Debug Interface
+ PM_HVSP: High Voltage Serial Programming (some classic parts)
+ PM_HVPP: High Voltage Parallel Programming (most non-HVSP classic parts)
+ PM_debugWIRE: Simpler alternative to JTAG (a subset of HVPP/HVSP parts)
+ PM_JTAG: some classic parts, some xmega
+ PM_aWire: AVR32 parts
- Add mcuid, a unique id in 0..2039, to part definition for urclock programmer
- Add n_interrupts, the number of interrupts, to part definition
- Add n_page_erase to part definition (# of pages erased during NVM erase)
- Implement a simple calculator in config_gram.y so numeric values can be
expressed as simple expressions such as PM_SPM | PM_UPDI
- Introduce a new method of assigning simple components to the grammar without
touching config_gram.y via an eligible-component list in config.c; numeric
expressions on the rhs of an assignment resolve to integer values
- Update documentation in avrdude.conf.in and avrdude.texi
2022-08-30 01:08:15 +00:00
|
|
|
int current_strct;
|
2001-10-14 23:17:26 +00:00
|
|
|
LISTID part_list;
|
|
|
|
LISTID programmers;
|
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().
2022-02-10 19:39:19 +00:00
|
|
|
bool is_alias;
|
2001-10-14 23:17:26 +00:00
|
|
|
|
2022-07-18 17:10:09 +00:00
|
|
|
int cfg_lineno;
|
|
|
|
char * cfg_infile;
|
2007-01-24 21:07:54 +00:00
|
|
|
|
|
|
|
extern char * yytext;
|
2001-10-14 23:17:26 +00:00
|
|
|
|
Prepare for new components in avrdude.conf incl prog_modes
- Add prog_modes to part and programmer definitions; prog_mode is a bitwise
or of programming modes
+ PM_SPM: Bootloaders, self-programming with SPM/NVM Controllers
+ PM_TPI: t4, t5, t9, t10, t20, t40, t102, t104
+ PM_ISP: SPI programming for In-System Programming (typ classic parts)
+ PM_PDI: Program and Debug Interface (xmega parts)
+ PM_UPDI: Unified Program and Debug Interface
+ PM_HVSP: High Voltage Serial Programming (some classic parts)
+ PM_HVPP: High Voltage Parallel Programming (most non-HVSP classic parts)
+ PM_debugWIRE: Simpler alternative to JTAG (a subset of HVPP/HVSP parts)
+ PM_JTAG: some classic parts, some xmega
+ PM_aWire: AVR32 parts
- Add mcuid, a unique id in 0..2039, to part definition for urclock programmer
- Add n_interrupts, the number of interrupts, to part definition
- Add n_page_erase to part definition (# of pages erased during NVM erase)
- Implement a simple calculator in config_gram.y so numeric values can be
expressed as simple expressions such as PM_SPM | PM_UPDI
- Introduce a new method of assigning simple components to the grammar without
touching config_gram.y via an eligible-component list in config.c; numeric
expressions on the rhs of an assignment resolve to integer values
- Update documentation in avrdude.conf.in and avrdude.texi
2022-08-30 01:08:15 +00:00
|
|
|
#define pgm_comp_desc(x, type) { #x, COMP_PROGRAMMER, offsetof(PROGRAMMER, x), sizeof(((PROGRAMMER *) NULL)->x), type }
|
|
|
|
#define part_comp_desc(x, type) { #x, COMP_AVRPART, offsetof(AVRPART, x), sizeof(((AVRPART *) NULL)->x), type }
|
|
|
|
#define mem_comp_desc(x, type) { #x, COMP_AVRMEM, offsetof(AVRMEM, x), sizeof(((AVRMEM *) NULL)->x), type }
|
|
|
|
|
|
|
|
// Component description for config_gram.y, will be sorted appropriately on first use
|
|
|
|
Component_t avr_comp[] = {
|
|
|
|
// PROGRAMMER
|
|
|
|
pgm_comp_desc(prog_modes, COMP_INT),
|
|
|
|
|
|
|
|
// AVRPART
|
|
|
|
part_comp_desc(prog_modes, COMP_INT),
|
|
|
|
part_comp_desc(mcuid, COMP_INT),
|
|
|
|
part_comp_desc(n_interrupts, COMP_INT),
|
|
|
|
part_comp_desc(n_page_erase, COMP_INT),
|
|
|
|
};
|
|
|
|
|
2001-10-14 23:17:26 +00:00
|
|
|
#define DEBUG 0
|
|
|
|
|
2012-01-17 20:56:37 +00:00
|
|
|
void cleanup_config(void)
|
|
|
|
{
|
2012-01-31 17:03:43 +00:00
|
|
|
ldestroy_cb(part_list, (void(*)(void*))avr_free_part);
|
|
|
|
ldestroy_cb(programmers, (void(*)(void*))pgm_free);
|
|
|
|
ldestroy_cb(string_list, (void(*)(void*))free_token);
|
|
|
|
ldestroy_cb(number_list, (void(*)(void*))free_token);
|
2012-01-17 20:56:37 +00:00
|
|
|
}
|
2001-10-14 23:17:26 +00:00
|
|
|
|
|
|
|
int init_config(void)
|
|
|
|
{
|
|
|
|
string_list = lcreat(NULL, 0);
|
|
|
|
number_list = lcreat(NULL, 0);
|
|
|
|
current_prog = NULL;
|
|
|
|
current_part = NULL;
|
2012-01-17 20:56:37 +00:00
|
|
|
current_mem = NULL;
|
2001-10-14 23:17:26 +00:00
|
|
|
part_list = lcreat(NULL, 0);
|
|
|
|
programmers = lcreat(NULL, 0);
|
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().
2022-02-10 19:39:19 +00:00
|
|
|
is_alias = false;
|
2001-10-14 23:17:26 +00:00
|
|
|
|
2022-07-18 17:10:09 +00:00
|
|
|
cfg_lineno = 1;
|
|
|
|
cfg_infile = NULL;
|
2001-10-14 23:17:26 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-08-09 20:20:44 +00:00
|
|
|
void *cfg_malloc(const char *funcname, size_t n) {
|
|
|
|
void *ret = malloc(n);
|
|
|
|
if(!ret) {
|
Replace string arrays with const char * and allocated space (part 2)
This commit replaces fixed-string buffers in PROGRAMMER, AVRPART and AVRMEM
that are dealt with by the parser and grammar. Now, string assignments are
always to const char *, ie, these are read-only strings with arbitrary
length.
config_gram.y now only needs to consider one type of string assignment.
This commit also
- Replaces the simple linear-search cache_string() function with faster
hashed cache_string(). Either way, the returned value is likely to be
shared, so should never be free()'d.
- Duplicates hvupdi_support list in pgm_dup() and frees it in pgm_free()
- Adds const qualifier to some function args in avrpart.c and pgm.c
- Hardens some functions against being called with NULL pointers
- Ensures _new() and _dup() functions for parts, programmers and memory
return a suitable memory. Out of memory triggers exit in one of three
functions, cfg_malloc(), cfg_realloc() and cfg_strdup(); there is
rarely anything useful that AVRDUDE or, for that matter, any
application compiled against libavrdude can do once you run out of
memory as AVRDUDE/libavrdude rely heavily on allocation of memory.
2022-08-10 15:14:56 +00:00
|
|
|
avrdude_message(MSG_INFO, "%s: out of memory in %s (needed %lu bytes)\n", progname, funcname, (unsigned long) n);
|
2022-08-09 20:20:44 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
memset(ret, 0, n);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
Replace string arrays with const char * and allocated space (part 2)
This commit replaces fixed-string buffers in PROGRAMMER, AVRPART and AVRMEM
that are dealt with by the parser and grammar. Now, string assignments are
always to const char *, ie, these are read-only strings with arbitrary
length.
config_gram.y now only needs to consider one type of string assignment.
This commit also
- Replaces the simple linear-search cache_string() function with faster
hashed cache_string(). Either way, the returned value is likely to be
shared, so should never be free()'d.
- Duplicates hvupdi_support list in pgm_dup() and frees it in pgm_free()
- Adds const qualifier to some function args in avrpart.c and pgm.c
- Hardens some functions against being called with NULL pointers
- Ensures _new() and _dup() functions for parts, programmers and memory
return a suitable memory. Out of memory triggers exit in one of three
functions, cfg_malloc(), cfg_realloc() and cfg_strdup(); there is
rarely anything useful that AVRDUDE or, for that matter, any
application compiled against libavrdude can do once you run out of
memory as AVRDUDE/libavrdude rely heavily on allocation of memory.
2022-08-10 15:14:56 +00:00
|
|
|
void *cfg_realloc(const char *funcname, void *p, size_t n) {
|
|
|
|
void *ret;
|
|
|
|
|
|
|
|
if(!(ret = p? realloc(p, n): calloc(1, n))) {
|
|
|
|
avrdude_message(MSG_INFO, "%s: out of memory in %s (needed %lu bytes)\n", progname, funcname, (unsigned long) n);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2022-08-09 20:20:44 +00:00
|
|
|
|
|
|
|
char *cfg_strdup(const char *funcname, const char *s) {
|
|
|
|
char *ret = strdup(s);
|
|
|
|
if(!ret) {
|
|
|
|
avrdude_message(MSG_INFO, "%s: out of memory in %s\n", progname, funcname);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
2001-10-14 23:17:26 +00:00
|
|
|
|
|
|
|
|
|
|
|
int yywrap()
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-17 20:08:28 +00:00
|
|
|
int yyerror(char * errmsg, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
char message[512];
|
|
|
|
|
|
|
|
va_start(args, errmsg);
|
|
|
|
|
|
|
|
vsnprintf(message, sizeof(message), errmsg, args);
|
2022-07-18 17:10:09 +00:00
|
|
|
avrdude_message(MSG_INFO, "%s: error at %s:%d: %s\n", progname, cfg_infile, cfg_lineno, message);
|
2014-06-17 20:08:28 +00:00
|
|
|
|
|
|
|
va_end(args);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int yywarning(char * errmsg, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
char message[512];
|
|
|
|
|
|
|
|
va_start(args, errmsg);
|
|
|
|
|
|
|
|
vsnprintf(message, sizeof(message), errmsg, args);
|
2022-07-18 17:10:09 +00:00
|
|
|
avrdude_message(MSG_INFO, "%s: warning at %s:%d: %s\n", progname, cfg_infile, cfg_lineno, message);
|
2014-06-17 20:08:28 +00:00
|
|
|
|
|
|
|
va_end(args);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-08-09 20:20:44 +00:00
|
|
|
TOKEN * new_token(int primary) {
|
|
|
|
TOKEN * tkn = (TOKEN *) cfg_malloc("new_token()", sizeof(TOKEN));
|
2001-10-14 23:17:26 +00:00
|
|
|
tkn->primary = primary;
|
|
|
|
return tkn;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void free_token(TOKEN * tkn)
|
|
|
|
{
|
|
|
|
if (tkn) {
|
2012-01-31 19:28:01 +00:00
|
|
|
switch (tkn->value.type) {
|
|
|
|
case V_STR:
|
2001-10-14 23:17:26 +00:00
|
|
|
if (tkn->value.string)
|
|
|
|
free(tkn->value.string);
|
|
|
|
tkn->value.string = NULL;
|
|
|
|
break;
|
|
|
|
}
|
2012-11-04 17:18:59 +00:00
|
|
|
|
2001-10-14 23:17:26 +00:00
|
|
|
free(tkn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void free_tokens(int n, ...)
|
|
|
|
{
|
|
|
|
TOKEN * t;
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
va_start(ap, n);
|
|
|
|
while (n--) {
|
|
|
|
t = va_arg(ap, TOKEN *);
|
|
|
|
free_token(t);
|
|
|
|
}
|
|
|
|
va_end(ap);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
Prepare for new components in avrdude.conf incl prog_modes
- Add prog_modes to part and programmer definitions; prog_mode is a bitwise
or of programming modes
+ PM_SPM: Bootloaders, self-programming with SPM/NVM Controllers
+ PM_TPI: t4, t5, t9, t10, t20, t40, t102, t104
+ PM_ISP: SPI programming for In-System Programming (typ classic parts)
+ PM_PDI: Program and Debug Interface (xmega parts)
+ PM_UPDI: Unified Program and Debug Interface
+ PM_HVSP: High Voltage Serial Programming (some classic parts)
+ PM_HVPP: High Voltage Parallel Programming (most non-HVSP classic parts)
+ PM_debugWIRE: Simpler alternative to JTAG (a subset of HVPP/HVSP parts)
+ PM_JTAG: some classic parts, some xmega
+ PM_aWire: AVR32 parts
- Add mcuid, a unique id in 0..2039, to part definition for urclock programmer
- Add n_interrupts, the number of interrupts, to part definition
- Add n_page_erase to part definition (# of pages erased during NVM erase)
- Implement a simple calculator in config_gram.y so numeric values can be
expressed as simple expressions such as PM_SPM | PM_UPDI
- Introduce a new method of assigning simple components to the grammar without
touching config_gram.y via an eligible-component list in config.c; numeric
expressions on the rhs of an assignment resolve to integer values
- Update documentation in avrdude.conf.in and avrdude.texi
2022-08-30 01:08:15 +00:00
|
|
|
TOKEN *new_number(const char *text) {
|
2022-08-09 20:20:44 +00:00
|
|
|
struct token_t *tkn = new_token(TKN_NUMBER);
|
2001-10-14 23:17:26 +00:00
|
|
|
tkn->value.type = V_NUM;
|
2012-11-04 17:18:59 +00:00
|
|
|
tkn->value.number = atoi(text);
|
2001-10-14 23:17:26 +00:00
|
|
|
|
|
|
|
#if DEBUG
|
2014-06-13 20:07:40 +00:00
|
|
|
avrdude_message(MSG_INFO, "NUMBER(%d)\n", tkn->value.number);
|
2001-10-14 23:17:26 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return tkn;
|
|
|
|
}
|
|
|
|
|
Prepare for new components in avrdude.conf incl prog_modes
- Add prog_modes to part and programmer definitions; prog_mode is a bitwise
or of programming modes
+ PM_SPM: Bootloaders, self-programming with SPM/NVM Controllers
+ PM_TPI: t4, t5, t9, t10, t20, t40, t102, t104
+ PM_ISP: SPI programming for In-System Programming (typ classic parts)
+ PM_PDI: Program and Debug Interface (xmega parts)
+ PM_UPDI: Unified Program and Debug Interface
+ PM_HVSP: High Voltage Serial Programming (some classic parts)
+ PM_HVPP: High Voltage Parallel Programming (most non-HVSP classic parts)
+ PM_debugWIRE: Simpler alternative to JTAG (a subset of HVPP/HVSP parts)
+ PM_JTAG: some classic parts, some xmega
+ PM_aWire: AVR32 parts
- Add mcuid, a unique id in 0..2039, to part definition for urclock programmer
- Add n_interrupts, the number of interrupts, to part definition
- Add n_page_erase to part definition (# of pages erased during NVM erase)
- Implement a simple calculator in config_gram.y so numeric values can be
expressed as simple expressions such as PM_SPM | PM_UPDI
- Introduce a new method of assigning simple components to the grammar without
touching config_gram.y via an eligible-component list in config.c; numeric
expressions on the rhs of an assignment resolve to integer values
- Update documentation in avrdude.conf.in and avrdude.texi
2022-08-30 01:08:15 +00:00
|
|
|
TOKEN *new_number_real(const char *text) {
|
2022-08-09 20:20:44 +00:00
|
|
|
struct token_t * tkn = new_token(TKN_NUMBER);
|
2012-11-04 17:18:59 +00:00
|
|
|
tkn->value.type = V_NUM_REAL;
|
|
|
|
tkn->value.number_real = atof(text);
|
|
|
|
|
|
|
|
#if DEBUG
|
2014-06-13 20:07:40 +00:00
|
|
|
avrdude_message(MSG_INFO, "NUMBER(%g)\n", tkn->value.number_real);
|
2012-11-04 17:18:59 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return tkn;
|
|
|
|
}
|
2001-10-14 23:17:26 +00:00
|
|
|
|
Prepare for new components in avrdude.conf incl prog_modes
- Add prog_modes to part and programmer definitions; prog_mode is a bitwise
or of programming modes
+ PM_SPM: Bootloaders, self-programming with SPM/NVM Controllers
+ PM_TPI: t4, t5, t9, t10, t20, t40, t102, t104
+ PM_ISP: SPI programming for In-System Programming (typ classic parts)
+ PM_PDI: Program and Debug Interface (xmega parts)
+ PM_UPDI: Unified Program and Debug Interface
+ PM_HVSP: High Voltage Serial Programming (some classic parts)
+ PM_HVPP: High Voltage Parallel Programming (most non-HVSP classic parts)
+ PM_debugWIRE: Simpler alternative to JTAG (a subset of HVPP/HVSP parts)
+ PM_JTAG: some classic parts, some xmega
+ PM_aWire: AVR32 parts
- Add mcuid, a unique id in 0..2039, to part definition for urclock programmer
- Add n_interrupts, the number of interrupts, to part definition
- Add n_page_erase to part definition (# of pages erased during NVM erase)
- Implement a simple calculator in config_gram.y so numeric values can be
expressed as simple expressions such as PM_SPM | PM_UPDI
- Introduce a new method of assigning simple components to the grammar without
touching config_gram.y via an eligible-component list in config.c; numeric
expressions on the rhs of an assignment resolve to integer values
- Update documentation in avrdude.conf.in and avrdude.texi
2022-08-30 01:08:15 +00:00
|
|
|
TOKEN *new_hexnumber(const char *text) {
|
2022-08-09 20:20:44 +00:00
|
|
|
struct token_t *tkn = new_token(TKN_NUMBER);
|
2001-10-14 23:17:26 +00:00
|
|
|
char * e;
|
|
|
|
|
|
|
|
tkn->value.type = V_NUM;
|
|
|
|
tkn->value.number = strtoul(text, &e, 16);
|
|
|
|
if ((e == text) || (*e != 0)) {
|
2014-06-17 20:08:28 +00:00
|
|
|
yyerror("can't scan hex number \"%s\"", text);
|
2020-03-14 22:34:45 +00:00
|
|
|
free_token(tkn);
|
2014-06-17 20:08:28 +00:00
|
|
|
return NULL;
|
2001-10-14 23:17:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#if DEBUG
|
2014-06-13 20:07:40 +00:00
|
|
|
avrdude_message(MSG_INFO, "HEXNUMBER(%g)\n", tkn->value.number);
|
2001-10-14 23:17:26 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return tkn;
|
|
|
|
}
|
|
|
|
|
Prepare for new components in avrdude.conf incl prog_modes
- Add prog_modes to part and programmer definitions; prog_mode is a bitwise
or of programming modes
+ PM_SPM: Bootloaders, self-programming with SPM/NVM Controllers
+ PM_TPI: t4, t5, t9, t10, t20, t40, t102, t104
+ PM_ISP: SPI programming for In-System Programming (typ classic parts)
+ PM_PDI: Program and Debug Interface (xmega parts)
+ PM_UPDI: Unified Program and Debug Interface
+ PM_HVSP: High Voltage Serial Programming (some classic parts)
+ PM_HVPP: High Voltage Parallel Programming (most non-HVSP classic parts)
+ PM_debugWIRE: Simpler alternative to JTAG (a subset of HVPP/HVSP parts)
+ PM_JTAG: some classic parts, some xmega
+ PM_aWire: AVR32 parts
- Add mcuid, a unique id in 0..2039, to part definition for urclock programmer
- Add n_interrupts, the number of interrupts, to part definition
- Add n_page_erase to part definition (# of pages erased during NVM erase)
- Implement a simple calculator in config_gram.y so numeric values can be
expressed as simple expressions such as PM_SPM | PM_UPDI
- Introduce a new method of assigning simple components to the grammar without
touching config_gram.y via an eligible-component list in config.c; numeric
expressions on the rhs of an assignment resolve to integer values
- Update documentation in avrdude.conf.in and avrdude.texi
2022-08-30 01:08:15 +00:00
|
|
|
TOKEN *new_constant(const char *con) {
|
|
|
|
struct token_t *tkn = new_token(TKN_NUMBER);
|
|
|
|
int assigned = 1;
|
|
|
|
|
|
|
|
tkn->value.type = V_NUM;
|
|
|
|
tkn->value.number =
|
|
|
|
!strcmp("PM_SPM", con)? PM_SPM:
|
|
|
|
!strcmp("PM_TPI", con)? PM_TPI:
|
|
|
|
!strcmp("PM_ISP", con)? PM_ISP:
|
|
|
|
!strcmp("PM_PDI", con)? PM_PDI:
|
|
|
|
!strcmp("PM_UPDI", con)? PM_UPDI:
|
|
|
|
!strcmp("PM_HVSP", con)? PM_HVSP:
|
|
|
|
!strcmp("PM_HVPP", con)? PM_HVPP:
|
|
|
|
!strcmp("PM_debugWIRE", con)? PM_debugWIRE:
|
|
|
|
!strcmp("PM_JTAG", con)? PM_JTAG:
|
|
|
|
!strcmp("PM_aWire", con)? PM_aWire:
|
|
|
|
(assigned = 0);
|
|
|
|
|
|
|
|
if(!assigned) {
|
|
|
|
yyerror("can't identify constant %s", con);
|
|
|
|
free_token(tkn);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if DEBUG
|
|
|
|
avrdude_message(MSG_INFO, "CONSTANT(%s=%d)\n", con, tkn->value.number);
|
|
|
|
#endif
|
2001-10-14 23:17:26 +00:00
|
|
|
|
Prepare for new components in avrdude.conf incl prog_modes
- Add prog_modes to part and programmer definitions; prog_mode is a bitwise
or of programming modes
+ PM_SPM: Bootloaders, self-programming with SPM/NVM Controllers
+ PM_TPI: t4, t5, t9, t10, t20, t40, t102, t104
+ PM_ISP: SPI programming for In-System Programming (typ classic parts)
+ PM_PDI: Program and Debug Interface (xmega parts)
+ PM_UPDI: Unified Program and Debug Interface
+ PM_HVSP: High Voltage Serial Programming (some classic parts)
+ PM_HVPP: High Voltage Parallel Programming (most non-HVSP classic parts)
+ PM_debugWIRE: Simpler alternative to JTAG (a subset of HVPP/HVSP parts)
+ PM_JTAG: some classic parts, some xmega
+ PM_aWire: AVR32 parts
- Add mcuid, a unique id in 0..2039, to part definition for urclock programmer
- Add n_interrupts, the number of interrupts, to part definition
- Add n_page_erase to part definition (# of pages erased during NVM erase)
- Implement a simple calculator in config_gram.y so numeric values can be
expressed as simple expressions such as PM_SPM | PM_UPDI
- Introduce a new method of assigning simple components to the grammar without
touching config_gram.y via an eligible-component list in config.c; numeric
expressions on the rhs of an assignment resolve to integer values
- Update documentation in avrdude.conf.in and avrdude.texi
2022-08-30 01:08:15 +00:00
|
|
|
return tkn;
|
|
|
|
}
|
|
|
|
|
|
|
|
TOKEN *new_string(const char *text) {
|
2022-08-09 20:20:44 +00:00
|
|
|
struct token_t *tkn = new_token(TKN_STRING);
|
2001-10-14 23:17:26 +00:00
|
|
|
tkn->value.type = V_STR;
|
Prepare for new components in avrdude.conf incl prog_modes
- Add prog_modes to part and programmer definitions; prog_mode is a bitwise
or of programming modes
+ PM_SPM: Bootloaders, self-programming with SPM/NVM Controllers
+ PM_TPI: t4, t5, t9, t10, t20, t40, t102, t104
+ PM_ISP: SPI programming for In-System Programming (typ classic parts)
+ PM_PDI: Program and Debug Interface (xmega parts)
+ PM_UPDI: Unified Program and Debug Interface
+ PM_HVSP: High Voltage Serial Programming (some classic parts)
+ PM_HVPP: High Voltage Parallel Programming (most non-HVSP classic parts)
+ PM_debugWIRE: Simpler alternative to JTAG (a subset of HVPP/HVSP parts)
+ PM_JTAG: some classic parts, some xmega
+ PM_aWire: AVR32 parts
- Add mcuid, a unique id in 0..2039, to part definition for urclock programmer
- Add n_interrupts, the number of interrupts, to part definition
- Add n_page_erase to part definition (# of pages erased during NVM erase)
- Implement a simple calculator in config_gram.y so numeric values can be
expressed as simple expressions such as PM_SPM | PM_UPDI
- Introduce a new method of assigning simple components to the grammar without
touching config_gram.y via an eligible-component list in config.c; numeric
expressions on the rhs of an assignment resolve to integer values
- Update documentation in avrdude.conf.in and avrdude.texi
2022-08-30 01:08:15 +00:00
|
|
|
tkn->value.string = cfg_strdup("new_string()", text);
|
2001-10-14 23:17:26 +00:00
|
|
|
|
|
|
|
#if DEBUG
|
2014-06-13 20:07:40 +00:00
|
|
|
avrdude_message(MSG_INFO, "STRING(%s)\n", tkn->value.string);
|
2001-10-14 23:17:26 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return tkn;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
Prepare for new components in avrdude.conf incl prog_modes
- Add prog_modes to part and programmer definitions; prog_mode is a bitwise
or of programming modes
+ PM_SPM: Bootloaders, self-programming with SPM/NVM Controllers
+ PM_TPI: t4, t5, t9, t10, t20, t40, t102, t104
+ PM_ISP: SPI programming for In-System Programming (typ classic parts)
+ PM_PDI: Program and Debug Interface (xmega parts)
+ PM_UPDI: Unified Program and Debug Interface
+ PM_HVSP: High Voltage Serial Programming (some classic parts)
+ PM_HVPP: High Voltage Parallel Programming (most non-HVSP classic parts)
+ PM_debugWIRE: Simpler alternative to JTAG (a subset of HVPP/HVSP parts)
+ PM_JTAG: some classic parts, some xmega
+ PM_aWire: AVR32 parts
- Add mcuid, a unique id in 0..2039, to part definition for urclock programmer
- Add n_interrupts, the number of interrupts, to part definition
- Add n_page_erase to part definition (# of pages erased during NVM erase)
- Implement a simple calculator in config_gram.y so numeric values can be
expressed as simple expressions such as PM_SPM | PM_UPDI
- Introduce a new method of assigning simple components to the grammar without
touching config_gram.y via an eligible-component list in config.c; numeric
expressions on the rhs of an assignment resolve to integer values
- Update documentation in avrdude.conf.in and avrdude.texi
2022-08-30 01:08:15 +00:00
|
|
|
TOKEN *new_keyword(int primary) {
|
2022-08-09 20:20:44 +00:00
|
|
|
return new_token(primary);
|
2001-10-14 23:17:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void print_token(TOKEN * tkn)
|
|
|
|
{
|
|
|
|
if (!tkn)
|
|
|
|
return;
|
|
|
|
|
2014-06-13 20:07:40 +00:00
|
|
|
avrdude_message(MSG_INFO, "token = %d = ", tkn->primary);
|
2012-01-31 19:28:01 +00:00
|
|
|
switch (tkn->value.type) {
|
2012-11-04 17:18:59 +00:00
|
|
|
case V_NUM:
|
2014-06-13 20:07:40 +00:00
|
|
|
avrdude_message(MSG_INFO, "NUMBER, value=%d", tkn->value.number);
|
2012-11-04 17:18:59 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case V_NUM_REAL:
|
2014-06-13 20:07:40 +00:00
|
|
|
avrdude_message(MSG_INFO, "NUMBER, value=%g", tkn->value.number_real);
|
2001-10-14 23:17:26 +00:00
|
|
|
break;
|
|
|
|
|
2012-11-04 17:18:59 +00:00
|
|
|
case V_STR:
|
2014-06-13 20:07:40 +00:00
|
|
|
avrdude_message(MSG_INFO, "STRING, value=%s", tkn->value.string);
|
2001-10-14 23:17:26 +00:00
|
|
|
break;
|
|
|
|
|
2012-11-04 17:18:59 +00:00
|
|
|
default:
|
2014-06-13 20:07:40 +00:00
|
|
|
avrdude_message(MSG_INFO, "<other>");
|
2001-10-14 23:17:26 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-06-13 20:07:40 +00:00
|
|
|
avrdude_message(MSG_INFO, "\n");
|
2001-10-14 23:17:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void pyytext(void)
|
|
|
|
{
|
|
|
|
#if DEBUG
|
2014-06-13 20:07:40 +00:00
|
|
|
avrdude_message(MSG_INFO, "TOKEN: \"%s\"\n", yytext);
|
2001-10-14 23:17:26 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-01-31 17:03:43 +00:00
|
|
|
#ifdef HAVE_YYLEX_DESTROY
|
|
|
|
/* reset lexer and free any allocated memory */
|
|
|
|
extern int yylex_destroy(void);
|
|
|
|
#endif
|
|
|
|
|
2007-01-30 13:41:54 +00:00
|
|
|
int read_config(const char * file)
|
2007-01-24 22:43:46 +00:00
|
|
|
{
|
|
|
|
FILE * f;
|
2014-06-17 20:08:28 +00:00
|
|
|
int r;
|
2007-01-24 22:43:46 +00:00
|
|
|
|
2022-07-18 17:10:09 +00:00
|
|
|
if(!(cfg_infile = realpath(file, NULL))) {
|
|
|
|
avrdude_message(MSG_INFO, "%s: can't determine realpath() of config file \"%s\": %s\n",
|
|
|
|
progname, file, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
f = fopen(cfg_infile, "r");
|
2007-01-24 22:43:46 +00:00
|
|
|
if (f == NULL) {
|
2014-06-13 20:07:40 +00:00
|
|
|
avrdude_message(MSG_INFO, "%s: can't open config file \"%s\": %s\n",
|
2022-07-18 17:10:09 +00:00
|
|
|
progname, cfg_infile, strerror(errno));
|
|
|
|
free(cfg_infile);
|
|
|
|
cfg_infile = NULL;
|
2007-01-24 22:43:46 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-07-18 17:10:09 +00:00
|
|
|
cfg_lineno = 1;
|
2007-01-24 22:43:46 +00:00
|
|
|
yyin = f;
|
|
|
|
|
2014-06-17 20:08:28 +00:00
|
|
|
r = yyparse();
|
2007-01-24 22:43:46 +00:00
|
|
|
|
2012-01-17 20:56:37 +00:00
|
|
|
#ifdef HAVE_YYLEX_DESTROY
|
|
|
|
/* reset lexer and free any allocated memory */
|
|
|
|
yylex_destroy();
|
|
|
|
#endif
|
|
|
|
|
2007-01-24 22:43:46 +00:00
|
|
|
fclose(f);
|
|
|
|
|
2022-07-18 17:10:09 +00:00
|
|
|
if(cfg_infile) {
|
|
|
|
free(cfg_infile);
|
|
|
|
cfg_infile = NULL;
|
|
|
|
}
|
|
|
|
|
2014-06-17 20:08:28 +00:00
|
|
|
return r;
|
2007-01-24 22:43:46 +00:00
|
|
|
}
|
2022-07-18 17:10:09 +00:00
|
|
|
|
|
|
|
|
Replace string arrays with const char * and allocated space (part 2)
This commit replaces fixed-string buffers in PROGRAMMER, AVRPART and AVRMEM
that are dealt with by the parser and grammar. Now, string assignments are
always to const char *, ie, these are read-only strings with arbitrary
length.
config_gram.y now only needs to consider one type of string assignment.
This commit also
- Replaces the simple linear-search cache_string() function with faster
hashed cache_string(). Either way, the returned value is likely to be
shared, so should never be free()'d.
- Duplicates hvupdi_support list in pgm_dup() and frees it in pgm_free()
- Adds const qualifier to some function args in avrpart.c and pgm.c
- Hardens some functions against being called with NULL pointers
- Ensures _new() and _dup() functions for parts, programmers and memory
return a suitable memory. Out of memory triggers exit in one of three
functions, cfg_malloc(), cfg_realloc() and cfg_strdup(); there is
rarely anything useful that AVRDUDE or, for that matter, any
application compiled against libavrdude can do once you run out of
memory as AVRDUDE/libavrdude rely heavily on allocation of memory.
2022-08-10 15:14:56 +00:00
|
|
|
// Adapted version of a neat empirical hash function from comp.lang.c by Daniel Bernstein
|
|
|
|
unsigned strhash(const char *str) {
|
|
|
|
unsigned c, hash = 5381, n = 0;
|
2022-07-18 17:10:09 +00:00
|
|
|
|
Replace string arrays with const char * and allocated space (part 2)
This commit replaces fixed-string buffers in PROGRAMMER, AVRPART and AVRMEM
that are dealt with by the parser and grammar. Now, string assignments are
always to const char *, ie, these are read-only strings with arbitrary
length.
config_gram.y now only needs to consider one type of string assignment.
This commit also
- Replaces the simple linear-search cache_string() function with faster
hashed cache_string(). Either way, the returned value is likely to be
shared, so should never be free()'d.
- Duplicates hvupdi_support list in pgm_dup() and frees it in pgm_free()
- Adds const qualifier to some function args in avrpart.c and pgm.c
- Hardens some functions against being called with NULL pointers
- Ensures _new() and _dup() functions for parts, programmers and memory
return a suitable memory. Out of memory triggers exit in one of three
functions, cfg_malloc(), cfg_realloc() and cfg_strdup(); there is
rarely anything useful that AVRDUDE or, for that matter, any
application compiled against libavrdude can do once you run out of
memory as AVRDUDE/libavrdude rely heavily on allocation of memory.
2022-08-10 15:14:56 +00:00
|
|
|
while((c = (unsigned char) *str++) && n++ < 20)
|
|
|
|
hash = 33*hash ^ c;
|
|
|
|
|
|
|
|
return hash;
|
|
|
|
}
|
2022-07-18 17:10:09 +00:00
|
|
|
|
|
|
|
|
Replace string arrays with const char * and allocated space (part 2)
This commit replaces fixed-string buffers in PROGRAMMER, AVRPART and AVRMEM
that are dealt with by the parser and grammar. Now, string assignments are
always to const char *, ie, these are read-only strings with arbitrary
length.
config_gram.y now only needs to consider one type of string assignment.
This commit also
- Replaces the simple linear-search cache_string() function with faster
hashed cache_string(). Either way, the returned value is likely to be
shared, so should never be free()'d.
- Duplicates hvupdi_support list in pgm_dup() and frees it in pgm_free()
- Adds const qualifier to some function args in avrpart.c and pgm.c
- Hardens some functions against being called with NULL pointers
- Ensures _new() and _dup() functions for parts, programmers and memory
return a suitable memory. Out of memory triggers exit in one of three
functions, cfg_malloc(), cfg_realloc() and cfg_strdup(); there is
rarely anything useful that AVRDUDE or, for that matter, any
application compiled against libavrdude can do once you run out of
memory as AVRDUDE/libavrdude rely heavily on allocation of memory.
2022-08-10 15:14:56 +00:00
|
|
|
static char **hstrings[1<<12];
|
|
|
|
|
|
|
|
// Return a copy of the argument as hashed string
|
|
|
|
const char *cache_string(const char *p) {
|
|
|
|
int h, k;
|
|
|
|
char **hs;
|
|
|
|
|
|
|
|
if(!p)
|
|
|
|
p = "(NULL)";
|
2022-07-18 17:10:09 +00:00
|
|
|
|
Replace string arrays with const char * and allocated space (part 2)
This commit replaces fixed-string buffers in PROGRAMMER, AVRPART and AVRMEM
that are dealt with by the parser and grammar. Now, string assignments are
always to const char *, ie, these are read-only strings with arbitrary
length.
config_gram.y now only needs to consider one type of string assignment.
This commit also
- Replaces the simple linear-search cache_string() function with faster
hashed cache_string(). Either way, the returned value is likely to be
shared, so should never be free()'d.
- Duplicates hvupdi_support list in pgm_dup() and frees it in pgm_free()
- Adds const qualifier to some function args in avrpart.c and pgm.c
- Hardens some functions against being called with NULL pointers
- Ensures _new() and _dup() functions for parts, programmers and memory
return a suitable memory. Out of memory triggers exit in one of three
functions, cfg_malloc(), cfg_realloc() and cfg_strdup(); there is
rarely anything useful that AVRDUDE or, for that matter, any
application compiled against libavrdude can do once you run out of
memory as AVRDUDE/libavrdude rely heavily on allocation of memory.
2022-08-10 15:14:56 +00:00
|
|
|
h = strhash(p) % (sizeof hstrings/sizeof*hstrings);
|
|
|
|
if(!(hs=hstrings[h]))
|
|
|
|
hs = hstrings[h] = (char **) cfg_realloc("cache_string()", NULL, (16+1)*sizeof**hstrings);
|
2022-07-18 17:10:09 +00:00
|
|
|
|
Replace string arrays with const char * and allocated space (part 2)
This commit replaces fixed-string buffers in PROGRAMMER, AVRPART and AVRMEM
that are dealt with by the parser and grammar. Now, string assignments are
always to const char *, ie, these are read-only strings with arbitrary
length.
config_gram.y now only needs to consider one type of string assignment.
This commit also
- Replaces the simple linear-search cache_string() function with faster
hashed cache_string(). Either way, the returned value is likely to be
shared, so should never be free()'d.
- Duplicates hvupdi_support list in pgm_dup() and frees it in pgm_free()
- Adds const qualifier to some function args in avrpart.c and pgm.c
- Hardens some functions against being called with NULL pointers
- Ensures _new() and _dup() functions for parts, programmers and memory
return a suitable memory. Out of memory triggers exit in one of three
functions, cfg_malloc(), cfg_realloc() and cfg_strdup(); there is
rarely anything useful that AVRDUDE or, for that matter, any
application compiled against libavrdude can do once you run out of
memory as AVRDUDE/libavrdude rely heavily on allocation of memory.
2022-08-10 15:14:56 +00:00
|
|
|
for(k=0; hs[k]; k++)
|
|
|
|
if(*p == *hs[k] && !strcmp(p, hs[k]))
|
|
|
|
return hs[k];
|
|
|
|
|
|
|
|
if(k && k%16 == 0)
|
|
|
|
hstrings[h] = (char **) cfg_realloc("cache_string()", hstrings[h], (k+16+1)*sizeof**hstrings);
|
|
|
|
|
|
|
|
hstrings[h][k+1]=NULL;
|
|
|
|
|
|
|
|
return hstrings[h][k] = cfg_strdup("cache_string()", p);
|
2022-07-18 17:10:09 +00:00
|
|
|
}
|
2022-08-08 15:52:09 +00:00
|
|
|
|
2022-08-11 23:28:54 +00:00
|
|
|
|
|
|
|
static LISTID cfg_comms; // A chain of comment lines
|
|
|
|
static LISTID cfg_prologue; // Comment lines at start of avrdude.conf
|
|
|
|
static char *lkw; // Last seen keyword
|
|
|
|
static int lkw_lineno; // Line number of that
|
|
|
|
|
|
|
|
static LISTID cfg_strctcomms; // Passed on to config_gram.y
|
|
|
|
static LISTID cfg_pushedcomms; // Temporarily pushed main comments
|
|
|
|
static int cfg_pushed; // ... for memory sections
|
|
|
|
|
|
|
|
COMMENT *locate_comment(const LISTID comments, const char *where, int rhs) {
|
|
|
|
if(comments)
|
|
|
|
for(LNODEID ln=lfirst(comments); ln; ln=lnext(ln)) {
|
|
|
|
COMMENT *n = ldata(ln);
|
|
|
|
if(n && rhs == n->rhs && n->kw && strcmp(where, n->kw) == 0)
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void addcomment(int rhs) {
|
|
|
|
if(lkw) {
|
|
|
|
COMMENT *node = cfg_malloc("addcomment()", sizeof(*node));
|
|
|
|
node->rhs = rhs;
|
|
|
|
node->kw = cfg_strdup("addcomment()", lkw);
|
|
|
|
node->comms = cfg_comms;
|
|
|
|
cfg_comms = NULL;
|
|
|
|
if(!cfg_strctcomms)
|
|
|
|
cfg_strctcomms = lcreat(NULL, 0);
|
|
|
|
ladd(cfg_strctcomms, node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Capture prologue during parsing (triggered by lexer.l)
|
|
|
|
void cfg_capture_prologue(void) {
|
|
|
|
cfg_prologue = cfg_comms;
|
|
|
|
cfg_comms = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
LISTID cfg_get_prologue(void) {
|
|
|
|
return cfg_prologue;
|
|
|
|
}
|
|
|
|
|
2022-08-08 15:52:09 +00:00
|
|
|
// Captures comments during parsing
|
2022-08-11 23:28:54 +00:00
|
|
|
void capture_comment_str(const char *com, int lineno) {
|
|
|
|
if(!cfg_comms)
|
|
|
|
cfg_comms = lcreat(NULL, 0);
|
|
|
|
ladd(cfg_comms, cfg_strdup("capture_comment_str()", com));
|
|
|
|
|
|
|
|
// Last keyword lineno is the same as this comment's
|
|
|
|
if(lkw && lkw_lineno == lineno)
|
|
|
|
addcomment(1); // Register comms to show right of lkw = ...;
|
2022-08-08 15:52:09 +00:00
|
|
|
}
|
2022-08-09 20:20:44 +00:00
|
|
|
|
2022-08-11 23:28:54 +00:00
|
|
|
// Capture assignments (keywords left of =) and associate comments to them
|
|
|
|
void capture_lvalue_kw(const char *kw, int lineno) {
|
|
|
|
if(!strcmp(kw, "memory")) { // Push part comments and start memory comments
|
|
|
|
if(!cfg_pushed) { // config_gram.y pops the part comments
|
|
|
|
cfg_pushed = 1;
|
|
|
|
cfg_pushedcomms = cfg_strctcomms;
|
|
|
|
cfg_strctcomms = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!strcmp(kw, "programmer") || !strcmp(kw, "part") || !strcmp(kw, "memory"))
|
|
|
|
kw = "*"; // Show comment before programmer/part/memory
|
|
|
|
|
|
|
|
if(lkw)
|
|
|
|
free(lkw);
|
|
|
|
lkw = cfg_strdup("capture_lvalue_kw()", kw);
|
|
|
|
lkw_lineno = lineno;
|
|
|
|
if(cfg_comms) // Accrued list of # one-line comments
|
|
|
|
addcomment(0); // Register comment to appear before lkw assignment
|
|
|
|
}
|
|
|
|
|
|
|
|
// config_gram.y calls this once for each programmer/part/memory structure
|
|
|
|
LISTID cfg_move_comments(void) {
|
|
|
|
capture_lvalue_kw(";", -1);
|
|
|
|
|
|
|
|
LISTID ret = cfg_strctcomms;
|
|
|
|
cfg_strctcomms = NULL;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// config_gram.y calls this after ingressing the memory structure
|
|
|
|
void cfg_pop_comms(void) {
|
|
|
|
if(cfg_pushed) {
|
|
|
|
cfg_pushed = 0;
|
|
|
|
cfg_strctcomms = cfg_pushedcomms;
|
|
|
|
}
|
|
|
|
}
|
2022-08-09 20:20:44 +00:00
|
|
|
|
|
|
|
// Convert the next n hex digits of s to a hex number
|
|
|
|
static unsigned int tohex(const unsigned char *s, unsigned int n) {
|
|
|
|
int ret, c;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
while(n--) {
|
|
|
|
ret *= 16;
|
|
|
|
c = *s++;
|
|
|
|
ret += c >= '0' && c <= '9'? c - '0': c >= 'a' && c <= 'f'? c - 'a' + 10: c - 'A' + 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create a utf-8 character sequence from a single unicode character.
|
|
|
|
* Permissive for some invalid unicode sequences but not for those with
|
|
|
|
* high bit set). Returns numbers of characters written (0-6).
|
|
|
|
*/
|
|
|
|
static int wc_to_utf8str(unsigned int wc, unsigned char *str) {
|
|
|
|
if(!(wc & ~0x7fu)) {
|
|
|
|
*str = (char) wc;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if(!(wc & ~0x7ffu)) {
|
|
|
|
*str++ = (char) ((wc >> 6) | 0xc0);
|
|
|
|
*str++ = (char) ((wc & 0x3f) | 0x80);
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
if(!(wc & ~0xffffu)) {
|
|
|
|
*str++ = (char) ((wc >> 12) | 0xe0);
|
|
|
|
*str++ = (char) (((wc >> 6) & 0x3f) | 0x80);
|
|
|
|
*str++ = (char) ((wc & 0x3f) | 0x80);
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
if(!(wc & ~0x1fffffu)) {
|
|
|
|
*str++ = (char) ((wc >> 18) | 0xf0);
|
|
|
|
*str++ = (char) (((wc >> 12) & 0x3f) | 0x80);
|
|
|
|
*str++ = (char) (((wc >> 6) & 0x3f) | 0x80);
|
|
|
|
*str++ = (char) ((wc & 0x3f) | 0x80);
|
|
|
|
return 4;
|
|
|
|
}
|
|
|
|
if(!(wc & ~0x3ffffffu)) {
|
|
|
|
*str++ = (char) ((wc >> 24) | 0xf8);
|
|
|
|
*str++ = (char) (((wc >> 18) & 0x3f) | 0x80);
|
|
|
|
*str++ = (char) (((wc >> 12) & 0x3f) | 0x80);
|
|
|
|
*str++ = (char) (((wc >> 6) & 0x3f) | 0x80);
|
|
|
|
*str++ = (char) ((wc & 0x3f) | 0x80);
|
|
|
|
return 5;
|
|
|
|
}
|
|
|
|
if(!(wc & ~0x7fffffffu)) {
|
|
|
|
*str++ = (char) ((wc >> 30) | 0xfc);
|
|
|
|
*str++ = (char) (((wc >> 24) & 0x3f) | 0x80);
|
|
|
|
*str++ = (char) (((wc >> 18) & 0x3f) | 0x80);
|
|
|
|
*str++ = (char) (((wc >> 12) & 0x3f) | 0x80);
|
|
|
|
*str++ = (char) (((wc >> 6) & 0x3f) | 0x80);
|
|
|
|
*str++ = (char) ((wc & 0x3f) | 0x80);
|
|
|
|
return 6;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unescape C-style strings, destination d must hold enough space (and can be source s)
|
|
|
|
unsigned char *cfg_unescapeu(unsigned char *d, const unsigned char *s) {
|
|
|
|
unsigned char *ret = d;
|
|
|
|
int n, k;
|
|
|
|
|
|
|
|
while(*s) {
|
|
|
|
switch (*s) {
|
|
|
|
case '\\':
|
|
|
|
switch (*++s) {
|
Replace string arrays with const char * and allocated space (part 2)
This commit replaces fixed-string buffers in PROGRAMMER, AVRPART and AVRMEM
that are dealt with by the parser and grammar. Now, string assignments are
always to const char *, ie, these are read-only strings with arbitrary
length.
config_gram.y now only needs to consider one type of string assignment.
This commit also
- Replaces the simple linear-search cache_string() function with faster
hashed cache_string(). Either way, the returned value is likely to be
shared, so should never be free()'d.
- Duplicates hvupdi_support list in pgm_dup() and frees it in pgm_free()
- Adds const qualifier to some function args in avrpart.c and pgm.c
- Hardens some functions against being called with NULL pointers
- Ensures _new() and _dup() functions for parts, programmers and memory
return a suitable memory. Out of memory triggers exit in one of three
functions, cfg_malloc(), cfg_realloc() and cfg_strdup(); there is
rarely anything useful that AVRDUDE or, for that matter, any
application compiled against libavrdude can do once you run out of
memory as AVRDUDE/libavrdude rely heavily on allocation of memory.
2022-08-10 15:14:56 +00:00
|
|
|
case '\n': // String continuation over new line
|
|
|
|
#if '\n' != '\r'
|
|
|
|
case '\r':
|
|
|
|
#endif
|
|
|
|
--d;
|
|
|
|
break;
|
2022-08-09 20:20:44 +00:00
|
|
|
case 'n':
|
|
|
|
*d = '\n';
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
*d = '\t';
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
|
|
*d = '\a';
|
|
|
|
break;
|
|
|
|
case 'b':
|
|
|
|
*d = '\b';
|
|
|
|
break;
|
|
|
|
case 'e': // Non-standard ESC
|
|
|
|
*d = 27;
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
*d = '\f';
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
*d = '\r';
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
*d = '\v';
|
|
|
|
break;
|
|
|
|
case '?':
|
|
|
|
*d = '?';
|
|
|
|
break;
|
|
|
|
case '`':
|
|
|
|
*d = '`';
|
|
|
|
break;
|
|
|
|
case '"':
|
|
|
|
*d = '"';
|
|
|
|
break;
|
|
|
|
case '\'':
|
|
|
|
*d = '\'';
|
|
|
|
break;
|
|
|
|
case '\\':
|
|
|
|
*d = '\\';
|
|
|
|
break;
|
|
|
|
case '0':
|
|
|
|
case '1':
|
|
|
|
case '2':
|
|
|
|
case '3':
|
|
|
|
case '4':
|
|
|
|
case '5':
|
|
|
|
case '6':
|
|
|
|
case '7': // 1-3 octal digits
|
|
|
|
n = *s - '0';
|
|
|
|
for(k = 0; k < 2 && s[1] >= '0' && s[1] <= '7'; k++) // Max 2 more octal characters
|
|
|
|
n *= 8, n += s[1] - '0', s++;
|
|
|
|
*d = n;
|
|
|
|
break;
|
|
|
|
case 'x': // Unlimited hex digits
|
|
|
|
for(k = 0; isxdigit(s[k + 1]); k++)
|
|
|
|
continue;
|
|
|
|
if(k > 0) {
|
|
|
|
*d = tohex(s + 1, k);
|
|
|
|
s += k;
|
|
|
|
} else { // No hex digits after \x? copy \x
|
|
|
|
*d++ = '\\';
|
|
|
|
*d = 'x';
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'u': // Exactly 4 hex digits and valid unicode
|
|
|
|
if(isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]) && isxdigit(s[4]) &&
|
|
|
|
(n = wc_to_utf8str(tohex(s+1, 4), d))) {
|
|
|
|
d += n - 1;
|
|
|
|
s += 4;
|
|
|
|
} else { // Invalid \u sequence? copy \u
|
|
|
|
*d++ = '\\';
|
|
|
|
*d = 'u';
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'U': // Exactly 6 hex digits and valid unicode
|
|
|
|
if(isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]) && isxdigit(s[4]) && isxdigit(s[5]) && isxdigit(s[6]) &&
|
|
|
|
(n = wc_to_utf8str(tohex(s+1, 6), d))) {
|
|
|
|
d += n - 1;
|
|
|
|
s += 6;
|
|
|
|
} else { // Invalid \U sequence? copy \U
|
|
|
|
*d++ = '\\';
|
|
|
|
*d = 'U';
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default: // Keep the escape sequence (C would warn and remove \)
|
|
|
|
*d++ = '\\';
|
|
|
|
*d = *s;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default: // Not an escape sequence: just copy the character
|
|
|
|
*d = *s;
|
|
|
|
}
|
|
|
|
d++;
|
|
|
|
s++;
|
|
|
|
}
|
|
|
|
*d = *s; // Terminate
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unescape C-style strings, destination d must hold enough space (and can be source s)
|
|
|
|
char *cfg_unescape(char *d, const char *s) {
|
|
|
|
return (char *) cfg_unescapeu((unsigned char *) d, (const unsigned char *) s);
|
|
|
|
}
|
|
|
|
|
2022-08-11 23:28:54 +00:00
|
|
|
// Return an escaped string that looks like a C-style input string incl quotes, memory is malloc'd
|
2022-08-09 20:20:44 +00:00
|
|
|
char *cfg_escape(const char *s) {
|
2022-08-11 23:28:54 +00:00
|
|
|
char buf[50*1024], *d = buf;
|
2022-08-09 20:20:44 +00:00
|
|
|
|
|
|
|
*d++ = '"';
|
2022-08-11 23:28:54 +00:00
|
|
|
for(; *s && d-buf < sizeof buf-7; s++) {
|
2022-08-09 20:20:44 +00:00
|
|
|
switch(*s) {
|
|
|
|
case '\n':
|
|
|
|
*d++ = '\\'; *d++ = 'n';
|
|
|
|
break;
|
|
|
|
case '\t':
|
|
|
|
*d++ = '\\'; *d++ = 't';
|
|
|
|
break;
|
|
|
|
case '\a':
|
|
|
|
*d++ = '\\'; *d++ = 'a';
|
|
|
|
break;
|
|
|
|
case '\b':
|
|
|
|
*d++ = '\\'; *d++ = 'b';
|
|
|
|
break;
|
|
|
|
case '\f':
|
|
|
|
*d++ = '\\'; *d++ = 'f';
|
|
|
|
break;
|
|
|
|
#if '\r' != '\n'
|
|
|
|
case '\r':
|
|
|
|
*d++ = '\\'; *d++ = 'r';
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
case '\v':
|
|
|
|
*d++ = '\\'; *d++ = 'v';
|
|
|
|
break;
|
|
|
|
case '\"':
|
|
|
|
*d++ = '\\'; *d++ = '\"';
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if(*s == 0x7f || (*s >= 0 && *s < 32)) {
|
|
|
|
sprintf(d, "\\%03o", *s);
|
|
|
|
d += strlen(d);
|
|
|
|
} else
|
|
|
|
*d++ = *s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*d++ = '"';
|
|
|
|
*d = 0;
|
|
|
|
|
2022-08-11 23:28:54 +00:00
|
|
|
return cfg_strdup("cfg_escape()", buf);
|
2022-08-09 20:20:44 +00:00
|
|
|
}
|
Prepare for new components in avrdude.conf incl prog_modes
- Add prog_modes to part and programmer definitions; prog_mode is a bitwise
or of programming modes
+ PM_SPM: Bootloaders, self-programming with SPM/NVM Controllers
+ PM_TPI: t4, t5, t9, t10, t20, t40, t102, t104
+ PM_ISP: SPI programming for In-System Programming (typ classic parts)
+ PM_PDI: Program and Debug Interface (xmega parts)
+ PM_UPDI: Unified Program and Debug Interface
+ PM_HVSP: High Voltage Serial Programming (some classic parts)
+ PM_HVPP: High Voltage Parallel Programming (most non-HVSP classic parts)
+ PM_debugWIRE: Simpler alternative to JTAG (a subset of HVPP/HVSP parts)
+ PM_JTAG: some classic parts, some xmega
+ PM_aWire: AVR32 parts
- Add mcuid, a unique id in 0..2039, to part definition for urclock programmer
- Add n_interrupts, the number of interrupts, to part definition
- Add n_page_erase to part definition (# of pages erased during NVM erase)
- Implement a simple calculator in config_gram.y so numeric values can be
expressed as simple expressions such as PM_SPM | PM_UPDI
- Introduce a new method of assigning simple components to the grammar without
touching config_gram.y via an eligible-component list in config.c; numeric
expressions on the rhs of an assignment resolve to integer values
- Update documentation in avrdude.conf.in and avrdude.texi
2022-08-30 01:08:15 +00:00
|
|
|
|
|
|
|
|
|
|
|
static int cmp_comp(const void *v1, const void *v2) {
|
|
|
|
const Component_t *c1 = v1, *c2 = v2;
|
|
|
|
int ret = strcmp(c1->name, c2->name);
|
|
|
|
|
|
|
|
return ret? ret: c1->strct - c2->strct;
|
|
|
|
}
|
|
|
|
|
|
|
|
Component_t *cfg_comp_search(const char *name, int strct) {
|
|
|
|
static int init;
|
|
|
|
Component_t key;
|
|
|
|
|
|
|
|
if(!init++)
|
|
|
|
qsort(avr_comp, sizeof avr_comp/sizeof*avr_comp, sizeof(Component_t), cmp_comp);
|
|
|
|
|
|
|
|
|
|
|
|
key.name = name;
|
|
|
|
key.strct = strct;
|
|
|
|
return bsearch(&key, avr_comp, sizeof avr_comp/sizeof*avr_comp, sizeof(Component_t), cmp_comp);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const char *cfg_strct_name(int strct) {
|
|
|
|
switch(strct) {
|
|
|
|
case COMP_CONFIG_MAIN: return "avrdude.conf main";
|
|
|
|
case COMP_AVRPART: return "AVRPART";
|
|
|
|
case COMP_AVRMEM: return "AVRMEM";
|
|
|
|
case COMP_PROGRAMMER: return "PROGRAMMER";
|
|
|
|
}
|
|
|
|
return "unknown struct";
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *cfg_v_type(int type) {
|
|
|
|
switch(type) {
|
|
|
|
case V_NONE: return "void";
|
|
|
|
case V_NUM: return "number";
|
|
|
|
case V_NUM_REAL: return "real";
|
|
|
|
case V_STR: return "string";
|
|
|
|
case V_COMPONENT: return "component";
|
|
|
|
}
|
|
|
|
return "unknown v type";
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *cfg_comp_type(int type) {
|
|
|
|
switch(type) {
|
|
|
|
case COMP_INT: return "number";
|
|
|
|
case COMP_SHORT: return "short";
|
|
|
|
case COMP_CHAR: return "char";
|
|
|
|
case COMP_STRING: return "string";
|
|
|
|
case COMP_CHAR_ARRAY: return "byte array";
|
|
|
|
case COMP_INT_LISTID: return "number list";
|
|
|
|
case COMP_STRING_LISTID: return "string list";
|
|
|
|
case COMP_OPCODE: return "opcode";
|
|
|
|
case COMP_PIN: return "pin";
|
|
|
|
case COMP_PIN_LIST: return "pin list";
|
|
|
|
}
|
|
|
|
return "unknown comp type";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Used by config_gram.y to assign a component in one of the relevant structures with a value
|
|
|
|
void cfg_assign(char *sp, int strct, Component_t *cp, VALUE *v) {
|
|
|
|
const char *str;
|
|
|
|
int num;
|
|
|
|
|
|
|
|
switch(cp->type) {
|
|
|
|
case COMP_CHAR:
|
|
|
|
case COMP_SHORT:
|
|
|
|
case COMP_INT:
|
|
|
|
if(v->type != V_NUM) {
|
|
|
|
yywarning("%s in %s expects a %s but is assigned a %s",
|
|
|
|
cp->name, cfg_strct_name(strct), cfg_comp_type(cp->type), cfg_v_type(v->type));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// TODO: consider endianess (code currently assumes little endian)
|
|
|
|
num = v->number;
|
|
|
|
memcpy(sp+cp->offset, &num, cp->size);
|
|
|
|
break;
|
|
|
|
case COMP_STRING:
|
|
|
|
if(v->type != V_STR) {
|
|
|
|
yywarning("%s in %s expects a string but is assigned a %s",
|
|
|
|
cp->name, cfg_strct_name(strct), cfg_v_type(v->type));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
str = cache_string(v->string);
|
|
|
|
memcpy(sp+cp->offset, &str, cp->size);
|
|
|
|
break;
|
|
|
|
// TODO: implement COMP_CHAR_ARRAY, COMP_INT_LISTID, COMP_STRING_LISTID, ...
|
|
|
|
default:
|
|
|
|
yywarning("%s in %s expects a %s but that is not implemented",
|
|
|
|
cp->name, cfg_strct_name(strct), cfg_comp_type(cp->type));
|
|
|
|
}
|
|
|
|
}
|
2022-08-30 18:48:17 +00:00
|
|
|
|
|
|
|
// Automatically assign an mcuid if known from avrintel.c table
|
|
|
|
void cfg_update_mcuid(AVRPART *part) {
|
|
|
|
// Don't assign an mcuid for template parts that has a space in desc
|
|
|
|
if(!part->desc || *part->desc == 0 || strchr(part->desc, ' '))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Don't assign an mcuid for template parts where id starts with "."
|
|
|
|
if(!part->id || !*part->id || *part->id == '.')
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Don't assign an mcuid for 32-bit AVR parts
|
|
|
|
if(part->prog_modes & PM_aWire)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Find an entry that shares the same name
|
|
|
|
for(int i=0; i < sizeof uP_table/sizeof *uP_table; i++) {
|
|
|
|
if(strcasecmp(part->desc, uP_table[i].name) == 0) {
|
|
|
|
if(part->mcuid != (int) uP_table[i].mcuid) {
|
|
|
|
part->mcuid = uP_table[i].mcuid;
|
|
|
|
yywarning("assigned mcuid = %d to part %s", part->mcuid, part->desc);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-31 10:59:19 +00:00
|
|
|
// None have the same name: an entry with part->mcuid might be an error
|
2022-08-30 18:48:17 +00:00
|
|
|
for(int i=0; i < sizeof uP_table/sizeof *uP_table; i++)
|
|
|
|
if(part->mcuid == (int) uP_table[i].mcuid) {
|
2022-08-31 10:59:19 +00:00
|
|
|
// Complain unless it can be considered a variant, eg, ATmega32L and ATmega32
|
|
|
|
AVRMEM *flash = avr_locate_mem(part, "flash");
|
|
|
|
if(flash) {
|
|
|
|
size_t l1 = strlen(part->desc), l2 = strlen(uP_table[i].name);
|
|
|
|
if(strncasecmp(part->desc, uP_table[i].name, l1 < l2? l1: l2) ||
|
|
|
|
flash->size != uP_table[i].flashsize ||
|
|
|
|
flash->page_size != uP_table[i].pagesize ||
|
|
|
|
part->n_interrupts != uP_table[i].ninterrupts)
|
|
|
|
yywarning("mcuid %d is reserved for %s, use a free number >= %d",
|
|
|
|
part->mcuid, uP_table[i].name, sizeof uP_table/sizeof *uP_table);
|
|
|
|
}
|
2022-08-30 18:48:17 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Range check
|
|
|
|
if(part->mcuid < 0 || part->mcuid >= UB_N_MCU)
|
|
|
|
yywarning("mcuid %d for %s is out of range [0..%d], use a free number >= %d",
|
|
|
|
part->mcuid, part->desc, UB_N_MCU-1, sizeof uP_table/sizeof *uP_table);
|
|
|
|
}
|