Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use byte-wise read/write when page size is 1 in terminal cache #1121

Merged
merged 3 commits into from
Oct 17, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 58 additions & 22 deletions src/avrcache.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
#include "avrintel.h"

/*
* Provides an API for cached byte-wise access
* Provides an API for cached bytewise access
*
* int avr_read_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const
* AVRMEM *mem, unsigned long addr, unsigned char *value);
Expand All @@ -52,8 +52,8 @@
* 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
* respectively. Bytewise cached read always gets its data from the cache,
* possibly after reading a page from the device memory. Bytewise 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
Expand Down Expand Up @@ -114,7 +114,10 @@
* - Memory has positive page size, which is a power of two
* - Memory has positive size, which is a multiple of the page size
* - Memory is flash type or eeprom type
*
* Note that in this definition the page size can be 1
*/

int avr_has_paged_access(const PROGRAMMER *pgm, const AVRMEM *mem) {
return pgm->paged_load && pgm->paged_write &&
mem->page_size > 0 && (mem->page_size & (mem->page_size-1)) == 0 &&
Expand All @@ -127,18 +130,35 @@ int avr_has_paged_access(const PROGRAMMER *pgm, const AVRMEM *mem) {
* Read the page containing addr from the device into buf
* - Caller to ensure buf has mem->page_size bytes
* - Part memory buffer mem is unaffected by this (though temporarily changed)
* - Uses read_byte() if memory page size is one, otherwise paged_load()
* - Fall back to bytewise read if paged_load() returned an error
*/
int avr_read_page_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, int addr, unsigned char *buf) {
if(!avr_has_paged_access(pgm, mem) || addr < 0 || addr >= mem->size)
return LIBAVRDUDE_GENERAL_FAILURE;

int rc, pgsize = mem->page_size, off = addr & ~(pgsize-1);
int rc, pgsize = mem->page_size, base = addr & ~(pgsize-1);
unsigned char *pagecopy = cfg_malloc("avr_read_page_default()", pgsize);

memcpy(pagecopy, mem->buf + off, pgsize);
if((rc = pgm->paged_load(pgm, p, mem, pgsize, off, pgsize)) >= 0)
memcpy(buf, mem->buf + off, pgsize);
memcpy(mem->buf + off, pagecopy, pgsize);
if(pgsize == 1)
return pgm->read_byte(pgm, p, mem, addr, buf);

memcpy(pagecopy, mem->buf + base, pgsize);
if((rc = pgm->paged_load(pgm, p, mem, pgsize, base, pgsize)) >= 0)
memcpy(buf, mem->buf + base, pgsize);
memcpy(mem->buf + base, pagecopy, pgsize);

if(rc < 0) {
rc = LIBAVRDUDE_SUCCESS;
for(int i=0; i<pgsize; i++) {
if(pgm->read_byte(pgm, p, mem, base+i, pagecopy+i) < 0) {
rc = LIBAVRDUDE_GENERAL_FAILURE;
break;
}
}
if(rc == LIBAVRDUDE_SUCCESS)
memcpy(buf, pagecopy, pgsize);
}
free(pagecopy);

return rc;
Expand All @@ -149,18 +169,22 @@ int avr_read_page_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM
* Write the data page to the device into the page containing addr
* - Caller to provide all mem->page_size bytes incl padding if any
* - Part memory buffer mem is unaffected by this (though temporarily changed)
* - Uses write_byte() if memory page size is one, otherwise paged_write()
*/
int avr_write_page_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, int addr, unsigned char *data) {
if(!avr_has_paged_access(pgm, mem) || addr < 0 || addr >= mem->size)
return LIBAVRDUDE_GENERAL_FAILURE;

int rc, pgsize = mem->page_size, off = addr & ~(pgsize-1);
int rc, pgsize = mem->page_size, base = addr & ~(pgsize-1);
unsigned char *pagecopy = cfg_malloc("avr_write_page_default()", pgsize);

memcpy(pagecopy, mem->buf + off, pgsize);
memcpy(mem->buf + off, data, pgsize);
rc = pgm->paged_write(pgm, p, mem, pgsize, off, pgsize);
memcpy(mem->buf + off, pagecopy, pgsize);
if(pgsize == 1)
return pgm->write_byte(pgm, p, mem, addr, *data);

memcpy(pagecopy, mem->buf + base, pgsize);
memcpy(mem->buf + base, data, pgsize);
rc = pgm->paged_write(pgm, p, mem, pgsize, base, pgsize);
memcpy(mem->buf + base, pagecopy, pgsize);
free(pagecopy);

return rc;
Expand Down Expand Up @@ -237,13 +261,20 @@ 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 nlOnErr) {
// Write modified page cont to device
// Write modified page cont to device; if unsuccessful try bytewise access
if(avr_write_page_default(pgm, p, mem, base, cp->cont + base) < 0) {
report_progress(1, -1, NULL);
if(nlOnErr && quell_progress)
avrdude_message(MSG_INFO, "\n");
avrdude_message(MSG_INFO, "%s: writeCachePage() %s write error at addr 0x%04x\n", progname, mem->desc, base);
return LIBAVRDUDE_GENERAL_FAILURE;
for(int i=0; i < cp->page_size; i++)
if(cp->cont[base+i] != cp->copy[base+i])
if(pgm->write_byte(pgm, p, mem, base+i, cp->cont[base+i]) < 0 ||
pgm->read_byte(pgm, p, mem, base+i, cp->copy+base+i) < 0) {
report_progress(1, -1, NULL);
if(nlOnErr && quell_progress)
avrdude_message(MSG_INFO, "\n");
avrdude_message(MSG_INFO, "%s: writeCachePage() %s access error at addr 0x%04x\n", progname, mem->desc, base+i);
return LIBAVRDUDE_GENERAL_FAILURE;
}

return LIBAVRDUDE_SUCCESS; // Bytewise writes & reads successful
}
// 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) {
Expand Down Expand Up @@ -652,11 +683,16 @@ int avr_page_erase_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM

int addr = uaddr;

if(!pgm->page_erase || !avr_has_paged_access(pgm, mem) || addr < 0 || addr >= mem->size)
if(!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;
if(mem->page_size == 1) {
if(pgm->write_byte(pgm, p, mem, uaddr, 0xff) < 0)
return LIBAVRDUDE_GENERAL_FAILURE;
} else {
if(!pgm->page_erase || 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;

Expand Down