From 952ad72fb9f962e450764d506044987aafa1d855 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 24 May 2022 16:56:11 +0100 Subject: [PATCH 01/47] 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/47] 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 17509d2ef4ade40b84a969b810b92b77663cf101 Mon Sep 17 00:00:00 2001 From: Fabrice Fontaine Date: Sun, 26 Jun 2022 21:31:44 +0200 Subject: [PATCH 03/47] CMakeLists.txt: fix build without C++ Fix the following build failure without a C++ compiler: CMake Error at CMakeLists.txt:24 (project): No CMAKE_CXX_COMPILER could be found. Tell CMake where to find the compiler by setting either the environment variable "CXX" or the CMake cache entry CMAKE_CXX_COMPILER to the full path to the compiler, or to the compiler name if it is in the PATH. Signed-off-by: Fabrice Fontaine --- CMakeLists.txt | 2 +- src/CMakeLists.txt | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 19897c72..5efc8d45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,7 @@ # cmake --build build cmake_minimum_required(VERSION 3.12) -project(avrdude VERSION 7.0) +project(avrdude VERSION 7.0 LANGUAGES C) set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED True) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bd3c6dee..f2dfe9cc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -56,6 +56,8 @@ if(WIN32) endif() if(MSVC) + enable_language(CXX) + add_compile_definitions(_CRT_SECURE_NO_WARNINGS=1) add_compile_definitions(_CRT_NONSTDC_NO_WARNINGS=1) add_compile_definitions(_WINSOCK_DEPRECATED_NO_WARNINGS=1) From 3bd75e74c6c65bd3b0c7fdb170f39b380dec1286 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 28 Jun 2022 20:14:29 +0100 Subject: [PATCH 04/47] 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 05/47] 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 79921e52dc76f0adc6edb07f873a74aa5fb1123c Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Sat, 16 Jul 2022 23:40:36 +0100 Subject: [PATCH 06/47] Provide file format I: Intel HEX with comments that ignores checksum errors The new file type I is essentially Intel HEX that, on download, inserts comments next to data records with the resolved effective address and an ASCII dump of that same record. On upload the `I` format is permissive with respect to check sum errors, eg, after manipulated an Intel HEX file for debugging. --- src/avrdude.1 | 2 ++ src/doc/avrdude.texi | 3 +++ src/fileio.c | 60 +++++++++++++++++++++++++++++++------------- src/libavrdude.h | 3 ++- src/update.c | 1 + 5 files changed, 50 insertions(+), 19 deletions(-) diff --git a/src/avrdude.1 b/src/avrdude.1 index c4fc850f..be22e0c1 100644 --- a/src/avrdude.1 +++ b/src/avrdude.1 @@ -709,6 +709,8 @@ can be one of: .Bl -tag -width sss .It Ar i Intel Hex +.It Ar I +Intel Hex with comments on download and tolerance of checksum errors on upload .It Ar s Motorola S-record .It Ar r diff --git a/src/doc/avrdude.texi b/src/doc/avrdude.texi index d99b0a85..42cdc88a 100644 --- a/src/doc/avrdude.texi +++ b/src/doc/avrdude.texi @@ -768,6 +768,9 @@ the file to read or write. Possible values are: @item i Intel Hex +@item I +Intel Hex with comments on download and tolerance of checksum errors on upload + @item s Motorola S-record diff --git a/src/fileio.c b/src/fileio.c index 1c81682d..f1df1158 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -59,10 +59,11 @@ struct ihexrec { static int b2ihex(unsigned char * inbuf, int bufsize, int recsize, int startaddr, - char * outfile, FILE * outf); + char * outfile, FILE * outf, FILEFMT ffmt); static int ihex2b(char * infile, FILE * inf, - AVRMEM * mem, int bufsize, unsigned int fileoffset); + AVRMEM * mem, int bufsize, unsigned int fileoffset, + FILEFMT ffmt); static int b2srec(unsigned char * inbuf, int bufsize, int recsize, int startaddr, @@ -79,7 +80,8 @@ static int fileio_rbin(struct fioparms * fio, char * filename, FILE * f, AVRMEM * mem, int size); static int fileio_ihex(struct fioparms * fio, - char * filename, FILE * f, AVRMEM * mem, int size); + char * filename, FILE * f, AVRMEM * mem, int size, + FILEFMT ffmt); static int fileio_srec(struct fioparms * fio, char * filename, FILE * f, AVRMEM * mem, int size); @@ -108,6 +110,7 @@ char * fmtstr(FILEFMT format) case FMT_AUTO : return "auto-detect"; break; case FMT_SREC : return "Motorola S-Record"; break; case FMT_IHEX : return "Intel Hex"; break; + case FMT_IHXC : return "Intel Hex with comments"; break; case FMT_RBIN : return "raw binary"; break; case FMT_ELF : return "ELF"; break; default : return "invalid format"; break; @@ -115,10 +118,9 @@ char * fmtstr(FILEFMT format) } - static int b2ihex(unsigned char * inbuf, int bufsize, int recsize, int startaddr, - char * outfile, FILE * outf) + char * outfile, FILE * outf, FILEFMT ffmt) { unsigned char * buf; unsigned int nextaddr; @@ -154,8 +156,20 @@ static int b2ihex(unsigned char * inbuf, int bufsize, cksum += buf[i]; } cksum = -cksum; - fprintf(outf, "%02X\n", cksum); - + fprintf(outf, "%02X", cksum); + + if(ffmt == FMT_IHXC) { /* Print comment with address and ASCII dump */ + for(i=n; i ", n_64k*0x10000 + nextaddr); + for (i=0; iop) { case FIO_WRITE: - rc = b2ihex(mem->buf, size, 32, fio->fileoffset, filename, f); + rc = b2ihex(mem->buf, size, 32, fio->fileoffset, filename, f, ffmt); if (rc < 0) { return -1; } break; case FIO_READ: - rc = ihex2b(filename, f, mem, size, fio->fileoffset); + rc = ihex2b(filename, f, mem, size, fio->fileoffset, ffmt); if (rc < 0) return -1; break; @@ -1547,7 +1570,8 @@ int fileio(int oprwv, char * filename, FILEFMT format, switch (format) { case FMT_IHEX: - rc = fileio_ihex(&fio, fname, f, mem, size); + case FMT_IHXC: + rc = fileio_ihex(&fio, fname, f, mem, size, format); break; case FMT_SREC: diff --git a/src/libavrdude.h b/src/libavrdude.h index 7088b108..6ef8da14 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -822,7 +822,8 @@ typedef enum { FMT_DEC, FMT_OCT, FMT_BIN, - FMT_ELF + FMT_ELF, + FMT_IHXC, } FILEFMT; struct fioparms { diff --git a/src/update.c b/src/update.c index d3c208fc..1840f81f 100644 --- a/src/update.c +++ b/src/update.c @@ -130,6 +130,7 @@ UPDATE * parse_op(char * s) case 'a': upd->format = FMT_AUTO; break; case 's': upd->format = FMT_SREC; break; case 'i': upd->format = FMT_IHEX; break; + case 'I': upd->format = FMT_IHXC; break; case 'r': upd->format = FMT_RBIN; break; case 'e': upd->format = FMT_ELF; break; case 'm': upd->format = FMT_IMM; break; From 5904611928565c135887f851dd7a101358e79fd9 Mon Sep 17 00:00:00 2001 From: MCUdude Date: Sun, 17 Jul 2022 12:51:43 +0200 Subject: [PATCH 07/47] Apply jtagmki patch provided in #443 --- src/jtagmkI.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/jtagmkI.c b/src/jtagmkI.c index 7a97217b..43141263 100644 --- a/src/jtagmkI.c +++ b/src/jtagmkI.c @@ -1058,7 +1058,7 @@ static int jtagmkI_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, { unsigned char cmd[6], datacmd[1 * 2 + 1]; unsigned char resp[1], writedata; - int len, need_progmode = 1; + int len, need_progmode = 1, need_dummy_read = 0; avrdude_message(MSG_NOTICE2, "%s: jtagmkI_write_byte(.., %s, 0x%lx, ...)\n", progname, mem->desc, addr); @@ -1075,17 +1075,22 @@ static int jtagmkI_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L; } else if (strcmp(mem->desc, "lfuse") == 0) { cmd[1] = MTYPE_FUSE_BITS; + need_dummy_read = 1; addr = 0; } else if (strcmp(mem->desc, "hfuse") == 0) { cmd[1] = MTYPE_FUSE_BITS; + need_dummy_read = 1; addr = 1; } else if (strcmp(mem->desc, "efuse") == 0) { cmd[1] = MTYPE_FUSE_BITS; + need_dummy_read = 1; addr = 2; } else if (strcmp(mem->desc, "lock") == 0) { cmd[1] = MTYPE_LOCK_BITS; + need_dummy_read = 1; } else if (strcmp(mem->desc, "calibration") == 0) { cmd[1] = MTYPE_OSCCAL_BYTE; + need_dummy_read = 1; } else if (strcmp(mem->desc, "signature") == 0) { cmd[1] = MTYPE_SIGN_JTAG; } @@ -1154,6 +1159,8 @@ static int jtagmkI_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, avrdude_message(MSG_NOTICE2, "OK\n"); } + if(need_dummy_read) + jtagmkI_recv(pgm, resp, 1); return 0; } From ec467c465e8dc41505573cc5b814623ca59362e2 Mon Sep 17 00:00:00 2001 From: MCUdude Date: Mon, 18 Jul 2022 17:13:10 +0200 Subject: [PATCH 08/47] Ignore -s flag as safemode is no longer supported Resolves #1032 --- src/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.c b/src/main.c index 1d00ae67..3ed3fc78 100644 --- a/src/main.c +++ b/src/main.c @@ -576,6 +576,7 @@ int main(int argc, char * argv []) terminal = 1; break; + case 's': case 'u': avrdude_message(MSG_INFO, "%s: \"safemode\" feature no longer supported\n", progname); From 8989e6515b102f6984620b1b6cec675d7fe4c1b3 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 19 Jul 2022 14:38:34 +0100 Subject: [PATCH 09/47] 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 10/47] 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 11/47] 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 12/47] 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 13/47] 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 14/47] 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 15/47] 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 16/47] 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 bfdad78fcba338d0d8815cd98672ab2bb4558662 Mon Sep 17 00:00:00 2001 From: MCUdude Date: Tue, 19 Jul 2022 23:44:22 +0200 Subject: [PATCH 17/47] Add EEPROM dummy read --- src/jtagmkI.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/jtagmkI.c b/src/jtagmkI.c index 43141263..e5d3d5d8 100644 --- a/src/jtagmkI.c +++ b/src/jtagmkI.c @@ -1072,6 +1072,7 @@ static int jtagmkI_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, } else if (strcmp(mem->desc, "eeprom") == 0) { cmd[1] = MTYPE_EEPROM; need_progmode = 0; + need_dummy_read = 1; PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L; } else if (strcmp(mem->desc, "lfuse") == 0) { cmd[1] = MTYPE_FUSE_BITS; From 30041e3f5f4ce5f10e3679f61d30d6e01219acc5 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 19 Jul 2022 22:59:46 +0100 Subject: [PATCH 18/47] 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 19/47] 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 20/47] 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 21/47] 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 22/47] 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 23/47] 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 24/47] 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 25/47] 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 26/47] 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 27/47] 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 248c17177c48a1695748fc24ef85a92dca097d81 Mon Sep 17 00:00:00 2001 From: MCUdude Date: Sat, 23 Jul 2022 22:33:11 +0200 Subject: [PATCH 28/47] Mention -s and -u in the docs --- src/avrdude.1 | 5 +++-- src/doc/avrdude.texi | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/avrdude.1 b/src/avrdude.1 index c4fc850f..efeaa2fe 100644 --- a/src/avrdude.1 +++ b/src/avrdude.1 @@ -44,9 +44,7 @@ .Op Fl O .Op Fl P Ar port .Op Fl q -.Op Fl s .Op Fl t -.Op Fl u .Op Fl U Ar memtype:op:filename:filefmt .Op Fl v .Op Fl x Ar extended_param @@ -626,6 +624,9 @@ Posix systems (by now). .It Fl q Disable (or quell) output of the progress bar while reading or writing to the device. Specify it a second time for even quieter operation. +.It Fl s, u +These options used to control the obsolete "safemode" feature which +is no longer present. They are silently ignored for backwards compatibility. .It Fl t Tells .Nm diff --git a/src/doc/avrdude.texi b/src/doc/avrdude.texi index d99b0a85..ae04dac6 100644 --- a/src/doc/avrdude.texi +++ b/src/doc/avrdude.texi @@ -693,6 +693,10 @@ Posix systems (by now). Disable (or quell) output of the progress bar while reading or writing to the device. Specify it a second time for even quieter operation. +@item -s, -u +These options used to control the obsolete "safemode" feature which +is no longer present. They are silently ignored for backwards compatibility. + @item -t Tells AVRDUDE to enter the interactive ``terminal'' mode instead of up- or downloading files. See below for a detailed description of the From 4babe183dae107fc249d4f853faa61b0653d8baa Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Sun, 24 Jul 2022 18:20:35 +0100 Subject: [PATCH 29/47] Initialise memory before avr_set_bits() calls in stk500.c and stk500v2.c --- src/stk500.c | 5 ++--- src/stk500v2.c | 11 +++++++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/stk500.c b/src/stk500.c index cb270036..fa013012 100644 --- a/src/stk500.c +++ b/src/stk500.c @@ -212,7 +212,6 @@ static int stk500_chip_erase(PROGRAMMER * pgm, AVRPART * p) pgm->pgm_led(pgm, ON); memset(cmd, 0, sizeof(cmd)); - avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd); pgm->cmd(pgm, cmd, res); usleep(p->chip_erase_delay); @@ -745,8 +744,8 @@ static int stk500_loadaddr(PROGRAMMER * pgm, AVRMEM * mem, unsigned int addr) if (lext != NULL) { ext_byte = (addr >> 16) & 0xff; if (ext_byte != PDATA(pgm)->ext_addr_byte) { - /* Either this is the first addr load, or a 64K word boundary is - * crossed, so set the ext addr byte */ + /* Either this is the first addr load, or a different 64K word section */ + memset(buf, 0, 4); avr_set_bits(lext, buf); avr_set_addr(lext, buf, addr); stk500_cmd(pgm, buf, buf); diff --git a/src/stk500v2.c b/src/stk500v2.c index 523d6539..b0ccaad2 100644 --- a/src/stk500v2.c +++ b/src/stk500v2.c @@ -991,6 +991,7 @@ static int stk500v2_chip_erase(PROGRAMMER * pgm, AVRPART * p) buf[0] = CMD_CHIP_ERASE_ISP; buf[1] = p->chip_erase_delay / 1000; buf[2] = 0; // use delay (?) + memset(buf+3, 0, 4); avr_set_bits(p->op[AVR_OP_CHIP_ERASE], buf+3); result = stk500v2_command(pgm, buf, 7, sizeof(buf)); usleep(p->chip_erase_delay); @@ -1121,8 +1122,8 @@ retry: buf[5] = p->bytedelay; buf[6] = p->pollvalue; buf[7] = p->pollindex; + memset(buf+8, 0, 4); avr_set_bits(p->op[AVR_OP_PGM_ENABLE], buf+8); - buf[10] = buf[11] = 0; rv = stk500v2_command(pgm, buf, 12, sizeof(buf)); @@ -1957,12 +1958,12 @@ static int stk500isp_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, buf[0] = CMD_READ_SIGNATURE_ISP; } - memset(buf + 1, 0, 5); if ((op = mem->op[AVR_OP_READ]) == NULL) { avrdude_message(MSG_INFO, "%s: stk500isp_read_byte(): invalid operation AVR_OP_READ on %s memory\n", progname, mem->desc); return -1; } + memset(buf+2, 0, 4); avr_set_bits(op, buf + 2); if ((pollidx = avr_get_output_index(op)) == -1) { avrdude_message(MSG_INFO, "%s: stk500isp_read_byte(): cannot determine pollidx to read %s memory\n", @@ -2314,6 +2315,7 @@ static int stk500v2_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, progname, p->desc); return -1; } + memset(cmds, 0, sizeof cmds); avr_set_bits(m->op[AVR_OP_LOADPAGE_LO], cmds); commandbuf[5] = cmds[0]; @@ -2322,6 +2324,8 @@ static int stk500v2_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, progname, p->desc); return -1; } + + memset(cmds, 0, sizeof cmds); avr_set_bits(m->op[AVR_OP_WRITEPAGE], cmds); commandbuf[6] = cmds[0]; @@ -2335,6 +2339,7 @@ static int stk500v2_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, progname, p->desc); return -1; } + memset(cmds, 0, sizeof cmds); avr_set_bits(wop, cmds); commandbuf[5] = cmds[0]; commandbuf[6] = 0; @@ -2346,6 +2351,7 @@ static int stk500v2_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, progname, p->desc); return -1; } + memset(cmds, 0, sizeof cmds); avr_set_bits(rop, cmds); commandbuf[7] = cmds[0]; @@ -2549,6 +2555,7 @@ static int stk500v2_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, progname, p->desc); return -1; } + memset(cmds, 0, sizeof cmds); avr_set_bits(rop, cmds); commandbuf[3] = cmds[0]; From 7310df030f19d8e11586fc53f02f667031b78c54 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Sun, 24 Jul 2022 18:48:22 +0100 Subject: [PATCH 30/47] Check stk500_recv() actually worked before accepting SYNC byte --- src/stk500.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/stk500.c b/src/stk500.c index fa013012..208fb1a3 100644 --- a/src/stk500.c +++ b/src/stk500.c @@ -91,8 +91,6 @@ int stk500_getsync(PROGRAMMER * pgm) int attempt; int max_sync_attempts; - /* - * get in sync */ buf[0] = Cmnd_STK_GET_SYNC; buf[1] = Sync_CRC_EOP; @@ -119,11 +117,11 @@ int stk500_getsync(PROGRAMMER * pgm) usleep(50*1000); stk500_drain(pgm, 0); } + stk500_send(pgm, buf, 2); - stk500_recv(pgm, resp, 1); - if (resp[0] == Resp_STK_INSYNC){ + if(stk500_recv(pgm, resp, 1) >= 0 && resp[0] == Resp_STK_INSYNC) break; - } + avrdude_message(MSG_INFO, "%s: stk500_getsync() attempt %d of %d: not in sync: resp=0x%02x\n", progname, attempt + 1, max_sync_attempts, resp[0]); } From 535004ee3da1d73858e71fb48ac8867964425264 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Sun, 24 Jul 2022 19:27:07 +0100 Subject: [PATCH 31/47] Consolidate error messages for stk500.c --- src/stk500.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/stk500.c b/src/stk500.c index 208fb1a3..b3ed3980 100644 --- a/src/stk500.c +++ b/src/stk500.c @@ -119,6 +119,7 @@ int stk500_getsync(PROGRAMMER * pgm) } stk500_send(pgm, buf, 2); + resp[0] = 0; if(stk500_recv(pgm, resp, 1) >= 0 && resp[0] == Resp_STK_INSYNC) break; @@ -202,8 +203,8 @@ static int stk500_chip_erase(PROGRAMMER * pgm, AVRPART * p) } if (p->op[AVR_OP_CHIP_ERASE] == NULL) { - avrdude_message(MSG_INFO, "chip erase instruction not defined for part \"%s\"\n", - p->desc); + avrdude_message(MSG_INFO, "%s: chip erase instruction not defined for part \"%s\"\n", + progname, p->desc); return -1; } @@ -779,13 +780,12 @@ static int stk500_loadaddr(PROGRAMMER * pgm, AVRMEM * mem, unsigned int addr) if (stk500_recv(pgm, buf, 1) < 0) return -1; - if (buf[0] == Resp_STK_OK) { + if (buf[0] == Resp_STK_OK) return 0; - } - avrdude_message(MSG_INFO, "%s: loadaddr(): (b) protocol error, " + avrdude_message(MSG_INFO, "%s: stk500_loadaddr(): (b) protocol error, " "expect=0x%02x, resp=0x%02x\n", - progname, Resp_STK_INSYNC, buf[0]); + progname, Resp_STK_OK, buf[0]); return -1; } @@ -876,9 +876,9 @@ static int stk500_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, if (stk500_recv(pgm, buf, 1) < 0) return -1; if (buf[0] != Resp_STK_OK) { - avrdude_message(MSG_INFO, "\n%s: stk500_paged_write(): (a) protocol error, " + avrdude_message(MSG_INFO, "\n%s: stk500_paged_write(): (b) protocol error, " "expect=0x%02x, resp=0x%02x\n", - progname, Resp_STK_INSYNC, buf[0]); + progname, Resp_STK_OK, buf[0]); return -5; } } @@ -970,7 +970,7 @@ static int stk500_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, } else { if (buf[0] != Resp_STK_OK) { - avrdude_message(MSG_INFO, "\n%s: stk500_paged_load(): (a) protocol error, " + avrdude_message(MSG_INFO, "\n%s: stk500_paged_load(): (b) protocol error, " "expect=0x%02x, resp=0x%02x\n", progname, Resp_STK_OK, buf[0]); return -5; @@ -1152,7 +1152,7 @@ static int stk500_getparm(PROGRAMMER * pgm, unsigned parm, unsigned * value) return -3; } else if (buf[0] != Resp_STK_OK) { - avrdude_message(MSG_INFO, "\n%s: stk500_getparm(): (a) protocol error, " + avrdude_message(MSG_INFO, "\n%s: stk500_getparm(): (b) protocol error, " "expect=0x%02x, resp=0x%02x\n", progname, Resp_STK_OK, buf[0]); return -3; @@ -1211,9 +1211,9 @@ static int stk500_setparm(PROGRAMMER * pgm, unsigned parm, unsigned value) return -3; } else { - avrdude_message(MSG_INFO, "\n%s: stk500_setparm(): (a) protocol error, " + avrdude_message(MSG_INFO, "\n%s: stk500_setparm(): (b) protocol error, " "expect=0x%02x, resp=0x%02x\n", - progname, Resp_STK_INSYNC, buf[0]); + progname, Resp_STK_OK, buf[0]); return -3; } } From 29c6645abc92441f204f04e6a220e628fed9aab6 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Sun, 24 Jul 2022 19:41:42 +0100 Subject: [PATCH 32/47] Resolve signed/unsigned comparisons in stk500.c and stk500v2.c --- src/stk500.c | 3 ++- src/stk500v2.c | 33 ++++++++++++++++----------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/stk500.c b/src/stk500.c index b3ed3980..084bbec8 100644 --- a/src/stk500.c +++ b/src/stk500.c @@ -1034,7 +1034,8 @@ static int stk500_set_fosc(PROGRAMMER * pgm, double v) static unsigned ps[] = { 1, 8, 32, 64, 128, 256, 1024 }; - int idx, rc; + size_t idx; + int rc; prescale = cmatch = 0; if (v > 0.0) { diff --git a/src/stk500v2.c b/src/stk500v2.c index b0ccaad2..a50fda4c 100644 --- a/src/stk500v2.c +++ b/src/stk500v2.c @@ -392,9 +392,7 @@ static int stk500v2_send_mk2(PROGRAMMER * pgm, unsigned char * data, size_t len) static unsigned short get_jtagisp_return_size(unsigned char cmd) { - int i; - - for (i = 0; i < sizeof jtagispcmds / sizeof jtagispcmds[0]; i++) + for (size_t i = 0; i < sizeof jtagispcmds / sizeof jtagispcmds[0]; i++) if (jtagispcmds[i].cmd == cmd) return jtagispcmds[i].size; @@ -481,7 +479,6 @@ static int stk500v2_jtag3_send(PROGRAMMER * pgm, unsigned char * data, size_t le static int stk500v2_send(PROGRAMMER * pgm, unsigned char * data, size_t len) { unsigned char buf[275 + 6]; // max MESSAGE_BODY of 275 bytes, 6 bytes overhead - int i; if (PDATA(pgm)->pgmtype == PGMTYPE_AVRISP_MKII || PDATA(pgm)->pgmtype == PGMTYPE_STK600) @@ -500,12 +497,13 @@ static int stk500v2_send(PROGRAMMER * pgm, unsigned char * data, size_t len) // calculate the XOR checksum buf[5+len] = 0; - for (i=0;i<5+len;i++) + for (size_t i=0; i<5+len; i++) buf[5+len] ^= buf[i]; DEBUG("STK500V2: stk500v2_send("); - for (i=0;ifd, buf, len+6) != 0) { avrdude_message(MSG_INFO, "%s: stk500_send(): failed to send command to serial port\n",progname); @@ -551,9 +549,9 @@ static int stk500v2_jtagmkII_recv(PROGRAMMER * pgm, unsigned char *msg, progname); return -1; } - if (rv - 1 > maxsize) { + if ((size_t) rv - 1 > maxsize) { avrdude_message(MSG_INFO, "%s: stk500v2_jtagmkII_recv(): got %u bytes, have only room for %u bytes\n", - progname, (unsigned)rv - 1, (unsigned)maxsize); + progname, (unsigned) rv - 1, (unsigned) maxsize); rv = maxsize; } switch (jtagmsg[0]) { @@ -597,9 +595,9 @@ static int stk500v2_jtag3_recv(PROGRAMMER * pgm, unsigned char *msg, implementation of JTAGICE3, as they always request a full 512 octets from the ICE. Thus, only complain at high verbose levels. */ - if (rv - 1 > maxsize) { + if ((size_t) rv - 1 > maxsize) { avrdude_message(MSG_DEBUG, "%s: stk500v2_jtag3_recv(): got %u bytes, have only room for %u bytes\n", - progname, (unsigned)rv - 1, (unsigned)maxsize); + progname, (unsigned) rv - 1, (unsigned) maxsize); rv = maxsize; } if (jtagmsg[0] != SCOPE_AVR_ISP) { @@ -814,13 +812,13 @@ retry: static int stk500v2_command(PROGRAMMER * pgm, unsigned char * buf, size_t len, size_t maxlen) { - int i; int tries = 0; int status; DEBUG("STK500V2: stk500v2_command("); - for (i=0;i 0.0) { @@ -2781,7 +2780,7 @@ static int stk500v2_set_fosc(PROGRAMMER * pgm, double v) fosc = (unsigned)v; for (idx = 0; idx < sizeof(ps) / sizeof(ps[0]); idx++) { - if (fosc >= STK500V2_XTAL / (256 * ps[idx] * 2)) { + if ((unsigned) fosc >= STK500V2_XTAL / (256 * ps[idx] * 2)) { /* this prescaler value can handle our frequency */ prescale = idx + 1; cmatch = (unsigned)(STK500V2_XTAL / (2 * fosc * ps[idx])) - 1; @@ -2828,7 +2827,7 @@ static double avrispmkIIfreqs[] = { static int stk500v2_set_sck_period_mk2(PROGRAMMER * pgm, double v) { - int i; + size_t i; for (i = 0; i < sizeof(avrispmkIIfreqs) / sizeof(avrispmkIIfreqs[0]); i++) { if (1 / avrispmkIIfreqs[i] >= v) From 3d06457a1614a2247efc846b8e73788cb8585978 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Sun, 24 Jul 2022 20:18:15 +0100 Subject: [PATCH 33/47] Deprecate original STK500 v1 protocol in favour of optiboot and Arduino as ISP For paged read/write early AVRDUDE implementations of the STK500 v1 protocol communicated a word address (below a_div=2) or byte address (a_div=1) based on the following code irrespective of which memories were used: if(m->op[AVR_OP_LOADPAGE_LO] || m->op[AVR_OP_READ_LO]) a_div = 2; else a_div = 1; This turned out to be a bug: it really should have been a_div=2 for flash and a_div=1 for eeprom. At the time presumably no one noted because Atmel was at the cusp of replacing their FW 1.x with FW 2 (and the STK500 v2 protocol). It seems that the world (optiboot, Arduino as ISP, ...) has compensated for the bug by assuming AVRDUDE sends *all* eeprom addresses as word addresses. Actually these programmers overcompensated for the bug because for six out of the 146 known SPI programmable parts with eeprom and page size > 1, AVRDUDE would still send the eeprom addresses as byte addresses (ATmega8 ATmega8A ATmega64 ATmega64A ATmega128 ATmega128A) owing to above code. It makes no sense to correct the bug now seeing that virtually no one uses the old 2005 STK 500 v1 firmware. This commit now follows optiboot, Arduino as ISP and other projects, and simply sends all addresses for paged read or write as word addresses. There are no longer (little known) exceptions for ATmega8 et al that surprised some optiboot etc users. --- src/stk500.c | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/stk500.c b/src/stk500.c index 084bbec8..27334297 100644 --- a/src/stk500.c +++ b/src/stk500.c @@ -805,19 +805,20 @@ static int stk500_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, if (strcmp(m->desc, "flash") == 0) { memtype = 'F'; - } - else if (strcmp(m->desc, "eeprom") == 0) { + a_div = 2; + } else if (strcmp(m->desc, "eeprom") == 0) { memtype = 'E'; - } - else { + /* + * The STK original 500 v1 protocol actually expects a_div = 1, but the + * v1.x FW of the STK500 kit has been superseded by v2 FW in the mid + * 2000s. Since optiboot, arduino as ISP and others assume a_div = 2, + * better use that. See https://github.com/avrdudes/avrdude/issues/967 + */ + a_div = 2; + } else { return -2; } - if ((m->op[AVR_OP_LOADPAGE_LO]) || (m->op[AVR_OP_READ_LO])) - a_div = 2; - else - a_div = 1; - n = addr + n_bytes; #if 0 avrdude_message(MSG_INFO, "n_bytes = %d\n" @@ -825,7 +826,7 @@ static int stk500_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, "a_div = %d\n" "page_size = %d\n", n_bytes, n, a_div, page_size); -#endif +#endif for (; addr < n; addr += block_size) { // MIB510 uses fixed blocks size of 256 bytes @@ -872,7 +873,7 @@ static int stk500_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, progname, Resp_STK_INSYNC, buf[0]); return -4; } - + if (stk500_recv(pgm, buf, 1) < 0) return -1; if (buf[0] != Resp_STK_OK) { @@ -899,19 +900,20 @@ static int stk500_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, if (strcmp(m->desc, "flash") == 0) { memtype = 'F'; - } - else if (strcmp(m->desc, "eeprom") == 0) { + a_div = 2; + } else if (strcmp(m->desc, "eeprom") == 0) { memtype = 'E'; - } - else { + /* + * The STK original 500 v1 protocol actually expects a_div = 1, but the + * v1.x FW of the STK500 kit has been superseded by v2 FW in the mid + * 2000s. Since optiboot, arduino as ISP and others assume a_div = 2, + * better use that. See https://github.com/avrdudes/avrdude/issues/967 + */ + a_div = 2; + } else { return -2; } - if ((m->op[AVR_OP_LOADPAGE_LO]) || (m->op[AVR_OP_READ_LO])) - a_div = 2; - else - a_div = 1; - n = addr + n_bytes; for (; addr < n; addr += block_size) { // MIB510 uses fixed blocks size of 256 bytes From d5d3a0e09eb68e9889c85e0ea317a07e49f29727 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Sun, 24 Jul 2022 23:38:51 +0100 Subject: [PATCH 34/47] 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 35/47] 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 104dcf60527422ab3323fb77780376e872e03bee Mon Sep 17 00:00:00 2001 From: MCUdude Date: Tue, 26 Jul 2022 11:30:53 +0200 Subject: [PATCH 36/47] Add new jtagmkii_updi programmer type option in order to resolve issue #1037 --- src/avrdude.conf.in | 2 +- src/jtagmkII.c | 37 +++++++++++++++++++++++++++++++++++-- src/jtagmkII.h | 2 ++ src/pgm_type.c | 1 + 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in index 1728497f..92c578e8 100644 --- a/src/avrdude.conf.in +++ b/src/avrdude.conf.in @@ -1734,7 +1734,7 @@ programmer programmer id = "jtag2updi"; desc = "JTAGv2 to UPDI bridge"; - type = "jtagmkii_pdi"; + type = "jtagmkii_updi"; connection_type = serial; baudrate = 115200; ; diff --git a/src/jtagmkII.c b/src/jtagmkII.c index b1024b53..675c9540 100644 --- a/src/jtagmkII.c +++ b/src/jtagmkII.c @@ -1306,9 +1306,9 @@ static int jtagmkII_initialize(PROGRAMMER * pgm, AVRPART * p) const char *ifname; /* Abort and print error if programmer does not support the target microcontroller */ - if ((strncmp(ldata(lfirst(pgm->id)), "jtag2updi", strlen("jtag2updi")) == 0 && p->flags & AVRPART_HAS_PDI) || + if ((strncmp(pgm->type, "JTAGMKII_UPDI", strlen("JTAGMKII_UPDI")) == 0 && p->flags & AVRPART_HAS_PDI) || (strncmp(ldata(lfirst(pgm->id)), "jtagmkII", strlen("jtagmkII")) == 0 && p->flags & AVRPART_HAS_UPDI)) { - avrdude_message(MSG_INFO, "Error: programmer %s does not support target %s\n\n", + avrdude_message(MSG_INFO, "ERROR: programmer %s does not support target %s\n\n", ldata(lfirst(pgm->id)), p->desc); return -1; } @@ -3929,6 +3929,39 @@ void jtagmkII_pdi_initpgm(PROGRAMMER * pgm) pgm->flag = PGM_FL_IS_PDI; } +const char jtagmkII_updi_desc[] = "Atmel JTAG ICE mkII in UPDI mode"; + +void jtagmkII_updi_initpgm(PROGRAMMER * pgm) +{ + strcpy(pgm->type, "JTAGMKII_UPDI"); + + /* + * mandatory functions + */ + pgm->initialize = jtagmkII_initialize; + pgm->display = jtagmkII_display; + pgm->enable = jtagmkII_enable; + pgm->disable = jtagmkII_disable; + pgm->program_enable = jtagmkII_program_enable_INFO; + pgm->chip_erase = jtagmkII_chip_erase; + pgm->open = jtagmkII_open_pdi; + pgm->close = jtagmkII_close; + pgm->read_byte = jtagmkII_read_byte; + pgm->write_byte = jtagmkII_write_byte; + + /* + * optional functions + */ + pgm->paged_write = jtagmkII_paged_write; + pgm->paged_load = jtagmkII_paged_load; + pgm->page_erase = jtagmkII_page_erase; + pgm->print_parms = jtagmkII_print_parms; + pgm->setup = jtagmkII_setup; + pgm->teardown = jtagmkII_teardown; + pgm->page_size = 256; + pgm->flag = PGM_FL_IS_PDI; +} + const char jtagmkII_dragon_desc[] = "Atmel AVR Dragon in JTAG mode"; void jtagmkII_dragon_initpgm(PROGRAMMER * pgm) diff --git a/src/jtagmkII.h b/src/jtagmkII.h index aa79c18d..34004d6d 100644 --- a/src/jtagmkII.h +++ b/src/jtagmkII.h @@ -36,6 +36,7 @@ extern const char jtagmkII_desc[]; extern const char jtagmkII_avr32_desc[]; extern const char jtagmkII_dw_desc[]; extern const char jtagmkII_pdi_desc[]; +extern const char jtagmkII_updi_desc[]; extern const char jtagmkII_dragon_desc[]; extern const char jtagmkII_dragon_dw_desc[]; extern const char jtagmkII_dragon_pdi_desc[]; @@ -43,6 +44,7 @@ void jtagmkII_initpgm (PROGRAMMER * pgm); void jtagmkII_avr32_initpgm (PROGRAMMER * pgm); void jtagmkII_dw_initpgm (PROGRAMMER * pgm); void jtagmkII_pdi_initpgm (PROGRAMMER * pgm); +void jtagmkII_updi_initpgm (PROGRAMMER * pgm); void jtagmkII_dragon_initpgm (PROGRAMMER * pgm); void jtagmkII_dragon_dw_initpgm (PROGRAMMER * pgm); void jtagmkII_dragon_pdi_initpgm (PROGRAMMER * pgm); diff --git a/src/pgm_type.c b/src/pgm_type.c index 8afb50bd..82320fab 100644 --- a/src/pgm_type.c +++ b/src/pgm_type.c @@ -80,6 +80,7 @@ const PROGRAMMER_TYPE programmers_types[] = { {"jtagmkii_dw", jtagmkII_dw_initpgm, jtagmkII_dw_desc}, {"jtagmkii_isp", stk500v2_jtagmkII_initpgm, stk500v2_jtagmkII_desc}, {"jtagmkii_pdi", jtagmkII_pdi_initpgm, jtagmkII_pdi_desc}, + {"jtagmkii_updi", jtagmkII_updi_initpgm, jtagmkII_updi_desc}, {"jtagice3", jtag3_initpgm, jtag3_desc}, {"jtagice3_pdi", jtag3_pdi_initpgm, jtag3_pdi_desc}, {"jtagice3_updi", jtag3_updi_initpgm, jtag3_updi_desc}, From 78754b8ccc619b5cb42c7140aa97c7da7e70e2c4 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 26 Jul 2022 23:43:56 +0100 Subject: [PATCH 37/47] 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 38/47] 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 39/47] 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 40/47] 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 From de124bfd9b3b4a002b71bf73574d412c0c9bb573 Mon Sep 17 00:00:00 2001 From: MCUdude Date: Fri, 29 Jul 2022 12:48:53 +0200 Subject: [PATCH 41/47] Improve error detection logic --- src/jtagmkII.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jtagmkII.c b/src/jtagmkII.c index 675c9540..7181d186 100644 --- a/src/jtagmkII.c +++ b/src/jtagmkII.c @@ -1306,7 +1306,7 @@ static int jtagmkII_initialize(PROGRAMMER * pgm, AVRPART * p) const char *ifname; /* Abort and print error if programmer does not support the target microcontroller */ - if ((strncmp(pgm->type, "JTAGMKII_UPDI", strlen("JTAGMKII_UPDI")) == 0 && p->flags & AVRPART_HAS_PDI) || + if ((strncmp(pgm->type, "JTAGMKII_UPDI", strlen("JTAGMKII_UPDI")) == 0 && !(p->flags & AVRPART_HAS_UPDI)) || (strncmp(ldata(lfirst(pgm->id)), "jtagmkII", strlen("jtagmkII")) == 0 && p->flags & AVRPART_HAS_UPDI)) { avrdude_message(MSG_INFO, "ERROR: programmer %s does not support target %s\n\n", ldata(lfirst(pgm->id)), p->desc); From 02027ab766e0654d1c5c73dc09e5cddcd4fd1525 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 2 Aug 2022 23:26:01 +0100 Subject: [PATCH 42/47] Enable stdin verification and display correct number of bytes written/verified Counting the number of bytes written to a memory and/or verified is not trivial owing to potential holes in the input file and to potential trailing 0xff bytes in flash memory that are not written per default (but see -A). The new function memstats(), which is best called just after an input file has been read into mem->buf/mem->tags, computes the right number of bytes written and allows easy computation of the number of bytes verified. This commit also changes the strategy for the default verification after writing to a chip memory, so that the input file only needs reading once thus enabling successful verification of stdin input files. Other, minor changes: - Improving the grammar of AVRDUDE output, eg, 1 byte written instead of 1 bytes written - Better description of the input file structure in terms of its sections, the interval it spans, the number of pages, the number of padding bytes in pages, and the number of actually cut off trailing 0xff bytes for flash - Printing or instead of - in the -U routines - Option -V no longer needs to be specified before option -U in order to work As an aside this commit also provides useful helper functions for printing plural(), inname(), outname() and interval() all of which return strings fit for printing. $ avrdude -qp ATmega2560 -c usbtiny -U blink-mega2560+lext-test.hex avrdude: AVR device initialized and ready to accept instructions avrdude: Device signature = 0x1e9801 (probably m2560) avrdude: NOTE: "flash" memory has been specified, an erase cycle will be performed To disable this feature, specify the -D option. avrdude: erasing chip avrdude: input file blink-mega2560+lext-test.hex auto detected as Intel Hex avrdude: reading input file blink-mega2560+lext-test.hex for flash with 1346 bytes in 4 sections within [0, 0x3106d] using 7 pages and 446 pad bytes avrdude: writing 1346 bytes flash ... avrdude: 1346 bytes of flash written avrdude: verifying flash memory against blink-mega2560+lext-test.hex avrdude: 1346 bytes of flash verified avrdude done. Thank you. $ avrdude -qp ATmega328P -c usb-bub-ii -U sketch-ending-in-ff.hex avrdude: AVR device initialized and ready to accept instructions avrdude: Device signature = 0x1e950f (probably m328p) avrdude: NOTE: "flash" memory has been specified, an erase cycle will be performed To disable this feature, specify the -D option. avrdude: erasing chip avrdude: input file sketch-ending-in-ff.hex auto detected as Intel Hex avrdude: reading input file sketch-ending-in-ff.hex for flash with 2160 bytes in 1 section within [0, 0x888] using 17 pages and 16 pad bytes, cutting off 25 trailing 0xff bytes avrdude: writing 2160 bytes flash ... avrdude: 2160 bytes of flash written avrdude: verifying flash memory against sketch-ending-in-ff.hex avrdude: 2185 bytes of flash verified avrdude done. Thank you. $ echo "Hello, world..." | avrdude -qp ATmega328P -c ... -U eeprom:w:-:r avrdude: AVR device initialized and ready to accept instructions avrdude: Device signature = 0x1e950f (probably m328p) avrdude: reading input file for eeprom avrdude: writing 16 bytes eeprom ... avrdude: 16 bytes of eeprom written avrdude: verifying eeprom memory against avrdude: 16 bytes of eeprom verified avrdude done. Thank you. --- src/libavrdude.h | 20 +++ src/main.c | 14 +- src/update.c | 330 ++++++++++++++++++++++++++++++++--------------- 3 files changed, 252 insertions(+), 112 deletions(-) diff --git a/src/libavrdude.h b/src/libavrdude.h index dad47922..95e08d18 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -888,6 +888,7 @@ enum updateflags { UF_NONE = 0, UF_NOWRITE = 1, UF_AUTO_ERASE = 2, + UF_VERIFY = 4, }; @@ -898,6 +899,17 @@ typedef struct update_t { int format; } UPDATE; +typedef struct { // File reads for flash can exclude trailing 0xff, which are cut off + int nbytes, // Number of bytes set including 0xff but excluding cut off, trailing 0xff + nsections, // Number of consecutive sections in source excluding cut off, trailing 0xff + npages, // Number of memory pages needed excluding pages solely with trailing 0xff + nfill, // Number of fill bytes to make up full pages that are needed + ntrailing, // Number of trailing 0xff in source + firstaddr, // First address set in [0, mem->size-1] + lastaddr; // Highest address set by input file +} Filestats; + + #ifdef __cplusplus extern "C" { #endif @@ -910,6 +922,14 @@ extern void free_update(UPDATE * upd); extern int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags flags); +extern int memstats(struct avrpart *p, char *memtype, int size, Filestats *fsp); + +// Convenience functions for printing +const char *plural(int x); +const char *inname(const char *fn); +const char *outname(const char *fn); +const char *interval(int a, int b); + #ifdef __cplusplus } #endif diff --git a/src/main.c b/src/main.c index 772762f3..f4095d5f 100644 --- a/src/main.c +++ b/src/main.c @@ -237,7 +237,7 @@ static void cleanup_main(void) static void replace_backslashes(char *s) { // Replace all backslashes with forward slashes - for (int i = 0; i < strlen(s); i++) { + for (size_t i = 0; i < strlen(s); i++) { if (s[i] == '\\') { s[i] = '/'; } @@ -267,7 +267,6 @@ int main(int argc, char * argv []) int calibrate; /* 1=calibrate RC oscillator, 0=don't */ char * port; /* device port (/dev/xxx) */ int terminal; /* 1=enter terminal mode, 0=don't */ - int verify; /* perform a verify operation */ char * exitspecs; /* exit specs string from command line */ char * programmer; /* programmer id */ char * partdesc; /* part id */ @@ -284,7 +283,7 @@ int main(int argc, char * argv []) int init_ok; /* Device initialization worked well */ int is_open; /* Device open succeeded */ char * logfile; /* Use logfile rather than stderr for diagnostics */ - enum updateflags uflags = UF_AUTO_ERASE; /* Flags for do_op() */ + enum updateflags uflags = UF_AUTO_ERASE | UF_VERIFY; /* Flags for do_op() */ #if !defined(WIN32) char * homedir; @@ -349,7 +348,6 @@ int main(int argc, char * argv []) p = NULL; ovsigck = 0; terminal = 0; - verify = 1; /* on by default */ quell_progress = 0; exitspecs = NULL; pgm = NULL; @@ -525,12 +523,6 @@ int main(int argc, char * argv []) exit(1); } ladd(updates, upd); - - if (verify && upd->op == DEVICE_WRITE) { - upd = dup_update(upd); - upd->op = DEVICE_VERIFY; - ladd(updates, upd); - } break; case 'v': @@ -538,7 +530,7 @@ int main(int argc, char * argv []) break; case 'V': - verify = 0; + uflags &= ~UF_VERIFY; break; case 'x': diff --git a/src/update.c b/src/update.c index 1840f81f..ffddfa16 100644 --- a/src/update.c +++ b/src/update.c @@ -45,7 +45,7 @@ UPDATE * parse_op(char * s) i = 0; p = s; - while ((i < (sizeof(buf)-1) && *p && (*p != ':'))) + while (i < (int) sizeof(buf)-1 && *p && *p != ':') buf[i++] = *p++; buf[i] = 0; @@ -214,18 +214,124 @@ void free_update(UPDATE * u) } +// Memory statistics considering holes after a file read returned size bytes +int memstats(struct avrpart *p, char *memtype, int size, Filestats *fsp) { + Filestats ret = { 0 }; + AVRMEM *mem = avr_locate_mem(p, memtype); + + if(!mem) { + avrdude_message(MSG_INFO, "%s: %s %s undefined\n", + progname, p->desc, memtype); + return LIBAVRDUDE_GENERAL_FAILURE; + } + + if(!mem->buf || !mem->tags) { + avrdude_message(MSG_INFO, "%s: %s %s is not set\n", + progname, p->desc, memtype); + return LIBAVRDUDE_GENERAL_FAILURE; + } + + int pgsize = mem->page_size; + if(pgsize < 1) + pgsize = 1; + + if(size < 0 || size > mem->size) { + avrdude_message(MSG_INFO, "%s: memstats() size %d at odds with %s %s size %d\n", + progname, size, p->desc, memtype, mem->size); + return LIBAVRDUDE_GENERAL_FAILURE; + } + + ret.lastaddr = -1; + int firstset = 0, insection = 0; + // Scan all memory + for(int addr = 0; addr < mem->size; ) { + int pageset = 0; + // Go page by page + for(int pgi = 0; pgi < pgsize; pgi++, addr++) { + if(mem->tags[addr] & TAG_ALLOCATED) { + if(!firstset) { + firstset = 1; + ret.firstaddr = addr; + } + ret.lastaddr = addr; + // size can be smaller than tags suggest owing to flash trailing-0xff + if(addr < size) { + ret.nbytes++; + if(!pageset) { + pageset = 1; + ret.nfill += pgi; + ret.npages++; + } + if(!insection) { + insection = 1; + ret.nsections++; + } + } else { // Now beyond size returned by input file read + ret.ntrailing++; + if(pageset) + ret.nfill++; + } + } else { // In a hole or beyond input file + insection = 0; + if(pageset) + ret.nfill++; + } + } + } + + if(fsp) + *fsp = ret; + + return LIBAVRDUDE_SUCCESS; +} + + +// Convenience functions for printing +const char *plural(int x) { + return x==1? "": "s"; +} + +const char *inname(const char *fn) { + return !fn? "???": strcmp(fn, "-")? fn: ""; +} + +const char *outname(const char *fn) { + return !fn? "???": strcmp(fn, "-")? fn: ""; +} + +// Return sth like "[0, 0x1ff]" +const char *interval(int a, int b) { + // Cyclic buffer for 20+ temporary interval strings each max 41 bytes at 64-bit int + static char space[20*41 + 80], *sp; + if(!sp || sp-space > (int) sizeof space - 80) + sp = space; + + char *ret = sp; + + sprintf(sp, a<16? "[%d": "[0x%x", a); + sp += strlen(sp); + sprintf(sp, b<16? ", %d]": ", 0x%x]", b); + + // Advance beyond return string in temporary ring buffer + sp += strlen(sp)+1; + + return ret; +} + + int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags flags) { struct avrpart * v; AVRMEM * mem; - int size, vsize; + int size; int rc; + Filestats fs; mem = avr_locate_mem(p, upd->memtype); if (mem == NULL) { - avrdude_message(MSG_INFO, "\"%s\" memory type not defined for part \"%s\"\n", - upd->memtype, p->desc); - return -1; + avrdude_message(MSG_INFO, "%s memory type not defined for part %s\n", + upd->memtype, p->desc); + return LIBAVRDUDE_GENERAL_FAILURE; } AVRMEM_ALIAS * alias_mem = avr_find_memalias(p, mem); @@ -235,167 +341,189 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f strcat(alias_mem_desc, alias_mem->desc); } - if (upd->op == DEVICE_READ) { - /* - * read out the specified device memory and write it to a file - */ + switch (upd->op) { + case DEVICE_READ: + // Read out the specified device memory and write it to a file if (upd->format == FMT_IMM) { avrdude_message(MSG_INFO, - "%s: Invalid file format 'immediate' for output\n", - progname, upd->filename); - return -1; + "%s: Invalid file format 'immediate' for output\n", progname); + return LIBAVRDUDE_GENERAL_FAILURE; } - if (quell_progress < 2) { - avrdude_message(MSG_INFO, "%s: reading %s%s memory:\n", - progname, mem->desc, alias_mem_desc); - } - report_progress(0,1,"Reading"); + if (quell_progress < 2) + avrdude_message(MSG_INFO, "%s: reading %s%s memory ...\n", + progname, mem->desc, alias_mem_desc); + + report_progress(0, 1, "Reading"); rc = avr_read(pgm, p, upd->memtype, 0); + report_progress(1, 1, NULL); if (rc < 0) { avrdude_message(MSG_INFO, "%s: failed to read all of %s%s memory, rc=%d\n", - progname, mem->desc, alias_mem_desc, rc); - return -1; + progname, mem->desc, alias_mem_desc, rc); + return LIBAVRDUDE_GENERAL_FAILURE; } - report_progress(1,1,NULL); size = rc; if (quell_progress < 2) { if (rc == 0) - avrdude_message(MSG_INFO, "%s: Flash is empty, resulting file has no contents.\n", - progname); - avrdude_message(MSG_INFO, "%s: writing output file \"%s\"\n", - progname, - strcmp(upd->filename, "-")==0 ? "" : upd->filename); + avrdude_message(MSG_INFO, "%s: flash is empty, resulting file has no contents\n", + progname); + avrdude_message(MSG_INFO, "%s: writing output file %s\n", + progname, outname(upd->filename)); } rc = fileio(FIO_WRITE, upd->filename, upd->format, p, upd->memtype, size); if (rc < 0) { - avrdude_message(MSG_INFO, "%s: write to file '%s' failed\n", - progname, upd->filename); - return -1; - } - } - else if (upd->op == DEVICE_WRITE) { - /* - * write the selected device memory using data from a file; first - * read the data from the specified file - */ - if (quell_progress < 2) { - avrdude_message(MSG_INFO, "%s: reading input file \"%s\"\n", - progname, - strcmp(upd->filename, "-")==0 ? "" : upd->filename); + avrdude_message(MSG_INFO, "%s: write to file %s failed\n", + progname, outname(upd->filename)); + return LIBAVRDUDE_GENERAL_FAILURE; } + break; + + case DEVICE_WRITE: + // Write the selected device memory using data from a file + rc = fileio(FIO_READ, upd->filename, upd->format, p, upd->memtype, -1); + if (quell_progress < 2) + avrdude_message(MSG_INFO, "%s: reading input file %s for %s%s\n", + progname, inname(upd->filename), mem->desc, alias_mem_desc); if (rc < 0) { - avrdude_message(MSG_INFO, "%s: read from file '%s' failed\n", - progname, upd->filename); - return -1; + avrdude_message(MSG_INFO, "%s: read from file %s failed\n", + progname, inname(upd->filename)); + return LIBAVRDUDE_GENERAL_FAILURE; } size = rc; - /* - * write the buffer contents to the selected memory type - */ - if (quell_progress < 2) { - avrdude_message(MSG_INFO, "%s: writing %s%s (%d bytes):\n", - progname, mem->desc, alias_mem_desc, size); - } + if(memstats(p, upd->memtype, size, &fs) < 0) + return LIBAVRDUDE_GENERAL_FAILURE; + + if(quell_progress < 2) { + int level = fs.nsections > 1 || fs.firstaddr > 0 || fs.ntrailing? MSG_INFO: MSG_NOTICE; + + avrdude_message(level, "%*s with %d byte%s in %d section%s within %s\n", + (int) strlen(progname)+1, "", + fs.nbytes, plural(fs.nbytes), + fs.nsections, plural(fs.nsections), + interval(fs.firstaddr, fs.lastaddr)); + if(mem->page_size > 1) { + avrdude_message(level, "%*s using %d page%s and %d pad byte%s", + (int) strlen(progname)+1, "", + fs.npages, plural(fs.npages), + fs.nfill, plural(fs.nfill)); + if(fs.ntrailing) + avrdude_message(level, ", cutting off %d trailing 0xff byte%s", + fs.ntrailing, plural(fs.ntrailing)); + avrdude_message(level, "\n"); + } + } + + // Write the buffer contents to the selected memory type + if (quell_progress < 2) + avrdude_message(MSG_INFO, "%s: writing %d byte%s %s%s ...\n", + progname, fs.nbytes, plural(fs.nbytes), mem->desc, alias_mem_desc); if (!(flags & UF_NOWRITE)) { - report_progress(0,1,"Writing"); + report_progress(0, 1, "Writing"); rc = avr_write(pgm, p, upd->memtype, size, (flags & UF_AUTO_ERASE) != 0); - report_progress(1,1,NULL); - } - else { - /* - * test mode, don't actually write to the chip, output the buffer - * to stdout in intel hex instead - */ + report_progress(1, 1, NULL); + } else { + // Test mode: write to stdout in intel hex rather than to the chip rc = fileio(FIO_WRITE, "-", FMT_IHEX, p, upd->memtype, size); } if (rc < 0) { avrdude_message(MSG_INFO, "%s: failed to write %s%s memory, rc=%d\n", - progname, mem->desc, alias_mem_desc, rc); - return -1; + progname, mem->desc, alias_mem_desc, rc); + return LIBAVRDUDE_GENERAL_FAILURE; } - vsize = rc; + if (quell_progress < 2) + avrdude_message(MSG_INFO, "%s: %d byte%s of %s%s written\n", + progname, fs.nbytes, plural(fs.nbytes), mem->desc, alias_mem_desc); - if (quell_progress < 2) { - avrdude_message(MSG_INFO, "%s: %d bytes of %s%s written\n", progname, - vsize, mem->desc, alias_mem_desc); - } + // Fall through for (default) auto verify, ie, unless -V was specified + if (!(flags & UF_VERIFY)) + break; - } - else if (upd->op == DEVICE_VERIFY) { - /* - * verify that the in memory file (p->mem[AVR_M_FLASH|AVR_M_EEPROM]) - * is the same as what is on the chip - */ + case DEVICE_VERIFY: + // Verify that the in memory file is the same as what is on the chip pgm->vfy_led(pgm, ON); + int userverify = upd->op == DEVICE_VERIFY; // Explicit -U :v by user + if (quell_progress < 2) { - avrdude_message(MSG_INFO, "%s: verifying %s%s memory against %s:\n", - progname, mem->desc, alias_mem_desc, upd->filename); + avrdude_message(MSG_INFO, "%s: verifying %s%s memory against %s\n", + progname, mem->desc, alias_mem_desc, inname(upd->filename)); - avrdude_message(MSG_NOTICE2, "%s: load data %s%s data from input file %s:\n", - progname, mem->desc, alias_mem_desc, upd->filename); + if (userverify) + avrdude_message(MSG_NOTICE, "%s: load %s%s data from input file %s\n", + progname, mem->desc, alias_mem_desc, inname(upd->filename)); } - rc = fileio(FIO_READ_FOR_VERIFY, upd->filename, upd->format, p, upd->memtype, -1); - if (rc < 0) { - avrdude_message(MSG_INFO, "%s: read from file '%s' failed\n", - progname, upd->filename); - return -1; + // No need to read file when fallen through from DEVICE_WRITE + if (userverify) { + rc = fileio(FIO_READ_FOR_VERIFY, upd->filename, upd->format, p, upd->memtype, -1); + + if (rc < 0) { + avrdude_message(MSG_INFO, "%s: read from file %s failed\n", + progname, inname(upd->filename)); + return LIBAVRDUDE_GENERAL_FAILURE; + } + size = rc; + + if(memstats(p, upd->memtype, size, &fs) < 0) + return LIBAVRDUDE_GENERAL_FAILURE; + } else { + // Correct size of last read to include potentially cut off, trailing 0xff (flash) + size = fs.lastaddr+1; } + v = avr_dup_part(p); - size = rc; + if (quell_progress < 2) { - avrdude_message(MSG_NOTICE2, "%s: input file %s contains %d bytes\n", - progname, upd->filename, size); - avrdude_message(MSG_NOTICE2, "%s: reading on-chip %s%s data:\n", - progname, mem->desc, alias_mem_desc); + if (userverify) + avrdude_message(MSG_NOTICE, "%s: input file %s contains %d byte%s\n", + progname, inname(upd->filename), fs.nbytes, plural(fs.nbytes)); + avrdude_message(MSG_NOTICE2, "%s: reading on-chip %s%s data ...\n", + progname, mem->desc, alias_mem_desc); } report_progress (0,1,"Reading"); rc = avr_read(pgm, p, upd->memtype, v); + report_progress (1,1,NULL); if (rc < 0) { avrdude_message(MSG_INFO, "%s: failed to read all of %s%s memory, rc=%d\n", - progname, mem->desc, alias_mem_desc, rc); + progname, mem->desc, alias_mem_desc, rc); pgm->err_led(pgm, ON); avr_free_part(v); - return -1; + return LIBAVRDUDE_GENERAL_FAILURE; } - report_progress (1,1,NULL); - - - if (quell_progress < 2) { + if (quell_progress < 2) avrdude_message(MSG_NOTICE2, "%s: verifying ...\n", progname); - } + rc = avr_verify(p, v, upd->memtype, size); if (rc < 0) { avrdude_message(MSG_INFO, "%s: verification error; content mismatch\n", - progname); + progname); pgm->err_led(pgm, ON); avr_free_part(v); - return -1; + return LIBAVRDUDE_GENERAL_FAILURE; } if (quell_progress < 2) { - avrdude_message(MSG_INFO, "%s: %d bytes of %s%s verified\n", - progname, rc, mem->desc, alias_mem_desc); + int verified = fs.nbytes+fs.ntrailing; + avrdude_message(MSG_INFO, "%s: %d byte%s of %s%s verified\n", + progname, verified, plural(verified), mem->desc, alias_mem_desc); } pgm->vfy_led(pgm, OFF); avr_free_part(v); - } - else { + break; + + default: avrdude_message(MSG_INFO, "%s: invalid update operation (%d) requested\n", - progname, upd->op); - return -1; + progname, upd->op); + return LIBAVRDUDE_GENERAL_FAILURE; } - return 0; + return LIBAVRDUDE_SUCCESS; } - From 42c8169c37923345758664ca3fdc4e229bc112d0 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 2 Aug 2022 23:53:00 +0100 Subject: [PATCH 43/47] Add ordered list of known memories to avr.c with access functions --- src/avr.c | 39 +++++++++++++++++++++++++++++++++++++++ src/config_gram.y | 1 + src/developer_opts.c | 43 +++++++------------------------------------ src/libavrdude.h | 5 +++++ 4 files changed, 52 insertions(+), 36 deletions(-) diff --git a/src/avr.c b/src/avr.c index 7f91e9a1..eb077b32 100644 --- a/src/avr.c +++ b/src/avr.c @@ -1220,7 +1220,46 @@ int avr_put_cycle_count(PROGRAMMER * pgm, AVRPART * p, int cycles) } return 0; +} + + +// Typical order in which memories show in avrdude.conf, runtime adds unknown ones (if any) +const char *avr_mem_order[100] = { + "eeprom", "flash", "application", "apptable", + "boot", "lfuse", "hfuse", "efuse", + "fuse", "fuse0", "wdtcfg", "fuse1", + "bodcfg", "fuse2", "osccfg", "fuse3", + "fuse4", "tcd0cfg", "fuse5", "syscfg0", + "fuse6", "syscfg1", "fuse7", "append", + "codesize", "fuse8", "fuse9", "bootend", + "bootsize", "fuses", "lock", "lockbits", + "tempsense", "signature", "prodsig", "sernum", + "calibration", "osccal16", "osccal20", "osc16err", + "osc20err", "usersig", "userrow", "data", +}; + +void avr_add_mem_order(const char *str) { + for(size_t i=0; i < sizeof avr_mem_order/sizeof *avr_mem_order; i++) { + if(avr_mem_order[i] && !strcmp(avr_mem_order[i], str)) + return; + if(!avr_mem_order[i]) { + avr_mem_order[i] = strdup(str); + return; + } } + avrdude_message(MSG_INFO, + "%s: avr_mem_order[] under-dimensioned in avr.c; increase and recompile\n", + progname); + exit(1); +} + +int avr_known_mem(const char *str) { + for(size_t i=0; i < sizeof avr_mem_order/sizeof *avr_mem_order; i++) + if(avr_mem_order[i] && !strcmp(avr_mem_order[i], str)) + return 1; + return 0; +} + int avr_chip_erase(PROGRAMMER * pgm, AVRPART * p) { diff --git a/src/config_gram.y b/src/config_gram.y index 68718dd1..ce11b924 100644 --- a/src/config_gram.y +++ b/src/config_gram.y @@ -1320,6 +1320,7 @@ part_parm : mem->desc[AVR_MEMDESCLEN-1] = 0; ladd(current_part->mem, mem); } + avr_add_mem_order($2->value.string); current_mem = mem; free_token($2); } diff --git a/src/developer_opts.c b/src/developer_opts.c index f4a55478..b82c1805 100644 --- a/src/developer_opts.c +++ b/src/developer_opts.c @@ -280,35 +280,6 @@ static void dev_stack_out(bool tsv, AVRPART *p, const char *name, unsigned char } -// 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", - "fuse", "fuse0", "wdtcfg", "fuse1", - "bodcfg", "fuse2", "osccfg", "fuse3", - "fuse4", "tcd0cfg", "fuse5", "syscfg0", - "fuse6", "syscfg1", "fuse7", "append", - "codesize", "fuse8", "fuse9", "bootend", - "bootsize", "fuses", "lock", "lockbits", - "tempsense", "signature", "prodsig", "sernum", - "calibration", "osccal16", "osccal20", "osc16err", - "osc20err", "usersig", "userrow", "data", -}; - -static void add_mem_order(const char *str) { - 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]) { - mem_order[i] = strdup(str); - return; - } - } - dev_info("%s: mem_order[] under-dimensioned in developer_opts.c; increase and recompile\n", progname); - exit(1); -} - - static int intcmp(int a, int b) { return a-b; } @@ -410,8 +381,8 @@ static int avrpart_deep_copy(AVRPARTdeep *d, AVRPART *p) { // fill in all memories we got in defined order di = 0; - for(size_t mi=0; mi < sizeof mem_order/sizeof *mem_order && mem_order[mi]; mi++) { - m = p->mem? avr_locate_mem(p, mem_order[mi]): NULL; + for(size_t mi=0; mi < sizeof avr_mem_order/sizeof *avr_mem_order && avr_mem_order[mi]; mi++) { + m = p->mem? avr_locate_mem(p, avr_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); @@ -566,11 +537,11 @@ 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(size_t mi=0; mi < sizeof mem_order/sizeof *mem_order && mem_order[mi]; mi++) { + for(size_t mi=0; mi < sizeof avr_mem_order/sizeof *avr_mem_order && avr_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; + m = p->mem? avr_locate_mem(p, avr_mem_order[mi]): NULL; + bm = base && base->mem? avr_locate_mem(base, avr_mem_order[mi]): NULL; if(!m && bm && !tsv) dev_info("\n memory \"%s\" = NULL;\n", bm->desc); @@ -694,12 +665,12 @@ void dev_output_part_defs(char *partdesc) { AVRPART *p = ldata(ln1); if(p->mem) for(LNODEID lnm=lfirst(p->mem); lnm; lnm=lnext(lnm)) - add_mem_order(((AVRMEM *) ldata(lnm))->desc); + avr_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); + avr_add_mem_order(((AVRMEM_ALIAS *) ldata(lnm))->desc); } nprinted = dev_nprinted; diff --git a/src/libavrdude.h b/src/libavrdude.h index 95e08d18..cc332ec7 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -783,6 +783,7 @@ void sort_programmers(LISTID programmers); typedef void (*FP_UpdateProgress)(int percent, double etime, char *hdr); extern struct avrpart parts[]; +extern const char *avr_mem_order[100]; extern FP_UpdateProgress update_progress; @@ -818,6 +819,10 @@ int avr_get_cycle_count(PROGRAMMER * pgm, AVRPART * p, int * cycles); int avr_put_cycle_count(PROGRAMMER * pgm, AVRPART * p, int cycles); +void avr_add_mem_order(const char *str); + +int avr_known_mem(const char *str); + #define disable_trailing_ff_removal() avr_mem_hiaddr(NULL) int avr_mem_hiaddr(AVRMEM * mem); From 9604a3ef365b088b2d6b36e04dde6a225b271a56 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Wed, 3 Aug 2022 00:04:14 +0100 Subject: [PATCH 44/47] Check -U option for unknown memories during parsing $ avrdude -qp ATmega2560 -c usbtiny -U flesh:w:blink-mega2560+lext-test.hex:i avrdude: unknown memory type flesh avrdude: error parsing update operation 'flesh:w:blink-mega2560+lext-test.hex:i' --- src/avr.c | 2 +- src/libavrdude.h | 2 +- src/update.c | 6 ++++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/avr.c b/src/avr.c index eb077b32..3a7d4a9e 100644 --- a/src/avr.c +++ b/src/avr.c @@ -1253,7 +1253,7 @@ void avr_add_mem_order(const char *str) { exit(1); } -int avr_known_mem(const char *str) { +int avr_mem_is_known(const char *str) { for(size_t i=0; i < sizeof avr_mem_order/sizeof *avr_mem_order; i++) if(avr_mem_order[i] && !strcmp(avr_mem_order[i], str)) return 1; diff --git a/src/libavrdude.h b/src/libavrdude.h index cc332ec7..f8bdf682 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -821,7 +821,7 @@ int avr_put_cycle_count(PROGRAMMER * pgm, AVRPART * p, int cycles); void avr_add_mem_order(const char *str); -int avr_known_mem(const char *str); +int avr_mem_is_known(const char *str); #define disable_trailing_ff_removal() avr_mem_hiaddr(NULL) int avr_mem_hiaddr(AVRMEM * mem); diff --git a/src/update.c b/src/update.c index ffddfa16..ee205bbc 100644 --- a/src/update.c +++ b/src/update.c @@ -62,6 +62,12 @@ UPDATE * parse_op(char * s) return upd; } + if (!avr_mem_is_known(buf)) { + avrdude_message(MSG_INFO, "%s: unknown memory type %s\n", progname, buf); + free(upd); + return NULL; + } + upd->memtype = (char *)malloc(strlen(buf)+1); if (upd->memtype == NULL) { avrdude_message(MSG_INFO, "%s: out of memory\n", progname); From 648f3319a92ab0fdd004cb88bbb84dc6c04bf280 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Wed, 3 Aug 2022 00:23:15 +0100 Subject: [PATCH 45/47] Ignore target memories not present in part $ avrdude -qp m8 -c ... -U efuse:w:0xff:m && echo OK avrdude: AVR device initialized and ready to accept instructions avrdude: skipping -U efuse:... as memory not defined for part ATmega8 avrdude done. Thank you. OK --- src/main.c | 2 +- src/update.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main.c b/src/main.c index f4095d5f..2984203a 100644 --- a/src/main.c +++ b/src/main.c @@ -1243,7 +1243,7 @@ int main(int argc, char * argv []) for (ln=lfirst(updates); ln; ln=lnext(ln)) { upd = ldata(ln); rc = do_op(pgm, p, upd, uflags); - if (rc) { + if (rc && rc != LIBAVRDUDE_SOFTFAIL) { exitrc = 1; break; } diff --git a/src/update.c b/src/update.c index ee205bbc..78703e89 100644 --- a/src/update.c +++ b/src/update.c @@ -335,9 +335,9 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f mem = avr_locate_mem(p, upd->memtype); if (mem == NULL) { - avrdude_message(MSG_INFO, "%s memory type not defined for part %s\n", - upd->memtype, p->desc); - return LIBAVRDUDE_GENERAL_FAILURE; + avrdude_message(MSG_INFO, "%s: skipping -U %s:... as memory not defined for part %s\n", + progname, upd->memtype, p->desc); + return LIBAVRDUDE_SOFTFAIL; } AVRMEM_ALIAS * alias_mem = avr_find_memalias(p, mem); From 53ece538622ec695893bff35ee2650c1640b012a Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Wed, 3 Aug 2022 01:19:48 +0100 Subject: [PATCH 46/47] Update NEWS --- NEWS | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/NEWS b/NEWS index 84852dbf..d820a6a4 100644 --- a/NEWS +++ b/NEWS @@ -44,6 +44,16 @@ Changes since version 7.0: add one read mode; add quell command #1025 - Fix usbtiny read for parts with more than 64 kB flash #1029 + - CMakeLists.txt: fix build without C++ #1016 + - Provide file format I: Intel HEX with comments that ignores + checksum errors #1030 + - Enable writing fuse and lock bits for AVR-JTAGICE #1031 + - Ignore -s flag as safemode is no longer supported #1033 + - Developer options to describe parts and + extend avrdude.conf syntax #1040 + - Deprecate original STK500 v1 protocol in favour of optiboot + and Arduino as ISP #1046 + - Add jtagmkii_updi programmer option #1048 * Internals: From 3412196cd904dc02bc04678758c8f2e7c943c09f Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Thu, 4 Aug 2022 00:14:19 +0100 Subject: [PATCH 47/47] Weaken -U memory type check and move after config file parsing in main.c The check for typos in -U memory names against a list of known memory names now happens after the config files have been read, so newly declared memory names can be considered. This commit also weakens the check against existence of a known memory: it is now sufficent for a name to pass when it could be the initial string of any known memory of any part. Any -U memory that cannot possibly be matched up with a known memory is considered a typo and leads to an exit before the programmer is opened. This to protect users from typos that leave a device partially programmed. When every -U memory name might be matching one of the known memories, the programming is attempted. If the part to be programmed turns out not to have a particular -U memory, AVRDUDE warns the user and skips this -U update. This to support unifying interfaces that call AVRDUDE with potentially more memories than the actual part has (eg, efuse on ATmega8). --- src/avr.c | 15 ++++++++++++--- src/libavrdude.h | 1 + src/main.c | 7 +++++++ src/update.c | 6 ------ 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/avr.c b/src/avr.c index 3a7d4a9e..eea0ad8a 100644 --- a/src/avr.c +++ b/src/avr.c @@ -1254,9 +1254,18 @@ void avr_add_mem_order(const char *str) { } int avr_mem_is_known(const char *str) { - for(size_t i=0; i < sizeof avr_mem_order/sizeof *avr_mem_order; i++) - if(avr_mem_order[i] && !strcmp(avr_mem_order[i], str)) - return 1; + if(str && *str) + for(size_t i=0; i < sizeof avr_mem_order/sizeof *avr_mem_order; i++) + if(avr_mem_order[i] && !strcmp(avr_mem_order[i], str)) + return 1; + return 0; +} + +int avr_mem_might_be_known(const char *str) { + if(str && *str) + for(size_t i=0; i < sizeof avr_mem_order/sizeof *avr_mem_order; i++) + if(avr_mem_order[i] && !strncmp(avr_mem_order[i], str, strlen(str))) + return 1; return 0; } diff --git a/src/libavrdude.h b/src/libavrdude.h index f8bdf682..a30c1402 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -822,6 +822,7 @@ int avr_put_cycle_count(PROGRAMMER * pgm, AVRPART * p, int cycles); void avr_add_mem_order(const char *str); int avr_mem_is_known(const char *str); +int avr_mem_might_be_known(const char *str); #define disable_trailing_ff_removal() avr_mem_hiaddr(NULL) int avr_mem_hiaddr(AVRMEM * mem); diff --git a/src/main.c b/src/main.c index 2984203a..9f72847f 100644 --- a/src/main.c +++ b/src/main.c @@ -751,6 +751,7 @@ int main(int argc, char * argv []) bitclock = default_bitclock; } + avrdude_message(MSG_NOTICE, "\n"); // developer option -p /[*codws] prints various aspects of part descriptions and exits @@ -918,6 +919,12 @@ int main(int argc, char * argv []) exit(1); } } + + if (!avr_mem_might_be_known(upd->memtype)) { + avrdude_message(MSG_INFO, "%s: unknown memory type %s\n", progname, upd->memtype); + exit(1); + } + // TODO: check whether filename other than "-" is readable/writable } /* diff --git a/src/update.c b/src/update.c index 78703e89..025bfb6b 100644 --- a/src/update.c +++ b/src/update.c @@ -62,12 +62,6 @@ UPDATE * parse_op(char * s) return upd; } - if (!avr_mem_is_known(buf)) { - avrdude_message(MSG_INFO, "%s: unknown memory type %s\n", progname, buf); - free(upd); - return NULL; - } - upd->memtype = (char *)malloc(strlen(buf)+1); if (upd->memtype == NULL) { avrdude_message(MSG_INFO, "%s: out of memory\n", progname);