Provide cached byte-wise read/write API (#1106)

* Provide cached byte-wise read/write API

int avr_read_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const
  AVRMEM *mem, unsigned long addr, unsigned char *value);

int avr_write_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const
 AVRMEM *mem, unsigned long addr, unsigned char data);

int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p);

int avr_chip_erase_cached(const PROGRAMMER *pgm, const AVRPART *p);

int avr_reset_cache(const PROGRAMMER *pgm, const AVRPART *p);

avr_read_byte_cached() and avr_write_byte_cached() use a cache if paged
routines are available and if the device memory is EEPROM or flash,
otherwise they fall back to pgm->read_byte() and pgm->write_byte(),
respectively. Byte-wise cached read always gets its data from the cache,
possibly after reading a page from the device memory. Byte-wise cached
write with an address in memory range only ever modifies the cache. Any
modifications are written to the device after calling avr_flush_cache() or
when attempting to read or write from a location outside the address range
of the device memory.

avr_flush_cache() synchronises pending writes to EEPROM and flash with the
device. With some programmer and part combinations, flash (and sometimes
EEPROM, too) looks like a NOR memory, ie, one can only write 0 bits, not 1
bits. When this is detected, 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 back to the device. Hence, it can
take minutes to ensure that a single previously cleared bit is set and,
therefore, this routine should be called sparingly.

avr_chip_erase_cached() erases the chip and discards pending writes() to
flash or EEPROM. It presets the flash cache to all 0xff alleviating the
need to read from the device flash. However, if the programmer serves
bootloaders (pgm->prog_modes & PM_SPM) then the flash cache is reset
instead, necessitating flash memory be fetched from the device on first
read; the reason for this is that bootloaders emulate chip erase and they
won't overwrite themselves (some bootloaders, eg, optiboot ignore chip
erase commands altogether) making it truly unknowable what the flash
contents on device is after a chip erase. 

For EEPROM avr_chip_erase_cached() concludes that it has been deleted if a
previously cached EEPROM page that contained cleared bits now no longer
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.

Finally, avr_reset_cache() resets the cache without synchronising pending
writes() to the device.
This commit is contained in:
Stefan Rueger
2022-10-05 22:16:15 +01:00
committed by GitHub
parent c4cb242823
commit d74b17b9b4
9 changed files with 1056 additions and 194 deletions

View File

