URL
https://opencores.org/ocsvn/adv_debug_sys/adv_debug_sys/trunk
Subversion Repositories adv_debug_sys
[/] [adv_debug_sys/] [trunk/] [Software/] [adv_jtag_bridge/] [adv_jtag_bridge.c] - Rev 32
Go to most recent revision | Compare with Previous | Blame | View Log
/* adv_jtag_bridge.c -- JTAG protocol bridge between GDB and Advanced debug module. Copyright(C) 2001 Marko Mlinar, markom@opencores.org Code for TCP/IP copied from gdb, by Chris Ziomkowski Refactoring by Nathan Yawn <nyawn@opencores.org> (C) 2008 - 2010 This file was part of the OpenRISC 1000 Architectural Simulator. It is now also used to connect GDB to a running hardware OpenCores / OR1200 advanced debug unit. 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. */ /* Establishes jtag proxy server and communicates with parallel port directly. Requires root access. */ #include <stdio.h> #include <stdlib.h> // for exit(), atoi(), strtoul() #include <unistd.h> #include <stdarg.h> #include <string.h> // for strstr() #include <sys/types.h> #include "adv_jtag_bridge.h" #include "rsp-server.h" #include "chain_commands.h" #include "cable_common.h" #include "or32_selftest.h" #include "bsdl.h" #include "errcodes.h" #define debug(...) //fprintf(stderr, __VA_ARGS__ ) // How many command-line IR length settings to create by default #define IR_START_SETS 16 ////////////////////////////////////////////////// // Command line option flags / values /* Which device in the scan chain we want to target. * 0 is the first device we find, which is nearest the data input of the cable. */ unsigned int target_dev_pos = 0; // Do test before setting up server? unsigned char do_selftest = 0; // IR register length in TAP of // Can override autoprobe, or set if IDCODE not supported typedef struct { int dev_index; int ir_length; } irset; #define START_IR_SETS 16 int reallocs = 0; int num_ir_sets = 0; irset * cmd_line_ir_sizes = NULL; // DEBUG command for target device TAP // May actually be USER1, for Xilinx devices using internal BSCAN modules // Can override autoprobe, or set if unable to find in BSDL files int cmd_line_cmd_debug = -1; // 0 is a valid debug command, so use -1 // TCP port to set up the server for GDB on char *port; char default_port[] = "9999"; // Force altera virtual jtag mode on(1) or off(-1) int force_alt_vjtag = 0; // Pointer to the command line arg used as the cable name char * cable_name = NULL; //////////////////////////////////////////////////////// // List of IDCODES of devices on the JTAG scan chain // The array is dynamically allocated in chain_commands/jtag_enumerate_chain() uint32_t *idcodes = NULL; int num_devices = 0; const char *name_not_found = "(unknown)"; /////////////////////////////////////////////////////////// // JTAG constants // Defines for Altera JTAG constants #define ALTERA_MANUFACTURER_ID 0x6E // Defines for Xilinx JTAG constants #define XILINX_MANUFACTURER_ID 0x49 /////////////////////////////////////////////////// // Prototypes for local / helper functions int get_IR_size(int devidx); uint32_t get_debug_cmd(int devidx); void configure_chain(void); void print_usage(char *func); void parse_args(int argc, char **argv); void get_ir_opts(char *optstr, int *idx, int *val); ////////////////////////////////////////////////////////////////////////////////////// /*----------------------------------------------------------------------------------*/ // Functions ///////////////////////////////////////////////////////////////////////////////////// // Resets JTAG, and sets up DEBUG scan chain void configure_chain(void) { int i; unsigned int manuf_id; uint32_t cmd; const char *name; int irlen; int err = APP_ERR_NONE; err |= tap_reset(); err |= jtag_enumerate_chain(&idcodes, &num_devices); if(err != APP_ERR_NONE) { printf("Error %s enumerating JTAG chain, aborting.\n", get_err_string(err)); exit(1); } printf("\nDevices on JTAG chain:\n"); printf("Index\tName\t\tID Code\t\tIR Length\n"); printf("----------------------------------------------------------------\n"); for(i = 0; i < num_devices; i++) { if(idcodes[i] != IDCODE_INVALID) { name = bsdl_get_name(idcodes[i]); irlen = bsdl_get_IR_size(idcodes[i]); if(name == NULL) name = name_not_found; } else { name = name_not_found; irlen = -1; } printf("%d: \t%s \t0x%08X \t%d\n", i, name, idcodes[i], irlen); } printf("\n"); #ifdef __LEGACY__ // The legacy debug interface cannot support multi-device chains. If there is more than // one device on this chain, pull the cord. if(num_devices > 1) { fprintf(stderr, "\n*** ERROR: The legacy debug hardware cannot support JTAG chains with\n"); fprintf(stderr, "*** more than one device. Reconnect the JTAG cable to ONLY the legacy\n"); fprintf(stderr, "*** debug unit, or change your SoC to use the Advanced Debug Unit.\n"); exit(0); } #endif if(target_dev_pos >= num_devices) { printf("ERROR: Requested target device (%i) beyond highest device index (%i).\n", target_dev_pos, num_devices-1); exit(1); } else { printf("Target device %i, JTAG ID = 0x%08x\n", target_dev_pos, idcodes[target_dev_pos]); } manuf_id = (idcodes[target_dev_pos] >> 1) & 0x7FF; // Use BSDL files to determine prefix bits, postfix bits, debug command, IR length config_set_IR_size(get_IR_size(target_dev_pos)); // Set the IR prefix / postfix bits int total = 0; for(i = 0; i < num_devices; i++) { if(i == target_dev_pos) { config_set_IR_postfix_bits(total); //debug("Postfix bits: %d\n", total); total = 0; continue; } total += get_IR_size(i); debug("Adding %i to total for devidx %i\n", get_IR_size(i), i); } config_set_IR_prefix_bits(total); debug("Prefix bits: %d\n", total); // Note that there's a little translation here, since device index 0 is actually closest to the cable data input config_set_DR_prefix_bits(num_devices - target_dev_pos - 1); // number of devices between cable data out and target device config_set_DR_postfix_bits(target_dev_pos); // number of devices between target device and cable data in // Set the DEBUG command for the IR of the target device. // If this is a Xilinx device, use USER1 instead of DEBUG // If we Altera Virtual JTAG mode, we don't care. if((force_alt_vjtag == -1) || ((force_alt_vjtag == 0) && (manuf_id != ALTERA_MANUFACTURER_ID))) { cmd = get_debug_cmd(target_dev_pos); if(cmd == TAP_CMD_INVALID) { printf("Unable to find DEBUG command, aborting.\n"); exit(1); } config_set_debug_cmd(cmd); // This may have to be USER1 if this is a Xilinx device } // Enable the kludge for Xilinx BSCAN, if necessary. // Safe, but slower, for non-BSCAN TAPs. if(manuf_id == XILINX_MANUFACTURER_ID) { config_set_xilinx_bscan(1); } // Set Altera Virtual JTAG mode on or off. If not forced, then enable // if the target device has an Altera manufacturer IDCODE if(force_alt_vjtag == 1) { config_set_alt_vjtag(1); } else if(force_alt_vjtag == -1) { config_set_alt_vjtag(0); } else { if(manuf_id == ALTERA_MANUFACTURER_ID) { config_set_alt_vjtag(1); } else { config_set_alt_vjtag(0); } } // Do a sanity test cmd = bsdl_get_idcode_cmd(idcodes[target_dev_pos]); if(cmd != TAP_CMD_INVALID) { uint32_t id_read; err |= jtag_get_idcode(cmd, &id_read); if(err != APP_ERR_NONE) { printf("Error %s checking IDCODE, aborting.\n", get_err_string(err)); exit(1); } if(id_read == idcodes[target_dev_pos]) { printf("IDCODE sanity test passed, chain OK!\n"); } else { printf("Warning: IDCODE sanity test failed. Read IDCODE 0x%08X, expected 0x%08X\n", id_read, idcodes[target_dev_pos]); } } if(err |= tap_enable_debug_module()) { // Select the debug unit in the TAP. printf("Error %s enabling debug module, aborting.\n", get_err_string(err)); exit(1); } } void print_usage(char *func) { printf("JTAG connection between GDB and the SoC debug interface.\n"); #ifdef __LEGACY__ printf("Compiled with support for the Legacy debug unit (debug_if).\n"); #else printf("Compiled with support for the Advanced Debug Interface (adv_dbg_if).\n"); #endif printf("Copyright (C) 2008 Nathan Yawn, nathan.yawn@opencores.org\n\n"); printf("Usage: %s (options) [cable] (cable options)\n", func); printf("Options:\n"); printf("\t-g [port] : port number for GDB (default: 9999)\n"); printf("\t-x [index] : Position of the target device in the scan chain\n"); printf("\t-a [0 / 1] : force Altera virtual JTAG mode off (0) or on (1)\n"); printf("\t-l [<index>:<bits>] : Specify length of IR register for device\n"); printf("\t <index>, override autodetect (if any)\n"); printf("\t-c [hex cmd] : Debug command for target TAP, override autodetect\n"); printf("\t (ignored for Altera targets)\n"); printf("\t-v [hex cmd] : VIR command for target TAP, override autodetect\n"); printf("\t (Altera virtual JTAG targets only)\n"); printf("\t-r [hex cmd] : VDR for target TAP, override autodetect\n"); printf("\t (Altera virtual JTAG targets only)\n"); printf("\t-b [dirname] : Add a directory to search for BSDL files\n"); printf("\t-t : perform CPU / memory self-test before starting server\n"); printf("\t-h : show help\n\n"); cable_print_help(); } void parse_args(int argc, char **argv) { int c; int i; int idx, val; const char *valid_cable_args = NULL; port = NULL; force_alt_vjtag = 0; cmd_line_cmd_debug = -1; /* Parse the global arguments (if-any) */ while((c = getopt(argc, argv, "+g:x:a:l:c:v:r:b:th")) != -1) { switch(c) { case 'h': print_usage(argv[0]); exit(0); break; case 'g': port = optarg; break; case 'x': target_dev_pos = atoi(optarg); break; case 'l': get_ir_opts(optarg, &idx, &val); // parse the option if(num_ir_sets >= (IR_START_SETS<<reallocs)) { cmd_line_ir_sizes = (irset *) realloc(cmd_line_ir_sizes, (IR_START_SETS<<reallocs)*sizeof(irset)); if(cmd_line_ir_sizes == NULL) { printf("Error: out of memory while parsing command line. Aborting.\n"); exit(1); } } cmd_line_ir_sizes[num_ir_sets].dev_index = idx; cmd_line_ir_sizes[num_ir_sets].ir_length = val; num_ir_sets++; break; case 'c': cmd_line_cmd_debug = strtoul(optarg, NULL, 16); break; case 'v': config_set_vjtag_cmd_vir(strtoul(optarg, NULL, 16)); break; case 'r': config_set_vjtag_cmd_vdr(strtoul(optarg, NULL, 16)); break; case 't': do_selftest = 1; break; case 'a': if(atoi(optarg) == 1) force_alt_vjtag = 1; else force_alt_vjtag = -1; break; case 'b': bsdl_add_directory(optarg); break; default: print_usage(argv[0]); exit(1); } } if(port == NULL) port = default_port; int found_cable = 0; char* start_str = argv[optind]; int start_idx = optind; for(i = optind; i < argc; i++) { if(cable_select(argv[i]) == APP_ERR_NONE) { found_cable = 1; cable_name = argv[i]; argv[optind] = argv[start_idx]; // swap the cable name with the other arg, argv[start_idx] = start_str; // keep all cable opts at the end break; } } if(!found_cable) { fprintf(stderr, "No valid cable specified.\n"); exit(1); } optind = start_idx+1; // reset the parse index /* Get the cable-arguments */ valid_cable_args = cable_get_args(); /* Parse the remaining options for the cable. * Note that this will include unrecognized option from before the cable name. */ while((c = getopt(argc, argv, valid_cable_args)) != -1) { //printf("Got cable opt %c (0x%X)\n", (char)c, c); if(c == '?') { printf("\nERROR: Unknown cable option \'-%c\'\n\n", optopt); print_usage(argv[0]); exit(1); } else if(cable_parse_opt(c, optarg) != APP_ERR_NONE) { printf("\nERROR: Failed to parse cable option \'-%c\' %s\n\n", (char)c, optarg); print_usage(argv[0]); exit(1); } } } int main(int argc, char *argv[]) { char *s; long int serverPort; srand(getpid()); bsdl_init(); cmd_line_ir_sizes = (irset *) malloc(IR_START_SETS * sizeof(irset)); if(cmd_line_ir_sizes == NULL) { printf("ERROR: out of memory allocating array for IR sizes.\n"); return 1; } parse_args(argc, argv); if(cable_init() != APP_ERR_NONE) { printf("Failed to initialize cable \'%s\', aborting.\n", cable_name); exit(1); } /* Initialize a new connection to the or1k board, and make sure we are really connected. */ configure_chain(); if(do_selftest) { // Test the connection. printf("*** Doing self-test ***\n"); if(dbg_test() != APP_ERR_NONE) { printf("Self-test FAILED *** Bailing out!\n"); exit(1); } printf("*** Self-test PASSED ***\n"); } /* We have a connection. Establish server. */ serverPort = strtol(port,&s,10); if(*s) return -1; rsp_init(serverPort); printf("JTAG bridge ready!\n"); // This handles requests from GDB. I'd prefer the while() loop to be in the function // with the select()/poll(), but the or1ksim rsp code (ported for use here) doesn't work // that way, and I don't want to rework that code (to make it easier to import fixes // written for the or1ksim rsp server). --NAY while(handle_rsp()); return 0; } ////////////////////////////////////////////////// // Helper functions int get_IR_size(int devidx) { int retval = -1; int i; if(idcodes[devidx] != IDCODE_INVALID) { retval = bsdl_get_IR_size(idcodes[devidx]); } // Search for this devices in the array of command line IR sizes for(i = 0; i < num_ir_sets; i++) { if(cmd_line_ir_sizes[i].dev_index == devidx) { if((retval > 0) && (retval != cmd_line_ir_sizes[i].ir_length)) printf("Warning: overriding autoprobed IR length (%i) with command line value (%i) for device %i\n", retval, cmd_line_ir_sizes[i].ir_length, devidx); retval = cmd_line_ir_sizes[i].ir_length; } } if(retval < 0) { // Make sure we have a value printf("ERROR! Unable to autoprobe IR length for device index %i; Must set IR size on command line. Aborting.\n", devidx); exit(1); } return retval; } uint32_t get_debug_cmd(int devidx) { int retval = TAP_CMD_INVALID; uint32_t manuf_id = (idcodes[devidx] >> 1) & 0x7FF; if(idcodes[devidx] != IDCODE_INVALID) { if(manuf_id == XILINX_MANUFACTURER_ID) { retval = bsdl_get_user1_cmd(idcodes[devidx]); if(cmd_line_cmd_debug < 0) printf("Xilinx IDCODE, assuming internal BSCAN mode\n\t(using USER1 instead of DEBUG TAP command)\n"); } else { retval = bsdl_get_debug_cmd(idcodes[devidx]); } } if(cmd_line_cmd_debug >= 0) { if(retval != TAP_CMD_INVALID) { printf("Warning: overriding autoprobe debug command (0x%X) with command line value (0x%X)\n", retval, cmd_line_cmd_debug); } else { printf("Using command-line debug command 0x%X\n", cmd_line_cmd_debug); } retval = cmd_line_cmd_debug; } if(retval == TAP_CMD_INVALID) { printf("ERROR! Unable to find DEBUG command for device index %i, device ID 0x%0X\n", devidx, idcodes[devidx]); } return retval; } // Extracts two values from an option string // of the form "<index>:<value>", where both args // are in base 10 void get_ir_opts(char *optstr, int *idx, int *val) { char *ptr; ptr = strstr(optstr, ":"); if(ptr == NULL) { printf("Error: badly formatted IR length option. Use format \'<index>:<value>\', without spaces, where both args are in base 10\n"); exit(1); } *ptr = '\0'; ptr++; // This now points to the second (value) arg string *idx = strtoul(optstr, NULL, 10); *val = strtoul(ptr, NULL, 10); // ***CHECK FOR SUCCESS }
Go to most recent revision | Compare with Previous | Blame | View Log