2003-11-30 16:42:10 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* avrdude - A Downloader/Uploader for AVR device programmers
|
2004-12-22 01:52:45 +00:00
|
|
|
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
|
2006-07-16 21:30:14 +00:00
|
|
|
* Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
|
2003-11-30 16:42:10 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
2012-11-20 14:03:50 +00:00
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2003-11-30 16:42:10 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* $Id$ */
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2007-01-24 21:07:54 +00:00
|
|
|
#include "avrdude.h"
|
2014-05-19 10:01:59 +00:00
|
|
|
#include "libavrdude.h"
|
2003-11-30 16:42:10 +00:00
|
|
|
|
|
|
|
/***
|
|
|
|
*** Elementary functions dealing with OPCODE structures
|
|
|
|
***/
|
|
|
|
|
|
|
|
OPCODE * avr_new_opcode(void)
|
|
|
|
{
|
|
|
|
OPCODE * m;
|
|
|
|
|
|
|
|
m = (OPCODE *)malloc(sizeof(*m));
|
|
|
|
if (m == NULL) {
|
2014-06-13 20:07:40 +00:00
|
|
|
avrdude_message(MSG_INFO, "avr_new_opcode(): out of memory\n");
|
2003-11-30 16:42:10 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(m, 0, sizeof(*m));
|
|
|
|
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
2011-12-29 16:51:44 +00:00
|
|
|
static OPCODE * avr_dup_opcode(OPCODE * op)
|
|
|
|
{
|
|
|
|
OPCODE * m;
|
|
|
|
|
|
|
|
/* this makes life easier */
|
|
|
|
if (op == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
m = (OPCODE *)malloc(sizeof(*m));
|
|
|
|
if (m == NULL) {
|
2014-06-13 20:07:40 +00:00
|
|
|
avrdude_message(MSG_INFO, "avr_dup_opcode(): out of memory\n");
|
2011-12-29 16:51:44 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(m, op, sizeof(*m));
|
|
|
|
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
2012-01-17 20:56:37 +00:00
|
|
|
void avr_free_opcode(OPCODE * op)
|
|
|
|
{
|
|
|
|
free(op);
|
|
|
|
}
|
2003-11-30 16:42:10 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* avr_set_bits()
|
|
|
|
*
|
|
|
|
* Set instruction bits in the specified command based on the opcode.
|
|
|
|
*/
|
|
|
|
int avr_set_bits(OPCODE * op, unsigned char * cmd)
|
|
|
|
{
|
|
|
|
int i, j, bit;
|
|
|
|
unsigned char mask;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* avr_set_addr()
|
|
|
|
*
|
|
|
|
* Set address bits in the specified command based on the opcode, and
|
|
|
|
* the address.
|
|
|
|
*/
|
|
|
|
int avr_set_addr(OPCODE * op, unsigned char * cmd, unsigned long addr)
|
|
|
|
{
|
|
|
|
int i, j, bit;
|
|
|
|
unsigned long value;
|
|
|
|
unsigned char mask;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* avr_set_input()
|
|
|
|
*
|
|
|
|
* Set input data bits in the specified command based on the opcode,
|
|
|
|
* and the data byte.
|
|
|
|
*/
|
|
|
|
int avr_set_input(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_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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* avr_get_output()
|
|
|
|
*
|
|
|
|
* Retreive output data bits from the command results based on the
|
|
|
|
* opcode data.
|
|
|
|
*/
|
|
|
|
int avr_get_output(OPCODE * op, unsigned char * res, 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 = ((res[j] & mask) >> bit) & 0x01;
|
|
|
|
value = value << op->bit[i].bitno;
|
|
|
|
if (value)
|
|
|
|
*data = *data | value;
|
|
|
|
else
|
|
|
|
*data = *data & ~value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-12-03 15:52:38 +00:00
|
|
|
/*
|
|
|
|
* avr_get_output_index()
|
|
|
|
*
|
|
|
|
* Calculate the byte number of the output data based on the
|
|
|
|
* opcode data.
|
|
|
|
*/
|
|
|
|
int avr_get_output_index(OPCODE * op)
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
for (i=0; i<32; i++) {
|
|
|
|
if (op->bit[i].type == AVR_CMDBIT_OUTPUT) {
|
|
|
|
j = 3 - i / 8;
|
|
|
|
return j;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-01-24 22:43:46 +00:00
|
|
|
static char * avr_op_str(int op)
|
2003-11-30 16:42:10 +00:00
|
|
|
{
|
|
|
|
switch (op) {
|
|
|
|
case AVR_OP_READ : return "READ"; break;
|
|
|
|
case AVR_OP_WRITE : return "WRITE"; break;
|
|
|
|
case AVR_OP_READ_LO : return "READ_LO"; break;
|
|
|
|
case AVR_OP_READ_HI : return "READ_HI"; break;
|
|
|
|
case AVR_OP_WRITE_LO : return "WRITE_LO"; break;
|
|
|
|
case AVR_OP_WRITE_HI : return "WRITE_HI"; break;
|
|
|
|
case AVR_OP_LOADPAGE_LO : return "LOADPAGE_LO"; break;
|
|
|
|
case AVR_OP_LOADPAGE_HI : return "LOADPAGE_HI"; break;
|
2006-05-23 22:27:43 +00:00
|
|
|
case AVR_OP_LOAD_EXT_ADDR : return "LOAD_EXT_ADDR"; break;
|
2003-11-30 16:42:10 +00:00
|
|
|
case AVR_OP_WRITEPAGE : return "WRITEPAGE"; break;
|
|
|
|
case AVR_OP_CHIP_ERASE : return "CHIP_ERASE"; break;
|
|
|
|
case AVR_OP_PGM_ENABLE : return "PGM_ENABLE"; break;
|
|
|
|
default : return "<unknown opcode>"; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-01-24 22:43:46 +00:00
|
|
|
static char * bittype(int type)
|
2003-11-30 16:42:10 +00:00
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case AVR_CMDBIT_IGNORE : return "IGNORE"; break;
|
|
|
|
case AVR_CMDBIT_VALUE : return "VALUE"; break;
|
|
|
|
case AVR_CMDBIT_ADDRESS : return "ADDRESS"; break;
|
|
|
|
case AVR_CMDBIT_INPUT : return "INPUT"; break;
|
|
|
|
case AVR_CMDBIT_OUTPUT : return "OUTPUT"; break;
|
|
|
|
default : return "<unknown bit type>"; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***
|
|
|
|
*** Elementary functions dealing with AVRMEM structures
|
|
|
|
***/
|
|
|
|
|
|
|
|
AVRMEM * avr_new_memtype(void)
|
|
|
|
{
|
|
|
|
AVRMEM * m;
|
|
|
|
|
|
|
|
m = (AVRMEM *)malloc(sizeof(*m));
|
|
|
|
if (m == NULL) {
|
2014-06-13 20:07:40 +00:00
|
|
|
avrdude_message(MSG_INFO, "avr_new_memtype(): out of memory\n");
|
2003-11-30 16:42:10 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(m, 0, sizeof(*m));
|
2020-09-10 21:37:34 +00:00
|
|
|
m->page_size = 1; // ensure not 0
|
2003-11-30 16:42:10 +00:00
|
|
|
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate and initialize memory buffers for each of the device's
|
|
|
|
* defined memory regions.
|
|
|
|
*/
|
|
|
|
int avr_initmem(AVRPART * p)
|
|
|
|
{
|
|
|
|
LNODEID ln;
|
|
|
|
AVRMEM * m;
|
|
|
|
|
|
|
|
for (ln=lfirst(p->mem); ln; ln=lnext(ln)) {
|
|
|
|
m = ldata(ln);
|
|
|
|
m->buf = (unsigned char *) malloc(m->size);
|
|
|
|
if (m->buf == NULL) {
|
2014-06-13 20:07:40 +00:00
|
|
|
avrdude_message(MSG_INFO, "%s: can't alloc buffer for %s size of %d bytes\n",
|
2003-11-30 16:42:10 +00:00
|
|
|
progname, m->desc, m->size);
|
|
|
|
return -1;
|
|
|
|
}
|
2011-09-14 21:49:42 +00:00
|
|
|
m->tags = (unsigned char *) malloc(m->size);
|
|
|
|
if (m->tags == NULL) {
|
2014-06-13 20:07:40 +00:00
|
|
|
avrdude_message(MSG_INFO, "%s: can't alloc buffer for %s size of %d bytes\n",
|
2011-09-14 21:49:42 +00:00
|
|
|
progname, m->desc, m->size);
|
|
|
|
return -1;
|
|
|
|
}
|
2003-11-30 16:42:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AVRMEM * avr_dup_mem(AVRMEM * m)
|
|
|
|
{
|
|
|
|
AVRMEM * n;
|
2011-12-29 16:51:44 +00:00
|
|
|
int i;
|
2003-11-30 16:42:10 +00:00
|
|
|
|
|
|
|
n = avr_new_memtype();
|
|
|
|
|
|
|
|
*n = *m;
|
|
|
|
|
2011-12-29 16:51:44 +00:00
|
|
|
if (m->buf != NULL) {
|
|
|
|
n->buf = (unsigned char *)malloc(n->size);
|
|
|
|
if (n->buf == NULL) {
|
2014-06-13 20:07:40 +00:00
|
|
|
avrdude_message(MSG_INFO, "avr_dup_mem(): out of memory (memsize=%d)\n",
|
2014-05-18 08:41:46 +00:00
|
|
|
n->size);
|
2011-12-29 16:51:44 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
memcpy(n->buf, m->buf, n->size);
|
2003-11-30 16:42:10 +00:00
|
|
|
}
|
2011-09-14 21:49:42 +00:00
|
|
|
|
2011-12-29 16:51:44 +00:00
|
|
|
if (m->tags != NULL) {
|
|
|
|
n->tags = (unsigned char *)malloc(n->size);
|
|
|
|
if (n->tags == NULL) {
|
2014-06-13 20:07:40 +00:00
|
|
|
avrdude_message(MSG_INFO, "avr_dup_mem(): out of memory (memsize=%d)\n",
|
2014-05-18 08:41:46 +00:00
|
|
|
n->size);
|
2011-12-29 16:51:44 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
memcpy(n->tags, m->tags, n->size);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < AVR_OP_MAX; i++) {
|
|
|
|
n->op[i] = avr_dup_opcode(n->op[i]);
|
2011-09-14 21:49:42 +00:00
|
|
|
}
|
2003-11-30 16:42:10 +00:00
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2012-01-17 20:56:37 +00:00
|
|
|
void avr_free_mem(AVRMEM * m)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
if (m->buf != NULL) {
|
|
|
|
free(m->buf);
|
|
|
|
m->buf = NULL;
|
|
|
|
}
|
|
|
|
if (m->tags != NULL) {
|
|
|
|
free(m->tags);
|
|
|
|
m->tags = NULL;
|
|
|
|
}
|
|
|
|
for(i=0;i<sizeof(m->op)/sizeof(m->op[0]);i++)
|
|
|
|
{
|
|
|
|
if (m->op[i] != NULL)
|
|
|
|
{
|
|
|
|
avr_free_opcode(m->op[i]);
|
|
|
|
m->op[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(m);
|
|
|
|
}
|
2003-11-30 16:42:10 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-01-08 22:57:37 +00:00
|
|
|
void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, AVRPART * p,
|
|
|
|
int type, int verbose)
|
2003-11-30 16:42:10 +00:00
|
|
|
{
|
2022-01-08 22:57:37 +00:00
|
|
|
static unsigned int prev_mem_offset, prev_mem_size;
|
2003-11-30 16:42:10 +00:00
|
|
|
int i, j;
|
|
|
|
char * optr;
|
|
|
|
|
|
|
|
if (m == NULL) {
|
Mega-commit to bring in both, the STK500v2 support from Erik
Walthinsen, as well as JTAG ICE mkII support (by me).
Erik's submission has been cleaned up a little bit, mostly to add his
name and the current year to the copyright of the new file, remove
trailing white space before importing the files, and fix the minor
syntax errors in his avrdude.conf.in additions (missing semicolons).
The JTAG ICE mkII support should be considered alpha to beta quality
at this point. Few things are still to be done, like defering the
hfuse (OCDEN) tweaks until they are really required. Also, for
reasons not yet known, the target MCU doesn't start to run after
signing off from the ICE, it needs a power-cycle first (at least on my
STK500).
Note that for the JTAG ICE, I did change a few things in the internal
API. Notably I made the serial receive timeout configurable by the
backends via an exported variable (done in both the Posix and the
Win32 implementation), and I made the serial_recv() function return a
-1 instead of bailing out with exit(1) upon encountering a receive
timeout (currently only done in the Posix implementation). Both
measures together allow me to receive a datastreem from the ICE at 115
kbps on a somewhat lossy PCI multi-UART card that occasionally drops a
character. The JTAG ICE mkII protocol has enough of safety layers to
allow recovering from these events, but the previous code wasn't
prepared for any kind of recovery. The Win32 change for this still
has to be done, and the traditional drivers need to be converted to
exit(1) upon encountering a timeout (as they're now getting a -1
returned they didn't see before in that case).
git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@451 81a1dc3b-b13d-400b-aceb-764788c761c2
2005-05-10 19:17:12 +00:00
|
|
|
fprintf(f,
|
|
|
|
"%s Block Poll Page Polled\n"
|
|
|
|
"%sMemory Type Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack\n"
|
|
|
|
"%s----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------\n",
|
2003-11-30 16:42:10 +00:00
|
|
|
prefix, prefix, prefix);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (verbose > 2) {
|
|
|
|
fprintf(f,
|
Mega-commit to bring in both, the STK500v2 support from Erik
Walthinsen, as well as JTAG ICE mkII support (by me).
Erik's submission has been cleaned up a little bit, mostly to add his
name and the current year to the copyright of the new file, remove
trailing white space before importing the files, and fix the minor
syntax errors in his avrdude.conf.in additions (missing semicolons).
The JTAG ICE mkII support should be considered alpha to beta quality
at this point. Few things are still to be done, like defering the
hfuse (OCDEN) tweaks until they are really required. Also, for
reasons not yet known, the target MCU doesn't start to run after
signing off from the ICE, it needs a power-cycle first (at least on my
STK500).
Note that for the JTAG ICE, I did change a few things in the internal
API. Notably I made the serial receive timeout configurable by the
backends via an exported variable (done in both the Posix and the
Win32 implementation), and I made the serial_recv() function return a
-1 instead of bailing out with exit(1) upon encountering a receive
timeout (currently only done in the Posix implementation). Both
measures together allow me to receive a datastreem from the ICE at 115
kbps on a somewhat lossy PCI multi-UART card that occasionally drops a
character. The JTAG ICE mkII protocol has enough of safety layers to
allow recovering from these events, but the previous code wasn't
prepared for any kind of recovery. The Win32 change for this still
has to be done, and the traditional drivers need to be converted to
exit(1) upon encountering a timeout (as they're now getting a -1
returned they didn't see before in that case).
git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@451 81a1dc3b-b13d-400b-aceb-764788c761c2
2005-05-10 19:17:12 +00:00
|
|
|
"%s Block Poll Page Polled\n"
|
|
|
|
"%sMemory Type Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack\n"
|
|
|
|
"%s----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------\n",
|
2003-11-30 16:42:10 +00:00
|
|
|
prefix, prefix, prefix);
|
|
|
|
}
|
2022-01-08 22:57:37 +00:00
|
|
|
if ((prev_mem_offset != m->offset || prev_mem_size != m->size) || (strcmp(p->family_id, "") == 0)) { // Don't print memory aliases
|
|
|
|
prev_mem_offset = m->offset;
|
|
|
|
prev_mem_size = m->size;
|
|
|
|
fprintf(f,
|
|
|
|
"%s%-11s %4d %5d %5d %4d %-6s %6d %4d %6d %5d %5d 0x%02x 0x%02x\n",
|
|
|
|
prefix, m->desc, m->mode, m->delay, m->blocksize, m->pollindex,
|
|
|
|
m->paged ? "yes" : "no",
|
|
|
|
m->size,
|
|
|
|
m->page_size,
|
|
|
|
m->num_pages,
|
|
|
|
m->min_write_delay,
|
|
|
|
m->max_write_delay,
|
|
|
|
m->readback[0],
|
|
|
|
m->readback[1]);
|
|
|
|
}
|
2006-07-21 21:51:13 +00:00
|
|
|
if (verbose > 4) {
|
2014-06-13 20:07:40 +00:00
|
|
|
avrdude_message(MSG_TRACE2, "%s Memory Ops:\n"
|
2014-05-18 08:41:46 +00:00
|
|
|
"%s Oeration Inst Bit Bit Type Bitno Value\n"
|
|
|
|
"%s ----------- -------- -------- ----- -----\n",
|
|
|
|
prefix, prefix, prefix);
|
2003-11-30 16:42:10 +00:00
|
|
|
for (i=0; i<AVR_OP_MAX; i++) {
|
|
|
|
if (m->op[i]) {
|
|
|
|
for (j=31; j>=0; j--) {
|
|
|
|
if (j==31)
|
|
|
|
optr = avr_op_str(i);
|
|
|
|
else
|
|
|
|
optr = " ";
|
|
|
|
fprintf(f,
|
|
|
|
"%s %-11s %8d %8s %5d %5d\n",
|
|
|
|
prefix, optr, j,
|
|
|
|
bittype(m->op[i]->bit[j].type),
|
|
|
|
m->op[i]->bit[j].bitno,
|
|
|
|
m->op[i]->bit[j].value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Elementary functions dealing with AVRPART structures
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
AVRPART * avr_new_part(void)
|
|
|
|
{
|
|
|
|
AVRPART * p;
|
|
|
|
|
|
|
|
p = (AVRPART *)malloc(sizeof(AVRPART));
|
|
|
|
if (p == NULL) {
|
2014-06-13 20:07:40 +00:00
|
|
|
avrdude_message(MSG_INFO, "new_part(): out of memory\n");
|
2003-11-30 16:42:10 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(p, 0, sizeof(*p));
|
|
|
|
|
|
|
|
p->id[0] = 0;
|
|
|
|
p->desc[0] = 0;
|
|
|
|
p->reset_disposition = RESET_DEDICATED;
|
|
|
|
p->retry_pulse = PIN_AVR_SCK;
|
Quite some cleanup of the JTAG ICE mkII stuff.
. Implement the new EECRAddress field in the device descriptor that is
required by the 4.x firmware; make an uneducated guess about what
firmware requires what length of device descriptor -- perhaps Atmel
can be convinced to publish an official matrix for that.
. Specify EECR in the config file where required. Obviously, only
locations that differ from the 0x3c default are mentioned in the
XML files, so by now, this only affects the AT90CAN128 for us.
. After clarification with Atmel, EnablePageProgramming should really
default to 1, and only cleared if specified by an XML parameter. So
far, only the XML files for the ATmega256x and ATmega406 do specify
it at all, and they specify a 1, too.
. Drop the entire OCDEN fuse heuristic. If OCDEN is unprogrammed at
startup, issue a warning that single-byte EEPROM updates won't be
possible. Leave it to the user to program the fuse if desired.
That way, we won't run into any issue of prematurely wearing out the
hfuse EEPROM cell. Interestingly enough, this also solved the
problem of the target not restarting from scratch upon sign-off.
git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@461 81a1dc3b-b13d-400b-aceb-764788c761c2
2005-05-11 20:06:23 +00:00
|
|
|
p->flags = AVRPART_SERIALOK | AVRPART_PARALLELOK | AVRPART_ENABLEPAGEPROGRAMMING;
|
2003-11-30 16:42:10 +00:00
|
|
|
p->config_file[0] = 0;
|
|
|
|
p->lineno = 0;
|
2006-02-27 17:18:42 +00:00
|
|
|
memset(p->signature, 0xFF, 3);
|
2006-07-16 21:30:14 +00:00
|
|
|
p->ctl_stack_type = CTL_STACK_NONE;
|
2012-12-04 13:59:37 +00:00
|
|
|
p->ocdrev = -1;
|
2003-11-30 16:42:10 +00:00
|
|
|
|
|
|
|
p->mem = lcreat(NULL, 0);
|
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AVRPART * avr_dup_part(AVRPART * d)
|
|
|
|
{
|
|
|
|
AVRPART * p;
|
|
|
|
LISTID save;
|
|
|
|
LNODEID ln;
|
2011-12-29 16:51:44 +00:00
|
|
|
int i;
|
2003-11-30 16:42:10 +00:00
|
|
|
|
|
|
|
p = avr_new_part();
|
|
|
|
save = p->mem;
|
|
|
|
|
|
|
|
*p = *d;
|
|
|
|
|
|
|
|
p->mem = save;
|
|
|
|
|
|
|
|
for (ln=lfirst(d->mem); ln; ln=lnext(ln)) {
|
|
|
|
ladd(p->mem, avr_dup_mem(ldata(ln)));
|
|
|
|
}
|
|
|
|
|
2011-12-29 16:51:44 +00:00
|
|
|
for (i = 0; i < AVR_OP_MAX; i++) {
|
|
|
|
p->op[i] = avr_dup_opcode(p->op[i]);
|
|
|
|
}
|
|
|
|
|
2003-11-30 16:42:10 +00:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2012-01-17 20:56:37 +00:00
|
|
|
void avr_free_part(AVRPART * d)
|
|
|
|
{
|
|
|
|
int i;
|
2012-02-03 20:07:54 +00:00
|
|
|
ldestroy_cb(d->mem, (void(*)(void *))avr_free_mem);
|
2012-01-17 20:56:37 +00:00
|
|
|
d->mem = NULL;
|
|
|
|
for(i=0;i<sizeof(d->op)/sizeof(d->op[0]);i++)
|
|
|
|
{
|
|
|
|
if (d->op[i] != NULL)
|
|
|
|
{
|
|
|
|
avr_free_opcode(d->op[i]);
|
|
|
|
d->op[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(d);
|
|
|
|
}
|
2003-11-30 16:42:10 +00:00
|
|
|
|
2003-11-30 16:49:00 +00:00
|
|
|
AVRPART * locate_part(LISTID parts, char * partdesc)
|
|
|
|
{
|
|
|
|
LNODEID ln1;
|
|
|
|
AVRPART * p = NULL;
|
|
|
|
int found;
|
|
|
|
|
|
|
|
found = 0;
|
|
|
|
|
|
|
|
for (ln1=lfirst(parts); ln1 && !found; ln1=lnext(ln1)) {
|
|
|
|
p = ldata(ln1);
|
|
|
|
if ((strcasecmp(partdesc, p->id) == 0) ||
|
|
|
|
(strcasecmp(partdesc, p->desc) == 0))
|
|
|
|
found = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (found)
|
|
|
|
return p;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2004-01-12 22:48:50 +00:00
|
|
|
AVRPART * locate_part_by_avr910_devcode(LISTID parts, int devcode)
|
|
|
|
{
|
|
|
|
LNODEID ln1;
|
|
|
|
AVRPART * p = NULL;
|
|
|
|
|
|
|
|
for (ln1=lfirst(parts); ln1; ln1=lnext(ln1)) {
|
|
|
|
p = ldata(ln1);
|
|
|
|
if (p->avr910_devcode == devcode)
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2003-11-30 16:49:00 +00:00
|
|
|
|
2014-08-18 21:43:08 +00:00
|
|
|
AVRPART * locate_part_by_signature(LISTID parts, unsigned char * sig,
|
|
|
|
int sigsize)
|
|
|
|
{
|
|
|
|
LNODEID ln1;
|
|
|
|
AVRPART * p = NULL;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (sigsize == 3) {
|
|
|
|
for (ln1=lfirst(parts); ln1; ln1=lnext(ln1)) {
|
|
|
|
p = ldata(ln1);
|
|
|
|
for (i=0; i<3; i++)
|
|
|
|
if (p->signature[i] != sig[i])
|
|
|
|
break;
|
|
|
|
if (i == 3)
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-01-29 20:41:47 +00:00
|
|
|
/*
|
|
|
|
* Iterate over the list of avrparts given as "avrparts", and
|
|
|
|
* call the callback function cb for each entry found. cb is being
|
|
|
|
* passed the following arguments:
|
|
|
|
* . the name of the avrpart (for -p)
|
|
|
|
* . the descriptive text given in the config file
|
|
|
|
* . the name of the config file this avrpart has been defined in
|
|
|
|
* . the line number of the config file this avrpart has been defined at
|
|
|
|
* . the "cookie" passed into walk_avrparts() (opaque client data)
|
|
|
|
*/
|
|
|
|
void walk_avrparts(LISTID avrparts, walk_avrparts_cb cb, void *cookie)
|
2003-11-30 16:49:00 +00:00
|
|
|
{
|
|
|
|
LNODEID ln1;
|
|
|
|
AVRPART * p;
|
|
|
|
|
2007-01-29 20:41:47 +00:00
|
|
|
for (ln1 = lfirst(avrparts); ln1; ln1 = lnext(ln1)) {
|
2003-11-30 16:49:00 +00:00
|
|
|
p = ldata(ln1);
|
2007-01-29 20:41:47 +00:00
|
|
|
cb(p->id, p->desc, p->config_file, p->lineno, cookie);
|
2003-11-30 16:49:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-16 20:44:07 +00:00
|
|
|
/*
|
|
|
|
* Compare function to sort the list of programmers
|
|
|
|
*/
|
|
|
|
static int sort_avrparts_compare(AVRPART * p1,AVRPART * p2)
|
|
|
|
{
|
|
|
|
if(p1 == NULL || p2 == NULL) {
|
|
|
|
return 0;
|
|
|
|
}
|
2011-12-29 12:53:20 +00:00
|
|
|
return strncasecmp(p1->desc,p2->desc,AVR_DESCLEN);
|
2011-12-16 20:44:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Sort the list of programmers given as "programmers"
|
|
|
|
*/
|
|
|
|
void sort_avrparts(LISTID avrparts)
|
|
|
|
{
|
|
|
|
lsort(avrparts,(int (*)(void*, void*)) sort_avrparts_compare);
|
|
|
|
}
|
2003-11-30 16:49:00 +00:00
|
|
|
|
2007-01-29 20:41:47 +00:00
|
|
|
|
2007-01-24 22:43:46 +00:00
|
|
|
static char * reset_disp_str(int r)
|
2003-11-30 16:42:10 +00:00
|
|
|
{
|
|
|
|
switch (r) {
|
|
|
|
case RESET_DEDICATED : return "dedicated";
|
|
|
|
case RESET_IO : return "possible i/o";
|
|
|
|
default : return "<invalid>";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-01-30 13:41:54 +00:00
|
|
|
void avr_display(FILE * f, AVRPART * p, const char * prefix, int verbose)
|
2003-11-30 16:42:10 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
char * buf;
|
2007-01-30 13:41:54 +00:00
|
|
|
const char * px;
|
2003-11-30 16:42:10 +00:00
|
|
|
LNODEID ln;
|
|
|
|
AVRMEM * m;
|
|
|
|
|
|
|
|
fprintf(f,
|
2008-06-07 21:03:41 +00:00
|
|
|
"%sAVR Part : %s\n"
|
|
|
|
"%sChip Erase delay : %d us\n"
|
|
|
|
"%sPAGEL : P%02X\n"
|
|
|
|
"%sBS2 : P%02X\n"
|
|
|
|
"%sRESET disposition : %s\n"
|
|
|
|
"%sRETRY pulse : %s\n"
|
|
|
|
"%sserial program mode : %s\n"
|
|
|
|
"%sparallel program mode : %s\n"
|
|
|
|
"%sTimeout : %d\n"
|
|
|
|
"%sStabDelay : %d\n"
|
|
|
|
"%sCmdexeDelay : %d\n"
|
|
|
|
"%sSyncLoops : %d\n"
|
|
|
|
"%sByteDelay : %d\n"
|
|
|
|
"%sPollIndex : %d\n"
|
|
|
|
"%sPollValue : 0x%02x\n"
|
|
|
|
"%sMemory Detail :\n\n",
|
2003-11-30 16:42:10 +00:00
|
|
|
prefix, p->desc,
|
|
|
|
prefix, p->chip_erase_delay,
|
|
|
|
prefix, p->pagel,
|
|
|
|
prefix, p->bs2,
|
|
|
|
prefix, reset_disp_str(p->reset_disposition),
|
2012-07-20 20:05:30 +00:00
|
|
|
prefix, avr_pin_name(p->retry_pulse),
|
2003-11-30 16:42:10 +00:00
|
|
|
prefix, (p->flags & AVRPART_SERIALOK) ? "yes" : "no",
|
|
|
|
prefix, (p->flags & AVRPART_PARALLELOK) ?
|
2019-01-05 23:01:56 +00:00
|
|
|
((p->flags & AVRPART_PSEUDOPARALLEL) ? "pseudo" : "yes") : "no",
|
Mega-commit to bring in both, the STK500v2 support from Erik
Walthinsen, as well as JTAG ICE mkII support (by me).
Erik's submission has been cleaned up a little bit, mostly to add his
name and the current year to the copyright of the new file, remove
trailing white space before importing the files, and fix the minor
syntax errors in his avrdude.conf.in additions (missing semicolons).
The JTAG ICE mkII support should be considered alpha to beta quality
at this point. Few things are still to be done, like defering the
hfuse (OCDEN) tweaks until they are really required. Also, for
reasons not yet known, the target MCU doesn't start to run after
signing off from the ICE, it needs a power-cycle first (at least on my
STK500).
Note that for the JTAG ICE, I did change a few things in the internal
API. Notably I made the serial receive timeout configurable by the
backends via an exported variable (done in both the Posix and the
Win32 implementation), and I made the serial_recv() function return a
-1 instead of bailing out with exit(1) upon encountering a receive
timeout (currently only done in the Posix implementation). Both
measures together allow me to receive a datastreem from the ICE at 115
kbps on a somewhat lossy PCI multi-UART card that occasionally drops a
character. The JTAG ICE mkII protocol has enough of safety layers to
allow recovering from these events, but the previous code wasn't
prepared for any kind of recovery. The Win32 change for this still
has to be done, and the traditional drivers need to be converted to
exit(1) upon encountering a timeout (as they're now getting a -1
returned they didn't see before in that case).
git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@451 81a1dc3b-b13d-400b-aceb-764788c761c2
2005-05-10 19:17:12 +00:00
|
|
|
prefix, p->timeout,
|
|
|
|
prefix, p->stabdelay,
|
|
|
|
prefix, p->cmdexedelay,
|
|
|
|
prefix, p->synchloops,
|
|
|
|
prefix, p->bytedelay,
|
|
|
|
prefix, p->pollindex,
|
|
|
|
prefix, p->pollvalue,
|
2003-11-30 16:42:10 +00:00
|
|
|
prefix);
|
|
|
|
|
|
|
|
px = prefix;
|
|
|
|
i = strlen(prefix) + 5;
|
|
|
|
buf = (char *)malloc(i);
|
|
|
|
if (buf == NULL) {
|
|
|
|
/* ugh, this is not important enough to bail, just ignore it */
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
strcpy(buf, prefix);
|
|
|
|
strcat(buf, " ");
|
|
|
|
px = buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (verbose <= 2) {
|
2022-01-08 22:57:37 +00:00
|
|
|
avr_mem_display(px, f, NULL, p, 0, verbose);
|
2003-11-30 16:42:10 +00:00
|
|
|
}
|
|
|
|
for (ln=lfirst(p->mem); ln; ln=lnext(ln)) {
|
|
|
|
m = ldata(ln);
|
2022-01-08 22:57:37 +00:00
|
|
|
avr_mem_display(px, f, m, p, i, verbose);
|
2003-11-30 16:42:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (buf)
|
|
|
|
free(buf);
|
|
|
|
}
|