Move useful CMDBIT/part functions from developer_opts.c to avrpart.c

This commit is contained in:
Stefan Rueger 2022-07-27 00:12:57 +01:00
parent 62dcc2e6e8
commit 004b46b594
2 changed files with 339 additions and 337 deletions

View File

@ -71,6 +71,21 @@ void avr_free_opcode(OPCODE * op)
free(op);
}
// returns position 0..31 of highest bit set or INT_MIN if no bit is set
int intlog2(unsigned int n) {
int ret;
if(!n)
return INT_MIN;
for(ret = 0; n >>= 1; ret++)
continue;
return ret;
}
/*
* avr_set_bits()
*
@ -126,6 +141,101 @@ int avr_set_addr(OPCODE * op, unsigned char * cmd, unsigned long addr)
}
/*
* 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;
}
/*
* avr_set_input()
*
@ -239,7 +349,6 @@ static char * bittype(int type)
}
/***
*** Elementary functions dealing with AVRMEM structures
***/
@ -556,12 +665,10 @@ void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, AVRPART * p,
}
/*
* Elementary functions dealing with AVRPART structures
*/
AVRPART * avr_new_part(void)
{
AVRPART * p;
@ -819,3 +926,232 @@ void avr_display(FILE * f, AVRPART * p, const char * prefix, int verbose)
if (buf)
free(buf);
}
char cmdbitchar(CMDBIT cb) {
switch(cb.type) {
case AVR_CMDBIT_IGNORE:
return 'x';
case AVR_CMDBIT_VALUE:
return cb.value? '1': '0';
case AVR_CMDBIT_ADDRESS:
return 'a';
case AVR_CMDBIT_INPUT:
return 'i';
case AVR_CMDBIT_OUTPUT:
return 'o';
default:
return '?';
}
}
char *cmdbitstr(CMDBIT cb) {
char space[32];
*space = cmdbitchar(cb);
if(*space == 'a')
sprintf(space+1, "%d", cb.bitno);
else
space[1] = 0;
return strdup(space);
}
const char *opcodename(int opnum) {
switch(opnum) {
case AVR_OP_READ:
return "read";
case AVR_OP_WRITE:
return "write";
case AVR_OP_READ_LO:
return "read_lo";
case AVR_OP_READ_HI:
return "read_hi";
case AVR_OP_WRITE_LO:
return "write_lo";
case AVR_OP_WRITE_HI:
return "write_hi";
case AVR_OP_LOADPAGE_LO:
return "loadpage_lo";
case AVR_OP_LOADPAGE_HI:
return "loadpage_hi";
case AVR_OP_LOAD_EXT_ADDR:
return "load_ext_addr";
case AVR_OP_WRITEPAGE:
return "writepage";
case AVR_OP_CHIP_ERASE:
return "chip_erase";
case AVR_OP_PGM_ENABLE:
return "pgm_enable";
default:
return "???";
}
}
// Unique string representation of an opcode
char *opcode2str(OPCODE *op, int opnum, int detailed) {
char cb, space[1024], *sp = space;
int compact = 1;
if(!op)
return strdup("NULL");
// Can the opcode be printed in a compact way? Only if address bits are systematic.
for(int i=31; i >= 0; i--)
if(op->bit[i].type == AVR_CMDBIT_ADDRESS)
if(i<8 || i>23 || op->bit[i].bitno != (opnum == AVR_OP_LOAD_EXT_ADDR? i+8: i-8))
compact = 0;
if(detailed)
*sp++ = '"';
for(int i=31; i >= 0; i--) {
*sp++ = cb = cmdbitchar(op->bit[i]);
if(compact) {
if(i && i%8 == 0)
*sp++ = '-', *sp++ = '-';
else if(i && i%4 == 0)
*sp++ = '.';
} else {
if(cb == 'a') {
sprintf(sp, "%d", op->bit[i].bitno);
sp += strlen(sp);
}
if(i) {
if(detailed)
*sp++ = ' ';
if(i%8 == 0)
*sp++ = ' ';
}
}
}
if(detailed)
*sp++ = '"';
*sp = 0;
return strdup(space);
}
/*
* Match STRING against the partname pattern PATTERN, returning 1 if it
* matches, 0 if not. NOTE: part_match() is a modified old copy of !fnmatch()
* from the GNU C Library (published under GLP v2). Used for portability.
*/
inline static int fold(int c) {
return (c >= 'A' && c <= 'Z')? c+('a'-'A'): c;
}
int part_match(const char *pattern, const char *string) {
unsigned char c;
const char *p = pattern, *n = string;
if(!*n) // AVRDUDE specialty: empty string never matches
return 0;
while((c = fold(*p++))) {
switch(c) {
case '?':
if(*n == 0)
return 0;
break;
case '\\':
c = fold(*p++);
if(fold(*n) != c)
return 0;
break;
case '*':
for(c = *p++; c == '?' || c == '*'; c = *p++)
if(c == '?' && *n++ == 0)
return 0;
if(c == 0)
return 1;
{
unsigned char c1 = fold(c == '\\'? *p : c); // This char
for(--p; *n; ++n) // Recursively check reminder of string for *
if((c == '[' || fold(*n) == c1) && part_match(p, n) == 1)
return 1;
return 0;
}
case '[':
{
int negate;
if(*n == 0)
return 0;
negate = (*p == '!' || *p == '^');
if(negate)
++p;
c = *p++;
for(;;) {
unsigned char cstart = c, cend = c;
if(c == '\\')
cstart = cend = *p++;
cstart = cend = fold(cstart);
if(c == 0) // [ (unterminated)
return 0;
c = *p++;
c = fold(c);
if(c == '-' && *p != ']') {
cend = *p++;
if(cend == '\\')
cend = *p++;
if(cend == 0)
return 0;
cend = fold(cend);
c = *p++;
}
if(fold(*n) >= cstart && fold(*n) <= cend)
goto matched;
if(c == ']')
break;
}
if(!negate)
return 0;
break;
matched:;
while(c != ']') { // Skip the rest of the [...] that already matched
if(c == 0) // [... (unterminated)
return 0;
c = *p++;
if(c == '\\') // XXX 1003.2d11 is unclear if this is right
++p;
}
if(negate)
return 0;
}
break;
default:
if(c != fold(*n))
return 0;
}
++n;
}
return *n == 0;
}

