jtag: drivers: Add JTAP VPI client driver 09/1609/4
authorFranck Jullien <franck.jullien@gmail.com>
Fri, 6 Sep 2013 16:42:39 +0000 (18:42 +0200)
committerSpencer Oliver <spen@spen-soft.co.uk>
Sun, 8 Sep 2013 15:37:51 +0000 (15:37 +0000)
This patch adds a driver for the jtag_vpi server [1]. This server is
now part of the ORPSoC version 3 (OpenRISC Reference Platform SoC).
The jtag_vpi server provides an interface between OpenOCD and a simulated
core.

[1] http://github.com/fjullien/jtag_vpi

Change-Id: I717b72cace4845f66c878581345074f99002e21a
Signed-off-by: Franck Jullien <franck.jullien@gmail.com>
Reviewed-on: http://openocd.zylin.com/1609
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
configure.ac
doc/openocd.texi
src/jtag/drivers/Makefile.am
src/jtag/drivers/jtag_vpi.c [new file with mode: 0644]
src/jtag/interfaces.c
tcl/interface/jtag_vpi.cfg [new file with mode: 0644]

index 1a647475a3dc25db66c64dd0e04a40bc56ade5e7..c7700dc3157b2bdce73b12dada2c2e89e87cd527 100644 (file)
@@ -355,6 +355,10 @@ AC_ARG_ENABLE([ftdi],
   AS_HELP_STRING([--enable-ftdi], [Enable building support for the MPSSE mode of FTDI based devices, using libusb-1.0 in asynchronous mode]),
   [build_ftdi=$enableval], [build_ftdi=no])
 
+AC_ARG_ENABLE([jtag_vpi],
+  AS_HELP_STRING([--enable-jtag_vpi], [Enable building support for JTAG VPI]),
+  [build_jtag_vpi=$enableval], [build_jtag_vpi=no])
+
 AC_ARG_ENABLE([usb_blaster_libftdi],
   AS_HELP_STRING([--enable-usb_blaster_libftdi], [Enable building support for the Altera USB-Blaster using the libftdi driver, opensource alternate of FTD2XX]),
   [build_usb_blaster_libftdi=$enableval], [build_usb_blaster_libftdi=no])
