From ed2b8342df46c1bbd3919fe3734cdde234d2d132 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 30 Aug 2022 02:08:15 +0100 Subject: [PATCH] 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 --- src/avrdude.conf.in | 60 +++++++++----- src/config.c | 154 ++++++++++++++++++++++++++++++++++-- src/config.h | 59 ++++++++++++-- src/config_gram.y | 112 +++++++++++++++++++------- src/developer_opts.c | 39 +++++++++- src/doc/avrdude.texi | 181 +++++++++++++++++++++++++++---------------- src/lexer.l | 39 ++++++++-- src/libavrdude.h | 40 +++++++++- 8 files changed, 542 insertions(+), 142 deletions(-) diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in index 5a68cff5..e2a330ff 100644 --- a/src/avrdude.conf.in +++ b/src/avrdude.conf.in @@ -21,39 +21,56 @@ # id = [, [, ] ...] ; # are quoted strings # desc = ; # quoted string # 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_ {| PM_} # interfaces, eg, PM_SPM|PM_PDI (1) # connection_type = parallel | serial | usb | spi # baudrate = ; # baudrate for avr910-programmer -# vcc = [, ... ] ; # pin number(s) -# buff = [, ... ] ; # pin number(s) -# reset = ; # pin number -# sck = ; # pin number -# mosi = ; # pin number -# miso = ; # pin number -# errled = ; # pin number -# rdyled = ; # pin number -# pgmled = ; # pin number -# vfyled = ; # pin number +# vcc = [, ... ] ; # pin number(s) +# buff = [, ... ] ; # pin number(s) +# reset = ; # pin number +# sck = ; # pin number +# mosi = ; # pin number +# miso = ; # pin number +# errled = ; # pin number +# rdyled = ; # pin number +# pgmled = ; # pin number +# vfyled = ; # pin number # usbvid = ; # USB VID (Vendor ID) -# usbpid = [, ...] ; # USB PID (Product ID) (1) +# usbpid = [, ...] ; # USB PID (Product ID) (2) # usbdev = ; # USB interface or other device info # usbvendor = ; # USB Vendor Name # usbproduct = ; # USB Product Name # usbsn = ; # USB Serial Number # hvupdi_support = [, , ... ] ; # UPDI HV Variants Support -# -# To invert a bit, use = ~ , the spaces are important. -# For a pin list all pins must be inverted. -# A single pin can be specified as usual = ~ , for lists -# specify it as follows = ~ ( [, ... ] ) . -# -# (1) Not all programmer types can process a list of PIDs. # ; # +# # To invert a bit, use = ~ , the spaces are important. +# # For a pin list all pins must be inverted. +# # A single pin can be specified as usual = ~ , for lists +# # specify it as follows = ~ ( [, ... ] ). +# # +# # (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 = ; # quoted string # id = ; # quoted string # family_id = ; # quoted string, eg, "megaAVR" or "tinyAVR" +# prog_modes = PM_ {| PM_} # interfaces, eg, PM_SPM|PM_ISP|PM_HVPP|PM_debugWIRE +# mcuid = ; # unique id in 0..2039 for urclock programmer +# n_interrupts = ; # number of interrupts, used for vector bootloaders +# n_page_erase = ; # if set, number of pages erased during NVM erase # hvupdi_variant = ; # numeric -1 (n/a) or 0..2 # devicecode = ; # deprecated, use stk500_devcode # stk500_devcode = ; # numeric @@ -63,8 +80,9 @@ # has_pdi = ; # part has PDI i/f # has_updi = ; # part has UPDI i/f # has_tpi = ; # part has TPI i/f -# is_at90s1200 = ; # AT90S1200 part # is_avr32 = ; # AVR32 part +# +# is_at90s1200 = ; # AT90S1200 part # signature = ; # signature bytes # usbpid = ; # DFU USB PID # chip_erase_delay = ; # 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! */ diff --git a/src/config.c b/src/config.c index d36e0814..531dac83 100644 --- a/src/config.c +++ b/src/config.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -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)); + } +} diff --git a/src/config.h b/src/config.h index b8bd2031..42b6219b 100644 --- a/src/config.h +++ b/src/config.h @@ -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 diff --git a/src/config_gram.y b/src/config_gram.y index dfdf50b5..bc48d098 100644 --- a/src/config_gram.y +++ b/src/config_gram.y @@ -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; diff --git a/src/developer_opts.c b/src/developer_opts.c index c8aa903c..8f716f03 100644 --- a/src/developer_opts.c +++ b/src/developer_opts.c @@ -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); diff --git a/src/doc/avrdude.texi b/src/doc/avrdude.texi index cdc7602b..19d019c5 100644 --- a/src/doc/avrdude.texi +++ b/src/doc/avrdude.texi @@ -1694,34 +1694,53 @@ The format of the programmer definition is as follows: @smallexample programmer - parent # is a quoted string + parent # optional parent id = [, [, ] ...] ; # are quoted strings desc = ; # quoted string - type = "par" | "stk500" | ... ; # programmer type (see below for a list) - baudrate = ; # baudrate for serial ports - vcc = [, ... ] ; # pin number(s) - buff = [, ... ] ; # pin number(s) - reset = ; # pin number - sck = ; # pin number - mosi = ; # pin number - miso = ; # pin number - errled = ; # pin number - rdyled = ; # pin number - pgmled = ; # pin number - vfyled = ; # pin number - usbvid = ; # USB VID (Vendor ID) - usbpid = [, ...]; # USB PID (Product ID) - usbdev = ; # USB interface or other device info - usbvendor = ; # USB Vendor Name - usbproduct = ; # USB Product Name - usbsn = ; # USB Serial Number - ; + type = ; # programmer type, quoted string + # supported types can be listed by "-c ?type" + prog_modes = PM_ @{ | PM_ @} # interfaces, eg, PM_SPM|PM_PDI + connection_type = parallel | serial | usb | spi + baudrate = ; # baudrate for avr910-programmer + vcc = [, ... ] ; # pin number(s) + buff = [, ... ] ; # pin number(s) + reset = ; # pin number + sck = ; # pin number + mosi = ; # pin number + miso = ; # pin number + errled = ; # pin number + rdyled = ; # pin number + pgmled = ; # pin number + vfyled = ; # pin number + usbvid = ; # USB VID (Vendor ID) + usbpid = [, ...] ; # USB PID (Product ID) + usbdev = ; # USB interface or other device info + usbvendor = ; # USB Vendor Name + usbproduct = ; # USB Product Name + usbsn = ; # USB Serial Number + hvupdi_support = [, , ... ] ; # 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{= ~ }. @@ -1729,7 +1748,7 @@ To invert a bit in the pin definitions, use @code{= ~ }. 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 = ; # quoted string desc = ; # quoted string - family_id = ; # quoted string + id = ; # quoted string + family_id = ; # quoted string, eg, "megaAVR" or "tinyAVR" + prog_modes = PM_ @{ | PM_ @} # interfaces, eg, PM_SPM|PM_ISP|PM_HVPP|PM_debugWIRE + mcuid = ; # unique id in 0..2039 for urclock programmer + n_interrupts = ; # number of interrupts, used for vector bootloaders + n_page_erase = ; # if set, number of pages erased during NVM erase + hvupdi_variant = ; # numeric -1 (n/a) or 0..2 + devicecode = ; # deprecated, use stk500_devcode + stk500_devcode = ; # numeric + avr910_devcode = ; # numeric has_jtag = ; # part has JTAG i/f has_debugwire = ; # part has debugWire i/f has_pdi = ; # part has PDI i/f has_updi = ; # part has UPDI i/f has_tpi = ; # part has TPI i/f - devicecode = ; # numeric - stk500_devcode = ; # numeric - avr910_devcode = ; # numeric + is_avr32 = ; # AVR32 part + is_at90s1200 = ; # AT90S1200 part signature = ; # signature bytes usbpid = ; # DFU USB PID - reset = dedicated | io; - retry_pulse = reset | sck; - pgm_enable = ; - chip_erase = ; chip_erase_delay = ; # micro-seconds + reset = dedicated | io ; + retry_pulse = reset | sck ; + chip_erase_delay = ; # chip erase delay (us) # STK500 parameters (parallel programming IO lines) pagel = ; # pin name in hex, i.e., 0xD7 bs2 = ; # pin name in hex, i.e., 0xA0 serial = ; # can use serial downloading - parallel = ; # can use par. programming + parallel = ; # can use par. programming # STK500v2 parameters, to be taken from Atmel's XML files timeout = ; stabdelay = ; @@ -1777,52 +1802,59 @@ part predelay = ; postdelay = ; pollmethod = ; - mode = ; - delay = ; - blocksize = ; - readsize = ; hvspcmdexedelay = ; # STK500v2 HV programming parameters, from XML - pp_controlstack = , , ...; # PP only - hvsp_controlstack = , , ...; # HVSP only - hventerstabdelay = ; - progmodedelay = ; # PP only - latchcycles = ; - togglevtg = ; - poweroffdelay = ; - resetdelayms = ; - resetdelayus = ; - hvleavestabdelay = ; - resetdelay = ; - synchcycles = ; # HVSP only - chiperasepulsewidth = ; # PP only - chiperasepolltimeout = ; - chiperasetime = ; # HVSP only - programfusepulsewidth = ; # PP only - programfusepolltimeout = ; - programlockpulsewidth = ; # PP only - programlockpolltimeout = ; + pp_controlstack = , , ... ; # PP only + hvsp_controlstack = , , ... ; # HVSP only + flash_instr = , , ; + eeprom_instr = , , ... ; + hventerstabdelay = ; + progmodedelay = ; # PP only + latchcycles = ; + togglevtg = ; + poweroffdelay = ; + resetdelayms = ; + resetdelayus = ; + hvleavestabdelay = ; + resetdelay = ; + synchcycles = ; # HVSP only + chiperasepulsewidth = ; # PP only + chiperasepolltimeout = ; + chiperasetime = ; # HVSP only + programfusepulsewidth = ; # PP only + programfusepolltimeout = ; + programlockpulsewidth = ; # PP only + programlockpolltimeout = ; # JTAG ICE mkII parameters, also from XML files allowfullpagebitstream = ; enablepageprogramming = ; - idr = ; # IO addr of IDR (OCD) reg. - rampz = ; # IO addr of RAMPZ reg. - spmcr = ; # mem addr of SPMC[S]R reg. - eecr = ; # mem addr of EECR reg. - # (only when != 0x3F) - is_at90s1200 = ; # AT90S1200 part - is_avr32 = ; # AVR32 part + idr = ; # IO addr of IDR (OCD) reg + rampz = ; # IO addr of RAMPZ reg + spmcr = ; # mem addr of SPMC[S]R reg + eecr = ; # mem addr of EECR reg only when != 0x3f + mcu_base = ; + nvm_base = ; + ocd_base = ; + ocdrev = ; + pgm_enable = ; + chip_erase = ; memory - paged = ; # yes / no + paged = ; # yes/no (flash only, do not use for EEPROM) + offset = ; # memory offset size = ; # bytes page_size = ; # bytes num_pages = ; # numeric min_write_delay = ; # micro-seconds max_write_delay = ; # micro-seconds - readback_p1 = ; # byte value - readback_p2 = ; # byte value - pwroff_after_write = ; # yes / no + readback = ; # pair of byte values + readback_p1 = ; # byte value (first component) + readback_p2 = ; # byte value (second component) + pwroff_after_write = ; # yes/no + mode = ; # STK500 v2 file parameter from Atmel's XML files + delay = ; # " + blocksize = ; # " + readsize = ; # " read = ; write = ; read_lo = ; @@ -1832,8 +1864,8 @@ part loadpage_lo = ; loadpage_hi = ; writepage = ; - ; - ; + ; +; @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 diff --git a/src/lexer.l b/src/lexer.l index a69130d3..65b7a451 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -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; } diff --git a/src/libavrdude.h b/src/libavrdude.h index 9288b43b..c99117f4 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -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];