Implement debugWire programming support. Several limitations are

imposed by debugWire itself, so effectively, only flash ROM can be
read and written.

Currently, the required changes to avrdude.conf.in are only present
for the ATtiny44.


git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@688 81a1dc3b-b13d-400b-aceb-764788c761c2
This commit is contained in:
joerg_wunsch
2006-11-20 23:23:37 +00:00
parent 46e0286657
commit 8ed8377442
9 changed files with 477 additions and 48 deletions

View File

@@ -106,6 +106,11 @@ static struct {
RC(RSP_SET_N_PARAMETERS)
};
/*
* pgm->flag is marked as "for private use of the programmer".
* The following defines this programmer's use of that field.
*/
#define PGM_FL_IS_DW (0x0001)
/* The length of the device descriptor is firmware-dependent. */
static size_t device_descriptor_length;
@@ -801,6 +806,18 @@ static int jtagmkII_chip_erase(PROGRAMMER * pgm, AVRPART * p)
return 0;
}
/*
* There is no chip erase functionality in debugWire mode.
*/
static int jtagmkII_chip_erase_dw(PROGRAMMER * pgm, AVRPART * p)
{
fprintf(stderr, "%s: Chip erase not supported in debugWire mode\n",
progname);
return 0;
}
static void jtagmkII_set_devdescr(PROGRAMMER * pgm, AVRPART * p)
{
int status;
@@ -829,6 +846,8 @@ static void jtagmkII_set_devdescr(PROGRAMMER * pgm, AVRPART * p)
u32_to_b4(sendbuf.dd.ulFlashSize, m->size);
u16_to_b2(sendbuf.dd.uiFlashPageSize, flash_pagesize);
u16_to_b2(sendbuf.dd.uiFlashpages, m->size / flash_pagesize);
if (p->flags & AVRPART_HAS_DW)
memcpy(sendbuf.dd.ucFlashInst, p->flash_instr, FLASH_INSTR_SIZE);
} else if (strcmp(m->desc, "eeprom") == 0) {
sendbuf.dd.ucEepromPageSize = eeprom_pagesize = m->page_size;
}
@@ -874,11 +893,21 @@ static int jtagmkII_reset(PROGRAMMER * pgm, unsigned char flags)
int status;
unsigned char buf[2], *resp, c;
buf[0] = CMND_RESET;
buf[1] = flags;
/*
* In debugWire mode, don't reset. Do a forced stop, and tell the
* ICE to stop any timers, too.
*/
if (pgm->flag & PGM_FL_IS_DW) {
unsigned char parm[] = { 0 };
(void)jtagmkII_setparm(pgm, PAR_TIMERS_RUNNING, parm);
}
buf[0] = (pgm->flag & PGM_FL_IS_DW)? CMND_FORCED_STOP: CMND_RESET;
buf[1] = (pgm->flag & PGM_FL_IS_DW)? 1: flags;
if (verbose >= 2)
fprintf(stderr, "%s: jtagmkII_reset(): Sending reset command: ",
progname);
fprintf(stderr, "%s: jtagmkII_reset(): Sending %s command: ",
progname, (pgm->flag & PGM_FL_IS_DW)? "stop": "reset");
jtagmkII_send(pgm, buf, 2);
status = jtagmkII_recv(pgm, &resp);
@@ -1038,10 +1067,23 @@ static int jtagmkII_initialize(PROGRAMMER * pgm, AVRPART * p)
{
AVRMEM hfuse;
unsigned char b;
int ok;
const char *ifname;
if (!(p->flags & AVRPART_HAS_JTAG)) {
fprintf(stderr, "%s: jtagmkII_initialize(): part %s has no JTAG interface\n",
progname, p->desc);
ok = 0;
if (pgm->flag & PGM_FL_IS_DW) {
ifname = "debugWire";
if (p->flags & AVRPART_HAS_DW)
ok = 1;
} else {
ifname = "JTAG";
if (p->flags & AVRPART_HAS_JTAG)
ok = 1;
}
if (!ok) {
fprintf(stderr, "%s: jtagmkII_initialize(): part %s has no %s interface\n",
progname, p->desc, ifname);
return -1;
}
@@ -1058,7 +1100,7 @@ static int jtagmkII_initialize(PROGRAMMER * pgm, AVRPART * p)
serial_setspeed(pgm->fd, pgm->baudrate);
}
}
if (pgm->bitclock != 0.0) {
if (!(pgm->flag & PGM_FL_IS_DW) && pgm->bitclock != 0.0) {
if (verbose >= 2)
fprintf(stderr, "%s: jtagmkII_initialize(): "
"trying to set JTAG clock period to %.1f us\n",
@@ -1090,14 +1132,16 @@ static int jtagmkII_initialize(PROGRAMMER * pgm, AVRPART * p)
if (jtagmkII_reset(pgm, 0x01) < 0)
return -1;
strcpy(hfuse.desc, "hfuse");
if (jtagmkII_read_byte(pgm, p, &hfuse, 1, &b) < 0)
return -1;
if ((b & OCDEN) != 0)
fprintf(stderr,
"%s: jtagmkII_initialize(): warning: OCDEN fuse not programmed, "
"single-byte EEPROM updates not possible\n",
progname);
if (!(pgm->flag & PGM_FL_IS_DW)) {
strcpy(hfuse.desc, "hfuse");
if (jtagmkII_read_byte(pgm, p, &hfuse, 1, &b) < 0)
return -1;
if ((b & OCDEN) != 0)
fprintf(stderr,
"%s: jtagmkII_initialize(): warning: OCDEN fuse not programmed, "
"single-byte EEPROM updates not possible\n",
progname);
}
return 0;
}
@@ -1111,7 +1155,8 @@ static void jtagmkII_disable(PROGRAMMER * pgm)
free(eeprom_pagecache);
eeprom_pagecache = NULL;
(void)jtagmkII_program_disable(pgm);
if (!(pgm->flag & PGM_FL_IS_DW))
(void)jtagmkII_program_disable(pgm);
}
static void jtagmkII_enable(PROGRAMMER * pgm)
@@ -1165,6 +1210,51 @@ static int jtagmkII_open(PROGRAMMER * pgm, char * port)
}
static int jtagmkII_open_dw(PROGRAMMER * pgm, char * port)
{
long baud;
if (verbose >= 2)
fprintf(stderr, "%s: jtagmkII_open_dw()\n", progname);
/*
* The JTAG ICE mkII always starts with a baud rate of 19200 Bd upon
* attaching. If the config file or command-line parameters specify
* a higher baud rate, we switch to it later on, after establishing
* the connection with the ICE.
*/
baud = 19200;
/*
* If the port name starts with "usb", divert the serial routines
* to the USB ones. The serial_open() function for USB overrides
* the meaning of the "baud" parameter to be the USB device ID to
* search for.
*/
if (strncmp(port, "usb", 3) == 0) {
#if defined(HAVE_LIBUSB)
serdev = &usb_serdev;
baud = USB_DEVICE_JTAGICEMKII;
#else
fprintf(stderr, "avrdude was compiled without usb support.\n");
return -1;
#endif
}
strcpy(pgm->port, port);
pgm->fd = serial_open(port, baud);
/*
* drain any extraneous input
*/
jtagmkII_drain(pgm, 0);
jtagmkII_getsync(pgm, EMULATOR_MODE_DEBUGWIRE);
return 0;
}
static int jtagmkII_dragon_open(PROGRAMMER * pgm, char * port)
{
long baud;
@@ -1210,6 +1300,51 @@ static int jtagmkII_dragon_open(PROGRAMMER * pgm, char * port)
}
static int jtagmkII_dragon_open_dw(PROGRAMMER * pgm, char * port)
{
long baud;
if (verbose >= 2)
fprintf(stderr, "%s: jtagmkII_dragon_open_dw()\n", progname);
/*
* The JTAG ICE mkII always starts with a baud rate of 19200 Bd upon
* attaching. If the config file or command-line parameters specify
* a higher baud rate, we switch to it later on, after establishing
* the connection with the ICE.
*/
baud = 19200;
/*
* If the port name starts with "usb", divert the serial routines
* to the USB ones. The serial_open() function for USB overrides
* the meaning of the "baud" parameter to be the USB device ID to
* search for.
*/
if (strncmp(port, "usb", 3) == 0) {
#if defined(HAVE_LIBUSB)
serdev = &usb_serdev;
baud = USB_DEVICE_AVRDRAGON;
#else
fprintf(stderr, "avrdude was compiled without usb support.\n");
return -1;
#endif
}
strcpy(pgm->port, port);
pgm->fd = serial_open(port, baud);
/*
* drain any extraneous input
*/
jtagmkII_drain(pgm, 0);
jtagmkII_getsync(pgm, EMULATOR_MODE_DEBUGWIRE);
return 0;
}
void jtagmkII_close(PROGRAMMER * pgm)
{
int status;
@@ -1299,7 +1434,7 @@ static int jtagmkII_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
fprintf(stderr, "%s: jtagmkII_paged_write(.., %s, %d, %d)\n",
progname, m->desc, page_size, n_bytes);
if (jtagmkII_program_enable(pgm) < 0)
if (!(pgm->flag & PGM_FL_IS_DW) && jtagmkII_program_enable(pgm) < 0)
return -1;
if (page_size == 0) page_size = 256;
@@ -1319,6 +1454,10 @@ static int jtagmkII_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
cmd[1] = MTYPE_EEPROM_PAGE;
eeprom_pageaddr = (unsigned long)-1L;
page_size = eeprom_pagesize;
if (pgm->flag & PGM_FL_IS_DW) {
free(cmd);
return -1;
}
}
serial_recv_timeout = 100;
@@ -1393,6 +1532,7 @@ static int jtagmkII_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
return -1;
}
free(resp);
usleep(1000000);
}
free(cmd);
@@ -1414,7 +1554,7 @@ static int jtagmkII_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
fprintf(stderr, "%s: jtagmkII_paged_load(.., %s, %d, %d)\n",
progname, m->desc, page_size, n_bytes);
if (jtagmkII_program_enable(pgm) < 0)
if (!(pgm->flag & PGM_FL_IS_DW) && jtagmkII_program_enable(pgm) < 0)
return -1;
page_size = m->readsize;
@@ -1424,6 +1564,8 @@ static int jtagmkII_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
cmd[1] = MTYPE_FLASH_PAGE;
} else if (strcmp(m->desc, "eeprom") == 0) {
cmd[1] = MTYPE_EEPROM_PAGE;
if (pgm->flag & PGM_FL_IS_DW)
return -1;
}
serial_recv_timeout = 100;
@@ -1497,7 +1639,7 @@ static int jtagmkII_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
{
unsigned char cmd[10];
unsigned char *resp = NULL, *cache_ptr = NULL;
int status, tries;
int status, tries, unsupp;
unsigned long paddr = 0UL, *paddr_ptr = NULL;
unsigned int pagesize = 0;
@@ -1505,10 +1647,11 @@ static int jtagmkII_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
fprintf(stderr, "%s: jtagmkII_read_byte(.., %s, 0x%lx, ...)\n",
progname, mem->desc, addr);
if (jtagmkII_program_enable(pgm) < 0)
if (!(pgm->flag & PGM_FL_IS_DW) && jtagmkII_program_enable(pgm) < 0)
return -1;
cmd[0] = CMND_READ_MEMORY;
unsupp = 0;
if (strcmp(mem->desc, "flash") == 0) {
cmd[1] = MTYPE_FLASH_PAGE;
@@ -1522,21 +1665,71 @@ static int jtagmkII_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
paddr = addr & ~(pagesize - 1);
paddr_ptr = &eeprom_pageaddr;
cache_ptr = eeprom_pagecache;
if (pgm->flag & PGM_FL_IS_DW)
unsupp = 1;
} else if (strcmp(mem->desc, "lfuse") == 0) {
cmd[1] = MTYPE_FUSE_BITS;
addr = 0;
if (pgm->flag & PGM_FL_IS_DW)
unsupp = 1;
} else if (strcmp(mem->desc, "hfuse") == 0) {
cmd[1] = MTYPE_FUSE_BITS;
addr = 1;
if (pgm->flag & PGM_FL_IS_DW)
unsupp = 1;
} else if (strcmp(mem->desc, "efuse") == 0) {
cmd[1] = MTYPE_FUSE_BITS;
addr = 2;
if (pgm->flag & PGM_FL_IS_DW)
unsupp = 1;
} else if (strcmp(mem->desc, "lock") == 0) {
cmd[1] = MTYPE_LOCK_BITS;
if (pgm->flag & PGM_FL_IS_DW)
unsupp = 1;
} else if (strcmp(mem->desc, "calibration") == 0) {
cmd[1] = MTYPE_OSCCAL_BYTE;
if (pgm->flag & PGM_FL_IS_DW)
unsupp = 1;
} else if (strcmp(mem->desc, "signature") == 0) {
cmd[1] = MTYPE_SIGN_JTAG;
if (pgm->flag & PGM_FL_IS_DW) {
/*
* In debugWire mode, there is no accessible memory area to read
* the signature from, but the essential two bytes can be read
* as a parameter from the ICE.
*/
unsigned char parm[4];
switch (addr) {
case 0:
*value = 0x1E; /* Atmel vendor ID */
break;
case 1:
case 2:
if (jtagmkII_getparm(pgm, PAR_TARGET_SIGNATURE, parm) < 0)
return -1;
*value = parm[2 - addr];
break;
default:
fprintf(stderr, "%s: illegal address %lu for signature memory\n",
progname, addr);
*value = 42;
return -1;
}
return 0;
}
}
/*
* If the respective memory area is not supported under debugWire,
* leave here.
*/
if (unsupp) {
*value = 42;
return -1;
}
/*
@@ -1720,6 +1913,17 @@ fail:
}
static int jtagmkII_write_byte_dw(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
unsigned long addr, unsigned char data)
{
fprintf(stderr,
"%s: jtagmkII_write_byte_dw(): no single-byte writes supported in debugWire\n",
progname);
return -1;
}
/*
* Set the JTAG clock. The actual frequency is quite a bit of
* guesswork, based on the values claimed by AVR Studio. Inside the
@@ -1824,6 +2028,7 @@ static int jtagmkII_setparm(PROGRAMMER * pgm, unsigned char parm,
case PAR_BAUD_RATE: size = 1; break;
case PAR_OCD_VTARGET: size = 2; break;
case PAR_OCD_JTAG_CLK: size = 1; break;
case PAR_TIMERS_RUNNING: size = 1; break;
default:
fprintf(stderr, "%s: jtagmkII_setparm(): unknown parameter 0x%02x\n",
progname, parm);
@@ -1895,28 +2100,33 @@ static void jtagmkII_print_parms1(PROGRAMMER * pgm, char * p)
char clkbuf[20];
double clk;
if (jtagmkII_getparm(pgm, PAR_OCD_VTARGET, vtarget) < 0 ||
jtagmkII_getparm(pgm, PAR_OCD_JTAG_CLK, jtag_clock) < 0)
if (jtagmkII_getparm(pgm, PAR_OCD_VTARGET, vtarget) < 0)
return;
if (jtag_clock[0] == 0) {
strcpy(clkbuf, "6.4 MHz");
clk = 6.4e6;
} else if (jtag_clock[0] == 1) {
strcpy(clkbuf, "2.8 MHz");
clk = 2.8e6;
} else if (jtag_clock[0] <= 5) {
sprintf(clkbuf, "%.1f MHz", 5.35 / (double)jtag_clock[0]);
clk = 5.35e6 / (double)jtag_clock[0];
} else {
sprintf(clkbuf, "%.1f kHz", 5.35e3 / (double)jtag_clock[0]);
clk = 5.35e6 / (double)jtag_clock[0];
}
fprintf(stderr, "%sVtarget : %.1f V\n", p,
b2_to_u16(vtarget) / 1000.0);
fprintf(stderr, "%sJTAG clock : %s (%.1f us)\n", p, clkbuf,
1.0e6 / clk);
if (!(pgm->flag & PGM_FL_IS_DW)) {
if (jtagmkII_getparm(pgm, PAR_OCD_JTAG_CLK, jtag_clock) < 0)
return;
if (jtag_clock[0] == 0) {
strcpy(clkbuf, "6.4 MHz");
clk = 6.4e6;
} else if (jtag_clock[0] == 1) {
strcpy(clkbuf, "2.8 MHz");
clk = 2.8e6;
} else if (jtag_clock[0] <= 5) {
sprintf(clkbuf, "%.1f MHz", 5.35 / (double)jtag_clock[0]);
clk = 5.35e6 / (double)jtag_clock[0];
} else {
sprintf(clkbuf, "%.1f kHz", 5.35e3 / (double)jtag_clock[0]);
clk = 5.35e6 / (double)jtag_clock[0];
fprintf(stderr, "%sJTAG clock : %s (%.1f us)\n", p, clkbuf,
1.0e6 / clk);
}
}
return;
}
@@ -1957,6 +2167,35 @@ void jtagmkII_initpgm(PROGRAMMER * pgm)
}
void jtagmkII_dw_initpgm(PROGRAMMER * pgm)
{
strcpy(pgm->type, "JTAGMKII_DW");
/*
* mandatory functions
*/
pgm->initialize = jtagmkII_initialize;
pgm->display = jtagmkII_display;
pgm->enable = jtagmkII_enable;
pgm->disable = jtagmkII_disable;
pgm->program_enable = jtagmkII_program_enable_dummy;
pgm->chip_erase = jtagmkII_chip_erase_dw;
pgm->open = jtagmkII_open_dw;
pgm->close = jtagmkII_close;
pgm->read_byte = jtagmkII_read_byte;
pgm->write_byte = jtagmkII_write_byte_dw;
/*
* optional functions
*/
pgm->paged_write = jtagmkII_paged_write;
pgm->paged_load = jtagmkII_paged_load;
pgm->print_parms = jtagmkII_print_parms;
pgm->page_size = 256;
pgm->flag = PGM_FL_IS_DW;
}
void jtagmkII_dragon_initpgm(PROGRAMMER * pgm)
{
strcpy(pgm->type, "DRAGON_JTAG");
@@ -1984,3 +2223,32 @@ void jtagmkII_dragon_initpgm(PROGRAMMER * pgm)
pgm->set_sck_period = jtagmkII_set_sck_period;
pgm->page_size = 256;
}
void jtagmkII_dragon_dw_initpgm(PROGRAMMER * pgm)
{
strcpy(pgm->type, "DRAGON_DW");
/*
* mandatory functions
*/
pgm->initialize = jtagmkII_initialize;
pgm->display = jtagmkII_display;
pgm->enable = jtagmkII_enable;
pgm->disable = jtagmkII_disable;
pgm->program_enable = jtagmkII_program_enable_dummy;
pgm->chip_erase = jtagmkII_chip_erase_dw;
pgm->open = jtagmkII_dragon_open_dw;
pgm->close = jtagmkII_close;
pgm->read_byte = jtagmkII_read_byte;
pgm->write_byte = jtagmkII_write_byte_dw;
/*
* optional functions
*/
pgm->paged_write = jtagmkII_paged_write;
pgm->paged_load = jtagmkII_paged_load;
pgm->print_parms = jtagmkII_print_parms;
pgm->page_size = 256;
pgm->flag = PGM_FL_IS_DW;
}