@@ -692,6 +696,12 @@ else
   AC_DEFINE([BUILD_USB_BLASTER_LIBFTDI], [0], [0 if you don't want libftdi usb_blaster.])
 fi
 
+if test $build_jtag_vpi = yes; then
+  AC_DEFINE([BUILD_JTAG_VPI], [1], [1 if you want JTAG VPI.])
+else
+  AC_DEFINE([BUILD_JTAG_VPI], [0], [0 if you don't want JTAG VPI.])
+fi
+
 if test $build_usb_blaster_ftd2xx = yes; then
   AC_DEFINE([BUILD_USB_BLASTER_FTD2XX], [1], [1 if you want ftd2xx usb_blaster.])
 else
@@ -1206,6 +1216,7 @@ AM_CONDITIONAL([FT2232_DRIVER], [test $build_ft2232_ftd2xx = yes -o $build_ft223
 AM_CONDITIONAL([FTDI_DRIVER], [test $build_ftdi = yes])
 AM_CONDITIONAL([USB_BLASTER_LIBFTDI], [test $build_usb_blaster_libftdi = yes])
 AM_CONDITIONAL([USB_BLASTER_FTD2XX], [test $build_usb_blaster_ftd2xx = yes])
+AM_CONDITIONAL([JTAG_VPI], [test $build_jtag_vpi = yes -o $build_jtag_vpi = yes])
 AM_CONDITIONAL([USB_BLASTER_DRIVER], [test $build_usb_blaster_ftd2xx = yes -o $build_usb_blaster_libftdi = yes])
 AM_CONDITIONAL([AMTJTAGACCEL], [test $build_amtjtagaccel = yes])
 AM_CONDITIONAL([GW16012], [test $build_gw16012 = yes])
index 78a4e8ed921255489678f9dc52cb90003ad4ac82..a747f9ac4b4a44c113ab74f890543d1e13016211 100644 (file)
@@ -578,6 +578,10 @@ produced, PDF schematics are easily found and it is easy to make.
 @item @b{bcm2835gpio}
 @* A BCM2835-based board (e.g. Raspberry Pi) using the GPIO pins of the expansion header.
 
+@item @b{jtag_vpi}
+@* A JTAG driver acting as a client for the JTAG VPI server interface.
+@* Link: @url{http://github.com/fjullien/jtag_vpi}
+
 @end itemize
 
 @node About Jim-Tcl
index e242cc6757ea6fee22a4664035f152e028be957c..e3ed2199a494c762606e7dc6657f7ddcceff187a 100644 (file)
@@ -42,6 +42,9 @@ endif
 if FTDI_DRIVER
 DRIVERFILES += ftdi.c mpsse.c
 endif
+if JTAG_VPI
+DRIVERFILES += jtag_vpi.c
+endif
 if USB_BLASTER_DRIVER
 SUBDIRS += usb_blaster
 libocdjtagdrivers_la_LIBADD += $(top_builddir)/src/jtag/drivers/usb_blaster/libocdusbblaster.la
diff --git a/src/jtag/drivers/jtag_vpi.c b/src/jtag/drivers/jtag_vpi.c
new file mode 100644 (file)
index 0000000..84cd947
--- /dev/null
@@ -0,0 +1,440 @@
+/*
+ * JTAG to VPI driver
+ *
+ * Copyright (C) 2013 Franck Jullien, <elec4fun@gmail.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <jtag/interface.h>
+#include <arpa/inet.h>
+
+#define NO_TAP_SHIFT   0
+#define TAP_SHIFT      1
+
+#define SERVER_ADDRESS "127.0.0.1"
+#define SERVER_PORT    5555
+
+#define        XFERT_MAX_SIZE          512
+
+#define CMD_RESET              0
+#define CMD_TMS_SEQ            1
+#define CMD_SCAN_CHAIN         2
+#define CMD_SCAN_CHAIN_FLIP_TMS        3
+#define CMD_STOP_SIMU          4
+
+int server_port = SERVER_PORT;
+
+int sockfd;
+struct sockaddr_in serv_addr;
+
+struct vpi_cmd {
+       int cmd;
+       unsigned char buffer_out[XFERT_MAX_SIZE];
+       unsigned char buffer_in[XFERT_MAX_SIZE];
+       int length;
+       int nb_bits;
+};
+
+static int jtag_vpi_send_cmd(struct vpi_cmd *vpi)
+{
+       int retval = write(sockfd, vpi, sizeof(struct vpi_cmd));
+       if (retval <= 0)
+               return ERROR_FAIL;
+
+       return ERROR_OK;
+}
+
+static int jtag_vpi_receive_cmd(struct vpi_cmd *vpi)
+{
+       int retval = read(sockfd, vpi, sizeof(struct vpi_cmd));
+       if (retval < (int)sizeof(struct vpi_cmd))
+               return ERROR_FAIL;
+
+       return ERROR_OK;
+}
+
+/**
+ * jtag_vpi_reset - ask to reset the JTAG device
+ * @trst: 1 if TRST is to be asserted
+ * @srst: 1 if SRST is to be asserted
+ */
+static int jtag_vpi_reset(int trst, int srst)
+{
+       struct vpi_cmd vpi;
+
+       vpi.cmd = CMD_RESET;
+       vpi.length = 0;
+       return jtag_vpi_send_cmd(&vpi);
+}
+
+/**
+ * jtag_vpi_tms_seq - ask a TMS sequence transition to JTAG
+ * @bits: TMS bits to be written (bit0, bit1 .. bitN)
+ * @nb_bits: number of TMS bits (between 1 and 8)
+ *
+ * Write a serie of TMS transitions, where each transition consists in :
+ *  - writing out TCK=0, TMS=<new_state>, TDI=<???>
+ *  - writing out TCK=1, TMS=<new_state>, TDI=<???> which triggers the transition
+ * The function ensures that at the end of the sequence, the clock (TCK) is put
+ * low.
+ */
+static int jtag_vpi_tms_seq(const uint8_t *bits, int nb_bits)
+{
+       struct vpi_cmd vpi;
+       int nb_bytes;
+
+       nb_bytes = (nb_bits / 8) + !!(nb_bits % 8);
+
+       vpi.cmd = CMD_TMS_SEQ;
+       memcpy(vpi.buffer_out, bits, nb_bytes);
+       vpi.length = nb_bytes;
+       vpi.nb_bits = nb_bits;
+
+       return jtag_vpi_send_cmd(&vpi);
+}
+
+/**
+ * jtag_vpi_path_move - ask a TMS sequence transition to JTAG
+ * @cmd: path transition
+ *
+ * Write a serie of TMS transitions, where each transition consists in :
+ *  - writing out TCK=0, TMS=<new_state>, TDI=<???>
+ *  - writing out TCK=1, TMS=<new_state>, TDI=<???> which triggers the transition
+ * The function ensures that at the end of the sequence, the clock (TCK) is put
+ * low.
+ */
+
+static int jtag_vpi_path_move(struct pathmove_command *cmd)
+{
+       uint16_t trans = 0;
+       int retval;
+       int i;
+
+       for (i = 0; i < cmd->num_states; i++) {
+               if (tap_state_transition(tap_get_state(), true) == cmd->path[i])
+                       trans = trans | 1;
+               trans = trans << 1;
+       }
+
+       retval = jtag_vpi_tms_seq((uint8_t *)&trans, 1);
+       if (retval != ERROR_OK)
+               return retval;
+
+       tap_set_state(cmd->path[i]);
+
+       return ERROR_OK;
+}
+
+/**
+ * jtag_vpi_tms - ask a tms command
+ * @cmd: tms command
+ */
+static int jtag_vpi_tms(struct tms_command *cmd)
+{
+       return jtag_vpi_tms_seq(cmd->bits, cmd->num_bits);
+}
+
+static int jtag_vpi_state_move(tap_state_t state)
+{
+       if (tap_get_state() == state)
+               return ERROR_OK;
+
+       uint8_t tms_scan = tap_get_tms_path(tap_get_state(), state);
+       int tms_len = tap_get_tms_path_len(tap_get_state(), state);
+
+       int retval = jtag_vpi_tms_seq(&tms_scan, tms_len);
+       if (retval != ERROR_OK)
+               return retval;
+
+       tap_set_state(state);
+
+       return ERROR_OK;
+}
+
+static int jtag_vpi_queue_tdi_xfer(uint8_t *bits, int nb_bits, int tap_shift)
+{
+       struct vpi_cmd vpi;
+       int nb_bytes = (nb_bits / 8) + !!(nb_bits % 8);
+
+       vpi.cmd = tap_shift ? CMD_SCAN_CHAIN_FLIP_TMS : CMD_SCAN_CHAIN;
+
+       if (bits)
+               memcpy(vpi.buffer_out, bits, nb_bytes);
+       else
+               memset(vpi.buffer_out, 0xff, nb_bytes);
+
+       vpi.length = nb_bytes;
+       vpi.nb_bits = nb_bits;
+
+       int retval = jtag_vpi_send_cmd(&vpi);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = jtag_vpi_receive_cmd(&vpi);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (bits)
+               memcpy(bits, vpi.buffer_in, nb_bytes);
+
+       return ERROR_OK;
+}
+
+/**
+ * jtag_vpi_queue_tdi - short description
+ * @bits: bits to be queued on TDI (or NULL if 0 are to be queued)
+ * @nb_bits: number of bits
+ */
+static int jtag_vpi_queue_tdi(uint8_t *bits, int nb_bits, int tap_shift)
+{
+       int nb_xfer = (nb_bits / (XFERT_MAX_SIZE * 8)) + !!(nb_bits % (XFERT_MAX_SIZE * 8));
+       uint8_t *xmit_buffer = bits;
+       int xmit_nb_bits = nb_bits;
+       int i = 0;
+       int retval;
+
+       while (nb_xfer) {
+
+               if (nb_xfer ==  1) {
+                       retval = jtag_vpi_queue_tdi_xfer(&xmit_buffer[i], xmit_nb_bits, tap_shift);
+                       if (retval != ERROR_OK)
+                               return retval;
+               } else {
+                       retval = jtag_vpi_queue_tdi_xfer(&xmit_buffer[i], XFERT_MAX_SIZE * 8, NO_TAP_SHIFT);
+                       if (retval != ERROR_OK)
+                               return retval;
+                       xmit_nb_bits -= XFERT_MAX_SIZE * 8;
+                       i += XFERT_MAX_SIZE;
+               }
+
+               nb_xfer--;
+       }
+
+       return ERROR_OK;
+}
+
+/**
+ * jtag_vpi_clock_tms - clock a TMS transition
+ * @tms: the TMS to be sent
+ *
+ * Triggers a TMS transition (ie. one JTAG TAP state move).
+ */
+static int jtag_vpi_clock_tms(int tms)
+{
+       const uint8_t tms_0 = 0;
+       const uint8_t tms_1 = 1;
+
+       return jtag_vpi_tms_seq(tms ? &tms_1 : &tms_0, 1);
+}
+
+/**
+ * jtag_vpi_scan - launches a DR-scan or IR-scan
+ * @cmd: the command to launch
+ *
+ * Launch a JTAG IR-scan or DR-scan
+ *
+ * Returns ERROR_OK if OK, ERROR_xxx if a read/write error occured.
+ */
+static int jtag_vpi_scan(struct scan_command *cmd)
+{
+       int scan_bits;
+       uint8_t *buf = NULL;
+       int retval = ERROR_OK;
+
+       scan_bits = jtag_build_buffer(cmd, &buf);
+
+       if (cmd->ir_scan) {
+               retval = jtag_vpi_state_move(TAP_IRSHIFT);
+               if (retval != ERROR_OK)
+                       return retval;
+       } else {
+               retval = jtag_vpi_state_move(TAP_DRSHIFT);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       if (cmd->end_state == TAP_DRSHIFT) {
+               retval = jtag_vpi_queue_tdi(buf, scan_bits, NO_TAP_SHIFT);
+               if (retval != ERROR_OK)
+                       return retval;
+       } else {
+               retval = jtag_vpi_queue_tdi(buf, scan_bits, TAP_SHIFT);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       if (cmd->end_state != TAP_DRSHIFT) {
+               /*
+                * As our JTAG is in an unstable state (IREXIT1 or DREXIT1), move it
+                * forward to a stable IRPAUSE or DRPAUSE.
+                */
+               retval = jtag_vpi_clock_tms(0);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               if (cmd->ir_scan)
+                       tap_set_state(TAP_IRPAUSE);
+               else
+                       tap_set_state(TAP_DRPAUSE);
+       }
+
+       retval = jtag_read_buffer(buf, cmd);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (buf)
+               free(buf);
+
+       if (cmd->end_state != TAP_DRSHIFT) {
+               retval = jtag_vpi_state_move(cmd->end_state);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       return ERROR_OK;
+}
+
+static int jtag_vpi_runtest(int cycles, tap_state_t state)
+{
+       int retval;
+
+       retval = jtag_vpi_state_move(TAP_IDLE);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = jtag_vpi_queue_tdi(NULL, cycles, TAP_SHIFT);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return jtag_vpi_state_move(state);
+}
+
+static int jtag_vpi_stableclocks(int cycles)
+{
+       return jtag_vpi_queue_tdi(NULL, cycles, TAP_SHIFT);
+}
+
+static int jtag_vpi_execute_queue(void)
+{
+       struct jtag_command *cmd;
+       int retval = ERROR_OK;
+
+       for (cmd = jtag_command_queue; retval == ERROR_OK && cmd != NULL;
+            cmd = cmd->next) {
+               switch (cmd->type) {
+               case JTAG_RESET:
+                       retval = jtag_vpi_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
+                       break;
+               case JTAG_RUNTEST:
+                       retval = jtag_vpi_runtest(cmd->cmd.runtest->num_cycles,
+                                                 cmd->cmd.runtest->end_state);
+                       break;
+               case JTAG_STABLECLOCKS:
+                       retval = jtag_vpi_stableclocks(cmd->cmd.stableclocks->num_cycles);
+                       break;
+               case JTAG_TLR_RESET:
+                       retval = jtag_vpi_state_move(cmd->cmd.statemove->end_state);
+                       break;
+               case JTAG_PATHMOVE:
+                       retval = jtag_vpi_path_move(cmd->cmd.pathmove);
+                       break;
+               case JTAG_TMS:
+                       retval = jtag_vpi_tms(cmd->cmd.tms);
+                       break;
+               case JTAG_SLEEP:
+                       jtag_sleep(cmd->cmd.sleep->us);
+                       break;
+               case JTAG_SCAN:
+                       retval = jtag_vpi_scan(cmd->cmd.scan);
+                       break;
+               }
+       }
+
+       return retval;
+}
+
+static int jtag_vpi_init(void)
+{
+       sockfd = socket(AF_INET, SOCK_STREAM, 0);
+       if (sockfd < 0) {
+               LOG_ERROR("Could not create socket");
+               return ERROR_FAIL;
+       }
+
+       memset(&serv_addr, 0, sizeof(serv_addr));
+
+       serv_addr.sin_family = AF_INET;
+       serv_addr.sin_port = htons(server_port);
+
+       if (inet_pton(AF_INET, SERVER_ADDRESS, &serv_addr.sin_addr) <= 0) {
+               LOG_ERROR("inet_pton error occured");
+               return ERROR_FAIL;
+       }
+
+       if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
+               close(sockfd);
+               LOG_ERROR("Can't connect to %s : %u", SERVER_ADDRESS, server_port);
+               return ERROR_COMMAND_CLOSE_CONNECTION;
+       }
+
+       LOG_INFO("Connection to %s : %u succeed", SERVER_ADDRESS, server_port);
+
+       return ERROR_OK;
+}
+
+static int jtag_vpi_quit(void)
+{
+       return close(sockfd);
+}
+
+COMMAND_HANDLER(jtag_vpi_set_port)
+{
+       if (CMD_ARGC == 0)
+               LOG_WARNING("You need to set a port number");
+       else
+               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], server_port);
+
+       LOG_INFO("Set server port to %u", server_port);
+
+       return ERROR_OK;
+}
+
+
+static const struct command_registration jtag_vpi_command_handlers[] = {
+       {
+               .name = "jtag_vpi_set_port",
+               .handler = &jtag_vpi_set_port,
+               .mode = COMMAND_CONFIG,
+               .help = "set the port of the VPI server",
+               .usage = "description_string",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+struct jtag_interface jtag_vpi_interface = {
+       .name = "jtag_vpi",
+       .supported = DEBUG_CAP_TMS_SEQ,
+       .commands = jtag_vpi_command_handlers,
+       .transports = jtag_only,
+
+       .init = jtag_vpi_init,
+       .quit = jtag_vpi_quit,
+       .execute_queue = jtag_vpi_execute_queue,
+};
index 579e9e74ddbf42187b100ccdf7b4d825d976199d..eb447cddd05dfa207e347370b4845d5455cff7bf 100644 (file)
@@ -65,6 +65,9 @@ extern struct jtag_interface ftdi_interface;
 #if BUILD_USB_BLASTER_LIBFTDI == 1 || BUILD_USB_BLASTER_FTD2XX == 1
 extern struct jtag_interface usb_blaster_interface;
 #endif
+#if BUILD_JTAG_VPI == 1
+extern struct jtag_interface jtag_vpi_interface;
+#endif
 #if BUILD_AMTJTAGACCEL == 1
 extern struct jtag_interface amt_jtagaccel_interface;
 #endif
@@ -158,6 +161,9 @@ struct jtag_interface *jtag_interfaces[] = {
 #if BUILD_USB_BLASTER_LIBFTDI == 1 || BUILD_USB_BLASTER_FTD2XX == 1
                &usb_blaster_interface,
 #endif
+#if BUILD_JTAG_VPI == 1
+               &jtag_vpi_interface,
+#endif
 #if BUILD_AMTJTAGACCEL == 1
                &amt_jtagaccel_interface,
 #endif
diff --git a/tcl/interface/jtag_vpi.cfg b/tcl/interface/jtag_vpi.cfg
new file mode 100644 (file)
index 0000000..2756b25
--- /dev/null
@@ -0,0 +1,10 @@
+interface jtag_vpi
+
+# Set the VPI JTAG server address
+if { [info exists VPI_PORT] } {
+   set _VPI_PORT $VPI_PORT
+} else {
+   set _VPI_PORT 50020
+}
+
+jtag_vpi_set_port $_VPI_PORT

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)