This is an automated email from Gerrit.

"Jose Borja Castillo Sanchez <joscas...@uma.es>" just uploaded a new patch set 
to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/6866

-- gerrit

commit 1df7a0d47ad0280b9913a3e2400d061684a66a58
Author: Jose Borja Castillo <joscas...@uma.es>
Date:   Wed Mar 2 16:06:14 2022 +0100

    Added XVC (TCP) driver, including missing file 'xvc.c'
    
    Added new XVC TCP driver based on Xilinx's specs. Coding style is
    heavily influenced by bitbang.c and jlink.c, credits to the corresponding 
authors.
    This protocol is intended to be used for bitbanging remote JTAG devices 
while
    using pre-defined messages, like 'shift'.
    
    Signed-off-by: Jose Borja Castillo <joscas...@uma.es>
    Change-Id: I0b3fcea4fa3c4d23863ea14a18d40739289d5740

diff --git a/src/jtag/drivers/xvc.c b/src/jtag/drivers/xvc.c
new file mode 100644
index 0000000000..d00b733e4f
--- /dev/null
+++ b/src/jtag/drivers/xvc.c
@@ -0,0 +1,824 @@
+/***************************************************************************
+ *   Copyright (C) 2021 by Jose Borja Castillo, DTE-UMA                    *
+ *   joscas...@uma.es                                                      *
+ *                                                                         *
+ *   Some parts of the code are inspired on both bitbang.c and jlink.c     *
+ *   by Øyvind Harboe and Paul Fertser, respectively.                      *
+ *                                                                         *
+ *   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, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef _WIN32
+#include <netdb.h>
+#include <netinet/tcp.h>
+#include <sys/un.h>
+#else
+#include <winsock.h>
+#endif
+//#include "helper/system.h"
+#include <fcntl.h>
+#include <jtag/commands.h>
+#include <jtag/interface.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <time.h>
+
+#include "helper/log.h"
+#include "helper/replacements.h"
+
+static char *xvc_host;
+static char *xvc_port;
+static uint32_t xvc_tck;
+
+static int xvc_fd;
+static uint8_t *xvc_tms_buf;
+static uint8_t *xvc_tdi_buf;
+static uint8_t *xvc_send_buf;
+static uint8_t *xvc_tdo_buf;
+static uint8_t *xvc_action_bits;
+/* Being realistic, the protocol won't use as many bits. */
+static uint32_t xvc_used_bits;
+
+/* XVC implementation specifics. */
+static unsigned int xvc_max_vector_size;
+/* max_vector_size discounting command header. */
+static unsigned int xvc_max_usable_vector_size;
+static uint32_t xvc_tck_period_ns;
+
+/* LOG */
+static bool xvc_stats_enabled;
+static FILE *xvc_stats_fd;
+static char *file_path;
+static void xvc_stats_print(int type, int arg, int chunk, int order);
+static struct timeval begin_time, curr_time;
+#define USECONDS_IN_SECOND 1000000
+
+struct shift_result {
+  /** First bit position in TDO to read. */
+  unsigned first;
+  /** Number of bits to read. */
+  unsigned length;
+  /** Destination address to store the result **/
+  void *buffer;
+  /** Offset in the destination buffer. **/
+  unsigned buffer_offset;
+};
+
+#define MAX_SHIFT_RESULTS 256
+static unsigned int last_used_bits = 0;
+static int pending_shift_results = 0;
+static struct shift_result shift_result_buffer[MAX_SHIFT_RESULTS];
+
+static int xvc_init(void);
+static int xvc_quit(void);
+static int xvc_tap_execute_queue(void);
+static void xvc_fill_buffer(void);
+
+static unsigned int xvc_bits_to_bytes(unsigned int bits)
+{
+  return (bits + 7) / 8;
+}
+
+static int32_t read_frame(int SockID, unsigned char *ptr, int32_t size)
+{
+  int32_t state, i;
+
+  i = size;
+  while (i > 0) {
+    state = read_socket(SockID, ptr, i);
+    if (state > 0) {
+      ptr += state;
+      i -= state;
+    } else {
+      perror("read_frame");
+      return state;
+    }
+  }
+  return size;
+}
+
+static int xvc_flush(void)
+{
+  if (xvc_used_bits == 0) {
+    /* Nothing to send, so we don't expect any bit back either */
+    last_used_bits = 0;
+    LOG_DEBUG("XVC flush: no bits to flush");
+    return ERROR_OK;
+  }
+
+  /* Converts bits to bytes, to reckon how many bytes we should send. */
+  unsigned int number_of_bytes = xvc_bits_to_bytes(xvc_used_bits);
+  /* Creates the header. */
+  const char *shift = "shift:";
+  int shift_len = strlen(shift);
+  int cp_offset = 0;
+  /* Copies the header */
+  memcpy(xvc_send_buf + cp_offset, shift, shift_len);
+  /* Updates the offset. */
+  cp_offset += shift_len;
+  /* Copies number of bytes. */
+  memcpy(xvc_send_buf + cp_offset, &xvc_used_bits, sizeof(xvc_used_bits));
+  cp_offset += sizeof(xvc_used_bits);
+  /* Copies TMS vector */
+  memcpy(xvc_send_buf + cp_offset, xvc_tms_buf, number_of_bytes);
+  cp_offset += number_of_bytes;
+  /* Copies TDI vector */
+  memcpy(xvc_send_buf + cp_offset, xvc_tdi_buf, number_of_bytes);
+  cp_offset += number_of_bytes;
+  /* Updates the number of bytes used. */
+  LOG_DEBUG("XVC flush: cp_offset: %d", cp_offset);
+  LOG_DEBUG("XVC flush: used_bits: %d", xvc_used_bits);
+  /* LOG -> type 1 = SHIFT */
+  xvc_stats_print(1, xvc_used_bits, 0, 0);
+  ssize_t written = write_socket(xvc_fd, xvc_send_buf, cp_offset);
+  if (written != cp_offset) {
+    perror("write_socket ");
+    LOG_ERROR("xvc_putc");
+    return ERROR_FAIL;
+  }
+
+  memset(xvc_tms_buf, 0, xvc_max_usable_vector_size / 2);
+  memset(xvc_tdi_buf, 0, xvc_max_usable_vector_size / 2);
+  last_used_bits = xvc_used_bits;
+  xvc_used_bits = 0;
+
+  return ERROR_OK;
+}
+
+enum block_bool { NO_BLOCK, BLOCK };
+
+typedef enum { NO_FLUSH, FLUSH_SEND_BUF } flush_bool_t;
+
+static int xvc_queue(const uint8_t *tms, unsigned tms_offset, const uint8_t 
*tdi,
+unsigned tdi_offset, uint8_t *tdo, unsigned tdo_offset, unsigned length)
+{
+  do {
+    unsigned available_length =
+        (xvc_max_usable_vector_size / 2) - (xvc_used_bits / 8);
+    if ((!available_length) || (pending_shift_results >= MAX_SHIFT_RESULTS)) {
+      xvc_flush();
+      xvc_fill_buffer();
+    }
+
+    struct shift_result *shift_result =
+        &shift_result_buffer[pending_shift_results];
+    unsigned scan_length =
+        length > available_length ? available_length : length;
+    if (tdi)
+      buf_set_buf(tdi, tdi_offset, xvc_tdi_buf, xvc_used_bits, scan_length);
+    if (tms)
+      buf_set_buf(tms, tms_offset, xvc_tms_buf, xvc_used_bits, scan_length);
+    if (tdo) {
+      shift_result->buffer = tdo;
+      shift_result->buffer_offset = tdo_offset;
+      shift_result->first = xvc_used_bits;
+      shift_result->length = scan_length;
+      pending_shift_results++;
+    }
+    xvc_used_bits += scan_length;
+    tdi_offset += scan_length;
+    tms_offset += scan_length;
+    tdo_offset += scan_length;
+    length -= scan_length;
+  } while (length > 0);
+
+  return ERROR_OK;
+}
+
+static int xvc_getinfo(void)
+{
+  const char *getinfo = "getinfo:";
+  int len = strlen(getinfo);
+  /* Sends getinfo command */
+  ssize_t written = write_socket(xvc_fd, getinfo, len);
+  if (written != len)
+    LOG_ERROR("xvc_getinfo: write");
+  char info_recv_buf[20];
+  /* Potentially waits until response gets received. */
+  ssize_t read = read_socket(xvc_fd, &info_recv_buf, 20);
+  if (read < 0)
+    LOG_ERROR("xvc_getinfo: read");
+  LOG_INFO("XVC HW server version: %.19s", info_recv_buf);
+  if (strncmp((char *)&info_recv_buf, "xvcServer_v1.0:", 15) == 0) {
+    xvc_max_usable_vector_size = strtoul(&info_recv_buf[15], NULL, 10);
+    if (xvc_max_usable_vector_size > 32757) {
+      LOG_DEBUG("Exceeded maximum vector size, outputting to 32757 bytes");
+      xvc_max_usable_vector_size = 32757;
+    }
+    xvc_max_vector_size = xvc_max_usable_vector_size + 10;
+    LOG_DEBUG("Maximum vector size set to: %u\n", xvc_max_vector_size);
+    /**Usable size: maximum vector size determined by the server minus the
+sizeof the command, 10 bytes in worst-case (6 bytes from shift: and 4
+additional ones for bit_length).*/
+    /* Updates TX Buffer sizes: */
+    xvc_send_buf = (uint8_t *)malloc(xvc_max_vector_size * sizeof(uint8_t));
+    xvc_tms_buf =
+        (uint8_t *)malloc(xvc_max_usable_vector_size / 2 * sizeof(uint8_t));
+    xvc_tdi_buf =
+        (uint8_t *)malloc(xvc_max_usable_vector_size / 2 * sizeof(uint8_t));
+    xvc_tdo_buf =
+        (uint8_t *)malloc(xvc_max_usable_vector_size / 2 * sizeof(uint8_t));
+    xvc_action_bits = malloc(xvc_max_usable_vector_size / 2 * sizeof(uint8_t));
+    return ERROR_OK;
+  }
+  /* We got something unexpected. */
+  exit(1);
+}
+
+static int xvc_settck(void)
+{
+  /**Creates the command:
+   * copies the header and appends the value.
+   * */
+  char *settck = malloc(12 * sizeof(char));
+  const char *header = "settck:";
+  memcpy(settck, header, 7);
+  memcpy(settck + 7, &xvc_tck, 4);
+  /* Writes the request */
+  ssize_t written = write_socket(xvc_fd, settck, 11);
+  if (written != 11)
+    LOG_ERROR("xvc_settck: write");
+  free(settck);
+  char tck_recv_buf[4];
+  /* Potentially waits for a response. */
+  ssize_t read = read_socket(xvc_fd, &tck_recv_buf, 4);
+  if (read < 0) {
+    LOG_ERROR("xvc_settck: read");
+    exit(1);
+  }
+  /* Prints raw message, as an ASCII array. */
+  LOG_DEBUG("settck: replied %.4s\n", tck_recv_buf);
+  /* Copies the entire buffer, regardless of machine's endianess. */
+  memcpy(&xvc_tck_period_ns, tck_recv_buf, 4);
+  LOG_INFO("XVC tck period ns: %u", xvc_tck_period_ns);
+  return ERROR_OK;
+}
+
+static void xvc_fill_buffer(void)
+{
+  if (read_frame(xvc_fd, xvc_tdo_buf, (7 + last_used_bits) / 8) < 0)
+    LOG_ERROR("Read_frame");
+  for (int i = 0; i < pending_shift_results; i++) {
+    struct shift_result *shift_result = &shift_result_buffer[i];
+    buf_set_buf(xvc_tdo_buf, shift_result->first, shift_result->buffer,
+                shift_result->buffer_offset, shift_result->length);
+  }
+  memset(xvc_tdo_buf, 0, xvc_max_usable_vector_size / 2);
+  pending_shift_results = 0;
+}
+
+static int xvc_reset(int trst, int srst)
+{
+  /*XVC does not have dedicated Reset lines. */
+  return ERROR_OK;
+}
+
+static int xvc_init_tcp(void)
+{
+  struct addrinfo hints = {.ai_family = AF_UNSPEC, .ai_socktype = SOCK_STREAM};
+  struct addrinfo *result, *rp;
+  int fd = 0;
+
+  LOG_INFO("Connecting to %s:%s", xvc_host ? xvc_host : "localhost", xvc_port);
+
+  /* Obtain address(es) matching host/port */
+  int s = getaddrinfo(xvc_host, xvc_port, &hints, &result);
+  if (s != 0) {
+    LOG_ERROR("getaddrinfo: %s\n", gai_strerror(s));
+    return ERROR_FAIL;
+  }
+
+  /* getaddrinfo() returns a list of address structures.
+     Try each address until we successfully connect(2).
+     If socket(2) (or connect(2)) fails, we (close the socket
+     and) try the next address. */
+
+  for (rp = result; rp; rp = rp->ai_next) {
+    fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+#ifndef _WIN32
+    if (fd == -1)
+      continue;
+#else
+    if (fd == INVALID_SOCKET)
+      continue;
+#endif
+
+    if (connect(fd, rp->ai_addr, rp->ai_addrlen) != -1)
+      break; /* Success */
+
+    close(fd);
+  }
+
+  /* We work hard to collapse the writes into the minimum number, so when
+   * we write something we want to get it to the other end of the
+   * connection as fast as possible. */
+  int one = 1;
+  /* On Windows optval has to be a const char *. */
+  setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char *)&one, sizeof(one));
+
+  freeaddrinfo(result); /* No longer needed */
+
+  if (!rp) { /* No address succeeded */
+    LOG_ERROR("Failed to connect");
+    return ERROR_FAIL;
+  }
+
+  return fd;
+}
+
+static int xvc_init_unix(void)
+{
+  if (!xvc_host) {
+    LOG_ERROR("host/socket not specified");
+    return ERROR_FAIL;
+  }
+
+  LOG_INFO("Connecting to unix socket %s", xvc_host);
+  int fd = socket(PF_UNIX, SOCK_STREAM, 0);
+  if (fd < 0) {
+    LOG_ERROR("socket");
+    return ERROR_FAIL;
+  }
+
+  struct sockaddr_un addr;
+  addr.sun_family = AF_UNIX;
+  strncpy(addr.sun_path, xvc_host, sizeof(addr.sun_path));
+  addr.sun_path[sizeof(addr.sun_path) - 1] = '\0';
+
+  if (connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) {
+    LOG_ERROR("connect");
+    return ERROR_FAIL;
+  }
+
+  return fd;
+}
+
+/**
+ * COMMAND_HANDLERS
+ * */
+COMMAND_HANDLER(xvc_handle_port_command)
+{
+  if (CMD_ARGC == 1) {
+    uint16_t port;
+    COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], port);
+    free(xvc_port);
+    xvc_port = port == 0 ? NULL : strdup(CMD_ARGV[0]);
+    return ERROR_OK;
+  }
+  return ERROR_COMMAND_SYNTAX_ERROR;
+}
+
+COMMAND_HANDLER(xvc_handle_host_command)
+{
+  if (CMD_ARGC == 1) {
+    free(xvc_host);
+    xvc_host = strdup(CMD_ARGV[0]);
+    return ERROR_OK;
+  }
+  return ERROR_COMMAND_SYNTAX_ERROR;
+}
+
+COMMAND_HANDLER(xvc_handle_tck_command)
+{
+  if (CMD_ARGC == 1) {
+    xvc_tck = strtoul(CMD_ARGV[0], NULL, 10);
+    return ERROR_OK;
+  }
+  return ERROR_COMMAND_SYNTAX_ERROR;
+}
+
+COMMAND_HANDLER(xvc_stats_handle_command)
+{
+  if (CMD_ARGC == 1) {
+    int len = strlen(CMD_ARGV[0]);
+    if (len > 0) {
+      xvc_stats_enabled = true;
+      file_path = malloc(len);
+      memcpy(file_path, CMD_ARGV[0], len);
+    } else
+      return ERROR_FAIL;
+  } else
+    xvc_stats_enabled = false;
+  return ERROR_OK; /* Stats disabled. */
+}
+
+/**
+ * Structure where commands in configuration stage are parsed.
+ * name: command name
+ * handler: C callback -or handler- to be called.
+ * mode: possible values are COMMAND_EXEC, COMMAND_CONFIG, COMMAND_ANY.
+ * help: displays some useful help
+ * usage: prints the correct usage.
+ * */
+const struct command_registration xvc_command_handlers[] = {
+    {
+        .name = "xvc_port",
+        .handler = xvc_handle_port_command,
+        .mode = COMMAND_CONFIG,
+        .help =
+            "Set the port to use to connect to the XVC remote server.\n"
+            " If 0 or unset, use unix sockets to connect to the remote 
server.",
+        .usage = "port_number",
+    },
+    {
+        .name = "xvc_host",
+        .handler = xvc_handle_host_command,
+        .mode = COMMAND_CONFIG,
+        .help = "Set the host to use to connect to the remote XVC server.\n"
+                " If port is 0 or unset, this is the name of the unix socket "
+                "to use.",
+        .usage = "host_name",
+    },
+    {
+        .name = "xvc_tck",
+        .handler = xvc_handle_tck_command,
+        .mode = COMMAND_CONFIG,
+        .help = "Set the TCK period in ns.",
+        .usage = "TCK period [ns]",
+    },
+    {
+        .name = "xvc_stats",
+        .handler = xvc_stats_handle_command,
+        .mode = COMMAND_CONFIG,
+        .help = "Enables or disables the stats.\n"
+                "To enable the stats, type a valid file path and name",
+        .usage = " path if desired",
+    },
+    COMMAND_REGISTRATION_DONE};
+
+static int xvc_init(void)
+{
+  xvc_used_bits = 0;
+
+  LOG_INFO("Initializing XVC driver");
+  if (!xvc_port)
+    xvc_fd = xvc_init_unix();
+  else
+    xvc_fd = xvc_init_tcp();
+  if (xvc_fd < 0)
+    return xvc_fd;
+
+  xvc_getinfo();
+
+  xvc_settck();
+  /* LOG */
+  if (xvc_stats_enabled) {
+    xvc_stats_fd = fopen(file_path, "w");
+    if (!xvc_stats_fd) {
+      LOG_ERROR("Statistics file can not be opened");
+      exit(1);
+    }
+    memset(&curr_time, 0, sizeof(struct timeval));
+    gettimeofday(&begin_time, 0);
+  }
+
+  LOG_INFO("XVC driver initialized");
+
+  return ERROR_OK;
+}
+
+static int xvc_quit(void)
+{
+  /**Due to the fact that XVC does not
+   * specify a reset terminal, we won't care about that.
+   * */
+
+  if (close_socket(xvc_fd) != 0) {
+    LOG_ERROR("close_socket");
+    return ERROR_FAIL;
+  }
+  free(xvc_port);
+  free(xvc_host);
+  free(xvc_tms_buf);
+  free(xvc_tdi_buf);
+  free(xvc_send_buf);
+  free(xvc_tdo_buf);
+  free(xvc_action_bits);
+  /* LOG */
+  if (xvc_stats_enabled) {
+    fclose(xvc_stats_fd);
+    free(file_path);
+  }
+  LOG_INFO("XVC interface quit");
+  return ERROR_OK;
+}
+
+/* The driver leaves the TCK 0 when in idle */
+static void xvc_tap_end_state(tap_state_t state)
+{
+  assert(tap_is_state_stable(state));
+  tap_set_end_state(state);
+}
+
+static int xvc_tap_state_move(int skip)
+{
+  uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state());
+  int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state());
+
+  xvc_queue(&tms_scan, 0, NULL, 0, NULL, 0, tms_count);
+
+  tap_set_state(tap_get_end_state());
+  return ERROR_OK;
+}
+
+/**
+ * Clock a bunch of TMS (or SWDIO) transitions, to change the JTAG
+ * (or SWD) state machine. "Legacy enqueue"
+ */
+static int xvc_tap_execute_tms(struct jtag_command *cmd)
+{
+  unsigned num_bits = cmd->cmd.tms->num_bits;
+  const uint8_t *bits = cmd->cmd.tms->bits;
+
+  LOG_DEBUG_IO("TMS: %d bits", num_bits);
+
+  uint8_t tms = 0;
+
+  for (unsigned i = 0; i < num_bits; i++) {
+    tms = ((bits[i / 8] >> (i % 8)) & 1);
+    if (xvc_queue(&tms, 0, NULL, 0, NULL, 0, 1) != ERROR_OK)
+      return ERROR_FAIL;
+  }
+
+  return ERROR_OK;
+}
+
+static int xvc_tap_path_move(struct pathmove_command *cmd)
+{
+  int num_states = cmd->num_states;
+  int state_count;
+  uint8_t tms = 0xff;
+
+  state_count = 0;
+  while (num_states) {
+    if (tap_state_transition(tap_get_state(), false) == cmd->path[state_count])
+      xvc_queue(NULL, 0, NULL, 0, NULL, 0, 1);
+    else if (tap_state_transition(tap_get_state(), true) ==
+             cmd->path[state_count])
+      xvc_queue(&tms, 0, NULL, 0, NULL, 0, 1);
+    else {
+      LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition",
+                tap_state_name(tap_get_state()),
+                tap_state_name(cmd->path[state_count]));
+      exit(1);
+    }
+
+    tap_set_state(cmd->path[state_count]);
+    state_count++;
+    num_states--;
+  }
+
+  tap_set_end_state(tap_get_state());
+  return ERROR_OK;
+}
+
+static int xvc_tap_stableclocks(int num_cycles)
+{
+  int i;
+  uint8_t tms = (tap_get_state() == TAP_RESET ? 0xff : 0);
+
+  for (i = 0; i < num_cycles; i++) {
+    xvc_queue(&tms, 0, NULL, 0, NULL, 0, 1);
+  }
+
+  return ERROR_OK;
+}
+
+static int xvc_tap_runtest(int num_cycles)
+{
+  tap_state_t saved_end_state = tap_get_end_state();
+
+  /* only do a state_move when we're not already in IDLE */
+  if (tap_get_state() != TAP_IDLE) {
+    xvc_tap_end_state(TAP_IDLE);
+    if (xvc_tap_state_move(0) != ERROR_OK)
+      return ERROR_FAIL;
+  }
+
+  xvc_tap_stableclocks(num_cycles);
+
+  /* finish in end_state */
+  xvc_tap_end_state(saved_end_state);
+  if (tap_get_state() != tap_get_end_state())
+    if (xvc_tap_state_move(0) != ERROR_OK)
+      return ERROR_FAIL;
+
+  return ERROR_OK;
+}
+
+static int xvc_tap_scan_write(struct scan_command cmd, bool *read_required)
+{
+  /* Make sure there are no trailing fields with num_bits == 0, or the logic
+   * below will fail. */
+  while (cmd.num_fields > 0 && cmd.fields[cmd.num_fields - 1].num_bits == 0) {
+    cmd.num_fields--;
+    LOG_DEBUG("discarding trailing empty field");
+  }
+  if (cmd.num_fields == 0) {
+    LOG_DEBUG("empty scan, doing nothing");
+    return ERROR_OK;
+  }
+
+  bool ir_scan = cmd.ir_scan;
+  if (ir_scan) {
+    if (tap_get_state() != TAP_IRSHIFT) {
+      tap_set_end_state(TAP_IRSHIFT);
+      xvc_tap_state_move(0);
+    }
+  } else {
+    if (tap_get_state() != TAP_DRSHIFT) {
+      xvc_tap_end_state(TAP_DRSHIFT);
+      xvc_tap_state_move(0);
+    }
+  }
+  xvc_tap_end_state(cmd.end_state);
+
+  for (int i = 0; i < cmd.num_fields; i++) {
+    if (cmd.fields[i].in_value)
+      *read_required = true;
+
+    /**
+     * Last field
+     * */
+    if (i == (cmd.num_fields - 1) && tap_get_state() != tap_get_end_state()) {
+      /* All bits except the last one */
+      xvc_queue(NULL, 0, cmd.fields[i].out_value, 0, cmd.fields[i].in_value, 0,
+                cmd.fields[i].num_bits - 1);
+      /* Last bit to copy */
+      uint8_t last_bit = 0;
+      if (cmd.fields[i].out_value)
+        bit_copy(&last_bit, 0, cmd.fields[i].out_value,
+                 cmd.fields[i].num_bits - 1, 1);
+      /* TMS set to 1 to leave the current state. */
+      uint8_t tms_bits = 0x01;
+      xvc_queue(&tms_bits, 0, &last_bit, 0, cmd.fields[i].in_value,
+                cmd.fields[i].num_bits - 1, 1);
+      tap_set_state(tap_state_transition(tap_get_state(), 1));
+      xvc_queue(&tms_bits, 1, NULL, 0, NULL, 0, 1);
+      tap_set_state(tap_state_transition(tap_get_state(), 0));
+    } else {
+      xvc_queue(NULL, 0, cmd.fields[i].out_value, 0, cmd.fields[i].in_value, 0,
+                cmd.fields[i].num_bits);
+    }
+  }
+
+  if (tap_get_state() != tap_get_end_state()) {
+    /* we *KNOW* the above loop transitioned out of
+     * the shift state, so we skip the first state
+     * and move directly to the end state.
+     */
+
+    if (xvc_tap_state_move(0) != ERROR_OK)
+      return ERROR_FAIL;
+  }
+  return ERROR_OK;
+}
+
+static void xvc_stats_print(int type, int arg, int chunk, int order)
+{
+  /**
+   * If logging is enabled, writes to xvc_stats_fd with the following format:
+   * time type arg
+   * -type is the operation to be performed.
+   * -arg is the argument to be printed.
+   * */
+  if (xvc_stats_enabled) {
+    gettimeofday(&curr_time, 0);
+    long unsigned int useconds_elapsed =
+        ((curr_time.tv_sec - begin_time.tv_sec) * USECONDS_IN_SECOND) +
+        (curr_time.tv_usec - begin_time.tv_usec);
+    fprintf(xvc_stats_fd, "%lu %d %d %d %d\n", useconds_elapsed, type, arg,
+            chunk, order);
+  }
+}
+
+static int xvc_tap_execute_queue(void)
+{
+  struct jtag_command *cmd =
+      jtag_command_queue; /* currently processed command */
+  bool any_read = false;
+  int retval;
+
+  /* LOG */
+  static int chunk_count =
+      0; /* It will count many times this routine gets called. */
+  int chunk_element = 0; /* It will count and iterate for each command. */
+
+  /* return ERROR_OK, unless a jtag_read_buffer returns a failed check
+   * that wasn't handled by a caller-provided error handler
+   */
+  retval = ERROR_OK;
+
+  while (cmd) {
+    switch (cmd->type) {
+    case JTAG_RESET:
+      LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst,
+                   cmd->cmd.reset->srst);
+      if ((cmd->cmd.reset->trst == 1) ||
+          (cmd->cmd.reset->srst &&
+           (jtag_get_reset_config() & RESET_SRST_PULLS_TRST)))
+        tap_set_state(TAP_RESET);
+      if (xvc_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst) != ERROR_OK)
+        return ERROR_FAIL;
+      xvc_stats_print(JTAG_RESET, 1, chunk_count, chunk_element);
+      break;
+    case JTAG_RUNTEST:
+      LOG_DEBUG_IO("runtest %i cycles, end in %s", 
cmd->cmd.runtest->num_cycles,
+                   tap_state_name(cmd->cmd.runtest->end_state));
+      xvc_tap_end_state(cmd->cmd.runtest->end_state);
+      if (xvc_tap_runtest(cmd->cmd.runtest->num_cycles) != ERROR_OK)
+        return ERROR_FAIL;
+      xvc_stats_print(JTAG_RUNTEST, cmd->cmd.runtest->num_cycles, chunk_count,
+                      chunk_element);
+      break;
+
+    case JTAG_STABLECLOCKS:
+      /* this is only allowed while in a stable state.  A check for a stable
+       * state was done in jtag_add_clocks()
+       */
+      xvc_stats_print(JTAG_STABLECLOCKS, cmd->cmd.stableclocks->num_cycles,
+                      chunk_count, chunk_element);
+      if (xvc_tap_stableclocks(cmd->cmd.stableclocks->num_cycles) != ERROR_OK)
+        return ERROR_FAIL;
+      break;
+
+    case JTAG_TLR_RESET:
+      LOG_DEBUG_IO("statemove end in %s",
+                   tap_state_name(cmd->cmd.statemove->end_state));
+      xvc_tap_end_state(cmd->cmd.statemove->end_state);
+      xvc_stats_print(JTAG_TLR_RESET, 1, chunk_count,
+                      chunk_element); /* 1 operation */
+      if (xvc_tap_state_move(0) != ERROR_OK)
+        return ERROR_FAIL;
+      break;
+    case JTAG_PATHMOVE:
+      LOG_DEBUG_IO(
+          "pathmove: %i states, end in %s", cmd->cmd.pathmove->num_states,
+          tap_state_name(
+              cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]));
+      xvc_stats_print(JTAG_PATHMOVE, 0, chunk_count,
+                      chunk_element); /* nothing to say about it. */
+      if (xvc_tap_path_move(cmd->cmd.pathmove) != ERROR_OK)
+        return ERROR_FAIL;
+      break;
+    case JTAG_SCAN:
+      if (xvc_tap_scan_write(*cmd->cmd.scan, &any_read) != ERROR_OK)
+        return ERROR_FAIL;
+      break;
+    case JTAG_SLEEP:
+      LOG_DEBUG_IO("sleep %" PRIi32, cmd->cmd.sleep->us);
+      jtag_sleep(cmd->cmd.sleep->us);
+      xvc_stats_print(JTAG_SLEEP, cmd->cmd.sleep->us, chunk_count,
+                      chunk_element); /* LOG */
+      break;
+    case JTAG_TMS:
+      retval = xvc_tap_execute_tms(cmd);
+      xvc_stats_print(JTAG_TMS, cmd->cmd.tms->num_bits, chunk_count,
+                      chunk_element); /* LOG */
+      break;
+    default:
+      LOG_ERROR("BUG: unknown JTAG command type encountered");
+      exit(1);
+    }
+    cmd = cmd->next;
+    chunk_element++; /* LOG */
+  }
+
+  xvc_flush();
+  xvc_fill_buffer();
+
+  /* LOG */
+  chunk_count++;
+
+  return retval;
+}
+
+static struct jtag_interface xvc_interface = {
+    .execute_queue = &xvc_tap_execute_queue,
+};
+
+struct adapter_driver xvc_driver = {
+    .name = "XVC",
+    .transports = jtag_only,
+    .commands = xvc_command_handlers,
+    .init = xvc_init,
+    .quit = xvc_quit,
+    .jtag_ops = &xvc_interface,
+};

-- 

Reply via email to