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
This commit is contained in:
Stefan Rueger 2022-08-30 02:08:15 +01:00
parent cddf2943eb
commit ed2b8342df
No known key found for this signature in database
GPG Key ID: B0B4F1FD86B1EC55
8 changed files with 542 additions and 142 deletions

View File

@ -21,39 +21,56 @@
# id = <id1> [, <id2> [, <id3>] ...] ; # <idN> are quoted strings
# desc = <description> ; # quoted string
# type = <type>; # programmer type, quoted string
# # supported programmer types can be listed by "-c ?type"
# # supported types can be listed by "-c ?type"
# prog_modes = PM_<i/f> {| PM_<i/f>} # interfaces, eg, PM_SPM|PM_PDI (1)
# connection_type = parallel | serial | usb | spi
# baudrate = <num> ; # baudrate for avr910-programmer
# vcc = <num1> [, <num2> ... ] ; # pin number(s)
# buff = <num1> [, <num2> ... ] ; # pin number(s)
# reset = <num> ; # pin number
# sck = <num> ; # pin number
# mosi = <num> ; # pin number
# miso = <num> ; # pin number
# errled = <num> ; # pin number
# rdyled = <num> ; # pin number
# pgmled = <num> ; # pin number
# vfyled = <num> ; # pin number
# vcc = <pin1> [, <pin2> ... ] ; # pin number(s)
# buff = <pin1> [, <pin2> ... ] ; # pin number(s)
# reset = <pin> ; # pin number
# sck = <pin> ; # pin number
# mosi = <pin> ; # pin number
# miso = <pin> ; # pin number
# errled = <pin> ; # pin number
# rdyled = <pin> ; # pin number
# pgmled = <pin> ; # pin number
# vfyled = <pin> ; # pin number
# usbvid = <hexnum> ; # USB VID (Vendor ID)
# usbpid = <hexnum> [, <hexnum> ...] ; # USB PID (Product ID) (1)
# usbpid = <hexnum> [, <hexnum> ...] ; # USB PID (Product ID) (2)
# usbdev = <interface> ; # USB interface or other device info
# usbvendor = <vendorname> ; # USB Vendor Name
# usbproduct = <productname> ; # USB Product Name
# usbsn = <serialno> ; # USB Serial Number
# hvupdi_support = <num> [, <num>, ... ] ; # UPDI HV Variants Support
#
# To invert a bit, use = ~ <num>, the spaces are important.
# For a pin list all pins must be inverted.
# A single pin can be specified as usual = ~ <num>, for lists
# specify it as follows = ~ ( <num> [, <num2> ... ] ) .
#
# (1) Not all programmer types can process a list of PIDs.
# ;
#
# # To invert a bit, use = ~ <num>, the spaces are important.
# # For a pin list all pins must be inverted.
# # A single pin can be specified as usual = ~ <num>, for lists
# # specify it as follows = ~ ( <num> [, <num2> ... ] ).
# #
# # (1) The following program modes are known:
# # - PM_SPM: Bootloaders, self-programming with SPM opcodes or NVM Controllers
# # - PM_TPI: Tiny Programming Interface (t4, t5, t9, t10, t20, t40, t102, t104)
# # - PM_ISP: SPI programming for In-System Programming (almost all 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: Joint Test Action Group standard (some classic parts, some xmega)
# # - PM_aWire: AVR32 parts
# #
# # (2) Not all programmer types can process a list of PIDs
#
# part
# desc = <description> ; # quoted string
# id = <id> ; # quoted string
# family_id = <id> ; # quoted string, eg, "megaAVR" or "tinyAVR"
# prog_modes = PM_<i/f> {| PM_<i/f>} # interfaces, eg, PM_SPM|PM_ISP|PM_HVPP|PM_debugWIRE
# mcuid = <num>; # unique id in 0..2039 for urclock programmer
# n_interrupts = <num>; # number of interrupts, used for vector bootloaders
# n_page_erase = <num>; # if set, number of pages erased during NVM erase
# hvupdi_variant = <num> ; # numeric -1 (n/a) or 0..2
# devicecode = <num> ; # deprecated, use stk500_devcode
# stk500_devcode = <num> ; # numeric
@ -63,8 +80,9 @@
# has_pdi = <yes/no> ; # part has PDI i/f
# has_updi = <yes/no> ; # part has UPDI i/f
# has_tpi = <yes/no> ; # part has TPI i/f
# is_at90s1200 = <yes/no> ; # AT90S1200 part
# is_avr32 = <yes/no> ; # AVR32 part
#
# is_at90s1200 = <yes/no> ; # AT90S1200 part
# signature = <num> <num> <num> ; # signature bytes
# usbpid = <num> ; # DFU USB PID
# chip_erase_delay = <num> ; # micro-seconds
@ -247,7 +265,7 @@
# section avr061.zip which accompanies the application note
# AVR061 available from:
#
# http://www.atmel.com/dyn/resources/prod_documents/doc2525.pdf
# https://ww1.microchip.com/downloads/en/Appnotes/doc2525.pdf
#
#define ATTINY10 0x10 /* the _old_ one that never existed! */

View File

