svf: various improvements

* added support for targeting particular tap
* improved file reading
* improved command line parsing
* added progress meter
* more readable time measurement output
This commit is contained in:
Andrew Leech 2010-12-07 08:05:56 +11:00 committed by Øyvind Harboe
parent 6ef4e97779
commit 5cd931ed1c
1 changed files with 294 additions and 80 deletions

View File

@ -206,21 +206,33 @@ struct svf_check_tdo_para
static struct svf_check_tdo_para *svf_check_tdo_para = NULL; static struct svf_check_tdo_para *svf_check_tdo_para = NULL;
static int svf_check_tdo_para_index = 0; static int svf_check_tdo_para_index = 0;
static int svf_read_command_from_file(int fd); static int svf_read_command_from_file(FILE * fd);
static int svf_check_tdo(void); static int svf_check_tdo(void);
static int svf_add_check_para(uint8_t enabled, int buffer_offset, int bit_len); static int svf_add_check_para(uint8_t enabled, int buffer_offset, int bit_len);
static int svf_run_command(struct command_context *cmd_ctx, char *cmd_str); static int svf_run_command(struct command_context *cmd_ctx, char *cmd_str);
static int svf_fd = 0; static FILE * svf_fd = NULL;
static char * svf_read_line = NULL;
static size_t svf_read_line_size = 0;
static char *svf_command_buffer = NULL; static char *svf_command_buffer = NULL;
static int svf_command_buffer_size = 0; static size_t svf_command_buffer_size = 0;
static int svf_line_number = 1; static int svf_line_number = 1;
static int svf_getline (char **lineptr, size_t *n, FILE *stream);
#define SVF_MAX_BUFFER_SIZE_TO_COMMIT (4 * 1024) #define SVF_MAX_BUFFER_SIZE_TO_COMMIT (4 * 1024)
static uint8_t *svf_tdi_buffer = NULL, *svf_tdo_buffer = NULL, *svf_mask_buffer = NULL; static uint8_t *svf_tdi_buffer = NULL, *svf_tdo_buffer = NULL, *svf_mask_buffer = NULL;
static int svf_buffer_index = 0, svf_buffer_size = 0; static int svf_buffer_index = 0, svf_buffer_size = 0;
static int svf_quiet = 0; static int svf_quiet = 0;
// Targetting particular tap
static int svf_tap_is_specified = 0;
static int svf_set_padding(struct svf_xxr_para *para, int len, unsigned char tdi);
// Progress Indicator
static int svf_progress_enabled = 0;
static long svf_total_lines = 0;
static int svf_percentage = 0;
static int svf_last_printed_percentage = -1;
static void svf_free_xxd_para(struct svf_xxr_para *para) static void svf_free_xxd_para(struct svf_xxr_para *para)
{ {
@ -301,46 +313,71 @@ int svf_add_statemove(tap_state_t state_to)
COMMAND_HANDLER(handle_svf_command) COMMAND_HANDLER(handle_svf_command)
{ {
#define SVF_NUM_OF_OPTIONS 1 #define SVF_MIN_NUM_OF_OPTIONS 1
#define SVF_MAX_NUM_OF_OPTIONS 5
#define USAGE [-tap device.tap] <file> [quiet] [progress]
#define PRINT_USAGE command_print(CMD_CTX, "svf USAGE")
int command_num = 0; int command_num = 0;
int ret = ERROR_OK; int ret = ERROR_OK;
long long time_ago; long long time_measure_ms;
int time_measure_s, time_measure_m;
if ((CMD_ARGC < 1) || (CMD_ARGC > (1 + SVF_NUM_OF_OPTIONS))) /* use NULL to indicate a "plain" svf file which accounts for
any additional devices in the scan chain, otherwise the device
that should be affected
*/
struct jtag_tap *tap = NULL;
if ((CMD_ARGC < SVF_MIN_NUM_OF_OPTIONS) || (CMD_ARGC > SVF_MAX_NUM_OF_OPTIONS))
{ {
command_print(CMD_CTX, "usage: svf <file> [quiet]"); PRINT_USAGE;
return ERROR_FAIL; return ERROR_FAIL;
} }
// parse variant // parse command line
svf_quiet = 0; svf_quiet = 0;
for (unsigned i = 1; i < CMD_ARGC; i++) for (unsigned int i = 0; i < CMD_ARGC; i++)
{ {
if (!strcmp(CMD_ARGV[i], "quiet")) if (strcmp(CMD_ARGV[i], "-tap") == 0)
{
tap = jtag_tap_by_string(CMD_ARGV[i+1]);
if (!tap)
{
command_print(CMD_CTX, "Tap: %s unknown", CMD_ARGV[i+1]);
return ERROR_FAIL;
}
i++;
}
else if ((strcmp(CMD_ARGV[i], "quiet") == 0) || (strcmp(CMD_ARGV[i], "-quiet") == 0))
{ {
svf_quiet = 1; svf_quiet = 1;
} }
else if ((strcmp(CMD_ARGV[i], "progress") == 0) || (strcmp(CMD_ARGV[i], "-progress") == 0))
{
svf_progress_enabled = 1;
}
else if ((svf_fd = fopen(CMD_ARGV[i], "r")) == NULL)
{
int err = errno;
PRINT_USAGE;
command_print(CMD_CTX, "open(\"%s\"): %s", CMD_ARGV[i], strerror(err));
// no need to free anything now
return ERROR_FAIL;
}
else else
{ {
LOG_ERROR("unknown variant for svf: %s", CMD_ARGV[i]); LOG_USER("svf processing file: \"%s\"", CMD_ARGV[i]);
// no need to free anything now
return ERROR_FAIL;
} }
} }
if ((svf_fd = open(CMD_ARGV[0], O_RDONLY)) < 0) if (svf_fd == NULL)
{ {
command_print(CMD_CTX, "file \"%s\" not found", CMD_ARGV[0]); PRINT_USAGE;
// no need to free anything now
return ERROR_FAIL; return ERROR_FAIL;
} }
LOG_USER("svf processing file: \"%s\"", CMD_ARGV[0]);
// get time // get time
time_ago = timeval_ms(); time_measure_ms = timeval_ms();
// init // init
svf_line_number = 1; svf_line_number = 1;
@ -388,8 +425,97 @@ COMMAND_HANDLER(handle_svf_command)
// TAP_RESET // TAP_RESET
jtag_add_tlr(); jtag_add_tlr();
if (tap)
{
/* Tap is specified, set header/trailer paddings */
int header_ir_len = 0, header_dr_len = 0, trailer_ir_len = 0, trailer_dr_len = 0;
struct jtag_tap *check_tap;
svf_tap_is_specified = 1;
for (check_tap = jtag_all_taps(); check_tap; check_tap = check_tap->next_tap) {
if (check_tap->abs_chain_position < tap->abs_chain_position)
{
//Header
header_ir_len += check_tap->ir_length;
header_dr_len ++;
}
else if (check_tap->abs_chain_position > tap->abs_chain_position)
{
//Trailer
trailer_ir_len += check_tap->ir_length;
trailer_dr_len ++;
}
}
// HDR %d TDI (0)
if (ERROR_OK != svf_set_padding(&svf_para.hdr_para, header_dr_len, 0))
{
LOG_ERROR("failed to set data header");
return ERROR_FAIL;
}
// HIR %d TDI (0xFF)
if (ERROR_OK != svf_set_padding(&svf_para.hir_para, header_ir_len, 0xFF))
{
LOG_ERROR("failed to set instruction header");
return ERROR_FAIL;
}
// TDR %d TDI (0)
if (ERROR_OK != svf_set_padding(&svf_para.tdr_para, trailer_dr_len, 0))
{
LOG_ERROR("failed to set data trailer");
return ERROR_FAIL;
}
// TIR %d TDI (0xFF)
if (ERROR_OK != svf_set_padding(&svf_para.tir_para, trailer_ir_len, 0xFF))
{
LOG_ERROR("failed to set instruction trailer");
return ERROR_FAIL;
}
}
if (svf_progress_enabled)
{
// Count total lines in file.
while ( ! feof (svf_fd) )
{
svf_getline (&svf_command_buffer, &svf_command_buffer_size, svf_fd);
svf_total_lines++;
}
rewind(svf_fd);
}
while (ERROR_OK == svf_read_command_from_file(svf_fd)) while (ERROR_OK == svf_read_command_from_file(svf_fd))
{ {
// Log Output
if (svf_quiet)
{
if (svf_progress_enabled)
{
svf_percentage = ((svf_line_number * 20) / svf_total_lines) * 5;
if (svf_last_printed_percentage != svf_percentage)
{
LOG_USER_N("\r%d%% ", svf_percentage);
svf_last_printed_percentage = svf_percentage;
}
}
}
else
{
if (svf_progress_enabled)
{
svf_percentage = ((svf_line_number * 20) / svf_total_lines) * 5;
LOG_USER_N("%3d%% %s", svf_percentage, svf_read_line);
}
else
{
LOG_USER_N("%s",svf_read_line);
}
}
// Run Command
if (ERROR_OK != svf_run_command(CMD_CTX, svf_command_buffer)) if (ERROR_OK != svf_run_command(CMD_CTX, svf_command_buffer))
{ {
LOG_ERROR("fail to run command at line %d", svf_line_number); LOG_ERROR("fail to run command at line %d", svf_line_number);
@ -408,11 +534,19 @@ COMMAND_HANDLER(handle_svf_command)
} }
// print time // print time
command_print(CMD_CTX, "%lld ms used", timeval_ms() - time_ago); time_measure_ms = timeval_ms() - time_measure_ms;
time_measure_s = time_measure_ms / 1000;
time_measure_ms %= 1000;
time_measure_m = time_measure_s / 60;
time_measure_s %= 60;
if (time_measure_ms < 1000)
{
command_print(CMD_CTX, "\r\nTime used: %dm%ds%lldms ", time_measure_m, time_measure_s, time_measure_ms);
}
free_all: free_all:
close(svf_fd); fclose(svf_fd);
svf_fd = 0; svf_fd = 0;
// free buffers // free buffers
@ -465,36 +599,92 @@ free_all:
return ret; return ret;
} }
static int svf_getline (char **lineptr, size_t *n, FILE *stream)
{
#define MIN_CHUNK 16 //Buffer is increased by this size each time as required
size_t i = 0;
if (*lineptr == NULL)
{
*n = MIN_CHUNK;
*lineptr = (char *)malloc (*n);
if (!*lineptr)
{
return -1;
}
}
(*lineptr)[0] = fgetc(stream);
while ((*lineptr)[i] != '\n')
{
(*lineptr)[++i] = fgetc(stream);
if (feof(stream))
{
(*lineptr)[0] = 0;
return -1;
}
if ((i + 2) > *n)
{
*n += MIN_CHUNK;
*lineptr = realloc(*lineptr, *n);
}
}
(*lineptr)[++i] = 0;
return sizeof(*lineptr);
}
#define SVFP_CMD_INC_CNT 1024 #define SVFP_CMD_INC_CNT 1024
static int svf_read_command_from_file(int fd) static int svf_read_command_from_file(FILE * fd)
{ {
unsigned char ch; unsigned char ch;
char *tmp_buffer = NULL; int i = 0;
int cmd_pos = 0, cmd_ok = 0, slash = 0, comment = 0; size_t cmd_pos = 0;
int cmd_ok = 0, slash = 0, comment = 0;
while (!cmd_ok && (read(fd, &ch, 1) > 0)) if (svf_getline (&svf_read_line, &svf_read_line_size, svf_fd) <= 0)
{
return ERROR_FAIL;
}
svf_line_number++;
ch = svf_read_line[0];
while (!cmd_ok && (ch != 0))
{ {
switch (ch) switch (ch)
{ {
case '!': case '!':
slash = 0; slash = 0;
comment = 1; if (svf_getline (&svf_read_line, &svf_read_line_size, svf_fd) <= 0)
{
return ERROR_FAIL;
}
svf_line_number++;
i = -1;
break; break;
case '/': case '/':
if (++slash == 2) if (++slash == 2)
{ {
comment = 1; slash = 0;
if (svf_getline (&svf_read_line, &svf_read_line_size, svf_fd) <= 0)
{
return ERROR_FAIL;
}
svf_line_number++;
i = -1;
} }
break; break;
case ';': case ';':
slash = 0; slash = 0;
if (!comment)
{
cmd_ok = 1; cmd_ok = 1;
}
break; break;
case '\n': case '\n':
svf_line_number++; svf_line_number++;
if (svf_getline (&svf_read_line, &svf_read_line_size, svf_fd) <= 0)
{
return ERROR_FAIL;
}
i = -1;
case '\r': case '\r':
slash = 0; slash = 0;
comment = 0; comment = 0;
@ -502,8 +692,6 @@ static int svf_read_command_from_file(int fd)
if (!cmd_pos) if (!cmd_pos)
break; break;
default: default:
if (!comment)
{
/* The parsing code currently expects a space /* The parsing code currently expects a space
* before parentheses -- "TDI (123)". Also a * before parentheses -- "TDI (123)". Also a
* space afterwards -- "TDI (123) TDO(456)". * space afterwards -- "TDI (123) TDO(456)".
@ -518,24 +706,12 @@ static int svf_read_command_from_file(int fd)
*/ */
if ((cmd_pos + 2) >= svf_command_buffer_size) if ((cmd_pos + 2) >= svf_command_buffer_size)
{ {
/* REVISIT use realloc(); simpler */ svf_command_buffer = realloc(svf_command_buffer, (cmd_pos + 2));
tmp_buffer = malloc( if (svf_command_buffer == NULL)
svf_command_buffer_size
+ SVFP_CMD_INC_CNT);
if (NULL == tmp_buffer)
{ {
LOG_ERROR("not enough memory"); LOG_ERROR("not enough memory");
return ERROR_FAIL; return ERROR_FAIL;
} }
if (svf_command_buffer_size > 0)
memcpy(tmp_buffer,
svf_command_buffer,
svf_command_buffer_size);
if (svf_command_buffer != NULL)
free(svf_command_buffer);
svf_command_buffer = tmp_buffer;
svf_command_buffer_size += SVFP_CMD_INC_CNT;
tmp_buffer = NULL;
} }
/* insert a space before '(' */ /* insert a space before '(' */
@ -547,9 +723,9 @@ static int svf_read_command_from_file(int fd)
/* insert a space after ')' */ /* insert a space after ')' */
if (')' == ch) if (')' == ch)
svf_command_buffer[cmd_pos++] = ' '; svf_command_buffer[cmd_pos++] = ' ';
}
break; break;
} }
ch = svf_read_line[++i];
} }
if (cmd_ok) if (cmd_ok)
@ -645,6 +821,19 @@ static int svf_adjust_array_length(uint8_t **arr, int orig_bit_len, int new_bit_
return ERROR_OK; return ERROR_OK;
} }
static int svf_set_padding(struct svf_xxr_para *para, int len, unsigned char tdi)
{
int error = ERROR_OK;
error |= svf_adjust_array_length(&para->tdi, para->len, len);
memset(para->tdi, tdi, (len + 7) >> 3);
error |= svf_adjust_array_length(&para->tdo, para->len, len);
error |= svf_adjust_array_length(&para->mask, para->len, len);
para->len = len;
para->data_mask = XXR_TDI;
return error;
}
static int svf_copy_hexstring_to_binary(char *str, uint8_t **bin, int orig_bit_len, int bit_len) static int svf_copy_hexstring_to_binary(char *str, uint8_t **bin, int orig_bit_len, int bit_len)
{ {
int i, str_len = strlen(str), str_hbyte_len = (bit_len + 3) >> 2; int i, str_len = strlen(str), str_hbyte_len = (bit_len + 3) >> 2;
@ -803,11 +992,8 @@ static int svf_run_command(struct command_context *cmd_ctx, char *cmd_str)
struct scan_field field; struct scan_field field;
// for STATE // for STATE
tap_state_t *path = NULL, state; tap_state_t *path = NULL, state;
// flag padding commands skipped due to -tap command
if (!svf_quiet) int padding_command_skipped = 0;
{
LOG_USER("%s", svf_command_buffer);
}
if (ERROR_OK != svf_parse_cmd_string(cmd_str, strlen(cmd_str), argus, &num_of_argu)) if (ERROR_OK != svf_parse_cmd_string(cmd_str, strlen(cmd_str), argus, &num_of_argu))
{ {
@ -886,15 +1072,35 @@ static int svf_run_command(struct command_context *cmd_ctx, char *cmd_str)
} }
break; break;
case HDR: case HDR:
if (svf_tap_is_specified)
{
padding_command_skipped = 1;
break;
}
xxr_para_tmp = &svf_para.hdr_para; xxr_para_tmp = &svf_para.hdr_para;
goto XXR_common; goto XXR_common;
case HIR: case HIR:
if (svf_tap_is_specified)
{
padding_command_skipped = 1;
break;
}
xxr_para_tmp = &svf_para.hir_para; xxr_para_tmp = &svf_para.hir_para;
goto XXR_common; goto XXR_common;
case TDR: case TDR:
if (svf_tap_is_specified)
{
padding_command_skipped = 1;
break;
}
xxr_para_tmp = &svf_para.tdr_para; xxr_para_tmp = &svf_para.tdr_para;
goto XXR_common; goto XXR_common;
case TIR: case TIR:
if (svf_tap_is_specified)
{
padding_command_skipped = 1;
break;
}
xxr_para_tmp = &svf_para.tir_para; xxr_para_tmp = &svf_para.tir_para;
goto XXR_common; goto XXR_common;
case SDR: case SDR:
@ -1454,6 +1660,14 @@ static int svf_run_command(struct command_context *cmd_ctx, char *cmd_str)
break; break;
} }
if (!svf_quiet)
{
if (padding_command_skipped)
{
LOG_USER("(Above Padding command skipped, as per -tap argument)");
}
}
if (debug_level >= LOG_LVL_DEBUG) if (debug_level >= LOG_LVL_DEBUG)
{ {
// for convenient debugging, execute tap if possible // for convenient debugging, execute tap if possible
@ -1498,7 +1712,7 @@ static const struct command_registration svf_command_handlers[] = {
.handler = handle_svf_command, .handler = handle_svf_command,
.mode = COMMAND_EXEC, .mode = COMMAND_EXEC,
.help = "Runs a SVF file.", .help = "Runs a SVF file.",
.usage = "filename ['quiet']", .usage = "USAGE",
}, },
COMMAND_REGISTRATION_DONE COMMAND_REGISTRATION_DONE
}; };