This is an automated email from Gerrit. Jacek Wuwer ([email protected]) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/6097
-- gerrit commit 5727e30ac46c281e7e3925798abcc8dcba6bd2ff Author: Jacek Wuwer <[email protected]> Date: Fri Mar 12 16:57:20 2021 +0100 Cadence virtual debug interface (vdebug) integration Change-Id: I1bc105b3addc3f34161c2356c482ff3011e3f2cc Signed-off-by: Jacek Wuwer <[email protected]> diff --git a/configure.ac b/configure.ac index a8c2e9d..caa79a3 100644 --- a/configure.ac +++ b/configure.ac @@ -275,6 +275,10 @@ 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([vdebug], + AS_HELP_STRING([--enable-vdebug], [Enable building support for Cadence Virtual Debug Interface]), + [build_vdebug=$enableval], [build_vdebug=no]) + AC_ARG_ENABLE([jtag_dpi], AS_HELP_STRING([--enable-jtag_dpi], [Enable building support for JTAG DPI]), [build_jtag_dpi=$enableval], [build_jtag_dpi=no]) @@ -581,6 +585,12 @@ AS_IF([test "x$build_jtag_vpi" = "xyes"], [ AC_DEFINE([BUILD_JTAG_VPI], [0], [0 if you don't want JTAG VPI.]) ]) +AS_IF([test "x$build_vdebug" = "xyes"], [ + AC_DEFINE([BUILD_VDEBUG], [1], [1 if you want Cadence vdebug interface.]) +], [ + AC_DEFINE([BUILD_VDEBUG], [0], [0 if you don't want Cadence vdebug interface.]) +]) + AS_IF([test "x$build_jtag_dpi" = "xyes"], [ AC_DEFINE([BUILD_JTAG_DPI], [1], [1 if you want JTAG DPI.]) ], [ @@ -773,8 +783,9 @@ AM_CONDITIONAL([AT91RM9200], [test "x$build_at91rm9200" = "xyes"]) AM_CONDITIONAL([BCM2835GPIO], [test "x$build_bcm2835gpio" = "xyes"]) AM_CONDITIONAL([IMX_GPIO], [test "x$build_imx_gpio" = "xyes"]) AM_CONDITIONAL([BITBANG], [test "x$build_bitbang" = "xyes"]) -AM_CONDITIONAL([JTAG_VPI], [test "x$build_jtag_vpi" = "xyes" -o "x$build_jtag_vpi" = "xyes"]) -AM_CONDITIONAL([JTAG_DPI], [test "x$build_jtag_dpi" = "xyes" -o "x$build_jtag_dpi" = "xyes"]) +AM_CONDITIONAL([JTAG_VPI], [test "x$build_jtag_vpi" = "xyes"]) +AM_CONDITIONAL([VDEBUG], [test "x$build_vdebug" = "xyes"]) +AM_CONDITIONAL([JTAG_DPI], [test "x$build_jtag_dpi" = "xyes"]) AM_CONDITIONAL([USB_BLASTER_DRIVER], [test "x$enable_usb_blaster" != "xno" -o "x$enable_usb_blaster_2" != "xno"]) AM_CONDITIONAL([AMTJTAGACCEL], [test "x$build_amtjtagaccel" = "xyes"]) AM_CONDITIONAL([GW16012], [test "x$build_gw16012" = "xyes"]) diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am index f7a54b0..e8063fb 100644 --- a/src/jtag/drivers/Makefile.am +++ b/src/jtag/drivers/Makefile.am @@ -82,6 +82,9 @@ endif if JTAG_VPI DRIVERFILES += %D%/jtag_vpi.c endif +if VDEBUG +DRIVERFILES += %D%/vdebug.c +endif if JTAG_DPI DRIVERFILES += %D%/jtag_dpi.c endif diff --git a/src/jtag/drivers/vdebug.c b/src/jtag/drivers/vdebug.c new file mode 100644 index 0000000..84ea513 --- /dev/null +++ b/src/jtag/drivers/vdebug.c @@ -0,0 +1,1220 @@ +//#---------------------------------------------------------------------------- +//# Copyright 2020-2021 Cadence Design Systems, Inc. +//# +//# Redistribution and use in source and binary forms, with or without modification, +//# are permitted provided that the following conditions are met: +//# 1. Redistributions of source code must retain the above copyright notice, +//# this list of conditions and the following disclaimer. +//# 2. Redistributions in binary form must reproduce the above copyright notice, +//# this list of conditions and the following disclaimer in the documentation +//# and/or other materials provided with the distribution. +//#---------------------------------------------------------------------------- +//# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +//# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +//# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +//# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +//# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +//# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +//# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +//# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +//# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +//#---------------------------------------------------------------------------- +//# Revisions : +//# 41 10.12.20 : based on vd_client and vd_test +//# 42 16.02.21 : shift_tap fix +//#---------------------------------------------------------------------------- + +/*! + * @file + * + * @brief the virtual debug interface provides a connection between a sw debugger + * and the simulated, emulated core over a soft connection, implemented by DPI + * It implements an interface and JTAG, DAP and AMBA transports + * +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#else +#define SOCKET int +#ifdef HAVE_UNISTD_H +#include <unistd.h> /* close */ +#endif +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif +#endif +#include <stdio.h> +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#include <stdarg.h> +#include <string.h> +#include <errno.h> + +#include "jtag/interface.h" +#include "jtag/commands.h" +#include "transport/transport.h" +#include "target/target.h" +#include "target/target_type.h" +#include "helper/log.h" + +#define VD_VERSION 42 +#define VD_BUILD "16.02.21" +#define VD_BUFFER_LEN 4024 +#define VD_CHEADER_LEN 24 +#define VD_SHEADER_LEN 16 + +#define VD_MAX_MEMORIES 3 + +/** + * @brief List of transactor types + */ +typedef enum { + VD_BFM_JTDP = 0x0001, /**< transactor DAP JTAG DP */ + VD_BFM_SWDP = 0x0002, /**< transactor DAP SWD DP */ + VD_BFM_AHB = 0x0003, /**< transactor AMBA AHB */ + VD_BFM_APB = 0x0004, /**< transactor AMBA APB */ + VD_BFM_AXI = 0x0005, /**< transactor AMBA AXI */ + VD_BFM_JTAG = 0x0006, /**< transactor serial JTAG */ + VD_BFM_SWD = 0x0007, /**< transactor serial SWD */ +} vd_bfm_et; + +/** + * @brief List of signals that can be read or written by the debugger + */ +typedef enum { + VD_SIG_TCK = 0x0001, /**< JTAG clock; tclk */ + VD_SIG_TDI = 0x0002, /**< JTAG TDI; tdi */ + VD_SIG_TMS = 0x0004, /**< JTAG TMS; tms */ + VD_SIG_RESET = 0x0008, /**< DUT reset; rst */ + VD_SIG_TRST = 0x0010, /**< JTAG Reset; trstn */ + VD_SIG_TDO = 0x0020, /**< JTAG TDO; tdo */ + VD_SIG_POWER = 0x0100, /**< BFM power; bfm_up */ + VD_SIG_TCKDIV= 0x0200, /**< JTAG clock divider; tclkdiv */ + VD_SIG_BUF = 0x1000, /**< memory buffer; mem */ +} vd_sig_et; + +/** + * @brief List of errors + */ +typedef enum { + VD_ERR_NONE = 0x0000, /**< no error */ + VD_ERR_NOT_IMPL = 0x0100, /**< feature not implemented */ + VD_ERR_USAGE = 0x0101, /**< incorrect usage */ + VD_ERR_PARAM = 0x0102, /**< incorrect parameter */ + VD_ERR_CONFIG = 0x0107, /**< incorrect configuration */ + VD_ERR_NO_MEMORY = 0x0104, /**< out of memory */ + VD_ERR_SHM_OPEN = 0x010a, /**< cannot open shared memory */ + VD_ERR_SHM_MAP = 0x010b, /**< cannot map shared memory */ + VD_ERR_SOC_OPEN = 0x011a, /**< cannot open socket */ + VD_ERR_SOC_OPT = 0x011b, /**< cannot set socket option */ + VD_ERR_SOC_ADDR = 0x011c, /**< cannot resolve host address */ + VD_ERR_SOC_CONN = 0x011d, /**< cannot connect to host */ + VD_ERR_SOC_SEND = 0x011e, /**< error sending data on socket */ + VD_ERR_SOC_RECV = 0x011f, /**< error receiving data from socket */ + VD_ERR_LOCKED = 0x0202, /**< device locked */ + VD_ERR_NOT_RUN = 0x0204, /**< transactor not running */ + VD_ERR_NOT_OPEN = 0x0205, /**< transactor not open/connected */ + VD_ERR_LICENSE = 0x0206, /**< cannot check out the license */ + VD_ERR_VERSION = 0x0207, /**< transactor version mismatch */ + VD_ERR_TIME_OUT = 0x0301, /**< time out, waiting */ + VD_ERR_NO_POWER = 0x0302, /**< power out error */ + VD_ERR_BUS_ERROR = 0x0304, /**< bus protocol error, like pslverr */ + VD_ERR_NO_ACCESS = 0x0306, /**< no access to an object */ + VD_ERR_INV_HANDLE= 0x0307, /**< invalid object handle */ + VD_ERR_INV_SCOPE = 0x0308, /**< invalid scope */ +} vd_err_et; + +typedef struct +{ + struct + { // VD_CHEADER_LEN written by client + uint8_t cmd; // 000; + uint8_t type; // 001; + uint16_t waddr; // 002; + uint16_t wbytes; // 004; + uint16_t rbytes; // 006; + uint16_t wwords; // 008; + uint16_t rwords; // 00a; + uint32_t rwdata; // 00c; + uint32_t offset; // 010; + uint16_t offseth; // 014; + uint16_t wid; // 016; + }; + union + { // 018; + uint8_t wd8[VD_BUFFER_LEN]; + uint32_t wd32[VD_BUFFER_LEN/4]; + uint64_t wd64[VD_BUFFER_LEN/8]; + }; + struct + { // VD_SHEADER_LEN written by server + uint16_t rid; // fd0: + uint16_t awords; // fd2: + int32_t status; // fd4; + uint64_t duttime; // fd8; + }; + union + { // fe0: + uint8_t rd8[VD_BUFFER_LEN]; + uint32_t rd32[VD_BUFFER_LEN/4]; + uint64_t rd64[VD_BUFFER_LEN/8]; + }; + uint32_t state; // 1f98; + uint32_t count; // 1f9c; + uint8_t dummy[96]; // 1fa0; 48+40B+8B; +} vd_shm_st; + +static const char* const vdebug_transports[] = { "jtag", NULL }; + +static FILE* debug_log = NULL; +static uint16_t debug = 0; +static uint8_t debug_out = 0; +static uint8_t trans_batch = 1; +static uint8_t trans_first = 0; +static uint8_t trans_last = 0; +static uint8_t mem_ndx = 0; +static uint8_t buf_width; +static uint8_t addr_bits; +static uint8_t bfm_type; +static uint16_t sig_read; +static uint16_t sig_write; +static uint32_t bfm_period; +static uint32_t mem_base[VD_MAX_MEMORIES]; +static uint32_t mem_size[VD_MAX_MEMORIES]; +static uint32_t mem_width[VD_MAX_MEMORIES]; +static uint32_t mem_depth[VD_MAX_MEMORIES]; +static uint32_t server_port; +static uint32_t pollcycles = 10000; +static uint32_t pollmin; +static uint32_t pollmax; +static int hsocket; +static char server_name[32]; +static char bfm_path[128]; +static char mem_path[VD_MAX_MEMORIES][128]; +static vd_shm_st* pbuf = NULL; + +static struct target* ptarg = NULL; +static int (*targ_poll)(struct target* ptar) = NULL; +static int (*targ_write_memory)(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) = NULL; + +static void debug_open(void) +{ + char msg[32]; + char *p = getenv( "VD_DEBUG" ); + debug = (p ? strtol( p, NULL, 0 ) : 0); + if( debug ) + { + if( (p = getenv( "VD_LOG" )) == NULL ) + { + strcpy( msg, "vd_client.log" ); + debug_log = fopen( msg, "w" ); + } + else + debug_log = fopen( p, "w" ); + if( debug > 0x100 ) + { + debug_out = debug >> 8; + debug &= 0x00ff; + } + sprintf( msg, "OpenOCD vdebug client %d", VD_VERSION ); + if( debug_log ) + { + fputs( msg, debug_log ); fputc( '\n', debug_log ); + } + } +} + +static uint32_t debug_msg( uint32_t er_code, char* format, ...) +{ + char msg[128]; + long long unsigned duttime = (pbuf ? pbuf->duttime : 0); + if (format) + { + va_list ap; + snprintf( msg, 15, "%10lluns: ", duttime ); + va_start(ap,format); // explicitly terminating string, Windows bug + vsnprintf(msg+14, sizeof(msg)-15, format, ap); msg[127]='\0'; + if( er_code ) + LOG_ERROR("%s: vdebug code 0x%x", msg, er_code); + else if( debug_out ) + LOG_DEBUG("%s", msg); + va_end(ap); + if( debug && debug_log ) + { + fputs( msg, debug_log ); fputc( '\n', debug_log ); + } + } + return er_code; +} + +static int socket_error(void) +{ +#ifdef _WIN32 + return WSAGetLastError(); +#else + return errno; +#endif +} + +static int socket_close(SOCKET hsock) +{ +#ifdef _WIN32 + closesocket(hsock); + WSACleanup(); +#else + close(hsock); +#endif + return 0; +} + +static SOCKET socket_open(char* server_addr, uint32_t port) +{ + SOCKET hsock; + int rc = 0; + uint32_t buflen = sizeof(vd_shm_st); // size of the send and rcv buffer + struct addrinfo *ainfo = NULL; + struct addrinfo ahint = { 0, AF_INET, SOCK_STREAM, 0, 0, NULL, NULL, NULL }; + +#ifdef _WIN32 + WSADATA ver; + if ((rc = WSAStartup(MAKEWORD(2, 2), &ver)) != 0) + ; + else if ((hsock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) == INVALID_SOCKET) + rc = debug_msg( VD_ERR_SOC_OPEN, "socket_open: cannot open socket, error %d", socket_error() ); +#else + uint32_t rcvwat = VD_SHEADER_LEN; // size of the rcv header, as rcv min watermark + if ((hsock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) < 0) + rc = debug_msg( VD_ERR_SOC_OPEN, "socket_open: cannot open socket, error %d", socket_error() ); + else if (setsockopt(hsock, SOL_SOCKET, SO_RCVLOWAT, &rcvwat, sizeof(rcvwat)) < 0) + rc = errno; +#endif + else if (setsockopt(hsock, SOL_SOCKET, SO_SNDBUF, (const char*)&buflen, sizeof(buflen)) < 0) + rc = socket_error(); + else if (setsockopt(hsock, SOL_SOCKET, SO_RCVBUF, (const char*)&buflen, sizeof(buflen)) < 0) + rc = socket_error(); + if (rc) + rc = debug_msg( VD_ERR_SOC_OPT, "socket_open: cannot set socket option, error %d", rc ); + else if ((rc = getaddrinfo(server_addr, NULL, &ahint, &ainfo)) != 0) + rc = debug_msg( VD_ERR_SOC_ADDR, "socket_open: cannot resolve address %s, error %d", server_addr, rc ); + else + { + ((struct sockaddr_in*)(ainfo->ai_addr))->sin_port = htons(port); + if (connect(hsock, ainfo->ai_addr, sizeof(struct sockaddr)) < 0) + rc = debug_msg( VD_ERR_SOC_CONN, "socket_open: cannot connect to %s:%d, error %d", server_addr, port, socket_error() ); + } + if (rc) + { + socket_close(hsock); + hsock = 0; + } + if (ainfo) + freeaddrinfo(ainfo); + return hsock; +} + +static int socket_receive(SOCKET hsock, vd_shm_st* pmem) +{ + int rc; + uint16_t dreceived = 0; + uint16_t offset = (uint8_t*)&pmem->rid - &pmem->cmd; + uint16_t to_receive = VD_SHEADER_LEN + pmem->rbytes; + char *pb = (char*)pmem; + + do + { + if ((rc = recv(hsock, pb + offset, to_receive, 0)) <= 0) + break; + else + { // the data can come in pieces + to_receive -= rc; + offset += rc; + } + if (debug > 2) + debug_msg( VD_ERR_NONE, "socket_receive: received %u, to receive %u", rc, to_receive ); + dreceived += rc; + } while (rc > 0 && to_receive); + if (rc <= 0) + debug_msg( VD_ERR_SOC_RECV, "socket_receive: recv failed, error %d", socket_error() ); + else + rc = dreceived; + return rc; +} + +static int socket_send(SOCKET hsock, vd_shm_st* pmem) +{ + int rc; + if( (rc = send(hsock, (const char*)&pmem->cmd, VD_CHEADER_LEN + pmem->wbytes, 0)) <= 0) + debug_msg( VD_ERR_SOC_SEND, "socket_send: send failed, error %d", socket_error() ); + else if (debug > 2) + debug_msg( VD_ERR_NONE, "socket_send: sent %u, to send %u", rc, 0 ); + return rc; +} + +static uint32_t wait_server( SOCKET hsock, vd_shm_st* pmem ) +{ + int st, rd; + if( !hsock ) + st = VD_ERR_SOC_OPEN; + else if( (st = socket_send(hsock, pmem)) <= 0 ) + st = VD_ERR_SOC_SEND; + else if( (rd = socket_receive(hsock, pmem)) <= 0 ) + st = VD_ERR_SOC_RECV; + else + { + if( debug > 3 ) + debug_msg( 0, "wait_server: cmd %02hx done, sent %d, rcvd %d, status %d time %llu", pmem->cmd, st, rd, pmem->status, pmem->duttime ); + st = pmem->status; + } + return st; +} + +static int vdebug_open( SOCKET hsock, vd_shm_st* pm, const char* path, uint32_t type, uint32_t period_ps, uint32_t sig_mask ) +{ + int rc; + + if( pm ) + { + pm->cmd = 0x01; + pm->wid = (uint16_t)VD_VERSION; + pm->wbytes = pm->rbytes = pm->wwords = pm->rwords = 0; + if( (rc = wait_server( hsock, pm )) != 0 ) // communication problem + debug_msg( rc, "vdebug_open: Error 0x%x connecting to server", rc ); + else if( pm->rid < pm->wid ) // communication OK, but version wrong + { + debug_msg( VD_ERR_VERSION, "vdebug_open: server version %d too old for the client %d", pm->rid, pm->wid ); + pm->cmd = 0x02; // let server close the connection + wait_server( hsock, pm ); + rc = 0x207; + } + else + { + pm->cmd = 0x04; + pm->type = (uint8_t)type; + pm->rwdata = sig_mask | VD_SIG_BUF | (VD_SIG_BUF << 16); + pm->wbytes = (uint16_t)strlen(path)+1; pm->rbytes = 12; + pm->wid = 0; // reset wid for transaction ID + pm->wwords = pm->rwords = 0; + memcpy( pm->wd8, path, pm->wbytes+1 ); + rc = wait_server( hsock, pm ); + bfm_type = type; + sig_read = (uint16_t)(pm->rwdata >> 16); // signal read mask + sig_write = (uint16_t)pm->rwdata; // signal write mask + bfm_period = period_ps; + buf_width = pm->rd32[0]/8;// access width in bytes + addr_bits = pm->rd32[2]; + } + if( rc ) + debug_msg( rc, "vdebug_open: Error 0x%x connecting to BFM %s", rc, path ); + else if( debug ) + debug_msg( VD_ERR_NONE, "vdebug_open: %s type %0x, period %dps, buffer %dx%dB signals r%04xw%04x", + path, bfm_type, bfm_period, VD_BUFFER_LEN/buf_width, buf_width, sig_read, sig_write ); + } + else + rc = VD_ERR_NOT_OPEN; + return rc; +} + +static int vdebug_close( SOCKET hsock, vd_shm_st* pm, uint32_t type ) +{ + int rc = VD_ERR_NOT_OPEN; + if( pm ) + { + pm->cmd = 0x05; + pm->type = (uint8_t)type; + pm->wbytes = pm->rbytes = pm->wwords = pm->rwords = 0; + rc = wait_server( hsock, pm ); + pm->cmd = 0x02; + pm->wid = (uint16_t)VD_VERSION; + pm->wbytes = pm->rbytes = pm->wwords = pm->rwords = 0; + wait_server( hsock, pm ); + if( debug ) + debug_msg( VD_ERR_NONE, "vdebug_close: type %0x", type ); + } + return rc; +} + +static int vdebug_wait( SOCKET hsock, vd_shm_st* pm, uint32_t cycles ) +{ + int rc = VD_ERR_NOT_OPEN; + if( pm && cycles ) + { + pm->cmd = 0x09; + pm->wbytes = 0; + pm->rbytes = 0; + pm->rwdata = cycles; + rc = wait_server( hsock, pm ); + if( debug ) + debug_msg( VD_ERR_NONE, "vdebug_wait: %d cycles", cycles ); + } + return rc; +} + +static int vdebug_sig_set( SOCKET hsock, vd_shm_st* pm, uint32_t write_mask, uint32_t value ) +{ + int rc = VD_ERR_NOT_OPEN; + if( pm ) + { + pm->cmd = 0x0a; + pm->wbytes = 0; + pm->rbytes = 0; + pm->rwdata = (write_mask << 16) | (value & 0xffff); + rc = wait_server( hsock, pm ); + if( rc ) + debug_msg( rc, "vdebug_sig_set: Error 0x%x setting signals %04x", rc, write_mask ); + else if( debug ) + debug_msg( VD_ERR_NONE, "vdebug_sig_set: setting signals %04x to %04x", write_mask, value ); + } + return rc; +} + +static int vdebug_jtag_clock( SOCKET hsock, vd_shm_st* pm, uint32_t value ) +{ + int rc = VD_ERR_NOT_OPEN; + if( pm ) + { + pm->cmd = 0x0f; + pm->wbytes = 0; + pm->rbytes = 0; + pm->rwdata = value; + rc = wait_server( hsock, pm ); + if( rc ) + debug_msg( rc, "vdebug_jtag_clock: Error 0x%x setting jtag_clock", rc ); + else if( debug ) + debug_msg( VD_ERR_NONE, "vdebug_jtag_clock: setting jtag clock divider to %d", value ); + } + return rc; +} + +static int vdebug_jtag_shift_tap( SOCKET hsock, vd_shm_st* pm, uint8_t num_pre, const uint8_t tms_pre, uint32_t num, const uint8_t* tdi, uint8_t num_post, const uint8_t tms_post, uint8_t* tdo, uint8_t f_last ) +{ + const uint32_t tobits = 8; + uint8_t ftdi, ftms; + uint16_t req, rreq, i,j; + uint16_t bytes, hwords, anum, words, rwords, waddr; + uint8_t* data; + int rc = 0; + + if( pm ) + { + pm->cmd = 0x1a; + trans_last = f_last || (trans_batch == 0) || (trans_batch == 1 && tdo); + if( trans_first ) + waddr = 0; // reset buffer offset + else + waddr = pm->offseth; // continue from the previous transaction + if( num_post ) // actual number of bits to shift + anum = num + num_pre + num_post - 1; + else + anum = num + num_pre; + hwords = (anum+4*buf_width-1)/(4*buf_width); // in 4B TDI/TMS words + words = (hwords+1)/2; // in 8B TDO words to read + bytes = (num+7)/8; // data only portion in bytes + // buffer overflow check and flush + if( waddr + 2 + 2*hwords + 16 > VD_BUFFER_LEN/4 ) + trans_last = 1; // force flush within 64B of buffer end + else if( waddr + 2 + 2*hwords > VD_BUFFER_LEN/4 ) + { // this req does not fit, discard it + rc = debug_msg( VD_ERR_NO_MEMORY, "vdebug_jtag_shift_tap: %04x Error too many bits, discarded L:%02d O:%05x @%04x", pm->wid, anum, ((trans_first << 14)|(trans_last << 15)), waddr ); + } + if( !rc && anum ) // support for calls with num=0 as flush + { + pm->wd32[waddr++] = (tdo ? 0xc0000000: 0x40000000) + (num_pre << 27) + (num_post << 24) + anum; + pm->wd32[waddr++] = hwords + (tdo ? (words << 16): 0); + pm->wid++; + pm->wd8[4*waddr] = (tdi ? (tdi[0] << num_pre) : 0); + pm->wd8[4*waddr+4] = tms_pre; // init with tms_pre + if( num+num_pre <= 8 ) // and tms_post for num <=4 + pm->wd8[4*waddr+4] |= (tms_post << (num+num_pre-1)); + for( i=1,j=4*waddr; i<bytes; i++ ) // copy the tdi and tms data + { + if( i == bytes-1 && num+num_pre <= bytes*tobits ) + pm->wd8[j+i+4] = tms_post << ((num+num_pre-1) % 8); + else + pm->wd8[j+i+4] = 0x0;// placing 4 bytes of TMS bits into high word + if( !tdi ) // placing 4 bytes of TDI bits into low word + pm->wd8[j+i] = 0x0; + else + pm->wd8[j+i] = (tdi[i] << num_pre) | (tdi[i-1] >> (8-num_pre)); + if( i % 4 == 3 ) + j += 4; + } + if( tdi ) + { + if( num+num_pre > bytes*tobits )// in case 1 additional byte needed for TDI + pm->wd8[j+i] = (tdi[i-1] >> (8-num_pre)); // put last TDI bits there + } + if( num+num_pre <= bytes*tobits )// in case no or 1 additional byte needed + pm->wd8[j+i+4] = tms_post >> (8-(num+num_pre-1) % 8); // may need to add higher part + // in case exactly 1 additional byte needed + else if( num+num_pre > bytes*tobits && anum <= (bytes+1)*tobits ) + pm->wd8[j+i+4] = tms_post << ((num+num_pre-1) % 8); // add whole tms_post + else // in case 2 additional bytes, tms_post split + { + pm->wd8[j+i+4] = tms_post << ((num+num_pre-1) % 8);// add lower part of tms_post + if( i % 4 == 3 ) // next byte is in the next 32b word + pm->wd8[j+i+4+5] = tms_post >> (8-(num+num_pre-1) % 8); // and higher part + else // next byte is in the same 32b word + pm->wd8[j+i+4+1] = tms_post >> (8-(num+num_pre-1) % 8); // and higher part + } + if( tdo ) + { + pm->rwords += words; // keep track of the words to read + pm->rd64[VD_BUFFER_LEN/8-(++pm->offset)] = (uintptr_t)tdo; + } + pm->wwords = waddr/2 + hwords; // payload size *2 to include both TDI and TMS data + pm->waddr++; + } + + if( !waddr ) // no action + ; + else if( !trans_last ) // buffered request + pm->offseth = waddr + hwords*2; // offset for next transaction, must be even + else // execute batch of requests + { + req = rreq = waddr = rwords = 0; // beginning of request + pm->wbytes = pm->wwords*8; + pm->rbytes = pm->rwords*8; + if( (rc = wait_server( hsock, pm )) != 0) + debug_msg( rc, "vdebug_jtag_shift_tap: Error 0x%x executing transaction", rc ); + else do + { // loop over requests to read data and print out + hwords = pm->wd32[waddr+1]; // reconstrcut data this request + anum = pm->wd32[waddr] & 0xffff; + num_pre = (pm->wd32[waddr] >> 27) & 0x7; + num_post = (pm->wd32[waddr] >> 24) & 0x7; + if( num_post ) + num = anum - num_pre - num_post + 1; + else + num = anum - num_pre; + words = (hwords+1)/2; + bytes = (num+7)/tobits; + trans_last = (req+1 < pm->waddr ? 0 : 1); + trans_first = (waddr ? 0 : 1); + if( pm->wd32[waddr] & 0x80000000 ) + { + data = (uint8_t*)(uintptr_t)pm->rd64[VD_BUFFER_LEN/8-1-rreq++]; + for( j=0; j<bytes; j++ ) + { + data[j] = (pm->rd8[rwords*8+j] >> num_pre) | (pm->rd8[rwords*8+j+1] << (tobits-num_pre)); + if( debug > 4 ) + debug_msg( VD_ERR_NONE, "vdebug_jtag_shift_tap: %04x D0[%02x]:%02x", pm->wid-pm->waddr+req, j, data[j] ); + } + rwords += words; // read data offset + } + else + data = NULL; + if( debug ) + { + ftdi = (pm->wd8[(waddr+2)*4] >> num_pre) | (pm->wd8[(waddr+2)*4+1] << (8-num_pre)); + ftms = (pm->wd8[(waddr+2)*4+4] >> num_pre) | (pm->wd8[(waddr+2)*4+4+1] << (8-num_pre)); + debug_msg( VD_ERR_NONE, "vd_jtag_shift_tap: %04x L:%02d O:%05x @%03x DI:%02x MS:%02x DO:%02x", pm->wid-pm->waddr+req, num, ((trans_first << 14)|(trans_last << 15)), waddr, ftdi, ftms, (data ? data[0] : 0xdd) ); + } + waddr += 2+hwords*2; // next request beginning + } while( ++req < pm->waddr ); + pm->offseth = 0; // reset buffer write address + pm->offset = 0; + pm->rwords = 0; + pm->waddr = 0; + } + trans_first = trans_last; // flush forces trans_first flag + } + else + rc = VD_ERR_NOT_OPEN; + return rc; +} + +static int vdebug_mem_open( SOCKET hsock, vd_shm_st* pm, const char* path, uint8_t ndx ) +{ + int rc = VD_ERR_NOT_OPEN; + + if( pm ) + { + pm->cmd = 0x21; + pm->wbytes = (uint16_t)strlen( path )+1; + pm->rbytes = 8; + pm->wwords = pm->rwords = 0; + memcpy( pm->wd8, path, pm->wbytes+1 ); + rc = wait_server( hsock, pm ); + if( rc ) + debug_msg( rc, "vdebug_mem_open: Error 0x%x opening memory %s", rc, path ); + else + { + mem_width[ndx] = pm->rd32[0]/8; // memory width in bytes + mem_depth[ndx] = pm->rd32[1]; // memory depth in words + if( debug ) + debug_msg( VD_ERR_NONE, "vdebug_mem_open: %s memory %xx%dB, buffer %dx%dB", + path, mem_depth[ndx], mem_width[ndx], VD_BUFFER_LEN/mem_width[ndx], mem_width[ndx] ); + } + } + return rc; +} + +static void vdebug_mem_close( SOCKET hsock, vd_shm_st* pm, uint8_t ndx ) +{ + if( pm ) + { + pm->cmd = 0x22; + pm->wbytes = pm->rbytes = pm->wwords = pm->rwords = 0; + wait_server( hsock, pm ); + if( debug ) + debug_msg( VD_ERR_NONE, "vdebug_mem_close: %s", mem_path[ndx] ); + } +} + +static int vdebug_mem_write( SOCKET hsock, vd_shm_st* pm, uint8_t ndx, uint64_t addr, uint32_t num, const uint8_t* data ) +{ + int rc = VD_ERR_NOT_OPEN; + if( pm ) + { + pm->cmd = 0x23; + pm->wbytes = num; + pm->wwords = (num+mem_width[ndx]-1)/mem_width[ndx]; + pm->rbytes = pm->rwords = 0; +#ifndef _M_IX86 + pm->offset = (uint32_t)(addr/mem_width[ndx]); + pm->offseth = (uint16_t)(addr/mem_width[ndx] >> 32); +#else + pm->offset = ((uint32_t)(addr))/mem_width[ndx]; // 32 bit calculation for Win32 + pm->offseth = 0; +#endif + memcpy( pm->wd8, data, num ); + rc = wait_server( hsock, pm ); + if( rc ) + debug_msg( rc, "vdebug_mem_write: Error 0x%x writing %d bytes at %llx", rc, num, addr ); + else if( debug ) + debug_msg( VD_ERR_NONE, "vdebug_mem_write: A:%08llx L:%d D:%08x", addr, num, pm->wd32[0] ); + pm->offset = 0; + pm->offseth = 0; + } + return rc; +} + +static int vdebug_poll( struct target* pt ) +{ + int rc; + struct timeval ts, te; + uint32_t cmdtime; + + assert( pt != NULL ); + gettimeofday( &ts, NULL ); + if( targ_poll ) + rc = targ_poll( pt ); + if( pt->state == TARGET_RUNNING ) + pollcycles = pollmax; + else + pollcycles = pollmin; + vdebug_wait( hsocket, pbuf, pollcycles ); + gettimeofday( &ts, NULL ); + cmdtime = (uint32_t)((te.tv_sec - ts.tv_sec) * 1000000 + te.tv_usec - ts.tv_usec); + LOG_DEBUG("poll state:%u cycles:%u executed in %uus", pt->state, pollcycles, cmdtime ); + return rc; +} + +static int vdebug_write_memory( struct target* pt, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) +{ + int rc; + int ndx; + uint32_t offset; + uint32_t written; + uint32_t towrite; + assert( pt != NULL ); + for( ndx = 0; ndx < VD_MAX_MEMORIES; ndx++ ) + if( address >= mem_base[ndx] && address+size*count <= mem_base[ndx]+mem_size[ndx] ) + break; // hit one of the declared memories + if( ndx < VD_MAX_MEMORIES && size*count > 4 ) + { + if( ndx != mem_ndx && mem_width[mem_ndx] ) + { // need to switch memory + vdebug_mem_close( hsocket, pbuf, mem_ndx ); + mem_width[mem_ndx] = 0; + } + mem_ndx = ndx; + if( mem_width[ndx] == 0 ) + rc = vdebug_mem_open( hsocket, pbuf, mem_path[ndx], ndx ); + else + rc = 0; + offset = address-mem_base[ndx]; + LOG_INFO("vdebug_mem_write: i:%d a:0x%08x n:%d rc:%d", ndx, mem_base[ndx]+offset, count*size, rc ); + written = 0; + while( !rc && written < count*size ) + { + towrite = (count*size - written < VD_BUFFER_LEN ? count*size - written : VD_BUFFER_LEN); + rc = vdebug_mem_write( hsocket, pbuf, ndx, offset, towrite, buffer+written ); + offset += towrite; + written += towrite; + } + } + else if( targ_write_memory ) + rc = targ_write_memory( pt, address, size, count, buffer ); + LOG_DEBUG("write_memory: " TARGET_ADDR_FMT " n:%d w:%d", address, count, size ); + return rc; +} + +static int vdebug_init(void) +{ + uint32_t type, sig_mask; + int rc; + + debug_open(); + for( rc = 0; rc < VD_MAX_MEMORIES; rc++ ) + mem_width[rc] = 0; + pollmin = 1000; pollmax = 5000; pollcycles = pollmax; + type = VD_BFM_JTAG; + sig_mask = VD_SIG_RESET | VD_SIG_TRST | VD_SIG_TCKDIV; + rc = ERROR_OK; + if( (hsocket = socket_open( server_name, server_port )) <= 0 ) + rc = VD_ERR_SOC_OPEN; + else if( (pbuf = (vd_shm_st*)calloc( 1, sizeof( vd_shm_st ))) == NULL ) + { + socket_close( hsocket ); + hsocket = 0; + LOG_ERROR("cannot allocate %lu bytes", sizeof( vd_shm_st ) ); + } + else if( (rc = vdebug_open( hsocket, pbuf, bfm_path, type, bfm_period, sig_mask)) != 0 ) + ; + else + LOG_INFO("vdebug %d %s connected to %s through %s:%d", VD_VERSION, VD_BUILD, bfm_path, server_name, server_port); + trans_first = 1; + return rc; +} + +static int vdebug_quit(void) +{ + int rc; + + targ_write_memory = NULL; // target is already destroyed at this point + targ_poll = NULL; + for( rc = 0; rc < VD_MAX_MEMORIES; rc++ ) + if( mem_width[rc] ) + vdebug_mem_close( hsocket, pbuf, rc ); + rc = vdebug_close( hsocket, pbuf, VD_BFM_JTAG ); + if( hsocket ) + socket_close( hsocket ); + if( pbuf ) + free( pbuf ); + if( debug_log ) + fclose( debug_log ); + pbuf = NULL; + hsocket = -1; + debug_log = NULL; + LOG_INFO("vdebug %d disconnected from %s through %s:%d", VD_VERSION, bfm_path, server_name, server_port); + return rc; +} + +static int vdebug_reset(int trst, int srst) +{ + uint16_t sig_val = 0xffff; + uint16_t sig_mask = 0; + int rc; + + sig_mask |= VD_SIG_RESET; + if( srst ) + sig_val &= ~VD_SIG_RESET;// active low + if( transport_is_jtag() ) + { + sig_mask |= VD_SIG_TRST; + if( trst ) + sig_val &= ~VD_SIG_TRST; // active low + } + LOG_INFO("rst trst:%d srst:%d mask:%x val:%x", trst, srst, sig_mask, sig_val); + if( (rc = vdebug_sig_set( hsocket, pbuf, sig_mask, sig_val )) != 0 ) + ; + else + rc = vdebug_wait( hsocket, pbuf, 20 ); + + return rc; +} + +static int vdebug_tms_seq(const uint8_t *tms, int num, uint8_t f_flush) +{ + LOG_INFO("tms len:%d tms:%x", num, *(const uint32_t*)tms); + return vdebug_jtag_shift_tap( hsocket, pbuf, num, *tms, 0, NULL, 0, 0, NULL, f_flush ); +} + +static int vdebug_path_move(struct pathmove_command *cmd, uint8_t f_flush) +{ + uint8_t tms[DIV_ROUND_UP(cmd->num_states, 8)]; + LOG_INFO("path num states %d", cmd->num_states ); + + memset(tms, 0, DIV_ROUND_UP(cmd->num_states, 8)); + + for (int i = 0; i < cmd->num_states; i++) { + if (tap_state_transition(tap_get_state(), true) == cmd->path[i]) + buf_set_u32(tms, i, 1, 1); + tap_set_state(cmd->path[i]); + } + return vdebug_tms_seq(tms, cmd->num_states, f_flush); +} + +static int vdebug_tlr(tap_state_t state, uint8_t f_flush) +{ + int rc = ERROR_OK; + uint8_t tms_pre; + uint8_t num_pre; + uint8_t cur; + + cur = tap_get_state(); + tms_pre = tap_get_tms_path( cur, state ); + num_pre = tap_get_tms_path_len( cur, state ); + LOG_INFO("tlr from %x to %x", cur, state ); + if (cur != state) + { + rc = vdebug_jtag_shift_tap( hsocket, pbuf, num_pre, tms_pre, 0, NULL, 0, 0, NULL, f_flush ); + tap_set_state(state); + } + return rc; +} + +static int vdebug_scan(struct scan_command *cmd, uint8_t f_flush) +{ + int num_bits; + int i, rc; + uint8_t tms_pre, tms_post; // tms value pre and post shift + uint8_t num_pre, num_post; // num bits pre shift, post shift + uint8_t state; + uint8_t cur; + + cur = tap_get_state(); + state = cmd->ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT; + tms_pre = tap_get_tms_path( cur, state ); + num_pre = tap_get_tms_path_len( cur, state ); + tms_post = tap_get_tms_path( state, cmd->end_state ); + num_post = tap_get_tms_path_len( state, cmd->end_state ); + num_bits = jtag_scan_size( cmd ); + LOG_DEBUG("scan len:%d fields:%d ir/!dr:%d state cur:%x end:%x", num_bits, cmd->num_fields, cmd->ir_scan, cur, cmd->end_state ); + for( i=0, rc=0; rc == 0 && i < cmd->num_fields; i++ ) + rc = vdebug_jtag_shift_tap( hsocket, pbuf, (i==0 ? num_pre : 0), (i==0 ? tms_pre : 0), cmd->fields[i].num_bits, cmd->fields[i].out_value, (i==cmd->num_fields-1 ? num_post : 0), (i==cmd->num_fields-1 ? tms_post : 0), cmd->fields[i].in_value, (i==cmd->num_fields-1 ? f_flush : 0) ); + if( cur != cmd->end_state ) + tap_set_state(cmd->end_state); + return rc; +} + +static int vdebug_runtest(int cycles, tap_state_t state, uint8_t f_flush) +{ + int rc; + uint8_t tms_pre; + uint8_t num_pre; + uint8_t cur; + + cur = tap_get_state(); + tms_pre = tap_get_tms_path( cur, state ); + num_pre = tap_get_tms_path_len( cur, state ); + LOG_DEBUG("idle len:%d state cur:%x end:%x", cycles, cur, state ); + rc = vdebug_jtag_shift_tap( hsocket, pbuf, num_pre, tms_pre, cycles, NULL, 0, 0, NULL, f_flush ); + if( cur != state ) + tap_set_state( state ); + return rc; +} + +static int vdebug_stableclocks(int num, uint8_t f_flush) +{ + LOG_INFO("stab len:%d state cur:%x", num, tap_get_state() ); + return vdebug_jtag_shift_tap( hsocket, pbuf, 0, 0, num, NULL, 0, 0, NULL, f_flush ); +} + +static int vdebug_sleep(int us) +{ + int rc; + + LOG_INFO("sleep %d us", us ); + rc = vdebug_wait( hsocket, pbuf, us/1000 ); + return rc; +} + +static int vdebug_speed(int speed) +{ + uint32_t divval, clkmax; + int rc; + + clkmax = 1000000000/(bfm_period * 2); // kHz + divval = clkmax/speed; + LOG_INFO("jclk speed:%d kHz set, BFM divider %u", speed, divval ); + rc = vdebug_jtag_clock( hsocket, pbuf, divval ); + return rc; +} + +static int vdebug_khz(int khz, int* jtag_speed) +{ + uint32_t divval, clkmax; + + clkmax = 1000000000/(bfm_period * 2); // kHz + divval = khz ? clkmax/khz : 1; + *jtag_speed = clkmax/divval; + LOG_DEBUG("khz speed:%d from khz:%d", *jtag_speed, khz ); + return ERROR_OK; +} + +static int vdebug_div(int speed, int* khz) +{ + *khz = speed; + LOG_DEBUG("div khz:%d from speed:%d", *khz, speed ); + return ERROR_OK; +} + +static int vdebug_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 = vdebug_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); + break; + case JTAG_RUNTEST: + retval = vdebug_runtest(cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state, cmd->next == NULL); + break; + case JTAG_STABLECLOCKS: + retval = vdebug_stableclocks(cmd->cmd.stableclocks->num_cycles, cmd->next == NULL); + break; + case JTAG_TLR_RESET: + retval = vdebug_tlr(cmd->cmd.statemove->end_state, cmd->next == NULL); + break; + case JTAG_PATHMOVE: + retval = vdebug_path_move(cmd->cmd.pathmove, cmd->next == NULL); + break; + case JTAG_TMS: + retval = vdebug_tms_seq(cmd->cmd.tms->bits, cmd->cmd.tms->num_bits, cmd->next == NULL); + break; + case JTAG_SLEEP: + retval = vdebug_sleep(cmd->cmd.sleep->us); + break; + case JTAG_SCAN: + retval = vdebug_scan(cmd->cmd.scan, cmd->next == NULL); + break; + } + } + return retval; +} + +static int vdebug_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, + uint32_t port_size, unsigned int *trace_freq, unsigned int traceclkin_freq, uint16_t *prescaler ) +{ + *trace_freq = 0; + LOG_DEBUG("config_trace en:%d prot:%u size:%u freq:%u scale:%u", enabled, pin_protocol, port_size, traceclkin_freq, *prescaler); + return ERROR_OK; +} + +static int vdebug_poll_trace( uint8_t* buf, size_t* size ) +{ + *size = 0; + LOG_DEBUG("poll_trace "); + return vdebug_wait( hsocket, pbuf, pollcycles ); +} + +COMMAND_HANDLER(vdebug_set_server) +{ + char* pchar; + int rc = ERROR_FAIL; + if (CMD_ARGC == 0) + { + strcpy( server_name, "localhost" ); + server_port = 8192; + } + else if( (pchar = strchr( CMD_ARGV[0], ':' )) != NULL ) + { // server:port + *pchar = '\0'; + strncpy( server_name, CMD_ARGV[0], sizeof(server_name)-1 ); + server_port = atoi( ++pchar ); + rc = ERROR_OK; + } + else + { + strncpy( server_name, CMD_ARGV[0], sizeof(server_name)-1 ); + server_port = 8192; + rc = ERROR_OK; + } + LOG_DEBUG("vdebug server: %s port %u", server_name, server_port); + return rc; +} + +COMMAND_HANDLER(vdebug_set_bfm) +{ + int rc = ERROR_FAIL; + char prefix; + if (CMD_ARGC != 2) + LOG_ERROR("vdebug bfm_path <path> <clk_period[p|n|u]s>"); + else + { + strncpy( bfm_path, CMD_ARGV[0], sizeof(bfm_path)-1 ); + if( sscanf( CMD_ARGV[1], "%u%cs*", &bfm_period, &prefix ) == 2 ) + { + switch( prefix ) + { + case 'u': bfm_period *= 1000000; + break; + case 'n': bfm_period *= 1000; + break; + case 'p': + default: + break; + } + rc = ERROR_OK; + LOG_DEBUG("vdebug bfm_path: %s clk_period %dps", bfm_path, bfm_period); + } + } + return rc; +} + +COMMAND_HANDLER(vdebug_set_mem) +{ + int rc = ERROR_FAIL; + if (CMD_ARGC != 3) + LOG_ERROR("mem_path <path> <base_address> <size>"); + else if( mem_ndx >= VD_MAX_MEMORIES ) + LOG_ERROR("mem_path declared more than %d allowed times", VD_MAX_MEMORIES); + else + { + strncpy( mem_path[mem_ndx], CMD_ARGV[0], sizeof(mem_path[mem_ndx])-1 ); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], mem_base[mem_ndx]); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], mem_size[mem_ndx]); + rc = ERROR_OK; + LOG_DEBUG("vdebug mem_path: set %s @ 0x%08x+0x%08x", mem_path[mem_ndx], mem_base[mem_ndx], mem_size[mem_ndx]); + mem_ndx++; + } + return rc; +} + +COMMAND_HANDLER(vdebug_set_batching) +{ + int rc = ERROR_FAIL; + + if (CMD_ARGC != 1) + LOG_ERROR("transaction_batching <level>"); + else + { + if( isdigit( CMD_ARGV[0][0] ) ) + trans_batch = (CMD_ARGV[0][0] == '0' ? 0 : (CMD_ARGV[0][0] == '1' ? 1: 2 )); + else if( CMD_ARGV[0][0] == 'r' ) + trans_batch = 2; + else if( CMD_ARGV[0][0] == 'w' ) + trans_batch = 1; + else + trans_batch = 0; + LOG_DEBUG("transaction_batching: set to %u", trans_batch); + rc = ERROR_OK; + } + return rc; +} + +COMMAND_HANDLER(vdebug_register_poll) +{ + int rc = ERROR_FAIL; + + if (CMD_ARGC != 2) + LOG_ERROR("register_target_poll <min cycles>> <max cycles>"); + else + { + pollmin = atoi( CMD_ARGV[0] ); + pollmax = atoi( CMD_ARGV[1] ); + if( ((ptarg = get_target_by_num(0)) != NULL) && ptarg->type != NULL ) + { + targ_poll = ptarg->type->poll; + ptarg->type->poll = &vdebug_poll; + LOG_INFO("register_target_poll: set min %u max %u cycles", pollmin, pollmax); + } + rc = ERROR_OK; + } + return rc; +} + +COMMAND_HANDLER(vdebug_register_dma) +{ + int rc = ERROR_FAIL; + + if( ((ptarg = get_target_by_num(0)) != NULL) && ptarg->type != NULL ) + { + targ_write_memory = ptarg->type->write_memory; + ptarg->type->write_memory = &vdebug_write_memory; + LOG_INFO("register_target_dma: %u target memories registered for direct access", mem_ndx); + rc = ERROR_OK; + } + return rc; +} + +static const struct command_registration vdebug_command_handlers[] = +{ + { + .name = "server", + .handler = &vdebug_set_server, + .mode = COMMAND_CONFIG, + .help = "set the vdebug server name or address", + .usage = "server <host:port>", + }, + { + .name = "bfm_path", + .handler = &vdebug_set_bfm, + .mode = COMMAND_CONFIG, + .help = "set the vdebug BFM hierarchical path", + .usage = "bfm_path <path> <clk_period[p|n|u]s>", + }, + { + .name = "mem_path", + .handler = &vdebug_set_mem, + .mode = COMMAND_ANY, + .help = "set the design memory for the code load", + .usage = "mem_path <path> <base_address> <size>", + }, + { + .name = "transaction_batching", + .handler = &vdebug_set_batching, + .mode = COMMAND_CONFIG, + .help = "set the transaction batching no|wr|rd [0|1|2]", + .usage = "transaction_batching <level>", + }, + { + .name = "register_target_poll", + .handler = &vdebug_register_poll, + .mode = COMMAND_EXEC, + .help = "set the polling pause, executing hardware cycles between min and max", + .usage = "register_target_poll <min cycles> <max cycles>", + }, + { + .name = "register_target_dma", + .handler = &vdebug_register_dma, + .mode = COMMAND_EXEC, + .help = "Hook up the direct memory access routines to the memories specified by mem_path", + .usage = "register_target_dma", + }, + COMMAND_REGISTRATION_DONE +}; + +static struct jtag_interface vdebug_interface = +{ + .supported = DEBUG_CAP_TMS_SEQ, + .execute_queue = vdebug_execute_queue, +}; + +struct adapter_driver vdebug_adapter_driver = +{ + .name = "vdebug", + .transports = vdebug_transports, + .speed = vdebug_speed, + .khz = vdebug_khz, + .speed_div = vdebug_div, + .commands = vdebug_command_handlers, + .init = vdebug_init, + .quit = vdebug_quit, + .config_trace = vdebug_config_trace, + .poll_trace = vdebug_poll_trace, + .jtag_ops = &vdebug_interface, +}; diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c index 061a78f..c530b0b 100644 --- a/src/jtag/interfaces.c +++ b/src/jtag/interfaces.c @@ -62,6 +62,9 @@ extern struct adapter_driver usb_blaster_adapter_driver; #if BUILD_JTAG_VPI == 1 extern struct adapter_driver jtag_vpi_adapter_driver; #endif +#if BUILD_VDEBUG == 1 +extern struct adapter_driver vdebug_adapter_driver; +#endif #if BUILD_JTAG_DPI == 1 extern struct adapter_driver jtag_dpi_adapter_driver; #endif @@ -182,6 +185,9 @@ struct adapter_driver *adapter_drivers[] = { #if BUILD_JTAG_VPI == 1 &jtag_vpi_adapter_driver, #endif +#if BUILD_VDEBUG == 1 + &vdebug_adapter_driver, +#endif #if BUILD_JTAG_DPI == 1 &jtag_dpi_adapter_driver, #endif diff --git a/tcl/interface/vdebug.cfg b/tcl/interface/vdebug.cfg new file mode 100644 index 0000000..a3f78e7 --- /dev/null +++ b/tcl/interface/vdebug.cfg @@ -0,0 +1,15 @@ +# +# Cadence virtual debug interface + +# vdebug server:port +adapter driver vdebug + +server localhost:8192 + +debug_level 2 +log_output vd_ocd.log + +bindto 0.0.0.0 +gdb_port 3333 +telnet_port disabled +tcl_port disabled diff --git a/tcl/target/vd_a53x2_jtag.cfg b/tcl/target/vd_a53x2_jtag.cfg new file mode 100644 index 0000000..e1bb943 --- /dev/null +++ b/tcl/target/vd_a53x2_jtag.cfg @@ -0,0 +1,77 @@ +# Cadence virtual debug interface +# Arm Cortex A53x2 through JTAG + +interface vdebug +# vdebug server:port +server localhost:8192 + +# debug level and log +#debug_level 2 +#log_output vd_ocd.log + +# listen on all interfaces +bindto 0.0.0.0 +gdb_port 3333 +gdb_report_data_abort enable +gdb_report_register_access_error enable +telnet_port disabled +tcl_port disabled + +# target specific data +set _CHIPNAME a53x2 +set _MEMSTART 0x00000000 +set _MEMSIZE 0x1000000 +set _CPUTAPID 0x5ba00477 +set _TARGETNAME $_CHIPNAME.cpu +set _CTINAME $_CHIPNAME.cti +set _cores 2 + +set DBGBASE {0x80810000 0x80910000} +set CTIBASE {0x80820000 0x80920000} + +# BFM hierarchical path and input clk period +bfm_path tbench.u_vd_jtag_bfm 10ns +# DMA Memories to access backdoor (up to 3) +mem_path tbench.u_memory.mem_array $_MEMSTART $_MEMSIZE + +transport select jtag + +reset_config trst_and_srst +adapter speed 50000 +adapter srst delay 5 + +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID + +jtag arp_init-reset + +dap create $_CHIPNAME.dap -chain-position $_TARGETNAME + +for { set _core 0 } { $_core < $_cores } { incr _core } \ +{ + cti create $_CTINAME.$_core -dap $_CHIPNAME.dap -ap-num 1 \ + -baseaddr [lindex $CTIBASE $_core] + set _command "target create $_TARGETNAME.$_core aarch64 -dap $_CHIPNAME.dap \ + -dbgbase [lindex $DBGBASE $_core] -cti $_CTINAME.$_core" + if { $_core != 0 } { + # non-boot core examination may fail + #set _command "$_command -defer-examine" + set _smp_command "$_smp_command $_TARGETNAME.$_core" + } else { + set _smp_command "target smp $_TARGETNAME.$_core" + } + eval $_command +} +eval $_smp_command + +# register vdebug routines +proc vdebug_examine_end {} { + register_target_poll 2000 20000 + register_target_dma +} + +# Default hooks +$_TARGETNAME.0 configure -event examine-end { vdebug_examine_end } +#$_TARGETNAME.1 configure -event examine-end { vdebug_examine_end } + +# default target is A53 core 0 +targets $_TARGETNAME.0 diff --git a/tcl/target/vd_m4f_jtag.cfg b/tcl/target/vd_m4f_jtag.cfg new file mode 100644 index 0000000..c0c975d --- /dev/null +++ b/tcl/target/vd_m4f_jtag.cfg @@ -0,0 +1,56 @@ +# Cadence virtual debug interface +# Arm Cortex m4f through JTAG + +adapter driver vdebug +# vdebug server:port +server localhost:8192 + +# debug level and log +#debug_level 2 +#log_output vd_ocd.log + +# listen on all interfaces +bindto 0.0.0.0 +gdb_port 3333 +telnet_port disabled +tcl_port disabled + +# target specific data +set _CHIPNAME m4f +set _MEMSTART 0x20000000 +set _MEMSIZE 0x100000 +set _CPUTAPID 0x4ba00477 +set _TARGETNAME $_CHIPNAME.cpu + +# BFM hierarchical path and input clk period +bfm_path tbench.u_vd_jtag_bfm 20ns +# DMA Memories to access backdoor (up to 3) +mem_path tbench.u_mcu.u_sys.u_rom.rom 0x0 $_MEMSIZE +mem_path tbench.u_mcu.u_sys.u_ram.ram $_MEMSTART $_MEMSIZE + +transaction_batching 2 + +transport select jtag + +reset_config trst_and_srst +adapter speed 25000 +adapter srst delay 10 + +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID + +jtag arp_init-reset + +dap create $_CHIPNAME.dap -chain-position $_TARGETNAME + +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap +#target create $_TARGETNAME cortex_m -chain-position $_CHIPNAME.cpu + +# register the polling routine +proc vdebug_examine_end {} { + register_target_poll 5000 20000 + register_target_dma +} + +# Default hooks +$_TARGETNAME configure -event examine-end { vdebug_examine_end } +$_TARGETNAME configure -work-area-phys $_MEMSTART -work-area-size $_MEMSIZE -work-area-backup 0 diff --git a/tcl/target/vd_m7f_jtag.cfg b/tcl/target/vd_m7f_jtag.cfg new file mode 100644 index 0000000..6d3b922 --- /dev/null +++ b/tcl/target/vd_m7f_jtag.cfg @@ -0,0 +1,56 @@ +# Cadence virtual debug interface +# Arm Cortex m7f through JTAG + +adapter driver vdebug +# vdebug server:port +server localhost:8192 + +# debug level and log +#debug_level 3 +#log_output vd_ocd.log + +# listen on all interfaces +bindto 0.0.0.0 +gdb_port 3333 +telnet_port disabled +tcl_port disabled + +# target specific data +set _CHIPNAME m7f +set _MEMSTART 0x20000000 +set _MEMSIZE 0x10000 +set _CPUTAPID 0x0ba02477 +set _TARGETNAME $_CHIPNAME.cpu + +# BFM hierarchical path and input clk period +bfm_path tbench.u_vd_jtag_bfm 10ns +# DMA Memories to access backdoor (up to 3) +#mem_path tbench.u_mcu.u_sys.u_itcm_ram.Mem 0x0 $_MEMSIZE +mem_path tbench.u_mcu.u_sys.u_ram.ram $_MEMSTART $_MEMSIZE + +transaction_batching 2 + +transport select jtag + +reset_config trst_and_srst +adapter speed 50000 +adapter srst delay 10 + +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID + +jtag arp_init-reset + +dap create $_CHIPNAME.dap -chain-position $_TARGETNAME + +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap +#target create $_TARGETNAME cortex_m -chain-position $_CHIPNAME.cpu + +# register the polling routine +proc vdebug_examine_end {} { + register_target_poll 5000 20000 + register_target_dma +} + +# Default hooks +$_TARGETNAME configure -event examine-end { vdebug_examine_end } +$_TARGETNAME configure -work-area-phys $_MEMSTART -work-area-size $_MEMSIZE -work-area-backup 0 diff --git a/tcl/target/vd_pulpissimo_jtag.cfg b/tcl/target/vd_pulpissimo_jtag.cfg new file mode 100644 index 0000000..30b2937 --- /dev/null +++ b/tcl/target/vd_pulpissimo_jtag.cfg @@ -0,0 +1,63 @@ +# Cadence virtual debug interface +# RISCV Ibex core with Pulpissimo through JTAG + +adapter driver vdebug +# vdebug server:port +server localhost:8192 + +# debug level and log +#debug_level 3 +#log_output vd_ocd.log + +# listen on all interfaces +bindto 0.0.0.0 +gdb_port 3333 +gdb_report_data_abort enable +gdb_report_register_access_error enable +telnet_port disabled +tcl_port disabled + +# target specific data +set _CHIPNAME riscv +set _CPUTAPID 0x249511c3 +set _TARGETNAME $_CHIPNAME.cpu + +# BFM hierarchical path and input clk period +bfm_path tbench.u_vd_jtag_bfm 40ns +# DMA Memories to access backdoor (up to 3) +mem_path tbench.soc_domain_i.pulp_soc_i.gen_mem_l2_pri\[0\].sram_i.mem_array 0x1c000000 0x8000 +mem_path tbench.soc_domain_i.pulp_soc_i.gen_mem_l2_pri\[1\].sram_i.mem_array 0x1c008000 0x8000 +mem_path tbench.soc_domain_i.pulp_soc_i.gen_mem_l2\[0\].sram_i.mem_array 0x1c010000 0x80000 + +transaction_batching 2 +transport list +transport select jtag + +reset_config trst_and_srst +adapter speed 12500 +adapter srst delay 10 + +# need to explicitely define riscv tap, autoprobing does not work for icapture != 0x01 +jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x05 -irmask 0x1f -expected-id $_CPUTAPID + +jtag arp_init-reset + +target create $_TARGETNAME riscv -chain-position $_TARGETNAME -coreid 0x20 + +#gdb_report_data_abort enable +#gdb_report_register_access_error enable + +riscv set_reset_timeout_sec 120 +riscv set_command_timeout_sec 120 + +# prefer to use sba for system bus access +riscv set_prefer_sba on + +# register vdebug routines +proc vdebug_examine_end {} { + register_target_poll 2000 20000 + register_target_dma +} + +# Default hooks +$_TARGETNAME configure -event examine-end { vdebug_examine_end } diff --git a/tcl/target/vd_swerv_jtag.cfg b/tcl/target/vd_swerv_jtag.cfg new file mode 100644 index 0000000..218d48a --- /dev/null +++ b/tcl/target/vd_swerv_jtag.cfg @@ -0,0 +1,61 @@ +# Cadence virtual debug interface +# RISCV swerv core with Swerv through JTAG + +adapter driver vdebug +# vdebug server:port +server localhost:8192 + +# debug level and log +#debug_level 2 +#log_output vd_ocd.log + +gdb_port +gdb_report_data_abort enable +gdb_report_register_access_error enable +telnet_port disabled +tcl_port disabled + +# target specific data +set _CHIPNAME riscv +set _MEMSTART 0x00000000 +set _MEMSIZE 0x10000 +set _CPUTAPID 0x1000008b +set _TARGETNAME $_CHIPNAME.cpu + +# BFM hierarchical path and input clk period +bfm_path tbench.u_vd_jtag_bfm 10ns +# DMA Memories to access backdoor (up to 3) +mem_path tbench.u_ahb_ic.mem $_MEMSTART $_MEMSIZE + +#transaction_batching 1 + +transport select jtag + +reset_config trst_and_srst +adapter speed 50000 +adapter srst delay 10 + +# need to explicitely define riscv tap, autoprobing does not work for icapture != 0x01 +jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x01 -irmask 0x1f -expected-id $_CPUTAPID + +jtag arp_init-reset + +target create $_TARGETNAME riscv -chain-position $_TARGETNAME -coreid 0x00 + +gdb_report_data_abort enable +gdb_report_register_access_error enable + +riscv set_reset_timeout_sec 120 +riscv set_command_timeout_sec 120 + +# prefer to use sba for system bus access +riscv set_prefer_sba off + +# register the polling routine +proc vdebug_examine_end {} { + register_target_poll 2000 20000 + register_target_dma +} + +# Default hooks +$_TARGETNAME configure -event examine-end { vdebug_examine_end } -- _______________________________________________ OpenOCD-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/openocd-devel