@@ -1333,91 +1333,139 @@ The following commands are implemented:
@table @code
@item dump @var{memtype} [@var{start_addr} [@var{nbytes}]]
@item dump @var{memtype} @var{addr} @var{nbytes}
Read @var{nbytes} from the specified memory area, and display them in
the usual hexadecimal and ASCII form.
@item dump @var{memtype} [@var{start_addr}] @dots{}
Start reading from @var{start_addr}, all the way to the last memory address.
@item dump @var{memtype} @var{addr} @dots{}
Start reading from @var{addr}, all the way to the last memory address.
@item dump @var{memtype} @var{addr}
Read 256 bytes from the specified memory area, and display them.
@item dump @var{memtype} @dots{}
Read all bytes from the specified memory, and display them.
@item dump @var{memtype}
Continue dumping the memory contents for another @var{nbytes} where the
previous dump command left off.
@item write @var{memtype} @var{start_addr} @var{data1} @var{data2} @dots{} @var{dataN}
Manually program the respective memory cells, starting at address @var{start_addr},
using the values @var{data1} through @var{dataN}. This feature is not
implemented for bank-addressed memories such as the flash memory of
ATMega devices.
@item write @var{memtype} @var{addr} @var{data[,]} @{@var{data[,]}@}
Manually program the respective memory cells, starting at address
@var{addr}, using the data items provided. The terminal implements
reading from and writing to flash and EEPROM type memories normally
through a cache and paged access functions. All other memories are
directly written to without use of a cache. Some older parts without paged
access will also have flash and EEPROM directly accessed without cache.
Items @var{dataN} can have the following formats:
Items @var{data} can have the following formats:
@multitable @columnfractions .3 .4 .3
@item @strong{Type}
@tab @strong{Example}
@tab @strong{Size (bytes)}
@item String
@tab @code{"Hello, world\n"}
@tab varying
@item Character
@tab @code{'A'}
@tab 1
@item Decimal integer
@tab 12345
@tab 1, 2, 4, or 8 (see below)
@tab 1, 2, 4, or 8
@item Octal integer
@tab 012345
@tab 1, 2, 4, or 8 (see below)
@tab 1, 2, 4, or 8
@item Hexadecimal integer
@tab 0x12345
@tab 1, 2, 4, or 8 (see below)
@tab 1, 2, 4, or 8
@item Float
@tab 3.1415926
@tab 4
@item Double
@tab 3.141592653589793D
@tab 8
@end multitable
Integer constants can be 1, 2, 4, or 8 bytes long.
By default, the smallest possible size will be used where
the specified number just fits into.
A specific size can be denoted by appending one of these suffixes:
@var{data}
can be hexadecimal, octal or decimal integers, floating point numbers
or C-style strings and characters. For integers, an optional case-insensitive
suffix specifies the data size as in the table below:
@table @code
@item LL
@itemx ll
8 bytes / 64 bits
@item L
@itemx l
4 bytes / 32 bits
@item H
@itemx h
@itemx S
@itemx s
@item H or S
2 bytes / 16 bits
@item HH
@itemx hh
1 byte / 8 bits
@end table
Similarly, floating-point constants can have an @code{F} or @code{f}
appended, but only 32-bit floating-point values are supported.
Suffix @code{D} indicates a 64-bit double, @code{F} a 32-bit float, whilst a
floating point number without suffix defaults to 32-bit float. Hexadecimal
floating point notation is supported. An ambiguous trailing suffix, eg,
@code{0x1.8D}, is read as no-suffix float where @code{D} is part of the
mantissa; use a zero exponent @code{0x1.8p0D} to clarify.
@item write @var{memtype} @var{start_addr} @var{length} @var{data1} @var{data2} @var{dataN} @dots{}
An optional @code{U} suffix makes integers unsigned. Ordinary @code{0x} hex
integers are always treated as unsigned. @code{+0x} or @code{-0x} hex
numbers are treated as signed unless they have a @code{U} suffix. Unsigned
integers cannot be larger than 2^64-1. If @var{n} is an unsigned integer then @var{-n}
is also a valid unsigned integer as in C. Signed integers must fall into
the [-2^63, 2^63-1] range or a correspondingly smaller range when a suffix
specifies a smaller type. Out of range signed numbers trigger a warning.
Similar to the above, but @var{length} byte of the memory are written.
For that purpose, after writing the initial items, @var{dataN} is
replicated as many times as needed.
Ordinary @code{0x} hex integers with @var{n} hex digits (counting leading
zeros) use the smallest size of 1, 2, 4 and 8 bytes that can accommodate
any n-digit hex integer. If an integer suffix specifies a size explicitly
the corresponding number of least significant bytes are written.
Otherwise, signed and unsigned integers alike occupy the smallest of 1, 2,
4, or 8 bytes needed to accommodate them in their respective
representation.
One trailing comma at the end of data items is ignored to facilitate copy
and paste of lists.
@item write @var{memtype} @var{addr} @var{length} @var{data[,]} @{@var{data[,]}@} @dots{}
The ellipses form @dots{} of write is similar to above, but @var{length}
byte of the memory are written. For that purpose, after writing the
initial items, the last @var{data} item is replicated as many times as
needed.
@item flush
Synchronise with the device all pending cached writes to EEPROM or flash.
With some programmer and part combinations, flash (and sometimes EEPROM,
too) looks like a NOR memory, ie, one can only write 0 bits, not 1 bits.
When this is detected, 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 chip erase command is issued and both
EEPROM and flash are written back to the device. Hence, it can take
minutes to ensure that a single previously cleared bit is set and,
therefore, this command should be used sparingly.
@item abort
Normally, caches are only ever actually written to the device when using
@code{flush}, at the end of the terminal session after typing @code{quit},
or after EOF on input is encountered. The @code{abort} command resets the
cache discarding all previous writes to the flash and EEPROM cache.
@item erase
Perform a chip erase.
Perform a chip erase and discard all pending writes to EEPROM and flash.
@item send @var{b1} @var{b2} @var{b3} @var{b4}
Send raw instruction codes to the AVR device. If you need access to a
Send raw instruction codes to the AVR device. If you need access to a
feature of an AVR part that is not directly supported by AVRDUDE, this
command allows you to use it, even though AVRDUDE does not implement the
command. When using direct SPI mode, up to 3 bytes
command. When using direct SPI mode, up to 3 bytes
can be omitted.
@item sig