#include "config.h"
#endif
-#include "jtag.h"
+#include <jtag/jtag.h>
#include "svf.h"
-#include "time_support.h"
+#include <helper/time_support.h>
// SVF command
"ABSENT"
};
-typedef struct
+struct svf_statemove
{
tap_state_t from;
tap_state_t to;
uint32_t num_of_moves;
tap_state_t paths[8];
-}svf_statemove_t;
+};
/*
* These paths are from the SVF specification for the STATE command, to be
* and many SVF implementations, we don't want to risk missing that state.
* To get to RESET, always we ignore the current state.
*/
-static const svf_statemove_t svf_statemoves[] =
+static const struct svf_statemove svf_statemoves[] =
{
// from to num_of_moves, paths[8]
// {TAP_RESET, TAP_RESET, 1, {TAP_RESET}},
#define XXR_TDO (1 << 1)
#define XXR_MASK (1 << 2)
#define XXR_SMASK (1 << 3)
-typedef struct
+struct svf_xxr_para
{
int len;
int data_mask;
uint8_t *tdo;
uint8_t *mask;
uint8_t *smask;
-}svf_xxr_para_t;
+};
-typedef struct
+struct svf_para
{
float frequency;
tap_state_t ir_end_state;
tap_state_t runtest_end_state;
trst_mode_t trst_mode;
- svf_xxr_para_t hir_para;
- svf_xxr_para_t hdr_para;
- svf_xxr_para_t tir_para;
- svf_xxr_para_t tdr_para;
- svf_xxr_para_t sir_para;
- svf_xxr_para_t sdr_para;
-}svf_para_t;
+ struct svf_xxr_para hir_para;
+ struct svf_xxr_para hdr_para;
+ struct svf_xxr_para tir_para;
+ struct svf_xxr_para tdr_para;
+ struct svf_xxr_para sir_para;
+ struct svf_xxr_para sdr_para;
+};
-static svf_para_t svf_para;
-static const svf_para_t svf_para_init =
+static struct svf_para svf_para;
+static const struct svf_para svf_para_init =
{
// frequency, ir_end_state, dr_end_state, runtest_run_state, runtest_end_state, trst_mode
0, TAP_IDLE, TAP_IDLE, TAP_IDLE, TAP_IDLE, TRST_Z,
{0, 0, NULL, NULL, NULL, NULL},
};
-typedef struct
+struct svf_check_tdo_para
{
int line_num; // used to record line number of the check operation
// so more information could be printed
int enabled; // check is enabled or not
int buffer_offset; // buffer_offset to buffers
int bit_len; // bit length to check
-}svf_check_tdo_para_t;
+};
#define SVF_CHECK_TDO_PARA_SIZE 1024
-static svf_check_tdo_para_t *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_read_command_from_file(int fd);
static int svf_check_tdo(void);
static int svf_add_check_para(uint8_t enabled, int buffer_offset, int bit_len);
-static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str);
+static int svf_run_command(struct command_context *cmd_ctx, char *cmd_str);
static int svf_fd = 0;
static char *svf_command_buffer = NULL;
static int svf_command_buffer_size = 0;
static int svf_line_number = 1;
-static struct jtag_tap *tap = NULL;
-
#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 int svf_buffer_index = 0, svf_buffer_size = 0;
static int svf_quiet = 0;
-static void svf_free_xxd_para(svf_xxr_para_t *para)
+static void svf_free_xxd_para(struct svf_xxr_para *para)
{
if (NULL != para)
{
int svf_add_statemove(tap_state_t state_to)
{
tap_state_t state_from = cmd_queue_cur_state;
- uint8_t index;
+ unsigned index_var;
/* when resetting, be paranoid and ignore current state */
if (state_to == TAP_RESET) {
return ERROR_OK;
}
- for (index = 0; index < DIM(svf_statemoves); index++)
+ for (index_var = 0; index_var < ARRAY_SIZE(svf_statemoves); index_var++)
{
- if ((svf_statemoves[index].from == state_from)
- && (svf_statemoves[index].to == state_to))
+ if ((svf_statemoves[index_var].from == state_from)
+ && (svf_statemoves[index_var].to == state_to))
{
/* recorded path includes current state ... avoid extra TCKs! */
- if (svf_statemoves[index].num_of_moves > 1)
- jtag_add_pathmove(svf_statemoves[index].num_of_moves - 1,
- svf_statemoves[index].paths + 1);
+ if (svf_statemoves[index_var].num_of_moves > 1)
+ jtag_add_pathmove(svf_statemoves[index_var].num_of_moves - 1,
+ svf_statemoves[index_var].paths + 1);
else
- jtag_add_pathmove(svf_statemoves[index].num_of_moves,
- svf_statemoves[index].paths);
+ jtag_add_pathmove(svf_statemoves[index_var].num_of_moves,
+ svf_statemoves[index_var].paths);
return ERROR_OK;
}
}
int ret = ERROR_OK;
long long time_ago;
- if ((argc < 1) || (argc > (1 + SVF_NUM_OF_OPTIONS)))
+ if ((CMD_ARGC < 1) || (CMD_ARGC > (1 + SVF_NUM_OF_OPTIONS)))
{
- command_print(cmd_ctx, "usage: svf <file> [quiet]");
+ command_print(CMD_CTX, "usage: svf <file> [quiet]");
return ERROR_FAIL;
}
// parse variant
svf_quiet = 0;
- for (unsigned i = 1; i < argc; i++)
+ for (unsigned i = 1; i < CMD_ARGC; i++)
{
- if (!strcmp(args[i], "quiet"))
+ if (!strcmp(CMD_ARGV[i], "quiet"))
{
svf_quiet = 1;
}
else
{
- LOG_ERROR("unknown variant for svf: %s", args[i]);
+ LOG_ERROR("unknown variant for svf: %s", CMD_ARGV[i]);
// no need to free anything now
return ERROR_FAIL;
}
}
- if ((svf_fd = open(args[0], O_RDONLY)) < 0)
+ if ((svf_fd = open(CMD_ARGV[0], O_RDONLY)) < 0)
{
- command_print(cmd_ctx, "file \"%s\" not found", args[0]);
+ command_print(CMD_CTX, "file \"%s\" not found", CMD_ARGV[0]);
// no need to free anything now
return ERROR_FAIL;
}
- LOG_USER("svf processing file: \"%s\"", args[0]);
+ LOG_USER("svf processing file: \"%s\"", CMD_ARGV[0]);
// get time
time_ago = timeval_ms();
svf_command_buffer_size = 0;
svf_check_tdo_para_index = 0;
- svf_check_tdo_para = malloc(sizeof(svf_check_tdo_para_t) * SVF_CHECK_TDO_PARA_SIZE);
+ svf_check_tdo_para = malloc(sizeof(struct svf_check_tdo_para) * SVF_CHECK_TDO_PARA_SIZE);
if (NULL == svf_check_tdo_para)
{
LOG_ERROR("not enough memory");
while (ERROR_OK == svf_read_command_from_file(svf_fd))
{
- 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);
ret = ERROR_FAIL;
}
// print time
- command_print(cmd_ctx, "%lld ms used", timeval_ms() - time_ago);
+ command_print(CMD_CTX, "%lld ms used", timeval_ms() - time_ago);
free_all:
if (ERROR_OK == ret)
{
- command_print(cmd_ctx, "svf file programmed successfully for %d commands", command_num);
+ command_print(CMD_CTX, "svf file programmed successfully for %d commands", command_num);
}
else
{
- command_print(cmd_ctx, "svf file programmed failed");
+ command_print(CMD_CTX, "svf file programmed failed");
}
return ret;
#define SVFP_CMD_INC_CNT 1024
static int svf_read_command_from_file(int fd)
{
- char ch, *tmp_buffer = NULL;
+ unsigned char ch;
+ char *tmp_buffer = NULL;
int cmd_pos = 0, cmd_ok = 0, slash = 0, comment = 0;
while (!cmd_ok && (read(fd, &ch, 1) > 0))
case '\r':
slash = 0;
comment = 0;
- break;
+ /* Don't save '\r' and '\n' if no data is parsed */
+ if (!cmd_pos)
+ break;
default:
if (!comment)
{
- if (cmd_pos >= svf_command_buffer_size - 1)
+ /* The parsing code currently expects a space
+ * before parentheses -- "TDI (123)". Also a
+ * space afterwards -- "TDI (123) TDO(456)".
+ * But such spaces are optional... instead of
+ * parser updates, cope with that by adding the
+ * spaces as needed.
+ *
+ * Ensure there are 3 bytes available, for:
+ * - current character
+ * - added space.
+ * - terminating NUL ('\0')
+ */
+ if ((cmd_pos + 2) >= svf_command_buffer_size)
{
- tmp_buffer = (char*)malloc(svf_command_buffer_size + SVFP_CMD_INC_CNT); // 1 more byte for '\0'
+ /* REVISIT use realloc(); simpler */
+ tmp_buffer = malloc(
+ svf_command_buffer_size
+ + SVFP_CMD_INC_CNT);
if (NULL == tmp_buffer)
{
LOG_ERROR("not enough memory");
return ERROR_FAIL;
}
if (svf_command_buffer_size > 0)
- {
- memcpy(tmp_buffer, svf_command_buffer, svf_command_buffer_size);
- }
+ 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 '(' */
+ if ('(' == ch)
+ svf_command_buffer[cmd_pos++] = ' ';
+
svf_command_buffer[cmd_pos++] = (char)toupper(ch);
+
+ /* insert a space after ')' */
+ if (')' == ch)
+ svf_command_buffer[cmd_pos++] = ' ';
}
break;
}
static int svf_parse_cmd_string(char *str, int len, char **argus, int *num_of_argu)
{
- int pos = 0, num = 0, space_found = 1;
+ int pos = 0, num = 0, space_found = 1, in_bracket = 0;
while (pos < len)
{
switch (str[pos])
{
- case '\n':
- case '\r':
case '!':
case '/':
LOG_ERROR("fail to parse svf command");
return ERROR_FAIL;
- break;
- case ' ':
- space_found = 1;
- str[pos] = '\0';
- break;
+ case '(':
+ in_bracket = 1;
+ goto parse_char;
+ case ')':
+ in_bracket = 0;
+ goto parse_char;
default:
- if (space_found)
+parse_char:
+ if (!in_bracket && isspace((int) str[pos]))
+ {
+ space_found = 1;
+ str[pos] = '\0';
+ }
+ else if (space_found)
{
argus[num++] = &str[pos];
space_found = 0;
return ERROR_FAIL;
}
+ /* fill from LSB (end of str) to MSB (beginning of str) */
for (i = 0; i < str_hbyte_len; i++)
{
ch = 0;
{
ch = str[--str_len];
- if (!isblank(ch))
+ /* Skip whitespace. The SVF specification (rev E) is
+ * deficient in terms of basic lexical issues like
+ * where whitespace is allowed. Long bitstrings may
+ * require line ends for correctness, since there is
+ * a hard limit on line length.
+ */
+ if (!isspace(ch))
{
if ((ch >= '0') && (ch <= '9'))
{
}
}
- // consume optional leading '0' characters
- while (str_len > 0 && str[str_len - 1] == '0')
+ /* consume optional leading '0' MSBs or whitespace */
+ while (str_len > 0 && ((str[str_len - 1] == '0')
+ || isspace((int) str[str_len - 1])))
str_len--;
- // check valid
+ /* check validity: we must have consumed everything */
if (str_len > 0 || (ch & ~((2 << ((bit_len - 1) % 4)) - 1)) != 0)
{
LOG_ERROR("value execeeds length");
static int svf_check_tdo(void)
{
- int i, len, index;
+ int i, len, index_var;
for (i = 0; i < svf_check_tdo_para_index; i++)
{
- index = svf_check_tdo_para[i].buffer_offset;
+ index_var = svf_check_tdo_para[i].buffer_offset;
len = svf_check_tdo_para[i].bit_len;
if ((svf_check_tdo_para[i].enabled)
- && buf_cmp_mask(&svf_tdi_buffer[index], &svf_tdo_buffer[index], &svf_mask_buffer[index], len))
+ && buf_cmp_mask(&svf_tdi_buffer[index_var], &svf_tdo_buffer[index_var], &svf_mask_buffer[index_var], len))
{
unsigned bitmask;
unsigned received, expected, tapmask;
bitmask = svf_get_mask_u32(svf_check_tdo_para[i].bit_len);
- memcpy(&received, svf_tdi_buffer + index, sizeof(unsigned));
- memcpy(&expected, svf_tdo_buffer + index, sizeof(unsigned));
- memcpy(&tapmask, svf_mask_buffer + index, sizeof(unsigned));
+ memcpy(&received, svf_tdi_buffer + index_var, sizeof(unsigned));
+ memcpy(&expected, svf_tdo_buffer + index_var, sizeof(unsigned));
+ memcpy(&tapmask, svf_mask_buffer + index_var, sizeof(unsigned));
LOG_ERROR("tdo check error at line %d",
svf_check_tdo_para[i].line_num);
LOG_ERROR("read = 0x%X, want = 0x%X, mask = 0x%X",
return ERROR_OK;
}
-static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str)
+static int svf_run_command(struct command_context *cmd_ctx, char *cmd_str)
{
char *argus[256], command;
int num_of_argu = 0, i;
int run_count;
float min_time, max_time;
// for XXR
- svf_xxr_para_t *xxr_para_tmp;
+ struct svf_xxr_para *xxr_para_tmp;
uint8_t **pbuffer_tmp;
struct scan_field field;
// for STATE
*/
command = svf_find_string_in_array(argus[0],
- (char **)svf_command_name, DIM(svf_command_name));
+ (char **)svf_command_name, ARRAY_SIZE(svf_command_name));
switch (command)
{
case ENDDR:
// TODO: set jtag speed to
if (svf_para.frequency > 0)
{
- command_run_linef(cmd_ctx, "jtag_khz %d", (int)svf_para.frequency / 1000);
+ command_run_linef(cmd_ctx, "adapter_khz %d", (int)svf_para.frequency / 1000);
LOG_DEBUG("\tfrequency = %f", svf_para.frequency);
}
}
{
svf_add_check_para(0, svf_buffer_index, i);
}
- field.tap = tap;
field.num_bits = i;
field.out_value = &svf_tdi_buffer[svf_buffer_index];
field.in_value = &svf_tdi_buffer[svf_buffer_index];
/* NOTE: doesn't use SVF-specified state paths */
- jtag_add_plain_dr_scan(1, &field, svf_para.dr_end_state);
+ jtag_add_plain_dr_scan(field.num_bits, field.out_value, field.in_value, svf_para.dr_end_state);
svf_buffer_index += (i + 7) >> 3;
}
{
svf_add_check_para(0, svf_buffer_index, i);
}
- field.tap = tap;
field.num_bits = i;
field.out_value = &svf_tdi_buffer[svf_buffer_index];
field.in_value = &svf_tdi_buffer[svf_buffer_index];
/* NOTE: doesn't use SVF-specified state paths */
- jtag_add_plain_ir_scan(1, &field, svf_para.ir_end_state);
+ jtag_add_plain_ir_scan(field.num_bits, field.out_value, field.in_value,
+ svf_para.ir_end_state);
svf_buffer_index += (i + 7) >> 3;
}
return ERROR_FAIL;
}
}
- // no need to keep this memory, in jtag_add_pathmove, path will be duplicated
- if (NULL != path)
- {
- free(path);
- path = NULL;
- }
+
+ free(path);
+ path = NULL;
}
else
{
}
i_tmp = svf_find_string_in_array(argus[1],
(char **)svf_trst_mode_name,
- DIM(svf_trst_mode_name));
+ ARRAY_SIZE(svf_trst_mode_name));
switch (i_tmp)
{
case TRST_ON:
return ERROR_OK;
}
-int svf_register_commands(struct command_context_s *cmd_ctx)
-{
- register_command(cmd_ctx, NULL, "svf",
- &handle_svf_command, COMMAND_EXEC,
- "run svf <file>");
+static const struct command_registration svf_command_handlers[] = {
+ {
+ .name = "svf",
+ .handler = handle_svf_command,
+ .mode = COMMAND_EXEC,
+ .help = "Runs a SVF file.",
+ .usage = "filename ['quiet']",
+ },
+ COMMAND_REGISTRATION_DONE
+};
- return ERROR_OK;
+int svf_register_commands(struct command_context *cmd_ctx)
+{
+ return register_commands(cmd_ctx, NULL, svf_command_handlers);
}