You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
475 lines
13 KiB
475 lines
13 KiB
/*
|
|
* Lib(X)SVF - A library for implementing SVF and XSVF JTAG players
|
|
*
|
|
* Copyright (C) 2009 RIEGL Research ForschungsGmbH
|
|
* Copyright (C) 2009 Clifford Wolf <clifford@clifford.at>
|
|
*
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*
|
|
*/
|
|
|
|
#include "libxsvf.h"
|
|
|
|
/* command codes as defined in xilinx xapp503 */
|
|
enum xsvf_cmd {
|
|
XCOMPLETE = 0x00,
|
|
XTDOMASK = 0x01,
|
|
XSIR = 0x02,
|
|
XSDR = 0x03,
|
|
XRUNTEST = 0x04,
|
|
XREPEAT = 0x07,
|
|
XSDRSIZE = 0x08,
|
|
XSDRTDO = 0x09,
|
|
XSETSDRMASKS = 0x0A,
|
|
XSDRINC = 0x0B,
|
|
XSDRB = 0x0C,
|
|
XSDRC = 0x0D,
|
|
XSDRE = 0x0E,
|
|
XSDRTDOB = 0x0F,
|
|
XSDRTDOC = 0x10,
|
|
XSDRTDOE = 0x11,
|
|
XSTATE = 0x12,
|
|
XENDIR = 0x13,
|
|
XENDDR = 0x14,
|
|
XSIR2 = 0x15,
|
|
XCOMMENT = 0x16,
|
|
XWAIT = 0x17
|
|
};
|
|
|
|
// This is to not confuse the VIM syntax highlighting
|
|
#define VAL_OPEN (
|
|
#define VAL_CLOSE )
|
|
|
|
#define READ_BITS(_buf, _len) do { \
|
|
unsigned char *_p = _buf; int _i; \
|
|
for (_i=0; _i<(_len); _i+=8) { \
|
|
int tmp = LIBXSVF_HOST_GETBYTE(); \
|
|
if (tmp < 0) { \
|
|
LIBXSVF_HOST_REPORT_ERROR("Unexpected EOF."); \
|
|
goto error; \
|
|
} \
|
|
*(_p++) = tmp; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define READ_LONG() VAL_OPEN{ \
|
|
long _buf = 0; int _i; \
|
|
for (_i=0; _i<4; _i++) { \
|
|
int tmp = LIBXSVF_HOST_GETBYTE(); \
|
|
if (tmp < 0) { \
|
|
LIBXSVF_HOST_REPORT_ERROR("Unexpected EOF."); \
|
|
goto error; \
|
|
} \
|
|
_buf = _buf << 8 | tmp; \
|
|
} \
|
|
_buf; \
|
|
}VAL_CLOSE
|
|
|
|
#define READ_BYTE() VAL_OPEN{ \
|
|
int _tmp = LIBXSVF_HOST_GETBYTE(); \
|
|
if (_tmp < 0) { \
|
|
LIBXSVF_HOST_REPORT_ERROR("Unexpected EOF."); \
|
|
goto error; \
|
|
} \
|
|
_tmp; \
|
|
}VAL_CLOSE
|
|
|
|
#define SHIFT_DATA(_inp, _outp, _maskp, _len, _state, _estate, _edelay, _ret) do { \
|
|
if (shift_data(h, _inp, _outp, _maskp, _len, _state, _estate, _edelay, _ret) < 0) { \
|
|
goto error; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define TAP(_state) do { \
|
|
if (libxsvf_tap_walk(h, _state) < 0) \
|
|
goto error; \
|
|
} while (0)
|
|
|
|
static int bits2bytes(int bits)
|
|
{
|
|
return (bits+7) / 8;
|
|
}
|
|
|
|
static int getbit(unsigned char *data, int n)
|
|
{
|
|
return (data[n/8] & (1 << (7 - n%8))) ? 1 : 0;
|
|
}
|
|
|
|
static void setbit(unsigned char *data, int n, int v)
|
|
{
|
|
unsigned char mask = 1 << (7 - n%8);
|
|
if (v)
|
|
data[n/8] |= mask;
|
|
else
|
|
data[n/8] &= ~mask;
|
|
}
|
|
|
|
static int xilinx_tap(int state)
|
|
{
|
|
/* state codes as defined in xilinx xapp503 */
|
|
switch (state)
|
|
{
|
|
case 0x00:
|
|
return LIBXSVF_TAP_RESET;
|
|
break;
|
|
case 0x01:
|
|
return LIBXSVF_TAP_IDLE;
|
|
break;
|
|
case 0x02:
|
|
return LIBXSVF_TAP_DRSELECT;
|
|
break;
|
|
case 0x03:
|
|
return LIBXSVF_TAP_DRCAPTURE;
|
|
break;
|
|
case 0x04:
|
|
return LIBXSVF_TAP_DRSHIFT;
|
|
break;
|
|
case 0x05:
|
|
return LIBXSVF_TAP_DREXIT1;
|
|
break;
|
|
case 0x06:
|
|
return LIBXSVF_TAP_DRPAUSE;
|
|
break;
|
|
case 0x07:
|
|
return LIBXSVF_TAP_DREXIT2;
|
|
break;
|
|
case 0x08:
|
|
return LIBXSVF_TAP_DRUPDATE;
|
|
break;
|
|
case 0x09:
|
|
return LIBXSVF_TAP_IRSELECT;
|
|
break;
|
|
case 0x0A:
|
|
return LIBXSVF_TAP_IRCAPTURE;
|
|
break;
|
|
case 0x0B:
|
|
return LIBXSVF_TAP_IRSHIFT;
|
|
break;
|
|
case 0x0C:
|
|
return LIBXSVF_TAP_IREXIT1;
|
|
break;
|
|
case 0x0D:
|
|
return LIBXSVF_TAP_IRPAUSE;
|
|
break;
|
|
case 0x0E:
|
|
return LIBXSVF_TAP_IREXIT2;
|
|
break;
|
|
case 0x0F:
|
|
return LIBXSVF_TAP_IRUPDATE;
|
|
break;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int shift_data(struct libxsvf_host *h, unsigned char *inp, unsigned char *outp, unsigned char *maskp, int len, enum libxsvf_tap_state state, enum libxsvf_tap_state estate, int edelay, int retries)
|
|
{
|
|
int left_padding = (8 - len % 8) % 8;
|
|
int with_retries = retries > 0;
|
|
int i;
|
|
|
|
if (with_retries && LIBXSVF_HOST_SYNC() < 0) {
|
|
LIBXSVF_HOST_REPORT_ERROR("TDO mismatch.");
|
|
return -1;
|
|
}
|
|
|
|
while (1)
|
|
{
|
|
int tdo_error = 0;
|
|
int tms = 0;
|
|
|
|
TAP(state);
|
|
tms = 0;
|
|
|
|
for (i=len+left_padding-1; i>=left_padding; i--) {
|
|
if (i == left_padding && h->tap_state != estate) {
|
|
h->tap_state++;
|
|
tms = 1;
|
|
}
|
|
int tdi = getbit(inp, i);
|
|
int tdo = -1;
|
|
if (maskp && getbit(maskp, i))
|
|
tdo = outp && getbit(outp, i);
|
|
int sync = with_retries && i == left_padding;
|
|
if (LIBXSVF_HOST_PULSE_TCK(tms, tdi, tdo, 0, sync) < 0)
|
|
tdo_error = 1;
|
|
}
|
|
|
|
if (tms)
|
|
LIBXSVF_HOST_REPORT_TAPSTATE();
|
|
|
|
if (edelay) {
|
|
TAP(LIBXSVF_TAP_IDLE);
|
|
LIBXSVF_HOST_UDELAY(edelay, 0, edelay);
|
|
} else {
|
|
TAP(estate);
|
|
}
|
|
|
|
if (!tdo_error)
|
|
return 0;
|
|
|
|
if (retries <= 0) {
|
|
LIBXSVF_HOST_REPORT_ERROR("TDO mismatch.");
|
|
return -1;
|
|
}
|
|
|
|
retries--;
|
|
}
|
|
|
|
error:
|
|
return -1;
|
|
}
|
|
|
|
int libxsvf_xsvf(struct libxsvf_host *h)
|
|
{
|
|
int rc = 0;
|
|
int i, j;
|
|
|
|
unsigned char *buf_tdi_data = (void*)0;
|
|
unsigned char *buf_tdo_data = (void*)0;
|
|
unsigned char *buf_tdo_mask = (void*)0;
|
|
unsigned char *buf_addr_mask = (void*)0;
|
|
unsigned char *buf_data_mask = (void*)0;
|
|
|
|
long state_dr_size = 0;
|
|
long state_data_size = 0;
|
|
long state_runtest = 0;
|
|
unsigned char state_xendir = 0;
|
|
unsigned char state_xenddr = 0;
|
|
unsigned char state_retries = 0;
|
|
unsigned char cmd = 0;
|
|
|
|
while (1)
|
|
{
|
|
unsigned char last_cmd = cmd;
|
|
cmd = LIBXSVF_HOST_GETBYTE();
|
|
|
|
#define STATUS(_c) LIBXSVF_HOST_REPORT_STATUS("XSVF Command " #_c);
|
|
|
|
switch (cmd)
|
|
{
|
|
case XCOMPLETE: {
|
|
STATUS(XCOMPLETE);
|
|
goto got_complete_command;
|
|
}
|
|
case XTDOMASK: {
|
|
STATUS(XTDOMASK);
|
|
READ_BITS(buf_tdo_mask, state_dr_size);
|
|
break;
|
|
}
|
|
case XSIR: {
|
|
STATUS(XSIR);
|
|
int length = READ_BYTE();
|
|
unsigned char buf[bits2bytes(length)];
|
|
READ_BITS(buf, length);
|
|
SHIFT_DATA(buf, (void*)0, (void*)0, length, LIBXSVF_TAP_IRSHIFT,
|
|
state_xendir ? LIBXSVF_TAP_IRPAUSE : LIBXSVF_TAP_IDLE,
|
|
state_runtest, state_retries);
|
|
break;
|
|
}
|
|
case XSDR: {
|
|
STATUS(XSDR);
|
|
READ_BITS(buf_tdi_data, state_dr_size);
|
|
SHIFT_DATA(buf_tdi_data, buf_tdo_data, buf_tdo_mask, state_dr_size, LIBXSVF_TAP_DRSHIFT,
|
|
state_xenddr ? LIBXSVF_TAP_DRPAUSE : LIBXSVF_TAP_IDLE,
|
|
state_runtest, state_retries);
|
|
break;
|
|
}
|
|
case XRUNTEST: {
|
|
STATUS(XRUNTEST);
|
|
state_runtest = READ_LONG();
|
|
break;
|
|
}
|
|
case XREPEAT: {
|
|
STATUS(XREPEAT);
|
|
state_retries = READ_BYTE();
|
|
break;
|
|
}
|
|
case XSDRSIZE: {
|
|
STATUS(XSDRSIZE);
|
|
state_dr_size = READ_LONG();
|
|
buf_tdi_data = LIBXSVF_HOST_REALLOC(buf_tdi_data, bits2bytes(state_dr_size), LIBXSVF_MEM_XSVF_TDI_DATA);
|
|
buf_tdo_data = LIBXSVF_HOST_REALLOC(buf_tdo_data, bits2bytes(state_dr_size), LIBXSVF_MEM_XSVF_TDO_DATA);
|
|
buf_tdo_mask = LIBXSVF_HOST_REALLOC(buf_tdo_mask, bits2bytes(state_dr_size), LIBXSVF_MEM_XSVF_TDO_MASK);
|
|
buf_addr_mask = LIBXSVF_HOST_REALLOC(buf_addr_mask, bits2bytes(state_dr_size), LIBXSVF_MEM_XSVF_ADDR_MASK);
|
|
buf_data_mask = LIBXSVF_HOST_REALLOC(buf_data_mask, bits2bytes(state_dr_size), LIBXSVF_MEM_XSVF_DATA_MASK);
|
|
if (!buf_tdi_data || !buf_tdo_data || !buf_tdo_mask || !buf_addr_mask || !buf_data_mask) {
|
|
LIBXSVF_HOST_REPORT_ERROR("Allocating memory failed.");
|
|
goto error;
|
|
}
|
|
break;
|
|
}
|
|
case XSDRTDO: {
|
|
STATUS(XSDRTDO);
|
|
READ_BITS(buf_tdi_data, state_dr_size);
|
|
READ_BITS(buf_tdo_data, state_dr_size);
|
|
SHIFT_DATA(buf_tdi_data, buf_tdo_data, buf_tdo_mask, state_dr_size, LIBXSVF_TAP_DRSHIFT,
|
|
state_xenddr ? LIBXSVF_TAP_DRPAUSE : LIBXSVF_TAP_IDLE,
|
|
state_runtest, state_retries);
|
|
break;
|
|
}
|
|
case XSETSDRMASKS: {
|
|
STATUS(XSETSDRMASKS);
|
|
READ_BITS(buf_addr_mask, state_dr_size);
|
|
READ_BITS(buf_data_mask, state_dr_size);
|
|
state_data_size = 0;
|
|
for (i=0; i<state_dr_size; i++)
|
|
state_data_size += getbit(buf_data_mask, i);
|
|
break;
|
|
}
|
|
case XSDRINC: {
|
|
STATUS(XSDRINC);
|
|
READ_BITS(buf_tdi_data, state_dr_size);
|
|
int num = READ_BYTE();
|
|
while (1) {
|
|
SHIFT_DATA(buf_tdi_data, buf_tdo_data, buf_tdo_mask, state_dr_size, LIBXSVF_TAP_DRSHIFT,
|
|
state_xenddr ? LIBXSVF_TAP_DRPAUSE : LIBXSVF_TAP_IDLE,
|
|
state_runtest, state_retries);
|
|
if (num-- <= 0)
|
|
break;
|
|
int carry = 1;
|
|
for (i=state_dr_size-1; i>=0; i--) {
|
|
if (getbit(buf_addr_mask, i) == 0)
|
|
continue;
|
|
if (getbit(buf_tdi_data, i)) {
|
|
setbit(buf_tdi_data, i, !carry);
|
|
} else {
|
|
setbit(buf_tdi_data, i, carry);
|
|
carry = 0;
|
|
}
|
|
}
|
|
unsigned char this_byte = 0;
|
|
for (i=0, j=0; i<state_data_size; i++) {
|
|
if (i%8 == 0)
|
|
this_byte = READ_BYTE();
|
|
while (getbit(buf_data_mask, j) == 0)
|
|
j++;
|
|
setbit(buf_tdi_data, j++, getbit(&this_byte, i%8));
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case XSDRB: {
|
|
STATUS(XSDRB);
|
|
READ_BITS(buf_tdi_data, state_dr_size);
|
|
SHIFT_DATA(buf_tdi_data, (void*)0, (void*)0, state_dr_size, LIBXSVF_TAP_DRSHIFT, LIBXSVF_TAP_DRSHIFT, 0, 0);
|
|
break;
|
|
}
|
|
case XSDRC: {
|
|
STATUS(XSDRC);
|
|
READ_BITS(buf_tdi_data, state_dr_size);
|
|
SHIFT_DATA(buf_tdi_data, (void*)0, (void*)0, state_dr_size, LIBXSVF_TAP_DRSHIFT, LIBXSVF_TAP_DRSHIFT, 0, 0);
|
|
break;
|
|
}
|
|
case XSDRE: {
|
|
STATUS(XSDRE);
|
|
READ_BITS(buf_tdi_data, state_dr_size);
|
|
SHIFT_DATA(buf_tdi_data, (void*)0, (void*)0, state_dr_size, LIBXSVF_TAP_DRSHIFT,
|
|
state_xenddr ? LIBXSVF_TAP_DRPAUSE : LIBXSVF_TAP_IDLE, 0, 0);
|
|
break;
|
|
}
|
|
case XSDRTDOB: {
|
|
STATUS(XSDRTDOB);
|
|
READ_BITS(buf_tdi_data, state_dr_size);
|
|
READ_BITS(buf_tdo_data, state_dr_size);
|
|
SHIFT_DATA(buf_tdi_data, buf_tdo_data, (void*)0, state_dr_size, LIBXSVF_TAP_DRSHIFT, LIBXSVF_TAP_DRSHIFT, 0, 0);
|
|
break;
|
|
}
|
|
case XSDRTDOC: {
|
|
STATUS(XSDRTDOC);
|
|
READ_BITS(buf_tdi_data, state_dr_size);
|
|
READ_BITS(buf_tdo_data, state_dr_size);
|
|
SHIFT_DATA(buf_tdi_data, buf_tdo_data, (void*)0, state_dr_size, LIBXSVF_TAP_DRSHIFT, LIBXSVF_TAP_DRSHIFT, 0, 0);
|
|
break;
|
|
}
|
|
case XSDRTDOE: {
|
|
STATUS(XSDRTDOE);
|
|
READ_BITS(buf_tdi_data, state_dr_size);
|
|
READ_BITS(buf_tdo_data, state_dr_size);
|
|
SHIFT_DATA(buf_tdi_data, buf_tdo_data, (void*)0, state_dr_size, LIBXSVF_TAP_DRSHIFT,
|
|
state_xenddr ? LIBXSVF_TAP_DRPAUSE : LIBXSVF_TAP_IDLE, 0, 0);
|
|
break;
|
|
}
|
|
case XSTATE: {
|
|
STATUS(XSTATE);
|
|
if (state_runtest && last_cmd == XRUNTEST) {
|
|
TAP(LIBXSVF_TAP_IDLE);
|
|
LIBXSVF_HOST_UDELAY(state_runtest, 0, state_runtest);
|
|
}
|
|
unsigned char state = READ_BYTE();
|
|
TAP(xilinx_tap(state));
|
|
break;
|
|
}
|
|
case XENDIR: {
|
|
STATUS(XENDIR);
|
|
state_xendir = READ_BYTE();
|
|
break;
|
|
}
|
|
case XENDDR: {
|
|
STATUS(XENDDR);
|
|
state_xenddr = READ_BYTE();
|
|
break;
|
|
}
|
|
case XSIR2: {
|
|
STATUS(XSIR2);
|
|
int length = READ_BYTE();
|
|
length = length << 8 | READ_BYTE();
|
|
unsigned char buf[bits2bytes(length)];
|
|
READ_BITS(buf, length);
|
|
SHIFT_DATA(buf, (void*)0, (void*)0, length, LIBXSVF_TAP_IRSHIFT,
|
|
state_xendir ? LIBXSVF_TAP_IRPAUSE : LIBXSVF_TAP_IDLE,
|
|
state_runtest, state_retries);
|
|
break;
|
|
}
|
|
case XCOMMENT: {
|
|
STATUS(XCOMMENT);
|
|
unsigned char this_byte;
|
|
do {
|
|
this_byte = READ_BYTE();
|
|
} while (this_byte);
|
|
break;
|
|
}
|
|
case XWAIT: {
|
|
STATUS(XWAIT);
|
|
unsigned char state1 = READ_BYTE();
|
|
unsigned char state2 = READ_BYTE();
|
|
long usecs = READ_LONG();
|
|
TAP(xilinx_tap(state1));
|
|
LIBXSVF_HOST_UDELAY(usecs, 0, 0);
|
|
TAP(xilinx_tap(state2));
|
|
break;
|
|
}
|
|
default:
|
|
LIBXSVF_HOST_REPORT_ERROR("Unknown XSVF command.");
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
error:
|
|
rc = -1;
|
|
|
|
got_complete_command:
|
|
if (LIBXSVF_HOST_SYNC() != 0 && rc >= 0 ) {
|
|
LIBXSVF_HOST_REPORT_ERROR("TDO mismatch.");
|
|
rc = -1;
|
|
}
|
|
|
|
LIBXSVF_HOST_REALLOC(buf_tdi_data, 0, LIBXSVF_MEM_XSVF_TDI_DATA);
|
|
LIBXSVF_HOST_REALLOC(buf_tdo_data, 0, LIBXSVF_MEM_XSVF_TDO_DATA);
|
|
LIBXSVF_HOST_REALLOC(buf_tdo_mask, 0, LIBXSVF_MEM_XSVF_TDO_MASK);
|
|
LIBXSVF_HOST_REALLOC(buf_addr_mask, 0, LIBXSVF_MEM_XSVF_ADDR_MASK);
|
|
LIBXSVF_HOST_REALLOC(buf_data_mask, 0, LIBXSVF_MEM_XSVF_DATA_MASK);
|
|
|
|
return rc;
|
|
}
|
|
|