diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f2dfe9cc..f3eedcd8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -252,6 +252,9 @@ add_executable(avrdude main.c term.c term.h + developer_opts.c + developer_opts.h + developer_opts_private.h whereami.c whereami.h "${EXTRA_WINDOWS_RESOURCES}" diff --git a/src/Makefile.am b/src/Makefile.am index 15162224..9e0929e1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -198,6 +198,9 @@ avrdude_SOURCES = \ main.c \ whereami.c \ whereami.h \ + developer_opts.c \ + developer_opts.h \ + developer_opts_private.h \ term.c \ term.h diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in index 8fc67080..8a9bca41 100644 --- a/src/avrdude.conf.in +++ b/src/avrdude.conf.in @@ -12,7 +12,7 @@ # # DO NOT MODIFY THIS FILE. Modifications will be overwritten the next # time a "make install" is run. For user-specific additions, use the -# "-C +filename" commandline option. +# "-C +filename" command line option. # # Possible entry formats are: # @@ -34,12 +34,12 @@ # rdyled = ; # pin number # pgmled = ; # pin number # vfyled = ; # pin number -# usbvid = ; # USB VID (Vendor ID) -# usbpid = [, ...] # USB PID (Product ID) (1) -# usbdev = ; # USB interface or other device info -# usbvendor = ; # USB Vendor Name -# usbproduct = ; # USB Product Name -# usbsn = ; # USB Serial Number +# usbvid = ; # USB VID (Vendor ID) +# usbpid = [, ...] ; # USB PID (Product ID) (1) +# 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. @@ -48,32 +48,34 @@ # specify it as follows = ~ ( [, ... ] ) . # # (1) Not all programmer types can process a list of PIDs. -# ; +# ; # # part -# id = ; # quoted string # desc = ; # quoted string +# id = ; # quoted string +# family_id = ; # quoted string, eg, "megaAVR" or "tinyAVR" +# 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 = ; # deprecated, use stk500_devcode -# stk500_devcode = ; # numeric -# avr910_devcode = ; # numeric +# is_at90s1200 = ; # AT90S1200 part +# is_avr32 = ; # AVR32 part # signature = ; # signature bytes # usbpid = ; # DFU USB PID # chip_erase_delay = ; # micro-seconds -# reset = dedicated | io; -# retry_pulse = reset | sck; -# pgm_enable = ; -# chip_erase = ; +# 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 = ; @@ -85,52 +87,59 @@ # 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 != 0x3c) -# 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 != 0x3c +# 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, to be taken from Atmel's XML files +# delay = ; # " +# blocksize = ; # " +# readsize = ; # " # read = ; # write = ; # read_lo = ; @@ -140,11 +149,12 @@ # loadpage_lo = ; # loadpage_hi = ; # writepage = ; -# ; -# ; +# ; +# ; # # If any of the above parameters are not specified, the default value -# of 0 is used for numerics or the empty string ("") for string +# of 0 is used for numerics (except for hvupdi_variant and ocdrev, +# where the default value is -1) or the empty string ("") for string # values. If a required parameter is left empty, AVRDUDE will # complain. # @@ -152,7 +162,12 @@ # using the following syntax. In this case specified integer and # string values override parameter values from the parent part. New # memory definitions are added to the definitions inherited from the -# parent. +# parent. If, however, a new memory definition refers to an existing +# one of the same name for that part then, from v7.1, the existing +# memory definition is extended, and components overwritten with new +# values. Assigning NULL removes an inherited SPI instruction format, +# memory definition, control stack, eeprom or flash instruction, eg, +# as in memory "efuse" = NULL; # # part parent # quoted string # id = ; # quoted string @@ -181,7 +196,7 @@ # # INSTRUCTION FORMATS # -# Instruction formats are specified as a comma seperated list of +# Instruction formats are specified as a comma separated list of # string values containing information (bit specifiers) about each # of the 32 bits of the instruction. Bit specifiers may be one of # the following formats: @@ -190,10 +205,11 @@ # # '0' = the bit is always clear on input as well as output # -# 'x' = the bit is ignored on input and output +# 'x' = the bit is ignored on input and output and set as 0 # -# 'a' = the bit is an address bit, the bit-number matches this bit -# specifier's position within the current instruction byte +# 'a' = the bit is an address bit; from v 7.1 the bit-number +# is set to match the right bit position for the +# instruction to "just work" # # 'aN' = the bit is the Nth address bit, bit-number = N, i.e., a12 # is address bit 12 on input, a0 is address bit 0. @@ -202,11 +218,28 @@ # # 'o' = the bit is an output data bit # -# Each instruction must be composed of 32 bit specifiers. The +# Each instruction must be composed of 32 bit specifiers. The # instruction specification closely follows the instruction data -# provided in Atmel's data sheets for their parts. +# provided in Atmel's data sheets for their parts. Note that flash +# addresses always refer to *word* addresses whilst all other +# memory types specify *byte* addresses. # -# See below for some examples. +# Example for signature read on the ATmega328P: +# read = "0 0 1 1 0 0 0 0", "0 0 0 x x x x x", +# "x x x x x x a1 a0", "o o o o o o o o"; +# +# 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 0, 1, x, a, i and o will be +# recognised as the corresponding bit, whilst any of the characters +# ., -, _ or / can act as arbitrary visual separators, which are +# ignored. Examples: +# +# loadpage_lo = "0100.0000--000x.xxxx--xxaa.aaaa--iiii.iiii"; +# +# loadpage_lo = "0100.0000", "000x.xxxx", "xxaa.aaaa", "iiii.iiii"; # # # The following are STK500 part device codes to use for the @@ -11845,6 +11878,8 @@ part parent "m2561" " a7 x x x x x x x", " x x x x x x x x"; + load_ext_addr = NULL; + mode = 0x41; delay = 20; blocksize = 256; diff --git a/src/avrpart.c b/src/avrpart.c index 34608155..4fc6304f 100644 --- a/src/avrpart.c +++ b/src/avrpart.c @@ -71,6 +71,21 @@ void avr_free_opcode(OPCODE * op) free(op); } + +// returns position 0..31 of highest bit set or INT_MIN if no bit is set +int intlog2(unsigned int n) { + int ret; + + if(!n) + return INT_MIN; + + for(ret = 0; n >>= 1; ret++) + continue; + + return ret; +} + + /* * avr_set_bits() * @@ -126,6 +141,101 @@ int avr_set_addr(OPCODE * op, unsigned char * cmd, unsigned long addr) } +/* + * avr_set_addr_mem() + * + * Set address bits in the specified command based on the memory, opcode and + * address; addr must be a word address for flash or, for all other memories, + * a byte address; returns 0 on success and -1 on error (no memory or no + * opcode) or, if positive, bn+1 where bn is bit number of the highest + * necessary bit that the opcode does not provide. + */ +int avr_set_addr_mem(AVRMEM *mem, int opnum, unsigned char *cmd, unsigned long addr) { + int ret, isflash, lo, hi, memsize, pagesize; + OPCODE *op; + + if(!mem) + return -1; + + if(!(op = mem->op[opnum])) + return -1; + + isflash = !strcmp(mem->desc, "flash"); // ISP parts have only one flash-like memory + memsize = mem->size >> isflash; // word addresses for flash + pagesize = mem->page_size >> isflash; + + // compute range lo..hi of needed address bits + switch(opnum) { + case AVR_OP_READ: + case AVR_OP_WRITE: + case AVR_OP_READ_LO: + case AVR_OP_READ_HI: + case AVR_OP_WRITE_LO: + case AVR_OP_WRITE_HI: + lo = 0; + hi = intlog2(memsize-1); // memsize = 1 implies no addr bit is needed + break; + + case AVR_OP_LOADPAGE_LO: + case AVR_OP_LOADPAGE_HI: + lo = 0; + hi = intlog2(pagesize-1); + break; + + case AVR_OP_LOAD_EXT_ADDR: + lo = 16; + hi = intlog2(memsize-1); + break; + + case AVR_OP_WRITEPAGE: + lo = intlog2(pagesize); + hi = intlog2(memsize-1); + break; + + case AVR_OP_CHIP_ERASE: + case AVR_OP_PGM_ENABLE: + default: + lo = 0; + hi = -1; + break; + } + + // Unless it's load extended address, ISP chips only deal with 16 bit addresses + if(opnum != AVR_OP_LOAD_EXT_ADDR && hi > 15) + hi = 15; + + unsigned char avail[32]; + memset(avail, 0, sizeof avail); + + for(int i=0; i<32; i++) { + if(op->bit[i].type == AVR_CMDBIT_ADDRESS) { + int bitno, j, bit; + unsigned char mask; + + bitno = op->bit[i].bitno & 31; + j = 3 - i / 8; + bit = i % 8; + mask = 1 << bit; + avail[bitno] = 1; + + // 'a' bit with number outside bit range [lo, hi] is set to 0 + if (bitno >= lo && bitno <= hi? (addr >> bitno) & 1: 0) + cmd[j] = cmd[j] | mask; + else + cmd[j] = cmd[j] & ~mask; + } + } + + ret = 0; + if(lo >= 0 && hi < 32 && lo <= hi) + for(int bn=lo; bn <= hi; bn++) + if(!avail[bn]) // necessary bit bn misses in opcode + ret = bn+1; + + return ret; +} + + /* * avr_set_input() * @@ -239,7 +349,6 @@ static char * bittype(int type) } - /*** *** Elementary functions dealing with AVRMEM structures ***/ @@ -354,7 +463,6 @@ AVRMEM_ALIAS * avr_dup_memalias(AVRMEM_ALIAS * m) void avr_free_mem(AVRMEM * m) { - int i; if (m->buf != NULL) { free(m->buf); m->buf = NULL; @@ -363,7 +471,7 @@ void avr_free_mem(AVRMEM * m) free(m->tags); m->tags = NULL; } - for(i=0;iop)/sizeof(m->op[0]);i++) + for(size_t i=0; iop)/sizeof(m->op[0]); i++) { if (m->op[i] != NULL) { @@ -379,13 +487,16 @@ void avr_free_memalias(AVRMEM_ALIAS * m) free(m); } -AVRMEM_ALIAS * avr_locate_memalias(AVRPART * p, char * desc) +AVRMEM_ALIAS * avr_locate_memalias(AVRPART * p, const char * desc) { AVRMEM_ALIAS * m, * match; LNODEID ln; int matches; int l; + if(!p || !desc || !p->mem_alias) + return NULL; + l = strlen(desc); matches = 0; match = NULL; @@ -403,13 +514,16 @@ AVRMEM_ALIAS * avr_locate_memalias(AVRPART * p, char * desc) return NULL; } -AVRMEM * avr_locate_mem_noalias(AVRPART * p, char * desc) +AVRMEM * avr_locate_mem_noalias(AVRPART * p, const char * desc) { AVRMEM * m, * match; LNODEID ln; int matches; int l; + if(!p || !desc || !p->mem) + return NULL; + l = strlen(desc); matches = 0; match = NULL; @@ -428,7 +542,7 @@ AVRMEM * avr_locate_mem_noalias(AVRPART * p, char * desc) } -AVRMEM * avr_locate_mem(AVRPART * p, char * desc) +AVRMEM * avr_locate_mem(AVRPART * p, const char * desc) { AVRMEM * m, * match; AVRMEM_ALIAS * alias; @@ -436,14 +550,19 @@ AVRMEM * avr_locate_mem(AVRPART * p, char * desc) int matches; int l; + if(!p || !desc) + return NULL; + l = strlen(desc); matches = 0; match = NULL; - for (ln=lfirst(p->mem); ln; ln=lnext(ln)) { - m = ldata(ln); - if (strncmp(desc, m->desc, l) == 0) { - match = m; - matches++; + if(p->mem) { + for (ln=lfirst(p->mem); ln; ln=lnext(ln)) { + m = ldata(ln); + if (strncmp(desc, m->desc, l) == 0) { + match = m; + matches++; + } } } @@ -476,7 +595,8 @@ AVRMEM_ALIAS * avr_find_memalias(AVRPART * p, AVRMEM * m_orig) void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, AVRPART * p, int type, int verbose) { - static unsigned int prev_mem_offset, prev_mem_size; + static unsigned int prev_mem_offset; + static int prev_mem_size; int i, j; char * optr; @@ -545,12 +665,10 @@ void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, AVRPART * p, } - /* * Elementary functions dealing with AVRPART structures */ - AVRPART * avr_new_part(void) { AVRPART * p; @@ -568,6 +686,7 @@ AVRPART * avr_new_part(void) p->reset_disposition = RESET_DEDICATED; p->retry_pulse = PIN_AVR_SCK; p->flags = AVRPART_SERIALOK | AVRPART_PARALLELOK | AVRPART_ENABLEPAGEPROGRAMMING; + p->parent_id = NULL; p->config_file = NULL; p->lineno = 0; memset(p->signature, 0xFF, 3); @@ -597,7 +716,6 @@ AVRPART * avr_dup_part(AVRPART * d) p->mem = save; p->mem_alias = save2; - for (ln=lfirst(d->mem); ln; ln=lnext(ln)) { AVRMEM *m = ldata(ln); AVRMEM *m2 = avr_dup_mem(m); @@ -625,28 +743,29 @@ AVRPART * avr_dup_part(AVRPART * d) void avr_free_part(AVRPART * d) { -int i; - ldestroy_cb(d->mem, (void(*)(void *))avr_free_mem); - d->mem = NULL; - ldestroy_cb(d->mem_alias, (void(*)(void *))avr_free_memalias); - d->mem_alias = NULL; - for(i=0;iop)/sizeof(d->op[0]);i++) - { - if (d->op[i] != NULL) - { - avr_free_opcode(d->op[i]); - d->op[i] = NULL; - } + ldestroy_cb(d->mem, (void(*)(void *))avr_free_mem); + d->mem = NULL; + ldestroy_cb(d->mem_alias, (void(*)(void *))avr_free_memalias); + d->mem_alias = NULL; + /* do not free d->parent_id and d->config_file */ + for(size_t i=0; iop)/sizeof(d->op[0]); i++) { + if (d->op[i] != NULL) { + avr_free_opcode(d->op[i]); + d->op[i] = NULL; } - free(d); + } + free(d); } -AVRPART * locate_part(LISTID parts, char * partdesc) +AVRPART * locate_part(LISTID parts, const char * partdesc) { LNODEID ln1; AVRPART * p = NULL; int found; + if(!parts || !partdesc) + return NULL; + found = 0; for (ln1=lfirst(parts); ln1 && !found; ln1=lnext(ln1)) { @@ -807,3 +926,232 @@ void avr_display(FILE * f, AVRPART * p, const char * prefix, int verbose) if (buf) free(buf); } + + +char cmdbitchar(CMDBIT cb) { + switch(cb.type) { + case AVR_CMDBIT_IGNORE: + return 'x'; + case AVR_CMDBIT_VALUE: + return cb.value? '1': '0'; + case AVR_CMDBIT_ADDRESS: + return 'a'; + case AVR_CMDBIT_INPUT: + return 'i'; + case AVR_CMDBIT_OUTPUT: + return 'o'; + default: + return '?'; + } +} + + +char *cmdbitstr(CMDBIT cb) { + char space[32]; + + *space = cmdbitchar(cb); + if(*space == 'a') + sprintf(space+1, "%d", cb.bitno); + else + space[1] = 0; + + return strdup(space); +} + + +const char *opcodename(int opnum) { + switch(opnum) { + case AVR_OP_READ: + return "read"; + case AVR_OP_WRITE: + return "write"; + case AVR_OP_READ_LO: + return "read_lo"; + case AVR_OP_READ_HI: + return "read_hi"; + case AVR_OP_WRITE_LO: + return "write_lo"; + case AVR_OP_WRITE_HI: + return "write_hi"; + case AVR_OP_LOADPAGE_LO: + return "loadpage_lo"; + case AVR_OP_LOADPAGE_HI: + return "loadpage_hi"; + case AVR_OP_LOAD_EXT_ADDR: + return "load_ext_addr"; + case AVR_OP_WRITEPAGE: + return "writepage"; + case AVR_OP_CHIP_ERASE: + return "chip_erase"; + case AVR_OP_PGM_ENABLE: + return "pgm_enable"; + default: + return "???"; + } +} + + +// Unique string representation of an opcode +char *opcode2str(OPCODE *op, int opnum, int detailed) { + char cb, space[1024], *sp = space; + int compact = 1; + + if(!op) + return strdup("NULL"); + + // Can the opcode be printed in a compact way? Only if address bits are systematic. + for(int i=31; i >= 0; i--) + if(op->bit[i].type == AVR_CMDBIT_ADDRESS) + if(i<8 || i>23 || op->bit[i].bitno != (opnum == AVR_OP_LOAD_EXT_ADDR? i+8: i-8)) + compact = 0; + + if(detailed) + *sp++ = '"'; + + for(int i=31; i >= 0; i--) { + *sp++ = cb = cmdbitchar(op->bit[i]); + if(compact) { + if(i && i%8 == 0) + *sp++ = '-', *sp++ = '-'; + else if(i && i%4 == 0) + *sp++ = '.'; + } else { + if(cb == 'a') { + sprintf(sp, "%d", op->bit[i].bitno); + sp += strlen(sp); + } + if(i) { + if(detailed) + *sp++ = ' '; + if(i%8 == 0) + *sp++ = ' '; + } + } + } + if(detailed) + *sp++ = '"'; + *sp = 0; + + return strdup(space); +} + + +/* + * Match STRING against the partname pattern PATTERN, returning 1 if it + * matches, 0 if not. NOTE: part_match() is a modified old copy of !fnmatch() + * from the GNU C Library (published under GLP v2). Used for portability. + */ + +inline static int fold(int c) { + return (c >= 'A' && c <= 'Z')? c+('a'-'A'): c; +} + +int part_match(const char *pattern, const char *string) { + unsigned char c; + const char *p = pattern, *n = string; + + if(!*n) // AVRDUDE specialty: empty string never matches + return 0; + + while((c = fold(*p++))) { + switch(c) { + case '?': + if(*n == 0) + return 0; + break; + + case '\\': + c = fold(*p++); + if(fold(*n) != c) + return 0; + break; + + case '*': + for(c = *p++; c == '?' || c == '*'; c = *p++) + if(c == '?' && *n++ == 0) + return 0; + + if(c == 0) + return 1; + + { + unsigned char c1 = fold(c == '\\'? *p : c); // This char + + for(--p; *n; ++n) // Recursively check reminder of string for * + if((c == '[' || fold(*n) == c1) && part_match(p, n) == 1) + return 1; + return 0; + } + + case '[': + { + int negate; + + if(*n == 0) + return 0; + + negate = (*p == '!' || *p == '^'); + if(negate) + ++p; + + c = *p++; + for(;;) { + unsigned char cstart = c, cend = c; + + if(c == '\\') + cstart = cend = *p++; + + cstart = cend = fold(cstart); + + if(c == 0) // [ (unterminated) + return 0; + + c = *p++; + c = fold(c); + + if(c == '-' && *p != ']') { + cend = *p++; + if(cend == '\\') + cend = *p++; + if(cend == 0) + return 0; + cend = fold(cend); + + c = *p++; + } + + if(fold(*n) >= cstart && fold(*n) <= cend) + goto matched; + + if(c == ']') + break; + } + if(!negate) + return 0; + break; + + matched:; + while(c != ']') { // Skip the rest of the [...] that already matched + + if(c == 0) // [... (unterminated) + return 0; + + c = *p++; + if(c == '\\') // XXX 1003.2d11 is unclear if this is right + ++p; + } + if(negate) + return 0; + } + break; + + default: + if(c != fold(*n)) + return 0; + } + + ++n; + } + + return *n == 0; +} diff --git a/src/config_gram.y b/src/config_gram.y index 2c6c1f46..68718dd1 100644 --- a/src/config_gram.y +++ b/src/config_gram.y @@ -25,10 +25,12 @@ #include #include #include +#include #include "avrdude.h" #include "libavrdude.h" #include "config.h" +#include "developer_opts.h" #if defined(WIN32) #define strtok_r( _s, _sep, _lasts ) \ @@ -45,11 +47,13 @@ int yywarning(char * errmsg, ...); static int assign_pin(int pinno, TOKEN * v, int invert); static int assign_pin_list(int invert); static int which_opcode(TOKEN * opcode); -static int parse_cmdbits(OPCODE * op); +static int parse_cmdbits(OPCODE * op, int opnum); static int pin_name; %} +%token K_NULL; + %token K_READ %token K_WRITE %token K_READ_LO @@ -112,6 +116,7 @@ static int pin_name; %token K_PSEUDO %token K_PWROFF_AFTER_WRITE %token K_RDYLED +%token K_READBACK %token K_READBACK_P1 %token K_READBACK_P2 %token K_READMEM @@ -329,6 +334,7 @@ prog_decl : free_token($3); YYABORT; } + current_prog->parent_id = cache_string($3->value.string); current_prog->config_file = cache_string(cfg_infile); current_prog->lineno = cfg_lineno; free_token($3); @@ -420,6 +426,7 @@ part_decl : free_token($3); YYABORT; } + current_part->parent_id = cache_string($3->value.string); current_part->config_file = cache_string(cfg_infile); current_part->lineno = cfg_lineno; @@ -797,6 +804,13 @@ part_parm : } } | + K_PP_CONTROLSTACK TKN_EQUAL K_NULL { + { + current_part->ctl_stack_type = CTL_STACK_NONE; + memset(current_part->controlstack, 0, CTL_STACK_SIZE); + } + } | + K_HVSP_CONTROLSTACK TKN_EQUAL num_list { { TOKEN * t; @@ -828,6 +842,13 @@ part_parm : } } | + K_HVSP_CONTROLSTACK TKN_EQUAL K_NULL { + { + current_part->ctl_stack_type = CTL_STACK_NONE; + memset(current_part->controlstack, 0, CTL_STACK_SIZE); + } + } | + K_FLASH_INSTR TKN_EQUAL num_list { { TOKEN * t; @@ -858,6 +879,12 @@ part_parm : } } | + K_FLASH_INSTR TKN_EQUAL K_NULL { + { + memset(current_part->flash_instr, 0, FLASH_INSTR_SIZE); + } + } | + K_EEPROM_INSTR TKN_EQUAL num_list { { TOKEN * t; @@ -888,6 +915,12 @@ part_parm : } } | + K_EEPROM_INSTR TKN_EQUAL K_NULL { + { + memset(current_part->eeprom_instr, 0, EEPROM_INSTR_SIZE); + } + } | + K_CHIP_ERASE_DELAY TKN_EQUAL TKN_NUMBER { current_part->chip_erase_delay = $3->value.number; @@ -1275,35 +1308,50 @@ part_parm : */ K_MEMORY TKN_STRING - { - current_mem = avr_new_memtype(); - if (current_mem == NULL) { - yyerror("could not create mem instance"); - free_token($2); - YYABORT; + { /* select memory for extension or create if not there */ + AVRMEM *mem = avr_locate_mem_noalias(current_part, $2->value.string); + if(!mem) { + if(!(mem = avr_new_memtype())) { + yyerror("could not create mem instance"); + free_token($2); + YYABORT; + } + strncpy(mem->desc, $2->value.string, AVR_MEMDESCLEN - 1); + mem->desc[AVR_MEMDESCLEN-1] = 0; + ladd(current_part->mem, mem); } - strncpy(current_mem->desc, $2->value.string, AVR_MEMDESCLEN - 1); - current_mem->desc[AVR_MEMDESCLEN-1] = 0; + current_mem = mem; free_token($2); } mem_specs - { - AVRMEM * existing_mem; + { + if (is_alias) { // alias mem has been already entered + lrmv_d(current_part->mem, current_mem); + avr_free_mem(current_mem); + is_alias = false; + } else { // check all opcodes re necessary address bits + unsigned char cmd[4] = { 0, 0, 0, 0, }; + int bn; - existing_mem = avr_locate_mem_noalias(current_part, current_mem->desc); + for(int i=0; iop[i]) { + if((bn = avr_set_addr_mem(current_mem, i, cmd, 0UL)) > 0) + yywarning("%s's %s %s misses a necessary address bit a%d", + current_part->desc, current_mem->desc, opcodename(i), bn-1); + } + } + current_mem = NULL; + } | + K_MEMORY TKN_STRING TKN_EQUAL K_NULL + { + AVRMEM *existing_mem = avr_locate_mem_noalias(current_part, $2->value.string); if (existing_mem != NULL) { lrmv_d(current_part->mem, existing_mem); avr_free_mem(existing_mem); } - if (is_alias) { - avr_free_mem(current_mem); // alias mem has been already entered below - is_alias = false; - } else { - ladd(current_part->mem, current_mem); - } - current_mem = NULL; + free_token($2); + current_mem = NULL; } | - opcode TKN_EQUAL string_list { { int opnum; @@ -1317,13 +1365,27 @@ part_parm : free_token($1); YYABORT; } - if(0 != parse_cmdbits(op)) YYABORT; + if(0 != parse_cmdbits(op, opnum)) + YYABORT; if (current_part->op[opnum] != NULL) { /*yywarning("operation redefined");*/ avr_free_opcode(current_part->op[opnum]); } current_part->op[opnum] = op; + free_token($1); + } + } | + + opcode TKN_EQUAL K_NULL { + { + int opnum = which_opcode($1); + if(opnum < 0) + YYABORT; + if(current_part->op[opnum] != NULL) + avr_free_opcode(current_part->op[opnum]); + current_part->op[opnum] = NULL; + free_token($1); } } @@ -1398,6 +1460,14 @@ mem_spec : free_token($3); } | + K_READBACK TKN_EQUAL TKN_NUMBER TKN_NUMBER + { + current_mem->readback[0] = $3->value.number; + current_mem->readback[1] = $4->value.number; + free_token($3); + free_token($4); + } | + K_READBACK_P1 TKN_EQUAL TKN_NUMBER { current_mem->readback[0] = $3->value.number; @@ -1455,13 +1525,27 @@ mem_spec : free_token($1); YYABORT; } - if(0 != parse_cmdbits(op)) YYABORT; + if(0 != parse_cmdbits(op, opnum)) + YYABORT; if (current_mem->op[opnum] != NULL) { /*yywarning("operation redefined");*/ avr_free_opcode(current_mem->op[opnum]); } current_mem->op[opnum] = op; + free_token($1); + } + } | + + opcode TKN_EQUAL K_NULL { + { + int opnum = which_opcode($1); + if(opnum < 0) + YYABORT; + if(current_mem->op[opnum] != NULL) + avr_free_opcode(current_mem->op[opnum]); + current_mem->op[opnum] = NULL; + free_token($1); } } @@ -1579,15 +1663,12 @@ static int which_opcode(TOKEN * opcode) } -static int parse_cmdbits(OPCODE * op) +static int parse_cmdbits(OPCODE * op, int opnum) { - TOKEN * t; + TOKEN *t; int bitno; - char ch; - char * e; - char * q; int len; - char * s, *brkt = NULL; + char *s, *brkt = NULL; int rv = 0; bitno = 32; @@ -1595,10 +1676,18 @@ static int parse_cmdbits(OPCODE * op) t = lrmv_n(string_list, 1); - s = strtok_r(t->value.string, " ", &brkt); + char *str = t->value.string; + // Compact alternative specification? (eg, "0100.0000--000x.xxxx--xxaa.aaaa--iiii.iiii") + char bit[2] = {0, 0}, *cc = str; + int compact = !strchr(str, ' ') && strlen(str) > 7; + + bit[0] = *cc++; + s = !compact? strtok_r(str, " ", &brkt): *bit? bit: NULL; while (rv == 0 && s != NULL) { - bitno--; + // Ignore visual grouping characters in compact mode + if(*s != '.' && *s != '-' && *s != '_' && *s !='/') + bitno--; if (bitno < 0) { yyerror("too many opcode bits for instruction"); rv = -1; @@ -1613,10 +1702,8 @@ static int parse_cmdbits(OPCODE * op) break; } - ch = s[0]; - if (len == 1) { - switch (ch) { + switch (*s) { case '1': op->bit[bitno].type = AVR_CMDBIT_VALUE; op->bit[bitno].value = 1; @@ -1635,7 +1722,10 @@ static int parse_cmdbits(OPCODE * op) case 'a': op->bit[bitno].type = AVR_CMDBIT_ADDRESS; op->bit[bitno].value = 0; - op->bit[bitno].bitno = 8*(bitno/8) + bitno % 8; + op->bit[bitno].bitno = bitno < 8 || bitno > 23? 0: + opnum == AVR_OP_LOAD_EXT_ADDR? bitno+8: bitno-8; /* correct bit number for lone 'a' */ + if(bitno < 8 || bitno > 23) + yywarning("address bits don't normally appear in Bytes 0 or 3 of SPI commands"); break; case 'i': op->bit[bitno].type = AVR_CMDBIT_INPUT; @@ -1647,21 +1737,40 @@ static int parse_cmdbits(OPCODE * op) op->bit[bitno].value = 0; op->bit[bitno].bitno = bitno % 8; break; + case '.': + case '-': + case '_': + case '/': + break; default : - yyerror("invalid bit specifier '%c'", ch); + yyerror("invalid bit specifier '%c'", *s); rv = -1; break; } } else { - if (ch == 'a') { - q = &s[1]; - op->bit[bitno].bitno = strtol(q, &e, 0); - if ((e == q)||(*e != 0)) { - yyerror("can't parse bit number from \"%s\"", q); - rv = -1; - break; + if (*s == 'a') { + int sb, bn; + char *e, *q; + + q = s+1; + errno = 0; + bn = strtol(q, &e, 0); // address line + if (e == q || *e != 0 || errno) { + yywarning("can't parse bit number from a%s", q); + bn = 0; } + + sb = opnum == AVR_OP_LOAD_EXT_ADDR? bitno+8: bitno-8; // should be this number + if(bitno < 8 || bitno > 23) + yywarning("address bits don't normally appear in Bytes 0 or 3 of SPI commands"); + else if((bn & 31) != sb) + yywarning("a%d would normally be expected to be a%d", bn, sb); + else if(bn < 0 || bn > 31) + yywarning("invalid address bit a%d, using a%d", bn, bn & 31); + + op->bit[bitno].bitno = bn & 31; + op->bit[bitno].type = AVR_CMDBIT_ADDRESS; op->bit[bitno].value = 0; } @@ -1672,12 +1781,16 @@ static int parse_cmdbits(OPCODE * op) } } - s = strtok_r(NULL, " ", &brkt); + bit[0] = *cc++; + s = !compact? strtok_r(NULL, " ", &brkt): *bit? bit: NULL; } /* while */ free_token(t); } /* while */ + if(bitno > 0) + yywarning("too few opcode bits in instruction"); + return rv; } diff --git a/src/developer_opts.c b/src/developer_opts.c new file mode 100644 index 00000000..f4a55478 --- /dev/null +++ b/src/developer_opts.c @@ -0,0 +1,917 @@ +/* + * avrdude - A Downloader/Uploader for AVR device programmers + * Copyright (C) 2022, Stefan Rueger + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* $Id$ */ + +/* + * Code to program an Atmel AVR device through one of the supported + * programmers. + * + * For parallel port connected programmers, the pin definitions can be + * changed via a config file. See the config file for instructions on + * how to add a programmer definition. + * + */ + +#include "ac_cfg.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "avrdude.h" +#include "libavrdude.h" + +#include "developer_opts.h" +#include "developer_opts_private.h" + +// return 0 if op code would encode (essentially) the same SPI command +static int opcodecmp(OPCODE *op1, OPCODE *op2, int opnum) { + char *opstr1, *opstr2, *p; + int cmp; + + if(!op1 && !op2) + return 0; + if(!op1 || !op2) + return op1? -1: 1; + + opstr1 = opcode2str(op1, opnum, 1); + opstr2 = opcode2str(op2, opnum, 1); + if(!opstr1 || !opstr2) { + dev_info("%s: out of memory\n", progname); + exit(1); + } + + // don't care x and 0 are functionally equivalent + for(p=opstr1; *p; p++) + if(*p == 'x') + *p = '0'; + for(p=opstr2; *p; p++) + if(*p == 'x') + *p = '0'; + + cmp = strcmp(opstr1, opstr2); + free(opstr1); + free(opstr2); + + return cmp; +} + + +static void printopcode(AVRPART *p, const char *d, OPCODE *op, int opnum) { + unsigned char cmd[4]; + int i; + + if(op) { + memset(cmd, 0, sizeof cmd); + avr_set_bits(op, cmd); + + dev_info(".op\t%s\t%s\t%s\t0x%02x%02x%02x%02x\t", p->desc, d, opcodename(opnum), cmd[0], cmd[1], cmd[2], cmd[3]); + for(i=31; i >= 0; i--) { + dev_info("%c", cmdbitchar(op->bit[i])); + if(i%8 == 0) + dev_info("%c", i? '\t': '\n'); + } + } +} + +static void printallopcodes(AVRPART *p, const char *d, OPCODE **opa) { + for(int i=0; iflags & (AVRPART_HAS_PDI | AVRPART_AVR32 | AVRPART_HAS_TPI | AVRPART_HAS_UPDI)) { + case 0: strcpy(type, "ISP"); break; + case AVRPART_HAS_PDI: strcpy(type, "PDI"); break; + case AVRPART_AVR32: strcpy(type, "AVR32"); break; + case AVRPART_HAS_TPI: strcpy(type, "TPI"); break; + case AVRPART_HAS_UPDI: strcpy(type, "UPDI"); break; + default: strcpy(type, "UNKNOWN"); break; + } + + if((p->flags & AVRPART_SERIALOK) == 0) + strcat(type, "|NOTSERIAL"); + if((p->flags & AVRPART_PARALLELOK) == 0) + strcat(type, "|NOTPARALLEL"); + if(p->flags & AVRPART_PSEUDOPARALLEL) + strcat(type, "|PSEUDOPARALLEL"); + if(p->flags & AVRPART_IS_AT90S1200) + strcat(type, "|IS_AT90S1200"); + + if(p->flags & AVRPART_HAS_DW) + strcat(type, "|DW"); + + if(p->flags & AVRPART_HAS_JTAG) + strcat(type, "|JTAG"); + if(p->flags & AVRPART_ALLOWFULLPAGEBITSTREAM) + strcat(type, "|PAGEBITSTREAM"); + if((p->flags & AVRPART_ENABLEPAGEPROGRAMMING) == 0) + strcat(type, "|NOPAGEPROGRAMMING"); + + return type; +} + + +// check whether address bits are where they should be in ISP commands +static void checkaddr(int memsize, int pagesize, int opnum, OPCODE *op, AVRPART *p, AVRMEM *m) { + int i, lo, hi; + const char *opstr = opcodename(opnum); + + lo = intlog2(pagesize); + hi = intlog2(memsize-1); + + // address bits should be between positions lo and hi (and fall in line), outside should be 0 or don't care + for(i=0; i<16; i++) { // ISP programming only deals with 16-bit addresses (words for flash, bytes for eeprom) + if(i < lo || i > hi) { + if(op->bit[i+8].type != AVR_CMDBIT_IGNORE && !(op->bit[i+8].type == AVR_CMDBIT_VALUE && op->bit[i+8].value == 0)) { + char *cbs = cmdbitstr(op->bit[i+8]); + dev_info(".cmderr\t%s\t%s-%s\tbit %d outside addressable space should be x or 0 but is %s\n", p->desc, m->desc, opstr, i+8, cbs? cbs: "NULL"); + if(cbs) + free(cbs); + } + } else { + if(op->bit[i+8].type != AVR_CMDBIT_ADDRESS) + dev_info(".cmderr\t%s\t%s-%s\tbit %d is %c but should be a\n", p->desc, m->desc, opstr, i+8, cmdbitchar(op->bit[i+8])); + else if(op->bit[i+8].bitno != i) + dev_info(".cmderr\t%s\t%s-%s\tbit %d inconsistent: a%d specified as a%d\n", p->desc, m->desc, opstr, i+8, i, op->bit[i+8].bitno); + } + } + for(i=0; i<32; i++) // command bits 8..23 should not contain address bits + if((i<8 || i>23) && op->bit[i].type == AVR_CMDBIT_ADDRESS) + dev_info(".cmderr\t%s\t%s-%s\tbit %d contains a%d which it shouldn't\n", p->desc, m->desc, opstr, i, op->bit[i].bitno); +} + + + +static char *dev_sprintf(const char *fmt, ...) { + int size = 0; + char *p = NULL; + va_list ap; + + // compute size + va_start(ap, fmt); + size = vsnprintf(p, size, fmt, ap); + va_end(ap); + + if(size < 0) + return NULL; + + size++; // for temrinating '\0' + if(!(p = malloc(size))) + return NULL; + + va_start(ap, fmt); + size = vsnprintf(p, size, fmt, ap); + va_end(ap); + + if(size < 0) { + free(p); + return NULL; + } + + return p; +} + + +static int dev_nprinted; + +int dev_message(int msglvl, const char *fmt, ...) { + va_list ap; + int rc = 0; + + if(verbose >= msglvl) { + va_start(ap, fmt); + rc = vfprintf(stderr, fmt, ap); + va_end(ap); + if(rc > 0) + dev_nprinted += rc; + } + + return rc; +} + + + +static int dev_part_strct_entry(bool tsv, char *col0, char *col1, char *col2, const char *name, char *cont) { + const char *n = name? name: "name_error"; + const char *c = cont? cont: "cont_error"; + + if(tsv) { // tab separated values + if(col0) { + dev_info("%s\t", col0); + if(col1) { + dev_info("%s\t", col1); + if(col2) { + dev_info("%s\t", col2); + } + } + } + dev_info("%s\t%s\n", n, c); + } else { // grammar conform + int indent = col2 && strcmp(col2, "part"); + + printf("%*s%-*s = %s;\n", indent? 8: 4, "", indent? 15: 19, n, c); + } + + if(cont) + free(cont); + + return 1; +} + + +static const char *dev_controlstack_name(AVRPART *p) { + return + p->ctl_stack_type == CTL_STACK_PP? "pp_controlstack": + p->ctl_stack_type == CTL_STACK_HVSP? "hvsp_controlstack": + p->ctl_stack_type == CTL_STACK_NONE? "NULL": + "unknown_controlstack"; +} + + +static void dev_stack_out(bool tsv, AVRPART *p, const char *name, unsigned char *stack, int ns) { + if(!strcmp(name, "NULL")) { + name = "pp_controlstack"; + ns = 0; + } + + if(tsv) + dev_info(".pt\t%s\t%s\t", p->desc, name); + else + dev_info(" %-19s =%s", name, ns <=8? " ": ""); + + if(ns <= 0) + dev_info(tsv? "NULL\n": "NULL;\n"); + else + for(int i=0; i 8 && i%8 == 0? "\n ": "", stack[i], i+1base = *m; + + // zap all bytes beyond terminating nul of desc array + len = strlen(m->desc)+1; + if(len < sizeof m->desc) + memset(d->base.desc + len, 0, sizeof m->desc - len); + + // zap address values + d->base.buf = NULL; + d->base.tags = NULL; + for(int i=0; ibase.op[i] = NULL; + + + // copy over the SPI operations themselves + memset(d->base.op, 0, sizeof d->base.op); + memset(d->ops, 0, sizeof d->ops); + for(size_t i=0; iops/sizeof *d->ops; i++) + if(m->op[i]) + d->ops[i] = *m->op[i]; + + return 0; +} + +static int memorycmp(AVRMEM *m1, AVRMEM *m2) { + AVRMEMdeep dm1, dm2; + + if(!m1 && !m2) + return 0; + + if(!m1 || !m2) + return m1? -1: 1; + + avrmem_deep_copy(&dm1, m1); + avrmem_deep_copy(&dm2, m2); + + return memcmp(&dm1, &dm2, sizeof dm1); +} + + +typedef struct { + AVRPART base; + OPCODE ops[AVR_OP_MAX]; + AVRMEMdeep mems[40]; +} AVRPARTdeep; + +static int avrpart_deep_copy(AVRPARTdeep *d, AVRPART *p) { + AVRMEM *m; + size_t len, di; + + memset(d, 0, sizeof *d); + + d->base = *p; + + d->base.parent_id = NULL; + d->base.config_file = NULL; + d->base.lineno = 0; + + // zap all bytes beyond terminating nul of desc, id and family_id array + len = strlen(p->desc); + if(len < sizeof p->desc) + memset(d->base.desc + len, 0, sizeof p->desc - len); + + len = strlen(p->family_id); + if(len < sizeof p->family_id) + memset(d->base.family_id + len, 0, sizeof p->family_id - len); + + len = strlen(p->id); + if(len < sizeof p->id) + memset(d->base.id + len, 0, sizeof p->id - len); + + // zap address values + d->base.mem = NULL; + d->base.mem_alias = NULL; + for(int i=0; ibase.op[i] = NULL; + + // copy over the SPI operations + memset(d->base.op, 0, sizeof d->base.op); + memset(d->ops, 0, sizeof d->ops); + for(int i=0; iop[i]) + d->ops[i] = *p->op[i]; + + // fill in all memories we got in defined order + di = 0; + for(size_t mi=0; mi < sizeof mem_order/sizeof *mem_order && mem_order[mi]; mi++) { + m = p->mem? avr_locate_mem(p, mem_order[mi]): NULL; + if(m) { + if(di >= sizeof d->mems/sizeof *d->mems) { + avrdude_message(MSG_INFO, "%s: ran out of mems[] space, increase size in AVRMEMdeep of developer_opts.c and recompile\n", progname); + exit(1); + } + avrmem_deep_copy(d->mems+di, m); + di++; + } + } + + return di; +} + +static char txtchar(unsigned char in) { + in &= 0x7f; + return in == ' '? '_': in > ' ' && in < 0x7f? in: '.'; +} + + +static void dev_raw_dump(unsigned char *p, int nbytes, const char *name, const char *sub, int idx) { + unsigned char *end = p+nbytes; + int n = ((end - p) + 15)/16; + + for(int i=0; idesc, "part", 0); + dev_raw_dump((unsigned char *) &dp.ops, sizeof dp.ops, part->desc, "ops", 1); + + for(int i=0; idesc, dp.mems[i].base.desc, i+2); +} + + +static void dev_part_strct(AVRPART *p, bool tsv, AVRPART *base) { + + if(!tsv) { + dev_info("#------------------------------------------------------------\n"); + dev_info("# %s\n", p->desc); + dev_info("#------------------------------------------------------------\n"); + if(p->parent_id) + dev_info("\npart parent \"%s\"\n", p->parent_id); + else + dev_info("\npart\n"); + } + + _if_partout(strcmp, "\"%s\"", desc); + _if_partout(strcmp, "\"%s\"", id); + _if_partout(strcmp, "\"%s\"", family_id); + _if_partout(intcmp, "%d", hvupdi_variant); + _if_partout(intcmp, "0x%02x", stk500_devcode); + _if_partout(intcmp, "0x%02x", avr910_devcode); + _if_partout(intcmp, "%d", chip_erase_delay); + _if_partout(intcmp, "0x%02x", pagel); + _if_partout(intcmp, "0x%02x", bs2); + _if_n_partout_str(memcmp, sizeof p->signature, dev_sprintf("0x%02x 0x%02x 0x%02x", p->signature[0], p->signature[1], p->signature[2]), signature); + _if_partout(intcmp, "0x%04x", usbpid); + + if(!base || base->reset_disposition != p->reset_disposition) + _partout_str(strdup(p->reset_disposition == RESET_DEDICATED? "dedicated": p->reset_disposition == RESET_IO? "io": "unknown"), reset); + + _if_partout_str(intcmp, strdup(p->retry_pulse == PIN_AVR_RESET? "reset": p->retry_pulse == PIN_AVR_SCK? "sck": "unknown"), retry_pulse); + + if(!base || base->flags != p->flags) { + if(tsv) { + _partout("0x%04x", flags); + } else { + _if_flagout(AVRPART_HAS_JTAG, has_jtag); + _if_flagout(AVRPART_HAS_DW, has_debugwire); + _if_flagout(AVRPART_HAS_PDI, has_pdi); + _if_flagout(AVRPART_HAS_UPDI, has_updi); + _if_flagout(AVRPART_HAS_TPI, has_tpi); + _if_flagout(AVRPART_IS_AT90S1200, is_at90s1200); + _if_flagout(AVRPART_AVR32, is_avr32); + _if_flagout(AVRPART_ALLOWFULLPAGEBITSTREAM, allowfullpagebitstream); + _if_flagout(AVRPART_ENABLEPAGEPROGRAMMING, enablepageprogramming); + _if_flagout(AVRPART_SERIALOK, serial); + + if(!base || (base->flags & (AVRPART_PARALLELOK | AVRPART_PSEUDOPARALLEL)) != (p->flags & (AVRPART_PARALLELOK | AVRPART_PSEUDOPARALLEL))) { + int par = p->flags & (AVRPART_PARALLELOK | AVRPART_PSEUDOPARALLEL); + _partout_str(strdup(par == 0? "no": par == AVRPART_PSEUDOPARALLEL? "unknown": AVRPART_PARALLELOK? "yes": "pseudo"), parallel); + } + } + } + + _if_partout(intcmp, "%d", timeout); + _if_partout(intcmp, "%d", stabdelay); + _if_partout(intcmp, "%d", cmdexedelay); + _if_partout(intcmp, "%d", synchloops); + _if_partout(intcmp, "%d", bytedelay); + _if_partout(intcmp, "%d", pollindex); + _if_partout(intcmp, "0x%02x", pollvalue); + _if_partout(intcmp, "%d", predelay); + _if_partout(intcmp, "%d", postdelay); + _if_partout(intcmp, "%d", pollmethod); + + if(!base && p->ctl_stack_type != CTL_STACK_NONE) + dev_stack_out(tsv, p, dev_controlstack_name(p), p->controlstack, CTL_STACK_SIZE); + + // @@@ may need to remove controlstack and set p->ctl_stack_type to CTL_STACK_NONE if base has controlstack? + if(base && (p->ctl_stack_type != base->ctl_stack_type || memcmp(base->controlstack, p->controlstack, sizeof base->controlstack))) + dev_stack_out(tsv, p, dev_controlstack_name(p), p->controlstack, CTL_STACK_SIZE); + + if(!base || memcmp(base->flash_instr, p->flash_instr, sizeof base->flash_instr)) + dev_stack_out(tsv, p, "flash_instr", p->flash_instr, FLASH_INSTR_SIZE); + + if(!base || memcmp(base->eeprom_instr, p->eeprom_instr, sizeof base->eeprom_instr)) + dev_stack_out(tsv, p, "eeprom_instr", p->eeprom_instr, EEPROM_INSTR_SIZE); + + _if_partout(intcmp, "%d", hventerstabdelay); + _if_partout(intcmp, "%d", progmodedelay); + _if_partout(intcmp, "%d", latchcycles); + _if_partout(intcmp, "%d", togglevtg); + _if_partout(intcmp, "%d", poweroffdelay); + _if_partout(intcmp, "%d", resetdelayms); + _if_partout(intcmp, "%d", resetdelayus); + _if_partout(intcmp, "%d", hvleavestabdelay); + _if_partout(intcmp, "%d", resetdelay); + _if_partout(intcmp, "%d", chiperasepulsewidth); + _if_partout(intcmp, "%d", chiperasepolltimeout); + _if_partout(intcmp, "%d", chiperasetime); + _if_partout(intcmp, "%d", programfusepulsewidth); + _if_partout(intcmp, "%d", programfusepolltimeout); + _if_partout(intcmp, "%d", programlockpulsewidth); + _if_partout(intcmp, "%d", programlockpolltimeout); + _if_partout(intcmp, "%d", synchcycles); + _if_partout(intcmp, "%d", hvspcmdexedelay); + + _if_partout(intcmp, "0x%02x", idr); + _if_partout(intcmp, "0x%02x", rampz); + _if_partout(intcmp, "0x%02x", spmcr); + _if_partout(intcmp, "0x%02x", eecr); // why is eecr an unsigned short? + _if_partout(intcmp, "0x%04x", mcu_base); + _if_partout(intcmp, "0x%04x", nvm_base); + _if_partout(intcmp, "0x%04x", ocd_base); + _if_partout(intcmp, "%d", ocdrev); + + for(int i=0; i < AVR_OP_MAX; i++) + if(!base || opcodecmp(p->op[i], base->op[i], i)) + dev_part_strct_entry(tsv, ".ptop", p->desc, "part", opcodename(i), opcode2str(p->op[i], i, !tsv)); + + for(size_t mi=0; mi < sizeof mem_order/sizeof *mem_order && mem_order[mi]; mi++) { + AVRMEM *m, *bm; + + m = p->mem? avr_locate_mem(p, mem_order[mi]): NULL; + bm = base && base->mem? avr_locate_mem(base, mem_order[mi]): NULL; + + if(!m && bm && !tsv) + dev_info("\n memory \"%s\" = NULL;\n", bm->desc); + + if(!m) + continue; + + if(base && !bm) + bm = avr_new_memtype(); + + if(!tsv) { + if(!memorycmp(bm, m)) // same memory bit for bit, no need to instantiate + continue; + + dev_info("\n memory \"%s\"\n", m->desc); + } + + _if_memout_yn(paged); + _if_memout(intcmp, m->size > 8192? "0x%x": "%d", size); + _if_memout(intcmp, "%d", page_size); + _if_memout(intcmp, "%d", num_pages); // why can AVRDUDE not compute this? + _if_memout(intcmp, "0x%x", offset); + _if_memout(intcmp, "%d", min_write_delay); + _if_memout(intcmp, "%d", max_write_delay); + _if_memout_yn(pwroff_after_write); + _if_n_memout_str(memcmp, 2, dev_sprintf("0x%02x 0x%02x", m->readback[0], m->readback[1]), readback); + _if_memout(intcmp, "%d", mode); + _if_memout(intcmp, "%d", delay); + _if_memout(intcmp, "%d", blocksize); + _if_memout(intcmp, "%d", readsize); + _if_memout(intcmp, "%d", pollindex); + + for(int i=0; i < AVR_OP_MAX; i++) + if(!bm || opcodecmp(bm->op[i], m->op[i], i)) + dev_part_strct_entry(tsv, ".ptmmop", p->desc, m->desc, opcodename(i), opcode2str(m->op[i], i, !tsv)); + + if(!tsv) + dev_info(" ;\n"); + + for(LNODEID lnm=lfirst(p->mem_alias); lnm; lnm=lnext(lnm)) { + AVRMEM_ALIAS *ma = ldata(lnm); + if(ma->aliased_mem && !strcmp(ma->aliased_mem->desc, m->desc)) { + if(tsv) + dev_info(".ptmm\t%s\t%s\talias\t%s\n", p->desc, ma->desc, m->desc); + else + dev_info("\n memory \"%s\"\n alias \"%s\";\n ;\n", ma->desc, m->desc); + } + } + } + + if(!tsv) + dev_info(";\n"); +} + + + + +// -p */[cdosw*] +void dev_output_part_defs(char *partdesc) { + bool cmdok, waits, opspi, descs, strct, cmpst, raw, all, tsv; + char *flags; + int nprinted; + AVRPART *nullpart = avr_new_part(); + + if((flags = strchr(partdesc, '/'))) + *flags++ = 0; + + if(!flags && !strcmp(partdesc, "*")) // treat -p * as if it was -p */* + flags = "*"; + + if(!*flags || !strchr("cdosSrw*t", *flags)) { + dev_info("%s: flags for developer option -p / not recognised\n", progname); + dev_info( + "Wildcard examples (these need protecting in the shell through quoting):\n" + " * all known parts\n" + " ATtiny10 just this part\n" + " *32[0-9] matches ATmega329, ATmega325 and ATmega328\n" + " *32? matches ATmega329, ATmega32A, ATmega325 and ATmega328\n" + "Flags (one or more of the characters below):\n" + " c check and report errors in address bits of SPI commands\n" + " d description of core part features\n" + " o opcodes for SPI programming parts and memories\n" + " S show entries of avrdude.conf parts with all values\n" + " s show entries of avrdude.conf parts with necessary values\n" + " r show entries of avrdude.conf parts as raw dump\n" + " w wd_... constants for ISP parts\n" + " * all of the above except s\n" + " t use tab separated values as much as possible\n" + "Examples:\n" + " $ avrdude -p ATmega328P/s\n" + " $ avrdude -p m328*/st | grep chip_erase_delay\n" + " avrdude -p*/r | sort\n" + "Notes:\n" + " -p * is the same as -p */*\n" + " This help message is printed using any unrecognised flag, eg, -p/h\n" + " Leaving no space after -p can be an OK substitute for quoting in shells\n" + " /s and /S outputs are designed to be used as input in avrdude.conf\n" + " Sorted /r output should stay invariant when rearranging avrdude.conf\n" + " The /c, /o and /w flags are less generic and may be removed sometime\n" + " These options are just to help development, so not further documented\n" + ); + return; + } + + // redirect stderr to stdout + fflush(stderr); fflush(stdout); dup2(1, 2); + + all = *flags == '*'; + cmdok = all || !!strchr(flags, 'c'); + descs = all || !!strchr(flags, 'd'); + opspi = all || !!strchr(flags, 'o'); + waits = all || !!strchr(flags, 'w'); + strct = all || !!strchr(flags, 'S'); + raw = all || !!strchr(flags, 'r'); + cmpst = !!strchr(flags, 's'); + tsv = !!strchr(flags, 't'); + + + // go through all memories and add them to the memory order list + for(LNODEID ln1 = lfirst(part_list); ln1; ln1 = lnext(ln1)) { + AVRPART *p = ldata(ln1); + if(p->mem) + for(LNODEID lnm=lfirst(p->mem); lnm; lnm=lnext(lnm)) + add_mem_order(((AVRMEM *) ldata(lnm))->desc); + + // same for aliased memories (though probably not needed) + if(p->mem_alias) + for(LNODEID lnm=lfirst(p->mem_alias); lnm; lnm=lnext(lnm)) + add_mem_order(((AVRMEM_ALIAS *) ldata(lnm))->desc); + } + + nprinted = dev_nprinted; + for(LNODEID ln1 = lfirst(part_list); ln1; ln1 = lnext(ln1)) { + AVRPART *p = ldata(ln1); + int flashsize, flashoffset, flashpagesize, eepromsize , eepromoffset, eeprompagesize; + + if(!descs || tsv) + if(dev_nprinted > nprinted) { + dev_info("\n"); + nprinted = dev_nprinted; + } + + if(!part_match(partdesc, p->desc) && !part_match(partdesc, p->id)) + continue; + + if(strct || cmpst) + dev_part_strct(p, tsv, !cmpst? NULL: p->parent_id? locate_part(part_list, p->parent_id): nullpart); + + if(raw) + dev_part_raw(p); + + // identify core flash and eeprom parameters + + flashsize = flashoffset = flashpagesize = eepromsize = eepromoffset = eeprompagesize = 0; + if(p->mem) { + for(LNODEID lnm=lfirst(p->mem); lnm; lnm=lnext(lnm)) { + AVRMEM *m = ldata(lnm); + if(!flashsize && 0==strcmp(m->desc, "flash")) { + flashsize = m->size; + flashpagesize = m->page_size; + flashoffset = m->offset; + } + if(!eepromsize && 0==strcmp(m->desc, "eeprom")) { + eepromsize = m->size; + eepromoffset = m->offset; + eeprompagesize = m->page_size; + } + } + } + + // "real" entries don't seem to have a space in their desc (a bit hackey) + if(flashsize && !strchr(p->desc, ' ')) { + int ok, nfuses; + AVRMEM *m; + OPCODE *oc; + + ok = 2047; + nfuses = 0; + + if(!p->op[AVR_OP_PGM_ENABLE]) + ok &= ~DEV_SPI_EN_CE_SIG; + + if(!p->op[AVR_OP_CHIP_ERASE]) + ok &= ~DEV_SPI_EN_CE_SIG; + + if((m = avr_locate_mem(p, "flash"))) { + if((oc = m->op[AVR_OP_LOAD_EXT_ADDR])) { + // @@@ to do: check whether address is put at lsb of third byte + } else + ok &= ~DEV_SPI_LOAD_EXT_ADDR; + + if((oc = m->op[AVR_OP_READ_HI])) { + if(cmdok) + checkaddr(m->size>>1, 1, AVR_OP_READ_HI, oc, p, m); + } else + ok &= ~DEV_SPI_PROGMEM; + + if((oc = m->op[AVR_OP_READ_LO])) { + if(cmdok) + checkaddr(m->size>>1, 1, AVR_OP_READ_LO, oc, p, m); + } else + ok &= ~DEV_SPI_PROGMEM; + + if((oc = m->op[AVR_OP_WRITE_HI])) { + if(cmdok) + checkaddr(m->size>>1, 1, AVR_OP_WRITE_HI, oc, p, m); + } else + ok &= ~DEV_SPI_PROGMEM; + + if((oc = m->op[AVR_OP_WRITE_LO])) { + if(cmdok) + checkaddr(m->size>>1, 1, AVR_OP_WRITE_LO, oc, p, m); + } else + ok &= ~DEV_SPI_PROGMEM; + + if((oc = m->op[AVR_OP_LOADPAGE_HI])) { + if(cmdok) + checkaddr(m->page_size>>1, 1, AVR_OP_LOADPAGE_HI, oc, p, m); + } else + ok &= ~DEV_SPI_PROGMEM_PAGED; + + if((oc = m->op[AVR_OP_LOADPAGE_LO])) { + if(cmdok) + checkaddr(m->page_size>>1, 1, AVR_OP_LOADPAGE_LO, oc, p, m); + } else + ok &= ~DEV_SPI_PROGMEM_PAGED; + + if((oc = m->op[AVR_OP_WRITEPAGE])) { + if(cmdok) + checkaddr(m->size>>1, m->page_size>>1, AVR_OP_WRITEPAGE, oc, p, m); + } else + ok &= ~DEV_SPI_PROGMEM_PAGED; + } else + ok &= ~(DEV_SPI_PROGMEM_PAGED | DEV_SPI_PROGMEM); + + if((m = avr_locate_mem(p, "eeprom"))) { + if((oc = m->op[AVR_OP_READ])) { + if(cmdok) + checkaddr(m->size, 1, AVR_OP_READ, oc, p, m); + } else + ok &= ~DEV_SPI_EEPROM; + + if((oc = m->op[AVR_OP_WRITE])) { + if(cmdok) + checkaddr(m->size, 1, AVR_OP_WRITE, oc, p, m); + } else + ok &= ~DEV_SPI_EEPROM; + + if((oc = m->op[AVR_OP_LOADPAGE_LO])) { + if(cmdok) + checkaddr(m->page_size, 1, AVR_OP_LOADPAGE_LO, oc, p, m); + } else + ok &= ~DEV_SPI_EEPROM_PAGED; + + if((oc = m->op[AVR_OP_WRITEPAGE])) { + if(cmdok) + checkaddr(m->size, m->page_size, AVR_OP_WRITEPAGE, oc, p, m); + } else + ok &= ~DEV_SPI_EEPROM_PAGED; + } else + ok &= ~(DEV_SPI_EEPROM_PAGED | DEV_SPI_EEPROM); + + if((m = avr_locate_mem(p, "signature")) && (oc = m->op[AVR_OP_READ])) { + if(cmdok) + checkaddr(m->size, 1, AVR_OP_READ, oc, p, m); + } else + ok &= ~DEV_SPI_EN_CE_SIG; + + if((m = avr_locate_mem(p, "calibration")) && (oc = m->op[AVR_OP_READ])) { + if(cmdok) + checkaddr(m->size, 1, AVR_OP_READ, oc, p, m); + } else + ok &= ~DEV_SPI_CALIBRATION; + + // actually, some AT90S... parts cannot read, only write lock bits :-0 + if( ! ((m = avr_locate_mem(p, "lock")) && m->op[AVR_OP_WRITE])) + ok &= ~DEV_SPI_LOCK; + + if(((m = avr_locate_mem(p, "fuse")) || (m = avr_locate_mem(p, "lfuse"))) && m->op[AVR_OP_READ] && m->op[AVR_OP_WRITE]) + nfuses++; + else + ok &= ~DEV_SPI_LFUSE; + + if((m = avr_locate_mem(p, "hfuse")) && m->op[AVR_OP_READ] && m->op[AVR_OP_WRITE]) + nfuses++; + else + ok &= ~DEV_SPI_HFUSE; + + if((m = avr_locate_mem(p, "efuse")) && m->op[AVR_OP_READ] && m->op[AVR_OP_WRITE]) + nfuses++; + else + ok &= ~DEV_SPI_EFUSE; + + if(descs) { + int len = 16-strlen(p->desc); + dev_info("%s '%s' =>%*s [0x%02X, 0x%02X, 0x%02X, 0x%08x, 0x%05x, 0x%03x, 0x%06x, 0x%04x, 0x%03x, %d, 0x%03x, 0x%04x, '%s'], # %s %d\n", + tsv || all? ".desc": " ", + p->desc, len > 0? len: 0, "", + p->signature[0], p->signature[1], p->signature[2], + flashoffset, flashsize, flashpagesize, + eepromoffset, eepromsize, eeprompagesize, + nfuses, + ok, + p->flags, + parttype(p), + p->config_file, p->lineno + ); + } + } + + if(opspi) { + printallopcodes(p, "part", p->op); + if(p->mem) { + for(LNODEID lnm=lfirst(p->mem); lnm; lnm=lnext(lnm)) { + AVRMEM *m = ldata(lnm); + if(m) + printallopcodes(p, m->desc, m->op); + } + } + } + + // print wait delays for AVR family parts + if(waits) { + if(!(p->flags & (AVRPART_HAS_PDI | AVRPART_HAS_UPDI | AVRPART_HAS_TPI | AVRPART_AVR32))) + dev_info(".wd_chip_erase %.3f ms %s\n", p->chip_erase_delay/1000.0, p->desc); + if(p->mem) { + for(LNODEID lnm=lfirst(p->mem); lnm; lnm=lnext(lnm)) { + AVRMEM *m = ldata(lnm); + // write delays not needed for read-only calibration and signature memories + if(strcmp(m->desc, "calibration") && strcmp(m->desc, "signature")) { + if(!(p->flags & (AVRPART_HAS_PDI | AVRPART_HAS_UPDI | AVRPART_HAS_TPI | AVRPART_AVR32))) { + if(m->min_write_delay == m->max_write_delay) + dev_info(".wd_%s %.3f ms %s\n", m->desc, m->min_write_delay/1000.0, p->desc); + else { + dev_info(".wd_min_%s %.3f ms %s\n", m->desc, m->min_write_delay/1000.0, p->desc); + dev_info(".wd_max_%s %.3f ms %s\n", m->desc, m->max_write_delay/1000.0, p->desc); + } + } + } + } + } + } + } +} diff --git a/src/developer_opts.h b/src/developer_opts.h new file mode 100644 index 00000000..6c4b3b71 --- /dev/null +++ b/src/developer_opts.h @@ -0,0 +1,24 @@ +/* + * avrdude - A Downloader/Uploader for AVR device programmers + * Copyright (C) 2022, Stefan Rueger + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef developer_opts_h +#define developer_opts_h + +void dev_output_part_defs(char *partdesc); + +#endif diff --git a/src/developer_opts_private.h b/src/developer_opts_private.h new file mode 100644 index 00000000..5a208199 --- /dev/null +++ b/src/developer_opts_private.h @@ -0,0 +1,116 @@ +/* + * avrdude - A Downloader/Uploader for AVR device programmers + * Copyright (C) 2022, Stefan Rueger + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef developer_opts_private_h +#define developer_opts_private_h + +#define DEV_SPI_EN_CE_SIG 1 +#define DEV_SPI_PROGMEM 2 +#define DEV_SPI_PROGMEM_PAGED 4 +#define DEV_SPI_LOAD_EXT_ADDR 8 +#define DEV_SPI_EEPROM 16 +#define DEV_SPI_EEPROM_PAGED 32 +#define DEV_SPI_LOCK 64 +#define DEV_SPI_CALIBRATION 128 +#define DEV_SPI_LFUSE 256 +#define DEV_SPI_HFUSE 512 +#define DEV_SPI_EFUSE 1024 + + +static int dev_message(int msglvl, const char *fmt, ...); + + +#ifndef DEV_INFO +#define DEV_INFO MSG_INFO +#endif + +#ifndef DEV_NOTICE +#define DEV_NOTICE MSG_NOTICE +#endif + +#ifndef DEV_NOTICE +#define DEV_NOTICE2 MSG_NOTICE2 +#endif + +#define dev_info(...) dev_message(DEV_INFO, __VA_ARGS__) +#define dev_notice(...) dev_message(DEV_NOTICE, __VA_ARGS__) +#define dev_notice2(...) dev_message(DEV_NOTICE2, __VA_ARGS__) + +#define _partout(fmt, component) \ + dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, dev_sprintf(fmt, p->component)) + +#define _if_partout(cmp, fmt, component) do { \ + if(!base || cmp(base->component, p->component)) \ + dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, dev_sprintf(fmt, p->component)); \ +} while(0) + +#define _if_n_partout(cmp, n, fmt, component) do { \ + if(!base || cmp(base->component, p->component, n)) \ + dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, dev_sprintf(fmt, p->component)); \ +} while(0) + +#define _partout_str(result, component) \ + dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, result) + +#define _if_partout_str(cmp, result, component) do { \ + if(!base || cmp(base->component, p->component)) \ + dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, result); \ +} while(0) + +#define _if_n_partout_str(cmp, n, result, component) do { \ + if(!base || cmp(base->component, p->component, n)) \ + dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, result); \ +} while(0) + + +#define _memout(fmt, component) \ + dev_part_strct_entry(tsv, ".ptmm", p->desc, m->desc, #component, dev_sprintf(fmt, m->component)) + +#define _if_memout(cmp, fmt, component) do { \ + if(!bm || cmp(bm->component, m->component)) \ + dev_part_strct_entry(tsv, ".ptmm", p->desc, m->desc, #component, dev_sprintf(fmt, m->component)); \ +} while(0) + +#define _memout_str(result, component) \ + dev_part_strct_entry(tsv, ".ptmm", p->desc, m->desc, #component, result) + +#define _if_n_memout_str(cmp, n, result, component) do { \ + if(!bm || cmp(bm->component, m->component, n)) \ + dev_part_strct_entry(tsv, ".ptmm", p->desc, m->desc, #component, result); \ +} while(0) + +#define _memout_yn(component) \ + dev_part_strct_entry(tsv, ".ptmm", p->desc, m->desc, #component, strdup(m->component? "yes": "no")) + +#define _if_memout_yn(component) do { \ + if(!bm || bm->component != m->component) \ + dev_part_strct_entry(tsv, ".ptmm", p->desc, m->desc, #component, strdup(m->component? "yes": "no")); \ +} while(0) + +#define _flagout(mask, name) \ + _partout_str(strdup(p->flags & (mask)? "yes": "no"), name) + +#define _if_flagout(mask, name) do { \ + if(!base || (base->flags & (mask)) != (p->flags & (mask))) \ + _partout_str(strdup(p->flags & (mask)? "yes": "no"), name); \ +} while(0) + +#define _cmderr(result, component) \ + dev_part_strct_entry(tsv, ".cmderr", p->desc, m->desc, #component, result) + +#endif diff --git a/src/lexer.l b/src/lexer.l index 4db95f6d..91d02597 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -57,12 +57,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; } -{DIGIT}+ { yylval = number(yytext); return TKN_NUMBER; } -{DIGIT}+"."{DIGIT}* { yylval = number_real(yytext); return TKN_NUMBER_REAL; } -"."{DIGIT}+ { yylval = number_real(yytext); return TKN_NUMBER_REAL; } +{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; } "\"" { string_buf_ptr = string_buf; BEGIN(strng); } @@ -179,6 +176,7 @@ miso { yylval=NULL; return K_MISO; } mode { yylval=NULL; return K_MODE; } mosi { yylval=NULL; return K_MOSI; } no { yylval=new_token(K_NO); return K_NO; } +NULL { yylval=NULL; return K_NULL; } num_banks { yylval=NULL; return K_NUM_PAGES; } num_pages { yylval=NULL; return K_NUM_PAGES; } nvm_base { yylval=NULL; return K_NVM_BASE; } @@ -213,6 +211,7 @@ rdyled { yylval=NULL; return K_RDYLED; } read { yylval=new_token(K_READ); return K_READ; } read_hi { yylval=new_token(K_READ_HI); return K_READ_HI; } read_lo { yylval=new_token(K_READ_LO); return K_READ_LO; } +readback { yylval=NULL; return K_READBACK; } readback_p1 { yylval=NULL; return K_READBACK_P1; } readback_p2 { yylval=NULL; return K_READBACK_P2; } readsize { yylval=NULL; return K_READSIZE; } diff --git a/src/libavrdude.h b/src/libavrdude.h index b21a45c2..dad47922 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -183,6 +183,7 @@ typedef struct opcode { } OPCODE; +/* Any changes here, please also reflect in dev_part_strct() of developer_opts.c */ #define AVRPART_SERIALOK 0x0001 /* part supports serial programming */ #define AVRPART_PARALLELOK 0x0002 /* part supports parallel programming */ #define AVRPART_PSEUDOPARALLEL 0x0004 /* part has pseudo parallel support */ @@ -212,9 +213,11 @@ 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 */ typedef struct avrpart { char desc[AVR_DESCLEN]; /* long part name */ char id[AVR_IDLEN]; /* short part name */ + char * parent_id; /* parent id if set, for -p.../s */ char family_id[AVR_FAMILYIDLEN+1]; /* family id in the SIB (avr8x) */ int hvupdi_variant; /* HV pulse on UPDI pin, no pin or RESET pin */ int stk500_devcode; /* stk500 device code */ @@ -317,14 +320,22 @@ typedef struct avrmem_alias { extern "C" { #endif + +int intlog2(unsigned int n); + /* Functions for OPCODE structures */ OPCODE * avr_new_opcode(void); void avr_free_opcode(OPCODE * op); int avr_set_bits(OPCODE * op, unsigned char * cmd); int avr_set_addr(OPCODE * op, unsigned char * cmd, unsigned long addr); +int avr_set_addr_mem(AVRMEM *mem, int opnum, unsigned char *cmd, unsigned long addr); int avr_set_input(OPCODE * op, unsigned char * cmd, unsigned char data); int avr_get_output(OPCODE * op, unsigned char * res, unsigned char * data); int avr_get_output_index(OPCODE * op); +char cmdbitchar(CMDBIT cb); +char *cmdbitstr(CMDBIT cb); +const char *opcodename(int opnum); +char *opcode2str(OPCODE *op, int opnum, int detailed); /* Functions for AVRMEM structures */ AVRMEM * avr_new_memtype(void); @@ -333,9 +344,9 @@ int avr_initmem(AVRPART * p); AVRMEM * avr_dup_mem(AVRMEM * m); void avr_free_mem(AVRMEM * m); void avr_free_memalias(AVRMEM_ALIAS * m); -AVRMEM * avr_locate_mem(AVRPART * p, char * desc); -AVRMEM * avr_locate_mem_noalias(AVRPART * p, char * desc); -AVRMEM_ALIAS * avr_locate_memalias(AVRPART * p, char * desc); +AVRMEM * avr_locate_mem(AVRPART * p, const char * desc); +AVRMEM * avr_locate_mem_noalias(AVRPART * p, const char * desc); +AVRMEM_ALIAS * avr_locate_memalias(AVRPART * p, const char * desc); AVRMEM_ALIAS * avr_find_memalias(AVRPART * p, AVRMEM * m_orig); void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, AVRPART * p, int type, int verbose); @@ -344,7 +355,7 @@ void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, AVRPART * p, AVRPART * avr_new_part(void); AVRPART * avr_dup_part(AVRPART * d); void avr_free_part(AVRPART * d); -AVRPART * locate_part(LISTID parts, char * partdesc); +AVRPART * locate_part(LISTID parts, const char * partdesc); AVRPART * locate_part_by_avr910_devcode(LISTID parts, int devcode); AVRPART * locate_part_by_signature(LISTID parts, unsigned char * sig, int sigsize); @@ -356,6 +367,8 @@ typedef void (*walk_avrparts_cb)(const char *name, const char *desc, void walk_avrparts(LISTID avrparts, walk_avrparts_cb cb, void *cookie); void sort_avrparts(LISTID avrparts); +int part_match(const char *pattern, const char *string); + int compare_memory_masked(AVRMEM * m, uint8_t buf1, uint8_t buf2); #ifdef __cplusplus @@ -659,6 +672,7 @@ typedef struct programmer_t { char desc[PGM_DESCLEN]; char type[PGM_TYPELEN]; char port[PGM_PORTLEN]; + char *parent_id; void (*initpgm)(struct programmer_t * pgm); unsigned int pinno[N_PINS]; struct pindef_t pin[N_PINS]; diff --git a/src/main.c b/src/main.c index 785f6033..772762f3 100644 --- a/src/main.c +++ b/src/main.c @@ -26,7 +26,7 @@ * For parallel port connected programmers, the pin definitions can be * changed via a config file. See the config file for instructions on * how to add a programmer definition. - * + * */ #include "ac_cfg.h" @@ -50,7 +50,7 @@ #include "libavrdude.h" #include "term.h" - +#include "developer_opts.h" /* Get VERSION from ac_cfg.h */ char * version = VERSION; @@ -102,7 +102,7 @@ int ovsigck; /* 1=override sig check, 0=don't */ */ static void usage(void) { - avrdude_message(MSG_INFO, + avrdude_message(MSG_INFO, "Usage: %s [options]\n" "Options:\n" " -p Required. Specify AVR device.\n" @@ -761,6 +761,12 @@ int main(int argc, char * argv []) avrdude_message(MSG_NOTICE, "\n"); + // developer option -p /[*codws] prints various aspects of part descriptions and exits + if(partdesc && (strcmp(partdesc, "*") == 0 || strchr(partdesc, '/'))) { + dev_output_part_defs(partdesc); + exit(1); + } + if (partdesc) { if (strcmp(partdesc, "?") == 0) { avrdude_message(MSG_INFO, "\n"); @@ -1097,7 +1103,7 @@ int main(int argc, char * argv []) goto main_exit; } } - + sig = avr_locate_mem(p, "signature"); if (sig == NULL) { avrdude_message(MSG_INFO, "%s: WARNING: signature data not defined for device \"%s\"\n", diff --git a/src/pgm.c b/src/pgm.c index d85f35e4..dd38552f 100644 --- a/src/pgm.c +++ b/src/pgm.c @@ -79,6 +79,7 @@ PROGRAMMER * pgm_new(void) pgm->usbpid = lcreat(NULL, 0); pgm->desc[0] = 0; pgm->type[0] = 0; + pgm->parent_id = NULL; pgm->config_file = NULL; pgm->lineno = 0; pgm->baudrate = 0; @@ -145,11 +146,8 @@ void pgm_free(PROGRAMMER * const p) ldestroy_cb(p->usbpid, free); p->id = NULL; p->usbpid = NULL; - /* this is done by pgm_teardown, but usually cookie is not set to NULL */ - /* if (p->cookie !=NULL) { - free(p->cookie); - p->cookie = NULL; - }*/ + /* do not free p->parent_id nor p->config_file */ + /* p->cookie is freed by pgm_teardown */ free(p); } @@ -169,7 +167,6 @@ PROGRAMMER * pgm_dup(const PROGRAMMER * const src) pgm->id = lcreat(NULL, 0); pgm->usbpid = lcreat(NULL, 0); - for (ln = lfirst(src->usbpid); ln; ln = lnext(ln)) { int *ip = malloc(sizeof(int)); if (ip == NULL) {