/* Remote debugging interface for JTAG debugging protocol.
|
/* Remote debugging interface for JTAG debugging protocol.
|
Copyright 1993-1995, 2000 Free Software Foundation, Inc.
|
Copyright 1993-1995, 2000 Free Software Foundation, Inc.
|
Contributed by Cygnus Support. Written by Marko Mlinar
|
Contributed by Cygnus Support. Written by Marko Mlinar
|
<markom@opencores.org>
|
<markom@opencores.org>
|
|
|
This file is part of GDB.
|
This file is part of GDB.
|
|
|
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
the Free Software Foundation; either version 2 of the License, or
|
the Free Software Foundation; either version 2 of the License, or
|
(at your option) any later version.
|
(at your option) any later version.
|
|
|
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
GNU General Public License for more details.
|
GNU General Public License for more details.
|
|
|
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
Foundation, Inc., 59 Temple Place - Suite 330,
|
Foundation, Inc., 59 Temple Place - Suite 330,
|
Boston, MA 02111-1307, USA. */
|
Boston, MA 02111-1307, USA. */
|
|
|
#include "defs.h"
|
#include "defs.h"
|
#include "inferior.h"
|
#include "inferior.h"
|
#include "bfd.h"
|
#include "bfd.h"
|
#include "symfile.h"
|
#include "symfile.h"
|
#include "gdb_wait.h"
|
#include "gdb_wait.h"
|
#include "gdbcmd.h"
|
#include "gdbcmd.h"
|
#include "gdbcore.h"
|
#include "gdbcore.h"
|
#include "serial.h"
|
#include "serial.h"
|
#include "target.h"
|
#include "target.h"
|
#include "remote-utils.h"
|
#include "remote-utils.h"
|
#include "gdb_string.h"
|
#include "gdb_string.h"
|
#include "tm.h"
|
#include "tm.h"
|
|
|
#include <signal.h>
|
#include <signal.h>
|
#include <sys/types.h>
|
#include <sys/types.h>
|
#include <sys/stat.h>
|
#include <sys/stat.h>
|
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
#include <fcntl.h>
|
#include <fcntl.h>
|
|
|
#define TCLK 0x01
|
#define TCLK 0x01
|
#define TRST 0x02
|
#define TRST 0x02
|
#define JTAG_WAIT()
|
#define JTAG_WAIT()
|
#define NUM_RETRIES 16
|
#define NUM_RETRIES 16
|
#define JTAG_RETRY_WAIT() usleep (100);
|
#define JTAG_RETRY_WAIT() usleep (100);
|
|
|
/* Scan chain for risc debug interface. */
|
/* Scan chain for risc debug interface. */
|
#define SC_RISC_DEBUG 0x1
|
#define SC_RISC_DEBUG 0x1
|
#define SC_SIZE 4
|
#define SC_SIZE 4
|
|
|
/* Designates whether we are in SELECT_DR state, otherwise in
|
/* Designates whether we are in SELECT_DR state, otherwise in
|
RUN TEST/IDLE */
|
RUN TEST/IDLE */
|
static int select_dr = 0;
|
static int select_dr = 0;
|
|
|
/* Printer compatible device we have open. */
|
/* Printer compatible device we have open. */
|
static int lp;
|
static int lp;
|
|
|
/* Crc of current read or written data. */
|
/* Crc of current read or written data. */
|
static int crc_r, crc_w = 0;
|
static int crc_r, crc_w = 0;
|
|
|
/* Generates new crc, sending in new bit input_bit */
|
/* Generates new crc, sending in new bit input_bit */
|
static int
|
static int
|
crc_calc (int crc, int input_bit)
|
crc_calc (int crc, int input_bit)
|
{
|
{
|
int c;
|
int c;
|
int new_crc;
|
int new_crc;
|
int d;
|
int d;
|
|
|
d = input_bit&1;
|
d = input_bit&1;
|
c = crc;
|
c = crc;
|
|
|
/* Move queue left. */
|
/* Move queue left. */
|
new_crc = crc << 1;
|
new_crc = crc << 1;
|
/* Mask upper five bits. */
|
/* Mask upper five bits. */
|
new_crc &= 0xF8;
|
new_crc &= 0xF8;
|
|
|
/* Set lower three bits */
|
/* Set lower three bits */
|
new_crc |= (d ^ ((c >> 7)&1));
|
new_crc |= (d ^ ((c >> 7)&1));
|
new_crc |= (d ^ ((c >> 0)&1) ^ ((c >> 7)&1)) << 1;
|
new_crc |= (d ^ ((c >> 0)&1) ^ ((c >> 7)&1)) << 1;
|
new_crc |= (d ^ ((c >> 1)&1) ^ ((c >> 7)&1)) << 2;
|
new_crc |= (d ^ ((c >> 1)&1) ^ ((c >> 7)&1)) << 2;
|
return new_crc;
|
return new_crc;
|
}
|
}
|
|
|
/* Resets JTAG.
|
/* Resets JTAG.
|
Writes TRST=0
|
Writes TRST=0
|
and TRST=1 */
|
and TRST=1 */
|
|
|
static void
|
static void
|
jp1_reset_JTAG ()
|
jp1_reset_JTAG ()
|
{
|
{
|
unsigned char data;
|
unsigned char data;
|
data = 0;
|
data = 0;
|
write (lp, &data, sizeof (data));
|
write (lp, &data, sizeof (data));
|
JTAG_WAIT();
|
JTAG_WAIT();
|
data = TRST;
|
data = TRST;
|
write (lp, &data, sizeof (data));
|
write (lp, &data, sizeof (data));
|
JTAG_WAIT();
|
JTAG_WAIT();
|
}
|
}
|
|
|
/* Writes TCLK=0, TRST=1, TMS=bit0, TDI=bit1
|
/* Writes TCLK=0, TRST=1, TMS=bit0, TDI=bit1
|
and TCLK=1, TRST=1, TMS=bit0, TDI=bit1 */
|
and TCLK=1, TRST=1, TMS=bit0, TDI=bit1 */
|
|
|
static void
|
static void
|
jp1_write_JTAG (packet)
|
jp1_write_JTAG (packet)
|
unsigned char packet;
|
unsigned char packet;
|
{
|
{
|
unsigned char data;
|
unsigned char data;
|
data = ((packet & 3) << 2) | TRST;
|
data = ((packet & 3) << 2) | TRST;
|
write (lp, &data, sizeof (data));
|
write (lp, &data, sizeof (data));
|
JTAG_WAIT();
|
JTAG_WAIT();
|
crc_w = crc_calc (crc_w, (packet >> 1)&1);
|
crc_w = crc_calc (crc_w, (packet >> 1)&1);
|
|
|
/* rise clock */
|
/* rise clock */
|
data |= TCLK;
|
data |= TCLK;
|
write (lp, &data, sizeof (data));
|
write (lp, &data, sizeof (data));
|
JTAG_WAIT();
|
JTAG_WAIT();
|
}
|
}
|
|
|
/* Reads TDO, using IOCTL. */
|
/* Reads TDO, using IOCTL. */
|
|
|
static int
|
static int
|
jp1_read_JTAG ()
|
jp1_read_JTAG ()
|
{
|
{
|
int data;
|
int data;
|
ioctl(data, 0x60b, &data);
|
ioctl(data, 0x60b, &data);
|
data = ((data & 0x80) != 0);
|
data = ((data & 0x80) != 0);
|
crc_r = crc_calc (crc_r, data);
|
crc_r = crc_calc (crc_r, data);
|
return data;
|
return data;
|
}
|
}
|
|
|
/* Writes bitstream. MS bit first. */
|
/* Writes bitstream. MS bit first. */
|
|
|
static void
|
static void
|
jp1_write_stream (stream, len, set_last_bit)
|
jp1_write_stream (stream, len, set_last_bit)
|
unsigned long stream;
|
unsigned long stream;
|
int len;
|
int len;
|
int set_last_bit;
|
int set_last_bit;
|
{
|
{
|
int i;
|
int i;
|
if (len <= 0) return;
|
if (len <= 0) return;
|
for (i = len - 1; i > 0; i--)
|
for (i = len - 1; i > 0; i--)
|
jp1_write_JTAG (((stream >> i) & 1) << 1);
|
jp1_write_JTAG (((stream >> i) & 1) << 1);
|
|
|
if (set_last_bit)
|
if (set_last_bit)
|
jp1_write_JTAG (((stream & 1) << 1) | 1);
|
jp1_write_JTAG (((stream & 1) << 1) | 1);
|
else
|
else
|
jp1_write_JTAG ((stream & 1) << 1);
|
jp1_write_JTAG ((stream & 1) << 1);
|
}
|
}
|
|
|
/* Gets bitstream. MS bit first. */
|
/* Gets bitstream. MS bit first. */
|
|
|
static unsigned long
|
static unsigned long
|
jp1_read_stream (len, stream, set_last_bit)
|
jp1_read_stream (len, stream, set_last_bit)
|
int len;
|
int len;
|
unsigned long stream;
|
unsigned long stream;
|
int set_last_bit;
|
int set_last_bit;
|
{
|
{
|
int i;
|
int i;
|
unsigned long data;
|
unsigned long data;
|
|
|
if (len <= 0) return;
|
if (len <= 0) return;
|
data = 0;
|
data = 0;
|
for (i = 0; i < len-1; i++)
|
for (i = 0; i < len-1; i++)
|
{
|
{
|
jp1_write_JTAG (0 + ((stream & 1) << 1));
|
jp1_write_JTAG (0 + ((stream & 1) << 1));
|
stream >>= 1;
|
stream >>= 1;
|
data <<= 1;
|
data <<= 1;
|
data |= jp1_read_JTAG ();
|
data |= jp1_read_JTAG ();
|
}
|
}
|
|
|
if (set_last_bit)
|
if (set_last_bit)
|
jp1_write_JTAG (1 + (stream & 1) << 1);
|
jp1_write_JTAG (1 + (stream & 1) << 1);
|
else
|
else
|
jp1_write_JTAG (0 + (stream & 1) << 1);
|
jp1_write_JTAG (0 + (stream & 1) << 1);
|
data <<= 1;
|
data <<= 1;
|
data |= jp1_read_JTAG ();
|
data |= jp1_read_JTAG ();
|
return data;
|
return data;
|
}
|
}
|
|
|
/* Goes into SELECT_IR state. Should be called before every control write. */
|
/* Goes into SELECT_IR state. Should be called before every control write. */
|
|
|
static void
|
static void
|
jp1_prepare_control ()
|
jp1_prepare_control ()
|
{
|
{
|
if (!select_dr)
|
if (!select_dr)
|
jp1_write_JTAG (1); /* SELECT_DR SCAN */
|
jp1_write_JTAG (1); /* SELECT_DR SCAN */
|
jp1_write_JTAG (1); /* SELECT_IR SCAN */
|
jp1_write_JTAG (1); /* SELECT_IR SCAN */
|
select_dr = 0;
|
select_dr = 0;
|
}
|
}
|
|
|
/* Sets register/memory regno to data. */
|
/* Sets register/memory regno to data. */
|
|
|
void
|
void
|
jtag_write_reg (regno, data)
|
jtag_write_reg (regno, data)
|
int regno;
|
int regno;
|
unsigned int data;
|
unsigned int data;
|
{
|
{
|
int crc_read, crc_write, crc_ok, retry;
|
int crc_read, crc_write, crc_ok, retry;
|
|
|
if (!select_dr)
|
if (!select_dr)
|
jp1_write_JTAG (1); /* SELECT_DR SCAN */
|
jp1_write_JTAG (1); /* SELECT_DR SCAN */
|
select_dr = 1;
|
select_dr = 1;
|
|
|
for (retry = 0; retry < NUM_RETRIES; retry++)
|
for (retry = 0; retry < NUM_RETRIES; retry++)
|
{
|
{
|
jp1_write_JTAG (0); /* CAPTURE_DR */
|
jp1_write_JTAG (0); /* CAPTURE_DR */
|
jp1_write_JTAG (0); /* SHIFT_DR */
|
jp1_write_JTAG (0); /* SHIFT_DR */
|
crc_w = 0;
|
crc_w = 0;
|
jp1_write_stream (regno, 32, 0); /* addr32 */
|
jp1_write_stream (regno, 32, 0); /* addr32 */
|
jp1_write_JTAG (2); /* write (R/W=1) */
|
jp1_write_JTAG (2); /* write (R/W=1) */
|
jp1_write_stream (data, 32, 0); /* data32 */
|
jp1_write_stream (data, 32, 0); /* data32 */
|
crc_write = crc_w;
|
crc_write = crc_w;
|
crc_read = jp1_read_stream (crc_write, 8, 1); /* write CRC, EXIT1_DR */
|
crc_read = jp1_read_stream (crc_write, 8, 1); /* write CRC, EXIT1_DR */
|
jp1_write_JTAG (1); /* UPDATE_DR */
|
jp1_write_JTAG (1); /* UPDATE_DR */
|
crc_ok = jp1_read_JTAG (); /* Did JTAG receive packet correctly? */
|
crc_ok = jp1_read_JTAG (); /* Did JTAG receive packet correctly? */
|
jp1_write_JTAG (1); /* SELECT_DR */
|
jp1_write_JTAG (1); /* SELECT_DR */
|
if ((crc_read == crc_write) && (crc_ok))
|
if ((crc_read == crc_write) && (crc_ok))
|
return;
|
return;
|
JTAG_RETRY_WAIT();
|
JTAG_RETRY_WAIT();
|
}
|
}
|
err = ERR_CRC;
|
err = ERR_CRC;
|
}
|
}
|
|
|
/* Reads register/memory from regno. */
|
/* Reads register/memory from regno. */
|
|
|
unsigned int
|
unsigned int
|
jtag_read_reg (regno)
|
jtag_read_reg (regno)
|
unsigned int regno;
|
unsigned int regno;
|
{
|
{
|
unsigned int data;
|
unsigned int data;
|
int crc_read, crc_write, crc_actual_read, retry, crc_ok;
|
int crc_read, crc_write, crc_actual_read, retry, crc_ok;
|
|
|
if (!select_dr)
|
if (!select_dr)
|
jp1_write_JTAG (1); /* SELECT_DR SCAN */
|
jp1_write_JTAG (1); /* SELECT_DR SCAN */
|
select_dr = 1;
|
select_dr = 1;
|
|
|
for (retry = 0; retry < NUM_RETRIES; retry++)
|
for (retry = 0; retry < NUM_RETRIES; retry++)
|
{
|
{
|
jp1_write_JTAG (0); /* CAPTURE_DR */
|
jp1_write_JTAG (0); /* CAPTURE_DR */
|
jp1_write_JTAG (0); /* SHIFT_DR */
|
jp1_write_JTAG (0); /* SHIFT_DR */
|
crc_w = 0;
|
crc_w = 0;
|
jp1_write_stream (regno, 32, 0); /* addr32 */
|
jp1_write_stream (regno, 32, 0); /* addr32 */
|
jp1_write_JTAG (0); /* read (R/W=0) */
|
jp1_write_JTAG (0); /* read (R/W=0) */
|
crc_r = 0;
|
crc_r = 0;
|
data = jp1_read_stream (0, 32, 0); /* data32=0 */
|
data = jp1_read_stream (0, 32, 0); /* data32=0 */
|
crc_write = crc_w;
|
crc_write = crc_w;
|
crc_actual_read = crc_read;
|
crc_actual_read = crc_read;
|
crc_read = jp1_read_stream (crc_write, 8, 1); /* Send my crc, EXIT1_DR */
|
crc_read = jp1_read_stream (crc_write, 8, 1); /* Send my crc, EXIT1_DR */
|
|
|
jp1_write_JTAG (1); /* UPDATE_DR */
|
jp1_write_JTAG (1); /* UPDATE_DR */
|
crc_ok = jp1_read_JTAG (); /* Did JTAG receive packet correctly? */
|
crc_ok = jp1_read_JTAG (); /* Did JTAG receive packet correctly? */
|
jp1_write_JTAG (1); /* SELECT_DR */
|
jp1_write_JTAG (1); /* SELECT_DR */
|
if ((crc_read == crc_actual_read) && (crc_ok))
|
if ((crc_read == crc_actual_read) && (crc_ok))
|
return;
|
return;
|
JTAG_RETRY_WAIT();
|
JTAG_RETRY_WAIT();
|
}
|
}
|
err = ERR_CRC;
|
err = ERR_CRC;
|
}
|
}
|
|
|
/* Initialize a new connection to the or1k board, and make sure we are
|
/* Initialize a new connection to the or1k board, and make sure we are
|
really connected. */
|
really connected. */
|
|
|
void
|
void
|
jtag_init (args)
|
jtag_init (args)
|
char * args;
|
char * args;
|
{
|
{
|
char *ptype;
|
char *ptype;
|
char *port_name;
|
char *port_name;
|
char **argv;
|
char **argv;
|
|
|
if (args == 0)
|
if (args == 0)
|
error ( "To open a or1k remote debugging connection, you need to specify what parallel\n"
|
error ( "To open a or1k remote debugging connection, you need to specify what parallel\n"
|
"port device is attached to the target board (e.g., /dev/lp0).\n");
|
"port device is attached to the target board (e.g., /dev/lp0).\n");
|
|
|
/* Parse the serial port name. */
|
/* Parse the serial port name. */
|
if ((argv = buildargv (args)) == NULL)
|
if ((argv = buildargv (args)) == NULL)
|
nomem (0);
|
nomem (0);
|
port_name = strsave (argv[0]);
|
port_name = strsave (argv[0]);
|
make_cleanup_freeargv (argv);
|
make_cleanup_freeargv (argv);
|
|
|
/* Open and initialize the parallel port. */
|
/* Open and initialize the parallel port. */
|
lp = open (port_name, O_WRONLY);
|
lp = open (port_name, O_WRONLY);
|
if (lp < 0)
|
if (lp < 0)
|
error ("Cannot open device.");
|
error ("Cannot open device.");
|
|
|
printf_unfiltered ("Remote or1k debugging using %s\n", port_name);
|
printf_unfiltered ("Remote or1k debugging using %s\n", port_name);
|
|
|
jp1_reset_JTAG ();
|
jp1_reset_JTAG ();
|
jp1_prepare_control ();
|
jp1_prepare_control ();
|
jp1_write_stream (SC_RISC_DEBUG, SC_SIZE, 1);
|
jp1_write_stream (SC_RISC_DEBUG, SC_SIZE, 1);
|
free (port_name);
|
free (port_name);
|
}
|
}
|
|
|
void
|
void
|
jtag_done ()
|
jtag_done ()
|
{
|
{
|
close (lp);
|
close (lp);
|
}
|
}
|
|
|