Merge pull request #1121 from stefanrueger/avr_cache

Use byte-wise read/write when page size is 1 in terminal cache
This commit is contained in:
Stefan Rueger 2022-10-17 14:16:43 +01:00 committed by GitHub
commit 8e879cfae6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 58 additions and 22 deletions

View File

@ -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);
@ -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
@ -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 &&
@ -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;
@ -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;
@ -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) {
@ -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;