This is a jajor re-write of the programming algorithms. The Atmel
serial programming instructions are not very orthoganal, i.e., the "read fuse bits" instruction on an ATMega103 is an entirely different opcode and data format from the _same_ instruction for an ATMega163! Thus, it becomes impossible to have a single instruction encoding (varying the data) across the chip lines. This set of changes allows and requires instruction encodings to be defined on a per-part basis within the configuration file. Hopefully I've defined the encoding scheme in a general enough way so it is useful in describing the instruction formats for yet-to-be invented Atmel chips. I've tried hard to make it match very closely with the specification in Atmel's data sheets for their parts. It's a little more verbose than what I initially hoped for, but I've tried to keep it as concise as I could, while still remaining reasonably flexible. git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@100 81a1dc3b-b13d-400b-aceb-764788c761c2
This commit is contained in:
parent
f1af5d3981
commit
fb233af934
3
Makefile
3
Makefile
|
@ -55,6 +55,9 @@ install : dirs \
|
|||
${CONFIGDIR}/avrprog.conf.sample \
|
||||
${CONFIGDIR}/avrprog.conf
|
||||
|
||||
config_gram.o : avr.h config.h lists.h pindefs.h
|
||||
|
||||
|
||||
dirs :
|
||||
@for dir in ${DIRS}; do \
|
||||
if [ ! -d $$dir ]; then \
|
||||
|
|
644
avr.c
644
avr.c
|
@ -37,6 +37,7 @@
|
|||
|
||||
#include "avr.h"
|
||||
#include "config.h"
|
||||
#include "lists.h"
|
||||
#include "pindefs.h"
|
||||
#include "ppi.h"
|
||||
|
||||
|
@ -64,33 +65,82 @@ AVRPART * avr_new_part(void)
|
|||
p->id[0] = 0;
|
||||
p->desc[0] = 0;
|
||||
|
||||
p->mem = lcreat(NULL, 0);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AVRPART * avr_dup_part(AVRPART * d)
|
||||
OPCODE * avr_new_opcode(void)
|
||||
{
|
||||
AVRPART * p;
|
||||
int i;
|
||||
OPCODE * m;
|
||||
|
||||
p = (AVRPART *)malloc(sizeof(AVRPART));
|
||||
if (p == NULL) {
|
||||
fprintf(stderr, "avr_dup_part(): out of memory\n");
|
||||
m = (OPCODE *)malloc(sizeof(*m));
|
||||
if (m == NULL) {
|
||||
fprintf(stderr, "avr_new_opcode(): out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(m, 0, sizeof(*m));
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AVRMEM * avr_new_memtype(void)
|
||||
{
|
||||
AVRMEM * m;
|
||||
|
||||
m = (AVRMEM *)malloc(sizeof(*m));
|
||||
if (m == NULL) {
|
||||
fprintf(stderr, "avr_new_memtype(): out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(m, 0, sizeof(*m));
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
AVRMEM * avr_dup_mem(AVRMEM * m)
|
||||
{
|
||||
AVRMEM * n;
|
||||
|
||||
n = avr_new_memtype();
|
||||
|
||||
*n = *m;
|
||||
|
||||
n->buf = (unsigned char *)malloc(n->size);
|
||||
if (n->buf == NULL) {
|
||||
fprintf(stderr,
|
||||
"avr_dup_mem(): out of memory (memsize=%d)\n",
|
||||
n->size);
|
||||
exit(1);
|
||||
}
|
||||
memset(n->buf, 0, n->size);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
AVRPART * avr_dup_part(AVRPART * d)
|
||||
{
|
||||
AVRPART * p;
|
||||
LISTID save;
|
||||
LNODEID ln;
|
||||
|
||||
p = avr_new_part();
|
||||
save = p->mem;
|
||||
|
||||
*p = *d;
|
||||
|
||||
for (i=0; i<AVR_MAXMEMTYPES; i++) {
|
||||
p->mem[i].buf = (unsigned char *)malloc(p->mem[i].size);
|
||||
if (p->mem[i].buf == NULL) {
|
||||
fprintf(stderr,
|
||||
"avr_dup_part(): out of memory (memsize=%d)\n",
|
||||
p->mem[i].size);
|
||||
exit(1);
|
||||
}
|
||||
memset(p->mem[i].buf, 0, p->mem[i].size);
|
||||
p->mem = save;
|
||||
|
||||
for (ln=lfirst(d->mem); ln; ln=lnext(ln)) {
|
||||
ladd(p->mem, avr_dup_mem(ldata(ln)));
|
||||
}
|
||||
|
||||
return p;
|
||||
|
@ -98,6 +148,32 @@ AVRPART * avr_dup_part(AVRPART * d)
|
|||
|
||||
|
||||
|
||||
AVRMEM * avr_locate_mem(AVRPART * p, char * desc)
|
||||
{
|
||||
AVRMEM * m, * match;
|
||||
LNODEID ln;
|
||||
int matches;
|
||||
int l;
|
||||
|
||||
l = strlen(desc);
|
||||
matches = 0;
|
||||
match = NULL;
|
||||
for (ln=lfirst(p->mem); ln; ln=lnext(ln)) {
|
||||
m = ldata(ln);
|
||||
if (strncmp(desc, m->desc, l) == 0) {
|
||||
match = m;
|
||||
matches++;
|
||||
}
|
||||
}
|
||||
|
||||
if (matches == 1)
|
||||
return match;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* transmit and receive a bit of data to/from the AVR device
|
||||
*/
|
||||
|
@ -155,132 +231,106 @@ int avr_cmd(int fd, unsigned char cmd[4], unsigned char res[4])
|
|||
res[i] = avr_txrx(fd, cmd[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* read a calibration byte
|
||||
*/
|
||||
unsigned char avr_read_calibration(int fd, AVRPART * p)
|
||||
{
|
||||
unsigned char cmd[4];
|
||||
unsigned char res[4];
|
||||
|
||||
LED_ON(fd, pgm->pinno[PIN_LED_PGM]);
|
||||
LED_OFF(fd, pgm->pinno[PIN_LED_ERR]);
|
||||
|
||||
cmd[0] = 0x38;
|
||||
cmd[1] = 0x00; /* don't care */
|
||||
cmd[2] = 0x00;
|
||||
cmd[3] = 0x00; /* don't care */
|
||||
|
||||
avr_cmd(fd, cmd, res);
|
||||
|
||||
LED_OFF(fd, pgm->pinno[PIN_LED_PGM]);
|
||||
|
||||
return res[3]; /* calibration byte */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* read a fuse byte
|
||||
*/
|
||||
unsigned char avr_read_fuse(int fd, AVRPART * p, int high)
|
||||
{
|
||||
unsigned char cmd[4];
|
||||
unsigned char res[4];
|
||||
static unsigned char cmdbyte1[2] = { 0x50, 0x58 };
|
||||
static unsigned char cmdbyte2[2] = { 0x00, 0x08 };
|
||||
|
||||
LED_ON(fd, pgm->pinno[PIN_LED_PGM]);
|
||||
LED_OFF(fd, pgm->pinno[PIN_LED_ERR]);
|
||||
|
||||
cmd[0] = cmdbyte1[high];
|
||||
cmd[1] = cmdbyte2[high];
|
||||
cmd[2] = 0; /* don't care */
|
||||
cmd[3] = 0; /* don't care */
|
||||
|
||||
avr_cmd(fd, cmd, res);
|
||||
|
||||
LED_OFF(fd, pgm->pinno[PIN_LED_PGM]);
|
||||
|
||||
return res[3]; /* fuse bits */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* write a fuse byte
|
||||
*/
|
||||
int avr_write_fuse(int fd, AVRPART * p, int high, unsigned char b)
|
||||
{
|
||||
unsigned char cmd[4];
|
||||
unsigned char res[4];
|
||||
static unsigned char cmdbyte[2] = { 0xa0, 0xa8 };
|
||||
|
||||
LED_ON(fd, pgm->pinno[PIN_LED_PGM]);
|
||||
LED_OFF(fd, pgm->pinno[PIN_LED_ERR]);
|
||||
|
||||
cmd[0] = 0xac;
|
||||
cmd[1] = cmdbyte[high];
|
||||
cmd[2] = 0x00; /* don't care */
|
||||
cmd[3] = b; /* fuse bits */
|
||||
|
||||
avr_cmd(fd, cmd, res);
|
||||
|
||||
usleep(2000);
|
||||
|
||||
LED_OFF(fd, pgm->pinno[PIN_LED_PGM]);
|
||||
#if 0
|
||||
fprintf(stderr, "avr_cmd(): [ ");
|
||||
for (i=0; i<4; i++)
|
||||
fprintf(stderr, "%02x ", cmd[i]);
|
||||
fprintf(stderr, "] [ ");
|
||||
for (i=0; i<4; i++)
|
||||
fprintf(stderr, "%02x ", res[i]);
|
||||
fprintf(stderr, "]\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* read a lock byte
|
||||
*/
|
||||
unsigned char avr_read_lock(int fd, AVRPART * p)
|
||||
int avr_set_bits(OPCODE * op, unsigned char * cmd)
|
||||
{
|
||||
unsigned char cmd[4];
|
||||
unsigned char res[4];
|
||||
int i, j, bit;
|
||||
unsigned char mask;
|
||||
|
||||
LED_ON(fd, pgm->pinno[PIN_LED_PGM]);
|
||||
LED_OFF(fd, pgm->pinno[PIN_LED_ERR]);
|
||||
for (i=0; i<32; i++) {
|
||||
if (op->bit[i].type == AVR_CMDBIT_VALUE) {
|
||||
j = 3 - i / 8;
|
||||
bit = i % 8;
|
||||
mask = 1 << bit;
|
||||
if (op->bit[i].value)
|
||||
cmd[j] = cmd[j] | mask;
|
||||
else
|
||||
cmd[j] = cmd[j] & ~mask;
|
||||
}
|
||||
}
|
||||
|
||||
cmd[0] = 0x58;
|
||||
cmd[1] = 0x00;
|
||||
cmd[2] = 0;
|
||||
cmd[3] = 0; /* don't care */
|
||||
|
||||
avr_cmd(fd, cmd, res);
|
||||
|
||||
LED_OFF(fd, pgm->pinno[PIN_LED_PGM]);
|
||||
|
||||
return res[3]; /* lock bits */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* write a lock byte
|
||||
*/
|
||||
int avr_write_lock(int fd, AVRPART * p, unsigned char b)
|
||||
int avr_set_addr(OPCODE * op, unsigned char * cmd, unsigned long addr)
|
||||
{
|
||||
unsigned char cmd[4];
|
||||
unsigned char res[4];
|
||||
int i, j, bit;
|
||||
unsigned long value;
|
||||
unsigned char mask;
|
||||
|
||||
LED_ON(fd, pgm->pinno[PIN_LED_PGM]);
|
||||
LED_OFF(fd, pgm->pinno[PIN_LED_ERR]);
|
||||
for (i=0; i<32; i++) {
|
||||
if (op->bit[i].type == AVR_CMDBIT_ADDRESS) {
|
||||
j = 3 - i / 8;
|
||||
bit = i % 8;
|
||||
mask = 1 << bit;
|
||||
value = addr >> op->bit[i].bitno & 0x01;
|
||||
if (value)
|
||||
cmd[j] = cmd[j] | mask;
|
||||
else
|
||||
cmd[j] = cmd[j] & ~mask;
|
||||
}
|
||||
}
|
||||
|
||||
cmd[0] = 0x5c;
|
||||
cmd[1] = 0xe0;
|
||||
cmd[2] = 0; /* don't care */
|
||||
cmd[3] = b; /* lock bits */
|
||||
return 0;
|
||||
}
|
||||
|
||||
avr_cmd(fd, cmd, res);
|
||||
|
||||
usleep(2000);
|
||||
int avr_set_input(OPCODE * op, unsigned char * cmd, unsigned char data)
|
||||
{
|
||||
int i, j, bit;
|
||||
unsigned char value;
|
||||
unsigned char mask;
|
||||
|
||||
LED_OFF(fd, pgm->pinno[PIN_LED_PGM]);
|
||||
for (i=0; i<32; i++) {
|
||||
if (op->bit[i].type == AVR_CMDBIT_INPUT) {
|
||||
j = 3 - i / 8;
|
||||
bit = i % 8;
|
||||
mask = 1 << bit;
|
||||
value = data >> op->bit[i].bitno & 0x01;
|
||||
if (value)
|
||||
cmd[j] = cmd[j] | mask;
|
||||
else
|
||||
cmd[j] = cmd[j] & ~mask;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int avr_get_output(OPCODE * op, unsigned char * cmd, unsigned char * data)
|
||||
{
|
||||
int i, j, bit;
|
||||
unsigned char value;
|
||||
unsigned char mask;
|
||||
|
||||
for (i=0; i<32; i++) {
|
||||
if (op->bit[i].type == AVR_CMDBIT_OUTPUT) {
|
||||
j = 3 - i / 8;
|
||||
bit = i % 8;
|
||||
mask = 1 << bit;
|
||||
value = ((cmd[j] & mask) >> bit) & 0x01;
|
||||
value = value << op->bit[i].bitno;
|
||||
if (value)
|
||||
*data = *data | value;
|
||||
else
|
||||
*data = *data & ~value;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -289,60 +339,89 @@ int avr_write_lock(int fd, AVRPART * p, unsigned char b)
|
|||
/*
|
||||
* read a byte of data from the indicated memory region
|
||||
*/
|
||||
unsigned char avr_read_byte(int fd, AVRPART * p,
|
||||
int memtype, unsigned long addr)
|
||||
int avr_read_byte(int fd, AVRPART * p, AVRMEM * mem, unsigned long addr,
|
||||
unsigned char * value)
|
||||
{
|
||||
unsigned short offset;
|
||||
unsigned char cmd[4];
|
||||
unsigned char res[4];
|
||||
/* order here is very important, AVR_EEPROM, AVR_FLASH, AVR_FLASH+1 */
|
||||
static unsigned char cmdbyte[3] = { 0xa0, 0x20, 0x28 };
|
||||
unsigned char data;
|
||||
OPCODE * readop;
|
||||
|
||||
LED_ON(fd, pgm->pinno[PIN_LED_PGM]);
|
||||
LED_OFF(fd, pgm->pinno[PIN_LED_ERR]);
|
||||
|
||||
offset = 0;
|
||||
|
||||
if (memtype == AVR_M_FLASH) {
|
||||
offset = addr & 0x01;
|
||||
addr = addr / 2;
|
||||
if (mem->op[AVR_OP_READ_LO]) {
|
||||
if (addr & 0x00000001)
|
||||
readop = mem->op[AVR_OP_READ_HI];
|
||||
else
|
||||
readop = mem->op[AVR_OP_READ_LO];
|
||||
addr = addr / 2;
|
||||
}
|
||||
else {
|
||||
readop = mem->op[AVR_OP_READ];
|
||||
}
|
||||
|
||||
cmd[0] = cmdbyte[memtype + offset];
|
||||
cmd[1] = addr >> 8; /* high order bits of address */
|
||||
cmd[2] = addr & 0x0ff; /* low order bits of address */
|
||||
cmd[3] = 0; /* don't care */
|
||||
if (readop == NULL) {
|
||||
fprintf(stderr,
|
||||
"avr_read_byte(): operation not supported on memory type \"%s\"\n",
|
||||
p->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
|
||||
avr_set_bits(readop, cmd);
|
||||
avr_set_addr(readop, cmd, addr);
|
||||
avr_cmd(fd, cmd, res);
|
||||
data = 0;
|
||||
avr_get_output(readop, res, &data);
|
||||
|
||||
LED_OFF(fd, pgm->pinno[PIN_LED_PGM]);
|
||||
|
||||
return res[3];
|
||||
*value = data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read the entirety of the specified memory type into the
|
||||
* corresponding buffer of the avrpart pointed to by 'p'. If size =
|
||||
* 0, read the entire contents, otherwize, read 'size' bytes.
|
||||
* 0, read the entire contents, otherwise, read 'size' bytes.
|
||||
*
|
||||
* Return the number of bytes read, or -1 if an error occurs. */
|
||||
int avr_read(int fd, AVRPART * p, int memtype, int size)
|
||||
* Return the number of bytes read, or -1 if an error occurs.
|
||||
*/
|
||||
int avr_read(int fd, AVRPART * p, char * memtype, int size, int verbose)
|
||||
{
|
||||
unsigned char rbyte;
|
||||
unsigned long i;
|
||||
unsigned char * buf;
|
||||
AVRMEM * mem;
|
||||
int rc;
|
||||
|
||||
buf = p->mem[memtype].buf;
|
||||
mem = avr_locate_mem(p, memtype);
|
||||
if (mem == NULL) {
|
||||
fprintf(stderr, "No \"%s\" memory for part %s\n",
|
||||
memtype, p->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf = mem->buf;
|
||||
if (size == 0) {
|
||||
size = p->mem[memtype].size;
|
||||
size = mem->size;
|
||||
}
|
||||
|
||||
for (i=0; i<size; i++) {
|
||||
rbyte = avr_read_byte(fd, p, memtype, i);
|
||||
if (i % 16 == 0)
|
||||
fprintf(stderr, " \r%4lu 0x%02x", i, rbyte);
|
||||
rc = avr_read_byte(fd, p, mem, i, &rbyte);
|
||||
if (rc != 0) {
|
||||
fprintf(stderr, "avr_read(): error reading address 0x%04lx\n", i);
|
||||
return -2;
|
||||
}
|
||||
buf[i] = rbyte;
|
||||
if (verbose) {
|
||||
if (i % 16 == 0)
|
||||
fprintf(stderr, " \r%4lu 0x%02x", i, rbyte);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
|
@ -357,39 +436,38 @@ int avr_read(int fd, AVRPART * p, int memtype, int size)
|
|||
/*
|
||||
* write a byte of data to the indicated memory region
|
||||
*/
|
||||
int avr_write_page(int fd, AVRPART * p, int memtype,
|
||||
unsigned short page)
|
||||
int avr_write_page(int fd, AVRPART * p, AVRMEM * mem,
|
||||
unsigned long addr)
|
||||
{
|
||||
unsigned char cmd[4];
|
||||
unsigned char res[4];
|
||||
OPCODE * wp;
|
||||
|
||||
wp = mem->op[AVR_OP_WRITEPAGE];
|
||||
if (wp == NULL) {
|
||||
fprintf(stderr,
|
||||
"avr_write_page(): memory \"%s\" not configured for page writes\n",
|
||||
mem->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mem->op[AVR_OP_LOADPAGE_LO])
|
||||
addr = addr / 2;
|
||||
|
||||
LED_ON(fd, pgm->pinno[PIN_LED_PGM]);
|
||||
LED_OFF(fd, pgm->pinno[PIN_LED_ERR]);
|
||||
|
||||
/*
|
||||
* 'page' indicates which page is being programmed: 0 for the first
|
||||
* page_size block, 1 for the second, up to num_pages-1 for the
|
||||
* last. The MCU actually wants the high-order bits of what would
|
||||
* be the actual address instead, shifted left to the upper most
|
||||
* bits of a 16 bit word. For a 128K flash, the actual address is a
|
||||
* 17 bits. To get the right value to send to the MCU, we want to
|
||||
* shift 'page' left by 16 - the number of bits in the page
|
||||
* address.
|
||||
*/
|
||||
page = page << p->mem[memtype].pageaddr_shift;
|
||||
|
||||
cmd[0] = 0x4c;
|
||||
cmd[1] = page >> 8; /* high order bits of address */
|
||||
cmd[2] = page & 0x0ff; /* low order bits of address */
|
||||
cmd[3] = 0; /* these bits are ignored */
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
|
||||
avr_set_bits(wp, cmd);
|
||||
avr_set_addr(wp, cmd, addr);
|
||||
avr_cmd(fd, cmd, res);
|
||||
|
||||
/*
|
||||
* since we don't know what voltage the target AVR is powered by, be
|
||||
* conservative and delay the max amount the spec says to wait
|
||||
*/
|
||||
usleep(p->mem[memtype].max_write_delay);
|
||||
usleep(mem->max_write_delay);
|
||||
|
||||
LED_OFF(fd, pgm->pinno[PIN_LED_PGM]);
|
||||
return 0;
|
||||
|
@ -399,7 +477,7 @@ int avr_write_page(int fd, AVRPART * p, int memtype,
|
|||
/*
|
||||
* write a byte of data to the indicated memory region
|
||||
*/
|
||||
int avr_write_byte(int fd, AVRPART * p, int memtype,
|
||||
int avr_write_byte(int fd, AVRPART * p, AVRMEM * mem,
|
||||
unsigned long addr, unsigned char data)
|
||||
{
|
||||
unsigned char cmd[4];
|
||||
|
@ -408,45 +486,67 @@ int avr_write_byte(int fd, AVRPART * p, int memtype,
|
|||
int ready;
|
||||
int tries;
|
||||
unsigned char b;
|
||||
unsigned short offset;
|
||||
unsigned short caddr;
|
||||
/* order here is very important, AVR_M_EEPROM, AVR_M_FLASH, AVR_M_FLASH+1 */
|
||||
static unsigned char cmdbyte[3] = { 0xc0, 0x40, 0x48 };
|
||||
OPCODE * writeop;
|
||||
int rc;
|
||||
|
||||
if (!p->mem[memtype].paged) {
|
||||
if (!mem->paged) {
|
||||
/*
|
||||
* check to see if the write is necessary by reading the existing
|
||||
* value and only write if we are changing the value; we can't
|
||||
* use this optimization for paged addressing.
|
||||
*/
|
||||
b = avr_read_byte(fd, p, memtype, addr);
|
||||
rc = avr_read_byte(fd, p, mem, addr, &b);
|
||||
if (rc != 0)
|
||||
return -1;
|
||||
|
||||
if (b == data) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
addr = addr % p->mem[memtype].page_size;
|
||||
|
||||
/*
|
||||
* determine which memory opcode to use
|
||||
*/
|
||||
if (mem->op[AVR_OP_WRITE_LO]) {
|
||||
if (addr & 0x01)
|
||||
writeop = mem->op[AVR_OP_WRITE_HI];
|
||||
else
|
||||
writeop = mem->op[AVR_OP_WRITE_LO];
|
||||
caddr = addr / 2;
|
||||
}
|
||||
else if (mem->op[AVR_OP_LOADPAGE_LO]) {
|
||||
if (addr & 0x01)
|
||||
writeop = mem->op[AVR_OP_LOADPAGE_HI];
|
||||
else
|
||||
writeop = mem->op[AVR_OP_LOADPAGE_LO];
|
||||
caddr = addr / 2;
|
||||
}
|
||||
else {
|
||||
writeop = mem->op[AVR_OP_WRITE];
|
||||
caddr = addr;
|
||||
}
|
||||
|
||||
if (writeop == NULL) {
|
||||
fprintf(stderr,
|
||||
"avr_write_byte(): write not support for memory type \"%s\"\n",
|
||||
mem->desc);
|
||||
exit(1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
LED_ON(fd, pgm->pinno[PIN_LED_PGM]);
|
||||
LED_OFF(fd, pgm->pinno[PIN_LED_ERR]);
|
||||
|
||||
offset = 0;
|
||||
|
||||
caddr = addr;
|
||||
if (memtype == AVR_M_FLASH) {
|
||||
offset = addr & 0x01;
|
||||
caddr = addr / 2;
|
||||
}
|
||||
|
||||
cmd[0] = cmdbyte[memtype + offset];
|
||||
cmd[1] = caddr >> 8; /* high order bits of address */
|
||||
cmd[2] = caddr & 0x0ff; /* low order bits of address */
|
||||
cmd[3] = data; /* data */
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
|
||||
avr_set_bits(writeop, cmd);
|
||||
avr_set_addr(writeop, cmd, caddr);
|
||||
avr_set_input(writeop, cmd, data);
|
||||
avr_cmd(fd, cmd, res);
|
||||
|
||||
if (p->mem[memtype].paged) {
|
||||
if (mem->paged) {
|
||||
/*
|
||||
* in paged addressing, single bytes to written to the memory
|
||||
* page complete immediately, we only need to delay when we commit
|
||||
|
@ -459,18 +559,24 @@ int avr_write_byte(int fd, AVRPART * p, int memtype,
|
|||
tries = 0;
|
||||
ready = 0;
|
||||
while (!ready) {
|
||||
usleep(p->mem[memtype].min_write_delay); /* typical write delay */
|
||||
r = avr_read_byte(fd, p, memtype, addr);
|
||||
if ((data == p->mem[memtype].readback[0]) ||
|
||||
(data == p->mem[memtype].readback[1])) {
|
||||
usleep(mem->min_write_delay); /* typical write delay */
|
||||
rc = avr_read_byte(fd, p, mem, addr, &r);
|
||||
if (rc != 0) {
|
||||
return -1;
|
||||
}
|
||||
if ((data == mem->readback[0]) ||
|
||||
(data == mem->readback[1])) {
|
||||
/*
|
||||
* use an extra long delay when we happen to be writing values
|
||||
* used for polled data read-back. In this case, polling
|
||||
* doesn't work, and we need to delay the worst case write time
|
||||
* specified for the chip.
|
||||
*/
|
||||
usleep(p->mem[memtype].max_write_delay);
|
||||
r = avr_read_byte(fd, p, memtype, addr);
|
||||
usleep(mem->max_write_delay);
|
||||
rc = avr_read_byte(fd, p, mem, addr, &r);
|
||||
if (rc != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (r == data) {
|
||||
|
@ -504,19 +610,28 @@ int avr_write_byte(int fd, AVRPART * p, int memtype,
|
|||
*
|
||||
* Return the number of bytes written, or -1 if an error occurs.
|
||||
*/
|
||||
int avr_write(int fd, AVRPART * p, int memtype, int size)
|
||||
int avr_write(int fd, AVRPART * p, char * memtype, int size, int verbose)
|
||||
{
|
||||
int rc;
|
||||
int wsize;
|
||||
unsigned long i;
|
||||
unsigned char data;
|
||||
int werror;
|
||||
AVRMEM * m;
|
||||
|
||||
m = avr_locate_mem(p, memtype);
|
||||
if (m == NULL) {
|
||||
fprintf(stderr, "No \"%s\" memory for part %s\n",
|
||||
memtype, p->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
LED_OFF(fd, pgm->pinno[PIN_LED_ERR]);
|
||||
|
||||
werror = 0;
|
||||
|
||||
wsize = p->mem[memtype].size;
|
||||
wsize = m->size;
|
||||
if (size < wsize) {
|
||||
wsize = size;
|
||||
}
|
||||
|
@ -530,10 +645,12 @@ int avr_write(int fd, AVRPART * p, int memtype, int size)
|
|||
|
||||
for (i=0; i<wsize; i++) {
|
||||
/* eeprom or low byte of flash */
|
||||
data = p->mem[memtype].buf[i];
|
||||
rc = avr_write_byte(fd, p, memtype, i, data);
|
||||
if (i % 16 == 0)
|
||||
fprintf(stderr, " \r%4lu 0x%02x", i, data);
|
||||
data = m->buf[i];
|
||||
if (verbose) {
|
||||
if (i % 16 == 0)
|
||||
fprintf(stderr, " \r%4lu 0x%02x ", i, data);
|
||||
}
|
||||
rc = avr_write_byte(fd, p, m, i, data);
|
||||
if (rc) {
|
||||
fprintf(stderr, " ***failed; ");
|
||||
fprintf(stderr, "\n");
|
||||
|
@ -541,15 +658,16 @@ int avr_write(int fd, AVRPART * p, int memtype, int size)
|
|||
werror = 1;
|
||||
}
|
||||
|
||||
if (p->mem[memtype].paged) {
|
||||
if (((i % p->mem[memtype].page_size) == p->mem[memtype].page_size-1) ||
|
||||
if (m->paged) {
|
||||
if (((i % m->page_size) == m->page_size-1) ||
|
||||
(i == wsize-1)) {
|
||||
rc = avr_write_page(fd, p, memtype, i/p->mem[memtype].page_size);
|
||||
rc = avr_write_page(fd, p, m, i);
|
||||
if (rc) {
|
||||
fprintf(stderr,
|
||||
" *** page %ld (addresses 0x%04lx - 0x%04lx) failed to write\n",
|
||||
i % p->mem[memtype].page_size,
|
||||
i-p->mem[memtype].page_size+1, i);
|
||||
" *** page %ld (addresses 0x%04lx - 0x%04lx) failed "
|
||||
"to write\n",
|
||||
i % m->page_size,
|
||||
i - m->page_size + 1, i);
|
||||
fprintf(stderr, "\n");
|
||||
LED_ON(fd, pgm->pinno[PIN_LED_ERR]);
|
||||
werror = 1;
|
||||
|
@ -576,15 +694,23 @@ int avr_write(int fd, AVRPART * p, int memtype, int size)
|
|||
/*
|
||||
* issue the 'program enable' command to the AVR device
|
||||
*/
|
||||
int avr_program_enable(int fd)
|
||||
int avr_program_enable(int fd, AVRPART * p)
|
||||
{
|
||||
unsigned char cmd[4] = {0xac, 0x53, 0x00, 0x00};
|
||||
unsigned char cmd[4];
|
||||
unsigned char res[4];
|
||||
|
||||
if (p->op[AVR_OP_PGM_ENABLE] == NULL) {
|
||||
fprintf(stderr, "program enable instruction not defined for part \"%s\"\n",
|
||||
p->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
avr_set_bits(p->op[AVR_OP_PGM_ENABLE], cmd);
|
||||
avr_cmd(fd, cmd, res);
|
||||
|
||||
if (res[2] != cmd[1])
|
||||
return -1;
|
||||
return -2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -595,12 +721,21 @@ int avr_program_enable(int fd)
|
|||
*/
|
||||
int avr_chip_erase(int fd, AVRPART * p)
|
||||
{
|
||||
unsigned char data[4] = {0xac, 0x80, 0x00, 0x00};
|
||||
unsigned char cmd[4];
|
||||
unsigned char res[4];
|
||||
|
||||
if (p->op[AVR_OP_CHIP_ERASE] == NULL) {
|
||||
fprintf(stderr, "chip erase instruction not defined for part \"%s\"\n",
|
||||
p->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
LED_ON(fd, pgm->pinno[PIN_LED_PGM]);
|
||||
|
||||
avr_cmd(fd, data, res);
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
|
||||
avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd);
|
||||
avr_cmd(fd, cmd, res);
|
||||
usleep(p->chip_erase_delay);
|
||||
avr_initialize(fd, p);
|
||||
|
||||
|
@ -613,16 +748,16 @@ int avr_chip_erase(int fd, AVRPART * p)
|
|||
/*
|
||||
* read the AVR device's signature bytes
|
||||
*/
|
||||
int avr_signature(int fd, unsigned char sig[4])
|
||||
int avr_signature(int fd, AVRPART * p)
|
||||
{
|
||||
unsigned char cmd[4] = {0x30, 0x00, 0x00, 0x00};
|
||||
unsigned char res[4];
|
||||
int i;
|
||||
int rc;
|
||||
|
||||
for (i=0; i<4; i++) {
|
||||
cmd[2] = i;
|
||||
avr_cmd(fd, cmd, res);
|
||||
sig[i] = res[3];
|
||||
rc = avr_read(fd, p, "signature", 0, 0);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr,
|
||||
"%s: error reading signature data for part \"%s\", rc=%d\n",
|
||||
progname, p->desc, rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -674,12 +809,12 @@ int avr_initialize(int fd, AVRPART * p)
|
|||
* of sync.
|
||||
*/
|
||||
if (strcmp(p->desc, "AT90S1200")==0) {
|
||||
avr_program_enable(fd);
|
||||
avr_program_enable(fd, p);
|
||||
}
|
||||
else {
|
||||
tries = 0;
|
||||
do {
|
||||
rc = avr_program_enable(fd);
|
||||
rc = avr_program_enable(fd, p);
|
||||
if (rc == 0)
|
||||
break;
|
||||
ppi_pulsepin(fd, pgm->pinno[PIN_AVR_SCK]);
|
||||
|
@ -700,27 +835,17 @@ int avr_initialize(int fd, AVRPART * p)
|
|||
|
||||
|
||||
|
||||
char * avr_memtstr(int memtype)
|
||||
{
|
||||
switch (memtype) {
|
||||
case AVR_M_EEPROM : return "eeprom"; break;
|
||||
case AVR_M_FLASH : return "flash"; break;
|
||||
case AVR_M_FUSE : return "fuse-bit"; break;
|
||||
case AVR_M_LOCK : return "fock-bit"; break;
|
||||
default : return "unknown-memtype"; break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int avr_initmem(AVRPART * p)
|
||||
{
|
||||
int i;
|
||||
LNODEID ln;
|
||||
AVRMEM * m;
|
||||
|
||||
for (i=0; i<AVR_MAXMEMTYPES; i++) {
|
||||
p->mem[i].buf = (unsigned char *) malloc(p->mem[i].size);
|
||||
if (p->mem[i].buf == NULL) {
|
||||
for (ln=lfirst(p->mem); ln; ln=lnext(ln)) {
|
||||
m = ldata(ln);
|
||||
m->buf = (unsigned char *) malloc(m->size);
|
||||
if (m->buf == NULL) {
|
||||
fprintf(stderr, "%s: can't alloc buffer for %s size of %d bytes\n",
|
||||
progname, avr_memtstr(i), p->mem[i].size);
|
||||
progname, m->desc, m->size);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -736,15 +861,32 @@ int avr_initmem(AVRPART * p)
|
|||
*
|
||||
* Return the number of bytes verified, or -1 if they don't match.
|
||||
*/
|
||||
int avr_verify(AVRPART * p, AVRPART * v, int memtype, int size)
|
||||
int avr_verify(AVRPART * p, AVRPART * v, char * memtype, int size)
|
||||
{
|
||||
int i;
|
||||
unsigned char * buf1, * buf2;
|
||||
int vsize;
|
||||
AVRMEM * a, * b;
|
||||
|
||||
buf1 = p->mem[memtype].buf;
|
||||
buf2 = v->mem[memtype].buf;
|
||||
vsize = p->mem[memtype].size;
|
||||
a = avr_locate_mem(p, memtype);
|
||||
if (a == NULL) {
|
||||
fprintf(stderr,
|
||||
"avr_verify(): memory type \"%s\" not defined for part %s\n",
|
||||
memtype, p->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
b = avr_locate_mem(v, memtype);
|
||||
if (b == NULL) {
|
||||
fprintf(stderr,
|
||||
"avr_verify(): memory type \"%s\" not defined for part %s\n",
|
||||
memtype, v->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf1 = a->buf;
|
||||
buf2 = b->buf;
|
||||
vsize = a->size;
|
||||
|
||||
if (vsize < size) {
|
||||
fprintf(stderr,
|
||||
|
@ -752,7 +894,7 @@ int avr_verify(AVRPART * p, AVRPART * v, int memtype, int size)
|
|||
"%s%s memory region only contains %d bytes\n"
|
||||
"%sOnly %d bytes will be verified.\n",
|
||||
progname, size,
|
||||
progbuf, avr_memtstr(memtype), vsize,
|
||||
progbuf, memtype, vsize,
|
||||
progbuf, vsize);
|
||||
size = vsize;
|
||||
}
|
||||
|
@ -777,20 +919,19 @@ void avr_mem_display(char * prefix, FILE * f, AVRMEM * m, int type)
|
|||
{
|
||||
if (m == NULL) {
|
||||
fprintf(f,
|
||||
"%sMem Page Page Polled\n"
|
||||
"%sType Paged Size Size #Pages Shift MinW MaxW ReadBack\n"
|
||||
"%s------ ------ ------ ---- ------ ----- ----- ----- ---------\n",
|
||||
"%sMem Page Polled\n"
|
||||
"%sType Paged Size Size #Pages MinW MaxW ReadBack\n"
|
||||
"%s----------- ------ ------ ---- ------ ----- ----- ---------\n",
|
||||
prefix, prefix, prefix);
|
||||
}
|
||||
else {
|
||||
fprintf(f,
|
||||
"%s%-6s %-6s %6d %4d %6d %5d %5d %5d 0x%02x 0x%02x\n",
|
||||
prefix, avr_memtstr(type),
|
||||
"%s%-11s %-6s %6d %4d %5d %5d %5d 0x%02x 0x%02x\n",
|
||||
prefix, m->desc,
|
||||
m->paged ? "yes" : "no",
|
||||
m->size,
|
||||
m->page_size,
|
||||
m->num_pages,
|
||||
m->pageaddr_shift,
|
||||
m->min_write_delay,
|
||||
m->max_write_delay,
|
||||
m->readback[0],
|
||||
|
@ -805,6 +946,8 @@ void avr_display(FILE * f, AVRPART * p, char * prefix)
|
|||
int i;
|
||||
char * buf;
|
||||
char * px;
|
||||
LNODEID ln;
|
||||
AVRMEM * m;
|
||||
|
||||
fprintf(f,
|
||||
"%sAVR Part : %s\n"
|
||||
|
@ -827,8 +970,9 @@ void avr_display(FILE * f, AVRPART * p, char * prefix)
|
|||
}
|
||||
|
||||
avr_mem_display(px, f, NULL, 0);
|
||||
for (i=0; i<AVR_MAXMEMTYPES; i++) {
|
||||
avr_mem_display(px, f, &p->mem[i], i);
|
||||
for (ln=lfirst(p->mem); ln; ln=lnext(ln)) {
|
||||
m = ldata(ln);
|
||||
avr_mem_display(px, f, m, i);
|
||||
}
|
||||
|
||||
if (buf)
|
||||
|
|
112
avr.h
112
avr.h
|
@ -34,29 +34,62 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "lists.h"
|
||||
|
||||
|
||||
/*
|
||||
* AVR memory designations; the order of these is important, these are
|
||||
* used as indexes into statically initialized data, don't change them
|
||||
* around. Specifically, avr_read_byte() and avr_write_byte() rely on
|
||||
* the order.
|
||||
* AVR serial programming instructions
|
||||
*/
|
||||
#define AVR_M_EEPROM 0
|
||||
#define AVR_M_FLASH 1
|
||||
#define AVR_M_FUSE 2
|
||||
#define AVR_M_LOCK 3
|
||||
enum {
|
||||
AVR_OP_READ,
|
||||
AVR_OP_WRITE,
|
||||
AVR_OP_READ_LO,
|
||||
AVR_OP_READ_HI,
|
||||
AVR_OP_WRITE_LO,
|
||||
AVR_OP_WRITE_HI,
|
||||
AVR_OP_LOADPAGE_LO,
|
||||
AVR_OP_LOADPAGE_HI,
|
||||
AVR_OP_WRITEPAGE,
|
||||
AVR_OP_CHIP_ERASE,
|
||||
AVR_OP_PGM_ENABLE,
|
||||
AVR_OP_MAX
|
||||
};
|
||||
|
||||
#define AVR_MAXMEMTYPES 2 /* just flash and eeprom */
|
||||
|
||||
enum {
|
||||
AVR_CMDBIT_IGNORE, /* bit is ignored on input and output */
|
||||
AVR_CMDBIT_VALUE, /* bit is set to 0 or 1 for input or output */
|
||||
AVR_CMDBIT_ADDRESS, /* this bit represents an input address bit */
|
||||
AVR_CMDBIT_INPUT, /* this bit is an input bit */
|
||||
AVR_CMDBIT_OUTPUT /* this bit is an output bit */
|
||||
};
|
||||
|
||||
/*
|
||||
* serial programming instruction bit specifications
|
||||
*/
|
||||
typedef struct cmdbit {
|
||||
int type; /* AVR_CMDBIT_* */
|
||||
int bitno; /* which input bit to use for this command bit */
|
||||
int value; /* bit value if type == AVR_CMDBIT_VALUD */
|
||||
} CMDBIT;
|
||||
|
||||
typedef struct opcode {
|
||||
CMDBIT bit[32]; /* opcode bit specs */
|
||||
} OPCODE;
|
||||
|
||||
|
||||
#define AVR_MEMDESCLEN 64
|
||||
typedef struct avrmem {
|
||||
int paged; /* page addressed (e.g. ATmega flash) */
|
||||
int size; /* total memory size in bytes */
|
||||
int page_size; /* size of memory page (if page addressed) */
|
||||
int num_pages; /* number of pages (if page addressed) */
|
||||
int pageaddr_shift; /* number of bits in the page address */
|
||||
int min_write_delay; /* microseconds */
|
||||
int max_write_delay; /* microseconds */
|
||||
unsigned char readback[2]; /* polled read-back values */
|
||||
unsigned char * buf; /* pointer to memory buffer */
|
||||
char desc[AVR_MEMDESCLEN]; /* memory description ("flash", "eeprom", etc) */
|
||||
int paged; /* page addressed (e.g. ATmega flash) */
|
||||
int size; /* total memory size in bytes */
|
||||
int page_size; /* size of memory page (if page addressed) */
|
||||
int num_pages; /* number of pages (if page addressed) */
|
||||
int min_write_delay; /* microseconds */
|
||||
int max_write_delay; /* microseconds */
|
||||
unsigned char readback[2]; /* polled read-back values */
|
||||
unsigned char * buf; /* pointer to memory buffer */
|
||||
OPCODE * op[AVR_OP_MAX]; /* opcodes */
|
||||
} AVRMEM;
|
||||
|
||||
|
||||
|
@ -65,10 +98,10 @@ typedef struct avrmem {
|
|||
typedef struct avrpart {
|
||||
char desc[AVR_DESCLEN]; /* long part name */
|
||||
char id[AVR_IDLEN]; /* short part name */
|
||||
int chip_erase_delay; /* microseconds */
|
||||
OPCODE * op[AVR_OP_MAX]; /* opcodes */
|
||||
|
||||
int chip_erase_delay; /* microseconds */
|
||||
|
||||
AVRMEM mem[AVR_MAXMEMTYPES];
|
||||
LISTID mem; /* avr memory definitions */
|
||||
} AVRPART;
|
||||
|
||||
|
||||
|
@ -80,42 +113,38 @@ AVRPART * avr_find_part(char * p);
|
|||
|
||||
AVRPART * avr_new_part(void);
|
||||
|
||||
OPCODE * avr_new_opcode(void);
|
||||
|
||||
AVRMEM * avr_new_memtype(void);
|
||||
|
||||
AVRPART * avr_dup_part(AVRPART * d);
|
||||
|
||||
AVRMEM * avr_locate_mem(AVRPART * p, char * desc);
|
||||
|
||||
int avr_txrx_bit(int fd, int bit);
|
||||
|
||||
unsigned char avr_txrx(int fd, unsigned char byte);
|
||||
|
||||
int avr_cmd(int fd, unsigned char cmd[4], unsigned char res[4]);
|
||||
|
||||
unsigned char avr_read_calibration(int fd, AVRPART * p);
|
||||
int avr_read_byte(int fd, AVRPART * p, AVRMEM * mem, unsigned long addr,
|
||||
unsigned char * value);
|
||||
|
||||
unsigned char avr_read_fuse(int fd, AVRPART * p, int high);
|
||||
int avr_read(int fd, AVRPART * p, char * memtype, int size, int verbose);
|
||||
|
||||
int avr_write_fuse(int fd, AVRPART * p, int high, unsigned char b);
|
||||
int avr_write_page(int fd, AVRPART * p, AVRMEM * mem,
|
||||
unsigned long addr);
|
||||
|
||||
unsigned char avr_read_lock(int fd, AVRPART * p);
|
||||
|
||||
int avr_write_lock(int fd, AVRPART * p, unsigned char b);
|
||||
|
||||
unsigned char avr_read_byte(int fd, AVRPART * p,
|
||||
int memtype, unsigned long addr);
|
||||
|
||||
int avr_read(int fd, AVRPART * p, int memtype, int size);
|
||||
|
||||
int avr_write_bank(int fd, AVRPART * p, int memtype,
|
||||
unsigned short bank);
|
||||
|
||||
int avr_write_byte(int fd, AVRPART * p, int memtype,
|
||||
int avr_write_byte(int fd, AVRPART * p, AVRMEM * mem,
|
||||
unsigned long addr, unsigned char data);
|
||||
|
||||
int avr_write(int fd, AVRPART * p, int memtype, int size);
|
||||
int avr_write(int fd, AVRPART * p, char * memtype, int size, int verbose);
|
||||
|
||||
int avr_program_enable(int fd);
|
||||
int avr_program_enable(int fd, AVRPART * p);
|
||||
|
||||
int avr_chip_erase(int fd, AVRPART * p);
|
||||
|
||||
int avr_signature(int fd, unsigned char sig[4]);
|
||||
int avr_signature(int fd, AVRPART * p);
|
||||
|
||||
void avr_powerup(int fd);
|
||||
|
||||
|
@ -127,8 +156,7 @@ char * avr_memtstr(int memtype);
|
|||
|
||||
int avr_initmem(AVRPART * p);
|
||||
|
||||
int avr_verify(AVRPART * p, AVRPART * v, int memtype,
|
||||
int size);
|
||||
int avr_verify(AVRPART * p, AVRPART * v, char * memtype, int size);
|
||||
|
||||
void avr_display(FILE * f, AVRPART * p, char * prefix);
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ programmer
|
|||
vfyled = 17;
|
||||
;
|
||||
|
||||
|
||||
/*
|
||||
part
|
||||
id = "1200";
|
||||
desc = "AT90S1200";
|
||||
|
@ -335,22 +335,40 @@ part
|
|||
readback_p2 = 0xff;
|
||||
;
|
||||
;
|
||||
*/
|
||||
|
||||
part
|
||||
id = "m163";
|
||||
desc = "ATMEGA163";
|
||||
pgm_enable = "1", "0", "1", "0", "1", "1", "0", "0",
|
||||
"0", "1", "0", "1", "0", "0", "1", "1",
|
||||
"x", "x", "x", "x", "x", "x", "x", "x",
|
||||
"x", "x", "x", "x", "x", "x", "x", "x";
|
||||
|
||||
chip_erase = "1", "0", "1", "0", "1", "1", "0", "0",
|
||||
"1", "0", "0", "0", "0", "0", "0", "0",
|
||||
"x", "x", "x", "x", "x", "x", "x", "x",
|
||||
"x", "x", "x", "x", "x", "x", "x", "x";
|
||||
|
||||
chip_erase_delay = 32000;
|
||||
eeprom
|
||||
paged = no;
|
||||
memory "eeprom"
|
||||
size = 512;
|
||||
page_size = 0;
|
||||
num_pages = 0;
|
||||
min_write_delay = 4000;
|
||||
max_write_delay = 4000;
|
||||
readback_p1 = 0xff;
|
||||
readback_p2 = 0xff;
|
||||
|
||||
read = "1", "0", "1", "0", "0", "0", "0", "0",
|
||||
"x", "x", "x", "x", "x", "x", "x", "a8",
|
||||
"a7", "a6", "a5", "a4", "a3", "a2", "a1", "a0",
|
||||
"o", "o", "o", "o", "o", "o", "o", "o";
|
||||
|
||||
write = "1", "1", "0", "0", "0", "0", "0", "0",
|
||||
"x", "x", "x", "x", "x", "x", "x", "a8",
|
||||
"a7", "a6", "a5", "a4", "a3", "a2", "a1", "a0",
|
||||
"i", "i", "i", "i", "i", "i", "i", "i";
|
||||
;
|
||||
flash
|
||||
memory "flash"
|
||||
paged = yes;
|
||||
size = 16384;
|
||||
page_size = 128;
|
||||
|
@ -359,7 +377,93 @@ part
|
|||
max_write_delay = 16000;
|
||||
readback_p1 = 0xff;
|
||||
readback_p2 = 0xff;
|
||||
|
||||
read_lo = "0", "0", "1", "0", "0", "0", "0", "0",
|
||||
"x", "x", "x", "a12", "a11", "a10", "a9", "a8",
|
||||
"a7", "a6", "a5", "a4", "a3", "a2", "a1", "a0",
|
||||
"o", "o", "o", "o", "o", "o", "o", "o";
|
||||
|
||||
read_hi = "0", "0", "1", "0", "1", "0", "0", "0",
|
||||
"x", "x", "x", "a12", "a11", "a10", "a9", "a8",
|
||||
"a7", "a6", "a5", "a4", "a3", "a2", "a1", "a0",
|
||||
"o", "o", "o", "o", "o", "o", "o", "o";
|
||||
|
||||
loadpage_lo = "0", "1", "0", "0", "0", "0", "0", "0",
|
||||
"x", "x", "x", "x", "x", "x", "x", "x",
|
||||
"x", "x", "a5", "a4", "a3", "a2", "a1", "a0",
|
||||
"i", "i", "i", "i", "i", "i", "i", "i";
|
||||
|
||||
loadpage_hi = "0", "1", "0", "0", "1", "0", "0", "0",
|
||||
"x", "x", "x", "x", "x", "x", "x", "x",
|
||||
"x", "x", "a5", "a4", "a3", "a2", "a1", "a0",
|
||||
"i", "i", "i", "i", "i", "i", "i", "i";
|
||||
|
||||
writepage = "0", "1", "0", "0", "1", "1", "0", "0",
|
||||
"x", "x", "x", "a12", "a11", "a10", "a9", "a8",
|
||||
"a7", "a6", "x", "x", "x", "x", "x", "x",
|
||||
"x", "x", "x", "x", "x", "x", "x", "x";
|
||||
;
|
||||
memory "lfuse"
|
||||
size = 1;
|
||||
min_write_delay = 2000;
|
||||
max_write_delay = 2000;
|
||||
|
||||
read = "0", "1", "0", "1", "0", "0", "0", "0",
|
||||
"0", "0", "0", "0", "0", "0", "0", "0",
|
||||
"x", "x", "x", "x", "x", "x", "x", "x",
|
||||
"o", "o", "x", "x", "o", "o", "o", "o";
|
||||
|
||||
write = "1", "0", "1", "0", "1", "1", "0", "0",
|
||||
"1", "0", "1", "0", "0", "0", "0", "0",
|
||||
"x", "x", "x", "x", "x", "x", "x", "x",
|
||||
"i", "i", "1", "1", "i", "i", "i", "i";
|
||||
;
|
||||
memory "hfuse"
|
||||
size = 1;
|
||||
min_write_delay = 2000;
|
||||
max_write_delay = 2000;
|
||||
|
||||
read = "0", "1", "0", "1", "1", "0", "0", "0",
|
||||
"0", "0", "0", "0", "1", "0", "0", "0",
|
||||
"x", "x", "x", "x", "x", "x", "x", "x",
|
||||
"x", "x", "x", "x", "1", "o", "o", "o";
|
||||
|
||||
write = "1", "0", "1", "0", "1", "1", "0", "0",
|
||||
"1", "0", "1", "0", "1", "0", "0", "0",
|
||||
"x", "x", "x", "x", "x", "x", "x", "x",
|
||||
"1", "1", "1", "1", "1", "i", "i", "i";
|
||||
;
|
||||
memory "lock"
|
||||
size = 1;
|
||||
min_write_delay = 2000;
|
||||
max_write_delay = 2000;
|
||||
|
||||
read = "0", "1", "0", "1", "1", "0", "0", "0",
|
||||
"0", "0", "0", "0", "0", "0", "0", "0",
|
||||
"x", "x", "x", "x", "0", "x", "x", "x",
|
||||
"x", "x", "o", "o", "o", "o", "o", "o";
|
||||
|
||||
write = "1", "0", "1", "0", "1", "1", "0", "0",
|
||||
"1", "1", "1", "x", "x", "x", "x", "x",
|
||||
"x", "x", "x", "x", "x", "x", "x", "x",
|
||||
"1", "1", "i", "i", "i", "i", "i", "i";
|
||||
;
|
||||
memory "signature"
|
||||
size = 3;
|
||||
|
||||
read = "0", "0", "1", "1", "0", "0", "0", "0",
|
||||
"x", "x", "x", "x", "x", "x", "x", "x",
|
||||
"x", "x", "x", "x", "x", "x", "a1", "a0",
|
||||
"o", "o", "o", "o", "o", "o", "o", "o";
|
||||
;
|
||||
memory "calibration"
|
||||
size = 1;
|
||||
read = "0", "0", "1", "1", "1", "0", "0", "0",
|
||||
"x", "x", "x", "x", "x", "x", "x", "x",
|
||||
"0", "0", "0", "0", "0", "0", "0", "0",
|
||||
"o", "o", "o", "o", "o", "o", "o", "o";
|
||||
;
|
||||
|
||||
/*
|
||||
instructions
|
||||
instr "pe", "programming enable" [ "1010 1100", "0101 0011", "xxxx xxxx", "xxxx xxxx" ];
|
||||
|
@ -381,6 +485,7 @@ part
|
|||
*/
|
||||
;
|
||||
|
||||
/*
|
||||
part
|
||||
id = "m8";
|
||||
desc = "ATMEGA8";
|
||||
|
@ -407,3 +512,4 @@ part
|
|||
;
|
||||
;
|
||||
|
||||
*/
|
2
config.c
2
config.c
|
@ -45,7 +45,7 @@ LISTID string_list;
|
|||
LISTID number_list;
|
||||
PROGRAMMER * current_prog;
|
||||
AVRPART * current_part;
|
||||
int current_mem;
|
||||
AVRMEM * current_mem;
|
||||
LISTID part_list;
|
||||
LISTID programmers;
|
||||
|
||||
|
|
2
config.h
2
config.h
|
@ -63,7 +63,7 @@ typedef struct programmer_t {
|
|||
extern FILE * yyin;
|
||||
extern PROGRAMMER * current_prog;
|
||||
extern AVRPART * current_part;
|
||||
extern int current_mem;
|
||||
extern AVRMEM * current_mem;
|
||||
extern LISTID programmers;
|
||||
extern LISTID part_list;
|
||||
extern int lineno;
|
||||
|
|
265
config_gram.y
265
config_gram.y
|
@ -29,8 +29,23 @@
|
|||
|
||||
/* $Id$ */
|
||||
|
||||
%token K_OP
|
||||
%token K_READ
|
||||
%token K_WRITE
|
||||
%token K_READ_LO
|
||||
%token K_READ_HI
|
||||
%token K_WRITE_LO
|
||||
%token K_WRITE_HI
|
||||
%token K_LOADPAGE_LO
|
||||
%token K_LOADPAGE_HI
|
||||
%token K_WRITEPAGE
|
||||
%token K_CHIP_ERASE
|
||||
%token K_PGM_ENABLE
|
||||
|
||||
%token K_MEMORY
|
||||
|
||||
%token K_PAGE_SIZE
|
||||
%token K_PAGEED
|
||||
%token K_PAGED
|
||||
%token K_BUFF
|
||||
%token K_CHIP_ERASE_DELAY
|
||||
%token K_DESC
|
||||
|
@ -107,7 +122,8 @@ part_def :
|
|||
{ current_part = avr_new_part(); }
|
||||
part_parms
|
||||
{
|
||||
unsigned int i, j, shift, psize;
|
||||
LNODEID ln;
|
||||
AVRMEM * m;
|
||||
|
||||
if (current_part->id[0] == 0) {
|
||||
fprintf(stderr,
|
||||
|
@ -121,49 +137,35 @@ part_def :
|
|||
* to shift a page for constructing the page address for
|
||||
* page-addressed memories.
|
||||
*/
|
||||
for (i=0; i<AVR_MAXMEMTYPES; i++) {
|
||||
if (current_part->mem[i].paged) {
|
||||
if (!current_part->mem[i].page_size) {
|
||||
for (ln=lfirst(current_part->mem); ln; ln=lnext(ln)) {
|
||||
m = ldata(ln);
|
||||
if (m->paged) {
|
||||
if (m->page_size == 0) {
|
||||
fprintf(stderr,
|
||||
"%s: error at %s:%d: must specify page_size for paged "
|
||||
"memory\n",
|
||||
progname, infile, lineno);
|
||||
exit(1);
|
||||
}
|
||||
if (!current_part->mem[i].num_pages) {
|
||||
if (m->num_pages == 0) {
|
||||
fprintf(stderr,
|
||||
"%s: error at %s:%d: must specify num_pages for paged "
|
||||
"memory\n",
|
||||
progname, infile, lineno);
|
||||
exit(1);
|
||||
}
|
||||
if (current_part->mem[i].size != current_part->mem[i].page_size *
|
||||
current_part->mem[i].num_pages) {
|
||||
if (m->size != m->page_size * m->num_pages) {
|
||||
fprintf(stderr,
|
||||
"%s: error at %s:%d: page size (%u) * num_pages (%u) = "
|
||||
"%u does not match memory size (%u)\n",
|
||||
progname, infile, lineno,
|
||||
current_part->mem[i].page_size,
|
||||
current_part->mem[i].num_pages,
|
||||
current_part->mem[i].page_size * current_part->mem[i].num_pages,
|
||||
current_part->mem[i].size);
|
||||
m->page_size,
|
||||
m->num_pages,
|
||||
m->page_size * m->num_pages,
|
||||
m->size);
|
||||
exit(1);
|
||||
}
|
||||
shift = 0;
|
||||
psize = current_part->mem[i].page_size / 2 - 1;
|
||||
for (j=0; j<32 && !shift; j++) {
|
||||
if ((psize >> j) == 0) {
|
||||
shift = j;
|
||||
}
|
||||
}
|
||||
if (!shift) {
|
||||
fprintf(stderr,
|
||||
"%s: error at %s:%d: can't determine amount to shift for the page address\n"
|
||||
" Are you sure page_size (=%u) is correct?\n",
|
||||
progname, infile, lineno, current_part->mem[i].page_size);
|
||||
exit(1);
|
||||
}
|
||||
current_part->mem[i].pageaddr_shift = shift;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -246,6 +248,21 @@ prog_parm :
|
|||
;
|
||||
|
||||
|
||||
opcode :
|
||||
K_READ |
|
||||
K_WRITE |
|
||||
K_READ_LO |
|
||||
K_READ_HI |
|
||||
K_WRITE_LO |
|
||||
K_WRITE_HI |
|
||||
K_LOADPAGE_LO |
|
||||
K_LOADPAGE_HI |
|
||||
K_WRITEPAGE |
|
||||
K_CHIP_ERASE |
|
||||
K_PGM_ENABLE
|
||||
;
|
||||
|
||||
|
||||
part_parms :
|
||||
part_parm TKN_SEMI |
|
||||
part_parms part_parm TKN_SEMI
|
||||
|
@ -273,11 +290,46 @@ part_parm :
|
|||
free_token($3);
|
||||
} |
|
||||
|
||||
/*
|
||||
K_EEPROM { current_mem = AVR_M_EEPROM; }
|
||||
mem_specs |
|
||||
|
||||
K_FLASH { current_mem = AVR_M_FLASH; }
|
||||
mem_specs
|
||||
mem_specs |
|
||||
*/
|
||||
|
||||
K_MEMORY TKN_STRING
|
||||
{
|
||||
current_mem = avr_new_memtype();
|
||||
strcpy(current_mem->desc, strdup($2->value.string));
|
||||
free_token($2);
|
||||
}
|
||||
mem_specs
|
||||
{
|
||||
ladd(current_part->mem, current_mem);
|
||||
current_mem = NULL;
|
||||
} |
|
||||
|
||||
opcode TKN_EQUAL string_list {
|
||||
{
|
||||
int opnum;
|
||||
OPCODE * op;
|
||||
|
||||
if (lsize(string_list) != 32) {
|
||||
fprintf(stderr,
|
||||
"%s: error at %s:%d: only %d bits specified, need 32\n",
|
||||
progname, infile, lineno, lsize(string_list));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
opnum = which_opcode($1);
|
||||
op = avr_new_opcode();
|
||||
parse_cmdbits(op);
|
||||
current_part->op[opnum] = op;
|
||||
|
||||
free_token($1);
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
|
@ -295,52 +347,73 @@ mem_specs :
|
|||
mem_spec :
|
||||
K_PAGED TKN_EQUAL yesno
|
||||
{
|
||||
current_part->mem[current_mem].paged = $3->primary == K_YES ? 1 : 0;
|
||||
current_mem->paged = $3->primary == K_YES ? 1 : 0;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_SIZE TKN_EQUAL TKN_NUMBER
|
||||
{
|
||||
current_part->mem[current_mem].size = $3->value.number;
|
||||
current_mem->size = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
|
||||
K_PAGE_SIZE TKN_EQUAL TKN_NUMBER
|
||||
{
|
||||
current_part->mem[current_mem].page_size = $3->value.number;
|
||||
current_mem->page_size = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_NUM_PAGES TKN_EQUAL TKN_NUMBER
|
||||
{
|
||||
current_part->mem[current_mem].num_pages = $3->value.number;
|
||||
current_mem->num_pages = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_MIN_WRITE_DELAY TKN_EQUAL TKN_NUMBER
|
||||
{
|
||||
current_part->mem[current_mem].min_write_delay = $3->value.number;
|
||||
current_mem->min_write_delay = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_MAX_WRITE_DELAY TKN_EQUAL TKN_NUMBER
|
||||
{
|
||||
current_part->mem[current_mem].max_write_delay = $3->value.number;
|
||||
current_mem->max_write_delay = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_READBACK_P1 TKN_EQUAL TKN_NUMBER
|
||||
{
|
||||
current_part->mem[current_mem].readback[0] = $3->value.number;
|
||||
current_mem->readback[0] = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_READBACK_P2 TKN_EQUAL TKN_NUMBER
|
||||
{
|
||||
current_part->mem[current_mem].readback[1] = $3->value.number;
|
||||
current_mem->readback[1] = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
opcode TKN_EQUAL string_list {
|
||||
{
|
||||
int opnum;
|
||||
OPCODE * op;
|
||||
|
||||
if (lsize(string_list) != 32) {
|
||||
fprintf(stderr,
|
||||
"%s: error at %s:%d: only %d bits specified, need 32\n",
|
||||
progname, infile, lineno, lsize(string_list));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
opnum = which_opcode($1);
|
||||
op = avr_new_opcode();
|
||||
parse_cmdbits(op);
|
||||
current_mem->op[opnum] = op;
|
||||
|
||||
free_token($1);
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
|
@ -392,3 +465,123 @@ static int assign_pin(int pinno, TOKEN * v)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int which_opcode(TOKEN * opcode)
|
||||
{
|
||||
switch (opcode->primary) {
|
||||
case K_READ : return AVR_OP_READ; break;
|
||||
case K_WRITE : return AVR_OP_WRITE; break;
|
||||
case K_READ_LO : return AVR_OP_READ_LO; break;
|
||||
case K_READ_HI : return AVR_OP_READ_HI; break;
|
||||
case K_WRITE_LO : return AVR_OP_WRITE_LO; break;
|
||||
case K_WRITE_HI : return AVR_OP_WRITE_HI; break;
|
||||
case K_LOADPAGE_LO : return AVR_OP_LOADPAGE_LO; break;
|
||||
case K_LOADPAGE_HI : return AVR_OP_LOADPAGE_HI; break;
|
||||
case K_WRITEPAGE : return AVR_OP_WRITEPAGE; break;
|
||||
case K_CHIP_ERASE : return AVR_OP_CHIP_ERASE; break;
|
||||
case K_PGM_ENABLE : return AVR_OP_PGM_ENABLE; break;
|
||||
default :
|
||||
fprintf(stderr,
|
||||
"%s: error at %s:%d: invalid opcode\n",
|
||||
progname, infile, lineno);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int parse_cmdbits(OPCODE * op)
|
||||
{
|
||||
TOKEN * t;
|
||||
int bitno;
|
||||
char ch;
|
||||
char * e;
|
||||
char * q;
|
||||
int len;
|
||||
|
||||
bitno = 31;
|
||||
while (lsize(string_list)) {
|
||||
|
||||
t = lrmv_n(string_list, 1);
|
||||
|
||||
len = strlen(t->value.string);
|
||||
|
||||
if (len == 0) {
|
||||
fprintf(stderr,
|
||||
"%s: error at %s:%d: invalid bit specifier \"\"\n",
|
||||
progname, infile, lineno);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ch = t->value.string[0];
|
||||
|
||||
if (len == 1) {
|
||||
switch (ch) {
|
||||
case '1':
|
||||
op->bit[bitno].type = AVR_CMDBIT_VALUE;
|
||||
op->bit[bitno].value = 1;
|
||||
op->bit[bitno].bitno = bitno % 8;
|
||||
break;
|
||||
case '0':
|
||||
op->bit[bitno].type = AVR_CMDBIT_VALUE;
|
||||
op->bit[bitno].value = 0;
|
||||
op->bit[bitno].bitno = bitno % 8;
|
||||
break;
|
||||
case 'x':
|
||||
op->bit[bitno].type = AVR_CMDBIT_IGNORE;
|
||||
op->bit[bitno].value = 0;
|
||||
op->bit[bitno].bitno = bitno % 8;
|
||||
break;
|
||||
case 'a':
|
||||
op->bit[bitno].type = AVR_CMDBIT_ADDRESS;
|
||||
op->bit[bitno].value = 0;
|
||||
op->bit[bitno].bitno = 8*(bitno/8) + bitno % 8;
|
||||
break;
|
||||
case 'i':
|
||||
op->bit[bitno].type = AVR_CMDBIT_INPUT;
|
||||
op->bit[bitno].value = 0;
|
||||
op->bit[bitno].bitno = bitno % 8;
|
||||
break;
|
||||
case 'o':
|
||||
op->bit[bitno].type = AVR_CMDBIT_OUTPUT;
|
||||
op->bit[bitno].value = 0;
|
||||
op->bit[bitno].bitno = bitno % 8;
|
||||
break;
|
||||
default :
|
||||
fprintf(stderr,
|
||||
"%s: error at %s:%d: invalid bit specifier '%c'\n",
|
||||
progname, infile, lineno, ch);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (ch == 'a') {
|
||||
q = &t->value.string[1];
|
||||
op->bit[bitno].bitno = strtol(q, &e, 0);
|
||||
if ((e == q)||(*e != 0)) {
|
||||
fprintf(stderr,
|
||||
"%s: error at %s:%d: can't parse bit number from \"%s\"\n",
|
||||
progname, infile, lineno, q);
|
||||
exit(1);
|
||||
}
|
||||
op->bit[bitno].type = AVR_CMDBIT_ADDRESS;
|
||||
op->bit[bitno].value = 0;
|
||||
}
|
||||
else {
|
||||
fprintf(stderr,
|
||||
"%s: error at %s:%d: invalid bit specifier \"%s\"\n",
|
||||
progname, infile, lineno, t->value.string);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
free_token(t);
|
||||
bitno--;
|
||||
|
||||
} /* while */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
15
fileio.c
15
fileio.c
|
@ -520,7 +520,7 @@ int fmt_autodetect(char * fname)
|
|||
|
||||
|
||||
int fileio(int op, char * filename, FILEFMT format,
|
||||
struct avrpart * p, int memtype, int size)
|
||||
struct avrpart * p, char * memtype, int size)
|
||||
{
|
||||
int rc;
|
||||
FILE * f;
|
||||
|
@ -528,6 +528,15 @@ int fileio(int op, char * filename, FILEFMT format,
|
|||
unsigned char * buf;
|
||||
struct fioparms fio;
|
||||
int i;
|
||||
AVRMEM * mem;
|
||||
|
||||
mem = avr_locate_mem(p, memtype);
|
||||
if (mem == NULL) {
|
||||
fprintf(stderr,
|
||||
"fileio(): memory type \"%s\" not configured for device \"%s\"\n",
|
||||
memtype, p->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = fileio_setparms(op, &fio);
|
||||
if (rc < 0)
|
||||
|
@ -554,9 +563,9 @@ int fileio(int op, char * filename, FILEFMT format,
|
|||
}
|
||||
|
||||
/* point at the requested memory buffer */
|
||||
buf = p->mem[memtype].buf;
|
||||
buf = mem->buf;
|
||||
if (fio.op == FIO_READ)
|
||||
size = p->mem[memtype].size;
|
||||
size = mem->size;
|
||||
|
||||
if (fio.op == FIO_READ) {
|
||||
/* 0xff fill unspecified memory */
|
||||
|
|
2
fileio.h
2
fileio.h
|
@ -57,6 +57,6 @@ char * fmtstr(FILEFMT format);
|
|||
int fileio_setparms(int op, struct fioparms * fp);
|
||||
|
||||
int fileio(int op, char * filename, FILEFMT format,
|
||||
struct avrpart * p, int memtype, int size);
|
||||
struct avrpart * p, char * memtype, int size);
|
||||
|
||||
#endif
|
||||
|
|
15
lexer.l
15
lexer.l
|
@ -152,6 +152,21 @@ size { yylval=NULL; return K_SIZE; }
|
|||
vcc { yylval=NULL; return K_VCC; }
|
||||
vfyled { yylval=NULL; return K_VFYLED; }
|
||||
|
||||
op { yylval=NULL; return K_OP; }
|
||||
read { yylval=new_token(K_READ); return K_READ; }
|
||||
write { yylval=new_token(K_WRITE); return K_WRITE; }
|
||||
read_lo { yylval=new_token(K_READ_LO); return K_READ_LO; }
|
||||
read_hi { yylval=new_token(K_READ_HI); return K_READ_HI; }
|
||||
write_lo { yylval=new_token(K_WRITE_LO); return K_WRITE_LO; }
|
||||
write_hi { yylval=new_token(K_WRITE_HI); return K_WRITE_HI; }
|
||||
loadpage_lo { yylval=new_token(K_LOADPAGE_LO); return K_LOADPAGE_LO; }
|
||||
loadpage_hi { yylval=new_token(K_LOADPAGE_HI); return K_LOADPAGE_HI; }
|
||||
writepage { yylval=new_token(K_WRITEPAGE); return K_WRITEPAGE; }
|
||||
chip_erase { yylval=new_token(K_CHIP_ERASE); return K_CHIP_ERASE; }
|
||||
pgm_enable { yylval=new_token(K_PGM_ENABLE); return K_PGM_ENABLE; }
|
||||
|
||||
memory { yylval=NULL; return K_MEMORY; }
|
||||
|
||||
no { yylval=new_token(K_NO); return K_NO; }
|
||||
yes { yylval=new_token(K_YES); return K_YES; }
|
||||
|
||||
|
|
90
main.c
90
main.c
|
@ -450,17 +450,16 @@ int main(int argc, char * argv [])
|
|||
int ch; /* options flag */
|
||||
int size; /* size of memory region */
|
||||
int len; /* length for various strings */
|
||||
unsigned char sig[4]; /* AVR signature bytes */
|
||||
unsigned char nulldev[4]; /* 0xff signature bytes for comparison */
|
||||
struct avrpart * p; /* which avr part we are programming */
|
||||
struct avrpart * v; /* used for verify */
|
||||
int readorwrite; /* true if a chip read/write op was selected */
|
||||
int ppidata; /* cached value of the ppi data register */
|
||||
int vsize=-1; /* number of bytes to verify */
|
||||
char timestamp[64];
|
||||
AVRMEM * sig; /* signature data */
|
||||
|
||||
/* options / operating mode variables */
|
||||
int memtype; /* AVR_FLASH or AVR_EEPROM */
|
||||
char * memtype; /* "flash", "eeprom", etc */
|
||||
int doread; /* 1=reading AVR, 0=writing AVR */
|
||||
int erase; /* 1=erase chip, 0=don't */
|
||||
char * outputf; /* output file name */
|
||||
|
@ -493,7 +492,7 @@ int main(int argc, char * argv [])
|
|||
outputf = NULL;
|
||||
inputf = NULL;
|
||||
doread = 1;
|
||||
memtype = AVR_M_FLASH;
|
||||
memtype = "flash";
|
||||
erase = 0;
|
||||
p = NULL;
|
||||
ovsigck = 0;
|
||||
|
@ -567,17 +566,14 @@ int main(int argc, char * argv [])
|
|||
|
||||
case 'm': /* select memory type to operate on */
|
||||
if ((strcasecmp(optarg,"e")==0)||(strcasecmp(optarg,"eeprom")==0)) {
|
||||
memtype = AVR_M_EEPROM;
|
||||
memtype = "eeprom";
|
||||
}
|
||||
else if ((strcasecmp(optarg,"f")==0)||
|
||||
(strcasecmp(optarg,"flash")==0)) {
|
||||
memtype = AVR_M_FLASH;
|
||||
memtype = "flash";
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "%s: invalid memory type \"%s\"\n\n",
|
||||
progname, optarg);
|
||||
usage();
|
||||
exit(1);
|
||||
memtype = optarg;
|
||||
}
|
||||
readorwrite = 1;
|
||||
break;
|
||||
|
@ -833,23 +829,43 @@ int main(int argc, char * argv [])
|
|||
* against 0xffffffff should ensure that the signature bytes are
|
||||
* valid.
|
||||
*/
|
||||
avr_signature(fd, sig);
|
||||
fprintf(stderr, "%s: Device signature = 0x", progname);
|
||||
for (i=0; i<4; i++)
|
||||
fprintf(stderr, "%02x", sig[i]);
|
||||
fprintf(stderr, "\n");
|
||||
rc = avr_signature(fd, p);
|
||||
if (rc != 0) {
|
||||
fprintf(stderr, "%s: error reading signature data, rc=%d\n",
|
||||
progname, rc);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(nulldev,0xff,4);
|
||||
if (memcmp(sig,nulldev,4)==0) {
|
||||
fprintf(stderr,
|
||||
"%s: Yikes! Invalid device signature.\n", progname);
|
||||
if (!ovsigck) {
|
||||
fprintf(stderr, "%sDouble check connections and try again, "
|
||||
"or use -F to override\n"
|
||||
"%sthis check.\n\n",
|
||||
progbuf, progbuf);
|
||||
exitrc = 1;
|
||||
goto main_exit;
|
||||
sig = avr_locate_mem(p, "signature");
|
||||
if (sig == NULL) {
|
||||
fprintf(stderr,
|
||||
"%s: WARNING: signature data not defined for device \"%s\"\n",
|
||||
progname, p->desc);
|
||||
}
|
||||
|
||||
if (sig != NULL) {
|
||||
int ff;
|
||||
|
||||
fprintf(stderr, "%s: Device signature = 0x", progname);
|
||||
ff = 1;
|
||||
for (i=0; i<sig->size; i++) {
|
||||
fprintf(stderr, "%02x", sig->buf[i]);
|
||||
if (sig->buf[i] != 0xff)
|
||||
ff = 0;
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
if (ff) {
|
||||
fprintf(stderr,
|
||||
"%s: Yikes! Invalid device signature.\n", progname);
|
||||
if (!ovsigck) {
|
||||
fprintf(stderr, "%sDouble check connections and try again, "
|
||||
"or use -F to override\n"
|
||||
"%sthis check.\n\n",
|
||||
progbuf, progbuf);
|
||||
exitrc = 1;
|
||||
goto main_exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -892,11 +908,11 @@ int main(int argc, char * argv [])
|
|||
* read out the specified device memory and write it to a file
|
||||
*/
|
||||
fprintf(stderr, "%s: reading %s memory:\n",
|
||||
progname, avr_memtstr(memtype));
|
||||
rc = avr_read(fd, p, memtype, 0);
|
||||
progname, memtype);
|
||||
rc = avr_read(fd, p, memtype, 0, 1);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "%s: failed to read all of %s memory, rc=%d\n",
|
||||
progname, avr_memtstr(memtype), rc);
|
||||
progname, memtype, rc);
|
||||
exitrc = 1;
|
||||
goto main_exit;
|
||||
}
|
||||
|
@ -931,10 +947,10 @@ int main(int argc, char * argv [])
|
|||
* write the buffer contents to the selected memory type
|
||||
*/
|
||||
fprintf(stderr, "%s: writing %s:\n",
|
||||
progname, avr_memtstr(memtype));
|
||||
progname, memtype);
|
||||
|
||||
if (!nowrite) {
|
||||
rc = avr_write(fd, p, memtype, size);
|
||||
rc = avr_write(fd, p, memtype, size, 1);
|
||||
}
|
||||
else {
|
||||
/*
|
||||
|
@ -954,7 +970,7 @@ int main(int argc, char * argv [])
|
|||
vsize = rc;
|
||||
|
||||
fprintf(stderr, "%s: %d bytes of %s written\n", progname,
|
||||
vsize, avr_memtstr(memtype));
|
||||
vsize, memtype);
|
||||
|
||||
}
|
||||
|
||||
|
@ -966,13 +982,13 @@ int main(int argc, char * argv [])
|
|||
LED_ON(fd, pgm->pinno[PIN_LED_VFY]);
|
||||
|
||||
fprintf(stderr, "%s: verifying %s memory against %s:\n",
|
||||
progname, avr_memtstr(memtype), inputf);
|
||||
progname, memtype, inputf);
|
||||
fprintf(stderr, "%s: reading on-chip %s data:\n",
|
||||
progname, avr_memtstr(memtype));
|
||||
rc = avr_read(fd, v, memtype, vsize);
|
||||
progname, memtype);
|
||||
rc = avr_read(fd, v, memtype, vsize, 1);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "%s: failed to read all of %s memory, rc=%d\n",
|
||||
progname, avr_memtstr(memtype), rc);
|
||||
progname, memtype, rc);
|
||||
LED_ON(fd, pgm->pinno[PIN_LED_ERR]);
|
||||
exitrc = 1;
|
||||
goto main_exit;
|
||||
|
@ -989,7 +1005,7 @@ int main(int argc, char * argv [])
|
|||
}
|
||||
|
||||
fprintf(stderr, "%s: %d bytes of %s verified\n",
|
||||
progname, rc, avr_memtstr(memtype));
|
||||
progname, rc, memtype);
|
||||
|
||||
LED_OFF(fd, pgm->pinno[PIN_LED_VFY]);
|
||||
}
|
||||
|
|
239
term.c
239
term.c
|
@ -38,6 +38,7 @@
|
|||
|
||||
#include "avr.h"
|
||||
#include "config.h"
|
||||
#include "lists.h"
|
||||
#include "pindefs.h"
|
||||
#include "ppi.h"
|
||||
|
||||
|
@ -64,8 +65,6 @@ int cmd_erase (int fd, struct avrpart * p, int argc, char *argv[]);
|
|||
|
||||
int cmd_sig (int fd, struct avrpart * p, int argc, char *argv[]);
|
||||
|
||||
int cmd_cal (int fd, struct avrpart * p, int argc, char *argv[]);
|
||||
|
||||
int cmd_part (int fd, struct avrpart * p, int argc, char *argv[]);
|
||||
|
||||
int cmd_help (int fd, struct avrpart * p, int argc, char *argv[]);
|
||||
|
@ -76,14 +75,13 @@ int cmd_send (int fd, struct avrpart * p, int argc, char *argv[]);
|
|||
|
||||
|
||||
struct command cmd[] = {
|
||||
{ "dump", cmd_dump, "dump memory : %s [eeprom|flash] <addr> <N-Bytes>" },
|
||||
{ "dump", cmd_dump, "dump memory : %s <memtype> <addr> <N-Bytes>" },
|
||||
{ "read", cmd_dump, "alias for dump" },
|
||||
{ "write", cmd_write, "write memory : %s [eeprom|flash] <addr> <b1> <b2> ... <bN>" },
|
||||
{ "write", cmd_write, "write memory : %s <memtype> <addr> <b1> <b2> ... <bN>" },
|
||||
{ "erase", cmd_erase, "perform a chip erase" },
|
||||
{ "sig", cmd_sig, "display device signature bytes" },
|
||||
{ "cal", cmd_cal, "display device calibration byte" },
|
||||
{ "part", cmd_part, "display the current part settings" },
|
||||
{ "send", cmd_send, "send a command : %s <b1> <b2> <b3> <b4>" },
|
||||
{ "part", cmd_part, "display the current part information" },
|
||||
{ "send", cmd_send, "send a raw command : %s <b1> <b2> <b3> <b4>" },
|
||||
{ "help", cmd_help, "help" },
|
||||
{ "?", cmd_help, "help" },
|
||||
{ "quit", cmd_quit, "quit" }
|
||||
|
@ -179,7 +177,7 @@ int chardump_line(char * buffer, unsigned char * p, int n, int pad)
|
|||
}
|
||||
|
||||
|
||||
int hexdump_buf(FILE * f, int startaddr, char * buf, int len)
|
||||
int hexdump_buf(FILE * f, int startaddr, unsigned char * buf, int len)
|
||||
{
|
||||
int addr;
|
||||
int i, n;
|
||||
|
@ -209,84 +207,51 @@ int hexdump_buf(FILE * f, int startaddr, char * buf, int len)
|
|||
int cmd_dump(int fd, struct avrpart * p, int argc, char * argv[])
|
||||
{
|
||||
char * e;
|
||||
int i, l;
|
||||
char * buf;
|
||||
unsigned char * buf;
|
||||
int maxsize;
|
||||
static int memtype=AVR_M_FLASH;
|
||||
static unsigned short addr=0;
|
||||
unsigned long i;
|
||||
static unsigned long addr=0;
|
||||
static int len=64;
|
||||
AVRMEM * mem;
|
||||
char * memtype = NULL;
|
||||
int rc;
|
||||
|
||||
if (argc == 1) {
|
||||
addr += len;
|
||||
if (!((argc == 2) || (argc == 4))) {
|
||||
fprintf(stderr, "Usage: dump <memtype> [<addr> <len>]\n");
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
if (!((argc == 2) || (argc == 4))) {
|
||||
fprintf(stderr, "Usage: dump flash|eeprom|fuse|lock [<addr> <len>]\n");
|
||||
|
||||
memtype = argv[1];
|
||||
|
||||
mem = avr_locate_mem(p, memtype);
|
||||
if (mem == NULL) {
|
||||
fprintf(stderr, "\"%s\" memory type not defined for part \"%s\"\n",
|
||||
memtype, p->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (argc == 4) {
|
||||
addr = strtoul(argv[2], &e, 0);
|
||||
if (*e || (e == argv[2])) {
|
||||
fprintf(stderr, "%s (dump): can't parse address \"%s\"\n",
|
||||
progname, argv[2]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
l = strlen(argv[1]);
|
||||
if (strncasecmp(argv[1],"flash",l)==0) {
|
||||
memtype = AVR_M_FLASH;
|
||||
}
|
||||
else if (strncasecmp(argv[1],"eeprom",l)==0) {
|
||||
memtype = AVR_M_EEPROM;
|
||||
}
|
||||
else if ((strncasecmp(argv[1],"fuse",l)==0)||
|
||||
(strncasecmp(argv[1],"fuse-bit",l)==0)) {
|
||||
memtype = AVR_M_FUSE;
|
||||
}
|
||||
else if ((strncasecmp(argv[1],"lock",l)==0)||
|
||||
(strncasecmp(argv[1],"lock-bit",l)==0)) {
|
||||
memtype = AVR_M_LOCK;
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "%s (dump): invalid memory type \"%s\"\n",
|
||||
progname, argv[1]);
|
||||
len = strtol(argv[3], &e, 0);
|
||||
if (*e || (e == argv[3])) {
|
||||
fprintf(stderr, "%s (dump): can't parse length \"%s\"\n",
|
||||
progname, argv[3]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (argc == 4) {
|
||||
addr = strtoul(argv[2], &e, 0);
|
||||
if (*e || (e == argv[2])) {
|
||||
fprintf(stderr, "%s (dump): can't parse address \"%s\"\n",
|
||||
progname, argv[2]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = strtol(argv[3], &e, 0);
|
||||
if (*e || (e == argv[3])) {
|
||||
fprintf(stderr, "%s (dump): can't parse length \"%s\"\n",
|
||||
progname, argv[3]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
maxsize = 0;
|
||||
|
||||
switch (memtype) {
|
||||
case AVR_M_FLASH:
|
||||
case AVR_M_EEPROM:
|
||||
maxsize = p->mem[memtype].size;
|
||||
break;
|
||||
case AVR_M_FUSE:
|
||||
maxsize = 2;
|
||||
break;
|
||||
case AVR_M_LOCK:
|
||||
maxsize = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (argc == 2) {
|
||||
addr = 0;
|
||||
len = maxsize;
|
||||
}
|
||||
maxsize = mem->size;
|
||||
|
||||
if (addr > maxsize) {
|
||||
fprintf(stderr,
|
||||
"%s (dump): address 0x%04x is out of range for %s memory\n",
|
||||
progname, addr, avr_memtstr(memtype));
|
||||
"%s (dump): address 0x%05lx is out of range for %s memory\n",
|
||||
progname, addr, mem->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -301,17 +266,11 @@ int cmd_dump(int fd, struct avrpart * p, int argc, char * argv[])
|
|||
}
|
||||
|
||||
for (i=0; i<len; i++) {
|
||||
switch (memtype) {
|
||||
case AVR_M_FLASH:
|
||||
case AVR_M_EEPROM:
|
||||
buf[i] = avr_read_byte(fd, p, memtype, addr+i);
|
||||
break;
|
||||
case AVR_M_FUSE:
|
||||
buf[i] = avr_read_fuse(fd, p, addr+i);
|
||||
break;
|
||||
case AVR_M_LOCK:
|
||||
buf[i] = avr_read_lock(fd, p);
|
||||
break;
|
||||
rc = avr_read_byte(fd, p, mem, addr+i, &buf[i]);
|
||||
if (rc != 0) {
|
||||
fprintf(stderr, "error reading %s address 0x%05lx of part %s\n",
|
||||
mem->desc, addr+i, p->desc);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -321,6 +280,8 @@ int cmd_dump(int fd, struct avrpart * p, int argc, char * argv[])
|
|||
|
||||
free(buf);
|
||||
|
||||
addr = addr + len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -328,13 +289,13 @@ int cmd_dump(int fd, struct avrpart * p, int argc, char * argv[])
|
|||
int cmd_write(int fd, struct avrpart * p, int argc, char * argv[])
|
||||
{
|
||||
char * e;
|
||||
int i, l;
|
||||
int len, maxsize;
|
||||
int memtype;
|
||||
unsigned short addr;
|
||||
char * memtype;
|
||||
unsigned long addr, i;
|
||||
char * buf;
|
||||
int rc;
|
||||
int werror;
|
||||
AVRMEM * mem;
|
||||
|
||||
if (argc < 4) {
|
||||
fprintf(stderr, "Usage: write flash|eeprom|fuse <addr> <byte1> "
|
||||
|
@ -342,46 +303,16 @@ int cmd_write(int fd, struct avrpart * p, int argc, char * argv[])
|
|||
return -1;
|
||||
}
|
||||
|
||||
l = strlen(argv[1]);
|
||||
if (strncasecmp(argv[1],"flash",l)==0) {
|
||||
memtype = AVR_M_FLASH;
|
||||
}
|
||||
else if (strncasecmp(argv[1],"eeprom",l)==0) {
|
||||
memtype = AVR_M_EEPROM;
|
||||
}
|
||||
else if ((strncasecmp(argv[1],"fuse",l)==0)||
|
||||
(strncasecmp(argv[1],"fuse-bit",l)==0)) {
|
||||
memtype = AVR_M_FUSE;
|
||||
}
|
||||
else if ((strncasecmp(argv[1],"lock",l)==0)||
|
||||
(strncasecmp(argv[1],"lock-bit",l)==0)) {
|
||||
memtype = AVR_M_LOCK;
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "%s (write): invalid memory type \"%s\"\n",
|
||||
progname, argv[1]);
|
||||
memtype = argv[1];
|
||||
|
||||
mem = avr_locate_mem(p, memtype);
|
||||
if (mem == NULL) {
|
||||
fprintf(stderr, "\"%s\" memory type not defined for part \"%s\"\n",
|
||||
memtype, p->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
maxsize = 0;
|
||||
|
||||
switch (memtype) {
|
||||
case AVR_M_FLASH:
|
||||
case AVR_M_EEPROM:
|
||||
if (p->mem[memtype].paged) {
|
||||
fprintf(stderr, "%s (write): sorry, interactive write of page "
|
||||
"addressed memory is not supported\n", progname);
|
||||
return -1;
|
||||
}
|
||||
maxsize = p->mem[memtype].size;
|
||||
break;
|
||||
case AVR_M_FUSE:
|
||||
maxsize = 2;
|
||||
break;
|
||||
case AVR_M_LOCK:
|
||||
maxsize = 1;
|
||||
break;
|
||||
}
|
||||
maxsize = mem->size;
|
||||
|
||||
addr = strtoul(argv[2], &e, 0);
|
||||
if (*e || (e == argv[2])) {
|
||||
|
@ -392,8 +323,8 @@ int cmd_write(int fd, struct avrpart * p, int argc, char * argv[])
|
|||
|
||||
if (addr > maxsize) {
|
||||
fprintf(stderr,
|
||||
"%s (write): address 0x%04x is out of range for %s memory\n",
|
||||
progname, addr, avr_memtstr(memtype));
|
||||
"%s (write): address 0x%05lx is out of range for %s memory\n",
|
||||
progname, addr, memtype);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -404,7 +335,7 @@ int cmd_write(int fd, struct avrpart * p, int argc, char * argv[])
|
|||
fprintf(stderr,
|
||||
"%s (write): selected address and # bytes exceed "
|
||||
"range for %s memory\n",
|
||||
progname, avr_memtstr(memtype));
|
||||
progname, memtype);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -427,22 +358,9 @@ int cmd_write(int fd, struct avrpart * p, int argc, char * argv[])
|
|||
LED_OFF(fd, pgm->pinno[PIN_LED_ERR]);
|
||||
for (werror=0, i=0; i<len; i++) {
|
||||
|
||||
rc = 0;
|
||||
switch (memtype) {
|
||||
case AVR_M_EEPROM:
|
||||
case AVR_M_FLASH:
|
||||
rc = avr_write_byte(fd, p, memtype, addr+i, buf[i]);
|
||||
break;
|
||||
case AVR_M_FUSE:
|
||||
rc = avr_write_fuse(fd, p, addr+i, buf[i]);
|
||||
break;
|
||||
case AVR_M_LOCK:
|
||||
rc = avr_write_lock(fd, p, buf[i]);
|
||||
break;
|
||||
}
|
||||
|
||||
rc = avr_write_byte(fd, p, mem, addr+i, buf[i]);
|
||||
if (rc) {
|
||||
fprintf(stderr, "%s (write): error writing 0x%02x at 0x%04x\n",
|
||||
fprintf(stderr, "%s (write): error writing 0x%02x at 0x%05lx\n",
|
||||
progname, buf[i], addr+i);
|
||||
werror = 1;
|
||||
}
|
||||
|
@ -522,25 +440,28 @@ int cmd_part(int fd, struct avrpart * p, int argc, char * argv[])
|
|||
|
||||
int cmd_sig(int fd, struct avrpart * p, int argc, char * argv[])
|
||||
{
|
||||
unsigned char sig[4]; /* AVR signature bytes */
|
||||
int i;
|
||||
int rc;
|
||||
AVRMEM * m;
|
||||
|
||||
avr_signature(fd, sig);
|
||||
fprintf(stdout, "\nDevice signature = 0x");
|
||||
for (i=0; i<4; i++)
|
||||
fprintf(stdout, "%02x", sig[i]);
|
||||
fprintf(stdout, "\n\n");
|
||||
rc = avr_signature(fd, p);
|
||||
if (rc != 0) {
|
||||
fprintf(stderr, "error reading signature data, rc=%d\n",
|
||||
rc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int cmd_cal(int fd, struct avrpart * p, int argc, char * argv[])
|
||||
{
|
||||
unsigned char byte;
|
||||
|
||||
byte = avr_read_calibration(fd, p);
|
||||
fprintf(stdout, "\nDevice calibration = 0x%02x\n\n", byte);
|
||||
m = avr_locate_mem(p, "signature");
|
||||
if (m == NULL) {
|
||||
fprintf(stderr,
|
||||
"signature data not defined for device \"%s\"\n",
|
||||
p->desc);
|
||||
}
|
||||
else {
|
||||
fprintf(stdout, "Device signature = 0x", progname);
|
||||
for (i=0; i<m->size; i++)
|
||||
fprintf(stdout, "%02x", m->buf[i]);
|
||||
fprintf(stdout, "\n\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -562,7 +483,9 @@ int cmd_help(int fd, struct avrpart * p, int argc, char * argv[])
|
|||
fprintf(stdout, cmd[i].desc, cmd[i].name);
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
fprintf(stdout, "\n");
|
||||
fprintf(stdout,
|
||||
"\nUse the 'part' command to display valid memory types for use with the\n"
|
||||
"'dump' and 'write' commands.\n\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue