Merge remote-tracking branch 'upstream/main' into swig_libavrdude

This commit is contained in:
Joerg Wunsch
2024-08-10 07:51:49 +02:00
146 changed files with 25960 additions and 21584 deletions

View File

@@ -213,6 +213,7 @@ jobs:
bison
libelf
libusb
libusb-compat
hidapi
libftdi
readline

25
AUTHORS
View File

@@ -13,32 +13,48 @@ AVRDUDE is currently maintained by:
Contributors:
Joerg Wunsch <j@uriah.heep.sax.de>
Eric Weddington <ericw@evcohs.com>
Eric B. Weddington <ericw@evcohs.com>
Martin J. Thomas <mthomas@rhrk.uni-kl.de>
Theodore A. Roth <troth@openavr.org>
Erik Walthinsen
Jan-Hinnerk Reichert <hinni@despammed.com>
Alex Shepherd <maillists@ajsystems.co.nz>
Martin Thomas <mthomas@rhrk.uni-kl.de>
Theodore A. Roth <troth@openavr.org>
Juliane Holzt <avrdude@juliane.holzt.de>
Colin O'Flynn <coflynn@newae.com>
Thomas Fischl <tfischl@gmx.de>
David Hoerl <dhoerl@mac.com>
Christian Starkjohann
David Moore
David Brownell
Dick Streefland
Limor Fried
Klaus Leidinger <klaus@mikrocontroller-projekte.de>
Lars Immisch
Michal Ludvig <mludvig@logix.net.nz>
Roger E. Wolff <R.E.Wolff@BitWizard.nl>
Darell Tan <darell.tan@gmail.com>
Brett Hagman <bhagman@roguerobotics.com>
Wolfgang Moser
Ville Voipio
Hannes Weisbach
Doug Springer
Brett Hagman <bhagman@roguerobotics.com>
Rene Liebscher <r.liebscher@gmx.de>
Jim Paris <jim@jtan.com>
Jan Egil Ruud <janegil.ruud@microchip.com>
David Mosberger <davidm@egauge.net>
Kirill Levchenko
Kevin Cuzner <kevin@kevincuzner.com>
David Sainty
Alexey Sadkov
Marius Greuel <greuelm@mgtek.com>
Ralf Ramsauer <ralf@vmexit.de>
Dawid Buchwald <dawid.buchwald@hotmail.com>
Hans Eirik Bull
Stefan Rueger
Xiaofan Chen
Jeff Kent
Sebastian Kuzminsky <seb@highlab.com>
Sydney Louisa Wilke <git@funkeleinhorn.com>
Contributors to code no longer present:
@@ -47,4 +63,3 @@ Contributors to code no longer present:
Chris Liechti for loaddrv modifications
For minor contributions, please see the ChangeLog files / Git log.

View File

@@ -220,7 +220,7 @@ endif()
find_library(HAVE_LIBREADLINE NAMES ${PREFERRED_LIBREADLINE})
if(HAVE_LIBREADLINE)
set(LIB_LIBREADLINE ${HAVE_LIBREADLINE})
find_library(LIB_NCURSES NAMES ncurses)
find_library(LIB_NCURSES NAMES ncurses pdcurses)
elseif(MSVC)
set(HAVE_LIBREADLINE 1)
endif()

74
NEWS
View File

@@ -1,5 +1,3 @@
$Id$
Approximate change log for AVRDUDE by version.
(For detailed changes, see the version control system logs.)
@@ -9,26 +7,57 @@ Changes since version 7.3:
* Major changes compared to the previous version:
- Support of multi-memory .hex/.srec files and memory lists #1828
- New terminal disasm command #1842
* New devices supported:
- AVR16DU14, AVR16DU20, AVR16DU28, AVR16DU32
- AVR32DU14, AVR32DU20, AVR32DU28, AVR32DU32
* New programmers supported:
- serprog
* New serial adapters supported:
- ch342, ch344, ch347, ch9103
* Issues fixed:
- Avrintel.h missing from installation #1683
- Use of undeclared identifier 'AVRDUDE_FULL_VERSION' #1706
- Wrong message level in jtag3_prmsg() #1726
- Old avrdude_message() can go away #1719
- avr_{read,write}_mem fail to initialize progress reporting #1718
- avr*timestamp() oddities #1722
- -F option not honored bug #1740
- -F option not honoured #1740
- "jtag2 is not a unique start of a programmer name" #1739
- Regression: EEPROM issue with official STK500 V1 FW #1713
- usbasp_write_byte in TPI mode not implemented #1755
- Remove calls to exit() from libavrdude library #774
- cmake enabling LINUXGPIO on ubuntu 20.04 fails #1782
- macOS github action failed. #1793
- Format mismatch warnings #1799
- 0xff optimization when reading #1732
- Add support for more AVR-DU parts #1742
- Misleading error message: cannot find programmer id #1805
- Custom programmer broken in v7.3 #1807
- ATtiny11 does not have EEPROM #1812
- AVRDUDE fails to return -1 on some write errors #1821
- Multi-memory files #1817
- Terminal erase command #1833
- Bootrow r/w does not work for -c serialupdi #1832
- Wrong error message when specifying wrong AVR-Ex part #1813
- AVR109 auto reset functionality #1697
- Unable to write LOCK bit byte to JTAG3_TPI #1858
- Unexpected auto-erase consequences #1861
- JTAGICE3 EDBG communication mode relies on hardcoded USBVID #1838
- avrdude documentation typo(s) attemps #1852
- Conflicting types for op16_is_mnemo: enum/integer #1851
* Pull requests:
- Remove 32bit MSYS2 mingw32 and clang32 build #1687
- Make avrintel.h an internal header file for libavrdude #1686
- Fix -Wcalloc-transposed-args warning #1680
@@ -65,9 +94,48 @@ Changes since version 7.3:
- Use magic memory tree interface throughout #1795
- Silence MacOS compiler warning #1794
- Add macOS autotools to github action #1798
- Silence compiler warnings #1800
- Fix 7 typos in 4 files #1802
- Put static variables into context structure #1803
- Add new AVRnnDUnn parts #1804
- Differentiate cause when programmer isn't found #1806
- Prepare for next urboot version #1808
- Rename AVRDUDE symbol names ending in _t #1809
- Warn when programmer failes to define prog_modes #1810
- Add serprog programmer #1801
- Remove EEPROM from ATtiny11 avrdude.conf entry #1814
- Guard serial_number access in usbhid_open() to avoid segfault #1815
- Allow selection of program modes for developer options #1816
- Return -1 on write error #1822
- Extend elf format for bootrow #1820
- Update AUTHORS list #1819
- Downgrade out-of-range file input errors on -F #1818
- Multi-memory file handling #1828
- Add developer options -p*/vcr to explore SW compatibility #1830
- Improve chip erase emulation for dryboot/dryrun #1836
- Use page erase for UPDI programming #1837
- Add fuses, calibration, sernum and tempsense memories #1829
- Fix bootrow access for -c serialupdi #1835
- Improve signature check for UPDI parts #1840
- Improve error handling for avrdude without libserialport #1843
- Provide terminal disasm command #1842
- Improve auto-reset handling and -x/-E parsing #1844
- Remove obsolete SVN $Id$ tags from source files #1850
- Update look and feel #1849
- Update documentation for -E and -x #1853
- Add more WCH USB to serial chips #1855
- cmake: LIB_NCURSES also accept pdcurses #1856
- Fix byte writes to TPI lockbits for jpag3.c #1859
- Refine auto-erase strategy #1862
- Provide -P usb:vid:pid for USB hid i/f and allow
long -P usb:serno for usblib and hidapi #186
* Internals:
- Created a context structure pointed to by cx, which harbours global
and static variables
- Made programmers libavrdude ready: remove exit() calls and moved
static variables into local struct pdata
Changes in version 7.3:

View File

@@ -175,6 +175,7 @@ set(SOURCES
avrftdi_tpi.h
avrintel.c
libavrdude-avrintel.h
avr_opcodes.c
avrpart.c
bitbang.c
bitbang.h
@@ -189,6 +190,7 @@ set(SOURCES
confwin.c
crc16.c
crc16.h
disasm.c
dfu.c
dfu.h
dryrun.c
@@ -240,6 +242,8 @@ set(SOURCES
serialadapter.c
serialupdi.c
serialupdi.h
serprog.c
serprog.h
solaris_ecpp.h
stk500.c
stk500.h
@@ -384,6 +388,7 @@ endif()
# =====================================
install(TARGETS avrdude DESTINATION bin)
install(PROGRAMS "elf2tag" DESTINATION bin)
install(TARGETS libavrdude
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}

View File

@@ -1,7 +1,7 @@
#
# avrdude - A Downloader/Uploader for AVR device programmers
# Copyright (C) 2003, 2004 Theodore A. Roth <troth@openavr.org>
# Copyright (C) 2003, 2004 Theodore A. Roth <troth@openavr.org>
#
# 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
@@ -26,10 +26,6 @@
#
# make V=1
#
# $Id$
#
EXTRA_DIST = \
avrdude.1 \
avrdude.spec \
@@ -105,6 +101,7 @@ libavrdude_a_SOURCES = \
avrintel.c \
libavrdude-avrintel.h \
avrpart.c \
avr_opcodes.c \
bitbang.c \
bitbang.h \
buspirate.c \
@@ -118,6 +115,7 @@ libavrdude_a_SOURCES = \
confwin.c \
crc16.c \
crc16.h \
disasm.c \
dfu.c \
dfu.h \
dryrun.c \
@@ -185,6 +183,8 @@ libavrdude_a_SOURCES = \
usbasp.h \
serialupdi.c \
serialupdi.h \
serprog.c \
serprog.h \
updi_constants.h \
updi_link.c \
updi_link.h \
@@ -232,6 +232,8 @@ avrdude_SOURCES = \
developer_opts.h \
developer_opts_private.h
dist_bin_SCRIPTS = elf2tag
man_MANS = avrdude.1
sysconf_DATA = avrdude.conf

View File

@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
/*
* avrdude interface for Arduino programmer
*
@@ -37,6 +35,43 @@
#include "stk500.h"
#include "arduino.h"
static int arduino_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) {
int attempts;
int rv = 0;
bool help = 0;
for (LNODEID ln = lfirst(extparms); ln; ln = lnext(ln)) {
const char *extended_param = ldata(ln);
if (sscanf(extended_param, "attempts=%i", &attempts) == 1) {
PDATA(pgm)->retry_attempts = attempts;
pmsg_info("setting number of retry attempts to %d\n", attempts);
continue;
}
if(str_eq(extended_param, "noautoreset")) {
PDATA(pgm)->autoreset = false;
continue;
}
if (str_eq(extended_param, "help")) {
help = true;
rv = LIBAVRDUDE_EXIT;
}
if (!help) {
pmsg_error("invalid extended parameter -x %s\n", extended_param);
rv = -1;
}
msg_error("%s -c %s extended options:\n", progname, pgmid);
msg_error(" -x attempts=<n> Specify the number <n> of connection retry attempts\n");
msg_error(" -x noautoreset Don't toggle RTS/DTR lines on port open to prevent a hardware reset\n");
msg_error(" -x help Show this help menu and exit\n");
return rv;
}
return rv;
}
/* read signature bytes - arduino version */
static int arduino_read_sig_bytes(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m) {
unsigned char buf[32];
@@ -85,28 +120,28 @@ static int arduino_open(PROGRAMMER *pgm, const char *port) {
return -1;
}
// This code assumes a negative-logic USB to TTL serial adapter
// Set RTS/DTR high to discharge the series-capacitor, if present
serial_set_dtr_rts(&pgm->fd, 0);
/*
* Long wait needed for optiboot: otherwise the second of two bootloader
* calls in quick succession fails:
*
* avrdude -c arduino -qqp m328p -U x.hex; avrdude -c arduino -qqp m328p -U x.hex
*/
usleep(250 * 1000);
// Pull the RTS/DTR line low to reset AVR
serial_set_dtr_rts(&pgm->fd, 1);
// Max 100 us: charging a cap longer creates a high reset spike above Vcc
usleep(100);
// Set the RTS/DTR line back to high, so direct connection to reset works
serial_set_dtr_rts(&pgm->fd, 0);
if(PDATA(pgm)->autoreset) {
// This code assumes a negative-logic USB to TTL serial adapter
// Set RTS/DTR high to discharge the series-capacitor, if present
serial_set_dtr_rts(&pgm->fd, 0);
/*
* Long wait needed for optiboot: otherwise the second of two bootloader
* calls in quick succession fails:
*
* avrdude -c arduino -qqp m328p -U x.hex; avrdude -c arduino -qqp m328p -U x.hex
*/
usleep(250 * 1000);
// Pull the RTS/DTR line low to reset AVR
serial_set_dtr_rts(&pgm->fd, 1);
// Max 100 us: charging a cap longer creates a high reset spike above Vcc
usleep(100);
// Set the RTS/DTR line back to high, so direct connection to reset works
serial_set_dtr_rts(&pgm->fd, 0);
usleep(100 * 1000);
usleep(100 * 1000);
}
/*
* drain any extraneous input
*/
// Drain any extraneous input
stk500_drain(pgm, 0);
if (stk500_getsync(pgm) < 0)
@@ -115,8 +150,7 @@ static int arduino_open(PROGRAMMER *pgm, const char *port) {
return 0;
}
static void arduino_close(PROGRAMMER * pgm)
{
static void arduino_close(PROGRAMMER *pgm) {
serial_close(&pgm->fd);
pgm->fd.ifd = -1;
}
@@ -129,11 +163,11 @@ void arduino_initpgm(PROGRAMMER *pgm) {
and the DTR signal is set when opening the serial port
for the Auto-Reset feature */
stk500_initpgm(pgm);
strcpy(pgm->type, "Arduino");
pgm->read_sig_bytes = arduino_read_sig_bytes;
pgm->open = arduino_open;
pgm->close = arduino_close;
pgm->parseextparams = arduino_parseextparms;
disable_trailing_ff_removal(); /* so that arduino bootloader can ignore chip erase */
cx->avr_disableffopt = 1; // Disable trailing 0xff removal
}

View File

@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#ifndef arduino_h__
#define arduino_h__

281
src/avr.c
View File

@@ -1,7 +1,8 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2011 Darell Tan <darell.tan@gmail.com>
* Copyright (C) 2022- Stefan Rueger <stefan.rueger@urclocks.com>
*
* 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
@@ -17,8 +18,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#include <ac_cfg.h>
#include <stdio.h>
@@ -180,6 +179,38 @@ static int avr_tpi_setup_rw(const PROGRAMMER *pgm, const AVRMEM *mem,
return 0;
}
// If mem is a sub-memory of sigrow return its offset within sigrow, 0 otherwise
int avr_sigrow_offset(const AVRPART *p, const AVRMEM *mem, int addr) {
int offset = 0;
if(mem_is_in_sigrow(mem)) {
AVRMEM *m = avr_locate_sigrow(p);
if(m) {
int off = mem->offset - m->offset;
if(off >= 0 && off + addr < m->size)
offset = off;
}
}
return offset;
}
// If mem is a sub-memory of flash return its offset within flash, 0 otherwise
int avr_flash_offset(const AVRPART *p, const AVRMEM *mem, int addr) {
int offset = 0;
if(mem_is_in_flash(mem)) {
AVRMEM *m = avr_locate_flash(p);
if(m) {
int off = mem->offset - m->offset;
if(off >= 0 && off + addr < m->size)
offset = off;
}
}
return offset;
}
int avr_read_byte_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem,
unsigned long addr, unsigned char * value)
{
@@ -190,8 +221,7 @@ int avr_read_byte_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM
OPCODE * readop, * lext;
if (pgm->cmd == NULL) {
pmsg_error("%s programmer uses avr_read_byte_default() but does not\n", pgm->type);
imsg_error("provide a cmd() method\n");
pmsg_error("%s programmer uses %s() without providing a cmd() method\n", pgm->type, __func__);
return -1;
}
@@ -257,7 +287,7 @@ int avr_read_byte_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM
memset(cmd, 0, sizeof(cmd));
avr_set_bits(readop, cmd);
avr_set_addr(readop, cmd, addr);
avr_set_addr(readop, cmd, addr + avr_sigrow_offset(p, mem, addr));
rc = pgm->cmd(pgm, cmd, res);
if(rc < 0)
goto rcerror;
@@ -291,15 +321,14 @@ rcerror:
int avr_mem_hiaddr(const AVRMEM * mem)
{
int i, n;
static int disableffopt;
/* calling once with NULL disables any future trailing-0xff optimisation */
// Deprecated: calling with NULL disables trailing 0xff optimisation (remove in v8.0)
if(!mem) {
disableffopt = 1;
cx->avr_disableffopt = 1;
return 0;
}
if(disableffopt)
if(cx->avr_disableffopt)
return mem->size;
/* if the memory is not a flash-type memory do not remove trailing 0xff */
@@ -323,10 +352,9 @@ int avr_mem_hiaddr(const AVRMEM * mem)
/*
* Read the entirety of the specified memory into the corresponding
* buffer of the avrpart pointed to by p. If v is non-NULL, verify against
* v's memory area, only those cells that are tagged TAG_ALLOCATED are
* verified.
* Read the entirety of the specified memory into the corresponding buffer of
* the avrpart pointed to by p. If v is non-NULL, verify against v's memory
* area, only those cells that are tagged TAG_ALLOCATED are verified.
*
* Return the number of bytes read, or < 0 if an error occurs.
*/
@@ -340,14 +368,6 @@ int avr_read(const PROGRAMMER *pgm, const AVRPART *p, const char *memstr, const
return avr_read_mem(pgm, p, mem, v);
}
/*
* Read the entirety of the specified memory into the corresponding buffer of
* the avrpart pointed to by p. If v is non-NULL, verify against v's memory
* area, only those cells that are tagged TAG_ALLOCATED are verified.
*
* Return the number of bytes read, or < 0 if an error occurs.
*/
int avr_read_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, const AVRPART *v) {
unsigned long i, lastaddr;
unsigned char cmd[4];
@@ -458,7 +478,7 @@ int avr_read_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, con
nread++;
report_progress(nread, npages, NULL);
} else {
pmsg_debug("avr_read_mem(): skipping page %u: no interesting data\n", pageaddr / mem->page_size);
pmsg_debug("%s(): skipping page %u: no interesting data\n", __func__, pageaddr / mem->page_size);
}
}
if (!failure) {
@@ -519,8 +539,7 @@ int avr_write_page(const PROGRAMMER *pgm, const AVRPART *p_unused, const AVRMEM
led_set(pgm, LED_PGM);
if (pgm->cmd == NULL) {
pmsg_error("%s programmer uses avr_write_page() but does not\n", pgm->type);
imsg_error("provide a cmd() method\n");
pmsg_error("%s programmer uses %s() without providing a cmd() method\n", pgm->type, __func__);
goto error;
}
@@ -578,16 +597,14 @@ uint64_t avr_ustimestamp() {
memset(&tv, 0, sizeof tv);
if(gettimeofday(&tv, NULL) == 0) {
static uint64_t epoch;
static int init;
uint64_t now;
now = tv.tv_sec*1000000ULL + tv.tv_usec;
if(!init) {
epoch = now;
init = 1;
if(!cx->avr_epoch_init) {
cx->avr_epoch = now;
cx->avr_epoch_init = 1;
}
return now - epoch;
return now - cx->avr_epoch;
}
return 0;
@@ -651,8 +668,7 @@ int avr_write_byte_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM
led_set(pgm, LED_PGM);
if (pgm->cmd == NULL) {
pmsg_error("%s programmer uses avr_write_byte_default() but does not\n", pgm->type);
imsg_error("provide a cmd() method\n");
pmsg_error("%s programmer uses %s() without providing a cmd() method\n", pgm->type, __func__);
goto error;
}
@@ -856,9 +872,9 @@ int avr_write_byte_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM
usleep(250000);
rc = pgm->initialize(pgm, p);
if (rc < 0) {
pmsg_error("initialization failed, rc=%d\n", rc);
imsg_error("cannot re-initialize device after programming the %s bits\n", mem->desc);
imsg_error("you must manually power-down the device and restart %s to continue\n", progname);
pmsg_error("initialization failed (rc = %d):\n", rc);
imsg_error("cannot re-initialize device after programming the %s bits; you\n", mem->desc);
imsg_error("must manually power-down the device and restart %s to continue\n", progname);
rc = -3;
goto rcerror;
}
@@ -936,14 +952,6 @@ int avr_write(const PROGRAMMER *pgm, const AVRPART *p, const char *memstr, int s
return avr_write_mem(pgm, p, m, size, auto_erase);
}
/*
* Write the whole memory region of the specified memory from its buffer of
* the avrpart pointed to by p to the device. Write up to size bytes from
* the buffer. Data is only written if the corresponding tags byte is set.
* Data beyond size bytes are not affected.
*
* Return the number of bytes written, or LIBAVRDUDE_GENERAL_FAILURE on error.
*/
int avr_write_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, int size, int auto_erase) {
int wsize;
unsigned int i, lastaddr;
@@ -957,8 +965,8 @@ int avr_write_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, int
if (size < wsize) {
wsize = size;
} else if (size > wsize) {
pmsg_warning("%d bytes requested, but memory region is only %d bytes\n", size, wsize);
imsg_warning("Only %d bytes will actually be written\n", wsize);
pmsg_warning("%d bytes requested, but memory region is only %d bytes;\n", size, wsize);
imsg_warning("only %d bytes will actually be written\n", wsize);
}
if(wsize <= 0) {
@@ -1107,14 +1115,14 @@ int avr_write_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, int
// Read flash contents to separate memory spc and fill in holes
if(avr_read_page_default(pgm, p, cm, beg, spc) >= 0) {
pmsg_notice2("padding %s [0x%04x, 0x%04x]\n", cm->desc, beg, end-1);
pmsg_debug("padding %s [0x%04x, 0x%04x]\n", cm->desc, beg, end-1);
for(i = beg; i < end; i++)
if(!(cm->tags[i] & TAG_ALLOCATED)) {
cm->tags[i] |= TAG_ALLOCATED;
cm->buf[i] = spc[i-beg];
}
} else {
pmsg_notice2("cannot read %s [0x%04x, 0x%04x] to pad page\n",
pmsg_debug("cannot read %s [0x%04x, 0x%04x] to pad page\n",
cm->desc, beg, end-1);
}
}
@@ -1206,8 +1214,9 @@ int avr_write_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, int
if (do_write) {
if(avr_write_byte(pgm, p, m, i, data)) {
msg_error(" ***failed;\n");
msg_error(" *** failed\n");
led_set(pgm, LED_ERR);
goto error;
}
}
@@ -1215,15 +1224,20 @@ int avr_write_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, int
flush_page = 0;
if(avr_write_page(pgm, p, m, i)) {
msg_error(" *** page %d (addresses 0x%04x - 0x%04x) failed to write\n\n",
msg_error(" *** failed to write page %d [0x%04x, 0x%04x]\n",
i / m->page_size, i - m->page_size + 1, i);
led_set(pgm, LED_ERR);
goto error;
}
}
}
led_clr(pgm, LED_PGM);
return i;
error:
led_clr(pgm, LED_PGM);
return -1;
}
@@ -1237,7 +1251,7 @@ int avr_signature(const PROGRAMMER *pgm, const AVRPART *p) {
report_progress(0, 1, "Reading");
rc = avr_read(pgm, p, "signature", 0);
if (rc < LIBAVRDUDE_SUCCESS && rc != LIBAVRDUDE_EXIT) {
pmsg_error("unable to read signature data for part %s, rc=%d\n", p->desc, rc);
pmsg_error("unable to read signature data for part %s (rc = %d)\n", p->desc, rc);
return rc;
}
report_progress(1, 1, NULL);
@@ -1268,7 +1282,7 @@ int avr_mem_bitmask(const AVRPART *p, const AVRMEM *mem, int addr) {
}
// Bitmask for ISP programming (classic parts only)
static uint8_t get_fuse_bitmask(AVRMEM * m) {
static uint8_t get_fuse_bitmask(const AVRMEM *m) {
uint8_t bitmask_r = 0;
uint8_t bitmask_w = 0;
int i;
@@ -1300,27 +1314,29 @@ int compare_memory_masked(AVRMEM * m, uint8_t b1, uint8_t b2) {
}
/*
* Verify the memory buffer of p with that of v. The byte range of v
* may be a subset of p. The byte range of p should cover the whole
* chip's memory size.
* Verify the memory buffer of p with that of v. The byte range of v may be a
* subset of p. The byte range of p should cover the whole chip's memory size.
*
* Return the number of bytes verified, or -1 if they don't match.
*/
int avr_verify(const PROGRAMMER *pgm, const AVRPART *p, const AVRPART *v, const char *memstr, int size) {
int i;
unsigned char * buf1, * buf2;
int vsize;
AVRMEM * a, * b;
const AVRMEM *a = avr_locate_mem(p, memstr);
a = avr_locate_mem(p, memstr);
if (a == NULL) {
if(!a) {
pmsg_error("memory %s not defined for part %s\n", memstr, p->desc);
return -1;
}
return avr_verify_mem(pgm, p, v, a, size);
}
b = avr_locate_mem(v, memstr);
if (b == NULL) {
pmsg_error("memory %s not defined for part %s\n", memstr, v->desc);
int avr_verify_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRPART *v, const AVRMEM *a, int size) {
int i;
unsigned char *buf1, *buf2;
int vsize;
AVRMEM *b;
if(!(b = avr_locate_mem(v, a->desc))) {
pmsg_error("memory %s not defined for part %s\n", a->desc, v->desc);
return -1;
}
@@ -1329,50 +1345,51 @@ int avr_verify(const PROGRAMMER *pgm, const AVRPART *p, const AVRPART *v, const
vsize = a->size;
if (vsize < size) {
pmsg_warning("requested verification for %d bytes\n", size);
imsg_warning("%s memory region only contains %d bytes\n", memstr, vsize);
pmsg_warning("requested verification for %d bytes but\n", size);
imsg_warning("%s memory region only contains %d bytes;\n", a->desc, vsize);
imsg_warning("only %d bytes will be verified\n", vsize);
size = vsize;
}
int verror = 0, vroerror = 0, maxerrs = verbose >= MSG_DEBUG? size+1: 10;
int ro = mem_is_readonly(a); // Other memories can have known protected zones such as bootloaders
for (i=0; i<size; i++) {
if ((b->tags[i] & TAG_ALLOCATED) != 0 && buf1[i] != buf2[i]) {
uint8_t bitmask = p->prog_modes & PM_ISP? get_fuse_bitmask(a): avr_mem_bitmask(p, a, i);
if(pgm->readonly && pgm->readonly(pgm, p, a, i)) {
if(ro || (pgm->readonly && pgm->readonly(pgm, p, a, i))) {
if(quell_progress < 2) {
if(vroerror < 10) {
if(!(verror + vroerror))
pmsg_warning("verification mismatch%s\n",
pmsg_warning("%s verification mismatch%s\n", a->desc,
mem_is_in_flash(a)? " in r/o areas, expected for vectors and/or bootloader": "");
imsg_warning("device 0x%02x != input 0x%02x at addr 0x%04x (read only location)\n",
imsg_warning(" device 0x%02x != input 0x%02x at addr 0x%04x (read only location: ignored)\n",
buf1[i], buf2[i], i);
} else if(vroerror == 10)
imsg_warning("suppressing further mismatches in read-only areas\n");
imsg_warning(" suppressing further mismatches in read-only areas\n");
}
vroerror++;
} else if((buf1[i] & bitmask) != (buf2[i] & bitmask)) {
// Mismatch is not just in unused bits
if(verror < maxerrs) {
if(!(verror + vroerror))
pmsg_warning("verification mismatch\n");
imsg_error("device 0x%02x != input 0x%02x at addr 0x%04x (error)\n", buf1[i], buf2[i], i);
pmsg_warning("%s verification mismatch\n", a->desc);
imsg_error(" device 0x%02x != input 0x%02x at addr 0x%04x (error)\n", buf1[i], buf2[i], i);
} else if(verror == maxerrs) {
imsg_warning("suppressing further verification errors\n");
imsg_warning(" suppressing further verification errors\n");
}
verror++;
if(verbose < 1)
if(verbose < MSG_NOTICE)
return -1;
} else {
// Mismatch is only in unused bits
if ((buf1[i] | bitmask) != 0xff) {
// Programmer returned unused bits as 0, must be the part/programmer
pmsg_warning("ignoring mismatch in unused bits of %s\n", memstr);
pmsg_warning("ignoring mismatch in unused bits of %s\n", a->desc);
imsg_warning("(device 0x%02x != input 0x%02x); to prevent this warning fix\n", buf1[i], buf2[i]);
imsg_warning("the part or programmer definition in the config file\n");
} else {
// Programmer returned unused bits as 1, must be the user
pmsg_warning("ignoring mismatch in unused bits of %s\n", memstr);
pmsg_warning("ignoring mismatch in unused bits of %s\n", a->desc);
imsg_warning("(device 0x%02x != input 0x%02x); to prevent this warning set\n", buf1[i], buf2[i]);
imsg_warning("unused bits to 1 when writing (double check with datasheet)\n");
}
@@ -1398,7 +1415,7 @@ int avr_get_cycle_count(const PROGRAMMER *pgm, const AVRPART *p, int *cycles) {
for (i=4; i>0; i--) {
rc = pgm->read_byte(pgm, p, a, a->size-i, &v1);
if (rc < 0) {
pmsg_warning("cannot read memory for cycle count, rc=%d\n", rc);
pmsg_warning("cannot read memory for cycle count (rc = %d)\n", rc);
return -1;
}
cycle_count = (cycle_count << 8) | v1;
@@ -1436,7 +1453,7 @@ int avr_put_cycle_count(const PROGRAMMER *pgm, const AVRPART *p, int cycles) {
rc = avr_write_byte(pgm, p, a, a->size-i, v1);
if (rc < 0) {
pmsg_warning("cannot write memory for cycle count, rc=%d\n", rc);
pmsg_warning("cannot write memory for cycle count (rc = %d)\n", rc);
return -1;
}
}
@@ -1445,44 +1462,93 @@ int avr_put_cycle_count(const PROGRAMMER *pgm, const AVRPART *p, int cycles) {
}
// Returns a pointer to static memory of list of programming modes
char *avr_prog_modes(int pm) {
static char type[1024];
// Return temporary string buffer with n bytes from a closed-circuit space
char *avr_cc_buffer(size_t n) {
size_t avail = sizeof cx->avr_space - AVR_SAFETY_MARGIN;
if(!is_memset(cx->avr_space + avail, 0, AVR_SAFETY_MARGIN)) {
pmsg_warning("avr_cc_buffer(n) overran; n chosen too small in previous calls? Change and recompile\n");
memset(cx->avr_space + avail, 0, AVR_SAFETY_MARGIN);
}
strcpy(type, "?");
if(n > avail) {
pmsg_error("requested size %lu too big for cx->avr_space[%lu+AVR_SAFETY_MARGIN] (change source)\n",
(unsigned long) n, (unsigned long) avail);
cx->avr_s = cx->avr_space;
n = avail;
} else if(!cx->avr_s)
cx->avr_s = cx->avr_space;
cx->avr_s += strlen(cx->avr_s) + 1; // Move behind string from last call
// Rewind if too little space left
if((size_t) (cx->avr_s - cx->avr_space) > avail - n)
cx->avr_s = cx->avr_space;
memset(cx->avr_s, 0, n);
return cx->avr_s;
}
/*
* Returns a string in closed-circuit space with a list of programming
* modes encoded in pm; variant creates the list in subtly different ways:
* - variants == 0: PM_SPM prints bootloader
* - variants == 1: PM_SPM prints SPM
* - variants == 2: rather than a comma-separated list it's | PM_... separated
* If pm is 0 (no programming modes) returns "0"
*/
static char *prog_modes_string(int pm, int variant) {
char *type = avr_cc_buffer(256); // Longest returned string has 142 chars
const char *spm = variant? "SPM": "bootloader";
const char *sep = variant == 2? " | PM_": ", ";
int skip = 3 + (variant == 2);
strcpy(type, "0");
if(pm & PM_SPM)
strcat(type, ", bootloader");
strcat(strcat(type, sep), spm);
if(pm & PM_TPI)
strcat(type, ", TPI");
strcat(strcat(type, sep), "TPI");
if(pm & PM_ISP)
strcat(type, ", ISP");
strcat(strcat(type, sep), "ISP");
if(pm & PM_PDI)
strcat(type, ", PDI");
strcat(strcat(type, sep), "PDI");
if(pm & PM_UPDI)
strcat(type, ", UPDI");
strcat(strcat(type, sep), "UPDI");
if(pm & PM_HVSP)
strcat(type, ", HVSP");
strcat(strcat(type, sep), "HVSP");
if(pm & PM_HVPP)
strcat(type, ", HVPP");
strcat(strcat(type, sep), "HVPP");
if(pm & PM_debugWIRE)
strcat(type, ", debugWIRE");
strcat(strcat(type, sep), "debugWIRE");
if(pm & PM_JTAG)
strcat(type, ", JTAG");
strcat(strcat(type, sep), "JTAG");
if(pm & PM_JTAGmkI)
strcat(type, ", JTAGmkI");
strcat(strcat(type, sep), "JTAGmkI");
if(pm & PM_XMEGAJTAG)
strcat(type, ", XMEGAJTAG");
strcat(strcat(type, sep), "XMEGAJTAG");
if(pm & PM_AVR32JTAG)
strcat(type, ", AVR32JTAG");
strcat(strcat(type, sep), "AVR32JTAG");
if(pm & PM_aWire)
strcat(type, ", aWire");
strcat(strcat(type, sep), "aWire");
return type + (type[1] == 0? 0: 3);
return type + (type[1] == 0? 0: skip);
}
char *avr_prog_modes(int pm) { // PM_SPM prints bootloader
return prog_modes_string(pm, 0);
}
char *str_prog_modes(int pm) { // PM_SPM prints SPM
return prog_modes_string(pm, 1);
}
char *dev_prog_modes(int pm) { // Symbolic C code of prog_modes
return prog_modes_string(pm, 2);
}
// Typical order in which memories show in avrdude.conf, runtime adds unknown ones (if any)
memtable_t avr_mem_order[100] = {
Memtable avr_mem_order[100] = {
{"eeprom", MEM_EEPROM},
{"flash", MEM_FLASH | MEM_IN_FLASH},
{"application", MEM_APPLICATION | MEM_IN_FLASH},
@@ -1517,8 +1583,8 @@ memtable_t avr_mem_order[100] = {
{"lockbits", MEM_LOCK},
{"prodsig", MEM_SIGROW | MEM_IN_SIGROW | MEM_READONLY},
{"sigrow", MEM_SIGROW | MEM_IN_SIGROW | MEM_READONLY},
{"signature", MEM_SIGNATURE | MEM_IN_SIGROW | MEM_READONLY},
{"calibration", MEM_CALIBRATION | MEM_IN_SIGROW | MEM_READONLY},
{"signature", MEM_SIGNATURE | MEM_IN_SIGROW | MEM_READONLY}, // Not in SIGROW in Classic/XMEGA parts
{"calibration", MEM_CALIBRATION | MEM_IN_SIGROW | MEM_READONLY}, // Not in SIGROW in Classic parts
{"tempsense", MEM_TEMPSENSE | MEM_IN_SIGROW | MEM_READONLY},
{"sernum", MEM_SERNUM | MEM_IN_SIGROW | MEM_READONLY},
{"osccal16", MEM_OSCCAL16 | MEM_IN_SIGROW | MEM_READONLY},
@@ -1582,6 +1648,11 @@ int avr_mem_cmp(void *mem1, void *mem2) {
return diff;
if(!m1) // Sanity, if called with NULL pointers
return 0;
if(mem_is_in_fuses(m1)) { // Sort by fuse offset if fuses or a fuse
diff = mem_fuse_offset(m1) - mem_fuse_offset(m2);
if(diff)
return diff;
}
diff = m1->offset - m2->offset; // Sort by offset within each group
if(diff)
return diff;
@@ -1710,8 +1781,6 @@ int avr_unlock(const PROGRAMMER *pgm, const AVRPART *p) {
*/
void report_progress(int completed, int total, const char *hdr) {
static int last;
static double start_time;
int percent;
double t;
@@ -1725,12 +1794,12 @@ void report_progress(int completed, int total, const char *hdr) {
t = avr_timestamp();
if(hdr || !start_time)
start_time = t;
if(hdr || !cx->avr_start_time)
cx->avr_start_time = t;
if(hdr || percent > last) {
last = percent;
update_progress(percent, t - start_time, hdr, total < 0? -1: !!total);
if(hdr || percent > cx->avr_last_percent) {
cx->avr_last_percent = percent;
update_progress(percent, t - cx->avr_start_time, hdr, total < 0? -1: !!total);
}
}

View File

@@ -1,8 +1,8 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2003-2004 Theodore A. Roth <troth@openavr.org>
* Copyright 2007 Joerg Wunsch <j@uriah.heep.sax.de>
* Copyright 2008 Klaus Leidinger <klaus@mikrocontroller-projekte.de>
* Copyright (C) 2003-2004 Theodore A. Roth <troth@openavr.org>
* Copyright (C) 2007 Joerg Wunsch <j@uriah.heep.sax.de>
* Copyright (C) 2008 Klaus Leidinger <klaus@mikrocontroller-projekte.de>
*
* 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
@@ -18,8 +18,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
/*
* avrdude interface for Atmel Low Cost Serial programmers which adher to the
* protocol described in application note avr910.
@@ -308,22 +306,21 @@ static int avr910_cmd(const PROGRAMMER *pgm, const unsigned char *cmd,
static int avr910_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) {
LNODEID ln;
const char *extended_param;
int rv = 0;
bool help = false;
for (ln = lfirst(extparms); ln; ln = lnext(ln)) {
extended_param = ldata(ln);
for (LNODEID ln = lfirst(extparms); ln; ln = lnext(ln)) {
const char *extended_param = ldata(ln);
if (str_starts(extended_param, "devcode=")) {
int devcode;
if (sscanf(extended_param, "devcode=%i", &devcode) != 1 ||
devcode <= 0 || devcode > 255) {
pmsg_error("invalid devcode '%s'\n", extended_param);
pmsg_error("invalid device code in -x %s\n", extended_param);
rv = -1;
continue;
break;
}
pmsg_notice2("avr910_parseextparms(): devcode overwritten as 0x%02x\n", devcode);
pmsg_notice2("%s(): devcode overwritten as 0x%02x\n", __func__, devcode);
PDATA(pgm)->devcode = devcode;
continue;
@@ -335,15 +332,19 @@ static int avr910_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) {
continue;
}
if (str_eq(extended_param, "help")) {
msg_error("%s -c %s extended options:\n", progname, pgmid);
msg_error(" -xdevcode=<arg> Override device code\n");
msg_error(" -xno_blockmode Disable default checking for block transfer capability\n");
msg_error(" -xhelp Show this help menu and exit\n");
return LIBAVRDUDE_EXIT;
help = true;
rv = LIBAVRDUDE_EXIT;
}
pmsg_error("invalid extended parameter '%s'\n", extended_param);
rv = -1;
if (!help) {
pmsg_error("invalid extended parameter -x %s\n", extended_param);
rv = -1;
}
msg_error("%s -c %s extended options:\n", progname, pgmid);
msg_error(" -x devcode=<n> Set device code to <n> (0x.. hex, 0... oct or dec)\n");
msg_error(" -x no_blockmode Disable default checking for block transfer capability\n");
msg_error(" -x help Show this help menu and exit\n");
return rv;
}
return rv;

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2003-2004 Theodore A. Roth <troth@openavr.org>
* Copyright (C) 2003-2004 Theodore A. Roth <troth@openavr.org>
*
* 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
@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#ifndef avr910_h
#define avr910_h

739
src/avr_opcodes.c Normal file
View File

@@ -0,0 +1,739 @@
/*
* AVRDUDE - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2024 Stefan Rueger <stefan.rueger@urclocks.com>
*
* 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/>.
*/
#include <stdio.h>
#include "libavrdude.h"
/*
* AVR opcode table
*
* - Order of enums MNEMO_... in libavedude.h must align with table
*
* - Order makes the first match of a 16-bit opcode a "good" one
* + Undocumented opcodes come last
* + Specific reduced-core sts/lds opcodes are penultimate
* + More specific opcodes before less specific ones (clr before eor)
* + Opcodes labelled alias come behind those not labelled so
*
* - The operand field has a very specific syntax as follows
*
* A 5-bit I/O address (sbic, sbis, sbi, cbi)
* 6-bit I/O address (in, out)
*
* a 7-bit encoded address 0x40..0xbf for reduced-core (lds, sts)
*
* b bit number 0..7 (sbrc, sbrs, sbic, sbis, sbi, cbi, bst, bld, u/bld,
* u/bst, u/sbrc, u/sbrs)
*
* k signed 7-bit for 2*k byte PC additional offset in [.-128, .+126]
* (brcs, brlo, breq, brmi, brvs, brlt, brhs, brts, brie, brcc, brsh,
* brne, brpl, brvc, brge, brhc, brtc, brid, brbs, brbc)
* signed 12-bit for 2*k bytes PC additional offset in [.-4096, .+4094]
* (rjmp, rcall)
* 16-bit absolute byte address (lds, sts)
* 22-bit absolute word address for the PC (jmp, call)
*
* K 4-bit encryption round index 0..15 (des)
* 6-bit constant 0..63 (adiw, sbiw)
* 8-bit constant 0..255 (subi, sbci, andi, ori, sbr, cbr, cpi, ldi)
*
* q 6-bit displacement 0..63 (ldd, ldd, std, std)
*
* Rd 2-bit destination register in r24, r26, r28, r30 (adiw, sbiw)
* 3-bit dest register in r16, ..., r23 (mulsu, fmul, fmuls, fmulsu)
* 4-bit destination register in r16, ..., r31 (subi, sbci, andi, ori,
* sbr, cbr, ser, muls, cpi, ldi, lds)
* 4-bit destination register in r0, r2, ..., r30 (movw)
* 5-bit destination register in r0, r1, ..., r31 (add, adc, sub, sbc,
* and, or, eor, com, neg, inc, dec, clr, mul, cpse, cp, cpc, mov,
* lds, ld, ldd, lpm, elpm, in, pop, xch, las, lac, lat, lsl, lsr,
* rol, ror, asr, swap, bld, u/bld)
*
* Rr 3-bit source register in r16, ..., r23 (mulsu, fmul, fmuls, fmulsu)
* 4-bit source register in r16, ..., r31 (muls, sts)
* 4-bit source register in r0, r2, ..., r30 (movw)
* 5-bit source register in r0, r1, ..., r31 (add, adc, sub, sbc, and,
* or, eor, tst, mul, cpse, cp, cpc, sbrc, sbrs, mov, sts, st,
* std, out, push, bst, u/bst, u/sbrc, u/sbrs)
*
* s SREG bit number 0..7 (brbs, brbc, bset, bclr)
*
* - Source: Table was curated from https://github.com/nlitsme/AVRInstructionSet
*/
const AVR_opcode avr_opcodes[MNEMO_N] = {
#define OP_ID(nam) MNEMO_##nam, #nam
// Arithmetic and Logic Instructions
{OP_ID(lsl), 0xfc00, 0x0c00, 1, OP_AVR1, "0000 11d= dddd ====", OTY_ALBI|OTY_RALL|OTY_CONSTRAINT,
"lsl", "Rd", "logical shift left", "C <-- Rd(7) <-- Rd(6) ... Rd(1) <-- Rd(0) <-- 0", "--H-VNZC",
{"1", "1", "1", "1"}, "alias for add Rd, Rd"},
{OP_ID(add), 0xfc00, 0x0c00, 1, OP_AVR1, "0000 11rd dddd rrrr", OTY_ALBI|OTY_RALL,
"add", "Rd, Rr", "add without carry", "Rd <-- Rd + Rr", "--HSVNZC",
{"1", "1", "1", "1"}, ""},
{OP_ID(rol), 0xfc00, 0x1c00, 1, OP_AVR1, "0001 11d= dddd ====", OTY_ALBI|OTY_RALL|OTY_CONSTRAINT,
"rol", "Rd", "rotate left through carry", "C <-- Rd(7) <-- Rd(6) ... Rd(1) <-- Rd(0) <-- C", "--H-VNZC",
{"1", "1", "1", "1"}, "alias for adc Rd, Rd"},
{OP_ID(adc), 0xfc00, 0x1c00, 1, OP_AVR1, "0001 11rd dddd rrrr", OTY_ALBI|OTY_RALL,
"adc", "Rd, Rr", "add with carry", "Rd <-- Rd + Rr + C", "--HSVNZC",
{"1", "1", "1", "1"}, ""},
{OP_ID(ror), 0xfe0f, 0x9407, 1, OP_AVR1, "1001 010d dddd 0111", OTY_ALBI|OTY_RALL,
"ror", "Rd", "rotate right through carry", "C --> Rd(7) --> Rd(6) ... Rd(1) --> Rd(0) --> C", "----VNZC",
{"1", "1", "1", "1"}, ""},
{OP_ID(asr), 0xfe0f, 0x9405, 1, OP_AVR1, "1001 010d dddd 0101", OTY_ALBI|OTY_RALL,
"asr", "Rd", "arithmetic shift right", "Rd(7) --> Rd(7) --> Rd(6) ... Rd(1) --> Rd(0) --> C", "----VNZC",
{"1", "1", "1", "1"}, ""},
{OP_ID(adiw), 0xff00, 0x9600, 1, OP_AVR2nRC, "1001 0110 KKdd KKKK", OTY_ALBI|OTY_RW24,
"adiw", "Rd, K", "add immediate to word", "Rd+1:Rd <-- Rd+1:Rd + K", "---SVNZC",
{"2", "2", "2", "n/a"}, "d in {24, 26, 28, 30}"},
{OP_ID(sub), 0xfc00, 0x1800, 1, OP_AVR1, "0001 10rd dddd rrrr", OTY_ALBI|OTY_RALL,
"sub", "Rd, Rr", "subtract without carry", "Rd <-- Rd - Rr", "--HSVNZC",
{"1", "1", "1", "1"}, ""},
{OP_ID(subi), 0xf000, 0x5000, 1, OP_AVR1, "0101 KKKK dddd KKKK", OTY_ALBI|OTY_RUPP,
"subi", "Rd, K", "subtract immediate", "Rd <-- Rd - K", "--HSVNZC",
{"1", "1", "1", "1"}, "d = 16..31"},
{OP_ID(sbc), 0xfc00, 0x0800, 1, OP_AVR1, "0000 10rd dddd rrrr", OTY_ALBI|OTY_RALL,
"sbc", "Rd, Rr", "subtract with carry", "Rd <-- Rd - Rr - C", "--HSVNZC",
{"1", "1", "1", "1"}, ""},
{OP_ID(sbci), 0xf000, 0x4000, 1, OP_AVR1, "0100 KKKK dddd KKKK", OTY_ALBI|OTY_RUPP,
"sbci", "Rd, K", "subtract immediate with carry", "Rd <-- Rd - K - C", "--HSVNZC",
{"1", "1", "1", "1"}, "d = 16..31"},
{OP_ID(sbiw), 0xff00, 0x9700, 1, OP_AVR2nRC, "1001 0111 KKdd KKKK", OTY_ALBI|OTY_RW24,
"sbiw", "Rd, K", "subtract immediate from word", "Rd+1:Rd <-- Rd+1:Rd - K", "---SVNZC",
{"2", "2", "2", "n/a"}, "d in {24, 26, 28, 30}"},
{OP_ID(tst), 0xfc00, 0x2000, 1, OP_AVR1, "0010 00r= rrrr ====", OTY_ALBI|OTY_RALL|OTY_CONSTRAINT,
"tst", "Rr", "test for zero or minus", "Rr <-- Rr & Rr", "---SVNZ-",
{"1", "1", "1", "1"}, "alias for and Rd, Rd"},
{OP_ID(and), 0xfc00, 0x2000, 1, OP_AVR1, "0010 00rd dddd rrrr", OTY_ALBI|OTY_RALL,
"and", "Rd, Rr", "logical and", "Rd <-- Rd & Rr", "---SVNZ-",
{"1", "1", "1", "1"}, ""},
{OP_ID(andi), 0xf000, 0x7000, 1, OP_AVR1, "0111 KKKK dddd KKKK", OTY_ALBI|OTY_RUPP,
"andi", "Rd, K", "logical and with immediate", "Rd <-- Rd & K", "---SVNZ-",
{"1", "1", "1", "1"}, "d = 16..31"},
{OP_ID(cbr), 0xf000, 0x7000, 1, OP_AVR1, "0111 KKKK dddd KKKK", OTY_ALBI|OTY_RUPP|OTY_ALIAS,
"cbr", "Rd, K", "clear bit(s) in register", "Rd <-- Rd & (0xff - K)", "---SVNZ-",
{"1", "1", "1", "1"}, "alias for andi Rd, (0xff - K); d = 16..31"},
{OP_ID(or), 0xfc00, 0x2800, 1, OP_AVR1, "0010 10rd dddd rrrr", OTY_ALBI|OTY_RALL,
"or", "Rd, Rr", "logical or", "Rd <-- Rd | Rr", "---SVNZ-",
{"1", "1", "1", "1"}, ""},
{OP_ID(ori), 0xf000, 0x6000, 1, OP_AVR1, "0110 KKKK dddd KKKK", OTY_ALBI|OTY_RUPP,
"ori", "Rd, K", "logical or with immediate", "Rd <-- Rd | K", "---SVNZ-",
{"1", "1", "1", "1"}, "d = 16..31"},
{OP_ID(sbr), 0xf000, 0x6000, 1, OP_AVR1, "0110 KKKK dddd KKKK", OTY_ALBI|OTY_RUPP|OTY_ALIAS,
"sbr", "Rd, K", "set bit(s) in register", "Rd <-- Rd | K", "---SVNZ-",
{"1", "1", "1", "1"}, "alias for ori Rd, K; d = 16..31"},
{OP_ID(clr), 0xfc00, 0x2400, 1, OP_AVR1, "0010 01d= dddd ====", OTY_ALBI|OTY_RALL|OTY_CONSTRAINT,
"clr", "Rd", "clear register", "Rd <-- Rd ^ Rd", "---SVNZ-",
{"1", "1", "1", "1"}, "alias for eor Rd, Rd"},
{OP_ID(eor), 0xfc00, 0x2400, 1, OP_AVR1, "0010 01rd dddd rrrr", OTY_ALBI|OTY_RALL,
"eor", "Rd, Rr", "exclusive or", "Rd <-- Rd ^ Rr", "---SVNZ-",
{"1", "1", "1", "1"}, ""},
{OP_ID(com), 0xfe0f, 0x9400, 1, OP_AVR1, "1001 010d dddd 0000", OTY_ALBI|OTY_RALL,
"com", "Rd", "one's complement", "Rd <-- 0xff - Rd", "---SVNZC",
{"1", "1", "1", "1"}, ""},
{OP_ID(neg), 0xfe0f, 0x9401, 1, OP_AVR1, "1001 010d dddd 0001", OTY_ALBI|OTY_RALL,
"neg", "Rd", "two's complement", "Rd <-- 0x00 - Rd", "--HSVNZC",
{"1", "1", "1", "1"}, ""},
{OP_ID(inc), 0xfe0f, 0x9403, 1, OP_AVR1, "1001 010d dddd 0011", OTY_ALBI|OTY_RALL,
"inc", "Rd", "increment", "Rd <-- Rd + 1", "---SVNZ-",
{"1", "1", "1", "1"}, ""},
{OP_ID(dec), 0xfe0f, 0x940a, 1, OP_AVR1, "1001 010d dddd 1010", OTY_ALBI|OTY_RALL,
"dec", "Rd", "decrement", "Rd <-- Rd - 1", "---SVNZ-",
{"1", "1", "1", "1"}, ""},
{OP_ID(mul), 0xfc00, 0x9c00, 1, OP_AVR4, "1001 11rd dddd rrrr", OTY_ALBI|OTY_RALL,
"mul", "Rd, Rr", "multiply unsigned", "R1:R0 <-- Rd x Rr (UU)", "------ZC",
{"2", "2", "2", "n/a"}, ""},
{OP_ID(muls), 0xff00, 0x0200, 1, OP_AVR4, "0000 0010 dddd rrrr", OTY_ALBI|OTY_RUPP,
"muls", "Rd, Rr", "multiply signed", "R1:R0 <-- Rd x Rr (SS)", "------ZC",
{"2", "2", "2", "n/a"}, "d, r = 16..31"},
{OP_ID(mulsu), 0xff88, 0x0300, 1, OP_AVR4, "0000 0011 0ddd 0rrr", OTY_ALBI|OTY_RUPP,
"mulsu", "Rd, Rr", "multiply signed with unsigned", "R1:R0 <-- Rd x Rr (SU)", "------ZC",
{"2", "2", "2", "n/a"}, "d, r = 16..23"},
{OP_ID(fmul), 0xff88, 0x0308, 1, OP_AVR4, "0000 0011 0ddd 1rrr", OTY_ALBI|OTY_RUPP,
"fmul", "Rd, Rr", "fractional multiply unsigned", "R1:R0 <-- Rd x Rr << 1 (UU)", "------ZC",
{"2", "2", "2", "n/a"}, "d, r = 16..23"},
{OP_ID(fmuls), 0xff88, 0x0380, 1, OP_AVR4, "0000 0011 1ddd 0rrr", OTY_ALBI|OTY_RUPP,
"fmuls", "Rd, Rr", "fractional multiply signed", "R1:R0 <-- Rd x Rr << 1 (SS)", "------ZC",
{"2", "2", "2", "n/a"}, "d, r = 16..23"},
{OP_ID(fmulsu), 0xff88, 0x0388, 1, OP_AVR4, "0000 0011 1ddd 1rrr", OTY_ALBI|OTY_RUPP,
"fmulsu", "Rd, Rr", "fractional multiply signed with unsigned", "R1:R0 <-- Rd x Rr << 1 (SU)", "------ZC",
{"2", "2", "2", "n/a"}, "d, r = 16..23"},
{OP_ID(des), 0xff0f, 0x940b, 1, OP_AVR_XM, "1001 0100 KKKK 1011", OTY_ALBI,
"des", "K", "data encryption round", "if (H = 0) then R15:R0 <-- Encrypt(R15:R0, K) if (H = 1) then R15:R0 <-- Decrypt(R15:R0, K)", "--------",
{"n/a", "1/2", "n/a", "n/a"}, ""},
// Branch Instructions (and compare)
{OP_ID(rjmp), 0xf000, 0xc000, 1, OP_AVR1, "1100 kkkk kkkk kkkk", OTY_RJMI,
"rjmp", "k", "relative jump", "PC <-- PC + k + 1", "--------",
{"2", "2", "2", "2"}, ""},
{OP_ID(ijmp), 0xffff, 0x9409, 1, OP_AVR2, "1001 0100 0000 1001", OTY_JMPI|OTY_ZWORD,
"ijmp", "", "indirect jump to (Z)", "PC(15:0) <-- Z, PC(21:16) <-- 0", "--------",
{"2", "2", "2", "2"}, ""},
{OP_ID(eijmp), 0xffff, 0x9419, 1, OP_AVR_XL, "1001 0100 0001 1001", OTY_JMPX|OTY_ZWORD,
"eijmp", "", "extended indirect jump to (Z)", "PC(15:0) <-- Z, PC(21:16) <-- EIND", "--------",
{"2", "2", "2", "n/a"}, ""},
{OP_ID(jmp), 0xfe0e, 0x940c, 2, OP_AVR_M, "1001 010k kkkk 110k kkkk kkkk kkkk kkkk", OTY_JMPI,
"jmp", "k", "jump", "PC <-- k", "--------",
{"3", "3", "3", "n/a"}, ""},
{OP_ID(rcall), 0xf000, 0xd000, 1, OP_AVR1, "1101 kkkk kkkk kkkk", OTY_RJMX,
"rcall", "k", "relative call subroutine", "PC <-- PC + k + 1", "--------",
{"3+", "2+", "2+", "3"}, ""},
{OP_ID(icall), 0xffff, 0x9509, 1, OP_AVR2, "1001 0101 0000 1001", OTY_JMPX|OTY_ZWORD,
"icall", "", "indirect call to (Z)", "PC(15:0) <-- Z, PC(21:16) <-- 0", "--------",
{"3+", "2+", "2+", "3"}, ""},
{OP_ID(eicall), 0xffff, 0x9519, 1, OP_AVR_XL, "1001 0101 0001 1001", OTY_JMPX|OTY_ZWORD,
"eicall", "", "extended indirect call to (Z)", "PC(15:0) <-- Z, PC(21:16) <-- EIND", "--------",
{"4", "3", "3", "n/a"}, ""},
{OP_ID(call), 0xfe0e, 0x940e, 2, OP_AVR_M, "1001 010k kkkk 111k kkkk kkkk kkkk kkkk", OTY_JMPX,
"call", "k", "call subroutine", "PC <-- k, STACK <-- PC, SP <-- SP - 2", "--------",
{"4+", "3+", "3+", "n/a"}, ""},
{OP_ID(ret), 0xffff, 0x9508, 1, OP_AVR1, "1001 0101 0000 1000", OTY_JMPX,
"ret", "", "subroutine return", "SP <-- SP + 2, PC <-- STACK", "--------",
{"4+", "4+", "4+", "6"}, ""},
{OP_ID(reti), 0xffff, 0x9518, 1, OP_AVR1, "1001 0101 0001 1000", OTY_JMPX,
"reti", "", "interrupt return", "SP <-- SP + 2, PC <-- STACK", "I-------",
{"4+", "4+", "4+", "6"}, ""},
{OP_ID(cpse), 0xfc00, 0x1000, 1, OP_AVR1, "0001 00rd dddd rrrr", OTY_SKPI|OTY_RALL,
"cpse", "Rd, Rr", "compare and skip if equal", "if(Rd=Rr) PC <-- PC + 2/3", "--------",
{"1-3", "1-3", "1-3", "1/2"}, ""},
{OP_ID(cp), 0xfc00, 0x1400, 1, OP_AVR1, "0001 01rd dddd rrrr", OTY_ALBI|OTY_RALL,
"cp", "Rd, Rr", "compare", "Rd - Rr", "--HSVNZC",
{"1", "1", "1", "1"}, ""},
{OP_ID(cpc), 0xfc00, 0x0400, 1, OP_AVR1, "0000 01rd dddd rrrr", OTY_ALBI|OTY_RALL,
"cpc", "Rd, Rr", "compare with carry", "Rd - Rr - C", "--HSVNZC",
{"1", "1", "1", "1"}, ""},
{OP_ID(cpi), 0xf000, 0x3000, 1, OP_AVR1, "0011 KKKK dddd KKKK", OTY_ALBI|OTY_RUPP,
"cpi", "Rd, K", "compare with immediate", "Rd - K", "--HSVNZC",
{"1", "1", "1", "1"}, "d = 16..31"},
{OP_ID(sbrc), 0xfe08, 0xfc00, 1, OP_AVR1, "1111 110r rrrr 0bbb", OTY_SKPI|OTY_RALL,
"sbrc", "Rr, b", "skip if bit in register cleared", "if(Rr(b)=0) PC <-- PC + 2/3", "--------",
{"1-3", "1-3", "1-3", "1/2"}, ""},
{OP_ID(sbrs), 0xfe08, 0xfe00, 1, OP_AVR1, "1111 111r rrrr 0bbb", OTY_SKPI|OTY_RALL,
"sbrs", "Rr, b", "skip if bit in register set", "if(Rr(b)=1) PC <-- PC + 2/3", "--------",
{"1-3", "1-3", "1-3", "1/2"}, ""},
{OP_ID(sbic), 0xff00, 0x9900, 1, OP_AVR1, "1001 1001 AAAA Abbb", OTY_SKPX,
"sbic", "A, b", "skip if bit in I/O register cleared", "if(I/O(A,b)=0) PC <-- PC + 2/3", "--------",
{"1-3", "2-4", "1-3", "1/2"}, ""},
{OP_ID(sbis), 0xff00, 0x9b00, 1, OP_AVR1, "1001 1011 AAAA Abbb", OTY_SKPX,
"sbis", "A, b", "skip if bit in I/O register set", "If(I/O(A,b)=1) PC <-- PC + 2/3", "--------",
{"1-3", "2-4", "1-3", "1/2"}, ""},
{OP_ID(brcs), 0xfc07, 0xf000, 1, OP_AVR1, "1111 00kk kkkk k000", OTY_BRAI,
"brcs", "k", "branch if carry set", "if(C=1) then PC <-- PC + k + 1", "--------",
{"1/2", "1/2", "1/2", "1/2"}, "alias for brbs 0, k (C Carry)"},
{OP_ID(brlo), 0xfc07, 0xf000, 1, OP_AVR1, "1111 00kk kkkk k000", OTY_BRAI|OTY_ALIAS,
"brlo", "k", "branch if lower", "if(C=1) then PC <-- PC + k + 1", "--------",
{"1/2", "1/2", "1/2", "1/2"}, "alias for brbs 0, k (C Carry)"},
{OP_ID(breq), 0xfc07, 0xf001, 1, OP_AVR1, "1111 00kk kkkk k001", OTY_BRAI,
"breq", "k", "branch if equal", "if(Z=1) then PC <-- PC + k + 1", "--------",
{"1/2", "1/2", "1/2", "1/2"}, "alias for brbs 1, k (Z Zero)"},
{OP_ID(brmi), 0xfc07, 0xf002, 1, OP_AVR1, "1111 00kk kkkk k010", OTY_BRAI,
"brmi", "k", "branch if minus", "if(N=1) then PC <-- PC + k + 1", "--------",
{"1/2", "1/2", "1/2", "1/2"}, "alias for brbs 2, k (N Negative)"},
{OP_ID(brvs), 0xfc07, 0xf003, 1, OP_AVR1, "1111 00kk kkkk k011", OTY_BRAI,
"brvs", "k", "branch if overflow flag is set", "if(V=1) then PC <-- PC + k + 1", "--------",
{"1/2", "1/2", "1/2", "1/2"}, "alias for brbs 3, k (V Overflow in two's complement)"},
{OP_ID(brlt), 0xfc07, 0xf004, 1, OP_AVR1, "1111 00kk kkkk k100", OTY_BRAI,
"brlt", "k", "branch if less than (signed)", "if(N^V=1) then PC <-- PC + k + 1", "--------",
{"1/2", "1/2", "1/2", "1/2"}, "alias for brbs 4, k (S Sign)"},
{OP_ID(brhs), 0xfc07, 0xf005, 1, OP_AVR1, "1111 00kk kkkk k101", OTY_BRAI,
"brhs", "k", "branch if half-carry flag set", "if(H=1) then PC <-- PC + k + 1", "--------",
{"1/2", "1/2", "1/2", "1/2"}, "alias for brbs 5, k (H Half carry)"},
{OP_ID(brts), 0xfc07, 0xf006, 1, OP_AVR1, "1111 00kk kkkk k110", OTY_BRAI,
"brts", "k", "branch if T flag set", "if(T=1) then PC <-- PC + k + 1", "--------",
{"1/2", "1/2", "1/2", "1/2"}, "alias for brbs 6, k (T Transfer bit)"},
{OP_ID(brie), 0xfc07, 0xf007, 1, OP_AVR1, "1111 00kk kkkk k111", OTY_BRAI,
"brie", "k", "branch if interrupt enabled", "if(I=1) then PC <-- PC + k + 1", "--------",
{"1/2", "1/2", "1/2", "1/2"}, "alias for brbs 7, k (I Interrupt enable)"},
{OP_ID(brbs), 0xfc00, 0xf000, 1, OP_AVR1, "1111 00kk kkkk ksss", OTY_BRAI,
"brbs", "s, k", "branch if status flag set", "if(SREG(s)=1) then PC <-- PC + k + 1", "--------",
{"1/2", "1/2", "1/2", "1/2"}, ""},
{OP_ID(brcc), 0xfc07, 0xf400, 1, OP_AVR1, "1111 01kk kkkk k000", OTY_BRAI,
"brcc", "k", "branch if carry cleared", "if(C=0) then PC <-- PC + k + 1", "--------",
{"1/2", "1/2", "1/2", "1/2"}, "alias for brbc 0, k (C Carry)"},
{OP_ID(brsh), 0xfc07, 0xf400, 1, OP_AVR1, "1111 01kk kkkk k000", OTY_BRAI|OTY_ALIAS,
"brsh", "k", "branch if same or higher", "if(C=0) then PC <-- PC + k + 1", "--------",
{"1/2", "1/2", "1/2", "1/2"}, "alias for brbc 0, k (C Carry)"},
{OP_ID(brne), 0xfc07, 0xf401, 1, OP_AVR1, "1111 01kk kkkk k001", OTY_BRAI,
"brne", "k", "branch if not equal", "if(Z=0) then PC <-- PC + k + 1", "--------",
{"1/2", "1/2", "1/2", "1/2"}, "alias for brbc 1, k (Z Zero)"},
{OP_ID(brpl), 0xfc07, 0xf402, 1, OP_AVR1, "1111 01kk kkkk k010", OTY_BRAI,
"brpl", "k", "branch if plus", "if(N=0) then PC <-- PC + k + 1", "--------",
{"1/2", "1/2", "1/2", "1/2"}, "alias for brbc 2, k (N Negative)"},
{OP_ID(brvc), 0xfc07, 0xf403, 1, OP_AVR1, "1111 01kk kkkk k011", OTY_BRAI,
"brvc", "k", "branch if overflow flag is cleared", "if(V=0) then PC <-- PC + k + 1", "--------",
{"1/2", "1/2", "1/2", "1/2"}, "alias for brbc 3, k (V Overflow in two's complement)"},
{OP_ID(brge), 0xfc07, 0xf404, 1, OP_AVR1, "1111 01kk kkkk k100", OTY_BRAI,
"brge", "k", "branch if greater or equal (signed)", "if(N^V=0) then PC <-- PC + k + 1", "--------",
{"1/2", "1/2", "1/2", "1/2"}, "alias for brbc 4, k (S Sign)"},
{OP_ID(brhc), 0xfc07, 0xf405, 1, OP_AVR1, "1111 01kk kkkk k101", OTY_BRAI,
"brhc", "k", "branch if half-carry flag cleared", "if(H=0) then PC <-- PC + k + 1", "--------",
{"1/2", "1/2", "1/2", "1/2"}, "alias for brbc 5, k (H Half carry)"},
{OP_ID(brtc), 0xfc07, 0xf406, 1, OP_AVR1, "1111 01kk kkkk k110", OTY_BRAI,
"brtc", "k", "branch if T flag cleared", "if(T=0) then PC <-- PC + k + 1", "--------",
{"1/2", "1/2", "1/2", "1/2"}, "alias for brbc 6, k (T Transfer bit)"},
{OP_ID(brid), 0xfc07, 0xf407, 1, OP_AVR1, "1111 01kk kkkk k111", OTY_BRAI,
"brid", "k", "branch if interrupt disabled", "if(I=0) then PC <-- PC + k + 1", "--------",
{"1/2", "1/2", "1/2", "1/2"}, "alias for brbc 7, k (I Interrupt enable)"},
{OP_ID(brbc), 0xfc00, 0xf400, 1, OP_AVR1, "1111 01kk kkkk ksss", OTY_BRAI,
"brbc", "s, k", "branch if status flag cleared", "if(SREG(s)=0) then PC <-- PC + k + 1", "--------",
{"1/2", "1/2", "1/2", "1/2"}, ""},
// Data Transfer Instructions
{OP_ID(mov), 0xfc00, 0x2c00, 1, OP_AVR1, "0010 11rd dddd rrrr", OTY_XFRI|OTY_RALL,
"mov", "Rd, Rr", "copy register", "Rd <-- Rr", "--------",
{"1", "1", "1", "1"}, ""},
{OP_ID(movw), 0xff00, 0x0100, 1, OP_AVR25, "0000 0001 dddd rrrr", OTY_XFRI|OTY_REVN,
"movw", "Rd, Rr", "copy register pair", "Rd+1:Rd <-- Rr+1:Rr", "--------",
{"1", "1", "1", "n/a"}, "d, r in {0, 2, ..., 30}"},
{OP_ID(ser), 0xff0f, 0xef0f, 1, OP_AVR1, "1110 1111 dddd 1111", OTY_ALBI|OTY_RUPP,
"ser", "Rd", "set register", "Rd <-- 0xff", "--------",
{"1", "1", "1", "1"}, "alias for ldi Rd, 0xff; d = 16..31"},
{OP_ID(ldi), 0xf000, 0xe000, 1, OP_AVR1, "1110 KKKK dddd KKKK", OTY_XFRI|OTY_RUPP,
"ldi", "Rd, K", "load immediate", "Rd <-- K", "--------",
{"1", "1", "1", "1"}, "d = 16..31"},
{OP_ID(lds), 0xfe0f, 0x9000, 2, OP_AVR2nRC, "1001 000d dddd 0000 kkkk kkkk kkkk kkkk", OTY_XFRX|OTY_RALL,
"lds", "Rd, k", "load direct from data space", "Rd <-- (k)", "--------",
{"2", "3", "3", "2"}, ""},
{OP_ID(ld_x), 0xfe0f, 0x900c, 1, OP_AVR2, "1001 000d dddd 1100", OTY_XFRX|OTY_RALL,
"ld", "Rd, X", "load indirect", "Rd <-- (X)", "--------",
{"2", "2", "2", "1/2"}, ""},
{OP_ID(ld_xp), 0xfe0f, 0x900d, 1, OP_AVR2, "1001 000d dddd 1101", OTY_XFRX|OTY_RALL|OTY_XWRN,
"ld", "Rd, X+", "load indirect and post-increment", "Rd <-- (X), X <-- X + 1", "--------",
{"2", "2", "2", "2/3"}, ""},
{OP_ID(ld_mx), 0xfe0f, 0x900e, 1, OP_AVR2, "1001 000d dddd 1110", OTY_XFRX|OTY_RALL|OTY_XWRN,
"ld", "Rd, -X", "load indirect and pre-decrement", "X <-- X - 1, Rd <-- (X)", "--------",
{"2", "3", "2", "2/3"}, ""},
{OP_ID(ld_y), 0xfe0f, 0x8008, 1, OP_AVR2, "1000 000d dddd 1000", OTY_XFRX|OTY_RALL,
"ld", "Rd, Y", "load indirect", "Rd <-- (Y) <-- (Y)", "--------",
{"2", "2", "2", "1/2"}, "alias for ldd Rd, Y+0"},
{OP_ID(ld_yp), 0xfe0f, 0x9009, 1, OP_AVR2, "1001 000d dddd 1001", OTY_XFRX|OTY_RALL|OTY_YWRN,
"ld", "Rd, Y+", "load indirect and post-increment", "Rd <-- (Y), Y <-- Y + 1", "--------",
{"2", "2", "2", "2/3"}, ""},
{OP_ID(ld_my), 0xfe0f, 0x900a, 1, OP_AVR2, "1001 000d dddd 1010", OTY_XFRX|OTY_RALL|OTY_YWRN,
"ld", "Rd, -Y", "load indirect and pre-decrement", "Y <-- Y - 1 Rd <-- (Y)", "--------",
{"2", "3", "2", "2/3"}, ""},
{OP_ID(ldd_y), 0xd208, 0x8008, 1, OP_AVR2nRC, "10q0 qq0d dddd 1qqq", OTY_XFRX|OTY_RALL,
"ldd", "Rd, Y+q", "load indirect with displacement", "Rd <-- (Y+q)", "--------",
{"2", "3", "2", "n/a"}, ""},
{OP_ID(ld_z), 0xfe0f, 0x8000, 1, OP_AVR1, "1000 000d dddd 0000", OTY_XFRX|OTY_RALL,
"ld", "Rd, Z", "load indirect", "Rd <-- (Z)", "--------",
{"2", "2", "2", "1/2"}, "alias for ldd Rd, Z+0"},
{OP_ID(ld_zp), 0xfe0f, 0x9001, 1, OP_AVR1, "1001 000d dddd 0001", OTY_XFRX|OTY_RALL|OTY_ZWRN,
"ld", "Rd, Z+", "load indirect and post-increment", "Rd <-- (Z), Z <-- Z + 1", "--------",
{"2", "2", "2", "2/3"}, ""},
{OP_ID(ld_mz), 0xfe0f, 0x9002, 1, OP_AVR1, "1001 000d dddd 0010", OTY_XFRX|OTY_RALL|OTY_ZWRN,
"ld", "Rd, -Z", "load indirect and pre-decrement", "Z <-- Z - 1, Rd <-- (Z)", "--------",
{"2", "3", "2", "2/3"}, ""},
{OP_ID(ldd_z), 0xd208, 0x8000, 1, OP_AVR2nRC, "10q0 qq0d dddd 0qqq", OTY_XFRX|OTY_RALL,
"ldd", "Rd, Z+q", "load indirect with displacement", "Rd <-- (Z+q)", "--------",
{"2", "3", "2", "n/a"}, ""},
{OP_ID(sts), 0xfe0f, 0x9200, 2, OP_AVR2nRC, "1001 001r rrrr 0000 kkkk kkkk kkkk kkkk", OTY_XFRX|OTY_RALL,
"sts", "k, Rr", "store direct to data space", "(k) <-- Rr", "--------",
{"2", "2", "2", "1"}, ""},
{OP_ID(st_x), 0xfe0f, 0x920c, 1, OP_AVR2, "1001 001r rrrr 1100", OTY_XFRX|OTY_RALL,
"st", "X, Rr", "store indirect", "(X) <-- Rr", "--------",
{"2", "1", "1", "1"}, ""},
{OP_ID(st_xp), 0xfe0f, 0x920d, 1, OP_AVR2, "1001 001r rrrr 1101", OTY_XFRX|OTY_RALL|OTY_XWRN,
"st", "X+, Rr", "store indirect and post-increment", "(X) <-- Rr, X <-- X + 1", "--------",
{"2", "1", "1", "1"}, ""},
{OP_ID(st_mx), 0xfe0f, 0x920e, 1, OP_AVR2, "1001 001r rrrr 1110", OTY_XFRX|OTY_RALL|OTY_XWRN,
"st", "-X, Rr", "store indirect and pre-decrement", "X <-- X - 1, (X) <-- Rr", "--------",
{"2", "2", "1", "1"}, ""},
{OP_ID(st_y), 0xfe0f, 0x8208, 1, OP_AVR2, "1000 001r rrrr 1000", OTY_XFRX|OTY_RALL,
"st", "Y, Rr", "store indirect", "(Y) <-- Rr", "--------",
{"2", "1", "1", "1"}, "alias for std Y+0, Rr"},
{OP_ID(st_yp), 0xfe0f, 0x9209, 1, OP_AVR2, "1001 001r rrrr 1001", OTY_XFRX|OTY_RALL|OTY_YWRN,
"st", "Y+, Rr", "store indirect and post-increment", "(Y) <-- Rr, Y <-- Y + 1", "--------",
{"2", "1", "1", "1"}, ""},
{OP_ID(st_my), 0xfe0f, 0x920a, 1, OP_AVR2, "1001 001r rrrr 1010", OTY_XFRX|OTY_RALL|OTY_YWRN,
"st", "-Y, Rr", "store indirect and pre-decrement", "Y <-- Y - 1, (Y) <-- Rr", "--------",
{"2", "2", "1", "1"}, ""},
{OP_ID(std_y), 0xd208, 0x8208, 1, OP_AVR2nRC, "10q0 qq1r rrrr 1qqq", OTY_XFRX|OTY_RALL,
"std", "Y+q, Rr", "store indirect with displacement", "(Y+q) <-- Rr", "--------",
{"2", "2", "1", "n/a"}, ""},
{OP_ID(st_z), 0xfe0f, 0x8200, 1, OP_AVR1, "1000 001r rrrr 0000", OTY_XFRX|OTY_RALL,
"st", "Z, Rr", "store indirect", "(Z) <-- Rr", "--------",
{"2", "1", "1", "1"}, "alias for std Z+0, Rr"},
{OP_ID(st_zp), 0xfe0f, 0x9201, 1, OP_AVR1, "1001 001r rrrr 0001", OTY_XFRX|OTY_RALL|OTY_ZWRN,
"st", "Z+, Rr", "store indirect and post-increment", "(Z) <-- Rr, Z <-- Z + 1", "--------",
{"2", "1", "1", "1"}, ""},
{OP_ID(st_mz), 0xfe0f, 0x9202, 1, OP_AVR1, "1001 001r rrrr 0010", OTY_XFRX|OTY_RALL|OTY_ZWRN,
"st", "-Z, Rr", "store indirect and pre-decrement", "Z <-- Z - 1, (Z) <-- Rr", "--------",
{"2", "2", "1", "1"}, ""},
{OP_ID(std_z), 0xd208, 0x8200, 1, OP_AVR2nRC, "10q0 qq1r rrrr 0qqq", OTY_XFRX|OTY_RALL,
"std", "Z+q, Rr", "store indirect with displacement", "(Z+q) <-- Rr", "--------",
{"2", "2", "1", "n/a"}, ""},
{OP_ID(lpm_0), 0xffff, 0x95c8, 1, OP_AVR1nRC, "1001 0101 1100 1000", OTY_XFRX,
"lpm", "", "load program memory", "R0 <-- (Z)", "--------",
{"3", "3", "3", "n/a"}, ""},
{OP_ID(lpm_z), 0xfe0f, 0x9004, 1, OP_AVR25, "1001 000d dddd 0100", OTY_XFRX|OTY_RALL,
"lpm", "Rd, Z", "load program memory", "Rd <-- (Z)", "--------",
{"3", "3", "3", "n/a"}, ""},
{OP_ID(lpm_zp), 0xfe0f, 0x9005, 1, OP_AVR25, "1001 000d dddd 0101", OTY_XFRX|OTY_RALL|OTY_ZWRN,
"lpm", "Rd, Z+", "load program memory and post-increment", "Rd <-- (Z), Z <-- Z + 1", "--------",
{"3", "3", "3", "n/a"}, ""},
{OP_ID(elpm_0), 0xffff, 0x95d8, 1, OP_AVR_L, "1001 0101 1101 1000", OTY_XFRX,
"elpm", "", "extended load program memory", "R0 <-- (RAMPZ:Z)", "--------",
{"3", "3", "3", "n/a"}, ""},
{OP_ID(elpm_z), 0xfe0f, 0x9006, 1, OP_AVR_L, "1001 000d dddd 0110", OTY_XFRX|OTY_RALL,
"elpm", "Rd, Z", "extended load program memory", "Rd <-- (RAMPZ:Z)", "--------",
{"3", "3", "3", "n/a"}, ""},
{OP_ID(elpm_zp), 0xfe0f, 0x9007, 1, OP_AVR_L, "1001 000d dddd 0111", OTY_XFRX|OTY_RALL|OTY_ZWRN,
"elpm", "Rd, Z+", "extended load program memory and post-increment", "Rd <-- (RAMPZ:Z), Z <-- Z + 1", "--------",
{"3", "3", "3", "n/a"}, ""},
{OP_ID(spm), 0xffff, 0x95e8, 1, OP_AVR25, "1001 0101 1110 1000", OTY_XFRX,
"spm", "", "store program memory", "(RAMPZ:Z) <-- R1:R0", "--------",
{"-", "-", "-", "-"}, ""},
{OP_ID(spm_zp), 0xffff, 0x95f8, 1, OP_AVR_XTM, "1001 0101 1111 1000", OTY_XFRX,
"spm", "Z+", "store program memory and post-increment by 2", "(RAMPZ:Z) <-- R1:R0, Z <-- Z + 2", "--------",
{"n/a", "-", "-", "n/a"}, ""},
{OP_ID(in), 0xf800, 0xb000, 1, OP_AVR1, "1011 0AAd dddd AAAA", OTY_XFRX|OTY_RALL,
"in", "Rd, A", "in from I/O location", "Rd <-- I/O(A)", "--------",
{"1", "1", "1", "1"}, ""},
{OP_ID(out), 0xf800, 0xb800, 1, OP_AVR1, "1011 1AAr rrrr AAAA", OTY_XFRX|OTY_RALL,
"out", "A, Rr", "out to I/O location", "I/O(A) <-- Rr", "--------",
{"1", "1", "1", "1"}, ""},
{OP_ID(push), 0xfe0f, 0x920f, 1, OP_AVR2, "1001 001r rrrr 1111", OTY_XFRX|OTY_RALL,
"push", "Rr", "push register on stack", "STACK <-- Rr, SP <-- SP - 2", "--------",
{"2", "1", "1", "1"}, ""},
{OP_ID(pop), 0xfe0f, 0x900f, 1, OP_AVR2, "1001 000d dddd 1111", OTY_XFRX|OTY_RALL,
"pop", "Rd", "pop register from stack", "SP <-- SP + 2, Rd <-- STACK", "--------",
{"2", "2", "2", "3"}, ""},
{OP_ID(xch), 0xfe0f, 0x9204, 1, OP_AVR_XM, "1001 001d dddd 0100", OTY_XFRX|OTY_RALL,
"xch", "Z, Rd", "exchange", "(Z) <-- Rd, Rd <-- (Z)", "--------",
{"n/a", "1", "n/a", "n/a"}, ""},
{OP_ID(las), 0xfe0f, 0x9205, 1, OP_AVR_XM, "1001 001d dddd 0101", OTY_ALBX|OTY_RALL,
"las", "Z, Rd", "load and set", "(Z) <-- Rd | (Z), Rd <-- (Z)", "--------",
{"n/a", "1", "n/a", "n/a"}, ""},
{OP_ID(lac), 0xfe0f, 0x9206, 1, OP_AVR_XM, "1001 001d dddd 0110", OTY_ALBX|OTY_RALL,
"lac", "Z, Rd", "load and clear", "(Z) <-- (0xff - Rd) & (Z), Rd <-- (Z)", "--------",
{"n/a", "1", "n/a", "n/a"}, ""},
{OP_ID(lat), 0xfe0f, 0x9207, 1, OP_AVR_XM, "1001 001d dddd 0111", OTY_ALBX|OTY_RALL,
"lat", "Z, Rd", "load and toggle", "(Z) <-- Rd ^ (Z), Rd <-- (Z)", "--------",
{"n/a", "1", "n/a", "n/a"}, ""},
// Bit and Bit-test Instructions
{OP_ID(lsr), 0xfe0f, 0x9406, 1, OP_AVR1, "1001 010d dddd 0110", OTY_ALBI|OTY_RALL,
"lsr", "Rd", "logical shift right", "0 --> Rd(7) --> Rd(6) ... Rd(1) --> Rd(0) --> C", "----VNZC",
{"1", "1", "1", "1"}, ""},
{OP_ID(swap), 0xfe0f, 0x9402, 1, OP_AVR1, "1001 010d dddd 0010", OTY_ALBI|OTY_RALL,
"swap", "Rd", "swap nibbles", "Rd(3..0) <--> Rd(7..4)", "--------",
{"1", "1", "1", "1"}, ""},
{OP_ID(sbi), 0xff00, 0x9a00, 1, OP_AVR1, "1001 1010 AAAA Abbb", OTY_ALBX,
"sbi", "A, b", "set bit in I/O register", "I/O(A,b) <-- 1", "--------",
{"2", "1", "1", "1"}, ""},
{OP_ID(cbi), 0xff00, 0x9800, 1, OP_AVR1, "1001 1000 AAAA Abbb", OTY_ALBX,
"cbi", "A, b", "clear bit in I/O register", "I/O(A,b) <-- 0", "--------",
{"2", "1", "1", "1"}, ""},
{OP_ID(bst), 0xfe08, 0xfa00, 1, OP_AVR1, "1111 101r rrrr 0bbb", OTY_ALBI|OTY_RALL,
"bst", "Rr, b", "bit store from register to T", "T <-- Rr(b)", "-T------",
{"1", "1", "1", "1"}, ""},
{OP_ID(bld), 0xfe08, 0xf800, 1, OP_AVR1, "1111 100d dddd 0bbb", OTY_ALBI|OTY_RALL,
"bld", "Rd, b", "bit load from T to register", "Rd(b) <-- T", "--------",
{"1", "1", "1", "1"}, ""},
{OP_ID(sec), 0xffff, 0x9408, 1, OP_AVR1, "1001 0100 0000 1000", OTY_ALBI,
"sec", "", "set carry", "C <-- 1", "-------C",
{"1", "1", "1", "1"}, "alias for bset 0"},
{OP_ID(clc), 0xffff, 0x9488, 1, OP_AVR1, "1001 0100 1000 1000", OTY_ALBI,
"clc", "", "clear carry", "C <-- 0", "-------C",
{"1", "1", "1", "1"}, "alias for bclr 0"},
{OP_ID(sen), 0xffff, 0x9428, 1, OP_AVR1, "1001 0100 0010 1000", OTY_ALBI,
"sen", "", "set negative flag", "N <-- 1", "-----N--",
{"1", "1", "1", "1"}, "alias for bset 2"},
{OP_ID(cln), 0xffff, 0x94a8, 1, OP_AVR1, "1001 0100 1010 1000", OTY_ALBI,
"cln", "", "clear negative flag", "N <-- 0", "-----N--",
{"1", "1", "1", "1"}, "alias for bclr 2"},
{OP_ID(sez), 0xffff, 0x9418, 1, OP_AVR1, "1001 0100 0001 1000", OTY_ALBI,
"sez", "", "set zero flag", "Z <-- 1", "------Z-",
{"1", "1", "1", "1"}, "alias for bset 1"},
{OP_ID(clz), 0xffff, 0x9498, 1, OP_AVR1, "1001 0100 1001 1000", OTY_ALBI,
"clz", "", "clear zero flag", "Z <-- 0", "------Z-",
{"1", "1", "1", "1"}, "alias for bclr 1"},
{OP_ID(sei), 0xffff, 0x9478, 1, OP_AVR1, "1001 0100 0111 1000", OTY_ALBX,
"sei", "", "global interrupt enable", "I <-- 1", "I-------",
{"1", "1", "1", "1"}, "alias for bset 7"},
{OP_ID(cli), 0xffff, 0x94f8, 1, OP_AVR1, "1001 0100 1111 1000", OTY_ALBI,
"cli", "", "global interrupt disable", "I <-- 0", "I-------",
{"1", "1", "1", "1"}, "alias for bclr 7"},
{OP_ID(ses), 0xffff, 0x9448, 1, OP_AVR1, "1001 0100 0100 1000", OTY_ALBI,
"ses", "", "set signed test flag", "S <-- 1", "---S----",
{"1", "1", "1", "1"}, "alias for bset 4"},
{OP_ID(cls), 0xffff, 0x94c8, 1, OP_AVR1, "1001 0100 1100 1000", OTY_ALBI,
"cls", "", "clear signed test flag", "S <-- 0", "---S----",
{"1", "1", "1", "1"}, "alias for bclr 4"},
{OP_ID(sev), 0xffff, 0x9438, 1, OP_AVR1, "1001 0100 0011 1000", OTY_ALBI,
"sev", "", "set two's complement overflow", "V <-- 1", "----V---",
{"1", "1", "1", "1"}, "alias for bset 3"},
{OP_ID(clv), 0xffff, 0x94b8, 1, OP_AVR1, "1001 0100 1011 1000", OTY_ALBI,
"clv", "", "clear two's complement overflow", "V <-- 0", "----V---",
{"1", "1", "1", "1"}, "alias for bclr 3"},
{OP_ID(set), 0xffff, 0x9468, 1, OP_AVR1, "1001 0100 0110 1000", OTY_ALBI,
"set", "", "set T in sreg", "T <-- 1", "-T------",
{"1", "1", "1", "1"}, "alias for bset 6"},
{OP_ID(clt), 0xffff, 0x94e8, 1, OP_AVR1, "1001 0100 1110 1000", OTY_ALBI,
"clt", "", "clear T in sreg", "T <-- 0", "-T------",
{"1", "1", "1", "1"}, "alias for bclr 6"},
{OP_ID(seh), 0xffff, 0x9458, 1, OP_AVR1, "1001 0100 0101 1000", OTY_ALBI,
"seh", "", "set half-carry flag in sreg", "H <-- 1", "--H-----",
{"1", "1", "1", "1"}, "alias for bset 5"},
{OP_ID(clh), 0xffff, 0x94d8, 1, OP_AVR1, "1001 0100 1101 1000", OTY_ALBI,
"clh", "", "clear half-carry flag in sreg", "H <-- 0", "--H-----",
{"1", "1", "1", "1"}, "alias for bclr 5"},
{OP_ID(bset), 0xff8f, 0x9408, 1, OP_AVR1, "1001 0100 0sss 1000", OTY_ALBX,
"bset", "s", "flag set", "SREG(s) <-- 1", "SREG-bit",
{"1", "1", "1", "1"}, "s = 0-7 = C,Z,N,V,S,H,T,I"},
{OP_ID(bclr), 0xff8f, 0x9488, 1, OP_AVR1, "1001 0100 1sss 1000", OTY_ALBI,
"bclr", "s", "flag clear", "SREG(s) <-- 0", "SREG-bit",
{"1", "1", "1", "1"}, "s = 0-7 = C,Z,N,V,S,H,T,I"},
// MCU Control Instructions
{OP_ID(break), 0xffff, 0x9598, 1, OP_AVR1, "1001 0101 1001 1000", OTY_MCUX,
"break", "", "break", "on-chip debug system breakpoint", "--------",
{"-", "-", "-", "-"}, "not available on all parts"},
{OP_ID(nop), 0xffff, 0x0000, 1, OP_AVR1, "0000 0000 0000 0000", OTY_MCUI,
"nop", "", "no operation", "-", "--------",
{"1", "1", "1", "1"}, ""},
{OP_ID(sleep), 0xffff, 0x9588, 1, OP_AVR1, "1001 0101 1000 1000", OTY_MCUX,
"sleep", "", "sleep", "sleep mode defined by the MCU control register", "--------",
{"-", "-", "-", "-"}, ""},
{OP_ID(wdr), 0xffff, 0x95a8, 1, OP_AVR1, "1001 0101 1010 1000", OTY_MCUI,
"wdr", "", "watchdog reset", "reset the watchdog timer", "--------",
{"1", "1", "1", "1"}, ""},
/*
* Special 16-bit lds/sts opcodes for reduced-core ATtinys only; they conflict with
* regular ldd Rd, Y+q; ldd Rd, Z+q; std Y+q, Rr; std Z+q, Rr opcodes
*/
{OP_ID(lds_rc), 0xf800, 0xa000, 1, OP_AVR_RC, "1010 0aaa dddd aaaa", OTY_XFRX|OTY_RUPP,
"lds", "Rd, a", "load direct from data space", "Rd <-- (a)", "--------",
{"n/a", "n/a", "n/a", "2"}, "AVRrc only (TPI parts); a = 0x40..0xbf"},
{OP_ID(sts_rc), 0xf800, 0xa800, 1, OP_AVR_RC, "1010 1aaa rrrr aaaa", OTY_XFRX|OTY_RUPP,
"sts", "a, Rr", "store direct to data space", "(a) <-- Rr", "--------",
{"n/a", "n/a", "n/a", "1"}, "AVRrc only (TPI parts); a = 0x40..0xbf"},
// Undocumented opcodes: they are said(!) to do the following
{OP_ID(u_nop_1), 0xff00, 0x0000, 1, OP_AVR_ILL, "0000 0000 xxxx xxxx", OTY_MCUI,
"u/nop", "", "no operation", "-", "--------",
{"1", "1", "1", "1"}, "xxxx xxxx != 0000 0000"},
{OP_ID(u_nop_2), 0xfe0f, 0x9003, 1, OP_AVR_ILL, "1001 000x xxxx 0011", OTY_MCUI,
"u/nop", "", "no operation", "-", "--------",
{"1", "1", "1", "1"}, ""},
{OP_ID(u_nop_3), 0xfe0f, 0x9008, 1, OP_AVR_ILL, "1001 000x xxxx 1000", OTY_MCUI,
"u/nop", "", "no operation", "-", "--------",
{"1", "1", "1", "1"}, ""},
{OP_ID(u_nop_4), 0xfe0f, 0x900b, 1, OP_AVR_ILL, "1001 000x xxxx 1011", OTY_MCUI,
"u/nop", "", "no operation", "-", "--------",
{"1", "1", "1", "1"}, ""},
{OP_ID(u_nop_5), 0xfe0f, 0x9203, 1, OP_AVR_ILL, "1001 001x xxxx 0011", OTY_MCUI,
"u/nop", "", "no operation", "-", "--------",
{"1", "1", "1", "1"}, ""},
{OP_ID(u_nop_6), 0xfe0f, 0x9208, 1, OP_AVR_ILL, "1001 001x xxxx 1000", OTY_MCUI,
"u/nop", "", "no operation", "-", "--------",
{"1", "1", "1", "1"}, ""},
{OP_ID(u_nop_7), 0xfe0f, 0x920b, 1, OP_AVR_ILL, "1001 001x xxxx 1011", OTY_MCUI,
"u/nop", "", "no operation", "-", "--------",
{"1", "1", "1", "1"}, ""},
{OP_ID(u_icall), 0xff1f, 0x9509, 1, OP_AVR_ILL, "1001 0101 xxx0 1001", OTY_JMPX|OTY_ZWORD,
"u/icall", "", "indirect call to (Z)", "PC(15:0) <-- Z, PC(21:16) <-- 0", "--------",
{"3+", "2+", "2+", "3"}, "xxx != 000"},
{OP_ID(u_eicall), 0xff1f, 0x9519, 1, OP_AVR_ILL, "1001 0101 xxx1 1001", OTY_JMPX|OTY_ZWORD,
"u/eicall", "", "extended indirect call to (Z)", "PC(15:0) <-- Z, PC(21:16) <-- EIND", "--------",
{"4", "3", "3", "n/a"}, "xxx != 000"},
{OP_ID(u_ret), 0xff9f, 0x9508, 1, OP_AVR_ILL, "1001 0101 0xx0 1000", OTY_JMPX,
"u/ret", "", "subroutine return", "SP --> SP + 2, PC <-- STACK", "--------",
{"4+", "4+", "4+", "6"}, "xx != 00"},
{OP_ID(u_reti), 0xff9f, 0x9518, 1, OP_AVR_ILL, "1001 0101 0xx1 1000", OTY_JMPX,
"u/reti", "", "interrupt return", "SP -> SP + 2, PC <-- STACK", "I-------",
{"4+", "4+", "4+", "6"}, "xx != 00"},
{OP_ID(u_nop_8), 0xffff, 0x95b8, 1, OP_AVR_ILL, "1001 0101 1011 1000", OTY_MCUI,
"u/nop", "", "no operation", "-", "--------",
{"1", "1", "1", "1"}, ""},
{OP_ID(u_nop_9), 0xfe0f, 0x9404, 1, OP_AVR_ILL, "1001 010x xxxx 0100", OTY_MCUI,
"u/nop", "", "no operation", "-", "--------",
{"1", "1", "1", "1"}, ""},
{OP_ID(u_nop_a), 0xff0f, 0x950b, 1, OP_AVR_ILL, "1001 0101 xxxx 1011", OTY_MCUI,
"u/nop", "", "no operation", "-", "--------",
{"1", "1", "1", "1"}, ""},
{OP_ID(u_ijmp), 0xff1f, 0x9409, 1, OP_AVR_ILL, "1001 0100 xxx0 1001", OTY_JMPI|OTY_ZWORD,
"u/ijmp", "", "indirect jump to (Z)", "PC(15:0) <-- Z, PC(21:16) <-- 0", "--------",
{"2", "2", "2", "2"}, "xxx != 000"},
{OP_ID(u_eijmp), 0xff1f, 0x9419, 1, OP_AVR_ILL, "1001 0100 xxx1 1001", OTY_JMPX|OTY_ZWORD,
"u/eijmp", "", "extended indirect jump to (Z)", "PC(15:0) <-- Z, PC(21:16) <-- EIND", "--------",
{"2", "2", "2", "n/a"}, "xxx != 000"},
{OP_ID(u_bld), 0xfe08, 0xf808, 1, OP_AVR_ILL, "1111 100d dddd 1bbb", OTY_ALBI|OTY_RALL,
"u/bld", "Rd, b", "bit load from T to register", "Rd(b) <-- T", "--------",
{"1", "1", "1", "1"}, ""},
{OP_ID(u_bst), 0xfe08, 0xfa08, 1, OP_AVR_ILL, "1111 101r rrrr 1bbb", OTY_ALBI|OTY_RALL,
"u/bst", "Rr, b", "bit store from register to T", "T <-- Rr(b)", "-T------",
{"1", "1", "1", "1"}, ""},
{OP_ID(u_sbrc), 0xfe08, 0xfc08, 1, OP_AVR_ILL, "1111 110r rrrr 1bbb", OTY_SKPI|OTY_RALL,
"u/sbrc", "Rr, b", "skip if bit in register cleared", "if(Rr(b)=0) PC <-- PC + 2/3", "--------",
{"1-3", "1-3", "1-3", "1/2"}, ""},
{OP_ID(u_sbrs), 0xfe08, 0xfe08, 1, OP_AVR_ILL, "1111 111r rrrr 1bbb", OTY_SKPI|OTY_RALL,
"u/sbrs", "Rr, b", "skip if bit in register set", "if(Rr(b)=1) PC <-- PC + 2/3", "--------",
{"1-3", "1-3", "1-3", "1/2"}, ""},
};
// Return whether or not the given 16-bit opcode is the mnemonic
int op16_is_mnemo(int op, AVR_mnemo mnemo) {
return mnemo < 0 || mnemo >= MNEMO_N? 0:
(op & avr_opcodes[mnemo].mask) != avr_opcodes[mnemo].value? 0:
!(avr_opcodes[mnemo].type & OTY_CONSTRAINT)? 1:
(op>>0 & 15) == (op>>4 & 15) && (op>>9 & 1) == (op>>8 & 1); // Constraint Rd == Rr
}
// Return whether or not the given 16-bit opcode has a 16-bit address argument
int is_opcode32(int op) {
return
op16_is_mnemo(op, MNEMO_call) || op16_is_mnemo(op, MNEMO_jmp) ||
op16_is_mnemo(op, MNEMO_sts) || op16_is_mnemo(op, MNEMO_lds);
}
// Return width of opcode in bytes (2 or 4)
int op_width(int op16) {
return is_opcode32(op16)? 4: 2;
}
// Return the register number of the 16-bit ldi opcode and 0 if it's not ldi
int ldi_Rd(int op) {
return op16_is_mnemo(op, MNEMO_ldi)? 16 + ((op >> 4) & 15): 0;
}
// Return the constant number in the 16-bit ldi opcode and -1 if it's not ldi
int ldi_K(int op) {
return op16_is_mnemo(op, MNEMO_ldi)? ((op & 0x0f00) >> 4) | (op & 0x0f): -1;
}
// Returns bitmask of first character chr in bits
static int bitmask_first_chr(const char *bits, int chr) {
int ret = 0x8000;
for(const char *c = bits; *c && *c != chr && ret; c++)
if(*c != ' ')
ret >>= 1;
return ret;
}
// Return first match of opcode that is compatible with avrlevel or MNEMO_NONE
AVR_mnemo opcode_mnemo(int op, int avrlevel) {
for(AVR_mnemo i = 0; i < MNEMO_N; i++)
if(avr_opcodes[i].avrlevel & avrlevel)
if(op16_is_mnemo(op, i)) {
if(avrlevel == PART_AVR_RC && (avr_opcodes[i].type & OTY_REG_MASK) == OTY_RALL) {
// Reduced-core ATtiny does not have registers r0, ..., r15
int bmask; // Assert highest bit in 5-bit r/d is set
if((bmask = bitmask_first_chr(avr_opcodes[i].bits, 'r')) && !(op & bmask))
return MNEMO_NONE;
if((bmask = bitmask_first_chr(avr_opcodes[i].bits, 'd')) && !(op & bmask))
return MNEMO_NONE;
}
return i;
}
return MNEMO_NONE;
}
// Opcodes in avr_opcodes[] that a part ought to be able to run
int avr_get_archlevel(const AVRPART *p) {
int ret =
p->prog_modes & PM_UPDI? PART_AVR_XT:
p->prog_modes & PM_PDI? PART_AVR_XM:
p->prog_modes & PM_TPI? PART_AVR_RC: 0;
if(!ret) { // Non-TPI classic part
switch(p->archnum) {
case 1:
ret = PART_AVR1;
break;
default: // If AVRDUE doesn't know, it's probably rare & old
case 2:
ret = PART_AVR2;
break;
case 25:
ret = PART_AVR25;
break;
case 3: case 31: case 35: // Sic
ret = PART_AVR3;
break;
break;
case 4:
ret = PART_AVR4;
break;
case 5:
ret = PART_AVR5;
break;
case 51:
ret = PART_AVR51;
break;
case 6:
ret = PART_AVR6;
}
}
AVRMEM *mem = avr_locate_flash(p);
if(mem) { // Add opcodes needed for large parts in any case
if(mem->size > 8192)
ret |= OP_AVR_M; // JMP, CALL
if(mem->size > 65536)
ret |= OP_AVR_L; // ELPM
if(mem->size > 128*1024)
ret |= OP_AVR_XL; // EIJMP, EICALL
}
return ret;
}
// Index in the avr_opcodes[].clock[] array for timings of an opcode
AVR_cycle_index avr_get_cycle_index(const AVRPART *p) {
return
p->prog_modes & PM_UPDI? OP_AVRxt:
p->prog_modes & PM_PDI? OP_AVRxm:
p->prog_modes & PM_TPI? OP_AVRrc: OP_AVRe;
}
// Return the mnemonic string of an opcode
const char *mnemo_str(int op) {
AVR_mnemo mnemo = opcode_mnemo(op, PART_ALL | OP_AVR_ILL);
if(mnemo < 0 || mnemo >= MNEMO_N)
return "illegal";
return avr_opcodes[mnemo].opcode;
}
/*
* Return
* 2 if opcode treats Z register as word address
* 1 if opcode treats Z as byte address
* 0 otherwise (Z not involved in opcode)
*/
int z_width(int op16, AVR_mnemo *mnemop) {
AVR_mnemo mlist[] = {
MNEMO_ijmp, MNEMO_eijmp, MNEMO_icall, MNEMO_eicall, MNEMO_u_icall, MNEMO_u_eicall,
MNEMO_u_ijmp, MNEMO_u_eijmp, MNEMO_ld_z, MNEMO_ld_zp, MNEMO_ld_mz, MNEMO_ldd_z,
MNEMO_st_z, MNEMO_st_zp, MNEMO_st_mz, MNEMO_std_z, MNEMO_lpm_0, MNEMO_lpm_z,
MNEMO_lpm_zp, MNEMO_elpm_0, MNEMO_elpm_z, MNEMO_elpm_zp, MNEMO_spm, MNEMO_spm_zp,
MNEMO_xch, MNEMO_las, MNEMO_lac, MNEMO_lat,
};
for(AVR_mnemo m=0; m < (AVR_mnemo) (sizeof mlist/sizeof*mlist); m++)
if(op16_is_mnemo(op16, mlist[m])) {
if(mnemop)
*mnemop = mlist[m];
return avr_opcodes[mlist[m]].type & OTY_ZWORD? 2: 1;
}
return 0;
}

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2022 Stefan Rueger <stefan.rueger@urclocks.c>
* Copyright (C) 2022 Stefan Rueger <stefan.rueger@urclocks.com>
*
* 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
@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#include <ac_cfg.h>
#include <stdio.h>
@@ -66,8 +64,8 @@
* flash (and sometimes EEPROM, too) looks like a NOR memory, ie, a write can
* only clear bits, never set them. For NOR memories a page erase or, if not
* available, a chip erase needs to be issued before writing arbitrary data.
* Bootrow and usersig are generally unaffected by a chip erase, so will need
* a page erase. When a memory looks like a NOR memory, either page erase is
* Usersig is generally unaffected by a chip erase, so will always need a
* page erase. When a memory looks like a NOR memory, either page erase is
* deployed (eg, with parts that have PDI/UPDI interfaces), or if that is not
* available, both EEPROM and flash caches are fully read in, a
* pgm->chip_erase() command is issued and both EEPROM and flash are written
@@ -90,7 +88,7 @@
* has these clear bits on the device. Only with this evidence is the EEPROM
* cache preset to all 0xff otherwise the cache discards all pending writes
* to EEPROM and is left unchanged otherwise. avr_chip_erase_cached() does not
* affect the bootrow or usersig cache.
* affect the usersig cache.
*
* The avr_page_erase_cached() function erases a page and synchronises it
* with the cache.
@@ -330,13 +328,6 @@ error:
}
// Does the memory region only haxe 0xff?
static int _is_all_0xff(const void *p, size_t n) {
const unsigned char *q = (const unsigned char *) p;
return n <= 0 || (*q == 0xff && memcmp(q, q+1, n-1) == 0);
}
// A coarse guess where any bootloader might start (prob underestimates the start)
static int guessBootStart(const PROGRAMMER *pgm, const AVRPART *p) {
int bootstart = 0;
@@ -370,12 +361,12 @@ typedef struct {
AVRMEM *mem;
AVR_Cache *cp;
int isflash, iseeprom, zopaddr, pgerase;
} CacheDesc_t;
} Cache_desc;
// Write flash, EEPROM, bootrow and usersig caches to device and free them
int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) {
CacheDesc_t mems[] = {
Cache_desc mems[] = {
{ avr_locate_flash(p), pgm->cp_flash, 1, 0, -1, 0 },
{ avr_locate_eeprom(p), pgm->cp_eeprom, 0, 1, -1, 0 },
{ avr_locate_bootrow(p), pgm->cp_bootrow, 0, 0, -1, 0 },
@@ -539,7 +530,7 @@ int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) {
} else if(mems[i].iseeprom) {
// Don't know whether chip erase has zapped EEPROM
for(int n = 0; n < cp->size; n += cp->page_size) {
if(!_is_all_0xff(cp->copy + n, cp->page_size)) { // First page that had EEPROM data
if(!is_memset(cp->copy + n, 0xff, cp->page_size)) { // First page that had EEPROM data
if(avr_read_page_default(pgm, p, mem, n, cp->copy + n) < 0) {
report_progress(1, -1, NULL);
if(quell_progress)
@@ -547,8 +538,8 @@ int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) {
pmsg_error("EEPROM read failed at addr 0x%04x\n", n);
return LIBAVRDUDE_GENERAL_FAILURE;
}
// EEPROM zapped by chip erase? Set all copy to 0xff
if(_is_all_0xff(cp->copy + n, cp->page_size))
// EEPROM zapped by chip erase? Set all of copy to 0xff
if(is_memset(cp->copy + n, 0xff, cp->page_size))
memset(cp->copy, 0xff, cp->size);
break;
}
@@ -696,10 +687,11 @@ int avr_write_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM
// Erase the chip and set the cache accordingly
int avr_chip_erase_cached(const PROGRAMMER *pgm, const AVRPART *p) {
CacheDesc_t mems[3] = {
Cache_desc mems[] = {
{ avr_locate_flash(p), pgm->cp_flash, 1, 0, -1, 0 },
{ avr_locate_eeprom(p), pgm->cp_eeprom, 0, 1, -1, 0 },
// bootrow/usersig is unaffected by CE
{ avr_locate_bootrow(p), pgm->cp_bootrow, 0, 0, -1, 0 },
// usersig is unaffected by CE
};
int rc;
@@ -725,19 +717,19 @@ int avr_chip_erase_cached(const PROGRAMMER *pgm, const AVRPART *p) {
memset(cp->cont, 0xff, cp->size);
memset(cp->iscached, 1, cp->size/cp->page_size);
}
} else if(mems[i].iseeprom) { // Test whether cached EEPROM pages were zapped
bool erasedee = 0;
} else { // Test whether cached EEPROM/bootrow pages were zapped
bool erased = 0;
for(int pgno = 0, n = 0; n < cp->size; pgno++, n += cp->page_size) {
if(cp->iscached[pgno]) {
if(!_is_all_0xff(cp->copy + n, cp->page_size)) { // Page has EEPROM data?
if(!is_memset(cp->copy + n, 0xff, cp->page_size)) { // Page has data?
if(avr_read_page_default(pgm, p, mem, n, cp->copy + n) < 0)
return LIBAVRDUDE_GENERAL_FAILURE;
erasedee = _is_all_0xff(cp->copy + n, cp->page_size);
erased = is_memset(cp->copy + n, 0xff, cp->page_size);
break;
}
}
}
if(erasedee) { // EEPROM was erased, set cache correspondingly
if(erased) { // Memory was erased, set cache correspondingly
memset(cp->copy, 0xff, cp->size);
memset(cp->cont, 0xff, cp->size);
memset(cp->iscached, 1, cp->size/cp->page_size);
@@ -788,7 +780,7 @@ int avr_page_erase_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM
if(loadCachePage(cp, pgm, p, mem, (int) addr, cacheaddr, 0) < 0)
return LIBAVRDUDE_GENERAL_FAILURE;
if(!_is_all_0xff(cp->cont + (cacheaddr & ~(cp->page_size-1)), cp->page_size))
if(!is_memset(cp->cont + (cacheaddr & ~(cp->page_size-1)), 0xff, cp->page_size))
return LIBAVRDUDE_GENERAL_FAILURE;
return LIBAVRDUDE_SUCCESS;

View File

@@ -17,8 +17,6 @@
.\" along with this program. If not, see <http://www.gnu.org/licenses/>.
.\"
.\"
.\" $Id$
.\"
.Dd January 15, 2023
.Os
.Dt AVRDUDE 1
@@ -286,7 +284,7 @@ for Teensy specific options.
.Pp
Input files can be provided, and output files can be written in
different file formats, such as raw binary files containing the data
to download to the chip, Intel hex format, or Motorola S-record
to download to the chip, Intel Hex format, or Motorola S-Record
format. There are a number of tools available to produce those files,
like
.Xr asl 1
@@ -470,106 +468,83 @@ is engaged by default when specifying
. Fl c
arduino.
.It Fl D
Disable auto erase for flash. When the
Disable auto-erase for flash. When the
.Fl U
option with flash memory is specified,
option for writing to any flash memory is specified,
.Nm
will perform a chip erase before starting any of the programming
operations, since it generally is a mistake to program the flash
without performing an erase first. This option disables that.
Auto erase is not used for ATxmega devices as these devices can
use page erase before writing each page so no explicit chip erase
is required.
Note however that any page not affected by the current operation
will retain its previous contents.
Setting
operations, since it generally is a mistake to program the flash without
performing an erase first. This option disables that. Auto-erase is not
used for ATxmega parts nor for the UPDI (AVR8X family) parts as these can
use page erase before writing each page so no explicit chip erase is
required. Note, however, that any flash page not affected by the current
operation will retain its previous contents. Setting
.Fl D
implies
.Fl A.
.It Fl e
Causes a chip erase to be executed. This will reset the contents of the
Causes a chip erase to be executed. This will reset the contents of the
flash ROM and EEPROM to the value
.Ql 0xff ,
and clear all lock bits.
Except for ATxmega devices which can use page erase,
it is basically a prerequisite command before the flash ROM can be
reprogrammed again. The only exception would be if the new
Except for ATxmega and UPDI (AVR8X family) devices, all of which can use
page erase, it is basically a prerequisite command before the flash ROM
can be reprogrammed again. The only exception would be if the new
contents would exclusively cause bits to be programmed from the value
.Ql 1
to
.Ql 0 .
Note that in order to reprogram EEPROM cells, no explicit prior chip
This option carries out the chip erase at the beginning, before any of the
.Fl U,
.Fl T
or
.Fl t
options are processed. If a chip erase is required in at a certain
position within the sequence of
.Fl U,
.Fl T
or
.Fl t
options it is recommended to use -T erase instead which is processed in
the given command line order.
.Pp
In absence of an explicit
.Fl e
or
.Fl D
option
.Nm
tries to augur from the command line whether or not the chip should be
auto-erased at the beginning. If
.Nm
detects a
.Fl U
command that writes to flash then auto-erase will be carried out before
any other programming unless a -T erase commad has been detected
beforehand and unless flash is read before writing to it. For the purpose
of this analysis any terminal command is considered to possibly read
flash.
.Pp
Note that for reprogramming EEPROM cells, no explicit prior chip
erase is required since the MCU provides an auto-erase cycle in that
case before programming the cell.
.It Xo Fl E Ar exitspec Ns
.Op \&, Ns Ar exitspec
.Xc
By default,
.Nm
leaves the parallel port in the same state at exit as it has been
found at startup. This option modifies the state of the
.Ql /RESET
and
.Ql Vcc
lines the parallel port is left at, according to the
Pass
.Ar exitspec
arguments provided, as follows:
.Bl -tag -width noreset
.It Ar reset
The
.Ql /RESET
signal will be left activated at program exit, that is it will be held
.Em low ,
in order to keep the MCU in reset state afterwards. Note in particular
that the programming algorithm for the AT90S1200 device mandates that
the
.Ql /RESET
signal is active
.Em before
powering up the MCU, so in case an external power supply is used for this
MCU type, a previous invocation of
to the chosen programmer. The interpretation of the exitspec parameter
depends on the programmer itself. See below for a list of programmers
accepting exitspec parameter options or issue
.Nm
with this option specified is one of the possible ways to guarantee this
condition.
.Em reset
is supported by the linuxspi and flip2 programmer options, as well as all
parallel port based programmers.
.It Ar noreset
The
.Ql /RESET
line will be deactivated at program exit, thus allowing the MCU target
program to run while the programming hardware remains connected.
.Em noreset
is supported by the linuxspi and flip2 programmer options, as well as all
parallel port based programmers.
.It Ar vcc
This option will leave those parallel port pins active
.Pq \&i. \&e. Em high
that can be used to supply
.Ql Vcc
power to the MCU.
.It Ar novcc
This option will pull the
.Ql Vcc
pins of the parallel port down at program exit.
.It Ar d_high
This option will leave the 8 data pins on the parallel port active.
.Pq \&i. \&e. Em high
.It Ar d_low
This option will leave the 8 data pins on the parallel port inactive.
.Pq \&i. \&e. Em low
.El
.Pp
Multiple
.Ar exitspec
arguments can be separated with commas.
-E help ... to see the options of the chosen programmer.
.It Fl F
Normally,
.Nm
tries to verify that the device signature read from the part is
reasonable before continuing. Since it can happen from time to time
that a device has a broken (erased or overwritten) device signature
but is otherwise operating normally, this options is provided to
but is otherwise operating normally, this option is provided to
override the check.
Also, for programmers like the Atmel STK500 and STK600 which can
adjust parameters local to the programming tool (independent of an
@@ -613,7 +588,7 @@ No-write: disables writing data to the MCU whilst processing -U
.Nm avrdude
). The terminal mode continues to write to the device.
.It Fl O
Perform a RC oscillator run-time calibration according to Atmel
Perform an RC oscillator run-time calibration according to Atmel
application note AVR053.
This is only supported on the STK500v2, AVRISP mkII, and JTAG ICE mkII
hardware.
@@ -773,10 +748,31 @@ Perform a memory operation as indicated when it is its turn in relation to
other -t interactive terminals, -T terminal commands and -U memory
operations. The
.Ar memory
field specifies the memory to operate on. The available memory types are
device-dependent, the actual configuration can be viewed with the
field specifies the memory to operate on. From version 8.0 the memory
field can also be a comma-separated list of memories, eg,
.Ar flash,eeprom ;
also, Intel Hex or Motorola S-Record files generated by AVRDUDE can store
multiple memories. The special memory
.Ar ALL
expands to all memories that a part has while
.Ar all
expands to all memories with exception of sub-memories.
.Ar etc
is the same as
.Ar all ;
this can be used to change the order in which memories are written to
or read from file, eg,
.Ar signature,etc
is a list of all memories such that the
.Ar signature
memory comes first. It is possible to remove a memory from the list so far
by preceding a minus or backslash, eg,
.Ar all,-calibration .
The available memory types are device-dependent, the actual configuration
can be viewed with the
.Cm part
command in terminal mode.
.Pp
Typically, a device's memory configuration at least contains
the memories
.Ar flash ,
@@ -792,10 +788,25 @@ memory contains the three device signature bytes, which should
be, but not always are, unique for the part. The
.Ar lock
memory of one or four bytes typically details whether or not external
reading/writing of the flash memory, or parts of it, is allowed. Parts
will also typically have fuse bytes, which are read/write memories for
configuration of the device and calibration memories that typically
contain read-only factory calibration values.
reading/writing of the flash memory, or parts of it, is allowed. After
restricting access via the lock memory, often the only way to unlock
memory is via a chip erase. Parts will also typically have fuse bytes,
which are read/write memories for configuration of the device and
calibration memories that typically contain read-only factory calibration
values.
.Pp
The flash memory, being physically implemented as NOR-memory, is special
in the sense that it is normally only possible to program bits to change
from 1 to 0. Before reprogramming takes place normally flash memory has
to be erased. Older parts would only offer a chip erase to do so, which
also erases EEPROM unless a fuse configuration preserves its contents. If
AVRDUDE detects a -U option that writes to a flash memory it will
automatically trigger a chip erase for these older parts. ATxmegas or
UPDI parts (AVR8X family) offer a page erase, and AVRDUDE takes advantage
of that by erasing pages before programming them unless -e (chip erase) or
-D (do not erase before writing) was requested. It should be noted that in
absence of the -e chip erase option any ATxmega or UPDI flash pages not
affected by the programming will retain their previous content.
.Pp
Classic devices may have the following memories in addition to eeprom, flash, signature and lock:
.Bl -tag -width " calibration" -compact
@@ -812,11 +823,17 @@ Low fuse byte
.It lock
Lock byte
.It prodsig
Signature, calibration byte and serial number in a small read-only memory,
Signature, calibration byte(s) and serial number in a small read-only memory,
which is only documented to be available for ATmega324PB, ATmega328PB,
ATtiny102 and ATtiny104; programmers may or may not be able to read this memory
ATtiny102 and ATtiny104;
.Nm
generally tries to make this memory available, also for parts where it is
not documented, but not all programmers may be able to read this memory
.It sigrow
Memory alias for prodsig
.It sernum
The serial number part of prodsig; owing to scarce documentation this may not
actually turn out to be a serial number or be readable by some programmers
.It usersig
Three extra flash pages for firmware settings; this memory is not erased
during a chip erase. Only some classic parts,
@@ -845,6 +862,13 @@ Application flash area
Application table flash area
.It boot
Boot flash area
.It calibration
An area of 4 (ATxmega-A series) or 5 bytes (ATxmega-B/C/D/E) with
oscillator calibration values; this is a sub-memory of prodsig
.It fuses
A logical memory of 7 bytes containing all fuseX of a part, which can be
used to program all fuses at the same time; note that some fuse bytes will
be reserved, though
.It fuse0
A.k.a. jtaguid: JTAG user ID for some devices
.It fuse1
@@ -857,12 +881,17 @@ Other fuse bytes of ATxmega devices, where
is 2, 4 or 5, for system configuration
.It prodsig
The production signature row is a read-only memory section for factory
programmed data such as the signature and calibration values for
oscillators or analogue modules; it also contains a serial number that
consists of the production lot number, wafer number and wafer coordinates
for the part
programmed data such as the calibration values for oscillators or analogue
modules; it also contains a serial number that consists of the production
lot number, wafer number and wafer coordinates for the part
.It sernum
Serial number with a unique ID for the part consisting of 10 bytes; these
are part of the prodsig memory above
.It sigrow
Memory alias for prodsig
.It tempsense
A two-byte memory, which is located within prodsig; it contains a 12-bit
temperature sensor calibration value
.It usersig
Additional flash memory page that can be used for firmware settings; this
memory is not erased during a chip erase
@@ -895,7 +924,7 @@ A.k.a. bootend or bootsize: end of the boot section or the boot size in blocks o
.It fusea
A.k.a. pdicfg: configures/locks updi access; it is the only fuse that consists of two bytes
.It fuses
A "logical" memory of up to 16 bytes containing all fuseX of a part, which can be
A logical memory of up to 16 bytes containing all fuseX of a part, which can be
used to program all fuses at the same time
.It osc16err
Two bytes typically describing the 16 MHz oscillator frequency error at 3 V and 5 V, respectively
@@ -917,10 +946,11 @@ Temperature sensor calibration values
.It bootrow
Extra page of memory that is only accessible by the MCU in bootloader
code; UDPI can read and write this memory only when the device is
unlocked; bootrow is not erased during chip erase
unlocked
.It userrow
Extra page of EEPROM memory that can be used for firmware settings; this
memory is not erased during a chip erase
memory is not erased during a chip erase; UPDI cannot read this memory
when the device is locked
.It sib
Special system information block memory with information about AVR family, chip revision etc.
.It io
@@ -941,7 +971,10 @@ field specifies what operation to perform:
.It Ar r
read device memory and write to the specified file
.It Ar w
read data from the specified file and write to the device memory
read data from the specified file and write to the device memories in the
list; read-only memories in a memory list are skipped, as are fuses and
lock bits when the programmer is a bootloader; writing to single read-only
memories fails only if the contents differs between the file and memory
.It Ar v
read data from both the device and the specified file and perform a verify
.El
@@ -961,11 +994,11 @@ Intel Hex
.It Ar I
Intel Hex with comments on download and tolerance of checksum errors on upload
.It Ar s
Motorola S-record
Motorola S-Record
.It Ar r
raw binary; little-endian byte order, in the case of the flash ROM data
raw binary; little-endian byte order, in the case of the flash data
.It Ar e
ELF (Executable and Linkable Format)
ELF (Executable and Linkable Format, for input only)
.It Ar m
immediate mode; actual byte values are specified on the command line,
separated by commas or spaces in place of the filename field of the -U
@@ -1016,8 +1049,15 @@ followed by 0x00, and 0x01234 will occupy 4 bytes. See the description of
the terminal write command for more details.
.Pp
In absence of an explicit file format, the default is to use auto
detection for input files, and raw binary format for output files. Note
that if a
detection for input files, raw binary format for output files from a
single memory read and Intel Hex with comments when an output file is
generated from a list of memories. Note that while
.Nm avrdude
will generate a single output file from a memory list for all formats with
the exception of elf (:e) it only recognises Intel hex (:I or :i),
Motorola S-Record (:s) or elf files (:e, generated by the compiler) as
valid multi-memory files when reading a file for verifying or writing
memories. Note also that if a
.Ar filename
contains a colon as penultimate character the
.Ar format
@@ -1073,10 +1113,10 @@ The
.Ar addr
and
.Ar len
parameters of the dump, read, write, save and erase commands can be
parameters of the dump, read, disasm, write, save and erase commands can be
negative with the same syntax as substring computations in perl or python.
The table below details their meaning with respect to an example memory of size
sz=0x800.
sz=0x800 (2048 bytes).
.Pp
.nf
addr len Memory interval Comment
@@ -1123,6 +1163,103 @@ and display them (deprecated: use dump memory addr -1).
Read all bytes from the specified memory, and display them (deprecated: use dump memory 0 -1).
.It Ar read
Can be used as an alias for dump.
.It Ar disasm [opts] [arguments]
Like dump, the disasm command displays a part of the specified memory,
albeit by interpreting the memory contents as AVR opcodes and showing it
as assembler source code. Unlike dump, the disasm command has options;
these control how disasm displays its result (see below). Other than that,
the syntax of specifying the memory and its to be processed interval is
virtually the same as that of dump: the default disasm length is 32 bytes,
though, and sometimes the length can be slightly shorter or longer than
requested, so that the memory section for disasm aligns with opcodes.
Disasm options, once set, stay in force until switched off, typically by
changing the case of the option. This way, a simple disasm without further
options can be used to step through memory keeping the appearance. Disasm
knows the following options:
.Bl -tag -offset indent -width indent
.It -g
Generate avr-gcc source: this sets -sOFQ and outputs a .text preamble and
a main symbol unless the disassembly emits one itself; -G (the default)
switches off -g and stops outputting a preamble
.It -A
Do not show addresses; -a (the default) shows addresses
.It -O
Do not show opcode bytes; -o (the default) show opcode bytes
.It -C
Do not show comments; -c (the default) show comments
.It -f
Show affected flags in SREG, eg, ---SVNZC for the sbiw opcode; -F (the
default) do not show SREG flags
.It -q
Show the number of machine cycles that an opcode takes; -Q (the default)
do not show the cycles
.It -n
Put the opcode full name into comment, eg, subtract immediate from word
for the sbiw opcode; -N (the default) do not show the full opcode names
.It -e
Put a technical explanation of the opcode into the comment, eg, Rd+1:Rd
<-- Rd+1:Rd - K for the sbiw opcode; -E (the default) do not show
technical explanations
.It -S
Use AVR instruction set style: this means that register pairs are shown
as, eg, in r31:30 instead of r30; -s (the default) use avr-gcc code style
.It -L
Do not preprocess labels; -l (the default) preprocess jump/call labels
.It -d
Decode all opcodes including those that are undocumented; -D (the default)
decode only opcodes that are valid for the part
.It -z
Zap the list of jumps and calls before disassembly
.It -t=<file>
Delete symbols from a previously read tagfile, if any, and read the tagfile
<file> for assigning addresses to symbol names
.El
The tagfile is an ASCII file where each line describes a symbol for code
label addresses (L), variable addresses in flash (P) and variables
addresses in memory or I/O space (M). Hashmarks start a tagfile comment
that extends to the end of the line and is ignored by disasm. Here is a
defining example of how a tagfile looks like
.nf
---------------------------------------------------------------
0x7f54 L putch Outputs a char # L are code labels
0x7ffe P W 1 version16 A word integer # P are PGM data
0x7f80 P A 4 headings Column headers # Auto-aligned strings
0x0100 M B 2048 sram 2 kB SRAM # Memory address
---------------------------------------------------------------
.fi
Code labels L can be, eg, function names in program space or goto labels.
They use up to four columns separated by white space: the address, the
letter L, the symbolic name of the label and an optional comment column
for the symbol, which is copied by disasm into the disassembly comment
column, should this label be referenced or used by the code. Variable
symbols have a P or M in the second column; they can be bytes or words as
determined by the letter B or W in the third column and either single
variables or arrays as specified by the multiplicity count in the forth
column. P symbols, but not M symbols, can also be the base location of
nul-terminated strings as encoded by A or S in the third column. Out of
necessity, the space occupied by A/S strings varies. The difference
between A and S symbols is that the array of A strings might have an
additional nul character to auto-align the space occupied by them to an
even address. The fifth column is the symbolic name for the P or M address
that can be used by disasm to output relevant addresses symbolically. P
areas described in the tagfile also tell disasm that the corresponding
area is not code and should not be disassembled as such; instead the
.byte, .word, .asciz and sometimes at the end of the memory section .ascii
directives are used for disassembly of that area. As with L labels, P and
M variables may have an optional final comment column pertaining to the
symbol that may be output in the disassembly column as and when the
corresponding variables are used.
.Pp
Tagfiles are useful for disassembly to make the output of disasm more
readable. They can be built manually and incrementally as one's
understanding of the code grows. Alternatively, the bash shell script
elf2tag can automatically generate a tag file from the .elf file that
produced the flash contents:
.Pp
$ elf2tag file.elf >file.tag
.Pp
elf2tag uses the avr-objdump -d disassembly to create L labels and avr-nm
to generate M symbols.
.It Ar write memory addr data[,] {data[,]}
Manually program the respective memory cells, starting at address
.Ar addr ,
@@ -1201,9 +1338,41 @@ the address information and concatenate the chosen memory segments into
the output file. If the file name is - then
.Nm
writes to stdout.
.It Ar backup memlist file[:format]
Backup one or more memories to the specified file using the selected
format. The default format for a single-memory backup is :r (raw
binary); for multi-memory backups it is :I (Intel Hex with comments).
Memlist can be a comma separated list of memories just as in the
.Ar -U
command line argument.
.Ar backup
flushes the cache before reading memories.
.It Ar restore memlist file[:format]
Restore one or more memories from the specified file. It is the user's
responsibility to erase memories as needed beforehand: some paged memories
look like NOR-memory when using certain programmers, meaning programming
cannot set bits to 1 (eg, flash under most programmers). These memories
need to be erased beforehand using the erase command (see below). The
format only needs to be specified if it cannot be automatically detected,
eg, when the file is - for standard input. Memlist can be a comma
separated list of memories just as in the
.Ar -U
command line argument.
.Ar restore
flushes the cache before writing memories and resets the cache after
writing memories. Note that restoring read-only memories verifies file
contents with the corresponding microprocessor's memories.
.It Ar verify memlist file[:format]
Compare one or more memories with the specified file.
Memlist can be a comma separated list of memories just as in the
.Ar -U
command line argument.
.Ar verify
flushes the cache before verifying memories.
.It Ar erase
Perform a chip erase and discard all pending writes to EEPROM and flash.
Note that EEPROM will be preserved if the EESAVE fuse bit is set.
Perform a chip erase and discard all pending writes to flash, EEPROM and bootrow.
Note that EEPROM will be preserved if the EESAVE fuse bit is active, ie, had
a corresponding value at the last reset prior to the operation.
.It Ar erase memory
Erase the entire specified memory.
.It Ar erase memory addr len
@@ -1213,8 +1382,8 @@ Synchronise with the device all pending writes to flash, EEPROM, bootrow and
usersig. With some programmer and part combinations, flash (and sometimes
EEPROM, too) looks like a NOR memory, i.e., a write can only clear bits,
never set them. For NOR memories a page erase or, if not available, a chip
erase needs to be issued before writing arbitrary data. Bootrow and usersig are
generally unaffected by a chip erase. When a memory looks like a NOR
erase needs to be issued before writing arbitrary data. Usersig is
unaffected by a chip erase. When a memory looks like a NOR
memory, either page erase is deployed (e.g., with parts that have PDI/UPDI
interfaces), or if that is not available, both EEPROM and flash caches are
fully read in, a chip erase command is issued and both EEPROM and flash
@@ -1504,6 +1673,30 @@ might leave the EEPROM unerased, at least on some
versions of the bootloader.
.Ss Programmers accepting extended parameters
.Bl -tag -offset indent -width indent
.It Ar dryrun
.It Ar dryboot
These two programmers emulate programming and accept the following parameters:
.Bl -tag -offset indent -width indent
.It Ar xinit
Initialise memories with human-readable patterns. Flash memory will be
randomly configured with respect to bootloader, data and code length.
Patterns can best be seen with fixed-width font and the :I format
by inspecting the generated hex file or by using, eg, -U flash:r:-:I.
Patterns in flash memory are executable and represent benign AVR code, ie,
no I/O memory access. Choose a fixed seed for reproducible results.
.It Ar random
Initialise memories with random code and values. Flash memory will be
randomly configured with respect to bootloader, data and code length.
Random code in flash will be benign, that is, not accessing I/O memories,
SRAM or flash. Choose a fixed seed for reproducible results.
.It Ar seed=<n>
Seed random number generator with <n>; the default is time(NULL).
Setting this option with a fixed n > 0 will make the random choices
reproducible, ie, they will stay the same between different avrdude
runs.
.It Ar help
Show help menu and exit.
.El
.It Ar JTAG ICE mkII
.It Ar JTAGICE3
.It Ar Atmel-ICE
@@ -1532,14 +1725,14 @@ Other JTAG units might require a different bit shift count.
.sp 0.5
High-voltage UPDI programming is used to enable a UPDI pin that has previously
been set to RESET or GPIO mode. Use
.Ar -xhvupdi
.Ar -x hvupdi
to enable high-voltage UPDI initialization for targets that supports this.
.It Ar vtarg=VALUE, vtarg
.Nm Power Debugger only
.sp 0.5
The voltage generator can be enabled by setting a target voltage.
The current set-voltage can be read by
.Ar -xvtarg
.Ar -x vtarg
alone.
.It Ar help
Show help menu and exit.
@@ -1552,9 +1745,9 @@ Switch programmer to AVR or PIC mode, then exit: the PICkit 4 and MPLAB SNAP
programmer can only be utilised by
.Nm
when in AVR mode. Use
.Ar -xmode=avr
.Ar -x mode=avr
for switching to AVR mode, or
.Ar -xmode=pic
.Ar -x mode=pic
for switching to PIC mode.
.It Ar help
Show help menu and exit.
@@ -1564,7 +1757,7 @@ Show help menu and exit.
.It Ar suffer=VALUE, suffer
The SUFFER register allows the user to modify the behavior of the on-board mEDBG.
The current state can be read by
.Ar -xsuffer
.Ar -x suffer
alone.
.Bl -tag -offset indent -width indent
.It Bit 7 ARDUINO:
@@ -1584,7 +1777,7 @@ Fuses are safe-masked when bit sent to 1. Fuses are unprotected when set to 0
.It Ar vtarg_switch=VALUE, vtarg_switch
The on-board target voltage switch can be turned on or off by writing a 1 or
a 0. The current state can be read by
.Ar -xvtarg_switch
.Ar -x vtarg_switch
alone.
Note that the target power switch will always be on after a power cycle.
Also note that the smaller Xplained Nano boards does not have a target power switch.
@@ -1596,7 +1789,7 @@ Show help menu and exit.
.It Ar vtarg=VALUE, vtarg
The generated on-board target voltage can be changed by specifying a new voltage.
The current set-voltage can be read by
.Ar -xvtarg
.Ar -x vtarg
alone.
.It Ar help
Show help menu and exit.
@@ -1607,16 +1800,16 @@ Show help menu and exit.
.It Ar vtarg=VALUE, vtarg
The generated on-board target voltage can be changed by specifying a new voltage.
The current set-voltage can be read by
.Ar -xvtarg
.Ar -x vtarg
alone.
.It Ar fosc=VALUE[MHz|M|kHz|k|Hz|H], fosc
Set the programmable oscillator frequency. The current frequency can be read by
.Ar -xfosc
.Ar -x fosc
alone.
.It Ar varef=VALUE, varef
The generated on-board analog reference voltage can be changed by specifying
a new reference voltage. The current reference voltage can be read by
.Ar -xvaref
.Ar -x varef
alone.
.It Ar varef[0,1]=VALUE, varef[0,1]
.Nm STK600 only
@@ -1624,9 +1817,9 @@ alone.
The generated on-board analog reference voltage for channel 0 or channel 1 can
be changed by specifying a new reference voltage.
The current reference voltage can be read by
.Ar -xvaref0
.Ar -x varef0
or
.Ar -xvaref1
.Ar -x varef1
alone.
.It Ar attemps[=<1..99>]
.Nm STK500V1 only
@@ -1639,6 +1832,13 @@ original STK500. Used by avrdude for the correct calculation of fosc and sck.
.It Ar help
Show help menu and exit.
.El
.It Ar AVR109
.Bl -tag -offset indent -width indent
.It Ar autoreset
Toggle RTS/DTR lines on port open to issue a hardware reset.
.It Ar help
Show help menu and exit.
.El
.It Ar AVR910
.Bl -tag -offset indent -width indent
.It Ar devcode=VALUE
@@ -1671,13 +1871,15 @@ Show help menu and exit.
.It Ar attemps[=<1..99>]
Specify how many connection retry attemps to perform before exiting.
Defaults to 10 if not specified.
.It Ar noautoreset
Don't toggle RTS/DTR lines on port open to prevent a hardware reset.
.It Ar help
Show help menu and exit.
.El
.It Ar Urclock
.Bl -tag -offset indent -width indent
.It Ar showall
Show all info for the connected part, then exit. The -xshow... options
Show all info for the connected part, then exit. The -x show... options
below can be used to assemble a bespoke response consisting of a subset
(or only one item) of all available relevant information about the
connected part and bootloader.
@@ -1686,7 +1888,7 @@ Show a unique Urclock ID stored in either flash or EEPROM of the MCU, then exit.
.It Ar id=<E|F>.<addr>.<len>
Historically, the Urclock ID was a six-byte unique little-endian number
stored in Urclock boards at EEPROM address 257. The location of this
number can be set by the -xid=<E|F>.<addr>.<len> extended parameter. E
number can be set by the -x id=<E|F>.<addr>.<len> extended parameter. E
stands for EEPROM and F stands for flash. A negative address addr counts
from the end of EEPROM and flash, respectively. The length len of the
Urclock ID can be between 1 and 8 bytes.
@@ -1695,7 +1897,7 @@ Show the last-modified date of the input file for the flash application,
then exit. If the input file was stdin, the date will be that of the
programming. Date and filename are part of the metadata that the urclock
programmer stores by default in high flash just under the bootloader; see also
-xnometadata.
-x nometadata.
.It Ar showfilename
Show the input filename (or title) of the last flash writing session, then exit.
.It Ar title=<string>
@@ -1727,7 +1929,7 @@ i.e., typically top of flash, so the urclock programmer can look up the
bootloader size itself. In backward-compatibility mode, when programming
via other bootloaders, this option can be used to tell the programmer the
size, and therefore the location, of the bootloader.
.It Ar vectornum=<arg>
.It Ar vectornum=<n>
Manual override for vector number. Urboot bootloaders put the vector
number used by a vector bootloader into a table at the top of flash, so
this option is normally not needed for urboot bootloaders. However, it is
@@ -1752,7 +1954,7 @@ Upload unchanged flash input files and trim below the bootloader if
needed. This is most useful when one has a backup of the full flash and
wants to play that back onto the device. No metadata are written in this
case and no vector patching happens either if it is a vector bootloader.
However, for vector bootloaders, even under the option -xrestore an
However, for vector bootloaders, even under the option -x restore an
input file will not be uploaded for which the reset vector does not point
to the vector bootloader. This is to avoid writing an input file to the
device that would render the vector bootloader not functional as it would
@@ -1769,20 +1971,22 @@ title) and no date either.
On writing to flash do not store metadata except the metadata code byte
0xff saying there are no metadata. In particular, no data store frame is
programmed.
.It Ar noautoreset
Don't toggle RTS/DTR lines on port open to prevent a hardware reset.
.It Ar nometadata
Do not support any metadata. The full flash besides the bootloader is
available for the application. If the application is smaller than the
available space then a metadata code byte 0xff is stored nevertheless to
indicate there are no further metadata available. In absence of
-xnometadata, the default for the urclock programmer is to write as much
-x nometadata, the default for the urclock programmer is to write as much
metadata (filename, data and store information) as the size of the
uploaded application and the other extended options allow. The subtle
difference between -xnometadata and -xnostore is that the latter always
difference between -x nometadata and -x nostore is that the latter always
explicitly stores in flash that no further metadata are available, so that
a such prepared flash can always be queried with
.Nm
-xshowall. In contrast to this, it cannot be guaranteed that a -xshowall
query on flash prepared with -xnometadata yields useful results.
-x showall. In contrast to this, it cannot be guaranteed that a -x showall
query on flash prepared with -x nometadata yields useful results.
.It Ar delay=<n>
Add a <n> ms delay after reset. This can be useful if a board takes a
particularly long time to exit from external reset. <n> can be negative,
@@ -1791,7 +1995,7 @@ shortened accordingly.
.It Ar strict
Urclock has a faster, but slightly different strategy than -c arduino to
synchronise with the bootloader; some stk500v1 bootloaders cannot cope
with this, and they need the -xstrict option.
with this, and they need the -x strict option.
.It Ar help
Show help menu and exit.
.El
@@ -1916,6 +2120,8 @@ Add a <n> milliseconds delay after resetting the part through toggling the
DTR/RTS lines. This can be useful if a board takes a particularly long
time to exit from external reset. <n> can be negative, in which case the
default 100 ms delay after issuing reset will be shortened accordingly.
.It Ar noautoreset
Don't toggle RTS/DTR lines on port open to prevent a hardware reset.
.It Ar help
Show help menu and exit.
.El
@@ -1988,6 +2194,68 @@ the CS line being managed outside the application.
.It Ar help
Show help menu and exit.
.El
.It Ar serprog
.Bl -tag -offset indent -width indent
.It Ar cs
Sets the chip select (CS) to use on supported programmers.
Programmers supporting the 0x16 serprog command can have more than the default CS (0).
This option allows to choose these additional CSes (1, 2, ...) for programming the AVR.
.It Ar help
Show help menu and exit.
.El
.El
.Ss Programmers accepting exitspec parameter
Currently, only the flip2, linuxspi and old school parallel port programmers
such as stk200 and dapa support exitspec parameter. These lets the user
decide in which state the programmer pins after ended programming session.
Multiple exitspec options can be separated with commas.
.Bl -tag -offset indent -width indent
.It Ar flip2
.It Ar linuxspi
.It Parallel port programmers
.Bl -tag -offset indent -width indent
.It Ar help
Show help menu and exit.
.It Ar reset
The
.Ql /RESET
signal will be left activated at program exit, that is it will be held
.Em low ,
in order to keep the MCU in reset state afterwards. Note in particular
that the programming algorithm for the AT90S1200 device mandates that
the
.Ql /RESET
signal is active
.Em before
powering up the MCU, so in case an external power supply is used for this
MCU type, a previous invocation of
.Nm
with this option specified is one of the possible ways to guarantee this
condition.
.It Ar noreset
The
.Ql /RESET
line will be deactivated at program exit, thus allowing the MCU target
program to run while the programming hardware remains connected.
.El
.It Parallel port programmers
.Bl -tag -offset indent -width indent
.It Ar vcc
This option will leave those parallel port pins active
.Pq \&i. \&e. Em high
that can be used to supply
.Ql Vcc
power to the MCU.
.It Ar novcc
This option will pull the
.Ql Vcc
pins of the parallel port down at program exit.
.It Ar d_high
This option will leave the 8 data pins on the parallel port active.
.Pq \&i. \&e. Em high
.It Ar d_low
This option will leave the 8 data pins on the parallel port inactive.
.Pq \&i. \&e. Em low
.El
.Sh FILES
.Bl -tag -offset indent -width /dev/ppi0XXX

File diff suppressed because it is too large Load Diff

View File

@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#ifndef avrdude_h
#define avrdude_h
@@ -32,8 +30,7 @@
#endif
extern char *progname; // Name of program, for messages
extern char progbuf[]; // Spaces same length as progname
#define progbuf "" // Used to be for indenting continuation below "avrdude: msg"
extern int ovsigck; // Override signature check (-F)
extern int verbose; // Verbosity level (-v, -vv, ...)
extern int quell_progress; // Quell progress report -q, reduce effective verbosity level (-qq, -qqq)
@@ -44,6 +41,7 @@ extern const char *pgmid; // Programmer -c string
#define mmt_strdup(s) cfg_strdup(__func__, s)
#define mmt_malloc(n) cfg_malloc(__func__, n)
#define mmt_realloc(p, n) cfg_realloc(__func__, p, n)
#define mmt_sprintf(...) str_sprintf(__VA_ARGS__)
#define mmt_free(p) free(p)
int avrdude_message2(FILE *fp, int lno, const char *file, const char *func, int msgmode, int msglvl, const char *format, ...)
@@ -63,25 +61,25 @@ int avrdude_message2(FILE *fp, int lno, const char *file, const char *func, int
#define msg_trace(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_TRACE, __VA_ARGS__)
#define msg_trace2(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, 0, MSG_TRACE2, __VA_ARGS__)
#define pmsg_ext_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FUNCTION|MSG2_FILELINE|MSG2_TYPE|MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_EXT_ERROR, __VA_ARGS__)
#define pmsg_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FUNCTION|MSG2_FILELINE|MSG2_TYPE|MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_ERROR, __VA_ARGS__)
#define pmsg_warning(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FUNCTION|MSG2_FILELINE|MSG2_TYPE|MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_WARNING, __VA_ARGS__)
#define pmsg_info(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_INFO, __VA_ARGS__)
#define pmsg_notice(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_NOTICE, __VA_ARGS__)
#define pmsg_notice2(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_NOTICE2, __VA_ARGS__)
#define pmsg_debug(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_DEBUG, __VA_ARGS__)
#define pmsg_trace(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_TRACE, __VA_ARGS__)
#define pmsg_trace2(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_PROGNAME|MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_TRACE2, __VA_ARGS__)
#define pmsg_ext_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_UCFIRST|MSG2_FUNCTION|MSG2_FILELINE|MSG2_TYPE|MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_EXT_ERROR, __VA_ARGS__)
#define pmsg_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_UCFIRST|MSG2_FUNCTION|MSG2_FILELINE|MSG2_TYPE|MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_ERROR, __VA_ARGS__)
#define pmsg_warning(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_UCFIRST|MSG2_FUNCTION|MSG2_FILELINE|MSG2_TYPE|MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_WARNING, __VA_ARGS__)
#define pmsg_info(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_UCFIRST|MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_INFO, __VA_ARGS__)
#define pmsg_notice(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_UCFIRST|MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_NOTICE, __VA_ARGS__)
#define pmsg_notice2(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_UCFIRST|MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_NOTICE2, __VA_ARGS__)
#define pmsg_debug(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_UCFIRST|MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_DEBUG, __VA_ARGS__)
#define pmsg_trace(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_UCFIRST|MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_TRACE, __VA_ARGS__)
#define pmsg_trace2(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_UCFIRST|MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_TRACE2, __VA_ARGS__)
#define imsg_ext_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT1|MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_EXT_ERROR, __VA_ARGS__)
#define imsg_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT1|MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_ERROR, __VA_ARGS__)
#define imsg_warning(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT1|MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_WARNING, __VA_ARGS__)
#define imsg_info(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT2|MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_INFO, __VA_ARGS__)
#define imsg_notice(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT2|MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_NOTICE, __VA_ARGS__)
#define imsg_notice2(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT2|MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_NOTICE2, __VA_ARGS__)
#define imsg_debug(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT2|MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_DEBUG, __VA_ARGS__)
#define imsg_trace(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT2|MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_TRACE, __VA_ARGS__)
#define imsg_trace2(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_INDENT2|MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_TRACE2, __VA_ARGS__)
#define imsg_ext_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_EXT_ERROR, __VA_ARGS__)
#define imsg_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_ERROR, __VA_ARGS__)
#define imsg_warning(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_WARNING, __VA_ARGS__)
#define imsg_info(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_INFO, __VA_ARGS__)
#define imsg_notice(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_NOTICE, __VA_ARGS__)
#define imsg_notice2(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_NOTICE2, __VA_ARGS__)
#define imsg_debug(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_DEBUG, __VA_ARGS__)
#define imsg_trace(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_TRACE, __VA_ARGS__)
#define imsg_trace2(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_FLUSH|MSG2_LEFT_MARGIN, MSG_TRACE2, __VA_ARGS__)
#define lmsg_ext_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_LEFT_MARGIN, MSG_EXT_ERROR, __VA_ARGS__)
#define lmsg_error(...) avrdude_message2(stderr, __LINE__, __FILE__, __func__, MSG2_LEFT_MARGIN, MSG_ERROR, __VA_ARGS__)

View File

@@ -1,7 +1,5 @@
## -*- mode: rpm-spec; -*-
##
## $Id$
##
## @configure_input@
##

View File

@@ -1,6 +1,6 @@
/*
* avrftdi - extension for avrdude, Wolfgang Moser, Ville Voipio
* Copyright (C) 2011 Hannes Weisbach, Doug Springer
* avrftdi - extension for avrdude
* Copyright (C) 2011 Wolfgang Moser, Ville Voipio, Hannes Weisbach, Doug Springer
* Copyright (C) 2023 Jeff Kent
*
* This program is free software; you can redistribute it and/or modify
@@ -17,7 +17,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
/*
* Interface to the MPSSE Engine of FTDI Chips using libftdi.
*/
@@ -52,8 +51,8 @@
#ifdef DO_NOT_BUILD_AVRFTDI
static int avrftdi_noftdi_open(PROGRAMMER *pgm, const char *name) {
pmsg_error("no libftdi or libusb support\n");
imsg_error("install libftdi1/libusb-1.0 or libftdi/libusb and run configure/make again\n");
pmsg_error("no libftdi or libusb support; install\n");
imsg_error("libftdi1/libusb-1.0 or libftdi/libusb and run configure/make again\n");
return -1;
}
@@ -84,13 +83,13 @@ enum {
FTDI_TMS_CS,
};
static int write_flush(avrftdi_t *);
static int write_flush(Avrftdi_data *);
/*
* returns a human-readable name for a pin number. The name should match with
* the pin names used in FTDI datasheets.
*/
static char *ftdi_pin_name(avrftdi_t *pdata, struct pindef_t pin) {
static char *ftdi_pin_name(Avrftdi_data *pdata, struct pindef pin) {
char *str = pdata->name_str;
size_t strsiz = sizeof pdata->name_str;
@@ -145,8 +144,7 @@ static void buf_dump(const unsigned char *buf, int len, char *desc,
* calculates the so-called 'divisor'-value from a given frequency.
* the divisor is sent to the chip.
*/
static int set_frequency(avrftdi_t* ftdi, uint32_t freq)
{
static int set_frequency(Avrftdi_data *ftdi, uint32_t freq) {
int32_t clock, divisor;
float hs_error, ls_error;
uint8_t buf[4], *ptr = buf;
@@ -176,22 +174,19 @@ static int set_frequency(avrftdi_t* ftdi, uint32_t freq)
}
if (divisor < 0) {
char *f = str_frq(freq, 6), *h = str_frq(clock/2.0, 6);
pmsg_warning("frequency %s too high, resetting to %s\n", f, h);
mmt_free(f); mmt_free(h);
pmsg_warning("frequency %s too high, resetting to %s\n",
str_ccfrq(freq, 6), str_ccfrq(clock/2.0, 6));
divisor = 0;
}
if (divisor > 65535) {
char *f = str_frq(freq, 6), *l = str_frq(clock/2.0 / 65536, 6);
pmsg_warning("frequency %s too low, resetting to %s\n", f, l);
mmt_free(f); mmt_free(l);
pmsg_warning("frequency %s too low, resetting to %s\n",
str_ccfrq(freq, 6), str_ccfrq(clock/2.0 / 65536, 6));
divisor = 65535;
}
char *f = str_frq(clock/2.0 / (divisor + 1), 6);
imsg_notice(" - frequency %s (clock divisor %d = 0x%04x)\n", f, divisor, divisor);
mmt_free(f);
imsg_notice(" - frequency %s (clock divisor %d = 0x%04x)\n",
str_ccfrq(clock/2.0 / (divisor + 1), 6), divisor, divisor);
*ptr++ = TCK_DIVISOR;
*ptr++ = (uint8_t)(divisor & 0xff);
@@ -214,8 +209,8 @@ static int set_pin(const PROGRAMMER *pgm, int pinfunc, int value) {
if(pinfunc < 0 || pinfunc >= N_PINS)
return -1;
avrftdi_t* pdata = to_pdata(pgm);
struct pindef_t pin = pgm->pin[pinfunc];
Avrftdi_data *pdata = to_pdata(pgm);
struct pindef pin = pgm->pin[pinfunc];
if (pin.mask[0] == 0) {
// ignore not defined pins (might be the led or vcc or buff if not needed)
@@ -223,9 +218,8 @@ static int set_pin(const PROGRAMMER *pgm, int pinfunc, int value) {
}
pmsg_debug("setting pin %s (%s) as %s: %s (%s active)\n",
pinmask_to_str(pin.mask), ftdi_pin_name(pdata, pin),
avr_pin_name(pinfunc),
(value) ? "high" : "low", (pin.inverse[0]) ? "low" : "high");
pinmask_to_str(pin.mask), ftdi_pin_name(pdata, pin), avr_pin_name(pinfunc),
(value) ? "high" : "low", (pin.inverse[0]) ? "low" : "high");
pdata->pin_value = SET_BITS_0(pdata->pin_value, pgm, pinfunc, value);
@@ -275,7 +269,7 @@ static inline int set_data(const PROGRAMMER *pgm, unsigned char *buf, unsigned c
int j;
int buf_pos = 0;
unsigned char bit = 0x80;
avrftdi_t* pdata = to_pdata(pgm);
Avrftdi_data *pdata = to_pdata(pgm);
for (j=0; j<8; j++) {
pdata->pin_value = SET_BITS_0(pdata->pin_value,pgm,PIN_AVR_SDO,data & bit);
@@ -328,14 +322,14 @@ static int avrftdi_transmit_bb(const PROGRAMMER *pgm, unsigned char mode, const
{
size_t remaining = buf_size;
size_t written = 0;
avrftdi_t* pdata = to_pdata(pgm);
Avrftdi_data *pdata = to_pdata(pgm);
size_t blocksize = pdata->rx_buffer_size/2; // we are reading 2 bytes per data byte
// determine a maximum size of data block
size_t max_size = MIN(pdata->ftdic->max_packet_size, (unsigned int) pdata->tx_buffer_size);
// select block size so that resulting commands does not exceed max_size if possible
blocksize = MAX(1,(max_size-7)/((8*2*6)+(8*1*2)));
// msg_info("blocksize %d \n", blocksize);
// msg_notice("blocksize %d \n", blocksize);
unsigned char* send_buffer = alloca((8 * 2 * 6) * blocksize + (8 * 1 * 2) * blocksize + 7);
unsigned char* recv_buffer = alloca(2 * 16 * blocksize);
@@ -391,7 +385,7 @@ static int avrftdi_transmit_bb(const PROGRAMMER *pgm, unsigned char mode, const
* Write is only performed when mode contains MPSSE_DO_WRITE.
* Read is only performed when mode contains MPSSE_DO_WRITE and MPSSE_DO_READ.
*/
static int avrftdi_transmit_mpsse(avrftdi_t* pdata, unsigned char mode, const unsigned char *buf,
static int avrftdi_transmit_mpsse(Avrftdi_data *pdata, unsigned char mode, const unsigned char *buf,
unsigned char *data, int buf_size)
{
size_t blocksize;
@@ -444,14 +438,14 @@ static int avrftdi_transmit_mpsse(avrftdi_t* pdata, unsigned char mode, const un
static inline int avrftdi_transmit(const PROGRAMMER *pgm, unsigned char mode, const unsigned char *buf,
unsigned char *data, int buf_size)
{
avrftdi_t* pdata = to_pdata(pgm);
Avrftdi_data *pdata = to_pdata(pgm);
if (pdata->use_bitbanging)
return avrftdi_transmit_bb(pgm, mode, buf, data, buf_size);
else
return avrftdi_transmit_mpsse(pdata, mode, buf, data, buf_size);
}
static int write_flush(avrftdi_t* pdata)
static int write_flush(Avrftdi_data *pdata)
{
unsigned char buf[6];
@@ -504,15 +498,15 @@ static int avrftdi_check_pins_bb(const PROGRAMMER *pgm, bool output) {
int pin;
/* pin checklist. */
struct pin_checklist_t pin_checklist[N_PINS];
Pin_checklist pin_checklist[N_PINS];
avrftdi_t* pdata = to_pdata(pgm);
Avrftdi_data *pdata = to_pdata(pgm);
/* value for 8/12/16 bit wide interface */
int valid_mask = ((1 << pdata->pin_limit) - 1);
pmsg_debug("using valid mask bitbanging: 0x%08x\n", valid_mask);
struct pindef_t *valid_pins_p = &pdata->valid_pins;
struct pindef *valid_pins_p = &pdata->valid_pins;
valid_pins_p->mask[0] = valid_mask;
valid_pins_p->inverse[0] = valid_mask ;
@@ -531,11 +525,11 @@ static int avrftdi_check_pins_mpsse(const PROGRAMMER *pgm, bool output) {
int pin;
/* pin checklist. */
struct pin_checklist_t pin_checklist[N_PINS];
Pin_checklist pin_checklist[N_PINS];
avrftdi_t* pdata = to_pdata(pgm);
Avrftdi_data *pdata = to_pdata(pgm);
struct pindef_t *valid_pins = pdata->mpsse_pins;
struct pindef *valid_pins = pdata->mpsse_pins;
/* value for 8/12/16 bit wide interface for other pins */
int valid_mask = ((1 << pdata->pin_limit) - 1);
@@ -547,7 +541,7 @@ static int avrftdi_check_pins_mpsse(const PROGRAMMER *pgm, bool output) {
}
pmsg_debug("using valid mask mpsse: 0x%08x\n", valid_mask);
struct pindef_t *valid_pins_others_p = &pdata->other_pins;
struct pindef *valid_pins_others_p = &pdata->other_pins;
valid_pins_others_p->mask[0] = valid_mask;
valid_pins_others_p->inverse[0] = valid_mask ;
@@ -589,19 +583,19 @@ static int avrftdi_pin_setup(const PROGRAMMER *pgm) {
* pin setup *
*************/
avrftdi_t* pdata = to_pdata(pgm);
Avrftdi_data *pdata = to_pdata(pgm);
bool pin_check_mpsse = (0 == avrftdi_check_pins_mpsse(pgm, verbose>3));
bool pin_check_mpsse = (0 == avrftdi_check_pins_mpsse(pgm, verbose >= MSG_TRACE));
bool pin_check_bitbanging = (0 == avrftdi_check_pins_bb(pgm, verbose>3));
bool pin_check_bitbanging = (0 == avrftdi_check_pins_bb(pgm, verbose >= MSG_TRACE));
if (!pin_check_mpsse && !pin_check_bitbanging) {
pmsg_error("no valid pin configuration found\n");
avrftdi_check_pins_bb(pgm, true);
imsg_error("pin configuration for FTDI MPSSE must be:\n");
pmsg_error("pin configuration for FTDI MPSSE must be:\n");
if (pgm->flag == PGM_FL_IS_JTAG) {
imsg_error("%s: 0, %s: 1, %s: 2, %s :3 (is: %s, %s, %s, %s)\n",
imsg_error(" %s: 0; %s: 1; %s: 2; %s: 3 (is: %s; %s; %s; %s)\n",
avr_pin_name(PIN_JTAG_TCK), avr_pin_name(PIN_JTAG_TDI),
avr_pin_name(PIN_JTAG_TDO), avr_pin_name(PIN_JTAG_TMS),
pins_to_str(&pgm->pin[PIN_JTAG_TCK]),
@@ -609,7 +603,7 @@ static int avrftdi_pin_setup(const PROGRAMMER *pgm) {
pins_to_str(&pgm->pin[PIN_JTAG_TDO]),
pins_to_str(&pgm->pin[PIN_JTAG_TMS]));
} else {
imsg_error("%s: 0, %s: 1, %s: 2 (is: %s, %s, %s)\n",
imsg_error(" %s: 0; %s: 1; %s: 2 (is: %s; %s; %s)\n",
avr_pin_name(PIN_AVR_SCK),
avr_pin_name(PIN_AVR_SDO),
avr_pin_name(PIN_AVR_SDI),
@@ -617,14 +611,14 @@ static int avrftdi_pin_setup(const PROGRAMMER *pgm) {
pins_to_str(&pgm->pin[PIN_AVR_SDO]),
pins_to_str(&pgm->pin[PIN_AVR_SDI]));
}
imsg_error("if other pin configuration is used, fallback to slower bitbanging mode is used\n");
pmsg_error("if other pin configuration is used, fallback to slower bitbanging mode is used\n");
return -1;
}
pdata->use_bitbanging = !pin_check_mpsse;
if (pdata->use_bitbanging)
imsg_info("because of pin configuration fallback to bitbanging mode\n");
pmsg_notice("fallback to bitbanging mode because of pin configuration\n");
/*
* TODO: No need to fail for a wrongly configured led or something.
@@ -667,7 +661,7 @@ static int avrftdi_pin_setup(const PROGRAMMER *pgm) {
static int avrftdi_open(PROGRAMMER *pgm, const char *port) {
int vid, pid, interface, err;
avrftdi_t* pdata = to_pdata(pgm);
Avrftdi_data *pdata = to_pdata(pgm);
/************************
* parameter validation *
@@ -694,7 +688,7 @@ static int avrftdi_open(PROGRAMMER *pgm, const char *port) {
else if (pgm->usbdev[0] == 'b' || pgm->usbdev[0] == 'B')
interface = INTERFACE_B;
else {
pmsg_warning("invalid interface '%s'. Setting to Interface A\n", pgm->usbdev);
pmsg_warning("invalid interface %s; setting to Interface A\n", pgm->usbdev);
interface = INTERFACE_A;
}
@@ -708,12 +702,12 @@ static int avrftdi_open(PROGRAMMER *pgm, const char *port) {
// Todo: use desc and index argument, currently set to NULL and 0
err = ftdi_usb_open_desc_index(pdata->ftdic, vid, pid, NULL, serial, 0);
if(err) {
pmsg_error("error %d occurred: %s\n", err, ftdi_get_error_string(pdata->ftdic));
pmsg_error("%s (%d)\n", ftdi_get_error_string(pdata->ftdic), err);
// usb_dev is initialized to the last usb device from probing
pdata->ftdic->usb_dev = NULL;
return err;
} else {
pmsg_info("using device VID:PID %04x:%04x and SN %s on interface %c\n",
pmsg_notice("using device VID:PID %04x:%04x and SN %s on interface %c\n",
vid, pid, serial? serial: "(none)", INTERFACE_A == interface? 'A': 'B');
}
@@ -746,7 +740,7 @@ static int avrftdi_open(PROGRAMMER *pgm, const char *port) {
case TYPE_BM:
case TYPE_R:
pmsg_error("found unsupported device type AM, BM or R\n");
imsg_error("avrftdi cannot work with your chip; try the 'synbb' programmer type\n");
imsg_error("avrftdi cannot work with your chip; try the synbb programmer type\n");
return -1;
case TYPE_2232C:
pdata->pin_limit = 12;
@@ -777,8 +771,7 @@ static int avrftdi_open(PROGRAMMER *pgm, const char *port) {
pdata->tx_buffer_size = 2048;
break;
default:
pmsg_warning("unknown device type 0x%02x\n", pdata->ftdic->type);
imsg_warning("continuing but no guarantees...\n");
pmsg_warning("unknown device type 0x%02x, continuing but no guarantees...\n", pdata->ftdic->type);
pdata->pin_limit = 8;
pdata->rx_buffer_size = pdata->ftdic->max_packet_size;
pdata->tx_buffer_size = pdata->ftdic->max_packet_size;
@@ -788,9 +781,8 @@ static int avrftdi_open(PROGRAMMER *pgm, const char *port) {
return avrftdi_pin_setup(pgm)? -1: 0;
}
static void avrftdi_close(PROGRAMMER * pgm)
{
avrftdi_t* pdata = to_pdata(pgm);
static void avrftdi_close(PROGRAMMER *pgm) {
Avrftdi_data *pdata = to_pdata(pgm);
if(pdata->ftdic->usb_dev) {
set_pin(pgm, PIN_AVR_RESET, ON);
@@ -913,7 +905,7 @@ static int avrftdi_lext(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m
if(m->op[AVR_OP_LOAD_EXT_ADDR] == NULL)
return 0;
avrftdi_t *pdata = to_pdata(pgm);
Avrftdi_data *pdata = to_pdata(pgm);
unsigned char buf[] = { 0x00, 0x00, 0x00, 0x00 };
/* only send load extended address command if high byte changed */
@@ -1061,22 +1053,22 @@ static int avrftdi_flash_write(const PROGRAMMER *pgm, const AVRPART *p, const AV
if(verbose >= MSG_TRACE2)
buf_dump(buf, buf_size, "command buffer", 0, 16*2);
pmsg_info("transmitting buffer of size: %d\n", buf_size);
pmsg_notice("transmitting buffer of size: %d\n", buf_size);
if (0 > avrftdi_transmit(pgm, MPSSE_DO_WRITE, buf, buf, buf_size))
return -1;
bufptr = buf;
pmsg_info("using m->buf[%d] = 0x%02x as polling value ", poll_index,
pmsg_notice("using m->buf[%d] = 0x%02x as polling value ", poll_index,
m->buf[poll_index]);
/* poll page write ready */
do {
msg_info(".");
msg_notice(".");
pgm->read_byte(pgm, p, m, poll_index, &poll_byte);
} while (m->buf[poll_index] != poll_byte);
msg_info("\n");
msg_notice("\n");
}
else
{
@@ -1095,7 +1087,7 @@ static int avrftdi_flash_write(const PROGRAMMER *pgm, const AVRPART *p, const AV
static int avrftdi_flash_read(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m,
unsigned int page_size, unsigned int addr, unsigned int len)
{
OPCODE * readop;
OPCODE *readop;
unsigned int buf_size = 4 * len + 4;
unsigned char* o_buf = alloca(buf_size);
@@ -1190,15 +1182,15 @@ static int avrftdi_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AVR
return -2;
}
static void avrftdi_setup(PROGRAMMER * pgm) {
avrftdi_t* pdata;
static void avrftdi_setup(PROGRAMMER *pgm) {
Avrftdi_data *pdata;
pgm->cookie = mmt_malloc(sizeof(avrftdi_t));
pgm->cookie = mmt_malloc(sizeof(Avrftdi_data));
pdata = to_pdata(pgm);
/* SCK/SDO/SDI are fixed and not invertible? */
/* TODO: inverted SCK/SDI/SDO */
const struct pindef_t valid_mpsse_pins[4] = {
const struct pindef valid_mpsse_pins[4] = {
{{0x01}, {0x00}},
{{0x02}, {0x00}},
{{0x04}, {0x00}},
@@ -1220,9 +1212,9 @@ static void avrftdi_setup(PROGRAMMER * pgm) {
pdata->lext_byte = 0xff;
}
static void avrftdi_teardown(PROGRAMMER * pgm) {
static void avrftdi_teardown(PROGRAMMER *pgm) {
if(pgm->cookie) {
avrftdi_t *pdata = to_pdata(pgm);
Avrftdi_data *pdata = to_pdata(pgm);
ftdi_deinit(pdata->ftdic);
ftdi_free(pdata->ftdic);
mmt_free(pdata);
@@ -1234,9 +1226,8 @@ static void avrftdi_teardown(PROGRAMMER * pgm) {
/* JTAG functions */
/******************/
static int avrftdi_jtag_reset(const PROGRAMMER *pgm)
{
avrftdi_t *pdata = to_pdata(pgm);
static int avrftdi_jtag_reset(const PROGRAMMER *pgm) {
Avrftdi_data *pdata = to_pdata(pgm);
unsigned char buf[3], *ptr = buf;
/* Unknown -> Reset -> Run-Test/Idle */
@@ -1249,9 +1240,8 @@ static int avrftdi_jtag_reset(const PROGRAMMER *pgm)
return 0;
}
static int avrftdi_jtag_ir_out(const PROGRAMMER *pgm, unsigned char ir)
{
avrftdi_t *pdata = to_pdata(pgm);
static int avrftdi_jtag_ir_out(const PROGRAMMER *pgm, unsigned char ir) {
Avrftdi_data *pdata = to_pdata(pgm);
unsigned char buf[9], *ptr = buf;
/* Idle -> Select-DR -> Select-IR -> Capture-IR -> Shift-IR */
@@ -1274,9 +1264,8 @@ static int avrftdi_jtag_ir_out(const PROGRAMMER *pgm, unsigned char ir)
return 0;
}
static int avrftdi_jtag_dr_out(const PROGRAMMER *pgm, unsigned int dr, int bits)
{
avrftdi_t *pdata = to_pdata(pgm);
static int avrftdi_jtag_dr_out(const PROGRAMMER *pgm, unsigned int dr, int bits) {
Avrftdi_data *pdata = to_pdata(pgm);
unsigned char buf[18], *ptr = buf;
if (bits <= 0 || bits > 31) {
@@ -1318,7 +1307,7 @@ static int avrftdi_jtag_dr_out(const PROGRAMMER *pgm, unsigned int dr, int bits)
static int avrftdi_jtag_dr_inout(const PROGRAMMER *pgm, unsigned int dr,
int bits)
{
avrftdi_t *pdata = to_pdata(pgm);
Avrftdi_data *pdata = to_pdata(pgm);
unsigned char buf[19], *ptr = buf;
unsigned char bytes = 1, pos;
unsigned int dr_in;
@@ -1403,7 +1392,7 @@ static int avrftdi_jtag_initialize(const PROGRAMMER *pgm, const AVRPART *p)
str_eq(p->id, "m16a") || str_eq(p->id, "m16") ||
str_eq(p->id, "m162")) {
pmsg_error("programmer type %s is known not to work for %s\n", pgm->type, p->desc);
imsg_error("exiting; use -F to carry on regardless\n");
pmsg_error("exiting, use -F to carry on regardless\n");
return LIBAVRDUDE_EXIT;
}
}
@@ -1423,9 +1412,8 @@ static int avrftdi_jtag_initialize(const PROGRAMMER *pgm, const AVRPART *p)
return 0;
}
static void avrftdi_jtag_disable(const PROGRAMMER *pgm)
{
avrftdi_t *pdata = to_pdata(pgm);
static void avrftdi_jtag_disable(const PROGRAMMER *pgm) {
Avrftdi_data *pdata = to_pdata(pgm);
/* NOP command */
avrftdi_jtag_ir_out(pgm, JTAG_IR_PROG_COMMANDS);
@@ -1511,7 +1499,8 @@ static int avrftdi_jtag_read_byte(const PROGRAMMER *pgm, const AVRPART *p,
avrftdi_jtag_dr_out(pgm, 0x3600, 15);
*value = avrftdi_jtag_dr_inout(pgm, 0x3700, 15) & 0xff;
} else if (mem_is_sigrow(m)) {
} else if (mem_is_in_sigrow(m)) {
addr += avr_sigrow_offset(p, m, addr);
avrftdi_jtag_ir_out(pgm, JTAG_IR_PROG_COMMANDS);
avrftdi_jtag_dr_out(pgm, 0x2300 | JTAG_DR_PROG_SIGCAL_READ, 15);
avrftdi_jtag_dr_out(pgm, 0x0300 | (addr/2 & 0xff), 15);
@@ -1686,7 +1675,7 @@ static int avrftdi_jtag_paged_read(const PROGRAMMER *pgm, const AVRPART *p,
const AVRMEM *m, unsigned int page_size, unsigned int addr,
unsigned int n_bytes)
{
avrftdi_t *pdata = to_pdata(pgm);
Avrftdi_data *pdata = to_pdata(pgm);
unsigned int maxaddr = addr + n_bytes;
unsigned char *buf, *ptr;
unsigned int bytes;

View File

@@ -1,6 +1,6 @@
/*
* avrftdi - extension for avrdude, Wolfgang Moser, Ville Voipio
* Copyright (C) 2011 Hannes Weisbach, Doug Springer
* avrftdi - extension for avrdude
* Copyright (C) 2011 Wolfgang Moser, Ville Voipio, Hannes Weisbach, Doug Springer
*
* 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
@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#ifndef avrftdi_h
#define avrftdi_h

View File

@@ -72,7 +72,7 @@ enum jtag_cmd {
};
#define to_pdata(pgm) \
((avrftdi_t *)((pgm)->cookie))
((Avrftdi_data *)((pgm)->cookie))
typedef struct avrftdi_s {
/* pointer to struct maintained by libftdi to identify the device */
@@ -95,10 +95,10 @@ typedef struct avrftdi_s {
uint8_t lext_byte;
char name_str[128]; // Used in ftdi_pin_name()
struct pindef_t valid_pins; // Used in avrftdi_check_pins_bb()
struct pindef_t mpsse_pins[4]; // Used in avrftdi_check_pins_mpsse()
struct pindef_t other_pins; // Used in avrftdi_check_pins_mpsse()
} avrftdi_t;
struct pindef valid_pins; // Used in avrftdi_check_pins_bb()
struct pindef mpsse_pins[4]; // Used in avrftdi_check_pins_mpsse()
struct pindef other_pins; // Used in avrftdi_check_pins_mpsse()
} Avrftdi_data;
#endif /* DO_NOT_BUILD_AVRFDTI */

View File

@@ -20,7 +20,7 @@ static int avrftdi_tpi_program_enable(const PROGRAMMER *pgm, const AVRPART *p);
#ifdef notyet
static void avrftdi_debug_frame(uint16_t frame) {
static char bit_name[] = "IDLES01234567PSS";
static const char bit_name[] = "IDLES01234567PSS";
//static char bit_name[] = "SSP76543210SELDI";
char line0[34], line1[34], line2[34];
int bit, pos;
@@ -64,10 +64,10 @@ int
avrftdi_tpi_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
int ret;
avrftdi_t* pdata = to_pdata(pgm);
Avrftdi_data *pdata = to_pdata(pgm);
unsigned char buf[] = { MPSSE_DO_WRITE | MPSSE_WRITE_NEG | MPSSE_LSB, 0x01, 0x00, 0xff, 0xff };
pmsg_info("Setting /Reset pin low\n");
pmsg_info("setting /Reset pin low\n");
pgm->setpin(pgm, PIN_AVR_RESET, OFF);
pgm->setpin(pgm, PIN_AVR_SCK, OFF);
pgm->setpin(pgm, PIN_AVR_SDO, ON);
@@ -82,7 +82,7 @@ avrftdi_tpi_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
/*wait at least 20ms bevor issuing spi commands to avr */
usleep(20 * 1000);
pmsg_info("Sending 16 init clock cycles ...\n");
pmsg_info("sending 16 init clock cycles ...\n");
ret = ftdi_write_data(pdata->ftdic, buf, sizeof(buf));
return ret;
@@ -90,7 +90,7 @@ avrftdi_tpi_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
void avrftdi_tpi_initpgm(PROGRAMMER *pgm) {
pmsg_info("Using TPI interface\n");
pmsg_info("using TPI interface\n");
pgm->program_enable = avrftdi_tpi_program_enable;
pgm->cmd_tpi = avrftdi_cmd_tpi;
@@ -132,7 +132,7 @@ static uint16_t tpi_byte2frame(uint8_t byte) {
return frame;
}
static int tpi_frame2byte(uint16_t frame, uint8_t * byte) {
static int tpi_frame2byte(uint16_t frame, uint8_t *byte) {
/* drop idle and start bit(s) */
*byte = (frame >> 5) & 0xff;
@@ -212,7 +212,7 @@ static int avrftdi_tpi_read_byte(const PROGRAMMER *pgm, unsigned char *byte) {
frame = buffer[0] | (buffer[1] << 8);
err = tpi_frame2byte(frame, byte);
pmsg_trace("Frame: 0x%04x, byte: 0x%02x\n", frame, *byte);
pmsg_trace("frame: 0x%04x, byte: 0x%02x\n", frame, *byte);
//avrftdi_debug_frame(frame);
@@ -250,7 +250,7 @@ static void avrftdi_tpi_disable(const PROGRAMMER *pgm) {
unsigned char cmd[] = {TPI_OP_SSTCS(TPIPCR), 0};
pgm->cmd_tpi(pgm, cmd, sizeof(cmd), NULL, 0);
pmsg_info("Leaving Programming mode.\n");
pmsg_info("leaving Programming mode\n");
}
#endif /* DO_NOT_BUILD_AVRFTDI */

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,9 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
* Copyright (C) 2022- Stefan Rueger <stefan.rueger@urclocks.com>
* Copyright (C) 2023- Hans Eirik Bull
*
* 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
@@ -17,8 +19,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
@@ -304,12 +304,43 @@ AVRMEM *avr_new_mem(void) {
return m;
}
// Create memory from name and size
AVRMEM *avr_new_memory(const char *name, int size) {
AVRMEM *m = (AVRMEM *) mmt_malloc(sizeof(*m));
m->desc = cache_string(name);
m->page_size = 1; // Ensure not 0
m->size = size;
m->buf = mmt_malloc(size);
m->tags = mmt_malloc(size);
m->initval = -1; // Unknown value represented as -1
m->bitmask = -1; // Default to -1
return m;
}
AVRMEM_ALIAS *avr_new_memalias(void) {
AVRMEM_ALIAS *m = (AVRMEM_ALIAS *) mmt_malloc(sizeof *m);
m->desc = cache_string("");
return m;
}
// Return longer name of memory including alias if any, eg, fuse7/codesize
const char *avr_mem_name(const AVRPART *p, const AVRMEM *mem) {
char ret[1024];
const int n = sizeof ret - 1;
strncpy(ret, mem->desc, n/2);
ret[n/2] = 0;
AVRMEM_ALIAS *alias = avr_find_memalias(p, mem);
if(alias && alias->desc && *alias->desc) {
int l = strlen(ret);
ret[l] = '/';
strncpy(ret+l+1, alias->desc, n-l-1);
ret[n] = 0;
}
return cache_string(ret);
}
/*
* Allocate and initialize memory buffers for each of the device's
@@ -462,10 +493,10 @@ AVRMEM *avr_locate_fuse_by_offset(const AVRPART *p, unsigned int off) {
}
// Return the first memory that shares the type incl any fuse identified by offset in fuses
AVRMEM *avr_locate_mem_by_type(const AVRPART *p, memtype_t type) {
AVRMEM *avr_locate_mem_by_type(const AVRPART *p, Memtype type) {
AVRMEM *m;
memtype_t off = type & MEM_FUSEOFF_MASK;
type &= ~(memtype_t) MEM_FUSEOFF_MASK;
Memtype off = type & MEM_FUSEOFF_MASK;
type &= ~(Memtype) MEM_FUSEOFF_MASK;
if(p && p->mem)
for(LNODEID ln=lfirst(p->mem); ln; ln=lnext(ln))
@@ -510,8 +541,16 @@ int avr_locate_upidx(const AVRPART *p) {
return idx;
}
// Return pointer to uP_table entry for part p
const Avrintel *avr_locate_uP(const AVRPART *p) {
int idx = avr_locate_upidx(p);
return idx < 0? NULL: uP_table + idx;
}
// Return pointer to config table for the part and set number of config bitfields
const Configitem_t *avr_locate_configitems(const AVRPART *p, int *ncp) {
const Configitem *avr_locate_configitems(const AVRPART *p, int *ncp) {
int idx = avr_locate_upidx(p);
if(idx < 0)
return NULL;
@@ -531,7 +570,7 @@ const char * const *avr_locate_isrtable(const AVRPART *p, int *nip) {
}
// Return pointer to register file for the part and set number of registers
const Register_file_t *avr_locate_register_file(const AVRPART *p, int *nrp) {
const Register_file *avr_locate_register_file(const AVRPART *p, int *nrp) {
int idx = avr_locate_upidx(p);
if(idx < 0)
return NULL;
@@ -556,13 +595,13 @@ const Register_file_t *avr_locate_register_file(const AVRPART *p, int *nrp) {
* though there are other registers that start with adc, eg, adc.adcsra.
*/
const Register_file_t *avr_locate_register(const Register_file_t *rgf, int nr, const char *reg,
const Register_file *avr_locate_register(const Register_file *rgf, int nr, const char *reg,
int (*match)(const char *, const char*)) {
if(!rgf || nr < 1 || !reg || !match)
return NULL;
const Register_file_t *ret = NULL;
const Register_file *ret = NULL;
int nmatches = 0, eqmatch = match == str_eq;
for(int i = 0; i < nr; i++) {
@@ -597,10 +636,10 @@ const Register_file_t *avr_locate_register(const Register_file_t *rgf, int nr, c
* behaviour can be suppressed by specifying a pattern for reg, eg, adc*
* together with the matching function str_matched_by.
*/
const Register_file_t **avr_locate_registerlist(const Register_file_t *rgf, int nr, const char *reg,
const Register_file **avr_locate_registerlist(const Register_file *rgf, int nr, const char *reg,
int (*match)(const char *, const char*)) {
const Register_file_t **ret = mmt_malloc(sizeof rgf*(nr>0? nr+1: 1)), **r = ret;
const Register_file **ret = mmt_malloc(sizeof rgf*(nr>0? nr+1: 1)), **r = ret;
int eqmatch = match == str_eq;
if(rgf && reg && match)
@@ -635,13 +674,13 @@ const Register_file_t **avr_locate_registerlist(const Register_file_t *rgf, int
* str_matched_by etc. If name is the full name of a configuration bitfield
* then a pointer to that is returned irrespective of the matching function.
*/
const Configitem_t *avr_locate_config(const Configitem_t *cfg, int nc, const char *name,
const Configitem *avr_locate_config(const Configitem *cfg, int nc, const char *name,
int (*match)(const char *, const char*)) {
if(!cfg || nc < 1 || !name || !match)
return NULL;
const Configitem_t *ret = NULL;
const Configitem *ret = NULL;
int nmatches = 0;
for(int i = 0; i < nc; i++) {
@@ -663,10 +702,10 @@ const Configitem_t *avr_locate_config(const Configitem_t *cfg, int nc, const cha
* returned list is confined to this specific entry irrespective of the
* matching function.
*/
const Configitem_t **avr_locate_configlist(const Configitem_t *cfg, int nc, const char *name,
const Configitem **avr_locate_configlist(const Configitem *cfg, int nc, const char *name,
int (*match)(const char *, const char*)) {
const Configitem_t **ret = mmt_malloc(sizeof cfg*(nc>0? nc+1: 1)), **r = ret;
const Configitem **ret = mmt_malloc(sizeof cfg*(nc>0? nc+1: 1)), **r = ret;
if(cfg && name && match) {
for(int i = 0; i < nc; i++)
@@ -684,19 +723,19 @@ const Configitem_t **avr_locate_configlist(const Configitem_t *cfg, int nc, cons
return ret;
}
// Return memory associated with config item and fill in pointer to Configitem_t record
// Return memory associated with config item and fill in pointer to Configitem record
static AVRMEM *avr_locate_config_mem_c_value(const PROGRAMMER *pgm, const AVRPART *p,
const char *cname, const Configitem_t **cp, int *valp) {
const char *cname, const Configitem **cp, int *valp) {
int nc = 0;
const Configitem_t *cfg = avr_locate_configitems(p, &nc);
const Configitem *cfg = avr_locate_configitems(p, &nc);
if(!cfg || nc < 1) {
pmsg_error("avrintel.c does not hold configuration information for %s\n", p->desc);
return NULL;
}
const Configitem_t *c = avr_locate_config(cfg, nc, cname, str_contains);
const Configitem *c = avr_locate_config(cfg, nc, cname, str_contains);
if(!c) {
pmsg_error("%s does not have a unique config item matched by %s\n", p->desc, cname);
return NULL;
@@ -729,20 +768,21 @@ static AVRMEM *avr_locate_config_mem_c_value(const PROGRAMMER *pgm, const AVRPAR
// Initialise *valuep with configuration value of named configuration bitfield
int avr_get_config_value(const PROGRAMMER *pgm, const AVRPART *p, const char *cname, int *valuep) {
const Configitem_t *c;
const Configitem *c;
int fusel;
if(!avr_locate_config_mem_c_value(pgm, p, cname, &c, &fusel))
return -1;
*valuep = (fusel & c->mask) >> c->lsh;
if(valuep)
*valuep = (fusel & c->mask) >> c->lsh;
return 0;
}
// Set configuration value of named configuration bitfield to value
int avr_set_config_value(const PROGRAMMER *pgm, const AVRPART *p, const char *cname, int value) {
AVRMEM *mem;
const Configitem_t *c;
const Configitem *c;
int fusel;
if(!(mem=avr_locate_config_mem_c_value(pgm, p, cname, &c, &fusel)))
@@ -766,7 +806,7 @@ int avr_set_config_value(const PROGRAMMER *pgm, const AVRPART *p, const char *cn
static char *print_num(const char *fmt, int n) {
return str_sprintf(n<10? "%d": fmt, n);
return mmt_sprintf(n<10? "%d": fmt, n);
}
static int num_len(const char *fmt, int n) {
@@ -835,7 +875,7 @@ void avr_mem_display(FILE *f, const AVRPART *p, const char *prefix) {
// Create mem desc string including alias if present
AVRMEM_ALIAS *a = avr_find_memalias(p, m);
char *m_desc_str = str_sprintf("%s%s%s", m->desc, a? "/": "", a? a->desc: "");
char *m_desc_str = mmt_sprintf("%s%s%s", m->desc, a? "/": "", a? a->desc: "");
// Print memory table content
if(p->prog_modes & (PM_PDI | PM_UPDI)) {
@@ -1029,12 +1069,16 @@ AVRPART *locate_part_by_avr910_devcode(const LISTID parts, int devcode) {
return NULL;
}
// Return pointer to first part that has signature sig (unless all 0xff or all 0x00); NULL if no match
AVRPART *locate_part_by_signature_pm(const LISTID parts, unsigned char *sig, int sigsize, int prog_modes) {
if(parts && sigsize == 3) {
for(LNODEID ln=lfirst(parts); ln; ln=lnext(ln)) {
AVRPART *p = ldata(ln);
if(memcmp(p->signature, sig, 3) == 0 && p->prog_modes & prog_modes)
return p;
if(!*p->id || *p->id == '.') // Skip stump entries
continue;
if(!is_memset(p->signature, 0xff, 3) && !is_memset(p->signature, 0, 3))
if(!memcmp(p->signature, sig, 3) && p->prog_modes & prog_modes)
return p;
}
}
return NULL;
@@ -1044,6 +1088,48 @@ AVRPART *locate_part_by_signature(const LISTID parts, unsigned char *sig, int si
return locate_part_by_signature_pm(parts, sig, sigsize, PM_ALL);
}
// Return whether two signatures represent SW-compatible parts
int avr_sig_compatible(const unsigned char *sig1, const unsigned char *sig2) {
// SW-compatible parts (same memories, interrupts and regfiles) despite different signatures
static const struct { unsigned char sig[3], equ[3]; } compat[] = {
{{0x1e, 0x97, 0x06}, {0x1e, 0x97, 0x05}}, // ATmega1284 vs ATmega1284P
{{0x1e, 0xa7, 0x03}, {0x1e, 0xa7, 0x02}}, // ATmega1284RFR2 vs ATmega128RFR2
{{0x1e, 0x94, 0x0f}, {0x1e, 0x94, 0x0a}}, // ATmega164A vs ATmega164P=ATmega164PA
{{0x1e, 0x94, 0x10}, {0x1e, 0x94, 0x07}}, // ATmega165A vs ATmega165=ATmega165=ATmega165PA
{{0x1e, 0x94, 0x06}, {0x1e, 0x94, 0x0b}}, // ATmega168=ATmega168A vs ATmega168P=ATmega168PA
{{0x1e, 0x94, 0x11}, {0x1e, 0x94, 0x05}}, // ATmega169A vs ATmega169=ATmega169P=ATmega169PA
{{0x1e, 0xa8, 0x03}, {0x1e, 0xa8, 0x02}}, // ATmega2564RFR2 vs ATmega256RFR2
{{0x1e, 0x95, 0x15}, {0x1e, 0x95, 0x08}}, // ATmega324A vs ATmega324P
{{0x1e, 0x95, 0x15}, {0x1e, 0x95, 0x11}}, // ATmega324A vs ATmega324PA
{{0x1e, 0x95, 0x08}, {0x1e, 0x95, 0x11}}, // ATmega324P vs ATmega324PA
{{0x1e, 0x95, 0x06}, {0x1e, 0x95, 0x0e}}, // ATmega3250=ATmega3250A vs ATmega3250P=ATmega3250PA
{{0x1e, 0x95, 0x05}, {0x1e, 0x95, 0x0d}}, // ATmega325=ATmega325A vs ATmega325P=ATmega325PA
{{0x1e, 0x95, 0x04}, {0x1e, 0x95, 0x0c}}, // ATmega3290=ATmega3290A vs ATmega3290P=ATmega3290PA
{{0x1e, 0x95, 0x03}, {0x1e, 0x95, 0x0b}}, // ATmega329=ATmega329A vs ATmega329P=ATmega329PA
{{0x1e, 0x92, 0x05}, {0x1e, 0x92, 0x0a}}, // ATmega48=ATmega48A vs ATmega48P=ATmega48PA
{{0x1e, 0x92, 0x05}, {0x1e, 0x92, 0x0a}}, // ATmega48=ATmega48A vs ATmega48P=ATmega48PA
{{0x1e, 0x96, 0x09}, {0x1e, 0x96, 0x0a}}, // ATmega644=ATmega644A vs ATmega644P=ATmega644PA
{{0x1e, 0xa6, 0x03}, {0x1e, 0xa6, 0x02}}, // ATmega644RFR2 vs ATmega64RFR2
{{0x1e, 0x96, 0x06}, {0x1e, 0x96, 0x0e}}, // ATmega6450=ATmega6450A vs ATmega6450P
{{0x1e, 0x96, 0x05}, {0x1e, 0x96, 0x0d}}, // ATmega645=ATmega645A vs ATmega645P
{{0x1e, 0x96, 0x04}, {0x1e, 0x96, 0x0c}}, // ATmega6490=ATmega6490A vs ATmega6490P
{{0x1e, 0x96, 0x03}, {0x1e, 0x96, 0x0b}}, // ATmega649=ATmega649A vs ATmega649P
{{0x1e, 0x93, 0x0a}, {0x1e, 0x93, 0x0f}}, // ATmega88=ATmega88A=ATA6612C vs ATmega88P=ATmega88PA
};
if(!memcmp(sig1, sig2, 3))
return 1;
for(size_t i = 0; i < sizeof compat/sizeof *compat; i++) {
if(!memcmp(sig1, compat[i].sig, 3) && !memcmp(sig2, compat[i].equ, 3))
return 1;
if(!memcmp(sig2, compat[i].sig, 3) && !memcmp(sig1, compat[i].equ, 3))
return 1;
}
return 0;
}
/*
* Iterate over the list of avrparts given as "avrparts", and
* call the callback function cb for each entry found. cb is being
@@ -1066,7 +1152,7 @@ void walk_avrparts(LISTID avrparts, walk_avrparts_cb cb, void *cookie)
}
/*
* Compare function to sort the list of programmers
* Compare function to sort a list of parts
*/
static int sort_avrparts_compare(const AVRPART *p1, const AVRPART *p2) {
if(p1 == NULL || p1->desc == NULL || p2 == NULL || p2->desc == NULL)
@@ -1076,51 +1162,17 @@ static int sort_avrparts_compare(const AVRPART *p1, const AVRPART *p2) {
}
/*
* Sort the list of programmers given as "programmers"
* Sort the list avrparts of parts
*/
void sort_avrparts(LISTID avrparts)
{
lsort(avrparts,(int (*)(void*, void*)) sort_avrparts_compare);
}
const char *avr_prog_modes_str(int pm) {
static char type[1024];
strcpy(type, "0");
if(pm & PM_TPI)
strcat(type, ", TPI");
if(pm & PM_ISP)
strcat(type, ", ISP");
if(pm & PM_PDI)
strcat(type, ", PDI");
if(pm & PM_UPDI)
strcat(type, ", UPDI");
if(pm & PM_HVSP)
strcat(type, ", HVSP");
if(pm & PM_HVPP)
strcat(type, ", HVPP");
if(pm & PM_debugWIRE)
strcat(type, ", debugWIRE");
if(pm & PM_JTAG)
strcat(type, ", JTAG");
if(pm & PM_JTAGmkI)
strcat(type, ", JTAGmkI");
if(pm & PM_XMEGAJTAG)
strcat(type, ", XMEGAJTAG");
if(pm & PM_AVR32JTAG)
strcat(type, ", AVR32JTAG");
if(pm & PM_aWire)
strcat(type, ", aWire");
if(pm & PM_SPM)
strcat(type, ", SPM");
return type + (type[1] == 0? 0: 3);
}
void avr_display(FILE *f, const AVRPART *p, const char *prefix, int verbose) {
fprintf(f, "%sAVR Part : %s\n", prefix, p->desc);
fprintf(f, "%sProgramming modes : %s\n", prefix, avr_prog_modes_str(p->prog_modes));
fprintf(f, "%sAVR part : %s\n", prefix, p->desc);
fprintf(f, "%sProgramming modes : %s\n", prefix, str_prog_modes(p->prog_modes));
if(verbose > 1) {
avr_mem_display(f, p, prefix);

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2005 Juliane Holzt <avrdude@juliane.holzt.de>
* Copyright (C) 2011 Darell Tan <darell.tan@gmail.com>
*
@@ -17,7 +17,6 @@
* 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$ */
#include <ac_cfg.h>
@@ -44,21 +43,12 @@
#include "tpi.h"
#include "bitbang.h"
static int delay_decrement;
#if defined(WIN32)
static int has_perfcount;
static LARGE_INTEGER freq;
#define freq (*(LARGE_INTEGER *)&cx->bb_freq)
#else
static volatile int done;
typedef void (*mysighandler_t)(int);
static mysighandler_t saved_alarmhandler;
static void alarmhandler(int signo)
{
done = 1;
signal(SIGALRM, saved_alarmhandler);
static void alarmhandler(int signo) {
*(volatile int *)&cx->bb_done = 1;
signal(SIGALRM, cx->bb_saved_alarmf);
}
#endif /* WIN32 */
@@ -75,7 +65,7 @@ static void bitbang_calibrate_delay(void)
*/
if (QueryPerformanceFrequency(&freq))
{
has_perfcount = 1;
cx->bb_has_perfcount = 1;
pmsg_notice2("using performance counter for bitbang delays\n");
}
else
@@ -90,7 +80,7 @@ static void bitbang_calibrate_delay(void)
* comparable hardware.
*/
pmsg_notice2("using guessed per-microsecond delay count for bitbang delays\n");
delay_decrement = 100;
cx->bb_delay_decrement = 100;
}
#else /* !WIN32 */
struct itimerval itv;
@@ -98,8 +88,8 @@ static void bitbang_calibrate_delay(void)
pmsg_notice2("calibrating delay loop ...");
i = 0;
done = 0;
saved_alarmhandler = signal(SIGALRM, alarmhandler);
*(volatile int *)&cx->bb_done = 0;
cx->bb_saved_alarmf = signal(SIGALRM, alarmhandler);
/*
* Set ITIMER_REAL to 100 ms. All known systems have a timer
* granularity of 10 ms or better, so counting the delay cycles
@@ -114,16 +104,15 @@ static void bitbang_calibrate_delay(void)
itv.it_value.tv_usec = 100000;
itv.it_interval.tv_sec = itv.it_interval.tv_usec = 0;
setitimer(ITIMER_REAL, &itv, 0);
while (!done)
while (!*(volatile int *)&cx->bb_done)
i--;
itv.it_value.tv_sec = itv.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &itv, 0);
/*
* Calculate back from 100 ms to 1 us.
*/
delay_decrement = -i / 100000;
msg_notice2(" calibrated to %d cycles per us\n",
delay_decrement);
cx->bb_delay_decrement = -i / 100000;
msg_notice2(" calibrated to %d cycles per us\n", cx->bb_delay_decrement);
#endif /* WIN32 */
}
@@ -137,7 +126,7 @@ void bitbang_delay(unsigned int us)
#if defined(WIN32)
LARGE_INTEGER countNow, countEnd;
if (has_perfcount)
if (cx->bb_has_perfcount)
{
QueryPerformanceCounter(&countNow);
countEnd.QuadPart = countNow.QuadPart + freq.QuadPart * us / 1000000ll;
@@ -148,7 +137,7 @@ void bitbang_delay(unsigned int us)
else /* no performance counters -- run normal uncalibrated delay */
{
#endif /* WIN32 */
volatile unsigned int del = us * delay_decrement;
volatile unsigned int del = us * cx->bb_delay_decrement;
while (del > 0)
del--;
@@ -323,17 +312,17 @@ int bitbang_cmd(const PROGRAMMER *pgm, const unsigned char *cmd,
res[i] = bitbang_txrx(pgm, cmd[i]);
}
if(verbose >= 2)
if(verbose >= MSG_DEBUG)
{
msg_notice2("bitbang_cmd(): [ ");
msg_debug("%s(): [ ", __func__);
for(i = 0; i < 4; i++)
msg_notice2("%02X ", cmd[i]);
msg_notice2("] [ ");
msg_debug("%02X ", cmd[i]);
msg_debug("] [ ");
for(i = 0; i < 4; i++)
{
msg_notice2("%02X ", res[i]);
msg_debug("%02X ", res[i]);
}
msg_notice2("]\n");
msg_debug("]\n");
}
return 0;
@@ -356,17 +345,17 @@ int bitbang_cmd_tpi(const PROGRAMMER *pgm, const unsigned char *cmd,
res[i] = r;
}
if(verbose >= 2)
if(verbose >= MSG_DEBUG)
{
msg_notice2("bitbang_cmd_tpi(): [ ");
msg_debug("%s(): [ ", __func__);
for(i = 0; i < cmd_len; i++)
msg_notice2("%02X ", cmd[i]);
msg_notice2("] [ ");
msg_debug("%02X ", cmd[i]);
msg_debug("] [ ");
for(i = 0; i < res_len; i++)
{
msg_notice2("%02X ", res[i]);
msg_debug("%02X ", res[i]);
}
msg_notice2("]\n");
msg_debug("]\n");
}
if (r == -1)
@@ -391,17 +380,17 @@ int bitbang_spi(const PROGRAMMER *pgm, const unsigned char *cmd,
pgm->setpin(pgm, PIN_LED_PGM, 1);
if(verbose >= 2)
if(verbose >= MSG_DEBUG)
{
msg_notice2("bitbang_cmd(): [ ");
msg_debug("%s(): [ ", __func__);
for(i = 0; i < count; i++)
msg_notice2("%02X ", cmd[i]);
msg_notice2("] [ ");
msg_debug("%02X ", cmd[i]);
msg_debug("] [ ");
for(i = 0; i < count; i++)
{
msg_notice2("%02X ", res[i]);
msg_debug("%02X ", res[i]);
}
msg_notice2("]\n");
msg_debug("]\n");
}
return 0;

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2005 Juliane Holzt <avrdude@juliane.holzt.de>
* Copyright (C) 2011 Darell Tan <darell.tan@gmail.com>
*
@@ -17,7 +17,6 @@
* 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$ */
#ifndef bitbang_h
#define bitbang_h

View File

@@ -33,8 +33,6 @@
* Tested with BusPirate PTH, firmware version 2.1 programming ATmega328P
*/
/* $Id$ */
#include <ac_cfg.h>
#include <stdio.h>
@@ -204,7 +202,7 @@ static char *buspirate_readline_noexit(const PROGRAMMER *pgm, char *buf, size_t
serial_recv_timeout = PDATA(pgm)->serial_recv_timeout;
}
serial_recv_timeout = orig_serial_recv_timeout;
pmsg_debug("buspirate_readline(): %s%s", buf, *buf && buf[strlen(buf)-1] == '\n'? "": "\n");
pmsg_debug("%s(): %s%s", __func__, buf, *buf && buf[strlen(buf)-1] == '\n'? "": "\n");
if (! buf[0])
return NULL;
@@ -226,7 +224,7 @@ static int buspirate_send(const PROGRAMMER *pgm, const char *str) {
int rc;
const char * readline;
pmsg_debug("buspirate_send(): %s", str);
pmsg_debug("%s(): %s", __func__, str);
if (PDATA(pgm)->flag & BP_FLAG_IN_BINMODE) {
pmsg_error("called from binmode\n");
@@ -288,17 +286,18 @@ static void buspirate_dummy_6(const PROGRAMMER *pgm, const char *p) {
/* ====== Config / parameters handling functions ====== */
static int buspirate_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) {
LNODEID ln;
const char *extended_param;
int rv = 0;
char reset[10];
char *preset = reset; /* for strtok() */
unsigned int spifreq;
unsigned int rawfreq;
unsigned int cpufreq;
int serial_recv_timeout;
bool help = false;
for (LNODEID ln = lfirst(extparms); ln; ln = lnext(ln)) {
const char *extended_param = ldata(ln);
for (ln = lfirst(extparms); ln; ln = lnext(ln)) {
extended_param = ldata(ln);
if (str_eq(extended_param, "ascii")) {
PDATA(pgm)->flag |= BP_FLAG_XPARM_FORCE_ASCII;
continue;
@@ -316,13 +315,14 @@ static int buspirate_parseextparms(const PROGRAMMER *pgm, const LISTID extparms)
if (sscanf(extended_param, "spifreq=%u", &spifreq) == 1) {
if (spifreq & (~0x07)) {
pmsg_error("spifreq must be between 0 and 7\n");
imsg_error("see BusPirate manual for details\n");
return -1;
pmsg_error("spifreq must be between 0 and 7; see BusPirate manual for details\n");
rv = -1;
break;
}
if (PDATA(pgm)->flag & BP_FLAG_XPARM_RAWFREQ) {
pmsg_error("set either spifreq or rawfreq\n");
return -1;
rv = -1;
break;
}
PDATA(pgm)->flag |= BP_FLAG_XPARM_SPIFREQ;
PDATA(pgm)->spifreq = spifreq;
@@ -332,11 +332,13 @@ static int buspirate_parseextparms(const PROGRAMMER *pgm, const LISTID extparms)
if (sscanf(extended_param, "rawfreq=%u", &rawfreq) == 1) {
if (rawfreq >= 4) {
pmsg_error("rawfreq must be between 0 and 3\n");
return -1;
rv = -1;
break;
}
if (PDATA(pgm)->flag & BP_FLAG_XPARM_SPIFREQ) {
pmsg_error("set either spifreq or rawfreq\n");
return -1;
rv = -1;
break;
}
PDATA(pgm)->flag |= BP_FLAG_XPARM_RAWFREQ;
PDATA(pgm)->spifreq = rawfreq;
@@ -346,9 +348,9 @@ static int buspirate_parseextparms(const PROGRAMMER *pgm, const LISTID extparms)
if (sscanf(extended_param, "cpufreq=%u", &cpufreq) == 1) {
/* lower limit comes from 'cpufreq > 4 * spifreq', spifreq in ascii mode is 30kHz. */
if (cpufreq < 125 || cpufreq > 4000) {
pmsg_error("cpufreq must be between 125 and 4000 kHz\n");
imsg_error("see BusPirate manual for details\n");
return -1;
pmsg_error("cpufreq must be between 125 and 4000 kHz; see BusPirate manual for details\n");
rv = -1;
break;
}
PDATA(pgm)->cpufreq = cpufreq;
PDATA(pgm)->flag |= BP_FLAG_XPARM_CPUFREQ;
@@ -366,8 +368,9 @@ static int buspirate_parseextparms(const PROGRAMMER *pgm, const LISTID extparms)
else if (str_caseeq(resetpin, "aux2"))
PDATA(pgm)->reset |= BP_RESET_AUX2;
else {
pmsg_error("reset must be either CS or AUX\n");
return -1;
pmsg_error("-x reset= value must be either CS, AUX or AUX2\n");
rv = -1;
break;
}
}
PDATA(pgm)->flag |= BP_FLAG_XPARM_RESET;
@@ -387,33 +390,38 @@ static int buspirate_parseextparms(const PROGRAMMER *pgm, const LISTID extparms)
if (sscanf(extended_param, "serial_recv_timeout=%d", &serial_recv_timeout) == 1) {
if (serial_recv_timeout < 1) {
pmsg_error("serial_recv_timeout must be greater 0\n");
return -1;
rv = -1;
break;
}
PDATA(pgm)->serial_recv_timeout = serial_recv_timeout;
continue;
}
if (str_eq(extended_param, "help")) {
msg_error("%s -c %s extended options:\n", progname, pgmid);
msg_error(" -xreset=cs,aux,aux2 Override default reset pin\n");
msg_error(" -xspifreq=<0..7> Set binary SPI mode speed\n");
msg_error(" -xrawfreq=<0..3> Set \"raw-wire\" SPI mode speed\n");
msg_error(" -xascii Use ASCII protocol between BP and Avrdude\n");
msg_error(" -xnopagedwrite Disable page write functionality\n");
msg_error(" -xnopagedread Disable page read functionality\n");
msg_error(" -xcpufreq=<125..4000> Set the AUX pin to output a frequency to n [kHz]\n");
msg_error(" -xserial_recv_timeout=<arg> Set serial receive timeout to <arg> [ms]\n");
msg_error(" -xpullups Enable internal pull-ups\n");
msg_error(" -xhiz SPI HiZ mode (open collector)\n");
msg_error(" -xhelp Show this help menu and exit\n");
return LIBAVRDUDE_EXIT;;
help = true;
rv = LIBAVRDUDE_EXIT;
}
pmsg_error("do not understand extended param '%s'\n", extended_param);
return -1;
if (!help) {
pmsg_error("invalid extended parameter -x %s\n", extended_param);
rv = -1;
}
msg_error("%s -c %s extended options:\n", progname, pgmid);
msg_error(" -x reset=[cs|aux|aux2] Override default reset pin\n");
msg_error(" -x spifreq=<0..7> Set binary SPI mode speed\n");
msg_error(" -x rawfreq=<0..3> Set \"raw-wire\" SPI mode speed\n");
msg_error(" -x ascii Use ASCII protocol between BP and Avrdude\n");
msg_error(" -x nopagedwrite Disable page write functionality\n");
msg_error(" -x nopagedread Disable page read functionality\n");
msg_error(" -x cpufreq=<125..4000> Set the AUX pin to output a frequency to <n> kHz\n");
msg_error(" -x serial_recv_timeout=<n> Set serial receive timeout to <n> ms\n");
msg_error(" -x pullups Enable internal pull-ups\n");
msg_error(" -x hiz SPI HiZ mode (open collector)\n");
msg_error(" -x help Show this help menu and exit\n");
return rv;
}
return 0;
return rv;
}
static int buspirate_verifyconfig(const PROGRAMMER *pgm) {
@@ -503,7 +511,7 @@ static void buspirate_reset_from_binmode(const PROGRAMMER *pgm) {
return;
}
msg_notice("BusPirate is back in text mode\n");
msg_notice2("BusPirate is back in text mode\n");
}
static int buspirate_start_mode_bin(PROGRAMMER *pgm)
@@ -548,11 +556,11 @@ static int buspirate_start_mode_bin(PROGRAMMER *pgm)
memset(buf, 0, sizeof(buf));
buspirate_recv_bin(pgm, buf, 5);
if (sscanf((const char*)buf, "BBIO%1d", &PDATA(pgm)->binmode_version) != 1) {
pmsg_error("binary mode not confirmed: '%s'\n", buf);
pmsg_error("binary mode not confirmed: %s\n", buf);
buspirate_reset_from_binmode(pgm);
return -1;
}
msg_notice("BusPirate binmode version: %d\n",
msg_notice2("BusPirate binmode version: %d\n",
PDATA(pgm)->binmode_version);
PDATA(pgm)->flag |= BP_FLAG_IN_BINMODE;
@@ -564,7 +572,7 @@ static int buspirate_start_mode_bin(PROGRAMMER *pgm)
pwm_period = 16000/(PDATA(pgm)->cpufreq) - 1; // oscillator runs at 32MHz, we don't use a prescaler
pwm_duty = pwm_period/2; // 50% duty cycle
msg_notice("setting up PWM for cpufreq\n");
msg_notice2("setting up PWM for cpufreq\n");
msg_debug("PWM settings: Prescaler=1, Duty Cycle=%hd, Period=%hd\n", pwm_duty, pwm_period);
buf[0] = 0x12; // pwm setup
@@ -586,14 +594,14 @@ static int buspirate_start_mode_bin(PROGRAMMER *pgm)
memset(buf, 0, sizeof(buf));
buspirate_recv_bin(pgm, buf, 4);
if (sscanf((const char*)buf, submode.entered_format, &PDATA(pgm)->submode_version) != 1) {
pmsg_error("%s mode not confirmed: '%s'\n", submode.name, buf);
pmsg_error("%s mode not confirmed: %s\n", submode.name, buf);
buspirate_reset_from_binmode(pgm);
return -1;
}
msg_notice("BusPirate %s version: %d\n",
msg_notice2("BusPirate %s version: %d\n",
submode.name, PDATA(pgm)->submode_version);
if (PDATA(pgm)->flag & BP_FLAG_NOPAGEDWRITE) {
pmsg_notice("paged flash write disabled\n");
pmsg_notice2("paged flash write disabled\n");
pgm->paged_write = NULL;
} else {
/* Check for write-then-read without !CS/CS and disable paged_write if absent: */
@@ -609,7 +617,7 @@ static int buspirate_start_mode_bin(PROGRAMMER *pgm)
buf[0] = 0x1;
buspirate_send_bin(pgm, buf, 1);
pmsg_notice("disabling paged flash write (need BusPirate firmware >= v5.10)\n");
pmsg_notice2("disabling paged flash write (need BusPirate firmware >= v5.10)\n");
/* Flush serial buffer: */
serial_drain(&pgm->fd, 0);
@@ -640,7 +648,7 @@ static int buspirate_start_mode_bin(PROGRAMMER *pgm)
/* AVR Extended Commands - test for existence */
if (PDATA(pgm)->flag & BP_FLAG_NOPAGEDREAD) {
pmsg_notice("paged flash read disabled\n");
pmsg_notice2("paged flash read disabled\n");
pgm->paged_load = NULL;
} else {
int rv = buspirate_expect_bin_byte(pgm, 0x06, 0x01);
@@ -652,9 +660,9 @@ static int buspirate_start_mode_bin(PROGRAMMER *pgm)
buspirate_send_bin(pgm, buf2, sizeof(buf2));
buspirate_recv_bin(pgm, buf, 3);
ver = buf[1] << 8 | buf[2];
msg_notice("AVR Extended Commands version %d\n", ver);
msg_notice2("AVR Extended Commands version %d\n", ver);
} else {
msg_notice("AVR Extended Commands not found\n");
msg_notice2("AVR Extended Commands not found\n");
PDATA(pgm)->flag |= BP_FLAG_NOPAGEDREAD;
pgm->paged_load = NULL;
}
@@ -685,7 +693,7 @@ static int buspirate_start_spi_mode_ascii(const PROGRAMMER *pgm) {
}
if (spi_cmd == -1) {
pmsg_error("SPI mode number not found; does your BusPirate support SPI?\n");
imsg_error("try powercycling your BusPirate and try again\n");
pmsg_error("try powercycling your BusPirate and try again\n");
return -1;
}
snprintf(buf, sizeof(buf), "%d\n", spi_cmd);
@@ -826,8 +834,7 @@ static void buspirate_powerup(const PROGRAMMER *pgm) {
}
}
pmsg_warning("did not get a response to PowerUp command\n");
imsg_warning("trying to continue anyway ...\n");
pmsg_warning("did not get a response to PowerUp command; trying to continue anyway ...\n");
}
static void buspirate_powerdown(const PROGRAMMER *pgm) {
@@ -920,7 +927,7 @@ static int buspirate_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const A
unsigned char buf[275];
unsigned int addr = 0;
msg_notice("buspirate_paged_load(..,%s,%d,%d,%d)\n",m->desc,m->page_size,address,n_bytes);
msg_debug("buspirate_paged_load(..,%s,%d,%d,%d)\n",m->desc,m->page_size,address,n_bytes);
// This should never happen, but still ...
if (PDATA(pgm)->flag & BP_FLAG_NOPAGEDREAD) {
@@ -954,7 +961,7 @@ static int buspirate_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const A
buspirate_recv_bin(pgm, buf, 1);
if (buf[0] != 0x01) {
pmsg_error("Paged Read command returned zero\n");
pmsg_error("paged read command returned zero\n");
return -1;
}
@@ -1181,7 +1188,7 @@ static void buspirate_bb_enable(PROGRAMMER *pgm, const AVRPART *p) {
memset(buf, 0, sizeof(buf));
buspirate_recv_bin(pgm, buf, 5);
if (sscanf((char*)buf, "BBIO%1d", &PDATA(pgm)->binmode_version) != 1) {
pmsg_error("binary mode not confirmed: '%s'\n", buf);
pmsg_error("binary mode not confirmed: %s\n", buf);
buspirate_reset_from_binmode(pgm);
return;
}

View File

@@ -19,8 +19,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#ifndef buspirate_h
#define buspirate_h

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2003-2004 Theodore A. Roth <troth@openavr.org>
* Copyright (C) 2003-2004 Theodore A. Roth <troth@openavr.org>
* Copyright (C) 2005, 2007 Joerg Wunsch <j@uriah.heep.sax.de>
*
* This program is free software; you can redistribute it and/or modify
@@ -17,8 +17,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
/*
* avrdude interface for the serial programming mode of the Atmel butterfly
* evaluation board. This board features a bootloader which uses a protocol
@@ -60,6 +58,7 @@ struct pdata
int ctype; // Cache one byte for flash
unsigned char cvalue;
unsigned long caddr;
bool autoreset;
};
#define PDATA(pgm) ((struct pdata *)(pgm->cookie))
@@ -316,7 +315,7 @@ static int butterfly_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
if (c == 0)
break;
msg_notice2(" Device code: 0x%02x\n", (unsigned int) (unsigned char) c);
msg_notice2(" Device code: 0x%02x\n", (unsigned char) c);
};
msg_notice2("\n");
@@ -361,9 +360,8 @@ static void butterfly_enable(PROGRAMMER *pgm, const AVRPART *p) {
static int butterfly_open(PROGRAMMER *pgm, const char *port) {
union pinfo pinfo;
pgm->port = port;
/*
* If baudrate was not specified use 19200 Baud
*/
// If baudrate was not specified use 19200 Baud
if(pgm->baudrate == 0) {
pgm->baudrate = 19200;
}
@@ -373,9 +371,22 @@ static int butterfly_open(PROGRAMMER *pgm, const char *port) {
return -1;
}
/*
* drain any extraneous input
*/
if(PDATA(pgm)->autoreset) {
// This code assumes a negative-logic USB to TTL serial adapter
// Set RTS/DTR high to discharge the series-capacitor, if present
pmsg_notice2("toggling the DTR/RTS lines to trigger a hardware reset\n");
serial_set_dtr_rts(&pgm->fd, 0);
usleep(250 * 1000);
// Pull the RTS/DTR line low to reset AVR
serial_set_dtr_rts(&pgm->fd, 1);
// Max 100 us: charging a cap longer creates a high reset spike above Vcc
usleep(100);
// Set the RTS/DTR line back to high, so direct connection to reset works
serial_set_dtr_rts(&pgm->fd, 0);
usleep(100 * 1000);
}
// Drain any extraneous input
(void) butterfly_drain(pgm, 0);
return 0;
@@ -491,7 +502,9 @@ static int butterfly_read_byte_flash(const PROGRAMMER *pgm, const AVRPART *p, co
unsigned long addr, unsigned char * value)
{
int ext_addr = m->op[AVR_OP_LOAD_EXT_ADDR] != NULL;
char mtype = mem_is_flash(m)? 'F': mem_is_sigrow(m)? 'P': mem_is_userrow(m)? 'U': '?';
char mtype = mem_is_flash(m)? 'F': mem_is_in_sigrow(m)? 'P': mem_is_userrow(m)? 'U': '?';
addr += avr_sigrow_offset(p, m, addr);
if(mtype == '?') {
pmsg_error("cannot read memory %s\n", m->desc);
@@ -533,7 +546,7 @@ static int butterfly_read_byte(const PROGRAMMER *pgm, const AVRPART *p, const AV
{
char cmd;
if (mem_is_flash(m) || mem_is_sigrow(m) || mem_is_userrow(m)) {
if (mem_is_flash(m) || mem_is_in_sigrow(m) || mem_is_userrow(m)) {
return butterfly_read_byte_flash(pgm, p, m, addr, value);
}
@@ -679,6 +692,37 @@ static int butterfly_read_sig_bytes(const PROGRAMMER *pgm, const AVRPART *p, con
return 3;
}
static int butterfly_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) {
const char *extended_param;
int rv = 0;
bool help = 0;
for (LNODEID ln = lfirst(extparms); ln; ln = lnext(ln)) {
extended_param = ldata(ln);
if(str_eq(extended_param, "autoreset")) {
PDATA(pgm)->autoreset = true;
continue;
}
if (str_eq(extended_param, "help")) {
help = true;
rv = LIBAVRDUDE_EXIT;
}
if (!help) {
pmsg_error("invalid extended parameter -x %s\n", extended_param);
rv = -1;
}
msg_error("%s -c %s extended options:\n", progname, pgmid);
msg_error(" -x autoreset Toggle RTS/DTR lines on port open to issue a hardware reset\n");
msg_error(" -x help Show this help menu and exit\n");
return rv;
}
return rv;
}
const char butterfly_desc[] = "Atmel Butterfly evaluation board; Atmel AppNotes AVR109, AVR911";
void butterfly_initpgm(PROGRAMMER *pgm) {
@@ -712,7 +756,7 @@ void butterfly_initpgm(PROGRAMMER *pgm) {
pgm->paged_load = butterfly_paged_load;
pgm->read_sig_bytes = butterfly_read_sig_bytes;
pgm->parseextparams = butterfly_parseextparms;
pgm->setup = butterfly_setup;
pgm->teardown = butterfly_teardown;
pgm->flag = 0;

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2003-2004 Theodore A. Roth <troth@openavr.org>
* Copyright (C) 2003-2004 Theodore A. Roth <troth@openavr.org>
*
* 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
@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#ifndef butterfly_h
#define butterfly_h

View File

@@ -2,7 +2,7 @@
* avrdude - A Downloader/Uploader for AVR device programmers
*
* avrdude support for CH341A/B
* Copyright (C) 2016 Alexey Sadkov, paged access by smr 2023
* Copyright (C) 2016 Alexey Sadkov, paged access by smr 2023
*
* 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
@@ -333,7 +333,7 @@ static int ch341a_spi_cmd(const PROGRAMMER *pgm, const unsigned char *cmd, unsig
}
static int ch341a_spi_chip_erase(const struct programmer_t *pgm, const AVRPART *p) {
static int ch341a_spi_chip_erase(const PROGRAMMER *pgm, const AVRPART *p) {
unsigned char cmd[4];
unsigned char res[4];
@@ -477,12 +477,12 @@ void ch341a_initpgm(PROGRAMMER *pgm) {
// ----------------------------------------------------------------------
#else // !defined(HAVE_LIBUSB_1_0)
static int ch341a_nousb_open(struct programmer_t *pgm, const char *name) {
static int ch341a_nousb_open(PROGRAMMER *pgm, const char *name) {
pmsg_error("no usb support, please compile again with libusb installed\n");
return -1;
}
void ch341a_initpgm(PROGRAMMER * pgm) {
void ch341a_initpgm(PROGRAMMER *pgm) {
strcpy(pgm->type, "ch341a");
pgm->open = ch341a_nousb_open;
}

View File

@@ -2,7 +2,7 @@
* avrdude - A Downloader/Uploader for AVR device programmers
*
* avrdude support for CH341A/B
* Copyright (C) 2016 Alexey Sadkov
* Copyright (C) 2016 Alexey Sadkov
*
* 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

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2022 Stefan Rueger <stefan.rueger@urclocks.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -17,8 +17,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#include <ac_cfg.h>
#include <errno.h>
@@ -28,6 +26,7 @@
#include <stddef.h>
#include <string.h>
#include <ctype.h>
#include <wchar.h>
#include "avrdude.h"
#include "libavrdude.h"
@@ -46,27 +45,27 @@ double default_bitclock;
char const *default_linuxgpio;
int allow_subshells;
LISTID string_list;
LISTID number_list;
PROGRAMMER * current_prog;
AVRPART * current_part;
AVRMEM * current_mem;
int current_strct;
LISTID part_list;
LISTID programmers;
bool is_alias;
LISTID string_list;
LISTID number_list;
PROGRAMMER *current_prog;
AVRPART *current_part;
AVRMEM *current_mem;
int current_strct;
LISTID part_list;
LISTID programmers;
bool is_alias;
int cfg_lineno;
char * cfg_infile;
int cfg_lineno;
char *cfg_infile;
extern char * yytext;
extern char *yytext;
#define pgm_comp_desc(x, type) { #x, COMP_PROGRAMMER, offsetof(PROGRAMMER, x), sizeof(((PROGRAMMER *) NULL)->x), type }
#define part_comp_desc(x, type) { #x, COMP_AVRPART, offsetof(AVRPART, x), sizeof(((AVRPART *) NULL)->x), type }
#define mem_comp_desc(x, type) { #x, COMP_AVRMEM, offsetof(AVRMEM, x), sizeof(((AVRMEM *) NULL)->x), type }
// Component description for config_gram.y, will be sorted appropriately on first use
Component_t avr_comp[] = {
Component avr_comp[] = {
// PROGRAMMER
pgm_comp_desc(desc, COMP_STRING),
pgm_comp_desc(prog_modes, COMP_INT),
@@ -84,6 +83,7 @@ Component_t avr_comp[] = {
part_comp_desc(family_id, COMP_STRING),
part_comp_desc(prog_modes, COMP_INT),
part_comp_desc(mcuid, COMP_INT),
part_comp_desc(archnum, COMP_INT),
part_comp_desc(n_interrupts, COMP_INT),
part_comp_desc(n_page_erase, COMP_INT),
part_comp_desc(n_boot_sections, COMP_INT),
@@ -228,8 +228,7 @@ int yywrap()
}
int yyerror(char * errmsg, ...)
{
int yyerror(char *errmsg, ...) {
va_list args;
char message[512];
@@ -245,8 +244,7 @@ int yyerror(char * errmsg, ...)
}
int yywarning(char * errmsg, ...)
{
int yywarning(char *errmsg, ...) {
va_list args;
char message[512];
@@ -262,15 +260,14 @@ int yywarning(char * errmsg, ...)
}
TOKEN * new_token(int primary) {
TOKEN * tkn = (TOKEN *) mmt_malloc(sizeof(TOKEN));
TOKEN *new_token(int primary) {
TOKEN *tkn = (TOKEN *) mmt_malloc(sizeof(TOKEN));
tkn->primary = primary;
return tkn;
}
void free_token(TOKEN * tkn)
{
void free_token(TOKEN *tkn) {
if (tkn) {
switch (tkn->value.type) {
case V_STR:
@@ -287,7 +284,7 @@ void free_token(TOKEN * tkn)
void free_tokens(int n, ...)
{
TOKEN * t;
TOKEN *t;
va_list ap;
va_start(ap, n);
@@ -299,10 +296,9 @@ void free_tokens(int n, ...)
}
TOKEN *new_number(const char *text) {
const char *errstr;
struct token_t *tkn = new_token(TKN_NUMBER);
TOKEN *tkn = new_token(TKN_NUMBER);
tkn->value.type = V_NUM;
tkn->value.number = str_int(text, STR_INT32, &errstr);
if(errstr) {
@@ -312,7 +308,7 @@ TOKEN *new_number(const char *text) {
}
#if DEBUG
msg_info("NUMBER(%d)\n", tkn->value.number);
msg_notice("NUMBER(%d)\n", tkn->value.number);
#endif
return tkn;
@@ -320,7 +316,7 @@ TOKEN *new_number(const char *text) {
TOKEN *new_number_real(const char *text) {
char *endptr;
struct token_t * tkn = new_token(TKN_NUMBER);
TOKEN *tkn = new_token(TKN_NUMBER);
tkn->value.type = V_NUM_REAL;
tkn->value.number_real = strtod(text, &endptr);
if(endptr == text || *endptr) {
@@ -330,14 +326,14 @@ TOKEN *new_number_real(const char *text) {
}
#if DEBUG
msg_info("NUMBER(%g)\n", tkn->value.number_real);
msg_notice("NUMBER(%g)\n", tkn->value.number_real);
#endif
return tkn;
}
TOKEN *new_constant(const char *con) {
struct token_t *tkn = new_token(TKN_NUMBER);
TOKEN *tkn = new_token(TKN_NUMBER);
int assigned = 1;
tkn->value.type = V_NUM;
@@ -373,19 +369,19 @@ TOKEN *new_constant(const char *con) {
}
#if DEBUG
msg_info("CONSTANT(%s=%d)\n", con, tkn->value.number);
msg_notice("CONSTANT(%s=%d)\n", con, tkn->value.number);
#endif
return tkn;
}
TOKEN *new_string(const char *text) {
struct token_t *tkn = new_token(TKN_STRING);
TOKEN *tkn = new_token(TKN_STRING);
tkn->value.type = V_STR;
tkn->value.string = mmt_strdup(text);
#if DEBUG
msg_info("STRING(%s)\n", tkn->value.string);
msg_notice("STRING(%s)\n", tkn->value.string);
#endif
return tkn;
@@ -397,8 +393,7 @@ TOKEN *new_keyword(int primary) {
}
void print_token(TOKEN * tkn)
{
void print_token(TOKEN *tkn) {
if (!tkn)
return;
@@ -428,7 +423,7 @@ void print_token(TOKEN * tkn)
void pyytext(void)
{
#if DEBUG
msg_info("TOKEN: %s\n", yytext);
msg_notice("TOKEN: %s\n", yytext);
#endif
}
@@ -438,9 +433,8 @@ void pyytext(void)
extern int yylex_destroy(void);
#endif
int read_config(const char * file)
{
FILE * f;
int read_config(const char *file) {
FILE *f;
int r;
if(!(cfg_infile = realpath(file, NULL))) {
@@ -488,8 +482,6 @@ unsigned strhash(const char *str) {
}
static char **hstrings[1<<12];
// Return a copy of the argument as hashed string
const char *cache_string(const char *p) {
int h, k;
@@ -498,32 +490,23 @@ const char *cache_string(const char *p) {
if(!p)
p = "(NULL)";
h = strhash(p) % (sizeof hstrings/sizeof*hstrings);
if(!(hs=hstrings[h]))
hs = hstrings[h] = (char **) mmt_realloc(NULL, (16+1)*sizeof**hstrings);
h = strhash(p) % (sizeof cx->cfg_hstrings/sizeof*cx->cfg_hstrings);
if(!(hs=cx->cfg_hstrings[h]))
hs = cx->cfg_hstrings[h] = (char **) mmt_realloc(NULL, (16+1)*sizeof**cx->cfg_hstrings);
for(k=0; hs[k]; k++)
if(*p == *hs[k] && str_eq(p, hs[k]))
return hs[k];
if(k && k%16 == 0)
hstrings[h] = (char **) mmt_realloc(hstrings[h], (k+16+1)*sizeof**hstrings);
cx->cfg_hstrings[h] = (char **) mmt_realloc(cx->cfg_hstrings[h], (k+16+1)*sizeof**cx->cfg_hstrings);
hstrings[h][k+1] = NULL;
cx->cfg_hstrings[h][k+1] = NULL;
return hstrings[h][k] = mmt_strdup(p);
return cx->cfg_hstrings[h][k] = mmt_strdup(p);
}
static LISTID cfg_comms; // A chain of comment lines
static LISTID cfg_prologue; // Comment lines at start of avrdude.conf
static char *lkw; // Last seen keyword
static int lkw_lineno; // Line number of that
static LISTID cfg_strctcomms; // Passed on to config_gram.y
static LISTID cfg_pushedcomms; // Temporarily pushed main comments
static int cfg_pushed; // ... for memory sections
COMMENT *locate_comment(const LISTID comments, const char *where, int rhs) {
if(comments)
for(LNODEID ln=lfirst(comments); ln; ln=lnext(ln)) {
@@ -536,57 +519,57 @@ COMMENT *locate_comment(const LISTID comments, const char *where, int rhs) {
}
static void addcomment(int rhs) {
if(lkw) {
if(cx->cfg_lkw) {
COMMENT *node = mmt_malloc(sizeof(*node));
node->rhs = rhs;
node->kw = mmt_strdup(lkw);
node->comms = cfg_comms;
cfg_comms = NULL;
if(!cfg_strctcomms)
cfg_strctcomms = lcreat(NULL, 0);
ladd(cfg_strctcomms, node);
node->kw = mmt_strdup(cx->cfg_lkw);
node->comms = cx->cfg_comms;
cx->cfg_comms = NULL;
if(!cx->cfg_strctcomms)
cx->cfg_strctcomms = lcreat(NULL, 0);
ladd(cx->cfg_strctcomms, node);
}
}
// Capture prologue during parsing (triggered by lexer.l)
void cfg_capture_prologue(void) {
cfg_prologue = cfg_comms;
cfg_comms = NULL;
cx->cfg_prologue = cx->cfg_comms;
cx->cfg_comms = NULL;
}
LISTID cfg_get_prologue(void) {
return cfg_prologue;
return cx->cfg_prologue;
}
// Captures comments during parsing
void capture_comment_str(const char *com, int lineno) {
if(!cfg_comms)
cfg_comms = lcreat(NULL, 0);
ladd(cfg_comms, mmt_strdup(com));
if(!cx->cfg_comms)
cx->cfg_comms = lcreat(NULL, 0);
ladd(cx->cfg_comms, mmt_strdup(com));
// Last keyword lineno is the same as this comment's
if(lkw && lkw_lineno == lineno)
if(cx->cfg_lkw && cx->cfg_lkw_lineno == lineno)
addcomment(1); // Register comms to show right of lkw = ...;
}
// Capture assignments (keywords left of =) and associate comments to them
void capture_lvalue_kw(const char *kw, int lineno) {
if(str_eq(kw, "memory")) { // Push part comments and start memory comments
if(!cfg_pushed) { // config_gram.y pops the part comments
cfg_pushed = 1;
cfg_pushedcomms = cfg_strctcomms;
cfg_strctcomms = NULL;
if(!cx->cfg_pushed) { // config_gram.y pops the part comments
cx->cfg_pushed = 1;
cx->cfg_pushedcomms = cx->cfg_strctcomms;
cx->cfg_strctcomms = NULL;
}
}
if(str_eq(kw, "programmer") || str_eq(kw, "serialadapter") || str_eq(kw, "part") || str_eq(kw, "memory"))
kw = "*"; // Show comment before programmer/part/memory
if(lkw)
mmt_free(lkw);
lkw = mmt_strdup(kw);
lkw_lineno = lineno;
if(cfg_comms) // Accrued list of # one-line comments
if(cx->cfg_lkw)
mmt_free(cx->cfg_lkw);
cx->cfg_lkw = mmt_strdup(kw);
cx->cfg_lkw_lineno = lineno;
if(cx->cfg_comms) // Accrued list of # one-line comments
addcomment(0); // Register comment to appear before lkw assignment
}
@@ -594,16 +577,16 @@ void capture_lvalue_kw(const char *kw, int lineno) {
LISTID cfg_move_comments(void) {
capture_lvalue_kw(";", -1);
LISTID ret = cfg_strctcomms;
cfg_strctcomms = NULL;
LISTID ret = cx->cfg_strctcomms;
cx->cfg_strctcomms = NULL;
return ret;
}
// config_gram.y calls this after ingressing the memory structure
void cfg_pop_comms(void) {
if(cfg_pushed) {
cfg_pushed = 0;
cfg_strctcomms = cfg_pushedcomms;
if(cx->cfg_pushed) {
cx->cfg_pushed = 0;
cx->cfg_strctcomms = cx->cfg_pushedcomms;
}
}
@@ -789,12 +772,94 @@ char *cfg_unescape(char *d, const char *s) {
return (char *) cfg_unescapeu((unsigned char *) d, (const unsigned char *) s);
}
// Returns the number of characters that a unicode character would need (0-6)
static int utf8width(wint_t wc) {
if(!(wc & ~0x7fu))
return 1;
if(!(wc & ~0x7ffu))
return 2;
if(!(wc & ~0xffffu))
return 3;
if(!(wc & ~0x1fffffu))
return 4;
if(!(wc & ~0x3ffffffu))
return 5;
if(!(wc & ~0x7fffffffu))
return 6;
return 0;
}
// Given the first byte c of a character sequence, how long is the sequence going to be?
static int utf8headlen(int c) {
return (c & 0xe0) == 0xc0? 2:
(c & 0xf0) == 0xe0? 3:
(c & 0xf8) == 0xf0? 4: (c & 0xfc) == 0xf8? 5: (c & 0xfe) == 0xfc? 6: 1 /* not a utf8 header byte */ ;
}
/*
* Return the next unicode character from a utf-8 string str with at least
* n characters and record the length of the utf-8 string eaten in *lenp
* Returns U+FFFD (illegal char) if parsing does not go well
*/
static wint_t nextutf8char(const char *str, int n, int *lenp) {
int j, utf8, len;
wint_t c, wc = 0;
c = str[0] & 0xff;
if(!(c & 0x80)) { // Simple ASCII - all done
if(lenp)
*lenp = 1;
return c;
}
utf8 = 0; // Possible UTF-8 character, convert to wint_t
len = utf8headlen((int) c);
if(len > 1 && len <= n) {
switch (len) {
case 2:
wc = c & 0x1f;
break;
case 3:
wc = c & 0xf;
break;
case 4:
wc = c & 0x7;
break;
case 5:
wc = c & 0x3;
break;
case 6:
wc = c & 0x1;
break;
}
for(utf8 = 1, j = 1; j < len; j++) {
if((str[j] & 0xc0) != 0x80) {
utf8 = 0;
break;
}
wc = (wc << 6) + (str[j] & 0x3f);
}
}
if(utf8 && utf8width(wc) != len) // Sequence code was longer than needed be, make invalid
utf8 = 0;
if(!utf8)
len = 1, wc = 0xFFFD; // Illegal character
if(lenp)
*lenp = len;
return wc;
}
// Return an mmt_malloc'd escaped string that looks like a C-style input string incl quotes
char *cfg_escape(const char *s) {
char buf[50*1024], *d = buf;
*d++ = '"';
for(; *s && d-buf < (long) sizeof buf-7; s++) {
for(; *s && d-buf < (long) sizeof buf - 10; s++) {
switch(*s) {
case '\n':
*d++ = '\\'; *d++ = 'n';
@@ -823,7 +888,17 @@ char *cfg_escape(const char *s) {
*d++ = '\\'; *d++ = '\"';
break;
default:
if(*s == 0x7f || (unsigned char) *s < 32) {
if(*s & 0x80) { // Check for utf8-sequences
int chrlen;
if(0xFFFD == nextutf8char(s, strlen(s), &chrlen)) { // Invalid UTF-8
sprintf(d, "\\%03o", *s & 0xff);
d += strlen(d);
} else { // Copy over valid UTF-8 character
memcpy(d, s, chrlen);
d += chrlen;
s += chrlen - 1;
}
} else if(*s == 0x7f || (unsigned char) *s < 32) {
sprintf(d, "\\%03o", *s);
d += strlen(d);
} else
@@ -838,23 +913,21 @@ char *cfg_escape(const char *s) {
static int cmp_comp(const void *v1, const void *v2) {
const Component_t *c1 = v1, *c2 = v2;
const Component *c1 = v1, *c2 = v2;
int ret = strcmp(c1->name, c2->name);
return ret? ret: c1->strct - c2->strct;
}
Component_t *cfg_comp_search(const char *name, int strct) {
static int init;
Component_t key;
if(!init++)
qsort(avr_comp, sizeof avr_comp/sizeof*avr_comp, sizeof(Component_t), cmp_comp);
Component *cfg_comp_search(const char *name, int strct) {
Component key;
if(!cx->cfg_init_search++)
qsort(avr_comp, sizeof avr_comp/sizeof*avr_comp, sizeof(Component), cmp_comp);
key.name = name;
key.strct = strct;
return bsearch(&key, avr_comp, sizeof avr_comp/sizeof*avr_comp, sizeof(Component_t), cmp_comp);
return bsearch(&key, avr_comp, sizeof avr_comp/sizeof*avr_comp, sizeof(Component), cmp_comp);
}
@@ -898,7 +971,7 @@ const char *cfg_comp_type(int type) {
// Used by config_gram.y to assign a component in one of the relevant structures with a value
void cfg_assign(char *sp, int strct, Component_t *cp, VALUE *v) {
void cfg_assign(char *sp, int strct, Component *cp, VALUE *v) {
const char *str;
int num;
@@ -912,7 +985,7 @@ void cfg_assign(char *sp, int strct, Component_t *cp, VALUE *v) {
cp->name, cfg_strct_name(strct), cfg_comp_type(cp->type), cfg_v_type(v->type));
return;
}
// TODO: consider endianess (code currently assumes little endian)
// TODO: consider endianness (code currently assumes little endian)
num = v->number;
memcpy(sp+cp->offset, &num, cp->size);
break;

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bdmicro.com>
*
* 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
@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
/* These are the internal definitions needed for config parsing */
#ifndef config_h
@@ -62,7 +60,7 @@ typedef struct { // Description of a component in a structure
const char *name; // Component name
int strct; // Structure, eg, COMP_AVRPART
int offset, size, type; // Location, size and type within structure
} Component_t;
} Component;
enum { // Value types for VALUE struct
@@ -73,34 +71,34 @@ enum { // Value types for VALUE struct
V_COMPONENT,
};
typedef struct value_t {
int type;
typedef struct {
int type;
union {
int number;
double number_real;
char * string;
Component_t *comp;
int number;
double number_real;
char *string;
Component *comp;
};
} VALUE;
typedef struct token_t {
typedef struct token {
int primary;
VALUE value;
} TOKEN;
typedef struct token_t *token_p;
typedef struct token *token_p;
extern FILE * yyin;
extern PROGRAMMER * current_prog;
extern AVRPART * current_part;
extern AVRMEM * current_mem;
extern int current_strct;
extern int cfg_lineno;
extern char * cfg_infile;
extern LISTID string_list;
extern LISTID number_list;
extern bool is_alias; // current entry is alias
extern FILE *yyin;
extern PROGRAMMER *current_prog;
extern AVRPART *current_part;
extern AVRMEM *current_mem;
extern int current_strct;
extern int cfg_lineno;
extern char *cfg_infile;
extern LISTID string_list;
extern LISTID number_list;
extern bool is_alias; // current entry is alias
#if !defined(HAS_YYSTYPE)
@@ -152,13 +150,13 @@ LISTID cfg_move_comments(void);
void cfg_pop_comms(void);
Component_t *cfg_comp_search(const char *name, int strct);
Component *cfg_comp_search(const char *name, int strct);
const char *cfg_v_type(int type);
const char *cfg_strct_name(int strct);
void cfg_assign(char *sp, int strct, Component_t *cp, VALUE *v);
void cfg_assign(char *sp, int strct, Component *cp, VALUE *v);
void cfg_update_mcuid(AVRPART *part);

View File

@@ -1,7 +1,8 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
* Copyright (C) 2022- Stefan Rueger <stefan.rueger@urclocks.com>
*
* 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
@@ -17,7 +18,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
%{
#include "ac_cfg.h"
@@ -50,7 +50,7 @@ static int assign_pin_list(int invert);
static int which_opcode(TOKEN * opcode);
static int parse_cmdbits(OPCODE * op, int opnum);
static int pin_name;
#define pin_name (cx->cfgy_pin_name)
%}
%token K_NULL;
@@ -274,6 +274,9 @@ prog_def :
yyerror("programmer type not specified");
YYABORT;
}
if(!current_prog->prog_modes && cx->lex_kw_is_programmer)
yywarning("programmer %s fails to specify prog_modes = PM_...;",
(char *) ldata(lfirst(current_prog->id)));
for(LNODEID ln = lfirst(current_prog->id); ln; ln = lnext(ln)) {
char *id = ldata(ln);
if((existing_prog = locate_programmer(programmers, id))) {
@@ -335,6 +338,10 @@ part_def :
cfg_update_mcuid(current_part);
Memtype and_mask = ~ ( // Remove in-flash/in-sigrow attributes if no respective memories
(!avr_locate_flash(current_part)? MEM_IN_FLASH: 0) |
(!avr_locate_sigrow(current_part)? MEM_IN_SIGROW: 0));
// Sanity checks for memory sizes and compute/override num_pages entry
for (ln=lfirst(current_part->mem); ln; ln=lnext(ln)) {
m = ldata(ln);
@@ -363,6 +370,20 @@ part_def :
m->num_pages = m->size / m->page_size;
}
m->type &= and_mask;
// Remove MEM_IN_SIGROW attribute from classic calibration and classic/XMEGA signature mem
if(current_part->prog_modes & PM_Classic) {
if(mem_is_signature(m))
m->type &= ~MEM_IN_SIGROW;
if(mem_is_calibration(m))
m->type &= ~MEM_IN_SIGROW;
} else if(current_part->prog_modes & PM_PDI) {
if(mem_is_signature(m))
m->type &= ~MEM_IN_SIGROW;
}
if(fileio_mem_offset(current_part, m) == ~0U)
yywarning("revise fileio_mem_offset(), avrdude.conf entry or memory type assignment");
}
existing_part = locate_part(part_list, current_part->id);
@@ -458,7 +479,7 @@ prog_parm_type:
prog_parm_type_id:
TKN_STRING {
const struct programmer_type_t * pgm_type = locate_programmer_type($1->value.string);
const PROGRAMMER_TYPE *pgm_type = locate_programmer_type($1->value.string);
if (pgm_type == NULL) {
yyerror("programmer type %s not found", $1->value.string);
free_token($1);
@@ -549,7 +570,10 @@ pin_number_non_empty:
pin_number:
pin_number_non_empty
|
/* empty */ { pin_clear_all(&(current_prog->pin[pin_name])); }
/* empty */ {
if(pin_name >= 0 && pin_name < N_PINS)
pin_clear_all(&(current_prog->pin[pin_name]));
}
;
pin_list_element:
@@ -568,7 +592,10 @@ pin_list_non_empty:
pin_list:
pin_list_non_empty
|
/* empty */ { pin_clear_all(&(current_prog->pin[pin_name])); }
/* empty */ {
if(pin_name >= 0 && pin_name < N_PINS)
pin_clear_all(&(current_prog->pin[pin_name]));
}
;
prog_parm_pins:
@@ -1368,11 +1395,11 @@ static int parse_cmdbits(OPCODE * op, int opnum)
case 'a':
sb = opnum == AVR_OP_LOAD_EXT_ADDR? bitno+8: bitno-8; // should be this number
if(bitno < 8 || bitno > 23) {
if(!current_mem || !mem_is_sigrow(current_mem)) // Known exemption
if(!current_mem || !mem_is_in_sigrow(current_mem)) // Known exemptions
yywarning("address bits don't normally appear in Bytes 0 or 3 of SPI commands");
} else if((bn & 31) != sb) {
if(!current_part || !str_casestarts(current_part->desc, "AT89S5")) // Exempt AT89S5x
if(!current_mem || !mem_is_sigrow(current_mem)) // and prodsig
if(!current_mem || !mem_is_in_sigrow(current_mem)) // ... and prodsig/sernum
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);

View File

@@ -1,6 +1,6 @@
#
# avrdude - A Downloader/Uploader for AVR device programmers
# Copyright (C) 2003, 2004 Theodore A. Roth <troth@openavr.org>
# Copyright (C) 2003, 2004 Theodore A. Roth <troth@openavr.org>
#
# 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
@@ -16,10 +16,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#
# $Id$
#
# Process this file with autoreconf to produce a configure script.
dnl A few tool releases with release dates for orientation which tool

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2003-2004 Eric B. Weddington <eric@ecentral.com>
* Copyright (C) 2024 Stefan Rueger <stefan.rueger@urclocks.com>
*
* 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
@@ -27,24 +27,10 @@
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
static char *filename;
void win_sys_config_set(char sys_config[PATH_MAX])
{
sys_config[0] = 0;
/* Use Windows API call to search for the Windows default system config file.*/
SearchPath(NULL, SYSTEM_CONF_FILE, NULL, PATH_MAX, sys_config, &filename);
return;
}
void win_usr_config_set(char usr_config[PATH_MAX])
{
usr_config[0] = 0;
/* Use Windows API call to search for the Windows default user config file. */
SearchPath(NULL, USER_CONF_FILE, NULL, PATH_MAX, usr_config, &filename);
return;
// Store the full path of a file using a registry-dependent system search path
int win_set_path(char *path, int n, const char *file) {
*path = 0;
return SearchPath(NULL, file, NULL, n, path, NULL);
}
#endif

View File

@@ -16,8 +16,6 @@
* 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.
@@ -59,14 +57,14 @@
// - Output again with -p*/s or -c*/s (no /i) and use that for final avrdude.conf
// - Remove entries from below tables
static struct {
static const struct {
const char *pgmid, *var, *value;
} pgminj[] = {
// Add triples here, eg, {"stk500v2", "prog_modes", "PM_TPI|PM_ISP"},
{NULL, NULL, NULL},
};
static struct {
static const struct {
const char *mcu, *var, *value;
} ptinj[] = {
// Add triples here, eg, {"ATmega328P", "mcuid", "999"},
@@ -133,43 +131,6 @@ static void printallopcodes(const AVRPART *p, const char *d, OPCODE * const *opa
}
// Programming modes
static char *prog_modes_str(int pm) {
static char type[1024];
strcpy(type, "0");
if(pm & PM_SPM)
strcat(type, " | PM_SPM");
if(pm & PM_TPI)
strcat(type, " | PM_TPI");
if(pm & PM_ISP)
strcat(type, " | PM_ISP");
if(pm & PM_PDI)
strcat(type, " | PM_PDI");
if(pm & PM_UPDI)
strcat(type, " | PM_UPDI");
if(pm & PM_HVSP)
strcat(type, " | PM_HVSP");
if(pm & PM_HVPP)
strcat(type, " | PM_HVPP");
if(pm & PM_debugWIRE)
strcat(type, " | PM_debugWIRE");
if(pm & PM_JTAG)
strcat(type, " | PM_JTAG");
if(pm & PM_JTAGmkI)
strcat(type, " | PM_JTAGmkI");
if(pm & PM_XMEGAJTAG)
strcat(type, " | PM_XMEGAJTAG");
if(pm & PM_AVR32JTAG)
strcat(type, " | PM_AVR32JTAG");
if(pm & PM_aWire)
strcat(type, " | PM_aWire");
return type + (type[1] == 0? 0: 4);
}
static char *extra_features_str(int m) {
static char mode[1024];
@@ -251,6 +212,9 @@ static char *dev_sprintf(const char *fmt, ...) {
static int dev_nprinted;
#if defined(__GNUC__)
__attribute__ ((format (printf, 2, 3)))
#endif
int dev_message(int msglvl, const char *fmt, ...) {
va_list ap;
int rc = 0;
@@ -406,8 +370,15 @@ static int avrmem_deep_copy(AVRMEMdeep *d, const AVRMEM *m) {
// Copy over the SPI operations themselves
memset(d->ops, 0, sizeof d->ops);
for(size_t i=0; i<AVR_OP_MAX; i++)
if(m->op[i])
if(m->op[i]) {
d->ops[i] = *m->op[i];
for(int b=0; b<32; b++) { // Replace x with 0 as they are treated the same
if(d->ops[i].bit[b].type == AVR_CMDBIT_IGNORE) {
d->ops[i].bit[b].type = AVR_CMDBIT_VALUE;
d->ops[i].bit[b].value = 0;
}
}
}
return 0;
}
@@ -529,11 +500,6 @@ static void dev_raw_dump(const void *v, int nbytes, const char *name, const char
}
}
static int _is_all_zero(const void *p, size_t n) {
const char *q = (const char *) p;
return n <= 0 || (*q == 0 && memcmp(q, q+1, n-1) == 0);
}
static char *opsnm(const char *pre, int opnum) {
static char ret[128];
sprintf(ret, "%.31s.%.95s", pre, opcodename(opnum));
@@ -547,7 +513,7 @@ static void dev_part_raw(const AVRPART *part) {
dev_raw_dump(&dp, (char *)&dp.base-(char *)&dp, part->desc, "part.intro", 0);
dev_raw_dump(&dp.base, sizeof dp.base, part->desc, "part", 0);
for(int i=0; i<AVR_OP_MAX; i++)
if(!_is_all_zero(dp.ops+i, sizeof*dp.ops))
if(!is_memset(dp.ops+i, 0, sizeof*dp.ops))
dev_raw_dump(dp.ops+i, sizeof*dp.ops, part->desc, opsnm("part", i), 1);
for(int i=0; i<di; i++) {
@@ -556,7 +522,7 @@ static void dev_part_raw(const AVRPART *part) {
dev_raw_dump(nm, sizeof dp.mems[i].descbuf, part->desc, nm, i+2);
dev_raw_dump(&dp.mems[i].base, sizeof dp.mems[i].base, part->desc, nm, i+2);
for(int j=0; j<AVR_OP_MAX; j++)
if(!_is_all_zero(dp.mems[i].ops+j, sizeof(OPCODE)))
if(!is_memset(dp.mems[i].ops+j, 0, sizeof(OPCODE)))
dev_raw_dump(dp.mems[i].ops+j, sizeof(OPCODE), part->desc, opsnm(nm, j), i+2);
}
}
@@ -572,7 +538,7 @@ static void dev_part_strct(const AVRPART *p, bool tsv, const AVRPART *base, bool
if(!cp || !dev_has_subsstr_comms(cp->comms, del)) {
dev_info("%s\n", del);
dev_info("# %.*s\n", strlen(descstr)-2, descstr+1); // Remove double quotes
dev_info("# %.*s\n", (int) strlen(descstr)-2, descstr+1); // Remove double quotes
dev_info("%s\n\n", del);
}
if(cp)
@@ -620,12 +586,13 @@ static void dev_part_strct(const AVRPART *p, bool tsv, const AVRPART *base, bool
}
_if_partout_str(strcmp, cfg_escape(p->family_id), family_id);
_if_partout_str(intcmp, mmt_strdup(prog_modes_str(p->prog_modes)), prog_modes);
_if_partout_str(intcmp, mmt_strdup(dev_prog_modes(p->prog_modes)), prog_modes);
if(p->mcuid == 21) {
_if_partout_str(intcmp, mmt_strdup("XVII + IV"), mcuid);
} else {
_if_partout(intcmp, "%d", mcuid);
}
_if_partout(intcmp, "%d", archnum);
_if_partout(intcmp, "%d", n_interrupts);
_if_partout(intcmp, "%d", n_page_erase);
_if_partout(intcmp, "%d", n_boot_sections);
@@ -731,7 +698,7 @@ static void dev_part_strct(const AVRPART *p, bool tsv, const AVRPART *base, bool
bm = base? dev_locate_mem(base, avr_mem_order[mi].str): NULL;
if(!m && bm && !tsv)
dev_info("\n memory \"%s\" %*s= NULL;\n", bm->desc, 13 > strlen(bm->desc)? 13-strlen(bm->desc): 0, "");
dev_info("\n memory \"%s\" %*s= NULL;\n", bm->desc, 13 > strlen(bm->desc)? 13 - (int) strlen(bm->desc): 0, "");
if(!m)
continue;
@@ -869,9 +836,42 @@ void dev_output_pgm_part(int dev_opt_c, const char *programmer, int dev_opt_p, c
}
// -p */[dASsrcow*ti]
// Which programming modes should be considered, given the flags?
static int prog_modes_in_flags(int prog_modes, const char *flags) {
int pm = 0, quirky = 0;
for(const char *p = flags; *p; p++)
switch(*p) {
case 'B': pm |= PM_SPM; break;
case 'C': pm |= PM_TPI | PM_ISP | PM_HVSP | PM_HVPP | PM_debugWIRE | PM_JTAG | PM_JTAGmkI; break;
case 'U': pm |= PM_UPDI; break;
case 'P': pm |= PM_PDI; break;
case 'T': pm |= PM_TPI; break;
case 'I': pm |= PM_ISP; break;
case 'J': pm |= PM_JTAG | PM_JTAGmkI | PM_XMEGAJTAG; break;
case 'W': pm |= PM_debugWIRE; break;
case 'H': pm |= PM_HVPP | PM_HVSP; break;
case 'Q': pm |= PM_ALL & ~(PM_SPM | PM_UPDI | PM_PDI | PM_TPI | PM_ISP | PM_JTAG | PM_JTAGmkI |
PM_XMEGAJTAG | PM_debugWIRE | PM_HVPP | PM_HVSP);
quirky = 1;
}
return (prog_modes == 0 && quirky) || !pm || (prog_modes & pm);
}
// Return pointer to uP_table entry for part p
static const Avrintel *silent_locate_uP(const AVRPART *p) {
int bakverb = verbose, idx;
verbose = -123;
idx = avr_locate_upidx(p);
verbose = bakverb;
return idx < 0? NULL: uP_table + idx;
}
// -p <wildcard>/[dsASRvcreow*tiBCUPTIJWHQ]
void dev_output_part_defs(char *partdesc) {
bool cmdok, waits, opspi, descs, astrc, strct, cmpst, injct, raw, all, tsv;
bool cmdok, waits, opspi, descs, vtabs, confs, regis, astrc, strct, cmpst, injct, raw, all, tsv;
char *flags;
int nprinted;
AVRPART *nullpart = avr_new_part();
@@ -882,29 +882,34 @@ void dev_output_part_defs(char *partdesc) {
if(!flags && str_eq(partdesc, "*")) // Treat -p * as if it was -p */s
flags = "s";
if(!*flags || !strchr("cdoASsrw*ti", *flags)) {
dev_info("%s: flags for developer option -p <wildcard>/<flags> not recognised\n", progname);
if(!*flags || !strchr("dsASRvcreow*tiBCUPTIJWHQ", *flags)) {
dev_info("Error: flags for developer option -p <wildcard>/<flags> not recognised\n");
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"
" * 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"
" d description of core part features\n"
" A show entries of avrdude.conf parts with all values\n"
" S show entries of avrdude.conf parts with necessary values\n"
" s show short entries of avrdude.conf parts using parent\n"
" r show entries of avrdude.conf parts as raw dump\n"
" c check and report errors in address bits of SPI commands\n"
" o opcodes for SPI programming parts and memories\n"
" w wd_... constants for ISP parts\n"
" * all of the above except s and S\n"
" t use tab separated values as much as possible\n"
" i inject assignments from source code table\n"
" d description of core part features\n"
" s show short entries of avrdude.conf parts using parent\n"
" A 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"
" v list interrupt vector names\n"
" c list configuration options in fuses\n"
" r list registers with I/O address and size\n"
" e check and report errors in address bits of SPI commands\n"
" o opcodes for SPI programming parts and memories\n"
" w wd_... constants for ISP parts\n"
" * as first character: all of the above except s and S\n"
" BCUPTIJWHQ only Boot/Classic/UPDI/PDI/TPI/ISP/JTAG/debugWire/HV/quirky MUCs\n"
" t use tab separated values as much as possible\n"
" i inject assignments from source code table\n"
"Examples:\n"
" $ avrdude -p ATmega328P/s\n"
" $ avrdude -p m328*/st | grep chip_erase_delay\n"
" $ avrdude -p ATmega*/Ud | wc -l\n"
" avrdude -p*/r | sort\n"
"Notes:\n"
" -p * is the same as -p */s\n"
@@ -912,25 +917,27 @@ void dev_output_part_defs(char *partdesc) {
" Leaving no space after -p can be an OK substitute for quoting in shells\n"
" /s, /S and /A 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"
" The /e, /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;
}
all = *flags == '*';
cmdok = all || !!strchr(flags, 'c');
descs = all || !!strchr(flags, 'd');
vtabs = all || !!strchr(flags, 'v');
confs = all || !!strchr(flags, 'c');
regis = all || !!strchr(flags, 'r');
cmdok = all || !!strchr(flags, 'e');
opspi = all || !!strchr(flags, 'o');
waits = all || !!strchr(flags, 'w');
astrc = all || !!strchr(flags, 'A');
raw = all || !!strchr(flags, 'r');
raw = all || !!strchr(flags, 'R');
strct = !!strchr(flags, 'S');
cmpst = !!strchr(flags, 's');
tsv = !!strchr(flags, 't');
injct = !!strchr(flags, 'i');
// 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);
@@ -960,6 +967,8 @@ void dev_output_part_defs(char *partdesc) {
if(!part_eq(p, partdesc, str_casematch))
continue;
if(!prog_modes_in_flags(p->prog_modes, flags))
continue;
if(astrc || strct || cmpst)
dev_part_strct(p, tsv,
@@ -995,6 +1004,7 @@ void dev_output_part_defs(char *partdesc) {
int ok, nfuses;
AVRMEM *m;
OPCODE *oc;
const Avrintel *up;
ok = 2047;
nfuses = 0;
@@ -1124,10 +1134,33 @@ void dev_output_part_defs(char *partdesc) {
nfuses,
ok,
p->flags,
prog_modes_str(p->prog_modes),
dev_prog_modes(p->prog_modes),
p->config_file, p->lineno
);
}
if(vtabs && (up = silent_locate_uP(p)) && up->isrtable)
for(int i=0; i < up->ninterrupts; i++)
dev_info(".vtab\t%s\t%d\t%s\n", p->desc, i, up->isrtable[i]);
if(confs && (up = silent_locate_uP(p)) && up->cfgtable)
for(int i=0; i < up->nconfigs; i++) {
const Configitem *cp = up->cfgtable+i;
unsigned c, n = cp->nvalues;
if(!n || !cp->vlist) { // Count bits set in mask
for(n = cp->mask, c=0; n; c++)
n &= n-1;
n = 1<<c;
}
dev_info(".cfgt\t%s\t%d\t%s\n", p->desc, n, cp->name);
if(cp->vlist && verbose)
for(int k=0; k < cp->nvalues; k++)
dev_info(".cfgv\t%s\t\tvalue\t%d\t%s\n", p->desc, cp->vlist[k].value, cp->vlist[k].label);
}
if(regis && (up = silent_locate_uP(p)) && up->regf)
for(int i=0; i < up->nregisters; i++)
dev_info(".regf\t%s\t0x%02x\t%d\t%s\n", p->desc, up->regf[i].addr, up->regf[i].size, up->regf[i].reg);
}
if(opspi) {
@@ -1217,7 +1250,7 @@ static void dev_pgm_raw(const PROGRAMMER *pgm) {
}
static const char *connstr(conntype_t conntype) {
static const char *connstr(Conntype conntype) {
switch(conntype) {
case CONNTYPE_LINUXGPIO: return "linuxgpio";
case CONNTYPE_PARALLEL: return "parallel";
@@ -1280,7 +1313,7 @@ static void dev_pgm_strct(const PROGRAMMER *pgm, bool tsv, const PROGRAMMER *bas
if(!firstid)
dev_info("/");
firstid = 0;
dev_info("%s", ldata(ln));
dev_info("%s", (char *) ldata(ln));
}
dev_info("\n%s\n\n", del);
}
@@ -1289,9 +1322,9 @@ static void dev_pgm_strct(const PROGRAMMER *pgm, bool tsv, const PROGRAMMER *bas
const char *prog_sea = is_programmer(pgm)? "programmer": is_serialadapter(pgm)? "serialadapter": "programmer";
if(pgm->parent_id && *pgm->parent_id)
dev_info("%s parent \"%s\" # %s\n", prog_sea, pgm->parent_id, ldata(lfirst(pgm->id)));
dev_info("%s parent \"%s\" # %s\n", prog_sea, pgm->parent_id, (char *) ldata(lfirst(pgm->id)));
else
dev_info("%s # %s\n", prog_sea, ldata(lfirst(pgm->id)));
dev_info("%s # %s\n", prog_sea, (char *) ldata(lfirst(pgm->id)));
}
if(tsv)
@@ -1318,7 +1351,7 @@ static void dev_pgm_strct(const PROGRAMMER *pgm, bool tsv, const PROGRAMMER *bas
_if_pgmout_str(strcmp, cfg_escape(pgm->desc), desc);
if(!base || base->initpgm != pgm->initpgm)
_pgmout_fmt("type", "\"%s\"", locate_programmer_type_id(pgm->initpgm));
_if_pgmout_str(intcmp, mmt_strdup(prog_modes_str(pgm->prog_modes)), prog_modes);
_if_pgmout_str(intcmp, mmt_strdup(dev_prog_modes(pgm->prog_modes)), prog_modes);
_if_pgmout_str(boolcmp, mmt_strdup(pgm->is_serialadapter? "yes": "no"), is_serialadapter);
_if_pgmout_str(intcmp, mmt_strdup(extra_features_str(pgm->extra_features)), extra_features);
if(!base || base->conntype != pgm->conntype)
@@ -1346,13 +1379,10 @@ static void dev_pgm_strct(const PROGRAMMER *pgm, bool tsv, const PROGRAMMER *bas
_if_pgmout_str(strcmp, cfg_escape(pgm->usbproduct), usbproduct);
for(int i=0; i<N_PINS; i++) {
char *str = pins_to_strdup(pgm->pin+i);
char *bstr = base? pins_to_strdup(base->pin+i): NULL;
const char *str = pins_to_str(pgm->pin+i);
const char *bstr = base? pins_to_str(base->pin+i): NULL;
if(!base || !str_eq(bstr, str))
_pgmout_fmt(avr_pin_lcname(i), "%s", str);
mmt_free(str);
mmt_free(bstr);
}
pgmstr = dev_hvupdi_support_liststr(pgm);
@@ -1383,9 +1413,9 @@ static void dev_pgm_strct(const PROGRAMMER *pgm, bool tsv, const PROGRAMMER *bas
}
// -c */[ASsrti]
// -c <wildcard>/[dASsrtiBUPTIJWHQ]
void dev_output_pgm_defs(char *pgmidcp) {
bool astrc, strct, cmpst, raw, tsv, injct;
bool descs, astrc, strct, cmpst, raw, tsv, injct;
char *flags;
int nprinted;
PROGRAMMER *nullpgm = pgm_new();
@@ -1396,8 +1426,8 @@ void dev_output_pgm_defs(char *pgmidcp) {
if(!flags && str_eq(pgmidcp, "*")) // Treat -c * as if it was -c */s
flags = "s";
if(!*flags || !strchr("ASsrti", *flags)) {
dev_info("%s: flags for developer option -c <wildcard>/<flags> not recognised\n", progname);
if(!*flags || !strchr("dASsrtiBUPTIJWHQ", *flags)) {
dev_info("Error: flags for developer option -c <wildcard>/<flags> not recognised\n");
dev_info(
"Wildcard examples (these need protecting in the shell through quoting):\n"
" * all known programmers\n"
@@ -1405,12 +1435,14 @@ void dev_output_pgm_defs(char *pgmidcp) {
" jtag*pdi matches jtag2pdi, jtag3pdi, jtag3updi and jtag2updi\n"
" jtag?pdi matches jtag2pdi and jtag3pdi\n"
"Flags (one or more of the characters below):\n"
" A show entries of avrdude.conf programmers with all values\n"
" S show entries of avrdude.conf programmers with necessary values\n"
" s show short entries of avrdude.conf programmers using parent\n"
" r show entries of avrdude.conf programmers as raw dump\n"
" t use tab separated values as much as possible\n"
" i inject assignments from source code table\n"
" d description of core programmer features\n"
" A show entries of avrdude.conf programmers with all values\n"
" S show entries of avrdude.conf programmers with necessary values\n"
" s show short entries of avrdude.conf programmers using parent\n"
" r show entries of avrdude.conf programmers as raw dump\n"
" t use tab separated values as much as possible\n"
" i inject assignments from source code table\n"
" BUPTIJWHQ only Bootloader/UPDI/PDI/TPI/ISP/JTAG/debugWire/HV/quirky MUCs\n"
"Examples:\n"
" $ avrdude -c usbasp/s\n"
" $ avrdude -c */st | grep baudrate\n"
@@ -1429,6 +1461,7 @@ void dev_output_pgm_defs(char *pgmidcp) {
astrc = !!strchr(flags, 'A');
strct = !!strchr(flags, 'S');
cmpst = !!strchr(flags, 's');
descs = !!strchr(flags, 'd');
raw = !!strchr(flags, 'r');
tsv = !!strchr(flags, 't');
injct = !!strchr(flags, 'i');
@@ -1447,8 +1480,10 @@ void dev_output_pgm_defs(char *pgmidcp) {
}
if(!matched)
continue;
if(!prog_modes_in_flags(pgm->prog_modes, flags))
continue;
if(dev_nprinted > nprinted) {
if(!descs && dev_nprinted > nprinted) {
dev_info("\n");
nprinted = dev_nprinted;
}
@@ -1460,6 +1495,19 @@ void dev_output_pgm_defs(char *pgmidcp) {
pgm->parent_id && *pgm->parent_id? locate_programmer(programmers, pgm->parent_id): nullpgm,
injct);
if(descs)
for(LNODEID idn=lfirst(pgm->id); idn; idn=lnext(idn)) {
char *id = ldata(idn);
int len = 19-strlen(id);
dev_info("%s '%s' =>%*s ['%s', '%s'], # %s %d\n",
tsv? ".desc": " ",
id, len > 0? len: 0, "",
dev_prog_modes(pgm->prog_modes),
pgm->desc,
pgm->config_file, pgm->lineno
);
}
if(raw)
dev_pgm_raw(pgm);
}

View File

@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#include <ac_cfg.h>
#include <stdio.h>
@@ -88,8 +86,6 @@ int dfu_upload(struct dfu_dev *dfu, void * ptr, int size) {
* is sent to the device.
*/
static uint16_t wIndex = 0;
/* INTERNAL FUNCTION PROTOTYPES
*/
@@ -196,7 +192,7 @@ int dfu_init(struct dfu_dev *dfu, unsigned short vid, unsigned short pid)
return -1;
}
pmsg_notice("found VID=0x%04x PID=0x%04x at %s:%s\n",
pmsg_notice2("found VID=0x%04x PID=0x%04x at %s:%s\n",
found->descriptor.idVendor, found->descriptor.idProduct,
found->bus->dirname, found->filename);
@@ -253,7 +249,7 @@ int dfu_getstatus(struct dfu_dev *dfu, struct dfu_status *status)
{
int result;
pmsg_trace("dfu_getstatus(): issuing control IN message\n");
pmsg_trace("%s(): issuing control IN message\n", __func__);
result = usb_control_msg(dfu->dev_handle,
0x80 | USB_TYPE_CLASS | USB_RECIP_INTERFACE, DFU_GETSTATUS, 0, 0,
@@ -274,7 +270,7 @@ int dfu_getstatus(struct dfu_dev *dfu, struct dfu_status *status)
return -1;
}
pmsg_trace("dfu_getstatus(): bStatus 0x%02x, bwPollTimeout %d, bState 0x%02x, iString %d\n",
pmsg_trace("%s(): bStatus 0x%02x, bwPollTimeout %d, bState 0x%02x, iString %d\n", __func__,
status->bStatus,
status->bwPollTimeout[0] | (status->bwPollTimeout[1] << 8) | (status->bwPollTimeout[2] << 16),
status->bState,
@@ -287,7 +283,7 @@ int dfu_clrstatus(struct dfu_dev *dfu)
{
int result;
pmsg_trace("dfu_clrstatus(): issuing control OUT message\n");
pmsg_trace("%s(): issuing control OUT message\n", __func__);
result = usb_control_msg(dfu->dev_handle,
USB_TYPE_CLASS | USB_RECIP_INTERFACE, DFU_CLRSTATUS, 0, 0,
@@ -305,7 +301,7 @@ int dfu_abort(struct dfu_dev *dfu)
{
int result;
pmsg_trace("dfu_abort(): issuing control OUT message\n");
pmsg_trace("%s(): issuing control OUT message\n", __func__);
result = usb_control_msg(dfu->dev_handle,
USB_TYPE_CLASS | USB_RECIP_INTERFACE, DFU_ABORT, 0, 0,
@@ -324,11 +320,11 @@ int dfu_dnload(struct dfu_dev *dfu, void *ptr, int size)
{
int result;
pmsg_trace("dfu_dnload(): issuing control OUT message, wIndex = %d, ptr = %p, size = %d\n",
wIndex, ptr, size);
pmsg_trace("%s(): issuing control OUT message, wIndex = %d, ptr = %p, size = %d\n", __func__,
cx->dfu_wIndex, ptr, size);
result = usb_control_msg(dfu->dev_handle,
USB_TYPE_CLASS | USB_RECIP_INTERFACE, DFU_DNLOAD, wIndex++, 0,
USB_TYPE_CLASS | USB_RECIP_INTERFACE, DFU_DNLOAD, cx->dfu_wIndex++, 0,
ptr, size, dfu->timeout);
if (result < 0) {
@@ -353,11 +349,11 @@ int dfu_upload(struct dfu_dev *dfu, void *ptr, int size)
{
int result;
pmsg_trace("dfu_upload(): issuing control IN message, wIndex = %d, ptr = %p, size = %d\n",
wIndex, ptr, size);
pmsg_trace("%s(): issuing control IN message, wIndex = %d, ptr = %p, size = %d\n", __func__,
cx->dfu_wIndex, ptr, size);
result = usb_control_msg(dfu->dev_handle,
0x80 | USB_TYPE_CLASS | USB_RECIP_INTERFACE, DFU_UPLOAD, wIndex++, 0,
0x80 | USB_TYPE_CLASS | USB_RECIP_INTERFACE, DFU_UPLOAD, cx->dfu_wIndex++, 0,
ptr, size, dfu->timeout);
if (result < 0) {
@@ -394,10 +390,10 @@ void dfu_show_info(struct dfu_dev *dfu)
msg_info(" USB Product : 0x%04hX\n",
(unsigned short) dfu->dev_desc.idProduct);
msg_info(" USB Release : %hu.%hu.%hu\n",
((unsigned short) dfu->dev_desc.bcdDevice >> 8) & 0xFF,
((unsigned short) dfu->dev_desc.bcdDevice >> 4) & 0xF,
((unsigned short) dfu->dev_desc.bcdDevice >> 0) & 0xF);
msg_info(" USB Release : %u.%u.%u\n",
(dfu->dev_desc.bcdDevice >> 8) & 0xFF,
(dfu->dev_desc.bcdDevice >> 4) & 0xF,
(dfu->dev_desc.bcdDevice >> 0) & 0xF);
if (dfu->serno_str != NULL)
msg_info(" USB Serial No : %s\n", dfu->serno_str);

View File

@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#ifndef dfu_h
#define dfu_h

1192
src/disasm.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
#
# avrdude - A Downloader/Uploader for AVR device programmers
# Copyright (C) 2003 Theodore A. Roth <troth@openavr.org>
# Copyright (C) 2003 Theodore A. Roth <troth@openavr.org>
#
# 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
@@ -16,10 +16,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#
# $Id$
#
GENERATED_TEXINFOS = \
$(builddir)/programmers.texi \
$(builddir)/parts.texi \

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/*
* AVRDUDE - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2022 Stefan Rueger <stefan.rueger@urclocks.com>
* Copyright (C) 2022- Stefan Rueger <stefan.rueger@urclocks.com>
*
* 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
@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
/*
* The dryrun programmer emulates a physical programmer by allocating a copy of the part and
* pretending all operations work well.
@@ -42,23 +40,35 @@
#include "dryrun.h"
#include "dryrun_private.h"
#define random() rand() // For platform independence
#define srandom(n) srand(n)
// Context of the programmer
typedef enum {
DRY_NOBOOTLOADER, // No bootloader, taking to an ordinary programmer
DRY_TOP, // Bootloader and it sits at top of flash
DRY_BOTTOM, // Bootloader sits at bottom of flash (UPDI parts)
} dry_prog_t;
} Dry_prog;
typedef struct {
AVRPART *dp;
dry_prog_t bl; // Bootloader and, if so, at top/bottom of flash?
int blsize; // Bootloader size min(flash size/4, 512)
} dryrun_t;
Dry_prog bl; // Bootloader and, if so, at top/bottom of flash?
int init; // Initialise memories with something interesting
int random; // Random initialisation of memories
int seed; // Seed for random number generator
// Flash configuration irrespective of -c programming is bootloading or not
int appstart, appsize; // Start and size of application section
int datastart, datasize; // Start and size of application data section (if any)
int bootstart, bootsize; // Start and size of boot section (if any)
int initialised; // 1 once the part memories are initialised
} Dryrun_data;
// Use private programmer data as if they were a global structure dry
#define dry (*(dryrun_t *)(pgm->cookie))
#define dry (*(Dryrun_data *)(pgm->cookie))
#define Return(...) do { pmsg_error(__VA_ARGS__); msg_error("\n"); return -1; } while (0)
#define Retwarning(...) do { pmsg_warning(__VA_ARGS__); \
msg_warning("; not initialising %s memories\n", p->desc); return -1; } while (0)
static int dryrun_readonly(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem,
unsigned int addr);
@@ -76,19 +86,40 @@ static int dryrun_read_sig_bytes(const PROGRAMMER *pgm, const AVRPART *p, const
}
// Emulate chip erase (only erase flash, pretend EESAVE fuse is active - FIXME: check EESAVE fuse)
// Emulate chip erase
static int dryrun_chip_erase(const PROGRAMMER *pgm, const AVRPART *punused) {
AVRMEM *flm;
AVRMEM *mem;
pmsg_debug("%s()\n", __func__);
if(!dry.dp)
Return("no dryrun device?");
if(!(flm = avr_locate_flash(dry.dp)))
if(!(mem = avr_locate_flash(dry.dp)))
Return("cannot locate %s flash memory for chip erase", dry.dp->desc);
if(flm->size < 1)
Return("cannot erase %s flash memory owing to its size %d", dry.dp->desc, flm->size);
if(mem->size < 1)
Return("cannot erase %s flash memory owing to its size %d", dry.dp->desc, mem->size);
memset(flm->buf, 0xff, flm->size);
if(dry.bl) { // Bootloaders won't overwrite themselves
memset(mem->buf + (dry.bl == DRY_TOP? 0: dry.bootsize), 0xff, mem->size-dry.bootsize);
return 0; // Assume that's all a bootloader does
}
memset(mem->buf, 0xff, mem->size);
int eesave, bakverb = verbose;
verbose = -123;
if((mem = avr_locate_eeprom(dry.dp))) // Check whether EEPROM needs erasing
if(avr_get_config_value(pgm, dry.dp, "eesave", &eesave) == 0 && eesave == !(dry.dp->prog_modes & PM_UPDI))
if(mem->size > 0)
memset(mem->buf, 0xff, mem->size);
verbose = bakverb;
if((mem = avr_locate_bootrow(dry.dp))) // Also erase bootrow if it's there
if(mem->size > 0)
memset(mem->buf, 0xff, mem->size);
if((mem = avr_locate_lock(dry.dp)))
if(mem->initval != -1 && mem->size > 0 && mem->size <= (int) sizeof(mem->initval))
memcpy(mem->buf, &mem->initval, mem->size); // FIXME: relying on little endian here
return 0;
}
@@ -113,120 +144,598 @@ static int dryrun_cmd(const PROGRAMMER *pgm, const unsigned char *cmd, unsigned
}
static int dryrun_page_erase(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m,
unsigned int addr) {
pmsg_debug("%s(%s, 0x%04x)\n", __func__, m->desc, addr);
if(!dry.dp)
Return("no dryrun device?");
AVRMEM *dmem;
if(!(dmem = avr_locate_mem(dry.dp, m->desc)))
Return("cannot locate %s %s memory for paged write", dry.dp->desc, m->desc);
if(!avr_has_paged_access(pgm, dmem) || addr >= (unsigned) dmem->size)
Return("%s does not support paged access", dmem->desc);
addr &= ~(dmem->page_size-1);
if(addr + dmem->page_size > (unsigned) dmem->size)
Return("%s page erase of %s reaches outside %s?", dmem->desc,
str_ccinterval(addr, addr + dmem->page_size-1), str_ccinterval(0, dmem->size-1));
memset(dmem->buf+addr, 0xff, dmem->page_size);
return 0;
}
static int dryrun_program_enable(const PROGRAMMER *pgm, const AVRPART *p_unused) {
pmsg_debug("%s()\n", __func__);
return 0;
}
// Randomly set configuration values for bootloading, bootloader size and codesize, if any
static void randflashconfig(const PROGRAMMER *pgm, const AVRPART *p,
const Avrintel *up, const Configitem *cp, int nc) {
if(up && p->prog_modes & PM_UPDI) {
int sectorsize = up->bootsize > 0? up->bootsize: 256;
int nsectors = up->flashsize/sectorsize;
int bootsize = random() % (nsectors > 4? nsectors/4: nsectors);
int codesize = !bootsize || random()%3? 0: bootsize + random()%(nsectors - bootsize);
int size = !!avr_locate_config(cp, nc, "bootsize", str_eq);
avr_set_config_value(pgm, p, size? "bootsize": "bootend", bootsize);
avr_set_config_value(pgm, p, size? "codesize": "append", codesize);
} else if(up && up->nboots >0 && (p->prog_modes & (PM_Classic | PM_PDI))) {
avr_set_config_value(pgm, p, "bootrst", random() % 2);
if(up->nboots == 4)
avr_set_config_value(pgm, p, "bootsz", random() % 4);
}
}
// Compute app, data and boot start/size
static int flashlayout(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *flm,
const Avrintel *up, const Configitem *cp, int nc) {
AVRMEM *m;
if(p->prog_modes & PM_UPDI) {
int nbootsec = 0, ncodesec = 0;
int size = !!avr_locate_config(cp, nc, "bootsize", str_eq);
avr_get_config_value(pgm, p, size? "bootsize": "bootend", &nbootsec);
avr_get_config_value(pgm, p, size? "codesize": "append", &ncodesec);
if(nbootsec == 0 || (ncodesec && ncodesec <= nbootsec)) { // Treat boot section for code
dry.bootstart = 0, dry.bootsize = 0;
dry.appstart = 0, dry.appsize = nbootsec? nbootsec*up->bootsize: up->flashsize;
} else { // Distinct boot and application section
dry.bootstart = 0, dry.bootsize = nbootsec*up->bootsize;
dry.appstart = dry.bootsize;
dry.appsize = ncodesec? (ncodesec - nbootsec) * up->bootsize: up->flashsize - dry.appstart;
}
dry.datasize = up->flashsize - dry.bootsize - dry.appsize; // Remainder is apptable
dry.datastart = dry.datasize? dry.bootsize + dry.appsize: 0;
} else if(p->prog_modes & (PM_Classic | PM_PDI)) {
dry.bootstart = 0, dry.bootsize = 0;
if(up->nboots) {
int bootrst = 1;
avr_get_config_value(pgm, p, "bootrst", &bootrst);
if(bootrst == 0) { // Jump to bootloader on reset
if((p->prog_modes & PM_PDI) && (m = avr_locate_boot(p)) && m->size > 0) {
dry.bootstart = m->offset - flm->offset;
dry.bootsize = m->size;
} else if(p->prog_modes & PM_Classic) {
if(up->nboots == 4) {
int bootsz = 0;
avr_get_config_value(pgm, p, "bootsz", &bootsz);
dry.bootsize = (8>>bootsz) * up->bootsize;
} else
dry.bootsize = up->bootsize;
dry.bootstart = up->flashsize - dry.bootsize;
}
}
}
dry.datastart = 0, dry.datasize = 0;
if((p->prog_modes & PM_PDI) && (m = avr_locate_apptable(p)) && m->size > 0) {
dry.datastart = m->offset - flm->offset;
dry.datasize = up->flashsize - dry.datastart - dry.bootsize;
}
dry.appstart = 0, dry.appsize = up->flashsize - dry.datasize - dry.bootsize;
}
// Sanity checks
if(dry.appsize < 0)
Retwarning("negative application size");
if(dry.appstart < 0 || dry.appstart+dry.appsize > up->flashsize)
Retwarning("application section %s outside flash [0, 0x%04x]",
str_ccinterval(dry.appstart, dry.appstart+dry.appsize-1), up->flashsize-1);
if(dry.datasize < 0)
Retwarning("negative apptable size");
if(dry.datastart < 0 || dry.datastart+dry.datasize > up->flashsize)
Retwarning("apptable section %s outside flash [0, 0x%04x]",
str_ccinterval(dry.datastart, dry.datastart+dry.datasize-1), up->flashsize-1);
if(dry.bootsize < 0)
Retwarning("negative boot section size");
if(dry.bootstart < 0 || dry.bootstart+dry.bootsize > up->flashsize)
Retwarning("boot section %s outside flassh [0, 0x%04x]",
str_ccinterval(dry.bootstart, dry.bootstart+dry.bootsize-1), up->flashsize-1);
if(dry.appsize + dry.datasize + dry.bootsize != up->flashsize)
Retwarning("section sizes do not add up (0x%x) to flash size 0x%x",
dry.appsize + dry.datasize + dry.bootsize, up->flashsize);
if(!dry.appsize)
Retwarning("no application section");
if(p->prog_modes & PM_UPDI) {
if(dry.bootsize && dry.appstart != dry.bootsize)
Retwarning("application section %s does not touch boot section %s",
str_ccinterval(dry.appstart, dry.appstart+dry.appsize-1),
str_ccinterval(dry.bootstart, dry.bootstart+dry.bootsize-1));
if(dry.datasize && dry.datastart != dry.bootsize + dry.appsize)
Retwarning("apptable section %s does not touch code section %s",
str_ccinterval(dry.datastart, dry.datastart+dry.appsize-1),
str_ccinterval(0, dry.bootsize+dry.appsize-1));
} else {
if(dry.datasize && dry.datastart != dry.appsize && dry.appstart !=0)
Retwarning("apptable section %s does not touch application section %s",
str_ccinterval(dry.datastart, dry.datastart+dry.appsize-1),
str_ccinterval(dry.appstart, dry.appstart+dry.appsize-1));
if(dry.datasize && dry.bootsize && dry.bootstart != dry.appsize + dry.datasize)
Retwarning("apptable section %s does not touch boot section %s",
str_ccinterval(dry.datastart, dry.datastart+dry.appsize-1),
str_ccinterval(dry.bootstart, dry.bootstart+dry.bootsize-1));
}
return 0;
}
// Write a vector table to flash addr and return number of bytes written
static int putvectortable(const AVRPART *p, const AVRMEM *flm, int addr) {
int vecsz = flm->size <= 8192? 2: 4, ret = p->n_interrupts * vecsz;
int app = (ret + vecsz - 2)/2; // Distance to application in words
for(int i = 0; i < ret; i += vecsz) { // First store rjmps to after table
flm->buf[addr + i] = app;
flm->buf[addr + i + 1] = 0xc0 + (app>>8); // rjmp app, rjmp app, ...
app -= vecsz/2;
}
for(int i=0; i < vecsz; i++) // Leave one vector gap
flm->buf[addr + ret++] = ' ';
flm->buf[addr + ret++] = 0xff; // Put endless lopp as application
flm->buf[addr + ret++] = 0xcf;
// Then round up to multiples of 32
while(ret%32)
flm->buf[addr + ret++] = ' ';
return ret;
}
// Human-readable messages in flash shown with, eg, avrdude -c dryrun -p m168 -xinit -Uflash:r:-:I
static const int u384[] = {
0x00000800, 0x08000800, 0x1c4218ca, 0x08a5284a, 0x1842184e, 0x00000000, 0x00000000, 0x08010000,
0x08010000, 0x08c53086, 0x00430942, 0x08653082,
}, u512[] = {
0x20000800, 0x20000800, 0xf71c7b51, 0x28a288d1, 0x28a28851, 0x28a28859, 0xc71c7856, 0x00000000,
0x80020000, 0x80020000, 0x8f22f1cd, 0x80920a23, 0x870e0a21, 0x08120a21, 0x87a2f1c1, 0x00000000,
}, bdata[] = {
0x00000000, 0x00000001, 0x00000001, 0x08000001, 0x08000001, 0xfe381c1d, 0x08442223, 0x08824121,
0x08824121, 0x08824121, 0x08442223, 0xf0381c1d, 0x00000000, 0x00000000, 0x00400000, 0x00400000,
0x00400000, 0x00400000, 0x785c0e3c, 0x88621102, 0x84422081, 0xfc422081, 0x04422081, 0x04621102,
0xf85c0e3c, 0x00000000, 0x00000000, 0x00000000,
}, adata[] = {
0x00000020, 0x00000020, 0x00040020, 0x00040020, 0x3c7f1e2e, 0x40042031, 0x40042021, 0x7c043e21,
0x42042121, 0x42042131, 0xfc787e2e, 0x00000000, 0x00000000, 0x00000000,
}, rocks[] = {
0x00000004, 0x0000003c, 0x000000fc, 0x000007fc, 0x00001ffc, 0x0000ffe0, 0x0003ff00, 0x001ffc00,
0x007fc000, 0x03fe0000, 0x07f00000, 0x07800000, 0x07e00000, 0x07fc0000, 0x03ff0000, 0x007fe000,
0x001ffc00, 0x0003ff00, 0x0000ffe0, 0x00001ffc, 0x000007fc, 0x000000fc, 0x0000003c, 0x00000004,
0x04000000, 0x07800000, 0x07e00000, 0x07fc0000, 0x07ff0000, 0x00ffe000, 0x003ff800, 0x0007ff00,
0x0001ffc0, 0x00003ff8, 0x00000ffc, 0x000001fc, 0x0000007c, 0x000003fc, 0x00001ff8, 0x0000ffc0,
0x0003ff00, 0x001ff800, 0x00ffe000, 0x03ff0000, 0x07fc0000, 0x07e00000, 0x07800000, 0x04000000,
0x00000000, 0x00000000, 0x00000000, 0x07fffffc, 0x07fffffc, 0x07fffffc, 0x07007000, 0x07007000,
0x07007c00, 0x0700fe00, 0x0700ff00, 0x0781ffc0, 0x07c3cfe0, 0x03ffc3f0, 0x03ff81fc, 0x01ff00fc,
0x007c003c, 0x0000001c, 0x0000000c, 0x00000000, 0x00000000, 0x00000000, 0x07fffffc, 0x07fffffc,
0x07fffffc, 0x0700001c, 0x0700001c, 0x0700001c, 0x0700003c, 0x03800038, 0x03c00078, 0x03e000f0,
0x01f803f0, 0x00ffffe0, 0x003fff00, 0x0007f800, 0x00000000, 0x00000000, 0x00000000, 0x07ffff00,
0x07ffffc0, 0x07fffff0, 0x000000f8, 0x00000038, 0x0000003c, 0x0000001c, 0x0000003c, 0x00000078,
0x000000f8, 0x07fffff0, 0x07ffffc0, 0x07ffff00, 0x00000000, 0x00000000, 0x00000000, 0x07fffffc,
0x07fffffc, 0x07fffffc, 0x0700001c, 0x0700001c, 0x0700001c, 0x0700003c, 0x03800038, 0x03c00078,
0x03e000f0, 0x01f803f0, 0x00ffffe0, 0x003fff00, 0x0007f800, 0x00000000, 0x00000000, 0x00000000,
0x07fffffc, 0x07fffffc, 0x07fffffc, 0x0700e01c, 0x0700e01c, 0x0700e01c, 0x0700e01c, 0x0700e01c,
0x0700e01c, 0x0700e01c, 0x0700001c, 0x0700001c, 0x0000001c, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x007ffffc, 0x007ffffc, 0x007ffffc, 0x00070000,
0x000e0000, 0x001c0000, 0x00380000, 0x00380000, 0x00700000, 0x00700000, 0x007f0000, 0x007f0000,
0x00000000, 0x00000000, 0x00000000, 0x0000fe00, 0x0007ffc0, 0x000fffe0, 0x003f01f8, 0x003c0078,
0x0078003c, 0x0070001c, 0x0070001c, 0x0078003c, 0x003c0078, 0x003f01f8, 0x000fffe0, 0x0007ffc0,
0x0000fe00, 0x00000000, 0x00000000, 0x00000000, 0x0000fe00, 0x0003ffc0, 0x000fffe0, 0x001f01f0,
0x003c0078, 0x0078003c, 0x0070001c, 0x0070001c, 0x0070001c, 0x0078003c, 0x00380038, 0x00380038,
0x00000000, 0x00000000, 0x00000000, 0xfffffffc, 0xfffffffc, 0xfffffffc, 0x00003000, 0x00007800,
0x0000fc00, 0x0003fe00, 0x0007ff00, 0x000fcf80, 0x001f87c0, 0x007f03f0, 0x007e01f8, 0x007800fc,
0x0070007c, 0x0060003c, 0x0040001c, 0x0000000c, 0x00000004, 0x00000000, 0x00000000, 0x00000000,
0x00000078, 0x000f8038, 0x001fc038, 0x003fe03c, 0x003fe01c, 0x0038f01c, 0x0078f01c, 0x0070701c,
0x0070381c, 0x00703c1c, 0x00703c3c, 0x00701e78, 0x00781ff8, 0x00380fe0, 0x000003c0, 0x00000000,
0x00000000, 0x00000000, 0x7ffffc3c, 0x7ffffc3c, 0x7ffffc3c, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
};
const struct { const int *bits, n32; } banner[] = {
{u384, sizeof u384/sizeof*u384},
{u512, sizeof u512/sizeof*u512},
{bdata, sizeof bdata/sizeof*bdata},
{adata, sizeof adata/sizeof*adata},
{rocks, sizeof rocks/sizeof*rocks},
{rocks, sizeof rocks/sizeof*rocks}, // Sic, dummy entry for RND
};
enum { U384, U512, BDATA, ADATA, ROCKS, RND };
/*
* Given a bit stream, put a sequence of '@' or ' ' into flash; note they are
* all benign opcodes that do not touch memory or the I/O area:
* " ": and r2, r0
* "@ ": and r4, r0
* " @": sbci r18, 0
* "@@": sbci r20, 0
*/
static void putbanner(const AVRMEM *flm, int addr, int n, int bi) {
const int *bp = banner[bi].bits, len = n/10 + random()%(9*n/10);
for(int i=0; i<n; ) {
int scan = bi == RND? random(): *bp;
for(int j=0; j<32; j++) {
flm->buf[addr++] = scan & 1? '@': ' ';
scan >>= 1;
if(++i == n)
break;
}
if(++bp == banner[bi].bits + banner[bi].n32) {
bp = banner[bi].bits;
if(i > len) // Stop repeating banner after some threshold
break;
}
}
}
// Is the opcode of benign nature, ie, not touching SRAM, I/O regs or flash?
static int is_benign_opcode(int op) {
static const struct { int mask, result; } benign[] = {
{0xfc00, 0x0c00}, // 0000 11rd dddd rrrr: add Rd, Rr
{0xfc00, 0x1c00}, // 0001 11rd dddd rrrr: adc Rd, Rr
{0xff00, 0x9600}, // 1001 0110 KKdd KKKK: adiw Rd, K
{0xfc00, 0x1800}, // 0001 10rd dddd rrrr: sub Rd, Rr
{0xf000, 0x5000}, // 0101 KKKK dddd KKKK: subi Rd, K
{0xfc00, 0x0800}, // 0000 10rd dddd rrrr: sbc Rd, Rr
{0xf000, 0x4000}, // 0100 KKKK dddd KKKK: sbci Rd, K
{0xff00, 0x9700}, // 1001 0111 KKdd KKKK: sbiw Rd, K
{0xfc00, 0x2000}, // 0010 00rd dddd rrrr: and Rd, Rr
{0xf000, 0x7000}, // 0111 KKKK dddd KKKK: andi Rd, K
{0xfc00, 0x2800}, // 0010 10rd dddd rrrr: or Rd, Rr
{0xf000, 0x6000}, // 0110 KKKK dddd KKKK: ori Rd, K
{0xfc00, 0x2400}, // 0010 01rd dddd rrrr: eor Rd, Rr
{0xfe0f, 0x9400}, // 1001 010d dddd 0000: com Rd
{0xfe0f, 0x9401}, // 1001 010d dddd 0001: neg Rd
{0xfe0f, 0x9403}, // 1001 010d dddd 0011: inc Rd
{0xfe0f, 0x940a}, // 1001 010d dddd 1010: dec Rd
{0xfc00, 0x9c00}, // 1001 11rd dddd rrrr: mul Rd, Rr
{0xff00, 0x0200}, // 0000 0010 dddd rrrr: muls Rd, Rr
{0xff88, 0x0300}, // 0000 0011 0ddd 0rrr: mulsu Rd, Rr
{0xff88, 0x0308}, // 0000 0011 0ddd 1rrr: fmul Rd, Rr
{0xff88, 0x0380}, // 0000 0011 1ddd 0rrr: fmuls Rd, Rr
{0xff88, 0x0388}, // 0000 0011 1ddd 1rrr: fmulsu Rd, Rr
// {0xff0f, 0x940b}, // 1001 0100 KKKK 1011: des K
{0xfc00, 0x1000}, // 0001 00rd dddd rrrr: cpse Rd, Rr
{0xfc00, 0x1400}, // 0001 01rd dddd rrrr: cp Rd, Rr
{0xfc00, 0x0400}, // 0000 01rd dddd rrrr: cpc Rd, Rr
{0xf000, 0x3000}, // 0011 KKKK dddd KKKK: cpi Rd, K
{0xfe08, 0xfc00}, // 1111 110r rrrr 0bbb: sbrc Rr, b
{0xfe08, 0xfe00}, // 1111 111r rrrr 0bbb: sbrs Rr, b
{0xfc00, 0x2c00}, // 0010 11rd dddd rrrr: mov Rd, Rr
{0xff00, 0x0100}, // 0000 0001 dddd rrrr: movw Rd, Rr
{0xf000, 0xe000}, // 1110 KKKK dddd KKKK: ldi Rd, K
{0xfe0f, 0x9406}, // 1001 010d dddd 0110: lsr Rd
{0xfe0f, 0x9407}, // 1001 010d dddd 0111: ror Rd
{0xfe0f, 0x9405}, // 1001 010d dddd 0101: asr Rd
{0xfe0f, 0x9402}, // 1001 010d dddd 0010: swap Rd
{0xfe08, 0xfa00}, // 1111 101d dddd 0bbb: bst Rr, b
{0xfe08, 0xf800}, // 1111 100d dddd 0bbb: bld Rd, b
{0xffff, 0x9408}, // 1001 0100 0000 1000: sec
{0xffff, 0x9488}, // 1001 0100 1000 1000: clc
{0xffff, 0x9428}, // 1001 0100 0010 1000: sen
{0xffff, 0x94a8}, // 1001 0100 1010 1000: cln
{0xffff, 0x9418}, // 1001 0100 0001 1000: sez
{0xffff, 0x9498}, // 1001 0100 1001 1000: clz
{0xffff, 0x94f8}, // 1001 0100 1111 1000: cli
{0xffff, 0x9448}, // 1001 0100 0100 1000: ses
{0xffff, 0x94c8}, // 1001 0100 1100 1000: cls
{0xffff, 0x9438}, // 1001 0100 0011 1000: sev
{0xffff, 0x94b8}, // 1001 0100 1011 1000: clv
{0xffff, 0x9468}, // 1001 0100 0110 1000: set
{0xffff, 0x94e8}, // 1001 0100 1110 1000: clt
{0xffff, 0x9458}, // 1001 0100 0101 1000: seh
{0xffff, 0x94d8}, // 1001 0100 1101 1000: clh
{0xffff, 0x95a8}, // 1001 0101 1010 1000: wdr
{0xffff, 0x0000}, // 0000 0000 0000 0000: nop
};
for(size_t i = 0; i < sizeof benign/sizeof*benign; i++)
if((op & benign[i].mask) == benign[i].result)
return 1;
return 0;
}
// Put n/2 random benign opcodes into memory at addr
static void putcode(const AVRMEM *flm, int addr, int n) {
int i = 0, op;
if(n < 2)
return;
if(n < 4)
goto endless;
for(; i < n/2 - 2; i++) {
do {
op = random() & 0xffff;
} while(!is_benign_opcode(op));
flm->buf[addr + 2*i] = op; // FIXME: relying on little endian here (and below)
flm->buf[addr + 2*i + 1] = op>>8;
}
flm->buf[addr+2*i] = 0;
flm->buf[addr+2*i+1] = 0; // nop (in case last opcode was of skip-next-instruction type
i++;
endless:
flm->buf[addr+2*i] = 255;
flm->buf[addr+2*i+1] = 0xcf; // rjmp .-2 (endless loop)
}
// Write valid opcodes to flash (banners for -xinit, random code for -xrandom)
static void putflash(const PROGRAMMER *pgm, const AVRMEM *flm, int addr, int n, int bi) {
if(dry.random) {
switch(bi) {
case U384: case U512: case BDATA: // Bootloader stuff, reduce code length a little
n -= random()%(n/8);
break;
case ADATA: case ROCKS: // Set random code length in [n/4, n]
n -= random()%(3*n/4);
}
if(bi != ADATA) {
putcode(flm, addr, n);
return;
}
bi = RND; // Make apptable data random @/space sequences
}
putbanner(flm, addr, n, bi);
}
// Initialise a user writable memory other than flash or fuses
static void putother(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, const char *str) {
const char *name = avr_mem_name(p, m);
int len = strlen(str);
if(len > m->size)
len = m->size;
if(len <= 0)
return;
memset(m->buf, 0xff, m->size);
if(dry.random)
putbanner(m, 0, m->size, RND);
else
for(int i = 0; i < m->size/3; i += len)
if(m->size - i > len)
memcpy(m->buf + i, str, len);
if((len = strlen(name)) > m->size)
len = m->size;
memcpy(m->buf+m->size-len, name, len);
if(len < m->size)
m->buf[m->size-len-1] = ' ';
}
// Copy chunk in one flash memory to other overlapping flash memories (think XMEGA)
static void sharedflash(const PROGRAMMER *pgm, const AVRMEM *fm, unsigned addr, int chunk) {
for(LNODEID ln=lfirst(dry.dp->mem); ln; ln=lnext(ln)) {
AVRMEM *m = ldata(ln);
if(mem_is_in_flash(m) && fm != m) { // Overlapping region?
unsigned int cpaddr = addr + fm->offset - m->offset;
if(cpaddr < (unsigned int) m->size && cpaddr + chunk <= (unsigned int) m->size)
memmove(m->buf+cpaddr, fm->buf+addr, chunk);
}
}
}
static void dryrun_enable(PROGRAMMER *pgm, const AVRPART *p) {
pmsg_debug("%s()\n", __func__);
AVRMEM *flm = avr_locate_flash(p);
if(flm && flm->size >= 1024) {
if(pgm->prog_modes & PM_SPM)
dry.bl = (p->prog_modes & PM_UPDI)? DRY_BOTTOM: DRY_TOP;
dry.blsize = flm->size/4;
if(dry.blsize > 512)
dry.blsize = 512;
}
if(dry.dp) // Already configured
return;
if(!dry.dp) {
unsigned char inifuses[16]; // For fuses, which is made up from fuse0, fuse1, ...
AVRMEM *fusesm = NULL, *prodsigm = NULL, *calm;
dry.dp = avr_dup_part(p); // Allocate dryrun part
unsigned char inifuses[16]; // For fuses: made up from fuse0, fuse1, ...
AVRMEM *m, *fusesm = NULL, *prodsigm = NULL, *calm;
AVRPART *q = dry.dp = avr_dup_part(p); // Allocate dryrun part and abbreviate with q
memset(inifuses, 0xff, sizeof inifuses);
// Initialise the device with factory setting and erase flash/EEPROM to 0xff
for (LNODEID ln=lfirst(dry.dp->mem); ln; ln=lnext(ln)) {
AVRMEM *m = ldata(ln);
if(mem_is_in_flash(m) || mem_is_eeprom(m)) {
memset(inifuses, 0xff, sizeof inifuses);
srandom(dry.seed? dry.seed: time(NULL));
// Initialise the device with factory setting and erase flash/EEPROM to 0xff
for (LNODEID ln=lfirst(q->mem); ln; ln=lnext(ln)) {
m = ldata(ln);
if(mem_is_in_flash(m) || mem_is_eeprom(m)) {
memset(m->buf, 0xff, m->size);
} else if(mem_is_fuses(m)) {
fusesm = m;
} else if(mem_is_a_fuse(m) || mem_is_lock(m)) {
// Lock, eg, can have 4 bytes: still allow initialisation from initval
if(m->initval != -1 && m->size >=1 && m->size <= (int) sizeof(m->initval)) {
memcpy(m->buf, &m->initval, m->size); // FIXME: relying on little endian here
if(mem_is_a_fuse(m)) {
int fno = mem_fuse_offset(m);
for(int i = 0; i < m->size && fno+i < (int) sizeof inifuses; i++) // pdicfg has 2 bytes
inifuses[fno+i] = m->initval >> 8*i;
}
} else {
memset(m->buf, 0xff, m->size);
// Overwrite ficticious bootloader section with block of endless loops
if(dry.bl && (mem_is_boot(m) || mem_is_flash(m)))
for(int i = dry.bl == DRY_TOP? m->size-dry.blsize: 0, end = i+dry.blsize, n = 0; i+1 < end; i+=2, n++)
m->buf[i] = 255-n, m->buf[i+1] = 0xcf; // rjmp .-2, rjmp .-4, ...
} else if(mem_is_fuses(m)) {
fusesm = m;
} else if(mem_is_a_fuse(m) || mem_is_lock(m)) {
// Lock, eg, can have 4 bytes: still allow initialisation from initval
if(m->initval != -1 && m->size >=1 && m->size <= (int) sizeof(m->initval)) {
memcpy(m->buf, &m->initval, m->size); // FIXME: relying on little endian here
if(mem_is_a_fuse(m)) {
int fno = mem_fuse_offset(m);
for(int i = 0; i < m->size && fno+i < (int) sizeof inifuses; i++) // pdicfg has 2 bytes
inifuses[fno+i] = m->initval >> 8*i;
}
} else {
memset(m->buf, 0xff, m->size);
}
} else if(mem_is_signature(m) && (int) sizeof(dry.dp->signature) == m->size) {
memcpy(m->buf, dry.dp->signature, m->size);
} else if(mem_is_calibration(m)) {
memset(m->buf, 'U', m->size); // 'U' for uncalibrated or unknown :)
} else if(mem_is_osc16err(m)) {
memset(m->buf, 'e', m->size);
} else if(mem_is_osc20err(m)) {
memset(m->buf, 'E', m->size);
} else if(mem_is_osccal16(m)) {
memset(m->buf, 'o', m->size);
} else if(mem_is_osccal20(m)) {
memset(m->buf, 'O', m->size);
} else if(mem_is_sib(m)) {
memset(m->buf, 'S', m->size);
} else if( mem_is_tempsense(m)) {
memset(m->buf, 'T', m->size); // 'T' for temperature calibration values
} else if(mem_is_sernum(m)) {
for(int i = 0; i < m->size; i++) // Set serial number UTSRQPONM...
m->buf[i] = 'U'-i >= 'A'? 'U'-i: 0xff;
} else if(mem_is_sigrow(m) && m->size >= 6) {
prodsigm = m;
memset(m->buf, 0xff, m->size);
if(p->prog_modes & PM_PDI) {
m->buf[0] = m->buf[1] = 'U';
} else if(!(p->prog_modes & PM_UPDI)) { // Classic parts: signature at even addresses
for(int i=0; i<3; i++)
m->buf[2*i] = dry.dp->signature[i];
}
} else if(mem_is_io(m)) { // Initialise reset values (if known)
int nr;
const Register_file_t *rf = avr_locate_register_file(p, &nr);
if(rf)
for(int i = 0; i < nr; i++)
if(rf[i].initval != -1 && rf[i].size > 0 && rf[i].size < 5)
if(rf[i].addr >= 0 && rf[i].addr+rf[i].size <= m->size)
for(int k = 0; k < rf[i].size; k++) // FIXME: Assume little endian compiler
m->buf[rf[i].addr+k] = ((unsigned char *) &rf[i].initval)[k];
}
}
if(prodsigm) {
if(p->prog_modes & PM_UPDI) {
for (LNODEID ln=lfirst(dry.dp->mem); ln; ln=lnext(ln)) {
AVRMEM *m = ldata(ln);
if(m->buf == prodsigm->buf) // Skip prodsig memory
continue;
int off = m->offset - prodsigm->offset;
int cpy = m->size;
// Submemory of prodsig, eg, signature and tempsense? Copy into prodsig
if(off >= 0 && off+cpy <= prodsigm->size)
memcpy(prodsigm->buf + off, m->buf, cpy);
}
}
if(!(p->prog_modes & (PM_PDI|PM_UPDI)) && (calm = avr_locate_calibration(dry.dp))) {
// Calibration bytes of classic parts are interspersed with signature
for(int i=0; i<calm->size; i++)
if(2*i+1 < prodsigm->size)
prodsigm->buf[2*i+1] = 'U';
}
}
if(fusesm) {
size_t fusz = fusesm->size;
memcpy(fusesm->buf, inifuses, fusz < sizeof inifuses? fusz: sizeof inifuses);
} else if(mem_is_signature(m) && (int) sizeof(q->signature) == m->size) {
memcpy(m->buf, q->signature, m->size);
} else if(mem_is_calibration(m)) {
memset(m->buf, 'U', m->size); // 'U' for uncalibrated or unknown :)
} else if(mem_is_osc16err(m)) {
memset(m->buf, 'e', m->size);
} else if(mem_is_osc20err(m)) {
memset(m->buf, 'E', m->size);
} else if(mem_is_osccal16(m)) {
memset(m->buf, 'o', m->size);
} else if(mem_is_osccal20(m)) {
memset(m->buf, 'O', m->size);
} else if(mem_is_sib(m)) {
memset(m->buf, 'S', m->size);
} else if( mem_is_tempsense(m)) {
memset(m->buf, 'T', m->size); // 'T' for temperature calibration values
} else if(mem_is_sernum(m)) {
for(int i = 0; i < m->size; i++) // Set serial number UTSRQPONM...
m->buf[i] = dry.random? 'A'+random()%26: 'U'-i >= 'A'? 'U'-i: 0xff;
} else if(mem_is_sigrow(m) && m->size >= 6) {
prodsigm = m;
memset(m->buf, 0xff, m->size);
// Classic parts: signature at even addresses
int n = q->prog_modes & PM_TPI? 1: 2; // ... unless it's the TPI parts t102/t104
if(q->prog_modes & PM_Classic)
for(int i=0; i<3; i++)
m->buf[n*i] = q->signature[i];
} else if(mem_is_io(m)) { // Initialise reset values (if known)
int nr;
const Register_file *rf = avr_locate_register_file(q, &nr);
if(rf)
for(int i = 0; i < nr; i++)
if(rf[i].initval != -1 && rf[i].size > 0 && rf[i].size < 5)
if(rf[i].addr >= 0 && rf[i].addr+rf[i].size <= m->size)
for(int k = 0; k < rf[i].size; k++) // FIXME: Assume little endian compiler
m->buf[rf[i].addr+k] = ((unsigned char *) &rf[i].initval)[k];
}
}
if(prodsigm) {
if(q->prog_modes & (PM_UPDI | PM_PDI)) {
for (LNODEID ln=lfirst(q->mem); ln; ln=lnext(ln)) {
AVRMEM *m = ldata(ln);
if(m->buf == prodsigm->buf) // Skip prodsig memory
continue;
int off = m->offset - prodsigm->offset;
int cpy = m->size;
// Submemory of prodsig, eg, signature and tempsense? Copy into prodsig
if(off >= 0 && off+cpy <= prodsigm->size)
memcpy(prodsigm->buf + off, m->buf, cpy);
}
}
if((q->prog_modes & PM_Classic) && (calm = avr_locate_calibration(q))) {
// Calibration bytes of classic parts are interspersed with signature
int n, tpi = !!(q->prog_modes & PM_TPI); // ... unless it's the TPI parts t102/t104
for(int i=0; i<calm->size; i++) {
if((n = tpi? 3+i: 2*i+1) < prodsigm->size)
prodsigm->buf[n] = 'U';
}
}
if((q->prog_modes & PM_Classic) && (m = avr_locate_sernum(q))) { // m324pb/m328pb, t102/t104
int off = m->offset - prodsigm->offset;
int cpy = m->size;
if(off >= 0 && off+cpy <= prodsigm->size)
memcpy(prodsigm->buf + off, m->buf, cpy);
}
}
if(fusesm) {
size_t fusz = fusesm->size;
memcpy(fusesm->buf, inifuses, fusz < sizeof inifuses? fusz: sizeof inifuses);
}
return;
// Is the programmer a bootloader?
if((m = avr_locate_flash(q)) && m->size >= 1024 && (pgm->prog_modes & PM_SPM))
dry.bl = (q->prog_modes & PM_UPDI)? DRY_BOTTOM: DRY_TOP;
// So that dryrun can emulate AVRDUDE page erase
if(!(pgm->prog_modes & PM_SPM) && (q->prog_modes & (PM_PDI | PM_UPDI)))
pgm->page_erase = dryrun_page_erase;
if(!dry.random && !dry.init) // OK, no further initialisation needed
return;
int nc, bakverb = verbose;
verbose = -123; // Silently retrieve uP_table[] entry and config list
const Avrintel *up = avr_locate_uP(q);
const Configitem *cp = avr_locate_configitems(q, &nc);
verbose = bakverb;
AVRMEM *flm = avr_locate_flash(q);
AVRMEM *ee = avr_locate_eeprom(q);
int incons = flm && up && (
up->flashsize != flm->size || flm->size <= 0 ||
(ee && (up->eeprompagesize != ee->page_size || ee->page_size <= 0)) ||
up->nboots != q->n_boot_sections || up->nboots < 0 ||
up->bootsize != q->boot_section_size || up->bootsize < 0 ||
memcmp(up->sigs, q->signature, 3)
);
// Ensure can use up and cp with impunity
if(!flm || !up || incons || !cp) {
pmsg_warning("%s for %s; not initialising memories beyond factory settings\n", !flm? "no flash":
!up? "no uP_table[] entry": incons? "inconsistent upP_table[] entry": "no config table", q->desc);
return;
}
randflashconfig(pgm, q, up, cp, nc);
if(flashlayout(pgm, q, flm, up, cp, nc) < 0)
return;
int vtb = putvectortable(q, flm, dry.appstart), urbtsz = 0;
int urboot = random()%3 && dry.bootsize <= 512 && flm->size >= 1024 &&
flm->size >= 4*dry.bootsize && (q->prog_modes & PM_Classic) && (q->prog_modes & PM_SPM);
if(urboot) { // Give some classic parts a small bootloader
int ps = flm->page_size;
urbtsz = dry.bootsize? dry.bootsize: flm->size > 32768? 512: flm->size < 16384? 256: 384;
urbtsz = (urbtsz + ps-1)/ps*ps;
if(!dry.bootsize && !dry.datasize) {
dry.bootsize += urbtsz;
dry.appsize -= urbtsz;
dry.bootstart = dry.appsize;
}
int ubaddr = dry.bootstart;
putflash(pgm, flm, ubaddr, urbtsz, urbtsz==384? U384: U512);
flm->buf[ubaddr] = 0xff; flm->buf[ubaddr+1] = 0xcf; // rjmp .-2
} else if(dry.bootsize) {
int btb = 0;
if(dry.bootsize >= 2048)
btb = putvectortable(q, flm, dry.bootstart);
putflash(pgm, flm, dry.bootstart + btb, dry.bootsize - btb, BDATA);
flm->buf[dry.bootstart] = 0xff; flm->buf[dry.bootstart+1] = 0xcf; // rjmp .-2
}
if(dry.datasize) {
putflash(pgm, flm, dry.datastart, dry.datasize, ADATA);
}
putflash(pgm, flm, dry.appstart+vtb, dry.appsize-vtb-urbtsz, ROCKS);
for(int i = 0; i < flm->size; i += flm->page_size)
sharedflash(pgm, flm, i, flm->page_size);
if((m = avr_locate_eeprom(q)))
putother(pgm, q, m, "The quick brown fox jumps over the lazy dog. ");
if((m = avr_locate_userrow(q)))
putother(pgm, q, m, "The five boxing wizards jump quickly. ");
if((m = avr_locate_bootrow(q)))
putother(pgm, q, m, "Lorem ipsum dolor sit amet. ");
dry.initialised = 1;
}
@@ -290,7 +799,7 @@ static int dryrun_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVR
Return("no dryrun device?");
if(n_bytes) {
AVRMEM *dmem, *dm2;
AVRMEM *dmem;
int mchr, chunk;
unsigned int end;
@@ -314,33 +823,14 @@ static int dryrun_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVR
for(; addr < end; addr += chunk) {
chunk = end-addr < page_size? end-addr: page_size;
// Return write error for protected bootloader region
if(dry.bl && (mem_is_boot(m) || mem_is_flash(m)))
if(dryrun_readonly(pgm, p, m, addr))
if(memcmp(dmem->buf+addr, m->buf+addr, chunk))
Return("Write error on protected bootloader region %s [0x%04x, 0x%04x]\n", m->desc,
dry.bl == DRY_TOP? m->size-dry.blsize: 0, dry.bl == DRY_TOP? m->size-1: dry.blsize-1);
// @@@ Check for bootloader write protection here
// Unless it is a bootloader flash looks like NOR-memory
(mchr == 'F' && !dry.bl? memand: memcpy)(dmem->buf+addr, m->buf+addr, chunk);
// Copy chunk to overlapping XMEGA's apptable, application, boot and flash memories
if(mchr == 'F') {
if(mem_is_flash(dmem)) {
for(LNODEID ln=lfirst(dry.dp->mem); ln; ln=lnext(ln)) {
dm2 = ldata(ln);
if(mem_is_in_flash(dm2) && !mem_is_flash(dm2)) { // Overlapping region?
unsigned int cpaddr = addr + dmem->offset - dm2->offset;
if(cpaddr < (unsigned int) dm2->size && cpaddr + chunk <= (unsigned int) dm2->size)
memcpy(dm2->buf+cpaddr, dmem->buf+addr, chunk);
}
}
} else if((dm2 = avr_locate_flash(dry.dp))) {
unsigned int cpaddr = addr + dmem->offset - dm2->offset;
if(cpaddr < (unsigned int) dm2->size && cpaddr + chunk <= (unsigned int) dm2->size)
memcpy(dm2->buf+cpaddr, dmem->buf+addr, chunk);
}
}
if(mchr == 'F')
sharedflash(pgm, dmem, addr, chunk);
}
}
@@ -415,7 +905,7 @@ int dryrun_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m,
Return("cannot write byte to %s %s as address 0x%04lx outside range [0, 0x%04x]",
dry.dp->desc, dmem->desc, addr, dmem->size-1);
if(!(p->prog_modes & (PM_UPDI | PM_aWire))) { // Initialise unused bits in classic & XMEGA parts
if(p->prog_modes & (PM_Classic | PM_PDI)) { // Initialise unused bits in classic & XMEGA parts
int bitmask = avr_mem_bitmask(dry.dp, dmem, addr);
// Read-modify-write for bitmasked memory
data = (data & bitmask) | (dmem->buf[addr] & ~bitmask);
@@ -461,7 +951,7 @@ int dryrun_read_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m,
Return("cannot read byte %s %s as address 0x%04lx outside range [0, 0x%04x]",
dry.dp->desc, dmem->desc, addr, dmem->size-1);
if(!dry.bl && (mem_is_io(dmem) || mem_is_sram(dmem)) && !(p->prog_modes & (PM_UPDI | PM_PDI)))
if(!dry.bl && (mem_is_io(dmem) || mem_is_sram(dmem)) && (p->prog_modes & PM_Classic))
Return("classic part io/sram memories cannot be read externally");
*value = dmem->buf[addr];
@@ -502,7 +992,7 @@ static int dryrun_vfy_led(const PROGRAMMER *pgm, int value) {
static void dryrun_display(const PROGRAMMER *pgm, const char *p_unused) {
imsg_info("%c%s programmer for %s\n", toupper(*pgmid), pgmid+1, dry.dp? dry.dp->desc: partdesc? partdesc: "???");
// imsg_info("%c%s programmer for %s\n", toupper(*pgmid), pgmid+1, dry.dp? dry.dp->desc: partdesc? partdesc: "???");
return;
}
@@ -520,12 +1010,9 @@ static int dryrun_readonly(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM
return 0;
}
// Bootloader restictions: emulate a bootloader for dryboot
if(mem_is_boot(mem) || mem_is_flash(mem))
if(dry.bl == DRY_TOP? (int) addr >= mem->size-dry.blsize: (int) addr < dry.blsize)
return 1;
// @@@ check for bootloader write protection
if(mem_is_in_fuses(mem) || mem_is_lock(mem))
if(dry.initialised && (mem_is_in_fuses(mem) || mem_is_lock(mem)))
return 1;
return 0;
@@ -535,7 +1022,7 @@ static int dryrun_readonly(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM
static void dryrun_setup(PROGRAMMER *pgm) {
pmsg_debug("%s()\n", __func__);
// Allocate dry
pgm->cookie = mmt_malloc(sizeof(dryrun_t));
pgm->cookie = mmt_malloc(sizeof(Dryrun_data));
}
@@ -546,6 +1033,56 @@ static void dryrun_teardown(PROGRAMMER *pgm) {
}
static int dryrun_parseextparams(const PROGRAMMER *pgm, const LISTID extparms) {
int rc = 0;
bool help = false;
for(LNODEID ln = lfirst(extparms); ln; ln = lnext(ln)) {
const char *xpara = ldata(ln);
if(str_starts(xpara, "init")) {
dry.init = 1;
continue;
}
if(str_starts(xpara, "random")) {
dry.random = 1;
continue;
}
if(str_starts(xpara, "seed=")) {
const char *errptr;
int seed = str_int(strchr(xpara, '=')+1, STR_INT32, &errptr);
if(errptr) {
pmsg_error("cannot parse %s seed value: %s\n", xpara, errptr);
rc = -1;
break;
}
dry.seed = seed;
continue;
}
if(str_eq(xpara, "help")) {
help = true;
rc = LIBAVRDUDE_EXIT;
}
if(!help) {
pmsg_error("invalid extended parameter -x %s\n", xpara);
rc = -1;
}
msg_error("%s -c %s extended options:\n", progname, pgmid);
msg_error(" -x init Initialise memories with human-readable patterns (1, 2, 3)\n");
msg_error(" -x random Initialise memories with random code/values (1, 3)\n");
msg_error(" -x seed=<n> Seed random number generator with <n>, n>0, default time(NULL)\n");
msg_error(" -x help Show this help menu and exit\n");
msg_error("Notes:\n");
msg_error(" (1) -x init and -x random randomly configure flash wrt boot/data/code length\n");
msg_error(" (2) Patterns can best be seen with fixed-width font on -U flash:r:-:I\n");
msg_error(" (3) Choose, eg, -x seed=1 for reproducible flash configuration and output\n");
return rc;
}
return rc;
}
const char dryrun_desc[] = "Dryrun programmer for testing avrdude";
void dryrun_initpgm(PROGRAMMER *pgm) {
@@ -579,4 +1116,5 @@ void dryrun_initpgm(PROGRAMMER *pgm) {
pgm->teardown = dryrun_teardown;
pgm->term_keep_alive = dryrun_term_keep_alive;
pgm->readonly = dryrun_readonly;
pgm->parseextparams = dryrun_parseextparams;
}

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2022 Stefan Rueger <stefan.rueger@dryruns.com>
* Copyright (C) 2022 Stefan Rueger <stefan.rueger@urclocks.com>
*
* 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
@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#ifndef dryrun_h__
#define dryrun_h__

View File

@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#ifndef dryrun_private_h__
#define dryrun_private_h__

47
src/elf2tag Executable file
View File

@@ -0,0 +1,47 @@
#!/usr/bin/env bash
# Part of the AVRDUDE project https://github.com/avrdudes/avrdude
# Published under GNU General Public License, version 2 (GPL-2.0)
# Copyright (C) 2007 Johannes Bauer <JohannesBauer@gmx.de>
# Copyright (C) 2024 Small modifications by Stefan Rueger <stefan.rueger@urclocks.com>
progname=$(basename "$0")
for pgm in sort grep awk avr-objdump avr-nm; do
hash $pgm 2>/dev/null || { echo "$progname: $pgm does not seem to be installed, exiting"; exit 1; }
done
if [ "$1" == "" ]; then
cat <<END
Syntax: $progname <file>.elf
Function: output a tagfile suitable for the avrdude disasm -t=<tagfile> command
Options: none
END
exit 1
fi
echo "# Automatically generated tagfile via ${progname} ${1}"
avr-objdump -d "$1" | grep '<.*>:' | awk '{
ADDR = strtonum("0x" $1);
printf("0x%04x L %s\n", ADDR, substr($2, 2, length($2) - 3));
}'
echo
avr-nm "$1" | grep '^0080' | sort | grep -Ev '_(_bss_start|_data_end|_data_start|_bss_end|edata|DATA_REGION_ORIGIN)' | awk '
{
ADDR = strtonum("0x" $1) - strtonum("0x800000");
if (LAST != "") {
STARTADDR = LAST;
ENDADDR = ADDR - 1;
SYMBOL = LASTSYM;
SIZE = ENDADDR - STARTADDR + 1;
if (SIZE == 1) {
printf("0x%04x M B 1 %s\n", STARTADDR, SYMBOL);
} else if (SIZE == 2) {
printf("0x%04x M W 1 %s\n", STARTADDR, SYMBOL);
} else {
printf("0x%04x M B %d %s\n", STARTADDR, SIZE, SYMBOL);
}
}
LAST = ADDR;
LASTSYM = $3;
}'

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2023 Stefan Rueger <stefan.rueger@urclocks.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -17,8 +17,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#include <ac_cfg.h>
#include <limits.h>
@@ -150,10 +148,130 @@ FILEFMT fileio_format(char c) {
}
}
// Same as fileio_format(ch) but show error message with originator who and list possible formats
FILEFMT fileio_format_with_errmsg(char ch, const char *who) {
FILEFMT format = fileio_format(ch);
if(format == FMT_ERROR) {
pmsg_error("%sinvalid file format :%c; known formats are\n", who? who: "", ch);
for(int f, c, i=0; i<62; i++) {
c = i<10? '0'+i: (i&1? 'A': 'a') + (i-10)/2;
f = fileio_format(c);
if(f != FMT_ERROR)
msg_error(" :%c %s\n", c, fileio_fmtstr(f));
}
}
return format;
}
// Multi-memory file flat address space layout (also used by avr-gcc's elf)
enum {
MULTI_FLASH, MULTI_DATA, MULTI_EEPROM,
MULTI_FUSES, MULTI_LOCK,
MULTI_SIGROW, MULTI_USERROW, MULTI_BOOTROW,
MULTI_N,
};
static const struct {
unsigned base, size;
const char *name;
} mulmem[] = {
{ 0, 0x800000, "flash"}, // rjmp/call can only address 8 MiB in AVR8 architectures
{0x800000, 0x10000, "data"}, // IO/SRAM
{0x810000, 0x10000, "EEPROM"},
{0x820000, 0x10000, "fuses"},
{0x830000, 0x10000, "lock"},
{0x840000, 0x10000, "sigrow"},
{0x850000, 0x10000, "userrow"},
{0x860000, 0x10000, "bootrow"},
};
#define ANY_MEM_SIZE (mulmem[MULTI_N-1].base + mulmem[MULTI_N-1].size)
#define MBASE(n) (mulmem[MULTI_ ## n].base)
#define MSIZE(n) (mulmem[MULTI_ ## n].size)
#define MEND(n) (MBASE(n) + MSIZE(n) - 1)
// Memory that holds all possible multi-memories as laid out above
AVRMEM *fileio_any_memory(const char *name) {
return avr_new_memory(name, ANY_MEM_SIZE);
}
#define boffset(p, basemem) baseoffset((p), avr_locate_ ## basemem(p), # basemem)
static int baseoffset(const AVRPART *p, const AVRMEM *base, const char *memname) {
if(!base)
pmsg_error("failed to locate %s memory in %s\n", memname, p->desc);
return base? base->offset: 0;
}
// Extends where memory is put in flat address space of .elf files
unsigned fileio_mem_offset(const AVRPART *p, const AVRMEM *mem) {
if(mem->type == 0 && mem->size == (int) ANY_MEM_SIZE)
return 0;
unsigned location =
mem_is_in_flash(mem)? MBASE(FLASH) + mem->offset - boffset(p, flash):
mem_is_io(mem) || mem_is_sram(mem)? MBASE(DATA) + mem->offset:
mem_is_eeprom(mem)? MBASE(EEPROM):
mem_is_in_fuses(mem)? MBASE(FUSES) + mem_fuse_offset(mem):
mem_is_lock(mem)? MBASE(LOCK):
// Classic parts intersperse signature and calibration bytes, this code places them together
(p->prog_modes & PM_Classic) && mem_is_signature(mem)? MBASE(SIGROW):
(p->prog_modes & PM_Classic) && mem_is_calibration(mem)? MBASE(SIGROW)+3:
(p->prog_modes & PM_Classic) && mem_is_in_sigrow(mem)? MBASE(SIGROW)+0x10+mem->offset-boffset(p, sigrow):
// XMEGA parts have signature separate from prodsig, place prodsig at +0x10 as above
(p->prog_modes & PM_PDI) && mem_is_signature(mem)? MBASE(SIGROW):
(p->prog_modes & PM_PDI) && mem_is_in_sigrow(mem)? MBASE(SIGROW)+0x10 + mem->offset - boffset(p, sigrow):
(p->prog_modes & PM_UPDI) && mem_is_in_sigrow(mem)? MBASE(SIGROW) + mem->offset - boffset(p, sigrow):
mem_is_sib(mem)? MBASE(SIGROW) + 0x1000: // Arbitrary 0x1000 offset in signature section for sib
mem_is_userrow(mem)? MBASE(USERROW):
mem_is_bootrow(mem)? MBASE(BOOTROW):
~0U;
if(location == ~0U)
pmsg_error("unable to locate %s's %s in multi-memory address space\n", p->desc, mem->desc);
else if(location >= ANY_MEM_SIZE || location + mem->size > ANY_MEM_SIZE) { // Overflow
pmsg_error("%s's %s location [0x%06x, 0x%06x] outside flat address space [0, 0x%06x]\n",
p->desc, mem->desc, location, location + mem->size-1, ANY_MEM_SIZE-1);
location = ~0U;
} else if(location <= MEND(FLASH) && location + mem->size > MEND(FLASH)+1) {
pmsg_error("%s's %s location [0x%06x, 0x%06x] straddles flash section boundary 0x%06x\n",
p->desc, mem->desc, location, location + mem->size-1, MEND(FLASH)+1);
location = ~0U;
} else if(location > MEND(FLASH) && location/0x10000 != (location + mem->size-1)/0x10000) {
pmsg_error("%s's %s memory location [0x%06x, 0x%06x] straddles memory section boundary 0x%02x0000\n",
p->desc, mem->desc, location, location + mem->size-1, 1+location/0x10000);
location = ~0U;
}
return location;
}
static const char *memlabel(const AVRPART *p, const AVRMEM *m, unsigned addr, int n) {
if(m->size < (int) ANY_MEM_SIZE) // Ordinary (single) memory
return addr? NULL: m->desc;
// Inverse lookup of which memory could have been mapped to this address
for(LNODEID lm = lfirst(p->mem); lm; lm = lnext(lm))
if(fileio_mem_offset(p, (m = ldata(lm))) == addr && n == m->size)
return avr_mem_name(p, m);
for(LNODEID lm = lfirst(p->mem); lm; lm = lnext(lm))
if(fileio_mem_offset(p, (m = ldata(lm))) == addr)
return avr_mem_name(p, m);
return NULL;
}
// Tells lower level .hex/.srec routines whether to write intros/outros
typedef enum {
FIRST_SEG = 1,
LAST_SEG = 2,
} Segorder_t;
} Segorder;
static void print_ihex_extended_addr(int n_64k, FILE *outf) {
@@ -163,6 +281,8 @@ static void print_ihex_extended_addr(int n_64k, FILE *outf) {
fprintf(outf, ":02000004%02X%02X%02X\n", hi, lo, cksum);
}
/*
* Binary buffer to Intel Hex, see https://en.wikipedia.org/wiki/Intel_HEX
*
@@ -176,10 +296,10 @@ static void print_ihex_extended_addr(int n_64k, FILE *outf) {
* Return the maximum memory address within mem->buf that was read from
* plus one. If an error occurs, return -1.
*/
static int b2ihex(const unsigned char *buf, const Segment_t *segp, Segorder_t where,
int recsize, int startaddr, const char *outfile_unused, FILE *outf,
FILEFMT ffmt) {
static int b2ihex(const AVRPART *p, const AVRMEM *mem, const Segment *segp, Segorder where,
int recsize, int startaddr, const char *outfile_unused, FILE *outf, FILEFMT ffmt) {
const unsigned char *buf = mem->buf;
int bufsize = segp->len;
unsigned int nextaddr;
int n, hiaddr, n_64k;
@@ -208,7 +328,7 @@ static int b2ihex(const unsigned char *buf, const Segment_t *segp, Segorder_t wh
if (n) {
fprintf(outf, ":%02X%04X00", n, nextaddr);
unsigned char cksum = n + ((nextaddr >> 8) & 0x0ff) + (nextaddr & 0x0ff);
unsigned char c, cksum = n + ((nextaddr >> 8) & 0x0ff) + (nextaddr & 0x0ff);
for(int i=0; i<n; i++) {
fprintf(outf, "%02X", buf[i]);
cksum += buf[i];
@@ -217,13 +337,23 @@ static int b2ihex(const unsigned char *buf, const Segment_t *segp, Segorder_t wh
fprintf(outf, "%02X", cksum);
if(ffmt == FMT_IHXC) { /* Print comment with address and ASCII dump */
const char *name = memlabel(p, mem, n_64k*0x10000 + nextaddr, n);
for(int i=n; i<recsize; i++)
fprintf(outf, " ");
fprintf(outf, " // %05x> ", n_64k*0x10000 + nextaddr);
for(int 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);
for(int i=0; i<n; i++)
if(n < 9 && name)
fprintf(outf, "%s0x%02x", i? " ": "", buf[i]);
else
putc((c = buf[i] & 0x7f) < ' ' || c == 0x7f? '.': c, outf);
if(name) {
fprintf(outf, " %s", name);
if((str_eq(name, "sigrow") || str_eq(name, "signature")) && !nextaddr) {
const char *mculist = str_ccmcunames_signature(buf, PM_ALL);
if(*mculist)
fprintf(outf, " (%s)", mculist);
}
}
}
putc('\n', outf);
@@ -258,7 +388,6 @@ static int ihex_readrec(struct ihexsrec *ihex, char * rec) {
int offset, len;
char * e;
unsigned char cksum;
int rc;
len = strlen(rec);
offset = 1;
@@ -320,37 +449,62 @@ static int ihex_readrec(struct ihexsrec *ihex, char * rec) {
if (e == buf || *e != 0)
return -1;
rc = -cksum & 0x000000ff;
pmsg_debug("read ihex record type 0x%02x at 0x%04x with %2d bytes and chksum 0x%02x (0x%02x)\n",
ihex->rectyp, ihex->loadofs, ihex->reclen, ihex->cksum, -cksum & 0xff);
return rc;
return -cksum & 0xff;
}
// Extract correct memory from large any memory assuming multi-memory model
static int any2mem(const AVRPART *p, const AVRMEM *mem, const Segment *segp,
const AVRMEM *any, unsigned maxsize) {
// Compute location for multi-memory file input
unsigned location = maxsize > MEND(FLASH)+1? fileio_mem_offset(p, mem): 0;
if(location == ~0U)
return -1;
unsigned ret = 0;
// Copy over memory to right place and return highest written address plus one
for(unsigned i = segp->addr, end = segp->addr + segp->len; i < end; i++)
if(any->tags[location + i]) {
mem->buf[i] = any->buf[location + i];
mem->tags[i] = any->tags[location + i];
ret = i+1;
}
return ret;
}
/*
* Intel Hex to binary buffer
*
* Given an open file 'inf' which contains Intel Hex formatted data,
* parse the file and lay it out within the memory buffer pointed to
* by mem->buf. The segment within buf, segp, is honoured; if data
* were to fall outside of the memory segment, an error is generated.
* Given an open file 'inf' which contains Intel Hex formatted data, parse
* the file, which potentially contains many AVR memories, and lay it out
* in a temporary AVR "any memory". This also determines whether inf
* contains the AVR memory mem to write to. Only the segment within
* mem->buf, segp, is written to.
*
* Return the maximum memory address within mem->buf that was written
* plus one. If an error occurs, return -1.
* Return 0 if nothing was written, otherwise the maximum memory address
* within mem->buf that was written plus one. On error, return -1.
*/
static int ihex2b(const char *infile, FILE *inf, const AVRMEM *mem,
const Segment_t *segp, unsigned int fileoffset, FILEFMT ffmt) {
static int ihex2b(const char *infile, FILE *inf, const AVRPART *p, const AVRMEM *mem,
const Segment *segp, unsigned int fileoffset, FILEFMT ffmt) {
const char *errstr;
unsigned int nextaddr, baseaddr, maxaddr;
int lineno, rc, digits;
int lineno, rc;
struct ihexsrec ihex;
lineno = 0;
baseaddr = 0;
maxaddr = 0;
nextaddr = 0;
digits = mem->size > 0x10000? 5: 4;
rewind(inf);
AVRMEM *any = fileio_any_memory("any");
for(char *buffer; (buffer = str_fgets(inf, &errstr)); mmt_free(buffer)) {
lineno++;
@@ -363,48 +517,78 @@ static int ihex2b(const char *infile, FILE *inf, const AVRMEM *mem,
if(rc < 0) {
pmsg_error("invalid record at line %d of %s\n", lineno, infile);
mmt_free(buffer);
return -1;
goto error;
}
if(rc != ihex.cksum) {
if(ffmt == FMT_IHEX) {
pmsg_error("checksum mismatch at line %d of %s\n", lineno, infile);
imsg_error("checksum=0x%02x, computed checksum=0x%02x\n", ihex.cksum, rc);
mmt_free(buffer);
return -1;
goto error;
}
// Just warn with more permissive format FMT_IHXC
pmsg_notice("checksum mismatch at line %d of %s\n", lineno, infile);
imsg_notice("checksum=0x%02x, computed checksum=0x%02x\n", ihex.cksum, rc);
}
unsigned below = 0, anysize = any->size;
switch (ihex.rectyp) {
case 0: /* data record */
if (fileoffset != 0 && ihex.loadofs + baseaddr < fileoffset) {
pmsg_error("address 0x%04x out of range (below fileoffset 0x%x) at line %d of %s\n",
if(ihex.loadofs + baseaddr < fileoffset) {
if(!ovsigck) {
pmsg_error("address 0x%06x below memory offset 0x%x at line %d of %s;\n",
ihex.loadofs + baseaddr, fileoffset, lineno, infile);
imsg_error("use -F to skip this check\n");
mmt_free(buffer);
goto error;
}
pmsg_warning("address 0x%06x below memory offset 0x%x at line %d of %s: ",
ihex.loadofs + baseaddr, fileoffset, lineno, infile);
mmt_free(buffer);
return -1;
below = fileoffset - baseaddr - ihex.loadofs;
if(below < ihex.reclen) { // Clip record
ihex.reclen -= below;
ihex.loadofs += below;
} else { // Nothing to write
ihex.reclen = 0;
}
msg_warning("%s record\n", ihex.reclen? "clipping": "ignoring");
}
nextaddr = ihex.loadofs + baseaddr - fileoffset;
unsigned int beg = segp->addr, end = segp->addr + segp->len-1;
if(nextaddr < beg || nextaddr + ihex.reclen-1 > end) {
pmsg_error("Intel Hex record [0x%0*x, 0x%0*x] out of range [0x%0*x, 0x%0*x]\n",
digits, nextaddr, digits, nextaddr+ihex.reclen-1, digits, beg, digits, end);
imsg_error("at line %d of %s\n", lineno, infile);
mmt_free(buffer);
return -1;
if(ihex.reclen && nextaddr + ihex.reclen > anysize) {
if(!ovsigck) {
pmsg_error("Intel Hex record [0x%06x, 0x%06x] out of range [0, 0x%06x]\n",
nextaddr, nextaddr+ihex.reclen-1, anysize-1);
imsg_error("at line %d of %s; use -F to skip this check\n", lineno, infile);
mmt_free(buffer);
goto error;
}
pmsg_warning("Intel Hex record [0x%06x, 0x%06x] out of range [0, 0x%06x]: ",
nextaddr, nextaddr+ihex.reclen-1, anysize-1);
if(ihex.reclen && nextaddr + ihex.reclen > anysize) {
unsigned above = nextaddr + ihex.reclen - anysize;
ihex.reclen = above < ihex.reclen? ihex.reclen - above: 0; // Clip or zap
}
msg_warning("%s it\n", ihex.reclen? "clipping": "ignoring");
}
for(int i=0; i<ihex.reclen; i++) {
mem->buf[nextaddr+i] = ihex.data[i];
mem->tags[nextaddr+i] = TAG_ALLOCATED;
any->buf[nextaddr+i] = ihex.data[below + i];
any->tags[nextaddr+i] = TAG_ALLOCATED;
}
if (nextaddr+ihex.reclen > maxaddr)
if(!ovsigck && nextaddr == mulmem[MULTI_SIGROW].base && ihex.reclen >= 3)
if(!avr_sig_compatible(p->signature, any->buf+nextaddr)) {
pmsg_error("signature of %s incompatible with file's (%s);\n", p->desc,
str_ccmcunames_signature(any->buf+nextaddr, PM_ALL));
imsg_error("use -F to override this check\n");
mmt_free(buffer);
goto error;
}
if(ihex.reclen && nextaddr+ihex.reclen > maxaddr)
maxaddr = nextaddr+ihex.reclen;
break;
case 1: /* end of file record */
mmt_free(buffer);
return maxaddr;
goto done;
case 2: /* extended segment address record */
baseaddr = (ihex.data[0] << 8 | ihex.data[1]) << 4;
@@ -426,22 +610,32 @@ static int ihex2b(const char *infile, FILE *inf, const AVRMEM *mem,
pmsg_error("do not know how to deal with rectype=%d "
"at line %d of %s\n", ihex.rectyp, lineno, infile);
mmt_free(buffer);
return -1;
goto error;
}
}
if(errstr) {
pmsg_error("read error in Intel Hex file %s: %s\n", infile, errstr);
return -1;
goto error;
}
if (maxaddr == 0) {
pmsg_error("no valid record found in Intel Hex file %s\n", infile);
return -1;
goto error;
}
pmsg_warning("no end of file record found for Intel Hex file %s\n", infile);
return maxaddr;
done:
rc = any2mem(p, mem, segp, any, maxaddr);
avr_free_mem(any);
if(!rc)
pmsg_warning("no %s data found in Intel Hex file %s\n", mem->desc, infile);
return rc;
error:
avr_free_mem(any);
return -1;
}
static unsigned int cksum_srec(const unsigned char *buf, int n, unsigned addr, int addr_width) {
@@ -458,12 +652,12 @@ static unsigned int cksum_srec(const unsigned char *buf, int n, unsigned addr, i
// Binary to Motorola S-Record, see https://en.wikipedia.org/wiki/SREC_(file_format)
static int b2srec(const AVRMEM *mem, const Segment_t *segp, Segorder_t where,
static int b2srec(const AVRMEM *mem, const Segment *segp, Segorder where,
int recsize, int startaddr, const char *outfile_unused, FILE *outf) {
const unsigned char *buf;
unsigned int nextaddr;
int n, hiaddr, addr_width, reccount;
int n, hiaddr, addr_width;
buf = mem->buf + segp->addr;
nextaddr = startaddr + segp->addr;
@@ -500,9 +694,9 @@ static int b2srec(const AVRMEM *mem, const Segment_t *segp, Segorder_t where,
for(int i = 0; i < len; i++)
fprintf(outf, "%02X", s[i]);
fprintf(outf, "%02X\n", cksum_srec((unsigned char *) s, len, 0, 2));
cx->reccount = 0;
}
reccount = 0;
for(int bufsize = segp->len; bufsize; bufsize -= n) {
n = recsize;
if(n > bufsize)
@@ -516,15 +710,15 @@ static int b2srec(const AVRMEM *mem, const Segment_t *segp, Segorder_t where,
buf += n;
nextaddr += n;
hiaddr +=n;
reccount++;
cx->reccount++;
}
// Add S5/6 record count record and S7/8/9 end of data record
if(where & LAST_SEG) {
if(reccount >= 0 && reccount <= 0xffffff) {
int wd = reccount <= 0xffff? 2: 3;
fprintf(outf, "S%c%02X%0*X%02X\n", '5' + (wd == 3), wd + 1, 2*wd, reccount,
cksum_srec(NULL, 0, reccount, wd));
if(cx->reccount >= 0 && cx->reccount <= 0xffffff) {
int wd = cx->reccount <= 0xffff? 2: 3;
fprintf(outf, "S%c%02X%0*X%02X\n", '5' + (wd == 3), wd + 1, 2*wd, cx->reccount,
cksum_srec(NULL, 0, cx->reccount, wd));
}
fprintf(outf, "S%c%02X%0*X", endrec, addr_width + 1, 2*addr_width, startaddr);
fprintf(outf, "%02X\n", cksum_srec(NULL, 0, startaddr, addr_width));
@@ -608,20 +802,22 @@ static int srec_readrec(struct ihexsrec *srec, char *rec) {
}
// Motorola S-Record to binary
static int srec2b(const char *infile, FILE * inf,
const AVRMEM *mem, const Segment_t *segp, unsigned int fileoffset) {
static int srec2b(const char *infile, FILE * inf, const AVRPART *p,
const AVRMEM *mem, const Segment *segp, unsigned int fileoffset) {
const char *errstr;
unsigned int nextaddr, maxaddr;
struct ihexsrec srec;
int lineno, rc, digits, hexdigs;
int lineno, rc, hexdigs;
unsigned int reccount;
unsigned char datarec;
lineno = 0;
maxaddr = 0;
reccount = 0;
digits = mem->size > 0x10000? 5: 4;
rewind(inf);
AVRMEM *any = fileio_any_memory("any");
for(char *buffer; (buffer = str_fgets(inf, &errstr)); mmt_free(buffer)) {
lineno++;
@@ -634,13 +830,13 @@ static int srec2b(const char *infile, FILE * inf,
if(rc < 0) {
pmsg_error("invalid record at line %d of %s\n", lineno, infile);
mmt_free(buffer);
return -1;
goto error;
}
if(rc != srec.cksum) {
pmsg_error("checksum mismatch at line %d of %s\n", lineno, infile);
imsg_error("checksum=0x%02x, computed checksum=0x%02x\n", srec.cksum, rc);
mmt_free(buffer);
return -1;
goto error;
}
datarec=0;
@@ -666,14 +862,14 @@ static int srec2b(const char *infile, FILE * inf,
case '4': // S4: symbol record (LSI extension)
pmsg_error("not supported record at line %d of %s\n", lineno, infile);
mmt_free(buffer);
return -1;
goto error;
case '5': // S5: count of S1, S2 and S3 records previously tx'd
if (srec.loadofs != reccount){
pmsg_error("count of transmitted data records mismatch at line %d of %s\n", lineno, infile);
imsg_error("transmitted data records= %d, expected value= %d\n", reccount, srec.loadofs);
mmt_free(buffer);
return -1;
goto error;
}
break;
@@ -681,37 +877,68 @@ static int srec2b(const char *infile, FILE * inf,
case '8': // S8: end record for 24 bit addresses
case '9': // S9: end record for 16 bit addresses
mmt_free(buffer);
return maxaddr;
goto done;
default:
pmsg_error("do not know how to deal with rectype S%d at line %d of %s\n",
srec.rectyp, lineno, infile);
mmt_free(buffer);
return -1;
goto error;
}
if (datarec == 1) {
nextaddr = srec.loadofs;
unsigned below = 0, anysize = any->size;
if (nextaddr < fileoffset) {
pmsg_error("address 0x%0*x below memory offset at line %d of %s\n",
hexdigs, nextaddr, lineno, infile);
mmt_free(buffer);
return -1;
if(!ovsigck) {
pmsg_error("address 0x%0*x below memory offset 0x%x at line %d of %s\n",
hexdigs, nextaddr, fileoffset, lineno, infile);
imsg_error("use -F to skip this check\n");
mmt_free(buffer);
goto error;
}
pmsg_warning("address 0x%0*x below memory offset 0x%x at line %d of %s: ",
hexdigs, nextaddr, fileoffset, lineno, infile);
below = fileoffset - nextaddr;
if(below < srec.reclen) { // Clip record
nextaddr += below;
srec.reclen -= below;
} else { // Ignore record
srec.reclen = 0;
}
msg_warning("%s record\n", srec.reclen? "clipping": "ignoring");
}
nextaddr -= fileoffset;
unsigned int beg = segp->addr, end = segp->addr + segp->len-1;
if(nextaddr < beg || nextaddr + srec.reclen-1 > end) {
pmsg_error("Motorola S-Record [0x%0*x, 0x%0*x] out of range [0x%0*x, 0x%0*x]\n",
digits, nextaddr, digits, nextaddr+srec.reclen-1, digits, beg, digits, end);
imsg_error("at line %d of %s\n", lineno, infile);
mmt_free(buffer);
return -1;
if(srec.reclen && nextaddr + srec.reclen > anysize) {
if(!ovsigck) {
pmsg_error("Motorola S-Record [0x%06x, 0x%06x] out of range [0, 0x%06x]\n",
nextaddr, nextaddr+srec.reclen-1, anysize-1);
imsg_error("at line %d of %s; use -F to skip this check\n", lineno, infile);
mmt_free(buffer);
goto error;
}
pmsg_warning("Motorola S-Record [0x%06x, 0x%06x] out of range [0, 0x%06x]: ",
nextaddr, nextaddr+srec.reclen-1, anysize-1);
if(srec.reclen && nextaddr + srec.reclen > anysize) {
unsigned above = nextaddr + srec.reclen - anysize;
srec.reclen = above < srec.reclen? srec.reclen - above: 0; // Clip or zap
}
msg_warning("%s it\n", srec.reclen? "clipping": "ignoring");
}
for(int i=0; i<srec.reclen; i++) {
mem->buf[nextaddr+i] = srec.data[i];
mem->tags[nextaddr+i] = TAG_ALLOCATED;
any->buf[nextaddr+i] = srec.data[below + i];
any->tags[nextaddr+i] = TAG_ALLOCATED;
}
if (nextaddr+srec.reclen > maxaddr)
if(!ovsigck && nextaddr == mulmem[MULTI_SIGROW].base && srec.reclen >= 3)
if(!avr_sig_compatible(p->signature, any->buf+nextaddr)) {
pmsg_error("signature of %s incompatible with file's (%s);\n", p->desc,
str_ccmcunames_signature(any->buf+nextaddr, PM_ALL));
imsg_error("use -F to override this check\n");
mmt_free(buffer);
goto error;
}
if(srec.reclen && nextaddr+srec.reclen > maxaddr)
maxaddr = nextaddr+srec.reclen;
reccount++;
}
@@ -719,11 +946,20 @@ static int srec2b(const char *infile, FILE * inf,
if(errstr) {
pmsg_error("read error in Motorola S-Record file %s: %s\n", infile, errstr);
return -1;
goto error;
}
pmsg_warning("no end of file record found for Motorola S-Records file %s\n", infile);
return maxaddr;
done:
rc = any2mem(p, mem, segp, any, maxaddr);
avr_free_mem(any);
if(!rc)
pmsg_warning("no %s data found in Motorola S-Record file %s\n", mem->desc, infile);
return rc;
error:
avr_free_mem(any);
return -1;
}
@@ -740,8 +976,7 @@ static int srec2b(const char *infile, FILE * inf,
* the entire ELF file "as is" (including things like the program
* header table itself).
*/
static inline
int is_section_in_segment(Elf32_Shdr *sh, Elf32_Phdr *ph)
static inline int is_section_in_segment(Elf32_Shdr *sh, Elf32_Phdr *ph)
{
if (sh->sh_offset < ph->p_offset)
return 0;
@@ -768,32 +1003,36 @@ static int elf_mem_limits(const AVRMEM *mem, const AVRPART *p,
}
} else {
if (mem_is_in_flash(mem)) {
*lowbound = 0;
*highbound = 0x7Fffff; // Max 8 MiB
*lowbound = MBASE(FLASH);
*highbound = MEND(FLASH); // Max 8 MiB
*fileoff = 0;
} else if (mem_is_io(mem) || mem_is_sram(mem)) { // IO & SRAM in data space
*lowbound = 0x800000 + mem->offset;
*highbound = 0x80ffff;
*lowbound = MBASE(DATA) + mem->offset;
*highbound = MEND(DATA);
*fileoff = 0;
} else if (mem_is_eeprom(mem)) {
*lowbound = 0x810000;
*highbound = 0x81ffff; // Max 64 KiB
*lowbound = MBASE(EEPROM);
*highbound = MEND(EEPROM); // Max 64 KiB
*fileoff = 0;
} else if (mem_is_a_fuse(mem) || mem_is_fuses(mem)) {
*lowbound = 0x820000;
*highbound = 0x82ffff;
*lowbound = MBASE(FUSES);
*highbound = MEND(FUSES);
*fileoff = mem_is_a_fuse(mem)? mem_fuse_offset(mem): 0;
} else if (mem_is_lock(mem)) { // Lock or lockbits
*lowbound = 0x830000;
*highbound = 0x83ffff;
*lowbound = MBASE(LOCK);
*highbound = MEND(LOCK);
*fileoff = 0;
} else if (mem_is_signature(mem)) { // Read only
*lowbound = 0x840000;
*highbound = 0x84ffff;
*lowbound = MBASE(SIGROW);
*highbound = MEND(SIGROW);
*fileoff = 0;
} else if (mem_is_userrow(mem)) { // usersig or userrow
*lowbound = 0x850000;
*highbound = 0x85ffff;
*lowbound = MBASE(USERROW);
*highbound = MEND(USERROW);
*fileoff = 0;
} else if (mem_is_bootrow(mem)) {
*lowbound = MBASE(BOOTROW);
*highbound = MEND(BOOTROW);
*fileoff = 0;
} else {
rv = -1;
@@ -806,7 +1045,7 @@ static int elf_mem_limits(const AVRMEM *mem, const AVRPART *p,
// ELF format to binary (the memory segment to read into is ignored)
static int elf2b(const char *infile, FILE *inf, const AVRMEM *mem,
const AVRPART *p, const Segment_t *segp_unused, unsigned int fileoffset_unused) {
const AVRPART *p, const Segment *segp_unused, unsigned int fileoffset_unused) {
Elf *e;
int rv = 0, size = 0;
@@ -857,16 +1096,16 @@ static int elf2b(const char *infile, FILE *inf, const AVRMEM *mem,
}
const char *endianname;
unsigned char endianess;
unsigned char endianness;
if (p->prog_modes & PM_aWire) { // AVR32
endianess = ELFDATA2MSB;
endianness = ELFDATA2MSB;
endianname = "little";
} else {
endianess = ELFDATA2LSB;
endianness = ELFDATA2LSB;
endianname = "big";
}
if (id[EI_CLASS] != ELFCLASS32 ||
id[EI_DATA] != endianess) {
id[EI_DATA] != endianness) {
pmsg_error("ELF file %s is not a 32-bit, %s-endian file that was expected\n",
infile, endianname);
goto done;
@@ -921,8 +1160,8 @@ static int elf2b(const char *infile, FILE *inf, const AVRMEM *mem,
if (ph[i].p_type != PT_LOAD || ph[i].p_filesz == 0)
continue;
pmsg_notice2("considering PT_LOAD program header entry #%d\n", (int) i);
imsg_notice2("p_vaddr 0x%x, p_paddr 0x%x, p_filesz %d\n", ph[i].p_vaddr, ph[i].p_paddr, ph[i].p_filesz);
pmsg_debug("considering PT_LOAD program header entry #%d\n", (int) i);
imsg_debug("p_vaddr 0x%x, p_paddr 0x%x, p_filesz %d\n", ph[i].p_vaddr, ph[i].p_paddr, ph[i].p_filesz);
Elf_Scn *scn = NULL;
while ((scn = elf_nextscn(e, scn)) != NULL) {
@@ -947,10 +1186,10 @@ static int elf2b(const char *infile, FILE *inf, const AVRMEM *mem,
const char *sname = sndx? elf_strptr(e, sndx, sh->sh_name): "*unknown*";
unsigned int lma = ph[i].p_paddr + sh->sh_offset - ph[i].p_offset;
pmsg_notice2("found section %s, LMA 0x%x, sh_size %u\n", sname, lma, sh->sh_size);
pmsg_debug("found section %s, LMA 0x%x, sh_size %u\n", sname, lma, sh->sh_size);
if(!(lma >= low && lma + sh->sh_size < high)) {
imsg_notice2("skipping %s (inappropriate for %s)\n", sname, mem->desc);
pmsg_debug("skipping %s (inappropriate for %s)\n", sname, mem->desc);
continue;
}
/*
@@ -970,7 +1209,7 @@ static int elf2b(const char *infile, FILE *inf, const AVRMEM *mem,
Elf_Data *d = NULL;
while ((d = elf_getdata(scn, d)) != NULL) {
imsg_notice2("data block: d_buf %p, d_off 0x%x, d_size %ld\n",
pmsg_debug("data block: d_buf %p, d_off 0x%x, d_size %ld\n",
d->d_buf, (unsigned int)d->d_off, (long) d->d_size);
if (mem->size == 1) {
if (d->d_off != 0) {
@@ -980,7 +1219,7 @@ static int elf2b(const char *infile, FILE *inf, const AVRMEM *mem,
pmsg_error("ELF file section does not contain byte at offset %d\n", foff);
rv = -1;
} else {
imsg_notice2("extracting one byte from file offset %d\n", foff);
pmsg_debug("extracting one byte from file offset %d\n", foff);
mem->buf[0] = ((unsigned char *)d->d_buf)[foff];
mem->tags[0] = TAG_ALLOCATED;
size = 1;
@@ -992,7 +1231,7 @@ static int elf2b(const char *infile, FILE *inf, const AVRMEM *mem,
if(idx >= 0 && idx < mem->size && end >= 0 && end <= mem->size && end-idx >= 0) {
if (end > size)
size = end;
imsg_debug("writing %d bytes to mem offset 0x%x\n", end-idx, idx);
pmsg_debug("writing %d bytes to mem offset 0x%x\n", end-idx, idx);
memcpy(mem->buf + idx, d->d_buf, end-idx);
memset(mem->tags + idx, TAG_ALLOCATED, end-idx);
} else {
@@ -1013,7 +1252,7 @@ done:
// Read/write binary files and return highest memory addr set + 1
static int fileio_rbin(struct fioparms *fio, const char *filename, FILE *f,
const AVRMEM *mem, const Segment_t *segp) {
const AVRMEM *mem, const Segment *segp) {
int rc;
switch (fio->op) {
@@ -1041,7 +1280,7 @@ static int fileio_rbin(struct fioparms *fio, const char *filename, FILE *f,
static int fileio_imm(struct fioparms *fio, const char *fname, FILE *f_unused,
const AVRMEM *mem, const Segment_t *segp) {
const AVRMEM *mem, const Segment *segp) {
char *tok, *p, *line;
const char *errstr;
@@ -1080,17 +1319,17 @@ static int fileio_imm(struct fioparms *fio, const char *fname, FILE *f_unused,
static int fileio_ihex(struct fioparms *fio, const char *filename, FILE *f,
const AVRMEM *mem, const Segment_t *segp, FILEFMT ffmt, Segorder_t where) {
const AVRPART *p, const AVRMEM *mem, const Segment *segp, FILEFMT ffmt, Segorder where) {
int rc;
switch (fio->op) {
case FIO_WRITE:
rc = b2ihex(mem->buf, segp, where, 32, fio->fileoffset, filename, f, ffmt);
rc = b2ihex(p, mem, segp, where, 32, fio->fileoffset, filename, f, ffmt);
break;
case FIO_READ:
rc = ihex2b(filename, f, mem, segp, fio->fileoffset, ffmt);
rc = ihex2b(filename, f, p, mem, segp, fio->fileoffset, ffmt);
break;
default:
@@ -1103,7 +1342,7 @@ static int fileio_ihex(struct fioparms *fio, const char *filename, FILE *f,
static int fileio_srec(struct fioparms *fio, const char *filename, FILE *f,
const AVRMEM *mem, const Segment_t *segp, Segorder_t where) {
const AVRPART* p, const AVRMEM *mem, const Segment *segp, Segorder where) {
int rc;
@@ -1113,7 +1352,7 @@ static int fileio_srec(struct fioparms *fio, const char *filename, FILE *f,
break;
case FIO_READ:
rc = srec2b(filename, f, mem, segp, fio->fileoffset);
rc = srec2b(filename, f, p, mem, segp, fio->fileoffset);
break;
default:
@@ -1127,7 +1366,7 @@ static int fileio_srec(struct fioparms *fio, const char *filename, FILE *f,
#ifdef HAVE_LIBELF
static int fileio_elf(struct fioparms *fio, const char *filename, FILE *f,
const AVRMEM *mem, const AVRPART *p, const Segment_t *segp) {
const AVRMEM *mem, const AVRPART *p, const Segment *segp) {
int rc;
@@ -1151,7 +1390,7 @@ static int fileio_elf(struct fioparms *fio, const char *filename, FILE *f,
#endif
static int b2num(const char *filename, FILE *f, const AVRMEM *mem, const Segment_t *segp, FILEFMT fmt) {
static int b2num(const char *filename, FILE *f, const AVRMEM *mem, const Segment *segp, FILEFMT fmt) {
const char *prefix;
int base;
@@ -1215,7 +1454,7 @@ static int b2num(const char *filename, FILE *f, const AVRMEM *mem, const Segment
}
static int num2b(const char *filename, FILE *f, const AVRMEM *mem, const Segment_t *segp) {
static int num2b(const char *filename, FILE *f, const AVRMEM *mem, const Segment *segp) {
const char *geterr = NULL;
char *line;
int n = segp->addr, end = segp->addr + segp->len;
@@ -1251,7 +1490,7 @@ static int num2b(const char *filename, FILE *f, const AVRMEM *mem, const Segment
static int fileio_num(struct fioparms *fio, const char *filename, FILE *f,
const AVRMEM *mem, const Segment_t *segp, FILEFMT fmt) {
const AVRMEM *mem, const Segment *segp, FILEFMT fmt) {
switch (fio->op) {
case FIO_WRITE:
@@ -1410,6 +1649,16 @@ int fileio_fmt_autodetect(const char *fname) {
}
int fileio_mem(int op, const char *filename, FILEFMT format,
const AVRPART *p, const AVRMEM *mem, int size) {
if(size < 0 || op == FIO_READ || op == FIO_READ_FOR_VERIFY)
size = mem->size;
const Segment seg = {0, size};
return fileio_segments(op, filename, format, p, mem, 1, &seg);
}
int fileio(int op, const char *filename, FILEFMT format,
const AVRPART *p, const char *memstr, int size) {
@@ -1420,16 +1669,12 @@ int fileio(int op, const char *filename, FILEFMT format,
return -1;
}
if(size < 0 || op == FIO_READ || op == FIO_READ_FOR_VERIFY)
size = mem->size;
const Segment_t seg = {0, size};
return fileio_segments(op, filename, format, p, mem, 1, &seg);
return fileio_mem(op, filename, format, p, mem, size);
}
// Normalise segment address and length to be non-negative
int segment_normalise(const AVRMEM *mem, Segment_t *segp) {
int segment_normalise(const AVRMEM *mem, Segment *segp) {
int addr = segp->addr, len = segp->len, maxsize = mem->size;
int digits = maxsize > 0x10000? 5: 4;
@@ -1459,7 +1704,7 @@ int segment_normalise(const AVRMEM *mem, Segment_t *segp) {
static int fileio_segments_normalise(int oprwv, const char *filename, FILEFMT format,
const AVRPART *p, const AVRMEM *mem, int n, Segment_t *seglist) {
const AVRPART *p, const AVRMEM *mem, int n, Segment *seglist) {
int op, rc;
FILE * f;
@@ -1489,7 +1734,7 @@ static int fileio_segments_normalise(int oprwv, const char *filename, FILEFMT fo
int format_detect;
if (using_stdio) {
pmsg_error("cannot auto detect file format when using stdin/out\n");
pmsg_error("cannot auto detect file format when using stdin/out;\n");
imsg_error("please specify a file format and try again\n");
return -1;
}
@@ -1541,10 +1786,8 @@ static int fileio_segments_normalise(int oprwv, const char *filename, FILEFMT fo
if(fio.op == FIO_READ) // Fill unspecified memory in segment
memset(mem->buf+addr, 0xff, len);
memset(mem->tags+addr, 0, len);
Segorder_t where = 0;
if(i == 0)
where |= FIRST_SEG;
Segorder where = i == 0? FIRST_SEG: 0;
if(i+1 == n)
where |= LAST_SEG;
@@ -1552,11 +1795,11 @@ static int fileio_segments_normalise(int oprwv, const char *filename, FILEFMT fo
switch(format) {
case FMT_IHEX:
case FMT_IHXC:
thisrc = fileio_ihex(&fio, fname, f, mem, seglist+i, format, where);
thisrc = fileio_ihex(&fio, fname, f, p, mem, seglist+i, format, where);
break;
case FMT_SREC:
thisrc = fileio_srec(&fio, fname, f, mem, seglist+i, where);
thisrc = fileio_srec(&fio, fname, f, p, mem, seglist+i, where);
break;
case FMT_RBIN:
@@ -1610,9 +1853,9 @@ static int fileio_segments_normalise(int oprwv, const char *filename, FILEFMT fo
}
int fileio_segments(int oprwv, const char *filename, FILEFMT format,
const AVRPART *p, const AVRMEM *mem, int n, const Segment_t *list) {
const AVRPART *p, const AVRMEM *mem, int n, const Segment *list) {
Segment_t *seglist = mmt_malloc(n*sizeof*seglist);
Segment *seglist = mmt_malloc(n*sizeof*seglist);
memcpy(seglist, list, n*sizeof*seglist);
int ret = fileio_segments_normalise(oprwv, filename, format, p, mem, n, seglist);
mmt_free(seglist);

View File

@@ -19,8 +19,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#include <ac_cfg.h>
#include <stdint.h>
@@ -240,7 +238,7 @@ static int flip1_initialize(const PROGRAMMER *pgm, const AVRPART *part) {
}
if (!ovsigck && (part->prog_modes & PM_PDI)) {
pmsg_error("flip1 (FLIP protocol version 1) is for AT90USB* and ATmega*U* devices\n");
imsg_error("for Xmega devices, use flip2 (or use -F to bypass this check)\n");
imsg_error("for Xmega devices, use flip2 or use -F to bypass this check\n");
return -1;
}
@@ -336,7 +334,7 @@ static int flip1_chip_erase(const PROGRAMMER *pgm, const AVRPART *part) {
int aux_result;
unsigned int default_timeout = FLIP1(pgm)->dfu->timeout;
pmsg_notice2("flip_chip_erase()\n");
pmsg_debug("flip_chip_erase()\n");
struct flip1_cmd cmd = {
FLIP1_CMD_WRITE_COMMAND, { 0, 0xff }
@@ -471,7 +469,7 @@ static int flip1_paged_write(const PROGRAMMER *pgm, const AVRPART *part, const A
}
static int flip1_read_sig_bytes(const PROGRAMMER *pgm, const AVRPART *part, const AVRMEM *mem) {
pmsg_notice2("flip1_read_sig_bytes(): ");
pmsg_debug("%s(): ", __func__);
if (FLIP1(pgm)->dfu == NULL)
return -1;
@@ -494,7 +492,7 @@ static int flip1_read_sig_bytes(const PROGRAMMER *pgm, const AVRPART *part, cons
FLIP1_CMD_READ_COMMAND, FLIP1_READ_FAMILY_CODE
};
msg_notice2("from device\n");
msg_debug("from device\n");
for (i = 0; i < 3; i++)
{
@@ -534,7 +532,7 @@ static int flip1_read_sig_bytes(const PROGRAMMER *pgm, const AVRPART *part, cons
}
else
{
msg_notice2("cached\n");
msg_debug("cached\n");
}
memcpy(mem->buf, FLIP1(pgm)->part_sig, sizeof(FLIP1(pgm)->part_sig));
@@ -573,7 +571,7 @@ static int flip1_read_memory(const PROGRAMMER *pgm,
unsigned int default_timeout = dfu->timeout;
pmsg_notice2("flip_read_memory(%s, 0x%04x, %d)\n", flip1_mem_unit_str(mem_unit), addr, size);
pmsg_debug("flip_read_memory(%s, 0x%04x, %d)\n", flip1_mem_unit_str(mem_unit), addr, size);
/*
* As this function is called once per page, no need to handle 64
@@ -615,14 +613,8 @@ static int flip1_read_memory(const PROGRAMMER *pgm,
if (cmd_result < 0 && aux_result == 0 &&
status.bStatus == DFU_STATUS_ERR_WRITE) {
if (FLIP1(pgm)->security_mode_flag == 0) {
msg_error("\n");
pmsg_error("\n");
imsg_error("***********************************************************************\n");
imsg_error("Maybe the device is in ``security mode´´, and needs a chip erase first?\n");
imsg_error("***********************************************************************\n");
msg_error("\n");
}
if (FLIP1(pgm)->security_mode_flag == 0)
pmsg_error("maybe the device is in security mode and needs a chip erase first?\n");
FLIP1(pgm)->security_mode_flag = 1;
}
@@ -664,7 +656,7 @@ static int flip1_write_memory(struct dfu_dev *dfu,
unsigned int default_timeout = dfu->timeout;
unsigned char *buf;
pmsg_notice2("flip_write_memory(%s, 0x%04x, %d)\n",
pmsg_debug("flip_write_memory(%s, 0x%04x, %d)\n",
flip1_mem_unit_str(mem_unit), addr, size);
if (size < 32) {
@@ -764,7 +756,7 @@ static int flip1_set_mem_page(struct dfu_dev *dfu, unsigned short page_addr) {
}
static const char *flip1_status_str(const struct dfu_status *status) {
static const char *msg[] = {
static const char * const msg[] = {
"No error condition is present",
"File is not targeted for use by this device",
"File is for this device but fails some vendor-specific verification test",

View File

@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#ifndef flip1_h
#define flip1_h

View File

@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#include <ac_cfg.h>
#include <stdint.h>
@@ -232,9 +230,8 @@ static int flip2_initialize(const PROGRAMMER *pgm, const AVRPART *part) {
}
if (!ovsigck && !(part->prog_modes & PM_PDI)) {
pmsg_error("flip2 (FLIP protocol version 2) is for Xmega devices\n");
imsg_error("for AT90USB* or ATmega*U* devices, use flip1\n");
imsg_error("(or use -F to bypass this check)\n");
pmsg_error("flip2 (FLIP protocol version 2) is for Xmega devices;\n");
imsg_error("for AT90USB* or ATmega*U* devices use flip1 or use -F to bypass this check\n");
return -1;
}
@@ -336,7 +333,7 @@ static int flip2_chip_erase(const PROGRAMMER *pgm, const AVRPART *part) {
int cmd_result = 0;
int aux_result;
pmsg_notice2("flip_chip_erase()\n");
pmsg_debug("flip_chip_erase()\n");
struct flip2_cmd cmd = {
FLIP2_CMD_GROUP_EXEC, FLIP2_CMD_CHIP_ERASE, { 0xFF, 0, 0, 0 }
@@ -494,6 +491,8 @@ static int flip2_paged_write(const PROGRAMMER *pgm, const AVRPART *part, const A
// Parse the -E option flag
static int flip2_parseexitspecs(PROGRAMMER *pgm, const char *sp) {
char *cp, *s, *str = mmt_strdup(sp);
int rv = 0;
bool help = false;
s = str;
while ((cp = strtok(s, ","))) {
@@ -506,12 +505,25 @@ static int flip2_parseexitspecs(PROGRAMMER *pgm, const char *sp) {
pgm->exit_reset = EXIT_RESET_DISABLED;
continue;
}
if (str_eq(cp, "help")) {
help = true;
rv = LIBAVRDUDE_EXIT;
}
if (!help) {
pmsg_error("invalid exitspec parameter -E %s\n", cp);
rv = -1;
}
msg_error("%s -c %s exitspec parameter options:\n", progname, pgmid);
msg_error(" -E reset Application will not start automatically after programming session\n");
msg_error(" -E noreset Application will start automatically after programming session\n");
msg_error(" -E help Show this help menu and exit\n");
mmt_free(str);
return -1;
return rv;
}
mmt_free(str);
return 0;
return rv;
}
static int flip2_read_sig_bytes(const PROGRAMMER *pgm, const AVRPART *part, const AVRMEM *mem) {
@@ -555,9 +567,9 @@ static void flip2_show_info(struct flip2 *flip2) {
(char) (flip2->part_rev / 26 - 1 + 'A'),
(char) (flip2->part_rev % 26 + 'A'));
msg_info(" Bootloader version : 2.%hu.%hu\n",
((unsigned short) flip2->boot_ver >> 4) & 0xF,
((unsigned short) flip2->boot_ver >> 0) & 0xF);
msg_info(" Bootloader version : 2.%u.%u\n",
(flip2->boot_ver >> 4) & 0xF,
(flip2->boot_ver >> 0) & 0xF);
msg_info(" USB max packet size : %hu\n",
(unsigned short) flip2->dfu->dev_desc.bMaxPacketSize0);
@@ -572,7 +584,7 @@ static int flip2_read_memory(struct dfu_dev *dfu,
int read_size;
int result;
pmsg_notice2("flip_read_memory(%s, 0x%04x, %d)\n", flip2_mem_unit_str(mem_unit), addr, size);
pmsg_debug("flip_read_memory(%s, 0x%04x, %d)\n", flip2_mem_unit_str(mem_unit), addr, size);
result = flip2_set_mem_unit(dfu, mem_unit);
@@ -629,7 +641,7 @@ static int flip2_write_memory(struct dfu_dev *dfu,
int write_size;
int result;
pmsg_notice2("flip_write_memory(%s, 0x%04x, %d)\n", flip2_mem_unit_str(mem_unit), addr, size);
pmsg_debug("flip_write_memory(%s, 0x%04x, %d)\n", flip2_mem_unit_str(mem_unit), addr, size);
result = flip2_set_mem_unit(dfu, mem_unit);
@@ -778,7 +790,7 @@ flip2_read_max1k_status:
if (status.bStatus == ((FLIP2_STATUS_OUTOFRANGE >> 8) & 0xFF) &&
status.bState == ((FLIP2_STATUS_OUTOFRANGE >> 0) & 0xFF))
{
pmsg_error("address out of range [0x%04hX,0x%04hX]\n", offset, offset+size-1);
pmsg_error("address out of range [0x%04X,0x%04X]\n", offset, (offset+size-1) & 0xffff);
} else
pmsg_error("DFU status %s\n", flip2_status_str(&status));
dfu_clrstatus(dfu);
@@ -836,7 +848,7 @@ static int flip2_write_max1k(struct dfu_dev *dfu,
if (status.bStatus == ((FLIP2_STATUS_OUTOFRANGE >> 8) & 0xFF) &&
status.bState == ((FLIP2_STATUS_OUTOFRANGE >> 0) & 0xFF))
{
pmsg_error("address out of range [0x%04hX,0x%04hX]\n", offset, offset+size-1);
pmsg_error("address out of range [0x%04X,0x%04X]\n", offset, (offset+size-1) & 0xffff);
} else
pmsg_error("DFU status %s\n", flip2_status_str(&status));
dfu_clrstatus(dfu);

View File

@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#ifndef flip2_h
#define flip2_h

View File

@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#ifndef freebsd_ppi_h
#define freebsd_ppi_h

View File

@@ -1,6 +1,6 @@
/*
* AVRDUDE - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2003-2004 Theodore A. Roth <troth@openavr.org>
* Copyright (C) 2003-2004 Theodore A. Roth <troth@openavr.org>
* some code:
* Copyright (C) 2011-2012 Roger E. Wolff <R.E.Wolff@BitWizard.nl>
*
@@ -19,8 +19,6 @@
*/
/* $Id$ */
/* ft245r -- FT245R/FT232R Synchronous BitBangMode Programmer
default pin assign
FT232R / FT245R
@@ -236,7 +234,7 @@ static int ft245r_flush(const PROGRAMMER *pgm) {
avail = len;
#if FT245R_DEBUG
msg_info("%s: writing %d bytes\n", __func__, avail);
msg_notice("%s: writing %d bytes\n", __func__, avail);
#endif
rv = ftdi_write_data(my.handle, src, avail);
if (rv != avail) {
@@ -279,7 +277,7 @@ static int ft245r_recv(const PROGRAMMER *pgm, unsigned char *buf, size_t len) {
ft245r_fill(pgm);
#if FT245R_DEBUG
msg_info("%s: discarding %d, consuming %lu bytes\n", __func__, my.rx.discard, (unsigned long) len);
msg_notice("%s: discarding %d, consuming %lu bytes\n", __func__, my.rx.discard, (unsigned long) len);
#endif
while (my.rx.discard > 0) {
int result = ft245r_rx_buf_fill_and_get(pgm);
@@ -378,7 +376,7 @@ static int ft245r_set_bitclock(const PROGRAMMER *pgm) {
r = ftdi_set_baudrate(my.handle, ftdi_rate);
if (r) {
msg_error("set baudrate %d failed with error '%s'\n", rate, ftdi_get_error_string (my.handle));
msg_error("setting baudrate %d failed with error %s\n", rate, ftdi_get_error_string (my.handle));
return -1;
}
return 0;
@@ -392,7 +390,7 @@ static int get_pin(const PROGRAMMER *pgm, int pinname) {
if (ftdi_read_pins(my.handle, &byte) != 0)
return -1;
if (FT245R_DEBUG)
msg_info("%s: in 0x%02x\n", __func__, byte);
msg_notice("%s: in 0x%02x\n", __func__, byte);
return GET_BITS_0(byte, pgm, pinname) != 0;
}
@@ -790,23 +788,23 @@ static int ft245r_cmd_tpi(const PROGRAMMER *pgm, const unsigned char *cmd,
for (i = 0; i < res_len; ++i)
if ((ret = ft245r_tpi_rx(pgm, &res[i])) < 0)
break;
if (verbose >= 2) {
msg_notice2("%s: [ ", __func__);
if (verbose >= MSG_DEBUG) {
msg_debug("%s: [ ", __func__);
for (i = 0; i < cmd_len; i++)
msg_notice2("%02X ", cmd[i]);
msg_notice2("] [ ");
msg_debug("%02X ", cmd[i]);
msg_debug("] [ ");
for(i = 0; i < res_len; i++)
msg_notice2("%02X ", res[i]);
msg_notice2("]\n");
msg_debug("%02X ", res[i]);
msg_debug("]\n");
}
return ret;
}
/* lower 8 pins are accepted, they might be also inverted */
static const struct pindef_t valid_pins = {{0xff}, {0xff}} ;
static const struct pindef valid_pins = {{0xff}, {0xff}};
static const struct pin_checklist_t pin_checklist[] = {
static const Pin_checklist pin_checklist[] = {
{ PIN_AVR_SCK, 1, &valid_pins},
{ PIN_AVR_SDO, 1, &valid_pins},
{ PIN_AVR_SDI, 1, &valid_pins},
@@ -830,12 +828,12 @@ static int ft245r_open(PROGRAMMER *pgm, const char *port) {
// read device string cut after 8 chars (max. length of serial number)
if ((sscanf(port, "usb:%8s", device) != 1)) {
pmsg_notice("ft245r_open(): no device identifier in portname, using default\n");
pmsg_notice("%s(): no device identifier in portname, using default\n", __func__);
pgm->usbsn = cache_string("");
devnum = 0;
} else {
if (strlen(device) == 8 ){ // serial number
pmsg_notice2("ft245r_open(): serial number parsed as: %s\n", device);
pmsg_notice2("%s(): serial number parsed as: %s\n", __func__, device);
// copy serial number to pgm struct
pgm->usbsn = cache_string(device);
// and use first device with matching serial (should be unique)
@@ -848,13 +846,13 @@ static int ft245r_open(PROGRAMMER *pgm, const char *port) {
if ((startptr==endptr) || (*endptr != '\0')) {
devnum = -1;
}
pmsg_notice2("ft245r_open(): device number parsed as: %d\n", devnum);
pmsg_notice2("%s(): device number parsed as: %d\n", __func__, devnum);
}
}
// if something went wrong before abort with helpful message
if (devnum < 0) {
pmsg_error("invalid portname '%s': use^ 'ft[0-9]+' or serial number\n", port);
pmsg_error("invalid port name %s: use ft[0-9]+ or serial number\n", port);
return -1;
}

View File

@@ -1,6 +1,7 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2012 Joerg Wunsch <j@uriah.heep.sax.de>
* Copyright (C) 2017 Jan Egil Ruud <janegil.ruud@microchip.com>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -17,8 +18,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
/*
* avrdude interface for Atmel JTAGICE3 programmer
*/
@@ -206,7 +205,7 @@ static void jtag3_print_data(unsigned char *b, size_t s) {
}
static void jtag3_prmsg(const PROGRAMMER *pgm, unsigned char *data, size_t len) {
if (verbose >= 4) {
if (verbose >= MSG_TRACE) {
size_t i;
msg_trace("Raw message:\n");
@@ -336,7 +335,7 @@ static int jtag3_errcode(int reason) {
}
static void jtag3_prevent(const PROGRAMMER *pgm, unsigned char *data, size_t len) {
if (verbose >= 4) {
if (verbose >= MSG_TRACE) {
size_t i;
msg_trace("Raw event:\n");
@@ -430,7 +429,7 @@ int jtag3_send(const PROGRAMMER *pgm, unsigned char *data, size_t len) {
return jtag3_edbg_send(pgm, data, len);
msg_debug("\n");
pmsg_debug("jtag3_send(): sending %lu bytes\n", (unsigned long) len);
pmsg_debug("%s(): sending %lu bytes\n", __func__, (unsigned long) len);
buf = mmt_malloc(len + 4);
buf[0] = TOKEN;
@@ -454,20 +453,20 @@ static int jtag3_edbg_send(const PROGRAMMER *pgm, unsigned char *data, size_t le
unsigned char status[USBDEV_MAX_XFER_3];
int rv;
if (verbose >= 4) {
if (verbose >= MSG_TRACE) {
memset(buf, 0, USBDEV_MAX_XFER_3);
memset(status, 0, USBDEV_MAX_XFER_3);
}
msg_debug("\n");
pmsg_debug("jtag3_edbg_send(): sending %lu bytes\n", (unsigned long) len);
pmsg_debug("%s(): sending %lu bytes\n", __func__, (unsigned long) len);
/* 4 bytes overhead for CMD, fragment #, and length info */
int max_xfer = pgm->fd.usb.max_xfer;
int nfragments = (len + max_xfer - 1) / max_xfer;
if (nfragments > 1) {
pmsg_debug("jtag3_edbg_send(): fragmenting into %d packets\n", nfragments);
pmsg_debug("%s(): fragmenting into %d packets\n", __func__, nfragments);
}
int frag;
for (frag = 0; frag < nfragments; frag++) {
@@ -505,20 +504,20 @@ static int jtag3_edbg_send(const PROGRAMMER *pgm, unsigned char *data, size_t le
}
if (serial_send(&pgm->fd, buf, max_xfer) != 0) {
pmsg_notice("jtag3_edbg_send(): unable to send command to serial port\n");
pmsg_notice("%s(): unable to send command to serial port\n", __func__);
return -1;
}
rv = serial_recv(&pgm->fd, status, max_xfer);
if (rv < 0) {
/* timeout in receive */
pmsg_notice2("jtag3_edbg_send(): timeout receiving packet\n");
pmsg_notice2("%s(): timeout receiving packet\n", __func__);
return -1;
}
if (status[0] != EDBG_VENDOR_AVR_CMD ||
(frag == nfragments - 1 && status[1] != 0x01)) {
/* what to do in this case? */
pmsg_notice("jtag3_edbg_send(): unexpected response 0x%02x, 0x%02x\n", status[0], status[1]);
pmsg_notice("%s(): unexpected response 0x%02x, 0x%02x\n", __func__, status[0], status[1]);
}
data += this_len;
len -= this_len;
@@ -538,7 +537,7 @@ static int jtag3_edbg_prepare(const PROGRAMMER *pgm) {
msg_debug("\n");
pmsg_debug("jtag3_edbg_prepare()\n");
if (verbose >= 4)
if (verbose >= MSG_TRACE)
memset(buf, 0, USBDEV_MAX_XFER_3);
buf[0] = CMSISDAP_CMD_CONNECT;
@@ -555,7 +554,7 @@ static int jtag3_edbg_prepare(const PROGRAMMER *pgm) {
if (status[0] != CMSISDAP_CMD_CONNECT ||
status[1] == 0)
pmsg_error("unexpected response 0x%02x, 0x%02x\n", status[0], status[1]);
pmsg_notice2("jtag3_edbg_prepare(): connection status 0x%02x\n", status[1]);
pmsg_notice2("%s(): connection status 0x%02x\n", __func__, status[1]);
buf[0] = CMSISDAP_CMD_LED;
buf[1] = CMSISDAP_LED_CONNECT;
@@ -588,38 +587,38 @@ static int jtag3_edbg_signoff(const PROGRAMMER *pgm) {
msg_debug("\n");
pmsg_debug("jtag3_edbg_signoff()\n");
if (verbose >= 4)
if (verbose >= MSG_TRACE)
memset(buf, 0, USBDEV_MAX_XFER_3);
buf[0] = CMSISDAP_CMD_LED;
buf[1] = CMSISDAP_LED_CONNECT;
buf[2] = 0;
if (serial_send(&pgm->fd, buf, pgm->fd.usb.max_xfer) != 0) {
pmsg_notice("jtag3_edbg_signoff(): unable to send command to serial port\n");
pmsg_notice("%s(): unable to send command to serial port\n", __func__);
return -1;
}
rv = serial_recv(&pgm->fd, status, pgm->fd.usb.max_xfer);
if (rv != pgm->fd.usb.max_xfer) {
pmsg_notice("jtag3_edbg_signoff(): unable to read from serial port (%d)\n", rv);
pmsg_notice("%s(): unable to read from serial port (%d)\n", __func__, rv);
return -1;
}
if (status[0] != CMSISDAP_CMD_LED ||
status[1] != 0)
pmsg_notice("jtag3_edbg_signoff(): unexpected response 0x%02x, 0x%02x\n", status[0], status[1]);
pmsg_notice("%s(): unexpected response 0x%02x, 0x%02x\n", __func__, status[0], status[1]);
buf[0] = CMSISDAP_CMD_DISCONNECT;
if (serial_send(&pgm->fd, buf, pgm->fd.usb.max_xfer) != 0) {
pmsg_notice("jtag3_edbg_signoff(): unable to send command to serial port\n");
pmsg_notice("%s(): unable to send command to serial port\n", __func__);
return -1;
}
rv = serial_recv(&pgm->fd, status, pgm->fd.usb.max_xfer);
if (rv != pgm->fd.usb.max_xfer) {
pmsg_notice("jtag3_edbg_signoff(): unable to read from serial port (%d)\n", rv);
pmsg_notice("%s(): unable to read from serial port (%d)\n", __func__, rv);
return -1;
}
if (status[0] != CMSISDAP_CMD_DISCONNECT ||
status[1] != 0)
pmsg_notice("jtag3_edbg_signoff(): unexpected response 0x%02x, 0x%02x\n", status[0], status[1]);
pmsg_notice("%s(): unexpected response 0x%02x, 0x%02x\n", __func__, status[0], status[1]);
return 0;
}
@@ -651,7 +650,7 @@ static int jtag3_recv_frame(const PROGRAMMER *pgm, unsigned char **msg) {
rv = serial_recv(&pgm->fd, buf, pgm->fd.usb.max_xfer);
if (rv < 0) {
pmsg_notice2("jtag3_recv_frame(): timeout receiving packet\n");
pmsg_notice2("%s(): timeout receiving packet\n", __func__);
mmt_free(buf);
return -1;
}
@@ -680,7 +679,7 @@ static int jtag3_edbg_recv_frame(const PROGRAMMER *pgm, unsigned char **msg) {
request[0] = EDBG_VENDOR_AVR_RSP;
if (serial_send(&pgm->fd, request, pgm->fd.usb.max_xfer) != 0) {
pmsg_notice("jtag3_edbg_recv(): unable to send CMSIS-DAP vendor command\n");
pmsg_notice("%s(): unable to send CMSIS-DAP vendor command\n", __func__);
mmt_free(request);
mmt_free(*msg);
return -1;
@@ -690,14 +689,14 @@ static int jtag3_edbg_recv_frame(const PROGRAMMER *pgm, unsigned char **msg) {
if (rv < 0) {
/* timeout in receive */
pmsg_notice2("jtag3_edbg_recv(): timeout receiving packet\n");
pmsg_notice2("%s(): timeout receiving packet\n", __func__);
mmt_free(*msg);
mmt_free(request);
return -1;
}
if (buf[0] != EDBG_VENDOR_AVR_RSP) {
pmsg_notice("jtag3_edbg_recv(): unexpected response 0x%02x\n", buf[0]);
pmsg_notice("%s(): unexpected response 0x%02x\n", __func__, buf[0]);
mmt_free(*msg);
mmt_free(request);
return -1;
@@ -707,7 +706,7 @@ static int jtag3_edbg_recv_frame(const PROGRAMMER *pgm, unsigned char **msg) {
// Documentation says:
// "FragmentInfo 0x00 indicates that no response data is
// available, and the rest of the packet is ignored."
pmsg_notice("jtag3_edbg_recv(): no response available\n");
pmsg_notice("%s(): no response available\n", __func__);
mmt_free(*msg);
mmt_free(request);
return -1;
@@ -720,8 +719,7 @@ static int jtag3_edbg_recv_frame(const PROGRAMMER *pgm, unsigned char **msg) {
thisfrag = 1;
} else {
if (nfrags != (buf[1] & 0x0F)) {
pmsg_notice("jtag3_edbg_recv(): "
"Inconsistent # of fragments; had %d, now %d\n",
pmsg_notice("%s(): inconsistent # of fragments; had %d, now %d\n", __func__,
nfrags, (buf[1] & 0x0F));
mmt_free(*msg);
mmt_free(request);
@@ -729,8 +727,7 @@ static int jtag3_edbg_recv_frame(const PROGRAMMER *pgm, unsigned char **msg) {
}
}
if (thisfrag != ((buf[1] >> 4) & 0x0F)) {
pmsg_notice("jtag3_edbg_recv(): "
"inconsistent fragment number; expect %d, got %d\n",
pmsg_notice("%s(): inconsistent fragment number; expect %d, got %d\n", __func__,
thisfrag, ((buf[1] >> 4) & 0x0F));
mmt_free(*msg);
mmt_free(request);
@@ -739,11 +736,11 @@ static int jtag3_edbg_recv_frame(const PROGRAMMER *pgm, unsigned char **msg) {
int thislen = (buf[2] << 8) | buf[3];
if (thislen > rv + 4) {
pmsg_notice("jtag3_edbg_recv(): unexpected length value (%d > %d)\n", thislen, rv + 4);
pmsg_notice("%s(): unexpected length value (%d > %d)\n", __func__, thislen, rv + 4);
thislen = rv + 4;
}
if (len + thislen > USBDEV_MAX_XFER_3) {
pmsg_notice("jtag3_edbg_recv(): length exceeds max size (%d > %d)\n", len + thislen, USBDEV_MAX_XFER_3);
pmsg_notice("%s(): length exceeds max size (%d > %d)\n", __func__, len + thislen, USBDEV_MAX_XFER_3);
thislen = USBDEV_MAX_XFER_3 - len;
}
memmove(buf, buf + 4, thislen);
@@ -765,7 +762,7 @@ int jtag3_recv(const PROGRAMMER *pgm, unsigned char **msg) {
return rv;
if ((rv & USB_RECV_FLAG_EVENT) != 0) {
if (verbose >= 3)
if (verbose >= MSG_DEBUG)
jtag3_prevent(pgm, *msg, rv & USB_RECV_LENGTH_MASK);
mmt_free(*msg);
@@ -774,8 +771,7 @@ int jtag3_recv(const PROGRAMMER *pgm, unsigned char **msg) {
rv &= USB_RECV_LENGTH_MASK;
r_seqno = ((*msg)[2] << 8) | (*msg)[1];
pmsg_debug("jtag3_recv(): "
"Got message seqno %d (command_sequence == %d)\n", r_seqno, PDATA(pgm)->command_sequence);
pmsg_debug("%s(): got message seqno %d (command_sequence == %d)\n", __func__, r_seqno, PDATA(pgm)->command_sequence);
if (r_seqno == PDATA(pgm)->command_sequence) {
if (++(PDATA(pgm)->command_sequence) == 0xffff)
PDATA(pgm)->command_sequence = 0;
@@ -794,8 +790,7 @@ int jtag3_recv(const PROGRAMMER *pgm, unsigned char **msg) {
return rv;
}
pmsg_notice2("jtag3_recv(): "
"got wrong sequence number, %u != %u\n", r_seqno, PDATA(pgm)->command_sequence);
pmsg_notice2("%s(): got wrong sequence number, %u != %u\n", __func__, r_seqno, PDATA(pgm)->command_sequence);
mmt_free(*msg);
}
@@ -816,7 +811,7 @@ int jtag3_command(const PROGRAMMER *pgm, unsigned char *cmd, unsigned int cmdlen
if (status == 0)
mmt_free(*resp);
return LIBAVRDUDE_GENERAL_FAILURE;
} else if (verbose >= 3) {
} else if (verbose >= MSG_DEBUG) {
msg_debug("\n");
jtag3_prmsg(pgm, *resp, status);
} else {
@@ -1010,7 +1005,7 @@ static int jtag3_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
if (pgm->fd.usb.max_xfer < USBDEV_MAX_XFER_3 && (pgm->flag & PGM_FL_IS_EDBG) == 0) {
if (ovsigck) {
pmsg_warning("JTAGICE3's firmware %d.%d is broken on USB 1.1 connections\n", parm[0], parm[1]);
imsg_warning("forced to continue by option -F; THIS PUTS THE DEVICE'S DATA INTEGRITY AT RISK!\n");
imsg_warning("forced to continue by option -F; this puts the device's data integrity at risk!\n");
} else {
pmsg_error("JTAGICE3's firmware %d.%d is broken on USB 1.1 connections\n", parm[0], parm[1]);
return -1;
@@ -1069,8 +1064,7 @@ static int jtag3_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
}
if (pgm->bitclock != 0.0 && PDATA(pgm)->set_sck != NULL) {
unsigned int clock = 1E-3 / pgm->bitclock; /* kHz */
pmsg_notice2("jtag3_initialize(): "
"trying to set JTAG clock to %u kHz\n", clock);
pmsg_notice2("%s(): trying to set JTAG clock to %u kHz\n", __func__, clock);
parm[0] = clock & 0xff;
parm[1] = (clock >> 8) & 0xff;
if (PDATA(pgm)->set_sck(pgm, parm) < 0)
@@ -1078,8 +1072,7 @@ static int jtag3_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
}
if (conn == PARM3_CONN_JTAG) {
pmsg_notice2("jtag3_initialize(): "
"trying to set JTAG daisy-chain info to %d,%d,%d,%d\n",
pmsg_notice2("%s(): trying to set JTAG daisy-chain info to %d,%d,%d,%d\n", __func__,
PDATA(pgm)->jtagchain[0], PDATA(pgm)->jtagchain[1],
PDATA(pgm)->jtagchain[2], PDATA(pgm)->jtagchain[3]);
if (jtag3_setparm(pgm, SCOPE_AVR, 1, PARM3_JTAGCHAIN, PDATA(pgm)->jtagchain, 4) < 0)
@@ -1118,7 +1111,7 @@ static int jtag3_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
imsg_info("Vtarg switch setting changed from %u to %u\n", PDATA(pgm)->vtarg_switch_data[0], PDATA(pgm)->vtarg_switch_data[1]);
// Exit early is the target power switch is off and print sensible info message
if (PDATA(pgm)->vtarg_switch_data[1] == 0) {
imsg_info("Turn on the Vtarg switch to establish connection with the target\n\n");
pmsg_info("turn on the Vtarg switch to establish connection with the target\n\n");
return -1;
}
}
@@ -1183,8 +1176,7 @@ static int jtag3_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
u32_to_b4(xd.nvm_prod_sig_offset, m->offset);
}
}
if(p->prog_modes & (PM_PDI | PM_UPDI))
u32_to_b4(xd.nvm_data_offset, DATA_OFFSET);
u32_to_b4(xd.nvm_data_offset, DATA_OFFSET);
if (jtag3_setparm(pgm, SCOPE_AVR, 2, PARM3_DEVICEDESC, (unsigned char *)&xd, sizeof xd) < 0)
return -1;
@@ -1244,8 +1236,7 @@ static int jtag3_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
}
// Generate UPDI high-voltage pulse if user asks for it and hardware supports it
if (p->prog_modes & PM_UPDI &&
PDATA(pgm)->use_hvupdi == true &&
if (PDATA(pgm)->use_hvupdi == true &&
p->hvupdi_variant != HV_UPDI_VARIANT_1) {
parm[0] = PARM3_UPDI_HV_NONE;
for (LNODEID ln = lfirst(pgm->hvupdi_support); ln; ln = lnext(ln)) {
@@ -1451,27 +1442,26 @@ static void jtag3_disable(const PROGRAMMER *pgm) {
static void jtag3_enable(PROGRAMMER *pgm, const AVRPART *p) {
// Page erase only useful for classic parts with usersig mem or AVR8X/XMEGAs
if(!(p->prog_modes & (PM_PDI | PM_UPDI)))
if(p->prog_modes & PM_Classic)
if(!avr_locate_usersig(p))
pgm->page_erase = NULL;
}
static int jtag3_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) {
LNODEID ln;
const char *extended_param;
int rv = 0;
bool help = false;
for(ln = lfirst(extparms); ln; ln = lnext(ln)) {
extended_param = ldata(ln);
for(LNODEID ln = lfirst(extparms); ln; ln = lnext(ln)) {
const char *extended_param = ldata(ln);
if(str_starts(extended_param, "jtagchain=") && (pgm->prog_modes & (PM_JTAG | PM_XMEGAJTAG | PM_AVR32JTAG))) {
unsigned int ub, ua, bb, ba;
if(sscanf(extended_param, "jtagchain=%u,%u,%u,%u", &ub, &ua, &bb, &ba) != 4) {
pmsg_error("invalid JTAG chain %s\n", extended_param);
pmsg_error("invalid JTAG chain in -x %s\n", extended_param);
rv = -1;
break;
}
pmsg_notice2("jtag3_parseextparms(): JTAG chain parsed as:\n");
pmsg_notice2("%s(): JTAG chain parsed as:\n", __func__);
imsg_notice2("%u units before, %u units after, %u bits before, %u bits after\n",
ub, ua, bb, ba);
PDATA(pgm)->jtagchain[0] = ub;
@@ -1493,7 +1483,7 @@ static int jtag3_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) {
break;
}
if(!str_eq(extended_param, "hvupdi")) {
pmsg_error("invalid -xhvupdi value %s. Use -xhvupdi\n", extended_param);
pmsg_error("invalid assignment in -x %s; use -x hvupdi\n", extended_param);
rv = -1;
break;
}
@@ -1512,13 +1502,13 @@ static int jtag3_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) {
// Set SUFFER value
if(str_starts(extended_param, "suffer=")) {
if(sscanf(extended_param, "suffer=%hhi", PDATA(pgm)->suffer_data+1) < 1) {
pmsg_error("invalid -xsuffer=<value> %s\n", extended_param);
pmsg_error("invalid value in -x %s\n", extended_param);
rv = -1;
break;
}
if((PDATA(pgm)->suffer_data[1] & 0x78) != 0x78) {
PDATA(pgm)->suffer_data[1] |= 0x78;
pmsg_info("setting -xsuffer=0x%02x so that reserved bits 3..6 are set\n",
pmsg_info("setting -x suffer=0x%02x so that reserved bits 3..6 are set\n",
PDATA(pgm)->suffer_data[1]);
}
PDATA(pgm)->suffer_set = true;
@@ -1529,7 +1519,7 @@ static int jtag3_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) {
PDATA(pgm)->suffer_get = true;
continue;
}
pmsg_error("invalid suffer setting %s. Use -xsuffer or -xsuffer=<arg>\n", extended_param);
pmsg_error("invalid setting in -x %s; use -x suffer or -x suffer=<n>\n", extended_param);
rv = -1;
break;
}
@@ -1541,7 +1531,7 @@ static int jtag3_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) {
if(str_starts(extended_param, "vtarg_switch=")) {
int sscanf_success = sscanf(extended_param, "vtarg_switch=%hhi", PDATA(pgm)->vtarg_switch_data+1);
if(sscanf_success < 1 || PDATA(pgm)->vtarg_switch_data[1] > 1) {
pmsg_error("invalid vtarg_switch value %s\n", extended_param);
pmsg_error("invalid value in -x %s\n", extended_param);
rv = -1;
break;
}
@@ -1553,7 +1543,7 @@ static int jtag3_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) {
PDATA(pgm)->vtarg_switch_get = true;
continue;
}
pmsg_error("invalid vtarg_switch setting %s. Use -xvtarg_switch or -xvtarg_switch=<0..1>\n", extended_param);
pmsg_error("invalid setting in -x %s; use -x vtarg_switch or -x vtarg_switch=<0..1>\n", extended_param);
rv = -1;
break;
}
@@ -1567,7 +1557,7 @@ static int jtag3_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) {
int sscanf_success = sscanf(extended_param, "vtarg=%lf", &vtarg_set_val);
PDATA(pgm)->vtarg_data = (double)((int)(vtarg_set_val * 100 + .5)) / 100;
if(sscanf_success < 1 || vtarg_set_val < 0) {
pmsg_error("invalid vtarg value %s\n", extended_param);
pmsg_error("invalid value in -x %s\n", extended_param);
rv = -1;
break;
}
@@ -1579,7 +1569,7 @@ static int jtag3_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) {
PDATA(pgm)->vtarg_get = true;
continue;
}
pmsg_error("invalid vtarg setting %s. Use -xvtarg or -xvtarg=<arg>\n", extended_param);
pmsg_error("invalid setting in -x %s; use -x vtarg or -x vtarg=<dbl>\n", extended_param);
rv = -1;
break;
}
@@ -1597,37 +1587,43 @@ static int jtag3_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) {
PDATA(pgm)->pk4_snap_mode = PK4_SNAP_MODE_PIC;
continue;
}
pmsg_error("invalid mode setting %s. Use -xmode=avr or -xmode=pic\n", extended_param);
pmsg_error("invalid setting in -x %s; use -x mode=avr or -x mode=pic\n", extended_param);
rv = -1;
break;
}
if(str_eq(extended_param, "help")) {
msg_error("%s -c %s extended options:\n", progname, pgmid);
if(str_eq(pgm->type, "JTAGICE3"))
msg_error(" -xjtagchain=UB,UA,BB,BA Setup the JTAG scan chain order\n");
if(lsize(pgm->hvupdi_support) > 1)
msg_error(" -xhvupdi Enable high-voltage UPDI initialization\n");
if(pgm->extra_features & HAS_SUFFER) {
msg_error(" -xsuffer Read SUFFER register value\n");
msg_error(" -xsuffer=<arg> Set SUFFER register value\n");
}
if(pgm->extra_features & HAS_VTARG_SWITCH) {
msg_error(" -xvtarg_switch Read on-board target voltage switch state\n");
msg_error(" -xvtarg_switch=<0..1> Set on-board target voltage switch state\n");
}
if(pgm->extra_features & HAS_VTARG_ADJ) {
msg_error(" -xvtarg Read on-board target supply voltage\n");
msg_error(" -xvtarg=<arg> Set on-board target supply voltage\n");
}
if(str_starts(pgmid, "pickit4") || str_starts(pgmid, "snap"))
msg_error(" -xmode=avr|pic Set programmer to AVR or PIC mode, then exit\n");
msg_error (" -xhelp Show this help menu and exit\n");
return LIBAVRDUDE_EXIT;;
help = true;
rv = LIBAVRDUDE_EXIT;
}
pmsg_error("invalid extended parameter %s\n", extended_param);
rv = -1;
if (!help) {
pmsg_error("invalid extended parameter -x %s\n", extended_param);
rv = -1;
}
msg_error("%s -c %s extended options:\n", progname, pgmid);
if(str_eq(pgm->type, "JTAGICE3")) {
msg_error(" -x jtagchain=UB,UA,BB,BA Setup the JTAG scan chain order\n");
msg_error(" UB/UA = units before/after, BB/BA = bits before/after\n");
}
if(lsize(pgm->hvupdi_support) > 1)
msg_error(" -x hvupdi Enable high-voltage UPDI initialization\n");
if(pgm->extra_features & HAS_SUFFER) {
msg_error(" -x suffer Read SUFFER register value\n");
msg_error(" -x suffer=<n> Set SUFFER register to <n> (0x.. hex, 0.. oct or dec)\n");
}
if(pgm->extra_features & HAS_VTARG_SWITCH) {
msg_error(" -x vtarg_switch Read on-board target voltage switch state\n");
msg_error(" -x vtarg_switch=<0..1> Set on-board target voltage switch state\n");
}
if(pgm->extra_features & HAS_VTARG_ADJ) {
msg_error(" -x vtarg Read on-board target supply voltage\n");
msg_error(" -x vtarg=<dbl> Set on-board target supply voltage to <dbl> V\n");
}
if(str_starts(pgmid, "pickit4") || str_starts(pgmid, "snap"))
msg_error(" -x mode=avr|pic Set programmer to AVR or PIC mode, then exit\n");
msg_error (" -x help Show this help menu and exit\n");
return rv;
}
return rv;
@@ -1712,7 +1708,7 @@ int jtag3_open_common(PROGRAMMER *pgm, const char *port, int mode_switch) {
pmsg_error("%s in %s mode detected\n",
pgmstr, pinfo.usbinfo.pid == bl_pid? "bootloader": "PIC");
if(mode_switch == PK4_SNAP_MODE_AVR) {
imsg_error("switching to AVR mode\n");
imsg_error("switching to AVR mode; ");
if(pinfo.usbinfo.pid == bl_pid)
serial_send(&pgm->fd, exit_bl_cmd, sizeof(exit_bl_cmd));
else {
@@ -1720,10 +1716,10 @@ int jtag3_open_common(PROGRAMMER *pgm, const char *port, int mode_switch) {
usleep(250*1000);
serial_send(&pgm->fd, reset_cmd, sizeof(reset_cmd));
}
imsg_error("please run Avrdude again to continue the session\n\n");
imsg_error("run %s again to continue the session\n\n", progname);
} else {
imsg_error("to switch into AVR mode try\n");
imsg_error("avrdude -c%s -p%s -P%s -xmode=avr\n", pgmid, partdesc, port);
pmsg_error("to switch into AVR mode try\n");
imsg_error("$ %s -c%s -p%s -P%s -x mode=avr\n", progname, pgmid, partdesc, port);
}
serial_close(&pgm->fd);
return LIBAVRDUDE_EXIT;;
@@ -1749,7 +1745,7 @@ int jtag3_open_common(PROGRAMMER *pgm, const char *port, int mode_switch) {
}
if (mode_switch == PK4_SNAP_MODE_AVR)
pmsg_warning("programmer is already in AVR mode. Ignoring -xmode");
pmsg_warning("programmer is already in AVR mode, ignoring -x mode");
// The event EP has been deleted by usb_open(), so we are
// running on a CMSIS-DAP device, using EDBG protocol
@@ -1767,13 +1763,13 @@ int jtag3_open_common(PROGRAMMER *pgm, const char *port, int mode_switch) {
// Switch from AVR to PIC mode
if (mode_switch == PK4_SNAP_MODE_PIC) {
imsg_error("switching to PIC mode\n");
imsg_error("switching to PIC mode: ");
unsigned char *resp, buf[] = {SCOPE_GENERAL, CMD3_FW_UPGRADE, 0x00, 0x00, 0x70, 0x6d, 0x6a};
if (jtag3_command(pgm, buf, sizeof(buf), &resp, "enter PIC mode") < 0) {
imsg_error("entering PIC mode failed\n");
msg_error("entering PIC mode failed\n");
return -1;
}
imsg_error("PIC mode switch successful\n");
msg_error("PIC mode switch successful\n");
serial_close(&pgm->fd);
return LIBAVRDUDE_EXIT;;
}
@@ -1866,7 +1862,7 @@ static int jtag3_page_erase(const PROGRAMMER *pgm, const AVRPART *p, const AVRME
pmsg_notice2("jtag3_page_erase(.., %s, 0x%x)\n", m->desc, addr);
if(!(p->prog_modes & (PM_PDI | PM_UPDI)) && !mem_is_userrow(m)) {
if((p->prog_modes & PM_Classic) && !mem_is_userrow(m)) {
pmsg_error("page erase only available for AVR8X/XMEGAs or classic-part usersig mem\n");
return -1;
}
@@ -1971,8 +1967,7 @@ static int jtag3_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVRM
block_size = maxaddr - addr;
else
block_size = page_size;
pmsg_debug("jtag3_paged_write(): "
"block_size at addr %d is %d\n", addr, block_size);
pmsg_debug("%s(): block_size at addr %d is %d\n", __func__, addr, block_size);
if (dynamic_mtype)
cmd[3] = jtag3_mtype(pgm, p, addr);
@@ -2062,8 +2057,7 @@ static int jtag3_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AVRME
block_size = maxaddr - addr;
else
block_size = page_size;
pmsg_debug("jtag3_paged_load(): "
"block_size at addr %d is %d\n", addr, block_size);
pmsg_debug("%s(): block_size at addr %d is %d\n", __func__, addr, block_size);
if (dynamic_mtype)
cmd[3] = jtag3_mtype(pgm, p, addr);
@@ -2107,7 +2101,7 @@ static int jtag3_read_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM
paddr = jtag3_memaddr(pgm, p, mem, addr);
if (paddr != addr)
imsg_notice2("mapped to address: 0x%lx\n", paddr);
imsg_debug("addr 0x%lx mapped to address 0x%lx\n", addr, paddr);
paddr = 0;
if (mem->size < 1) {
@@ -2130,13 +2124,13 @@ static int jtag3_read_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM
cmd[3] = p->prog_modes & (PM_PDI | PM_UPDI)? MTYPE_FLASH: MTYPE_FLASH_PAGE;
if (mem_is_in_flash(mem)) {
addr += mem->offset & (512 * 1024 - 1); /* max 512 KiB flash */
addr += mem->offset & (512 * 1024 - 1); /* max 512 KiB flash @@@ could be max 8M */
pagesize = PDATA(pgm)->flash_pagesize;
paddr = addr & ~(pagesize - 1);
paddr_ptr = &PDATA(pgm)->flash_pageaddr;
cache_ptr = PDATA(pgm)->flash_pagecache;
} else if (mem_is_eeprom(mem)) {
if ( (pgm->flag & PGM_FL_IS_DW) || (p->prog_modes & PM_PDI) || (p->prog_modes & PM_UPDI) ) {
if ((pgm->flag & PGM_FL_IS_DW) || (p->prog_modes & (PM_PDI | PM_UPDI))) {
cmd[3] = MTYPE_EEPROM;
} else {
cmd[3] = MTYPE_EEPROM_PAGE;
@@ -2166,19 +2160,7 @@ static int jtag3_read_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM
if (pgm->flag & PGM_FL_IS_DW)
unsupp = 1;
}
} else if (mem_is_sernum(mem)) {
cmd[3] = MTYPE_SIGN_JTAG;
} else if (mem_is_osccal16(mem)) {
cmd[3] = MTYPE_SIGN_JTAG;
} else if (mem_is_osccal20(mem)) {
cmd[3] = MTYPE_SIGN_JTAG;
} else if (mem_is_tempsense(mem)) {
cmd[3] = MTYPE_SIGN_JTAG;
} else if (mem_is_osc16err(mem)) {
cmd[3] = MTYPE_SIGN_JTAG;
} else if (mem_is_osc20err(mem)) {
cmd[3] = MTYPE_SIGN_JTAG;
} else if (mem_is_calibration(mem)) {
} else if ((p->prog_modes & PM_Classic) && mem_is_calibration(mem)) { // Classic part calibration
cmd[3] = MTYPE_OSCCAL_BYTE;
if (pgm->flag & PGM_FL_IS_DW)
unsupp = 1;
@@ -2225,6 +2207,11 @@ static int jtag3_read_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM
msg_error("address out of range for signature memory: %lu\n", addr);
return -1;
}
} else if(mem_is_in_sigrow(mem)) { // sigrow sub-memories but not signature nor sigrow itself
cmd[3] = (p->prog_modes & PM_UPDI)? MTYPE_SIGN_JTAG: MTYPE_PRODSIG;
AVRMEM *sigrow = avr_locate_sigrow(p);
if(sigrow)
addr += mem->offset - sigrow->offset; // Adjust offset for parent memory
} else {
pmsg_error("unknown memory %s\n", mem->desc);
return -1;
@@ -2484,7 +2471,7 @@ int jtag3_getparm(const PROGRAMMER *pgm, unsigned char scope,
c = resp[1];
if (c != RSP3_DATA || status < 3) {
pmsg_notice("jtag3_getparm(): bad response to %s\n", descr);
pmsg_notice("%s(): bad response to %s\n", __func__, descr);
mmt_free(resp);
return -1;
}
@@ -2551,7 +2538,7 @@ int jtag3_read_sib(const PROGRAMMER *pgm, const AVRPART *p, char *sib) {
memcpy(sib, resp+3, AVR_SIBLEN);
sib[AVR_SIBLEN-1] = 0; // Zero terminate string
pmsg_debug("jtag3_read_sib(): received SIB: %s\n", sib);
pmsg_debug("%s(): received SIB: %s\n", __func__, sib);
mmt_free(resp);
return 0;
}
@@ -2573,7 +2560,7 @@ int jtag3_read_chip_rev(const PROGRAMMER *pgm, const AVRPART *p, unsigned char *
return -1;
}
pmsg_debug("jtag3_read_chip_rev(): received chip silicon revision: 0x%02x\n", *chip_rev);
pmsg_debug("%s(): received chip silicon revision: 0x%02x\n", __func__, *chip_rev);
return 0;
}
@@ -2590,7 +2577,7 @@ int jtag3_set_vtarget(const PROGRAMMER *pgm, double v) {
uaref = b2_to_u16(buf);
u16_to_b2(buf, utarg);
pmsg_notice2("jtag3_set_vtarget(): changing V[target] from %.1f to %.1f\n", uaref / 1000.0, v);
pmsg_notice2("%s(): changing V[target] from %.1f to %.1f\n", __func__, uaref / 1000.0, v);
if (jtag3_setparm(pgm, SCOPE_GENERAL, 1, PARM3_VADJUST, buf, sizeof(buf)) < 0) {
pmsg_error("cannot confirm new V[target] value\n");
@@ -2823,7 +2810,7 @@ static unsigned char tpi_get_mtype(const AVRMEM *m) {
mem_is_lock(m)? XPRG_MEM_TYPE_LOCKBITS:
mem_is_calibration(m)? XPRG_MEM_TYPE_LOCKBITS: // Sic, uses offset to distingish memories
mem_is_signature(m)? XPRG_MEM_TYPE_LOCKBITS:
mem_is_sigrow(m)? XPRG_MEM_TYPE_LOCKBITS:
mem_is_in_sigrow(m)? XPRG_MEM_TYPE_LOCKBITS:
XPRG_MEM_TYPE_APPL; // Sic, TPI parts do not have eeprom
}
@@ -2860,7 +2847,7 @@ int jtag3_recv_tpi(const PROGRAMMER *pgm, unsigned char **msg) {
rv = jtag3_recv(pgm, msg);
if (rv <= 0) {
pmsg_error("jtag3_recv_tpi(): unable to receive\n");
pmsg_error("%s(): unable to receive\n", __func__);
return -1;
}
rv = rv - 1;
@@ -3043,10 +3030,12 @@ static int jtag3_write_byte_tpi(const PROGRAMMER *pgm, const AVRPART *p, const A
return -1;
}
status = jtag3_erase_tpi(pgm, p, mem, addr);
if (status < 0) {
pmsg_error("error in communication, received status 0x%02x\n", status);
return -1;
if (mem_is_a_fuse(mem) || mem_is_flash(mem)) {
status = jtag3_erase_tpi(pgm, p, mem, addr);
if (status < 0) {
pmsg_error("error in communication, received status 0x%02x\n", status);
return -1;
}
}
paddr = mem->offset + addr;
@@ -3147,8 +3136,7 @@ static int jtag3_paged_load_tpi(const PROGRAMMER *pgm, const AVRPART *p,
block_size = maxaddr - addr;
else
block_size = page_size;
pmsg_debug("jtag3_paged_load_tpi(): "
"block_size at addr 0x%x is %d\n", addr, block_size);
pmsg_debug("%s(): block_size at addr 0x%x is %d\n", __func__, addr, block_size);
u32_to_b4_big_endian((cmd+2), addr + m->offset); // Address
u16_to_b2_big_endian((cmd+6), block_size); // Size
@@ -3207,8 +3195,7 @@ static int jtag3_paged_write_tpi(const PROGRAMMER *pgm, const AVRPART *p,
block_size = maxaddr - addr;
else
block_size = page_size;
pmsg_debug("jtag3_paged_write(): "
"block_size at addr 0x%x is %d\n", addr, block_size);
pmsg_debug("%s(): block_size at addr 0x%x is %d\n", __func__, addr, block_size);
u32_to_b4_big_endian((cmd+3), addr + m->offset); // Address
u16_to_b2_big_endian((cmd+7), page_size); // Size

View File

@@ -1,6 +1,7 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2012 Joerg Wunsch <j@uriah.heep.sax.de>
* Copyright (C) 2017 Jan Egil Ruud <janegil.ruud@microchip.com>
*
* 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
@@ -16,8 +17,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#ifndef jtag3_h
#define jtag3_h

View File

@@ -1,6 +1,7 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2012 Joerg Wunsch <j@uriah.heep.sax.de>
* Copyright (C) 2017 Jan Egil Ruud <janegil.ruud@microchip.com>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -17,8 +18,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
/*
* JTAGICE3 definitions

View File

@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
/*
* avrdude interface for Atmel JTAG ICE (mkI) programmer
*/
@@ -119,7 +117,7 @@ static void u16_to_b2(unsigned char *b, unsigned short l) {
}
static void jtagmkI_prmsg(const PROGRAMMER *pgm, unsigned char *data, size_t len) {
if (verbose >= 4) {
if (verbose >= MSG_TRACE) {
msg_trace("Raw message:\n");
size_t i;
@@ -175,7 +173,7 @@ static int jtagmkI_send(const PROGRAMMER *pgm, unsigned char *data, size_t len)
unsigned char *buf;
msg_debug("\n");
pmsg_debug("jtagmkI_send(): sending %u bytes\n", (unsigned int) len);
pmsg_debug("%s(): sending %u bytes\n", __func__, (unsigned int) len);
buf = mmt_malloc(len + 2);
memcpy(buf, data, len);
@@ -199,7 +197,7 @@ static int jtagmkI_recv(const PROGRAMMER *pgm, unsigned char *buf, size_t len) {
pmsg_error("unable to send command to serial port\n");
return -1;
}
if (verbose >= 3) {
if (verbose >= MSG_DEBUG) {
msg_debug("\n");
jtagmkI_prmsg(pgm, buf, len);
}
@@ -227,7 +225,7 @@ static int jtagmkI_resync(const PROGRAMMER *pgm, int maxtries, int signon) {
/* Get the sign-on information. */
buf[0] = CMD_GET_SYNC;
pmsg_notice2("jtagmkI_resync(): sending sync command: ");
pmsg_notice2("%s(): sending sync command: ", __func__);
if (serial_send(&pgm->fd, buf, 1) != 0) {
msg_error("\n");
@@ -255,7 +253,7 @@ static int jtagmkI_resync(const PROGRAMMER *pgm, int maxtries, int signon) {
buf[1] = 'E';
buf[2] = ' ';
buf[3] = ' ';
pmsg_notice2("jtagmkI_resync(): sending sign-on command: ");
pmsg_notice2("%s(): sending sign-on command: ", __func__);
if (serial_send(&pgm->fd, buf, 4) != 0) {
msg_error("\n");
@@ -270,8 +268,7 @@ static int jtagmkI_resync(const PROGRAMMER *pgm, int maxtries, int signon) {
}
}
if (tries >= maxtries) {
pmsg_notice2("jtagmkI_resync(): "
"timeout/error communicating with programmer\n");
pmsg_notice2("%s(): timeout/error communicating with programmer\n", __func__);
serial_recv_timeout = otimeout;
return -1;
}
@@ -290,7 +287,7 @@ static int jtagmkI_getsync(const PROGRAMMER *pgm) {
jtagmkI_drain(pgm, 0);
pmsg_notice2("jtagmkI_getsync(): sending sign-on command; ");
pmsg_notice2("%s(): sending sign-on command; ", __func__);
buf[0] = CMD_GET_SIGNON;
jtagmkI_send(pgm, buf, 1);
@@ -309,7 +306,7 @@ static int jtagmkI_chip_erase(const PROGRAMMER *pgm, const AVRPART *p) {
unsigned char buf[1], resp[2];
buf[0] = CMD_CHIP_ERASE;
pmsg_notice2("jtagmkI_chip_erase(): sending chip erase command: ");
pmsg_notice2("%s(): sending chip erase command: ", __func__);
jtagmkI_send(pgm, buf, 1);
if (jtagmkI_recv(pgm, resp, 2) < 0)
return -1;
@@ -350,8 +347,7 @@ static void jtagmkI_set_devdescr(const PROGRAMMER *pgm, const AVRPART *p) {
}
}
pmsg_notice2("jtagmkI_set_devdescr(): "
"Sending set device descriptor command: ");
pmsg_notice2("%s(): sending set device descriptor command: ", __func__);
jtagmkI_send(pgm, (unsigned char *)&sendbuf, sizeof(sendbuf));
if (jtagmkI_recv(pgm, resp, 2) < 0)
@@ -371,7 +367,7 @@ static int jtagmkI_reset(const PROGRAMMER *pgm) {
unsigned char buf[1], resp[2];
buf[0] = CMD_RESET;
pmsg_notice2("jtagmkI_reset(): sending reset command: ");
pmsg_notice2("%s(): sending reset command: ", __func__);
jtagmkI_send(pgm, buf, 1);
if (jtagmkI_recv(pgm, resp, 2) < 0)
@@ -398,8 +394,7 @@ static int jtagmkI_program_enable(const PROGRAMMER *pgm) {
return 0;
buf[0] = CMD_ENTER_PROGMODE;
pmsg_notice2("jtagmkI_program_enable(): "
"Sending enter progmode command: ");
pmsg_notice2("%s(): sending enter progmode command: ", __func__);
jtagmkI_send(pgm, buf, 1);
if (jtagmkI_recv(pgm, resp, 2) < 0)
@@ -425,7 +420,7 @@ static int jtagmkI_program_disable(const PROGRAMMER *pgm) {
if (pgm->fd.ifd != -1) {
buf[0] = CMD_LEAVE_PROGMODE;
pmsg_notice2("jtagmkI_program_disable(): sending leave progmode command: ");
pmsg_notice2("%s(): sending leave progmode command: ", __func__);
jtagmkI_send(pgm, buf, 1);
if (jtagmkI_recv(pgm, resp, 2) < 0)
@@ -471,8 +466,7 @@ static int jtagmkI_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
if ((b = jtagmkI_get_baud(pgm->baudrate)) == 0) {
pmsg_error("unsupported baudrate %d\n", pgm->baudrate);
} else {
pmsg_notice2("jtagmkI_initialize(): "
"trying to set baudrate to %d\n", pgm->baudrate);
pmsg_notice2("%s(): trying to set baudrate to %d\n", __func__, pgm->baudrate);
if (jtagmkI_setparm(pgm, PARM_BITRATE, b) == 0) {
PDATA(pgm)->initial_baudrate = pgm->baudrate; /* don't adjust again later */
serial_setparams(&pgm->fd, pgm->baudrate, SERIAL_8N1);
@@ -481,8 +475,7 @@ static int jtagmkI_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
}
if (pgm->bitclock != 0.0) {
pmsg_notice2("jtagmkI_initialize(): "
"trying to set JTAG clock period to %.1f us\n", pgm->bitclock);
pmsg_notice2("%s(): trying to set JTAG clock period to %.1f us\n", __func__, pgm->bitclock);
if (jtagmkI_set_sck_period(pgm, pgm->bitclock) != 0)
return -1;
}
@@ -550,7 +543,7 @@ static int jtagmkI_open(PROGRAMMER *pgm, const char *port) {
union pinfo pinfo;
pinfo.serialinfo.baud = baudtab[i].baud;
pinfo.serialinfo.cflags = SERIAL_8N1;
pmsg_notice2("jtagmkI_open(): trying to sync at baud rate %ld:\n", pinfo.serialinfo.baud);
pmsg_notice2("%s(): trying to sync at baud rate %ld:\n", __func__, pinfo.serialinfo.baud);
if (serial_open(port, pinfo, &pgm->fd)==-1) {
return -1;
}
@@ -562,7 +555,7 @@ static int jtagmkI_open(PROGRAMMER *pgm, const char *port) {
if (jtagmkI_getsync(pgm) == 0) {
PDATA(pgm)->initial_baudrate = baudtab[i].baud;
pmsg_notice2("jtagmkI_open(): succeeded\n");
pmsg_notice2("%s(): succeeded\n", __func__);
return 0;
}
@@ -590,8 +583,7 @@ static void jtagmkI_close(PROGRAMMER *pgm) {
if ((b = jtagmkI_get_baud(PDATA(pgm)->initial_baudrate)) == 0) {
pmsg_error("unsupported baudrate %d\n", PDATA(pgm)->initial_baudrate);
} else {
pmsg_notice2("jtagmkI_close(): "
"trying to set baudrate to %d\n", PDATA(pgm)->initial_baudrate);
pmsg_notice2("%s(): trying to set baudrate to %d\n", __func__, PDATA(pgm)->initial_baudrate);
if (jtagmkI_setparm(pgm, PARM_BITRATE, b) == 0) {
serial_setparams(&pgm->fd, pgm->baudrate, SERIAL_8N1);
}
@@ -660,8 +652,7 @@ static int jtagmkI_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AV
block_size = n_bytes;
else
block_size = page_size;
pmsg_debug("jtagmkI_paged_write(): "
"block_size at addr %d is %d\n", addr, block_size);
pmsg_debug("%s(): block_size at addr %d is %d\n", __func__, addr, block_size);
/* We always write full pages. */
send_size = page_size;
@@ -673,8 +664,7 @@ static int jtagmkI_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AV
u32_to_b3(cmd + 3, addr);
}
pmsg_notice2("jtagmkI_paged_write(): "
"sending write memory command: ");
pmsg_notice2("%s(): sending write memory command: ", __func__);
/* First part, send the write command. */
jtagmkI_send(pgm, cmd, 6);
@@ -773,8 +763,7 @@ static int jtagmkI_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AVR
block_size = n_bytes;
else
block_size = page_size;
pmsg_debug("jtagmkI_paged_load(): "
"block_size at addr %d is %d\n", addr, block_size);
pmsg_debug("%s(): block_size at addr %d is %d\n", __func__, addr, block_size);
if (is_flash) {
read_size = 2 * ((block_size + 1) / 2); /* round up */
@@ -786,7 +775,7 @@ static int jtagmkI_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AVR
u32_to_b3(cmd + 3, addr);
}
pmsg_notice2("jtagmkI_paged_load(): sending read memory command: ");
pmsg_notice2("%s(): sending read memory command: ", __func__);
jtagmkI_send(pgm, cmd, 6);
if (jtagmkI_recv(pgm, resp, read_size + 3) < 0)
@@ -852,7 +841,8 @@ static int jtagmkI_read_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRM
cmd[1] = MTYPE_OSCCAL_BYTE;
} else if (mem_is_signature(mem)) {
cmd[1] = MTYPE_SIGN_JTAG;
} else if (mem_is_sigrow(mem)) {
} else if (mem_is_in_sigrow(mem)) {
addr += avr_sigrow_offset(p, mem, addr);
cmd[1] = addr&1? MTYPE_OSCCAL_BYTE: MTYPE_SIGN_JTAG;
addr /= 2;
} else {
@@ -1097,8 +1087,7 @@ static int jtagmkI_getparm(const PROGRAMMER *pgm, const unsigned char parm,
buf[0] = CMD_GET_PARAM;
buf[1] = parm;
pmsg_notice2("jtagmkI_getparm(): "
"Sending get parameter command (parm 0x%02x): ", parm);
pmsg_notice2("%s(): sending get parameter command (parm 0x%02x): ", __func__, parm);
jtagmkI_send(pgm, buf, 2);
if (jtagmkI_recv(pgm, resp, 3) < 0)
@@ -1133,8 +1122,7 @@ static int jtagmkI_setparm(const PROGRAMMER *pgm, unsigned char parm,
buf[0] = CMD_SET_PARAM;
buf[1] = parm;
buf[2] = value;
pmsg_notice2("jtagmkI_setparm(): "
"Sending set parameter command (parm 0x%02x): ", parm);
pmsg_notice2("%s(): sending set parameter command (parm 0x%02x): ", __func__, parm);
jtagmkI_send(pgm, buf, 3);
if (jtagmkI_recv(pgm, resp, 2) < 0)
return -1;

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2002-2004 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2002-2004 Brian S. Dean <bsd@bdmicro.com>
*
* 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
@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#ifndef jtagmkI_h
#define jtagmkI_h

View File

@@ -21,8 +21,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
/*
* avrdude interface for Atmel JTAG ICE mkII programmer
*
@@ -262,7 +260,7 @@ static void jtagmkII_print_memory(unsigned char *b, size_t s) {
static void jtagmkII_prmsg(const PROGRAMMER *pgm_unused, unsigned char *data, size_t len) {
size_t i;
if (verbose >= 4) {
if (verbose >= MSG_TRACE) {
msg_trace("Raw message:\n");
for (i = 0; i < len; i++) {
@@ -403,7 +401,7 @@ int jtagmkII_send(const PROGRAMMER *pgm, unsigned char *data, size_t len) {
unsigned char *buf;
msg_debug("\n");
pmsg_debug("jtagmkII_send(): sending %lu bytes\n", (unsigned long) len);
pmsg_debug("%s(): sending %lu bytes\n", __func__, (unsigned long) len);
buf = mmt_malloc(len + 10);
buf[0] = MESSAGE_START;
@@ -480,7 +478,7 @@ static int jtagmkII_recv_frame(const PROGRAMMER *pgm, unsigned char **msg,
if (rv != 0) {
timedout:
/* timeout in receive */
pmsg_notice2("jtagmkII_recv(): timeout receiving packet\n");
pmsg_notice2("%s(): timeout receiving packet\n", __func__);
mmt_free(buf);
return -1;
}
@@ -543,7 +541,7 @@ static int jtagmkII_recv_frame(const PROGRAMMER *pgm, unsigned char **msg,
if (state == sCSUM2 && buf) {
if (crcverify(buf, msglen + 10)) {
if (verbose >= 9)
pmsg_trace2("jtagmkII_recv(): CRC OK");
pmsg_trace2("%s(): CRC OK", __func__);
state = sDONE;
} else {
pmsg_error("wrong checksum\n");
@@ -582,7 +580,7 @@ int jtagmkII_recv(const PROGRAMMER *pgm, unsigned char **msg) {
for (;;) {
if ((rv = jtagmkII_recv_frame(pgm, msg, &r_seqno)) <= 0)
return rv;
pmsg_debug("jtagmkII_recv(): got message seqno %d (command_sequence == %d)\n",
pmsg_debug("%s(): got message seqno %d (command_sequence == %d)\n", __func__,
r_seqno, PDATA(pgm)->command_sequence);
if (r_seqno == PDATA(pgm)->command_sequence) {
if (++(PDATA(pgm)->command_sequence) == 0xffff)
@@ -594,15 +592,15 @@ int jtagmkII_recv(const PROGRAMMER *pgm, unsigned char **msg) {
*/
memmove(*msg, *msg + 8, rv);
if(verbose > 3)
if(verbose >= MSG_TRACE)
trace_buffer(__func__, *msg, rv);
return rv;
}
if (r_seqno == 0xffff) {
pmsg_debug("jtagmkII_recv(): got asynchronous event\n");
pmsg_debug("%s(): got asynchronous event\n", __func__);
} else {
pmsg_notice2("jtagmkII_recv(): got wrong sequence number, %u != %u\n",
pmsg_notice2("%s(): got wrong sequence number, %u != %u\n", __func__,
r_seqno, PDATA(pgm)->command_sequence);
}
mmt_free(*msg);
@@ -640,7 +638,7 @@ int jtagmkII_getsync(const PROGRAMMER *pgm, int mode) {
if (status <= 0) {
pmsg_warning("attempt %d of %d: sign-on command: status %d\n",
tries + 1, MAXTRIES, status);
} else if (verbose >= 3) {
} else if (verbose >= MSG_DEBUG) {
msg_debug("\n");
jtagmkII_prmsg(pgm, resp, status);
} else
@@ -705,7 +703,7 @@ int jtagmkII_getsync(const PROGRAMMER *pgm, int mode) {
PDATA(pgm)->device_descriptor_length -= 2;
}
if (mode != EMULATOR_MODE_SPI)
pmsg_notice2("jtagmkII_getsync(): using a %u-byte device descriptor\n",
pmsg_notice2("%s(): using a %u-byte device descriptor\n", __func__,
(unsigned) PDATA(pgm)->device_descriptor_length);
if (mode == EMULATOR_MODE_SPI) {
PDATA(pgm)->device_descriptor_length = 0;
@@ -770,7 +768,7 @@ retry:
/* GET SYNC forces the target into STOPPED mode */
buf[0] = CMND_GET_SYNC;
pmsg_notice2("jtagmkII_getsync(): sending get sync command: ");
pmsg_notice2("%s(): sending get sync command: ", __func__);
jtagmkII_send(pgm, buf, 1);
status = jtagmkII_recv(pgm, &resp);
@@ -779,7 +777,7 @@ retry:
pmsg_error("timeout/error communicating with programmer (status %d)\n", status);
return -1;
}
if (verbose >= 3) {
if (verbose >= MSG_DEBUG) {
msg_debug("\n");
jtagmkII_prmsg(pgm, resp, status);
} else
@@ -810,7 +808,7 @@ static int jtagmkII_chip_erase(const PROGRAMMER *pgm, const AVRPART *p) {
buf[0] = CMND_CHIP_ERASE;
len = 1;
}
pmsg_notice2("jtagmkII_chip_erase(): sending %schip erase command: ",
pmsg_notice2("%s(): sending %schip erase command: ", __func__,
p->prog_modes & (PM_PDI | PM_UPDI)? "Xmega ": "");
jtagmkII_send(pgm, buf, len);
@@ -820,7 +818,7 @@ static int jtagmkII_chip_erase(const PROGRAMMER *pgm, const AVRPART *p) {
pmsg_error("timeout/error communicating with programmer (status %d)\n", status);
return -1;
}
if (verbose >= 3) {
if (verbose >= MSG_DEBUG) {
msg_debug("\n");
jtagmkII_prmsg(pgm, resp, status);
} else
@@ -832,7 +830,7 @@ static int jtagmkII_chip_erase(const PROGRAMMER *pgm, const AVRPART *p) {
return -1;
}
if (!(p->prog_modes & (PM_PDI | PM_UPDI)))
if (p->prog_modes & PM_Classic)
pgm->initialize(pgm, p);
PDATA(pgm)->recently_written = 1;
@@ -892,10 +890,9 @@ static void jtagmkII_set_devdescr(const PROGRAMMER *pgm, const AVRPART *p) {
}
}
sendbuf.dd.ucCacheType =
p->prog_modes & (PM_PDI | PM_UPDI)? 0x02 /* ATxmega */: 0x00;
p->prog_modes & (PM_PDI | PM_UPDI)? 0x02: 0x00;
pmsg_notice2("jtagmkII_set_devdescr(): "
"Sending set device descriptor command: ");
pmsg_notice2("%s(): sending set device descriptor command: ", __func__);
jtagmkII_send(pgm, (unsigned char *)&sendbuf,
PDATA(pgm)->device_descriptor_length + sizeof(unsigned char));
@@ -905,7 +902,7 @@ static void jtagmkII_set_devdescr(const PROGRAMMER *pgm, const AVRPART *p) {
pmsg_error("timeout/error communicating with programmer (status %d)\n", status);
return;
}
if (verbose >= 3) {
if (verbose >= MSG_DEBUG) {
msg_debug("\n");
jtagmkII_prmsg(pgm, resp, status);
} else
@@ -975,7 +972,7 @@ static void jtagmkII_set_xmega_params(const PROGRAMMER *pgm, const AVRPART *p) {
pmsg_error("timeout/error communicating with programmer (status %d)\n", status);
return;
}
if (verbose >= 3) {
if (verbose >= MSG_DEBUG) {
msg_debug("\n");
jtagmkII_prmsg(pgm, resp, status);
} else
@@ -1006,7 +1003,7 @@ static int jtagmkII_reset(const PROGRAMMER *pgm, unsigned char flags) {
buf[0] = (pgm->flag & PGM_FL_IS_DW)? CMND_FORCED_STOP: CMND_RESET;
buf[1] = (pgm->flag & PGM_FL_IS_DW)? 1: flags;
pmsg_notice2("jtagmkII_reset(): sending %s command: ",
pmsg_notice2("%s(): sending %s command: ", __func__,
(pgm->flag & PGM_FL_IS_DW)? "stop": "reset");
jtagmkII_send(pgm, buf, 2);
@@ -1016,7 +1013,7 @@ static int jtagmkII_reset(const PROGRAMMER *pgm, unsigned char flags) {
pmsg_error("timeout/error communicating with programmer (status %d)\n", status);
return -1;
}
if (verbose >= 3) {
if (verbose >= MSG_DEBUG) {
msg_debug("\n");
jtagmkII_prmsg(pgm, resp, status);
} else
@@ -1045,8 +1042,7 @@ static int jtagmkII_program_enable(const PROGRAMMER *pgm) {
for (use_ext_reset = 0; use_ext_reset <= 1; use_ext_reset++) {
buf[0] = CMND_ENTER_PROGMODE;
pmsg_notice2("jtagmkII_program_enable(): "
"Sending enter progmode command: ");
pmsg_notice2("%s(): sending enter progmode command: ", __func__);
jtagmkII_send(pgm, buf, 1);
status = jtagmkII_recv(pgm, &resp);
@@ -1055,7 +1051,7 @@ static int jtagmkII_program_enable(const PROGRAMMER *pgm) {
pmsg_error("timeout/error communicating with programmer (status %d)\n", status);
return -1;
}
if (verbose >= 3) {
if (verbose >= MSG_DEBUG) {
msg_debug("\n");
jtagmkII_prmsg(pgm, resp, status);
} else
@@ -1091,8 +1087,7 @@ static int jtagmkII_program_disable(const PROGRAMMER *pgm) {
return 0;
buf[0] = CMND_LEAVE_PROGMODE;
pmsg_notice2("jtagmkII_program_disable(): "
"Sending leave progmode command: ");
pmsg_notice2("%s(): sending leave progmode command: ", __func__);
jtagmkII_send(pgm, buf, 1);
status = jtagmkII_recv(pgm, &resp);
@@ -1101,7 +1096,7 @@ static int jtagmkII_program_disable(const PROGRAMMER *pgm) {
pmsg_error("timeout/error communicating with programmer (status %d)\n", status);
return -1;
}
if (verbose >= 3) {
if (verbose >= MSG_DEBUG) {
msg_debug("\n");
jtagmkII_prmsg(pgm, resp, status);
} else
@@ -1175,7 +1170,7 @@ static int jtagmkII_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
const char *ifname;
if (PDATA(pgm)->rts_mode != RTS_MODE_DEFAULT) {
pmsg_info("forcing serial DTR/RTS handshake lines %s\n",
pmsg_notice("forcing serial DTR/RTS handshake lines %s\n",
PDATA(pgm)->rts_mode == RTS_MODE_LOW ? "LOW" : "HIGH");
}
@@ -1210,15 +1205,13 @@ static int jtagmkII_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
if ((b = jtagmkII_get_baud(pgm->baudrate)) == 0) {
pmsg_error("unsupported baudrate %d\n", pgm->baudrate);
} else {
pmsg_notice2("jtagmkII_initialize(): "
"trying to set baudrate to %d\n", pgm->baudrate);
pmsg_notice2("%s(): trying to set baudrate to %d\n", __func__, pgm->baudrate);
if (jtagmkII_setparm(pgm, PAR_BAUD_RATE, &b) == 0)
serial_setparams(&pgm->fd, pgm->baudrate, SERIAL_8N1);
}
}
if ((pgm->flag & PGM_FL_IS_JTAG) && pgm->bitclock != 0.0) {
pmsg_notice2("jtagmkII_initialize(): "
"trying to set JTAG clock period to %.1f us\n", pgm->bitclock);
pmsg_notice2("%s(): trying to set JTAG clock period to %.1f us\n", __func__, pgm->bitclock);
if (jtagmkII_set_sck_period(pgm, pgm->bitclock) != 0)
return -1;
}
@@ -1292,7 +1285,7 @@ static int jtagmkII_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
return -1;
}
if ((pgm->flag & PGM_FL_IS_JTAG) && !(p->prog_modes & (PM_PDI | PM_UPDI))) {
if ((pgm->flag & PGM_FL_IS_JTAG) && (p->prog_modes & PM_Classic)) {
int ocden = 0;
if(avr_get_config_value(pgm, p, "ocden", &ocden) == 0 && ocden) // ocden == 1 means disabled
pmsg_warning("OCDEN fuse not programmed, single-byte EEPROM updates not possible\n");
@@ -1323,7 +1316,7 @@ static void jtagmkII_disable(const PROGRAMMER *pgm) {
static void jtagmkII_enable(PROGRAMMER *pgm, const AVRPART *p) {
// Page erase only useful for classic parts with usersig mem or AVR8X/XMEGAs
if(!(p->prog_modes & (PM_PDI | PM_UPDI)))
if(p->prog_modes & PM_Classic)
if(!avr_locate_usersig(p))
pgm->page_erase = NULL;
@@ -1334,29 +1327,27 @@ static void jtagmkII_enable(PROGRAMMER *pgm, const AVRPART *p) {
}
static int jtagmkII_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) {
LNODEID ln;
const char *extended_param;
int rv = 0;
bool help = false;
for (ln = lfirst(extparms); ln; ln = lnext(ln)) {
extended_param = ldata(ln);
for (LNODEID ln = lfirst(extparms); ln; ln = lnext(ln)) {
const char *extended_param = ldata(ln);
if (pgm->flag & PGM_FL_IS_JTAG) {
if (str_eq(extended_param, "jtagchain=")) {
if (str_starts(extended_param, "jtagchain=")) {
unsigned int ub, ua, bb, ba;
if (sscanf(extended_param, "jtagchain=%u,%u,%u,%u", &ub, &ua, &bb, &ba) != 4) {
pmsg_error("invalid JTAG chain '%s'\n", extended_param);
pmsg_error("invalid JTAG chain in -x %s\n", extended_param);
rv = -1;
continue;
}
pmsg_notice2("jtagmkII_parseextparms(): JTAG chain parsed as:\n");
pmsg_notice2("%s(): JTAG chain parsed as:\n", __func__);
imsg_notice2("%u units before, %u units after, %u bits before, %u bits after\n",
ub, ua, bb, ba);
PDATA(pgm)->jtagchain[0] = ub;
PDATA(pgm)->jtagchain[1] = ua;
PDATA(pgm)->jtagchain[2] = bb;
PDATA(pgm)->jtagchain[3] = ba;
continue;
}
}
@@ -1370,24 +1361,29 @@ static int jtagmkII_parseextparms(const PROGRAMMER *pgm, const LISTID extparms)
PDATA(pgm)->rts_mode = RTS_MODE_HIGH;
} else {
pmsg_error("RTS/DTR mode must be LOW or HIGH\n");
return -1;
rv = -1;
break;
}
continue;
}
}
if (str_eq(extended_param, "help")) {
msg_error("%s -c %s extended options:\n", progname, pgmid);
if (pgm->flag & PGM_FL_IS_JTAG)
msg_error(" -xjtagchain=UB,UA,BB,BA Setup the JTAG scan chain order\n");
if (pgm->flag & PGM_FL_IS_PDI)
msg_error(" -xrtsdtr=low,high Force RTS/DTR lines low or high state during programming\n");
msg_error( " -xhelp Show this help menu and exit\n");
return LIBAVRDUDE_EXIT;;
help = true;
rv = LIBAVRDUDE_EXIT;
}
pmsg_error("invalid extended parameter '%s'\n", extended_param);
rv = -1;
if (!help) {
pmsg_error("invalid extended parameter -x %s\n", extended_param);
rv = -1;
}
msg_error("%s -c %s extended options:\n", progname, pgmid);
if (pgm->flag & PGM_FL_IS_JTAG)
msg_error(" -x jtagchain=UB,UA,BB,BA Setup the JTAG scan chain order\n");
if (pgm->flag & PGM_FL_IS_PDI)
msg_error(" -x rtsdtr=low,high Force RTS/DTR lines low or high state during programming\n");
msg_error( " -x help Show this help menu and exit\n");
return rv;
}
return rv;
@@ -1726,7 +1722,7 @@ void jtagmkII_close(PROGRAMMER * pgm)
if (pgm->flag & (PGM_FL_IS_PDI | PGM_FL_IS_JTAG)) {
/* When in PDI or JTAG mode, restart target. */
buf[0] = CMND_GO;
pmsg_notice2("jtagmkII_close(): sending GO command: ");
pmsg_notice2("%s(): sending GO command: ", __func__);
jtagmkII_send(pgm, buf, 1);
status = jtagmkII_recv(pgm, &resp);
@@ -1734,7 +1730,7 @@ void jtagmkII_close(PROGRAMMER * pgm)
msg_notice2("\n");
pmsg_error("timeout/error communicating with programmer (status %d)\n", status);
} else {
if (verbose >= 3) {
if (verbose >= MSG_DEBUG) {
msg_debug("\n");
jtagmkII_prmsg(pgm, resp, status);
} else
@@ -1748,7 +1744,7 @@ void jtagmkII_close(PROGRAMMER * pgm)
}
buf[0] = CMND_SIGN_OFF;
pmsg_notice2("jtagmkII_close(): sending sign-off command: ");
pmsg_notice2("%s(): sending sign-off command: ", __func__);
jtagmkII_send(pgm, buf, 1);
status = jtagmkII_recv(pgm, &resp);
@@ -1757,7 +1753,7 @@ void jtagmkII_close(PROGRAMMER * pgm)
pmsg_error("timeout/error communicating with programmer (status %d)\n", status);
return;
}
if (verbose >= 3) {
if (verbose >= MSG_DEBUG) {
msg_debug("\n");
jtagmkII_prmsg(pgm, resp, status);
} else
@@ -1769,7 +1765,7 @@ void jtagmkII_close(PROGRAMMER * pgm)
}
if (PDATA(pgm)->rts_mode != RTS_MODE_DEFAULT) {
pmsg_info("releasing DTR/RTS handshake lines\n");
pmsg_notice("releasing DTR/RTS handshake lines\n");
serial_set_dtr_rts(&pgm->fd, 0);
}
@@ -1796,7 +1792,7 @@ static int jtagmkII_page_erase(const PROGRAMMER *pgm, const AVRPART *p, const AV
pmsg_notice2("jtagmkII_page_erase(.., %s, 0x%x)\n", m->desc, addr);
if (!(p->prog_modes & (PM_PDI | PM_UPDI)) && !mem_is_userrow(m)) {
if ((p->prog_modes & PM_Classic) && !mem_is_userrow(m)) {
pmsg_error("page erase only available for AVR8X/XMEGAs or classic-part usersig mem\n");
return -1;
}
@@ -1836,8 +1832,7 @@ static int jtagmkII_page_erase(const PROGRAMMER *pgm, const AVRPART *p, const AV
tries = 0;
retry:
pmsg_notice2("jtagmkII_page_erase(): "
"Sending Xmega erase command: ");
pmsg_notice2("%s(): sending Xmega erase command: ", __func__);
jtagmkII_send(pgm, cmd, sizeof cmd);
status = jtagmkII_recv(pgm, &resp);
@@ -1852,7 +1847,7 @@ static int jtagmkII_page_erase(const PROGRAMMER *pgm, const AVRPART *p, const AV
serial_recv_timeout = otimeout;
return -1;
}
if (verbose >= 3) {
if (verbose >= MSG_DEBUG) {
msg_debug("\n");
jtagmkII_prmsg(pgm, resp, status);
} else
@@ -1929,8 +1924,7 @@ static int jtagmkII_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const A
block_size = maxaddr - addr;
else
block_size = page_size;
pmsg_debug("jtagmkII_paged_write(): "
"block_size at addr %d is %d\n", addr, block_size);
pmsg_debug("%s(): block_size at addr %d is %d\n", __func__, addr, block_size);
if (dynamic_mtype)
cmd[1] = jtagmkII_mtype(pgm, p, addr);
@@ -1951,8 +1945,7 @@ static int jtagmkII_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const A
tries = 0;
retry:
pmsg_notice2("jtagmkII_paged_write(): "
"Sending write memory command: ");
pmsg_notice2("%s(): sending write memory command: ", __func__);
jtagmkII_send(pgm, cmd, page_size + 10);
status = jtagmkII_recv(pgm, &resp);
@@ -1968,7 +1961,7 @@ static int jtagmkII_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const A
serial_recv_timeout = otimeout;
return -1;
}
if (verbose >= 3) {
if (verbose >= MSG_DEBUG) {
msg_debug("\n");
jtagmkII_prmsg(pgm, resp, status);
} else
@@ -2034,8 +2027,7 @@ static int jtagmkII_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AV
block_size = maxaddr - addr;
else
block_size = page_size;
pmsg_debug("jtagmkII_paged_load(): "
"block_size at addr %d is %d\n", addr, block_size);
pmsg_debug("%s(): block_size at addr %d is %d\n", __func__, addr, block_size);
if (dynamic_mtype)
cmd[1] = jtagmkII_mtype(pgm, p, addr);
@@ -2046,7 +2038,7 @@ static int jtagmkII_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AV
tries = 0;
retry:
pmsg_notice2("jtagmkII_paged_load(): sending read memory command: ");
pmsg_notice2("%s(): sending read memory command: ", __func__);
jtagmkII_send(pgm, cmd, 10);
status = jtagmkII_recv(pgm, &resp);
@@ -2061,7 +2053,7 @@ static int jtagmkII_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AV
serial_recv_timeout = otimeout;
return -1;
}
if (verbose >= 3) {
if (verbose >= MSG_DEBUG) {
msg_debug("\n");
jtagmkII_prmsg(pgm, resp, status);
} else
@@ -2098,7 +2090,7 @@ static int jtagmkII_read_chip_rev(const PROGRAMMER *pgm, const AVRPART *p, unsig
return -1;
}
pmsg_debug("jtagmkII_read_chip_rev(): received chip silicon revision: 0x%02x\n", *chip_rev);
pmsg_debug("%s(): received chip silicon revision: 0x%02x\n", __func__, *chip_rev);
return 0;
}
@@ -2139,7 +2131,7 @@ static int jtagmkII_read_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVR
}
} else if(mem_is_a_fuse(mem) || mem_is_fuses(mem)) {
cmd[1] = MTYPE_FUSE_BITS;
if(!(p->prog_modes & (PM_PDI | PM_UPDI)) && mem_is_a_fuse(mem))
if((p->prog_modes & PM_Classic) && mem_is_a_fuse(mem))
addr = mem_fuse_offset(mem);
if (pgm->flag & PGM_FL_IS_DW)
unsupp = 1;
@@ -2193,6 +2185,9 @@ static int jtagmkII_read_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVR
} else if ((p->prog_modes & (PM_PDI | PM_UPDI)) && mem_is_in_sigrow(mem)) {
cmd[1] = MTYPE_PRODSIG;
pmsg_notice2("in_sigrow addr 0x%05lx\n", addr);
} else if (mem_is_in_sigrow(mem)) { // Classic part
cmd[1] = addr&1? MTYPE_OSCCAL_BYTE: MTYPE_SIGN_JTAG;
addr /= 2;
} else if (mem_is_io(mem) || mem_is_sram(mem)) {
cmd[1] = MTYPE_FLASH;
addr += avr_data_offset(p);
@@ -2234,7 +2229,7 @@ static int jtagmkII_read_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVR
tries = 0;
retry:
pmsg_notice2("jtagmkII_read_byte(): sending read memory command: ");
pmsg_notice2("%s(): sending read memory command: ", __func__);
jtagmkII_send(pgm, cmd, 10);
status = jtagmkII_recv(pgm, &resp);
@@ -2248,7 +2243,7 @@ retry:
resp = 0;
goto fail;
}
if (verbose >= 3) {
if (verbose >= MSG_DEBUG) {
msg_debug("\n");
jtagmkII_prmsg(pgm, resp, status);
} else
@@ -2308,7 +2303,7 @@ static int jtagmkII_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const AV
PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L;
} else if (mem_is_a_fuse(mem) || mem_is_fuses(mem)) {
cmd[1] = MTYPE_FUSE_BITS;
if(!(p->prog_modes & (PM_PDI | PM_UPDI)) && mem_is_a_fuse(mem))
if((p->prog_modes & PM_Classic) && mem_is_a_fuse(mem))
addr = mem_fuse_offset(mem);
if (pgm->flag & PGM_FL_IS_DW)
unsupp = 1;
@@ -2353,20 +2348,19 @@ static int jtagmkII_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const AV
tries = 0;
retry:
pmsg_notice2("jtagmkII_write_byte(): sending write memory command: ");
pmsg_notice2("%s(): sending write memory command: ", __func__);
jtagmkII_send(pgm, cmd, 10 + writesize);
status = jtagmkII_recv(pgm, &resp);
if (status <= 0) {
msg_notice2("\n");
pmsg_notice2("jtagmkII_write_byte(): "
"timeout/error communicating with programmer (status %d)\n", status);
pmsg_notice2("%s(): timeout/error communicating with programmer (status %d)\n", __func__, status);
if (tries++ < 3)
goto retry;
pmsg_error("timeout/error communicating with programmer (status %d)\n", status);
goto fail;
}
if (verbose >= 3) {
if (verbose >= MSG_DEBUG) {
msg_debug("\n");
jtagmkII_prmsg(pgm, resp, status);
} else
@@ -2445,8 +2439,7 @@ int jtagmkII_getparm(const PROGRAMMER *pgm, unsigned char parm,
buf[0] = CMND_GET_PARAMETER;
buf[1] = parm;
pmsg_notice2("jtagmkII_getparm(): "
"Sending get parameter command (parm 0x%02x): ", parm);
pmsg_notice2("%s(): sending get parameter command (parm 0x%02x): ", __func__, parm);
jtagmkII_send(pgm, buf, 2);
status = jtagmkII_recv(pgm, &resp);
@@ -2455,7 +2448,7 @@ int jtagmkII_getparm(const PROGRAMMER *pgm, unsigned char parm,
pmsg_error("timeout/error communicating with programmer (status %d)\n", status);
return -1;
}
if (verbose >= 3) {
if (verbose >= MSG_DEBUG) {
msg_debug("\n");
jtagmkII_prmsg(pgm, resp, status);
} else
@@ -2520,7 +2513,7 @@ static int jtagmkII_setparm(const PROGRAMMER *pgm, unsigned char parm,
pmsg_error("timeout/error communicating with programmer (status %d)\n", status);
return -1;
}
if (verbose >= 3) {
if (verbose >= MSG_DEBUG) {
msg_debug("\n");
jtagmkII_prmsg(pgm, resp, status);
} else
@@ -2649,8 +2642,7 @@ static int jtagmkII_avr32_reset(const PROGRAMMER *pgm, unsigned char val,
status = jtagmkII_recv(pgm, &resp);
if (status != 2 || resp[0] != 0x87 || resp[1] != ret1) {
pmsg_notice("jtagmkII_avr32_reset(): "
"Get_IR, expecting %2.2x but got %2.2x\n", ret1, resp[1]);
pmsg_notice("%s(): Get_IR, expecting %2.2x but got %2.2x\n", __func__, ret1, resp[1]);
//return -1;
}
@@ -2663,8 +2655,7 @@ static int jtagmkII_avr32_reset(const PROGRAMMER *pgm, unsigned char val,
status = jtagmkII_recv(pgm, &resp);
if (status != 2 || resp[0] != 0x87 || resp[1] != ret2) {
pmsg_notice("jtagmkII_avr32_reset(): "
"Get_XXX, expecting %2.2x but got %2.2x\n", ret2, resp[1]);
pmsg_notice("%s(): Get_XXX, expecting %2.2x but got %2.2x\n", __func__, ret2, resp[1]);
//return -1;
}
@@ -3003,12 +2994,10 @@ static int jtagmkII_initialize32(const PROGRAMMER *pgm, const AVRPART *p) {
resp[3] != p->signature[1] ||
resp[4] != p->signature[2]) {
if (ovsigck) {
pmsg_warning("expected signature for %s is %02X %02X %02X\n", p->desc,
p->signature[0], p->signature[1], p->signature[2]);
pmsg_warning("expected signature for %s is%s\n", p->desc, str_cchex(p->signature, 3, 1));
} else {
pmsg_error("expected signature for %s is %02X %02X %02X\n", p->desc,
p->signature[0], p->signature[1], p->signature[2]);
imsg_error("double check chip or use -F to override this check\n");
pmsg_error("expected signature for %s is%s;\n", p->desc, str_cchex(p->signature, 3, 1));
imsg_error("double check chip or use -F to carry on regardless\n");
return -1;
}
}
@@ -3123,7 +3112,7 @@ static unsigned long jtagmkII_read_SABaddr(const PROGRAMMER *pgm, unsigned long
mmt_free(resp);
msg_notice2("\n");
pmsg_notice("jtagmkII_read_SABaddr(): OCD Register %lx -> %4.4lx\n", addr, val);
pmsg_notice("%s(): OCD Register %lx -> %4.4lx\n", __func__, addr, val);
serial_recv_timeout = otimeout;
return val;
}
@@ -3150,7 +3139,7 @@ static int jtagmkII_write_SABaddr(const PROGRAMMER *pgm, unsigned long addr,
}
msg_notice2("\n");
pmsg_notice("jtagmkII_write_SABaddr(): OCD Register %lx -> %4.4lx\n", addr, val);
pmsg_notice("%s(): OCD Register %lx -> %4.4lx\n", __func__, addr, val);
return 0;
}
@@ -3252,7 +3241,7 @@ static void jtagmkII_close32(PROGRAMMER * pgm) {
mmt_free(resp);
buf[0] = CMND_SIGN_OFF;
pmsg_notice2("jtagmkII_close(): sending sign-off command: ");
pmsg_notice2("%s(): sending sign-off command: ", __func__);
jtagmkII_send(pgm, buf, 1);
status = jtagmkII_recv(pgm, &resp);
@@ -3261,7 +3250,7 @@ static void jtagmkII_close32(PROGRAMMER * pgm) {
pmsg_error("timeout/error communicating with programmer (status %d)\n", status);
return;
}
if (verbose >= 3) {
if (verbose >= MSG_DEBUG) {
msg_debug("\n");
jtagmkII_prmsg(pgm, resp, status);
} else
@@ -3319,8 +3308,7 @@ static int jtagmkII_paged_load32(const PROGRAMMER *pgm, const AVRPART *p_unused,
for (; addr < maxaddr; addr += block_size) {
block_size = maxaddr - addr < (unsigned int) pgm->page_size?
maxaddr - addr: (unsigned int) pgm->page_size;
pmsg_debug("jtagmkII_paged_load32(): "
"block_size at addr %d is %d\n", addr, block_size);
pmsg_debug("%s(): block_size at addr %d is %d\n", __func__, addr, block_size);
u32_to_b4r(cmd + 3, m->offset + addr);
@@ -3329,7 +3317,7 @@ static int jtagmkII_paged_load32(const PROGRAMMER *pgm, const AVRPART *p_unused,
status = jtagmkII_recv(pgm, &resp);
if(status<0) {lineno = __LINE__; goto eRR;}
if (verbose >= 3) {
if (verbose >= MSG_DEBUG) {
msg_debug("\n");
jtagmkII_prmsg(pgm, resp, status);
} else
@@ -3414,8 +3402,7 @@ static int jtagmkII_paged_write32(const PROGRAMMER *pgm, const AVRPART *p_unused
for(blocks=0; blocks<2; ++blocks) {
block_size = maxaddr - addr < (unsigned int) pgm->page_size?
maxaddr - addr: (unsigned int) pgm->page_size;
pmsg_debug("jtagmkII_paged_write32(): "
"block_size at addr %d is %d\n", addr, block_size);
pmsg_debug("%s(): block_size at addr %d is %d\n", __func__, addr, block_size);
u32_to_b4r(cmd + 6, m->offset + addr);
memset(cmd + 10, 0xff, pgm->page_size);
@@ -3426,7 +3413,7 @@ static int jtagmkII_paged_write32(const PROGRAMMER *pgm, const AVRPART *p_unused
status = jtagmkII_recv(pgm, &resp);
if (status<0) {lineno = __LINE__; goto eRR;}
if (verbose >= 3) {
if (verbose >= MSG_DEBUG) {
msg_debug("\n");
jtagmkII_prmsg(pgm, resp, status);
} else

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2002-2004, 2006 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2002-2004, 2006 Brian S. Dean <bsd@bdmicro.com>
*
* 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
@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#ifndef jtagmkII_h
#define jtagmkII_h

View File

@@ -17,8 +17,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
/*
* JTAG ICE mkII definitions
@@ -335,7 +333,7 @@ typedef enum
* In appnote AVR067, struct device_descriptor is written with
* int/long field types. We cannot use them directly, as they were
* neither properly aligned for portability, nor did they care for
* endianess issues. We thus use arrays of unsigned chars, plus
* endianness issues. We thus use arrays of unsigned chars, plus
* conversion macros.
*/
struct device_descriptor

View File

@@ -17,8 +17,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
/*
* JTAG ICE mkI definitions

View File

@@ -59,7 +59,7 @@
#define CHECK 15 // Check LED needs changing
// Keep track of LED status and set LED 0 .. LED_N-1 physically on or off
static void led_direct(const PROGRAMMER *pgm, leds_t *ls, int led, int what) {
static void led_direct(const PROGRAMMER *pgm, Leds *ls, int led, int what) {
if(what ^ !!(ls->phy & (1<<led))) {
switch(led) {
case LED_RDY:
@@ -82,7 +82,7 @@ static void led_direct(const PROGRAMMER *pgm, leds_t *ls, int led, int what) {
}
// Physical level of LED setting, deal with max blinking frequency LED_FMAX
static void led_physical(const PROGRAMMER *pgm, leds_t *ls, int led, int what) {
static void led_physical(const PROGRAMMER *pgm, Leds *ls, int led, int what) {
if(led < 0 || led >= LED_N) // Sanity
return;
@@ -125,7 +125,7 @@ static void led_physical(const PROGRAMMER *pgm, leds_t *ls, int led, int what) {
// Logical level of setting LEDs, passes on to physical level
int led_set(const PROGRAMMER *pgm, int led) {
// leds should always be allocated, but if not use dummy
leds_t sanity = { 0, 0, 0, 0, 0, {0, } }, *ls = pgm->leds? pgm->leds: &sanity;
Leds sanity = { 0, 0, 0, 0, 0, {0, } }, *ls = pgm->leds? pgm->leds: &sanity;
int what = led >= 0 && led < LED_N && !(ls->now & (1<<led))? TON: CHECK;
switch(led) {
@@ -174,7 +174,7 @@ int led_clr(const PROGRAMMER *pgm, int led) {
}
// pgm->leds should always be allocated, but if not use dummy
leds_t sanity = { 0, 0, 0, 0, 0, {0, } }, *ls = pgm->leds? pgm->leds: &sanity;
Leds sanity = { 0, 0, 0, 0, 0, {0, } }, *ls = pgm->leds? pgm->leds: &sanity;
int what = ls->now & (1<<led)? TOFF: CHECK;
// Record logical level

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
*
* This program is free software; you can redistribute it and/or modify
@@ -17,8 +17,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
%{
#include <math.h>
#include <string.h>
@@ -149,7 +147,7 @@ INF [Ii][Nn][Ff]([Ii][Nn][Ii][Tt][Yy])?
(?x: desc | prog_modes | is_serialadapter | extra_features | baudrate | usbvid | usbdev | usbsn | usbvendor | usbproduct |
family_id | mcuid | n_interrupts | n_page_erase | n_boot_sections | boot_section_size |
family_id | mcuid | archnum | n_interrupts | n_page_erase | n_boot_sections | boot_section_size |
hvupdi_variant | stk500_devcode | avr910_devcode | chip_erase_delay | pagel | bs2 |
timeout | stabdelay | cmdexedelay | synchloops | bytedelay | pollindex | pollvalue | predelay | postdelay | pollmethod |
hventerstabdelay | progmodedelay | latchcycles | togglevtg | poweroffdelay | resetdelayms | resetdelayus | resetdelay | hvleavestabdelay |
@@ -159,7 +157,7 @@ INF [Ii][Nn][Ff]([Ii][Nn][Ii][Tt][Yy])?
paged | size | num_pages | initval | bitmask | n_word_writes | offset | min_write_delay | max_write_delay | pwroff_after_write |
readback_p1 | readback_p2 | mode | delay | blocksize | readsize ) {
/* struct components for PROGRAMMER, AVRPART and AVRMEM */
Component_t *cp = cfg_comp_search(yytext, current_strct);
Component *cp = cfg_comp_search(yytext, current_strct);
if(!cp) {
yyerror("unknown component %s in %s", yytext, cfg_strct_name(current_strct));
return YYERRCODE;
@@ -226,7 +224,8 @@ part { yylval=NULL; ccap(); current_strct = COMP_AVRPART; return K_P
pgm_enable { yylval=new_token(K_PGM_ENABLE); ccap(); return K_PGM_ENABLE; }
pgmled { yylval=NULL; ccap(); return K_PGMLED; }
pp_controlstack { yylval=NULL; ccap(); return K_PP_CONTROLSTACK; }
(programmer|serialadapter) { yylval=NULL; ccap(); current_strct = COMP_PROGRAMMER; return K_PROGRAMMER; }
(programmer|serialadapter) { yylval=NULL; ccap(); current_strct = COMP_PROGRAMMER;
cx->lex_kw_is_programmer = *yytext == 'p'; return K_PROGRAMMER; }
rdyled { yylval=NULL; ccap(); return K_RDYLED; }
read { yylval=new_token(K_READ); ccap(); return K_READ; }
read_hi { yylval=new_token(K_READ_HI); ccap(); return K_READ_HI; }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -254,7 +254,7 @@ typedef void * LNODEID;
typedef void * LISTID;
typedef struct avrmem AVRMEM;
typedef struct avrmem_alias AVRMEM_ALIAS;
typedef struct programmer_t PROGRAMMER;
typedef struct programmer PROGRAMMER;
typedef void pgm_initpgm(PROGRAMMER*);
enum msglvl {
@@ -405,9 +405,9 @@ typedef enum {
// https://stackoverflow.com/questions/11023940/how-do-i-get-swig-to-automatically-wrap-an-emulated-this-pointer-to-a-c-struct/11029809#11029809
// Make sure the wrapped function doesn't expect an input for this:
%typemap(in, numinputs=0) struct programmer_t *pgm "$1=NULL;"
%typemap(in, numinputs=0) struct programmer *pgm "$1=NULL;"
// Slightly abuse check typemap, but it needs to happen after the rest of the arguments have been set:
%typemap(check) struct programmer_t *pgm {
%typemap(check) struct programmer *pgm {
$1 = arg1;
}
@@ -518,19 +518,19 @@ typedef enum {
SWIG_exception_fail(SWIG_RuntimeError, "pgm->get_sck_period is NULL");
}
}
%typemap(check) (struct programmer_t *pgm_setup) {
%typemap(check) (struct programmer *pgm_setup) {
if ((arg1)->setup == NULL) {
SWIG_exception_fail(SWIG_RuntimeError, "pgm->setup is NULL");
}
}
%typemap(check) (struct programmer_t *pgm_teardown) {
%typemap(check) (struct programmer *pgm_teardown) {
if ((arg1)->teardown == NULL) {
SWIG_exception_fail(SWIG_RuntimeError, "pgm->teardown is NULL");
}
}
%immutable;
typedef struct programmer_t {
typedef struct programmer {
LISTID id;
const char *desc;
int prog_modes; // Programming interfaces, see #define PM_...
@@ -543,49 +543,49 @@ typedef struct programmer_t {
char type[PGM_TYPELEN];
// methods; they must *not* be declares as pointers
void initpgm (struct programmer_t *pgm); // Sets up the AVRDUDE programmer
int initialize (const struct programmer_t *pgm, const AVRPART *p); // Sets up the physical programmer
void setup (struct programmer_t *pgm);
void teardown (struct programmer_t *pgm);
int parseextparams (const struct programmer_t *pgm, const LISTID xparams);
int parseexitspecs (struct programmer_t *pgm, const char *s);
int open (struct programmer_t *pgm, const char *port);
void close (struct programmer_t *pgm);
void enable (struct programmer_t *pgm, const AVRPART *p);
void disable (const struct programmer_t *pgm);
int read_sib (const struct programmer_t *pgm, const AVRPART *p, char *sib);
void powerup (const struct programmer_t *pgm);
void powerdown (const struct programmer_t *pgm);
void initpgm (struct programmer *pgm); // Sets up the AVRDUDE programmer
int initialize (const struct programmer *pgm, const AVRPART *p); // Sets up the physical programmer
void setup (struct programmer *pgm);
void teardown (struct programmer *pgm);
int parseextparams (const struct programmer *pgm, const LISTID xparams);
int parseexitspecs (struct programmer *pgm, const char *s);
int open (struct programmer *pgm, const char *port);
void close (struct programmer *pgm);
void enable (struct programmer *pgm, const AVRPART *p);
void disable (const struct programmer *pgm);
int read_sib (const struct programmer *pgm, const AVRPART *p, char *sib);
void powerup (const struct programmer *pgm);
void powerdown (const struct programmer *pgm);
int chip_erase (const struct programmer_t *pgm, const AVRPART *p);
int term_keep_alive(const struct programmer_t *pgm, const AVRPART *p);
int end_programming(const struct programmer_t *pgm, const AVRPART *p);
int chip_erase (const struct programmer *pgm, const AVRPART *p);
int term_keep_alive(const struct programmer *pgm, const AVRPART *p);
int end_programming(const struct programmer *pgm, const AVRPART *p);
void print_parms (const struct programmer_t *pgm, FILE *f_parms);
int set_vtarget (const struct programmer_t *pgm, double vtarg_in);
int get_vtarget (const struct programmer_t *pgm, double *vtarg_out);
int set_varef (const struct programmer_t *pgm, unsigned int chan, double varef_in);
int get_varef (const struct programmer_t *pgm, unsigned int chan, double *varef_out);
int set_fosc (const struct programmer_t *pgm, double fosc_in);
int get_fosc (const struct programmer_t *pgm, double *fosc_out);
int set_sck_period (const struct programmer_t *pgm, double sck_in);
int get_sck_period (const struct programmer_t *pgm, double *sck_out);
void print_parms (const struct programmer *pgm, FILE *f_parms);
int set_vtarget (const struct programmer *pgm, double vtarg_in);
int get_vtarget (const struct programmer *pgm, double *vtarg_out);
int set_varef (const struct programmer *pgm, unsigned int chan, double varef_in);
int get_varef (const struct programmer *pgm, unsigned int chan, double *varef_out);
int set_fosc (const struct programmer *pgm, double fosc_in);
int get_fosc (const struct programmer *pgm, double *fosc_out);
int set_sck_period (const struct programmer *pgm, double sck_in);
int get_sck_period (const struct programmer *pgm, double *sck_out);
// Cached r/w API for terminal reads/writes
int write_byte_cached(const struct programmer_t *pgm, const AVRPART *p, const AVRMEM *m,
int write_byte_cached(const struct programmer *pgm, const AVRPART *p, const AVRMEM *m,
unsigned long addr, unsigned char value);
int read_byte_cached(const struct programmer_t *pgm, const AVRPART *p, const AVRMEM *m,
int read_byte_cached(const struct programmer *pgm, const AVRPART *p, const AVRMEM *m,
unsigned long addr, unsigned char *value);
int chip_erase_cached(const struct programmer_t *pgm, const AVRPART *p);
int page_erase_cached(const struct programmer_t *pgm, const AVRPART *p, const AVRMEM *m,
int chip_erase_cached(const struct programmer *pgm, const AVRPART *p);
int page_erase_cached(const struct programmer *pgm, const AVRPART *p, const AVRMEM *m,
unsigned int baseaddr);
int readonly (const struct programmer_t *pgm, const AVRPART *p, const AVRMEM *m,
int readonly (const struct programmer *pgm, const AVRPART *p, const AVRMEM *m,
unsigned int addr);
int flush_cache (const struct programmer_t *pgm, const AVRPART *p);
int reset_cache (const struct programmer_t *pgm, const AVRPART *p);
int flush_cache (const struct programmer *pgm, const AVRPART *p);
int reset_cache (const struct programmer *pgm, const AVRPART *p);
} PROGRAMMER;
%mutable;
%clear struct programmer_t *pgm;
%clear struct programmer *pgm;
// Config file handling
int init_config(void);

View File

@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#ifndef linux_ppdev_h
#define linux_ppdev_h

View File

@@ -733,7 +733,7 @@ void linuxgpio_initpgm(PROGRAMMER *pgm) {
#ifdef HAVE_LIBGPIOD
if (libgpiod_is_working()) {
msg_info("using libgpiod for linuxgpio\n");
msg_notice("using libgpiod for linuxgpio\n");
pgm->display = linuxgpio_libgpiod_display;
pgm->open = linuxgpio_libgpiod_open;
pgm->close = linuxgpio_libgpiod_close;
@@ -741,7 +741,7 @@ void linuxgpio_initpgm(PROGRAMMER *pgm) {
pgm->getpin = linuxgpio_libgpiod_getpin;
pgm->highpulsepin = linuxgpio_libgpiod_highpulsepin;
} else {
msg_info("falling back to sysfs for linuxgpio\n");
msg_notice("falling back to sysfs for linuxgpio\n");
}
#endif
}

View File

@@ -381,6 +381,8 @@ static int linuxspi_chip_erase(const PROGRAMMER *pgm, const AVRPART *p) {
static int linuxspi_parseexitspecs(PROGRAMMER *pgm, const char *sp) {
char *cp, *s, *str = mmt_strdup(sp);
int rv = 0;
bool help = false;
s = str;
while ((cp = strtok(s, ","))) {
@@ -393,35 +395,52 @@ static int linuxspi_parseexitspecs(PROGRAMMER *pgm, const char *sp) {
pgm->exit_reset = EXIT_RESET_DISABLED;
continue;
}
if (str_eq(cp, "help")) {
help = true;
rv = LIBAVRDUDE_EXIT;
}
if (!help) {
pmsg_error("invalid exitspec parameter -E %s\n", cp);
rv = -1;
}
msg_error("%s -c %s exitspec parameter options:\n", progname, pgmid);
msg_error(" -E reset Programmer will keep the reset line low after programming session\n");
msg_error(" -E noreset Programmer will not keep the reset line low after programming session\n");
msg_error(" -E help Show this help menu and exit\n");
mmt_free(str);
return -1;
return rv;
}
mmt_free(str);
return 0;
return rv;
}
static int linuxspi_parseextparams(const PROGRAMMER *pgm, const LISTID extparms) {
LNODEID ln;
const char *extended_param;
int rc = 0;
bool help = false;
for (ln = lfirst(extparms); ln; ln = lnext(ln)) {
extended_param = ldata(ln);
for (LNODEID ln = lfirst(extparms); ln; ln = lnext(ln)) {
const char *extended_param = ldata(ln);
if (str_eq(extended_param, "disable_no_cs")) {
my.disable_no_cs = 1;
continue;
}
if (str_eq(extended_param, "help")) {
msg_error("%s -c %s extended options:\n", progname, pgmid);
msg_error(" -xdisable_no_cs Do not use the SPI_NO_CS bit for the SPI driver\n");
msg_error(" -xhelp Show this help menu and exit\n");
return LIBAVRDUDE_EXIT;
help = true;
rc = LIBAVRDUDE_EXIT;
}
pmsg_error("invalid extended parameter '%s'\n", extended_param);
rc = -1;
if (!help) {
pmsg_error("invalid extended parameter -x %s\n", extended_param);
rc = -1;
}
msg_error("%s -c %s extended options:\n", progname, pgmid);
msg_error(" -x disable_no_cs Do not use the SPI_NO_CS bit for the SPI driver\n");
msg_error(" -x help Show this help menu and exit\n");
return rc;
}
return rc;

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2013 Kevin Cuzner <kevin@kevincuner.com>
* Copyright (C) 2013 Kevin Cuzner <kevin@kevincuzner.com>
*
* 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

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 1990-2004 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 1990-2004 Brian S. Dean <bsd@bdmicro.com>
*
* 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
@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
/*----------------------------------------------------------------------

View File

@@ -1,7 +1,7 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2000-2005 Brian S. Dean <bsd@bdmicro.com>
* Copyright Joerg Wunsch <j@uriah.heep.sax.de>
* Copyright (C) 2000-2005 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) Joerg Wunsch <j@uriah.heep.sax.de>
*
* 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
@@ -17,8 +17,6 @@
* 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.
@@ -52,10 +50,7 @@
#include "config.h"
#include "developer_opts.h"
char * progname;
char progbuf[PATH_MAX]; /* temporary buffer of spaces the same
length as progname; used for lining up
multiline messages */
char * progname = "avrdude";
static const char *avrdude_message_type(int msglvl) {
switch(msglvl) {
@@ -122,9 +117,20 @@ int avrdude_message2(FILE *fp, int lno, const char *file, const char *func, int
}
}
if(msgmode & MSG2_PROGNAME) {
fprintf(fp, "%s", progname);
if(verbose >= MSG_NOTICE && (msgmode & MSG2_FUNCTION))
if(msgmode & (MSG2_PROGNAME | MSG2_TYPE)) {
if(msgmode & MSG2_PROGNAME) {
fprintf(fp, "%s", progname);
bols[bi].bol = 0;
}
if(msgmode & MSG2_TYPE) {
const char *mt = avrdude_message_type(msglvl);
if(bols[bi].bol)
fprintf(fp, "%c%s", msgmode & (MSG2_UCFIRST)? toupper(*mt & 0xff): *mt, mt+1);
else
fprintf(fp, " %s", mt);
bols[bi].bol = 0;
}
if(verbose >= MSG_NOTICE2 && (msgmode & MSG2_FUNCTION))
fprintf(fp, " %s()", func);
if(verbose >= MSG_DEBUG && (msgmode & MSG2_FILELINE)) {
const char *pr = strrchr(file, '/'); // Only print basename
@@ -135,10 +141,7 @@ int avrdude_message2(FILE *fp, int lno, const char *file, const char *func, int
pr = pr? pr+1: file;
fprintf(fp, " [%s:%d]", pr, lno);
}
if(msgmode & MSG2_TYPE)
fprintf(fp, " %s", avrdude_message_type(msglvl));
fprintf(fp, ": ");
bols[bi].bol = 0;
} else if(msgmode & MSG2_INDENT1) {
fprintf(fp, "%*s", (int) strlen(progname)+1, "");
bols[bi].bol = 0;
@@ -168,8 +171,11 @@ int avrdude_message2(FILE *fp, int lno, const char *file, const char *func, int
return 0;
}
if(*p) {
fprintf(fp, "%s", p); // Finally: print!
if(*p) { // Finally: print!
if(bols[bi].bol && (msgmode & MSG2_UCFIRST))
fprintf(fp, "%c%s", toupper(*p & 0xff), p+1);
else
fprintf(fp, "%s", p);
bols[bi].bol = p[strlen(p)-1] == '\n';
}
mmt_free(p);
@@ -188,6 +194,9 @@ struct list_walk_cookie
const char *prefix;
};
libavrdude_context *cx; // Context pointer, eventually the only global variable
static LISTID updates = NULL;
static LISTID extended_params = NULL;
@@ -215,8 +224,8 @@ static void usage(void)
char *home = getenv("HOME");
size_t l = home? strlen(home): 0;
char *cfg = home && str_casestarts(usr_config, home)?
str_sprintf("~/%s", usr_config+l+(usr_config[l]=='/')):
str_sprintf("%s", usr_config);
mmt_sprintf("~/%s", usr_config+l+(usr_config[l]=='/')):
mmt_sprintf("%s", usr_config);
msg_error(
"Usage: %s [options]\n"
@@ -233,13 +242,13 @@ static void usage(void)
" -c <wildcard>/<flags> Run developer options for matched programmers,\n"
" e.g., -c 'ur*'/s for programmer info/definition\n"
" -A Disable trailing-0xff removal for file/AVR read\n"
" -D Disable auto erase for flash memory; implies -A\n"
" -D Disable auto-erase for flash memory; implies -A\n"
" -i <delay> ISP Clock Delay [in microseconds]\n"
" -P <port> Connection; -P ?s or -P ?sa lists serial ones\n"
" -r Reconnect to -P port after \"touching\" it; wait\n"
" 400 ms for each -r; needed for some USB boards\n"
" -F Override invalid signature or initial checks\n"
" -e Perform a chip erase\n"
" -e Perform a chip erase at the beginning\n"
" -O Perform RC oscillator calibration (see AVR053)\n"
" -t Run an interactive terminal when it is its turn\n"
" -T <terminal cmd line> Run terminal line when it is its turn\n"
@@ -249,7 +258,7 @@ static void usage(void)
" -n Do not write to the device whilst processing -U\n"
" -V Do not automatically verify during -U\n"
" -E <exitsp>[,<exitsp>] List programmer exit specifications\n"
" -x <extended_param> Pass <extended_param> to programmer, see -xhelp\n"
" -x <extended_param> Pass <extended_param> to programmer, see -x help\n"
" -v Verbose output; -v -v for more\n"
" -q Quell progress output; -q -q for less\n"
" -l logfile Use logfile rather than stderr for diagnostics\n"
@@ -373,7 +382,7 @@ static void list_parts(FILE *f, const char *prefix, LISTID avrparts, int pm) {
p = ldata(ln1);
// List part if pm or prog_modes uninitialised or if they are compatible otherwise
if(!pm || !p->prog_modes || (pm & p->prog_modes)) {
if(verbose < 2 && p->id[0] == '.') // hide ids starting with '.'
if(verbose < MSG_NOTICE2 && p->id[0] == '.') // hide ids starting with '.'
continue;
if((len = strlen(p->id)) > maxlen)
maxlen = len;
@@ -384,7 +393,7 @@ static void list_parts(FILE *f, const char *prefix, LISTID avrparts, int pm) {
p = ldata(ln1);
// List part if pm or prog_modes uninitialised or if they are compatible otherwise
if(!pm || !p->prog_modes || (pm & p->prog_modes)) {
if(verbose < 2 && p->id[0] == '.') // hide ids starting with '.'
if(verbose < MSG_NOTICE2 && p->id[0] == '.') // hide ids starting with '.'
continue;
if(verbose > 0)
fprintf(f, "%s%-*s = %-18s [%s:%d]", prefix, maxlen, p->id, p->desc, p->config_file, p->lineno);
@@ -434,11 +443,11 @@ static void replace_backslashes(char *s)
}
}
// Return 2 if str is * or starts with */, 1 if str contains / but is not a valid part, 0 otherwise
// Return whether a part/programmer string is a developer option and if so which type
static int dev_opt(const char *str) {
return
!str? 0:
str_eq(str, "*") || str_starts(str, "*/")? 2:
str_eq(str, "*") || str_starts(str, "*/s")? 2: // Print PART DEFINITIONS comment as well
strchr(str, '/') && !locate_part(part_list, str);
}
@@ -512,7 +521,9 @@ static int suggest_programmers(const char *programmer, LISTID programmers) {
return n;
}
static void programmer_not_found(const char *programmer, PROGRAMMER *pgm, int pmode) {
static void programmer_not_found(const char *programmer, const PROGRAMMER *pgm, const AVRPART *pt) {
int pmode = pt? pt->prog_modes: ~0;
if(!programmer || !*programmer) {
pmsg_error("no programmer has been specified on the command line or in the\n");
imsg_error("config file(s); specify one using the -c option and try again\n");
@@ -554,9 +565,15 @@ static void programmer_not_found(const char *programmer, PROGRAMMER *pgm, int pm
}
}
} else if(!pgm || !pgm->id || !lsize(pgm->id)) {
pmsg_error("cannot find programmer id %s\n", programmer);
suggest_programmers(programmer, programmers);
msg_info("use -c? to see all possible programmers\n");
PROGRAMMER *pg = locate_programmer(programmers, programmer);
if(!pgm && pt && pg && !(pg->prog_modes & pmode)) {
pmsg_error("programmer %s and part %s have no programming modes in common\n", programmer, pt->desc);
msg_info("use -c? -p %s to see all possible programmers for %s\n", pt->desc, pt->desc);
} else {
pmsg_error("cannot find programmer id %s\n", programmer);
suggest_programmers(programmer, programmers);
msg_info("use -c? to see all possible programmers\n");
}
} else
pmsg_error("programmer %s lacks %s setting\n", programmer,
!pgm->prog_modes? "prog_modes": !pgm->initpgm? "type": "some");
@@ -610,7 +627,6 @@ int main(int argc, char * argv [])
int exitrc; /* exit code for main() */
int i; /* general loop counter */
int ch; /* options flag */
int len; /* length for various strings */
struct avrpart * p; /* which avr part we are programming */
AVRMEM * sig; /* signature data */
struct stat sb;
@@ -619,6 +635,7 @@ int main(int argc, char * argv [])
/* options / operating mode variables */
int erase; /* 1=erase chip, 0=don't */
int flashread; /* 1=flash is going to be read, 0=no flash reads */
int calibrate; /* 1=calibrate RC oscillator, 0=don't */
int no_avrduderc; /* 1=don't load personal conf file */
char * port; /* device port (/dev/xxx) */
@@ -642,6 +659,7 @@ int main(int argc, char * argv [])
char * logfile; /* Use logfile rather than stderr for diagnostics */
enum updateflags uflags = UF_AUTO_ERASE | UF_VERIFY; /* Flags for do_op() */
cx = mmt_malloc(sizeof *cx); // Allocate and initialise context structure
(void) avr_ustimestamp(); // Base timestamps from program start
#ifdef _MSC_VER
@@ -712,6 +730,7 @@ int main(int argc, char * argv [])
partdesc = NULL;
port = NULL;
erase = 0;
flashread = 0;
calibrate = 0;
no_avrduderc = 0;
p = NULL;
@@ -731,22 +750,14 @@ int main(int argc, char * argv [])
ce_delayed = 0;
logfile = NULL;
len = strlen(progname) + 2;
for (i=0; i<len; i++)
progbuf[i] = ' ';
progbuf[i] = 0;
/*
* check for no arguments
*/
if (argc == 1) {
if(argc == 1) { // No arguments?
usage();
return 0;
}
// Determine the location of personal configuration file
#if defined(WIN32)
win_usr_config_set(usr_config);
win_set_path(usr_config, sizeof usr_config, USER_CONF_FILE);
#else
usr_config[0] = 0;
if(!concatpath(usr_config, getenv("XDG_CONFIG_HOME"), XDG_USER_CONF_FILE, sizeof usr_config))
@@ -759,7 +770,7 @@ int main(int argc, char * argv [])
/*
* process command line arguments
*/
while ((ch = getopt(argc,argv,"?Ab:B:c:C:DeE:Fi:l:nNp:OP:qrstT:U:uvVx:yY:")) != -1) {
while ((ch = getopt(argc, argv, "?Ab:B:c:C:DeE:Fi:l:nNp:OP:qrstT:U:uvVx:yY")) != -1) {
switch (ch) {
case 'b': /* override default programmer baud rate */
@@ -818,12 +829,12 @@ int main(int argc, char * argv [])
}
break;
case 'D': /* disable auto erase */
case 'D': /* disable auto-erase */
uflags &= ~UF_AUTO_ERASE;
/* fall through */
case 'A': /* explicit disabling of trailing-0xff removal */
disable_trailing_ff_removal();
cx->avr_disableffopt = 1;
break;
case 'e': /* perform a chip erase */
@@ -856,7 +867,7 @@ int main(int argc, char * argv [])
calibrate = 1;
break;
case 'p' : /* specify AVR part */
case 'p': /* specify AVR part */
partdesc = optarg;
break;
@@ -864,7 +875,7 @@ int main(int argc, char * argv [])
port = mmt_strdup(optarg);
break;
case 'q' : /* Quell progress output */
case 'q': /* Quell progress output */
quell_progress++ ;
break;
@@ -888,7 +899,7 @@ int main(int argc, char * argv [])
case 'U':
upd = parse_op(optarg);
if (upd == NULL) {
pmsg_error("unable to parse update operation '%s'\n", optarg);
pmsg_error("unable to parse update operation %s\n", optarg);
exit(1);
}
ladd(updates, upd);
@@ -907,9 +918,6 @@ int main(int argc, char * argv [])
break;
case 'y':
pmsg_error("erase cycle counter no longer supported\n");
break;
case 'Y':
pmsg_error("erase cycle counter no longer supported\n");
break;
@@ -928,6 +936,9 @@ int main(int argc, char * argv [])
}
if (logfile != NULL) {
FILE *newstderr = freopen(logfile, "w", stderr);
if (newstderr == NULL) {
@@ -939,7 +950,7 @@ int main(int argc, char * argv [])
size_t ztest;
if(1 != sscanf("42", "%zi", &ztest) || ztest != 42)
pmsg_warning("Linked C library does not conform to C99; %s may not work as expected\n", progname);
pmsg_warning("linked C library does not conform to C99; %s may not work as expected\n", progname);
/* search for system configuration file unless -C conffile was given */
if (strlen(sys_config) == 0) {
@@ -1020,7 +1031,7 @@ int main(int argc, char * argv [])
if (!sys_config_found) {
// 3. Check CONFIG_DIR/avrdude.conf
#if defined(WIN32)
win_sys_config_set(sys_config);
win_set_path(sys_config, sizeof sys_config, SYSTEM_CONF_FILE);
#else
strcpy(sys_config, CONFIG_DIR);
i = strlen(sys_config);
@@ -1045,15 +1056,13 @@ int main(int argc, char * argv [])
* Print out an identifying string so folks can tell what version
* they are running
*/
msg_notice("\n");
pmsg_notice("Version %s\n", AVRDUDE_FULL_VERSION);
imsg_notice("Copyright the AVRDUDE authors;\n");
imsg_notice("see https://github.com/avrdudes/avrdude/blob/main/AUTHORS\n\n");
pmsg_notice("%s version %s\n", progname, AVRDUDE_FULL_VERSION);
pmsg_notice("Copyright see https://github.com/avrdudes/avrdude/blob/main/AUTHORS\n\n");
if(*sys_config) {
char *real_sys_config = realpath(sys_config, NULL);
if(real_sys_config) {
imsg_notice("System wide configuration file is %s\n", real_sys_config);
pmsg_notice("system wide configuration file is %s\n", real_sys_config);
} else
pmsg_warning("cannot determine realpath() of config file %s: %s\n", sys_config, strerror(errno));
@@ -1066,12 +1075,11 @@ int main(int argc, char * argv [])
}
if (usr_config[0] != 0 && !no_avrduderc) {
imsg_notice("User configuration file is %s\n", usr_config);
int ok = (rc = stat(usr_config, &sb)) >= 0 && (sb.st_mode & S_IFREG);
pmsg_notice("user configuration file %s%s%s\n", ok? "is ": "", usr_config,
rc<0? " does not exist": !(sb.st_mode & S_IFREG)? " is not a regular file, skipping": "");
rc = stat(usr_config, &sb);
if ((rc < 0) || ((sb.st_mode & S_IFREG) == 0))
imsg_notice("User configuration file does not exist or is not a regular file, skipping\n");
else {
if(ok) {
rc = read_config(usr_config);
if (rc) {
pmsg_error("unable to process user configuration file %s\n", usr_config);
@@ -1081,7 +1089,7 @@ int main(int argc, char * argv [])
}
if(!str_eq(avrdude_conf_version, AVRDUDE_FULL_VERSION)) {
pmsg_warning("System wide configuration file version (%s)\n", avrdude_conf_version);
pmsg_warning("system wide configuration file version (%s)\n", avrdude_conf_version);
imsg_warning("does not match Avrdude build version (%s)\n", AVRDUDE_FULL_VERSION);
}
@@ -1091,7 +1099,7 @@ int main(int argc, char * argv [])
for (ln1=lfirst(additional_config_files); ln1; ln1=lnext(ln1)) {
p = ldata(ln1);
imsg_notice("additional configuration file is %s\n", p);
pmsg_notice("additional configuration file is %s\n", p);
rc = read_config(p);
if (rc) {
@@ -1115,8 +1123,8 @@ int main(int argc, char * argv [])
pgmid = cache_string(default_programmer);
// Developer options to print parts and/or programmer entries of avrdude.conf
int dev_opt_c = dev_opt(pgmid); // -c <wildcard>/[sSArt]
int dev_opt_p = dev_opt(partdesc); // -p <wildcard>/[dsSArcow*t]
int dev_opt_c = dev_opt(pgmid); // -c <wildcard>/[dASsrtiBUPTIJWHQ]
int dev_opt_p = dev_opt(partdesc); // -p <wildcard>/[cdoASsrw*tiBUPTIJWHQ]
if(dev_opt_c || dev_opt_p) { // See -c/h and or -p/h
dev_output_pgm_part(dev_opt_c, pgmid, dev_opt_p, partdesc);
@@ -1153,7 +1161,7 @@ int main(int argc, char * argv [])
if(pgmid && *pgmid && explicit_c) {
PROGRAMMER *pgm = locate_programmer_starts_set(programmers, pgmid, &pgmid, NULL);
if(!pgm || !is_programmer(pgm)) {
programmer_not_found(pgmid, pgm, ~0);
programmer_not_found(pgmid, pgm, NULL);
exit(1);
}
msg_error("\nValid parts for programmer %s are:\n", pgmid);
@@ -1196,14 +1204,14 @@ int main(int argc, char * argv [])
msg_notice("\n");
if(!pgmid || !*pgmid) {
programmer_not_found(NULL, NULL, ~0);
programmer_not_found(NULL, NULL, NULL);
exit(1);
}
p = partdesc && *partdesc? locate_part(part_list, partdesc): NULL;
pgm = locate_programmer_starts_set(programmers, pgmid, &pgmid, p);
if (pgm == NULL || !is_programmer(pgm)) {
programmer_not_found(pgmid, pgm, p? p->prog_modes: ~0);
programmer_not_found(pgmid, pgm, p);
exit(1);
}
@@ -1236,7 +1244,7 @@ int main(int argc, char * argv [])
const char *extended_param = ldata(ln);
if (str_eq(extended_param, "help")) {
msg_error("%s -c %s extended options:\n", progname, pgmid);
msg_error(" -xhelp Show this help menu and exit\n");
msg_error(" -x help Show this help menu and exit\n");
exit(0);
}
else
@@ -1247,7 +1255,7 @@ int main(int argc, char * argv [])
if(rc == LIBAVRDUDE_EXIT)
exit(0);
if(rc < 0) {
pmsg_error("unable to parse extended parameter list\n");
pmsg_error("unable to parse list of -x parameters\n");
exit(1);
}
}
@@ -1287,11 +1295,11 @@ int main(int argc, char * argv [])
}
}
int is_dryrun = str_eq(pgmid, "dryrun") || (dry && pgm->initpgm == dry->initpgm);
int is_dryrun = str_eq(pgm->type, "dryrun") || (dry && pgm->initpgm == dry->initpgm);
if((port[0] == 0 || str_eq(port, "unknown")) && !is_dryrun) {
msg_error("\n");
pmsg_error("no port has been specified on the command line or in the config file\n");
imsg_error("specify a port using the -P option and try again\n\n");
pmsg_error("no port has been specified on the command line or in the config file;\n");
imsg_error("specify a port using the -P option and try again\n");
exit(1);
}
@@ -1319,6 +1327,7 @@ int main(int argc, char * argv [])
// Use libserialport to find the actual serial port
ser = locate_programmer(programmers, port_tok[0]);
if (is_serialadapter(ser)) {
#ifdef HAVE_LIBSERIALPORT
int rv = setport_from_serialadapter(&port, ser, port_tok[1]);
if (rv == -1) {
pmsg_warning("serial adapter %s", port_tok[0]);
@@ -1332,6 +1341,7 @@ int main(int argc, char * argv [])
print_ports = false;
if(rv)
ser = NULL;
#endif
} else if(str_eq(port_tok[0], DEFAULT_USB)) {
// Port or usb:[vid]:[pid]
int vid, pid;
@@ -1357,37 +1367,37 @@ int main(int argc, char * argv [])
// Open the programmer
if (verbose > 0) {
if(!is_dryrun)
imsg_notice("Using port : %s\n", port);
imsg_notice("Using programmer : %s\n", pgmid);
pmsg_notice("using port : %s\n", port);
pmsg_notice("using programmer : %s\n", pgmid);
}
if (baudrate && !pgm->baudrate && !default_baudrate) { // none set
imsg_notice("Setting baud rate : %d\n", baudrate);
pmsg_notice("setting baud rate : %d\n", baudrate);
pgm->baudrate = baudrate;
}
else if (baudrate && ((pgm->baudrate && pgm->baudrate != baudrate)
|| (!pgm->baudrate && default_baudrate != baudrate))) {
imsg_notice("Overriding baud rate : %d\n", baudrate);
pmsg_notice("overriding baud rate : %d\n", baudrate);
pgm->baudrate = baudrate;
}
else if (!pgm->baudrate && default_baudrate) {
imsg_notice("Default baud rate : %d\n", default_baudrate);
pmsg_notice("default baud rate : %d\n", default_baudrate);
pgm->baudrate = default_baudrate;
}
else if (ser && ser->baudrate) {
imsg_notice("Serial baud rate : %d\n", ser->baudrate);
pmsg_notice("serial baud rate : %d\n", ser->baudrate);
pgm->baudrate = ser->baudrate;
}
else if (pgm->baudrate != 0)
imsg_notice("Programmer baud rate : %d\n", pgm->baudrate);
pmsg_notice("programmer baud rate : %d\n", pgm->baudrate);
if (bitclock != 0.0) {
imsg_notice("Setting bit clk period: %.1f us\n", bitclock);
pmsg_notice("setting bit clk period: %.1f us\n", bitclock);
pgm->bitclock = bitclock * 1e-6;
}
if (ispdelay != 0) {
imsg_notice("Setting ISP clk delay : %3i us\n", ispdelay);
pmsg_notice("setting ISP clk delay : %3i us\n", ispdelay);
pgm->ispdelay = ispdelay;
}
@@ -1401,9 +1411,11 @@ int main(int argc, char * argv [])
pmsg_error("unable to open port %s for programmer %s\n", port, pgmid);
skipopen:
if (print_ports && pgm->conntype == CONNTYPE_SERIAL) {
#ifdef HAVE_LIBSERIALPORT
list_available_serialports(programmers);
if(touch_1200bps == 1)
pmsg_info("alternatively, try -rr or -rrr for longer delays\n");
#endif
}
exitrc = 1;
pgm->ppidata = 0; /* clear all bits at exit */
@@ -1428,11 +1440,14 @@ skipopen:
if (pgm->parseexitspecs == NULL) {
pmsg_warning("-E option not supported by this programmer type\n");
exitspecs = NULL;
}
else if (pgm->parseexitspecs(pgm, exitspecs) < 0) {
usage();
exitrc = 1;
goto main_exit;
} else {
int rc = pgm->parseexitspecs(pgm, exitspecs);
if(rc == LIBAVRDUDE_EXIT)
exit(0);
if(rc < 0) {
pmsg_error("unable to parse list of -E parameters\n");
exit(1);
}
}
}
@@ -1488,18 +1503,20 @@ skipopen:
pmsg_error("programmer does not support RC oscillator calibration\n");
exitrc = 1;
} else {
pmsg_info("performing RC oscillator calibration\n");
pmsg_notice2("performing RC oscillator calibration\n");
exitrc = pgm->perform_osccal(pgm);
}
if (exitrc == 0)
pmsg_info("calibration value is now stored in EEPROM at address 0\n");
if (exitrc)
pmsg_error("RC calibration unsuccesful\n");
else
pmsg_notice("calibration value is now stored in EEPROM at address 0\n");
goto main_exit;
}
if (verbose > 0 && quell_progress < 2) {
avr_display(stderr, p, progbuf, verbose);
if (verbose > 1)
msg_notice("\n");
msg_notice2("\n");
programmer_display(pgm, progbuf);
}
@@ -1524,19 +1541,19 @@ skipopen:
exitrc = 0;
goto main_exit;
}
pmsg_error("initialization failed, rc=%d\n", rc);
pmsg_error("initialization failed (rc = %d)\n", rc);
if (rc == -2)
imsg_error("the programmer ISP clock is too fast for the target\n");
imsg_error(" - the programmer ISP clock is too fast for the target\n");
else
imsg_error("- double check the connections and try again\n");
imsg_error(" - double check the connections and try again\n");
if(str_eq(pgm->type, "serialupdi") || str_eq(pgm->type, "SERBB"))
imsg_error("- use -b to set lower baud rate, e.g. -b %d\n", baudrate? baudrate/2: 57600);
imsg_error(" - use -b to set lower baud rate, e.g. -b %d\n", baudrate? baudrate/2: 57600);
else
imsg_error("- use -B to set lower the bit clock frequency, e.g. -B 125kHz\n");
imsg_error(" - use -B to set lower the bit clock frequency, e.g. -B 125kHz\n");
if (!ovsigck) {
imsg_error("- use -F to override this check\n");
imsg_error(" - use -F to override this check\n");
exitrc = 1;
goto main_exit;
}
@@ -1545,7 +1562,8 @@ skipopen:
// Indicate programmer is ready
led_set(pgm, LED_RDY);
pmsg_info("AVR device initialized and ready to accept instructions\n");
msg_notice("\n");
pmsg_notice("AVR device initialized and ready to accept instructions\n");
/*
* Let's read the signature bytes to make sure there is at least a
@@ -1573,16 +1591,18 @@ skipopen:
char sib[AVR_SIBLEN + 1];
pgm->read_sib(pgm, p, sib);
pmsg_notice("System Information Block: %s\n", sib);
pmsg_info("received FamilyID: \"%.*s\"\n", AVR_FAMILYIDLEN, sib);
if (strncmp(p->family_id, sib, AVR_FAMILYIDLEN))
pmsg_error("expected FamilyID: \"%s\"\n", p->family_id);
if (strncmp(p->family_id, sib, AVR_FAMILYIDLEN)) {
pmsg_warning("received FamilyID: \"%.*s\"\n", AVR_FAMILYIDLEN, sib);
imsg_warning("expected FamilyID: \"%s\"\n", p->family_id);
} else
pmsg_notice("received FamilyID: \"%.*s\"\n", AVR_FAMILYIDLEN, sib);
}
if(erase) {
erase = 0;
if (uflags & UF_NOWRITE) {
pmsg_warning("conflicting -e and -n options specified, NOT erasing chip\n");
} else {
pmsg_info("erasing chip\n");
pmsg_notice("trying to unlock the chip\n");
exitrc = avr_unlock(pgm, p);
if(exitrc)
goto main_exit;
@@ -1590,12 +1610,12 @@ skipopen:
}
}
if (!ovsigck) {
imsg_error("double check chip or use -F to override this check\n");
pmsg_error("double check chip or use -F to override this check\n");
exitrc = 1;
goto main_exit;
}
}
pmsg_error("unable to read signature data, rc=%d\n", rc);
pmsg_error("unable to read signature data (rc = %d)\n", rc);
if(!ovsigck) {
imsg_error("use -F to override this check\n");
exitrc = 1;
@@ -1607,60 +1627,71 @@ skipopen:
sig = avr_locate_signature(p);
if (sig == NULL)
pmsg_warning("signature memory not defined for device %s\n", p->desc);
else {
const char *mculist = str_ccmcunames_signature(sig->buf, pgm->prog_modes);
if(!*mculist) { // No matching signatures?
if(p->prog_modes & PM_UPDI) { // UPDI parts have different(!) offsets for signature
int k, n = 0; // Gather list of known different signature offsets
unsigned myoff = sig->offset, offlist[10];
for(LNODEID ln1 = lfirst(part_list); ln1; ln1 = lnext(ln1)) {
AVRMEM *m = avr_locate_signature(ldata(ln1));
if(m && m->offset != myoff) {
for(k=0; k<n; k++)
if(m->offset == offlist[k])
break;
if(k == n && k < (int) (sizeof offlist/sizeof*offlist))
offlist[n++] = m->offset;
}
}
// Now go through the list of other(!) sig offsets and try these
for(k=0; k<n; k++) {
sig->offset = offlist[k];
if(avr_signature(pgm, p) >= 0)
if(*(mculist = str_ccmcunames_signature(sig->buf, pgm->prog_modes)))
break;
}
sig->offset = myoff;
}
}
if (sig != NULL) {
int ff, zz;
pmsg_info("device signature = 0x");
ff = zz = 1;
int ff = 1, zz = 1;
for (i=0; i<sig->size; i++) {
msg_info("%02x", sig->buf[i]);
if (sig->buf[i] != 0xff)
ff = 0;
if (sig->buf[i] != 0x00)
zz = 0;
}
bool signature_matches = sig->size >= 3 && !memcmp(sig->buf, p->signature, 3);
int showsig = !signature_matches || ff || zz || verbose > 0;
if(showsig)
pmsg_info("device signature =%s", str_cchex(sig->buf, sig->size, 1));
if(*mculist && showsig)
msg_info(" (%s)", is_dryrun? p->desc: mculist);
bool signature_matches =
sig->size == 3 &&
sig->buf[0] == p->signature[0] &&
sig->buf[1] == p->signature[1] &&
sig->buf[2] == p->signature[2];
if (quell_progress < 2) {
AVRPART *part;
if((part = locate_part_by_signature_pm(part_list, sig->buf, sig->size, pgm->prog_modes)) ||
(part = locate_part_by_signature(part_list, sig->buf, sig->size)))
msg_info(" (probably %s)", signature_matches? p->id: part->id);
}
if (ff || zz) {
if (ff || zz) { // All three bytes are 0xff or all three bytes are 0x00
if (++attempt < 3) {
waittime *= 5;
msg_info(" (retrying)\n");
goto sig_again;
}
msg_info("\n");
pmsg_error("Yikes! Invalid device signature.\n");
pmsg_error("invalid device signature\n");
if (!ovsigck) {
pmsg_error("expected signature for %s is %02X %02X %02X\n", p->desc,
p->signature[0], p->signature[1], p->signature[2]);
imsg_error("Double check connections and try again, or use -F to override\n");
imsg_error("this check.\n\n");
pmsg_error("expected signature for %s is%s; double\n", p->desc, str_cchex(p->signature, 3, 1));
imsg_error("check connections and try again, or use -F to carry on regardless\n");
exitrc = 1;
goto main_exit;
}
} else {
} else if(showsig) {
msg_info("\n");
}
if (!signature_matches) {
if (ovsigck) {
pmsg_warning("expected signature for %s is %02X %02X %02X\n", p->desc,
p->signature[0], p->signature[1], p->signature[2]);
pmsg_warning("expected signature for %s is%s\n", p->desc, str_cchex(p->signature, 3, 1));
} else {
pmsg_error("expected signature for %s is %02X %02X %02X\n", p->desc,
p->signature[0], p->signature[1], p->signature[2]);
imsg_error("double check chip or use -F to override this check\n");
pmsg_error("expected signature for %s is%s; double\n", p->desc, str_cchex(p->signature, 3, 1));
imsg_error("check chip or use -F to carry on regardless\n");
exitrc = 1;
goto main_exit;
}
@@ -1669,26 +1700,37 @@ skipopen:
}
if (uflags & UF_AUTO_ERASE) {
if ((p->prog_modes & PM_PDI) && pgm->page_erase && lsize(updates) > 0) {
pmsg_info("Note: programmer supports page erase for Xmega devices.\n");
imsg_info("Each page will be erased before programming it, but no chip erase is performed.\n");
imsg_info("To disable page erases, specify the -D option; for a chip-erase, use the -e option.\n");
} else {
AVRMEM * m;
const char *memname = p->prog_modes & PM_PDI? "application": "flash";
uflags &= ~UF_AUTO_ERASE;
for (ln=lfirst(updates); ln; ln=lnext(ln)) {
if((p->prog_modes & (PM_PDI | PM_UPDI)) && pgm->page_erase && lsize(updates) > 0) {
for(ln=lfirst(updates); ln; ln=lnext(ln)) {
upd = ldata(ln);
if(!upd->memstr)
continue;
m = avr_locate_mem(p, upd->memstr);
if (m == NULL)
continue;
if(str_eq(m->desc, memname) && upd->op == DEVICE_WRITE) {
erase = 1;
pmsg_info("Note: %s memory has been specified, an erase cycle will be performed.\n", memname);
imsg_info("To disable this feature, specify the -D option.\n");
if(upd->memstr && upd->op == DEVICE_WRITE && memlist_contains_flash(upd->memstr, p)) {
cx->avr_disableffopt = 1; // Must write full flash file including trailing 0xff
pmsg_notice("NOT erasing chip as page erase will be used for new flash%s contents;\n",
avr_locate_bootrow(p)? "/bootrow": "");
imsg_notice("unprogrammed flash contents remains: use -e for an explicit chip-erase\n");
break;
}
}
} else {
uflags &= ~UF_AUTO_ERASE;
for(ln=lfirst(updates); ln; ln=lnext(ln)) {
upd = ldata(ln);
if(upd->cmdline && *str_ltrim(upd->cmdline) && str_starts("erase", str_ltrim(upd->cmdline)))
break; // -T erase already erases the chip: no auto-erase needed
if(upd->cmdline || (upd->memstr && // Might be reading flash?
(upd->op == DEVICE_READ || upd->op == DEVICE_VERIFY) &&
memlist_contains_flash(upd->memstr, p)))
flashread = 1;
if(upd->memstr && upd->op == DEVICE_WRITE && memlist_contains_flash(upd->memstr, p)) {
if(flashread) {
pmsg_info("NOT auto-erasing chip as flash might need reading before writing to it\n");
} else {
erase = 1;
pmsg_notice("auto-erasing chip as flash memory needs programming (-U %s:w:...)\n", upd->memstr);
imsg_notice("specify the -D option to disable this feature\n");
}
break;
}
}
@@ -1701,16 +1743,21 @@ skipopen:
* before the chip can accept new programming
*/
if (uflags & UF_NOWRITE) {
pmsg_warning("%s-n specified, NOT erasing chip\n", explicit_e? "conflicting -e and ": "");
if(explicit_e)
pmsg_warning("conflicting -e and -n specified, NOT erasing chip\n");
else
pmsg_notice("-n specified, NOT erasing chip\n");
} else {
pmsg_info("erasing chip\n");
exitrc = avr_chip_erase(pgm, p);
if(exitrc == LIBAVRDUDE_SOFTFAIL) {
imsg_info("delaying chip erase until first -U upload to flash\n");
pmsg_notice("delaying chip erase until first -U upload to flash\n");
ce_delayed = 1;
exitrc = 0;
} else if(exitrc)
} else if(exitrc) {
pmsg_error("chip erase failed\n");
goto main_exit;
} else
pmsg_notice("erased chip\n");
}
}
@@ -1721,6 +1768,8 @@ skipopen:
int wrmem = 0, terminal = 0;
if(lsize(updates) <= 1)
uflags |= UF_NOHEADING;
for (ln=lfirst(updates); ln; ln=lnext(ln)) {
const AVRMEM *m;
upd = ldata(ln);
@@ -1757,7 +1806,8 @@ main_exit:
pgm->close(pgm);
}
msg_info("\n%s done. Thank you.\n\n", progname);
msg_info("\n");
pmsg_info("%s done. Thank you.\n", progname);
return ce_delayed? 1: exitrc;
}

View File

@@ -75,12 +75,11 @@
#define MICRONUCLEUS_DEFAULT_TIMEOUT 500
#define MICRONUCLEUS_MAX_MAJOR_VERSION 2
#define PDATA(pgm) ((pdata_t*)(pgm->cookie))
#define PDATA(pgm) ((struct pdata *)(pgm->cookie))
//-----------------------------------------------------------------------------
typedef struct pdata
{
struct pdata {
usb_dev_handle* usb_handle;
// Extended parameters
bool wait_until_device_present;
@@ -102,7 +101,7 @@ typedef struct pdata
uint16_t user_reset_vector; // reset vector of user program
bool write_last_page; // last page already programmed
bool start_program; // require start after flash
} pdata_t;
};
//-----------------------------------------------------------------------------
@@ -111,8 +110,7 @@ static void delay_ms(uint32_t duration)
usleep(duration * 1000);
}
static int micronucleus_check_connection(pdata_t* pdata)
{
static int micronucleus_check_connection(struct pdata *pdata) {
if (pdata->major_version >= 2)
{
uint8_t buffer[6] = { 0 };
@@ -139,8 +137,7 @@ static int micronucleus_check_connection(pdata_t* pdata)
}
}
static bool micronucleus_is_device_responsive(pdata_t* pdata, struct usb_device* device)
{
static bool micronucleus_is_device_responsive(struct pdata *pdata, struct usb_device *device) {
pdata->usb_handle = usb_open(device);
if (pdata->usb_handle == NULL)
{
@@ -155,8 +152,7 @@ static bool micronucleus_is_device_responsive(pdata_t* pdata, struct usb_device*
return result >= 0;
}
static int micronucleus_reconnect(pdata_t* pdata)
{
static int micronucleus_reconnect(struct pdata *pdata) {
struct usb_device* device = usb_device(pdata->usb_handle);
usb_close(pdata->usb_handle);
@@ -176,8 +172,7 @@ static int micronucleus_reconnect(pdata_t* pdata)
return -1;
}
static int micronucleus_get_bootloader_info_v1(pdata_t* pdata)
{
static int micronucleus_get_bootloader_info_v1(struct pdata *pdata) {
uint8_t buffer[4] = { 0 };
int result = usb_control_msg(
pdata->usb_handle,
@@ -243,8 +238,7 @@ static int micronucleus_get_bootloader_info_v1(pdata_t* pdata)
return 0;
}
static int micronucleus_get_bootloader_info_v2(pdata_t* pdata)
{
static int micronucleus_get_bootloader_info_v2(struct pdata *pdata) {
uint8_t buffer[6] = { 0 };
int result = usb_control_msg(
pdata->usb_handle,
@@ -284,8 +278,7 @@ static int micronucleus_get_bootloader_info_v2(pdata_t* pdata)
return 0;
}
static int micronucleus_get_bootloader_info(pdata_t* pdata)
{
static int micronucleus_get_bootloader_info(struct pdata *pdata) {
if (pdata->major_version >= 2)
{
return micronucleus_get_bootloader_info_v2(pdata);
@@ -296,8 +289,7 @@ static int micronucleus_get_bootloader_info(pdata_t* pdata)
}
}
static void micronucleus_dump_device_info(pdata_t* pdata)
{
static void micronucleus_dump_device_info(struct pdata *pdata) {
pmsg_notice("Bootloader version: %d.%d\n", pdata->major_version, pdata->minor_version);
imsg_notice("Available flash size: %u\n", pdata->flash_size);
imsg_notice("Page size: %u\n", pdata->page_size);
@@ -308,8 +300,7 @@ static void micronucleus_dump_device_info(pdata_t* pdata)
imsg_notice("Signature2: 0x%02X\n", pdata->signature2);
}
static int micronucleus_erase_device(pdata_t* pdata)
{
static int micronucleus_erase_device(struct pdata *pdata) {
pmsg_debug("micronucleus_erase_device()\n");
int result = usb_control_msg(
@@ -351,8 +342,7 @@ static int micronucleus_erase_device(pdata_t* pdata)
return 0;
}
static int micronucleus_patch_reset_vector(pdata_t* pdata, uint8_t* buffer)
{
static int micronucleus_patch_reset_vector(struct pdata *pdata, uint8_t *buffer) {
// Save user reset vector.
uint16_t word0 = (buffer[1] << 8) | buffer[0];
uint16_t word1 = (buffer[3] << 8) | buffer[2];
@@ -394,8 +384,7 @@ static int micronucleus_patch_reset_vector(pdata_t* pdata, uint8_t* buffer)
return 0;
}
static void micronucleus_patch_user_vector(pdata_t* pdata, uint8_t* buffer)
{
static void micronucleus_patch_user_vector(struct pdata *pdata, uint8_t *buffer) {
uint16_t user_reset_addr = pdata->bootloader_start - 4;
uint16_t address = pdata->bootloader_start - pdata->page_size;
if (user_reset_addr > 0x2000)
@@ -416,8 +405,7 @@ static void micronucleus_patch_user_vector(pdata_t* pdata, uint8_t* buffer)
}
}
static int micronucleus_write_page_v1(pdata_t* pdata, uint32_t address, uint8_t* buffer, uint32_t size)
{
static int micronucleus_write_page_v1(struct pdata *pdata, uint32_t address, uint8_t *buffer, uint32_t size) {
int result = usb_control_msg(
pdata->usb_handle,
USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
@@ -434,8 +422,7 @@ static int micronucleus_write_page_v1(pdata_t* pdata, uint32_t address, uint8_t*
return 0;
}
static int micronucleus_write_page_v2(pdata_t* pdata, uint32_t address, uint8_t* buffer, uint32_t size)
{
static int micronucleus_write_page_v2(struct pdata *pdata, uint32_t address, uint8_t *buffer, uint32_t size) {
int result = usb_control_msg(
pdata->usb_handle,
USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
@@ -470,8 +457,7 @@ static int micronucleus_write_page_v2(pdata_t* pdata, uint32_t address, uint8_t*
return 0;
}
static int micronucleus_write_page(pdata_t* pdata, uint32_t address, uint8_t* buffer, uint32_t size)
{
static int micronucleus_write_page(struct pdata *pdata, uint32_t address, uint8_t *buffer, uint32_t size) {
pmsg_debug("micronucleus_write_page(address=0x%04X, size=%d)\n", address, size);
if (address == 0)
@@ -522,8 +508,7 @@ static int micronucleus_write_page(pdata_t* pdata, uint32_t address, uint8_t* bu
return 0;
}
static int micronucleus_start(pdata_t* pdata)
{
static int micronucleus_start(struct pdata *pdata) {
pmsg_debug("micronucleus_start()\n");
int result = usb_control_msg(
@@ -546,7 +531,7 @@ static int micronucleus_start(pdata_t* pdata)
static void micronucleus_setup(PROGRAMMER *pgm) {
pmsg_debug("micronucleus_setup()\n");
pgm->cookie = mmt_malloc(sizeof(pdata_t));
pgm->cookie = mmt_malloc(sizeof(struct pdata));
}
static void micronucleus_teardown(PROGRAMMER* pgm) {
@@ -558,7 +543,7 @@ static void micronucleus_teardown(PROGRAMMER* pgm) {
static int micronucleus_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
pmsg_debug("micronucleus_initialize()\n");
pdata_t* pdata = PDATA(pgm);
struct pdata *pdata = PDATA(pgm);
int result = micronucleus_get_bootloader_info(pdata);
if (result < 0)
@@ -570,7 +555,7 @@ static int micronucleus_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
}
static void micronucleus_display(const PROGRAMMER *pgm, const char *prefix) {
pmsg_debug("micronucleus_display()\n");
// pmsg_debug("micronucleus_display()\n");
}
static void micronucleus_powerup(const PROGRAMMER *pgm) {
@@ -580,7 +565,7 @@ static void micronucleus_powerup(const PROGRAMMER *pgm) {
static void micronucleus_powerdown(const PROGRAMMER *pgm) {
pmsg_debug("micronucleus_powerdown()\n");
pdata_t* pdata = PDATA(pgm);
struct pdata *pdata = PDATA(pgm);
if (pdata->write_last_page)
{
pdata->write_last_page = false;
@@ -621,7 +606,7 @@ static int micronucleus_read_sig_bytes(const PROGRAMMER *pgm, const AVRPART *p,
return -1;
}
pdata_t* pdata = PDATA(pgm);
struct pdata *pdata = PDATA(pgm);
mem->buf[0] = 0x1E;
mem->buf[1] = pdata->signature1;
mem->buf[2] = pdata->signature2;
@@ -631,14 +616,14 @@ static int micronucleus_read_sig_bytes(const PROGRAMMER *pgm, const AVRPART *p,
static int micronucleus_chip_erase(const PROGRAMMER *pgm, const AVRPART *p) {
pmsg_debug("micronucleus_chip_erase()\n");
pdata_t* pdata = PDATA(pgm);
struct pdata *pdata = PDATA(pgm);
return micronucleus_erase_device(pdata);
}
static int micronucleus_open(PROGRAMMER* pgm, const char *port) {
pmsg_debug("micronucleus_open(\"%s\")\n", port);
pdata_t* pdata = PDATA(pgm);
struct pdata *pdata = PDATA(pgm);
const char *bus_name = NULL;
char* dev_name = NULL;
@@ -664,8 +649,7 @@ static int micronucleus_open(PROGRAMMER* pgm, const char *port) {
if (port != NULL && dev_name == NULL)
{
pmsg_error("invalid -P value %s\n", port);
imsg_error("use -P usb:bus:device\n");
pmsg_error("invalid -P %s; use -P usb:bus:device\n", port);
return -1;
}
@@ -790,7 +774,7 @@ static void micronucleus_close(PROGRAMMER* pgm)
{
pmsg_debug("micronucleus_close()\n");
pdata_t* pdata = PDATA(pgm);
struct pdata *pdata = PDATA(pgm);
if (pdata->usb_handle != NULL)
{
usb_close(pdata->usb_handle);
@@ -838,7 +822,7 @@ static int micronucleus_paged_write(const PROGRAMMER *pgm, const AVRPART *p, con
if (mem_is_flash(mem))
{
pdata_t* pdata = PDATA(pgm);
struct pdata *pdata = PDATA(pgm);
if (n_bytes > page_size)
{
@@ -884,39 +868,48 @@ static int micronucleus_paged_write(const PROGRAMMER *pgm, const AVRPART *p, con
}
static int micronucleus_parseextparams(const PROGRAMMER *pgm, const LISTID xparams) {
int rv = 0;
bool help = false;
pmsg_debug("micronucleus_parseextparams()\n");
pdata_t* pdata = PDATA(pgm);
for (LNODEID node = lfirst(xparams); node != NULL; node = lnext(node))
struct pdata *pdata = PDATA(pgm);
for (LNODEID node = lfirst(xparams); node; node = lnext(node))
{
const char* param = ldata(node);
const char* extended_param = ldata(node);
if (str_eq(param, "wait"))
if (str_eq(extended_param, "wait"))
{
pdata->wait_until_device_present = true;
pdata->wait_timout = -1;
continue;
}
else if (str_starts(param, "wait="))
if (str_starts(extended_param, "wait="))
{
pdata->wait_until_device_present = true;
pdata->wait_timout = atoi(param + 5);
pdata->wait_timout = atoi(extended_param + 5);
continue;
}
else if (str_eq(param, "help"))
if (str_eq(extended_param, "help"))
{
msg_error("%s -c %s extended options:\n", progname, pgmid);
msg_error(" -xwait Wait for the device to be plugged in if not connected\n");
msg_error(" -xwait=<arg> Wait <arg> [s] for the device to be plugged in if not connected\n");
msg_error(" -xhelp Show this help menu and exit\n");
return LIBAVRDUDE_EXIT;
help = true;
rv = LIBAVRDUDE_EXIT;
}
else
if (!help)
{
pmsg_error("invalid extended parameter '%s'\n", param);
return -1;
pmsg_error("invalid extended parameter -x %s\n", extended_param);
rv = -1;
}
msg_error("%s -c %s extended options:\n", progname, pgmid);
msg_error(" -x wait Wait for the device to be plugged in if not connected\n");
msg_error(" -x wait=<n> Wait <n> s for the device to be plugged in if not connected\n");
msg_error(" -x help Show this help menu and exit\n");
return rv;
}
return 0;
return rv;
}
void micronucleus_initpgm(PROGRAMMER *pgm) {

View File

@@ -2,7 +2,7 @@
/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
/*
* Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
* Copyright (C) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2000-2006 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2000-2006 Brian S. Dean <bsd@bdmicro.com>
*
* 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
@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#include <ac_cfg.h>
#include <stdio.h>
@@ -44,14 +42,14 @@
#if HAVE_PARPORT
struct ppipins_t {
struct ppipins {
int pin;
int reg;
int bit;
int inverted;
};
static const struct ppipins_t ppipins[] = {
static const struct ppipins ppipins[] = {
{ 1, PPICTRL, 0x01, 1 },
{ 2, PPIDATA, 0x01, 0 },
{ 3, PPIDATA, 0x02, 0 },
@@ -71,7 +69,7 @@ static const struct ppipins_t ppipins[] = {
{ 17, PPICTRL, 0x08, 1 }
};
#define NPINS (sizeof(ppipins)/sizeof(struct ppipins_t))
#define NPINS (sizeof(ppipins)/sizeof(struct ppipins))
static int par_setpin_internal(const PROGRAMMER *pgm, int pin, int value) {
int inverted;
@@ -335,36 +333,59 @@ static void par_close(PROGRAMMER *pgm) {
*/
static int par_parseexitspecs(PROGRAMMER *pgm, const char *sp) {
char *cp, *s, *str = mmt_strdup(sp);
int rv = 0;
bool help = false;
s = str;
while((cp = strtok(s, ","))) {
if(str_eq(cp, "reset"))
s = NULL;
if(str_eq(cp, "reset")) {
pgm->exit_reset = EXIT_RESET_ENABLED;
else if(str_eq(cp, "noreset"))
pgm->exit_reset = EXIT_RESET_DISABLED;
else if(str_eq(cp, "vcc"))
pgm->exit_vcc = EXIT_VCC_ENABLED;
else if(str_eq(cp, "novcc"))
pgm->exit_vcc = EXIT_VCC_DISABLED;
else if(str_eq(cp, "d_high"))
pgm->exit_datahigh = EXIT_DATAHIGH_ENABLED;
else if(str_eq(cp, "d_low"))
pgm->exit_datahigh = EXIT_DATAHIGH_DISABLED;
else {
mmt_free(str);
return -1;
continue;
}
s = NULL; // Only call strtok() once with the actual string
if(str_eq(cp, "noreset")) {
pgm->exit_reset = EXIT_RESET_DISABLED;
continue;
}
if(str_eq(cp, "vcc")) {
pgm->exit_vcc = EXIT_VCC_ENABLED;
continue;
}
if(str_eq(cp, "novcc")) {
pgm->exit_vcc = EXIT_VCC_DISABLED;
continue;
}
if(str_eq(cp, "d_high")) {
pgm->exit_datahigh = EXIT_DATAHIGH_ENABLED;
continue;
}
if(str_eq(cp, "d_low")) {
pgm->exit_datahigh = EXIT_DATAHIGH_DISABLED;
continue;
}
if (str_eq(cp, "help")) {
help = true;
rv = LIBAVRDUDE_EXIT;
}
if (!help) {
pmsg_error("invalid exitspec parameter -E %s\n", cp);
rv = -1;
}
msg_error("%s -c %s exitspec parameter options:\n", progname, pgmid);
msg_error(" -E reset Programmer will keep the reset line low after programming session\n");
msg_error(" -E noreset Programmer will not keep the reset line low after programming session\n");
msg_error(" -E vcc Programmer VCC pin(s) remain active after programming session\n");
msg_error(" -E novcc Programmer VCC pin(s) turned off after programming session\n");
msg_error(" -E d_high Set all 8 programmer data pins high after programming session\n");
msg_error(" -E d_low Set all 8 programmer data pins low after programming session\n");
msg_error(" -E help Show this help menu and exit\n");
mmt_free(str);
return rv;
}
mmt_free(str);
return 0;
return rv;
}
void par_initpgm(PROGRAMMER *pgm) {

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bdmicro.com>
*
* 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
@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#ifndef par_h
#define par_h

View File

@@ -1,7 +1,7 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2002-2004 Brian S. Dean <bsd@bdmicro.com>
* Copyright 2007 Joerg Wunsch <j@uriah.heep.sax.de>
* Copyright (C) 2002-2004 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2007 Joerg Wunsch <j@uriah.heep.sax.de>
*
* 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
@@ -17,8 +17,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#include <ac_cfg.h>
#include <stdio.h>
@@ -169,7 +167,7 @@ PROGRAMMER *pgm_new(void) {
pin_clear_all(&(pgm->pin[i]));
}
pgm->leds = mmt_malloc(sizeof(leds_t));
pgm->leds = mmt_malloc(sizeof(Leds));
pgm_init_functions(pgm);
@@ -218,7 +216,7 @@ PROGRAMMER *pgm_dup(const PROGRAMMER *src) {
if(pgm->cp_usersig)
mmt_free(pgm->cp_usersig);
leds_t *ls = pgm->leds;
Leds *ls = pgm->leds;
memcpy(pgm, src, sizeof(*pgm));
if(ls && src->leds)
memcpy(ls, src->leds, sizeof *ls);
@@ -284,7 +282,7 @@ static void pgm_default_setup_teardown(PROGRAMMER *pgm) {
void programmer_display(PROGRAMMER *pgm, const char * p) {
msg_info("%sProgrammer Type : %s\n", p, pgm->type);
msg_info("%sProgrammer type : %s\n", p, pgm->type);
msg_info("%sDescription : %s\n", p, pgm->desc);
pgm->display(pgm, p);
@@ -292,34 +290,11 @@ void programmer_display(PROGRAMMER *pgm, const char * p) {
void pgm_display_generic_mask(const PROGRAMMER *pgm, const char *p, unsigned int show) {
if(show & (1<<PPI_AVR_VCC))
msg_info("%s VCC = %s\n", p, pins_to_str(&pgm->pin[PPI_AVR_VCC]));
if(show & (1<<PPI_AVR_BUFF))
msg_info("%s BUFF = %s\n", p, pins_to_str(&pgm->pin[PPI_AVR_BUFF]));
if(show & (1<<PIN_AVR_RESET))
msg_info("%s RESET = %s\n", p, pins_to_str(&pgm->pin[PIN_AVR_RESET]));
if(show & (1<<PIN_AVR_SCK))
msg_info("%s SCK = %s\n", p, pins_to_str(&pgm->pin[PIN_AVR_SCK]));
if(show & (1<<PIN_AVR_SDO))
msg_info("%s SDO = %s\n", p, pins_to_str(&pgm->pin[PIN_AVR_SDO]));
if(show & (1<<PIN_AVR_SDI))
msg_info("%s SDI = %s\n", p, pins_to_str(&pgm->pin[PIN_AVR_SDI]));
if(show & (1<<PIN_JTAG_TCK))
msg_info("%s TCK = %s\n", p, pins_to_str(&pgm->pin[PIN_JTAG_TCK]));
if(show & (1<<PIN_JTAG_TDI))
msg_info("%s TDI = %s\n", p, pins_to_str(&pgm->pin[PIN_JTAG_TDI]));
if(show & (1<<PIN_JTAG_TDO))
msg_info("%s TDO = %s\n", p, pins_to_str(&pgm->pin[PIN_JTAG_TDO]));
if(show & (1<<PIN_JTAG_TMS))
msg_info("%s TMS = %s\n", p, pins_to_str(&pgm->pin[PIN_JTAG_TMS]));
if(show & (1<<PIN_LED_ERR))
msg_info("%s ERR LED = %s\n", p, pins_to_str(&pgm->pin[PIN_LED_ERR]));
if(show & (1<<PIN_LED_RDY))
msg_info("%s RDY LED = %s\n", p, pins_to_str(&pgm->pin[PIN_LED_RDY]));
if(show & (1<<PIN_LED_PGM))
msg_info("%s PGM LED = %s\n", p, pins_to_str(&pgm->pin[PIN_LED_PGM]));
if(show & (1<<PIN_LED_VFY))
msg_info("%s VFY LED = %s\n", p, pins_to_str(&pgm->pin[PIN_LED_VFY]));
for(int pbit = 1; pbit < N_PINS; pbit++)
if(show & (1<<pbit)) {
const char *pinstr = pins_to_str(pgm->pin + pbit);
msg_info("%s %-6s = %s\n", p, avr_pin_name(pbit), *pinstr? pinstr: "(not used)");
}
}
void pgm_display_generic(const PROGRAMMER *pgm, const char *p) {
@@ -435,7 +410,7 @@ void sort_programmers(LISTID programmers)
}
// Soft assignment: some struct programmer_t entries can be both programmers and serial adapters
// Soft assignment: some PROGRAMMER entries can be both programmers and serial adapters
int is_programmer(const PROGRAMMER *p) {
return p && p->id && lsize(p->id) && p->prog_modes && p->initpgm;
}

View File

@@ -1,7 +1,7 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2002-2004 Brian S. Dean <bsd@bdmicro.com>
* Copyright 2007 Joerg Wunsch <j@uriah.heep.sax.de>
* Copyright (C) 2002-2004 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2007 Joerg Wunsch <j@uriah.heep.sax.de>
*
* 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
@@ -49,6 +49,7 @@
#include "ppi.h"
#include "serbb.h"
#include "serialupdi.h"
#include "serprog.h"
#include "stk500.h"
#include "stk500generic.h"
#include "stk500v2.h"
@@ -100,6 +101,7 @@ const PROGRAMMER_TYPE programmers_types[] = { // Name(s) the programmers call th
{"pickit2", pickit2_initpgm, pickit2_desc}, // "pickit2"
{"serbb", serbb_initpgm, serbb_desc}, // "SERBB"
{"serialupdi", serialupdi_initpgm, serialupdi_desc}, // "serialupdi"
{"serprog", serprog_initpgm, serprog_desc}, // "serprog"
{"stk500", stk500_initpgm, stk500_desc}, // "STK500"
{"stk500generic", stk500generic_initpgm, stk500generic_desc}, // "STK500GENERIC"
{"stk500v2", stk500v2_initpgm, stk500v2_desc}, // "STK500V2"

View File

@@ -3,7 +3,7 @@
* Copyright (C) 2005 Erik Walthinsen
* Copyright (C) 2002-2004 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2006 David Moore
* Copyright (C) 2006,2007 Joerg Wunsch <j@uriah.heep.sax.de>
* Copyright (C) 2006, 2007 Joerg Wunsch <j@uriah.heep.sax.de>
*
* 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
@@ -249,7 +249,7 @@ static int pickit2_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
//memset(report, 0, sizeof(report));
if ((errorCode = pickit2_read_report(pgm, report)) >= 4)
{
pmsg_notice("%s firmware version %d.%d.%d\n", pgm->desc, (int)report[1], (int)report[2], (int)report[3]);
pmsg_notice2("%s firmware version %d.%d.%d\n", pgm->desc, report[1], report[2], report[3]);
// set the pins, apply reset,
// TO DO: apply vtarget (if requested though -x option)
@@ -408,7 +408,7 @@ static int pickit2_program_enable(const PROGRAMMER *pgm, const AVRPART *p) {
{
int i;
msg_debug("program_enable(): sending command. Resp = ");
msg_debug("%s(): sending command. Resp = ", __func__);
for (i = 0; i < 4; i++)
{
@@ -1105,7 +1105,7 @@ static int usb_open_device(PROGRAMMER *pgm, struct usb_dev_handle **device, int
// return with opened device handle
else
{
msg_notice("device %p seemed to open OK\n", handle);
msg_notice2("device %p seemed to open OK\n", handle);
if ((errorCode = usb_set_configuration(handle, 1)) < 0)
{
@@ -1144,30 +1144,28 @@ static int pickit2_read_report(const PROGRAMMER *pgm, unsigned char report[65])
#endif // WIN32
static int pickit2_parseextparams(const PROGRAMMER *pgm, const LISTID extparms) {
LNODEID ln;
const char *extended_param;
int rv = 0;
bool help = false;
for (ln = lfirst(extparms); ln; ln = lnext(ln))
for (LNODEID ln = lfirst(extparms); ln; ln = lnext(ln))
{
extended_param = ldata(ln);
const char *extended_param = ldata(ln);
if (str_starts(extended_param, "clockrate="))
{
int clock_rate;
if (sscanf(extended_param, "clockrate=%i", &clock_rate) != 1 || clock_rate <= 0)
{
pmsg_error("invalid clockrate '%s'\n", extended_param);
pmsg_error("invalid clock rate in -x %s\n", extended_param);
rv = -1;
continue;
break;
}
int clock_period = MIN(1000000 / clock_rate, 255); // max period is 255
clock_rate = (int)(1000000 / (clock_period + 5e-7)); // assume highest speed is 2MHz - should probably check this
pmsg_notice2("pickit2_parseextparms(): clockrate set to 0x%02x\n", clock_rate);
pmsg_notice2("%s(): effective clock rate set to 0x%02x\n", __func__, clock_rate);
PDATA(pgm)->clock_period = clock_period;
continue;
}
@@ -1176,26 +1174,32 @@ static int pickit2_parseextparams(const PROGRAMMER *pgm, const LISTID extparms)
int timeout;
if (sscanf(extended_param, "timeout=%i", &timeout) != 1 || timeout <= 0)
{
pmsg_error("invalid timeout '%s'\n", extended_param);
pmsg_error("invalid timeout in -x %s\n", extended_param);
rv = -1;
continue;
break;
}
pmsg_notice2("pickit2_parseextparms(): usb timeout set to 0x%02x\n", timeout);
pmsg_notice2("%s(): usb timeout set to 0x%02x\n", __func__, timeout);
PDATA(pgm)->transaction_timeout = timeout;
continue;
}
if (str_eq(extended_param, "help")) {
msg_error("%s -c %s extended options:\n", progname, pgmid);
msg_error(" -xclockrate=<arg> Set the SPI clocking rate in <arg> [Hz]\n");
msg_error(" -xtimeout=<arg> Set the timeout for USB read/write to <arg> [ms]\n");
msg_error(" -xhelp Show this help menu and exit\n");
return LIBAVRDUDE_EXIT;;
if (str_eq(extended_param, "help"))
{
help = true;
rv = LIBAVRDUDE_EXIT;
}
pmsg_error("invalid extended parameter '%s'\n", extended_param);
rv = -1;
if (!help)
{
pmsg_error("invalid extended parameter -x %s\n", extended_param);
rv = -1;
}
msg_error("%s -c %s extended options:\n", progname, pgmid);
msg_error(" -x clockrate=<n> Set the SPI clock rate to <n> Hz\n");
msg_error(" -x timeout=<n> Set the timeout for USB read/write to <n> ms\n");
msg_error(" -x help Show this help menu and exit\n");
return rv;
}
return rv;

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2006 Thomas Fischl
* Copyright (C) 2006 Thomas Fischl
*
* 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

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bdmicro.com>
*
* 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
@@ -34,7 +34,7 @@
* @param[in] pin number of pin [0..PIN_MAX]
* @param[in] inverse inverse (true) or normal (false) pin
*/
void pin_set_value(struct pindef_t * const pindef, const int pin, const bool inverse) {
void pin_set_value(struct pindef * const pindef, const int pin, const bool inverse) {
pindef->mask[pin / PIN_FIELD_ELEMENT_SIZE] |= 1 << (pin % PIN_FIELD_ELEMENT_SIZE);
if(inverse) {
@@ -49,8 +49,8 @@ void pin_set_value(struct pindef_t * const pindef, const int pin, const bool inv
*
* @param[out] pindef pin definition to clear
*/
void pin_clear_all(struct pindef_t * const pindef) {
memset(pindef, 0, sizeof(struct pindef_t));
void pin_clear_all(struct pindef * const pindef) {
memset(pindef, 0, sizeof(struct pindef));
}
/**
@@ -59,7 +59,7 @@ void pin_clear_all(struct pindef_t * const pindef) {
* @param[in] pindef new pin definition structure
* @param[out] pinno old pin definition integer
*/
static int pin_fill_old_pinno(const struct pindef_t * const pindef, unsigned int * const pinno) {
static int pin_fill_old_pinno(const struct pindef * const pindef, unsigned int * const pinno) {
bool found = false;
int i;
for(i = 0; i <= PIN_MAX; i++) {
@@ -84,7 +84,7 @@ static int pin_fill_old_pinno(const struct pindef_t * const pindef, unsigned int
* @param[in] pindef new pin definition structure
* @param[out] pinno old pin definition integer
*/
static int pin_fill_old_pinlist(const struct pindef_t * const pindef, unsigned int * const pinno) {
static int pin_fill_old_pinlist(const struct pindef * const pindef, unsigned int * const pinno) {
for(size_t i = 0; i < PIN_FIELD_SIZE; i++) {
if(i == 0) {
if((pindef->mask[i] & ~PIN_MASK) != 0) {
@@ -152,19 +152,17 @@ int pgm_fill_old_pins(PROGRAMMER * const pgm) {
}
/**
* This function returns a string representation of pins in the mask eg. 1,3,5-7,9,12
* Another execution of this function will overwrite the previous result in the static buffer.
* Consecutive pin number are represented as start-end.
* This function returns a string representation of pins in the mask eg. 1, 3, 5-7, 9, 12
* Consecutive pin numbers are represented as start-end.
*
* @param[in] pinmask the pin mask for which we want the string representation
* @returns pointer to a static string.
* @returns a temporary string that lives in closed-circuit space
*/
const char * pinmask_to_str(const pinmask_t * const pinmask) {
static char buf[(PIN_MAX + 1) * 5]; // should be enough for PIN_MAX=255
const char *pinmask_to_str(const Pinmask * const pinmask) {
char buf[6 * (PIN_MAX + 1)];
char *p = buf;
int n;
int pin;
const char * fmt;
int start = -1;
int end = -1;
@@ -189,11 +187,8 @@ const char * pinmask_to_str(const pinmask_t * const pinmask) {
start = pin;
end = start;
}
if(output) {
fmt = (buf[0] == 0) ? "%d" : ",%d";
n = sprintf(p, fmt, pin);
p += n;
}
if(output)
p += n = sprintf(p, *buf? ", %d": "%d", pin);
}
}
if(start != end) {
@@ -201,10 +196,7 @@ const char * pinmask_to_str(const pinmask_t * const pinmask) {
p += n;
}
if(buf[0] == 0)
return "(no pins)";
return buf;
return str_ccstrdup(*buf? buf: "(no pins)");
}
@@ -216,20 +208,20 @@ const char * pinmask_to_str(const pinmask_t * const pinmask) {
* @li any pins are used by more than one function
* @li any mandatory pin is not set all.
*
* In case of any error it report the wrong function and the pin numbers.
* For verbose >= 2 it also reports the possible correct values.
* For verbose >=3 it shows also which pins were ok.
* In case of any error it report the wrong function and the pin numbers
* For verbose >= MSG_NOTICE2 it also reports the possible correct values
* For verbose >= MSG_DEBUG it shows also which pins were ok
*
* @param[in] pgm the programmer to check
* @param[in] checklist the constraint for the pins
* @param[in] size the number of entries in checklist
* @returns 0 if all pin definitions are valid, -1 otherwise
*/
int pins_check(const PROGRAMMER *const pgm, const struct pin_checklist_t *const checklist, const int size, const bool output) {
static const struct pindef_t no_valid_pins = {{0}, {0}}; // default value if check list does not contain anything else
int pins_check(const PROGRAMMER *const pgm, const Pin_checklist *const checklist, const int size, const bool output) {
static const struct pindef no_valid_pins = {{0}, {0}}; // default value if check list does not contain anything else
int rv = 0; // return value
int pinname; // loop counter through pinnames
pinmask_t already_used_all[PIN_FIELD_SIZE] = {0}; // collect pin definitions of all pin names for check of double use
Pinmask already_used_all[PIN_FIELD_SIZE] = {0}; // collect pin definitions of all pin names for check of double use
// loop over all possible pinnames
for(pinname = 0; pinname < N_PINS; pinname++) {
bool used = false;
@@ -237,10 +229,10 @@ int pins_check(const PROGRAMMER *const pgm, const struct pin_checklist_t *const
bool inverse = false;
int index;
bool mandatory_used = false;
pinmask_t invalid_used[PIN_FIELD_SIZE] = {0};
pinmask_t inverse_used[PIN_FIELD_SIZE] = {0};
pinmask_t already_used[PIN_FIELD_SIZE] = {0};
const struct pindef_t * valid_pins = &no_valid_pins;
Pinmask invalid_used[PIN_FIELD_SIZE] = {0};
Pinmask inverse_used[PIN_FIELD_SIZE] = {0};
Pinmask already_used[PIN_FIELD_SIZE] = {0};
const struct pindef * valid_pins = &no_valid_pins;
bool is_mandatory = false;
bool is_ok = true;
//find corresponding check pattern
@@ -279,7 +271,7 @@ int pins_check(const PROGRAMMER *const pgm, const struct pin_checklist_t *const
if(output) {
pmsg_error("%s: these pins are not valid pins for this function: %s\n",
avr_pin_name(pinname), pinmask_to_str(invalid_used));
pmsg_notice("%s: valid pins for this function are: %s\n",
imsg_error("%s: valid pins for this function are: %s\n",
avr_pin_name(pinname), pinmask_to_str(valid_pins->mask));
}
is_ok = false;
@@ -288,7 +280,7 @@ int pins_check(const PROGRAMMER *const pgm, const struct pin_checklist_t *const
if(output) {
pmsg_error("%s: these pins are not usable as inverse pins for this function: %s\n",
avr_pin_name(pinname), pinmask_to_str(inverse_used));
pmsg_notice("%s: valid inverse pins for this function are: %s\n",
imsg_error("%s: valid inverse pins for this function are: %s\n",
avr_pin_name(pinname), pinmask_to_str(valid_pins->inverse));
}
is_ok = false;
@@ -315,48 +307,14 @@ int pins_check(const PROGRAMMER *const pgm, const struct pin_checklist_t *const
return rv;
}
/**
* This function returns a string of defined pins, eg, ~1,2,~4,~5,7 or " (not used)"
* Another execution of this function will overwrite the previous result in the static buffer.
*
* @param[in] pindef the pin definition for which we want the string representation
* @returns pointer to a static string.
*/
const char * pins_to_str(const struct pindef_t * const pindef) {
static char buf[(PIN_MAX + 1) * 5]; // should be enough for PIN_MAX=255
char *p = buf;
int n;
int pin;
const char * fmt;
buf[0] = 0;
for(pin = PIN_MIN; pin <= PIN_MAX; pin++) {
int index = pin / PIN_FIELD_ELEMENT_SIZE;
int bit = pin % PIN_FIELD_ELEMENT_SIZE;
if(pindef->mask[index] & (1 << bit)) {
if(pindef->inverse[index] & (1 << bit)) {
fmt = (buf[0] == 0) ? "~%d" : ",~%d";
} else {
fmt = (buf[0] == 0) ? " %d" : ",%d";
}
n = sprintf(p, fmt, pin);
p += n;
}
}
if(buf[0] == 0)
return " (not used)";
return buf;
}
/**
* This function returns a string of defined pins, eg, ~1, 2, ~4, ~5, 7 or ""
*
* @param[in] pindef the pin definition for which we want the string representation
* @returns a pointer to a string, which was created by mmt_strdup()
* @returns a temporary string that lives in closed-circuit space
*/
char *pins_to_strdup(const struct pindef_t * const pindef) {
const char *pins_to_str(const struct pindef * const pindef) {
char buf[6*(PIN_MAX+1)], *p = buf;
*buf = 0;
@@ -369,7 +327,7 @@ char *pins_to_strdup(const struct pindef_t * const pindef) {
}
}
return mmt_strdup(buf);
return str_ccstrdup(buf);
}
/**

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bdmicro.com>
*
* 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
@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#if !defined(WIN32)
@@ -54,7 +52,6 @@ enum {
static int ppi_shadow_access(const union filedescriptor *fdp, int reg,
unsigned char *v, unsigned char action)
{
static unsigned char shadow[3];
int shadow_num;
switch (reg) {
@@ -75,14 +72,14 @@ static int ppi_shadow_access(const union filedescriptor *fdp, int reg,
switch (action) {
case PPI_SHADOWREAD:
*v = shadow[shadow_num];
*v = cx->ppi_shadow[shadow_num];
break;
case PPI_READ:
DO_PPI_READ(fdp->ifd, reg, v);
shadow[shadow_num]=*v;
cx->ppi_shadow[shadow_num]=*v;
break;
case PPI_WRITE:
shadow[shadow_num]=*v;
cx->ppi_shadow[shadow_num]=*v;
DO_PPI_WRITE(fdp->ifd, reg, v);
break;
}

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bdmicro.com>
*
* 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
@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#ifndef ppi_h
#define ppi_h

View File

@@ -1,8 +1,7 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2003, 2004, 2006
* Eric B. Weddington <eweddington@cso.atmel.com>
* Copyright 2008, Joerg Wunsch
* Copyright (C) 2003, 2004, 2006 Eric B. Weddington <eweddington@cso.atmel.com>
* Copyright (C) 2008 Joerg Wunsch
*
* 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
@@ -18,8 +17,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
/*
This is the parallel port interface for Windows built using Cygwin.

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2003-2004 Theodore A. Roth <troth@openavr.org>
* Copyright (C) 2003-2004 Theodore A. Roth <troth@openavr.org>
* Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
* Copyright (C) 2006 Christian Starkjohann
*
@@ -18,8 +18,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
/*
* Serial Interface emulation for USB programmer "AVR-Doper" in HID mode.
*/
@@ -57,10 +55,6 @@
static const int reportDataSizes[4] = {13, 29, 61, 125};
static unsigned char avrdoperRxBuffer[280]; /* buffer for receive data */
static int avrdoperRxLength = 0; /* amount of valid bytes in rx buffer */
static int avrdoperRxPosition = 0; /* amount of bytes already consumed in rx buffer */
/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */
@@ -189,19 +183,18 @@ static void dumpBlock(const char *prefix, const unsigned char *buf, int len)
}
}
static char *usbErrorText(int usbErrno)
{
static char buffer[32];
static const char *usbErrorText(int usbErrno) {
switch(usbErrno){
case USB_ERROR_NONE: return "Success";
case USB_ERROR_ACCESS: return "Access denied";
case USB_ERROR_NOTFOUND:return "Device not found";
case USB_ERROR_BUSY: return "Device is busy";
case USB_ERROR_NONE: return "success";
case USB_ERROR_ACCESS: return "access denied";
case USB_ERROR_NOTFOUND:return "device not found";
case USB_ERROR_BUSY: return "device is busy";
case USB_ERROR_IO: return "I/O Error";
default:
sprintf(buffer, "Unknown error %d", usbErrno);
default: {
char *buffer = avr_cc_buffer(32);
sprintf(buffer, "unknown error %d", usbErrno);
return buffer;
}
}
}
@@ -215,7 +208,7 @@ static int avrdoper_open(const char *port, union pinfo pinfo, union filedescript
rval = usbOpenDevice(fdp, USB_VENDOR_ID, vname, USB_PRODUCT_ID, devname, 1);
if(rval != 0){
pmsg_ext_error("%s\n", usbErrorText(rval));
pmsg_ext_error("USB %s\n", usbErrorText(rval));
return -1;
}
return 0;
@@ -247,7 +240,7 @@ static int avrdoper_send(const union filedescriptor *fdp, const unsigned char *b
pmsg_error("%s() called with too large buflen = %lu\n", __func__, (unsigned long) buflen);
return -1;
}
if(verbose > 3)
if(verbose >= MSG_TRACE)
dumpBlock("Send", buf, buflen);
while(buflen > 0){
unsigned char buffer[256];
@@ -261,7 +254,7 @@ static int avrdoper_send(const union filedescriptor *fdp, const unsigned char *b
rval = usbSetReport(fdp, USB_HID_REPORT_TYPE_FEATURE, (char *)buffer,
reportDataSizes[lenIndex] + 2);
if(rval != 0){
pmsg_error("%s\n", usbErrorText(rval));
pmsg_error("USB %s\n", usbErrorText(rval));
return -1;
}
buflen -= thisLen;
@@ -275,18 +268,18 @@ static int avrdoper_send(const union filedescriptor *fdp, const unsigned char *b
static int avrdoperFillBuffer(const union filedescriptor *fdp) {
int bytesPending = reportDataSizes[1]; /* guess how much data is buffered in device */
avrdoperRxPosition = avrdoperRxLength = 0;
cx->sad_avrdoperRxPosition = cx->sad_avrdoperRxLength = 0;
while(bytesPending > 0){
int len, usbErr, lenIndex = chooseDataSize(bytesPending);
unsigned char buffer[128];
len = sizeof(avrdoperRxBuffer) - avrdoperRxLength; /* bytes remaining */
len = sizeof(cx->sad_avrdoperRxBuffer) - cx->sad_avrdoperRxLength; /* bytes remaining */
if(reportDataSizes[lenIndex] + 2 > len) /* requested data would not fit into buffer */
break;
len = reportDataSizes[lenIndex] + 2;
usbErr = usbGetReport(fdp, USB_HID_REPORT_TYPE_FEATURE, lenIndex + 1,
(char *)buffer, &len);
if(usbErr != 0){
pmsg_error("%s\n", usbErrorText(usbErr));
pmsg_error("USB %s\n", usbErrorText(usbErr));
return -1;
}
msg_trace("Received %d bytes data chunk of total %d\n", len - 2, buffer[1]);
@@ -294,12 +287,12 @@ static int avrdoperFillBuffer(const union filedescriptor *fdp) {
bytesPending = buffer[1] - len; /* amount still buffered */
if(len > buffer[1]) /* cut away padding */
len = buffer[1];
if(avrdoperRxLength + len > (int) sizeof(avrdoperRxBuffer)){
if(cx->sad_avrdoperRxLength + len > (int) sizeof(cx->sad_avrdoperRxBuffer)){
pmsg_error("buffer overflow\n");
return -1;
}
memcpy(avrdoperRxBuffer + avrdoperRxLength, buffer + 2, len);
avrdoperRxLength += len;
memcpy(cx->sad_avrdoperRxBuffer + cx->sad_avrdoperRxLength, buffer + 2, len);
cx->sad_avrdoperRxLength += len;
}
return 0;
}
@@ -310,19 +303,19 @@ static int avrdoper_recv(const union filedescriptor *fdp, unsigned char *buf, si
int remaining = buflen;
while(remaining > 0){
int len, available = avrdoperRxLength - avrdoperRxPosition;
int len, available = cx->sad_avrdoperRxLength - cx->sad_avrdoperRxPosition;
if(available <= 0){ /* buffer is empty */
if (avrdoperFillBuffer(fdp) < 0)
return -1;
continue;
}
len = remaining < available ? remaining : available;
memcpy(p, avrdoperRxBuffer + avrdoperRxPosition, len);
memcpy(p, cx->sad_avrdoperRxBuffer + cx->sad_avrdoperRxPosition, len);
p += len;
remaining -= len;
avrdoperRxPosition += len;
cx->sad_avrdoperRxPosition += len;
}
if(verbose > 3)
if(verbose >= MSG_TRACE)
dumpBlock("Receive", buf, buflen);
return 0;
}
@@ -334,7 +327,7 @@ static int avrdoper_drain(const union filedescriptor *fdp, int display)
do{
if (avrdoperFillBuffer(fdp) < 0)
return -1;
}while(avrdoperRxLength > 0);
}while(cx->sad_avrdoperRxLength > 0);
return 0;
}

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2003-2004 Theodore A. Roth <troth@openavr.org>
* Copyright (C) 2003-2004 Theodore A. Roth <troth@openavr.org>
* Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
*
* This program is free software; you can redistribute it and/or modify
@@ -17,8 +17,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
/*
* Posix serial interface for avrdude.
*/
@@ -59,9 +57,7 @@ struct baud_mapping {
speed_t speed;
};
/* There are a lot more baud rates we could handle, but what's the point? */
static struct baud_mapping baud_lookup_table [] = {
static const struct baud_mapping baud_lookup_table [] = {
{ 300, B300 },
{ 600, B600 },
{ 1200, B1200 },
@@ -121,28 +117,17 @@ static struct baud_mapping baud_lookup_table [] = {
{ 0, 0 } /* Terminator. */
};
static struct termios original_termios;
static int saved_original_termios;
static speed_t serial_baud_lookup(long baud, bool *nonstandard) {
struct baud_mapping *map = baud_lookup_table;
*nonstandard = false;
while (map->baud) {
for(const struct baud_mapping *map = baud_lookup_table; map->baud; map++)
if (map->baud == baud)
return map->speed;
map++;
}
/*
* If a non-standard BAUD rate is used, issue
* a warning (if we are verbose) and return the raw rate
*/
pmsg_notice2("serial_baud_lookup(): using non-standard baud rate: %ld\n", baud);
// Return the raw rate when asked for non-standard baud rate
pmsg_notice2("%s(): using non-standard baud rate: %ld\n", __func__, baud);
*nonstandard = true;
return baud;
}
@@ -168,9 +153,8 @@ static int ser_setparams(const union filedescriptor *fd, long baud, unsigned lon
/*
* copy termios for ser_close if we haven't already
*/
if (! saved_original_termios++) {
original_termios = termios;
}
if(!cx->ser_saved_original_termios++)
cx->ser_original_termios = termios;
if (cflags & SERIAL_CREAD) {
termios.c_cflag |= CREAD;
@@ -413,15 +397,12 @@ static int ser_open(const char *port, union pinfo pinfo, union filedescriptor *f
}
static void ser_close(union filedescriptor *fd) {
/*
* restore original termios settings from ser_open
*/
if (saved_original_termios) {
int rc = tcsetattr(fd->ifd, TCSANOW | TCSADRAIN, &original_termios);
if (rc) {
// Restore original termios settings from ser_open
if(cx->ser_saved_original_termios) {
int rc = tcsetattr(fd->ifd, TCSANOW | TCSADRAIN, &cx->ser_original_termios);
if(rc)
pmsg_ext_error("cannot reset attributes for device: %s\n", strerror(errno));
}
saved_original_termios = 0;
cx->ser_saved_original_termios = 0;
}
close(fd->ifd);
@@ -429,14 +410,14 @@ static void ser_close(union filedescriptor *fd) {
// Close but don't restore attributes
static void ser_rawclose(union filedescriptor *fd) {
saved_original_termios = 0;
cx->ser_saved_original_termios = 0;
close(fd->ifd);
}
static int ser_send(const union filedescriptor *fd, const unsigned char *buf, size_t len) {
int rc;
if(verbose > 3)
if(verbose >= MSG_TRACE)
trace_buffer(__func__, buf, len);
while(len) {
@@ -472,7 +453,7 @@ static int ser_recv(const union filedescriptor *fd, unsigned char *buf, size_t b
nfds = select(fd->ifd + 1, &rfds, NULL, NULL, &to2);
if (nfds == 0) {
pmsg_notice2("ser_recv(): programmer is not responding\n");
pmsg_notice2("%s(): programmer is not responding\n", __func__);
return -1;
}
else if (nfds == -1) {
@@ -495,7 +476,7 @@ static int ser_recv(const union filedescriptor *fd, unsigned char *buf, size_t b
len += rc;
}
if(verbose > 3)
if(verbose >= MSG_TRACE)
trace_buffer(__func__, buf, len);
return 0;

View File

@@ -1,7 +1,7 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2003, 2004 Martin J. Thomas <mthomas@rhrk.uni-kl.de>
* Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
* Copyright (C) 2003, 2004 Martin J. Thomas <mthomas@rhrk.uni-kl.de>
* Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
*
* 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
@@ -46,11 +46,9 @@ struct baud_mapping {
DWORD speed;
};
static unsigned char serial_over_ethernet = 0;
/* HANDLE hComPort=INVALID_HANDLE_VALUE; */
static struct baud_mapping baud_lookup_table [] = {
static const struct baud_mapping baud_lookup_table [] = {
{ 300, CBR_300 },
{ 600, CBR_600 },
{ 1200, CBR_1200 },
@@ -64,21 +62,13 @@ static struct baud_mapping baud_lookup_table [] = {
{ 0, 0 } /* Terminator. */
};
static DWORD serial_baud_lookup(long baud)
{
struct baud_mapping *map = baud_lookup_table;
while (map->baud) {
static DWORD serial_baud_lookup(long baud) {
for(const struct baud_mapping *map = baud_lookup_table; map->baud; map++)
if (map->baud == baud)
return map->speed;
map++;
}
/*
* If a non-standard BAUD rate is used, issue
* a warning (if we are verbose) and return the raw rate
*/
pmsg_notice2("serial_baud_lookup(): using non-standard baud rate: %ld", baud);
// Return the raw rate when asked for non-standard baud rate
pmsg_notice2("%s(): using non-standard baud rate: %ld", __func__, baud);
return baud;
}
@@ -96,57 +86,55 @@ static BOOL serial_w32SetTimeOut(HANDLE hComPort, DWORD timeout) // in ms
}
static int ser_setparams(const union filedescriptor *fd, long baud, unsigned long cflags) {
if (serial_over_ethernet) {
if(cx->ser_serial_over_ethernet)
return -ENOTTY;
} else {
DCB dcb;
HANDLE hComPort = (HANDLE)fd->pfd;
ZeroMemory (&dcb, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
dcb.BaudRate = serial_baud_lookup (baud);
dcb.fBinary = 1;
dcb.fDtrControl = DTR_CONTROL_DISABLE;
dcb.fRtsControl = RTS_CONTROL_DISABLE;
switch ((cflags & (SERIAL_CS5 | SERIAL_CS6 | SERIAL_CS7 | SERIAL_CS8))) {
case SERIAL_CS5:
dcb.ByteSize = 5;
break;
case SERIAL_CS6:
dcb.ByteSize = 6;
break;
case SERIAL_CS7:
dcb.ByteSize = 7;
break;
case SERIAL_CS8:
dcb.ByteSize = 8;
break;
}
switch ((cflags & (SERIAL_NO_PARITY | SERIAL_PARENB | SERIAL_PARODD))) {
case SERIAL_NO_PARITY:
dcb.Parity = NOPARITY;
break;
case SERIAL_PARENB:
dcb.Parity = EVENPARITY;
break;
case SERIAL_PARODD:
dcb.Parity = ODDPARITY;
break;
}
switch ((cflags & (SERIAL_NO_CSTOPB | SERIAL_CSTOPB))) {
case SERIAL_NO_CSTOPB:
dcb.StopBits = ONESTOPBIT;
break;
case SERIAL_CSTOPB:
dcb.StopBits = TWOSTOPBITS;
break;
}
DCB dcb;
HANDLE hComPort = (HANDLE)fd->pfd;
if (!SetCommState(hComPort, &dcb))
return -1;
return 0;
ZeroMemory (&dcb, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
dcb.BaudRate = serial_baud_lookup (baud);
dcb.fBinary = 1;
dcb.fDtrControl = DTR_CONTROL_DISABLE;
dcb.fRtsControl = RTS_CONTROL_DISABLE;
switch ((cflags & (SERIAL_CS5 | SERIAL_CS6 | SERIAL_CS7 | SERIAL_CS8))) {
case SERIAL_CS5:
dcb.ByteSize = 5;
break;
case SERIAL_CS6:
dcb.ByteSize = 6;
break;
case SERIAL_CS7:
dcb.ByteSize = 7;
break;
case SERIAL_CS8:
dcb.ByteSize = 8;
break;
}
switch ((cflags & (SERIAL_NO_PARITY | SERIAL_PARENB | SERIAL_PARODD))) {
case SERIAL_NO_PARITY:
dcb.Parity = NOPARITY;
break;
case SERIAL_PARENB:
dcb.Parity = EVENPARITY;
break;
case SERIAL_PARODD:
dcb.Parity = ODDPARITY;
break;
}
switch ((cflags & (SERIAL_NO_CSTOPB | SERIAL_CSTOPB))) {
case SERIAL_NO_CSTOPB:
dcb.StopBits = ONESTOPBIT;
break;
case SERIAL_CSTOPB:
dcb.StopBits = TWOSTOPBITS;
break;
}
if (!SetCommState(hComPort, &dcb))
return -1;
return 0;
}
static int net_open(const char *port, union filedescriptor *fdp) {
@@ -231,7 +219,7 @@ static int net_open(const char *port, union filedescriptor *fdp) {
fdp->ifd = fd;
serial_over_ethernet = 1;
cx->ser_serial_over_ethernet = 1;
return 0;
}
@@ -308,7 +296,7 @@ static int ser_open(const char *port, union pinfo pinfo, union filedescriptor *f
static void ser_close(union filedescriptor *fd) {
if (serial_over_ethernet) {
if (cx->ser_serial_over_ethernet) {
closesocket(fd->ifd);
WSACleanup();
} else {
@@ -321,20 +309,15 @@ static void ser_close(union filedescriptor *fd) {
}
static int ser_set_dtr_rts(const union filedescriptor *fd, int is_on) {
if (serial_over_ethernet) {
if(cx->ser_serial_over_ethernet)
return 0;
} else {
HANDLE hComPort=(HANDLE)fd->pfd;
if (is_on) {
EscapeCommFunction(hComPort, SETDTR);
EscapeCommFunction(hComPort, SETRTS);
} else {
EscapeCommFunction(hComPort, CLRDTR);
EscapeCommFunction(hComPort, CLRRTS);
}
return 0;
}
HANDLE hComPort=(HANDLE)fd->pfd;
EscapeCommFunction(hComPort, is_on? SETDTR: CLRDTR);
EscapeCommFunction(hComPort, is_on? SETRTS: CLRRTS);
return 0;
}
static int net_send(const union filedescriptor *fd, const unsigned char *buf, size_t len) {
@@ -342,14 +325,14 @@ static int net_send(const union filedescriptor *fd, const unsigned char *buf, si
int rc;
if (fd->ifd < 0) {
pmsg_notice("net_send(): connection not open\n");
pmsg_notice("%s(): connection not open\n", __func__);
return -1;
}
if (!len)
return 0;
if (verbose > 3)
if (verbose >= MSG_TRACE)
trace_buffer(__func__, buf, len);
while (len) {
@@ -378,7 +361,7 @@ static int net_send(const union filedescriptor *fd, const unsigned char *buf, si
static int ser_send(const union filedescriptor *fd, const unsigned char *buf, size_t len) {
if (serial_over_ethernet)
if(cx->ser_serial_over_ethernet)
return net_send(fd, buf, len);
DWORD written;
@@ -393,7 +376,7 @@ static int ser_send(const union filedescriptor *fd, const unsigned char *buf, si
if (!len)
return 0;
if (verbose > 3)
if (verbose >= MSG_TRACE)
trace_buffer(__func__, buf, len);
serial_w32SetTimeOut(hComPort,500);
@@ -437,13 +420,11 @@ reselect:
nfds = select(fd->ifd + 1, &rfds, NULL, NULL, &to2);
if (nfds == 0) {
if (verbose > 1) {
pmsg_notice("net_recv(): programmer is not responding\n");
}
pmsg_notice2("%s(): programmer is not responding\n", __func__);
return -1;
} else if (nfds == -1) {
if (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEINPROGRESS) {
pmsg_notice("net_recv(): programmer is not responding, reselecting\n");
pmsg_notice("%s(): programmer is not responding, reselecting\n", __func__);
goto reselect;
} else {
FormatMessage(
@@ -456,7 +437,7 @@ reselect:
(LPTSTR)&lpMsgBuf,
0,
NULL);
pmsg_error("select(): %s\n", (char *) lpMsgBuf);
pmsg_error("%s(): %s\n", __func__, (char *) lpMsgBuf);
LocalFree(lpMsgBuf);
return -1;
}
@@ -482,14 +463,14 @@ reselect:
len += rc;
}
if (verbose > 3)
if (verbose >= MSG_TRACE)
trace_buffer(__func__, buf, len);
return 0;
}
static int ser_recv(const union filedescriptor *fd, unsigned char *buf, size_t buflen) {
if (serial_over_ethernet)
if(cx->ser_serial_over_ethernet)
return net_recv(fd, buf, buflen);
DWORD read;
@@ -522,11 +503,11 @@ static int ser_recv(const union filedescriptor *fd, unsigned char *buf, size_t b
/* time out detected */
if (read < buflen) {
pmsg_notice2("ser_recv(): programmer is not responding\n");
pmsg_notice2("%s(): programmer is not responding\n", __func__);
return -1;
}
if (verbose > 3)
if (verbose >= MSG_TRACE)
trace_buffer(__func__, buf, read);
return 0;
@@ -566,7 +547,7 @@ static int net_drain(const union filedescriptor *fd, int display) {
}
else if (nfds == -1) {
if (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEINPROGRESS) {
pmsg_notice("ser_drain(): programmer is not responding, reselecting\n");
pmsg_notice("%s(): programmer is not responding, reselecting\n", __func__);
goto reselect;
} else {
FormatMessage(
@@ -579,7 +560,7 @@ static int net_drain(const union filedescriptor *fd, int display) {
(LPTSTR)&lpMsgBuf,
0,
NULL);
pmsg_error("select(): %s\n", (char *) lpMsgBuf);
pmsg_error("%s(): %s\n", __func__, (char *) lpMsgBuf);
LocalFree(lpMsgBuf);
return -1;
}
@@ -611,9 +592,8 @@ static int net_drain(const union filedescriptor *fd, int display) {
}
static int ser_drain(const union filedescriptor *fd, int display) {
if (serial_over_ethernet) {
if(cx->ser_serial_over_ethernet)
return net_drain(fd, display);
}
// int rc;
unsigned char buf[10];

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2005 Juliane Holzt <avrdude@juliane.holzt.de>
*
* This program is free software; you can redistribute it and/or modify
@@ -16,7 +16,6 @@
* 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$ */
#ifndef serbb_h
#define serbb_h

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2005 Juliane Holzt <avrdude@juliane.holzt.de>
* Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
*
@@ -17,7 +17,6 @@
* 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$ */
/*
* Posix serial bitbanging interface for avrdude.
@@ -44,7 +43,13 @@
#undef DEBUG
static struct termios oldmode;
struct pdata {
struct termios oldmode;
};
// Use private programmer data as if they were a global structure my
#define my (*(struct pdata *)(pgm->cookie))
/*
serial port/pin mapping
@@ -62,11 +67,11 @@ static struct termios oldmode;
#define DB9PINS 9
static int serregbits[DB9PINS + 1] =
static const int serregbits[DB9PINS + 1] =
{ 0, TIOCM_CD, 0, 0, TIOCM_DTR, 0, TIOCM_DSR, TIOCM_RTS, TIOCM_CTS, TIOCM_RI };
#ifdef DEBUG
static char *serpins[DB9PINS + 1] =
static const char * const serpins[DB9PINS + 1] =
{ "NONE", "CD", "RXD", "TXD", "DTR", "GND", "DSR", "RTS", "CTS", "RI" };
#endif
@@ -89,7 +94,7 @@ static int serbb_setpin(const PROGRAMMER *pgm, int pinfunc, int value) {
return -1;
#ifdef DEBUG
msg_info("%s to %d\n", serpins[pin], value);
msg_notice("%s to %d\n", serpins[pin], value);
#endif
switch ( pin )
@@ -167,14 +172,14 @@ static int serbb_getpin(const PROGRAMMER *pgm, int pinfunc) {
if ( !invert )
{
#ifdef DEBUG
msg_info("%s is %d\n", serpins[pin], ctl & serregbits[pin]? 1: 0);
msg_notice("%s is %d\n", serpins[pin], ctl & serregbits[pin]? 1: 0);
#endif
return ctl & serregbits[pin]? 1: 0;
}
else
{
#ifdef DEBUG
msg_info("%s is %d (~)\n", serpins[pin], ctl & serregbits[pin]? 0: 1);
msg_notice("%s is %d (~)\n", serpins[pin], ctl & serregbits[pin]? 0: 1);
#endif
return ctl & serregbits[pin]? 0: 1;
}
@@ -243,7 +248,7 @@ static int serbb_open(PROGRAMMER *pgm, const char *port) {
pmsg_ext_error("%s, tcgetattr(): %s\n", port, strerror(errno));
return(-1);
}
oldmode = mode;
my.oldmode = mode;
mode.c_iflag = IGNBRK | IGNPAR;
mode.c_oflag = 0;
@@ -277,13 +282,22 @@ static int serbb_open(PROGRAMMER *pgm, const char *port) {
static void serbb_close(PROGRAMMER *pgm) {
if (pgm->fd.ifd != -1)
{
(void)tcsetattr(pgm->fd.ifd, TCSANOW, &oldmode);
(void) tcsetattr(pgm->fd.ifd, TCSANOW, &my.oldmode);
pgm->setpin(pgm, PIN_AVR_RESET, 1);
close(pgm->fd.ifd);
}
return;
}
static void serbb_setup(PROGRAMMER *pgm) {
pgm->cookie = mmt_malloc(sizeof(struct pdata));
}
static void serbb_teardown(PROGRAMMER *pgm) {
mmt_free(pgm->cookie);
pgm->cookie = NULL;
}
const char serbb_desc[] = "Serial port bitbanging";
void serbb_initpgm(PROGRAMMER *pgm) {
@@ -291,6 +305,8 @@ void serbb_initpgm(PROGRAMMER *pgm) {
pgm_fill_old_pins(pgm); // TODO to be removed if old pin data no longer needed
pgm->setup = serbb_setup;
pgm->teardown = serbb_teardown;
pgm->rdy_led = bitbang_rdy_led;
pgm->err_led = bitbang_err_led;
pgm->pgm_led = bitbang_pgm_led;

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2003, 2004 Martin J. Thomas <mthomas@rhrk.uni-kl.de>
* Copyright (C) 2003, 2004 Martin J. Thomas <mthomas@rhrk.uni-kl.de>
* Copyright (C) 2005 Juliane Holzt <avrdude@juliane.holzt.de>
* Copyright (C) 2005, 2006 Joerg Wunsch <j@uriah.heep.sax.de>
*
@@ -17,7 +17,6 @@
* 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$ */
/*
* Win32 serial bitbanging interface for avrdude.
@@ -40,8 +39,12 @@
#include "bitbang.h"
#include "serbb.h"
/* cached status lines */
static int dtr, rts, txd;
struct pdata {
int dtr, rts, txd; // Cached status lines
};
// Use private programmer data as if they were a global structure my
#define my (*(struct pdata *)(pgm->cookie))
#define W32SERBUFSIZE 1024
@@ -85,25 +88,26 @@ static int serbb_setpin(const PROGRAMMER *pgm, int pinfunc, int value) {
case 3: /* txd */
dwFunc = value? SETBREAK: CLRBREAK;
name = value? "SETBREAK": "CLRBREAK";
txd = value;
my.txd = value;
break;
case 4: /* dtr */
dwFunc = value? SETDTR: CLRDTR;
name = value? "SETDTR": "CLRDTR";
dtr = value;
my.dtr = value;
break;
case 7: /* rts */
dwFunc = value? SETRTS: CLRRTS;
name = value? "SETRTS": "CLRRTS";
my.rts = value;
break;
default:
pmsg_notice("serbb_setpin(): unknown pin %d\n", pin + 1);
pmsg_warning("%s(): unknown pin %d\n", __func__, pin + 1);
return -1;
}
pmsg_trace2("serbb_setpin(): EscapeCommFunction(%s)\n", name);
pmsg_trace2("%s(): EscapeCommFunction(%s)\n", __func__, name);
if (!EscapeCommFunction(hComPort, dwFunc))
{
FormatMessage(
@@ -168,7 +172,7 @@ static int serbb_getpin(const PROGRAMMER *pgm, int pinfunc) {
LocalFree(lpMsgBuf);
return -1;
}
pmsg_trace2("serbb_getpin(): GetCommState() => 0x%lx\n", modemstate);
pmsg_trace2("%s(): GetCommState() => 0x%lx\n", __func__, modemstate);
switch (pin)
{
case 1:
@@ -191,22 +195,22 @@ static int serbb_getpin(const PROGRAMMER *pgm, int pinfunc) {
switch (pin)
{
case 3: /* txd */
rv = txd;
rv = my.txd;
name = "TXD";
break;
case 4: /* dtr */
rv = dtr;
rv = my.dtr;
name = "DTR";
break;
case 7: /* rts */
rv = rts;
rv = my.rts;
name = "RTS";
break;
default:
pmsg_notice("serbb_getpin(): unknown pin %d\n", pin + 1);
pmsg_warning("%s(): unknown pin %d\n", __func__, pin + 1);
return -1;
}
pmsg_trace2("serbb_getpin(): return cached state for %s\n", name);
pmsg_trace2("%s(): return cached state for %s\n", __func__, name);
if (invert)
rv = !rv;
@@ -299,11 +303,11 @@ static int serbb_open(PROGRAMMER *pgm, const char *port) {
pmsg_error("cannot set com-state for %s\n", port);
return -1;
}
pmsg_debug("ser_open(): opened comm port %s, handle 0x%lx\n", port, (long) (INT_PTR) hComPort);
pmsg_debug("%s(): opened comm port %s, handle 0x%lx\n", __func__, port, (long) (INT_PTR) hComPort);
pgm->fd.pfd = (void *)hComPort;
dtr = rts = txd = 0;
my.dtr = my.rts = my.txd = 0;
return 0;
}
@@ -315,11 +319,20 @@ static void serbb_close(PROGRAMMER *pgm) {
pgm->setpin(pgm, PIN_AVR_RESET, 1);
CloseHandle (hComPort);
}
pmsg_debug("ser_close(): closed comm port handle 0x%lx\n", (long) (INT_PTR) hComPort);
pmsg_debug("%s(): closed comm port handle 0x%lx\n", __func__, (long) (INT_PTR) hComPort);
hComPort = INVALID_HANDLE_VALUE;
}
static void serbb_setup(PROGRAMMER *pgm) {
pgm->cookie = mmt_malloc(sizeof(struct pdata));
}
static void serbb_teardown(PROGRAMMER *pgm) {
mmt_free(pgm->cookie);
pgm->cookie = NULL;
}
const char serbb_desc[] = "Serial port bitbanging";
void serbb_initpgm(PROGRAMMER *pgm) {
@@ -327,6 +340,8 @@ void serbb_initpgm(PROGRAMMER *pgm) {
pgm_fill_old_pins(pgm); // TODO to be removed if old pin data no longer needed
pgm->setup = serbb_setup;
pgm->teardown = serbb_teardown;
pgm->rdy_led = bitbang_rdy_led;
pgm->err_led = bitbang_err_led;
pgm->pgm_led = bitbang_pgm_led;

View File

@@ -217,7 +217,7 @@ static char **sa_list_specs(const SERPORT *sp, int n, int i) {
if(sa_unique_by_sea(sea, "", sp, n, i))
Plist[Pi++] = mmt_strdup(id);
else if(*sn && sa_unique_by_sea(sea, sn, sp, n, i))
Plist[Pi++] = str_sprintf("%s:%s", id, sn);
Plist[Pi++] = mmt_sprintf("%s:%s", id, sn);
else if(!via && sa_num_matches_by_sea(sea, "", sp+i, 1))
via = id;
@@ -232,11 +232,11 @@ static char **sa_list_specs(const SERPORT *sp, int n, int i) {
if(Pi == 0 && sp[i].vid) { // No unique serial adapter, so maybe vid:pid[:sn] works?
if(sa_unique_by_ids(sp[i].vid, sp[i].pid, "", sp, n, i))
Plist[Pi++] = str_sprintf("usb:%04x:%04x", sp[i].vid, sp[i].pid);
Plist[Pi++] = mmt_sprintf("usb:%04x:%04x", sp[i].vid, sp[i].pid);
else if(*sn && sa_unique_by_ids(sp[i].vid, sp[i].pid, sn, sp, n, i))
Plist[Pi++] = str_sprintf("usb:%04x:%04x:%s", sp[i].vid, sp[i].pid, sn);
Plist[Pi++] = mmt_sprintf("usb:%04x:%04x:%s", sp[i].vid, sp[i].pid, sn);
else if(via && Pi == 0)
Plist[Pi++] = str_sprintf("(via %s serial adapter)", via);
Plist[Pi++] = mmt_sprintf("(via %s serial adapter)", via);
}
Plist[Pi] = NULL;
@@ -315,7 +315,7 @@ int touch_serialport(char **portp, int baudrate, int nwaits) {
if(!sp1 || n1 <= 0 || !portp)
return -1;
pmsg_info("touching serial port %s at %d baud\n", *portp, baudrate);
pmsg_notice("touching serial port %s at %d baud\n", *portp, baudrate);
union pinfo pinfo;
union filedescriptor fd;
@@ -334,18 +334,18 @@ int touch_serialport(char **portp, int baudrate, int nwaits) {
#if (defined(__arm__) || defined(__aarch64__)) && !defined(__APPLE__)
nwaits += 2;
#endif
pmsg_info("waiting for new port...");
pmsg_notice("waiting for new port...");
usleep(400*1000*nwaits);
for(i = nloops; i > 0; i--) {
usleep(nap*1000);
if((sp2 = get_libserialport_data(&n2))) {
diff = sa_spa_not_spb(sp2, n2, sp1, n1);
if(*diff && diff[0]->port && !diff[1]) { // Exactly one new port sprung up
pmsg_notice("new port %s discovered\n", (*diff)->port);
pmsg_notice2("new port %s discovered\n", (*diff)->port);
if(*portp)
mmt_free(*portp);
*portp = mmt_strdup((*diff)->port);
msg_info(" %d ms:", (nloops-i+1)*nap + nwaits*400);
msg_notice(" %d ms:", (nloops-i+1)*nap + nwaits*400);
i = -1; // Leave loop
}
mmt_free(diff);
@@ -353,7 +353,7 @@ int touch_serialport(char **portp, int baudrate, int nwaits) {
}
}
free_libserialport_data(sp1, n1);
msg_info(" using %s port %s\n", i<0? "new": "same", *portp);
msg_notice(" using %s port %s\n", i<0? "new": "same", *portp);
return 0;
}

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2021 Dawid Buchwald
* Copyright (C) 2021 Dawid Buchwald
*
* 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
@@ -17,8 +17,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* $Id$ */
/*
* Interface to the SerialUPDI programmer.
*
@@ -186,7 +184,7 @@ static void serialupdi_close(PROGRAMMER * pgm)
pmsg_error("unable to leave NVM programming mode\n");
}
if (updi_get_rts_mode(pgm) != RTS_MODE_DEFAULT) {
pmsg_info("releasing DTR/RTS handshake lines\n");
pmsg_notice("releasing DTR/RTS handshake lines\n");
}
updi_link_close(pgm);
@@ -604,7 +602,7 @@ static int serialupdi_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
pmsg_notice2("UPDI link initialization OK\n");
if (updi_get_rts_mode(pgm) != RTS_MODE_DEFAULT) {
pmsg_info("forcing serial DTR/RTS handshake lines %s\n", updi_get_rts_mode(pgm) == RTS_MODE_LOW ? "LOW" : "HIGH");
pmsg_notice("forcing serial DTR/RTS handshake lines %s\n", updi_get_rts_mode(pgm) == RTS_MODE_LOW ? "LOW" : "HIGH");
}
if (updi_read_cs(pgm, UPDI_ASI_SYS_STATUS, &value)<0) {
@@ -677,11 +675,11 @@ static int serialupdi_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
if (serialupdi_enter_progmode(pgm) == 0) {
/* If successful, you can run silicon check */
if (updi_read_data(pgm, p->syscfg_base+1, &value, 1) < 0) {
pmsg_error("Reading chip silicon revision failed\n");
pmsg_error("reading chip silicon revision failed\n");
return -1;
} else {
pmsg_debug("Received chip silicon revision 0x%02x\n", value);
pmsg_notice("Chip silicon revision: %x.%x\n", value >> 4, value & 0x0f);
pmsg_debug("received chip silicon revision 0x%02x\n", value);
pmsg_notice("chip silicon revision: %x.%x\n", value >> 4, value & 0x0f);
}
}
@@ -769,6 +767,11 @@ static int serialupdi_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const
buffer[0]=value;
return updi_nvm_write_flash(pgm, p, mem->offset + addr, buffer, 1);
}
if (mem_is_bootrow(mem)) {
unsigned char buffer[1];
buffer[0]=value;
return updi_nvm_write_boot_row(pgm, p, mem->offset + addr, buffer, 1);
}
// Read-only memories
if(mem_is_readonly(mem)) {
unsigned char is;
@@ -841,6 +844,9 @@ static int serialupdi_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const
} else if (mem_is_userrow(m)) {
rc = serialupdi_write_userrow(pgm, p, m, page_size, write_offset,
remaining_bytes > m->page_size ? m->page_size : remaining_bytes);
} else if (mem_is_bootrow(m)) {
rc = updi_nvm_write_boot_row(pgm, p, m->offset + write_offset, m->buf + write_offset,
remaining_bytes > m->page_size ? m->page_size : remaining_bytes);
} else if (mem_is_fuses(m)) {
pmsg_debug("page write operation requested for fuses, falling back to byte-level write\n");
return -1;
@@ -866,6 +872,8 @@ static int serialupdi_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const
rc = updi_nvm_write_flash(pgm, p, m->offset+addr, m->buf+addr, n_bytes);
} else if (mem_is_userrow(m)) {
rc = serialupdi_write_userrow(pgm, p, m, page_size, addr, n_bytes);
} else if (mem_is_bootrow(m)) {
rc = updi_nvm_write_boot_row(pgm, p, m->offset+addr, m->buf+addr, n_bytes);
} else if (mem_is_fuses(m)) {
pmsg_debug("page write operation requested for fuses, falling back to byte-level write\n");
rc = -1;
@@ -1004,13 +1012,12 @@ static int serialupdi_read_sib(const PROGRAMMER *pgm, const AVRPART *p, char *si
}
static int serialupdi_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) {
LNODEID ln;
const char *extended_param;
char rts_mode[5];
int rv = 0;
bool help = false;
for (ln = lfirst(extparms); ln; ln = lnext(ln)) {
extended_param = ldata(ln);
for (LNODEID ln = lfirst(extparms); ln; ln = lnext(ln)) {
const char *extended_param = ldata(ln);
if (sscanf(extended_param, "rtsdtr=%4s", rts_mode) == 1) {
if (str_caseeq(rts_mode, "low")) {
@@ -1018,20 +1025,26 @@ static int serialupdi_parseextparms(const PROGRAMMER *pgm, const LISTID extparms
} else if (str_caseeq(rts_mode, "high")) {
updi_set_rts_mode(pgm, RTS_MODE_HIGH);
} else {
pmsg_error("RTS/DTR mode must be LOW or HIGH\n");
return -1;
pmsg_error("-x rtsdtr=<mode>: RTS/DTR mode must be LOW or HIGH\n");
rv = -1;
break;
}
continue;
}
if (str_eq(extended_param, "help")) {
msg_error("%s -c %s extended options:\n", progname, pgmid);
msg_error(" -xrtsdtr=low,high Force RTS/DTR lines low or high state during programming\n");
msg_error(" -xhelp Show this help menu and exit\n");
return LIBAVRDUDE_EXIT;;
help = true;
rv = LIBAVRDUDE_EXIT;
}
pmsg_error("invalid extended parameter '%s'\n", extended_param);
rv = -1;
if (!help) {
pmsg_error("invalid extended parameter -x %s\n", extended_param);
rv = -1;
}
msg_error("%s -c %s extended options:\n", progname, pgmid);
msg_error(" -x rtsdtr=[low|high] Set RTS/DTR lines low/high during programming\n");
msg_error(" -x help Show this help menu and exit\n");
return rv;
}
return rv;

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2021 Dawid Buchwald
* Copyright (C) 2021 Dawid Buchwald
*
* 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
@@ -17,8 +17,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* $Id$ */
/*
* Based on pymcuprog
* See https://github.com/microchip-pic-avr-tools/pymcuprog

523
src/serprog.c Normal file
View File

@@ -0,0 +1,523 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Support for using serprog programmers to program over ISP.
* For information on serprog see:
* https://flashrom.org/supported_hw/supported_prog/serprog/index.html
*
* Copyright (C) 2024 Sydney Louisa Wilke <git@funkeleinhorn.com>
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Known limitations:
* - performance is suboptimal
* - connecting over TCP/IP to programmers is not implemented yet
*/
#include "ac_cfg.h"
#include "avrdude.h"
#include "libavrdude.h"
#include "serprog.h"
#include <fcntl.h>
#include <unistd.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char serprog_desc[] = "Program via the Serprog protocol from Flashrom";
// Private data for this programmer
struct pdata {
unsigned char cmd_bitmap[32];
unsigned int cs;
uint32_t actual_frequency;
};
#define my (*(struct pdata *)(pgm->cookie))
// Serprog protocol specification
// According to Serial Flasher Protocol Specification - version 1
#define S_ACK 0x06
#define S_NAK 0x15
#define S_CMD_NOP 0x00 // No operation
#define S_CMD_Q_IFACE 0x01 // Query interface version
#define S_CMD_Q_CMDMAP 0x02 // Query supported commands bitmap
#define S_CMD_Q_PGMNAME 0x03 // Query programmer name
#define S_CMD_Q_SERBUF 0x04 // Query Serial Buffer Size
#define S_CMD_Q_BUSTYPE 0x05 // Query supported bustypes
#define S_CMD_Q_CHIPSIZE 0x06 // Query supported chipsize (2^n format)
#define S_CMD_Q_OPBUF 0x07 // Query operation buffer size
#define S_CMD_Q_WRNMAXLEN 0x08 // Query Write to opbuf: Write-N maximum length
#define S_CMD_R_BYTE 0x09 // Read a single byte
#define S_CMD_R_NBYTES 0x0A // Read n bytes
#define S_CMD_O_INIT 0x0B // Initialize operation buffer
#define S_CMD_O_WRITEB 0x0C // Write opbuf: Write byte with address
#define S_CMD_O_WRITEN 0x0D // Write to opbuf: Write-N
#define S_CMD_O_DELAY 0x0E // Write opbuf: udelay
#define S_CMD_O_EXEC 0x0F // Execute operation buffer
#define S_CMD_SYNCNOP 0x10 // Special no-operation that returns NAK+ACK
#define S_CMD_Q_RDNMAXLEN 0x11 // Query read-n maximum length
#define S_CMD_S_BUSTYPE 0x12 // Set used bustype(s).
#define S_CMD_O_SPIOP 0x13 // Perform SPI operation.
#define S_CMD_S_SPI_FREQ 0x14 // Set SPI clock frequency
#define S_CMD_S_PIN_STATE 0x15 // Enable/disable output drivers
#define S_CMD_S_SPI_CS 0x16 // Set SPI chip select to use
#define S_CMD_S_SPI_MODE 0x17 // Sets the SPI mode used by S_CMD_O_SPIOP
#define S_CMD_S_CS_MODE 0x18 // Sets the way the CS is controlled
enum spi_mode {
SPI_MODE_HALF_DUPLEX = 0,
SPI_MODE_FULL_DUPLEX = 1,
SPI_MODE_MAX = SPI_MODE_FULL_DUPLEX,
};
enum cs_mode {
CS_MODE_AUTO = 0,
CS_MODE_SELECTED = 1,
CS_MODE_DESELECTED = 2,
CS_MODE_MAX = CS_MODE_DESELECTED,
};
// Little endian helper functions
static uint16_t read_le16(const unsigned char *buf) {
return buf[0] | (buf[1] << 8);
}
static uint32_t read_le32(const unsigned char *buf) {
return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
}
static void write_le24(unsigned char *buf, uint32_t val) {
buf[0] = val;
buf[1] = val >> 8;
buf[2] = val >> 16;
}
static void write_le32(unsigned char *buf, uint32_t val) {
buf[0] = val;
buf[1] = val >> 8;
buf[2] = val >> 16;
buf[3] = val >> 24;
}
// Serprog communication functions
static int perform_serprog_cmd_full(const PROGRAMMER *pgm, uint8_t cmd,
const unsigned char *params, int params_len,
const unsigned char *send_buf, int send_len, unsigned char *recv_buf, int recv_len) {
unsigned char resp_status_code = 0;
if(serial_send(&pgm->fd, &cmd, 1) < 0)
return -1;
if(params_len > 0)
if(serial_send(&pgm->fd, params, params_len) < 0)
return -1;
if(send_len > 0)
if(serial_send(&pgm->fd, send_buf, send_len) < 0)
return -1;
if(serial_recv(&pgm->fd, &resp_status_code, 1) < 0 || serial_recv(&pgm->fd, recv_buf, recv_len) < 0)
return -1;
return resp_status_code == S_ACK? 0: resp_status_code == S_NAK? 1: -1;
}
static int perform_serprog_cmd(const PROGRAMMER *pgm, uint8_t cmd,
const unsigned char *params, int params_len, unsigned char *recv_buf, int recv_len) {
return perform_serprog_cmd_full(pgm, cmd, params, params_len, NULL, 0, recv_buf, recv_len);
}
/**
* @brief Sends/receives a message to the AVR in full duplex mode
* @return -1 on failure, otherwise number of bytes sent/received
*/
static int serprog_spi_duplex(const PROGRAMMER *pgm, const unsigned char *tx, unsigned char *rx, int len) {
unsigned char params[6];
write_le24(params, len);
write_le24(params + 3, len);
if(perform_serprog_cmd_full(pgm, S_CMD_O_SPIOP, params, sizeof params, tx, len, rx, len) != 0)
return -1;
return len;
}
static bool is_serprog_cmd_supported(const unsigned char *cmd_bitmap, unsigned char cmd) {
return (cmd_bitmap[cmd / 8] >> (cmd % 8)) & 1;
}
// Programmer lifecycle handlers
static int serprog_open(PROGRAMMER *pgm, const char *port) {
union pinfo pinfo;
pgm->port = port;
pinfo.serialinfo.baud = pgm->baudrate? pgm->baudrate: 115200;
pinfo.serialinfo.cflags = SERIAL_8N1;
if(serial_open(port, pinfo, &pgm->fd) == -1)
return -1;
unsigned char buf[32];
// Sync
memset(buf, 0, sizeof buf);
if(perform_serprog_cmd(pgm, S_CMD_SYNCNOP, NULL, 0, buf, 1) != 1 || buf[0] != S_ACK) {
pmsg_error("cannot sync; is this a serprog programmer?\n");
return -1;
}
// Get command bitmap
memset(my.cmd_bitmap, 0, sizeof my.cmd_bitmap);
if(perform_serprog_cmd(pgm, S_CMD_Q_CMDMAP, NULL, 0, my.cmd_bitmap, 32) != 0) {
pmsg_error("cannot get list of supported serprog commands\n");
return -1;
}
// Get protocol version
memset(buf, 0, sizeof buf);
if(!is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_Q_IFACE)
|| perform_serprog_cmd(pgm, S_CMD_Q_IFACE, NULL, 0, buf, 2) != 0) {
pmsg_error("cannot get serprog protocol version\n");
return -1;
}
if(read_le16(buf) != 0x01) {
pmsg_error("unsupported serprog protocol version: %d\n", read_le16(buf));
return -1;
}
pmsg_info("serprog protocol version: %d\n", read_le16(buf));
// Get programmer name
if(is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_Q_PGMNAME)) {
memset(buf, 0, sizeof buf);
if(perform_serprog_cmd(pgm, S_CMD_Q_PGMNAME, NULL, 0, buf, 16) != 0) {
pmsg_error("cannot get programmer name\n");
return -1;
}
pmsg_info("programmer name: %s\n", buf);
}
// Check if required commands are supported
if(!is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_O_SPIOP)) {
pmsg_error("the %s programmer does not support SPI operations\n", pgmid);
return -1;
}
if(!is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_CS_MODE)) {
pmsg_error("the %s programmer does not support setting the CS mode\n", pgmid);
return -1;
}
if(!is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_MODE)) {
pmsg_error("the %s programmer does not support setting the SPI mode\n", pgmid);
return -1;
}
if(my.cs > 0 && !is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_CS)) {
pmsg_error("the %s programmer does not support changing the CS\n", pgmid);
return -1;
}
return 0;
}
static void serprog_disable(const PROGRAMMER *pgm) {
unsigned char buf[32];
// Switch CS to auto
const unsigned char cs_mode = CS_MODE_AUTO;
if(perform_serprog_cmd(pgm, S_CMD_S_CS_MODE, &cs_mode, 1, NULL, 0) != 0) {
pmsg_error("cannot reset the CS mode to auto\n");
}
// Disable output
if(is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_PIN_STATE)) {
memset(buf, 0, sizeof buf);
buf[0] = 0; // Pin state disable
if(perform_serprog_cmd(pgm, S_CMD_S_PIN_STATE, buf, 1, NULL, 0) != 0) {
pmsg_error("cannot disable pin state\n");
}
}
// Restore half duplex
memset(buf, 0, sizeof buf);
buf[0] = SPI_MODE_HALF_DUPLEX;
if(perform_serprog_cmd(pgm, S_CMD_S_SPI_MODE, buf, 1, NULL, 0) != 0)
pmsg_error("cannot reset SPI half duplex mode\n");
// Reset CS to CS_0
if(is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_CS)) {
memset(buf, 0, sizeof buf);
buf[0] = 0;
if(perform_serprog_cmd(pgm, S_CMD_S_SPI_CS, buf, 1, NULL, 0) != 0)
pmsg_error("cannot reset CS to CS_0\n");
}
}
static void serprog_close(PROGRAMMER *pgm) {
serial_close(&pgm->fd);
}
static int serprog_cmd(const PROGRAMMER *pgm, const unsigned char *cmd, unsigned char *res) {
return serprog_spi_duplex(pgm, cmd, res, 4);
}
static int serprog_initialize(const PROGRAMMER *pgm, const AVRPART *part) {
if(part->prog_modes & PM_TPI) {
// We do not support TPI; this is a dedicated SPI thing
pmsg_error("the %s programmer does not support TPI\n", pgmid);
return -1;
}
unsigned char buf[32];
// Set SPI clock frequency
if(is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_FREQ)) {
memset(buf, 0, sizeof buf);
uint32_t frequency =
pgm->bitclock > 0? 1/pgm->bitclock:
part->factory_fcpu > 0? part->factory_fcpu/4:
250000;
write_le32(buf, frequency);
if(perform_serprog_cmd(pgm, S_CMD_S_SPI_FREQ, buf, 4, buf, 4) != 0) {
pmsg_error("cannot set SPI frequency %u Hz\n", (unsigned) frequency);
return -1;
}
my.actual_frequency = read_le32(buf);
}
// Set active chip select
if(is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_CS)) {
memset(buf, 0, sizeof buf);
buf[0] = my.cs;
if(perform_serprog_cmd(pgm, S_CMD_S_SPI_CS, buf, 1, NULL, 0) != 0) {
pmsg_error("cannot change CS\n");
return -1;
}
}
// Set full duplex
memset(buf, 0, sizeof buf);
buf[0] = SPI_MODE_FULL_DUPLEX;
if(perform_serprog_cmd(pgm, S_CMD_S_SPI_MODE, buf, 1, NULL, 0) != 0) {
pmsg_error("cannot set SPI full duplex mode\n");
return -1;
}
// Set output
if(is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_PIN_STATE)) {
memset(buf, 0, sizeof buf);
buf[0] = 1; // Pin state enable
if(perform_serprog_cmd(pgm, S_CMD_S_PIN_STATE, buf, 1, NULL, 0) != 0) {
pmsg_error("cannot enable pin state\n");
return -1;
}
}
// Enable the CS/reset pin
const unsigned char cs_mode = CS_MODE_SELECTED;
if(perform_serprog_cmd(pgm, S_CMD_S_CS_MODE, &cs_mode, 1, NULL, 0) != 0) {
pmsg_error("cannot enable the reset pin\n");
return -1;
}
int tries, ret;
// Enable programming on the part
tries = 0;
do {
ret = pgm->program_enable(pgm, part);
if(ret == 0 || ret == -1)
break;
} while(tries++ < 65);
if(ret)
pmsg_error("AVR device not responding\n");
return ret;
}
/* used linuxspi.c as a template:
* Copyright (C) 2013 Kevin Cuzner <kevin@kevincuzner.com>
* Copyright (C) 2018 Ralf Ramsauer <ralf@vmexit.de>
*/
static int serprog_program_enable(const PROGRAMMER *pgm, const AVRPART *p) {
unsigned char cmd[4], res[4];
if(!p->op[AVR_OP_PGM_ENABLE]) {
pmsg_error("program enable instruction not defined for part %s\n", p->desc);
return -1;
}
memset(cmd, 0, sizeof cmd);
avr_set_bits(p->op[AVR_OP_PGM_ENABLE], cmd); // Set the cmd
pgm->cmd(pgm, cmd, res);
if(res[2] != cmd[1]) {
/** From ATtiny441 datasheet:
*
* In some systems, the programmer cannot guarantee that SCK is held low
* during power-up. In this case, RESET must be given a positive pulse after
* SCK has been set to '0'. The duration of the pulse must be at least t RST
* plus two CPU clock cycles. See Table 25-5 on page 240 for definition of
* minimum pulse width on RESET pin, t RST
* 2. Wait for at least 20 ms and then enable serial programming by sending
* the Programming Enable serial instruction to the SDO pin
* 3. The serial programming instructions will not work if the communication
* is out of synchronization. When in sync, the second byte (0x53) will echo
* back when issuing the third byte of the Programming Enable instruction
* ...
* If the 0x53 did not echo back, give RESET a positive pulse and issue a
* new Programming Enable command
*/
unsigned char cs_mode = CS_MODE_DESELECTED;
if(perform_serprog_cmd(pgm, S_CMD_S_CS_MODE, &cs_mode, 1, NULL, 0) != 0)
return -1;
usleep(5);
cs_mode = CS_MODE_SELECTED;
if(perform_serprog_cmd(pgm, S_CMD_S_CS_MODE, &cs_mode, 1, NULL, 0) != 0)
return -1;
usleep(20000);
return -2;
}
return 0;
}
static int serprog_chip_erase(const PROGRAMMER *pgm, const AVRPART *p) {
unsigned char cmd[4], res[4];
if(!p->op[AVR_OP_CHIP_ERASE]) {
pmsg_error("chip erase instruction not defined for part %s\n", p->desc);
return -1;
}
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);
pgm->initialize(pgm, p);
return 0;
}
static void serprog_display(const PROGRAMMER *pgm, const char *p) {
}
static void serprog_enable(PROGRAMMER *pgm, const AVRPART *p) {
}
static void serprog_setup(PROGRAMMER *pgm) {
pgm->cookie = mmt_malloc(sizeof(struct pdata));
}
static void serprog_teardown(PROGRAMMER *pgm) {
mmt_free(pgm->cookie);
pgm->cookie = NULL;
}
static int serprog_set_sck_period(const PROGRAMMER *pgm, double v) {
if(!is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_FREQ))
return -1;
unsigned char buf[8];
memset(buf, 0, sizeof buf);
write_le32(buf, v);
if(perform_serprog_cmd(pgm, S_CMD_S_SPI_FREQ, buf, 4, buf, 4) != 0) {
pmsg_error("cannot set SPI frequency\n");
return -1;
}
my.actual_frequency = read_le32(buf);
return 0;
}
static int serprog_get_sck_period(const PROGRAMMER *pgm, double *v) {
*v = my.actual_frequency;
return 0;
}
static int serprog_parseextparams(const PROGRAMMER *pgm, const LISTID extparms) {
int rv = 0;
bool help = false;
for(LNODEID ln = lfirst(extparms); ln; ln = lnext(ln)) {
const char *extended_param = ldata(ln);
if(str_starts(extended_param, "cs=")) {
unsigned int cs;
if(sscanf(extended_param, "cs=%u", &cs) != 1) {
pmsg_error("invalid chip select in -x %s\n", extended_param);
rv = -1;
break;
}
my.cs = cs;
continue;
}
if(str_eq(extended_param, "help")) {
help = true;
rv = LIBAVRDUDE_EXIT;
}
if(!help) {
pmsg_error("invalid extended parameter -x %s\n", extended_param);
rv = -1;
}
msg_error("%s -c %s extended options:\n", progname, pgmid);
msg_error(" -x cs=<n> Sets the chip select line to CS<n> for supported programmers\n");
msg_error(" -x help Show this help menu and exit\n");
return rv;
}
return rv;
}
void serprog_initpgm(PROGRAMMER *pgm) {
strcpy(pgm->type, "serprog");
// Required fields
pgm->initialize = serprog_initialize;
pgm->display = serprog_display;
pgm->enable = serprog_enable;
pgm->disable = serprog_disable;
pgm->program_enable = serprog_program_enable;
pgm->chip_erase = serprog_chip_erase;
pgm->cmd = serprog_cmd;
pgm->open = serprog_open;
pgm->close = serprog_close;
pgm->read_byte = avr_read_byte_default;
pgm->write_byte = avr_write_byte_default;
// Optional fields
pgm->setup = serprog_setup;
pgm->teardown = serprog_teardown;
pgm->parseextparams = serprog_parseextparams;
pgm->get_sck_period = serprog_get_sck_period;
pgm->set_sck_period = serprog_set_sck_period;
}

35
src/serprog.h Normal file
View File

@@ -0,0 +1,35 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
*
* Copyright (C) 2024 Sydney Louisa Wilke <git@funkeleinhorn.com>
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef serprog_h
#define serprog_h
#ifdef __cplusplus
extern "C" {
#endif
extern const char serprog_desc[];
void serprog_initpgm(PROGRAMMER *pgm);
#ifdef __cplusplus
}
#endif
#endif // serprog_h

View File

@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#ifndef solaris_ecpp_h
#define solaris_ecpp_h

View File

@@ -1,7 +1,7 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2002-2004 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2008,2014 Joerg Wunsch
* Copyright (C) 2008, 2014 Joerg Wunsch
*
* 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
@@ -17,8 +17,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
/*
* avrdude interface for Atmel STK500 programmer
*
@@ -116,7 +114,7 @@ int stk500_getsync(const PROGRAMMER *pgm) {
for (attempt = 0; attempt < max_sync_attempts; attempt++) {
// Restart Arduino bootloader for every sync attempt
if (str_eq(pgm->type, "Arduino") && attempt > 0) {
if(str_eq(pgm->type, "Arduino") && PDATA(pgm)->autoreset && attempt > 0) {
// This code assumes a negative-logic USB to TTL serial adapter
// Pull the RTS/DTR line low to reset AVR: it is still high from open()/last attempt
serial_set_dtr_rts(&pgm->fd, 1);
@@ -202,8 +200,7 @@ static int stk500_chip_erase(const PROGRAMMER *pgm, const AVRPART *p) {
unsigned char res[4];
if (pgm->cmd == NULL) {
pmsg_error("%s programmer uses stk500_chip_erase() but does not\n", pgm->type);
imsg_error("provide a cmd() method\n");
pmsg_error("%s programmer uses %s() without providing a cmd() method\n", pgm->type, __func__);
return -1;
}
@@ -450,7 +447,7 @@ static int stk500_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
}
#if 0
pmsg_info("stk500_initialize(): n_extparms = %d\n", n_extparms);
pmsg_notice("%s(): n_extparms = %d\n", __func__, n_extparms);
#endif
buf[5] = 1; /* polling supported - XXX need this in config file */
@@ -640,30 +637,28 @@ static int stk500_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
return pgm->program_enable(pgm, p);
}
static int stk500_parseextparms(const PROGRAMMER *pgm, const LISTID extparms)
{
LNODEID ln;
const char *extended_param;
int attempts;
int rv = 0;
static int stk500_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) {
int attempts;
int rv = 0;
bool help = false;
for (ln = lfirst(extparms); ln; ln = lnext(ln)) {
extended_param = ldata(ln);
for (LNODEID ln = lfirst(extparms); ln; ln = lnext(ln)) {
const char *extended_param = ldata(ln);
if (sscanf(extended_param, "attempts=%2d", &attempts) == 1) {
if (sscanf(extended_param, "attempts=%i", &attempts) == 1) {
PDATA(pgm)->retry_attempts = attempts;
pmsg_info("setting number of retry attempts to %d\n", attempts);
continue;
}
else if (str_starts(extended_param, "vtarg")) {
if (str_starts(extended_param, "vtarg")) {
if ((pgm->extra_features & HAS_VTARG_ADJ) && (str_starts(extended_param, "vtarg="))) {
// Set target voltage
double vtarg_set_val = -1; // default = invlid value
int sscanf_success = sscanf(extended_param, "vtarg=%lf", &vtarg_set_val);
PDATA(pgm)->vtarg_data = (double)((int)(vtarg_set_val * 100 + .5)) / 100;
if (sscanf_success < 1 || vtarg_set_val < 0) {
pmsg_error("invalid vtarg value %s\n", extended_param);
pmsg_error("invalid target voltage in -x %s\n", extended_param);
rv = -1;
break;
}
@@ -699,7 +694,7 @@ static int stk500_parseextparms(const PROGRAMMER *pgm, const LISTID extparms)
if (PDATA(pgm)->varef_set) {
PDATA(pgm)->varef_data = (double)((int)(varef_set_val * 100 + .5)) / 100;
if (sscanf_success < 1 || varef_set_val < 0) {
pmsg_error("invalid varef value %s\n", extended_param);
pmsg_error("invalid value in -x %s\n", extended_param);
PDATA(pgm)->varef_set = false;
rv = -1;
break;
@@ -717,7 +712,7 @@ static int stk500_parseextparms(const PROGRAMMER *pgm, const LISTID extparms)
// allow spaces in fosc_str
int sscanf_success = sscanf(extended_param, "fosc=%15[0-9.eE MmKkHhZzof]", fosc_str);
if (sscanf_success < 1) {
pmsg_error("invalid fosc value %s\n", extended_param);
pmsg_error("invalid value in -x %s\n", extended_param);
rv = -1;
break;
}
@@ -726,13 +721,12 @@ static int stk500_parseextparms(const PROGRAMMER *pgm, const LISTID extparms)
if (endp == fosc_str){ // no number
while ( *endp == ' ' ) // remove leading spaces
++endp;
if (str_starts(endp, "off"))
PDATA(pgm)->fosc_data = 0.0;
else {
pmsg_error("invalid fosc value %s\n", fosc_str);
if (!str_eq(endp, "off")) {
pmsg_error("invalid -x fosc=%s value\n", fosc_str);
rv = -1;
break;
}
PDATA(pgm)->fosc_data = 0.0;
}
while ( *endp == ' ' ) // remove leading spaces before unit
++endp;
@@ -759,14 +753,14 @@ static int stk500_parseextparms(const PROGRAMMER *pgm, const LISTID extparms)
char xtal_str[16] = {0};
int sscanf_success = sscanf(extended_param, "xtal=%15[0-9.eE MmKkHhZz]", xtal_str);
if (sscanf_success < 1) {
pmsg_error("invalid xtal value %s\n", extended_param);
pmsg_error("invalid value in -x %s\n", extended_param);
rv = -1;
break;
}
char *endp;
double v = strtod(xtal_str, &endp);
if (endp == xtal_str){
pmsg_error("invalid xtal value %s\n", xtal_str);
pmsg_error("invalid -x xtal=%s value\n", xtal_str);
rv = -1;
break;
}
@@ -783,33 +777,38 @@ static int stk500_parseextparms(const PROGRAMMER *pgm, const LISTID extparms)
}
else if (str_eq(extended_param, "help")) {
msg_error("%s -c %s extended options:\n", progname, pgmid);
msg_error(" -xattempts=<arg> Specify no. connection retry attempts\n");
if (pgm->extra_features & HAS_VTARG_READ) {
msg_error(" -xvtarg Read target supply voltage\n");
}
if (pgm->extra_features & HAS_VTARG_ADJ) {
msg_error(" -xvtarg=<arg> Set target supply voltage\n");
}
if (pgm->extra_features & HAS_VAREF_ADJ) {
msg_error(" -xvaref Read analog reference voltage\n");
msg_error(" -xvaref=<arg> Set analog reference voltage\n");
}
if (pgm->extra_features & HAS_FOSC_ADJ) {
msg_error(" -xfosc Read oscillator clock frequency\n");
msg_error(" -xfosc=<arg>[M|k]|off Set oscillator clock frequency\n");
}
msg_error(" -xxtal=<arg>[M|k] Set programmer xtal frequency\n");
msg_error(" -xhelp Show this help menu and exit\n");
return LIBAVRDUDE_EXIT;;
help = true;
rv = LIBAVRDUDE_EXIT;
}
pmsg_error("invalid extended parameter %s\n", extended_param);
rv = -1;
}
if (!help) {
pmsg_error("invalid extended parameter -x %s\n", extended_param);
rv = -1;
}
msg_error("%s -c %s extended options:\n", progname, pgmid);
msg_error(" -x attempts=<n> Specify the number <n> of connection retry attempts\n");
if (pgm->extra_features & HAS_VTARG_READ) {
msg_error(" -x vtarg Read target supply voltage\n");
}
if (pgm->extra_features & HAS_VTARG_ADJ) {
msg_error(" -x vtarg=<dbl> Set target supply voltage to <dbl> V\n");
}
if (pgm->extra_features & HAS_VAREF_ADJ) {
msg_error(" -x varef Read analog reference voltage\n");
msg_error(" -x varef=<dbl> Set analog reference voltage to <dbl> V\n");
}
if (pgm->extra_features & HAS_FOSC_ADJ) {
msg_error(" -x fosc Read oscillator clock frequency\n");
msg_error(" -x fosc=<n>[unit] Set oscillator clock frequency to <n> Hz (or kHz/MHz)\n");
msg_error(" -x fosc=off Switch the oscillator clock off\n");
}
msg_error(" -x xtal=<n>[unit] Set programmer xtal frequency to <n> Hz (or kHz/MHz)\n");
msg_error(" -x help Show this help menu and exit\n");
return rv;
}
return rv;
}
return rv;
}
static void stk500_disable(const PROGRAMMER *pgm) {
unsigned char buf[16];
@@ -894,8 +893,7 @@ static int stk500_open(PROGRAMMER *pgm, const char *port) {
}
static void stk500_close(PROGRAMMER * pgm)
{
static void stk500_close(PROGRAMMER *pgm) {
// MIB510 close
if (str_eq(pgmid, "mib510"))
(void)mib510_isp(pgm, 0);
@@ -1006,9 +1004,9 @@ static int set_memchr_a_div(const PROGRAMMER *pgm, const AVRPART *p, const AVRME
if(mem_is_eeprom(m)) {
*memchrp = 'E';
// Word addr for bootloaders or Arduino as ISP if part is a "classic" part, byte addr otherwise
// Word addr for bootloaders or Arduino as ISP if part is a classic part; byte addr otherwise
*a_divp = ((pgm->prog_modes & PM_SPM) || str_caseeq(pgmid, "arduino_as_isp")) \
&& !(p->prog_modes & (PM_UPDI | PM_PDI))? 2: 1;
&& (p->prog_modes & PM_Classic)? 2: 1;
return 0;
}
@@ -1569,7 +1567,7 @@ static void stk500_print_parms(const PROGRAMMER *pgm, FILE *fp) {
stk500_print_parms1(pgm, "", fp);
}
static void stk500_setup(PROGRAMMER * pgm) {
static void stk500_setup(PROGRAMMER *pgm) {
pgm->cookie = mmt_malloc(sizeof(struct pdata));
PDATA(pgm)->ext_addr_byte = 0xff;
PDATA(pgm)->xbeeResetPin = XBEE_DEFAULT_RESET_PIN;
@@ -1578,9 +1576,12 @@ static void stk500_setup(PROGRAMMER * pgm) {
PDATA(pgm)->xtal = 16000000U;
else
PDATA(pgm)->xtal = STK500_XTAL;
// The -c arduino programmer has auto-reset enabled be default
if (str_eq(pgm->type, "Arduino"))
PDATA(pgm)->autoreset = true;
}
static void stk500_teardown(PROGRAMMER * pgm) {
static void stk500_teardown(PROGRAMMER *pgm) {
mmt_free(pgm->cookie);
pgm->cookie = NULL;
}

View File

@@ -1,6 +1,6 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2002-2004 Brian S. Dean <bsd@bdmicro.com>
* Copyright (C) 2002-2004 Brian S. Dean <bsd@bdmicro.com>
*
* 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
@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
#ifndef stk500_h
#define stk500_h
@@ -60,6 +58,9 @@ struct pdata {
double fosc_data;
unsigned xtal; // Set STK500 XTAL frequency
// Flag to enable/disable autoreset for the arduino programmer
bool autoreset;
};
#define PDATA(pgm) ((struct pdata *)(pgm->cookie))

View File

@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
/*
* avrdude interface for Atmel STK500 programmer
*
@@ -47,8 +45,8 @@ static int stk500generic_open(PROGRAMMER *pgm, const char *port) {
if(pgm->setup)
pgm->setup(pgm);
if(pgm->open(pgm, port) >= 0) {
pmsg_info("successfully opened stk500v2 device\n");
imsg_info("in future, please use -c stk500v2, so -x parameters are available\n");
pmsg_info("successfully opened stk500v2 device; in future\n");
imsg_info("please use -c stk500v2, so -x parameters are available\n");
return 0;
}
if(pgm->teardown)
@@ -59,8 +57,8 @@ static int stk500generic_open(PROGRAMMER *pgm, const char *port) {
if(pgm->setup)
pgm->setup(pgm);
if(pgm->open(pgm, port) >= 0) {
pmsg_info("successfully opened stk500v1 device\n");
imsg_info("in future, please use -c stk500v1, so -x parameters are available\n");
pmsg_info("successfully opened stk500v1 device; in future\n");
imsg_info("please use -c stk500v1, so -x parameters are available\n");
return 0;
}

Some files were not shown because too many files have changed in this diff Show More