Skip to content

Commit

Permalink
Merge branch 'avrdudes:main' into additional-memories
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanrueger committed Jul 7, 2024
2 parents 6de1cd9 + d10986f commit 09d4dbb
Show file tree
Hide file tree
Showing 8 changed files with 250 additions and 101 deletions.
8 changes: 8 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ Changes since version 7.3:

* Major changes compared to the previous version:

- Support of multi-memory .hex and .srec files and memory lists

* New devices supported:

- AVR16DU14, AVR16DU20, AVR16DU28, AVR16DU32
Expand Down Expand Up @@ -40,6 +42,8 @@ Changes since version 7.3:
- 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

* Pull requests:

Expand Down Expand Up @@ -95,6 +99,10 @@ Changes since version 7.3:
- 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

* Internals:

Expand Down
21 changes: 11 additions & 10 deletions src/avrcache.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,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
Expand All @@ -90,7 +90,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.
Expand Down Expand Up @@ -689,10 +689,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) {
Cache_desc 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;

Expand All @@ -718,19 +719,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_memset(cp->copy + n, 0xff, 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_memset(cp->copy + n, 0xff, 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);
Expand Down
61 changes: 39 additions & 22 deletions src/avrdude.1
Original file line number Diff line number Diff line change
Expand Up @@ -472,17 +472,15 @@ arduino.
.It Fl D
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.
Expand All @@ -491,9 +489,9 @@ 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
Expand Down Expand Up @@ -797,6 +795,7 @@ 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 ,
Expand All @@ -812,10 +811,26 @@ 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
Expand Down Expand Up @@ -949,10 +964,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
Expand Down Expand Up @@ -1275,8 +1291,9 @@ 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
Expand All @@ -1286,8 +1303,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
Expand Down
98 changes: 71 additions & 27 deletions src/developer_opts.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,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;
Expand Down Expand Up @@ -530,7 +533,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)
Expand Down Expand Up @@ -689,7 +692,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;
Expand Down Expand Up @@ -834,6 +837,7 @@ static int prog_modes_in_flags(int prog_modes, const char *flags) {
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;
Expand All @@ -849,9 +853,19 @@ static int prog_modes_in_flags(int prog_modes, const char *flags) {
return (prog_modes == 0 && quirky) || !pm || (prog_modes & pm);
}

// -p <wildcard>/[cdoASsrw*tiBUPTIJWHQ]
// 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();
Expand All @@ -862,27 +876,30 @@ 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*tiBUPTIJWHQ", *flags)) {
if(!*flags || !strchr("dsASRvcreow*tiBCUPTIJWHQ", *flags)) {
dev_info("%s: flags for developer option -p <wildcard>/<flags> not recognised\n", progname);
dev_info(
"Wildcard examples (these need protecting in the shell through quoting):\n"
" * all known parts\n"
" ATtiny10 just this part\n"
" *32[0-9] matches ATmega329, ATmega325 and ATmega328\n"
" *32? matches ATmega329, ATmega32A, ATmega325 and ATmega328\n"
" * 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"
" * as first character: all of the above except s and S\n"
" BUPTIJWHQ only Bootloader/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"
" 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"
Expand All @@ -894,19 +911,22 @@ 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');
Expand Down Expand Up @@ -978,6 +998,7 @@ void dev_output_part_defs(char *partdesc) {
int ok, nfuses;
AVRMEM *m;
OPCODE *oc;
const Avrintel *up;

ok = 2047;
nfuses = 0;
Expand Down Expand Up @@ -1111,6 +1132,29 @@ void dev_output_part_defs(char *partdesc) {
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) {
Expand Down Expand Up @@ -1263,7 +1307,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);
}
Expand All @@ -1272,9 +1316,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)
Expand Down
Loading

0 comments on commit 09d4dbb

Please sign in to comment.