Implementation of a new jtag remote_bitbang driver.
authorRichard Uhler <ruhler@mit.edu>
Thu, 25 Aug 2011 20:29:33 +0000 (13:29 -0700)
committerØyvind Harboe <oyvind.harboe@zylin.com>
Fri, 2 Sep 2011 14:50:01 +0000 (16:50 +0200)
The driver sends ascii encoded bitbang commands over unix sockets or TCP to
another process. This driver is useful for debugging software running on
processors which are being simulated.

configure.ac
doc/manual/jtag/drivers/remote_bitbang.txt [new file with mode: 0644]
doc/openocd.texi
src/jtag/drivers/Makefile.am
src/jtag/drivers/remote_bitbang.c [new file with mode: 0644]
src/jtag/interfaces.c

index b6c04ab..ec51bd7 100644 (file)
@@ -498,6 +498,10 @@ if test $build_zy1000 = yes; then
 fi
 AC_MSG_RESULT($build_zy1000)
 
+AC_ARG_ENABLE(remote-bitbang,
+  AS_HELP_STRING([--enable-remote-bitbang], [Enable building support for the Remote Bitbang jtag driver]),
+  [build_remote_bitbang=$enableval], [build_remote_bitbang=no])
+
 
 AC_MSG_CHECKING([whether to enable dummy minidriver])
 if test $build_minidriver_dummy = yes; then
@@ -778,6 +782,13 @@ if test "$use_internal_jimtcl" = yes; then
   fi
 fi
 
