URL
https://opencores.org/ocsvn/adv_debug_sys/adv_debug_sys/trunk
Subversion Repositories adv_debug_sys
Compare Revisions
- This comparison shows the changes necessary to convert path
/adv_debug_sys
- from Rev 65 to Rev 66
- ↔ Reverse comparison
Rev 65 → Rev 66
/tags/ADS_RELEASE_3_0_0/Software/adv_jtag_bridge/cable_xpc_dlc9.h
0,0 → 1,25
|
#ifndef _CABLE_XPC_DLC9_H_ |
#define _CABLE_XPC_DLC9_H_ |
|
#include <stdint.h> |
#include "cable_common.h" |
|
int cable_xpcusb_out(uint8_t value); |
int cable_xpcusb_inout(uint8_t value, uint8_t *inval); |
|
int cable_xpcusb_write_bit(uint8_t packet_out); |
int cable_xpcusb_read_write_bit(uint8_t packet_out, uint8_t *bit_in); |
|
int cable_xpcusb_cpld_write_bit(uint8_t value); |
int cable_xpcusb_cpld_readwrite_bit(uint8_t value, uint8_t *inval); |
|
int cable_xpcusb_write_stream(uint32_t *outstream, int len_bits, int set_last_bit); |
int cable_xpcusb_readwrite_stream(uint32_t *outstream, uint32_t *instream, int len_bits, int set_last_bit); |
|
int cable_xpcusb_opt(int c, char *str); |
jtag_cable_t *cable_xpcusb_get_driver(void); |
|
int cable_xpcusb_init(); |
|
#endif |
/tags/ADS_RELEASE_3_0_0/Software/adv_jtag_bridge/utilities.c
0,0 → 1,69
|
#include <stdlib.h> |
#include <stdio.h> |
#include <string.h> |
|
#include "utilities.h" |
#include "errcodes.h" |
|
|
int check_buffer_size(char **buf, int *buf_size_bytes, int requested_size_bytes) |
{ |
int ret = APP_ERR_NONE; |
|
if(*buf_size_bytes >= requested_size_bytes) |
{ |
return APP_ERR_NONE; |
} |
|
free(*buf); |
*buf = (char *) malloc(requested_size_bytes); |
if(*buf != NULL) { |
*buf_size_bytes = requested_size_bytes; |
} |
else { |
*buf_size_bytes = 0; |
ret = APP_ERR_MALLOC; |
} |
|
return ret; |
} |
|
|
int create_timer(timeout_timer * timer) |
{ |
int r; |
//first timer alarm |
timer->wait_time.it_value.tv_sec = 1; |
timer->wait_time.it_value.tv_nsec = 0; |
//continuous timer alarm -> 0 (we only want one alarm) |
timer->wait_time.it_interval.tv_sec = 0; |
timer->wait_time.it_interval.tv_nsec = 0; |
|
timer->sev.sigev_notify = SIGEV_NONE; |
|
r = timer_create(CLOCK_REALTIME, &timer->sev, &timer->timer); |
if ( r ) |
{ |
fprintf(stderr, "Timer for timeout failed: %s\n", strerror(r)); |
return APP_ERR_USB; |
} |
|
//remaining timer time |
timer->remaining_time = timer->wait_time; |
r = timer_settime(timer->timer, 0, &timer->wait_time, NULL); |
if ( r ) |
{ |
fprintf(stderr, "Setting timer failed: %s\n", strerror(r)); |
return APP_ERR_USB; |
} |
return APP_ERR_NONE; |
} |
|
int timedout(timeout_timer * timer) |
{ |
int timed_out = 0; |
timer_gettime(timer->timer, &timer->remaining_time); |
timed_out = timer->remaining_time.it_value.tv_sec == 0 && timer->remaining_time.it_value.tv_nsec == 0; |
return timed_out; |
} |
/tags/ADS_RELEASE_3_0_0/Software/adv_jtag_bridge/cable_sim.c
0,0 → 1,305
/* cable_sim.c - Simulation connection drivers for the Advanced JTAG Bridge |
Copyright (C) 2001 Marko Mlinar, markom@opencores.org |
|
|
|
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 |
along with this program; if not, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
|
|
#include <stdio.h> |
#include <string.h> |
#include <sys/types.h> |
#include <unistd.h> |
#include <errno.h> |
#include <stdlib.h> |
|
#include <sys/socket.h> |
#include <netinet/in.h> |
#include <netdb.h> |
|
#include "cable_sim.h" |
#include "errcodes.h" |
|
#define debug(...) //fprintf(stderr, __VA_ARGS__ ) |
|
/* Only used in the vpi */ |
jtag_cable_t vpi_cable_driver = { |
.name = "vpi", |
.inout_func = cable_vpi_inout, |
.out_func = cable_vpi_out, |
.init_func = cable_vpi_init, |
.opt_func = cable_vpi_opt, |
.bit_out_func = cable_common_write_bit, |
.bit_inout_func = cable_common_read_write_bit, |
.stream_out_func = cable_common_write_stream, |
.stream_inout_func = cable_common_read_stream, |
.flush_func = NULL, |
.opts = "s:p:", |
.help = "-p [port] Port number that the VPI module is listening on\n\t-s [server] Server that the VPI module is running on\n", |
}; |
|
static int vpi_comm; |
static int vpi_port = 4567; |
static char *vpi_server = "localhost"; |
|
/* Only used for the rtl_sim */ |
jtag_cable_t rtl_cable_driver = { |
.name ="rtl_sim", |
.inout_func = cable_rtl_sim_inout, |
.out_func = cable_rtl_sim_out, |
.init_func = cable_rtl_sim_init, |
.opt_func = cable_rtl_sim_opt, |
.bit_out_func = cable_common_write_bit, |
.bit_inout_func = cable_common_read_write_bit, |
.stream_out_func = cable_common_write_stream, |
.stream_inout_func = cable_common_read_stream, |
.flush_func = NULL, |
.opts = "d:", |
.help = "-d [directory] Directory in which gdb_in.dat/gdb_out.dat may be found\n" |
}; |
|
static char *gdb_in = "gdb_in.dat"; |
static char *gdb_out = "gdb_out.dat"; |
|
|
|
/*-------------------------------------------[ rtl_sim specific functions ]---*/ |
jtag_cable_t *cable_rtl_get_driver(void) |
{ |
return &rtl_cable_driver; |
} |
|
int cable_rtl_sim_init() |
{ |
FILE *fin = fopen (gdb_in, "wt+"); |
if(!fin) { |
fprintf(stderr, "Can not open %s\n", gdb_in); |
return APP_ERR_INIT_FAILED; |
} |
fclose(fin); |
return APP_ERR_NONE; |
} |
|
int cable_rtl_sim_out(uint8_t value) |
{ |
FILE *fout; |
int num_read; |
int r; |
debug("O (%x)\n", value); |
fout = fopen(gdb_in, "wt+"); |
fprintf(fout, "F\n"); |
fflush(fout); |
fclose(fout); |
fout = fopen(gdb_out, "wt+"); |
fprintf(fout, "%02X\n", value); |
fflush(fout); |
fclose(fout); |
do { |
fout = fopen(gdb_out, "rt"); |
r = fscanf(fout,"%x", &num_read); |
fclose(fout); |
usleep(1000); |
debug(" (Ack %x) ", num_read); |
} while(!r || (num_read != (0x10 | value))); |
debug("\n"); |
return APP_ERR_NONE; |
} |
|
int cable_rtl_sim_inout(uint8_t value, uint8_t *inval) |
{ |
FILE *fin = 0; |
char ch; |
uint8_t data; |
debug("IO ("); |
|
while(1) { |
fin = fopen(gdb_in, "rt"); |
if(!fin) { |
usleep(1000); |
continue; |
} |
ch = fgetc(fin); |
fclose(fin); |
if((ch != '0') && (ch != '1')) { |
usleep(1000); |
continue; |
} |
else |
break; |
} |
data = ch == '1' ? 1 : 0; |
|
debug("%x,", data); |
|
cable_rtl_sim_out(value); |
|
debug("%x)\n", value); |
|
*inval = data; |
return APP_ERR_NONE; |
} |
|
|
int cable_rtl_sim_opt(int c, char *str) |
{ |
switch(c) { |
case 'd': |
if(!(gdb_in = malloc(strlen(str) + 12))) { /* 12 == strlen("gdb_in.dat") + 2 */ |
fprintf(stderr, "Unable to allocate enough memory\n"); |
return APP_ERR_MALLOC; |
} |
if(!(gdb_out = malloc(strlen(str) + 13))) { /* 13 == strlen("gdb_out.dat") + 2 */ |
fprintf(stderr, "Unable to allocate enough memory\n"); |
free(gdb_in); |
return APP_ERR_MALLOC; |
} |
|
sprintf(gdb_in, "%s/gdb_in.dat", str); |
sprintf(gdb_out, "%s/gdb_out.dat", str); |
break; |
default: |
fprintf(stderr, "Unknown parameter '%c'\n", c); |
return APP_ERR_BAD_PARAM; |
} |
return APP_ERR_NONE; |
} |
|
/*-----------------------------------------------[ VPI specific functions ]---*/ |
jtag_cable_t *cable_vpi_get_driver(void) |
{ |
return &vpi_cable_driver; |
} |
|
|
int cable_vpi_init() |
{ |
struct sockaddr_in addr; |
struct hostent *he; |
|
if((vpi_comm = socket(PF_INET, SOCK_STREAM, 0)) < 0) { |
fprintf(stderr, "Unable to create socket (%s)\n", strerror(errno)); |
return APP_ERR_CONNECT; |
} |
|
|
if((he = gethostbyname(vpi_server)) == NULL) { |
perror("gethostbyname"); |
return APP_ERR_CONNECT; |
} |
|
addr.sin_family = AF_INET; |
addr.sin_port = htons(vpi_port); |
addr.sin_addr = *((struct in_addr *)he->h_addr); |
memset(addr.sin_zero, '\0', sizeof(addr.sin_zero)); |
|
if(connect(vpi_comm, (struct sockaddr *)&addr, sizeof(addr)) == -1) { |
fprintf(stderr, "Unable to connect to %s port %d (%s)\n", vpi_server, vpi_port, |
strerror(errno)); |
return APP_ERR_CONNECT; |
} |
|
debug("VPI connected!"); |
|
return APP_ERR_NONE; |
} |
|
int cable_vpi_out(uint8_t value) |
{ |
uint8_t ack; |
int ret; |
|
/* Send the data to the socket */ |
ret = send(vpi_comm, &value, 1, 0); |
debug("Sent %d, ret %d\n", value, ret); |
|
do { |
/* Ok, read the data */ |
ret = recv(vpi_comm, &ack, 1, 0); |
if(ret < 0) { |
printf("Error during receive (%s)\n", strerror(errno)); |
return APP_ERR_CONNECT; |
} |
} while(ack != (value | 0x10)); |
|
cable_vpi_wait(); // finish the transaction |
|
return APP_ERR_NONE; |
} |
|
int cable_vpi_inout(uint8_t value, uint8_t *inval) |
{ |
uint8_t dat; |
|
/* ask vpi to send us the out-bit */ |
dat = 0x80; |
send(vpi_comm, &dat, 1, 0); |
|
/* Wait and read the data */ |
recv(vpi_comm, &dat, 1, 0); |
|
if(dat > 1) |
fprintf(stderr, "Unexpected value: %i\n", dat); |
|
cable_vpi_out(value); |
|
*inval = dat; |
|
cable_vpi_wait(); // finish the transaction |
|
return APP_ERR_NONE; |
} |
|
void cable_vpi_wait() |
{ |
uint8_t dat = 0x81; |
|
/* Get the sim to reply when the timeout has been reached */ |
if(send(vpi_comm, &dat, 1, 0) < 1) { |
fprintf(stderr, "Failed to send pkt in cable_vpi_wait(): %s\n", strerror(errno)); |
} |
|
/* block, waiting for the data */ |
if(recv(vpi_comm, &dat, 1, 0) < 1) { |
fprintf(stderr, "Recv failed in cable_vpi_wait(): %s\n", strerror(errno)); |
} |
|
if(dat != 0xFF) |
fprintf(stderr, "Warning: got wrong byte waiting for timeout: 0x%X\n", dat); |
|
} |
|
int cable_vpi_opt(int c, char *str) |
{ |
switch(c) { |
case 'p': |
if((vpi_port = atoi(str)) == 0) { |
fprintf(stderr, "Bad port value for VPI sim: %s\n", str); |
return APP_ERR_BAD_PARAM; |
} |
break; |
case 's': |
vpi_server = strdup(str); |
if(vpi_server == NULL) { |
fprintf(stderr, "Unable to allocate enough memory for server string\n"); |
return APP_ERR_MALLOC; |
} |
break; |
default: |
fprintf(stderr, "Unknown parameter '%c'\n", c); |
return APP_ERR_BAD_PARAM; |
} |
return APP_ERR_NONE; |
} |
/tags/ADS_RELEASE_3_0_0/Software/adv_jtag_bridge/cable_common.c
0,0 → 1,279
/* cable_common.c -- Interface to the low-level cable drivers |
Copyright (C) 2001 Marko Mlinar, markom@opencores.org |
|
Copyright (C) 2008 - 2010 Nathan Yawn, nathan.yawn@opencores.org |
|
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 |
along with this program; if not, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
|
|
#include <stdio.h> |
#include <string.h> |
|
|
#include "cable_common.h" |
#include "cable_sim.h" |
|
#ifdef __SUPPORT_PARALLEL_CABLES__ |
#include "cable_parallel.h" |
#endif |
|
#ifdef __SUPPORT_USB_CABLES__ |
#include "cable_usbblaster.h" |
#include "cable_xpc_dlc9.h" |
|
#ifdef __SUPPORT_FTDI_CABLES__ |
#include "cable_ft245.h" |
#include "cable_ft2232.h" |
#endif |
|
#endif |
|
#include "errcodes.h" |
|
#define debug(...) //fprintf(stderr, __VA_ARGS__ ) |
|
#define JTAG_MAX_CABLES 16 |
jtag_cable_t *jtag_cables[JTAG_MAX_CABLES]; |
|
static jtag_cable_t *jtag_cable_in_use = NULL; /* The currently selected cable */ |
|
|
///////////////////////////////////////////////////////////////////////////////////// |
// Cable subsystem / init functions |
|
void cable_setup(void) |
{ |
int i = 0; |
|
memset(jtag_cables, 0, sizeof(jtag_cables)); |
|
jtag_cables[i++] = cable_rtl_get_driver(); |
jtag_cables[i++] = cable_vpi_get_driver(); |
|
#ifdef __SUPPORT_PARALLEL_CABLES__ |
jtag_cables[i++] = cable_xpc3_get_driver(); |
jtag_cables[i++] = cable_bb2_get_driver(); |
jtag_cables[i++] = cable_xess_get_driver(); |
#endif |
|
#ifdef __SUPPORT_USB_CABLES__ |
jtag_cables[i++] = cable_usbblaster_get_driver(); |
jtag_cables[i++] = cable_xpcusb_get_driver(); |
#ifdef __SUPPORT_FTDI_CABLES__ |
jtag_cables[i++] = cable_ftdi_get_driver(); |
jtag_cables[i++] = cable_ft245_get_driver(); |
#endif |
#endif |
} |
|
/* Selects a cable for use */ |
int cable_select(const char *cable) |
{ |
int i; |
|
for(i = 0; jtag_cables[i] != NULL; i++) { |
if(!strcmp(cable, jtag_cables[i]->name)) { |
jtag_cable_in_use = jtag_cables[i]; |
return APP_ERR_NONE; |
} |
} |
|
return APP_ERR_CABLE_INVALID; |
} |
|
/* Calls the init function of the cable |
*/ |
int cable_init() |
{ |
return jtag_cable_in_use->init_func(); |
} |
|
/* Parses command-line options specific to the selected cable */ |
int cable_parse_opt(int c, char *str) |
{ |
return jtag_cable_in_use->opt_func(c, str); |
} |
|
const char *cable_get_args() |
{ |
if(jtag_cable_in_use != NULL) |
return jtag_cable_in_use->opts; |
else |
return NULL; |
} |
|
/* Prints a (short) useage message for each available cable */ |
void cable_print_help() |
{ |
int i; |
printf("Available cables: "); |
|
for(i = 0; jtag_cables[i]; i++) { |
if(i) |
printf(", "); |
printf("%s", jtag_cables[i]->name); |
} |
|
printf("\n\nOptions availible for the cables:\n"); |
for(i = 0; jtag_cables[i]; i++) { |
if(!jtag_cables[i]->help) |
continue; |
printf(" %s:\n %s", jtag_cables[i]->name, jtag_cables[i]->help); |
} |
} |
|
|
///////////////////////////////////////////////////////////////////////////////// |
// Cable API Functions |
|
int cable_write_stream(uint32_t *stream, int len_bits, int set_last_bit) { |
return jtag_cable_in_use->stream_out_func(stream, len_bits, set_last_bit); |
} |
|
int cable_read_write_stream(uint32_t *outstream, uint32_t *instream, int len_bits, int set_last_bit) { |
return jtag_cable_in_use->stream_inout_func(outstream, instream, len_bits, set_last_bit); |
} |
|
int cable_write_bit(uint8_t packet) { |
return jtag_cable_in_use->bit_out_func(packet); |
} |
|
int cable_read_write_bit(uint8_t packet_out, uint8_t *bit_in) { |
return jtag_cable_in_use->bit_inout_func(packet_out, bit_in); |
} |
|
int cable_flush(void) { |
if(jtag_cable_in_use->flush_func != NULL) |
return jtag_cable_in_use->flush_func(); |
return APP_ERR_NONE; |
} |
|
|
///////////////////////////////////////////////////////////////////////////////////// |
// Common functions which may or may not be used by individual drivers |
|
|
/* Note that these make no assumption as to the starting state of the clock, |
* and they leave the clock HIGH. But, these need to interface with other routines (like |
* the byte-shift mode in the USB-Blaster), which begin by assuming that a new |
* data bit is available at TDO, which only happens after a FALLING edge of TCK. |
* So, routines which assume new data is available will need to start by dropping |
* the clock. |
*/ |
int cable_common_write_bit(uint8_t packet) { |
uint8_t data = TRST_BIT; // TRST is active low, don't clear unless /set/ in 'packet' |
int err = APP_ERR_NONE; |
|
/* Write data, drop clock */ |
if(packet & TDO) data |= TDI_BIT; |
if(packet & TMS) data |= TMS_BIT; |
if(packet & TRST) data &= ~TRST_BIT; |
|
err |= jtag_cable_in_use->out_func(data); |
|
/* raise clock, to do write */ |
err |= jtag_cable_in_use->out_func(data | TCLK_BIT); |
|
return err; |
} |
|
int cable_common_read_write_bit(uint8_t packet_out, uint8_t *bit_in) { |
uint8_t data = TRST_BIT; // TRST is active low, don't clear unless /set/ in 'packet' |
int err = APP_ERR_NONE; |
|
/* Write data, drop clock */ |
if(packet_out & TDO) data |= TDI_BIT; |
if(packet_out & TMS) data |= TMS_BIT; |
if(packet_out & TRST) data &= ~TRST_BIT; |
|
err |= jtag_cable_in_use->out_func(data); // drop the clock to make data available, set the out data |
err |= jtag_cable_in_use->inout_func((data | TCLK_BIT), bit_in); // read in bit, clock high for out bit. |
|
return err; |
} |
|
|
/* Writes bitstream via bit-bang. Can be used by any driver which does not have a high-speed transfer function. |
* Transfers LSB to MSB of stream[0], then LSB to MSB of stream[1], etc. |
*/ |
int cable_common_write_stream(uint32_t *stream, int len_bits, int set_last_bit) { |
int i; |
int index = 0; |
int bits_this_index = 0; |
uint8_t out; |
int err = APP_ERR_NONE; |
|
debug("writeStrm%d(", len_bits); |
for(i = 0; i < len_bits - 1; i++) { |
out = (stream[index] >> bits_this_index) & 1; |
err |= cable_write_bit(out); |
debug("%i", out); |
bits_this_index++; |
if(bits_this_index >= 32) { |
index++; |
bits_this_index = 0; |
} |
} |
|
out = (stream[index] >>(len_bits - 1)) & 0x1; |
if(set_last_bit) out |= TMS; |
err |= cable_write_bit(out); |
debug("%i)\n", out); |
return err; |
} |
|
/* Gets bitstream via bit-bang. Can be used by any driver which does not have a high-speed transfer function. |
* Transfers LSB to MSB of stream[0], then LSB to MSB of stream[1], etc. |
*/ |
int cable_common_read_stream(uint32_t *outstream, uint32_t *instream, int len_bits, int set_last_bit) { |
int i; |
int index = 0; |
int bits_this_index = 0; |
uint8_t inval, outval; |
int err = APP_ERR_NONE; |
|
instream[0] = 0; |
|
debug("readStrm%d(", len_bits); |
for(i = 0; i < (len_bits - 1); i++) { |
outval = (outstream[index] >> bits_this_index) & 0x1; |
err |= cable_read_write_bit(outval, &inval); |
debug("%i", inval); |
instream[index] |= (inval << bits_this_index); |
bits_this_index++; |
if(bits_this_index >= 32) { |
index++; |
bits_this_index = 0; |
instream[index] = 0; // It's safe to do this, because there's always at least one more bit |
} |
} |
|
if (set_last_bit) |
outval = ((outstream[index] >> (len_bits - 1)) & 1) | TMS; |
else |
outval = (outstream[index] >> (len_bits - 1)) & 1; |
|
err |= cable_read_write_bit(outval, &inval); |
debug("%i", inval); |
instream[index] |= (inval << bits_this_index); |
|
debug(") = 0x%lX\n", instream[0]); |
|
return err; |
} |
|
|
|
/tags/ADS_RELEASE_3_0_0/Software/adv_jtag_bridge/utilities.h
0,0 → 1,21
|
#ifndef _UTILITIES_H_ |
#define _UTILITIES_H_ |
|
#include <time.h> // for timer |
#include <signal.h> // for timer |
|
typedef struct |
{ |
timer_t timer; |
struct sigevent sev; |
struct itimerspec wait_time; |
struct itimerspec remaining_time; |
} timeout_timer; |
|
int create_timer(timeout_timer * timer); |
int timedout(timeout_timer * timer); |
|
int check_buffer_size(char **buf, int *buf_size_bytes, int requested_size_bytes); |
|
#endif |
/tags/ADS_RELEASE_3_0_0/Software/adv_jtag_bridge/cable_parallel.c
0,0 → 1,546
/* cable_parallel.c - Parallel cable drivers (XPC3 and XESS) for the Advanced JTAG Bridge |
Copyright (C) 2001 Marko Mlinar, markom@opencores.org |
Copyright (C) 2004 Gy�rgy Jeney, nog@sdf.lonestar.org |
|
UNIX parallel port control through device file added by: |
Copyright (C) 2011 Raul Fajardo, rfajardo@opencores.org |
|
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 |
along with this program; if not, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
|
#include <stdio.h> |
#include <sys/types.h> |
#include <sys/time.h> |
#include <unistd.h> |
#include <time.h> |
#include <string.h> |
|
#ifdef __LINUX_HOST__ |
#include <sys/stat.h> |
#include <fcntl.h> |
#include <sys/ioctl.h> |
#include <linux/ppdev.h> |
#include <linux/parport.h> |
#endif |
|
#ifdef __CYGWIN_HOST__ |
#include <sys/io.h> // for inb(), outb() |
#endif |
|
#ifdef __FREEBSD_HOST__ |
#include <fcntl.h> |
#include <sys/ioctl.h> |
#include <sys/dev/ppbus/ppi.h> |
#include <sys/dev/ppbus/ppbconf.h> |
#endif |
|
#include "cable_parallel.h" |
#include "errcodes.h" |
|
#ifdef __PARALLEL_TIMER_BUSY_WAIT__ |
#if ((_POSIX_TIMERS) && (_POSIX_CPUTIME)) |
#define PARALLEL_USE_PROCESS_TIMER |
#endif |
#endif |
|
jtag_cable_t xpc3_cable_driver = { |
.name = "xpc3", |
.inout_func = cable_xpc3_inout, |
.out_func = cable_xpc3_out, |
.init_func = cable_parallel_init, |
.opt_func = cable_parallel_opt, |
.bit_out_func = cable_common_write_bit, |
.bit_inout_func = cable_common_read_write_bit, |
.stream_out_func = cable_common_write_stream, |
.stream_inout_func = cable_common_read_stream, |
.flush_func = NULL, |
#ifdef __CYGWIN_HOST__ |
.opts = "p:", |
.help = "-p [port] Which port to use when communicating with the parport hardware (eg. 0x378)\n" |
#else |
.opts = "d:", |
.help = "-d [device file] Device file to use when communicating with the parport hardware (eg. /dev/parport0)\n" |
#endif |
}; |
|
jtag_cable_t bb2_cable_driver = { |
.name = "bb2", |
.inout_func = cable_bb2_inout, |
.out_func = cable_bb2_out, |
.init_func = cable_parallel_init, |
.opt_func = cable_parallel_opt, |
.bit_out_func = cable_common_write_bit, |
.bit_inout_func = cable_common_read_write_bit, |
.stream_out_func = cable_common_write_stream, |
.stream_inout_func = cable_common_read_stream, |
.flush_func = NULL, |
#ifdef __CYGWIN_HOST__ |
.opts = "p:", |
.help = "-p [port] Which port to use when communicating with the parport hardware (eg. 0x378)\n" |
#else |
.opts = "d:", |
.help = "-d [device file] Device file to use when communicating with the parport hardware (eg. /dev/parport0)\n" |
#endif |
}; |
|
jtag_cable_t xess_cable_driver = { |
.name = "xess", |
.inout_func = cable_xess_inout, |
.out_func = cable_xess_out, |
.init_func = cable_parallel_init, |
.opt_func = cable_parallel_opt, |
.bit_out_func = cable_common_write_bit, |
.bit_inout_func = cable_common_read_write_bit, |
.stream_out_func = cable_common_write_stream, |
.stream_inout_func = cable_common_read_stream, |
.flush_func = NULL, |
#ifdef __CYGWIN_HOST__ |
.opts = "p:", |
.help = "-p [port] Which port to use when communicating with the parport hardware (eg. 0x378)\n" |
#else |
.opts = "d:", |
.help = "-d [device file] Device file to use when communicating with the parport hardware (eg. /dev/parport0)\n" |
#endif |
}; |
|
|
// Common functions used by both cable types |
static int cable_parallel_out(uint8_t value); |
static int cable_parallel_inout(uint8_t value, uint8_t *inval); |
|
#ifdef __PARALLEL_TIMER_BUSY_WAIT__ |
#ifndef PARALLEL_USE_PROCESS_TIMER |
struct timeval last_tv; |
#endif |
#endif |
|
// If cygwin, we use inb / outb for parallel port access |
#ifdef __CYGWIN_HOST__ |
|
#define LPT_READ (base+1) |
#define LPT_WRITE base |
|
static int base = 0x378; |
|
///////////////////////////////////////////////////////////////////////////////// |
/*-------------------------------------[ Parallel port specific functions ]---*/ |
/////////////////////////////////////////////////////////////////////////////// |
|
int cable_parallel_init() |
{ |
if (ioperm(base, 3, 1)) { |
fprintf(stderr, "Couldn't get the port at %x\n", base); |
perror("Root privileges are required.\n"); |
return APP_ERR_INIT_FAILED; |
} |
printf("Connected to parallel port at %x\n", base); |
printf("Dropping root privileges.\n"); |
setreuid(getuid(), getuid()); |
|
#ifdef __PARALLEL_TIMER_BUSY_WAIT__ |
#ifdef PARALLEL_USE_PROCESS_TIMER |
struct timespec ts; |
ts.tv_sec = 0; |
ts.tv_nsec = 0; |
clock_settime(CLOCK_PROCESS_CPUTIME_ID, &ts); |
#else |
gettimeofday(&last_tv, NULL); |
#endif |
#endif |
|
return APP_ERR_NONE; |
} |
|
int cable_parallel_opt(int c, char *str) |
{ |
switch(c) { |
case 'p': |
if(!sscanf(str, "%x", &base)) { |
fprintf(stderr, "p parameter must have a hex number as parameter\n"); |
return APP_ERR_BAD_PARAM; |
} |
break; |
default: |
fprintf(stderr, "Unknown parameter '%c'\n", c); |
return APP_ERR_BAD_PARAM; |
} |
return APP_ERR_NONE; |
} |
|
/*----------------------------------------------[ common helper functions ]---*/ |
// 'static' for internal access only |
|
static int cable_parallel_out(uint8_t value) |
{ |
outb(value, LPT_WRITE); |
return APP_ERR_NONE; |
} |
|
static int cable_parallel_inout(uint8_t value, uint8_t *inval) |
{ |
*inval = inb(LPT_READ); |
outb(value, LPT_WRITE); |
|
return APP_ERR_NONE; |
} |
|
// For Linux / BSD, we use open / ioctl for parallel port access, |
// so that we don't need root permissions |
#else // ! defined __CYGWIN_HOST__ |
|
#ifdef __FREEBSD_HOST__ |
static int PPORT_PUT_DATA = PPISDATA; |
static int PPORT_GET_DATA = PPIGSTATUS; |
#else |
static int PPORT_PUT_DATA = PPWDATA; |
static int PPORT_GET_DATA = PPRSTATUS; |
#endif |
|
static int fd; |
static char default_dev_str[20] = "/dev/parport0"; |
static char *devsys = default_dev_str; |
|
|
///////////////////////////////////////////////////////////////////////////////// |
/*-------------------------------------[ Parallel port specific functions ]---*/ |
/////////////////////////////////////////////////////////////////////////////// |
|
int cable_parallel_init() |
{ |
int mode = IEEE1284_MODE_COMPAT; |
fd = open(devsys, O_RDWR | O_NONBLOCK); |
if (fd == -1) |
{ |
perror("Unable to open the device desriptor\n"); |
fprintf(stderr, "Check permission of %s (eg. 'ls -la %s').\n", devsys, devsys); |
fprintf(stderr, "Your user ID can be added to %s's group to allow for unprivileged access.\n", devsys); |
return APP_ERR_INIT_FAILED; |
} |
|
// I don't know if these ioctl() are supported under FreeBSD |
#ifdef __LINUX_HOST__ |
if (ioctl(fd, PPCLAIM) == -1) |
{ |
perror("Fail to claim the parallel port device interface.\n"); |
return APP_ERR_INIT_FAILED; |
} |
if (ioctl(fd, PPSETMODE, &mode) == -1) |
{ |
perror("Setting compatibility mode on parallel port device failed.\n"); |
return APP_ERR_INIT_FAILED; |
} |
#endif |
|
#ifdef __PARALLEL_TIMER_BUSY_WAIT__ |
#ifdef PARALLEL_USE_PROCESS_TIMER |
struct timespec ts; |
ts.tv_sec = 0; |
ts.tv_nsec = 0; |
clock_settime(CLOCK_PROCESS_CPUTIME_ID, &ts); |
#else |
gettimeofday(&last_tv, NULL); |
#endif |
#endif |
|
return APP_ERR_NONE; |
} |
|
|
int cable_parallel_opt(int c, char *str) |
{ |
switch(c) { |
case 'd': |
devsys = strdup(str); |
break; |
default: |
fprintf(stderr, "Unknown parameter '%c'\n", c); |
return APP_ERR_BAD_PARAM; |
} |
return APP_ERR_NONE; |
} |
|
/*----------------------------------------------[ common helper functions ]---*/ |
// 'static' for internal access only |
|
static int cable_parallel_out(uint8_t value) |
{ |
ioctl(fd, PPORT_PUT_DATA, &value); |
|
return APP_ERR_NONE; |
} |
|
static int cable_parallel_inout(uint8_t value, uint8_t *inval) |
{ |
ioctl(fd, PPORT_GET_DATA, inval); |
ioctl(fd, PPORT_PUT_DATA, &value); |
|
return APP_ERR_NONE; |
} |
|
#endif // !defined __CYGWIN_HOST__ |
|
/*-----------------------------------------[ Physical board wait function ]---*/ |
|
/* Multiple users have reported poor performance of parallel cables, |
* which has been traced to various sleep functions sleeping much longer than |
* microseconds. The same users have reported error-free functionality |
* and an order of magnitude improvement in upload speed with no wait. |
* Other users have reported errors when running without a wait. |
* Impact apparently limits the frequency of parallel JTAG cables |
* to 200 kHz, and some clones fail at higher speeds. |
*/ |
|
|
|
#ifdef __PARALLEL_SLEEP_WAIT__ |
void cable_parallel_phys_wait() |
{ |
struct timespec ts; |
ts.tv_sec = 0; |
ts.tv_nsec = 2500; |
nanosleep(&ts, NULL); |
} |
#else |
|
#ifdef __PARALLEL_TIMER_BUSY_WAIT__ |
|
#ifndef PARALLEL_USE_PROCESS_TIMER |
|
/* Helper function needed if process timer isn't implemented */ |
/* do x-y */ |
int timeval_subtract (struct timeval *result, struct timeval *x, struct timeval *y) |
{ |
/* Perform the carry for the later subtraction by updating y. */ |
if (x->tv_usec < y->tv_usec) { |
int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1; |
y->tv_usec -= 1000000 * nsec; |
y->tv_sec += nsec; |
} |
if (x->tv_usec - y->tv_usec > 1000000) { |
int nsec = (x->tv_usec - y->tv_usec) / 1000000; |
y->tv_usec += 1000000 * nsec; |
y->tv_sec -= nsec; |
} |
|
/* Compute the time remaining to wait. |
tv_usec is certainly positive. */ |
result->tv_sec = x->tv_sec - y->tv_sec; |
result->tv_usec = x->tv_usec - y->tv_usec; |
|
/* Return 1 if result is negative. */ |
return x->tv_sec < y->tv_sec; |
} |
#endif |
|
|
void cable_parallel_phys_wait() |
{ |
/* This busy wait attempts to make the frequency exactly 200kHz, |
* including the processing time between ticks. |
* This means a period of 5us, or half a period of 2.5us. |
*/ |
#ifdef PARALLEL_USE_PROCESS_TIMER |
struct timespec ts; |
do |
{ |
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts); |
} while((ts.tv_sec == 0) && (ts.tv_nsec < 2500)); |
|
/* Doing the set after the check means that processing time |
* is not added to the wait. */ |
ts.tv_sec = 0; |
ts.tv_nsec = 0; |
clock_settime(CLOCK_PROCESS_CPUTIME_ID, &ts); |
#else |
struct timeval now_tv; |
struct timeval results_tv; |
do |
{ |
gettimeofday(&now_tv, NULL); |
timeval_subtract (&results_tv, &now_tv, &last_tv); |
} while((results_tv.tv_sec == 0) && (results_tv.tv_usec < 3)); |
last_tv = now_tv; |
#endif |
} |
|
#else // NO WAIT |
|
void cable_parallel_phys_wait() |
{ |
// No wait, run max speed |
} |
|
#endif |
#endif |
|
|
/*----------------------------------------------[ xpc3 specific functions ]---*/ |
jtag_cable_t *cable_xpc3_get_driver(void) |
{ |
return &xpc3_cable_driver; |
} |
|
int cable_xpc3_out(uint8_t value) |
{ |
uint8_t out = 0; |
|
cable_parallel_phys_wait(); // Limit the max clock rate if necessary |
|
/* First convert the bits in value byte to the ones that the cable wants */ |
if(value & TCLK_BIT) |
out |= 0x02; /* D1 pin 3 */ |
if(value & TRST_BIT) |
out |= 0x10; /* Not used */ |
if(value & TDI_BIT) |
out |= 0x01; /* D0 pin 2 */ |
if(value & TMS_BIT) |
out |= 0x04; /* D2 pin 4 */ |
|
return cable_parallel_out(out); |
} |
|
int cable_xpc3_inout(uint8_t value, uint8_t *inval) |
{ |
uint8_t in; |
int retval; |
uint8_t out = 0; |
|
cable_parallel_phys_wait(); // Limit the max clock rate if necessary |
|
/* First convert the bits in value byte to the ones that the cable wants */ |
if(value & TCLK_BIT) |
out |= 0x02; /* D1 pin 3 */ |
if(value & TRST_BIT) |
out |= 0x10; /* Not used */ |
if(value & TDI_BIT) |
out |= 0x01; /* D0 pin 2 */ |
if(value & TMS_BIT) |
out |= 0x04; /* D2 pin 4 */ |
|
retval = cable_parallel_inout(out, &in); |
|
if(in & 0x10) /* S6 pin 13 */ |
*inval = 1; |
else |
*inval = 0; |
|
return retval; |
} |
|
|
/*----------------------------------------------[ bb2 specific functions ]---*/ |
jtag_cable_t *cable_bb2_get_driver(void) |
{ |
return &bb2_cable_driver; |
} |
|
int cable_bb2_out(uint8_t value) |
{ |
uint8_t out = 0; |
|
cable_parallel_phys_wait(); // Limit the max clock rate if necessary |
|
/* First convert the bits in value byte to the ones that the cable wants */ |
if(value & TCLK_BIT) |
out |= 0x01; /* D0 pin 2 */ |
if(value & TDI_BIT) |
out |= 0x40; /* D7 pin 8 */ |
if(value & TMS_BIT) |
out |= 0x02; /* D1 pin 3 */ |
|
return cable_parallel_out(out); |
} |
|
int cable_bb2_inout(uint8_t value, uint8_t *inval) |
{ |
uint8_t in; |
int retval; |
uint8_t out = 0; |
|
cable_parallel_phys_wait(); // Limit the max clock rate if necessary |
|
/* First convert the bits in value byte to the ones that the cable wants */ |
if(value & TCLK_BIT) |
out |= 0x01; /* D0 pin 2 */ |
if(value & TDI_BIT) |
out |= 0x40; /* D7 pin 8 */ |
if(value & TMS_BIT) |
out |= 0x02; /* D1 pin 3 */ |
|
retval = cable_parallel_inout(out, &in); |
|
if(in & 0x80) /* S7 pin 11 */ |
*inval = 0; |
else |
*inval = 1; |
|
return retval; |
} |
|
|
/*----------------------------------------------[ xess specific functions ]---*/ |
jtag_cable_t *cable_xess_get_driver(void) |
{ |
return &xess_cable_driver; |
} |
|
int cable_xess_out(uint8_t value) |
{ |
uint8_t out = 0; |
|
cable_parallel_phys_wait(); // Limit the max clock rate if necessary |
|
/* First convert the bits in value byte to the ones that the cable wants */ |
if(value & TCLK_BIT) |
out |= 0x04; /* D2 pin 4 */ |
if(value & TRST_BIT) |
out |= 0x08; /* D3 pin 5 */ |
if(value & TDI_BIT) |
out |= 0x10; /* D4 pin 6 */ |
if(value & TMS_BIT) |
out |= 0x20; /* D3 pin 5 */ |
|
return cable_parallel_out(out); |
} |
|
int cable_xess_inout(uint8_t value, uint8_t *inval) |
{ |
uint8_t in; |
int retval; |
uint8_t out = 0; |
|
cable_parallel_phys_wait(); // Limit the max clock rate if necessary |
|
/* First convert the bits in value byte to the ones that the cable wants */ |
if(value & TCLK_BIT) |
out |= 0x04; /* D2 pin 4 */ |
if(value & TRST_BIT) |
out |= 0x08; /* D3 pin 5 */ |
if(value & TDI_BIT) |
out |= 0x10; /* D4 pin 6 */ |
if(value & TMS_BIT) |
out |= 0x20; /* D3 pin 5 */ |
|
retval = cable_parallel_inout(out, &in); |
|
if(in & 0x20) /* S5 pin 12*/ |
*inval = 1; |
else |
*inval = 0; |
|
return retval; |
} |
|
|
/tags/ADS_RELEASE_3_0_0/Software/adv_jtag_bridge/configure.ac
0,0 → 1,347
AC_INIT([adv_jtag_bridge],[3.0.0]) |
AM_INIT_AUTOMAKE([-Wall -Werror]) |
LT_INIT |
|
# Use "make V=1" in order to see the gcc command-lines during compilation. |
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) |
|
# These compilation flags must be set before AC_PROG_CC/CXX, |
# or you'll get "-g -O2" by default. |
CFLAGS="${CFLAGS=} -g -Wall" |
|
AC_PROG_CC |
AC_PROG_INSTALL |
|
AC_CONFIG_MACRO_DIR([m4]) |
|
|
# ----------- Detect host type ----------- |
|
AC_CANONICAL_HOST |
|
case $host in |
*-cygwin) # Normally it is "i686-pc-cygwin" |
echo "Host system: Cygwin detected." |
MY_HOST=cygwin |
CFLAGS="$CFLAGS -D__CYGWIN_HOST__" |
AC_CHECK_HEADER(sys/io.h,,[AC_MSG_ERROR([Include file 'sys/io.h' not found, please install the Cygwin 'ioperm' package.])]) |
LIBS+=-lioperm |
;; |
*-linux-*) |
echo "Host system: Linux detected." |
MY_HOST=linux |
CFLAGS="$CFLAGS -D__LINUX_HOST__" |
;; |
*freebsd*) |
echo "Host system: FreeBSD detected." |
MY_HOST=freebsd |
CFLAGS="$CFLAGS -D__FREEBSD_HOST__" |
;; |
*) |
echo "Host system: Unknown, assuming a Linux host." |
MY_HOST=linux |
;; |
esac |
|
|
# ----------- Check whether debug or release build ----------- |
|
AC_MSG_CHECKING(whether to generate a debug build) |
AC_ARG_ENABLE([debug], |
[AS_HELP_STRING([--enable-debug=[[yes/no]]], |
[generate a debug build with assertions and no optimization [default=no]])], |
[case "${enableval}" in |
yes) debug_build=true ;; |
no) debug_build=false ;; |
*) AC_MSG_ERROR([bad value ${enableval} for --enable-debug]) ;; |
esac], |
debug_build=false) |
|
if [ test x$debug_build = xtrue ] |
then |
AC_MSG_RESULT(yes) |
CFLAGS="$CFLAGS -O0 -DDEBUG" |
else |
AC_MSG_RESULT(no) |
# If we let the 'omit frame pointer' optimisation enabled, |
# we'll have difficulty later on while trying |
# to analyse crash dump files sent by the users. |
CFLAGS="$CFLAGS -O2 -DNDEBUG -fno-omit-frame-pointer" |
fi |
|
|
# ----------- Check whether legacy debug_if ----------- |
|
AC_MSG_CHECKING(whether to build for the legacy debug unit) |
AC_ARG_ENABLE([legacy-debug-if], |
[AS_HELP_STRING([--enable-legacy-debug-if=[[yes/no]]], |
[build for the legacy debug unit, as opposed to the newer Advanced Debug Unit [default=no]])], |
[case "${enableval}" in |
yes) legacy_debug_if=true ;; |
no) legacy_debug_if=false ;; |
*) AC_MSG_ERROR([bad value ${enableval} for --enable-legacy-debug-if]) ;; |
esac], |
legacy_debug_if=false) |
|
if [ test x$legacy_debug_if = xtrue ] |
then |
AC_MSG_RESULT(yes) |
CFLAGS="$CFLAGS -D__LEGACY__" |
else |
AC_MSG_RESULT(no) |
fi |
|
|
# ----------- Check whether to support parallel cables ----------- |
|
AC_MSG_CHECKING(whether to support parallel cables) |
AC_ARG_ENABLE([parallel-cables], |
[AS_HELP_STRING([--enable-parallel-cables=[[yes/no]]], |
[support parallel cables (requires libioperm under Cygwin) [default=yes]])], |
[case "${enableval}" in |
yes) support_parallel=true ;; |
no) support_parallel=false ;; |
*) AC_MSG_ERROR([bad value ${enableval} for --enable-parallel-cables]) ;; |
esac], |
support_parallel=not_given) |
|
if [ test $support_parallel = not_given ] |
then |
support_parallel=true |
fi |
|
if [ test $MY_HOST = freebsd ] && [ test $support_parallel = true ] |
then |
AC_MSG_ERROR([Support for parallel cables is not available under FreeBSD.]) |
fi |
|
AM_CONDITIONAL(SUPPORT_PARALLEL_CABLES,[test x$support_parallel = xtrue]) |
AM_COND_IF([SUPPORT_PARALLEL_CABLES],[AC_MSG_RESULT(yes)],[AC_MSG_RESULT(no)]) |
|
|
# ----------- Check whether to support USB cables ----------- |
|
AC_MSG_CHECKING(whether to support usb cables) |
AC_ARG_ENABLE([usb-cables], |
[AS_HELP_STRING([--enable-usb-cables=[[yes/no]]], |
[support usb cables (requires libusb) [default=yes]])], |
[case "${enableval}" in |
yes) support_usb=true ;; |
no) support_usb=false ;; |
*) AC_MSG_ERROR([bad value ${enableval} for --enable-usb-cables]) ;; |
esac], |
support_usb=true) |
|
AM_CONDITIONAL(SUPPORT_USB_CABLES,[test x$support_usb = xtrue]) |
AM_COND_IF([SUPPORT_USB_CABLES],[AC_MSG_RESULT(yes)],[AC_MSG_RESULT(no)]) |
|
if [ test $support_usb = true ] |
then |
AC_CHECK_HEADER(usb.h,,[AC_MSG_ERROR([Include file 'usb.h' not found, please install the libusb-0.1 development files (for example, that would be package 'libusb-win32' under Cygwin, and 'libusb-dev' under Ubuntu).])]) |
fi |
|
|
# ------ At least one from (parallel, usb) must be enabled ------ |
|
if [ test x$support_parallel = xfalse ] && [ test x$support_usb = xfalse ]; then |
AC_MSG_ERROR([Support for both parallel and usb cables is disabled.]) |
fi |
|
# ------ Check whether the xilinx parallel cable mode is given ------ |
# This argument should be called --set-xxx and not --enable-xxx , |
# but autoconf identifies only the --enable and --with prefixes |
# for recursive configuration option processing. |
|
AC_MSG_CHECKING(xilinx parallel cable speed limit scheme) |
AC_ARG_ENABLE([xpc3-limit-scheme], |
[AS_HELP_STRING([--enable-xpc3-limit-scheme=[[sleep_wait/timer_wait/no_wait]]], |
[limit Xilinx parallel cable speed, as some clones cannot operate as fast as we can drive them [default=no_wait]])], |
[case "${enableval}" in |
sleep_wait) xpc3_limit_scheme=sleep_wait ;; |
timer_wait) xpc3_limit_scheme=timer_wait ;; |
no_wait) xpc3_limit_scheme=no_wait ;; |
*) AC_MSG_ERROR([bad value ${enableval} for --enable-xpc3-limit-scheme]) ;; |
esac], |
xpc3_limit_scheme=not_given) |
|
if [ ! test $xpc3_limit_scheme = not_given ] && [ test $support_parallel = false ] |
then |
AC_MSG_ERROR([Option --enable-xpc3-limit-scheme can only be supplied if support for the parallel cables has been enabled.]) |
fi |
|
if [ test $xpc3_limit_scheme = not_given ] |
then |
xpc3_limit_scheme=no_wait |
fi |
|
AC_MSG_RESULT($xpc3_limit_scheme) |
|
case "${xpc3_limit_scheme}" in |
sleep_wait) |
CFLAGS="$CFLAGS -D__PARALLEL_SLEEP_WAIT__" |
;; |
timer_wait) |
CFLAGS="$CFLAGS -D__PARALLEL_TIMER_BUSY_WAIT__" |
;; |
no_wait) |
# no_wait is the default, nothing to define |
;; |
*) |
AC_MSG_ERROR([Internal error in --enable-xpc3-limit-scheme.]) |
;; |
esac |
|
|
# ----------- Check whether to support FTDI cables ----------- |
|
AC_MSG_CHECKING(whether to support ftdi cables) |
AC_ARG_ENABLE([ftdi-cables], |
[AS_HELP_STRING([--enable-ftdi-cables=[[yes/no]]], |
[support ftdi cables (requires libftdi) [default=yes]])], |
[case "${enableval}" in |
yes) support_ftdi=true ;; |
no) support_ftdi=false ;; |
*) AC_MSG_ERROR([bad value ${enableval} for --enable-ftdi-cables]) ;; |
esac], |
support_ftdi=not_given) |
|
if [ test $support_ftdi = not_given ] |
then |
support_ftdi=$support_usb |
fi |
|
AM_CONDITIONAL(SUPPORT_FTDI_CABLES,[test x$support_ftdi = xtrue]) |
AM_COND_IF([SUPPORT_FTDI_CABLES],[AC_MSG_RESULT(yes)],[AC_MSG_RESULT(no)]) |
|
if [ test x$support_usb = xfalse ] && [ test x$support_ftdi = xtrue ]; then |
AC_MSG_ERROR([Support for FTDI cables requires support for USB cables.]) |
fi |
|
if [ test $support_ftdi = true ] |
then |
AC_CHECK_HEADER(ftdi.h,,[AC_MSG_ERROR([Include file 'ftdi.h' not found, please install the libftdi development files (for example, that would be package 'libftdi-dev' under Ubuntu).])]) |
fi |
|
|
# ----------- Check whether to enable the high-speed mode ----------- |
|
AC_MSG_CHECKING(whether to enable the high-speed mode) |
AC_ARG_ENABLE([high-speed], |
[AS_HELP_STRING([--enable-high-speed=[[yes/no]]], |
[enable the high-speed mode at the cost of some error checking (requires hardware HDL support) [default=yes]])], |
[case "${enableval}" in |
yes) enable_high_speed=true ;; |
no) enable_high_speed=false ;; |
*) AC_MSG_ERROR([bad value ${enableval} for --enable-high-speed]) ;; |
esac], |
enable_high_speed=true) |
|
if [ test x$enable_high_speed = xtrue ] |
then |
AC_MSG_RESULT(yes) |
CFLAGS="$CFLAGS -DADBG_OPT_HISPEED" |
else |
AC_MSG_RESULT(no) |
fi |
|
|
# ----------- Check whether to enable the JSP server ----------- |
|
AC_MSG_CHECKING(whether to enable the JSP server) |
AC_ARG_ENABLE([jsp-server], |
[AS_HELP_STRING([--enable-jsp-server=[[yes/no]]], |
[enable the JSP server (requires hardware HDL support) [default=yes]])], |
[case "${enableval}" in |
yes) enable_jsp_server=true ;; |
no) enable_jsp_server=false ;; |
*) AC_MSG_ERROR([bad value ${enableval} for --enable-jsp-server]) ;; |
esac], |
enable_jsp_server=not_given) |
|
if [ test x$legacy_debug_if = xtrue ] && [ test x$enable_jsp_server = xtrue ] |
then |
AC_MSG_ERROR([Option --enable-jsp-server cannot be true when using the legacy_debug_if hardware.]) |
fi |
|
if [ test $enable_jsp_server = not_given ] |
then |
if [ test x$legacy_debug_if = xtrue ] |
then |
enable_jsp_server=false |
else |
enable_jsp_server=true |
fi |
fi |
|
AM_CONDITIONAL(INCLUDE_JSP_SERVER,[test x$enable_jsp_server = xtrue]) |
AM_COND_IF([INCLUDE_JSP_SERVER],[AC_MSG_RESULT(yes)],[AC_MSG_RESULT(no)]) |
|
|
# ----------- Check whether to enable the JSP multi device support ----------- |
|
AC_MSG_CHECKING(whether to enable the JSP multi device chain support) |
AC_ARG_ENABLE([jsp-multi-device-chain], |
[AS_HELP_STRING([--enable-jsp-multi-device-chain=[[yes/no]]], |
[enable the JTAG Serial Port (JSP) multi device chain support (slower, requires hardware HDL support) [default=yes]])], |
[case "${enableval}" in |
yes) enable_jsp_multi_device_chain=true ;; |
no) enable_jsp_multi_device_chain=false ;; |
*) AC_MSG_ERROR([bad value ${enableval} for --enable-jsp-multi-device-chain]) ;; |
esac], |
enable_jsp_multi_device_chain=not_given) |
|
if [ ! test $enable_jsp_multi_device_chain = not_given ] && [ test $enable_jsp_server = false ] |
then |
AC_MSG_ERROR([Option --enable-jsp-multi-device-chain can only be supplied if the JSP server has been enabled.]) |
fi |
|
if [ test $enable_jsp_multi_device_chain = not_given ] |
then |
enable_jsp_multi_device_chain=true |
fi |
|
if [ test x$enable_jsp_multi_device_chain = xtrue ] |
then |
AC_MSG_RESULT(yes) |
CFLAGS="$CFLAGS -DENABLE_JSP_MULTI" |
else |
AC_MSG_RESULT(no) |
fi |
|
|
# ----------- Check whether to optimize the JSP for parallel or USB ----------- |
|
AC_MSG_CHECKING(whether to optimize the JSP for USB) |
AC_ARG_ENABLE([jsp-optimize-for-usb], |
[AS_HELP_STRING([--enable-jsp-optimize-for-usb=[[yes/no]]], |
[optimizes the JTAG Serial Port (JSP) for USB cables (as opposed to optimizing for parallel cables) [default=yes]])], |
[case "${enableval}" in |
yes) enable_jsp_optimize_for_usb=true ;; |
no) enable_jsp_optimize_for_usb=false ;; |
*) AC_MSG_ERROR([bad value ${enableval} for --enable-jsp-optimize-for-usb]) ;; |
esac], |
enable_jsp_optimize_for_usb=not_given) |
|
|
if [ ! test $enable_jsp_optimize_for_usb = not_given ] && [ test $enable_jsp_server = false ] |
then |
AC_MSG_ERROR([Option --enable-jsp-optimize-for-usb can only be supplied if the JSP server has been enabled.]) |
fi |
|
if [ test $enable_jsp_optimize_for_usb = not_given ] |
then |
enable_jsp_optimize_for_usb=true |
fi |
|
if [ test x$enable_jsp_optimize_for_usb = xtrue ] |
then |
AC_MSG_RESULT(yes) |
CFLAGS="$CFLAGS -DOPTIMIZE_JSP_FOR_USB" |
else |
AC_MSG_RESULT(no) |
fi |
|
# ---------------------------------------- |
|
AC_CONFIG_FILES([Makefile]) |
AC_OUTPUT |
tags/ADS_RELEASE_3_0_0/Software/adv_jtag_bridge/configure.ac
Property changes :
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: tags/ADS_RELEASE_3_0_0/Software/adv_jtag_bridge/hwp_server.c
===================================================================
--- tags/ADS_RELEASE_3_0_0/Software/adv_jtag_bridge/hwp_server.c (nonexistent)
+++ tags/ADS_RELEASE_3_0_0/Software/adv_jtag_bridge/hwp_server.c (revision 66)
@@ -0,0 +1,1059 @@
+/* hwp_server.c -- Server for hardware watchpoint handling
+ Copyright(C) 2010 Nathan Yawn
+
+ This file is part the advanced debug unit / bridge. GDB does not
+ have support for the OR1200's advanced hardware watchpoints. This
+ acts as a server for a client program that can read and set them.
+
+ 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
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "spr-defs.h"
+#include "dbg_api.h"
+#include "hardware_monitor.h"
+#include "errcodes.h"
+
+
+#define debug(...) // fprintf(stderr, __VA_ARGS__ )
+
+#define HWP_BUF_MAX 256
+
+/*! Data structure for RSP buffers. Can't be null terminated, since it may
+ include zero bytes */
+struct rsp_buf
+{
+ char data[HWP_BUF_MAX];
+ int len;
+};
+
+int hwp_server_fd = -1;
+int hwp_client_fd = -1;
+int hwp_pipe_fds[2];
+
+/* Some convenient net address info to have around */
+char hwp_ipstr[INET6_ADDRSTRLEN];
+char *hwp_ipver;
+int hwp_portnum;
+char hwp_hostname[256];
+
+/* Other local data */
+int hwp_server_running = 0;
+int hwp_target_is_running = 0;
+int use_cached_dmr2 = 0;
+uint32_t cached_dmr2 = 0;
+
+/* To track which watchpoints are in use by an external program,
+ * so that the RSP server can have the unused ones for GDB
+ */
+#define HWP_MAX_WP 8
+unsigned char hwp_in_use[HWP_MAX_WP];
+
+/*! String to map hex digits to chars */
+static const char hexchars[]="0123456789abcdef";
+
+pthread_t hwp_server_thread;
+void *hwp_server(void *arg);
+
+void hwp_server_close(void);
+void hwp_client_close(void);
+void hwp_client_request(void);
+
+struct rsp_buf *hwp_get_packet(void);
+void put_hwp_rsp_char(int fd, char c);
+int get_hwp_rsp_char(int fd);
+void hwp_read_reg(struct rsp_buf *buf);
+void hwp_write_reg (struct rsp_buf *buf);
+void hwp_put_str_packet (int fd, const char *str);
+void hwp_put_packet (int fd, struct rsp_buf *buf);
+unsigned long int hwp_hex2reg (char *buf);
+void hwp_reg2hex (unsigned long int val, char *buf);
+int hwp_hex(int c);
+void hwp_report_run(void);
+void hwp_report_stop(void);
+void hwp_set_in_use(unsigned int wp, unsigned char inuse);
+
+/*----------------------------------------------------------*/
+/* Public API */
+/*----------------------------------------------------------*/
+
+int hwp_init(int portNum)
+{
+ int status;
+ struct addrinfo hints;
+ struct addrinfo *servinfo; // will point to the results of getaddrinfo
+ int optval; /* Socket options */
+ char portnum[6]; /* portNum as a string */
+ void *addr;
+ int i, errcode;
+ uint32_t regaddr, tmp;
+
+ debug("HWP Server initializing\n");
+
+ /* First thing's first: Check if there are any HWP.
+ * Read all DCR, mark which are present.*/
+ status = 0;
+ for(i = 0; i < HWP_MAX_WP; i++)
+ {
+ regaddr = SPR_DCR(i);
+ errcode = dbg_cpu0_read(regaddr, &tmp);
+ if(errcode != APP_ERR_NONE)
+ {
+ fprintf(stderr, "ERROR reading DCR %i at startup! %s\n", i, get_err_string(errcode));
+ hwp_set_in_use(i, 1);
+ }
+ else
+ {
+ if(tmp & 0x1) /* HWP present */
+ {
+ hwp_set_in_use(i, 0);
+ status++;
+ }
+ else /* HWP not implemented */
+ {
+ hwp_set_in_use(i, 1);
+ }
+ }
+ debug("HWP %i is %s\n", i, hwp_in_use[i] ? "absent":"present");
+ }
+
+ if(status <= 0)
+ {
+ fprintf(stderr, "No watchpoint hardware found, HWP server not starting\n");
+ return 0;
+ }
+ else
+ {
+ fprintf(stderr, "HWP server initializing with %i watchpoints available\n", status);
+
+ /* We have watchpoint hardware. Initialize the server. */
+ hwp_server_fd = -1;
+ hwp_client_fd = -1;
+ hwp_portnum = portNum;
+
+ memset(portnum, '\0', sizeof(portnum));
+ snprintf(portnum, 5, "%i", portNum);
+
+ /* Get the address info for the local host */
+ memset(&hints, 0, sizeof hints); // make sure the struct is empty
+ hints.ai_family = AF_UNSPEC; // don't care IPv4 or IPv6
+ hints.ai_socktype = SOCK_STREAM; // TCP stream sockets
+ hints.ai_flags = AI_PASSIVE; // fill in my IP for me
+
+ if ((status = getaddrinfo(NULL, portnum, &hints, &servinfo)) != 0) {
+ fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
+ return 0;
+ }
+
+
+ /* *** TODO: Select the appropriate servinfo in the linked list
+ * For now, we just use the first entry in servinfo.
+ struct addrinfo *servinfo, *p;
+ for(p = servinfo;p != NULL; p = p->ai_next) {
+ if (p->ai_family == AF_INET) { // IPv4
+ } else { // IPv6
+ }
+ }
+ */
+
+
+ /* Save the IP address, for convenience (different fields in IPv4 and IPv6) */
+ if (servinfo->ai_family == AF_INET) { // IPv4
+ struct sockaddr_in *ipv4 = (struct sockaddr_in *)servinfo->ai_addr;
+ addr = &(ipv4->sin_addr);
+ hwp_ipver = "IPv4";
+ } else { // IPv6
+ struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)servinfo->ai_addr;
+ addr = &(ipv6->sin6_addr);
+ hwp_ipver = "IPv6";
+ }
+
+ /* convert the IP to a string */
+ inet_ntop(servinfo->ai_family, addr, hwp_ipstr, sizeof(hwp_ipstr));
+
+ /* Find out what our name is, save for convenience */
+ if (gethostname (hwp_hostname, sizeof(hwp_hostname)) < 0)
+ {
+ fprintf (stderr, "Warning: Unable to get hostname for HWP server: %s\n", strerror(errno));
+ hwp_hostname[0] = '\0'; /* This is not a fatal error. */
+ }
+
+ /* Create the socket */
+ hwp_server_fd = socket (servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);
+ if (hwp_server_fd < 0)
+ {
+ fprintf (stderr, "Error: HWP could not create server socket: %s\n", strerror(errno));
+ return 0;
+ }
+
+ /* Set this socket to reuse its address. */
+ optval = 1;
+ if (setsockopt(hwp_server_fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof (optval)) == -1)
+ {
+ fprintf (stderr, "Cannot set SO_REUSEADDR option on server socket %d: %s\n", hwp_server_fd, strerror(errno));
+ hwp_server_close();
+ return 0;
+ }
+
+ /* Bind the socket to the local address */
+ if (bind (hwp_server_fd, servinfo->ai_addr, servinfo->ai_addrlen) < 0)
+ {
+ fprintf (stderr, "Error: Unable to bind HWP server socket %d to port %d: %s\n", hwp_server_fd, portNum, strerror(errno));
+ hwp_server_close();
+ return 0;
+ }
+
+ /* Set us up as a server, with a maximum backlog of 1 connection */
+ if (listen (hwp_server_fd, 1) < 0)
+ {
+ fprintf (stderr, "Warning: Unable to set HWP backlog on server socket %d to %d: %s\n", hwp_server_fd, 1, strerror(errno));
+ hwp_server_close();
+ return 0;
+ }
+
+ fprintf(stderr, "HWP server listening on host %s (%s), port %i, address family %s\n",
+ hwp_hostname, hwp_ipstr, hwp_portnum, hwp_ipver);
+
+ /* Register for stall/unstall events from the target monitor thread. Also creates pipe
+ * for sending stall/unstall command to the target monitor, unused by us. */
+ if(0 > register_with_monitor_thread(hwp_pipe_fds)) { // pipe_fds[0] is for writing to monitor, [1] is to read from it
+ fprintf(stderr, "HWP server failed to register with monitor thread, exiting");
+ hwp_server_close();
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+
+int hwp_server_start(void)
+{
+
+ hwp_server_running = 1;
+
+ debug("Starting HWP server\n");
+
+ // Create the HWP server thread
+ if(pthread_create(&hwp_server_thread, NULL, hwp_server, NULL))
+ {
+ fprintf(stderr, "Failed to create HWP server thread!\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+int hwp_server_stop(void)
+{
+ /*** NOTE: Since we currently don't use select() in front of the accept()
+ *** in the server thread, this won't actually work unless/until a client
+ *** is connected. Otherwise, the server thread will be blocked on the
+ *** accept() (though closing the server socket may break it out.)
+ ***/
+
+ hwp_server_running = 0;
+ hwp_server_close();
+ return 1;
+}
+
+/*--------------------------------------------------------------------*/
+/* Main server thread */
+/*--------------------------------------------------------------------*/
+
+
+void *hwp_server(void *arg)
+{
+ struct sockaddr_storage their_addr;
+ struct timeval *tvp;
+ fd_set readset;
+ socklen_t addr_size;
+ int nfds, flags;
+ int ret;
+ char cmd;
+
+ fprintf(stderr, "HWP server thread running!\n");
+
+ while(hwp_server_running)
+ {
+ /* Listen for an incoming connection */
+ addr_size = sizeof their_addr;
+ hwp_client_fd = accept(hwp_server_fd, (struct sockaddr *)&their_addr, &addr_size);
+
+ if(hwp_client_fd == -1)
+ {
+ perror("Error in accept() in HWP server thread");
+ }
+ else
+ {
+ debug("HWP server got connection!\n");
+
+ /* Do new client init stuff here */
+ use_cached_dmr2 = 0;
+
+ /* New client should be non-blocking. */
+ flags = fcntl (hwp_client_fd, F_GETFL);
+ if (flags < 0)
+ {
+ fprintf (stderr, "Warning: Unable to get flags for HWP client socket %d: %s\n", hwp_client_fd, strerror(errno));
+ // Not really fatal.
+ }
+ else {
+ flags |= O_NONBLOCK;
+ if (fcntl (hwp_client_fd, F_SETFL, flags) < 0)
+ {
+ fprintf (stderr, "Warning: Unable to set flags for HWP client socket %d to 0x%08x: %s\n", hwp_client_fd, flags, strerror(errno));
+ // Also not really fatal.
+ }
+ }
+ }
+
+ /* Send/receive data on the new connection for as long as it's valid */
+ while(hwp_server_running && (hwp_client_fd != -1))
+ {
+ /* if target not running, block on data from client or monitor thread */
+ /* if target running, just poll (don't block) */
+ // if(hwp_target_is_running) {
+ // tv.tv_sec = 0; // Set this each loop, it may be changed by the select() call
+ // tv.tv_usec = 0; // instant timeout when polling
+ // tvp = &tv;
+ //} else {
+ tvp = NULL;
+ //}
+
+ FD_ZERO(&readset);
+ FD_SET(hwp_client_fd, &readset);
+ FD_SET(hwp_pipe_fds[1], &readset);
+ nfds = hwp_client_fd;
+ if(hwp_pipe_fds[1] > nfds) nfds = hwp_pipe_fds[1];
+ nfds++;
+
+ ret = select(nfds, &readset, NULL, NULL, tvp);
+
+ if(ret == -1) // error
+ {
+ perror("select()");
+ }
+ else if(ret != 0) // fd ready (ret == 0 on timeout)
+ {
+ debug("HWP thread got data\n");
+
+ if(FD_ISSET(hwp_pipe_fds[1], &readset))
+ {
+ ret = read(hwp_pipe_fds[1], &cmd, 1);
+ debug("HWP server got monitor status \'%c\' (0x%X)\n", cmd, cmd);
+ if(ret == 1)
+ {
+ if(cmd == 'H')
+ {
+ // Save state so we can tell client on request
+ hwp_target_is_running = 0;
+ }
+ else if(cmd == 'R')
+ {
+ // Save state so we can tell client on request
+ hwp_target_is_running = 1;
+ use_cached_dmr2 = 0;
+ }
+ else
+ {
+ fprintf(stderr, "HWP server got unknown monitor status \'%c\' (0x%X)\n", cmd, cmd);
+ }
+ }
+ else
+ {
+ fprintf(stderr, "HWP server failed to read from ready monitor pipe!\n");
+ }
+ } // if FD_ISSET(hwp_pipe_fds[1])
+
+ if(FD_ISSET(hwp_client_fd, &readset))
+ {
+ hwp_client_request();
+ }
+ } // else if (ret != 0)
+
+ } /* while client connection is valid */
+
+ } /* while(hwp_server_running) */
+
+ hwp_client_close();
+
+ return arg; // unused
+}
+
+/*--------------------------------------------------------------------*/
+/* Helper functions */
+/*--------------------------------------------------------------------*/
+
+void hwp_server_close(void)
+{
+ if (hwp_server_fd != -1)
+ {
+ close(hwp_server_fd);
+ hwp_server_fd = -1;
+ }
+}
+
+
+void hwp_client_close(void)
+{
+ if (hwp_client_fd != -1)
+ {
+ close (hwp_client_fd);
+ hwp_client_fd = -1;
+ }
+} /* hwp_client_close () */
+
+
+void hwp_client_request(void)
+{
+ struct rsp_buf *buf = hwp_get_packet (); /* Message sent to us */
+
+ // Null packet means we hit EOF or the link was closed for some other
+ // reason. Close the client and return
+ if (NULL == buf)
+ {
+ hwp_client_close ();
+ return;
+ }
+
+ debug("HWP Packet received %s: %d chars\n", buf->data, buf->len );
+
+ switch (buf->data[0])
+ {
+
+ case '?':
+ // Different meaning than RSP: in RSP, this always returns an 'S' packet.
+ // here, we want to know running / stopped.
+ if(hwp_target_is_running) {
+ hwp_report_run();
+ } else {
+ hwp_report_stop();
+ }
+ return;
+
+
+ /*
+ case 'g':
+ rsp_read_all_regs ();
+ return;
+
+ case 'G':
+ rsp_write_all_regs (buf);
+ return;
+ */
+
+
+ case 'p':
+ /* Read a register */
+ hwp_read_reg(buf);
+ return;
+
+ case 'P':
+ /* Write a register */
+ hwp_write_reg(buf);
+ return;
+
+ /*
+ case 'q':
+ // Any one of a number of query packets
+ rsp_query (buf);
+ return;
+
+ case 'Q':
+ // Any one of a number of set packets
+ rsp_set (buf);
+ return;
+ */
+
+ default:
+ /* Unknown commands are ignored */
+ fprintf (stderr, "Warning: Unknown HWP request %s\n", buf->data);
+ return;
+ }
+} /* hwp_client_request () */
+
+
+/*---------------------------------------------------------------------------*/
+/*!Get a packet from the GDB client
+
+ Modeled on the stub version supplied with GDB. The data is in a static
+ buffer. The data should be copied elsewhere if it is to be preserved across
+ a subsequent call to get_packet().
+
+ Unlike the reference implementation, we don't deal with sequence
+ numbers. GDB has never used them, and this implementation is only intended
+ for use with GDB 6.8 or later. Sequence numbers were removed from the RSP
+ standard at GDB 5.0.
+
+ @return A pointer to the static buffer containing the data */
+/*---------------------------------------------------------------------------*/
+struct rsp_buf *hwp_get_packet(void)
+{
+ static struct rsp_buf buf; /* Survives the return */
+
+ /* Keep getting packets, until one is found with a valid checksum */
+ while (1)
+ {
+ unsigned char checksum; /* The checksum we have computed */
+ int count; /* Index into the buffer */
+ int ch; /* Current character */
+
+ /* Wait around for the start character ('$'). Ignore all other
+ characters */
+ ch = get_hwp_rsp_char(hwp_client_fd);
+ while (ch != '$')
+ {
+ if (-1 == ch)
+ {
+ return NULL; /* Connection failed */
+ }
+
+ ch = get_hwp_rsp_char(hwp_client_fd);
+ }
+
+ /* Read until a '#' or end of buffer is found */
+ checksum = 0;
+ count = 0;
+ while (count < HWP_BUF_MAX - 1)
+ {
+ ch = get_hwp_rsp_char(hwp_client_fd);
+
+ /* Check for connection failure */
+ if (-1 == ch)
+ {
+ return NULL;
+ }
+
+ /* If we hit a start of line char begin all over again */
+ if ('$' == ch)
+ {
+ checksum = 0;
+ count = 0;
+
+ continue;
+ }
+
+ /* Break out if we get the end of line char */
+ if ('#' == ch)
+ {
+ break;
+ }
+
+ /* Update the checksum and add the char to the buffer */
+
+ checksum = checksum + (unsigned char)ch;
+ buf.data[count] = (char)ch;
+ count = count + 1;
+ }
+
+ /* Mark the end of the buffer with EOS - it's convenient for non-binary
+ data to be valid strings. */
+ buf.data[count] = 0;
+ buf.len = count;
+
+ /* If we have a valid end of packet char, validate the checksum */
+ if ('#' == ch)
+ {
+ unsigned char xmitcsum; /* The checksum in the packet */
+
+ ch = get_hwp_rsp_char(hwp_client_fd);
+ if (-1 == ch)
+ {
+ return NULL; /* Connection failed */
+ }
+ xmitcsum = hwp_hex(ch) << 4;
+
+ ch = get_hwp_rsp_char(hwp_client_fd);
+ if (-1 == ch)
+ {
+ return NULL; /* Connection failed */
+ }
+
+ xmitcsum += hwp_hex(ch);
+
+ /* If the checksums don't match print a warning, and put the
+ negative ack back to the client. Otherwise put a positive ack. */
+ if (checksum != xmitcsum)
+ {
+ fprintf (stderr, "Warning: Bad HWP RSP checksum: Computed "
+ "0x%02x, received 0x%02x\n", checksum, xmitcsum);
+
+ put_hwp_rsp_char (hwp_client_fd, '-'); /* Failed checksum */
+ }
+ else
+ {
+ put_hwp_rsp_char (hwp_client_fd, '+'); /* successful transfer */
+ break;
+ }
+ }
+ else
+ {
+ fprintf (stderr, "Warning: HWP RSP packet overran buffer\n");
+ }
+ }
+
+ return &buf; /* Success */
+
+} /* hwp_get_packet () */
+
+
+/*---------------------------------------------------------------------------*/
+/*Single character get/set routines */
+/*---------------------------------------------------------------------------*/
+void put_hwp_rsp_char(int fd, char c)
+{
+ if (-1 == fd)
+ {
+ fprintf (stderr, "Warning: Attempt to write '%c' to unopened HWP RSP client: Ignored\n", c);
+ return;
+ }
+
+ /* Write until successful (we retry after interrupts) or catastrophic
+ failure. */
+ while (1)
+ {
+ switch (write(fd, &c, sizeof (c)))
+ {
+ case -1:
+ /* Error: only allow interrupts or would block */
+ if ((EAGAIN != errno) && (EINTR != errno))
+ {
+ fprintf (stderr, "Warning: Failed to write to HWP RSP client: Closing client connection: %s\n",
+ strerror (errno));
+ hwp_client_close();
+ return;
+ }
+
+ break;
+
+ case 0:
+ break; /* Nothing written! Try again */
+
+ default:
+ return; /* Success, we can return */
+ }
+ }
+} /* put_hwp_rsp_char() */
+
+
+
+int get_hwp_rsp_char(int fd)
+{
+ unsigned char c; /* The character read */
+
+ if (-1 == fd)
+ {
+ fprintf (stderr, "Warning: Attempt to read from unopened HWP RSP client: Ignored\n");
+ return -1;
+ }
+
+ /* Read until successful (we retry after interrupts) or catastrophic
+ failure. */
+ while (1)
+ {
+ switch (read (fd, &c, sizeof (c)))
+ {
+ case -1:
+ /* Error: only allow interrupts or would block */
+ if ((EAGAIN != errno) && (EINTR != errno))
+ {
+ fprintf (stderr, "Warning: Failed to read from HWP RSP client: Closing client connection: %s\n",
+ strerror (errno));
+ hwp_client_close();
+ return -1;
+ }
+
+ break;
+
+ case 0:
+ // EOF
+ hwp_client_close();
+ return -1;
+
+ default:
+ return c & 0xff; /* Success, we can return (no sign extend!) */
+ }
+ }
+} /* get_hwp_rsp_char() */
+
+
+/*---------------------------------------------------------------------------*/
+/*!Read a single register
+
+ The registers follow the GDB sequence for OR1K: GPR0 through GPR31, PC
+ (i.e. SPR NPC) and SR (i.e. SPR SR). The register is returned as a
+ sequence of bytes in target endian order.
+
+ Each byte is packed as a pair of hex digits.
+
+ @param[in] buf The original packet request. Reused for the reply. */
+/*---------------------------------------------------------------------------*/
+void hwp_read_reg(struct rsp_buf *buf)
+{
+ unsigned int regnum;
+ uint32_t tmp;
+ unsigned int errcode = APP_ERR_NONE;
+
+ /* Break out the fields from the data */
+ if (1 != sscanf (buf->data, "p%x", ®num))
+ {
+ fprintf (stderr, "Warning: Failed to recognize HWP RSP read register command: \'%s\'\n", buf->data);
+ hwp_put_str_packet (hwp_client_fd, "E01");
+ return;
+ }
+
+ if((regnum == SPR_DMR2) && use_cached_dmr2) // Should we use the cached DMR2 value?
+ {
+ tmp = cached_dmr2;
+ errcode = APP_ERR_NONE;
+ fprintf(stderr, "Using cached DMR2 value 0x%X\n", tmp);
+ }
+ else
+ {
+ /* Get the relevant register. We assume the client is not GDB,
+ * and that no register number translation is needed.
+ */
+ errcode = dbg_cpu0_read(regnum, &tmp);
+ }
+
+ if(errcode == APP_ERR_NONE) {
+ hwp_reg2hex(tmp, buf->data);
+ buf->len = strlen (buf->data);
+ debug("Read reg 0x%x, got %s (0x%X), len %i\n", regnum, buf->data, tmp, buf->len);
+ hwp_put_packet (hwp_client_fd, buf);
+ }
+ else {
+ fprintf(stderr, "Error reading HWP register: %s\n", get_err_string(errcode));
+ hwp_put_str_packet(hwp_client_fd, "E01");
+ }
+
+} /* hwp_read_reg() */
+
+
+/*---------------------------------------------------------------------------*/
+/*!Write a single register
+
+ The registers follow the GDB sequence for OR1K: GPR0 through GPR31, PC
+ (i.e. SPR NPC) and SR (i.e. SPR SR). The register is specified as a
+ sequence of bytes in target endian order.
+
+ Each byte is packed as a pair of hex digits.
+
+ @param[in] buf The original packet request. */
+/*---------------------------------------------------------------------------*/
+void hwp_write_reg (struct rsp_buf *buf)
+{
+ unsigned int regnum;
+ char valstr[9]; /* Allow for EOS on the string */
+ unsigned int errcode = APP_ERR_NONE;
+ int dcridx;
+ uint32_t val, cc, ct;
+
+ /* Break out the fields from the data */
+ if (2 != sscanf (buf->data, "P%x=%8s", ®num, valstr))
+ {
+ fprintf (stderr, "Warning: Failed to recognize RSP write register command: %s\n", buf->data);
+ hwp_put_str_packet (hwp_client_fd, "E01");
+ return;
+ }
+
+ /* Set the relevant register. We assume that the client is not
+ * GDB, and no register number translation is needed. */
+ val = hwp_hex2reg(valstr);
+ errcode = dbg_cpu0_write(regnum, val);
+
+ if(errcode == APP_ERR_NONE) {
+ debug("Wrote reg 0x%X with val 0x%X (%s)\n", regnum, hwp_hex2reg(valstr), valstr);
+ hwp_put_str_packet (hwp_client_fd, "OK");
+ }
+ else {
+ fprintf(stderr, "Error writing register: %s\n", get_err_string(errcode));
+ hwp_put_str_packet(hwp_client_fd, "E01");
+ }
+
+ /* A bit of hackery: Determine if this write enables a comparison on a DCR.
+ * If so, then we mark this HWP as in use, so that GDB/RSP cannot use it.
+ * Note that there's no point making the HWP client check which watchpoints are in
+ * use - GDB only sets HWP as it is starting the CPU, and clears them
+ * immediately after a stop. So as far as the HWP client would see, GDB/RSP
+ * never uses any watchpoints.
+ */
+
+ if((regnum >= SPR_DCR(0)) && (regnum <= SPR_DCR(7)))
+ {
+ dcridx = regnum - SPR_DCR(0);
+ /* If the 'compare condition' (cc) or 'compare to' (ct) are 0,
+ * then matching is disabled and we can mark this HWP not in use.
+ */
+ cc = val & 0x0E;
+ ct = val & 0xE0;
+ if ((cc == 0) || (ct == 0))
+ hwp_set_in_use(dcridx, 0);
+ else
+ hwp_set_in_use(dcridx, 1);
+ }
+
+} /* hwp_write_reg() */
+
+/*---------------------------------------------------------------------------*/
+/*!Convenience to put a constant string packet
+
+ param[in] str The text of the packet */
+/*---------------------------------------------------------------------------*/
+void hwp_put_str_packet (int fd, const char *str)
+{
+ struct rsp_buf buf;
+ int len = strlen (str);
+
+ /* Construct the packet to send, so long as string is not too big,
+ otherwise truncate. Add EOS at the end for convenient debug printout */
+
+ if (len >= HWP_BUF_MAX)
+ {
+ fprintf (stderr, "Warning: String %s too large for HWP RSP packet: truncated\n", str);
+ len = HWP_BUF_MAX - 1;
+ }
+
+ strncpy (buf.data, str, len);
+ buf.data[len] = 0;
+ buf.len = len;
+
+ hwp_put_packet (fd, &buf);
+
+} /* hwp_put_str_packet () */
+
+/*---------------------------------------------------------------------------*/
+/*!Send a packet to the GDB client
+
+ Modeled on the stub version supplied with GDB. Put out the data preceded by
+ a '$', followed by a '#' and a one byte checksum. '$', '#', '*' and '}' are
+ escaped by preceding them with '}' and then XORing the character with
+ 0x20.
+
+ @param[in] buf The data to send */
+/*---------------------------------------------------------------------------*/
+void hwp_put_packet (int fd, struct rsp_buf *buf)
+{
+ int ch; /* Ack char */
+
+ /* Construct $#. Repeat until the GDB client
+ acknowledges satisfactory receipt. */
+ do
+ {
+ unsigned char checksum = 0; /* Computed checksum */
+ int count = 0; /* Index into the buffer */
+
+ debug("Putting %s\n", buf->data);
+
+ put_hwp_rsp_char (fd, '$'); /* Start char */
+
+ /* Body of the packet */
+ for (count = 0; count < buf->len; count++)
+ {
+ unsigned char ch = buf->data[count];
+
+ /* Check for escaped chars */
+ if (('$' == ch) || ('#' == ch) || ('*' == ch) || ('}' == ch))
+ {
+ ch ^= 0x20;
+ checksum += (unsigned char)'}';
+ put_hwp_rsp_char (fd, '}');
+ }
+
+ checksum += ch;
+ put_hwp_rsp_char (fd, ch);
+ }
+
+ put_hwp_rsp_char (fd, '#'); /* End char */
+
+ /* Computed checksum */
+ put_hwp_rsp_char (fd, hexchars[checksum >> 4]);
+ put_hwp_rsp_char (fd, hexchars[checksum % 16]);
+
+ /* Check for ack or connection failure */
+ ch = get_hwp_rsp_char (fd);
+ if (-1 == ch)
+ {
+ return; /* Fail the put silently. */
+ }
+ }
+ while ('+' != ch);
+
+} /* hwp_put_packet() */
+
+
+unsigned long int hwp_hex2reg (char *buf)
+{
+ int n; /* Counter for digits */
+ unsigned long int val = 0; /* The result */
+
+ for (n = 0; n < 8; n++)
+ {
+#ifdef WORDSBIGENDIAN
+ int nyb_shift = n * 4;
+#else
+ int nyb_shift = 28 - (n * 4);
+#endif
+ val |= hwp_hex(buf[n]) << nyb_shift;
+ }
+
+ return val;
+
+} /* hwp_hex2reg() */
+
+
+void hwp_reg2hex(unsigned long int val, char *buf)
+{
+ int n; /* Counter for digits */
+
+ for (n = 0; n < 8; n++)
+ {
+#ifdef WORDSBIGENDIAN
+ int nyb_shift = n * 4;
+#else
+ int nyb_shift = 28 - (n * 4);
+#endif
+ buf[n] = hexchars[(val >> nyb_shift) & 0xf];
+ }
+
+ buf[8] = 0; /* Useful to terminate as string */
+
+} /* hwp_reg2hex() */
+
+
+int hwp_hex(int c)
+{
+ return ((c >= 'a') && (c <= 'f')) ? c - 'a' + 10 :
+ ((c >= '0') && (c <= '9')) ? c - '0' :
+ ((c >= 'A') && (c <= 'F')) ? c - 'A' + 10 : -1;
+
+} /* hwp_hex() */
+
+/* ---------------------------------------------------------------------- */
+/* Functions to report stop and start to the client. */
+/* Not strictly correct RSP protocol. */
+/*------------------------------------------------------------------------*/
+
+void hwp_report_stop(void)
+{
+ struct rsp_buf buf;
+ uint32_t ppcval;
+
+ // Read the PPC
+ dbg_cpu0_read(SPR_PPC, &ppcval);
+
+ debug("HWP reporting stop, PPC = 0x%X\n", ppcval);
+
+ /* Construct a signal received packet */
+ buf.data[0] = 'S';
+ buf.data[1] = hexchars[ppcval >> 4];
+ buf.data[2] = hexchars[ppcval % 16];
+ buf.data[3] = 0;
+ buf.len = strlen (buf.data);
+
+ hwp_put_packet(hwp_client_fd, &buf);
+
+} /* rsp_report_exception () */
+
+
+void hwp_report_run(void)
+{
+ struct rsp_buf buf;
+
+ // Construct a 'run' packet. This is completely non-standard, non-RSP, made up.
+ buf.data[0] = 'R';
+ buf.data[1] = 'U';
+ buf.data[2] = 'N';
+ buf.data[3] = 0;
+ buf.len = strlen (buf.data);
+
+ hwp_put_packet(hwp_client_fd, &buf);
+
+} /* hwp_report_run() */
+
+/* Used by the HWP server to indicate which HWP are
+ * in long-term use by an external client
+ */
+void hwp_set_in_use(unsigned int wp, unsigned char inuse)
+{
+ if(wp < HWP_MAX_WP)
+ {
+ hwp_in_use[wp] = inuse;
+ debug("HWP setting wp %i status to %i\n", wp, inuse);
+ }
+ else
+ fprintf(stderr, "ERROR! value %i out of range when setting HWP in use!\n", wp);
+}
+
+/* Called by the RSP server to get any one unused HWP.
+ * This will only be called immediately before a 'step'
+ * or 'continue,' and the HWP will be disabled as soon
+ * as the CPU returns control to the RSP server.
+ * Returns -1 if no HWP available.
+ */
+int hwp_get_available_watchpoint(void)
+{
+ int i;
+ int ret = -1;
+
+ for(i = 0; i < HWP_MAX_WP; i++)
+ {
+ if(hwp_in_use[i] == 0)
+ {
+ ret = i;
+ hwp_in_use[i] = 1;
+
+ break;
+ }
+ }
+ debug("HWP granting wp %i to GDB/RSP\n", ret);
+ return ret;
+}
+
+/* Called by the RSP server to indicate it is no longer
+ * using a watchpoint previously granted by
+ * hwp_get_available_watchpoint()
+ */
+void hwp_return_watchpoint(int wp)
+{
+ if(wp >= HWP_MAX_WP)
+ {
+ fprintf(stderr, "ERROR! WP value %i out of range in hwp_return_watchpoint()!\n", wp);
+ }
+ else
+ {
+ if(hwp_in_use[wp] != 0)
+ {
+ hwp_in_use[wp] = 0;
+ debug("HWP got wp %i back from GDB/RSP\n", wp);
+ }
+ else
+ fprintf(stderr, "ERROR! hwp_return_watchpoint() returning wp %i, not in use!\n", wp);
+ }
+}
Index: tags/ADS_RELEASE_3_0_0/Software/adv_jtag_bridge/doc/adv_jtag_bridge.pdf
===================================================================
--- tags/ADS_RELEASE_3_0_0/Software/adv_jtag_bridge/doc/adv_jtag_bridge.pdf (nonexistent)
+++ tags/ADS_RELEASE_3_0_0/Software/adv_jtag_bridge/doc/adv_jtag_bridge.pdf (revision 66)
@@ -0,0 +1,2648 @@
+%PDF-1.4
+%äüöß
+2 0 obj
+<>
+stream
+xœeQMOÃ0½çWøŒÔ`糑¢H-]‘¸
+*q˜8ñuaH첿P›"9¶Ÿã÷ì &8ª/@èÝ@†mLb¯ðxŸ”sxWã¢(EÀÏË\ÏÆÁò¶ËHÅf4¥£Œ]½}1CucaÓcªÁÀ-ÝêF©Ä^žHâæ˜p#Ðܪ [÷ò´Ü©Í¢¶gâ\HÚ€Aû&Î