From 952ad72fb9f962e450764d506044987aafa1d855 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 24 May 2022 16:56:11 +0100 Subject: [PATCH 01/28] Add -p \* to summarise properties of parts in conf --- src/main.c | 313 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 310 insertions(+), 3 deletions(-) diff --git a/src/main.c b/src/main.c index 253c6e51..6ed62221 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" @@ -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" @@ -310,6 +310,119 @@ static void replace_backslashes(char *s) } +static 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 '?'; + } +} + +static const char *opcodename(int what) { + switch(what) { + 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 "???"; + } +} + +static void printopcode(AVRPART *p, const char *d, OPCODE **opa, int what) { + unsigned char cmd[4]; + int i; + + if(opa && opa[what]) { + memset(cmd, 0, sizeof cmd); + avr_set_bits(opa[what], cmd); + + avrdude_message(MSG_INFO, ".op %s %s %s 0x%02x%02x%02x%02x ", p->desc, d, opcodename(what), cmd[0], cmd[1], cmd[2], cmd[3]); + for(i=31; i >= 0; i--) { + avrdude_message(MSG_INFO, "%c", cmdbitchar(opa[what]->bit[i])); + if(i%8 == 0) + avrdude_message(MSG_INFO, "%c", i? ' ': '\n'); + } + } +} + +static void printallopcodes(AVRPART *p, const char *d, OPCODE **opa) { + for(int i=0; i>= 1; ret++) + continue; + + return ret; +} + +// check whether address bits are where they should be in ISP commands +static void checkaddr(int memsize, int pagesize, int what, OPCODE *op, AVRPART *p, AVRMEM *m) { + int i, lo, hi; + const char *whatstr = opcodename(what); + + 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)) { + avrdude_message(MSG_INFO, ".cmdbit%d %s %s-%s outside addressable space should be x or 0, but is %c", i+8, p->desc, m->desc, whatstr, cmdbitchar(op->bit[i+8])); + if(op->bit[i+8].type == AVR_CMDBIT_ADDRESS) + avrdude_message(MSG_INFO, "%d", op->bit[i+8].bitno); + avrdude_message(MSG_INFO, "\n"); + } + } else { + if(op->bit[i+8].type != AVR_CMDBIT_ADDRESS) + avrdude_message(MSG_INFO, ".cmdbit%d %s %s-%s is %c but should be a\n", i+8, p->desc, m->desc, whatstr, cmdbitchar(op->bit[i+8])); + else if(op->bit[i+8].bitno != i) + avrdude_message(MSG_INFO, ".cmdbit%d %s %s-%s inconsistent: a%d specified as a%d\n", i+8, p->desc, m->desc, whatstr, 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) + avrdude_message(MSG_INFO, ".cmdbit%d %s %s-%s contains a%d which it shouldn't\n", i, p->desc, m->desc, whatstr, op->bit[i].bitno); +} + /* * main routine */ @@ -830,6 +943,200 @@ int main(int argc, char * argv []) avrdude_message(MSG_NOTICE, "\n"); + // print part descriptions for debugging avrdude.conf and exit + if(partdesc && 0 == strcmp(partdesc, "*")) { + int first = 1; + + for(LNODEID ln1 = lfirst(part_list); ln1; ln1 = lnext(ln1)) { + AVRPART *p = ldata(ln1); + int flashsize = 0, flashoffset = 0, flashpagesize = 0, eepromsize = 0, eepromoffset = 0, eeprompagesize = 0; + + if(p->mem) { + for(LNODEID lnm=lfirst(p->mem); lnm; lnm=lnext(lnm)) { + AVRMEM *m = ldata(lnm); + if(!flashsize && m->desc && 0==strcmp(m->desc, "flash")) { + flashsize = m->size; + flashpagesize = m->page_size; + flashoffset = m->offset; + } + if(!eepromsize && m->desc && 0==strcmp(m->desc, "eeprom")) { + eepromsize = m->size; + eepromoffset = m->offset; + eeprompagesize = m->page_size; + } + } + } + +#define AD_SPI_EN_CE_SIG 1 +#define AD_SPI_PROGMEM 2 +#define AD_SPI_PROGMEM_PAGED 4 +#define AD_SPI_LOAD_EXT_ADDR 8 +#define AD_SPI_EEPROM 16 +#define AD_SPI_EEPROM_PAGED 32 +#define AD_SPI_LOCK 64 +#define AD_SPI_CALIBRATION 128 +#define AD_SPI_LFUSE 256 +#define AD_SPI_HFUSE 512 +#define AD_SPI_EFUSE 1024 + + if(flashsize && !index(p->desc, ' ')) { + int len, ok, nfuses; + AVRMEM *m; + OPCODE *oc; + + if(!first) + avrdude_message(MSG_INFO, "\n"); + first = 0; + + ok = 2047; + nfuses = 0; + + if(!p->op[AVR_OP_PGM_ENABLE]) + ok &= ~AD_SPI_EN_CE_SIG; + + if(!p->op[AVR_OP_CHIP_ERASE]) + ok &= ~AD_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 &= ~AD_SPI_LOAD_EXT_ADDR; + + if((oc = m->op[AVR_OP_READ_HI])) + checkaddr(m->size>>1, 1, AVR_OP_READ_HI, oc, p, m); + else + ok &= ~AD_SPI_PROGMEM; + + if((oc = m->op[AVR_OP_READ_LO])) + checkaddr(m->size>>1, 1, AVR_OP_READ_LO, oc, p, m); + else + ok &= ~AD_SPI_PROGMEM; + + if((oc = m->op[AVR_OP_WRITE_HI])) + checkaddr(m->size>>1, 1, AVR_OP_WRITE_HI, oc, p, m); + else + ok &= ~AD_SPI_PROGMEM; + + if((oc = m->op[AVR_OP_WRITE_LO])) + checkaddr(m->size>>1, 1, AVR_OP_WRITE_LO, oc, p, m); + else + ok &= ~AD_SPI_PROGMEM; + + if((oc = m->op[AVR_OP_LOADPAGE_HI])) + checkaddr(m->page_size>>1, 1, AVR_OP_LOADPAGE_HI, oc, p, m); + else + ok &= ~AD_SPI_PROGMEM_PAGED; + + if((oc = m->op[AVR_OP_LOADPAGE_LO])) + checkaddr(m->page_size>>1, 1, AVR_OP_LOADPAGE_LO, oc, p, m); + else + ok &= ~AD_SPI_PROGMEM_PAGED; + + if((oc = m->op[AVR_OP_WRITEPAGE])) + checkaddr(m->size>>1, m->page_size>>1, AVR_OP_WRITEPAGE, oc, p, m); + else + ok &= ~AD_SPI_PROGMEM_PAGED; + } else + ok &= ~(AD_SPI_PROGMEM_PAGED | AD_SPI_PROGMEM); + + if((m = avr_locate_mem(p, "eeprom"))) { + if((oc = m->op[AVR_OP_READ])) { + checkaddr(m->size, 1, AVR_OP_READ, oc, p, m); + } else + ok &= ~AD_SPI_EEPROM; + + if((oc = m->op[AVR_OP_WRITE])) { + checkaddr(m->size, 1, AVR_OP_WRITE, oc, p, m); + } else + ok &= ~AD_SPI_EEPROM; + + if((oc = m->op[AVR_OP_LOADPAGE_LO])) { + checkaddr(m->page_size, 1, AVR_OP_LOADPAGE_LO, oc, p, m); + } else + ok &= ~AD_SPI_EEPROM_PAGED; + + if((oc = m->op[AVR_OP_WRITEPAGE])) { + checkaddr(m->size, m->page_size, AVR_OP_WRITEPAGE, oc, p, m); + } else + ok &= ~AD_SPI_EEPROM_PAGED; + } else + ok &= ~(AD_SPI_EEPROM_PAGED | AD_SPI_EEPROM); + + if((m = avr_locate_mem(p, "signature")) && (oc = m->op[AVR_OP_READ])) + checkaddr(m->size, 1, AVR_OP_READ, oc, p, m); + else + ok &= ~AD_SPI_EN_CE_SIG; + + if((m = avr_locate_mem(p, "calibration")) && (oc = m->op[AVR_OP_READ])) + checkaddr(m->size, 1, AVR_OP_READ, oc, p, m); + else + ok &= ~AD_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 &= ~AD_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 &= ~AD_SPI_LFUSE; + + if((m = avr_locate_mem(p, "hfuse")) && m->op[AVR_OP_READ] && m->op[AVR_OP_WRITE]) + nfuses++; + else + ok &= ~AD_SPI_HFUSE; + + if((m = avr_locate_mem(p, "efuse")) && m->op[AVR_OP_READ] && m->op[AVR_OP_WRITE]) + nfuses++; + else + ok &= ~AD_SPI_EFUSE; + + len = 16-strlen(p->desc); + avrdude_message(MSG_INFO, ".desc '%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 %d\n", + 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, + p->config_file, p->lineno + ); + } + + 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(!(p->flags & (AVRPART_HAS_PDI | AVRPART_HAS_UPDI | AVRPART_HAS_TPI | AVRPART_AVR32))) + avrdude_message(MSG_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) + avrdude_message(MSG_INFO, ".wd_%s %.3f ms %s\n", m->desc, m->min_write_delay/1000.0, p->desc); + else { + avrdude_message(MSG_INFO, ".wd_min_%s %.3f ms %s\n", m->desc, m->min_write_delay/1000.0, p->desc); + avrdude_message(MSG_INFO, ".wd_max_%s %.3f ms %s\n", m->desc, m->max_write_delay/1000.0, p->desc); + } + } + } + } + } + } + exit(1); + } + if (partdesc) { if (strcmp(partdesc, "?") == 0) { avrdude_message(MSG_INFO, "\n"); @@ -1161,7 +1468,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", From 317cc6d49284e33eb6550ba8c92aeadda7794c3d Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Sun, 26 Jun 2022 15:10:19 +0100 Subject: [PATCH 02/28] Add part type to -p \* .desc output --- src/main.c | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index 6ed62221..43219bad 100644 --- a/src/main.c +++ b/src/main.c @@ -394,6 +394,42 @@ static int intlog2(unsigned int n) { return ret; } +// mnemonic characterisation of flags +static char *parttype(AVRPART *p) { + static char type[1024]; + + switch(p->flags & (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 what, OPCODE *op, AVRPART *p, AVRMEM *m) { int i, lo, hi; @@ -1093,7 +1129,7 @@ int main(int argc, char * argv []) ok &= ~AD_SPI_EFUSE; len = 16-strlen(p->desc); - avrdude_message(MSG_INFO, ".desc '%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 %d\n", + avrdude_message(MSG_INFO, ".desc '%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", p->desc, len > 0? len: 0, "", p->signature[0], p->signature[1], p->signature[2], flashoffset, flashsize, flashpagesize, @@ -1101,6 +1137,7 @@ int main(int argc, char * argv []) nfuses, ok, p->flags, + parttype(p), p->config_file, p->lineno ); } From 3bd75e74c6c65bd3b0c7fdb170f39b380dec1286 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 28 Jun 2022 20:14:29 +0100 Subject: [PATCH 03/28] Move developer options into own source file and expand part description -p \* -p \*/c check address bits in SPI commands -p \*/d description of core part features -p \*/o opcodes for SPI programming parts and memories -p \*/s show avrdude.conf entries of parts -p \*/ss show full avrdude.conf entry as tab separated table -p \*/w wd_... constants for ISP parts -p \*/\* all of the above except -p \*/s -p \* same as -p\*/\* --- src/CMakeLists.txt | 3 + src/Makefile.am | 3 + src/developer_opts.c | 651 +++++++++++++++++++++++++++++++++++ src/developer_opts.h | 24 ++ src/developer_opts_private.h | 50 +++ src/main.c | 346 +------------------ 6 files changed, 735 insertions(+), 342 deletions(-) create mode 100644 src/developer_opts.c create mode 100644 src/developer_opts.h create mode 100644 src/developer_opts_private.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bd3c6dee..d3f9b87a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -133,6 +133,9 @@ add_library(libavrdude confwin.c crc16.c crc16.h + developer_opts.c + developer_opts.h + developer_opts_private.h dfu.c dfu.h fileio.c diff --git a/src/Makefile.am b/src/Makefile.am index 15162224..f2747c1b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -110,6 +110,9 @@ libavrdude_a_SOURCES = \ confwin.c \ crc16.c \ crc16.h \ + developer_opts.c \ + developer_opts.h \ + developer_opts_private.h \ dfu.c \ dfu.h \ fileio.c \ diff --git a/src/developer_opts.c b/src/developer_opts.c new file mode 100644 index 00000000..36dd6461 --- /dev/null +++ b/src/developer_opts.c @@ -0,0 +1,651 @@ +/* + * 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" + +static 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 '?'; + } +} + + +static const char *opcodename(int what) { + switch(what) { + 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 "???"; + } +} + + +char *opcode2str(OPCODE *op, int detailed) { + char cb, space[1024], *sp = space; + + if(detailed) + *sp++ = '"'; + for(int i=31; i >= 0; i--) { + *sp++ = cb = cmdbitchar(op->bit[i]); + if(detailed && 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); +} + +static void printopcode(AVRPART *p, const char *d, OPCODE *op, int what) { + unsigned char cmd[4]; + int i; + + if(op) { + memset(cmd, 0, sizeof cmd); + avr_set_bits(op, cmd); + + dev_info(".op %s %s %s 0x%02x%02x%02x%02x ", p->desc, d, opcodename(what), 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? ' ': '\n'); + } + } +} + +static void printallopcodes(AVRPART *p, const char *d, OPCODE **opa) { + for(int i=0; i>= 1; ret++) + continue; + + return ret; +} + + +// mnemonic characterisation of flags +static char *parttype(AVRPART *p) { + static char type[1024]; + + switch(p->flags & (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 what, OPCODE *op, AVRPART *p, AVRMEM *m) { + int i, lo, hi; + const char *whatstr = opcodename(what); + + 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)) { + dev_info(".cmdbit%d %s %s-%s outside addressable space should be x or 0, but is %c", i+8, p->desc, m->desc, whatstr, cmdbitchar(op->bit[i+8])); + if(op->bit[i+8].type == AVR_CMDBIT_ADDRESS) + dev_info("%d", op->bit[i+8].bitno); + dev_info("\n"); + } + } else { + if(op->bit[i+8].type != AVR_CMDBIT_ADDRESS) + dev_info(".cmdbit%d %s %s-%s is %c but should be a\n", i+8, p->desc, m->desc, whatstr, cmdbitchar(op->bit[i+8])); + else if(op->bit[i+8].bitno != i) + dev_info(".cmdbit%d %s %s-%s inconsistent: a%d specified as a%d\n", i+8, p->desc, m->desc, whatstr, 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(".cmdbit%d %s %s-%s contains a%d which it shouldn't\n", i, p->desc, m->desc, whatstr, op->bit[i].bitno); +} + + +void dev_stack_out(bool dot, AVRPART *p, char *name, unsigned char *stack, int ns) { + if(dot) + dev_info("%s\t%s\t", p->desc, name); + else + dev_info(" %-19s = ", name); + for(int i=0; iconfig_file, real_config_file)) + memcpy(real_config_file, p->config_file, sizeof real_config_file); + dev_info("# %s %d\n", real_config_file, p->lineno); + + if(!dot) + dev_info("part\n"); + dev_partout("\"%s\"", desc); + dev_partout("\"%s\"", id); + dev_partout("\"%s\"", family_id); + dev_partout("0x%02x", stk500_devcode); + dev_partout("0x%02x", avr910_devcode); + dev_partout("%d", chip_erase_delay); + dev_partout("0x%02x", pagel); + dev_partout("0x%02x", bs2); + sprintf(space, "0x%02x 0x%02x 0x%02x", p->signature[0], p->signature[1], p->signature[2]); + dev_partout_str(space, signature); + dev_partout("0x%04x", usbpid); + sprintf(space, "%s", p->reset_disposition == RESET_DEDICATED? "dedicated": p->reset_disposition == RESET_IO? "io": "unknown"); + dev_partout_str(space, reset); + sprintf(space, "%s", p->retry_pulse == PIN_AVR_RESET? "reset": p->retry_pulse == PIN_AVR_SCK? "sck": "unknown"); + dev_partout_str(space, retry_pulse); + + if(dot) + dev_info(".part\t%s\tflags\t0x%04x\n", p->desc, p->flags); + else { + dev_flagout("has_jtag", AVRPART_HAS_JTAG); + dev_flagout("has_debugwire", AVRPART_HAS_DW); + dev_flagout("has_pdi", AVRPART_HAS_PDI); + dev_flagout("has_updi", AVRPART_HAS_UPDI); + dev_flagout("has_tpi", AVRPART_HAS_TPI); + dev_flagout("is_at90s1200", AVRPART_IS_AT90S1200); + dev_flagout("is_avr32", AVRPART_AVR32); + dev_flagout("allowfullpagebitstream", AVRPART_ALLOWFULLPAGEBITSTREAM); + dev_flagout("enablepageprogramming", AVRPART_ENABLEPAGEPROGRAMMING); + dev_flagout("serial", AVRPART_SERIALOK); + + switch(p->flags & (AVRPART_PARALLELOK | AVRPART_PSEUDOPARALLEL)) { + case 0: strcpy(space, "no"); break; + case AVRPART_PSEUDOPARALLEL: strcpy(space, "unknown"); break; + case AVRPART_PARALLELOK: strcpy(space, "yes"); break; + default: strcpy(space, "pseudo"); break; + } + dev_info(" %-19s = %s;\n", "parallel", space); + } + + dev_partout("%d", timeout); + dev_partout("%d", stabdelay); + dev_partout("%d", cmdexedelay); + dev_partout("%d", synchloops); + dev_partout("%d", bytedelay); + dev_partout("%d", pollindex); + dev_partout("0x%02x", pollvalue); + dev_partout("%d", predelay); + dev_partout("%d", postdelay); + dev_partout("%d", pollmethod); + + sprintf(space, "%s", p->ctl_stack_type == CTL_STACK_PP? "pp_controlstack": p->ctl_stack_type == CTL_STACK_HVSP? "hvsp_controlstack": "unknown_controlstack"); + if(p->ctl_stack_type != CTL_STACK_NONE) + dev_stack_out(dot, p, space, p->controlstack, CTL_STACK_SIZE); + dev_stack_out(dot, p, "flash_instr", p->flash_instr, FLASH_INSTR_SIZE); + dev_stack_out(dot, p, "eeprom_instr", p->eeprom_instr, EEPROM_INSTR_SIZE); + +/* + unsigned char controlstack[CTL_STACK_SIZE]; // stk500v2 PP/HVSP ctl stack + unsigned char flash_instr[FLASH_INSTR_SIZE]; // flash instructions (debugWire, JTAG) + unsigned char eeprom_instr[EEPROM_INSTR_SIZE]; // EEPROM instructions (debugWire, JTAG) +*/ + + dev_partout("%d", hventerstabdelay); + dev_partout("%d", progmodedelay); + dev_partout("%d", latchcycles); + dev_partout("%d", togglevtg); + dev_partout("%d", poweroffdelay); + dev_partout("%d", resetdelayms); + dev_partout("%d", resetdelayus); + dev_partout("%d", hvleavestabdelay); + dev_partout("%d", resetdelay); + dev_partout("%d", chiperasepulsewidth); + dev_partout("%d", chiperasepolltimeout); + dev_partout("%d", chiperasetime); + dev_partout("%d", programfusepulsewidth); + dev_partout("%d", programfusepolltimeout); + dev_partout("%d", programlockpulsewidth); + dev_partout("%d", programlockpolltimeout); + dev_partout("%d", synchcycles); + dev_partout("%d", hvspcmdexedelay); + + dev_partout("0x%02x", idr); + dev_partout("0x%02x", rampz); + dev_partout("0x%02x", spmcr); + dev_partout("0x%02x", eecr); // why is eecr an unsigned short? + + dev_partout("0x%04x", mcu_base); + dev_partout("0x%04x", nvm_base); + dev_partout("0x%04x", ocd_base); + + if(p->ocdrev >= 0) + dev_partout("%d", ocdrev); + else + dev_partout("0x%8x", ocdrev); + + for(int i=0; i < AVR_OP_MAX; i++) { + if(p->op[i]) { + char *opc = opcode2str(p->op[i], !dot); + + if(dot) + dev_info(".partop\t%s\t%s\t%s\n", p->desc, opcodename(i), opc? opc: "error"); + else + dev_info(" %-19s = %s;\n", opcodename(i), opc? opc: "error"); + + if(opc) + free(opc); + } + } + if(p->mem) { + for(LNODEID lnm=lfirst(p->mem); lnm; lnm=lnext(lnm)) { + AVRMEM *m = ldata(lnm); + if(!dot) + dev_info("\n memory \"%s\"\n", m->desc); + + dev_memout_yn(paged); + if(m->size > 8192) + dev_memout("0x%x", size); + else + dev_memout("%d", size); + dev_memout("%d", page_size); + dev_memout("%d", num_pages); // why can AVRDUDE not compute this? + dev_memout("0x%x", offset); + dev_memout("%d", min_write_delay); + dev_memout("%d", max_write_delay); + dev_memout_yn(pwroff_after_write); + sprintf(space, "0x%02x 0x%02x", m->readback[0], m->readback[1]); + dev_memout_str(space, readback); + dev_memout("%d", mode); + dev_memout("%d", delay); + dev_memout("%d", blocksize); + dev_memout("%d", readsize); + dev_memout("%d", pollindex); + + for(int i=0; i < AVR_OP_MAX; i++) { + if(m->op[i]) { + char *opc = opcode2str(m->op[i], !dot); + + if(dot) + dev_info(".pmemop\t%s\t%s\t%s\t%s\n", p->desc, m->desc, opcodename(i), opc? opc: "error"); + else + dev_info(" %-15s = %s;\n", opcodename(i), opc? opc: "error"); + + if(opc) + free(opc); + } + } + + if(!dot) + 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(dot) + dev_info(".pmem\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(!dot) + dev_info(";\n"); + } + + + // 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 && m->desc && 0==strcmp(m->desc, "flash")) { + flashsize = m->size; + flashpagesize = m->page_size; + flashoffset = m->offset; + } + if(!eepromsize && m->desc && 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 && !index(p->desc, ' ')) { + int ok, nfuses; + AVRMEM *m; + OPCODE *oc; + + if(!first && all) + dev_info("\n"); + first = 0; + + 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(".desc '%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", + 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..701d97e3 --- /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(); + +#endif diff --git a/src/developer_opts_private.h b/src/developer_opts_private.h new file mode 100644 index 00000000..ffeb5c05 --- /dev/null +++ b/src/developer_opts_private.h @@ -0,0 +1,50 @@ +#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 + +#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(...) avrdude_message(DEV_INFO, __VA_ARGS__) +#define dev_notice(...) avrdude_message(DEV_NOTICE, __VA_ARGS__) +#define dev_notice2(...) avrdude_message(DEV_NOTICE2, __VA_ARGS__) + +#define dev_partout(fmt, component) (dot? \ + dev_info(".part\t%s\t%s\t" fmt "\n", p->desc, #component, p->component): \ + dev_info(" %-19s = " fmt ";\n", #component, p->component)) + +#define dev_partout_str(result, component) (dot? \ + dev_info(".part\t%s\t%s\t%s\n", p->desc, #component, result): \ + dev_info(" %-19s = %s;\n", #component, result)) + +#define dev_memout(fmt, component) (dot? \ + dev_info(".pmem\t%s\t%s\t%s\t" fmt "\n", p->desc, m->desc, #component, m->component): \ + dev_info(" %-15s = " fmt ";\n", #component, m->component)) + +#define dev_memout_str(result, component) (dot? \ + dev_info(".pmem\t%s\t%s\t%s\t%s\n", p->desc, m->desc, #component, result): \ + dev_info(" %-15s = %s;\n", #component, result)) + +#define dev_memout_yn(component) (dot? \ + dev_info(".pmem\t%s\t%s\t%s\t%s\n", p->desc, m->desc, #component, m->component? "yes": "no"): \ + dev_info(" %-15s = %s;\n", #component, m->component? "yes": "no")) + + +#define dev_flagout(name, mask) dev_info(" %-19s = %s;\n", (name), p->flags & (mask)? "yes": "no") diff --git a/src/main.c b/src/main.c index 43219bad..121e865e 100644 --- a/src/main.c +++ b/src/main.c @@ -50,7 +50,7 @@ #include "libavrdude.h" #include "term.h" - +#include "developer_opts.h" /* Get VERSION from ac_cfg.h */ char * version = VERSION; @@ -310,155 +310,6 @@ static void replace_backslashes(char *s) } -static 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 '?'; - } -} - -static const char *opcodename(int what) { - switch(what) { - 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 "???"; - } -} - -static void printopcode(AVRPART *p, const char *d, OPCODE **opa, int what) { - unsigned char cmd[4]; - int i; - - if(opa && opa[what]) { - memset(cmd, 0, sizeof cmd); - avr_set_bits(opa[what], cmd); - - avrdude_message(MSG_INFO, ".op %s %s %s 0x%02x%02x%02x%02x ", p->desc, d, opcodename(what), cmd[0], cmd[1], cmd[2], cmd[3]); - for(i=31; i >= 0; i--) { - avrdude_message(MSG_INFO, "%c", cmdbitchar(opa[what]->bit[i])); - if(i%8 == 0) - avrdude_message(MSG_INFO, "%c", i? ' ': '\n'); - } - } -} - -static void printallopcodes(AVRPART *p, const char *d, OPCODE **opa) { - for(int i=0; i>= 1; ret++) - continue; - - return ret; -} - -// mnemonic characterisation of flags -static char *parttype(AVRPART *p) { - static char type[1024]; - - switch(p->flags & (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 what, OPCODE *op, AVRPART *p, AVRMEM *m) { - int i, lo, hi; - const char *whatstr = opcodename(what); - - 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)) { - avrdude_message(MSG_INFO, ".cmdbit%d %s %s-%s outside addressable space should be x or 0, but is %c", i+8, p->desc, m->desc, whatstr, cmdbitchar(op->bit[i+8])); - if(op->bit[i+8].type == AVR_CMDBIT_ADDRESS) - avrdude_message(MSG_INFO, "%d", op->bit[i+8].bitno); - avrdude_message(MSG_INFO, "\n"); - } - } else { - if(op->bit[i+8].type != AVR_CMDBIT_ADDRESS) - avrdude_message(MSG_INFO, ".cmdbit%d %s %s-%s is %c but should be a\n", i+8, p->desc, m->desc, whatstr, cmdbitchar(op->bit[i+8])); - else if(op->bit[i+8].bitno != i) - avrdude_message(MSG_INFO, ".cmdbit%d %s %s-%s inconsistent: a%d specified as a%d\n", i+8, p->desc, m->desc, whatstr, 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) - avrdude_message(MSG_INFO, ".cmdbit%d %s %s-%s contains a%d which it shouldn't\n", i, p->desc, m->desc, whatstr, op->bit[i].bitno); -} - /* * main routine */ @@ -979,198 +830,9 @@ int main(int argc, char * argv []) avrdude_message(MSG_NOTICE, "\n"); - // print part descriptions for debugging avrdude.conf and exit - if(partdesc && 0 == strcmp(partdesc, "*")) { - int first = 1; - - for(LNODEID ln1 = lfirst(part_list); ln1; ln1 = lnext(ln1)) { - AVRPART *p = ldata(ln1); - int flashsize = 0, flashoffset = 0, flashpagesize = 0, eepromsize = 0, eepromoffset = 0, eeprompagesize = 0; - - if(p->mem) { - for(LNODEID lnm=lfirst(p->mem); lnm; lnm=lnext(lnm)) { - AVRMEM *m = ldata(lnm); - if(!flashsize && m->desc && 0==strcmp(m->desc, "flash")) { - flashsize = m->size; - flashpagesize = m->page_size; - flashoffset = m->offset; - } - if(!eepromsize && m->desc && 0==strcmp(m->desc, "eeprom")) { - eepromsize = m->size; - eepromoffset = m->offset; - eeprompagesize = m->page_size; - } - } - } - -#define AD_SPI_EN_CE_SIG 1 -#define AD_SPI_PROGMEM 2 -#define AD_SPI_PROGMEM_PAGED 4 -#define AD_SPI_LOAD_EXT_ADDR 8 -#define AD_SPI_EEPROM 16 -#define AD_SPI_EEPROM_PAGED 32 -#define AD_SPI_LOCK 64 -#define AD_SPI_CALIBRATION 128 -#define AD_SPI_LFUSE 256 -#define AD_SPI_HFUSE 512 -#define AD_SPI_EFUSE 1024 - - if(flashsize && !index(p->desc, ' ')) { - int len, ok, nfuses; - AVRMEM *m; - OPCODE *oc; - - if(!first) - avrdude_message(MSG_INFO, "\n"); - first = 0; - - ok = 2047; - nfuses = 0; - - if(!p->op[AVR_OP_PGM_ENABLE]) - ok &= ~AD_SPI_EN_CE_SIG; - - if(!p->op[AVR_OP_CHIP_ERASE]) - ok &= ~AD_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 &= ~AD_SPI_LOAD_EXT_ADDR; - - if((oc = m->op[AVR_OP_READ_HI])) - checkaddr(m->size>>1, 1, AVR_OP_READ_HI, oc, p, m); - else - ok &= ~AD_SPI_PROGMEM; - - if((oc = m->op[AVR_OP_READ_LO])) - checkaddr(m->size>>1, 1, AVR_OP_READ_LO, oc, p, m); - else - ok &= ~AD_SPI_PROGMEM; - - if((oc = m->op[AVR_OP_WRITE_HI])) - checkaddr(m->size>>1, 1, AVR_OP_WRITE_HI, oc, p, m); - else - ok &= ~AD_SPI_PROGMEM; - - if((oc = m->op[AVR_OP_WRITE_LO])) - checkaddr(m->size>>1, 1, AVR_OP_WRITE_LO, oc, p, m); - else - ok &= ~AD_SPI_PROGMEM; - - if((oc = m->op[AVR_OP_LOADPAGE_HI])) - checkaddr(m->page_size>>1, 1, AVR_OP_LOADPAGE_HI, oc, p, m); - else - ok &= ~AD_SPI_PROGMEM_PAGED; - - if((oc = m->op[AVR_OP_LOADPAGE_LO])) - checkaddr(m->page_size>>1, 1, AVR_OP_LOADPAGE_LO, oc, p, m); - else - ok &= ~AD_SPI_PROGMEM_PAGED; - - if((oc = m->op[AVR_OP_WRITEPAGE])) - checkaddr(m->size>>1, m->page_size>>1, AVR_OP_WRITEPAGE, oc, p, m); - else - ok &= ~AD_SPI_PROGMEM_PAGED; - } else - ok &= ~(AD_SPI_PROGMEM_PAGED | AD_SPI_PROGMEM); - - if((m = avr_locate_mem(p, "eeprom"))) { - if((oc = m->op[AVR_OP_READ])) { - checkaddr(m->size, 1, AVR_OP_READ, oc, p, m); - } else - ok &= ~AD_SPI_EEPROM; - - if((oc = m->op[AVR_OP_WRITE])) { - checkaddr(m->size, 1, AVR_OP_WRITE, oc, p, m); - } else - ok &= ~AD_SPI_EEPROM; - - if((oc = m->op[AVR_OP_LOADPAGE_LO])) { - checkaddr(m->page_size, 1, AVR_OP_LOADPAGE_LO, oc, p, m); - } else - ok &= ~AD_SPI_EEPROM_PAGED; - - if((oc = m->op[AVR_OP_WRITEPAGE])) { - checkaddr(m->size, m->page_size, AVR_OP_WRITEPAGE, oc, p, m); - } else - ok &= ~AD_SPI_EEPROM_PAGED; - } else - ok &= ~(AD_SPI_EEPROM_PAGED | AD_SPI_EEPROM); - - if((m = avr_locate_mem(p, "signature")) && (oc = m->op[AVR_OP_READ])) - checkaddr(m->size, 1, AVR_OP_READ, oc, p, m); - else - ok &= ~AD_SPI_EN_CE_SIG; - - if((m = avr_locate_mem(p, "calibration")) && (oc = m->op[AVR_OP_READ])) - checkaddr(m->size, 1, AVR_OP_READ, oc, p, m); - else - ok &= ~AD_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 &= ~AD_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 &= ~AD_SPI_LFUSE; - - if((m = avr_locate_mem(p, "hfuse")) && m->op[AVR_OP_READ] && m->op[AVR_OP_WRITE]) - nfuses++; - else - ok &= ~AD_SPI_HFUSE; - - if((m = avr_locate_mem(p, "efuse")) && m->op[AVR_OP_READ] && m->op[AVR_OP_WRITE]) - nfuses++; - else - ok &= ~AD_SPI_EFUSE; - - len = 16-strlen(p->desc); - avrdude_message(MSG_INFO, ".desc '%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", - 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 - ); - } - - 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(!(p->flags & (AVRPART_HAS_PDI | AVRPART_HAS_UPDI | AVRPART_HAS_TPI | AVRPART_AVR32))) - avrdude_message(MSG_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) - avrdude_message(MSG_INFO, ".wd_%s %.3f ms %s\n", m->desc, m->min_write_delay/1000.0, p->desc); - else { - avrdude_message(MSG_INFO, ".wd_min_%s %.3f ms %s\n", m->desc, m->min_write_delay/1000.0, p->desc); - avrdude_message(MSG_INFO, ".wd_max_%s %.3f ms %s\n", m->desc, m->max_write_delay/1000.0, p->desc); - } - } - } - } - } - } + // developer option -p */[*codws] prints various aspects of part descriptions and exits + if(partdesc && *partdesc == '*') { + dev_output_part_defs(partdesc+1); exit(1); } From 9e2cea3adae89c05f41d7fda76a6c7316bd4dea1 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Thu, 7 Jul 2022 18:32:19 +0100 Subject: [PATCH 04/28] Implement developer options -p */[*cdosSrwt] for part descriptions --- src/avrpart.c | 32 +- src/developer_opts.c | 791 +++++++++++++++++++++++++---------- src/developer_opts_private.h | 104 ++++- src/libavrdude.h | 8 +- src/main.c | 6 +- 5 files changed, 690 insertions(+), 251 deletions(-) diff --git a/src/avrpart.c b/src/avrpart.c index dc6def44..7274050a 100644 --- a/src/avrpart.c +++ b/src/avrpart.c @@ -379,13 +379,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 +406,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 +434,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 +442,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++; + } } } @@ -640,12 +651,15 @@ int i; 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)) { diff --git a/src/developer_opts.c b/src/developer_opts.c index 36dd6461..76ab3160 100644 --- a/src/developer_opts.c +++ b/src/developer_opts.c @@ -44,6 +44,7 @@ #include #include #include +#include #include "avrdude.h" #include "libavrdude.h" @@ -68,6 +69,19 @@ static char cmdbitchar(CMDBIT cb) { } } +static char *cmdbitstr(CMDBIT cb) { + char space[10]; + + *space = cmdbitchar(cb); + if(*space == 'a') + sprintf(space+1, "%d", cb.bitno); + else + space[1] = 0; + + return strdup(space); +} + + static const char *opcodename(int what) { switch(what) { @@ -101,9 +115,12 @@ static const char *opcodename(int what) { } -char *opcode2str(OPCODE *op, int detailed) { +static char *opcode2str(OPCODE *op, int detailed) { char cb, space[1024], *sp = space; + if(!op) + return strdup("NULL"); + if(detailed) *sp++ = '"'; for(int i=31; i >= 0; i--) { @@ -126,6 +143,42 @@ char *opcode2str(OPCODE *op, int detailed) { return strdup(space); } + +// return 0 if op code would encode (essentially) the same SPI command +static int opcodecmp(OPCODE *op1, OPCODE *op2) { + char *opstr1, *opstr2, *p; + int cmp; + + if(!op1 && !op2) + return 0; + if(!op1 || !op2) + return op1? -1: 1; + + opstr1 = opcode2str(op1, 1); + opstr2 = opcode2str(op2, 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 what) { unsigned char cmd[4]; int i; @@ -134,11 +187,11 @@ static void printopcode(AVRPART *p, const char *d, OPCODE *op, int what) { memset(cmd, 0, sizeof cmd); avr_set_bits(op, cmd); - dev_info(".op %s %s %s 0x%02x%02x%02x%02x ", p->desc, d, opcodename(what), cmd[0], cmd[1], cmd[2], cmd[3]); + dev_info(".op\t%s\t%s\t%s\t0x%02x%02x%02x%02x\t", p->desc, d, opcodename(what), 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? ' ': '\n'); + dev_info("%c", i? '\t': '\n'); } } } @@ -175,6 +228,7 @@ static char *parttype(AVRPART *p) { 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) @@ -210,248 +264,556 @@ static void checkaddr(int memsize, int pagesize, int what, OPCODE *op, AVRPART * 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)) { - dev_info(".cmdbit%d %s %s-%s outside addressable space should be x or 0, but is %c", i+8, p->desc, m->desc, whatstr, cmdbitchar(op->bit[i+8])); - if(op->bit[i+8].type == AVR_CMDBIT_ADDRESS) - dev_info("%d", op->bit[i+8].bitno); - dev_info("\n"); + 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, whatstr, i+8, cbs? cbs: "NULL"); + if(cbs) + free(cbs); } } else { if(op->bit[i+8].type != AVR_CMDBIT_ADDRESS) - dev_info(".cmdbit%d %s %s-%s is %c but should be a\n", i+8, p->desc, m->desc, whatstr, cmdbitchar(op->bit[i+8])); + dev_info(".cmderr\t%s\t%s-%s\tbit %d is %c but should be a\n", p->desc, m->desc, whatstr, i+8, cmdbitchar(op->bit[i+8])); else if(op->bit[i+8].bitno != i) - dev_info(".cmdbit%d %s %s-%s inconsistent: a%d specified as a%d\n", i+8, p->desc, m->desc, whatstr, i, op->bit[i+8].bitno); + dev_info(".cmderr\t%s\t%s-%s\tbit %d inconsistent: a%d specified as a%d\n", p->desc, m->desc, whatstr, 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(".cmdbit%d %s %s-%s contains a%d which it shouldn't\n", i, p->desc, m->desc, whatstr, op->bit[i].bitno); + dev_info(".cmderr\t%s\t%s-%s\tbit %d contains a%d which it shouldn't\n", p->desc, m->desc, whatstr, i, op->bit[i].bitno); } -void dev_stack_out(bool dot, AVRPART *p, char *name, unsigned char *stack, int ns) { - if(dot) - dev_info("%s\t%s\t", p->desc, name); +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? "NONE": + "unknown_controlstack"; +} + + +static void dev_stack_out(bool tsv, AVRPART *p, const char *name, unsigned char *stack, int ns) { + if(!strcmp(name, "NONE")) { + name = "pp_controlstack"; + ns = 0; + } + + if(tsv) + dev_info(".pt\t%s\t%s\t", p->desc, name); else - dev_info(" %-19s = ", name); - 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(int 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; + int len, di; + + memset(d, 0, sizeof *d); + + d->base = *p; + + // remove location info + memset(d->base.config_file, 0, sizeof d->base.config_file); + 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(int 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) { + char real_config_file[PATH_MAX]; + + if(!realpath(p->config_file, real_config_file)) + memcpy(real_config_file, p->config_file, sizeof real_config_file); + + dev_info("# %s %d\n", real_config_file, p->lineno); + + if(!tsv) + dev_info("part\n"); + + __if_partout(strcmp, "\"%s\"", desc); + __if_partout(strcmp, "\"%s\"", id); + __if_partout(strcmp, "\"%s\"", family_id); + __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])) + dev_part_strct_entry(tsv, ".ptop", p->desc, "part", opcodename(i), opcode2str(p->op[i], !tsv)); + + for(int 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])) + dev_part_strct_entry(tsv, ".ptmmop", p->desc, m->desc, opcodename(i), opcode2str(m->op[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 first = 1, cmdok, waits, opspi, descs, strct, all, dot; + bool cmdok, waits, opspi, descs, strct, cmpst, raw, all, tsv; + char *flags; + int nprinted; + AVRPART *nullpart = avr_new_part(); - if(!*partdesc) - all = 1; - else if(*partdesc != '/' || (*partdesc == '/' && partdesc[1] && !strchr("cdosw*", partdesc[1]))) { - dev_info("%s: flags for developer option -p \\* not recognised\n", progname); - dev_info(" -p \\*/c check address bits in SPI commands\n"); - dev_info(" -p \\*/d description of core part features\n"); - dev_info(" -p \\*/o opcodes for SPI programming parts and memories\n"); - dev_info(" -p \\*/s show avrdude.conf entries of parts\n"); - dev_info(" -p \\*/ss show full avrdude.conf entry as tab separated table\n"); - dev_info(" -p \\*/w wd_... constants for ISP parts\n"); - dev_info(" -p \\*/\\* all of the above except -p \\*/s\n"); - dev_info(" -p \\* same as -p\\*/\\*\n"); + 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:\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 address bits in SPI commands and output errors\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" + "Note:\n" + " -p * same as -p */*\n" + ); return; - } else { - partdesc++; - all = !!strchr(partdesc, '*') || !strlen(partdesc); } // redirect stderr to stdout fflush(stderr); fflush(stdout); dup2(1, 2); - cmdok = all || !!strchr(partdesc, 'c'); - descs = all || !!strchr(partdesc, 'd'); - opspi = all || !!strchr(partdesc, 'o'); - strct = all || !!strchr(partdesc, 's'); - waits = all || !!strchr(partdesc, 'w'); - dot = strlen(partdesc) != 1; + 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(strct) { - char space[1024], real_config_file[PATH_MAX]; - - if(!first) + if(!descs || tsv) + if(dev_nprinted > nprinted) { dev_info("\n"); - first = 0; - - if(!realpath(p->config_file, real_config_file)) - memcpy(real_config_file, p->config_file, sizeof real_config_file); - dev_info("# %s %d\n", real_config_file, p->lineno); - - if(!dot) - dev_info("part\n"); - dev_partout("\"%s\"", desc); - dev_partout("\"%s\"", id); - dev_partout("\"%s\"", family_id); - dev_partout("0x%02x", stk500_devcode); - dev_partout("0x%02x", avr910_devcode); - dev_partout("%d", chip_erase_delay); - dev_partout("0x%02x", pagel); - dev_partout("0x%02x", bs2); - sprintf(space, "0x%02x 0x%02x 0x%02x", p->signature[0], p->signature[1], p->signature[2]); - dev_partout_str(space, signature); - dev_partout("0x%04x", usbpid); - sprintf(space, "%s", p->reset_disposition == RESET_DEDICATED? "dedicated": p->reset_disposition == RESET_IO? "io": "unknown"); - dev_partout_str(space, reset); - sprintf(space, "%s", p->retry_pulse == PIN_AVR_RESET? "reset": p->retry_pulse == PIN_AVR_SCK? "sck": "unknown"); - dev_partout_str(space, retry_pulse); - - if(dot) - dev_info(".part\t%s\tflags\t0x%04x\n", p->desc, p->flags); - else { - dev_flagout("has_jtag", AVRPART_HAS_JTAG); - dev_flagout("has_debugwire", AVRPART_HAS_DW); - dev_flagout("has_pdi", AVRPART_HAS_PDI); - dev_flagout("has_updi", AVRPART_HAS_UPDI); - dev_flagout("has_tpi", AVRPART_HAS_TPI); - dev_flagout("is_at90s1200", AVRPART_IS_AT90S1200); - dev_flagout("is_avr32", AVRPART_AVR32); - dev_flagout("allowfullpagebitstream", AVRPART_ALLOWFULLPAGEBITSTREAM); - dev_flagout("enablepageprogramming", AVRPART_ENABLEPAGEPROGRAMMING); - dev_flagout("serial", AVRPART_SERIALOK); - - switch(p->flags & (AVRPART_PARALLELOK | AVRPART_PSEUDOPARALLEL)) { - case 0: strcpy(space, "no"); break; - case AVRPART_PSEUDOPARALLEL: strcpy(space, "unknown"); break; - case AVRPART_PARALLELOK: strcpy(space, "yes"); break; - default: strcpy(space, "pseudo"); break; - } - dev_info(" %-19s = %s;\n", "parallel", space); + nprinted = dev_nprinted; } - dev_partout("%d", timeout); - dev_partout("%d", stabdelay); - dev_partout("%d", cmdexedelay); - dev_partout("%d", synchloops); - dev_partout("%d", bytedelay); - dev_partout("%d", pollindex); - dev_partout("0x%02x", pollvalue); - dev_partout("%d", predelay); - dev_partout("%d", postdelay); - dev_partout("%d", pollmethod); + // pattern match the name of the part with command line: FMP_CASEFOLD not available here :( + if(fnmatch(partdesc, p->desc, 0) && fnmatch(partdesc, p->id, 0)) + continue; - sprintf(space, "%s", p->ctl_stack_type == CTL_STACK_PP? "pp_controlstack": p->ctl_stack_type == CTL_STACK_HVSP? "hvsp_controlstack": "unknown_controlstack"); - if(p->ctl_stack_type != CTL_STACK_NONE) - dev_stack_out(dot, p, space, p->controlstack, CTL_STACK_SIZE); - dev_stack_out(dot, p, "flash_instr", p->flash_instr, FLASH_INSTR_SIZE); - dev_stack_out(dot, p, "eeprom_instr", p->eeprom_instr, EEPROM_INSTR_SIZE); - -/* - unsigned char controlstack[CTL_STACK_SIZE]; // stk500v2 PP/HVSP ctl stack - unsigned char flash_instr[FLASH_INSTR_SIZE]; // flash instructions (debugWire, JTAG) - unsigned char eeprom_instr[EEPROM_INSTR_SIZE]; // EEPROM instructions (debugWire, JTAG) -*/ - - dev_partout("%d", hventerstabdelay); - dev_partout("%d", progmodedelay); - dev_partout("%d", latchcycles); - dev_partout("%d", togglevtg); - dev_partout("%d", poweroffdelay); - dev_partout("%d", resetdelayms); - dev_partout("%d", resetdelayus); - dev_partout("%d", hvleavestabdelay); - dev_partout("%d", resetdelay); - dev_partout("%d", chiperasepulsewidth); - dev_partout("%d", chiperasepolltimeout); - dev_partout("%d", chiperasetime); - dev_partout("%d", programfusepulsewidth); - dev_partout("%d", programfusepolltimeout); - dev_partout("%d", programlockpulsewidth); - dev_partout("%d", programlockpolltimeout); - dev_partout("%d", synchcycles); - dev_partout("%d", hvspcmdexedelay); - - dev_partout("0x%02x", idr); - dev_partout("0x%02x", rampz); - dev_partout("0x%02x", spmcr); - dev_partout("0x%02x", eecr); // why is eecr an unsigned short? - - dev_partout("0x%04x", mcu_base); - dev_partout("0x%04x", nvm_base); - dev_partout("0x%04x", ocd_base); - - if(p->ocdrev >= 0) - dev_partout("%d", ocdrev); - else - dev_partout("0x%8x", ocdrev); - - for(int i=0; i < AVR_OP_MAX; i++) { - if(p->op[i]) { - char *opc = opcode2str(p->op[i], !dot); - - if(dot) - dev_info(".partop\t%s\t%s\t%s\n", p->desc, opcodename(i), opc? opc: "error"); - else - dev_info(" %-19s = %s;\n", opcodename(i), opc? opc: "error"); - - if(opc) - free(opc); - } - } - if(p->mem) { - for(LNODEID lnm=lfirst(p->mem); lnm; lnm=lnext(lnm)) { - AVRMEM *m = ldata(lnm); - if(!dot) - dev_info("\n memory \"%s\"\n", m->desc); - - dev_memout_yn(paged); - if(m->size > 8192) - dev_memout("0x%x", size); - else - dev_memout("%d", size); - dev_memout("%d", page_size); - dev_memout("%d", num_pages); // why can AVRDUDE not compute this? - dev_memout("0x%x", offset); - dev_memout("%d", min_write_delay); - dev_memout("%d", max_write_delay); - dev_memout_yn(pwroff_after_write); - sprintf(space, "0x%02x 0x%02x", m->readback[0], m->readback[1]); - dev_memout_str(space, readback); - dev_memout("%d", mode); - dev_memout("%d", delay); - dev_memout("%d", blocksize); - dev_memout("%d", readsize); - dev_memout("%d", pollindex); - - for(int i=0; i < AVR_OP_MAX; i++) { - if(m->op[i]) { - char *opc = opcode2str(m->op[i], !dot); - - if(dot) - dev_info(".pmemop\t%s\t%s\t%s\t%s\n", p->desc, m->desc, opcodename(i), opc? opc: "error"); - else - dev_info(" %-15s = %s;\n", opcodename(i), opc? opc: "error"); - - if(opc) - free(opc); - } - } - - if(!dot) - 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(dot) - dev_info(".pmem\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(!dot) - dev_info(";\n"); - } + if(strct || cmpst) + dev_part_strct(p, tsv, cmpst? nullpart: NULL); + if(raw) + dev_part_raw(p); // identify core flash and eeprom parameters @@ -478,10 +840,6 @@ void dev_output_part_defs(char *partdesc) { AVRMEM *m; OPCODE *oc; - if(!first && all) - dev_info("\n"); - first = 0; - ok = 2047; nfuses = 0; @@ -601,7 +959,8 @@ void dev_output_part_defs(char *partdesc) { if(descs) { int len = 16-strlen(p->desc); - dev_info(".desc '%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", + 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, diff --git a/src/developer_opts_private.h b/src/developer_opts_private.h index ffeb5c05..b05949bd 100644 --- a/src/developer_opts_private.h +++ b/src/developer_opts_private.h @@ -1,3 +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_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 @@ -10,6 +31,10 @@ #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 @@ -22,29 +47,70 @@ #define DEV_NOTICE2 MSG_NOTICE2 #endif -#define dev_info(...) avrdude_message(DEV_INFO, __VA_ARGS__) -#define dev_notice(...) avrdude_message(DEV_NOTICE, __VA_ARGS__) -#define dev_notice2(...) avrdude_message(DEV_NOTICE2, __VA_ARGS__) +#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 dev_partout(fmt, component) (dot? \ - dev_info(".part\t%s\t%s\t" fmt "\n", p->desc, #component, p->component): \ - dev_info(" %-19s = " fmt ";\n", #component, p->component)) +#define __partout(fmt, component) \ + dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, dev_sprintf(fmt, p->component)) -#define dev_partout_str(result, component) (dot? \ - dev_info(".part\t%s\t%s\t%s\n", p->desc, #component, result): \ - dev_info(" %-19s = %s;\n", #component, result)) +#define __if_partout(cmp, fmt, component) ({ \ + if(!base || cmp(base->component, p->component)) \ + dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, dev_sprintf(fmt, p->component)); \ +}) -#define dev_memout(fmt, component) (dot? \ - dev_info(".pmem\t%s\t%s\t%s\t" fmt "\n", p->desc, m->desc, #component, m->component): \ - dev_info(" %-15s = " fmt ";\n", #component, m->component)) +#define __if_n_partout(cmp, n, fmt, component) ({ \ + if(!base || cmp(base->component, p->component, n)) \ + dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, dev_sprintf(fmt, p->component)); \ +}) -#define dev_memout_str(result, component) (dot? \ - dev_info(".pmem\t%s\t%s\t%s\t%s\n", p->desc, m->desc, #component, result): \ - dev_info(" %-15s = %s;\n", #component, result)) +#define __partout_str(result, component) \ + dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, result) -#define dev_memout_yn(component) (dot? \ - dev_info(".pmem\t%s\t%s\t%s\t%s\n", p->desc, m->desc, #component, m->component? "yes": "no"): \ - dev_info(" %-15s = %s;\n", #component, m->component? "yes": "no")) +#define __if_partout_str(cmp, result, component) ({ \ + if(!base || cmp(base->component, p->component)) \ + dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, result); \ +}) + +#define __if_n_partout_str(cmp, n, result, component) ({ \ + if(!base || cmp(base->component, p->component, n)) \ + dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, result); \ +}) -#define dev_flagout(name, mask) dev_info(" %-19s = %s;\n", (name), p->flags & (mask)? "yes": "no") +#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) ({ \ + if(!bm || cmp(bm->component, m->component)) \ + dev_part_strct_entry(tsv, ".ptmm", p->desc, m->desc, #component, dev_sprintf(fmt, m->component)); \ +}) + +#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) ({ \ + if(!bm || cmp(bm->component, m->component, n)) \ + dev_part_strct_entry(tsv, ".ptmm", p->desc, m->desc, #component, result); \ +}) + +#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) ({ \ + if(!bm || bm->component != m->component) \ + dev_part_strct_entry(tsv, ".ptmm", p->desc, m->desc, #component, strdup(m->component? "yes": "no")); \ +}) + +#define __flagout(mask, name) \ + __partout_str(strdup(p->flags & (mask)? "yes": "no"), name) + +#define __if_flagout(mask, name) ({ \ + if(!base || (base->flags & (mask)) != (p->flags & (mask))) \ + __partout_str(strdup(p->flags & (mask)? "yes": "no"), name); \ +}) + +#define __cmderr(result, component) \ + dev_part_strct_entry(tsv, ".cmderr", p->desc, m->desc, #component, result) + +#endif diff --git a/src/libavrdude.h b/src/libavrdude.h index ddb72b48..e27d61ea 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -318,9 +318,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); @@ -329,7 +329,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); diff --git a/src/main.c b/src/main.c index 121e865e..755ae731 100644 --- a/src/main.c +++ b/src/main.c @@ -830,9 +830,9 @@ 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 && *partdesc == '*') { - dev_output_part_defs(partdesc+1); + // 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); } From 8989e6515b102f6984620b1b6cec675d7fe4c1b3 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 19 Jul 2022 14:38:34 +0100 Subject: [PATCH 05/28] Change macros __f() to _f() and adapt to config_file and hvupdi changes --- src/developer_opts.c | 160 +++++++++++++++++------------------ src/developer_opts_private.h | 34 ++++---- src/libavrdude.h | 2 + 3 files changed, 97 insertions(+), 99 deletions(-) diff --git a/src/developer_opts.c b/src/developer_opts.c index 76ab3160..482ece7d 100644 --- a/src/developer_opts.c +++ b/src/developer_opts.c @@ -485,8 +485,7 @@ static int avrpart_deep_copy(AVRPARTdeep *d, AVRPART *p) { d->base = *p; - // remove location info - memset(d->base.config_file, 0, sizeof d->base.config_file); + d->base.config_file = NULL; d->base.lineno = 0; // zap all bytes beyond terminating nul of desc, id and family_id array @@ -567,64 +566,60 @@ static void dev_part_raw(AVRPART *part) { static void dev_part_strct(AVRPART *p, bool tsv, AVRPART *base) { - char real_config_file[PATH_MAX]; - - if(!realpath(p->config_file, real_config_file)) - memcpy(real_config_file, p->config_file, sizeof real_config_file); - - dev_info("# %s %d\n", real_config_file, p->lineno); + dev_info("# %s %d\n", p->config_file, p->lineno); if(!tsv) dev_info("part\n"); - __if_partout(strcmp, "\"%s\"", desc); - __if_partout(strcmp, "\"%s\"", id); - __if_partout(strcmp, "\"%s\"", family_id); - __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_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); + _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_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); + _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_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); + _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_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); @@ -639,32 +634,33 @@ static void dev_part_strct(AVRPART *p, bool tsv, AVRPART *base) { 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); + _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])) @@ -692,20 +688,20 @@ static void dev_part_strct(AVRPART *p, bool tsv, AVRPART *base) { 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); + _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])) diff --git a/src/developer_opts_private.h b/src/developer_opts_private.h index b05949bd..9bdd185a 100644 --- a/src/developer_opts_private.h +++ b/src/developer_opts_private.h @@ -51,66 +51,66 @@ static int dev_message(int msglvl, const char *fmt, ...); #define dev_notice(...) dev_message(DEV_NOTICE, __VA_ARGS__) #define dev_notice2(...) dev_message(DEV_NOTICE2, __VA_ARGS__) -#define __partout(fmt, component) \ +#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) ({ \ +#define _if_partout(cmp, fmt, component) ({ \ if(!base || cmp(base->component, p->component)) \ dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, dev_sprintf(fmt, p->component)); \ }) -#define __if_n_partout(cmp, n, fmt, component) ({ \ +#define _if_n_partout(cmp, n, fmt, component) ({ \ if(!base || cmp(base->component, p->component, n)) \ dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, dev_sprintf(fmt, p->component)); \ }) -#define __partout_str(result, component) \ +#define _partout_str(result, component) \ dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, result) -#define __if_partout_str(cmp, result, component) ({ \ +#define _if_partout_str(cmp, result, component) ({ \ if(!base || cmp(base->component, p->component)) \ dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, result); \ }) -#define __if_n_partout_str(cmp, n, result, component) ({ \ +#define _if_n_partout_str(cmp, n, result, component) ({ \ if(!base || cmp(base->component, p->component, n)) \ dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, result); \ }) -#define __memout(fmt, component) \ +#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) ({ \ +#define _if_memout(cmp, fmt, component) ({ \ if(!bm || cmp(bm->component, m->component)) \ dev_part_strct_entry(tsv, ".ptmm", p->desc, m->desc, #component, dev_sprintf(fmt, m->component)); \ }) -#define __memout_str(result, component) \ +#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) ({ \ +#define _if_n_memout_str(cmp, n, result, component) ({ \ if(!bm || cmp(bm->component, m->component, n)) \ dev_part_strct_entry(tsv, ".ptmm", p->desc, m->desc, #component, result); \ }) -#define __memout_yn(component) \ +#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) ({ \ +#define _if_memout_yn(component) ({ \ if(!bm || bm->component != m->component) \ dev_part_strct_entry(tsv, ".ptmm", p->desc, m->desc, #component, strdup(m->component? "yes": "no")); \ }) -#define __flagout(mask, name) \ - __partout_str(strdup(p->flags & (mask)? "yes": "no"), name) +#define _flagout(mask, name) \ + _partout_str(strdup(p->flags & (mask)? "yes": "no"), name) -#define __if_flagout(mask, name) ({ \ +#define _if_flagout(mask, name) ({ \ if(!base || (base->flags & (mask)) != (p->flags & (mask))) \ - __partout_str(strdup(p->flags & (mask)? "yes": "no"), name); \ + _partout_str(strdup(p->flags & (mask)? "yes": "no"), name); \ }) -#define __cmderr(result, component) \ +#define _cmderr(result, component) \ dev_part_strct_entry(tsv, ".cmderr", p->desc, m->desc, #component, result) #endif diff --git a/src/libavrdude.h b/src/libavrdude.h index 5e0e7807..c55608bc 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,6 +213,7 @@ 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 */ From 8da9c2bbf6b4e9467d362f0af242189b5173a94f Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 19 Jul 2022 14:46:08 +0100 Subject: [PATCH 06/28] Correct bit number for lone 'a' in config_gram.y When an SPI command has a lone 'a' the initialisation now is as would be expected by all commands that take an address. Atmel's opcodes for SPI programming are consistent in this respect. This commit makes specifying the bit number in avrdude.conf optional. Instead of read_lo = "0 0 1 0 0 0 0 0 0 0 a13 a12 a11 a10 a9 a8 a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; one can now use read_lo = "0 0 1 0 0 0 0 0 0 0 a a a a a a a a a a a a a a o o o o o o o o"; --- src/config_gram.y | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/config_gram.y b/src/config_gram.y index 2c6c1f46..71553aaa 100644 --- a/src/config_gram.y +++ b/src/config_gram.y @@ -45,7 +45,7 @@ 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; %} @@ -1317,7 +1317,8 @@ 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]); @@ -1455,7 +1456,8 @@ 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]); @@ -1579,7 +1581,7 @@ static int which_opcode(TOKEN * opcode) } -static int parse_cmdbits(OPCODE * op) +static int parse_cmdbits(OPCODE * op, int opnum) { TOKEN * t; int bitno; @@ -1635,7 +1637,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 Byte 0 or Byte 3 of SPI programming commands"); break; case 'i': op->bit[bitno].type = AVR_CMDBIT_INPUT; @@ -1679,5 +1684,8 @@ static int parse_cmdbits(OPCODE * op) } /* while */ + if(bitno > 0) + yywarning("too few opcode bits in instruction"); + return rv; } From bb6e1bbaecffaad45663c6333e000e60dc476830 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 19 Jul 2022 15:01:51 +0100 Subject: [PATCH 07/28] Add avrdude.conf new syntax: readback = 0x80 0x7f; --- src/config_gram.y | 9 +++++++++ src/lexer.l | 1 + 2 files changed, 10 insertions(+) diff --git a/src/config_gram.y b/src/config_gram.y index 71553aaa..e2dd669a 100644 --- a/src/config_gram.y +++ b/src/config_gram.y @@ -112,6 +112,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 @@ -1399,6 +1400,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; diff --git a/src/lexer.l b/src/lexer.l index 4db95f6d..e392324a 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -213,6 +213,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; } From f8b6a246efbd3658c6185d43054df118f6c69866 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 19 Jul 2022 15:17:00 +0100 Subject: [PATCH 08/28] Add in lexer.l capability to scan negative decimal integers or reals --- src/lexer.l | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/lexer.l b/src/lexer.l index e392324a..f2f4b2ce 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); } From 8503f2d2d54823bee32ad753ef7da1252a7cb542 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 19 Jul 2022 15:38:54 +0100 Subject: [PATCH 09/28] Add avrdude.conf syntax opcode = NULL; for SPI programming --- src/config_gram.y | 28 ++++++++++++++++++++++++++++ src/lexer.l | 1 + 2 files changed, 29 insertions(+) diff --git a/src/config_gram.y b/src/config_gram.y index e2dd669a..0ca1d782 100644 --- a/src/config_gram.y +++ b/src/config_gram.y @@ -50,6 +50,8 @@ 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 @@ -1326,6 +1328,19 @@ part_parm : } 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); } } @@ -1473,6 +1488,19 @@ mem_spec : } 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); } } diff --git a/src/lexer.l b/src/lexer.l index f2f4b2ce..91d02597 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -176,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; } From 155590660464b6a10e3f79340097a90f84da3df4 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 19 Jul 2022 15:58:40 +0100 Subject: [PATCH 10/28] Add avrdude.conf syntax memory "name" = NULL; --- src/config_gram.y | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/config_gram.y b/src/config_gram.y index 0ca1d782..bdea3352 100644 --- a/src/config_gram.y +++ b/src/config_gram.y @@ -1306,7 +1306,16 @@ part_parm : } 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); + } + free_token($2); + current_mem = NULL; + } | opcode TKN_EQUAL string_list { { int opnum; From bdb5ba60552d25b56fe5f681cdbf90041dbb2172 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 19 Jul 2022 16:16:55 +0100 Subject: [PATCH 11/28] Add avrdude.conf syntax ((pp|hvsp)_controlstack|(eeprom|flash)_instr) = NULL; --- src/config_gram.y | 26 ++++++++++++++++++++++++++ src/developer_opts.c | 4 ++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/config_gram.y b/src/config_gram.y index bdea3352..6f6f8765 100644 --- a/src/config_gram.y +++ b/src/config_gram.y @@ -800,6 +800,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; @@ -831,6 +838,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; @@ -861,6 +875,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; @@ -891,6 +911,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; diff --git a/src/developer_opts.c b/src/developer_opts.c index 482ece7d..5784b64f 100644 --- a/src/developer_opts.c +++ b/src/developer_opts.c @@ -363,13 +363,13 @@ 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? "NONE": + 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, "NONE")) { + if(!strcmp(name, "NULL")) { name = "pp_controlstack"; ns = 0; } From db37c9d2862b1229a91cb325ff70496d19d3ff10 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 19 Jul 2022 20:00:17 +0100 Subject: [PATCH 12/28] Extend rather than reset memory entries in avrdude.conf This commit changes the philosophy whenever avrdude.conf encounters the same memory of a part for the second time or whenever a memory is described that, through inheritance, already existed: AVRDUDE no longer zaps the memory, it rather extends it. Therefore, avrdude.conf.in's entry for ATmega128RFA1, which inherits from the ATmega2561, needs a line `load_ext_addr = NULL;` in its flash memory description to zap the inherited load_ext_addr SPI command. Other than this, avrdude.conf.in needs no other change in order to effect the same internal representation proving earlier updates to the .conf.in file correct that manually ensured inheritance of memory contents. --- src/avrdude.conf.in | 2 ++ src/config_gram.y | 36 ++++++++++++++++-------------------- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in index 8fc67080..3b8c5a6e 100644 --- a/src/avrdude.conf.in +++ b/src/avrdude.conf.in @@ -11845,6 +11845,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/config_gram.y b/src/config_gram.y index 6f6f8765..7a8cb7eb 100644 --- a/src/config_gram.y +++ b/src/config_gram.y @@ -1304,31 +1304,27 @@ 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; - - existing_mem = avr_locate_mem_noalias(current_part, current_mem->desc); - 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 + { + 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 { - ladd(current_part->mem, current_mem); } current_mem = NULL; } | From 30041e3f5f4ce5f10e3679f61d30d6e01219acc5 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 19 Jul 2022 22:59:46 +0100 Subject: [PATCH 13/28] Add compact alternative specification for SPI opcodes in avrdude.conf As the address bit numbers in the SPI opcodes are highly systematic, they don't really need to be specified. Each bit can therefore be described as one of the characters 0 (always 0), 1 (always 1), x (don't care, but will be set as 0), a (a copy of the correct bit of the byte or word address of read, write, load, pagewrite or load extended address command of memories with more than one byte), i (input bit for a load/write) or o (output bit from a read). The bits therefore do not need to be individually separated. If a string in the list of strings that describe an SPI opcode does *not* contain a space *and* is longer than 7 characters, it is interpreted as a compact bit-pattern representation. 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"; loadpage_lo = "0100.0000", "000x.xxxx.xxaa.aaaa", "iiii.iiii"; loadpage_lo = "0100.0000-000x.xxxx--xxaa.aaaa-iiii.iiii"; loadpage_lo = "0100.0000/000x.xxxx/xxaa.aaaa/iiii.iiii"; The compact format is an extension of the current format, which remains valid. Both, the compact and the traditional specification can be mixed in different strings, albeit not in the same string: load_ext_addr = "0100.1101", "0000.0000.0000", "0 0 0 a16", "0000.0000"; --- src/config_gram.y | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/config_gram.y b/src/config_gram.y index 7a8cb7eb..3b979c20 100644 --- a/src/config_gram.y +++ b/src/config_gram.y @@ -1653,7 +1653,6 @@ static int parse_cmdbits(OPCODE * op, int opnum) { TOKEN * t; int bitno; - char ch; char * e; char * q; int len; @@ -1665,10 +1664,18 @@ static int parse_cmdbits(OPCODE * op, int opnum) 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; @@ -1683,10 +1690,8 @@ static int parse_cmdbits(OPCODE * op, int opnum) 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; @@ -1720,14 +1725,19 @@ static int parse_cmdbits(OPCODE * op, int opnum) 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') { + if (*s == 'a') { q = &s[1]; op->bit[bitno].bitno = strtol(q, &e, 0); if ((e == q)||(*e != 0)) { @@ -1745,7 +1755,8 @@ static int parse_cmdbits(OPCODE * op, int opnum) } } - s = strtok_r(NULL, " ", &brkt); + bit[0] = *cc++; + s = !compact? strtok_r(NULL, " ", &brkt): *bit? bit: NULL; } /* while */ free_token(t); From 6afa115a5ffd40ffc174c2665e4513cfbefc54f4 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 19 Jul 2022 23:44:58 +0100 Subject: [PATCH 14/28] Make -p*/s print SPI opcodes like "0100.0000--000.aaaa--aaaa.aaaa--iiii.iiii" --- src/developer_opts.c | 50 +++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/src/developer_opts.c b/src/developer_opts.c index 5784b64f..1b3d17d9 100644 --- a/src/developer_opts.c +++ b/src/developer_opts.c @@ -115,25 +115,41 @@ static const char *opcodename(int what) { } -static char *opcode2str(OPCODE *op, int detailed) { +// Unique string representation of an opcode +static 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(detailed && cb == 'a') { - sprintf(sp, "%d", op->bit[i].bitno); - sp += strlen(sp); - } - if(i) { - if(detailed) - *sp++ = ' '; - if(i%8 == 0) - *sp++ = ' '; + 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) @@ -145,7 +161,7 @@ static char *opcode2str(OPCODE *op, int detailed) { // return 0 if op code would encode (essentially) the same SPI command -static int opcodecmp(OPCODE *op1, OPCODE *op2) { +static int opcodecmp(OPCODE *op1, OPCODE *op2, int opnum) { char *opstr1, *opstr2, *p; int cmp; @@ -154,8 +170,8 @@ static int opcodecmp(OPCODE *op1, OPCODE *op2) { if(!op1 || !op2) return op1? -1: 1; - opstr1 = opcode2str(op1, 1); - opstr2 = opcode2str(op2, 1); + opstr1 = opcode2str(op1, opnum, 1); + opstr2 = opcode2str(op2, opnum, 1); if(!opstr1 || !opstr2) { dev_info("%s: out of memory\n", progname); exit(1); @@ -663,8 +679,8 @@ static void dev_part_strct(AVRPART *p, bool tsv, AVRPART *base) { _if_partout(intcmp, "%d", ocdrev); for(int i=0; i < AVR_OP_MAX; i++) - if(!base || opcodecmp(p->op[i], base->op[i])) - dev_part_strct_entry(tsv, ".ptop", p->desc, "part", opcodename(i), opcode2str(p->op[i], !tsv)); + 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(int mi=0; mi < sizeof mem_order/sizeof *mem_order && mem_order[mi]; mi++) { AVRMEM *m, *bm; @@ -704,8 +720,8 @@ static void dev_part_strct(AVRPART *p, bool tsv, AVRPART *base) { _if_memout(intcmp, "%d", pollindex); for(int i=0; i < AVR_OP_MAX; i++) - if(!bm || opcodecmp(bm->op[i], m->op[i])) - dev_part_strct_entry(tsv, ".ptmmop", p->desc, m->desc, opcodename(i), opcode2str(m->op[i], !tsv)); + 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"); From 4ada98a1a8fdb90dd918a0d11c9ded87b3edd114 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Wed, 20 Jul 2022 00:57:26 +0100 Subject: [PATCH 15/28] Udate the avrdude.conf introductory documentation --- src/avrdude.conf.in | 157 +++++++++++++++++++++++++++----------------- 1 file changed, 95 insertions(+), 62 deletions(-) diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in index 3b8c5a6e..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 From 696574d1ebfa6cf3891247f79cc8f0a629955527 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Thu, 21 Jul 2022 18:04:41 +0100 Subject: [PATCH 16/28] Replace !fnmatch(p, s, 0) with own part_match(p, s) --- src/developer_opts.c | 125 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 122 insertions(+), 3 deletions(-) diff --git a/src/developer_opts.c b/src/developer_opts.c index 1b3d17d9..0f0bdab0 100644 --- a/src/developer_opts.c +++ b/src/developer_opts.c @@ -44,7 +44,6 @@ #include #include #include -#include #include "avrdude.h" #include "libavrdude.h" @@ -742,6 +741,127 @@ 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. + */ + +#define FOLD(c) ({ int _c = (unsigned char) (c); isascii(_c)? tolower(_c): _c; }) + +static 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) { bool cmdok, waits, opspi, descs, strct, cmpst, raw, all, tsv; @@ -817,8 +937,7 @@ void dev_output_part_defs(char *partdesc) { nprinted = dev_nprinted; } - // pattern match the name of the part with command line: FMP_CASEFOLD not available here :( - if(fnmatch(partdesc, p->desc, 0) && fnmatch(partdesc, p->id, 0)) + if(!part_match(partdesc, p->desc) && !part_match(partdesc, p->id)) continue; if(strct || cmpst) From 192e118d2cd9706beec96fad0a94b968e205a035 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Thu, 21 Jul 2022 18:36:04 +0100 Subject: [PATCH 17/28] Make useful functions from developer_optc.c available --- src/developer_opts.c | 20 +++++++++----------- src/developer_opts.h | 7 ++++++- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/developer_opts.c b/src/developer_opts.c index 0f0bdab0..db100eb3 100644 --- a/src/developer_opts.c +++ b/src/developer_opts.c @@ -51,7 +51,7 @@ #include "developer_opts.h" #include "developer_opts_private.h" -static char cmdbitchar(CMDBIT cb) { +char cmdbitchar(CMDBIT cb) { switch(cb.type) { case AVR_CMDBIT_IGNORE: return 'x'; @@ -68,8 +68,9 @@ static char cmdbitchar(CMDBIT cb) { } } -static char *cmdbitstr(CMDBIT cb) { - char space[10]; + +char *cmdbitstr(CMDBIT cb) { + char space[32]; *space = cmdbitchar(cb); if(*space == 'a') @@ -81,9 +82,8 @@ static char *cmdbitstr(CMDBIT cb) { } - -static const char *opcodename(int what) { - switch(what) { +const char *opcodename(int opcode) { + switch(opcode) { case AVR_OP_READ: return "read"; case AVR_OP_WRITE: @@ -192,8 +192,6 @@ static int opcodecmp(OPCODE *op1, OPCODE *op2, int opnum) { } - - static void printopcode(AVRPART *p, const char *d, OPCODE *op, int what) { unsigned char cmd[4]; int i; @@ -218,7 +216,7 @@ 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 -static int intlog2(unsigned int n) { +int intlog2(unsigned int n) { int ret; if(!n) @@ -402,7 +400,7 @@ static void dev_stack_out(bool tsv, AVRPART *p, const char *name, unsigned char } -// order in which memories are processed, runtime adds unknown ones +// order in which memories are processed, runtime adds unknown ones (but there shouldn't be any) static const char *mem_order[100] = { "eeprom", "flash", "application", "apptable", "boot", "lfuse", "hfuse", "efuse", @@ -750,7 +748,7 @@ static void dev_part_strct(AVRPART *p, bool tsv, AVRPART *base) { #define FOLD(c) ({ int _c = (unsigned char) (c); isascii(_c)? tolower(_c): _c; }) -static int part_match(const char *pattern, const char *string) { +int part_match(const char *pattern, const char *string) { unsigned char c; const char *p = pattern, *n = string; diff --git a/src/developer_opts.h b/src/developer_opts.h index 701d97e3..8a4d821b 100644 --- a/src/developer_opts.h +++ b/src/developer_opts.h @@ -19,6 +19,11 @@ #ifndef developer_opts_h #define developer_opts_h -void dev_output_part_defs(); +char cmdbitchar(CMDBIT cb); +char *cmdbitstr(CMDBIT cb); +const char *opcodename(int opcode); +int intlog2(unsigned int n); +int part_match(const char *pattern, const char *string); +void dev_output_part_defs(char *partdesc); #endif From 55f6765ea516564a86431226f8aab0ea01f6986a Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Thu, 21 Jul 2022 18:47:48 +0100 Subject: [PATCH 18/28] Make more useful functions from developer_optc.c available --- src/developer_opts.c | 25 ++++++++++++------------- src/developer_opts.h | 4 +++- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/developer_opts.c b/src/developer_opts.c index db100eb3..cdc40a21 100644 --- a/src/developer_opts.c +++ b/src/developer_opts.c @@ -82,8 +82,8 @@ char *cmdbitstr(CMDBIT cb) { } -const char *opcodename(int opcode) { - switch(opcode) { +const char *opcodename(int opnum) { + switch(opnum) { case AVR_OP_READ: return "read"; case AVR_OP_WRITE: @@ -115,7 +115,7 @@ const char *opcodename(int opcode) { // Unique string representation of an opcode -static char *opcode2str(OPCODE *op, int opnum, int detailed) { +char *opcode2str(OPCODE *op, int opnum, int detailed) { char cb, space[1024], *sp = space; int compact = 1; @@ -160,7 +160,7 @@ static char *opcode2str(OPCODE *op, int opnum, int detailed) { // return 0 if op code would encode (essentially) the same SPI command -static int opcodecmp(OPCODE *op1, OPCODE *op2, int opnum) { +int opcodecmp(OPCODE *op1, OPCODE *op2, int opnum) { char *opstr1, *opstr2, *p; int cmp; @@ -192,7 +192,7 @@ static int opcodecmp(OPCODE *op1, OPCODE *op2, int opnum) { } -static void printopcode(AVRPART *p, const char *d, OPCODE *op, int what) { +static void printopcode(AVRPART *p, const char *d, OPCODE *op, int opnum) { unsigned char cmd[4]; int i; @@ -200,7 +200,7 @@ static void printopcode(AVRPART *p, const char *d, OPCODE *op, int what) { 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(what), cmd[0], cmd[1], cmd[2], cmd[3]); + 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) @@ -266,9 +266,9 @@ static char *parttype(AVRPART *p) { // check whether address bits are where they should be in ISP commands -static void checkaddr(int memsize, int pagesize, int what, OPCODE *op, AVRPART *p, AVRMEM *m) { +static void checkaddr(int memsize, int pagesize, int opnum, OPCODE *op, AVRPART *p, AVRMEM *m) { int i, lo, hi; - const char *whatstr = opcodename(what); + const char *opstr = opcodename(opnum); lo = intlog2(pagesize); hi = intlog2(memsize-1); @@ -278,20 +278,20 @@ static void checkaddr(int memsize, int pagesize, int what, OPCODE *op, AVRPART * 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, whatstr, i+8, cbs? cbs: "NULL"); + 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, whatstr, i+8, cmdbitchar(op->bit[i+8])); + 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, whatstr, i+8, i, op->bit[i+8].bitno); + 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, whatstr, i, op->bit[i].bitno); + 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); } @@ -859,7 +859,6 @@ int part_match(const char *pattern, const char *string) { } - // -p */[cdosw*] void dev_output_part_defs(char *partdesc) { bool cmdok, waits, opspi, descs, strct, cmpst, raw, all, tsv; diff --git a/src/developer_opts.h b/src/developer_opts.h index 8a4d821b..00c13005 100644 --- a/src/developer_opts.h +++ b/src/developer_opts.h @@ -21,7 +21,9 @@ char cmdbitchar(CMDBIT cb); char *cmdbitstr(CMDBIT cb); -const char *opcodename(int opcode); +const char *opcodename(int opnum); +char *opcode2str(OPCODE *op, int opnum, int detailed); +int opcodecmp(OPCODE *op1, OPCODE *op2, int opnum); int intlog2(unsigned int n); int part_match(const char *pattern, const char *string); void dev_output_part_defs(char *partdesc); From 572849ec2af20416c118248b0ce95d4bb70929be Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Thu, 21 Jul 2022 21:42:07 +0100 Subject: [PATCH 19/28] Provide avr_set_addr_mem() to set addresses in SPI opcodes within boundaries The function avr_set_addr_mem(AVRMEM *mem, int opnum, unsigned char *cmd, unsigned long addr) is meant to replace avr_set_addr(OPCODE *op, unsigned char *cmd, unsigned long addr) in future. avr_set_addr_mem() has more information about the context of the task in that it knows the memory size, memory page size, whether or not the memory is a flash memory (which gets words addressees supplied) and, crucially, knows which SPI operation it is meant to compute the address bits for. avr_set_addr_mem() first computes the interval of bit numbers that must be supplied for the SPI command to stand a chance to work. The function only sets those address bits that are needed. Once all avr_set_addr() function calls have been replaced by avr_set_addr_mem(), the SPI commands that need an address can afford to declare in avrdude.conf all 16 address bits in the middle two bytes of the SPI command. This over-declaration will be corrected during runtime by avr_set_addr_mem(). One consequence of this is that parts can inherit smaller or larger memories from parents without the need to use different SPI codes in avrdude.conf. Another consequence is that avr_set_addr_mem() can, and does, tell the caller whether vital address bits were not declared in the SPI opcode. During parsing of avrdude.conf this might be utilised to generate a corresponding warning. This will uncover problematic SPI codes in avrdude.conf that in the past went undetected. --- src/developer_opts.c | 94 ++++++++++++++++++++++++++++++++++++++++++++ src/developer_opts.h | 1 + 2 files changed, 95 insertions(+) diff --git a/src/developer_opts.c b/src/developer_opts.c index cdc40a21..2f50eda6 100644 --- a/src/developer_opts.c +++ b/src/developer_opts.c @@ -295,6 +295,100 @@ 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; char *p = NULL; diff --git a/src/developer_opts.h b/src/developer_opts.h index 00c13005..d112f517 100644 --- a/src/developer_opts.h +++ b/src/developer_opts.h @@ -25,6 +25,7 @@ const char *opcodename(int opnum); char *opcode2str(OPCODE *op, int opnum, int detailed); int opcodecmp(OPCODE *op1, OPCODE *op2, int opnum); int intlog2(unsigned int n); +int avr_set_addr_mem(AVRMEM *mem, int opnum, unsigned char *cmd, unsigned long addr); int part_match(const char *pattern, const char *string); void dev_output_part_defs(char *partdesc); From 02788fb48aed795cb71855e4434bc0b64ab82fd1 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Thu, 21 Jul 2022 22:43:08 +0100 Subject: [PATCH 20/28] Warn whenever address bits in avrdude.conf SPI commands miss --- src/config_gram.y | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/config_gram.y b/src/config_gram.y index 3b979c20..3507fd29 100644 --- a/src/config_gram.y +++ b/src/config_gram.y @@ -29,6 +29,7 @@ #include "avrdude.h" #include "libavrdude.h" #include "config.h" +#include "developer_opts.h" #if defined(WIN32) #define strtok_r( _s, _sep, _lasts ) \ @@ -1325,6 +1326,16 @@ part_parm : 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; + + 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; } | From a95d169ccc0ac6964a3b1da3dccad29092928f50 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Thu, 21 Jul 2022 23:11:44 +0100 Subject: [PATCH 21/28] Warn whenever address bits in avrdude.conf SPI commands are misplaced --- src/config_gram.y | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/src/config_gram.y b/src/config_gram.y index 3507fd29..4de668b5 100644 --- a/src/config_gram.y +++ b/src/config_gram.y @@ -25,6 +25,7 @@ #include #include #include +#include #include "avrdude.h" #include "libavrdude.h" @@ -1662,12 +1663,10 @@ static int which_opcode(TOKEN * opcode) static int parse_cmdbits(OPCODE * op, int opnum) { - TOKEN * t; + TOKEN *t; int bitno; - char * e; - char * q; int len; - char * s, *brkt = NULL; + char *s, *brkt = NULL; int rv = 0; bitno = 32; @@ -1724,7 +1723,7 @@ static int parse_cmdbits(OPCODE * op, int opnum) 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 Byte 0 or Byte 3 of SPI programming commands"); + 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; @@ -1749,13 +1748,27 @@ static int parse_cmdbits(OPCODE * op, int opnum) } else { if (*s == '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; + 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; } From 5a517fb74dd2c5bb375ce480fb3bf1d9e0ead182 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Fri, 22 Jul 2022 23:50:22 +0100 Subject: [PATCH 22/28] Make developer opts portable: change statement exprs and index(); use size_t --- src/developer_opts.c | 42 +++++++++++++++++++----------------- src/developer_opts_private.h | 32 +++++++++++++-------------- 2 files changed, 38 insertions(+), 36 deletions(-) diff --git a/src/developer_opts.c b/src/developer_opts.c index 2f50eda6..f1f465cc 100644 --- a/src/developer_opts.c +++ b/src/developer_opts.c @@ -510,7 +510,7 @@ static const char *mem_order[100] = { }; static void add_mem_order(const char *str) { - for(int i=0; i < sizeof mem_order/sizeof *mem_order; i++) { + for(size_t i=0; i < sizeof mem_order/sizeof *mem_order; i++) { if(mem_order[i] && !strcmp(mem_order[i], str)) return; if(!mem_order[i]) { @@ -536,7 +536,7 @@ typedef struct { } AVRMEMdeep; static int avrmem_deep_copy(AVRMEMdeep *d, AVRMEM *m) { - int len; + size_t len; d->base = *m; @@ -555,7 +555,7 @@ static int avrmem_deep_copy(AVRMEMdeep *d, AVRMEM *m) { // copy over the SPI operations themselves memset(d->base.op, 0, sizeof d->base.op); memset(d->ops, 0, sizeof d->ops); - for(int i=0; iops/sizeof *d->ops; i++) + for(size_t i=0; iops/sizeof *d->ops; i++) if(m->op[i]) d->ops[i] = *m->op[i]; @@ -586,7 +586,7 @@ typedef struct { static int avrpart_deep_copy(AVRPARTdeep *d, AVRPART *p) { AVRMEM *m; - int len, di; + size_t len, di; memset(d, 0, sizeof *d); @@ -623,7 +623,7 @@ static int avrpart_deep_copy(AVRPARTdeep *d, AVRPART *p) { // fill in all memories we got in defined order di = 0; - for(int mi=0; mi < sizeof mem_order/sizeof *mem_order && mem_order[mi]; mi++) { + 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) { @@ -773,7 +773,7 @@ static void dev_part_strct(AVRPART *p, bool tsv, AVRPART *base) { 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(int mi=0; mi < sizeof mem_order/sizeof *mem_order && mem_order[mi]; mi++) { + 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; @@ -840,7 +840,9 @@ static void dev_part_strct(AVRPART *p, bool tsv, AVRPART *base) { * from the GNU C Library (published under GLP v2). Used for portability. */ -#define FOLD(c) ({ int _c = (unsigned char) (c); isascii(_c)? tolower(_c): _c; }) +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; @@ -849,7 +851,7 @@ int part_match(const char *pattern, const char *string) { if(!*n) // AVRDUDE specialty: empty string never matches return 0; - while((c = FOLD(*p++))) { + while((c = fold(*p++))) { switch(c) { case '?': if(*n == 0) @@ -857,8 +859,8 @@ int part_match(const char *pattern, const char *string) { break; case '\\': - c = FOLD(*p++); - if(FOLD(*n) != c) + c = fold(*p++); + if(fold(*n) != c) return 0; break; @@ -871,10 +873,10 @@ int part_match(const char *pattern, const char *string) { return 1; { - unsigned char c1 = FOLD(c == '\\'? *p : c); // This char + 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) + if((c == '[' || fold(*n) == c1) && part_match(p, n) == 1) return 1; return 0; } @@ -897,13 +899,13 @@ int part_match(const char *pattern, const char *string) { if(c == '\\') cstart = cend = *p++; - cstart = cend = FOLD(cstart); + cstart = cend = fold(cstart); if(c == 0) // [ (unterminated) return 0; c = *p++; - c = FOLD(c); + c = fold(c); if(c == '-' && *p != ']') { cend = *p++; @@ -911,12 +913,12 @@ int part_match(const char *pattern, const char *string) { cend = *p++; if(cend == 0) return 0; - cend = FOLD(cend); + cend = fold(cend); c = *p++; } - if(FOLD(*n) >= cstart && FOLD(*n) <= cend) + if(fold(*n) >= cstart && fold(*n) <= cend) goto matched; if(c == ']') @@ -942,7 +944,7 @@ int part_match(const char *pattern, const char *string) { break; default: - if(c != FOLD(*n)) + if(c != fold(*n)) return 0; } @@ -1043,12 +1045,12 @@ void dev_output_part_defs(char *partdesc) { if(p->mem) { for(LNODEID lnm=lfirst(p->mem); lnm; lnm=lnext(lnm)) { AVRMEM *m = ldata(lnm); - if(!flashsize && m->desc && 0==strcmp(m->desc, "flash")) { + if(!flashsize && 0==strcmp(m->desc, "flash")) { flashsize = m->size; flashpagesize = m->page_size; flashoffset = m->offset; } - if(!eepromsize && m->desc && 0==strcmp(m->desc, "eeprom")) { + if(!eepromsize && 0==strcmp(m->desc, "eeprom")) { eepromsize = m->size; eepromoffset = m->offset; eeprompagesize = m->page_size; @@ -1057,7 +1059,7 @@ void dev_output_part_defs(char *partdesc) { } // "real" entries don't seem to have a space in their desc (a bit hackey) - if(flashsize && !index(p->desc, ' ')) { + if(flashsize && !strchr(p->desc, ' ')) { int ok, nfuses; AVRMEM *m; OPCODE *oc; diff --git a/src/developer_opts_private.h b/src/developer_opts_private.h index 9bdd185a..5a208199 100644 --- a/src/developer_opts_private.h +++ b/src/developer_opts_private.h @@ -54,61 +54,61 @@ static int dev_message(int msglvl, const char *fmt, ...); #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) ({ \ +#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) ({ \ +#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) ({ \ +#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) ({ \ +#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) ({ \ +#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) ({ \ +#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) ({ \ +#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) ({ \ +#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) From d5d3a0e09eb68e9889c85e0ea317a07e49f29727 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Sun, 24 Jul 2022 23:38:51 +0100 Subject: [PATCH 23/28] Improve help message -p/h for developer option -p --- src/developer_opts.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/developer_opts.c b/src/developer_opts.c index f1f465cc..94051fe9 100644 --- a/src/developer_opts.c +++ b/src/developer_opts.c @@ -971,13 +971,13 @@ void dev_output_part_defs(char *partdesc) { if(!*flags || !strchr("cdosSrw*t", *flags)) { dev_info("%s: flags for developer option -p / not recognised\n", progname); dev_info( - "Wildcard examples:\n" + "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 address bits in SPI commands and output errors\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" @@ -986,8 +986,18 @@ void dev_output_part_defs(char *partdesc) { " w wd_... constants for ISP parts\n" " * all of the above except s\n" " t use tab separated values as much as possible\n" - "Note:\n" - " -p * same as -p */*\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; } From 154927352911a3021cbec29621ece4feca57c6da Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Mon, 25 Jul 2022 20:30:40 +0100 Subject: [PATCH 24/28] Add comments with part names to -p*/s output --- src/developer_opts.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/developer_opts.c b/src/developer_opts.c index 94051fe9..589dae05 100644 --- a/src/developer_opts.c +++ b/src/developer_opts.c @@ -673,10 +673,13 @@ static void dev_part_raw(AVRPART *part) { static void dev_part_strct(AVRPART *p, bool tsv, AVRPART *base) { - dev_info("# %s %d\n", p->config_file, p->lineno); - if(!tsv) - dev_info("part\n"); + if(!tsv) { + dev_info("#------------------------------------------------------------\n"); + dev_info("# %s\n", p->desc); + dev_info("#------------------------------------------------------------\n"); + dev_info("\npart\n"); + } _if_partout(strcmp, "\"%s\"", desc); _if_partout(strcmp, "\"%s\"", id); From 78754b8ccc619b5cb42c7140aa97c7da7e70e2c4 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 26 Jul 2022 23:43:56 +0100 Subject: [PATCH 25/28] Add parent id output for developer options -p*/s for parts --- src/avrpart.c | 32 +++++++++++++++----------------- src/config_gram.y | 2 ++ src/developer_opts.c | 8 ++++++-- src/libavrdude.h | 2 ++ src/pgm.c | 9 +++------ 5 files changed, 28 insertions(+), 25 deletions(-) diff --git a/src/avrpart.c b/src/avrpart.c index 29bfbcc2..96e45334 100644 --- a/src/avrpart.c +++ b/src/avrpart.c @@ -354,7 +354,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 +362,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) { @@ -487,7 +486,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; @@ -579,6 +579,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); @@ -608,7 +609,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); @@ -636,20 +636,18 @@ 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, const char * partdesc) diff --git a/src/config_gram.y b/src/config_gram.y index 4de668b5..68718dd1 100644 --- a/src/config_gram.y +++ b/src/config_gram.y @@ -334,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); @@ -425,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; diff --git a/src/developer_opts.c b/src/developer_opts.c index 589dae05..5e5b312e 100644 --- a/src/developer_opts.c +++ b/src/developer_opts.c @@ -592,6 +592,7 @@ static int avrpart_deep_copy(AVRPARTdeep *d, AVRPART *p) { d->base = *p; + d->base.parent_id = NULL; d->base.config_file = NULL; d->base.lineno = 0; @@ -678,7 +679,10 @@ static void dev_part_strct(AVRPART *p, bool tsv, AVRPART *base) { dev_info("#------------------------------------------------------------\n"); dev_info("# %s\n", p->desc); dev_info("#------------------------------------------------------------\n"); - dev_info("\npart\n"); + if(p->parent_id) + dev_info("\npart parent \"%s\"\n", p->parent_id); + else + dev_info("\npart\n"); } _if_partout(strcmp, "\"%s\"", desc); @@ -1047,7 +1051,7 @@ void dev_output_part_defs(char *partdesc) { continue; if(strct || cmpst) - dev_part_strct(p, tsv, cmpst? nullpart: NULL); + dev_part_strct(p, tsv, !cmpst? NULL: p->parent_id? locate_part(part_list, p->parent_id): nullpart); if(raw) dev_part_raw(p); diff --git a/src/libavrdude.h b/src/libavrdude.h index c55608bc..76772e25 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -217,6 +217,7 @@ typedef struct opcode { 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 */ @@ -661,6 +662,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/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) { From 62dcc2e6e819edb39a24b0ca744b72828a5d0514 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 26 Jul 2022 23:55:42 +0100 Subject: [PATCH 26/28] Declare useful CMDBIT/part functions of developer_opts.c in libavrdude.h --- src/developer_opts.c | 2 +- src/developer_opts.h | 8 -------- src/libavrdude.h | 10 ++++++++++ 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/developer_opts.c b/src/developer_opts.c index 5e5b312e..0ddf68b2 100644 --- a/src/developer_opts.c +++ b/src/developer_opts.c @@ -160,7 +160,7 @@ char *opcode2str(OPCODE *op, int opnum, int detailed) { // return 0 if op code would encode (essentially) the same SPI command -int opcodecmp(OPCODE *op1, OPCODE *op2, int opnum) { +static int opcodecmp(OPCODE *op1, OPCODE *op2, int opnum) { char *opstr1, *opstr2, *p; int cmp; diff --git a/src/developer_opts.h b/src/developer_opts.h index d112f517..6c4b3b71 100644 --- a/src/developer_opts.h +++ b/src/developer_opts.h @@ -19,14 +19,6 @@ #ifndef developer_opts_h #define developer_opts_h -char cmdbitchar(CMDBIT cb); -char *cmdbitstr(CMDBIT cb); -const char *opcodename(int opnum); -char *opcode2str(OPCODE *op, int opnum, int detailed); -int opcodecmp(OPCODE *op1, OPCODE *op2, int opnum); -int intlog2(unsigned int n); -int avr_set_addr_mem(AVRMEM *mem, int opnum, unsigned char *cmd, unsigned long addr); -int part_match(const char *pattern, const char *string); void dev_output_part_defs(char *partdesc); #endif diff --git a/src/libavrdude.h b/src/libavrdude.h index 76772e25..ced77554 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -320,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); @@ -359,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 From 004b46b594e66beea17fd92f16dc47da1847816c Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Wed, 27 Jul 2022 00:12:57 +0100 Subject: [PATCH 27/28] Move useful CMDBIT/part functions from developer_opts.c to avrpart.c --- src/avrpart.c | 342 ++++++++++++++++++++++++++++++++++++++++++- src/developer_opts.c | 334 ------------------------------------------ 2 files changed, 339 insertions(+), 337 deletions(-) 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) { From f299439b972ab8a115f090981a290a4f5e56a3ad Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Wed, 27 Jul 2022 00:18:06 +0100 Subject: [PATCH 28/28] Move developer_opts* file names from library section to main section for c/make --- src/CMakeLists.txt | 6 +++--- src/Makefile.am | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d3f9b87a..d34e85e0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -133,9 +133,6 @@ add_library(libavrdude confwin.c crc16.c crc16.h - developer_opts.c - developer_opts.h - developer_opts_private.h dfu.c dfu.h fileio.c @@ -253,6 +250,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 f2747c1b..9e0929e1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -110,9 +110,6 @@ libavrdude_a_SOURCES = \ confwin.c \ crc16.c \ crc16.h \ - developer_opts.c \ - developer_opts.h \ - developer_opts_private.h \ dfu.c \ dfu.h \ fileio.c \ @@ -201,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