+if test $build_remote_bitbang = yes; then
+  build_bitbang=yes
+  AC_DEFINE(BUILD_REMOTE_BITBANG, 1, [1 if you want the Remote Bitbang JTAG driver.])
+else
+  AC_DEFINE(BUILD_REMOTE_BITBNAG, 0, [0 if you don't want the Remote Bitbang JTAG driver.])
+fi
+
 #-- Deal with MingW/Cygwin FTD2XX issues
 
 if test $is_win32 = yes; then
@@ -1075,6 +1086,7 @@ AM_CONDITIONAL(VSLLINK, test $build_vsllink = yes)
 AM_CONDITIONAL(RLINK, test $build_rlink = yes)
 AM_CONDITIONAL(ULINK, test $build_ulink = yes)
 AM_CONDITIONAL(ARMJTAGEW, test $build_armjtagew = yes)
+AM_CONDITIONAL(REMOTE_BITBANG, test $build_remote_bitbang = yes)
 AM_CONDITIONAL(BUSPIRATE, test $build_buspirate = yes)
 AM_CONDITIONAL(USB, test $build_usb = yes)
 AM_CONDITIONAL(IS_CYGWIN, test $is_cygwin = yes)
diff --git a/doc/manual/jtag/drivers/remote_bitbang.txt b/doc/manual/jtag/drivers/remote_bitbang.txt
new file mode 100644 (file)
index 0000000..5a80047
--- /dev/null
@@ -0,0 +1,53 @@
+/** @remote_bitbangpage OpenOCD Developer's Guide
+
+The remote_bitbang JTAG driver is used to drive JTAG from a remote process. The
+remote_bitbang driver communicates via TCP or UNIX sockets with some remote
+process using an ASCII encoding of the bitbang interface. The remote process
+presumably then drives the JTAG however it pleases. The remote process should
+act as a server, listening for connections from the openocd remote_bitbang
+driver.
+
+The remote bitbang driver is useful for debugging software running on
+processors which are being simulated.
+
+The bitbang interface consists of the following functions.
+
+blink on
+       Blink a light somewhere. The argument on is either 1 or 0.
+
+read
+       Sample the value of tdo.
+
+write tck tms tdi
+       Set the value of tck, tms, and tdi.
+
+reset trst srst
+       Set the value of trst, srst.
+
+An additional function, quit, is added to the remote_bitbang interface to
+indicate there will be no more requests and the connection with the remote
+driver should be closed.
+
+These five functions are encoded in ascii by assigning a single character to
+each possible request. The assignments are:
+
+       B - Blink on
+       b - Blink off
+       R - Read request
+       Q - Quit request
+       0 - Write 0 0 0
+       1 - Write 0 0 1
+       2 - Write 0 1 0
+       3 - Write 0 1 1
+       4 - Write 1 0 0
+       5 - Write 1 0 1
+       6 - Write 1 1 0
+       7 - Write 1 1 1
+       r - Reset 0 0
+       s - Reset 0 1
+       t - Reset 1 0
+       u - Reset 1 1
+
+The read response is encoded in ascii as either digit 0 or 1.
+
+ */
index 8b7e588..05c06b8 100644 (file)
@@ -2321,6 +2321,43 @@ ft2232_vid_pid 0x0403 0xbdc8
 @end example
 @end deffn
 
+@deffn {Interface Driver} {remote_bitbang}
+Drive JTAG from a remote process. This sets up a UNIX or TCP socket connection
+with a remote process and sends ASCII encoded bitbang requests to that process
+instead of directly driving JTAG.
+
+The remote_bitbang driver is useful for debugging software running on
+processors which are being simulated.
+
+@deffn {Config Command} {remote_bitbang_port} number
+Specifies the TCP port of the remote process to connect to or 0 to use UNIX
+sockets instead of TCP.
+@end deffn
+
+@deffn {Config Command} {remote_bitbang_host} hostname
+Specifies the hostname of the remote process to connect to using TCP, or the
+name of the UNIX socket to use if remote_bitbang_port is 0.
+@end deffn
+
+For example, to connect remotely via TCP to the host foobar you might have
+something like:
+
+@example
+interface remote_bitbang
+remote_bitbang_port 3335
+remote_bitbang_host foobar
+@end example
+
+To connect to another process running locally via UNIX sockets with socket
+named mysocket:
+
+@example
+interface remote_bitbang
+remote_bitbang_port 0
+remote_bitbang_host mysocket
+@end example
+@end deffn
+
 @deffn {Interface Driver} {usb_blaster}
 USB JTAG/USB-Blaster compatibles over one of the userspace libraries
 for FTDI chips.  These interfaces have several commands, used to
index 805d1a4..408ea81 100644 (file)
@@ -81,6 +81,9 @@ endif
 if BUSPIRATE
 DRIVERFILES += buspirate.c
 endif
+if REMOTE_BITBANG
+DRIVERFILES += remote_bitbang.c
+endif
 
 noinst_HEADERS = \
        bitbang.h \
diff --git a/src/jtag/drivers/remote_bitbang.c b/src/jtag/drivers/remote_bitbang.c
new file mode 100644 (file)
index 0000000..d3ab1b1
--- /dev/null
@@ -0,0 +1,286 @@
+/***************************************************************************
+ *   Copyright (C) 2011 by Richard Uhler                                   *
+ *   ruhler@mit.edu                                                        *
+ *                                                                         *
+ *   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.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netdb.h>
+#include <jtag/interface.h>
+#include "bitbang.h"
+
+// from unix man page and sys/un.h:
+#define UNIX_PATH_MAX 108
+
+// arbitrary limit on host name length:
+#define REMOTE_BITBANG_HOST_MAX 255
+
+#define REMOTE_BITBANG_RAISE_ERROR(expr ...) \
+               LOG_ERROR(expr); LOG_ERROR("Terminating openocd."); exit(-1);
+
+static char remote_bitbang_host[REMOTE_BITBANG_HOST_MAX] = "openocd";
+static uint16_t remote_bitbang_port = 0;
+
+FILE* remote_bitbang_in;
+FILE* remote_bitbang_out;
+
+static void remote_bitbang_putc(int c)
+{
+       if (EOF == fputc(c, remote_bitbang_out)) {
+               REMOTE_BITBANG_RAISE_ERROR("remote_bitbang_putc: %s", strerror(errno));
+       }
+}
+
+static int remote_bitbang_quit(void)
+{
+       if (EOF == fputc('Q', remote_bitbang_out)) {
+               LOG_ERROR("fputs: %s", strerror(errno));
+               return ERROR_FAIL;
+       }
+
+       if (EOF == fflush(remote_bitbang_out)) {
+               LOG_ERROR("fflush: %s", strerror(errno));
+               return ERROR_FAIL;
+       }
+               
+       // We only need to close one of the FILE*s, because they both use the same
+       // underlying file descriptor.
+       if (EOF == fclose(remote_bitbang_out)) {
+               LOG_ERROR("fclose: %s", strerror(errno));
+               return ERROR_FAIL;
+       }
+
+       LOG_INFO("remote_bitbang interface quit");
+       return ERROR_OK;
+}
+
+// Get the next read response.
+static int remote_bitbang_rread(void)
+{
+       if (EOF == fflush(remote_bitbang_out)) {
+               remote_bitbang_quit();
+               REMOTE_BITBANG_RAISE_ERROR("fflush: %s", strerror(errno));
+       }
+
+       int c = fgetc(remote_bitbang_in);
+       switch (c) {
+               case '0': return 0;
+               case '1': return 1;
+               default:
+                       remote_bitbang_quit();
+                       REMOTE_BITBANG_RAISE_ERROR(
+                               "remote_bitbang: invalid read response: %c(%i)", c, c);
+       }
+}
+
+static int remote_bitbang_read(void)
+{
+       remote_bitbang_putc('R');
+       return remote_bitbang_rread();
+}
+
+static void remote_bitbang_write(int tck, int tms, int tdi)
+{
+       char c = '0' + ((tck ? 0x4 : 0x0) | (tms ? 0x2 : 0x0) | (tdi ? 0x1 : 0x0));
+       remote_bitbang_putc(c);
+}
+
+static void remote_bitbang_reset(int trst, int srst)
+{
+       char c = 'r' + ((trst ? 0x2 : 0x0) | (srst ? 0x1 : 0x0));
+       remote_bitbang_putc(c);
+}
+
+static void remote_bitbang_blink(int on)
+{
+       char c = on ? 'B' : 'b';
+       remote_bitbang_putc(c);
+}
+
+static struct bitbang_interface remote_bitbang_bitbang = {
+       .read = &remote_bitbang_read,
+       .write = &remote_bitbang_write,
+       .reset = &remote_bitbang_reset,
+       .blink = &remote_bitbang_blink,
+};
+
+static int remote_bitbang_speed(int speed)
+{
+       return ERROR_OK;
+}
+
+static int remote_bitbang_init_tcp(void)
+{
+       LOG_INFO("Connecting to %s:%i", remote_bitbang_host, remote_bitbang_port);
+       int fd = socket(PF_INET, SOCK_STREAM, 0);
+       if (fd < 0) {
+               LOG_ERROR("socket: %s", strerror(errno));
+               return ERROR_FAIL;
+       }
+
+       struct hostent* hent = gethostbyname(remote_bitbang_host);
+       if (hent == NULL) {
+               char* errorstr = "???";
+               switch (h_errno) {
+                       case HOST_NOT_FOUND: errorstr = "host not found"; break;
+                       case NO_ADDRESS: errorstr = "no address"; break;
+                       case NO_RECOVERY: errorstr = "no recovery"; break;
+                       case TRY_AGAIN: errorstr = "try again"; break;
+               }
+               LOG_ERROR("gethostbyname: %s", errorstr);
+               return ERROR_FAIL;
+       }
+
+       struct sockaddr_in addr;
+       addr.sin_family = AF_INET;
+       addr.sin_port = htons(remote_bitbang_port);
+       addr.sin_addr = *(struct in_addr*)hent->h_addr;
+       if (connect(fd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) < 0) {
+               LOG_ERROR("connect: %s", strerror(errno));
+               return ERROR_FAIL;
+       }
+
+       remote_bitbang_in = fdopen(fd, "r");
+       if (remote_bitbang_in == NULL) {
+               LOG_ERROR("fdopen: failed to open read stream");
+               return ERROR_FAIL;
+       }
+
+       remote_bitbang_out = fdopen(fd, "w");
+       if (remote_bitbang_out == NULL) {
+               LOG_ERROR("fdopen: failed to open write stream");
+               return ERROR_FAIL;
+       }
+
+       LOG_INFO("remote_bitbang driver initialized");
+       return ERROR_OK;
+}
+
+static int remote_bitbang_init_unix(void)
+{
+       LOG_INFO("Connecting to unix socket %s", remote_bitbang_host);
+       int fd = socket(PF_UNIX, SOCK_STREAM, 0);
+       if (fd < 0) {
+               LOG_ERROR("socket: %s", strerror(errno));
+               return ERROR_FAIL;
+       }
+
+       struct sockaddr_un addr;
+       addr.sun_family = AF_UNIX;
+       strncpy(addr.sun_path, remote_bitbang_host, UNIX_PATH_MAX);
+       addr.sun_path[UNIX_PATH_MAX-1] = '\0';
+
+       if (connect(fd, (struct sockaddr*)&addr, sizeof(struct sockaddr_un)) < 0) {
+               LOG_ERROR("connect: %s", strerror(errno));
+               return ERROR_FAIL;
+       }
+
+       remote_bitbang_in = fdopen(fd, "r");
+       if (remote_bitbang_in == NULL) {
+               LOG_ERROR("fdopen: failed to open read stream");
+               return ERROR_FAIL;
+       }
+
+       remote_bitbang_out = fdopen(fd, "w");
+       if (remote_bitbang_out == NULL) {
+               LOG_ERROR("fdopen: failed to open write stream");
+               return ERROR_FAIL;
+       }
+
+       LOG_INFO("remote_bitbang driver initialized");
+       return ERROR_OK;
+}
+
+static int remote_bitbang_init(void)
+{
+       bitbang_interface = &remote_bitbang_bitbang;
+
+       LOG_INFO("Initializing remote_bitbang driver");
+       if (remote_bitbang_port == 0) {
+               return remote_bitbang_init_unix();
+       }
+       return remote_bitbang_init_tcp();
+}
+
+static int remote_bitbang_khz(int khz, int* jtag_speed)
+{
+       *jtag_speed = 0;
+       return ERROR_OK;
+}
+
+static int remote_bitbang_speed_div(int speed, int* khz)
+{
+       // I don't think this really matters any.
+       *khz = 1;
+       return ERROR_OK;
+}
+
+
+COMMAND_HANDLER(remote_bitbang_handle_remote_bitbang_port_command)
+{
+       if (CMD_ARGC == 1) {
+               COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], remote_bitbang_port);
+               return ERROR_OK;
+       }
+       return ERROR_COMMAND_SYNTAX_ERROR;
+}
+
+COMMAND_HANDLER(remote_bitbang_handle_remote_bitbang_host_command)
+{
+       if (CMD_ARGC == 1) {
+               strncpy(remote_bitbang_host, CMD_ARGV[0], REMOTE_BITBANG_HOST_MAX);
+               remote_bitbang_host[REMOTE_BITBANG_HOST_MAX-1] = '\0';
+               return ERROR_OK;
+       }
+       return ERROR_COMMAND_SYNTAX_ERROR;
+}
+
+
+static const struct command_registration remote_bitbang_command_handlers[] = {
+       {
+               .name = "remote_bitbang_port",
+               .handler = remote_bitbang_handle_remote_bitbang_port_command,
+               .mode = COMMAND_CONFIG,
+               .help = "Set the port to use to connect to the remote jtag.\n"
+                       "  if 0, use unix sockets to connect to the remote jtag.",
+               .usage = "port_number",
+       },
+       {
+               .name = "remote_bitbang_host",
+               .handler = remote_bitbang_handle_remote_bitbang_host_command,
+               .mode = COMMAND_CONFIG,
+               .help = "Set the host to use to connect to the remote jtag.\n"
+                       "  if port is 0, this is the name of the unix socket to use.",
+               .usage = "host_name",
+       },
+       COMMAND_REGISTRATION_DONE,
+};
+
+struct jtag_interface remote_bitbang_interface = {
+       .name = "remote_bitbang",
+       .execute_queue = &bitbang_execute_queue,
+       .speed = &remote_bitbang_speed,
+       .commands = remote_bitbang_command_handlers,
+       .init = &remote_bitbang_init,
+       .quit = &remote_bitbang_quit,
+       .khz = &remote_bitbang_khz,
+       .speed_div = &remote_bitbang_speed_div,
+};
index dbc69d0..76a4e8d 100644 (file)
@@ -97,6 +97,9 @@ extern struct jtag_interface armjtagew_interface;
 #if BUILD_BUSPIRATE == 1
 extern struct jtag_interface buspirate_interface;
 #endif
+#if BUILD_REMOTE_BITBANG == 1
+extern struct jtag_interface remote_bitbang_interface;
+#endif
 #endif // standard drivers
 
 /**
@@ -163,6 +166,9 @@ struct jtag_interface *jtag_interfaces[] = {
 #if BUILD_BUSPIRATE == 1
                &buspirate_interface,
 #endif
+#if BUILD_REMOTE_BITBANG == 1
+               &remote_bitbang_interface,
+#endif
 #endif // standard drivers
                NULL,
        };