View File

@ -51,114 +51,6 @@
#include "developer_opts.h"
#include "developer_opts_private.h"
char cmdbitchar(CMDBIT cb) {
switch(cb.type) {
case AVR_CMDBIT_IGNORE:
return 'x';
case AVR_CMDBIT_VALUE:
return cb.value? '1': '0';
case AVR_CMDBIT_ADDRESS:
return 'a';
case AVR_CMDBIT_INPUT:
return 'i';
case AVR_CMDBIT_OUTPUT:
return 'o';
default:
return '?';
}
}
char *cmdbitstr(CMDBIT cb) {
char space[32];
*space = cmdbitchar(cb);
if(*space == 'a')
sprintf(space+1, "%d", cb.bitno);
else
space[1] = 0;
return strdup(space);
}
const char *opcodename(int opnum) {
switch(opnum) {
case AVR_OP_READ:
return "read";
case AVR_OP_WRITE:
return "write";
case AVR_OP_READ_LO:
return "read_lo";
case AVR_OP_READ_HI:
return "read_hi";
case AVR_OP_WRITE_LO:
return "write_lo";
case AVR_OP_WRITE_HI:
return "write_hi";
case AVR_OP_LOADPAGE_LO:
return "loadpage_lo";
case AVR_OP_LOADPAGE_HI:
return "loadpage_hi";
case AVR_OP_LOAD_EXT_ADDR:
return "load_ext_addr";
case AVR_OP_WRITEPAGE:
return "writepage";
case AVR_OP_CHIP_ERASE:
return "chip_erase";
case AVR_OP_PGM_ENABLE:
return "pgm_enable";
default:
return "???";
}
}
// Unique string representation of an opcode
char *opcode2str(OPCODE *op, int opnum, int detailed) {
char cb, space[1024], *sp = space;
int compact = 1;
if(!op)
return strdup("NULL");
// Can the opcode be printed in a compact way? Only if address bits are systematic.
for(int i=31; i >= 0; i--)
if(op->bit[i].type == AVR_CMDBIT_ADDRESS)
if(i<8 || i>23 || op->bit[i].bitno != (opnum == AVR_OP_LOAD_EXT_ADDR? i+8: i-8))
compact = 0;
if(detailed)
*sp++ = '"';
for(int i=31; i >= 0; i--) {
*sp++ = cb = cmdbitchar(op->bit[i]);
if(compact) {
if(i && i%8 == 0)
*sp++ = '-', *sp++ = '-';
else if(i && i%4 == 0)
*sp++ = '.';
} else {
if(cb == 'a') {
sprintf(sp, "%d", op->bit[i].bitno);
sp += strlen(sp);
}
if(i) {
if(detailed)
*sp++ = ' ';
if(i%8 == 0)
*sp++ = ' ';
}
}
}
if(detailed)
*sp++ = '"';
*sp = 0;
return strdup(space);
}
// return 0 if op code would encode (essentially) the same SPI command
static int opcodecmp(OPCODE *op1, OPCODE *op2, int opnum) {
char *opstr1, *opstr2, *p;
@ -215,19 +107,6 @@ static void printallopcodes(AVRPART *p, const char *d, OPCODE **opa) {
}
// returns position 0..31 of highest bit set or INT_MIN if no bit is set
int intlog2(unsigned int n) {
int ret;
if(!n)
return INT_MIN;
for(ret = 0; n >>= 1; ret++)
continue;
return ret;
}
// mnemonic characterisation of flags
static char *parttype(AVRPART *p) {
@ -295,99 +174,6 @@ 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, ...) {
int size = 0;
@ -841,126 +627,6 @@ static void dev_part_strct(AVRPART *p, bool tsv, AVRPART *base) {
/*
* Match STRING against the partname pattern PATTERN, returning 1 if it
* matches, 0 if not. NOTE: part_match() is a modified old copy of !fnmatch()
* from the GNU C Library (published under GLP v2). Used for portability.
*/
inline static int fold(int c) {
return (c >= 'A' && c <= 'Z')? c+('a'-'A'): c;
}
int part_match(const char *pattern, const char *string) {
unsigned char c;
const char *p = pattern, *n = string;
if(!*n) // AVRDUDE specialty: empty string never matches
return 0;
while((c = fold(*p++))) {
switch(c) {
case '?':
if(*n == 0)
return 0;
break;
case '\\':
c = fold(*p++);
if(fold(*n) != c)
return 0;
break;
case '*':
for(c = *p++; c == '?' || c == '*'; c = *p++)
if(c == '?' && *n++ == 0)
return 0;
if(c == 0)
return 1;
{
unsigned char c1 = fold(c == '\\'? *p : c); // This char
for(--p; *n; ++n) // Recursively check reminder of string for *
if((c == '[' || fold(*n) == c1) && part_match(p, n) == 1)
return 1;
return 0;
}
case '[':
{
int negate;
if(*n == 0)
return 0;
negate = (*p == '!' || *p == '^');
if(negate)
++p;
c = *p++;
for(;;) {
unsigned char cstart = c, cend = c;
if(c == '\\')
cstart = cend = *p++;
cstart = cend = fold(cstart);
if(c == 0) // [ (unterminated)
return 0;
c = *p++;
c = fold(c);
if(c == '-' && *p != ']') {
cend = *p++;
if(cend == '\\')
cend = *p++;
if(cend == 0)
return 0;
cend = fold(cend);
c = *p++;
}
if(fold(*n) >= cstart && fold(*n) <= cend)
goto matched;
if(c == ']')
break;
}
if(!negate)
return 0;
break;
matched:;
while(c != ']') { // Skip the rest of the [...] that already matched
if(c == 0) // [... (unterminated)
return 0;
c = *p++;
if(c == '\\') // XXX 1003.2d11 is unclear if this is right
++p;
}
if(negate)
return 0;
}
break;
default:
if(c != fold(*n))
return 0;
}
++n;
}
return *n == 0;
}
// -p */[cdosw*]
void dev_output_part_defs(char *partdesc) {