Merge branch 'main' into fix_1041

This commit is contained in:
Stefan Rueger 2022-08-04 18:03:49 +01:00 committed by GitHub
commit ed36c7e1f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 2204 additions and 350 deletions

View File

@ -21,7 +21,7 @@
# cmake --build build # cmake --build build
cmake_minimum_required(VERSION 3.12) 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 11)
set(CMAKE_C_STANDARD_REQUIRED True) set(CMAKE_C_STANDARD_REQUIRED True)

10
NEWS
View File

@ -44,6 +44,16 @@ Changes since version 7.0:
add one read mode; add one read mode;
add quell command #1025 add quell command #1025
- Fix usbtiny read for parts with more than 64 kB flash #1029 - 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: * Internals:

View File

@ -56,6 +56,8 @@ if(WIN32)
endif() endif()
if(MSVC) if(MSVC)
enable_language(CXX)
add_compile_definitions(_CRT_SECURE_NO_WARNINGS=1) add_compile_definitions(_CRT_SECURE_NO_WARNINGS=1)
add_compile_definitions(_CRT_NONSTDC_NO_WARNINGS=1) add_compile_definitions(_CRT_NONSTDC_NO_WARNINGS=1)
add_compile_definitions(_WINSOCK_DEPRECATED_NO_WARNINGS=1) add_compile_definitions(_WINSOCK_DEPRECATED_NO_WARNINGS=1)
@ -250,6 +252,9 @@ add_executable(avrdude
main.c main.c
term.c term.c
term.h term.h
developer_opts.c
developer_opts.h
developer_opts_private.h
whereami.c whereami.c
whereami.h whereami.h
"${EXTRA_WINDOWS_RESOURCES}" "${EXTRA_WINDOWS_RESOURCES}"

View File

@ -198,6 +198,9 @@ avrdude_SOURCES = \
main.c \ main.c \
whereami.c \ whereami.c \
whereami.h \ whereami.h \
developer_opts.c \
developer_opts.h \
developer_opts_private.h \
term.c \ term.c \
term.h term.h

View File

@ -1220,7 +1220,55 @@ int avr_put_cycle_count(PROGRAMMER * pgm, AVRPART * p, int cycles)
} }
return 0; 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_mem_is_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] && !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;
}
int avr_chip_erase(PROGRAMMER * pgm, AVRPART * p) int avr_chip_erase(PROGRAMMER * pgm, AVRPART * p)
{ {

View File

@ -44,9 +44,7 @@
.Op Fl O .Op Fl O
.Op Fl P Ar port .Op Fl P Ar port
.Op Fl q .Op Fl q
.Op Fl s
.Op Fl t .Op Fl t
.Op Fl u
.Op Fl U Ar memtype:op:filename:filefmt .Op Fl U Ar memtype:op:filename:filefmt
.Op Fl v .Op Fl v
.Op Fl x Ar extended_param .Op Fl x Ar extended_param
@ -626,6 +624,9 @@ Posix systems (by now).
.It Fl q .It Fl q
Disable (or quell) output of the progress bar while reading or writing Disable (or quell) output of the progress bar while reading or writing
to the device. Specify it a second time for even quieter operation. 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 .It Fl t
Tells Tells
.Nm .Nm
@ -709,6 +710,8 @@ can be one of:
.Bl -tag -width sss .Bl -tag -width sss
.It Ar i .It Ar i
Intel Hex Intel Hex
.It Ar I
Intel Hex with comments on download and tolerance of checksum errors on upload
.It Ar s .It Ar s
Motorola S-record Motorola S-record
.It Ar r .It Ar r

View File

@ -12,7 +12,7 @@
# #
# DO NOT MODIFY THIS FILE. Modifications will be overwritten the next # DO NOT MODIFY THIS FILE. Modifications will be overwritten the next
# time a "make install" is run. For user-specific additions, use the # 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: # Possible entry formats are:
# #
@ -34,12 +34,12 @@
# rdyled = <num> ; # pin number # rdyled = <num> ; # pin number
# pgmled = <num> ; # pin number # pgmled = <num> ; # pin number
# vfyled = <num> ; # pin number # vfyled = <num> ; # pin number
# usbvid = <hexnum>; # USB VID (Vendor ID) # usbvid = <hexnum> ; # USB VID (Vendor ID)
# usbpid = <hexnum> [, <hexnum> ...] # USB PID (Product ID) (1) # usbpid = <hexnum> [, <hexnum> ...] ; # USB PID (Product ID) (1)
# usbdev = <interface>; # USB interface or other device info # usbdev = <interface> ; # USB interface or other device info
# usbvendor = <vendorname>; # USB Vendor Name # usbvendor = <vendorname> ; # USB Vendor Name
# usbproduct = <productname>; # USB Product Name # usbproduct = <productname> ; # USB Product Name
# usbsn = <serialno>; # USB Serial Number # usbsn = <serialno> ; # USB Serial Number
# hvupdi_support = <num> [, <num>, ... ] ; # UPDI HV Variants Support # hvupdi_support = <num> [, <num>, ... ] ; # UPDI HV Variants Support
# #
# To invert a bit, use = ~ <num>, the spaces are important. # To invert a bit, use = ~ <num>, the spaces are important.
@ -51,29 +51,31 @@
# ; # ;
# #
# part # part
# id = <id> ; # quoted string
# desc = <description> ; # quoted string # desc = <description> ; # quoted string
# id = <id> ; # quoted string
# family_id = <id> ; # quoted string, eg, "megaAVR" or "tinyAVR"
# hvupdi_variant = <num> ; # numeric -1 (n/a) or 0..2
# devicecode = <num> ; # deprecated, use stk500_devcode
# stk500_devcode = <num> ; # numeric
# avr910_devcode = <num> ; # numeric
# has_jtag = <yes/no> ; # part has JTAG i/f # has_jtag = <yes/no> ; # part has JTAG i/f
# has_debugwire = <yes/no> ; # part has debugWire i/f # has_debugwire = <yes/no> ; # part has debugWire i/f
# has_pdi = <yes/no> ; # part has PDI i/f # has_pdi = <yes/no> ; # part has PDI i/f
# has_updi = <yes/no> ; # part has UPDI i/f # has_updi = <yes/no> ; # part has UPDI i/f
# has_tpi = <yes/no> ; # part has TPI i/f # has_tpi = <yes/no> ; # part has TPI i/f
# devicecode = <num> ; # deprecated, use stk500_devcode # is_at90s1200 = <yes/no> ; # AT90S1200 part
# stk500_devcode = <num> ; # numeric # is_avr32 = <yes/no> ; # AVR32 part
# avr910_devcode = <num> ; # numeric
# signature = <num> <num> <num> ; # signature bytes # signature = <num> <num> <num> ; # signature bytes
# usbpid = <num> ; # DFU USB PID # usbpid = <num> ; # DFU USB PID
# chip_erase_delay = <num> ; # micro-seconds # chip_erase_delay = <num> ; # micro-seconds
# reset = dedicated | io; # reset = dedicated | io ;
# retry_pulse = reset | sck; # retry_pulse = reset | sck ;
# pgm_enable = <instruction format> ;
# chip_erase = <instruction format> ;
# chip_erase_delay = <num> ; # chip erase delay (us) # chip_erase_delay = <num> ; # chip erase delay (us)
# # STK500 parameters (parallel programming IO lines) # # STK500 parameters (parallel programming IO lines)
# pagel = <num> ; # pin name in hex, i.e., 0xD7 # pagel = <num> ; # pin name in hex, i.e., 0xD7
# bs2 = <num> ; # pin name in hex, i.e., 0xA0 # bs2 = <num> ; # pin name in hex, i.e., 0xA0
# serial = <yes/no> ; # can use serial downloading # serial = <yes/no> ; # can use serial downloading
# parallel = <yes/no/pseudo>; # can use par. programming # parallel = <yes/no/pseudo> ; # can use par. programming
# # STK500v2 parameters, to be taken from Atmel's XML files # # STK500v2 parameters, to be taken from Atmel's XML files
# timeout = <num> ; # timeout = <num> ;
# stabdelay = <num> ; # stabdelay = <num> ;
@ -85,52 +87,59 @@
# predelay = <num> ; # predelay = <num> ;
# postdelay = <num> ; # postdelay = <num> ;
# pollmethod = <num> ; # pollmethod = <num> ;
# mode = <num> ;
# delay = <num> ;
# blocksize = <num> ;
# readsize = <num> ;
# hvspcmdexedelay = <num> ; # hvspcmdexedelay = <num> ;
# # STK500v2 HV programming parameters, from XML # # STK500v2 HV programming parameters, from XML
# pp_controlstack = <num>, <num>, ...; # PP only # pp_controlstack = <num>, <num>, ... ; # PP only
# hvsp_controlstack = <num>, <num>, ...; # HVSP only # hvsp_controlstack = <num>, <num>, ... ; # HVSP only
# hventerstabdelay = <num>; # flash_instr = <num>, <num>, <num> ;
# progmodedelay = <num>; # PP only # eeprom_instr = <num>, <num>, ... ;
# latchcycles = <num>; # hventerstabdelay = <num> ;
# togglevtg = <num>; # progmodedelay = <num> ; # PP only
# poweroffdelay = <num>; # latchcycles = <num> ;
# resetdelayms = <num>; # togglevtg = <num> ;
# resetdelayus = <num>; # poweroffdelay = <num> ;
# hvleavestabdelay = <num>; # resetdelayms = <num> ;
# resetdelay = <num>; # resetdelayus = <num> ;
# synchcycles = <num>; # HVSP only # hvleavestabdelay = <num> ;
# chiperasepulsewidth = <num>; # PP only # resetdelay = <num> ;
# chiperasepolltimeout = <num>; # synchcycles = <num> ; # HVSP only
# chiperasetime = <num>; # HVSP only # chiperasepulsewidth = <num> ; # PP only
# programfusepulsewidth = <num>; # PP only # chiperasepolltimeout = <num> ;
# programfusepolltimeout = <num>; # chiperasetime = <num> ; # HVSP only
# programlockpulsewidth = <num>; # PP only # programfusepulsewidth = <num> ; # PP only
# programlockpolltimeout = <num>; # programfusepolltimeout = <num> ;
# programlockpulsewidth = <num> ; # PP only
# programlockpolltimeout = <num> ;
# # JTAG ICE mkII parameters, also from XML files # # JTAG ICE mkII parameters, also from XML files
# allowfullpagebitstream = <yes/no> ; # allowfullpagebitstream = <yes/no> ;
# enablepageprogramming = <yes/no> ; # enablepageprogramming = <yes/no> ;
# idr = <num> ; # IO addr of IDR (OCD) reg. # idr = <num> ; # IO addr of IDR (OCD) reg
# rampz = <num> ; # IO addr of RAMPZ reg. # rampz = <num> ; # IO addr of RAMPZ reg
# spmcr = <num> ; # mem addr of SPMC[S]R reg. # spmcr = <num> ; # mem addr of SPMC[S]R reg
# eecr = <num> ; # mem addr of EECR reg. # eecr = <num> ; # mem addr of EECR reg only when != 0x3c
# # (only when != 0x3c) # mcu_base = <num> ;
# is_at90s1200 = <yes/no> ; # AT90S1200 part # nvm_base = <num> ;
# is_avr32 = <yes/no> ; # AVR32 part # ocd_base = <num> ;
# ocdrev = <num> ;
# pgm_enable = <instruction format> ;
# chip_erase = <instruction format> ;
# #
# memory <memtype> # memory <memtype>
# paged = <yes/no> ; # yes / no # paged = <yes/no> ; # yes/no (flash only, do not use for EEPROM)
# offset = <num> ; # memory offset
# size = <num> ; # bytes # size = <num> ; # bytes
# page_size = <num> ; # bytes # page_size = <num> ; # bytes
# num_pages = <num> ; # numeric # num_pages = <num> ; # numeric
# min_write_delay = <num> ; # micro-seconds # min_write_delay = <num> ; # micro-seconds
# max_write_delay = <num> ; # micro-seconds # max_write_delay = <num> ; # micro-seconds
# readback_p1 = <num> ; # byte value # readback = <num> <num> ; # pair of byte values
# readback_p2 = <num> ; # byte value # readback_p1 = <num> ; # byte value (first component)
# pwroff_after_write = <yes/no> ; # yes / no # readback_p2 = <num> ; # byte value (second component)
# pwroff_after_write = <yes/no> ; # yes/no
# mode = <num> ; # STK500 v2 file parameter, to be taken from Atmel's XML files
# delay = <num> ; # "
# blocksize = <num> ; # "
# readsize = <num> ; # "
# read = <instruction format> ; # read = <instruction format> ;
# write = <instruction format> ; # write = <instruction format> ;
# read_lo = <instruction format> ; # read_lo = <instruction format> ;
@ -144,7 +153,8 @@
# ; # ;
# #
# If any of the above parameters are not specified, the default value # 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 # values. If a required parameter is left empty, AVRDUDE will
# complain. # complain.
# #
@ -152,7 +162,12 @@
# using the following syntax. In this case specified integer and # using the following syntax. In this case specified integer and
# string values override parameter values from the parent part. New # string values override parameter values from the parent part. New
# memory definitions are added to the definitions inherited from the # 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 <id> # quoted string # part parent <id> # quoted string
# id = <id> ; # quoted string # id = <id> ; # quoted string
@ -181,7 +196,7 @@
# #
# INSTRUCTION FORMATS # 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 # string values containing information (bit specifiers) about each
# of the 32 bits of the instruction. Bit specifiers may be one of # of the 32 bits of the instruction. Bit specifiers may be one of
# the following formats: # the following formats:
@ -190,10 +205,11 @@
# #
# '0' = the bit is always clear on input as well as output # '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 # 'a' = the bit is an address bit; from v 7.1 the bit-number
# specifier's position within the current instruction byte # 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 # '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. # is address bit 12 on input, a0 is address bit 0.
@ -204,9 +220,26 @@
# #
# 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 # 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 # The following are STK500 part device codes to use for the
@ -1746,7 +1779,7 @@ programmer
programmer programmer
id = "jtag2updi"; id = "jtag2updi";
desc = "JTAGv2 to UPDI bridge"; desc = "JTAGv2 to UPDI bridge";
type = "jtagmkii_pdi"; type = "jtagmkii_updi";
connection_type = serial; connection_type = serial;
baudrate = 115200; baudrate = 115200;
hvupdi_support = 1; hvupdi_support = 1;
@ -11845,6 +11878,8 @@ part parent "m2561"
" a7 x x x x x x x", " a7 x x x x x x x",
" x x x x x x x x"; " x x x x x x x x";
load_ext_addr = NULL;
mode = 0x41; mode = 0x41;
delay = 20; delay = 20;
blocksize = 256; blocksize = 256;

View File

@ -71,6 +71,21 @@ void avr_free_opcode(OPCODE * op)
free(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() * 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() * avr_set_input()
* *
@ -239,7 +349,6 @@ static char * bittype(int type)
} }
/*** /***
*** Elementary functions dealing with AVRMEM structures *** Elementary functions dealing with AVRMEM structures
***/ ***/
@ -354,7 +463,6 @@ AVRMEM_ALIAS * avr_dup_memalias(AVRMEM_ALIAS * m)
void avr_free_mem(AVRMEM * m) void avr_free_mem(AVRMEM * m)
{ {
int i;
if (m->buf != NULL) { if (m->buf != NULL) {
free(m->buf); free(m->buf);
m->buf = NULL; m->buf = NULL;
@ -363,7 +471,7 @@ void avr_free_mem(AVRMEM * m)
free(m->tags); free(m->tags);
m->tags = NULL; m->tags = NULL;
} }
for(i=0;i<sizeof(m->op)/sizeof(m->op[0]);i++) for(size_t i=0; i<sizeof(m->op)/sizeof(m->op[0]); i++)
{ {
if (m->op[i] != NULL) if (m->op[i] != NULL)
{ {
@ -379,13 +487,16 @@ void avr_free_memalias(AVRMEM_ALIAS * m)
free(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; AVRMEM_ALIAS * m, * match;
LNODEID ln; LNODEID ln;
int matches; int matches;
int l; int l;
if(!p || !desc || !p->mem_alias)
return NULL;
l = strlen(desc); l = strlen(desc);
matches = 0; matches = 0;
match = NULL; match = NULL;
@ -403,13 +514,16 @@ AVRMEM_ALIAS * avr_locate_memalias(AVRPART * p, char * desc)
return NULL; return NULL;
} }
AVRMEM * avr_locate_mem_noalias(AVRPART * p, char * desc) AVRMEM * avr_locate_mem_noalias(AVRPART * p, const char * desc)
{ {
AVRMEM * m, * match; AVRMEM * m, * match;
LNODEID ln; LNODEID ln;
int matches; int matches;
int l; int l;
if(!p || !desc || !p->mem)
return NULL;
l = strlen(desc); l = strlen(desc);
matches = 0; matches = 0;
match = NULL; match = NULL;
@ -428,7 +542,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 * m, * match;
AVRMEM_ALIAS * alias; AVRMEM_ALIAS * alias;
@ -436,9 +550,13 @@ AVRMEM * avr_locate_mem(AVRPART * p, char * desc)
int matches; int matches;
int l; int l;
if(!p || !desc)
return NULL;
l = strlen(desc); l = strlen(desc);
matches = 0; matches = 0;
match = NULL; match = NULL;
if(p->mem) {
for (ln=lfirst(p->mem); ln; ln=lnext(ln)) { for (ln=lfirst(p->mem); ln; ln=lnext(ln)) {
m = ldata(ln); m = ldata(ln);
if (strncmp(desc, m->desc, l) == 0) { if (strncmp(desc, m->desc, l) == 0) {
@ -446,6 +564,7 @@ AVRMEM * avr_locate_mem(AVRPART * p, char * desc)
matches++; matches++;
} }
} }
}
if (matches == 1) if (matches == 1)
return match; return match;
@ -476,7 +595,8 @@ AVRMEM_ALIAS * avr_find_memalias(AVRPART * p, AVRMEM * m_orig)
void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, AVRPART * p, void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, AVRPART * p,
int type, int verbose) 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; int i, j;
char * optr; char * optr;
@ -545,12 +665,10 @@ void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, AVRPART * p,
} }
/* /*
* Elementary functions dealing with AVRPART structures * Elementary functions dealing with AVRPART structures
*/ */
AVRPART * avr_new_part(void) AVRPART * avr_new_part(void)
{ {
AVRPART * p; AVRPART * p;
@ -568,6 +686,7 @@ AVRPART * avr_new_part(void)
p->reset_disposition = RESET_DEDICATED; p->reset_disposition = RESET_DEDICATED;
p->retry_pulse = PIN_AVR_SCK; p->retry_pulse = PIN_AVR_SCK;
p->flags = AVRPART_SERIALOK | AVRPART_PARALLELOK | AVRPART_ENABLEPAGEPROGRAMMING; p->flags = AVRPART_SERIALOK | AVRPART_PARALLELOK | AVRPART_ENABLEPAGEPROGRAMMING;
p->parent_id = NULL;
p->config_file = NULL; p->config_file = NULL;
p->lineno = 0; p->lineno = 0;
memset(p->signature, 0xFF, 3); memset(p->signature, 0xFF, 3);
@ -597,7 +716,6 @@ AVRPART * avr_dup_part(AVRPART * d)
p->mem = save; p->mem = save;
p->mem_alias = save2; p->mem_alias = save2;
for (ln=lfirst(d->mem); ln; ln=lnext(ln)) { for (ln=lfirst(d->mem); ln; ln=lnext(ln)) {
AVRMEM *m = ldata(ln); AVRMEM *m = ldata(ln);
AVRMEM *m2 = avr_dup_mem(m); AVRMEM *m2 = avr_dup_mem(m);
@ -625,15 +743,13 @@ AVRPART * avr_dup_part(AVRPART * d)
void avr_free_part(AVRPART * d) void avr_free_part(AVRPART * d)
{ {
int i;
ldestroy_cb(d->mem, (void(*)(void *))avr_free_mem); ldestroy_cb(d->mem, (void(*)(void *))avr_free_mem);
d->mem = NULL; d->mem = NULL;
ldestroy_cb(d->mem_alias, (void(*)(void *))avr_free_memalias); ldestroy_cb(d->mem_alias, (void(*)(void *))avr_free_memalias);
d->mem_alias = NULL; d->mem_alias = NULL;
for(i=0;i<sizeof(d->op)/sizeof(d->op[0]);i++) /* do not free d->parent_id and d->config_file */
{ for(size_t i=0; i<sizeof(d->op)/sizeof(d->op[0]); i++) {
if (d->op[i] != NULL) if (d->op[i] != NULL) {
{
avr_free_opcode(d->op[i]); avr_free_opcode(d->op[i]);
d->op[i] = NULL; d->op[i] = NULL;
} }
@ -641,12 +757,15 @@ int i;
free(d); free(d);
} }
AVRPART * locate_part(LISTID parts, char * partdesc) AVRPART * locate_part(LISTID parts, const char * partdesc)
{ {
LNODEID ln1; LNODEID ln1;
AVRPART * p = NULL; AVRPART * p = NULL;
int found; int found;
if(!parts || !partdesc)
return NULL;
found = 0; found = 0;
for (ln1=lfirst(parts); ln1 && !found; ln1=lnext(ln1)) { for (ln1=lfirst(parts); ln1 && !found; ln1=lnext(ln1)) {
@ -807,3 +926,232 @@ void avr_display(FILE * f, AVRPART * p, const char * prefix, int verbose)
if (buf) if (buf)
free(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;
}

View File

@ -25,10 +25,12 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
#include <errno.h>
#include "avrdude.h" #include "avrdude.h"
#include "libavrdude.h" #include "libavrdude.h"
#include "config.h" #include "config.h"
#include "developer_opts.h"
#if defined(WIN32) #if defined(WIN32)
#define strtok_r( _s, _sep, _lasts ) \ #define strtok_r( _s, _sep, _lasts ) \
@ -45,11 +47,13 @@ int yywarning(char * errmsg, ...);
static int assign_pin(int pinno, TOKEN * v, int invert); static int assign_pin(int pinno, TOKEN * v, int invert);
static int assign_pin_list(int invert); static int assign_pin_list(int invert);
static int which_opcode(TOKEN * opcode); static int which_opcode(TOKEN * opcode);
static int parse_cmdbits(OPCODE * op); static int parse_cmdbits(OPCODE * op, int opnum);
static int pin_name; static int pin_name;
%} %}
%token K_NULL;
%token K_READ %token K_READ
%token K_WRITE %token K_WRITE
%token K_READ_LO %token K_READ_LO
@ -112,6 +116,7 @@ static int pin_name;
%token K_PSEUDO %token K_PSEUDO
%token K_PWROFF_AFTER_WRITE %token K_PWROFF_AFTER_WRITE
%token K_RDYLED %token K_RDYLED
%token K_READBACK
%token K_READBACK_P1 %token K_READBACK_P1
%token K_READBACK_P2 %token K_READBACK_P2
%token K_READMEM %token K_READMEM
@ -329,6 +334,7 @@ prog_decl :
free_token($3); free_token($3);
YYABORT; YYABORT;
} }
current_prog->parent_id = cache_string($3->value.string);
current_prog->config_file = cache_string(cfg_infile); current_prog->config_file = cache_string(cfg_infile);
current_prog->lineno = cfg_lineno; current_prog->lineno = cfg_lineno;
free_token($3); free_token($3);
@ -420,6 +426,7 @@ part_decl :
free_token($3); free_token($3);
YYABORT; YYABORT;
} }
current_part->parent_id = cache_string($3->value.string);
current_part->config_file = cache_string(cfg_infile); current_part->config_file = cache_string(cfg_infile);
current_part->lineno = cfg_lineno; current_part->lineno = cfg_lineno;
@ -797,6 +804,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 { K_HVSP_CONTROLSTACK TKN_EQUAL num_list {
{ {
TOKEN * t; TOKEN * t;
@ -828,6 +842,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 { K_FLASH_INSTR TKN_EQUAL num_list {
{ {
TOKEN * t; TOKEN * t;
@ -858,6 +879,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 { K_EEPROM_INSTR TKN_EQUAL num_list {
{ {
TOKEN * t; TOKEN * t;
@ -888,6 +915,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 K_CHIP_ERASE_DELAY TKN_EQUAL TKN_NUMBER
{ {
current_part->chip_erase_delay = $3->value.number; current_part->chip_erase_delay = $3->value.number;
@ -1275,35 +1308,51 @@ part_parm :
*/ */
K_MEMORY TKN_STRING K_MEMORY TKN_STRING
{ { /* select memory for extension or create if not there */
current_mem = avr_new_memtype(); AVRMEM *mem = avr_locate_mem_noalias(current_part, $2->value.string);
if (current_mem == NULL) { if(!mem) {
if(!(mem = avr_new_memtype())) {
yyerror("could not create mem instance"); yyerror("could not create mem instance");
free_token($2); free_token($2);
YYABORT; YYABORT;
} }
strncpy(current_mem->desc, $2->value.string, AVR_MEMDESCLEN - 1); strncpy(mem->desc, $2->value.string, AVR_MEMDESCLEN - 1);
current_mem->desc[AVR_MEMDESCLEN-1] = 0; mem->desc[AVR_MEMDESCLEN-1] = 0;
ladd(current_part->mem, mem);
}
avr_add_mem_order($2->value.string);
current_mem = mem;
free_token($2); free_token($2);
} }
mem_specs mem_specs
{ {
AVRMEM * existing_mem; 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 { // check all opcodes re necessary address bits
unsigned char cmd[4] = { 0, 0, 0, 0, };
int bn;
existing_mem = avr_locate_mem_noalias(current_part, current_mem->desc); for(int i=0; i<AVR_OP_MAX; i++)
if(current_mem && current_mem->op[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;
} |
K_MEMORY TKN_STRING TKN_EQUAL K_NULL
{
AVRMEM *existing_mem = avr_locate_mem_noalias(current_part, $2->value.string);
if (existing_mem != NULL) { if (existing_mem != NULL) {
lrmv_d(current_part->mem, existing_mem); lrmv_d(current_part->mem, existing_mem);
avr_free_mem(existing_mem); avr_free_mem(existing_mem);
} }
if (is_alias) { free_token($2);
avr_free_mem(current_mem); // alias mem has been already entered below
is_alias = false;
} else {
ladd(current_part->mem, current_mem);
}
current_mem = NULL; current_mem = NULL;
} | } |
opcode TKN_EQUAL string_list { opcode TKN_EQUAL string_list {
{ {
int opnum; int opnum;
@ -1317,13 +1366,27 @@ part_parm :
free_token($1); free_token($1);
YYABORT; YYABORT;
} }
if(0 != parse_cmdbits(op)) YYABORT; if(0 != parse_cmdbits(op, opnum))
YYABORT;
if (current_part->op[opnum] != NULL) { if (current_part->op[opnum] != NULL) {
/*yywarning("operation redefined");*/ /*yywarning("operation redefined");*/
avr_free_opcode(current_part->op[opnum]); avr_free_opcode(current_part->op[opnum]);
} }
current_part->op[opnum] = op; 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); free_token($1);
} }
} }
@ -1398,6 +1461,14 @@ mem_spec :
free_token($3); 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 K_READBACK_P1 TKN_EQUAL TKN_NUMBER
{ {
current_mem->readback[0] = $3->value.number; current_mem->readback[0] = $3->value.number;
@ -1455,13 +1526,27 @@ mem_spec :
free_token($1); free_token($1);
YYABORT; YYABORT;
} }
if(0 != parse_cmdbits(op)) YYABORT; if(0 != parse_cmdbits(op, opnum))
YYABORT;
if (current_mem->op[opnum] != NULL) { if (current_mem->op[opnum] != NULL) {
/*yywarning("operation redefined");*/ /*yywarning("operation redefined");*/
avr_free_opcode(current_mem->op[opnum]); avr_free_opcode(current_mem->op[opnum]);
} }
current_mem->op[opnum] = op; 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); free_token($1);
} }
} }
@ -1579,15 +1664,12 @@ static int which_opcode(TOKEN * opcode)
} }
static int parse_cmdbits(OPCODE * op) static int parse_cmdbits(OPCODE * op, int opnum)
{ {
TOKEN * t; TOKEN *t;
int bitno; int bitno;
char ch;
char * e;
char * q;
int len; int len;
char * s, *brkt = NULL; char *s, *brkt = NULL;
int rv = 0; int rv = 0;
bitno = 32; bitno = 32;
@ -1595,9 +1677,17 @@ static int parse_cmdbits(OPCODE * op)
t = lrmv_n(string_list, 1); 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) { while (rv == 0 && s != NULL) {
// Ignore visual grouping characters in compact mode
if(*s != '.' && *s != '-' && *s != '_' && *s !='/')
bitno--; bitno--;
if (bitno < 0) { if (bitno < 0) {
yyerror("too many opcode bits for instruction"); yyerror("too many opcode bits for instruction");
@ -1613,10 +1703,8 @@ static int parse_cmdbits(OPCODE * op)
break; break;
} }
ch = s[0];
if (len == 1) { if (len == 1) {
switch (ch) { switch (*s) {
case '1': case '1':
op->bit[bitno].type = AVR_CMDBIT_VALUE; op->bit[bitno].type = AVR_CMDBIT_VALUE;
op->bit[bitno].value = 1; op->bit[bitno].value = 1;
@ -1635,7 +1723,10 @@ static int parse_cmdbits(OPCODE * op)
case 'a': case 'a':
op->bit[bitno].type = AVR_CMDBIT_ADDRESS; op->bit[bitno].type = AVR_CMDBIT_ADDRESS;
op->bit[bitno].value = 0; 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 Bytes 0 or 3 of SPI commands");
break; break;
case 'i': case 'i':
op->bit[bitno].type = AVR_CMDBIT_INPUT; op->bit[bitno].type = AVR_CMDBIT_INPUT;
@ -1647,21 +1738,40 @@ static int parse_cmdbits(OPCODE * op)
op->bit[bitno].value = 0; op->bit[bitno].value = 0;
op->bit[bitno].bitno = bitno % 8; op->bit[bitno].bitno = bitno % 8;
break; break;
case '.':
case '-':
case '_':
case '/':
break;
default : default :
yyerror("invalid bit specifier '%c'", ch); yyerror("invalid bit specifier '%c'", *s);
rv = -1; rv = -1;
break; break;
} }
} }
else { else {
if (ch == 'a') { if (*s == 'a') {
q = &s[1]; int sb, bn;
op->bit[bitno].bitno = strtol(q, &e, 0); char *e, *q;
if ((e == q)||(*e != 0)) {
yyerror("can't parse bit number from \"%s\"", q); q = s+1;
rv = -1; errno = 0;
break; 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].type = AVR_CMDBIT_ADDRESS;
op->bit[bitno].value = 0; op->bit[bitno].value = 0;
} }
@ -1672,12 +1782,16 @@ static int parse_cmdbits(OPCODE * op)
} }
} }
s = strtok_r(NULL, " ", &brkt); bit[0] = *cc++;
s = !compact? strtok_r(NULL, " ", &brkt): *bit? bit: NULL;
} /* while */ } /* while */
free_token(t); free_token(t);
} /* while */ } /* while */
if(bitno > 0)
yywarning("too few opcode bits in instruction");
return rv; return rv;
} }

888
src/developer_opts.c Normal file
View File

@ -0,0 +1,888 @@
/*
* 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"
// 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;
int cmp;
if(!op1 && !op2)
return 0;
if(!op1 || !op2)
return op1? -1: 1;
opstr1 = opcode2str(op1, opnum, 1);
opstr2 = opcode2str(op2, opnum, 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 opnum) {
unsigned char cmd[4];
int i;
if(op) {
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(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)
dev_info("%c", i? '\t': '\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);
}
// 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 opnum, OPCODE *op, AVRPART *p, AVRMEM *m) {
int i, lo, hi;
const char *opstr = opcodename(opnum);
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)) {
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, 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, 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, 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, opstr, i, op->bit[i].bitno);
}
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? "NULL":
"unknown_controlstack";
}
static void dev_stack_out(bool tsv, AVRPART *p, const char *name, unsigned char *stack, int ns) {
if(!strcmp(name, "NULL")) {
name = "pp_controlstack";
ns = 0;
}
if(tsv)
dev_info(".pt\t%s\t%s\t", p->desc, name);
else
dev_info(" %-19s =%s", name, ns <=8? " ": "");
if(ns <= 0)
dev_info(tsv? "NULL\n": "NULL;\n");
else
for(int i=0; i<ns; i++)
dev_info("%s0x%02x%s", !tsv && ns > 8 && i%8 == 0? "\n ": "", stack[i], i+1<ns? ", ": tsv? "\n": ";\n");
}
static int intcmp(int a, int b) {
return a-b;
}
// deep copies for comparison and raw output
typedef struct {
AVRMEM base;
OPCODE ops[AVR_OP_MAX];
} AVRMEMdeep;
static int avrmem_deep_copy(AVRMEMdeep *d, AVRMEM *m) {
size_t len;
d->base = *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; i<AVR_OP_MAX; i++)
d->base.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(size_t i=0; i<sizeof d->ops/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;
size_t len, di;
memset(d, 0, sizeof *d);
d->base = *p;
d->base.parent_id = NULL;
d->base.config_file = NULL;
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; i<AVR_OP_MAX; i++)
d->base.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; i<AVR_OP_MAX; i++)
if(p->op[i])
d->ops[i] = *p->op[i];
// fill in all memories we got in defined order
di = 0;
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);
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; i<n; i++, p += 16) {
dev_info("%s\t%s\t%02x%04x: ", name, sub, idx, i*16);
for(int j=0; j<16; j++)
dev_info("%02x", p+i*16+j<end? p[i*16+j]: 0);
dev_info(" ");
for(int j=0; j<16; j++)
dev_info("%c", txtchar(p+i*16+j<end? p[i*16+j]: 0));
dev_info("\n");
}
}
static void dev_part_raw(AVRPART *part) {
AVRPARTdeep dp;
int di = avrpart_deep_copy(&dp, part);
dev_raw_dump((unsigned char *) &dp.base, sizeof dp.base, part->desc, "part", 0);
dev_raw_dump((unsigned char *) &dp.ops, sizeof dp.ops, part->desc, "ops", 1);
for(int i=0; i<di; i++)
dev_raw_dump((unsigned char *) (dp.mems+i), sizeof dp.mems[i], part->desc, dp.mems[i].base.desc, i+2);
}
static void dev_part_strct(AVRPART *p, bool tsv, AVRPART *base) {
if(!tsv) {
dev_info("#------------------------------------------------------------\n");
dev_info("# %s\n", p->desc);
dev_info("#------------------------------------------------------------\n");
if(p->parent_id)
dev_info("\npart parent \"%s\"\n", p->parent_id);
else
dev_info("\npart\n");
}
_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);
_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], 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 avr_mem_order/sizeof *avr_mem_order && avr_mem_order[mi]; mi++) {
AVRMEM *m, *bm;
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);
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], i))
dev_part_strct_entry(tsv, ".ptmmop", p->desc, m->desc, opcodename(i), opcode2str(m->op[i], 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 cmdok, waits, opspi, descs, strct, cmpst, raw, all, tsv;
char *flags;
int nprinted;
AVRPART *nullpart = avr_new_part();
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 <wildcard>/<flags> not recognised\n", progname);
dev_info(
"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 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"
" 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"
"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;
}
// redirect stderr to stdout
fflush(stderr); fflush(stdout); dup2(1, 2);
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))
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))
avr_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(!descs || tsv)
if(dev_nprinted > nprinted) {
dev_info("\n");
nprinted = dev_nprinted;
}
if(!part_match(partdesc, p->desc) && !part_match(partdesc, p->id))
continue;
if(strct || cmpst)
dev_part_strct(p, tsv, !cmpst? NULL: p->parent_id? locate_part(part_list, p->parent_id): nullpart);
if(raw)
dev_part_raw(p);
// 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 && 0==strcmp(m->desc, "flash")) {
flashsize = m->size;
flashpagesize = m->page_size;
flashoffset = m->offset;
}
if(!eepromsize && 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 && !strchr(p->desc, ' ')) {
int ok, nfuses;
AVRMEM *m;
OPCODE *oc;
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("%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,
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);
}
}
}
}
}
}
}
}

24
src/developer_opts.h Normal file
View File

@ -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(char *partdesc);
#endif

View File

@ -0,0 +1,116 @@
/*
* 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_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
#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
static int dev_message(int msglvl, const char *fmt, ...);
#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(...) 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 _partout(fmt, component) \
dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, dev_sprintf(fmt, p->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) 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) 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) 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) 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) 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) 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) 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)
#endif

View File

@ -694,6 +694,10 @@ Posix systems (by now).
Disable (or quell) output of the progress bar while reading or writing Disable (or quell) output of the progress bar while reading or writing
to the device. Specify it a second time for even quieter operation. 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 @item -t
Tells AVRDUDE to enter the interactive ``terminal'' mode instead of up- Tells AVRDUDE to enter the interactive ``terminal'' mode instead of up-
or downloading files. See below for a detailed description of the or downloading files. See below for a detailed description of the
@ -769,6 +773,9 @@ the file to read or write. Possible values are:
@item i @item i
Intel Hex Intel Hex
@item I
Intel Hex with comments on download and tolerance of checksum errors on upload
@item s @item s
Motorola S-record Motorola S-record

View File

@ -59,10 +59,11 @@ struct ihexrec {
static int b2ihex(unsigned char * inbuf, int bufsize, static int b2ihex(unsigned char * inbuf, int bufsize,
int recsize, int startaddr, int recsize, int startaddr,
char * outfile, FILE * outf); char * outfile, FILE * outf, FILEFMT ffmt);
static int ihex2b(char * infile, FILE * inf, 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, static int b2srec(unsigned char * inbuf, int bufsize,
int recsize, int startaddr, int recsize, int startaddr,
@ -79,7 +80,8 @@ static int fileio_rbin(struct fioparms * fio,
char * filename, FILE * f, AVRMEM * mem, int size); char * filename, FILE * f, AVRMEM * mem, int size);
static int fileio_ihex(struct fioparms * fio, 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, static int fileio_srec(struct fioparms * fio,
char * filename, FILE * f, AVRMEM * mem, int size); 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_AUTO : return "auto-detect"; break;
case FMT_SREC : return "Motorola S-Record"; break; case FMT_SREC : return "Motorola S-Record"; break;
case FMT_IHEX : return "Intel Hex"; 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_RBIN : return "raw binary"; break;
case FMT_ELF : return "ELF"; break; case FMT_ELF : return "ELF"; break;
default : return "invalid format"; break; default : return "invalid format"; break;
@ -115,10 +118,9 @@ char * fmtstr(FILEFMT format)
} }
static int b2ihex(unsigned char * inbuf, int bufsize, static int b2ihex(unsigned char * inbuf, int bufsize,
int recsize, int startaddr, int recsize, int startaddr,
char * outfile, FILE * outf) char * outfile, FILE * outf, FILEFMT ffmt)
{ {
unsigned char * buf; unsigned char * buf;
unsigned int nextaddr; unsigned int nextaddr;
@ -154,7 +156,19 @@ static int b2ihex(unsigned char * inbuf, int bufsize,
cksum += buf[i]; cksum += buf[i];
} }
cksum = -cksum; 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<recsize; i++)
fprintf(outf, " ");
fprintf(outf, " // %05x> ", n_64k*0x10000 + nextaddr);
for (i=0; i<n; i++) {
unsigned char c = buf[i] & 0x7f;
/* Print space as _ so that line is one word */
putc(c == ' '? '_': c < ' ' || c == 0x7f? '.': c, outf);
}
}
putc('\n', outf);
nextaddr += n; nextaddr += n;
nbytes += n; nbytes += n;
@ -283,7 +297,8 @@ static int ihex_readrec(struct ihexrec * ihex, char * rec)
* *
* */ * */
static int ihex2b(char * infile, FILE * inf, static int ihex2b(char * infile, FILE * inf,
AVRMEM * mem, int bufsize, unsigned int fileoffset) AVRMEM * mem, int bufsize, unsigned int fileoffset,
FILEFMT ffmt)
{ {
char buffer [ MAX_LINE_LEN ]; char buffer [ MAX_LINE_LEN ];
unsigned int nextaddr, baseaddr, maxaddr; unsigned int nextaddr, baseaddr, maxaddr;
@ -312,11 +327,18 @@ static int ihex2b(char * infile, FILE * inf,
return -1; return -1;
} }
else if (rc != ihex.cksum) { else if (rc != ihex.cksum) {
if(ffmt == FMT_IHEX) {
avrdude_message(MSG_INFO, "%s: ERROR: checksum mismatch at line %d of \"%s\"\n", avrdude_message(MSG_INFO, "%s: ERROR: checksum mismatch at line %d of \"%s\"\n",
progname, lineno, infile); progname, lineno, infile);
avrdude_message(MSG_INFO, "%s: checksum=0x%02x, computed checksum=0x%02x\n", avrdude_message(MSG_INFO, "%s: checksum=0x%02x, computed checksum=0x%02x\n",
progname, ihex.cksum, rc); progname, ihex.cksum, rc);
return -1; return -1;
} else { /* Just warn with more permissive format FMT_IHXC */
avrdude_message(MSG_NOTICE, "%s: warning: checksum mismatch at line %d of \"%s\"\n",
progname, lineno, infile);
avrdude_message(MSG_NOTICE, "%s: checksum=0x%02x, computed checksum=0x%02x\n",
progname, ihex.cksum, rc);
}
} }
switch (ihex.rectyp) { switch (ihex.rectyp) {
@ -1160,20 +1182,21 @@ static int fileio_imm(struct fioparms * fio,
static int fileio_ihex(struct fioparms * fio, 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)
{ {
int rc; int rc;
switch (fio->op) { switch (fio->op) {
case FIO_WRITE: 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) { if (rc < 0) {
return -1; return -1;
} }
break; break;
case FIO_READ: case FIO_READ:
rc = ihex2b(filename, f, mem, size, fio->fileoffset); rc = ihex2b(filename, f, mem, size, fio->fileoffset, ffmt);
if (rc < 0) if (rc < 0)
return -1; return -1;
break; break;
@ -1566,7 +1589,8 @@ int fileio(int oprwv, char * filename, FILEFMT format,
switch (format) { switch (format) {
case FMT_IHEX: case FMT_IHEX:
rc = fileio_ihex(&fio, fname, f, mem, size); case FMT_IHXC:
rc = fileio_ihex(&fio, fname, f, mem, size, format);
break; break;
case FMT_SREC: case FMT_SREC:

View File

@ -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 cmd[6], datacmd[1 * 2 + 1];
unsigned char resp[1], writedata; 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", avrdude_message(MSG_NOTICE2, "%s: jtagmkI_write_byte(.., %s, 0x%lx, ...)\n",
progname, mem->desc, addr); progname, mem->desc, addr);
@ -1072,20 +1072,26 @@ static int jtagmkI_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
} else if (strcmp(mem->desc, "eeprom") == 0) { } else if (strcmp(mem->desc, "eeprom") == 0) {
cmd[1] = MTYPE_EEPROM; cmd[1] = MTYPE_EEPROM;
need_progmode = 0; need_progmode = 0;
need_dummy_read = 1;
PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L; PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L;
} else if (strcmp(mem->desc, "lfuse") == 0) { } else if (strcmp(mem->desc, "lfuse") == 0) {
cmd[1] = MTYPE_FUSE_BITS; cmd[1] = MTYPE_FUSE_BITS;
need_dummy_read = 1;
addr = 0; addr = 0;
} else if (strcmp(mem->desc, "hfuse") == 0) { } else if (strcmp(mem->desc, "hfuse") == 0) {
cmd[1] = MTYPE_FUSE_BITS; cmd[1] = MTYPE_FUSE_BITS;
need_dummy_read = 1;
addr = 1; addr = 1;
} else if (strcmp(mem->desc, "efuse") == 0) { } else if (strcmp(mem->desc, "efuse") == 0) {
cmd[1] = MTYPE_FUSE_BITS; cmd[1] = MTYPE_FUSE_BITS;
need_dummy_read = 1;
addr = 2; addr = 2;
} else if (strcmp(mem->desc, "lock") == 0) { } else if (strcmp(mem->desc, "lock") == 0) {
cmd[1] = MTYPE_LOCK_BITS; cmd[1] = MTYPE_LOCK_BITS;
need_dummy_read = 1;
} else if (strcmp(mem->desc, "calibration") == 0) { } else if (strcmp(mem->desc, "calibration") == 0) {
cmd[1] = MTYPE_OSCCAL_BYTE; cmd[1] = MTYPE_OSCCAL_BYTE;
need_dummy_read = 1;
} else if (strcmp(mem->desc, "signature") == 0) { } else if (strcmp(mem->desc, "signature") == 0) {
cmd[1] = MTYPE_SIGN_JTAG; cmd[1] = MTYPE_SIGN_JTAG;
} }
@ -1154,6 +1160,8 @@ static int jtagmkI_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
avrdude_message(MSG_NOTICE2, "OK\n"); avrdude_message(MSG_NOTICE2, "OK\n");
} }
if(need_dummy_read)
jtagmkI_recv(pgm, resp, 1);
return 0; return 0;
} }

View File

@ -1306,9 +1306,9 @@ static int jtagmkII_initialize(PROGRAMMER * pgm, AVRPART * p)
const char *ifname; const char *ifname;
/* Abort and print error if programmer does not support the target microcontroller */ /* 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_UPDI)) ||
(strncmp(ldata(lfirst(pgm->id)), "jtagmkII", strlen("jtagmkII")) == 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", avrdude_message(MSG_INFO, "ERROR: programmer %s does not support target %s\n\n",
ldata(lfirst(pgm->id)), p->desc); ldata(lfirst(pgm->id)), p->desc);
return -1; return -1;
} }
@ -3929,6 +3929,39 @@ void jtagmkII_pdi_initpgm(PROGRAMMER * pgm)
pgm->flag = PGM_FL_IS_PDI; 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"; const char jtagmkII_dragon_desc[] = "Atmel AVR Dragon in JTAG mode";
void jtagmkII_dragon_initpgm(PROGRAMMER * pgm) void jtagmkII_dragon_initpgm(PROGRAMMER * pgm)

View File

@ -36,6 +36,7 @@ extern const char jtagmkII_desc[];
extern const char jtagmkII_avr32_desc[]; extern const char jtagmkII_avr32_desc[];
extern const char jtagmkII_dw_desc[]; extern const char jtagmkII_dw_desc[];
extern const char jtagmkII_pdi_desc[]; extern const char jtagmkII_pdi_desc[];
extern const char jtagmkII_updi_desc[];
extern const char jtagmkII_dragon_desc[]; extern const char jtagmkII_dragon_desc[];
extern const char jtagmkII_dragon_dw_desc[]; extern const char jtagmkII_dragon_dw_desc[];
extern const char jtagmkII_dragon_pdi_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_avr32_initpgm (PROGRAMMER * pgm);
void jtagmkII_dw_initpgm (PROGRAMMER * pgm); void jtagmkII_dw_initpgm (PROGRAMMER * pgm);
void jtagmkII_pdi_initpgm (PROGRAMMER * pgm); void jtagmkII_pdi_initpgm (PROGRAMMER * pgm);
void jtagmkII_updi_initpgm (PROGRAMMER * pgm);
void jtagmkII_dragon_initpgm (PROGRAMMER * pgm); void jtagmkII_dragon_initpgm (PROGRAMMER * pgm);
void jtagmkII_dragon_dw_initpgm (PROGRAMMER * pgm); void jtagmkII_dragon_dw_initpgm (PROGRAMMER * pgm);
void jtagmkII_dragon_pdi_initpgm (PROGRAMMER * pgm); void jtagmkII_dragon_pdi_initpgm (PROGRAMMER * pgm);

View File

@ -57,12 +57,9 @@ SIGN [+-]
%% %%
#{SIGN}*{DIGIT}+ { yylval = number(yytext); return TKN_NUMBER; } {SIGN}?{DIGIT}+ { yylval = number(yytext); return TKN_NUMBER; }
#{SIGN}*{DIGIT}+"."{DIGIT}* { yylval = number_real(yytext); return TKN_NUMBER_REAL; } {SIGN}?{DIGIT}+"."{DIGIT}* { yylval = number_real(yytext); return TKN_NUMBER_REAL; }
#{SIGN}*"."{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; }
"\"" { string_buf_ptr = string_buf; BEGIN(strng); } "\"" { string_buf_ptr = string_buf; BEGIN(strng); }
@ -179,6 +176,7 @@ miso { yylval=NULL; return K_MISO; }
mode { yylval=NULL; return K_MODE; } mode { yylval=NULL; return K_MODE; }
mosi { yylval=NULL; return K_MOSI; } mosi { yylval=NULL; return K_MOSI; }
no { yylval=new_token(K_NO); return K_NO; } no { yylval=new_token(K_NO); return K_NO; }
NULL { yylval=NULL; return K_NULL; }
num_banks { yylval=NULL; return K_NUM_PAGES; } num_banks { yylval=NULL; return K_NUM_PAGES; }
num_pages { yylval=NULL; return K_NUM_PAGES; } num_pages { yylval=NULL; return K_NUM_PAGES; }
nvm_base { yylval=NULL; return K_NVM_BASE; } nvm_base { yylval=NULL; return K_NVM_BASE; }
@ -213,6 +211,7 @@ rdyled { yylval=NULL; return K_RDYLED; }
read { yylval=new_token(K_READ); return K_READ; } read { yylval=new_token(K_READ); return K_READ; }
read_hi { yylval=new_token(K_READ_HI); return K_READ_HI; } read_hi { yylval=new_token(K_READ_HI); return K_READ_HI; }
read_lo { yylval=new_token(K_READ_LO); return K_READ_LO; } 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_p1 { yylval=NULL; return K_READBACK_P1; }
readback_p2 { yylval=NULL; return K_READBACK_P2; } readback_p2 { yylval=NULL; return K_READBACK_P2; }
readsize { yylval=NULL; return K_READSIZE; } readsize { yylval=NULL; return K_READSIZE; }

View File

@ -183,6 +183,7 @@ typedef struct opcode {
} 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_SERIALOK 0x0001 /* part supports serial programming */
#define AVRPART_PARALLELOK 0x0002 /* part supports parallel programming */ #define AVRPART_PARALLELOK 0x0002 /* part supports parallel programming */
#define AVRPART_PSEUDOPARALLEL 0x0004 /* part has pseudo parallel support */ #define AVRPART_PSEUDOPARALLEL 0x0004 /* part has pseudo parallel support */
@ -212,9 +213,11 @@ typedef struct opcode {
#define TAG_ALLOCATED 1 /* memory byte is allocated */ #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 { typedef struct avrpart {
char desc[AVR_DESCLEN]; /* long part name */ char desc[AVR_DESCLEN]; /* long part name */
char id[AVR_IDLEN]; /* short 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) */ 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 hvupdi_variant; /* HV pulse on UPDI pin, no pin or RESET pin */
int stk500_devcode; /* stk500 device code */ int stk500_devcode; /* stk500 device code */
@ -317,14 +320,22 @@ typedef struct avrmem_alias {
extern "C" { extern "C" {
#endif #endif
int intlog2(unsigned int n);
/* Functions for OPCODE structures */ /* Functions for OPCODE structures */
OPCODE * avr_new_opcode(void); OPCODE * avr_new_opcode(void);
void avr_free_opcode(OPCODE * op); void avr_free_opcode(OPCODE * op);
int avr_set_bits(OPCODE * op, unsigned char * cmd); 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(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_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(OPCODE * op, unsigned char * res, unsigned char * data);
int avr_get_output_index(OPCODE * op); 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 */ /* Functions for AVRMEM structures */
AVRMEM * avr_new_memtype(void); AVRMEM * avr_new_memtype(void);
@ -333,9 +344,9 @@ int avr_initmem(AVRPART * p);
AVRMEM * avr_dup_mem(AVRMEM * m); AVRMEM * avr_dup_mem(AVRMEM * m);
void avr_free_mem(AVRMEM * m); void avr_free_mem(AVRMEM * m);
void avr_free_memalias(AVRMEM_ALIAS * m); void avr_free_memalias(AVRMEM_ALIAS * m);
AVRMEM * avr_locate_mem(AVRPART * p, char * desc); AVRMEM * avr_locate_mem(AVRPART * p, const char * desc);
AVRMEM * avr_locate_mem_noalias(AVRPART * p, char * desc); AVRMEM * avr_locate_mem_noalias(AVRPART * p, const char * desc);
AVRMEM_ALIAS * avr_locate_memalias(AVRPART * p, char * desc); AVRMEM_ALIAS * avr_locate_memalias(AVRPART * p, const char * desc);
AVRMEM_ALIAS * avr_find_memalias(AVRPART * p, AVRMEM * m_orig); AVRMEM_ALIAS * avr_find_memalias(AVRPART * p, AVRMEM * m_orig);
void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, AVRPART * p, void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, AVRPART * p,
int type, int verbose); int type, int verbose);
@ -344,7 +355,7 @@ void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, AVRPART * p,
AVRPART * avr_new_part(void); AVRPART * avr_new_part(void);
AVRPART * avr_dup_part(AVRPART * d); AVRPART * avr_dup_part(AVRPART * d);
void avr_free_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_avr910_devcode(LISTID parts, int devcode);
AVRPART * locate_part_by_signature(LISTID parts, unsigned char * sig, AVRPART * locate_part_by_signature(LISTID parts, unsigned char * sig,
int sigsize); int sigsize);
@ -356,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 walk_avrparts(LISTID avrparts, walk_avrparts_cb cb, void *cookie);
void sort_avrparts(LISTID avrparts); 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); int compare_memory_masked(AVRMEM * m, uint8_t buf1, uint8_t buf2);
#ifdef __cplusplus #ifdef __cplusplus
@ -659,6 +672,7 @@ typedef struct programmer_t {
char desc[PGM_DESCLEN]; char desc[PGM_DESCLEN];
char type[PGM_TYPELEN]; char type[PGM_TYPELEN];
char port[PGM_PORTLEN]; char port[PGM_PORTLEN];
char *parent_id;
void (*initpgm)(struct programmer_t * pgm); void (*initpgm)(struct programmer_t * pgm);
unsigned int pinno[N_PINS]; unsigned int pinno[N_PINS];
struct pindef_t pin[N_PINS]; struct pindef_t pin[N_PINS];
@ -769,6 +783,7 @@ void sort_programmers(LISTID programmers);
typedef void (*FP_UpdateProgress)(int percent, double etime, char *hdr); typedef void (*FP_UpdateProgress)(int percent, double etime, char *hdr);
extern struct avrpart parts[]; extern struct avrpart parts[];
extern const char *avr_mem_order[100];
extern FP_UpdateProgress update_progress; extern FP_UpdateProgress update_progress;
@ -804,6 +819,11 @@ int avr_get_cycle_count(PROGRAMMER * pgm, AVRPART * p, int * cycles);
int avr_put_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_mem_is_known(const char *str);
int avr_mem_might_be_known(const char *str);
#define disable_trailing_ff_removal() avr_mem_hiaddr(NULL) #define disable_trailing_ff_removal() avr_mem_hiaddr(NULL)
int avr_mem_hiaddr(AVRMEM * mem); int avr_mem_hiaddr(AVRMEM * mem);
@ -829,7 +849,8 @@ typedef enum {
FMT_DEC, FMT_DEC,
FMT_OCT, FMT_OCT,
FMT_BIN, FMT_BIN,
FMT_ELF FMT_ELF,
FMT_IHXC,
} FILEFMT; } FILEFMT;
struct fioparms { struct fioparms {
@ -873,6 +894,7 @@ enum updateflags {
UF_NONE = 0, UF_NONE = 0,
UF_NOWRITE = 1, UF_NOWRITE = 1,
UF_AUTO_ERASE = 2, UF_AUTO_ERASE = 2,
UF_VERIFY = 4,
}; };
@ -883,6 +905,17 @@ typedef struct update_t {
int format; int format;
} UPDATE; } 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 #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -895,6 +928,14 @@ extern void free_update(UPDATE * upd);
extern int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, extern int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd,
enum updateflags flags); 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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -50,7 +50,7 @@
#include "libavrdude.h" #include "libavrdude.h"
#include "term.h" #include "term.h"
#include "developer_opts.h"
/* Get VERSION from ac_cfg.h */ /* Get VERSION from ac_cfg.h */
char * version = VERSION; char * version = VERSION;
@ -237,7 +237,7 @@ static void cleanup_main(void)
static void replace_backslashes(char *s) static void replace_backslashes(char *s)
{ {
// Replace all backslashes with forward slashes // 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] == '\\') { if (s[i] == '\\') {
s[i] = '/'; s[i] = '/';
} }
@ -267,7 +267,6 @@ int main(int argc, char * argv [])
int calibrate; /* 1=calibrate RC oscillator, 0=don't */ int calibrate; /* 1=calibrate RC oscillator, 0=don't */
char * port; /* device port (/dev/xxx) */ char * port; /* device port (/dev/xxx) */
int terminal; /* 1=enter terminal mode, 0=don't */ int terminal; /* 1=enter terminal mode, 0=don't */
int verify; /* perform a verify operation */
char * exitspecs; /* exit specs string from command line */ char * exitspecs; /* exit specs string from command line */
char * programmer; /* programmer id */ char * programmer; /* programmer id */
char * partdesc; /* part id */ char * partdesc; /* part id */
@ -284,7 +283,7 @@ int main(int argc, char * argv [])
int init_ok; /* Device initialization worked well */ int init_ok; /* Device initialization worked well */
int is_open; /* Device open succeeded */ int is_open; /* Device open succeeded */
char * logfile; /* Use logfile rather than stderr for diagnostics */ 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) #if !defined(WIN32)
char * homedir; char * homedir;
@ -349,7 +348,6 @@ int main(int argc, char * argv [])
p = NULL; p = NULL;
ovsigck = 0; ovsigck = 0;
terminal = 0; terminal = 0;
verify = 1; /* on by default */
quell_progress = 0; quell_progress = 0;
exitspecs = NULL; exitspecs = NULL;
pgm = NULL; pgm = NULL;
@ -511,6 +509,7 @@ int main(int argc, char * argv [])
terminal = 1; terminal = 1;
break; break;
case 's':
case 'u': case 'u':
avrdude_message(MSG_INFO, "%s: \"safemode\" feature no longer supported\n", avrdude_message(MSG_INFO, "%s: \"safemode\" feature no longer supported\n",
progname); progname);
@ -524,12 +523,6 @@ int main(int argc, char * argv [])
exit(1); exit(1);
} }
ladd(updates, upd); ladd(updates, upd);
if (verify && upd->op == DEVICE_WRITE) {
upd = dup_update(upd);
upd->op = DEVICE_VERIFY;
ladd(updates, upd);
}
break; break;
case 'v': case 'v':
@ -537,7 +530,7 @@ int main(int argc, char * argv [])
break; break;
case 'V': case 'V':
verify = 0; uflags &= ~UF_VERIFY;
break; break;
case 'x': case 'x':
@ -758,8 +751,15 @@ int main(int argc, char * argv [])
bitclock = default_bitclock; bitclock = default_bitclock;
} }
avrdude_message(MSG_NOTICE, "\n"); avrdude_message(MSG_NOTICE, "\n");
// developer option -p <wildcard>/[*codws] prints various aspects of part descriptions and exits
if(partdesc && (strcmp(partdesc, "*") == 0 || strchr(partdesc, '/'))) {
dev_output_part_defs(partdesc);
exit(1);
}
if (partdesc) { if (partdesc) {
if (strcmp(partdesc, "?") == 0) { if (strcmp(partdesc, "?") == 0) {
avrdude_message(MSG_INFO, "\n"); avrdude_message(MSG_INFO, "\n");
@ -919,6 +919,12 @@ int main(int argc, char * argv [])
exit(1); 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
} }
/* /*
@ -1244,7 +1250,7 @@ int main(int argc, char * argv [])
for (ln=lfirst(updates); ln; ln=lnext(ln)) { for (ln=lfirst(updates); ln; ln=lnext(ln)) {
upd = ldata(ln); upd = ldata(ln);
rc = do_op(pgm, p, upd, uflags); rc = do_op(pgm, p, upd, uflags);
if (rc) { if (rc && rc != LIBAVRDUDE_SOFTFAIL) {
exitrc = 1; exitrc = 1;
break; break;
} }

View File

@ -79,6 +79,7 @@ PROGRAMMER * pgm_new(void)
pgm->usbpid = lcreat(NULL, 0); pgm->usbpid = lcreat(NULL, 0);
pgm->desc[0] = 0; pgm->desc[0] = 0;
pgm->type[0] = 0; pgm->type[0] = 0;
pgm->parent_id = NULL;
pgm->config_file = NULL; pgm->config_file = NULL;
pgm->lineno = 0; pgm->lineno = 0;
pgm->baudrate = 0; pgm->baudrate = 0;
@ -145,11 +146,8 @@ void pgm_free(PROGRAMMER * const p)
ldestroy_cb(p->usbpid, free); ldestroy_cb(p->usbpid, free);
p->id = NULL; p->id = NULL;
p->usbpid = NULL; p->usbpid = NULL;
/* this is done by pgm_teardown, but usually cookie is not set to NULL */ /* do not free p->parent_id nor p->config_file */
/* if (p->cookie !=NULL) { /* p->cookie is freed by pgm_teardown */
free(p->cookie);
p->cookie = NULL;
}*/
free(p); free(p);
} }
@ -169,7 +167,6 @@ PROGRAMMER * pgm_dup(const PROGRAMMER * const src)
pgm->id = lcreat(NULL, 0); pgm->id = lcreat(NULL, 0);
pgm->usbpid = lcreat(NULL, 0); pgm->usbpid = lcreat(NULL, 0);
for (ln = lfirst(src->usbpid); ln; ln = lnext(ln)) { for (ln = lfirst(src->usbpid); ln; ln = lnext(ln)) {
int *ip = malloc(sizeof(int)); int *ip = malloc(sizeof(int));
if (ip == NULL) { if (ip == NULL) {

View File

@ -80,6 +80,7 @@ const PROGRAMMER_TYPE programmers_types[] = {
{"jtagmkii_dw", jtagmkII_dw_initpgm, jtagmkII_dw_desc}, {"jtagmkii_dw", jtagmkII_dw_initpgm, jtagmkII_dw_desc},
{"jtagmkii_isp", stk500v2_jtagmkII_initpgm, stk500v2_jtagmkII_desc}, {"jtagmkii_isp", stk500v2_jtagmkII_initpgm, stk500v2_jtagmkII_desc},
{"jtagmkii_pdi", jtagmkII_pdi_initpgm, jtagmkII_pdi_desc}, {"jtagmkii_pdi", jtagmkII_pdi_initpgm, jtagmkII_pdi_desc},
{"jtagmkii_updi", jtagmkII_updi_initpgm, jtagmkII_updi_desc},
{"jtagice3", jtag3_initpgm, jtag3_desc}, {"jtagice3", jtag3_initpgm, jtag3_desc},
{"jtagice3_pdi", jtag3_pdi_initpgm, jtag3_pdi_desc}, {"jtagice3_pdi", jtag3_pdi_initpgm, jtag3_pdi_desc},
{"jtagice3_updi", jtag3_updi_initpgm, jtag3_updi_desc}, {"jtagice3_updi", jtag3_updi_initpgm, jtag3_updi_desc},

View File

@ -91,8 +91,6 @@ int stk500_getsync(PROGRAMMER * pgm)
int attempt; int attempt;
int max_sync_attempts; int max_sync_attempts;
/*
* get in sync */
buf[0] = Cmnd_STK_GET_SYNC; buf[0] = Cmnd_STK_GET_SYNC;
buf[1] = Sync_CRC_EOP; buf[1] = Sync_CRC_EOP;
@ -119,11 +117,12 @@ int stk500_getsync(PROGRAMMER * pgm)
usleep(50*1000); usleep(50*1000);
stk500_drain(pgm, 0); stk500_drain(pgm, 0);
} }
stk500_send(pgm, buf, 2); stk500_send(pgm, buf, 2);
stk500_recv(pgm, resp, 1); resp[0] = 0;
if (resp[0] == Resp_STK_INSYNC){ if(stk500_recv(pgm, resp, 1) >= 0 && resp[0] == Resp_STK_INSYNC)
break; break;
}
avrdude_message(MSG_INFO, "%s: stk500_getsync() attempt %d of %d: not in sync: resp=0x%02x\n", 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]); progname, attempt + 1, max_sync_attempts, resp[0]);
} }
@ -204,15 +203,14 @@ static int stk500_chip_erase(PROGRAMMER * pgm, AVRPART * p)
} }
if (p->op[AVR_OP_CHIP_ERASE] == NULL) { if (p->op[AVR_OP_CHIP_ERASE] == NULL) {
avrdude_message(MSG_INFO, "chip erase instruction not defined for part \"%s\"\n", avrdude_message(MSG_INFO, "%s: chip erase instruction not defined for part \"%s\"\n",
p->desc); progname, p->desc);
return -1; return -1;
} }
pgm->pgm_led(pgm, ON); pgm->pgm_led(pgm, ON);
memset(cmd, 0, sizeof(cmd)); memset(cmd, 0, sizeof(cmd));
avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd); avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd);
pgm->cmd(pgm, cmd, res); pgm->cmd(pgm, cmd, res);
usleep(p->chip_erase_delay); usleep(p->chip_erase_delay);
@ -745,8 +743,8 @@ static int stk500_loadaddr(PROGRAMMER * pgm, AVRMEM * mem, unsigned int addr)
if (lext != NULL) { if (lext != NULL) {
ext_byte = (addr >> 16) & 0xff; ext_byte = (addr >> 16) & 0xff;
if (ext_byte != PDATA(pgm)->ext_addr_byte) { if (ext_byte != PDATA(pgm)->ext_addr_byte) {
/* Either this is the first addr load, or a 64K word boundary is /* Either this is the first addr load, or a different 64K word section */
* crossed, so set the ext addr byte */ memset(buf, 0, 4);
avr_set_bits(lext, buf); avr_set_bits(lext, buf);
avr_set_addr(lext, buf, addr); avr_set_addr(lext, buf, addr);
stk500_cmd(pgm, buf, buf); stk500_cmd(pgm, buf, buf);
@ -782,13 +780,12 @@ static int stk500_loadaddr(PROGRAMMER * pgm, AVRMEM * mem, unsigned int addr)
if (stk500_recv(pgm, buf, 1) < 0) if (stk500_recv(pgm, buf, 1) < 0)
return -1; return -1;
if (buf[0] == Resp_STK_OK) { if (buf[0] == Resp_STK_OK)
return 0; 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", "expect=0x%02x, resp=0x%02x\n",
progname, Resp_STK_INSYNC, buf[0]); progname, Resp_STK_OK, buf[0]);
return -1; return -1;
} }
@ -808,19 +805,20 @@ static int stk500_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
if (strcmp(m->desc, "flash") == 0) { if (strcmp(m->desc, "flash") == 0) {
memtype = 'F'; memtype = 'F';
} a_div = 2;
else if (strcmp(m->desc, "eeprom") == 0) { } else if (strcmp(m->desc, "eeprom") == 0) {
memtype = 'E'; 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; 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; n = addr + n_bytes;
#if 0 #if 0
avrdude_message(MSG_INFO, "n_bytes = %d\n" avrdude_message(MSG_INFO, "n_bytes = %d\n"
@ -879,9 +877,9 @@ static int stk500_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
if (stk500_recv(pgm, buf, 1) < 0) if (stk500_recv(pgm, buf, 1) < 0)
return -1; return -1;
if (buf[0] != Resp_STK_OK) { 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", "expect=0x%02x, resp=0x%02x\n",
progname, Resp_STK_INSYNC, buf[0]); progname, Resp_STK_OK, buf[0]);
return -5; return -5;
} }
} }
@ -902,19 +900,20 @@ static int stk500_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
if (strcmp(m->desc, "flash") == 0) { if (strcmp(m->desc, "flash") == 0) {
memtype = 'F'; memtype = 'F';
} a_div = 2;
else if (strcmp(m->desc, "eeprom") == 0) { } else if (strcmp(m->desc, "eeprom") == 0) {
memtype = 'E'; 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; 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; n = addr + n_bytes;
for (; addr < n; addr += block_size) { for (; addr < n; addr += block_size) {
// MIB510 uses fixed blocks size of 256 bytes // MIB510 uses fixed blocks size of 256 bytes
@ -973,7 +972,7 @@ static int stk500_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
} }
else { else {
if (buf[0] != Resp_STK_OK) { 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", "expect=0x%02x, resp=0x%02x\n",
progname, Resp_STK_OK, buf[0]); progname, Resp_STK_OK, buf[0]);
return -5; return -5;
@ -1037,7 +1036,8 @@ static int stk500_set_fosc(PROGRAMMER * pgm, double v)
static unsigned ps[] = { static unsigned ps[] = {
1, 8, 32, 64, 128, 256, 1024 1, 8, 32, 64, 128, 256, 1024
}; };
int idx, rc; size_t idx;
int rc;
prescale = cmatch = 0; prescale = cmatch = 0;
if (v > 0.0) { if (v > 0.0) {
@ -1155,7 +1155,7 @@ static int stk500_getparm(PROGRAMMER * pgm, unsigned parm, unsigned * value)
return -3; return -3;
} }
else if (buf[0] != Resp_STK_OK) { 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", "expect=0x%02x, resp=0x%02x\n",
progname, Resp_STK_OK, buf[0]); progname, Resp_STK_OK, buf[0]);
return -3; return -3;
@ -1214,9 +1214,9 @@ static int stk500_setparm(PROGRAMMER * pgm, unsigned parm, unsigned value)
return -3; return -3;
} }
else { 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", "expect=0x%02x, resp=0x%02x\n",
progname, Resp_STK_INSYNC, buf[0]); progname, Resp_STK_OK, buf[0]);
return -3; return -3;
} }
} }

