diff --git a/src/avrpart.c b/src/avrpart.c index 96e45334..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 ***/ @@ -556,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; @@ -819,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/developer_opts.c b/src/developer_opts.c index 0ddf68b2..f4a55478 100644 --- a/src/developer_opts.c +++ b/src/developer_opts.c @@ -51,114 +51,6 @@ #include "developer_opts.h" #include "developer_opts_private.h" -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); -} - - // 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; @@ -215,19 +107,6 @@ static void printallopcodes(AVRPART *p, const char *d, OPCODE **opa) { } -// 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; -} - // mnemonic characterisation of flags static char *parttype(AVRPART *p) { @@ -295,99 +174,6 @@ static void checkaddr(int memsize, int pagesize, int opnum, OPCODE *op, AVRPART } -/* - * 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; -} static char *dev_sprintf(const char *fmt, ...) { int size = 0; @@ -841,126 +627,6 @@ static void dev_part_strct(AVRPART *p, bool tsv, AVRPART *base) { -/* - * 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; -} - // -p */[cdosw*] void dev_output_part_defs(char *partdesc) {