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\*/\*
This commit is contained in:
parent
0a7f2645c9
commit
3bd75e74c6
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -0,0 +1,651 @@
|
|||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2022, Stefan Rueger <smr@theblueorange.space>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <whereami.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#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<AVR_OP_MAX; i++)
|
||||
printopcode(p, d, opa[i], i);
|
||||
}
|
||||
|
||||
|
||||
// returns position 0..31 of highest bit set or INT_MIN if no bit is set
|
||||
static 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) {
|
||||
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; i<ns; i++)
|
||||
dev_info("0x%02x%s", stack[ns], i+1<ns? " ": dot? "\n": ";\n");
|
||||
}
|
||||
|
||||
|
||||
// -p */[cdosw*]
|
||||
void dev_output_part_defs(char *partdesc) {
|
||||
bool first = 1, cmdok, waits, opspi, descs, strct, all, dot;
|
||||
|
||||
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");
|
||||
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;
|
||||
|
||||
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)
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2022, Stefan Rueger <smr@theblueorange.space>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef developer_opts_h
|
||||
#define developer_opts_h
|
||||
|
||||
void dev_output_part_defs();
|
||||
|
||||
#endif
|
|
@ -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")
|
346
src/main.c
346
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<AVR_OP_MAX; i++)
|
||||
printopcode(p, d, opa, i);
|
||||
}
|
||||
|
||||
|
||||
/* returns position 0..31 of highest bit set or INT_MIN if no bit is set */
|
||||
static 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) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue