From c4b6182c30054ebc66d0a3ce59d7c94764b48dfa Mon Sep 17 00:00:00 2001 From: Stephen Tridgell Date: Sun, 17 Aug 2025 21:02:16 +1000 Subject: [PATCH] Apply XVC patch from openocd main to riscv --- configure.ac | 12 +- doc/openocd.info-3 | Bin 0 -> 86276 bytes src/jtag/drivers/Makefile.am | 3 + src/jtag/drivers/xvc.c | 727 +++++++++++++++++++++++++++++++++++ src/jtag/interface.h | 1 + src/jtag/interfaces.c | 3 + 6 files changed, 745 insertions(+), 1 deletion(-) create mode 100644 doc/openocd.info-3 create mode 100644 src/jtag/drivers/xvc.c diff --git a/configure.ac b/configure.ac index ba073f121b..96ba58dc56 100644 --- a/configure.ac +++ b/configure.ac @@ -191,6 +191,9 @@ m4_define([JTAG_VPI_ADAPTER], m4_define([RSHIM_ADAPTER], [[[rshim], [BlueField SoC via rshim], [RSHIM]]]) +m4_define([NETWORK_ADAPTERS], + [[[xvc], [Xilinx XVC TCP], [XVC]]]) + # The word 'Adapter' in "Dummy Adapter" below must begin with a capital letter # because there is an M4 macro called 'adapter'. m4_define([DUMMY_ADAPTER], @@ -322,7 +325,8 @@ AC_ARG_ADAPTERS([ JTAG_VPI_ADAPTER, RSHIM_ADAPTER, PCIE_ADAPTERS, - LIBJAYLINK_ADAPTERS + LIBJAYLINK_ADAPTERS, + NETWORK_ADAPTERS ],[auto]) AC_ARG_ENABLE([parport], @@ -721,6 +725,11 @@ PROCESS_ADAPTERS([JTAG_VPI_ADAPTER], [true], [unused]) PROCESS_ADAPTERS([RSHIM_ADAPTER], ["x$can_build_rshim" = "xyes"], [internal error: validation should happen beforehand]) PROCESS_ADAPTERS([DUMMY_ADAPTER], [true], [unused]) +PROCESS_ADAPTERS([NETWORK_ADAPTERS], [true], [unused]) + +AS_IF([test "x$enable_xvc" != "xno"], [ + build_bitbang=yes +]) AS_IF([test "x$enable_linuxgpiod" != "xno"], [ build_bitbang=yes @@ -873,6 +882,7 @@ m4_foreach([adapter], [USB1_ADAPTERS, LIBGPIOD_ADAPTERS, REMOTE_BITBANG_ADAPTER, LIBJAYLINK_ADAPTERS, PCIE_ADAPTERS, SERIAL_PORT_ADAPTERS, + NETWORK_ADAPTERS, LINUXSPIDEV_ADAPTER, VDEBUG_ADAPTER, JTAG_DPI_ADAPTER, diff --git a/doc/openocd.info-3 b/doc/openocd.info-3 new file mode 100644 index 0000000000000000000000000000000000000000..78ca9e5d730cbf46cfed7b569311184c292621b3 GIT binary patch literal 86276 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 rt%5|IjQECC4j56-fc{B)s)^Ayvx> +#include +#include +#else +#include +#endif +#include "helper/bits.h" +#include "helper/replacements.h" +#include +#include +#include "helper/log.h" +#include +#include +#include +#include +#include +#include + +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; +/* 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; + +struct shift_result { + /* First bit position in TDO to read. */ + unsigned int first; + /* Number of bits to read. */ + unsigned int length; + /* Destination address to store the result */ + void *buffer; + /* Offset in the destination buffer. */ + unsigned int buffer_offset; +}; +/* MAX_BUF_SIZE holds the maximum size that internal buffers are allowed to + be allocated. This parameter is limited by the size of an unsigned int + (2/4) bytes. Unsigned int types are employed by several functions in OpenOCD, + like 'write_socket'. The offset of 11 bytes is set to ensure XVC commands + like 'shift' in deed fit inside the aforementioned buffers. + */ +#define MAX_BUF_SIZE (BIT(16) - 11) +#define MAX_SHIFT_RESULTS 256 +static unsigned int last_used_bits; +static unsigned int pending_shift_results; +static struct shift_result shift_result_buffer[MAX_SHIFT_RESULTS]; + +static int xvc_set_tck(void); +static int xvc_fill_buffer(void); + +static unsigned int xvc_bits_to_bytes(unsigned int bits) +{ + return DIV_ROUND_UP(bits, 8); +} + +static int xvc_speed(int speed) +{ + /* Converts TCK speed in kHz to ns. */ + xvc_tck = 1000000 / speed; + /* Changes default speed to adapter speed */ + return xvc_set_tck(); +} + +static int xvc_speed_div(int speed, int *khz) +{ + *khz = speed; + + return ERROR_OK; +} + +static int xvc_khz(int khz, int *jtag_speed) +{ + *jtag_speed = khz; + + return ERROR_OK; +} + +static int read_frame(int sock_id, unsigned char *ptr, unsigned int size) +{ + unsigned int i = size; + while (i > 0) { + int state = read_socket(sock_id, ptr, i); + if (state == 0) { + LOG_ERROR("No data available in socket at %s", __func__); + return ERROR_FAIL; + } + if (state < 0) { + LOG_ERROR("Reading error in %s", __func__); + return ERROR_FAIL; + } + ptr += state; + i -= state; + } + return ERROR_OK; +} + +static int xvc_flush(void) +{ + if (!xvc_used_bits) { + /* 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. */ + h_u32_to_le(xvc_send_buf + cp_offset, 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); + + int written = write_socket(xvc_fd, xvc_send_buf, cp_offset); + if (written != cp_offset) { + LOG_ERROR("Error writing socket in %s", __func__); + 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; +} + +static int xvc_queue(const uint8_t *tms, unsigned int tms_offset, const uint8_t *tdi, + unsigned int tdi_offset, uint8_t *tdo, unsigned int tdo_offset, unsigned int length) +{ + do { + unsigned int 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 int 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); + int written = write_socket(xvc_fd, getinfo, len); + if (written != len) { + LOG_ERROR("%s: write", __func__); + return ERROR_FAIL; + } + char info_recv_buf[20]; + int read = read_socket(xvc_fd, info_recv_buf, sizeof(info_recv_buf)); + if (read < 0) { + LOG_ERROR("%s: read", __func__); + return ERROR_FAIL; + } + LOG_INFO("XVC HW server version: %.19s", info_recv_buf); + if (strncmp(info_recv_buf, "xvcServer_v1.0:", 15) != 0 && + strncmp(info_recv_buf, "xvcServer_v1.1:", 15) != 0) { + LOG_ERROR("Unexpected response from XVC server"); + return ERROR_FAIL; + } + xvc_max_usable_vector_size = strtoul(&info_recv_buf[15], NULL, 10); + if (xvc_max_usable_vector_size > MAX_BUF_SIZE) { + LOG_DEBUG("Exceeded maximum vector size, outputting to %lu bytes", + MAX_BUF_SIZE); + xvc_max_usable_vector_size = MAX_BUF_SIZE; + } + xvc_max_vector_size = xvc_max_usable_vector_size + 10; + LOG_DEBUG("Maximum vector size set to: %u", 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 = malloc(xvc_max_vector_size * sizeof(uint8_t)); + xvc_tms_buf = malloc(xvc_max_usable_vector_size / 2 * sizeof(uint8_t)); + xvc_tdi_buf = malloc(xvc_max_usable_vector_size / 2 * sizeof(uint8_t)); + xvc_tdo_buf = malloc(xvc_max_usable_vector_size / 2 * sizeof(uint8_t)); + if (!xvc_send_buf || !xvc_tms_buf || !xvc_tdi_buf || !xvc_tdo_buf) { + LOG_ERROR("Out of memory"); + free(xvc_send_buf); + free(xvc_tms_buf); + free(xvc_tdi_buf); + free(xvc_tdo_buf); + return ERROR_FAIL; + } + return ERROR_OK; +} + +static int xvc_set_tck(void) +{ + /* Creates the command: + * copies the header and appends the value. + * */ + uint8_t set_tck[12]; + const char *header = "settck:"; + memcpy(set_tck, header, strlen(header)); + h_u32_to_le(set_tck + strlen(header), xvc_tck); + int written = write_socket(xvc_fd, set_tck, 11); + if (written != 11) { + LOG_ERROR("%s: write", __func__); + return ERROR_FAIL; + } + uint32_t tck_recv_buf; + int read = read_socket(xvc_fd, &tck_recv_buf, sizeof(tck_recv_buf)); + if (read < 0) { + LOG_ERROR("%s: read", __func__); + return ERROR_FAIL; + } + /* Prints response, regardless of machine endianness. */ + uint32_t xvc_tck_period_ns; + xvc_tck_period_ns = le_to_h_u32((uint8_t *)&tck_recv_buf); + LOG_INFO("XVC tck period ns: %u", xvc_tck_period_ns); + return ERROR_OK; +} + +static int xvc_fill_buffer(void) +{ + if (read_frame(xvc_fd, xvc_tdo_buf, DIV_ROUND_UP(last_used_bits, 8)) != ERROR_OK) { + LOG_ERROR("Read_frame"); + return ERROR_FAIL; + } + for (unsigned 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; + return ERROR_OK; +} + +static int xvc_reset(int trst, int srst) +{ + /* XVC does not have dedicated Reset lines. */ + static bool first_time = true; + if (first_time) { + LOG_WARNING("Adapter has no reset lines. Fix \"reset_config\" command in " + "config file"); + first_time = false; + } + return ERROR_OK; +} + +static int xvc_init_tcp(int *fd) +{ + struct addrinfo hints = {.ai_family = AF_UNSPEC, .ai_socktype = SOCK_STREAM}; + + LOG_INFO("Connecting to %s:%s", xvc_host ? xvc_host : "localhost", xvc_port); + + struct addrinfo *result; + /* Obtain address(es) matching host/port */ + int s = getaddrinfo(xvc_host, xvc_port, &hints, &result); + if (s != 0) { + LOG_ERROR("getaddrinfo: %s", 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. */ + struct addrinfo *rp; + 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 == (int)INVALID_SOCKET) + continue; +#endif + + if (connect(*fd, rp->ai_addr, rp->ai_addrlen) != -1) + break; /* Success */ + + close_socket(*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); + + if (!rp) { + LOG_ERROR("Failed to connect"); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int xvc_init_unix(int *fd) +{ + if (!xvc_host) { + LOG_ERROR("host/socket not specified"); + return ERROR_FAIL; + } + + LOG_INFO("Connecting to unix socket %s", xvc_host); + *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 ERROR_OK; +} + +/* + * COMMAND_HANDLERS + * */ +COMMAND_HANDLER(xvc_handle_port_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + 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; +} + +COMMAND_HANDLER(xvc_handle_host_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + free(xvc_host); + xvc_host = strdup(CMD_ARGV[0]); + return ERROR_OK; +} + +static const struct command_registration xvc_subcommand_handlers[] = { + { + .name = "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 = "host", + .handler = xvc_handle_host_command, + .mode = COMMAND_CONFIG, + .help = "Set the host to use or UNIX socket to connect to the remote XVC server.", + .usage = "host_name", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration xvc_command_handlers[] = { + { + .name = "xvc", + .mode = COMMAND_ANY, + .help = "perform XVC driver configuration", + .chain = xvc_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + +static int xvc_init(void) +{ + xvc_used_bits = 0; + last_used_bits = 0; + pending_shift_results = 0; + /* Default clock: 1000 ns period */ + xvc_tck = 1000; + + LOG_DEBUG("Initializing XVC driver"); + int err = ERROR_OK; + if (!xvc_port) + err = xvc_init_unix(&xvc_fd); + else + err = xvc_init_tcp(&xvc_fd); + if (err != ERROR_OK) + return err; + + xvc_getinfo(); + xvc_set_tck(); + + LOG_DEBUG("XVC driver initialized"); + + return ERROR_OK; +} + +static int xvc_quit(void) +{ + 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); + return ERROR_OK; +} + +/* The driver leaves the TCK 0 when in idle */ +static void xvc_tap_end_state(enum tap_state 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 int num_bits = cmd->cmd.tms->num_bits; + const uint8_t *bits = cmd->cmd.tms->bits; + + LOG_DEBUG_IO("TMS: %d bits", num_bits); + + for (unsigned int i = 0; i < num_bits; i++) { + uint8_t tms = 0; + 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) +{ + unsigned int num_states = cmd->num_states; + unsigned int state_count = 0; + uint8_t tms = 0xff; + + 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])); + return ERROR_FAIL; + } + + tap_set_state(cmd->path[state_count]); + state_count++; + num_states--; + } + + tap_set_end_state(tap_get_state()); + return ERROR_OK; +} + +static unsigned int xvc_tap_stableclocks(int num_cycles) +{ + uint8_t tms = (tap_get_state() == TAP_RESET ? 0xff : 0); + + for (int i = 0; i < num_cycles; i++) + xvc_queue(&tms, 0, NULL, 0, NULL, 0, 1); + + return ERROR_OK; +} + +static int xvc_tap_runtest(unsigned int num_cycles) +{ + enum tap_state 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) +{ + /* 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 (unsigned int i = 0; i < cmd->num_fields; i++) { + /* + * 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 int xvc_tap_execute_queue(struct jtag_command *cmd_queue) +{ + struct jtag_command *cmd = cmd_queue; + + while (cmd) { + switch (cmd->type) { + 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; + 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() + */ + 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); + 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])); + 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) != ERROR_OK) + return ERROR_FAIL; + break; + case JTAG_SLEEP: + LOG_DEBUG_IO("sleep %" PRIi32, cmd->cmd.sleep->us); + /* Flush the cmd FIFO before entering sleep to keep timing. */ + xvc_flush(); + jtag_sleep(cmd->cmd.sleep->us); + break; + case JTAG_TMS: + if (xvc_tap_execute_tms(cmd) != ERROR_OK) + return ERROR_FAIL; + break; + default: + LOG_ERROR("BUG: unknown JTAG command type encountered"); + return ERROR_FAIL; + } + cmd = cmd->next; + } + + if (xvc_flush() != ERROR_OK) + return ERROR_FAIL; + if (xvc_fill_buffer() != ERROR_OK) + return ERROR_FAIL; + + return ERROR_OK; +} + +static struct jtag_interface xvc_interface = { + .execute_queue = &xvc_tap_execute_queue, + .supported = DEBUG_CAP_TMS_SEQ, +}; + +struct adapter_driver xvc_adapter_driver = { + .name = "xvc", + //.transport_ids = TRANSPORT_JTAG, + //.transport_preferred_id = TRANSPORT_JTAG, + .transports = jtag_only, + .commands = xvc_command_handlers, + .init = xvc_init, + .quit = xvc_quit, + .reset = &xvc_reset, + .speed = &xvc_speed, + .khz = &xvc_khz, + .speed_div = &xvc_speed_div, + .jtag_ops = &xvc_interface, +}; diff --git a/src/jtag/interface.h b/src/jtag/interface.h index b2d7123fd4..ec7864b5b8 100644 --- a/src/jtag/interface.h +++ b/src/jtag/interface.h @@ -404,5 +404,6 @@ extern struct adapter_driver vdebug_adapter_driver; extern struct adapter_driver vsllink_adapter_driver; extern struct adapter_driver xds110_adapter_driver; extern struct adapter_driver xlnx_pcie_xvc_adapter_driver; +extern struct adapter_driver xvc_adapter_driver; #endif /* OPENOCD_JTAG_INTERFACE_H */ diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c index e49bd9e0f3..70993bdead 100644 --- a/src/jtag/interfaces.c +++ b/src/jtag/interfaces.c @@ -155,6 +155,9 @@ struct adapter_driver *adapter_drivers[] = { #endif #if BUILD_AM335XGPIO == 1 &am335xgpio_adapter_driver, +#endif +#if BUILD_XVC == 1 + &xvc_adapter_driver, #endif NULL, };