Provide avr_set_addr_mem() to set addresses in SPI opcodes within boundaries
The function avr_set_addr_mem(AVRMEM *mem, int opnum, unsigned char *cmd, unsigned long addr) is meant to replace avr_set_addr(OPCODE *op, unsigned char *cmd, unsigned long addr) in future. avr_set_addr_mem() has more information about the context of the task in that it knows the memory size, memory page size, whether or not the memory is a flash memory (which gets words addressees supplied) and, crucially, knows which SPI operation it is meant to compute the address bits for. avr_set_addr_mem() first computes the interval of bit numbers that must be supplied for the SPI command to stand a chance to work. The function only sets those address bits that are needed. Once all avr_set_addr() function calls have been replaced by avr_set_addr_mem(), the SPI commands that need an address can afford to declare in avrdude.conf all 16 address bits in the middle two bytes of the SPI command. This over-declaration will be corrected during runtime by avr_set_addr_mem(). One consequence of this is that parts can inherit smaller or larger memories from parents without the need to use different SPI codes in avrdude.conf. Another consequence is that avr_set_addr_mem() can, and does, tell the caller whether vital address bits were not declared in the SPI opcode. During parsing of avrdude.conf this might be utilised to generate a corresponding warning. This will uncover problematic SPI codes in avrdude.conf that in the past went undetected.
This commit is contained in:
parent
55f6765ea5
commit
572849ec2a
|
@ -295,6 +295,100 @@ static void checkaddr(int memsize, int pagesize, int opnum, OPCODE *op, AVRPART
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* avr_set_addr_mem()
|
||||||
|
*
|
||||||
|
* Set address bits in the specified command based on the memory, opcode and
|
||||||
|
* address; addr must be a word address for flash or, for all other memories,
|
||||||
|
* a byte address; returns 0 on success and -1 on error (no memory or no
|
||||||
|
* opcode) or, if positive, bn+1 where bn is bit number of the highest
|
||||||
|
* necessary bit that the opcode does not provide.
|
||||||
|
*/
|
||||||
|
int avr_set_addr_mem(AVRMEM *mem, int opnum, unsigned char *cmd, unsigned long addr) {
|
||||||
|
int ret, isflash, lo, hi, memsize, pagesize;
|
||||||
|
OPCODE *op;
|
||||||
|
|
||||||
|
if(!mem)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if(!(op = mem->op[opnum]))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
isflash = !strcmp(mem->desc, "flash"); // ISP parts have only one flash-like memory
|
||||||
|
memsize = mem->size >> isflash; // word addresses for flash
|
||||||
|
pagesize = mem->page_size >> isflash;
|
||||||
|
|
||||||
|
// compute range lo..hi of needed address bits
|
||||||
|
switch(opnum) {
|
||||||
|
case AVR_OP_READ:
|
||||||
|
case AVR_OP_WRITE:
|
||||||
|
case AVR_OP_READ_LO:
|
||||||
|
case AVR_OP_READ_HI:
|
||||||
|
case AVR_OP_WRITE_LO:
|
||||||
|
case AVR_OP_WRITE_HI:
|
||||||
|
lo = 0;
|
||||||
|
hi = intlog2(memsize-1); // memsize = 1 implies no addr bit is needed
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AVR_OP_LOADPAGE_LO:
|
||||||
|
case AVR_OP_LOADPAGE_HI:
|
||||||
|
lo = 0;
|
||||||
|
hi = intlog2(pagesize-1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AVR_OP_LOAD_EXT_ADDR:
|
||||||
|
lo = 16;
|
||||||
|
hi = intlog2(memsize-1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AVR_OP_WRITEPAGE:
|
||||||
|
lo = intlog2(pagesize);
|
||||||
|
hi = intlog2(memsize-1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AVR_OP_CHIP_ERASE:
|
||||||
|
case AVR_OP_PGM_ENABLE:
|
||||||
|
default:
|
||||||
|
lo = 0;
|
||||||
|
hi = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unless it's load extended address, ISP chips only deal with 16 bit addresses
|
||||||
|
if(opnum != AVR_OP_LOAD_EXT_ADDR && hi > 15)
|
||||||
|
hi = 15;
|
||||||
|
|
||||||
|
unsigned char avail[32];
|
||||||
|
memset(avail, 0, sizeof avail);
|
||||||
|
|
||||||
|
for(int i=0; i<32; i++) {
|
||||||
|
if(op->bit[i].type == AVR_CMDBIT_ADDRESS) {
|
||||||
|
int bitno, j, bit;
|
||||||
|
unsigned char mask;
|
||||||
|
|
||||||
|
bitno = op->bit[i].bitno & 31;
|
||||||
|
j = 3 - i / 8;
|
||||||
|
bit = i % 8;
|
||||||
|
mask = 1 << bit;
|
||||||
|
avail[bitno] = 1;
|
||||||
|
|
||||||
|
// 'a' bit with number outside bit range [lo, hi] is set to 0
|
||||||
|
if (bitno >= lo && bitno <= hi? (addr >> bitno) & 1: 0)
|
||||||
|
cmd[j] = cmd[j] | mask;
|
||||||
|
else
|
||||||
|
cmd[j] = cmd[j] & ~mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
if(lo >= 0 && hi < 32 && lo <= hi)
|
||||||
|
for(int bn=lo; bn <= hi; bn++)
|
||||||
|
if(!avail[bn]) // necessary bit bn misses in opcode
|
||||||
|
ret = bn+1;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static char *dev_sprintf(const char *fmt, ...) {
|
static char *dev_sprintf(const char *fmt, ...) {
|
||||||
int size = 0;
|
int size = 0;
|
||||||
char *p = NULL;
|
char *p = NULL;
|
||||||
|
|
|
@ -25,6 +25,7 @@ const char *opcodename(int opnum);
|
||||||
char *opcode2str(OPCODE *op, int opnum, int detailed);
|
char *opcode2str(OPCODE *op, int opnum, int detailed);
|
||||||
int opcodecmp(OPCODE *op1, OPCODE *op2, int opnum);
|
int opcodecmp(OPCODE *op1, OPCODE *op2, int opnum);
|
||||||
int intlog2(unsigned int n);
|
int intlog2(unsigned int n);
|
||||||
|
int avr_set_addr_mem(AVRMEM *mem, int opnum, unsigned char *cmd, unsigned long addr);
|
||||||
int part_match(const char *pattern, const char *string);
|
int part_match(const char *pattern, const char *string);
|
||||||
void dev_output_part_defs(char *partdesc);
|
void dev_output_part_defs(char *partdesc);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue