diff options
Diffstat (limited to 'fpga/xilinx/programmer/dependencies/libxsvf/svf.c')
| -rw-r--r-- | fpga/xilinx/programmer/dependencies/libxsvf/svf.c | 657 | 
1 files changed, 657 insertions, 0 deletions
| diff --git a/fpga/xilinx/programmer/dependencies/libxsvf/svf.c b/fpga/xilinx/programmer/dependencies/libxsvf/svf.c new file mode 100644 index 0000000..0ba13f4 --- /dev/null +++ b/fpga/xilinx/programmer/dependencies/libxsvf/svf.c @@ -0,0 +1,657 @@ +/* + *  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" + +static int read_command(struct libxsvf_host *h, char **buffer_p, int *len_p) +{ +	char *buffer = *buffer_p; +	int braket_mode = 0; +	int len = *len_p; +	int p = 0; + +	while (1) +	{ +		if (len < p+10) { +			len = len < 64 ? 96 : len*2; +			buffer = LIBXSVF_HOST_REALLOC(buffer, len, LIBXSVF_MEM_SVF_COMMANDBUF); +			*buffer_p = buffer; +			*len_p = len; +			if (!buffer) { +				LIBXSVF_HOST_REPORT_ERROR("Allocating memory failed."); +				return -1; +			} +		} +		buffer[p] = 0; + +		int ch = LIBXSVF_HOST_GETBYTE(); +		if (ch < 0) { +handle_eof: +			if (p == 0) +				return 0; +			LIBXSVF_HOST_REPORT_ERROR("Unexpected EOF."); +			return -1; +		} +		if (ch <= ' ') { +insert_eol: +			if (!braket_mode && p > 0 && buffer[p-1] != ' ') +				buffer[p++] = ' '; +			continue; +		} +		if (ch == '!') { +skip_to_eol: +			while (1) { +				ch = LIBXSVF_HOST_GETBYTE(); +				if (ch < 0) +					goto handle_eof; +				if (ch < ' ' && ch != '\t') +					goto insert_eol; +			} +		} +		if (ch == '/' && p > 0 && buffer[p-1] == '/') { +			p--; +			goto skip_to_eol; +		} +		if (ch == ';') +			break; +		if (ch == '(') { +			if (!braket_mode && p > 0 && buffer[p-1] != ' ') +				buffer[p++] = ' '; +			braket_mode++; +		} +		if (ch >= 'a' && ch <= 'z') +			buffer[p++] = ch - ('a' - 'A'); +		else +			buffer[p++] = ch; +		if (ch == ')') { +			braket_mode--; +			if (!braket_mode) +				buffer[p++] = ' '; +		} +	} +	return 1; +} + +static int strtokencmp(const char *str1, const char *str2) +{ +	int i = 0; +	while (1) { +		if ((str1[i] == ' ' || str1[i] == 0) && (str2[i] == ' ' || str2[i] == 0)) +			return 0; +		if (str1[i] < str2[i]) +			return -1; +		if (str1[i] > str2[i]) +			return +1; +		i++; +	} +} + +static int strtokenskip(const char *str1) +{ +	int i = 0; +	while (str1[i] != 0 && str1[i] != ' ') i++; +	while (str1[i] == ' ') i++; +	return i; +} + +static int token2tapstate(const char *str1) +{ +#define X(_t) if (!strtokencmp(str1, #_t)) return LIBXSVF_TAP_ ## _t; +	X(RESET) +	X(IDLE) +	X(DRSELECT) +	X(DRCAPTURE) +	X(DRSHIFT) +	X(DREXIT1) +	X(DRPAUSE) +	X(DREXIT2) +	X(DRUPDATE) +	X(IRSELECT) +	X(IRCAPTURE) +	X(IRSHIFT) +	X(IREXIT1) +	X(IRPAUSE) +	X(IREXIT2) +	X(IRUPDATE) +#undef X +	return -1; +} + +struct bitdata_s { +	int len, alloced_len; +	int alloced_bytes; +	unsigned char *tdi_data; +	unsigned char *tdi_mask; +	unsigned char *tdo_data; +	unsigned char *tdo_mask; +	unsigned char *ret_mask; +	int has_tdo_data; +}; + +static void bitdata_free(struct libxsvf_host *h, struct bitdata_s *bd, int offset) +{ +	LIBXSVF_HOST_REALLOC(bd->tdi_data, 0, offset+0); +	LIBXSVF_HOST_REALLOC(bd->tdi_mask, 0, offset+1); +	LIBXSVF_HOST_REALLOC(bd->tdo_data, 0, offset+2); +	LIBXSVF_HOST_REALLOC(bd->tdo_mask, 0, offset+3); +	LIBXSVF_HOST_REALLOC(bd->ret_mask, 0, offset+4); + +	bd->tdi_data = (void*)0; +	bd->tdi_mask = (void*)0; +	bd->tdo_data = (void*)0; +	bd->tdo_mask = (void*)0; +	bd->ret_mask = (void*)0; +} + +static int hex(char ch) +{ +	if (ch >= 'A' && ch <= 'Z') +		return (ch - 'A') + 10; +	if (ch >= '0' && ch <= '9') +		return ch - '0'; +	return 0; +} + +static const char *bitdata_parse(struct libxsvf_host *h, const char *p, struct bitdata_s *bd, int offset) +{ +	int i, j; +	bd->len = 0; +	bd->has_tdo_data = 0; +	while (*p >= '0' && *p <= '9') { +		bd->len = bd->len * 10 + (*p - '0'); +		p++; +	} +	while (*p == ' ') { +		p++; +	} +	if (bd->len != bd->alloced_len) { +		bitdata_free(h, bd, offset); +		bd->alloced_len = bd->len; +		bd->alloced_bytes = (bd->len+7) / 8; +	} +	while (*p) +	{ +		int memnum = 0; +		unsigned char **dp = (void*)0; +		if (!strtokencmp(p, "TDI")) { +			p += strtokenskip(p); +			dp = &bd->tdi_data; +			memnum = 0; +		} +		if (!strtokencmp(p, "TDO")) { +			p += strtokenskip(p); +			dp = &bd->tdo_data; +			bd->has_tdo_data = 1; +			memnum = 1; +		} +		if (!strtokencmp(p, "SMASK")) { +			p += strtokenskip(p); +			dp = &bd->tdi_mask; +			memnum = 2; +		} +		if (!strtokencmp(p, "MASK")) { +			p += strtokenskip(p); +			dp = &bd->tdo_mask; +			memnum = 3; +		} +		if (!strtokencmp(p, "RMASK")) { +			p += strtokenskip(p); +			dp = &bd->ret_mask; +			memnum = 4; +		} +		if (!dp) +			return (void*)0; +		if (*dp == (void*)0) { +			*dp = LIBXSVF_HOST_REALLOC(*dp, bd->alloced_bytes, offset+memnum); +		} +		if (*dp == (void*)0) { +			LIBXSVF_HOST_REPORT_ERROR("Allocating memory failed."); +			return (void*)0; +		} + +		unsigned char *d = *dp; +		for (i=0; i<bd->alloced_bytes; i++) +			d[i] = 0; + +		if (*p != '(') +			return (void*)0; +		p++; + +		int hexdigits = 0; +		for (i=0; (p[i] >= 'A' && p[i] <= 'F') || (p[i] >= '0' && p[i] <= '9'); i++) +			hexdigits++; + +		i = bd->alloced_bytes*2 - hexdigits; +		for (j=0; j<hexdigits; j++, i++, p++) { +			if (i%2 == 0) { +				d[i/2] |= hex(*p) << 4; +			} else { +				d[i/2] |= hex(*p); +			} +		} + +		if (*p != ')') +			return (void*)0; +		p++; +		while (*p == ' ') { +			p++; +		} +	} +#if 0 +	/* Debugging Output, needs <stdio.h> */ +	printf("--- Parsed bitdata [%d] ---\n", bd->len); +	if (bd->tdi_data) { +		printf("TDI DATA:"); +		for (i=0; i<bd->alloced_bytes; i++) +			printf(" %02x", bd->tdi_data[i]); +		printf("\n"); +	} +	if (bd->tdo_data && has_tdo_data) { +		printf("TDO DATA:"); +		for (i=0; i<bd->alloced_bytes; i++) +			printf(" %02x", bd->tdo_data[i]); +		printf("\n"); +	} +	if (bd->tdi_mask) { +		printf("TDI MASK:"); +		for (i=0; i<bd->alloced_bytes; i++) +			printf(" %02x", bd->tdi_mask[i]); +		printf("\n"); +	} +	if (bd->tdo_mask) { +		printf("TDO MASK:"); +		for (i=0; i<bd->alloced_bytes; i++) +			printf(" %02x", bd->tdo_mask[i]); +		printf("\n"); +	} +#endif +	return p; +} + +static int getbit(unsigned char *data, int n) +{ +	return (data[n/8] & (1 << (7 - n%8))) ? 1 : 0; +} + +static int bitdata_play(struct libxsvf_host *h, struct bitdata_s *bd, enum libxsvf_tap_state estate) +{ +	int left_padding = (8 - bd->len % 8) % 8; +	int tdo_error = 0; +	int tms = 0; +	int i; + +	for (i=bd->len+left_padding-1; i >= left_padding; i--) { +		if (i == left_padding && h->tap_state != estate) { +			h->tap_state++; +			tms = 1; +		} +		int tdi = -1; +		if (bd->tdi_data) { +			if (!bd->tdi_mask || getbit(bd->tdi_mask, i)) +				tdi = getbit(bd->tdi_data, i); +		} +		int tdo = -1; +		if (bd->tdo_data && bd->has_tdo_data && (!bd->tdo_mask || getbit(bd->tdo_mask, i))) +			tdo = getbit(bd->tdo_data, i); +		int rmask = bd->ret_mask && getbit(bd->ret_mask, i); +		if (LIBXSVF_HOST_PULSE_TCK(tms, tdi, tdo, rmask, 0) < 0) +			tdo_error = 1; +	} + +	if (tms) +		LIBXSVF_HOST_REPORT_TAPSTATE(); + +	if (!tdo_error) +		return 0; + +	LIBXSVF_HOST_REPORT_ERROR("TDO mismatch."); +	return -1; +} + +int libxsvf_svf(struct libxsvf_host *h) +{ +	char *command_buffer = (void*)0; +	int command_buffer_len = 0; +	int rc, i; + +	struct bitdata_s bd_hdr = { 0, 0, 0, (void*)0, (void*)0, (void*)0, (void*)0, (void*)0 }; +	struct bitdata_s bd_hir = { 0, 0, 0, (void*)0, (void*)0, (void*)0, (void*)0, (void*)0 }; +	struct bitdata_s bd_tdr = { 0, 0, 0, (void*)0, (void*)0, (void*)0, (void*)0, (void*)0 }; +	struct bitdata_s bd_tir = { 0, 0, 0, (void*)0, (void*)0, (void*)0, (void*)0, (void*)0 }; +	struct bitdata_s bd_sdr = { 0, 0, 0, (void*)0, (void*)0, (void*)0, (void*)0, (void*)0 }; +	struct bitdata_s bd_sir = { 0, 0, 0, (void*)0, (void*)0, (void*)0, (void*)0, (void*)0 }; + +	int state_endir = LIBXSVF_TAP_IDLE; +	int state_enddr = LIBXSVF_TAP_IDLE; +	int state_run = LIBXSVF_TAP_IDLE; +	int state_endrun = LIBXSVF_TAP_IDLE; + +	while (1) +	{ +		rc = read_command(h, &command_buffer, &command_buffer_len); + +		if (rc <= 0) +			break; + +		const char *p = command_buffer; + +		LIBXSVF_HOST_REPORT_STATUS(command_buffer); + +		if (!strtokencmp(p, "ENDIR")) { +			p += strtokenskip(p); +			state_endir = token2tapstate(p); +			if (state_endir < 0) +				goto syntax_error; +			p += strtokenskip(p); +			goto eol_check; +		} + +		if (!strtokencmp(p, "ENDDR")) { +			p += strtokenskip(p); +			state_enddr = token2tapstate(p); +			if (state_endir < 0) +				goto syntax_error; +			p += strtokenskip(p); +			goto eol_check; +		} + +		if (!strtokencmp(p, "FREQUENCY")) { +			unsigned long number = 0; +			int exp = 0; +			p += strtokenskip(p); +			if (*p < '0' || *p > '9') +				goto syntax_error; +			while (*p >= '0' && *p <= '9') { +				number = number*10 + (*p - '0'); +				p++; +			} +			if(*p == 'E' || *p == 'e') { +				p++; +				while (*p >= '0' && *p <= '9') { +					exp = exp*10 + (*p - '0'); +					p++; +				} +				for(i=0; i<exp; i++) +					number *= 10; +			} +			while (*p == ' ') { +				p++; +			} +			p += strtokenskip(p); +			if (LIBXSVF_HOST_SET_FREQUENCY(number) < 0) { +				LIBXSVF_HOST_REPORT_ERROR("FREQUENCY command failed!"); +				goto error; +			} +			goto eol_check; +		} + +		if (!strtokencmp(p, "HDR")) { +			p += strtokenskip(p); +			p = bitdata_parse(h, p, &bd_hdr, LIBXSVF_MEM_SVF_HDR_TDI_DATA); +			if (!p) +				goto syntax_error; +			goto eol_check; +		} + +		if (!strtokencmp(p, "HIR")) { +			p += strtokenskip(p); +			p = bitdata_parse(h, p, &bd_hir, LIBXSVF_MEM_SVF_HIR_TDI_DATA); +			if (!p) +				goto syntax_error; +			goto eol_check; +		} + +		if (!strtokencmp(p, "PIO") || !strtokencmp(p, "PIOMAP")) { +			goto unsupported_error; +		} + +		if (!strtokencmp(p, "RUNTEST")) { +			p += strtokenskip(p); +			int tck_count = -1; +			int sck_count = -1; +			int min_time = -1; +			int max_time = -1; +			while (*p) { +				int got_maximum = 0; +				if (!strtokencmp(p, "MAXIMUM")) { +					p += strtokenskip(p); +					got_maximum = 1; +				} +				int got_endstate = 0; +				if (!strtokencmp(p, "ENDSTATE")) { +					p += strtokenskip(p); +					got_endstate = 1; +				} +				int st = token2tapstate(p); +				if (st >= 0) { +					p += strtokenskip(p); +					if (got_endstate) +						state_endrun = st; +					else +						state_run = st; +					continue; +				} +				if (*p < '0' || *p > '9') +					goto syntax_error; +				int number = 0; +				int exp = 0, expsign = 1; +				int number_e6, exp_e6; +				while (*p >= '0' && *p <= '9') { +					number = number*10 + (*p - '0'); +					p++; +				} +				if(*p == 'E' || *p == 'e') { +					p++; +					if(*p == '-') { +						expsign = -1; +						p++; +					} +					while (*p >= '0' && *p <= '9') { +						exp = exp*10 + (*p - '0'); +						p++; +					} +					exp = exp * expsign; +					number_e6 = number; +					exp_e6 = exp + 6; +					while (exp < 0) { +						number /= 10; +						exp++; +					} +					while (exp > 0) { +						number *= 10; +						exp--; +					} +					while (exp_e6 < 0) { +						number_e6 /= 10; +						exp_e6++; +					} +					while (exp_e6 > 0) { +						number_e6 *= 10; +						exp_e6--; +					} +				} else { +					number_e6 = number * 1000000; +				} +				while (*p == ' ') { +					p++; +				} +				if (!strtokencmp(p, "SEC")) { +					p += strtokenskip(p); +					if (got_maximum) +						max_time = number_e6; +					else +						min_time = number_e6; +					continue; +				} +				if (!strtokencmp(p, "TCK")) { +					p += strtokenskip(p); +					tck_count = number; +					continue; +				} +				if (!strtokencmp(p, "SCK")) { +					p += strtokenskip(p); +					sck_count = number; +					continue; +				} +				goto syntax_error; +			} +			if (libxsvf_tap_walk(h, state_run) < 0) +				goto error; +			if (max_time >= 0) { +				LIBXSVF_HOST_REPORT_ERROR("WARNING: Maximum time in SVF RUNTEST command is ignored."); +			} +			if (sck_count >= 0) { +				for (i=0; i < sck_count; i++) { +					LIBXSVF_HOST_PULSE_SCK(); +				} +			} +			if (min_time >= 0 || tck_count >= 0) { +				LIBXSVF_HOST_UDELAY(min_time >= 0 ? min_time : 0, 0, tck_count >= 0 ? tck_count : 0); +			} +			if (libxsvf_tap_walk(h, state_endrun) < 0) +				goto error; +			goto eol_check; +		} + +		if (!strtokencmp(p, "SDR")) { +			p += strtokenskip(p); +			p = bitdata_parse(h, p, &bd_sdr, LIBXSVF_MEM_SVF_SDR_TDI_DATA); +			if (!p) +				goto syntax_error; +			if (libxsvf_tap_walk(h, LIBXSVF_TAP_DRSHIFT) < 0) +				goto error; +			if (bitdata_play(h, &bd_hdr, bd_sdr.len+bd_tdr.len > 0 ? LIBXSVF_TAP_DRSHIFT : state_enddr) < 0) +				goto error; +			if (bitdata_play(h, &bd_sdr, bd_tdr.len > 0 ? LIBXSVF_TAP_DRSHIFT : state_enddr) < 0) +				goto error; +			if (bitdata_play(h, &bd_tdr, state_enddr) < 0) +				goto error; +			if (libxsvf_tap_walk(h, state_enddr) < 0) +				goto error; +			goto eol_check; +		} + +		if (!strtokencmp(p, "SIR")) { +			p += strtokenskip(p); +			p = bitdata_parse(h, p, &bd_sir, LIBXSVF_MEM_SVF_SIR_TDI_DATA); +			if (!p) +				goto syntax_error; +			if (libxsvf_tap_walk(h, LIBXSVF_TAP_IRSHIFT) < 0) +				goto error; +			if (bitdata_play(h, &bd_hir, bd_sir.len+bd_tir.len > 0 ? LIBXSVF_TAP_IRSHIFT : state_endir) < 0) +				goto error; +			if (bitdata_play(h, &bd_sir, bd_tir.len > 0 ? LIBXSVF_TAP_IRSHIFT : state_endir) < 0) +				goto error; +			if (bitdata_play(h, &bd_tir, state_endir) < 0) +				goto error; +			if (libxsvf_tap_walk(h, state_endir) < 0) +				goto error; +			goto eol_check; +		} + +		if (!strtokencmp(p, "STATE")) { +			p += strtokenskip(p); +			while (*p) { +				int st = token2tapstate(p); +				if (st < 0) +					goto syntax_error; +				if (libxsvf_tap_walk(h, st) < 0) +					goto error; +				p += strtokenskip(p); +			} +			goto eol_check; +		} + +		if (!strtokencmp(p, "TDR")) { +			p += strtokenskip(p); +			p = bitdata_parse(h, p, &bd_tdr, LIBXSVF_MEM_SVF_TDR_TDI_DATA); +			if (!p) +				goto syntax_error; +			goto eol_check; +		} + +		if (!strtokencmp(p, "TIR")) { +			p += strtokenskip(p); +			p = bitdata_parse(h, p, &bd_tir, LIBXSVF_MEM_SVF_TIR_TDI_DATA); +			if (!p) +				goto syntax_error; +			goto eol_check; +		} + +		if (!strtokencmp(p, "TRST")) { +			p += strtokenskip(p); +			if (!strtokencmp(p, "ON")) { +				p += strtokenskip(p); +				LIBXSVF_HOST_SET_TRST(1); +				goto eol_check; +			} +			if (!strtokencmp(p, "OFF")) { +				p += strtokenskip(p); +				LIBXSVF_HOST_SET_TRST(0); +				goto eol_check; +			} +			if (!strtokencmp(p, "Z")) { +				p += strtokenskip(p); +				LIBXSVF_HOST_SET_TRST(-1); +				goto eol_check; +			} +			if (!strtokencmp(p, "ABSENT")) { +				p += strtokenskip(p); +				LIBXSVF_HOST_SET_TRST(-2); +				goto eol_check; +			} +			goto syntax_error; +		} + +eol_check: +		while (*p == ' ') +			p++; +		if (*p == 0) +			continue; + +syntax_error: +		LIBXSVF_HOST_REPORT_ERROR("SVF Syntax Error:"); +		if (0) { +unsupported_error: +			LIBXSVF_HOST_REPORT_ERROR("Error in SVF input: unsupported command:"); +		} +		LIBXSVF_HOST_REPORT_ERROR(command_buffer); +error: +		rc = -1; +		break; +	} + +	if (LIBXSVF_HOST_SYNC() != 0 && rc >= 0 ) { +		LIBXSVF_HOST_REPORT_ERROR("TDO mismatch."); +		rc = -1; +	} + +	bitdata_free(h, &bd_hdr, LIBXSVF_MEM_SVF_HDR_TDI_DATA); +	bitdata_free(h, &bd_hir, LIBXSVF_MEM_SVF_HIR_TDI_DATA); +	bitdata_free(h, &bd_tdr, LIBXSVF_MEM_SVF_TDR_TDI_DATA); +	bitdata_free(h, &bd_tir, LIBXSVF_MEM_SVF_TIR_TDI_DATA); +	bitdata_free(h, &bd_sdr, LIBXSVF_MEM_SVF_SDR_TDI_DATA); +	bitdata_free(h, &bd_sir, LIBXSVF_MEM_SVF_SIR_TDI_DATA); + +	LIBXSVF_HOST_REALLOC(command_buffer, 0, LIBXSVF_MEM_SVF_COMMANDBUF); + +	return rc; +} + | 
