Merge branch 'main' into pr-pointer-truncation

This commit is contained in:
Stefan Rueger 2022-10-11 14:43:19 +01:00 committed by GitHub
commit 22362e9f08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 341 additions and 336 deletions

View File

@ -44,6 +44,9 @@
* *
* int avr_chip_erase_cached(const PROGRAMMER *pgm, const AVRPART *p); * int avr_chip_erase_cached(const PROGRAMMER *pgm, const AVRPART *p);
* *
* int avr_page_erase_cached(const PROGRAMMER *pgm, const AVRPART *p, const
* AVRMEM *mem, unsigned int baseaddr);
*
* int avr_reset_cache(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 * avr_read_byte_cached() and avr_write_byte_cached() use a cache if paged
@ -82,6 +85,9 @@
* cache preset to all 0xff otherwise the cache discards all pending writes * cache preset to all 0xff otherwise the cache discards all pending writes
* to EEPROM and is left unchanged otherwise. * to EEPROM and is left unchanged otherwise.
* *
* The avr_page_erase_cached() function erases a page and synchronises it
* with the cache.
*
* Finally, avr_reset_cache() resets the cache without synchronising pending * Finally, avr_reset_cache() resets the cache without synchronising pending
* writes() to the device. * writes() to the device.
* *
@ -188,21 +194,18 @@ static int initCache(AVR_Cache *cp, const PROGRAMMER *pgm, const AVRPART *p) {
} }
static int cacheAddress(int addr, const AVR_Cache *cp, const AVRMEM *mem, int level) { static int cacheAddress(int addr, const AVR_Cache *cp, const AVRMEM *mem) {
int cacheaddr = addr + (int) (mem->offset - cp->offset); int cacheaddr = addr + (int) (mem->offset - cp->offset);
if(cacheaddr < 0 || cacheaddr >= cp->size) { // Should never happen (unless offsets wrong in avrdude.conf) if(cacheaddr < 0 || cacheaddr >= cp->size) { // Should never happen (unless offsets wrong in avrdude.conf)
if(level != MSG_INFO) avrdude_message(MSG_INFO, "%s: cacheAddress() %s cache address 0x%04x out of range [0, 0x%04x]\n",
avrdude_message(level, "%s: ", progname); progname, mem->desc, cacheaddr, cp->size);
avrdude_message(level, "cacheAddress() %s cache address 0x%04x out of range [0, 0x%04x]\n", mem->desc, cacheaddr, cp->size);
return LIBAVRDUDE_GENERAL_FAILURE; return LIBAVRDUDE_GENERAL_FAILURE;
} }
if(mem->page_size != cp->page_size) { // Should never happen (unless incompatible page sizes in avrdude.conf) if(mem->page_size != cp->page_size) { // Should never happen (unless incompatible page sizes in avrdude.conf)
if(level != MSG_INFO) avrdude_message(MSG_INFO, "%s: cacheAddress() %s page size %d incompatible with cache page size %d\n",
avrdude_message(level, "%s: ", progname); progname, mem->desc, mem->page_size, cp->page_size);
avrdude_message(level, "cacheAddress() %s page size %d incompatible with cache page size %d\n",
mem->desc, mem->page_size, cp->page_size);
return LIBAVRDUDE_GENERAL_FAILURE; return LIBAVRDUDE_GENERAL_FAILURE;
} }
@ -210,7 +213,7 @@ static int cacheAddress(int addr, const AVR_Cache *cp, const AVRMEM *mem, int le
} }
static int loadCachePage(AVR_Cache *cp, const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, int addr, int cacheaddr, int level) { static int loadCachePage(AVR_Cache *cp, const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, int addr, int cacheaddr, int nlOnErr) {
int pgno = cacheaddr/cp->page_size; int pgno = cacheaddr/cp->page_size;
if(!cp->iscached[pgno]) { if(!cp->iscached[pgno]) {
@ -218,9 +221,9 @@ static int loadCachePage(AVR_Cache *cp, const PROGRAMMER *pgm, const AVRPART *p,
int cachebase = cacheaddr & ~(cp->page_size-1); int cachebase = cacheaddr & ~(cp->page_size-1);
if(avr_read_page_default(pgm, p, mem, addr & ~(cp->page_size-1), cp->cont + cachebase) < 0) { if(avr_read_page_default(pgm, p, mem, addr & ~(cp->page_size-1), cp->cont + cachebase) < 0) {
report_progress(1, -1, NULL); report_progress(1, -1, NULL);
if(level != MSG_INFO || !quell_progress) if(nlOnErr && quell_progress)
avrdude_message(level, "%s: ", progname); avrdude_message(MSG_INFO, "\n");
avrdude_message(level, "loadCachePage() %s read failed at addr 0x%04x\n", mem->desc, addr); avrdude_message(MSG_INFO, "%s: loadCachePage() %s read error at addr 0x%04x\n", progname, mem->desc, addr);
return LIBAVRDUDE_GENERAL_FAILURE; return LIBAVRDUDE_GENERAL_FAILURE;
} }
@ -233,21 +236,21 @@ static int loadCachePage(AVR_Cache *cp, const PROGRAMMER *pgm, const AVRPART *p,
} }
static int writeCachePage(AVR_Cache *cp, const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, int base, int level) { static int writeCachePage(AVR_Cache *cp, const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, int base, int nlOnErr) {
// Write modified page cont to device // Write modified page cont to device
if(avr_write_page_default(pgm, p, mem, base, cp->cont + base) < 0) { if(avr_write_page_default(pgm, p, mem, base, cp->cont + base) < 0) {
report_progress(1, -1, NULL); report_progress(1, -1, NULL);
if(level != MSG_INFO || !quell_progress) if(nlOnErr && quell_progress)
avrdude_message(level, "%s: ", progname); avrdude_message(MSG_INFO, "\n");
avrdude_message(level, "writeCachePage() %s write error at addr 0x%04x\n", mem->desc, base); avrdude_message(MSG_INFO, "%s: writeCachePage() %s write error at addr 0x%04x\n", progname, mem->desc, base);
return LIBAVRDUDE_GENERAL_FAILURE; return LIBAVRDUDE_GENERAL_FAILURE;
} }
// Read page back from device and update copy to what is on device // Read page back from device and update copy to what is on device
if(avr_read_page_default(pgm, p, mem, base, cp->copy + base) < 0) { if(avr_read_page_default(pgm, p, mem, base, cp->copy + base) < 0) {
report_progress(1, -1, NULL); report_progress(1, -1, NULL);
if(level != MSG_INFO || !quell_progress) if(nlOnErr && quell_progress)
avrdude_message(level, "%s: ", progname); avrdude_message(MSG_INFO, "\n");
avrdude_message(level, "writeCachePage() %s read error at addr 0x%04x\n", mem->desc, base); avrdude_message(MSG_INFO, "%s: writeCachePage() %s read error at addr 0x%04x\n", progname, mem->desc, base);
return LIBAVRDUDE_GENERAL_FAILURE; return LIBAVRDUDE_GENERAL_FAILURE;
} }
@ -326,15 +329,17 @@ int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) {
AVR_Cache *cp = mems[i].cp; AVR_Cache *cp = mems[i].cp;
if(!cp->cont) // Ensure cache is initialised from now on if(!cp->cont) // Ensure cache is initialised from now on
if(initCache(cp, pgm, p) < 0) if(initCache(cp, pgm, p) < 0) {
avrdude_message(MSG_INFO, "%s: initialising the cache failed\n", progname);
return LIBAVRDUDE_GENERAL_FAILURE; return LIBAVRDUDE_GENERAL_FAILURE;
}
if(chiperase || !mem || mems[i].zopaddr < 0) if(chiperase || !mem || mems[i].zopaddr < 0)
continue; continue;
int n=mems[i].zopaddr; int n=mems[i].zopaddr;
if(writeCachePage(cp, pgm, p, mem, n, MSG_INFO) < 0) if(writeCachePage(cp, pgm, p, mem, n, 1) < 0)
return LIBAVRDUDE_GENERAL_FAILURE; return LIBAVRDUDE_GENERAL_FAILURE;
// Same? OK, can set cleared bit to one, "normal" memory // Same? OK, can set cleared bit to one, "normal" memory
if(!memcmp(cp->copy + n, cp->cont + n, cp->page_size)) { if(!memcmp(cp->copy + n, cp->cont + n, cp->page_size)) {
@ -344,7 +349,7 @@ int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) {
// Probably NOR memory, check out page erase // Probably NOR memory, check out page erase
if(pgm->page_erase && pgm->page_erase(pgm, p, mem, n) >= 0) { if(pgm->page_erase && pgm->page_erase(pgm, p, mem, n) >= 0) {
if(writeCachePage(cp, pgm, p, mem, n, MSG_INFO) < 0) if(writeCachePage(cp, pgm, p, mem, n, 1) < 0)
return LIBAVRDUDE_GENERAL_FAILURE; return LIBAVRDUDE_GENERAL_FAILURE;
// Worked OK? Can use page erase on this memory // Worked OK? Can use page erase on this memory
if(!memcmp(cp->copy + n, cp->cont + n, cp->page_size)) { if(!memcmp(cp->copy + n, cp->cont + n, cp->page_size)) {
@ -357,8 +362,10 @@ int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) {
chiperase = 1; chiperase = 1;
} }
if(!chpages) if(!chpages) {
avrdude_message(MSG_INFO, "done\n");
return LIBAVRDUDE_SUCCESS; return LIBAVRDUDE_SUCCESS;
}
if(chiperase) { if(chiperase) {
if(quell_progress) { if(quell_progress) {
@ -379,8 +386,8 @@ int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) {
nrd++; nrd++;
} }
report_progress(0, 1, "Reading");
if(nrd) { if(nrd) {
report_progress(0, 1, "Reading");
// Read full flash and EEPROM // Read full flash and EEPROM
for(size_t i = 0; i < sizeof mems/sizeof*mems; i++) { for(size_t i = 0; i < sizeof mems/sizeof*mems; i++) {
AVRMEM *mem = mems[i].mem; AVRMEM *mem = mems[i].mem;
@ -391,20 +398,20 @@ int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) {
for(int ird = 0, pgno = 0, n = 0; n < cp->size; pgno++, n += cp->page_size) { for(int ird = 0, pgno = 0, n = 0; n < cp->size; pgno++, n += cp->page_size) {
if(!cp->iscached[pgno]) { if(!cp->iscached[pgno]) {
report_progress(ird++, nrd, NULL); report_progress(ird++, nrd, NULL);
if(loadCachePage(cp, pgm, p, mem, n, n, MSG_INFO) < 0) if(loadCachePage(cp, pgm, p, mem, n, n, 1) < 0)
return LIBAVRDUDE_GENERAL_FAILURE; return LIBAVRDUDE_GENERAL_FAILURE;
} }
} }
} }
report_progress(1, 0, NULL);
} }
report_progress(1, 0, NULL);
report_progress(0, 1, "Erasing"); report_progress(0, 1, "Erasing");
if(avr_chip_erase(pgm, p) < 0) { if(avr_chip_erase(pgm, p) < 0) {
report_progress(1, -1, NULL); report_progress(1, -1, NULL);
if(!quell_progress) if(quell_progress)
avrdude_message(MSG_INFO, "%s: ", progname); avrdude_message(MSG_INFO, "\n");
avrdude_message(MSG_INFO, "avr_flush_cache() chip erase failed\n"); avrdude_message(MSG_INFO, "%s: avr_flush_cache() chip erase failed\n", progname);
return LIBAVRDUDE_GENERAL_FAILURE; return LIBAVRDUDE_GENERAL_FAILURE;
} }
@ -426,9 +433,9 @@ int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) {
report_progress(1+ibo++, nbo+2, NULL); report_progress(1+ibo++, nbo+2, NULL);
if(avr_read_page_default(pgm, p, mem, n, cp->copy + n) < 0) { if(avr_read_page_default(pgm, p, mem, n, cp->copy + n) < 0) {
report_progress(1, -1, NULL); report_progress(1, -1, NULL);
if(!quell_progress) if(quell_progress)
avrdude_message(MSG_INFO, "%s: ", progname); avrdude_message(MSG_INFO, "\n");
avrdude_message(MSG_INFO, "flash read failed at addr 0x%04x\n", n); avrdude_message(MSG_INFO, "%s: flash read failed at addr 0x%04x\n", progname, n);
return LIBAVRDUDE_GENERAL_FAILURE; return LIBAVRDUDE_GENERAL_FAILURE;
} }
} }
@ -439,9 +446,9 @@ int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) {
if(!_is_all_0xff(cp->copy + n, cp->page_size)) { // First page that had EEPROM data if(!_is_all_0xff(cp->copy + n, cp->page_size)) { // First page that had EEPROM data
if(avr_read_page_default(pgm, p, mem, n, cp->copy + n) < 0) { if(avr_read_page_default(pgm, p, mem, n, cp->copy + n) < 0) {
report_progress(1, -1, NULL); report_progress(1, -1, NULL);
if(!quell_progress) if(quell_progress)
avrdude_message(MSG_INFO, "%s: ", progname); avrdude_message(MSG_INFO, "\n");
avrdude_message(MSG_INFO, "EEPROM read failed at addr 0x%04x\n", n); avrdude_message(MSG_INFO, "%s: EEPROM read failed at addr 0x%04x\n", progname, n);
return LIBAVRDUDE_GENERAL_FAILURE; return LIBAVRDUDE_GENERAL_FAILURE;
} }
// EEPROM zapped by chip erase? Set all copy to 0xff // EEPROM zapped by chip erase? Set all copy to 0xff
@ -468,8 +475,8 @@ int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) {
nwr++; nwr++;
} }
report_progress(0, 1, "Writing");
if(nwr) { if(nwr) {
report_progress(0, 1, "Writing");
// Write all modified pages to the device // Write all modified pages to the device
for(size_t i = 0; i < sizeof mems/sizeof*mems; i++) { for(size_t i = 0; i < sizeof mems/sizeof*mems; i++) {
AVRMEM *mem = mems[i].mem; AVRMEM *mem = mems[i].mem;
@ -481,24 +488,23 @@ int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) {
if(cp->iscached[pgno] && memcmp(cp->copy + n, cp->cont + n, cp->page_size)) { if(cp->iscached[pgno] && memcmp(cp->copy + n, cp->cont + n, cp->page_size)) {
if(!chiperase && mems[i].pgerase) if(!chiperase && mems[i].pgerase)
pgm->page_erase(pgm, p, mem, n); pgm->page_erase(pgm, p, mem, n);
if(writeCachePage(cp, pgm, p, mem, n, MSG_INFO) < 0) if(writeCachePage(cp, pgm, p, mem, n, 1) < 0)
return LIBAVRDUDE_GENERAL_FAILURE; return LIBAVRDUDE_GENERAL_FAILURE;
if(memcmp(cp->copy + n, cp->cont + n, cp->page_size)) { if(memcmp(cp->copy + n, cp->cont + n, cp->page_size)) {
report_progress(1, -1, NULL); report_progress(1, -1, NULL);
if(!quell_progress) if(quell_progress)
avrdude_message(MSG_INFO, "%s: ", progname); avrdude_message(MSG_INFO, "\n");
avrdude_message(MSG_INFO, "%s verification error at addr 0x%04x\n", mem->desc, n); avrdude_message(MSG_INFO, "%s: %s verification error at addr 0x%04x\n", progname, mem->desc, n);
return LIBAVRDUDE_GENERAL_FAILURE; return LIBAVRDUDE_GENERAL_FAILURE;
} }
report_progress(iwr++, nwr, NULL); report_progress(iwr++, nwr, NULL);
} }
} }
} }
report_progress(1, 0, NULL);
} }
report_progress(1, 0, NULL);
avrdude_message(MSG_INFO, quell_progress? "done\n": "\n"); avrdude_message(MSG_INFO, quell_progress? "done\n": "\n");
return LIBAVRDUDE_SUCCESS; return LIBAVRDUDE_SUCCESS;
} }
@ -531,12 +537,12 @@ int avr_read_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *
if(initCache(cp, pgm, p) < 0) if(initCache(cp, pgm, p) < 0)
return LIBAVRDUDE_GENERAL_FAILURE; return LIBAVRDUDE_GENERAL_FAILURE;
int cacheaddr = cacheAddress((int) addr, cp, mem, MSG_NOTICE); int cacheaddr = cacheAddress((int) addr, cp, mem);
if(cacheaddr < 0) if(cacheaddr < 0)
return LIBAVRDUDE_GENERAL_FAILURE; return LIBAVRDUDE_GENERAL_FAILURE;
// Ensure cache page is there // Ensure cache page is there
if(loadCachePage(cp, pgm, p, mem, addr, cacheaddr, MSG_NOTICE) < 0) if(loadCachePage(cp, pgm, p, mem, addr, cacheaddr, 0) < 0)
return LIBAVRDUDE_GENERAL_FAILURE; return LIBAVRDUDE_GENERAL_FAILURE;
*value = cp->cont[cacheaddr]; *value = cp->cont[cacheaddr];
@ -569,12 +575,12 @@ int avr_write_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM
if(initCache(cp, pgm, p) < 0) if(initCache(cp, pgm, p) < 0)
return LIBAVRDUDE_GENERAL_FAILURE; return LIBAVRDUDE_GENERAL_FAILURE;
int cacheaddr = cacheAddress((int) addr, cp, mem, MSG_NOTICE); int cacheaddr = cacheAddress((int) addr, cp, mem);
if(cacheaddr < 0) if(cacheaddr < 0)
return LIBAVRDUDE_GENERAL_FAILURE; return LIBAVRDUDE_GENERAL_FAILURE;
// Ensure cache page is there // Ensure cache page is there
if(loadCachePage(cp, pgm, p, mem, addr, cacheaddr, MSG_NOTICE) < 0) if(loadCachePage(cp, pgm, p, mem, addr, cacheaddr, 0) < 0)
return LIBAVRDUDE_GENERAL_FAILURE; return LIBAVRDUDE_GENERAL_FAILURE;
cp->cont[cacheaddr] = data; cp->cont[cacheaddr] = data;
@ -640,6 +646,42 @@ int avr_chip_erase_cached(const PROGRAMMER *pgm, const AVRPART *p) {
} }
// Erase a page and synchronise it with the cache
int avr_page_erase_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem,
unsigned int uaddr) {
int addr = uaddr;
if(!pgm->page_erase || !avr_has_paged_access(pgm, mem) || addr < 0 || addr >= mem->size)
return LIBAVRDUDE_GENERAL_FAILURE;
if(pgm->page_erase(pgm, p, mem, uaddr) < 0)
return LIBAVRDUDE_GENERAL_FAILURE;
AVR_Cache *cp = avr_mem_is_eeprom_type(mem)? pgm->cp_eeprom: pgm->cp_flash;
if(!cp->cont) // Init cache if needed
if(initCache(cp, pgm, p) < 0)
return LIBAVRDUDE_GENERAL_FAILURE;
int cacheaddr = cacheAddress(addr, cp, mem);
if(cacheaddr < 0)
return LIBAVRDUDE_GENERAL_FAILURE;
// Invalidate this cache page and read back, ie, we don't trust the page_erase() routine
cp->iscached[cacheaddr/cp->page_size] = 0;
// Reload cache page
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))
return LIBAVRDUDE_GENERAL_FAILURE;
return LIBAVRDUDE_SUCCESS;
}
// Free cache(s) discarding any pending writes // Free cache(s) discarding any pending writes
int avr_reset_cache(const PROGRAMMER *pgm, const AVRPART *p) { int avr_reset_cache(const PROGRAMMER *pgm, const AVRPART *p) {
AVR_Cache *mems[2] = { pgm->cp_flash, pgm->cp_eeprom, }; AVR_Cache *mems[2] = { pgm->cp_flash, pgm->cp_eeprom, };

View File

@ -639,7 +639,7 @@ Note: The ability to handle IPv6 hostnames and addresses is limited to
Posix systems (by now). Posix systems (by now).
.It Fl q .It Fl q
Disable (or quell) output of the progress bar while reading or writing Disable (or quell) output of the progress bar while reading or writing
to the device. Specify it a second time for even quieter operation. to the device. Specify it more often for even quieter operations.
.It Fl s, u .It Fl s, u
These options used to control the obsolete "safemode" feature which These options used to control the obsolete "safemode" feature which
is no longer present. They are silently ignored for backwards compatibility. is no longer present. They are silently ignored for backwards compatibility.
@ -812,7 +812,7 @@ abbreviated to the shortest unambiguous form. Terminal mode provides
a command history using a command history using
.Xr readline 3 , .Xr readline 3 ,
so previously entered command lines can be recalled and edited. The so previously entered command lines can be recalled and edited. The
following commands are currently implemented: following commands are currently implemented for all programmers:
.Bl -tag -offset indent -width indent .Bl -tag -offset indent -width indent
.It Ar dump memory addr len .It Ar dump memory addr len
Read Read
@ -827,12 +827,14 @@ and display them.
Read 256 bytes from the specified memory area, and display them. Read 256 bytes from the specified memory area, and display them.
.It Ar dump memory ... .It Ar dump memory ...
Read all bytes from the specified memory, and display them. Read all bytes from the specified memory, and display them.
.It Ar dump .It Ar dump memory
Continue dumping the memory contents for another Continue dumping the memory contents for another
.Ar 256 .Ar 256
bytes where the previous bytes where the previous
.Ar dump .Ar dump
command left off. command left off.
.It Ar read
can be used as an alias for dump
.It Ar write memory addr data[,] {data[,]} .It Ar write memory addr data[,] {data[,]}
Manually program the respective memory cells, starting at address Manually program the respective memory cells, starting at address
.Ar addr , .Ar addr ,
@ -895,6 +897,39 @@ or after EOF on input is encountered. The abort command resets
the cache discarding all previous writes to the flash and EEPROM cache. the cache discarding all previous writes to the flash and EEPROM cache.
.It Ar erase .It Ar erase
Perform a chip erase and discard all pending writes to EEPROM and flash. Perform a chip erase and discard all pending writes to EEPROM and flash.
.It Ar sig
Display the device signature bytes.
.It Ar part
Display the current part settings and parameters. Includes chip
specific information including all memory types supported by the
device, read/write timing, etc.
.It Ar verbose Op Ar level
Change (when
.Ar level
is provided), or display the verbosity level.
The initial verbosity level is controlled by the number of
.Fl v
options given on the commandline.
.It Ar quell Op Ar level
Change (when
.Ar level
is provided), or display the quell level. 1 is used to suppress progress reports.
2 or higher yields in progressively quieter operations.
The initial quell level is controlled by the number of
.Fl q
options given on the commandline.
.It Ar \&?
.It Ar help
Give a short on-line summary of the available commands.
.It Ar quit
Leave terminal mode and thus
.Nm avrdude .
.El
.Pp
The terminal commands below may only be implemented on some specific programmers, and may therefore not be available in the help menu.
.Bl -tag -offset indent -width indent
.It pgerase memory addr
Erase one page of the memory specified.
.It Ar send b1 b2 b3 b4 .It Ar send b1 b2 b3 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 feature of an AVR part that is not directly supported by
@ -903,24 +938,18 @@ this command allows you to use it, even though
.Nm .Nm
does not implement the command. When using direct SPI mode, up to 3 bytes does not implement the command. When using direct SPI mode, up to 3 bytes
can be omitted. can be omitted.
.It Ar sig
Display the device signature bytes.
.It Ar spi .It Ar spi
Enter direct SPI mode. The Enter direct SPI mode. The
.Em pgmled .Em pgmled
pin acts as slave select. pin acts as slave select.
.Em Only supported on parallel bitbang programmers, and partially by USBtiny. .Em Supported on parallel bitbang programmers, and partially by USBtiny.
.It Ar part
Display the current part settings and parameters. Includes chip
specific information including all memory types supported by the
device, read/write timing, etc.
.It Ar pgm .It Ar pgm
Return to programming mode (from direct SPI mode). Return to programming mode (from direct SPI mode).
.It Ar vtarg voltage .It Ar vtarg voltage
Set the target's supply voltage to Set the target's supply voltage to
.Ar voltage .Ar voltage
Volts. Volts.
.Em Only supported on the STK500 and STK600 programmer. .Em Supported on the STK500 and STK600 programmer.
.It Ar varef Oo Ar channel Oc Ar voltage .It Ar varef Oo Ar channel Oc Ar voltage
Set the adjustable voltage source to Set the adjustable voltage source to
.Ar voltage .Ar voltage
@ -932,7 +961,7 @@ On the Atmel STK600, two reference voltages are available, which
can be selected by the optional can be selected by the optional
.Ar channel .Ar channel
argument (either 0 or 1). argument (either 0 or 1).
.Em Only supported on the STK500 and STK600 programmer. .Em Supported on the STK500 and STK600 programmer.
.It Ar fosc freq Ns Op M Ns \&| Ns k .It Ar fosc freq Ns Op M Ns \&| Ns k
Set the master oscillator to Set the master oscillator to
.Ar freq .Ar freq
@ -942,17 +971,16 @@ An optional trailing letter
multiplies by 1E6, a trailing letter multiplies by 1E6, a trailing letter
.Ar \&k .Ar \&k
by 1E3. by 1E3.
.Em Only supported on the STK500 and STK600 programmer. .Em Supported on the STK500 and STK600 programmer.
.It Ar fosc off .It Ar fosc off
Turn the master oscillator off. Turn the master oscillator off.
.Em Only supported on the STK500 and STK600 programmer. .Em Supported on the STK500 and STK600 programmer.
.It Ar sck period .It Ar sck period
.Em STK500 and STK600 programmer only: .Em STK500 and STK600 programmer:
Set the SCK clock period to Set the SCK clock period to
.Ar period .Ar period
microseconds. microseconds.
.Pp .Em JTAG ICE:
.Em JTAG ICE only:
Set the JTAG ICE bit clock period to Set the JTAG ICE bit clock period to
.Ar period .Ar period
microseconds. microseconds.
@ -962,24 +990,12 @@ software signs off from the JTAG ICE.
This parameter can also be used on the JTAG ICE mkII, JTAGICE3, and Atmel-ICE to specify the This parameter can also be used on the JTAG ICE mkII, JTAGICE3, and Atmel-ICE to specify the
ISP clock period when operating the ICE in ISP mode. ISP clock period when operating the ICE in ISP mode.
.It Ar parms .It Ar parms
.Em STK500 and STK600 programmer only: .Em STK500 and STK600 programmer:
Display the current voltage and master oscillator parameters. Display the current voltage and master oscillator parameters.
.Pp .Em JTAG ICE:
.Em JTAG ICE only:
Display the current target supply voltage and JTAG bit clock rate/period. Display the current target supply voltage and JTAG bit clock rate/period.
.It Ar verbose Op Ar level .Em Other programmers:
Change (when Display the programmer specific parameters.
.Ar level
is provided), or display the verbosity level.
The initial verbosity level is controlled by the number of
.Fl v
options given on the commandline.
.It Ar \&?
.It Ar help
Give a short on-line summary of the available commands.
.It Ar quit
Leave terminal mode and thus
.Nm avrdude .
.El .El
.Ss Default Parallel port pin connections .Ss Default Parallel port pin connections
(these can be changed, see the (these can be changed, see the

View File

@ -1329,7 +1329,7 @@ commands can be recalled and edited.
@section Terminal Mode Commands @section Terminal Mode Commands
@noindent @noindent
The following commands are implemented: The following commands are implemented for all programmers:
@table @code @table @code
@ -1350,6 +1350,9 @@ Read all bytes from the specified memory, and display them.
Continue dumping the memory contents for another @var{nbytes} where the Continue dumping the memory contents for another @var{nbytes} where the
previous dump command left off. previous dump command left off.
@item read
Can be used as an alias for dump.
@item write @var{memtype} @var{addr} @var{data[,]} @{@var{data[,]}@} @item write @var{memtype} @var{addr} @var{data[,]} @{@var{data[,]}@}
Manually program the respective memory cells, starting at address Manually program the respective memory cells, starting at address
@var{addr}, using the data items provided. The terminal implements @var{addr}, using the data items provided. The terminal implements
@ -1461,36 +1464,26 @@ cache discarding all previous writes to the flash and EEPROM cache.
@item erase @item erase
Perform a chip erase and discard all pending writes to EEPROM and flash. 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
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
can be omitted.
@item sig @item sig
Display the device signature bytes. Display the device signature bytes.
@item spi
Enter direct SPI mode. The @emph{pgmled} pin acts as slave select.
@emph{Only supported on parallel bitbang programmers, and partially by USBtiny.}
Slave Select must be externally held low for direct SPI when
using USBtinyISP, and send must be a multiple of four bytes.
@item part @item part
Display the current part settings and parameters. Includes chip Display the current part settings and parameters. Includes chip
specific information including all memory types supported by the specific information including all memory types supported by the
device, read/write timing, etc. device, read/write timing, etc.
@item pgm
Return to programming mode (from direct SPI mode).
@item verbose [@var{level}] @item verbose [@var{level}]
Change (when @var{level} is provided), or display the verbosity Change (when @var{level} is provided), or display the verbosity
level. level.
The initial verbosity level is controlled by the number of @code{-v} options The initial verbosity level is controlled by the number of @code{-v} options
given on the command line. given on the command line.
@item quell [@var{level}]
Change (when @var{level} is provided), or display the quell
level. 1 is used to suppress progress reports. 2 or higher yields
progressively quieter operations. The initial quell level is controlled
by the number of @code{-q} options given on the command line.
@item ? @item ?
@itemx help @itemx help
Give a short on-line summary of the available commands. Give a short on-line summary of the available commands.
@ -1501,11 +1494,29 @@ Leave terminal mode and thus AVRDUDE.
@end table @end table
@noindent @noindent
In addition, the following commands are supported on the STK500 In addition, the following commands are supported on some programmers:
and STK600 programmer:
@table @code @table @code
@item pgerase @var{memory} @var{addr}
Erase one page of the memory specified.
@item send @var{b1} @var{b2} @var{b3} @var{b4}
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
can be omitted.
@item spi
Enter direct SPI mode. The @emph{pgmled} pin acts as slave select.
@emph{Only supported on parallel bitbang programmers, and partially by USBtiny.}
Slave Select must be externally held low for direct SPI when
using USBtinyISP, and send must be a multiple of four bytes.
@item pgm
Return to programming mode (from direct SPI mode).
@item vtarg @var{voltage} @item vtarg @var{voltage}
Set the target's supply voltage to @var{voltage} Volts. Set the target's supply voltage to @var{voltage} Volts.
@ -1528,7 +1539,6 @@ Turn the master oscillator off.
@item sck @var{period} @item sck @var{period}
@emph{STK500 and STK600 only:} @emph{STK500 and STK600 only:}
Set the SCK clock period to @var{period} microseconds. Set the SCK clock period to @var{period} microseconds.
@emph{JTAG ICE only:} @emph{JTAG ICE only:}
Set the JTAG ICE bit clock period to @var{period} microseconds. Set the JTAG ICE bit clock period to @var{period} microseconds.
Note that unlike STK500 settings, this setting will be reverted to Note that unlike STK500 settings, this setting will be reverted to
@ -1540,7 +1550,6 @@ ISP clock period when operating the ICE in ISP mode.
@item parms @item parms
@emph{STK500 and STK600 only:} @emph{STK500 and STK600 only:}
Display the current voltage and master oscillator parameters. Display the current voltage and master oscillator parameters.
@emph{JTAG ICE only:} @emph{JTAG ICE only:}
Display the current target supply voltage and JTAG bit clock rate/period. Display the current target supply voltage and JTAG bit clock rate/period.

View File

@ -802,6 +802,8 @@ typedef struct programmer_t {
int (*read_byte_cached)(const struct programmer_t *pgm, const AVRPART *p, const AVRMEM *m, int (*read_byte_cached)(const struct programmer_t *pgm, const AVRPART *p, const AVRMEM *m,
unsigned long addr, unsigned char *value); unsigned long addr, unsigned char *value);
int (*chip_erase_cached)(const struct programmer_t *pgm, const AVRPART *p); 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,
unsigned int baseaddr);
int (*flush_cache) (const struct programmer_t *pgm, const AVRPART *p); int (*flush_cache) (const struct programmer_t *pgm, const AVRPART *p);
int (*reset_cache) (const struct programmer_t *pgm, const AVRPART *p); int (*reset_cache) (const struct programmer_t *pgm, const AVRPART *p);
AVR_Cache *cp_flash, *cp_eeprom; AVR_Cache *cp_flash, *cp_eeprom;
@ -918,6 +920,7 @@ int avr_is_and(const unsigned char *s1, const unsigned char *s2, const unsigned
int avr_read_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, unsigned long addr, unsigned char *value); 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_write_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, unsigned long addr, unsigned char data);
int avr_chip_erase_cached(const PROGRAMMER *pgm, const AVRPART *p); int avr_chip_erase_cached(const PROGRAMMER *pgm, const AVRPART *p);
int avr_page_erase_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, unsigned int baseaddr);
int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p); int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p);
int avr_reset_cache(const PROGRAMMER *pgm, const AVRPART *p); int avr_reset_cache(const PROGRAMMER *pgm, const AVRPART *p);

View File

@ -122,6 +122,7 @@ PROGRAMMER *pgm_new(void) {
pgm->read_byte_cached = avr_read_byte_cached; pgm->read_byte_cached = avr_read_byte_cached;
pgm->write_byte_cached = avr_write_byte_cached; pgm->write_byte_cached = avr_write_byte_cached;
pgm->chip_erase_cached = avr_chip_erase_cached; pgm->chip_erase_cached = avr_chip_erase_cached;
pgm->page_erase_cached = avr_page_erase_cached;
pgm->flush_cache = avr_flush_cache; pgm->flush_cache = avr_flush_cache;
pgm->reset_cache = avr_reset_cache; pgm->reset_cache = avr_reset_cache;

View File

@ -26,6 +26,7 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <stddef.h>
#include <stdarg.h> #include <stdarg.h>
#include <limits.h> #include <limits.h>
#include <unistd.h> #include <unistd.h>
@ -40,91 +41,60 @@
#include "term.h" #include "term.h"
struct command { struct command {
char * name; char *name;
int (*func)(PROGRAMMER * pgm, struct avrpart * p, int argc, char *argv[]); int (*func)(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
char * desc; size_t fnoff;
char *desc;
}; };
static int cmd_dump (PROGRAMMER * pgm, struct avrpart * p, static int cmd_dump (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
int argc, char *argv[]); static int cmd_write (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
static int cmd_flush (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
static int cmd_abort (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
static int cmd_erase (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
static int cmd_pgerase(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
static int cmd_sig (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
static int cmd_part (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
static int cmd_help (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
static int cmd_quit (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
static int cmd_send (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
static int cmd_parms (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
static int cmd_vtarg (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
static int cmd_varef (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
static int cmd_fosc (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
static int cmd_sck (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
static int cmd_spi (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
static int cmd_pgm (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
static int cmd_verbose(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
static int cmd_quell (PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]);
static int cmd_write (PROGRAMMER * pgm, struct avrpart * p, #define _fo(x) offsetof(PROGRAMMER, x)
int argc, char *argv[]);
static int cmd_flush (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_abort (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_erase (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_sig (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_part (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_help (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_quit (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_send (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_parms (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_vtarg (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_varef (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_fosc (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_sck (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_spi (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_pgm (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_verbose (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
static int cmd_quell (PROGRAMMER * pgm, struct avrpart * p,
int argc, char *argv[]);
struct command cmd[] = { struct command cmd[] = {
{ "dump", cmd_dump, "%s <memory> [<addr> <len> | <addr> ... | <addr> | ...]" }, { "dump", cmd_dump, _fo(read_byte_cached), "%s <memory> [<addr> <len> | <addr> ... | <addr> | ...]" },
{ "read", cmd_dump, "alias for dump" }, { "read", cmd_dump, _fo(read_byte_cached), "alias for dump" },
{ "write", cmd_write, "%s <memory> <addr> [<data>[,] {<data>[,]} | <len> <data>[,] {<data>[,]} ...]" }, { "write", cmd_write, _fo(write_byte_cached), "write <memory> <addr> <data>[,] {<data>[,]}" },
{ "flush", cmd_flush, "synchronise flash & EEPROM writes with the device" }, { "", cmd_write, _fo(write_byte_cached), "write <memory> <addr> <len> <data>[,] {<data>[,]} ..." },
{ "abort", cmd_abort, "abort flash & EEPROM writes (reset the r/w cache)" }, { "flush", cmd_flush, _fo(flush_cache), "synchronise flash & EEPROM writes with the device" },
{ "erase", cmd_erase, "perform a chip erase" }, { "abort", cmd_abort, _fo(reset_cache), "abort flash & EEPROM writes (reset the r/w cache)" },
{ "sig", cmd_sig, "display device signature bytes" }, { "erase", cmd_erase, _fo(chip_erase_cached), "perform a chip erase" },
{ "part", cmd_part, "display the current part information" }, { "pgerase", cmd_pgerase, _fo(page_erase), "pgerase <memory> <addr>" },
{ "send", cmd_send, "send a raw command: %s <b1> <b2> <b3> <b4>" }, { "sig", cmd_sig, _fo(open), "display device signature bytes" },
{ "parms", cmd_parms, "display adjustable parameters (STK500 and Curiosity Nano only)" }, { "part", cmd_part, _fo(open), "display the current part information" },
{ "vtarg", cmd_vtarg, "set <V[target]> (STK500 and Curiosity Nano only)" }, { "send", cmd_send, _fo(cmd), "send a raw command: %s <b1> <b2> <b3> <b4>" },
{ "varef", cmd_varef, "set <V[aref]> (STK500 only)" }, { "parms", cmd_parms, _fo(print_parms), "display adjustable parameters" },
{ "fosc", cmd_fosc, "set <oscillator frequency> (STK500 only)" }, { "vtarg", cmd_vtarg, _fo(set_vtarget), "set <V[target]>" },
{ "sck", cmd_sck, "set <SCK period> (STK500 only)" }, { "varef", cmd_varef, _fo(set_varef), "set <V[aref]>" },
{ "spi", cmd_spi, "enter direct SPI mode" }, { "fosc", cmd_fosc, _fo(set_fosc), "set <oscillator frequency>" },
{ "pgm", cmd_pgm, "return to programming mode" }, { "sck", cmd_sck, _fo(set_sck_period), "set <SCK period>" },
{ "verbose", cmd_verbose, "change verbosity" }, { "spi", cmd_spi, _fo(setpin), "enter direct SPI mode" },
{ "quell", cmd_quell, "set quell level for progress bars" }, { "pgm", cmd_pgm, _fo(setpin), "return to programming mode" },
{ "help", cmd_help, "help" }, { "verbose", cmd_verbose, _fo(open), "change verbosity" },
{ "?", cmd_help, "help" }, { "quell", cmd_quell, _fo(open), "set quell level for progress bars" },
{ "quit", cmd_quit, "quit after writing out cache for flash & EEPROM" } { "help", cmd_help, _fo(open), "show help message" },
{ "?", cmd_help, _fo(open), "same as help" },
{ "quit", cmd_quit, _fo(open), "quit after writing out cache for flash & EEPROM" }
}; };
#define NCMDS ((int)(sizeof(cmd)/sizeof(struct command))) #define NCMDS ((int)(sizeof(cmd)/sizeof(struct command)))
@ -133,8 +103,7 @@ struct command cmd[] = {
static int spi_mode = 0; static int spi_mode = 0;
static int nexttok(char * buf, char ** tok, char ** next) static int nexttok(char *buf, char **tok, char **next) {
{
unsigned char *q, *n; unsigned char *q, *n;
q = (unsigned char *) buf; q = (unsigned char *) buf;
@ -171,10 +140,9 @@ static int nexttok(char * buf, char ** tok, char ** next)
} }
static int hexdump_line(char * buffer, unsigned char * p, int n, int pad) static int hexdump_line(char *buffer, unsigned char *p, int n, int pad) {
{ char *hexdata = "0123456789abcdef";
char * hexdata = "0123456789abcdef"; char *b = buffer;
char * b = buffer;
int i = 0; int i = 0;
int j = 0; int j = 0;
@ -201,8 +169,7 @@ static int hexdump_line(char * buffer, unsigned char * p, int n, int pad)
} }
static int chardump_line(char * buffer, unsigned char * p, int n, int pad) static int chardump_line(char *buffer, unsigned char *p, int n, int pad) {
{
int i; int i;
unsigned char b[128]; unsigned char b[128];
@ -223,13 +190,12 @@ static int chardump_line(char * buffer, unsigned char * p, int n, int pad)
} }
static int hexdump_buf(FILE * f, int startaddr, unsigned char * buf, int len) static int hexdump_buf(FILE *f, int startaddr, unsigned char *buf, int len) {
{
char dst1[80]; char dst1[80];
char dst2[80]; char dst2[80];
int addr = startaddr; int addr = startaddr;
unsigned char * p = (unsigned char *)buf; unsigned char *p = (unsigned char *)buf;
while (len) { while (len) {
int n = 16; int n = 16;
if (n > len) if (n > len)
@ -246,9 +212,7 @@ static int hexdump_buf(FILE * f, int startaddr, unsigned char * buf, int len)
} }
static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, static int cmd_dump(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
int argc, char * argv[])
{
if (argc < 2 || argc > 4) { if (argc < 2 || argc > 4) {
terminal_message(MSG_INFO, terminal_message(MSG_INFO,
"Usage: %s <memory> <addr> <len>\n" "Usage: %s <memory> <addr> <len>\n"
@ -262,8 +226,8 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p,
enum { read_size = 256 }; enum { read_size = 256 };
static const char *prevmem = ""; static const char *prevmem = "";
char * memtype = argv[1]; char *memtype = argv[1];
AVRMEM * mem = avr_locate_mem(p, memtype); AVRMEM *mem = avr_locate_mem(p, memtype);
if (mem == NULL) { if (mem == NULL) {
terminal_message(MSG_INFO, "%s (dump): %s memory type not defined for part %s\n", terminal_message(MSG_INFO, "%s (dump): %s memory type not defined for part %s\n",
progname, memtype, p->desc); progname, memtype, p->desc);
@ -272,7 +236,7 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p,
int maxsize = mem->size; int maxsize = mem->size;
// Get start address if present // Get start address if present
char * end_ptr; char *end_ptr;
static int addr = 0; static int addr = 0;
if (argc >= 3 && strcmp(argv[2], "...") != 0) { if (argc >= 3 && strcmp(argv[2], "...") != 0) {
@ -281,9 +245,9 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p,
terminal_message(MSG_INFO, "%s (dump): can't parse address %s\n", terminal_message(MSG_INFO, "%s (dump): can't parse address %s\n",
progname, argv[2]); progname, argv[2]);
return -1; return -1;
} else if (addr >= maxsize) { } else if (addr < 0 || addr >= maxsize) {
terminal_message(MSG_INFO, "%s (dump): address 0x%05lx is out of range for %s memory\n", terminal_message(MSG_INFO, "%s (dump): %s address 0x%05x is out of range [0, 0x%05x]\n",
progname, (long) addr, mem->desc); progname, mem->desc, addr, maxsize-1);
return -1; return -1;
} }
} }
@ -322,7 +286,7 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p,
if ((addr + len) > maxsize) if ((addr + len) > maxsize)
len = maxsize - addr; len = maxsize - addr;
uint8_t * buf = malloc(len); uint8_t *buf = malloc(len);
if (buf == NULL) { if (buf == NULL) {
terminal_message(MSG_INFO, "%s (dump): out of memory\n", progname); terminal_message(MSG_INFO, "%s (dump): out of memory\n", progname);
return -1; return -1;
@ -399,12 +363,10 @@ static int is_mantissa_only(char *p) {
} }
static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, static int cmd_write(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
int argc, char * argv[])
{
if (argc < 4) { if (argc < 4) {
terminal_message(MSG_INFO, terminal_message(MSG_INFO,
"Usage: write <memory> <addr> <data>[,] {<data>[,]} \n" "Usage: write <memory> <addr> <data>[,] {<data>[,]}\n"
" write <memory> <addr> <len> <data>[,] {<data>[,]} ...\n" " write <memory> <addr> <len> <data>[,] {<data>[,]} ...\n"
"\n" "\n"
"Ellipsis ... writes <len> bytes padded by repeating the last <data> item.\n" "Ellipsis ... writes <len> bytes padded by repeating the last <data> item.\n"
@ -440,8 +402,8 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
uint8_t write_mode; // Operation mode, "standard" or "fill" uint8_t write_mode; // Operation mode, "standard" or "fill"
uint8_t start_offset; // Which argc argument uint8_t start_offset; // Which argc argument
int len; // Number of bytes to write to memory int len; // Number of bytes to write to memory
char * memtype = argv[1]; // Memory name string char *memtype = argv[1]; // Memory name string
AVRMEM * mem = avr_locate_mem(p, memtype); AVRMEM *mem = avr_locate_mem(p, memtype);
if (mem == NULL) { if (mem == NULL) {
terminal_message(MSG_INFO, "%s (write): %s memory type not defined for part %s\n", terminal_message(MSG_INFO, "%s (write): %s memory type not defined for part %s\n",
progname, memtype, p->desc); progname, memtype, p->desc);
@ -449,7 +411,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
} }
int maxsize = mem->size; int maxsize = mem->size;
char * end_ptr; char *end_ptr;
int addr = strtoul(argv[2], &end_ptr, 0); int addr = strtoul(argv[2], &end_ptr, 0);
if (*end_ptr || (end_ptr == argv[2])) { if (*end_ptr || (end_ptr == argv[2])) {
terminal_message(MSG_INFO, "%s (write): can't parse address %s\n", terminal_message(MSG_INFO, "%s (write): can't parse address %s\n",
@ -457,14 +419,14 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
return -1; return -1;
} }
if (addr > maxsize) { if (addr < 0 || addr >= maxsize) {
terminal_message(MSG_INFO, "%s (write): address 0x%05lx is out of range for %s memory\n", terminal_message(MSG_INFO, "%s (write): %s address 0x%05x is out of range [0, 0x%05x]\n",
progname, (long) addr, memtype); progname, mem->desc, addr, maxsize);
return -1; return -1;
} }
// Allocate a buffer guaranteed to be large enough // Allocate a buffer guaranteed to be large enough
uint8_t * buf = calloc(mem->size + 8 + maxstrlen(argc-3, argv+3)+1, sizeof(uint8_t)); uint8_t *buf = calloc(mem->size + 8 + maxstrlen(argc-3, argv+3)+1, sizeof(uint8_t));
if (buf == NULL) { if (buf == NULL) {
terminal_message(MSG_INFO, "%s (write): out of memory\n", progname); terminal_message(MSG_INFO, "%s (write): out of memory\n", progname);
return -1; return -1;
@ -732,32 +694,24 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
} }
static int cmd_flush(PROGRAMMER *pgm, struct avrpart *p, int ac, char *av[]) { static int cmd_flush(PROGRAMMER *pgm, AVRPART *p, int ac, char *av[]) {
pgm->flush_cache(pgm, p); pgm->flush_cache(pgm, p);
return 0; return 0;
} }
static int cmd_abort(PROGRAMMER *pgm, struct avrpart *p, int ac, char *av[]) { static int cmd_abort(PROGRAMMER *pgm, AVRPART *p, int ac, char *av[]) {
pgm->reset_cache(pgm, p); pgm->reset_cache(pgm, p);
return 0; return 0;
} }
static int cmd_send(PROGRAMMER * pgm, struct avrpart * p, static int cmd_send(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
int argc, char * argv[])
{
unsigned char cmd[4], res[4]; unsigned char cmd[4], res[4];
char * e; char *e;
int i; int i;
int len; int len;
if (pgm->cmd == NULL) {
terminal_message(MSG_INFO, "%s (send): the %s programmer does not support direct ISP commands\n",
progname, pgm->type);
return -1;
}
if (spi_mode && (pgm->spi == NULL)) { if (spi_mode && (pgm->spi == NULL)) {
terminal_message(MSG_INFO, "%s (send): the %s programmer does not support direct SPI transfers\n", terminal_message(MSG_INFO, "%s (send): the %s programmer does not support direct SPI transfers\n",
progname, pgm->type); progname, pgm->type);
@ -806,9 +760,7 @@ static int cmd_send(PROGRAMMER * pgm, struct avrpart * p,
} }
static int cmd_erase(PROGRAMMER * pgm, struct avrpart * p, static int cmd_erase(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
int argc, char * argv[])
{
terminal_message(MSG_INFO, "%s: erasing chip\n", progname); terminal_message(MSG_INFO, "%s: erasing chip\n", progname);
// Erase chip and clear cache // Erase chip and clear cache
pgm->chip_erase_cached(pgm, p); pgm->chip_erase_cached(pgm, p);
@ -817,9 +769,53 @@ static int cmd_erase(PROGRAMMER * pgm, struct avrpart * p,
} }
static int cmd_part(PROGRAMMER * pgm, struct avrpart * p, static int cmd_pgerase(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
int argc, char * argv[]) if(argc < 3) {
{ terminal_message(MSG_INFO, "Usage: pgerase <memory> <addr>\n");
return -1;
}
char *memtype = argv[1];
AVRMEM *mem = avr_locate_mem(p, memtype);
if(!mem) {
terminal_message(MSG_INFO, "%s (pgerase): %s memory type not defined for part %s\n",
progname, memtype, p->desc);
return -1;
}
if(!avr_has_paged_access(pgm, mem)) {
terminal_message(MSG_INFO, "%s (pgerase): %s memory cannot be paged addressed by %s\n",
progname, memtype, ldata(lfirst(pgm->id)));
return -1;
}
int maxsize = mem->size;
char *end_ptr;
int addr = strtoul(argv[2], &end_ptr, 0);
if(*end_ptr || (end_ptr == argv[2])) {
terminal_message(MSG_INFO, "%s (pgerase): can't parse address %s\n",
progname, argv[2]);
return -1;
}
if (addr < 0 || addr >= maxsize) {
terminal_message(MSG_INFO, "%s (pgerase): %s address 0x%05x is out of range [0, 0x%05x]\n",
progname, mem->desc, addr, maxsize-1);
return -1;
}
// terminal_message(MSG_INFO, "%s: %s page erase 0x%05x\n", progname, mem->desc, addr & ~(mem->page_size-1));
if(pgm->page_erase_cached(pgm, p, mem, (unsigned int) addr) < 0) {
terminal_message(MSG_INFO, "%s (pgerase): %s page at 0x%05x could not be erased\n",
progname, mem->desc, addr);
return -1;
}
return 0;
}
static int cmd_part(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
fprintf(stdout, "\n"); fprintf(stdout, "\n");
avr_display(stdout, p, "", 0); avr_display(stdout, p, "", 0);
fprintf(stdout, "\n"); fprintf(stdout, "\n");
@ -828,12 +824,10 @@ static int cmd_part(PROGRAMMER * pgm, struct avrpart * p,
} }
static int cmd_sig(PROGRAMMER * pgm, struct avrpart * p, static int cmd_sig(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
int argc, char * argv[])
{
int i; int i;
int rc; int rc;
AVRMEM * m; AVRMEM *m;
rc = avr_signature(pgm, p); rc = avr_signature(pgm, p);
if (rc != 0) { if (rc != 0) {
@ -857,9 +851,7 @@ static int cmd_sig(PROGRAMMER * pgm, struct avrpart * p,
} }
static int cmd_quit(PROGRAMMER * pgm, struct avrpart * p, static int cmd_quit(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
int argc, char * argv[])
{
/* FUSE bit verify will fail if left in SPI mode */ /* FUSE bit verify will fail if left in SPI mode */
if (spi_mode) { if (spi_mode) {
cmd_pgm(pgm, p, 0, NULL); cmd_pgm(pgm, p, 0, NULL);
@ -868,23 +860,14 @@ static int cmd_quit(PROGRAMMER * pgm, struct avrpart * p,
} }
static int cmd_parms(PROGRAMMER * pgm, struct avrpart * p, static int cmd_parms(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
int argc, char * argv[])
{
if (pgm->print_parms == NULL) {
terminal_message(MSG_INFO, "%s (parms): the %s programmer does not support "
"adjustable parameters\n", progname, pgm->type);
return -1;
}
pgm->print_parms(pgm); pgm->print_parms(pgm);
terminal_message(MSG_INFO, "\n"); terminal_message(MSG_INFO, "\n");
return 0; return 0;
} }
static int cmd_vtarg(PROGRAMMER * pgm, struct avrpart * p, static int cmd_vtarg(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
int argc, char * argv[])
{
int rc; int rc;
double v; double v;
char *endp; char *endp;
@ -899,11 +882,6 @@ static int cmd_vtarg(PROGRAMMER * pgm, struct avrpart * p,
progname, argv[1]); progname, argv[1]);
return -1; return -1;
} }
if (pgm->set_vtarget == NULL) {
terminal_message(MSG_INFO, "%s (vtarg): the %s programmer cannot set V[target]\n",
progname, pgm->type);
return -2;
}
if ((rc = pgm->set_vtarget(pgm, v)) != 0) { if ((rc = pgm->set_vtarget(pgm, v)) != 0) {
terminal_message(MSG_INFO, "%s (vtarg): failed to set V[target] (rc = %d)\n", terminal_message(MSG_INFO, "%s (vtarg): failed to set V[target] (rc = %d)\n",
progname, rc); progname, rc);
@ -913,9 +891,7 @@ static int cmd_vtarg(PROGRAMMER * pgm, struct avrpart * p,
} }
static int cmd_fosc(PROGRAMMER * pgm, struct avrpart * p, static int cmd_fosc(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
int argc, char * argv[])
{
int rc; int rc;
double v; double v;
char *endp; char *endp;
@ -938,11 +914,6 @@ static int cmd_fosc(PROGRAMMER * pgm, struct avrpart * p,
v *= 1e6; v *= 1e6;
else if (*endp == 'k' || *endp == 'K') else if (*endp == 'k' || *endp == 'K')
v *= 1e3; v *= 1e3;
if (pgm->set_fosc == NULL) {
terminal_message(MSG_INFO, "%s (fosc): the %s programmer cannot set oscillator frequency\n",
progname, pgm->type);
return -2;
}
if ((rc = pgm->set_fosc(pgm, v)) != 0) { if ((rc = pgm->set_fosc(pgm, v)) != 0) {
terminal_message(MSG_INFO, "%s (fosc): failed to set oscillator frequency (rc = %d)\n", terminal_message(MSG_INFO, "%s (fosc): failed to set oscillator frequency (rc = %d)\n",
progname, rc); progname, rc);
@ -952,9 +923,7 @@ static int cmd_fosc(PROGRAMMER * pgm, struct avrpart * p,
} }
static int cmd_sck(PROGRAMMER * pgm, struct avrpart * p, static int cmd_sck(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
int argc, char * argv[])
{
int rc; int rc;
double v; double v;
char *endp; char *endp;
@ -970,11 +939,6 @@ static int cmd_sck(PROGRAMMER * pgm, struct avrpart * p,
return -1; return -1;
} }
v *= 1e-6; /* Convert from microseconds to seconds. */ v *= 1e-6; /* Convert from microseconds to seconds. */
if (pgm->set_sck_period == NULL) {
terminal_message(MSG_INFO, "%s (sck): the %s programmer cannot set SCK period\n",
progname, pgm->type);
return -2;
}
if ((rc = pgm->set_sck_period(pgm, v)) != 0) { if ((rc = pgm->set_sck_period(pgm, v)) != 0) {
terminal_message(MSG_INFO, "%s (sck): failed to set SCK period (rc = %d)\n", terminal_message(MSG_INFO, "%s (sck): failed to set SCK period (rc = %d)\n",
progname, rc); progname, rc);
@ -984,9 +948,7 @@ static int cmd_sck(PROGRAMMER * pgm, struct avrpart * p,
} }
static int cmd_varef(PROGRAMMER * pgm, struct avrpart * p, static int cmd_varef(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
int argc, char * argv[])
{
int rc; int rc;
unsigned int chan; unsigned int chan;
double v; double v;
@ -1018,11 +980,6 @@ static int cmd_varef(PROGRAMMER * pgm, struct avrpart * p,
return -1; return -1;
} }
} }
if (pgm->set_varef == NULL) {
terminal_message(MSG_INFO, "%s (varef): the %s programmer cannot set V[aref]\n",
progname, pgm->type);
return -2;
}
if ((rc = pgm->set_varef(pgm, chan, v)) != 0) { if ((rc = pgm->set_varef(pgm, chan, v)) != 0) {
terminal_message(MSG_INFO, "%s (varef): failed to set V[aref] (rc = %d)\n", terminal_message(MSG_INFO, "%s (varef): failed to set V[aref] (rc = %d)\n",
progname, rc); progname, rc);
@ -1032,56 +989,39 @@ static int cmd_varef(PROGRAMMER * pgm, struct avrpart * p,
} }
static int cmd_help(PROGRAMMER * pgm, struct avrpart * p, static int cmd_help(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
int argc, char * argv[])
{
int i; int i;
fprintf(stdout, "Valid commands:\n"); fprintf(stdout, "Valid commands:\n");
for (i=0; i<NCMDS; i++) { for (i=0; i<NCMDS; i++) {
if(!*(void (**)(void)) ((char *) pgm + cmd[i].fnoff))
continue;
fprintf(stdout, " %-7s : ", cmd[i].name); fprintf(stdout, " %-7s : ", cmd[i].name);
fprintf(stdout, cmd[i].desc, cmd[i].name); fprintf(stdout, cmd[i].desc, cmd[i].name);
fprintf(stdout, "\n"); fprintf(stdout, "\n");
} }
fprintf(stdout, "\n" fprintf(stdout, "\n"
"Note that flash and EEPROM type memories are normally read and written\n" "Note that not all programmer derivatives support all commands. Flash and\n"
"using a cache and paged r/w access; the cache is synchronised on quit.\n" "EEPROM type memories are normally read and written using a cache via paged\n"
"Use the 'part' command to display valid memory types for use with the\n" "read and write access; the cache is synchronised on quit. Use the part\n"
"'dump' and 'write' commands.\n\n"); "command to display valid memory types for use with dump and write.\n\n");
return 0; return 0;
} }
static int cmd_spi(PROGRAMMER * pgm, struct avrpart * p, static int cmd_spi(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
int argc, char * argv[]) pgm->setpin(pgm, PIN_AVR_RESET, 1);
{ spi_mode = 1;
if (pgm->setpin != NULL) { return 0;
pgm->setpin(pgm, PIN_AVR_RESET, 1);
spi_mode = 1;
return 0;
}
terminal_message(MSG_INFO, "%s: spi command unavailable for this programmer type\n",
progname);
return -1;
} }
static int cmd_pgm(PROGRAMMER * pgm, struct avrpart * p, static int cmd_pgm(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
int argc, char * argv[]) pgm->setpin(pgm, PIN_AVR_RESET, 0);
{ spi_mode = 0;
if (pgm->setpin != NULL) { pgm->initialize(pgm, p);
pgm->setpin(pgm, PIN_AVR_RESET, 0); return 0;
spi_mode = 0;
pgm->initialize(pgm, p);
return 0;
}
terminal_message(MSG_INFO, "%s: pgm command unavailable for this programmer type\n",
progname);
return -1;
} }
static int cmd_verbose(PROGRAMMER * pgm, struct avrpart * p, static int cmd_verbose(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
int argc, char * argv[])
{
int nverb; int nverb;
char *endp; char *endp;
@ -1110,9 +1050,7 @@ static int cmd_verbose(PROGRAMMER * pgm, struct avrpart * p,
return 0; return 0;
} }
static int cmd_quell(PROGRAMMER * pgm, struct avrpart * p, static int cmd_quell(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
int argc, char * argv[])
{
int nquell; int nquell;
char *endp; char *endp;
@ -1146,17 +1084,16 @@ static int cmd_quell(PROGRAMMER * pgm, struct avrpart * p,
return 0; return 0;
} }
static int tokenize(char * s, char *** argv) static int tokenize(char * s, char ***argv) {
{
int i, n, l, nargs; int i, n, l, nargs;
int len, slen; int len, slen;
char * buf; char *buf;
int bufsize; int bufsize;
char ** bufv; char **bufv;
char * bufp; char *bufp;
char * q, * r; char *q, *r;
char * nbuf; char *nbuf;
char ** av; char **av;
slen = strlen(s); slen = strlen(s);
@ -1244,9 +1181,7 @@ static int tokenize(char * s, char *** argv)
} }
static int do_cmd(PROGRAMMER * pgm, struct avrpart * p, static int do_cmd(PROGRAMMER *pgm, AVRPART *p, int argc, char *argv[]) {
int argc, char * argv[])
{
int i; int i;
int hold; int hold;
int len; int len;
@ -1254,10 +1189,11 @@ static int do_cmd(PROGRAMMER * pgm, struct avrpart * p,
len = strlen(argv[0]); len = strlen(argv[0]);
hold = -1; hold = -1;
for (i=0; i<NCMDS; i++) { for (i=0; i<NCMDS; i++) {
if (strcasecmp(argv[0], cmd[i].name) == 0) { if(!*(void (**)(void)) ((char *) pgm + cmd[i].fnoff))
continue;
if (len && strcasecmp(argv[0], cmd[i].name) == 0)
return cmd[i].func(pgm, p, argc, argv); return cmd[i].func(pgm, p, argc, argv);
} if (len && strncasecmp(argv[0], cmd[i].name, len)==0) {
else if (strncasecmp(argv[0], cmd[i].name, len)==0) {
if (hold != -1) { if (hold != -1) {
terminal_message(MSG_INFO, "%s (cmd): command %s is ambiguous\n", terminal_message(MSG_INFO, "%s (cmd): command %s is ambiguous\n",
progname, argv[0]); progname, argv[0]);
@ -1277,8 +1213,7 @@ static int do_cmd(PROGRAMMER * pgm, struct avrpart * p,
} }
char * terminal_get_input(const char *prompt) char *terminal_get_input(const char *prompt) {
{
#if defined(HAVE_LIBREADLINE) && !defined(WIN32) #if defined(HAVE_LIBREADLINE) && !defined(WIN32)
char *input; char *input;
input = readline(prompt); input = readline(prompt);
@ -1300,13 +1235,12 @@ char * terminal_get_input(const char *prompt)
} }
int terminal_mode(PROGRAMMER * pgm, struct avrpart * p) int terminal_mode(PROGRAMMER *pgm, AVRPART *p) {
{ char *cmdbuf;
char * cmdbuf; char *q;
char * q; int rc;
int rc; int argc;
int argc; char **argv;
char ** argv;
rc = 0; rc = 0;
while ((cmdbuf = terminal_get_input("avrdude> ")) != NULL) { while ((cmdbuf = terminal_get_input("avrdude> ")) != NULL) {