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); }