View File

@ -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) static unsigned short get_jtagisp_return_size(unsigned char cmd)
{ {
int i; for (size_t i = 0; i < sizeof jtagispcmds / sizeof jtagispcmds[0]; i++)
for (i = 0; i < sizeof jtagispcmds / sizeof jtagispcmds[0]; i++)
if (jtagispcmds[i].cmd == cmd) if (jtagispcmds[i].cmd == cmd)
return jtagispcmds[i].size; 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) 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 unsigned char buf[275 + 6]; // max MESSAGE_BODY of 275 bytes, 6 bytes overhead
int i;
if (PDATA(pgm)->pgmtype == PGMTYPE_AVRISP_MKII || if (PDATA(pgm)->pgmtype == PGMTYPE_AVRISP_MKII ||
PDATA(pgm)->pgmtype == PGMTYPE_STK600) 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 // calculate the XOR checksum
buf[5+len] = 0; 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]; buf[5+len] ^= buf[i];
DEBUG("STK500V2: stk500v2_send("); DEBUG("STK500V2: stk500v2_send(");
for (i=0;i<len+6;i++) DEBUG("0x%02x ",buf[i]); for (size_t i=0; i<len+6; i++)
DEBUG(", %d)\n",len+6); DEBUG("0x%02x ", buf[i]);
DEBUG(", %d)\n", (int) len+6);
if (serial_send(&pgm->fd, buf, len+6) != 0) { if (serial_send(&pgm->fd, buf, len+6) != 0) {
avrdude_message(MSG_INFO, "%s: stk500_send(): failed to send command to serial port\n",progname); 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); progname);
return -1; 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", 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; rv = maxsize;
} }
switch (jtagmsg[0]) { 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 implementation of JTAGICE3, as they always request a full 512
octets from the ICE. Thus, only complain at high verbose octets from the ICE. Thus, only complain at high verbose
levels. */ 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", 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; rv = maxsize;
} }
if (jtagmsg[0] != SCOPE_AVR_ISP) { if (jtagmsg[0] != SCOPE_AVR_ISP) {
@ -814,13 +812,13 @@ retry:
static int stk500v2_command(PROGRAMMER * pgm, unsigned char * buf, static int stk500v2_command(PROGRAMMER * pgm, unsigned char * buf,
size_t len, size_t maxlen) { size_t len, size_t maxlen) {
int i;
int tries = 0; int tries = 0;
int status; int status;
DEBUG("STK500V2: stk500v2_command("); DEBUG("STK500V2: stk500v2_command(");
for (i=0;i<len;i++) DEBUG("0x%02x ",buf[i]); for (size_t i=0; i<len; i++)
DEBUG(", %d)\n",len); DEBUG("0x%02x ",buf[i]);
DEBUG(", %d)\n", (int) len);
retry: retry:
tries++; tries++;
@ -991,6 +989,7 @@ static int stk500v2_chip_erase(PROGRAMMER * pgm, AVRPART * p)
buf[0] = CMD_CHIP_ERASE_ISP; buf[0] = CMD_CHIP_ERASE_ISP;
buf[1] = p->chip_erase_delay / 1000; buf[1] = p->chip_erase_delay / 1000;
buf[2] = 0; // use delay (?) buf[2] = 0; // use delay (?)
memset(buf+3, 0, 4);
avr_set_bits(p->op[AVR_OP_CHIP_ERASE], buf+3); avr_set_bits(p->op[AVR_OP_CHIP_ERASE], buf+3);
result = stk500v2_command(pgm, buf, 7, sizeof(buf)); result = stk500v2_command(pgm, buf, 7, sizeof(buf));
usleep(p->chip_erase_delay); usleep(p->chip_erase_delay);
@ -1121,8 +1120,8 @@ retry:
buf[5] = p->bytedelay; buf[5] = p->bytedelay;
buf[6] = p->pollvalue; buf[6] = p->pollvalue;
buf[7] = p->pollindex; buf[7] = p->pollindex;
memset(buf+8, 0, 4);
avr_set_bits(p->op[AVR_OP_PGM_ENABLE], buf+8); avr_set_bits(p->op[AVR_OP_PGM_ENABLE], buf+8);
buf[10] = buf[11] = 0;
rv = stk500v2_command(pgm, buf, 12, sizeof(buf)); rv = stk500v2_command(pgm, buf, 12, sizeof(buf));
@ -1957,12 +1956,12 @@ static int stk500isp_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
buf[0] = CMD_READ_SIGNATURE_ISP; buf[0] = CMD_READ_SIGNATURE_ISP;
} }
memset(buf + 1, 0, 5);
if ((op = mem->op[AVR_OP_READ]) == NULL) { 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", avrdude_message(MSG_INFO, "%s: stk500isp_read_byte(): invalid operation AVR_OP_READ on %s memory\n",
progname, mem->desc); progname, mem->desc);
return -1; return -1;
} }
memset(buf+2, 0, 4);
avr_set_bits(op, buf + 2); avr_set_bits(op, buf + 2);
if ((pollidx = avr_get_output_index(op)) == -1) { if ((pollidx = avr_get_output_index(op)) == -1) {
avrdude_message(MSG_INFO, "%s: stk500isp_read_byte(): cannot determine pollidx to read %s memory\n", avrdude_message(MSG_INFO, "%s: stk500isp_read_byte(): cannot determine pollidx to read %s memory\n",
@ -2314,6 +2313,7 @@ static int stk500v2_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
progname, p->desc); progname, p->desc);
return -1; return -1;
} }
memset(cmds, 0, sizeof cmds);
avr_set_bits(m->op[AVR_OP_LOADPAGE_LO], cmds); avr_set_bits(m->op[AVR_OP_LOADPAGE_LO], cmds);
commandbuf[5] = cmds[0]; commandbuf[5] = cmds[0];
@ -2322,6 +2322,8 @@ static int stk500v2_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
progname, p->desc); progname, p->desc);
return -1; return -1;
} }
memset(cmds, 0, sizeof cmds);
avr_set_bits(m->op[AVR_OP_WRITEPAGE], cmds); avr_set_bits(m->op[AVR_OP_WRITEPAGE], cmds);
commandbuf[6] = cmds[0]; commandbuf[6] = cmds[0];
@ -2335,6 +2337,7 @@ static int stk500v2_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
progname, p->desc); progname, p->desc);
return -1; return -1;
} }
memset(cmds, 0, sizeof cmds);
avr_set_bits(wop, cmds); avr_set_bits(wop, cmds);
commandbuf[5] = cmds[0]; commandbuf[5] = cmds[0];
commandbuf[6] = 0; commandbuf[6] = 0;
@ -2346,6 +2349,7 @@ static int stk500v2_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
progname, p->desc); progname, p->desc);
return -1; return -1;
} }
memset(cmds, 0, sizeof cmds);
avr_set_bits(rop, cmds); avr_set_bits(rop, cmds);
commandbuf[7] = cmds[0]; commandbuf[7] = cmds[0];
@ -2549,6 +2553,7 @@ static int stk500v2_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
progname, p->desc); progname, p->desc);
return -1; return -1;
} }
memset(cmds, 0, sizeof cmds);
avr_set_bits(rop, cmds); avr_set_bits(rop, cmds);
commandbuf[3] = cmds[0]; commandbuf[3] = cmds[0];
@ -2753,7 +2758,8 @@ static int stk500v2_set_fosc(PROGRAMMER * pgm, double v)
static unsigned ps[] = { static unsigned ps[] = {
1, 8, 32, 64, 128, 256, 1024 1, 8, 32, 64, 128, 256, 1024
}; };
int idx, rc; size_t idx;
int rc;
prescale = cmatch = 0; prescale = cmatch = 0;
if (v > 0.0) { if (v > 0.0) {
@ -2774,7 +2780,7 @@ static int stk500v2_set_fosc(PROGRAMMER * pgm, double v)
fosc = (unsigned)v; fosc = (unsigned)v;
for (idx = 0; idx < sizeof(ps) / sizeof(ps[0]); idx++) { 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 */ /* this prescaler value can handle our frequency */
prescale = idx + 1; prescale = idx + 1;
cmatch = (unsigned)(STK500V2_XTAL / (2 * fosc * ps[idx])) - 1; cmatch = (unsigned)(STK500V2_XTAL / (2 * fosc * ps[idx])) - 1;
@ -2821,7 +2827,7 @@ static double avrispmkIIfreqs[] = {
static int stk500v2_set_sck_period_mk2(PROGRAMMER * pgm, double v) 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++) { for (i = 0; i < sizeof(avrispmkIIfreqs) / sizeof(avrispmkIIfreqs[0]); i++) {
if (1 / avrispmkIIfreqs[i] >= v) if (1 / avrispmkIIfreqs[i] >= v)

View File

@ -45,7 +45,7 @@ UPDATE * parse_op(char * s)
i = 0; i = 0;
p = s; p = s;
while ((i < (sizeof(buf)-1) && *p && (*p != ':'))) while (i < (int) sizeof(buf)-1 && *p && *p != ':')
buf[i++] = *p++; buf[i++] = *p++;
buf[i] = 0; buf[i] = 0;
@ -130,6 +130,7 @@ UPDATE * parse_op(char * s)
case 'a': upd->format = FMT_AUTO; break; case 'a': upd->format = FMT_AUTO; break;
case 's': upd->format = FMT_SREC; break; case 's': upd->format = FMT_SREC; break;
case 'i': upd->format = FMT_IHEX; break; case 'i': upd->format = FMT_IHEX; break;
case 'I': upd->format = FMT_IHXC; break;
case 'r': upd->format = FMT_RBIN; break; case 'r': upd->format = FMT_RBIN; break;
case 'e': upd->format = FMT_ELF; break; case 'e': upd->format = FMT_ELF; break;
case 'm': upd->format = FMT_IMM; break; case 'm': upd->format = FMT_IMM; break;
@ -213,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: "<stdin>";
}
const char *outname(const char *fn) {
return !fn? "???": strcmp(fn, "-")? fn: "<stdout>";
}
// 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) int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags flags)
{ {
struct avrpart * v; struct avrpart * v;
AVRMEM * mem; AVRMEM * mem;
int size, vsize; int size;
int rc; int rc;
Filestats fs;
mem = avr_locate_mem(p, upd->memtype); mem = avr_locate_mem(p, upd->memtype);
if (mem == NULL) { if (mem == NULL) {
avrdude_message(MSG_INFO, "\"%s\" memory type not defined for part \"%s\"\n", avrdude_message(MSG_INFO, "%s: skipping -U %s:... as memory not defined for part %s\n",
upd->memtype, p->desc); progname, upd->memtype, p->desc);
return -1; return LIBAVRDUDE_SOFTFAIL;
} }
AVRMEM_ALIAS * alias_mem = avr_find_memalias(p, mem); AVRMEM_ALIAS * alias_mem = avr_find_memalias(p, mem);
@ -234,161 +341,190 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f
strcat(alias_mem_desc, alias_mem->desc); strcat(alias_mem_desc, alias_mem->desc);
} }
if (upd->op == DEVICE_READ) { switch (upd->op) {
/* case DEVICE_READ:
* read out the specified device memory and write it to a file // Read out the specified device memory and write it to a file
*/ if (upd->format == FMT_IMM) {
if (quell_progress < 2) { avrdude_message(MSG_INFO,
avrdude_message(MSG_INFO, "%s: reading %s%s memory:\n", "%s: Invalid file format 'immediate' for output\n", progname);
progname, mem->desc, alias_mem_desc); return LIBAVRDUDE_GENERAL_FAILURE;
} }
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); rc = avr_read(pgm, p, upd->memtype, 0);
report_progress(1, 1, NULL);
if (rc < 0) { if (rc < 0) {
avrdude_message(MSG_INFO, "%s: failed to read all of %s%s memory, rc=%d\n", 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);
return -1; return LIBAVRDUDE_GENERAL_FAILURE;
} }
report_progress(1,1,NULL);
size = rc; size = rc;
if (quell_progress < 2) { if (quell_progress < 2) {
if (rc == 0) if (rc == 0)
avrdude_message(MSG_INFO, "%s: Flash is empty, resulting file has no contents.\n", avrdude_message(MSG_INFO, "%s: flash is empty, resulting file has no contents\n",
progname); progname);
avrdude_message(MSG_INFO, "%s: writing output file \"%s\"\n", avrdude_message(MSG_INFO, "%s: writing output file %s\n",
progname, progname, outname(upd->filename));
strcmp(upd->filename, "-")==0 ? "<stdout>" : upd->filename);
} }
rc = fileio(FIO_WRITE, upd->filename, upd->format, p, upd->memtype, size); rc = fileio(FIO_WRITE, upd->filename, upd->format, p, upd->memtype, size);
if (rc < 0) { if (rc < 0) {
avrdude_message(MSG_INFO, "%s: write to file '%s' failed\n", avrdude_message(MSG_INFO, "%s: write to file %s failed\n",
progname, upd->filename); progname, outname(upd->filename));
return -1; return LIBAVRDUDE_GENERAL_FAILURE;
}
}
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 ? "<stdin>" : upd->filename);
} }
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); 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) { if (rc < 0) {
avrdude_message(MSG_INFO, "%s: read from file '%s' failed\n", avrdude_message(MSG_INFO, "%s: read from file %s failed\n",
progname, upd->filename); progname, inname(upd->filename));
return -1; return LIBAVRDUDE_GENERAL_FAILURE;
} }
size = rc; size = rc;
/* if(memstats(p, upd->memtype, size, &fs) < 0)
* write the buffer contents to the selected memory type return LIBAVRDUDE_GENERAL_FAILURE;
*/
if (quell_progress < 2) { if(quell_progress < 2) {
avrdude_message(MSG_INFO, "%s: writing %s%s (%d bytes):\n", int level = fs.nsections > 1 || fs.firstaddr > 0 || fs.ntrailing? MSG_INFO: MSG_NOTICE;
progname, mem->desc, alias_mem_desc, size);
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)) { 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); rc = avr_write(pgm, p, upd->memtype, size, (flags & UF_AUTO_ERASE) != 0);
report_progress(1,1,NULL); report_progress(1, 1, NULL);
} } else {
else { // Test mode: write to stdout in intel hex rather than to the chip
/*
* test mode, don't actually write to the chip, output the buffer
* to stdout in intel hex instead
*/
rc = fileio(FIO_WRITE, "-", FMT_IHEX, p, upd->memtype, size); rc = fileio(FIO_WRITE, "-", FMT_IHEX, p, upd->memtype, size);
} }
if (rc < 0) { if (rc < 0) {
avrdude_message(MSG_INFO, "%s: failed to write %s%s memory, rc=%d\n", avrdude_message(MSG_INFO, "%s: failed to write %s%s memory, rc=%d\n",
progname, mem->desc, alias_mem_desc, rc); progname, mem->desc, alias_mem_desc, rc);
return -1; 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) { // Fall through for (default) auto verify, ie, unless -V was specified
avrdude_message(MSG_INFO, "%s: %d bytes of %s%s written\n", progname, if (!(flags & UF_VERIFY))
vsize, mem->desc, alias_mem_desc); break;
}
} case DEVICE_VERIFY:
else if (upd->op == DEVICE_VERIFY) { // Verify that the in memory file is the same as what is on the chip
/*
* verify that the in memory file (p->mem[AVR_M_FLASH|AVR_M_EEPROM])
* is the same as what is on the chip
*/
pgm->vfy_led(pgm, ON); pgm->vfy_led(pgm, ON);
if (quell_progress < 2) { int userverify = upd->op == DEVICE_VERIFY; // Explicit -U :v by user
avrdude_message(MSG_INFO, "%s: verifying %s%s memory against %s:\n",
progname, mem->desc, alias_mem_desc, upd->filename);
avrdude_message(MSG_NOTICE2, "%s: load data %s%s data from input file %s:\n", if (quell_progress < 2) {
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));
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));
} }
// 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); rc = fileio(FIO_READ_FOR_VERIFY, upd->filename, upd->format, p, upd->memtype, -1);
if (rc < 0) { if (rc < 0) {
avrdude_message(MSG_INFO, "%s: read from file '%s' failed\n", avrdude_message(MSG_INFO, "%s: read from file %s failed\n",
progname, upd->filename); progname, inname(upd->filename));
return -1; return LIBAVRDUDE_GENERAL_FAILURE;
} }
v = avr_dup_part(p);
size = rc; 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);
if (quell_progress < 2) { if (quell_progress < 2) {
avrdude_message(MSG_NOTICE2, "%s: input file %s contains %d bytes\n", if (userverify)
progname, upd->filename, size); avrdude_message(MSG_NOTICE, "%s: input file %s contains %d byte%s\n",
avrdude_message(MSG_NOTICE2, "%s: reading on-chip %s%s data:\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); progname, mem->desc, alias_mem_desc);
} }
report_progress (0,1,"Reading"); report_progress (0,1,"Reading");
rc = avr_read(pgm, p, upd->memtype, v); rc = avr_read(pgm, p, upd->memtype, v);
report_progress (1,1,NULL);
if (rc < 0) { if (rc < 0) {
avrdude_message(MSG_INFO, "%s: failed to read all of %s%s memory, rc=%d\n", 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); pgm->err_led(pgm, ON);
avr_free_part(v); 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); avrdude_message(MSG_NOTICE2, "%s: verifying ...\n", progname);
}
rc = avr_verify(p, v, upd->memtype, size); rc = avr_verify(p, v, upd->memtype, size);
if (rc < 0) { if (rc < 0) {
avrdude_message(MSG_INFO, "%s: verification error; content mismatch\n", avrdude_message(MSG_INFO, "%s: verification error; content mismatch\n",
progname); progname);
pgm->err_led(pgm, ON); pgm->err_led(pgm, ON);
avr_free_part(v); avr_free_part(v);
return -1; return LIBAVRDUDE_GENERAL_FAILURE;
} }
if (quell_progress < 2) { if (quell_progress < 2) {
avrdude_message(MSG_INFO, "%s: %d bytes of %s%s verified\n", int verified = fs.nbytes+fs.ntrailing;
progname, rc, mem->desc, alias_mem_desc); 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); pgm->vfy_led(pgm, OFF);
avr_free_part(v); avr_free_part(v);
} break;
else {
default:
avrdude_message(MSG_INFO, "%s: invalid update operation (%d) requested\n", avrdude_message(MSG_INFO, "%s: invalid update operation (%d) requested\n",
progname, upd->op); progname, upd->op);
return -1; return LIBAVRDUDE_GENERAL_FAILURE;
} }
return 0; return LIBAVRDUDE_SUCCESS;
} }