@ -24,6 +24,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stddef.h>
#include <string.h>
#include <ctype.h>
@ -44,6 +45,7 @@ LISTID number_list;
PROGRAMMER * current_prog;
AVRPART * current_part;
AVRMEM * current_mem;
int current_strct;
LISTID part_list;
LISTID programmers;
bool is_alias;
@ -53,6 +55,22 @@ char * cfg_infile;
extern char * yytext;
#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),
};
#define DEBUG 0
void cleanup_config(void)
@ -190,7 +208,7 @@ void free_tokens(int n, ...)
TOKEN *number(const char *text) {
TOKEN *new_number(const char *text) {
struct token_t *tkn = new_token(TKN_NUMBER);
tkn->value.type = V_NUM;
tkn->value.number = atoi(text);
@ -202,7 +220,7 @@ TOKEN *number(const char *text) {
return tkn;
}
TOKEN *number_real(const char *text) {
TOKEN *new_number_real(const char *text) {
struct token_t * tkn = new_token(TKN_NUMBER);
tkn->value.type = V_NUM_REAL;
tkn->value.number_real = atof(text);
@ -214,7 +232,7 @@ TOKEN *number_real(const char *text) {
return tkn;
}
TOKEN *hexnumber(const char *text) {
TOKEN *new_hexnumber(const char *text) {
struct token_t *tkn = new_token(TKN_NUMBER);
char * e;
@ -233,11 +251,41 @@ TOKEN *hexnumber(const char *text) {
return tkn;
}
TOKEN *new_constant(const char *con) {
struct token_t *tkn = new_token(TKN_NUMBER);
int assigned = 1;
TOKEN *string(const char *text) {
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
return tkn;
}
TOKEN *new_string(const char *text) {
struct token_t *tkn = new_token(TKN_STRING);
tkn->value.type = V_STR;
tkn->value.string = cfg_strdup("string()", text);
tkn->value.string = cfg_strdup("new_string()", text);
#if DEBUG
avrdude_message(MSG_INFO, "STRING(%s)\n", tkn->value.string);
@ -247,7 +295,7 @@ TOKEN *string(const char *text) {
}
TOKEN * keyword(int primary) {
TOKEN *new_keyword(int primary) {
return new_token(primary);
}
@ -692,3 +740,97 @@ char *cfg_escape(const char *s) {
return cfg_strdup("cfg_escape()", buf);
}
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));
}
}

View File

@ -37,13 +37,48 @@ typedef struct {
} COMMENT;
enum { V_NONE, V_NUM, V_NUM_REAL, V_STR };
enum { // Which structures a component can occur in
COMP_CONFIG_MAIN,
COMP_PROGRAMMER,
COMP_AVRPART,
COMP_AVRMEM,
};
enum { // Component types in structure
COMP_INT,
COMP_SHORT,
COMP_CHAR,
COMP_STRING,
COMP_CHAR_ARRAY, // This and below are not yet implemented
COMP_INT_LISTID,
COMP_STRING_LISTID,
COMP_OPCODE,
COMP_PIN, // Pins may never be implemented
COMP_PIN_LIST
};
typedef struct { // Description of a component in a structure
const char *name; // Component name
int strct; // Structure, eg, COMP_AVRPART
int offset, size, type; // Location, size and type within structure
} Component_t;
enum { // Value types for VALUE struct
V_NONE,
V_NUM,
V_NUM_REAL,
V_STR,
V_COMPONENT,
};
typedef struct value_t {
int type;
union {
int number;
double number_real;
char * string;
Component_t *comp;
};
} VALUE;
@ -59,6 +94,7 @@ extern FILE * yyin;
extern PROGRAMMER * current_prog;
extern AVRPART * current_part;
extern AVRMEM * current_mem;
int current_strct;
extern int cfg_lineno;
extern char * cfg_infile;
extern LISTID string_list;
@ -87,15 +123,17 @@ void free_token(TOKEN *tkn);
void free_tokens(int n, ...);
TOKEN *number(const char *text);
TOKEN *new_number(const char *text);
TOKEN *number_real(const char *text);
TOKEN *new_number_real(const char *text);
TOKEN *hexnumber(const char *text);
TOKEN *new_hexnumber(const char *text);
TOKEN *string(const char *text);
TOKEN *new_constant(const char *text);
TOKEN *keyword(int primary);
TOKEN *new_string(const char *text);
TOKEN *new_keyword(int primary);
void print_token(TOKEN *tkn);
@ -115,6 +153,15 @@ LISTID cfg_move_comments(void);
void cfg_pop_comms(void);
Component_t *cfg_comp_search(const char *name, int strct);
const char *cfg_v_type(int type);
const char *cfg_strct_name(int strct);
void cfg_assign(char *sp, int strct, Component_t *cp, VALUE *v);
#ifdef __cplusplus
}
#endif

View File

@ -208,12 +208,19 @@ static int pin_name;
%token TKN_COMMA
%token TKN_EQUAL
%token TKN_SEMI
%token TKN_TILDE
%token TKN_LEFT_PAREN
%token TKN_RIGHT_PAREN
%token TKN_NUMBER
%token TKN_NUMBER_REAL
%token TKN_STRING
%token TKN_COMPONENT
%left OP_OR /* calculator operations */
%left OP_XOR
%left OP_AND
%left OP_PLUS OP_MINUS
%left OP_TIMES OP_DIVIDE OP_MODULO
%right OP_TILDE UNARY
%start configuration
@ -229,6 +236,27 @@ number_real :
TKN_NUMBER_REAL {
$$ = $1;
}
;
expr: numexpr | TKN_STRING;
numexpr:
TKN_NUMBER |
numexpr OP_OR numexpr { $$ = $1; $$->value.number |= $3->value.number; } |
numexpr OP_XOR numexpr { $$ = $1; $$->value.number ^= $3->value.number; } |
numexpr OP_AND numexpr { $$ = $1; $$->value.number &= $3->value.number; } |
numexpr OP_PLUS numexpr { $$ = $1; $$->value.number += $3->value.number; } |
numexpr OP_MINUS numexpr { $$ = $1; $$->value.number -= $3->value.number; } |
numexpr OP_TIMES numexpr { $$ = $1; $$->value.number *= $3->value.number; } |
numexpr OP_DIVIDE numexpr { $$ = $1; $$->value.number /= $3->value.number; } |
numexpr OP_MODULO numexpr { $$ = $1; $$->value.number %= $3->value.number; } |
OP_PLUS numexpr %prec UNARY { $$ = $2; } |
OP_MINUS numexpr %prec UNARY { $$ = $2; $$->value.number = -$$->value.number; } |
OP_TILDE numexpr %prec UNARY { $$ = $2; $$->value.number = ~$$->value.number; } |
TKN_LEFT_PAREN numexpr TKN_RIGHT_PAREN { $$ = $2; }
;
configuration :
/* empty */ | config
@ -302,6 +330,7 @@ prog_def :
// pgm_fill_old_pins(current_prog); // TODO to be removed if old pin data no longer needed
// pgm_display_generic(current_prog, id);
current_prog = NULL;
current_strct = COMP_CONFIG_MAIN;
}
;
@ -309,6 +338,7 @@ prog_def :
prog_decl :
K_PROGRAMMER
{ current_prog = pgm_new();
current_strct = COMP_PROGRAMMER;
current_prog->config_file = cache_string(cfg_infile);
current_prog->lineno = cfg_lineno;
}
@ -322,6 +352,7 @@ prog_decl :
YYABORT;
}
current_prog = pgm_dup(pgm);
current_strct = COMP_PROGRAMMER;
current_prog->parent_id = cache_string($3->value.string);
current_prog->comments = NULL;
current_prog->config_file = cache_string(cfg_infile);
@ -389,6 +420,7 @@ part_def :
current_part->comments = cfg_move_comments();
LISTADD(part_list, current_part);
current_part = NULL;
current_strct = COMP_CONFIG_MAIN;
}
;
@ -396,6 +428,7 @@ part_decl :
K_PART
{
current_part = avr_new_part();
current_strct = COMP_AVRPART;
current_part->config_file = cache_string(cfg_infile);
current_part->lineno = cfg_lineno;
} |
@ -409,6 +442,7 @@ part_decl :
}
current_part = avr_dup_part(parent_part);
current_strct = COMP_AVRPART;
current_part->parent_id = cache_string($3->value.string);
current_part->comments = NULL;
current_part->config_file = cache_string(cfg_infile);
@ -435,6 +469,10 @@ prog_parms :
;
prog_parm :
TKN_COMPONENT TKN_EQUAL expr {
cfg_assign((char *) current_prog, COMP_PROGRAMMER, $1->value.comp, &$3->value);
free_token($1);
} |
K_ID TKN_EQUAL string_list {
{
while (lsize(string_list)) {
@ -589,7 +627,7 @@ hvupdi_support_list:
pin_number_non_empty:
TKN_NUMBER { if(0 != assign_pin(pin_name, $1, 0)) YYABORT; }
|
TKN_TILDE TKN_NUMBER { if(0 != assign_pin(pin_name, $2, 1)) YYABORT; }
OP_TILDE TKN_NUMBER { if(0 != assign_pin(pin_name, $2, 1)) YYABORT; }
;
pin_number:
@ -601,7 +639,7 @@ pin_number:
pin_list_element:
pin_number_non_empty
|
TKN_TILDE TKN_LEFT_PAREN num_list TKN_RIGHT_PAREN { if(0 != assign_pin_list(1)) YYABORT; }
OP_TILDE TKN_LEFT_PAREN num_list TKN_RIGHT_PAREN { if(0 != assign_pin_list(1)) YYABORT; }
;
pin_list_non_empty:
@ -665,6 +703,10 @@ retry_lines :
;
part_parm :
TKN_COMPONENT TKN_EQUAL expr {
cfg_assign((char *) current_part, COMP_AVRPART, $1->value.comp, &$3->value);
free_token($1);
} |
K_ID TKN_EQUAL TKN_STRING
{
current_part->id = cache_string($3->value.string);
@ -1075,51 +1117,61 @@ part_parm :
K_HAS_JTAG TKN_EQUAL yesno
{
if ($3->primary == K_YES)
if ($3->primary == K_YES) {
current_part->flags |= AVRPART_HAS_JTAG;
else if ($3->primary == K_NO)
current_part->prog_modes |= PM_JTAG;
} else if ($3->primary == K_NO) {
current_part->flags &= ~AVRPART_HAS_JTAG;
current_part->prog_modes &= ~PM_JTAG;
}
free_token($3);
} |
K_HAS_DW TKN_EQUAL yesno
{
if ($3->primary == K_YES)
if ($3->primary == K_YES) {
current_part->flags |= AVRPART_HAS_DW;
else if ($3->primary == K_NO)
current_part->prog_modes |= PM_debugWIRE;
} else if ($3->primary == K_NO) {
current_part->flags &= ~AVRPART_HAS_DW;
current_part->prog_modes &= ~PM_debugWIRE;
}
free_token($3);
} |
K_HAS_PDI TKN_EQUAL yesno
{
if ($3->primary == K_YES)
if ($3->primary == K_YES) {
current_part->flags |= AVRPART_HAS_PDI;
else if ($3->primary == K_NO)
current_part->prog_modes |= PM_PDI;
} else if ($3->primary == K_NO) {
current_part->flags &= ~AVRPART_HAS_PDI;
current_part->prog_modes &= ~PM_PDI;
}
free_token($3);
} |
K_HAS_UPDI TKN_EQUAL yesno
{
if ($3->primary == K_YES)
if ($3->primary == K_YES) {
current_part->flags |= AVRPART_HAS_UPDI;
else if ($3->primary == K_NO)
current_part->prog_modes |= PM_UPDI;
} else if ($3->primary == K_NO) {
current_part->flags &= ~AVRPART_HAS_UPDI;
current_part->prog_modes &= ~PM_UPDI;
}
free_token($3);
} |
K_HAS_TPI TKN_EQUAL yesno
{
if ($3->primary == K_YES)
if ($3->primary == K_YES) {
current_part->flags |= AVRPART_HAS_TPI;
else if ($3->primary == K_NO)
current_part->prog_modes |= PM_TPI;
} else if ($3->primary == K_NO) {
current_part->flags &= ~AVRPART_HAS_TPI;
current_part->prog_modes &= ~PM_TPI;
}
free_token($3);
} |
@ -1135,11 +1187,13 @@ part_parm :
K_IS_AVR32 TKN_EQUAL yesno
{
if ($3->primary == K_YES)
if ($3->primary == K_YES) {
current_part->flags |= AVRPART_AVR32;
else if ($3->primary == K_NO)
current_part->prog_modes |= PM_aWire;
} else if ($3->primary == K_NO) {
current_part->flags &= ~AVRPART_AVR32;
current_part->prog_modes &= ~PM_aWire;
}
free_token($3);
} |
@ -1255,14 +1309,6 @@ part_parm :
} |
/*
K_EEPROM { current_mem = AVR_M_EEPROM; }
mem_specs |
K_FLASH { current_mem = AVR_M_FLASH; }
mem_specs |
*/
K_MEMORY TKN_STRING
{ /* select memory for extension or create if not there */
AVRMEM *mem = avr_locate_mem_noalias(current_part, $2->value.string);
@ -1273,6 +1319,7 @@ part_parm :
}
avr_add_mem_order($2->value.string);
current_mem = mem;
current_strct = COMP_AVRMEM;
free_token($2);
}
mem_specs
@ -1295,6 +1342,7 @@ part_parm :
}
cfg_pop_comms();
current_mem = NULL;
current_strct = COMP_AVRPART;
} |
K_MEMORY TKN_STRING TKN_EQUAL K_NULL
{
@ -1306,6 +1354,7 @@ part_parm :
free_token($2);
cfg_pop_comms();
current_mem = NULL;
current_strct = COMP_AVRPART;
} |
opcode TKN_EQUAL string_list {
{
@ -1355,6 +1404,11 @@ mem_specs :
mem_spec :
TKN_COMPONENT TKN_EQUAL expr {
cfg_assign((char *) current_mem, COMP_AVRMEM, $1->value.comp, &$3->value);
free_token($1);
} |
K_PAGED TKN_EQUAL yesno
{
current_mem->paged = $3->primary == K_YES ? 1 : 0;

View File

@ -63,7 +63,7 @@ static struct {
const char *mcu, *var, *value;
} ptinj[] = {
// Add triples here, eg, {"ATmega328P", "mcuid", "999"},
{NULL, NULL, NULL},
{NULL, NULL, NULL},
};
static struct {
@ -134,7 +134,7 @@ static void printallopcodes(const AVRPART *p, const char *d, OPCODE * const *opa
// Programming modes
static char *prog_modes(const AVRPART *p) {
static char *prog_modes_str_flags(const AVRPART *p) {
static char type[1024];
*type = 0;
@ -194,6 +194,34 @@ static char *prog_modes(const AVRPART *p) {
return type + (*type == '|');
}
static char *prog_modes_str(int pm) {
static char type[1024];
strcpy(type, "0");
if(pm & PM_SPM)
strcat(type, " | PM_SPM");
if(pm & PM_TPI)
strcat(type, " | PM_TPI");
if(pm & PM_ISP)
strcat(type, " | PM_ISP");
if(pm & PM_PDI)
strcat(type, " | PM_PDI");
if(pm & PM_UPDI)
strcat(type, " | PM_UPDI");
if(pm & PM_HVSP)
strcat(type, " | PM_HVSP");
if(pm & PM_HVPP)
strcat(type, " | PM_HVPP");
if(pm & PM_debugWIRE)
strcat(type, " | PM_debugWIRE");
if(pm & PM_JTAG)
strcat(type, " | PM_JTAG");
if(pm & PM_aWire)
strcat(type, " | PM_aWire");
return type + (type[1] == 0? 0: 4);
}
// Check whether address bits are where they should be in ISP commands
static void checkaddr(int memsize, int pagesize, int opnum, const OPCODE *op, const AVRPART *p, const AVRMEM *m) {
@ -573,6 +601,10 @@ static void dev_part_strct(const AVRPART *p, bool tsv, const AVRPART *base, bool
_if_partout_str(strcmp, descstr, desc);
_if_partout_str(strcmp, cfg_escape(p->id), id);
_if_partout_str(strcmp, cfg_escape(p->family_id), family_id);
_if_partout_str(intcmp, cfg_strdup("dev_part_strct()", prog_modes_str(p->prog_modes)), prog_modes);
_if_partout(intcmp, "%d", mcuid);
_if_partout(intcmp, "%d", n_interrupts);
_if_partout(intcmp, "%d", n_page_erase);
_if_partout(intcmp, "%d", hvupdi_variant);
_if_partout(intcmp, "0x%02x", stk500_devcode);
_if_partout(intcmp, "0x%02x", avr910_devcode);
@ -1032,7 +1064,7 @@ void dev_output_part_defs(char *partdesc) {
nfuses,
ok,
p->flags,
prog_modes(p),
prog_modes_str_flags(p),
p->config_file, p->lineno
);
}
@ -1189,6 +1221,7 @@ static void dev_pgm_strct(const PROGRAMMER *pgm, bool tsv, const PROGRAMMER *bas
_if_pgmout_str(strcmp, cfg_escape(pgm->desc), desc);
if(!base || base->initpgm != pgm->initpgm)
_pgmout_fmt("type", "\"%s\"", locate_programmer_type_id(pgm->initpgm));
_if_pgmout_str(intcmp, cfg_strdup("dev_pgm_strct()", prog_modes_str(pgm->prog_modes)), prog_modes);
if(!base || base->conntype != pgm->conntype)
_pgmout_fmt("connection_type", "%s", connstr(pgm->conntype));
_if_pgmout(intcmp, "%d", baudrate);

View File

@ -1694,34 +1694,53 @@ The format of the programmer definition is as follows:
@smallexample
programmer
parent <id> # <id> is a quoted string
parent <id> # optional parent
id = <id1> [, <id2> [, <id3>] ...] ; # <idN> are quoted strings
desc = <description> ; # quoted string
type = "par" | "stk500" | ... ; # programmer type (see below for a list)
baudrate = <num> ; # baudrate for serial ports
vcc = <num1> [, <num2> ... ] ; # pin number(s)
buff = <num1> [, <num2> ... ] ; # pin number(s)
reset = <num> ; # pin number
sck = <num> ; # pin number
mosi = <num> ; # pin number
miso = <num> ; # pin number
errled = <num> ; # pin number
rdyled = <num> ; # pin number
pgmled = <num> ; # pin number
vfyled = <num> ; # pin number
usbvid = <hexnum>; # USB VID (Vendor ID)
usbpid = <hexnum> [, <hexnum> ...]; # USB PID (Product ID)
usbdev = <interface>; # USB interface or other device info
usbvendor = <vendorname>; # USB Vendor Name
usbproduct = <productname>; # USB Product Name
usbsn = <serialno>; # USB Serial Number
;
type = <type>; # programmer type, quoted string
# supported types can be listed by "-c ?type"
prog_modes = PM_<i/f> @{ | PM_<i/f> @} # interfaces, eg, PM_SPM|PM_PDI
connection_type = parallel | serial | usb | spi
baudrate = <num> ; # baudrate for avr910-programmer
vcc = <pin1> [, <pin2> ... ] ; # pin number(s)
buff = <pin1> [, <pin2> ... ] ; # pin number(s)
reset = <pin> ; # pin number
sck = <pin> ; # pin number
mosi = <pin> ; # pin number
miso = <pin> ; # pin number
errled = <pin> ; # pin number
rdyled = <pin> ; # pin number
pgmled = <pin> ; # pin number
vfyled = <pin> ; # pin number
usbvid = <hexnum> ; # USB VID (Vendor ID)
usbpid = <hexnum> [, <hexnum> ...] ; # USB PID (Product ID)
usbdev = <interface> ; # USB interface or other device info
usbvendor = <vendorname> ; # USB Vendor Name
usbproduct = <productname> ; # USB Product Name
usbsn = <serialno> ; # USB Serial Number
hvupdi_support = <num> [, <num>, ... ] ; # UPDI HV Variants Support
;
@end smallexample
@noindent
If a parent is specified, all settings of it (except its ids) are used for the new
programmer. These values can be changed by new setting them for the new programmer.
@noindent
Known programming modes are
@itemize @bullet
@item @code{PM_SPM}: Bootloaders, self-programming with SPM opcodes or NVM Controllers
@item @code{PM_TPI}: Tiny Programming Interface (t4, t5, t9, t10, t20, t40, t102, t104)
@item @code{PM_ISP}: SPI programming for In-System Programming (almost all classic parts)
@item @code{PM_PDI}: Program and Debug Interface (xmega parts)
@item @code{PM_UPDI}: Unified Program and Debug Interface
@item @code{PM_HVSP}: High Voltage Serial Programming (some classic parts)
@item @code{PM_HVPP}: High Voltage Parallel Programming (most non-HVSP classic parts)
@item @code{PM_debugWIRE}: Simpler alternative to JTAG (a subset of HVPP/HVSP parts)
@item @code{PM_JTAG}: Joint Test Action Group standard (some classic parts, some xmega)
@item @code{PM_aWire}: AVR32 parts
@end itemize
@noindent
To invert a bit in the pin definitions, use @code{= ~ <num>}.
@ -1729,7 +1748,7 @@ To invert a bit in the pin definitions, use @code{= ~ <num>}.
Not all programmer types can handle a list of USB PIDs.
@noindent
Following programmer types are currently implemented:
The following programmer types are currently implemented:
@multitable @columnfractions .25 .6
@include programmer_types.texi
@ -1743,29 +1762,35 @@ Following programmer types are currently implemented:
@smallexample
part
id = <id> ; # quoted string
desc = <description> ; # quoted string
family_id = <description> ; # quoted string
id = <id> ; # quoted string
family_id = <id> ; # quoted string, eg, "megaAVR" or "tinyAVR"
prog_modes = PM_<i/f> @{ | PM_<i/f> @} # interfaces, eg, PM_SPM|PM_ISP|PM_HVPP|PM_debugWIRE
mcuid = <num>; # unique id in 0..2039 for urclock programmer
n_interrupts = <num>; # number of interrupts, used for vector bootloaders
n_page_erase = <num>; # if set, number of pages erased during NVM erase
hvupdi_variant = <num> ; # numeric -1 (n/a) or 0..2
devicecode = <num> ; # deprecated, use stk500_devcode
stk500_devcode = <num> ; # numeric
avr910_devcode = <num> ; # numeric
has_jtag = <yes/no> ; # part has JTAG i/f
has_debugwire = <yes/no> ; # part has debugWire i/f
has_pdi = <yes/no> ; # part has PDI i/f
has_updi = <yes/no> ; # part has UPDI i/f
has_tpi = <yes/no> ; # part has TPI i/f
devicecode = <num> ; # numeric
stk500_devcode = <num> ; # numeric
avr910_devcode = <num> ; # numeric
is_avr32 = <yes/no> ; # AVR32 part
is_at90s1200 = <yes/no> ; # AT90S1200 part
signature = <num> <num> <num> ; # signature bytes
usbpid = <num> ; # DFU USB PID
reset = dedicated | io;
retry_pulse = reset | sck;
pgm_enable = <instruction format> ;
chip_erase = <instruction format> ;
chip_erase_delay = <num> ; # micro-seconds
reset = dedicated | io ;
retry_pulse = reset | sck ;
chip_erase_delay = <num> ; # chip erase delay (us)
# STK500 parameters (parallel programming IO lines)
pagel = <num> ; # pin name in hex, i.e., 0xD7
bs2 = <num> ; # pin name in hex, i.e., 0xA0
serial = <yes/no> ; # can use serial downloading
parallel = <yes/no/pseudo>; # can use par. programming
parallel = <yes/no/pseudo> ; # can use par. programming
# STK500v2 parameters, to be taken from Atmel's XML files
timeout = <num> ;
stabdelay = <num> ;
@ -1777,52 +1802,59 @@ part
predelay = <num> ;
postdelay = <num> ;
pollmethod = <num> ;
mode = <num> ;
delay = <num> ;
blocksize = <num> ;
readsize = <num> ;
hvspcmdexedelay = <num> ;
# STK500v2 HV programming parameters, from XML
pp_controlstack = <num>, <num>, ...; # PP only
hvsp_controlstack = <num>, <num>, ...; # HVSP only
hventerstabdelay = <num>;
progmodedelay = <num>; # PP only
latchcycles = <num>;
togglevtg = <num>;
poweroffdelay = <num>;
resetdelayms = <num>;
resetdelayus = <num>;
hvleavestabdelay = <num>;
resetdelay = <num>;
synchcycles = <num>; # HVSP only
chiperasepulsewidth = <num>; # PP only
chiperasepolltimeout = <num>;
chiperasetime = <num>; # HVSP only
programfusepulsewidth = <num>; # PP only
programfusepolltimeout = <num>;
programlockpulsewidth = <num>; # PP only
programlockpolltimeout = <num>;
pp_controlstack = <num>, <num>, ... ; # PP only
hvsp_controlstack = <num>, <num>, ... ; # HVSP only
flash_instr = <num>, <num>, <num> ;
eeprom_instr = <num>, <num>, ... ;
hventerstabdelay = <num> ;
progmodedelay = <num> ; # PP only
latchcycles = <num> ;
togglevtg = <num> ;
poweroffdelay = <num> ;
resetdelayms = <num> ;
resetdelayus = <num> ;
hvleavestabdelay = <num> ;
resetdelay = <num> ;
synchcycles = <num> ; # HVSP only
chiperasepulsewidth = <num> ; # PP only
chiperasepolltimeout = <num> ;
chiperasetime = <num> ; # HVSP only
programfusepulsewidth = <num> ; # PP only
programfusepolltimeout = <num> ;
programlockpulsewidth = <num> ; # PP only
programlockpolltimeout = <num> ;
# JTAG ICE mkII parameters, also from XML files
allowfullpagebitstream = <yes/no> ;
enablepageprogramming = <yes/no> ;
idr = <num> ; # IO addr of IDR (OCD) reg.
rampz = <num> ; # IO addr of RAMPZ reg.
spmcr = <num> ; # mem addr of SPMC[S]R reg.
eecr = <num> ; # mem addr of EECR reg.
# (only when != 0x3F)
is_at90s1200 = <yes/no> ; # AT90S1200 part
is_avr32 = <yes/no> ; # AVR32 part
idr = <num> ; # IO addr of IDR (OCD) reg
rampz = <num> ; # IO addr of RAMPZ reg
spmcr = <num> ; # mem addr of SPMC[S]R reg
eecr = <num> ; # mem addr of EECR reg only when != 0x3f
mcu_base = <num> ;
nvm_base = <num> ;
ocd_base = <num> ;
ocdrev = <num> ;
pgm_enable = <instruction format> ;
chip_erase = <instruction format> ;
memory <memtype>
paged = <yes/no> ; # yes / no
paged = <yes/no> ; # yes/no (flash only, do not use for EEPROM)
offset = <num> ; # memory offset
size = <num> ; # bytes
page_size = <num> ; # bytes
num_pages = <num> ; # numeric
min_write_delay = <num> ; # micro-seconds
max_write_delay = <num> ; # micro-seconds
readback_p1 = <num> ; # byte value
readback_p2 = <num> ; # byte value
pwroff_after_write = <yes/no> ; # yes / no
readback = <num> <num> ; # pair of byte values
readback_p1 = <num> ; # byte value (first component)
readback_p2 = <num> ; # byte value (second component)
pwroff_after_write = <yes/no> ; # yes/no
mode = <num> ; # STK500 v2 file parameter from Atmel's XML files
delay = <num> ; # "
blocksize = <num> ; # "
readsize = <num> ; # "
read = <instruction format> ;
write = <instruction format> ;
read_lo = <instruction format> ;
@ -1832,8 +1864,8 @@ part
loadpage_lo = <instruction format> ;
loadpage_hi = <instruction format> ;
writepage = <instruction format> ;
;
;
;
;
@end smallexample
@menu
@ -1914,7 +1946,22 @@ write = "1 1 0 0 0 0 0 0 x x x x x x x x",
@end smallexample
As the address bit numbers in the SPI opcodes are highly systematic, they
don't really need to be specified. A compact version of the format
specification neither uses bit-numbers for address lines nor spaces. If such
a string is longer than 7 characters, then the characters @code{0}, @code{1},
@code{x}, @code{a}, @code{i} and @code{o} will be recognised as the
corresponding bit, whilst any of the characters @code{.}, @code{-}, @code{_}
or @code{/} can act as arbitrary visual separators, which are ignored.
Examples:
@smallexample
loadpage_lo = "0100.0000--000x.xxxx--xxaa.aaaa--iiii.iiii";
loadpage_lo = "0100.0000", "000x.xxxx", "xxaa.aaaa", "iiii.iiii";
@end smallexample
@c
@c Node

View File

@ -63,9 +63,9 @@ SIGN [+-]
%%
{SIGN}?{DIGIT}+ { yylval = number(yytext); return TKN_NUMBER; }
{SIGN}?{DIGIT}+"."{DIGIT}* { yylval = number_real(yytext); return TKN_NUMBER_REAL; }
{SIGN}?"."{DIGIT}+ { yylval = number_real(yytext); return TKN_NUMBER_REAL; }
{SIGN}?{DIGIT}+ { yylval = new_number(yytext); return TKN_NUMBER; }
{SIGN}?{DIGIT}+"."{DIGIT}* { yylval = new_number_real(yytext); return TKN_NUMBER_REAL; }
{SIGN}?"."{DIGIT}+ { yylval = new_number_real(yytext); return TKN_NUMBER_REAL; }
["]([^"\\\n]|\\.|\\\n)*["] {
char *str= cfg_strdup("lexer.l", yytext);
@ -73,12 +73,12 @@ SIGN [+-]
size_t len = strlen(str);
if(len)
str[len-1] = 0;
yylval = string(str);
yylval = new_string(str);
free(str);
return TKN_STRING;
}
0x{HEXDIGIT}+ { yylval = hexnumber(yytext); return TKN_NUMBER; }
0x{HEXDIGIT}+ { yylval = new_hexnumber(yytext); return TKN_NUMBER; }
#\n#\ PROGRAMMER\ DEFINITIONS\n#\n+ { /* Record comments so far as prologue and skip */
cfg_capture_prologue();
@ -121,6 +121,23 @@ SIGN [+-]
}
prog_modes|mcuid|n_interrupts|n_page_erase { /* Components for assignment */
Component_t *cp = cfg_comp_search(yytext, current_strct);
if(!cp) {
yyerror("Unknown component %s in %s", yytext, cfg_strct_name(current_strct));
return YYERRCODE;
}
yylval = new_token(TKN_COMPONENT);
yylval->value.comp = cp;
ccap();
return TKN_COMPONENT;
}
PM_SPM|PM_TPI|PM_ISP|PM_PDI|PM_UPDI|PM_HVSP|PM_HVPP|PM_debugWIRE|PM_JTAG|PM_aWire { /* Constants */
yylval = new_constant(yytext);
return TKN_NUMBER;
}
alias { yylval=NULL; return K_ALIAS; }
allowfullpagebitstream { yylval=NULL; ccap(); return K_ALLOWFULLPAGEBITSTREAM; }
avr910_devcode { yylval=NULL; ccap(); return K_AVR910_DEVCODE; }
@ -258,7 +275,17 @@ yes { yylval=new_token(K_YES); return K_YES; }
"," { yylval = NULL; pyytext(); return TKN_COMMA; }
"=" { yylval = NULL; pyytext(); return TKN_EQUAL; }
";" { yylval = NULL; pyytext(); return TKN_SEMI; }
"~" { yylval = NULL; pyytext(); return TKN_TILDE; }
"|" { yylval = NULL; pyytext(); return OP_OR; }
"^" { yylval = NULL; pyytext(); return OP_XOR; }
"&" { yylval = NULL; pyytext(); return OP_AND; }
"+" { yylval = NULL; pyytext(); return OP_PLUS; }
"-" { yylval = NULL; pyytext(); return OP_MINUS; }
"*" { yylval = NULL; pyytext(); return OP_TIMES; }
"/" { yylval = NULL; pyytext(); return OP_DIVIDE; }
"%" { yylval = NULL; pyytext(); return OP_MODULO; }
"~" { yylval = NULL; pyytext(); return OP_TILDE; }
"(" { yylval = NULL; pyytext(); return TKN_LEFT_PAREN; }
")" { yylval = NULL; pyytext(); return TKN_RIGHT_PAREN; }

View File

@ -169,6 +169,7 @@ enum ctl_stack_t {
CTL_STACK_HVSP /* high voltage serial programming control stack */
};
/*
* serial programming instruction bit specifications
*/
@ -197,6 +198,18 @@ typedef struct opcode {
#define AVRPART_IS_AT90S1200 0x1000 /* part is an AT90S1200 (needs special treatment) */
#define AVRPART_HAS_UPDI 0x2000 /* part has UPDI i/f (AVR8X) */
// Programming modes for parts and programmers: reflect changes in lexer.l, developer_opts.c and config.c
#define PM_SPM 1 // Bootloaders, self-programming with SPM opcodes or NVM Controllers
#define PM_TPI 2 // Tiny Programming Interface (t4, t5, t9, t10, t20, t40, t102, t104)
#define PM_ISP 4 // SPI programming for In-System Programming (almost all classic parts)
#define PM_PDI 8 // Program and Debug Interface (xmega parts)
#define PM_UPDI 16 // Unified Program and Debug Interface
#define PM_HVSP 32 // High Voltage Serial Programming (some classic parts)
#define PM_HVPP 64 // High Voltage Parallel Programming (most non-HVSP classic parts)
#define PM_debugWIRE 128 // Simpler alternative to JTAG (a subset of HVPP/HVSP parts)
#define PM_JTAG 256 // Joint Test Action Group standard (some classic parts, some xmega)
#define PM_aWire 512 // AVR32 parts
#define HV_UPDI_VARIANT_0 0 /* Shared UPDI/GPIO/RESET pin, HV on UPDI pin (tinyAVR0/1/2)*/
#define HV_UPDI_VARIANT_1 1 /* Dedicated UPDI pin, no HV (megaAVR0/AVR-Dx) */
#define HV_UPDI_VARIANT_2 2 /* Shared UPDI pin, HV on _RESET (AVR-Ex) */
@ -209,13 +222,24 @@ typedef struct opcode {
#define TAG_ALLOCATED 1 /* memory byte is allocated */
/* Any changes here, please also reflect in dev_part_strct() of developer_opts.c */
/*
* Any changes in AVRPART or AVRMEM, please also ensure changes are made in
* - lexer.l
* - Either Component_t avr_comp[] of config.c or in config_gram.y
* - dev_part_strct() in developer_opts.c
* - avr_new_part() and/or avr_new_memtype() in avrpart.c for
* initialisation; note that all const char * must be initialised with ""
*/
typedef struct avrpart {
const char * desc; /* long part name */
const char * id; /* short part name */
LISTID comments; // Used by developer options -p*/[ASsr...]
const char * parent_id; /* Used by developer options */
const char * family_id; /* family id in the SIB (avr8x) */
int prog_modes; /* Programming interfaces, see #define PM_... */
int mcuid; /* Unique id in 0..2039 for urclock programmer */
int n_interrupts; /* Number of interrupts, used for vector bootloaders */
int n_page_erase; /* If set, number of pages erased during NVM erase */
int hvupdi_variant; /* HV pulse on UPDI pin, no pin or RESET pin */
int stk500_devcode; /* stk500 device code */
int avr910_devcode; /* avr910 device code */
@ -262,7 +286,7 @@ typedef struct avrpart {
int programlockpulsewidth; /* stk500 v2 hv mode parameter */
int programlockpolltimeout; /* stk500 v2 hv mode parameter */
int synchcycles; /* stk500 v2 hv mode parameter */
int hvspcmdexedelay; /* stk500 v2 xml file parameter */
int hvspcmdexedelay; /* stk500 v2 hv mode file parameter */
unsigned char idr; /* JTAG ICE mkII XML file parameter */
unsigned char rampz; /* JTAG ICE mkII XML file parameter */
@ -677,13 +701,21 @@ typedef enum {
CONNTYPE_SPI
} conntype_t;
/* Any changes here, please also reflect in dev_pgm_strct() of developer_opts.c */
/*
* Any changes in PROGRAMMER, please also ensure changes are made in
* - lexer.l
* - Either Component_t avr_comp[] of config.c or config_gram.y
* - dev_pgm_strct() in developer_opts.c
* - pgm_new() in pgm.c for initialisation; note that all const char * must
* be initialised with ""
*/
typedef struct programmer_t {
LISTID id;
const char *desc;
void (*initpgm)(struct programmer_t *pgm); // Sets up the AVRDUDE programmer
LISTID comments; // Used by developer options -c*/[ASsr...]
const char *parent_id; // Used by developer options
int prog_modes; // Programming interfaces, see #define PM_...
struct pindef_t pin[N_PINS];
conntype_t conntype;
int baudrate;
@ -695,7 +727,7 @@ typedef struct programmer_t {
const char *usbproduct;
LISTID hvupdi_support; // List of UPDI HV variants the tool supports, see HV_UPDI_VARIANT_x
// Values below are not set by config_gram.y; make sure fd is first for dev_pgm_raw()
// Values below are not set by config_gram.y; ensure fd is first for dev_pgm_raw()
union filedescriptor fd;
char type[PGM_TYPELEN];
char port[PGM_PORTLEN];