Merge branch 'main' into fix_1041
This commit is contained in:
commit
ed36c7e1f6
|
@ -21,7 +21,7 @@
|
|||
# cmake --build build
|
||||
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
project(avrdude VERSION 7.0)
|
||||
project(avrdude VERSION 7.0 LANGUAGES C)
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_C_STANDARD_REQUIRED True)
|
||||
|
|
10
NEWS
10
NEWS
|
@ -44,6 +44,16 @@ Changes since version 7.0:
|
|||
add one read mode;
|
||||
add quell command #1025
|
||||
- Fix usbtiny read for parts with more than 64 kB flash #1029
|
||||
- CMakeLists.txt: fix build without C++ #1016
|
||||
- Provide file format I: Intel HEX with comments that ignores
|
||||
checksum errors #1030
|
||||
- Enable writing fuse and lock bits for AVR-JTAGICE #1031
|
||||
- Ignore -s flag as safemode is no longer supported #1033
|
||||
- Developer options to describe parts and
|
||||
extend avrdude.conf syntax #1040
|
||||
- Deprecate original STK500 v1 protocol in favour of optiboot
|
||||
and Arduino as ISP #1046
|
||||
- Add jtagmkii_updi programmer option #1048
|
||||
|
||||
* Internals:
|
||||
|
||||
|
|
|
@ -56,6 +56,8 @@ if(WIN32)
|
|||
endif()
|
||||
|
||||
if(MSVC)
|
||||
enable_language(CXX)
|
||||
|
||||
add_compile_definitions(_CRT_SECURE_NO_WARNINGS=1)
|
||||
add_compile_definitions(_CRT_NONSTDC_NO_WARNINGS=1)
|
||||
add_compile_definitions(_WINSOCK_DEPRECATED_NO_WARNINGS=1)
|
||||
|
@ -250,6 +252,9 @@ add_executable(avrdude
|
|||
main.c
|
||||
term.c
|
||||
term.h
|
||||
developer_opts.c
|
||||
developer_opts.h
|
||||
developer_opts_private.h
|
||||
whereami.c
|
||||
whereami.h
|
||||
"${EXTRA_WINDOWS_RESOURCES}"
|
||||
|
|
|
@ -198,6 +198,9 @@ avrdude_SOURCES = \
|
|||
main.c \
|
||||
whereami.c \
|
||||
whereami.h \
|
||||
developer_opts.c \
|
||||
developer_opts.h \
|
||||
developer_opts_private.h \
|
||||
term.c \
|
||||
term.h
|
||||
|
||||
|
|
48
src/avr.c
48
src/avr.c
|
@ -1220,7 +1220,55 @@ int avr_put_cycle_count(PROGRAMMER * pgm, AVRPART * p, int cycles)
|
|||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Typical order in which memories show in avrdude.conf, runtime adds unknown ones (if any)
|
||||
const char *avr_mem_order[100] = {
|
||||
"eeprom", "flash", "application", "apptable",
|
||||
"boot", "lfuse", "hfuse", "efuse",
|
||||
"fuse", "fuse0", "wdtcfg", "fuse1",
|
||||
"bodcfg", "fuse2", "osccfg", "fuse3",
|
||||
"fuse4", "tcd0cfg", "fuse5", "syscfg0",
|
||||
"fuse6", "syscfg1", "fuse7", "append",
|
||||
"codesize", "fuse8", "fuse9", "bootend",
|
||||
"bootsize", "fuses", "lock", "lockbits",
|
||||
"tempsense", "signature", "prodsig", "sernum",
|
||||
"calibration", "osccal16", "osccal20", "osc16err",
|
||||
"osc20err", "usersig", "userrow", "data",
|
||||
};
|
||||
|
||||
void avr_add_mem_order(const char *str) {
|
||||
for(size_t i=0; i < sizeof avr_mem_order/sizeof *avr_mem_order; i++) {
|
||||
if(avr_mem_order[i] && !strcmp(avr_mem_order[i], str))
|
||||
return;
|
||||
if(!avr_mem_order[i]) {
|
||||
avr_mem_order[i] = strdup(str);
|
||||
return;
|
||||
}
|
||||
}
|
||||
avrdude_message(MSG_INFO,
|
||||
"%s: avr_mem_order[] under-dimensioned in avr.c; increase and recompile\n",
|
||||
progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int avr_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)
|
||||
{
|
||||
|
|
|
@ -44,9 +44,7 @@
|
|||
.Op Fl O
|
||||
.Op Fl P Ar port
|
||||
.Op Fl q
|
||||
.Op Fl s
|
||||
.Op Fl t
|
||||
.Op Fl u
|
||||
.Op Fl U Ar memtype:op:filename:filefmt
|
||||
.Op Fl v
|
||||
.Op Fl x Ar extended_param
|
||||
|
@ -626,6 +624,9 @@ Posix systems (by now).
|
|||
.It Fl q
|
||||
Disable (or quell) output of the progress bar while reading or writing
|
||||
to the device. Specify it a second time for even quieter operation.
|
||||
.It Fl s, u
|
||||
These options used to control the obsolete "safemode" feature which
|
||||
is no longer present. They are silently ignored for backwards compatibility.
|
||||
.It Fl t
|
||||
Tells
|
||||
.Nm
|
||||
|
@ -709,6 +710,8 @@ can be one of:
|
|||
.Bl -tag -width sss
|
||||
.It Ar i
|
||||
Intel Hex
|
||||
.It Ar I
|
||||
Intel Hex with comments on download and tolerance of checksum errors on upload
|
||||
.It Ar s
|
||||
Motorola S-record
|
||||
.It Ar r
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#
|
||||
# DO NOT MODIFY THIS FILE. Modifications will be overwritten the next
|
||||
# time a "make install" is run. For user-specific additions, use the
|
||||
# "-C +filename" commandline option.
|
||||
# "-C +filename" command line option.
|
||||
#
|
||||
# Possible entry formats are:
|
||||
#
|
||||
|
@ -34,12 +34,12 @@
|
|||
# rdyled = <num> ; # pin number
|
||||
# pgmled = <num> ; # pin number
|
||||
# vfyled = <num> ; # pin number
|
||||
# usbvid = <hexnum>; # USB VID (Vendor ID)
|
||||
# usbpid = <hexnum> [, <hexnum> ...] # USB PID (Product ID) (1)
|
||||
# usbdev = <interface>; # USB interface or other device info
|
||||
# usbvendor = <vendorname>; # USB Vendor Name
|
||||
# usbproduct = <productname>; # USB Product Name
|
||||
# usbsn = <serialno>; # USB Serial Number
|
||||
# usbvid = <hexnum> ; # USB VID (Vendor ID)
|
||||
# usbpid = <hexnum> [, <hexnum> ...] ; # USB PID (Product ID) (1)
|
||||
# usbdev = <interface> ; # USB interface or other device info
|
||||
# usbvendor = <vendorname> ; # USB Vendor Name
|
||||
# usbproduct = <productname> ; # USB Product Name
|
||||
# usbsn = <serialno> ; # USB Serial Number
|
||||
# hvupdi_support = <num> [, <num>, ... ] ; # UPDI HV Variants Support
|
||||
#
|
||||
# To invert a bit, use = ~ <num>, the spaces are important.
|
||||
|
@ -48,32 +48,34 @@
|
|||
# specify it as follows = ~ ( <num> [, <num2> ... ] ) .
|
||||
#
|
||||
# (1) Not all programmer types can process a list of PIDs.
|
||||
# ;
|
||||
# ;
|
||||
#
|
||||
# part
|
||||
# id = <id> ; # 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_debugwire = <yes/no> ; # part has debugWire i/f
|
||||
# has_pdi = <yes/no> ; # part has PDI i/f
|
||||
# has_updi = <yes/no> ; # part has UPDI i/f
|
||||
# has_tpi = <yes/no> ; # part has TPI i/f
|
||||
# devicecode = <num> ; # deprecated, use stk500_devcode
|
||||
# stk500_devcode = <num> ; # numeric
|
||||
# avr910_devcode = <num> ; # numeric
|
||||
# is_at90s1200 = <yes/no> ; # AT90S1200 part
|
||||
# is_avr32 = <yes/no> ; # AVR32 part
|
||||
# signature = <num> <num> <num> ; # signature bytes
|
||||
# usbpid = <num> ; # DFU USB PID
|
||||
# chip_erase_delay = <num> ; # micro-seconds
|
||||
# reset = dedicated | io;
|
||||
# retry_pulse = reset | sck;
|
||||
# pgm_enable = <instruction format> ;
|
||||
# chip_erase = <instruction format> ;
|
||||
# reset = dedicated | io ;
|
||||
# retry_pulse = reset | sck ;
|
||||
# chip_erase_delay = <num> ; # chip erase delay (us)
|
||||
# # STK500 parameters (parallel programming IO lines)
|
||||
# pagel = <num> ; # pin name in hex, i.e., 0xD7
|
||||
# bs2 = <num> ; # pin name in hex, i.e., 0xA0
|
||||
# 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
|
||||
# timeout = <num> ;
|
||||
# stabdelay = <num> ;
|
||||
|
@ -85,52 +87,59 @@
|
|||
# predelay = <num> ;
|
||||
# postdelay = <num> ;
|
||||
# pollmethod = <num> ;
|
||||
# mode = <num> ;
|
||||
# delay = <num> ;
|
||||
# blocksize = <num> ;
|
||||
# readsize = <num> ;
|
||||
# hvspcmdexedelay = <num> ;
|
||||
# # STK500v2 HV programming parameters, from XML
|
||||
# pp_controlstack = <num>, <num>, ...; # PP only
|
||||
# hvsp_controlstack = <num>, <num>, ...; # HVSP only
|
||||
# hventerstabdelay = <num>;
|
||||
# progmodedelay = <num>; # PP only
|
||||
# latchcycles = <num>;
|
||||
# togglevtg = <num>;
|
||||
# poweroffdelay = <num>;
|
||||
# resetdelayms = <num>;
|
||||
# resetdelayus = <num>;
|
||||
# hvleavestabdelay = <num>;
|
||||
# resetdelay = <num>;
|
||||
# synchcycles = <num>; # HVSP only
|
||||
# chiperasepulsewidth = <num>; # PP only
|
||||
# chiperasepolltimeout = <num>;
|
||||
# chiperasetime = <num>; # HVSP only
|
||||
# programfusepulsewidth = <num>; # PP only
|
||||
# programfusepolltimeout = <num>;
|
||||
# programlockpulsewidth = <num>; # PP only
|
||||
# programlockpolltimeout = <num>;
|
||||
# pp_controlstack = <num>, <num>, ... ; # PP only
|
||||
# hvsp_controlstack = <num>, <num>, ... ; # HVSP only
|
||||
# flash_instr = <num>, <num>, <num> ;
|
||||
# eeprom_instr = <num>, <num>, ... ;
|
||||
# hventerstabdelay = <num> ;
|
||||
# progmodedelay = <num> ; # PP only
|
||||
# latchcycles = <num> ;
|
||||
# togglevtg = <num> ;
|
||||
# poweroffdelay = <num> ;
|
||||
# resetdelayms = <num> ;
|
||||
# resetdelayus = <num> ;
|
||||
# hvleavestabdelay = <num> ;
|
||||
# resetdelay = <num> ;
|
||||
# synchcycles = <num> ; # HVSP only
|
||||
# chiperasepulsewidth = <num> ; # PP only
|
||||
# chiperasepolltimeout = <num> ;
|
||||
# chiperasetime = <num> ; # HVSP only
|
||||
# programfusepulsewidth = <num> ; # PP only
|
||||
# programfusepolltimeout = <num> ;
|
||||
# programlockpulsewidth = <num> ; # PP only
|
||||
# programlockpolltimeout = <num> ;
|
||||
# # JTAG ICE mkII parameters, also from XML files
|
||||
# allowfullpagebitstream = <yes/no> ;
|
||||
# enablepageprogramming = <yes/no> ;
|
||||
# idr = <num> ; # IO addr of IDR (OCD) reg.
|
||||
# rampz = <num> ; # IO addr of RAMPZ reg.
|
||||
# spmcr = <num> ; # mem addr of SPMC[S]R reg.
|
||||
# eecr = <num> ; # mem addr of EECR reg.
|
||||
# # (only when != 0x3c)
|
||||
# is_at90s1200 = <yes/no> ; # AT90S1200 part
|
||||
# is_avr32 = <yes/no> ; # AVR32 part
|
||||
# idr = <num> ; # IO addr of IDR (OCD) reg
|
||||
# rampz = <num> ; # IO addr of RAMPZ reg
|
||||
# spmcr = <num> ; # mem addr of SPMC[S]R reg
|
||||
# eecr = <num> ; # mem addr of EECR reg only when != 0x3c
|
||||
# mcu_base = <num> ;
|
||||
# nvm_base = <num> ;
|
||||
# ocd_base = <num> ;
|
||||
# ocdrev = <num> ;
|
||||
# pgm_enable = <instruction format> ;
|
||||
# chip_erase = <instruction format> ;
|
||||
#
|
||||
# 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
|
||||
# page_size = <num> ; # bytes
|
||||
# num_pages = <num> ; # numeric
|
||||
# min_write_delay = <num> ; # micro-seconds
|
||||
# max_write_delay = <num> ; # micro-seconds
|
||||
# readback_p1 = <num> ; # byte value
|
||||
# readback_p2 = <num> ; # byte value
|
||||
# pwroff_after_write = <yes/no> ; # yes / no
|
||||
# readback = <num> <num> ; # pair of byte values
|
||||
# readback_p1 = <num> ; # byte value (first component)
|
||||
# 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> ;
|
||||
# write = <instruction format> ;
|
||||
# read_lo = <instruction format> ;
|
||||
|
@ -140,11 +149,12 @@
|
|||
# loadpage_lo = <instruction format> ;
|
||||
# loadpage_hi = <instruction format> ;
|
||||
# writepage = <instruction format> ;
|
||||
# ;
|
||||
# ;
|
||||
# ;
|
||||
# ;
|
||||
#
|
||||
# If any of the above parameters are not specified, the default value
|
||||
# of 0 is used for numerics or the empty string ("") for string
|
||||
# of 0 is used for numerics (except for hvupdi_variant and ocdrev,
|
||||
# where the default value is -1) or the empty string ("") for string
|
||||
# values. If a required parameter is left empty, AVRDUDE will
|
||||
# complain.
|
||||
#
|
||||
|
@ -152,7 +162,12 @@
|
|||
# using the following syntax. In this case specified integer and
|
||||
# string values override parameter values from the parent part. New
|
||||
# memory definitions are added to the definitions inherited from the
|
||||
# parent.
|
||||
# parent. If, however, a new memory definition refers to an existing
|
||||
# one of the same name for that part then, from v7.1, the existing
|
||||
# memory definition is extended, and components overwritten with new
|
||||
# values. Assigning NULL removes an inherited SPI instruction format,
|
||||
# memory definition, control stack, eeprom or flash instruction, eg,
|
||||
# as in memory "efuse" = NULL;
|
||||
#
|
||||
# part parent <id> # quoted string
|
||||
# id = <id> ; # quoted string
|
||||
|
@ -181,7 +196,7 @@
|
|||
#
|
||||
# INSTRUCTION FORMATS
|
||||
#
|
||||
# Instruction formats are specified as a comma seperated list of
|
||||
# Instruction formats are specified as a comma separated list of
|
||||
# string values containing information (bit specifiers) about each
|
||||
# of the 32 bits of the instruction. Bit specifiers may be one of
|
||||
# the following formats:
|
||||
|
@ -190,10 +205,11 @@
|
|||
#
|
||||
# '0' = the bit is always clear on input as well as output
|
||||
#
|
||||
# 'x' = the bit is ignored on input and output
|
||||
# 'x' = the bit is ignored on input and output and set as 0
|
||||
#
|
||||
# 'a' = the bit is an address bit, the bit-number matches this bit
|
||||
# specifier's position within the current instruction byte
|
||||
# 'a' = the bit is an address bit; from v 7.1 the bit-number
|
||||
# is set to match the right bit position for the
|
||||
# instruction to "just work"
|
||||
#
|
||||
# 'aN' = the bit is the Nth address bit, bit-number = N, i.e., a12
|
||||
# is address bit 12 on input, a0 is address bit 0.
|
||||
|
@ -202,11 +218,28 @@
|
|||
#
|
||||
# 'o' = the bit is an output data bit
|
||||
#
|
||||
# Each instruction must be composed of 32 bit specifiers. The
|
||||
# Each instruction must be composed of 32 bit specifiers. The
|
||||
# instruction specification closely follows the instruction data
|
||||
# provided in Atmel's data sheets for their parts.
|
||||
# provided in Atmel's data sheets for their parts. Note that flash
|
||||
# addresses always refer to *word* addresses whilst all other
|
||||
# memory types specify *byte* addresses.
|
||||
#
|
||||
# See below for some examples.
|
||||
# Example for signature read on the ATmega328P:
|
||||
# read = "0 0 1 1 0 0 0 0", "0 0 0 x x x x x",
|
||||
# "x x x x x x a1 a0", "o o o o o o o o";
|
||||
#
|
||||
# As the address bit numbers in the SPI opcodes are highly
|
||||
# systematic, they don't really need to be specified. A compact
|
||||
# version of the format specification neither uses bit-numbers for
|
||||
# address lines nor spaces. If such a string is longer than 7
|
||||
# characters, then the characters 0, 1, x, a, i and o will be
|
||||
# recognised as the corresponding bit, whilst any of the characters
|
||||
# ., -, _ or / can act as arbitrary visual separators, which are
|
||||
# ignored. Examples:
|
||||
#
|
||||
# loadpage_lo = "0100.0000--000x.xxxx--xxaa.aaaa--iiii.iiii";
|
||||
#
|
||||
# loadpage_lo = "0100.0000", "000x.xxxx", "xxaa.aaaa", "iiii.iiii";
|
||||
#
|
||||
#
|
||||
# The following are STK500 part device codes to use for the
|
||||
|
@ -1746,7 +1779,7 @@ programmer
|
|||
programmer
|
||||
id = "jtag2updi";
|
||||
desc = "JTAGv2 to UPDI bridge";
|
||||
type = "jtagmkii_pdi";
|
||||
type = "jtagmkii_updi";
|
||||
connection_type = serial;
|
||||
baudrate = 115200;
|
||||
hvupdi_support = 1;
|
||||
|
@ -11845,6 +11878,8 @@ part parent "m2561"
|
|||
" a7 x x x x x x x",
|
||||
" x x x x x x x x";
|
||||
|
||||
load_ext_addr = NULL;
|
||||
|
||||
mode = 0x41;
|
||||
delay = 20;
|
||||
blocksize = 256;
|
||||
|
|
406
src/avrpart.c
406
src/avrpart.c
|
@ -71,6 +71,21 @@ void avr_free_opcode(OPCODE * op)
|
|||
free(op);
|
||||
}
|
||||
|
||||
|
||||
// returns position 0..31 of highest bit set or INT_MIN if no bit is set
|
||||
int intlog2(unsigned int n) {
|
||||
int ret;
|
||||
|
||||
if(!n)
|
||||
return INT_MIN;
|
||||
|
||||
for(ret = 0; n >>= 1; ret++)
|
||||
continue;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* avr_set_bits()
|
||||
*
|
||||
|
@ -126,6 +141,101 @@ int avr_set_addr(OPCODE * op, unsigned char * cmd, unsigned long addr)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* avr_set_addr_mem()
|
||||
*
|
||||
* Set address bits in the specified command based on the memory, opcode and
|
||||
* address; addr must be a word address for flash or, for all other memories,
|
||||
* a byte address; returns 0 on success and -1 on error (no memory or no
|
||||
* opcode) or, if positive, bn+1 where bn is bit number of the highest
|
||||
* necessary bit that the opcode does not provide.
|
||||
*/
|
||||
int avr_set_addr_mem(AVRMEM *mem, int opnum, unsigned char *cmd, unsigned long addr) {
|
||||
int ret, isflash, lo, hi, memsize, pagesize;
|
||||
OPCODE *op;
|
||||
|
||||
if(!mem)
|
||||
return -1;
|
||||
|
||||
if(!(op = mem->op[opnum]))
|
||||
return -1;
|
||||
|
||||
isflash = !strcmp(mem->desc, "flash"); // ISP parts have only one flash-like memory
|
||||
memsize = mem->size >> isflash; // word addresses for flash
|
||||
pagesize = mem->page_size >> isflash;
|
||||
|
||||
// compute range lo..hi of needed address bits
|
||||
switch(opnum) {
|
||||
case AVR_OP_READ:
|
||||
case AVR_OP_WRITE:
|
||||
case AVR_OP_READ_LO:
|
||||
case AVR_OP_READ_HI:
|
||||
case AVR_OP_WRITE_LO:
|
||||
case AVR_OP_WRITE_HI:
|
||||
lo = 0;
|
||||
hi = intlog2(memsize-1); // memsize = 1 implies no addr bit is needed
|
||||
break;
|
||||
|
||||
case AVR_OP_LOADPAGE_LO:
|
||||
case AVR_OP_LOADPAGE_HI:
|
||||
lo = 0;
|
||||
hi = intlog2(pagesize-1);
|
||||
break;
|
||||
|
||||
case AVR_OP_LOAD_EXT_ADDR:
|
||||
lo = 16;
|
||||
hi = intlog2(memsize-1);
|
||||
break;
|
||||
|
||||
case AVR_OP_WRITEPAGE:
|
||||
lo = intlog2(pagesize);
|
||||
hi = intlog2(memsize-1);
|
||||
break;
|
||||
|
||||
case AVR_OP_CHIP_ERASE:
|
||||
case AVR_OP_PGM_ENABLE:
|
||||
default:
|
||||
lo = 0;
|
||||
hi = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
// Unless it's load extended address, ISP chips only deal with 16 bit addresses
|
||||
if(opnum != AVR_OP_LOAD_EXT_ADDR && hi > 15)
|
||||
hi = 15;
|
||||
|
||||
unsigned char avail[32];
|
||||
memset(avail, 0, sizeof avail);
|
||||
|
||||
for(int i=0; i<32; i++) {
|
||||
if(op->bit[i].type == AVR_CMDBIT_ADDRESS) {
|
||||
int bitno, j, bit;
|
||||
unsigned char mask;
|
||||
|
||||
bitno = op->bit[i].bitno & 31;
|
||||
j = 3 - i / 8;
|
||||
bit = i % 8;
|
||||
mask = 1 << bit;
|
||||
avail[bitno] = 1;
|
||||
|
||||
// 'a' bit with number outside bit range [lo, hi] is set to 0
|
||||
if (bitno >= lo && bitno <= hi? (addr >> bitno) & 1: 0)
|
||||
cmd[j] = cmd[j] | mask;
|
||||
else
|
||||
cmd[j] = cmd[j] & ~mask;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
if(lo >= 0 && hi < 32 && lo <= hi)
|
||||
for(int bn=lo; bn <= hi; bn++)
|
||||
if(!avail[bn]) // necessary bit bn misses in opcode
|
||||
ret = bn+1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* avr_set_input()
|
||||
*
|
||||
|
@ -239,7 +349,6 @@ static char * bittype(int type)
|
|||
}
|
||||
|
||||
|
||||
|
||||
/***
|
||||
*** Elementary functions dealing with AVRMEM structures
|
||||
***/
|
||||
|
@ -354,7 +463,6 @@ AVRMEM_ALIAS * avr_dup_memalias(AVRMEM_ALIAS * m)
|
|||
|
||||
void avr_free_mem(AVRMEM * m)
|
||||
{
|
||||
int i;
|
||||
if (m->buf != NULL) {
|
||||
free(m->buf);
|
||||
m->buf = NULL;
|
||||
|
@ -363,7 +471,7 @@ void avr_free_mem(AVRMEM * m)
|
|||
free(m->tags);
|
||||
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)
|
||||
{
|
||||
|
@ -379,13 +487,16 @@ void avr_free_memalias(AVRMEM_ALIAS * m)
|
|||
free(m);
|
||||
}
|
||||
|
||||
AVRMEM_ALIAS * avr_locate_memalias(AVRPART * p, char * desc)
|
||||
AVRMEM_ALIAS * avr_locate_memalias(AVRPART * p, const char * desc)
|
||||
{
|
||||
AVRMEM_ALIAS * m, * match;
|
||||
LNODEID ln;
|
||||
int matches;
|
||||
int l;
|
||||
|
||||
if(!p || !desc || !p->mem_alias)
|
||||
return NULL;
|
||||
|
||||
l = strlen(desc);
|
||||
matches = 0;
|
||||
match = NULL;
|
||||
|
@ -403,13 +514,16 @@ AVRMEM_ALIAS * avr_locate_memalias(AVRPART * p, char * desc)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
AVRMEM * avr_locate_mem_noalias(AVRPART * p, char * desc)
|
||||
AVRMEM * avr_locate_mem_noalias(AVRPART * p, const char * desc)
|
||||
{
|
||||
AVRMEM * m, * match;
|
||||
LNODEID ln;
|
||||
int matches;
|
||||
int l;
|
||||
|
||||
if(!p || !desc || !p->mem)
|
||||
return NULL;
|
||||
|
||||
l = strlen(desc);
|
||||
matches = 0;
|
||||
match = NULL;
|
||||
|
@ -428,7 +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_ALIAS * alias;
|
||||
|
@ -436,14 +550,19 @@ AVRMEM * avr_locate_mem(AVRPART * p, char * desc)
|
|||
int matches;
|
||||
int l;
|
||||
|
||||
if(!p || !desc)
|
||||
return NULL;
|
||||
|
||||
l = strlen(desc);
|
||||
matches = 0;
|
||||
match = NULL;
|
||||
for (ln=lfirst(p->mem); ln; ln=lnext(ln)) {
|
||||
m = ldata(ln);
|
||||
if (strncmp(desc, m->desc, l) == 0) {
|
||||
match = m;
|
||||
matches++;
|
||||
if(p->mem) {
|
||||
for (ln=lfirst(p->mem); ln; ln=lnext(ln)) {
|
||||
m = ldata(ln);
|
||||
if (strncmp(desc, m->desc, l) == 0) {
|
||||
match = m;
|
||||
matches++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
int type, int verbose)
|
||||
{
|
||||
static unsigned int prev_mem_offset, prev_mem_size;
|
||||
static unsigned int prev_mem_offset;
|
||||
static int prev_mem_size;
|
||||
int i, j;
|
||||
char * optr;
|
||||
|
||||
|
@ -545,12 +665,10 @@ void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, AVRPART * p,
|
|||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Elementary functions dealing with AVRPART structures
|
||||
*/
|
||||
|
||||
|
||||
AVRPART * avr_new_part(void)
|
||||
{
|
||||
AVRPART * p;
|
||||
|
@ -568,6 +686,7 @@ AVRPART * avr_new_part(void)
|
|||
p->reset_disposition = RESET_DEDICATED;
|
||||
p->retry_pulse = PIN_AVR_SCK;
|
||||
p->flags = AVRPART_SERIALOK | AVRPART_PARALLELOK | AVRPART_ENABLEPAGEPROGRAMMING;
|
||||
p->parent_id = NULL;
|
||||
p->config_file = NULL;
|
||||
p->lineno = 0;
|
||||
memset(p->signature, 0xFF, 3);
|
||||
|
@ -597,7 +716,6 @@ AVRPART * avr_dup_part(AVRPART * d)
|
|||
|
||||
p->mem = save;
|
||||
p->mem_alias = save2;
|
||||
|
||||
for (ln=lfirst(d->mem); ln; ln=lnext(ln)) {
|
||||
AVRMEM *m = ldata(ln);
|
||||
AVRMEM *m2 = avr_dup_mem(m);
|
||||
|
@ -625,28 +743,29 @@ AVRPART * avr_dup_part(AVRPART * d)
|
|||
|
||||
void avr_free_part(AVRPART * d)
|
||||
{
|
||||
int i;
|
||||
ldestroy_cb(d->mem, (void(*)(void *))avr_free_mem);
|
||||
d->mem = NULL;
|
||||
ldestroy_cb(d->mem_alias, (void(*)(void *))avr_free_memalias);
|
||||
d->mem_alias = NULL;
|
||||
for(i=0;i<sizeof(d->op)/sizeof(d->op[0]);i++)
|
||||
{
|
||||
if (d->op[i] != NULL)
|
||||
{
|
||||
avr_free_opcode(d->op[i]);
|
||||
d->op[i] = NULL;
|
||||
}
|
||||
ldestroy_cb(d->mem, (void(*)(void *))avr_free_mem);
|
||||
d->mem = NULL;
|
||||
ldestroy_cb(d->mem_alias, (void(*)(void *))avr_free_memalias);
|
||||
d->mem_alias = NULL;
|
||||
/* do not free d->parent_id and d->config_file */
|
||||
for(size_t i=0; i<sizeof(d->op)/sizeof(d->op[0]); i++) {
|
||||
if (d->op[i] != NULL) {
|
||||
avr_free_opcode(d->op[i]);
|
||||
d->op[i] = NULL;
|
||||
}
|
||||
free(d);
|
||||
}
|
||||
free(d);
|
||||
}
|
||||
|
||||
AVRPART * locate_part(LISTID parts, char * partdesc)
|
||||
AVRPART * locate_part(LISTID parts, const char * partdesc)
|
||||
{
|
||||
LNODEID ln1;
|
||||
AVRPART * p = NULL;
|
||||
int found;
|
||||
|
||||
if(!parts || !partdesc)
|
||||
return NULL;
|
||||
|
||||
found = 0;
|
||||
|
||||
for (ln1=lfirst(parts); ln1 && !found; ln1=lnext(ln1)) {
|
||||
|
@ -807,3 +926,232 @@ void avr_display(FILE * f, AVRPART * p, const char * prefix, int verbose)
|
|||
if (buf)
|
||||
free(buf);
|
||||
}
|
||||
|
||||
|
||||
char cmdbitchar(CMDBIT cb) {
|
||||
switch(cb.type) {
|
||||
case AVR_CMDBIT_IGNORE:
|
||||
return 'x';
|
||||
case AVR_CMDBIT_VALUE:
|
||||
return cb.value? '1': '0';
|
||||
case AVR_CMDBIT_ADDRESS:
|
||||
return 'a';
|
||||
case AVR_CMDBIT_INPUT:
|
||||
return 'i';
|
||||
case AVR_CMDBIT_OUTPUT:
|
||||
return 'o';
|
||||
default:
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char *cmdbitstr(CMDBIT cb) {
|
||||
char space[32];
|
||||
|
||||
*space = cmdbitchar(cb);
|
||||
if(*space == 'a')
|
||||
sprintf(space+1, "%d", cb.bitno);
|
||||
else
|
||||
space[1] = 0;
|
||||
|
||||
return strdup(space);
|
||||
}
|
||||
|
||||
|
||||
const char *opcodename(int opnum) {
|
||||
switch(opnum) {
|
||||
case AVR_OP_READ:
|
||||
return "read";
|
||||
case AVR_OP_WRITE:
|
||||
return "write";
|
||||
case AVR_OP_READ_LO:
|
||||
return "read_lo";
|
||||
case AVR_OP_READ_HI:
|
||||
return "read_hi";
|
||||
case AVR_OP_WRITE_LO:
|
||||
return "write_lo";
|
||||
case AVR_OP_WRITE_HI:
|
||||
return "write_hi";
|
||||
case AVR_OP_LOADPAGE_LO:
|
||||
return "loadpage_lo";
|
||||
case AVR_OP_LOADPAGE_HI:
|
||||
return "loadpage_hi";
|
||||
case AVR_OP_LOAD_EXT_ADDR:
|
||||
return "load_ext_addr";
|
||||
case AVR_OP_WRITEPAGE:
|
||||
return "writepage";
|
||||
case AVR_OP_CHIP_ERASE:
|
||||
return "chip_erase";
|
||||
case AVR_OP_PGM_ENABLE:
|
||||
return "pgm_enable";
|
||||
default:
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Unique string representation of an opcode
|
||||
char *opcode2str(OPCODE *op, int opnum, int detailed) {
|
||||
char cb, space[1024], *sp = space;
|
||||
int compact = 1;
|
||||
|
||||
if(!op)
|
||||
return strdup("NULL");
|
||||
|
||||
// Can the opcode be printed in a compact way? Only if address bits are systematic.
|
||||
for(int i=31; i >= 0; i--)
|
||||
if(op->bit[i].type == AVR_CMDBIT_ADDRESS)
|
||||
if(i<8 || i>23 || op->bit[i].bitno != (opnum == AVR_OP_LOAD_EXT_ADDR? i+8: i-8))
|
||||
compact = 0;
|
||||
|
||||
if(detailed)
|
||||
*sp++ = '"';
|
||||
|
||||
for(int i=31; i >= 0; i--) {
|
||||
*sp++ = cb = cmdbitchar(op->bit[i]);
|
||||
if(compact) {
|
||||
if(i && i%8 == 0)
|
||||
*sp++ = '-', *sp++ = '-';
|
||||
else if(i && i%4 == 0)
|
||||
*sp++ = '.';
|
||||
} else {
|
||||
if(cb == 'a') {
|
||||
sprintf(sp, "%d", op->bit[i].bitno);
|
||||
sp += strlen(sp);
|
||||
}
|
||||
if(i) {
|
||||
if(detailed)
|
||||
*sp++ = ' ';
|
||||
if(i%8 == 0)
|
||||
*sp++ = ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
if(detailed)
|
||||
*sp++ = '"';
|
||||
*sp = 0;
|
||||
|
||||
return strdup(space);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Match STRING against the partname pattern PATTERN, returning 1 if it
|
||||
* matches, 0 if not. NOTE: part_match() is a modified old copy of !fnmatch()
|
||||
* from the GNU C Library (published under GLP v2). Used for portability.
|
||||
*/
|
||||
|
||||
inline static int fold(int c) {
|
||||
return (c >= 'A' && c <= 'Z')? c+('a'-'A'): c;
|
||||
}
|
||||
|
||||
int part_match(const char *pattern, const char *string) {
|
||||
unsigned char c;
|
||||
const char *p = pattern, *n = string;
|
||||
|
||||
if(!*n) // AVRDUDE specialty: empty string never matches
|
||||
return 0;
|
||||
|
||||
while((c = fold(*p++))) {
|
||||
switch(c) {
|
||||
case '?':
|
||||
if(*n == 0)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
c = fold(*p++);
|
||||
if(fold(*n) != c)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case '*':
|
||||
for(c = *p++; c == '?' || c == '*'; c = *p++)
|
||||
if(c == '?' && *n++ == 0)
|
||||
return 0;
|
||||
|
||||
if(c == 0)
|
||||
return 1;
|
||||
|
||||
{
|
||||
unsigned char c1 = fold(c == '\\'? *p : c); // This char
|
||||
|
||||
for(--p; *n; ++n) // Recursively check reminder of string for *
|
||||
if((c == '[' || fold(*n) == c1) && part_match(p, n) == 1)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
case '[':
|
||||
{
|
||||
int negate;
|
||||
|
||||
if(*n == 0)
|
||||
return 0;
|
||||
|
||||
negate = (*p == '!' || *p == '^');
|
||||
if(negate)
|
||||
++p;
|
||||
|
||||
c = *p++;
|
||||
for(;;) {
|
||||
unsigned char cstart = c, cend = c;
|
||||
|
||||
if(c == '\\')
|
||||
cstart = cend = *p++;
|
||||
|
||||
cstart = cend = fold(cstart);
|
||||
|
||||
if(c == 0) // [ (unterminated)
|
||||
return 0;
|
||||
|
||||
c = *p++;
|
||||
c = fold(c);
|
||||
|
||||
if(c == '-' && *p != ']') {
|
||||
cend = *p++;
|
||||
if(cend == '\\')
|
||||
cend = *p++;
|
||||
if(cend == 0)
|
||||
return 0;
|
||||
cend = fold(cend);
|
||||
|
||||
c = *p++;
|
||||
}
|
||||
|
||||
if(fold(*n) >= cstart && fold(*n) <= cend)
|
||||
goto matched;
|
||||
|
||||
if(c == ']')
|
||||
break;
|
||||
}
|
||||
if(!negate)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
matched:;
|
||||
while(c != ']') { // Skip the rest of the [...] that already matched
|
||||
|
||||
if(c == 0) // [... (unterminated)
|
||||
return 0;
|
||||
|
||||
c = *p++;
|
||||
if(c == '\\') // XXX 1003.2d11 is unclear if this is right
|
||||
++p;
|
||||
}
|
||||
if(negate)
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if(c != fold(*n))
|
||||
return 0;
|
||||
}
|
||||
|
||||
++n;
|
||||
}
|
||||
|
||||
return *n == 0;
|
||||
}
|
||||
|
|
|
@ -25,10 +25,12 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
#include "config.h"
|
||||
#include "developer_opts.h"
|
||||
|
||||
#if defined(WIN32)
|
||||
#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_list(int invert);
|
||||
static int which_opcode(TOKEN * opcode);
|
||||
static int parse_cmdbits(OPCODE * op);
|
||||
static int parse_cmdbits(OPCODE * op, int opnum);
|
||||
|
||||
static int pin_name;
|
||||
%}
|
||||
|
||||
%token K_NULL;
|
||||
|
||||
%token K_READ
|
||||
%token K_WRITE
|
||||
%token K_READ_LO
|
||||
|
@ -112,6 +116,7 @@ static int pin_name;
|
|||
%token K_PSEUDO
|
||||
%token K_PWROFF_AFTER_WRITE
|
||||
%token K_RDYLED
|
||||
%token K_READBACK
|
||||
%token K_READBACK_P1
|
||||
%token K_READBACK_P2
|
||||
%token K_READMEM
|
||||
|
@ -329,6 +334,7 @@ prog_decl :
|
|||
free_token($3);
|
||||
YYABORT;
|
||||
}
|
||||
current_prog->parent_id = cache_string($3->value.string);
|
||||
current_prog->config_file = cache_string(cfg_infile);
|
||||
current_prog->lineno = cfg_lineno;
|
||||
free_token($3);
|
||||
|
@ -420,6 +426,7 @@ part_decl :
|
|||
free_token($3);
|
||||
YYABORT;
|
||||
}
|
||||
current_part->parent_id = cache_string($3->value.string);
|
||||
current_part->config_file = cache_string(cfg_infile);
|
||||
current_part->lineno = cfg_lineno;
|
||||
|
||||
|
@ -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 {
|
||||
{
|
||||
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 {
|
||||
{
|
||||
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 {
|
||||
{
|
||||
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
|
||||
{
|
||||
current_part->chip_erase_delay = $3->value.number;
|
||||
|
@ -1275,35 +1308,51 @@ part_parm :
|
|||
*/
|
||||
|
||||
K_MEMORY TKN_STRING
|
||||
{
|
||||
current_mem = avr_new_memtype();
|
||||
if (current_mem == NULL) {
|
||||
yyerror("could not create mem instance");
|
||||
free_token($2);
|
||||
YYABORT;
|
||||
{ /* select memory for extension or create if not there */
|
||||
AVRMEM *mem = avr_locate_mem_noalias(current_part, $2->value.string);
|
||||
if(!mem) {
|
||||
if(!(mem = avr_new_memtype())) {
|
||||
yyerror("could not create mem instance");
|
||||
free_token($2);
|
||||
YYABORT;
|
||||
}
|
||||
strncpy(mem->desc, $2->value.string, AVR_MEMDESCLEN - 1);
|
||||
mem->desc[AVR_MEMDESCLEN-1] = 0;
|
||||
ladd(current_part->mem, mem);
|
||||
}
|
||||
strncpy(current_mem->desc, $2->value.string, AVR_MEMDESCLEN - 1);
|
||||
current_mem->desc[AVR_MEMDESCLEN-1] = 0;
|
||||
avr_add_mem_order($2->value.string);
|
||||
current_mem = mem;
|
||||
free_token($2);
|
||||
}
|
||||
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) {
|
||||
lrmv_d(current_part->mem, existing_mem);
|
||||
avr_free_mem(existing_mem);
|
||||
}
|
||||
if (is_alias) {
|
||||
avr_free_mem(current_mem); // alias mem has been already entered below
|
||||
is_alias = false;
|
||||
} else {
|
||||
ladd(current_part->mem, current_mem);
|
||||
}
|
||||
current_mem = NULL;
|
||||
free_token($2);
|
||||
current_mem = NULL;
|
||||
} |
|
||||
|
||||
opcode TKN_EQUAL string_list {
|
||||
{
|
||||
int opnum;
|
||||
|
@ -1317,13 +1366,27 @@ part_parm :
|
|||
free_token($1);
|
||||
YYABORT;
|
||||
}
|
||||
if(0 != parse_cmdbits(op)) YYABORT;
|
||||
if(0 != parse_cmdbits(op, opnum))
|
||||
YYABORT;
|
||||
if (current_part->op[opnum] != NULL) {
|
||||
/*yywarning("operation redefined");*/
|
||||
avr_free_opcode(current_part->op[opnum]);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -1398,6 +1461,14 @@ mem_spec :
|
|||
free_token($3);
|
||||
} |
|
||||
|
||||
K_READBACK TKN_EQUAL TKN_NUMBER TKN_NUMBER
|
||||
{
|
||||
current_mem->readback[0] = $3->value.number;
|
||||
current_mem->readback[1] = $4->value.number;
|
||||
free_token($3);
|
||||
free_token($4);
|
||||
} |
|
||||
|
||||
K_READBACK_P1 TKN_EQUAL TKN_NUMBER
|
||||
{
|
||||
current_mem->readback[0] = $3->value.number;
|
||||
|
@ -1455,13 +1526,27 @@ mem_spec :
|
|||
free_token($1);
|
||||
YYABORT;
|
||||
}
|
||||
if(0 != parse_cmdbits(op)) YYABORT;
|
||||
if(0 != parse_cmdbits(op, opnum))
|
||||
YYABORT;
|
||||
if (current_mem->op[opnum] != NULL) {
|
||||
/*yywarning("operation redefined");*/
|
||||
avr_free_opcode(current_mem->op[opnum]);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
char ch;
|
||||
char * e;
|
||||
char * q;
|
||||
int len;
|
||||
char * s, *brkt = NULL;
|
||||
char *s, *brkt = NULL;
|
||||
int rv = 0;
|
||||
|
||||
bitno = 32;
|
||||
|
@ -1595,10 +1677,18 @@ static int parse_cmdbits(OPCODE * op)
|
|||
|
||||
t = lrmv_n(string_list, 1);
|
||||
|
||||
s = strtok_r(t->value.string, " ", &brkt);
|
||||
char *str = t->value.string;
|
||||
// Compact alternative specification? (eg, "0100.0000--000x.xxxx--xxaa.aaaa--iiii.iiii")
|
||||
char bit[2] = {0, 0}, *cc = str;
|
||||
int compact = !strchr(str, ' ') && strlen(str) > 7;
|
||||
|
||||
bit[0] = *cc++;
|
||||
s = !compact? strtok_r(str, " ", &brkt): *bit? bit: NULL;
|
||||
while (rv == 0 && s != NULL) {
|
||||
|
||||
bitno--;
|
||||
// Ignore visual grouping characters in compact mode
|
||||
if(*s != '.' && *s != '-' && *s != '_' && *s !='/')
|
||||
bitno--;
|
||||
if (bitno < 0) {
|
||||
yyerror("too many opcode bits for instruction");
|
||||
rv = -1;
|
||||
|
@ -1613,10 +1703,8 @@ static int parse_cmdbits(OPCODE * op)
|
|||
break;
|
||||
}
|
||||
|
||||
ch = s[0];
|
||||
|
||||
if (len == 1) {
|
||||
switch (ch) {
|
||||
switch (*s) {
|
||||
case '1':
|
||||
op->bit[bitno].type = AVR_CMDBIT_VALUE;
|
||||
op->bit[bitno].value = 1;
|
||||
|
@ -1635,7 +1723,10 @@ static int parse_cmdbits(OPCODE * op)
|
|||
case 'a':
|
||||
op->bit[bitno].type = AVR_CMDBIT_ADDRESS;
|
||||
op->bit[bitno].value = 0;
|
||||
op->bit[bitno].bitno = 8*(bitno/8) + bitno % 8;
|
||||
op->bit[bitno].bitno = bitno < 8 || bitno > 23? 0:
|
||||
opnum == AVR_OP_LOAD_EXT_ADDR? bitno+8: bitno-8; /* correct bit number for lone 'a' */
|
||||
if(bitno < 8 || bitno > 23)
|
||||
yywarning("address bits don't normally appear in Bytes 0 or 3 of SPI commands");
|
||||
break;
|
||||
case 'i':
|
||||
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].bitno = bitno % 8;
|
||||
break;
|
||||
case '.':
|
||||
case '-':
|
||||
case '_':
|
||||
case '/':
|
||||
break;
|
||||
default :
|
||||
yyerror("invalid bit specifier '%c'", ch);
|
||||
yyerror("invalid bit specifier '%c'", *s);
|
||||
rv = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (ch == 'a') {
|
||||
q = &s[1];
|
||||
op->bit[bitno].bitno = strtol(q, &e, 0);
|
||||
if ((e == q)||(*e != 0)) {
|
||||
yyerror("can't parse bit number from \"%s\"", q);
|
||||
rv = -1;
|
||||
break;
|
||||
if (*s == 'a') {
|
||||
int sb, bn;
|
||||
char *e, *q;
|
||||
|
||||
q = s+1;
|
||||
errno = 0;
|
||||
bn = strtol(q, &e, 0); // address line
|
||||
if (e == q || *e != 0 || errno) {
|
||||
yywarning("can't parse bit number from a%s", q);
|
||||
bn = 0;
|
||||
}
|
||||
|
||||
sb = opnum == AVR_OP_LOAD_EXT_ADDR? bitno+8: bitno-8; // should be this number
|
||||
if(bitno < 8 || bitno > 23)
|
||||
yywarning("address bits don't normally appear in Bytes 0 or 3 of SPI commands");
|
||||
else if((bn & 31) != sb)
|
||||
yywarning("a%d would normally be expected to be a%d", bn, sb);
|
||||
else if(bn < 0 || bn > 31)
|
||||
yywarning("invalid address bit a%d, using a%d", bn, bn & 31);
|
||||
|
||||
op->bit[bitno].bitno = bn & 31;
|
||||
|
||||
op->bit[bitno].type = AVR_CMDBIT_ADDRESS;
|
||||
op->bit[bitno].value = 0;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
||||
free_token(t);
|
||||
|
||||
} /* while */
|
||||
|
||||
if(bitno > 0)
|
||||
yywarning("too few opcode bits in instruction");
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -694,6 +694,10 @@ Posix systems (by now).
|
|||
Disable (or quell) output of the progress bar while reading or writing
|
||||
to the device. Specify it a second time for even quieter operation.
|
||||
|
||||
@item -s, -u
|
||||
These options used to control the obsolete "safemode" feature which
|
||||
is no longer present. They are silently ignored for backwards compatibility.
|
||||
|
||||
@item -t
|
||||
Tells AVRDUDE to enter the interactive ``terminal'' mode instead of up-
|
||||
or downloading files. See below for a detailed description of the
|
||||
|
@ -769,6 +773,9 @@ the file to read or write. Possible values are:
|
|||
@item i
|
||||
Intel Hex
|
||||
|
||||
@item I
|
||||
Intel Hex with comments on download and tolerance of checksum errors on upload
|
||||
|
||||
@item s
|
||||
Motorola S-record
|
||||
|
||||
|
|
60
src/fileio.c
60
src/fileio.c
|
@ -59,10 +59,11 @@ struct ihexrec {
|
|||
|
||||
static int b2ihex(unsigned char * inbuf, int bufsize,
|
||||
int recsize, int startaddr,
|
||||
char * outfile, FILE * outf);
|
||||
char * outfile, FILE * outf, FILEFMT ffmt);
|
||||
|
||||
static int ihex2b(char * infile, FILE * inf,
|
||||
AVRMEM * mem, int bufsize, unsigned int fileoffset);
|
||||
AVRMEM * mem, int bufsize, unsigned int fileoffset,
|
||||
FILEFMT ffmt);
|
||||
|
||||
static int b2srec(unsigned char * inbuf, int bufsize,
|
||||
int recsize, int startaddr,
|
||||
|
@ -79,7 +80,8 @@ static int fileio_rbin(struct fioparms * fio,
|
|||
char * filename, FILE * f, AVRMEM * mem, int size);
|
||||
|
||||
static int fileio_ihex(struct fioparms * fio,
|
||||
char * filename, FILE * f, AVRMEM * mem, int size);
|
||||
char * filename, FILE * f, AVRMEM * mem, int size,
|
||||
FILEFMT ffmt);
|
||||
|
||||
static int fileio_srec(struct fioparms * fio,
|
||||
char * filename, FILE * f, AVRMEM * mem, int size);
|
||||
|
@ -108,6 +110,7 @@ char * fmtstr(FILEFMT format)
|
|||
case FMT_AUTO : return "auto-detect"; break;
|
||||
case FMT_SREC : return "Motorola S-Record"; break;
|
||||
case FMT_IHEX : return "Intel Hex"; break;
|
||||
case FMT_IHXC : return "Intel Hex with comments"; break;
|
||||
case FMT_RBIN : return "raw binary"; break;
|
||||
case FMT_ELF : return "ELF"; break;
|
||||
default : return "invalid format"; break;
|
||||
|
@ -115,10 +118,9 @@ char * fmtstr(FILEFMT format)
|
|||
}
|
||||
|
||||
|
||||
|
||||
static int b2ihex(unsigned char * inbuf, int bufsize,
|
||||
int recsize, int startaddr,
|
||||
char * outfile, FILE * outf)
|
||||
char * outfile, FILE * outf, FILEFMT ffmt)
|
||||
{
|
||||
unsigned char * buf;
|
||||
unsigned int nextaddr;
|
||||
|
@ -154,8 +156,20 @@ static int b2ihex(unsigned char * inbuf, int bufsize,
|
|||
cksum += buf[i];
|
||||
}
|
||||
cksum = -cksum;
|
||||
fprintf(outf, "%02X\n", cksum);
|
||||
|
||||
fprintf(outf, "%02X", cksum);
|
||||
|
||||
if(ffmt == FMT_IHXC) { /* Print comment with address and ASCII dump */
|
||||
for(i=n; i<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;
|
||||
nbytes += n;
|
||||
}
|
||||
|
@ -283,7 +297,8 @@ static int ihex_readrec(struct ihexrec * ihex, char * rec)
|
|||
*
|
||||
* */
|
||||
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 ];
|
||||
unsigned int nextaddr, baseaddr, maxaddr;
|
||||
|
@ -312,11 +327,18 @@ static int ihex2b(char * infile, FILE * inf,
|
|||
return -1;
|
||||
}
|
||||
else if (rc != ihex.cksum) {
|
||||
avrdude_message(MSG_INFO, "%s: ERROR: checksum mismatch at line %d of \"%s\"\n",
|
||||
progname, lineno, infile);
|
||||
avrdude_message(MSG_INFO, "%s: checksum=0x%02x, computed checksum=0x%02x\n",
|
||||
progname, ihex.cksum, rc);
|
||||
return -1;
|
||||
if(ffmt == FMT_IHEX) {
|
||||
avrdude_message(MSG_INFO, "%s: ERROR: checksum mismatch at line %d of \"%s\"\n",
|
||||
progname, lineno, infile);
|
||||
avrdude_message(MSG_INFO, "%s: checksum=0x%02x, computed checksum=0x%02x\n",
|
||||
progname, ihex.cksum, rc);
|
||||
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) {
|
||||
|
@ -1159,21 +1181,22 @@ static int fileio_imm(struct fioparms * fio,
|
|||
}
|
||||
|
||||
|
||||
static int fileio_ihex(struct fioparms * fio,
|
||||
char * filename, FILE * f, AVRMEM * mem, int size)
|
||||
static int fileio_ihex(struct fioparms * fio,
|
||||
char * filename, FILE * f, AVRMEM * mem, int size,
|
||||
FILEFMT ffmt)
|
||||
{
|
||||
int rc;
|
||||
|
||||
switch (fio->op) {
|
||||
case FIO_WRITE:
|
||||
rc = b2ihex(mem->buf, size, 32, fio->fileoffset, filename, f);
|
||||
rc = b2ihex(mem->buf, size, 32, fio->fileoffset, filename, f, ffmt);
|
||||
if (rc < 0) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case FIO_READ:
|
||||
rc = ihex2b(filename, f, mem, size, fio->fileoffset);
|
||||
rc = ihex2b(filename, f, mem, size, fio->fileoffset, ffmt);
|
||||
if (rc < 0)
|
||||
return -1;
|
||||
break;
|
||||
|
@ -1566,7 +1589,8 @@ int fileio(int oprwv, char * filename, FILEFMT format,
|
|||
|
||||
switch (format) {
|
||||
case FMT_IHEX:
|
||||
rc = fileio_ihex(&fio, fname, f, mem, size);
|
||||
case FMT_IHXC:
|
||||
rc = fileio_ihex(&fio, fname, f, mem, size, format);
|
||||
break;
|
||||
|
||||
case FMT_SREC:
|
||||
|
|
|
@ -1058,7 +1058,7 @@ static int jtagmkI_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
|
|||
{
|
||||
unsigned char cmd[6], datacmd[1 * 2 + 1];
|
||||
unsigned char resp[1], writedata;
|
||||
int len, need_progmode = 1;
|
||||
int len, need_progmode = 1, need_dummy_read = 0;
|
||||
|
||||
avrdude_message(MSG_NOTICE2, "%s: jtagmkI_write_byte(.., %s, 0x%lx, ...)\n",
|
||||
progname, mem->desc, addr);
|
||||
|
@ -1072,20 +1072,26 @@ static int jtagmkI_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
|
|||
} else if (strcmp(mem->desc, "eeprom") == 0) {
|
||||
cmd[1] = MTYPE_EEPROM;
|
||||
need_progmode = 0;
|
||||
need_dummy_read = 1;
|
||||
PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L;
|
||||
} else if (strcmp(mem->desc, "lfuse") == 0) {
|
||||
cmd[1] = MTYPE_FUSE_BITS;
|
||||
need_dummy_read = 1;
|
||||
addr = 0;
|
||||
} else if (strcmp(mem->desc, "hfuse") == 0) {
|
||||
cmd[1] = MTYPE_FUSE_BITS;
|
||||
need_dummy_read = 1;
|
||||
addr = 1;
|
||||
} else if (strcmp(mem->desc, "efuse") == 0) {
|
||||
cmd[1] = MTYPE_FUSE_BITS;
|
||||
need_dummy_read = 1;
|
||||
addr = 2;
|
||||
} else if (strcmp(mem->desc, "lock") == 0) {
|
||||
cmd[1] = MTYPE_LOCK_BITS;
|
||||
need_dummy_read = 1;
|
||||
} else if (strcmp(mem->desc, "calibration") == 0) {
|
||||
cmd[1] = MTYPE_OSCCAL_BYTE;
|
||||
need_dummy_read = 1;
|
||||
} else if (strcmp(mem->desc, "signature") == 0) {
|
||||
cmd[1] = MTYPE_SIGN_JTAG;
|
||||
}
|
||||
|
@ -1154,6 +1160,8 @@ static int jtagmkI_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
|
|||
avrdude_message(MSG_NOTICE2, "OK\n");
|
||||
}
|
||||
|
||||
if(need_dummy_read)
|
||||
jtagmkI_recv(pgm, resp, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1306,9 +1306,9 @@ static int jtagmkII_initialize(PROGRAMMER * pgm, AVRPART * p)
|
|||
const char *ifname;
|
||||
|
||||
/* Abort and print error if programmer does not support the target microcontroller */
|
||||
if ((strncmp(ldata(lfirst(pgm->id)), "jtag2updi", strlen("jtag2updi")) == 0 && p->flags & AVRPART_HAS_PDI) ||
|
||||
if ((strncmp(pgm->type, "JTAGMKII_UPDI", strlen("JTAGMKII_UPDI")) == 0 && !(p->flags & AVRPART_HAS_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);
|
||||
return -1;
|
||||
}
|
||||
|
@ -3929,6 +3929,39 @@ void jtagmkII_pdi_initpgm(PROGRAMMER * pgm)
|
|||
pgm->flag = PGM_FL_IS_PDI;
|
||||
}
|
||||
|
||||
const char jtagmkII_updi_desc[] = "Atmel JTAG ICE mkII in UPDI mode";
|
||||
|
||||
void jtagmkII_updi_initpgm(PROGRAMMER * pgm)
|
||||
{
|
||||
strcpy(pgm->type, "JTAGMKII_UPDI");
|
||||
|
||||
/*
|
||||
* mandatory functions
|
||||
*/
|
||||
pgm->initialize = jtagmkII_initialize;
|
||||
pgm->display = jtagmkII_display;
|
||||
pgm->enable = jtagmkII_enable;
|
||||
pgm->disable = jtagmkII_disable;
|
||||
pgm->program_enable = jtagmkII_program_enable_INFO;
|
||||
pgm->chip_erase = jtagmkII_chip_erase;
|
||||
pgm->open = jtagmkII_open_pdi;
|
||||
pgm->close = jtagmkII_close;
|
||||
pgm->read_byte = jtagmkII_read_byte;
|
||||
pgm->write_byte = jtagmkII_write_byte;
|
||||
|
||||
/*
|
||||
* optional functions
|
||||
*/
|
||||
pgm->paged_write = jtagmkII_paged_write;
|
||||
pgm->paged_load = jtagmkII_paged_load;
|
||||
pgm->page_erase = jtagmkII_page_erase;
|
||||
pgm->print_parms = jtagmkII_print_parms;
|
||||
pgm->setup = jtagmkII_setup;
|
||||
pgm->teardown = jtagmkII_teardown;
|
||||
pgm->page_size = 256;
|
||||
pgm->flag = PGM_FL_IS_PDI;
|
||||
}
|
||||
|
||||
const char jtagmkII_dragon_desc[] = "Atmel AVR Dragon in JTAG mode";
|
||||
|
||||
void jtagmkII_dragon_initpgm(PROGRAMMER * pgm)
|
||||
|
|
|
@ -36,6 +36,7 @@ extern const char jtagmkII_desc[];
|
|||
extern const char jtagmkII_avr32_desc[];
|
||||
extern const char jtagmkII_dw_desc[];
|
||||
extern const char jtagmkII_pdi_desc[];
|
||||
extern const char jtagmkII_updi_desc[];
|
||||
extern const char jtagmkII_dragon_desc[];
|
||||
extern const char jtagmkII_dragon_dw_desc[];
|
||||
extern const char jtagmkII_dragon_pdi_desc[];
|
||||
|
@ -43,6 +44,7 @@ void jtagmkII_initpgm (PROGRAMMER * pgm);
|
|||
void jtagmkII_avr32_initpgm (PROGRAMMER * pgm);
|
||||
void jtagmkII_dw_initpgm (PROGRAMMER * pgm);
|
||||
void jtagmkII_pdi_initpgm (PROGRAMMER * pgm);
|
||||
void jtagmkII_updi_initpgm (PROGRAMMER * pgm);
|
||||
void jtagmkII_dragon_initpgm (PROGRAMMER * pgm);
|
||||
void jtagmkII_dragon_dw_initpgm (PROGRAMMER * pgm);
|
||||
void jtagmkII_dragon_pdi_initpgm (PROGRAMMER * pgm);
|
||||
|
|
11
src/lexer.l
11
src/lexer.l
|
@ -57,12 +57,9 @@ SIGN [+-]
|
|||
|
||||
%%
|
||||
|
||||
#{SIGN}*{DIGIT}+ { yylval = number(yytext); return TKN_NUMBER; }
|
||||
#{SIGN}*{DIGIT}+"."{DIGIT}* { yylval = number_real(yytext); return TKN_NUMBER_REAL; }
|
||||
#{SIGN}*"."{DIGIT}* { yylval = number_real(yytext); return TKN_NUMBER_REAL; }
|
||||
{DIGIT}+ { yylval = number(yytext); return TKN_NUMBER; }
|
||||
{DIGIT}+"."{DIGIT}* { yylval = number_real(yytext); return TKN_NUMBER_REAL; }
|
||||
"."{DIGIT}+ { yylval = number_real(yytext); return TKN_NUMBER_REAL; }
|
||||
{SIGN}?{DIGIT}+ { yylval = number(yytext); return TKN_NUMBER; }
|
||||
{SIGN}?{DIGIT}+"."{DIGIT}* { yylval = number_real(yytext); return TKN_NUMBER_REAL; }
|
||||
{SIGN}?"."{DIGIT}+ { yylval = number_real(yytext); return TKN_NUMBER_REAL; }
|
||||
|
||||
"\"" { string_buf_ptr = string_buf; BEGIN(strng); }
|
||||
|
||||
|
@ -179,6 +176,7 @@ miso { yylval=NULL; return K_MISO; }
|
|||
mode { yylval=NULL; return K_MODE; }
|
||||
mosi { yylval=NULL; return K_MOSI; }
|
||||
no { yylval=new_token(K_NO); return K_NO; }
|
||||
NULL { yylval=NULL; return K_NULL; }
|
||||
num_banks { yylval=NULL; return K_NUM_PAGES; }
|
||||
num_pages { yylval=NULL; return K_NUM_PAGES; }
|
||||
nvm_base { yylval=NULL; return K_NVM_BASE; }
|
||||
|
@ -213,6 +211,7 @@ rdyled { yylval=NULL; return K_RDYLED; }
|
|||
read { yylval=new_token(K_READ); return K_READ; }
|
||||
read_hi { yylval=new_token(K_READ_HI); return K_READ_HI; }
|
||||
read_lo { yylval=new_token(K_READ_LO); return K_READ_LO; }
|
||||
readback { yylval=NULL; return K_READBACK; }
|
||||
readback_p1 { yylval=NULL; return K_READBACK_P1; }
|
||||
readback_p2 { yylval=NULL; return K_READBACK_P2; }
|
||||
readsize { yylval=NULL; return K_READSIZE; }
|
||||
|
|
|
@ -183,6 +183,7 @@ typedef struct opcode {
|
|||
} OPCODE;
|
||||
|
||||
|
||||
/* Any changes here, please also reflect in dev_part_strct() of developer_opts.c */
|
||||
#define AVRPART_SERIALOK 0x0001 /* part supports serial programming */
|
||||
#define AVRPART_PARALLELOK 0x0002 /* part supports parallel programming */
|
||||
#define AVRPART_PSEUDOPARALLEL 0x0004 /* part has pseudo parallel support */
|
||||
|
@ -212,9 +213,11 @@ typedef struct opcode {
|
|||
|
||||
#define TAG_ALLOCATED 1 /* memory byte is allocated */
|
||||
|
||||
/* Any changes here, please also reflect in dev_part_strct() of developer_opts.c */
|
||||
typedef struct avrpart {
|
||||
char desc[AVR_DESCLEN]; /* long part name */
|
||||
char id[AVR_IDLEN]; /* short part name */
|
||||
char * parent_id; /* parent id if set, for -p.../s */
|
||||
char family_id[AVR_FAMILYIDLEN+1]; /* family id in the SIB (avr8x) */
|
||||
int hvupdi_variant; /* HV pulse on UPDI pin, no pin or RESET pin */
|
||||
int stk500_devcode; /* stk500 device code */
|
||||
|
@ -317,14 +320,22 @@ typedef struct avrmem_alias {
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
int intlog2(unsigned int n);
|
||||
|
||||
/* Functions for OPCODE structures */
|
||||
OPCODE * avr_new_opcode(void);
|
||||
void avr_free_opcode(OPCODE * op);
|
||||
int avr_set_bits(OPCODE * op, unsigned char * cmd);
|
||||
int avr_set_addr(OPCODE * op, unsigned char * cmd, unsigned long addr);
|
||||
int avr_set_addr_mem(AVRMEM *mem, int opnum, unsigned char *cmd, unsigned long addr);
|
||||
int avr_set_input(OPCODE * op, unsigned char * cmd, unsigned char data);
|
||||
int avr_get_output(OPCODE * op, unsigned char * res, unsigned char * data);
|
||||
int avr_get_output_index(OPCODE * op);
|
||||
char cmdbitchar(CMDBIT cb);
|
||||
char *cmdbitstr(CMDBIT cb);
|
||||
const char *opcodename(int opnum);
|
||||
char *opcode2str(OPCODE *op, int opnum, int detailed);
|
||||
|
||||
/* Functions for AVRMEM structures */
|
||||
AVRMEM * avr_new_memtype(void);
|
||||
|
@ -333,9 +344,9 @@ int avr_initmem(AVRPART * p);
|
|||
AVRMEM * avr_dup_mem(AVRMEM * m);
|
||||
void avr_free_mem(AVRMEM * m);
|
||||
void avr_free_memalias(AVRMEM_ALIAS * m);
|
||||
AVRMEM * avr_locate_mem(AVRPART * p, char * desc);
|
||||
AVRMEM * avr_locate_mem_noalias(AVRPART * p, char * desc);
|
||||
AVRMEM_ALIAS * avr_locate_memalias(AVRPART * p, char * desc);
|
||||
AVRMEM * avr_locate_mem(AVRPART * p, const char * desc);
|
||||
AVRMEM * avr_locate_mem_noalias(AVRPART * p, const char * desc);
|
||||
AVRMEM_ALIAS * avr_locate_memalias(AVRPART * p, const char * desc);
|
||||
AVRMEM_ALIAS * avr_find_memalias(AVRPART * p, AVRMEM * m_orig);
|
||||
void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, AVRPART * p,
|
||||
int type, int verbose);
|
||||
|
@ -344,7 +355,7 @@ void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, AVRPART * p,
|
|||
AVRPART * avr_new_part(void);
|
||||
AVRPART * avr_dup_part(AVRPART * d);
|
||||
void avr_free_part(AVRPART * d);
|
||||
AVRPART * locate_part(LISTID parts, char * partdesc);
|
||||
AVRPART * locate_part(LISTID parts, const char * partdesc);
|
||||
AVRPART * locate_part_by_avr910_devcode(LISTID parts, int devcode);
|
||||
AVRPART * locate_part_by_signature(LISTID parts, unsigned char * sig,
|
||||
int sigsize);
|
||||
|
@ -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 sort_avrparts(LISTID avrparts);
|
||||
|
||||
int part_match(const char *pattern, const char *string);
|
||||
|
||||
int compare_memory_masked(AVRMEM * m, uint8_t buf1, uint8_t buf2);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -659,6 +672,7 @@ typedef struct programmer_t {
|
|||
char desc[PGM_DESCLEN];
|
||||
char type[PGM_TYPELEN];
|
||||
char port[PGM_PORTLEN];
|
||||
char *parent_id;
|
||||
void (*initpgm)(struct programmer_t * pgm);
|
||||
unsigned int pinno[N_PINS];
|
||||
struct pindef_t pin[N_PINS];
|
||||
|
@ -769,6 +783,7 @@ void sort_programmers(LISTID programmers);
|
|||
typedef void (*FP_UpdateProgress)(int percent, double etime, char *hdr);
|
||||
|
||||
extern struct avrpart parts[];
|
||||
extern const char *avr_mem_order[100];
|
||||
|
||||
extern FP_UpdateProgress update_progress;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
void avr_add_mem_order(const char *str);
|
||||
|
||||
int avr_mem_is_known(const char *str);
|
||||
int avr_mem_might_be_known(const char *str);
|
||||
|
||||
#define disable_trailing_ff_removal() avr_mem_hiaddr(NULL)
|
||||
int avr_mem_hiaddr(AVRMEM * mem);
|
||||
|
||||
|
@ -829,7 +849,8 @@ typedef enum {
|
|||
FMT_DEC,
|
||||
FMT_OCT,
|
||||
FMT_BIN,
|
||||
FMT_ELF
|
||||
FMT_ELF,
|
||||
FMT_IHXC,
|
||||
} FILEFMT;
|
||||
|
||||
struct fioparms {
|
||||
|
@ -873,6 +894,7 @@ enum updateflags {
|
|||
UF_NONE = 0,
|
||||
UF_NOWRITE = 1,
|
||||
UF_AUTO_ERASE = 2,
|
||||
UF_VERIFY = 4,
|
||||
};
|
||||
|
||||
|
||||
|
@ -883,6 +905,17 @@ typedef struct update_t {
|
|||
int format;
|
||||
} UPDATE;
|
||||
|
||||
typedef struct { // File reads for flash can exclude trailing 0xff, which are cut off
|
||||
int nbytes, // Number of bytes set including 0xff but excluding cut off, trailing 0xff
|
||||
nsections, // Number of consecutive sections in source excluding cut off, trailing 0xff
|
||||
npages, // Number of memory pages needed excluding pages solely with trailing 0xff
|
||||
nfill, // Number of fill bytes to make up full pages that are needed
|
||||
ntrailing, // Number of trailing 0xff in source
|
||||
firstaddr, // First address set in [0, mem->size-1]
|
||||
lastaddr; // Highest address set by input file
|
||||
} Filestats;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -895,6 +928,14 @@ extern void free_update(UPDATE * upd);
|
|||
extern int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd,
|
||||
enum updateflags flags);
|
||||
|
||||
extern int memstats(struct avrpart *p, char *memtype, int size, Filestats *fsp);
|
||||
|
||||
// Convenience functions for printing
|
||||
const char *plural(int x);
|
||||
const char *inname(const char *fn);
|
||||
const char *outname(const char *fn);
|
||||
const char *interval(int a, int b);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
38
src/main.c
38
src/main.c
|
@ -26,7 +26,7 @@
|
|||
* For parallel port connected programmers, the pin definitions can be
|
||||
* changed via a config file. See the config file for instructions on
|
||||
* how to add a programmer definition.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ac_cfg.h"
|
||||
|
@ -50,7 +50,7 @@
|
|||
#include "libavrdude.h"
|
||||
|
||||
#include "term.h"
|
||||
|
||||
#include "developer_opts.h"
|
||||
|
||||
/* Get VERSION from ac_cfg.h */
|
||||
char * version = VERSION;
|
||||
|
@ -102,7 +102,7 @@ int ovsigck; /* 1=override sig check, 0=don't */
|
|||
*/
|
||||
static void usage(void)
|
||||
{
|
||||
avrdude_message(MSG_INFO,
|
||||
avrdude_message(MSG_INFO,
|
||||
"Usage: %s [options]\n"
|
||||
"Options:\n"
|
||||
" -p <partno> Required. Specify AVR device.\n"
|
||||
|
@ -237,7 +237,7 @@ static void cleanup_main(void)
|
|||
static void replace_backslashes(char *s)
|
||||
{
|
||||
// Replace all backslashes with forward slashes
|
||||
for (int i = 0; i < strlen(s); i++) {
|
||||
for (size_t i = 0; i < strlen(s); i++) {
|
||||
if (s[i] == '\\') {
|
||||
s[i] = '/';
|
||||
}
|
||||
|
@ -267,7 +267,6 @@ int main(int argc, char * argv [])
|
|||
int calibrate; /* 1=calibrate RC oscillator, 0=don't */
|
||||
char * port; /* device port (/dev/xxx) */
|
||||
int terminal; /* 1=enter terminal mode, 0=don't */
|
||||
int verify; /* perform a verify operation */
|
||||
char * exitspecs; /* exit specs string from command line */
|
||||
char * programmer; /* programmer id */
|
||||
char * partdesc; /* part id */
|
||||
|
@ -284,7 +283,7 @@ int main(int argc, char * argv [])
|
|||
int init_ok; /* Device initialization worked well */
|
||||
int is_open; /* Device open succeeded */
|
||||
char * logfile; /* Use logfile rather than stderr for diagnostics */
|
||||
enum updateflags uflags = UF_AUTO_ERASE; /* Flags for do_op() */
|
||||
enum updateflags uflags = UF_AUTO_ERASE | UF_VERIFY; /* Flags for do_op() */
|
||||
|
||||
#if !defined(WIN32)
|
||||
char * homedir;
|
||||
|
@ -349,7 +348,6 @@ int main(int argc, char * argv [])
|
|||
p = NULL;
|
||||
ovsigck = 0;
|
||||
terminal = 0;
|
||||
verify = 1; /* on by default */
|
||||
quell_progress = 0;
|
||||
exitspecs = NULL;
|
||||
pgm = NULL;
|
||||
|
@ -511,6 +509,7 @@ int main(int argc, char * argv [])
|
|||
terminal = 1;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
case 'u':
|
||||
avrdude_message(MSG_INFO, "%s: \"safemode\" feature no longer supported\n",
|
||||
progname);
|
||||
|
@ -524,12 +523,6 @@ int main(int argc, char * argv [])
|
|||
exit(1);
|
||||
}
|
||||
ladd(updates, upd);
|
||||
|
||||
if (verify && upd->op == DEVICE_WRITE) {
|
||||
upd = dup_update(upd);
|
||||
upd->op = DEVICE_VERIFY;
|
||||
ladd(updates, upd);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
|
@ -537,7 +530,7 @@ int main(int argc, char * argv [])
|
|||
break;
|
||||
|
||||
case 'V':
|
||||
verify = 0;
|
||||
uflags &= ~UF_VERIFY;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
|
@ -758,8 +751,15 @@ int main(int argc, char * argv [])
|
|||
bitclock = default_bitclock;
|
||||
}
|
||||
|
||||
|
||||
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 (strcmp(partdesc, "?") == 0) {
|
||||
avrdude_message(MSG_INFO, "\n");
|
||||
|
@ -919,6 +919,12 @@ int main(int argc, char * argv [])
|
|||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!avr_mem_might_be_known(upd->memtype)) {
|
||||
avrdude_message(MSG_INFO, "%s: unknown memory type %s\n", progname, upd->memtype);
|
||||
exit(1);
|
||||
}
|
||||
// TODO: check whether filename other than "-" is readable/writable
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1096,7 +1102,7 @@ int main(int argc, char * argv [])
|
|||
goto main_exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sig = avr_locate_mem(p, "signature");
|
||||
if (sig == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s: WARNING: signature data not defined for device \"%s\"\n",
|
||||
|
@ -1244,7 +1250,7 @@ int main(int argc, char * argv [])
|
|||
for (ln=lfirst(updates); ln; ln=lnext(ln)) {
|
||||
upd = ldata(ln);
|
||||
rc = do_op(pgm, p, upd, uflags);
|
||||
if (rc) {
|
||||
if (rc && rc != LIBAVRDUDE_SOFTFAIL) {
|
||||
exitrc = 1;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -79,6 +79,7 @@ PROGRAMMER * pgm_new(void)
|
|||
pgm->usbpid = lcreat(NULL, 0);
|
||||
pgm->desc[0] = 0;
|
||||
pgm->type[0] = 0;
|
||||
pgm->parent_id = NULL;
|
||||
pgm->config_file = NULL;
|
||||
pgm->lineno = 0;
|
||||
pgm->baudrate = 0;
|
||||
|
@ -145,11 +146,8 @@ void pgm_free(PROGRAMMER * const p)
|
|||
ldestroy_cb(p->usbpid, free);
|
||||
p->id = NULL;
|
||||
p->usbpid = NULL;
|
||||
/* this is done by pgm_teardown, but usually cookie is not set to NULL */
|
||||
/* if (p->cookie !=NULL) {
|
||||
free(p->cookie);
|
||||
p->cookie = NULL;
|
||||
}*/
|
||||
/* do not free p->parent_id nor p->config_file */
|
||||
/* p->cookie is freed by pgm_teardown */
|
||||
free(p);
|
||||
}
|
||||
|
||||
|
@ -169,7 +167,6 @@ PROGRAMMER * pgm_dup(const PROGRAMMER * const src)
|
|||
|
||||
pgm->id = lcreat(NULL, 0);
|
||||
pgm->usbpid = lcreat(NULL, 0);
|
||||
|
||||
for (ln = lfirst(src->usbpid); ln; ln = lnext(ln)) {
|
||||
int *ip = malloc(sizeof(int));
|
||||
if (ip == NULL) {
|
||||
|
|
|
@ -80,6 +80,7 @@ const PROGRAMMER_TYPE programmers_types[] = {
|
|||
{"jtagmkii_dw", jtagmkII_dw_initpgm, jtagmkII_dw_desc},
|
||||
{"jtagmkii_isp", stk500v2_jtagmkII_initpgm, stk500v2_jtagmkII_desc},
|
||||
{"jtagmkii_pdi", jtagmkII_pdi_initpgm, jtagmkII_pdi_desc},
|
||||
{"jtagmkii_updi", jtagmkII_updi_initpgm, jtagmkII_updi_desc},
|
||||
{"jtagice3", jtag3_initpgm, jtag3_desc},
|
||||
{"jtagice3_pdi", jtag3_pdi_initpgm, jtag3_pdi_desc},
|
||||
{"jtagice3_updi", jtag3_updi_initpgm, jtag3_updi_desc},
|
||||
|
|
82
src/stk500.c
82
src/stk500.c
|
@ -91,8 +91,6 @@ int stk500_getsync(PROGRAMMER * pgm)
|
|||
int attempt;
|
||||
int max_sync_attempts;
|
||||
|
||||
/*
|
||||
* get in sync */
|
||||
buf[0] = Cmnd_STK_GET_SYNC;
|
||||
buf[1] = Sync_CRC_EOP;
|
||||
|
||||
|
@ -119,11 +117,12 @@ int stk500_getsync(PROGRAMMER * pgm)
|
|||
usleep(50*1000);
|
||||
stk500_drain(pgm, 0);
|
||||
}
|
||||
|
||||
stk500_send(pgm, buf, 2);
|
||||
stk500_recv(pgm, resp, 1);
|
||||
if (resp[0] == Resp_STK_INSYNC){
|
||||
resp[0] = 0;
|
||||
if(stk500_recv(pgm, resp, 1) >= 0 && resp[0] == Resp_STK_INSYNC)
|
||||
break;
|
||||
}
|
||||
|
||||
avrdude_message(MSG_INFO, "%s: stk500_getsync() attempt %d of %d: not in sync: resp=0x%02x\n",
|
||||
progname, attempt + 1, max_sync_attempts, resp[0]);
|
||||
}
|
||||
|
@ -204,15 +203,14 @@ static int stk500_chip_erase(PROGRAMMER * pgm, AVRPART * p)
|
|||
}
|
||||
|
||||
if (p->op[AVR_OP_CHIP_ERASE] == NULL) {
|
||||
avrdude_message(MSG_INFO, "chip erase instruction not defined for part \"%s\"\n",
|
||||
p->desc);
|
||||
avrdude_message(MSG_INFO, "%s: chip erase instruction not defined for part \"%s\"\n",
|
||||
progname, p->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pgm->pgm_led(pgm, ON);
|
||||
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
|
||||
avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd);
|
||||
pgm->cmd(pgm, cmd, res);
|
||||
usleep(p->chip_erase_delay);
|
||||
|
@ -745,8 +743,8 @@ static int stk500_loadaddr(PROGRAMMER * pgm, AVRMEM * mem, unsigned int addr)
|
|||
if (lext != NULL) {
|
||||
ext_byte = (addr >> 16) & 0xff;
|
||||
if (ext_byte != PDATA(pgm)->ext_addr_byte) {
|
||||
/* Either this is the first addr load, or a 64K word boundary is
|
||||
* crossed, so set the ext addr byte */
|
||||
/* Either this is the first addr load, or a different 64K word section */
|
||||
memset(buf, 0, 4);
|
||||
avr_set_bits(lext, buf);
|
||||
avr_set_addr(lext, buf, addr);
|
||||
stk500_cmd(pgm, buf, buf);
|
||||
|
@ -782,13 +780,12 @@ static int stk500_loadaddr(PROGRAMMER * pgm, AVRMEM * mem, unsigned int addr)
|
|||
|
||||
if (stk500_recv(pgm, buf, 1) < 0)
|
||||
return -1;
|
||||
if (buf[0] == Resp_STK_OK) {
|
||||
if (buf[0] == Resp_STK_OK)
|
||||
return 0;
|
||||
}
|
||||
|
||||
avrdude_message(MSG_INFO, "%s: loadaddr(): (b) protocol error, "
|
||||
avrdude_message(MSG_INFO, "%s: stk500_loadaddr(): (b) protocol error, "
|
||||
"expect=0x%02x, resp=0x%02x\n",
|
||||
progname, Resp_STK_INSYNC, buf[0]);
|
||||
progname, Resp_STK_OK, buf[0]);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
@ -808,19 +805,20 @@ static int stk500_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
|||
|
||||
if (strcmp(m->desc, "flash") == 0) {
|
||||
memtype = 'F';
|
||||
}
|
||||
else if (strcmp(m->desc, "eeprom") == 0) {
|
||||
a_div = 2;
|
||||
} else if (strcmp(m->desc, "eeprom") == 0) {
|
||||
memtype = 'E';
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* The STK original 500 v1 protocol actually expects a_div = 1, but the
|
||||
* v1.x FW of the STK500 kit has been superseded by v2 FW in the mid
|
||||
* 2000s. Since optiboot, arduino as ISP and others assume a_div = 2,
|
||||
* better use that. See https://github.com/avrdudes/avrdude/issues/967
|
||||
*/
|
||||
a_div = 2;
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
|
||||
if ((m->op[AVR_OP_LOADPAGE_LO]) || (m->op[AVR_OP_READ_LO]))
|
||||
a_div = 2;
|
||||
else
|
||||
a_div = 1;
|
||||
|
||||
n = addr + n_bytes;
|
||||
#if 0
|
||||
avrdude_message(MSG_INFO, "n_bytes = %d\n"
|
||||
|
@ -828,7 +826,7 @@ static int stk500_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
|||
"a_div = %d\n"
|
||||
"page_size = %d\n",
|
||||
n_bytes, n, a_div, page_size);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
for (; addr < n; addr += block_size) {
|
||||
// MIB510 uses fixed blocks size of 256 bytes
|
||||
|
@ -875,13 +873,13 @@ static int stk500_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
|||
progname, Resp_STK_INSYNC, buf[0]);
|
||||
return -4;
|
||||
}
|
||||
|
||||
|
||||
if (stk500_recv(pgm, buf, 1) < 0)
|
||||
return -1;
|
||||
if (buf[0] != Resp_STK_OK) {
|
||||
avrdude_message(MSG_INFO, "\n%s: stk500_paged_write(): (a) protocol error, "
|
||||
avrdude_message(MSG_INFO, "\n%s: stk500_paged_write(): (b) protocol error, "
|
||||
"expect=0x%02x, resp=0x%02x\n",
|
||||
progname, Resp_STK_INSYNC, buf[0]);
|
||||
progname, Resp_STK_OK, buf[0]);
|
||||
return -5;
|
||||
}
|
||||
}
|
||||
|
@ -902,19 +900,20 @@ static int stk500_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
|||
|
||||
if (strcmp(m->desc, "flash") == 0) {
|
||||
memtype = 'F';
|
||||
}
|
||||
else if (strcmp(m->desc, "eeprom") == 0) {
|
||||
a_div = 2;
|
||||
} else if (strcmp(m->desc, "eeprom") == 0) {
|
||||
memtype = 'E';
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* The STK original 500 v1 protocol actually expects a_div = 1, but the
|
||||
* v1.x FW of the STK500 kit has been superseded by v2 FW in the mid
|
||||
* 2000s. Since optiboot, arduino as ISP and others assume a_div = 2,
|
||||
* better use that. See https://github.com/avrdudes/avrdude/issues/967
|
||||
*/
|
||||
a_div = 2;
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
|
||||
if ((m->op[AVR_OP_LOADPAGE_LO]) || (m->op[AVR_OP_READ_LO]))
|
||||
a_div = 2;
|
||||
else
|
||||
a_div = 1;
|
||||
|
||||
n = addr + n_bytes;
|
||||
for (; addr < n; addr += block_size) {
|
||||
// MIB510 uses fixed blocks size of 256 bytes
|
||||
|
@ -973,7 +972,7 @@ static int stk500_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
|||
}
|
||||
else {
|
||||
if (buf[0] != Resp_STK_OK) {
|
||||
avrdude_message(MSG_INFO, "\n%s: stk500_paged_load(): (a) protocol error, "
|
||||
avrdude_message(MSG_INFO, "\n%s: stk500_paged_load(): (b) protocol error, "
|
||||
"expect=0x%02x, resp=0x%02x\n",
|
||||
progname, Resp_STK_OK, buf[0]);
|
||||
return -5;
|
||||
|
@ -1037,7 +1036,8 @@ static int stk500_set_fosc(PROGRAMMER * pgm, double v)
|
|||
static unsigned ps[] = {
|
||||
1, 8, 32, 64, 128, 256, 1024
|
||||
};
|
||||
int idx, rc;
|
||||
size_t idx;
|
||||
int rc;
|
||||
|
||||
prescale = cmatch = 0;
|
||||
if (v > 0.0) {
|
||||
|
@ -1155,7 +1155,7 @@ static int stk500_getparm(PROGRAMMER * pgm, unsigned parm, unsigned * value)
|
|||
return -3;
|
||||
}
|
||||
else if (buf[0] != Resp_STK_OK) {
|
||||
avrdude_message(MSG_INFO, "\n%s: stk500_getparm(): (a) protocol error, "
|
||||
avrdude_message(MSG_INFO, "\n%s: stk500_getparm(): (b) protocol error, "
|
||||
"expect=0x%02x, resp=0x%02x\n",
|
||||
progname, Resp_STK_OK, buf[0]);
|
||||
return -3;
|
||||
|
@ -1214,9 +1214,9 @@ static int stk500_setparm(PROGRAMMER * pgm, unsigned parm, unsigned value)
|
|||
return -3;
|
||||
}
|
||||
else {
|
||||
avrdude_message(MSG_INFO, "\n%s: stk500_setparm(): (a) protocol error, "
|
||||
avrdude_message(MSG_INFO, "\n%s: stk500_setparm(): (b) protocol error, "
|
||||
"expect=0x%02x, resp=0x%02x\n",
|
||||
progname, Resp_STK_INSYNC, buf[0]);
|
||||
progname, Resp_STK_OK, buf[0]);
|
||||
return -3;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -392,9 +392,7 @@ static int stk500v2_send_mk2(PROGRAMMER * pgm, unsigned char * data, size_t len)
|
|||
|
||||
static unsigned short get_jtagisp_return_size(unsigned char cmd)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof jtagispcmds / sizeof jtagispcmds[0]; i++)
|
||||
for (size_t i = 0; i < sizeof jtagispcmds / sizeof jtagispcmds[0]; i++)
|
||||
if (jtagispcmds[i].cmd == cmd)
|
||||
return jtagispcmds[i].size;
|
||||
|
||||
|
@ -481,7 +479,6 @@ static int stk500v2_jtag3_send(PROGRAMMER * pgm, unsigned char * data, size_t le
|
|||
static int stk500v2_send(PROGRAMMER * pgm, unsigned char * data, size_t len)
|
||||
{
|
||||
unsigned char buf[275 + 6]; // max MESSAGE_BODY of 275 bytes, 6 bytes overhead
|
||||
int i;
|
||||
|
||||
if (PDATA(pgm)->pgmtype == PGMTYPE_AVRISP_MKII ||
|
||||
PDATA(pgm)->pgmtype == PGMTYPE_STK600)
|
||||
|
@ -500,12 +497,13 @@ static int stk500v2_send(PROGRAMMER * pgm, unsigned char * data, size_t len)
|
|||
|
||||
// calculate the XOR checksum
|
||||
buf[5+len] = 0;
|
||||
for (i=0;i<5+len;i++)
|
||||
for (size_t i=0; i<5+len; i++)
|
||||
buf[5+len] ^= buf[i];
|
||||
|
||||
DEBUG("STK500V2: stk500v2_send(");
|
||||
for (i=0;i<len+6;i++) DEBUG("0x%02x ",buf[i]);
|
||||
DEBUG(", %d)\n",len+6);
|
||||
for (size_t i=0; i<len+6; i++)
|
||||
DEBUG("0x%02x ", buf[i]);
|
||||
DEBUG(", %d)\n", (int) len+6);
|
||||
|
||||
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);
|
||||
|
@ -551,9 +549,9 @@ static int stk500v2_jtagmkII_recv(PROGRAMMER * pgm, unsigned char *msg,
|
|||
progname);
|
||||
return -1;
|
||||
}
|
||||
if (rv - 1 > maxsize) {
|
||||
if ((size_t) rv - 1 > maxsize) {
|
||||
avrdude_message(MSG_INFO, "%s: stk500v2_jtagmkII_recv(): got %u bytes, have only room for %u bytes\n",
|
||||
progname, (unsigned)rv - 1, (unsigned)maxsize);
|
||||
progname, (unsigned) rv - 1, (unsigned) maxsize);
|
||||
rv = maxsize;
|
||||
}
|
||||
switch (jtagmsg[0]) {
|
||||
|
@ -597,9 +595,9 @@ static int stk500v2_jtag3_recv(PROGRAMMER * pgm, unsigned char *msg,
|
|||
implementation of JTAGICE3, as they always request a full 512
|
||||
octets from the ICE. Thus, only complain at high verbose
|
||||
levels. */
|
||||
if (rv - 1 > maxsize) {
|
||||
if ((size_t) rv - 1 > maxsize) {
|
||||
avrdude_message(MSG_DEBUG, "%s: stk500v2_jtag3_recv(): got %u bytes, have only room for %u bytes\n",
|
||||
progname, (unsigned)rv - 1, (unsigned)maxsize);
|
||||
progname, (unsigned) rv - 1, (unsigned) maxsize);
|
||||
rv = maxsize;
|
||||
}
|
||||
if (jtagmsg[0] != SCOPE_AVR_ISP) {
|
||||
|
@ -814,13 +812,13 @@ retry:
|
|||
|
||||
static int stk500v2_command(PROGRAMMER * pgm, unsigned char * buf,
|
||||
size_t len, size_t maxlen) {
|
||||
int i;
|
||||
int tries = 0;
|
||||
int status;
|
||||
|
||||
DEBUG("STK500V2: stk500v2_command(");
|
||||
for (i=0;i<len;i++) DEBUG("0x%02x ",buf[i]);
|
||||
DEBUG(", %d)\n",len);
|
||||
for (size_t i=0; i<len; i++)
|
||||
DEBUG("0x%02x ",buf[i]);
|
||||
DEBUG(", %d)\n", (int) len);
|
||||
|
||||
retry:
|
||||
tries++;
|
||||
|
@ -991,6 +989,7 @@ static int stk500v2_chip_erase(PROGRAMMER * pgm, AVRPART * p)
|
|||
buf[0] = CMD_CHIP_ERASE_ISP;
|
||||
buf[1] = p->chip_erase_delay / 1000;
|
||||
buf[2] = 0; // use delay (?)
|
||||
memset(buf+3, 0, 4);
|
||||
avr_set_bits(p->op[AVR_OP_CHIP_ERASE], buf+3);
|
||||
result = stk500v2_command(pgm, buf, 7, sizeof(buf));
|
||||
usleep(p->chip_erase_delay);
|
||||
|
@ -1121,8 +1120,8 @@ retry:
|
|||
buf[5] = p->bytedelay;
|
||||
buf[6] = p->pollvalue;
|
||||
buf[7] = p->pollindex;
|
||||
memset(buf+8, 0, 4);
|
||||
avr_set_bits(p->op[AVR_OP_PGM_ENABLE], buf+8);
|
||||
buf[10] = buf[11] = 0;
|
||||
|
||||
rv = stk500v2_command(pgm, buf, 12, sizeof(buf));
|
||||
|
||||
|
@ -1957,12 +1956,12 @@ static int stk500isp_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
|
|||
buf[0] = CMD_READ_SIGNATURE_ISP;
|
||||
}
|
||||
|
||||
memset(buf + 1, 0, 5);
|
||||
if ((op = mem->op[AVR_OP_READ]) == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s: stk500isp_read_byte(): invalid operation AVR_OP_READ on %s memory\n",
|
||||
progname, mem->desc);
|
||||
return -1;
|
||||
}
|
||||
memset(buf+2, 0, 4);
|
||||
avr_set_bits(op, buf + 2);
|
||||
if ((pollidx = avr_get_output_index(op)) == -1) {
|
||||
avrdude_message(MSG_INFO, "%s: stk500isp_read_byte(): cannot determine pollidx to read %s memory\n",
|
||||
|
@ -2314,6 +2313,7 @@ static int stk500v2_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
|||
progname, p->desc);
|
||||
return -1;
|
||||
}
|
||||
memset(cmds, 0, sizeof cmds);
|
||||
avr_set_bits(m->op[AVR_OP_LOADPAGE_LO], cmds);
|
||||
commandbuf[5] = cmds[0];
|
||||
|
||||
|
@ -2322,6 +2322,8 @@ static int stk500v2_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
|||
progname, p->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(cmds, 0, sizeof cmds);
|
||||
avr_set_bits(m->op[AVR_OP_WRITEPAGE], cmds);
|
||||
commandbuf[6] = cmds[0];
|
||||
|
||||
|
@ -2335,6 +2337,7 @@ static int stk500v2_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
|||
progname, p->desc);
|
||||
return -1;
|
||||
}
|
||||
memset(cmds, 0, sizeof cmds);
|
||||
avr_set_bits(wop, cmds);
|
||||
commandbuf[5] = cmds[0];
|
||||
commandbuf[6] = 0;
|
||||
|
@ -2346,6 +2349,7 @@ static int stk500v2_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
|||
progname, p->desc);
|
||||
return -1;
|
||||
}
|
||||
memset(cmds, 0, sizeof cmds);
|
||||
avr_set_bits(rop, cmds);
|
||||
commandbuf[7] = cmds[0];
|
||||
|
||||
|
@ -2549,6 +2553,7 @@ static int stk500v2_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
|||
progname, p->desc);
|
||||
return -1;
|
||||
}
|
||||
memset(cmds, 0, sizeof cmds);
|
||||
avr_set_bits(rop, cmds);
|
||||
commandbuf[3] = cmds[0];
|
||||
|
||||
|
@ -2753,7 +2758,8 @@ static int stk500v2_set_fosc(PROGRAMMER * pgm, double v)
|
|||
static unsigned ps[] = {
|
||||
1, 8, 32, 64, 128, 256, 1024
|
||||
};
|
||||
int idx, rc;
|
||||
size_t idx;
|
||||
int rc;
|
||||
|
||||
prescale = cmatch = 0;
|
||||
if (v > 0.0) {
|
||||
|
@ -2774,7 +2780,7 @@ static int stk500v2_set_fosc(PROGRAMMER * pgm, double v)
|
|||
fosc = (unsigned)v;
|
||||
|
||||
for (idx = 0; idx < sizeof(ps) / sizeof(ps[0]); idx++) {
|
||||
if (fosc >= STK500V2_XTAL / (256 * ps[idx] * 2)) {
|
||||
if ((unsigned) fosc >= STK500V2_XTAL / (256 * ps[idx] * 2)) {
|
||||
/* this prescaler value can handle our frequency */
|
||||
prescale = idx + 1;
|
||||
cmatch = (unsigned)(STK500V2_XTAL / (2 * fosc * ps[idx])) - 1;
|
||||
|
@ -2821,7 +2827,7 @@ static double avrispmkIIfreqs[] = {
|
|||
|
||||
static int stk500v2_set_sck_period_mk2(PROGRAMMER * pgm, double v)
|
||||
{
|
||||
int i;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < sizeof(avrispmkIIfreqs) / sizeof(avrispmkIIfreqs[0]); i++) {
|
||||
if (1 / avrispmkIIfreqs[i] >= v)
|
||||
|
|
332
src/update.c
332
src/update.c
|
@ -45,7 +45,7 @@ UPDATE * parse_op(char * s)
|
|||
|
||||
i = 0;
|
||||
p = s;
|
||||
while ((i < (sizeof(buf)-1) && *p && (*p != ':')))
|
||||
while (i < (int) sizeof(buf)-1 && *p && *p != ':')
|
||||
buf[i++] = *p++;
|
||||
buf[i] = 0;
|
||||
|
||||
|
@ -130,6 +130,7 @@ UPDATE * parse_op(char * s)
|
|||
case 'a': upd->format = FMT_AUTO; break;
|
||||
case 's': upd->format = FMT_SREC; break;
|
||||
case 'i': upd->format = FMT_IHEX; break;
|
||||
case 'I': upd->format = FMT_IHXC; break;
|
||||
case 'r': upd->format = FMT_RBIN; break;
|
||||
case 'e': upd->format = FMT_ELF; break;
|
||||
case 'm': upd->format = FMT_IMM; break;
|
||||
|
@ -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)
|
||||
{
|
||||
struct avrpart * v;
|
||||
AVRMEM * mem;
|
||||
int size, vsize;
|
||||
int size;
|
||||
int rc;
|
||||
Filestats fs;
|
||||
|
||||
mem = avr_locate_mem(p, upd->memtype);
|
||||
if (mem == NULL) {
|
||||
avrdude_message(MSG_INFO, "\"%s\" memory type not defined for part \"%s\"\n",
|
||||
upd->memtype, p->desc);
|
||||
return -1;
|
||||
avrdude_message(MSG_INFO, "%s: skipping -U %s:... as memory not defined for part %s\n",
|
||||
progname, upd->memtype, p->desc);
|
||||
return LIBAVRDUDE_SOFTFAIL;
|
||||
}
|
||||
|
||||
AVRMEM_ALIAS * alias_mem = avr_find_memalias(p, mem);
|
||||
|
@ -234,161 +341,190 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f
|
|||
strcat(alias_mem_desc, alias_mem->desc);
|
||||
}
|
||||
|
||||
if (upd->op == DEVICE_READ) {
|
||||
/*
|
||||
* read out the specified device memory and write it to a file
|
||||
*/
|
||||
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");
|
||||
switch (upd->op) {
|
||||
case DEVICE_READ:
|
||||
// Read out the specified device memory and write it to a file
|
||||
if (upd->format == FMT_IMM) {
|
||||
avrdude_message(MSG_INFO,
|
||||
"%s: Invalid file format 'immediate' for output\n", progname);
|
||||
return LIBAVRDUDE_GENERAL_FAILURE;
|
||||
}
|
||||
if (quell_progress < 2)
|
||||
avrdude_message(MSG_INFO, "%s: reading %s%s memory ...\n",
|
||||
progname, mem->desc, alias_mem_desc);
|
||||
|
||||
report_progress(0, 1, "Reading");
|
||||
|
||||
rc = avr_read(pgm, p, upd->memtype, 0);
|
||||
report_progress(1, 1, NULL);
|
||||
if (rc < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: failed to read all of %s%s memory, rc=%d\n",
|
||||
progname, mem->desc, alias_mem_desc, rc);
|
||||
return -1;
|
||||
progname, mem->desc, alias_mem_desc, rc);
|
||||
return LIBAVRDUDE_GENERAL_FAILURE;
|
||||
}
|
||||
report_progress(1,1,NULL);
|
||||
size = rc;
|
||||
|
||||
if (quell_progress < 2) {
|
||||
if (rc == 0)
|
||||
avrdude_message(MSG_INFO, "%s: Flash is empty, resulting file has no contents.\n",
|
||||
progname);
|
||||
avrdude_message(MSG_INFO, "%s: writing output file \"%s\"\n",
|
||||
progname,
|
||||
strcmp(upd->filename, "-")==0 ? "<stdout>" : upd->filename);
|
||||
avrdude_message(MSG_INFO, "%s: flash is empty, resulting file has no contents\n",
|
||||
progname);
|
||||
avrdude_message(MSG_INFO, "%s: writing output file %s\n",
|
||||
progname, outname(upd->filename));
|
||||
}
|
||||
rc = fileio(FIO_WRITE, upd->filename, upd->format, p, upd->memtype, size);
|
||||
if (rc < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: write to file '%s' failed\n",
|
||||
progname, upd->filename);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (upd->op == DEVICE_WRITE) {
|
||||
/*
|
||||
* write the selected device memory using data from a file; first
|
||||
* read the data from the specified file
|
||||
*/
|
||||
if (quell_progress < 2) {
|
||||
avrdude_message(MSG_INFO, "%s: reading input file \"%s\"\n",
|
||||
progname,
|
||||
strcmp(upd->filename, "-")==0 ? "<stdin>" : upd->filename);
|
||||
avrdude_message(MSG_INFO, "%s: write to file %s failed\n",
|
||||
progname, outname(upd->filename));
|
||||
return LIBAVRDUDE_GENERAL_FAILURE;
|
||||
}
|
||||
break;
|
||||
|
||||
case DEVICE_WRITE:
|
||||
// Write the selected device memory using data from a file
|
||||
|
||||
rc = fileio(FIO_READ, upd->filename, upd->format, p, upd->memtype, -1);
|
||||
if (quell_progress < 2)
|
||||
avrdude_message(MSG_INFO, "%s: reading input file %s for %s%s\n",
|
||||
progname, inname(upd->filename), mem->desc, alias_mem_desc);
|
||||
if (rc < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: read from file '%s' failed\n",
|
||||
progname, upd->filename);
|
||||
return -1;
|
||||
avrdude_message(MSG_INFO, "%s: read from file %s failed\n",
|
||||
progname, inname(upd->filename));
|
||||
return LIBAVRDUDE_GENERAL_FAILURE;
|
||||
}
|
||||
size = rc;
|
||||
|
||||
/*
|
||||
* write the buffer contents to the selected memory type
|
||||
*/
|
||||
if (quell_progress < 2) {
|
||||
avrdude_message(MSG_INFO, "%s: writing %s%s (%d bytes):\n",
|
||||
progname, mem->desc, alias_mem_desc, size);
|
||||
}
|
||||
if(memstats(p, upd->memtype, size, &fs) < 0)
|
||||
return LIBAVRDUDE_GENERAL_FAILURE;
|
||||
|
||||
if(quell_progress < 2) {
|
||||
int level = fs.nsections > 1 || fs.firstaddr > 0 || fs.ntrailing? MSG_INFO: MSG_NOTICE;
|
||||
|
||||
avrdude_message(level, "%*s with %d byte%s in %d section%s within %s\n",
|
||||
(int) strlen(progname)+1, "",
|
||||
fs.nbytes, plural(fs.nbytes),
|
||||
fs.nsections, plural(fs.nsections),
|
||||
interval(fs.firstaddr, fs.lastaddr));
|
||||
if(mem->page_size > 1) {
|
||||
avrdude_message(level, "%*s using %d page%s and %d pad byte%s",
|
||||
(int) strlen(progname)+1, "",
|
||||
fs.npages, plural(fs.npages),
|
||||
fs.nfill, plural(fs.nfill));
|
||||
if(fs.ntrailing)
|
||||
avrdude_message(level, ", cutting off %d trailing 0xff byte%s",
|
||||
fs.ntrailing, plural(fs.ntrailing));
|
||||
avrdude_message(level, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Write the buffer contents to the selected memory type
|
||||
if (quell_progress < 2)
|
||||
avrdude_message(MSG_INFO, "%s: writing %d byte%s %s%s ...\n",
|
||||
progname, fs.nbytes, plural(fs.nbytes), mem->desc, alias_mem_desc);
|
||||
|
||||
if (!(flags & UF_NOWRITE)) {
|
||||
report_progress(0,1,"Writing");
|
||||
report_progress(0, 1, "Writing");
|
||||
rc = avr_write(pgm, p, upd->memtype, size, (flags & UF_AUTO_ERASE) != 0);
|
||||
report_progress(1,1,NULL);
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* test mode, don't actually write to the chip, output the buffer
|
||||
* to stdout in intel hex instead
|
||||
*/
|
||||
report_progress(1, 1, NULL);
|
||||
} else {
|
||||
// Test mode: write to stdout in intel hex rather than to the chip
|
||||
rc = fileio(FIO_WRITE, "-", FMT_IHEX, p, upd->memtype, size);
|
||||
}
|
||||
|
||||
if (rc < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: failed to write %s%s memory, rc=%d\n",
|
||||
progname, mem->desc, alias_mem_desc, rc);
|
||||
return -1;
|
||||
progname, mem->desc, alias_mem_desc, rc);
|
||||
return LIBAVRDUDE_GENERAL_FAILURE;
|
||||
}
|
||||
|
||||
vsize = rc;
|
||||
if (quell_progress < 2)
|
||||
avrdude_message(MSG_INFO, "%s: %d byte%s of %s%s written\n",
|
||||
progname, fs.nbytes, plural(fs.nbytes), mem->desc, alias_mem_desc);
|
||||
|
||||
if (quell_progress < 2) {
|
||||
avrdude_message(MSG_INFO, "%s: %d bytes of %s%s written\n", progname,
|
||||
vsize, mem->desc, alias_mem_desc);
|
||||
}
|
||||
// Fall through for (default) auto verify, ie, unless -V was specified
|
||||
if (!(flags & UF_VERIFY))
|
||||
break;
|
||||
|
||||
}
|
||||
else if (upd->op == DEVICE_VERIFY) {
|
||||
/*
|
||||
* verify that the in memory file (p->mem[AVR_M_FLASH|AVR_M_EEPROM])
|
||||
* is the same as what is on the chip
|
||||
*/
|
||||
case DEVICE_VERIFY:
|
||||
// Verify that the in memory file is the same as what is on the chip
|
||||
pgm->vfy_led(pgm, ON);
|
||||
|
||||
int userverify = upd->op == DEVICE_VERIFY; // Explicit -U :v by user
|
||||
|
||||
if (quell_progress < 2) {
|
||||
avrdude_message(MSG_INFO, "%s: verifying %s%s memory against %s:\n",
|
||||
progname, mem->desc, alias_mem_desc, upd->filename);
|
||||
avrdude_message(MSG_INFO, "%s: verifying %s%s memory against %s\n",
|
||||
progname, mem->desc, alias_mem_desc, inname(upd->filename));
|
||||
|
||||
avrdude_message(MSG_NOTICE2, "%s: load data %s%s data from input file %s:\n",
|
||||
progname, mem->desc, alias_mem_desc, upd->filename);
|
||||
if (userverify)
|
||||
avrdude_message(MSG_NOTICE, "%s: load %s%s data from input file %s\n",
|
||||
progname, mem->desc, alias_mem_desc, inname(upd->filename));
|
||||
}
|
||||
|
||||
rc = fileio(FIO_READ_FOR_VERIFY, upd->filename, upd->format, p, upd->memtype, -1);
|
||||
if (rc < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: read from file '%s' failed\n",
|
||||
progname, upd->filename);
|
||||
return -1;
|
||||
// No need to read file when fallen through from DEVICE_WRITE
|
||||
if (userverify) {
|
||||
rc = fileio(FIO_READ_FOR_VERIFY, upd->filename, upd->format, p, upd->memtype, -1);
|
||||
|
||||
if (rc < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: read from file %s failed\n",
|
||||
progname, inname(upd->filename));
|
||||
return LIBAVRDUDE_GENERAL_FAILURE;
|
||||
}
|
||||
size = rc;
|
||||
|
||||
if(memstats(p, upd->memtype, size, &fs) < 0)
|
||||
return LIBAVRDUDE_GENERAL_FAILURE;
|
||||
} else {
|
||||
// Correct size of last read to include potentially cut off, trailing 0xff (flash)
|
||||
size = fs.lastaddr+1;
|
||||
}
|
||||
|
||||
v = avr_dup_part(p);
|
||||
size = rc;
|
||||
|
||||
if (quell_progress < 2) {
|
||||
avrdude_message(MSG_NOTICE2, "%s: input file %s contains %d bytes\n",
|
||||
progname, upd->filename, size);
|
||||
avrdude_message(MSG_NOTICE2, "%s: reading on-chip %s%s data:\n",
|
||||
progname, mem->desc, alias_mem_desc);
|
||||
if (userverify)
|
||||
avrdude_message(MSG_NOTICE, "%s: input file %s contains %d byte%s\n",
|
||||
progname, inname(upd->filename), fs.nbytes, plural(fs.nbytes));
|
||||
avrdude_message(MSG_NOTICE2, "%s: reading on-chip %s%s data ...\n",
|
||||
progname, mem->desc, alias_mem_desc);
|
||||
}
|
||||
|
||||
report_progress (0,1,"Reading");
|
||||
rc = avr_read(pgm, p, upd->memtype, v);
|
||||
report_progress (1,1,NULL);
|
||||
if (rc < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: failed to read all of %s%s memory, rc=%d\n",
|
||||
progname, mem->desc, alias_mem_desc, rc);
|
||||
progname, mem->desc, alias_mem_desc, rc);
|
||||
pgm->err_led(pgm, ON);
|
||||
avr_free_part(v);
|
||||
return -1;
|
||||
return LIBAVRDUDE_GENERAL_FAILURE;
|
||||
}
|
||||
report_progress (1,1,NULL);
|
||||
|
||||
|
||||
|
||||
if (quell_progress < 2) {
|
||||
if (quell_progress < 2)
|
||||
avrdude_message(MSG_NOTICE2, "%s: verifying ...\n", progname);
|
||||
}
|
||||
|
||||
rc = avr_verify(p, v, upd->memtype, size);
|
||||
if (rc < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: verification error; content mismatch\n",
|
||||
progname);
|
||||
progname);
|
||||
pgm->err_led(pgm, ON);
|
||||
avr_free_part(v);
|
||||
return -1;
|
||||
return LIBAVRDUDE_GENERAL_FAILURE;
|
||||
}
|
||||
|
||||
if (quell_progress < 2) {
|
||||
avrdude_message(MSG_INFO, "%s: %d bytes of %s%s verified\n",
|
||||
progname, rc, mem->desc, alias_mem_desc);
|
||||
int verified = fs.nbytes+fs.ntrailing;
|
||||
avrdude_message(MSG_INFO, "%s: %d byte%s of %s%s verified\n",
|
||||
progname, verified, plural(verified), mem->desc, alias_mem_desc);
|
||||
}
|
||||
|
||||
pgm->vfy_led(pgm, OFF);
|
||||
avr_free_part(v);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
|
||||
default:
|
||||
avrdude_message(MSG_INFO, "%s: invalid update operation (%d) requested\n",
|
||||
progname, upd->op);
|
||||
return -1;
|
||||
progname, upd->op);
|
||||
return LIBAVRDUDE_GENERAL_FAILURE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return LIBAVRDUDE_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue