/* * JTAG Core library * Copyright (c) 2008 - 2024 Viveris Technologies * * JTAG Core library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * JTAG Core library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with JTAG Core library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file script.c * @brief Script engine. * @author Jean-François DEL NERO */ #include #include #include #include #define MAX_PATH 256 #include "script.h" #include "jtag_core/jtag_core.h" #include "config/version.h" #include "bsdl_parser/bsdl_loader.h" #include "os_interface/os_interface.h" #include "fpga/fpga.h" #include "bscan_spi/bscan_spi.h" #include "spi_flash/spi_flash.h" #include "env.h" static int dummy_script_printf(script_ctx *ctx, enum MSGTYPE typ, char *string, ...) { return 0; } static int is_end_line(char c) { if (c == 0 || c == '#' || c == '\r' || c == '\n') { return 1; } else { return 0; } } static int is_space(char c) { if (c == ' ' || c == '\t') { return 1; } else { return 0; } } static int is_label(char *command) { int i; i = 0; while (command[i]) { i++; } if (i > 1) { if (command[i - 1] == ':') return 1; } return 0; } static int is_variable(char *command) { if (strlen(command) > 1) { if (command[0] == '$' && command[1] && (command[1] != ' ' || command[1] != '\t')) return 1; else return 0; } return 0; } static int get_next_word(char *line, int offset) { while (!is_end_line(line[offset]) && (line[offset] == ' ' || line[offset] == '\t')) { offset++; } return offset; } static int copy_param(char *dest, char *line, int offs) { int i, insidequote; i = 0; insidequote = 0; while (!is_end_line(line[offs]) && (insidequote || !is_space(line[offs])) && (i < (DEFAULT_BUFLEN - 1))) { if (line[offs] != '"') { if (dest) dest[i] = line[offs]; i++; } else { if (insidequote) insidequote = 0; else insidequote = 1; } offs++; } if (dest) dest[i] = 0; return offs; } static int get_param_offset(char *line, int param) { int param_cnt, offs; offs = 0; offs = get_next_word(line, offs); if (param) { param_cnt = 0; do { offs = copy_param(NULL, line, offs); offs = get_next_word(line, offs); if (line[offs] == 0 || line[offs] == '#' || line[offs] == '\r' || line[offs] == '\n') return -1; param_cnt++; } while (param_cnt < param); } return offs; } static int get_param(script_ctx *ctx, char *line, int param_offset, char *param) { int offs; char var_str[DEFAULT_BUFLEN]; offs = get_param_offset(line, param_offset); if (offs >= 0) { if (line[offs] != '$') { offs = copy_param(param, line, offs); } else { copy_param(var_str, line, offs); if (!strcmp(var_str, "$LASTDATA")) { sprintf(param, "0x" LONGHEXSTR, ctx->last_data_value); return 1; } if (!strcmp(var_str, "$LASTFLAGS")) { sprintf(param, "0x%X", ctx->last_flags); return 1; } if (!strcmp(var_str, "$LASTERROR")) { sprintf(param, "%d", ctx->last_error_code); return 1; } if (!getEnvVarDat((envvar_entry *)ctx->env, (char *)&var_str[1], param, DEFAULT_BUFLEN)) { copy_param(param, line, offs); } } return 1; } return -1; } static int get_param_str(script_ctx *ctx, char *line, int param_offset, char *param) { int offs; offs = get_param_offset(line, param_offset); if (offs >= 0) { offs = copy_param(param, line, offs); return 1; } return -1; } env_var_value strbin_to_val(char *str) { int l; env_var_value val; env_var_value mask; val = 0; // -> end of the string l = 0; while (str[l]) { l++; } // -> find the lowest bit while (l) { if (str[l] == '1' || str[l] == '0') { break; } l--; }; mask = 0x1; // convert while (l >= 0) { if (str[l] != '1' && str[l] != '0') { break; } if (str[l] == '1') { val |= mask; } mask <<= 1; l--; } return val; } static env_var_value str_to_int(char *str) { env_var_value value; value = 0; if (str) { if (strlen(str) > 2) { if (str[0] == '0') { switch (str[1]) { // hex case 'x': case 'X': value = (env_var_value)STRTOVALUE(str, NULL, 0); break; // binary case 'b': case 'B': value = strbin_to_val(str); break; // decimal default: value = atoi(str); break; } } else { value = atoi(str); } } else { value = atoi(str); } } return value; } static env_var_value get_script_variable(script_ctx *ctx, char *varname) { env_var_value value; if (!strcmp(varname, "$LASTDATA")) { return ctx->last_data_value; } if (!strcmp(varname, "$LASTFLAGS")) { return ctx->last_flags; } if (!strcmp(varname, "$LASTERROR")) { return (env_var_value)(ctx->last_error_code); } if (varname[0] == '$') value = getEnvVarValue((envvar_entry *)ctx->env, (char *)&varname[1]); else value = str_to_int((char *)varname); return value; } static void set_script_variable(script_ctx *ctx, char *varname, env_var_value value) { char tmp_str[64]; if (!strcmp(varname, "$LASTDATA")) { ctx->last_data_value = value; return; } if (!strcmp(varname, "$LASTFLAGS")) { ctx->last_flags = value; return; } if (!strcmp(varname, "$LASTERROR")) { ctx->last_error_code = value; return; } if (varname[0] == '$' && varname[1]) { sprintf(tmp_str, "0x" LONGHEXSTR, value); setEnvVarDat((envvar_entry *)ctx->env, (char *)&varname[1], tmp_str); return; } } script_ctx *init_script(void *app_ctx, unsigned int flags, void *env) { script_ctx *ctx; ctx = malloc(sizeof(script_ctx)); if (ctx) { memset(ctx, 0, sizeof(script_ctx)); ctx->env = env; setOutputFunc_script(ctx, dummy_script_printf); ctx->app_ctx = (void *)app_ctx; ctx->cur_label_index = 0; ctx->cmdlist = (void *)script_commands_list; ctx->script_file = NULL; } return ctx; } static int extract_cmd(script_ctx *ctx, char *line, char *command) { int offs, i; i = 0; offs = 0; offs = get_next_word(line, offs); if (!is_end_line(line[offs])) { while (!is_end_line(line[offs]) && !is_space(line[offs]) && i < (DEFAULT_BUFLEN - 1)) { command[i] = line[offs]; offs++; i++; } command[i] = 0; return i; } return 0; } static int exec_cmd(script_ctx *ctx, char *command, char *line) { int i; cmd_list *cmdlist; cmdlist = (cmd_list *)ctx->cmdlist; i = 0; while (cmdlist[i].func) { if (!strcmp(cmdlist[i].command, command)) { return cmdlist[i].func(ctx, line); } i++; } return JTAG_CORE_CMD_NOT_FOUND; } static int add_label(script_ctx *ctx, char *label) { int i, j; char tmp_label[MAX_LABEL_SIZE]; if (ctx->cur_label_index < MAX_LABEL) { i = 0; while (i < (MAX_LABEL_SIZE - 1) && label[i] && label[i] != ':') { tmp_label[i] = label[i]; i++; } tmp_label[i] = 0; i = 0; while (i < ctx->cur_label_index) { if (!strcmp(tmp_label, ctx->labels[i].label_name)) { break; } i++; } j = i; i = 0; while (i < (MAX_LABEL_SIZE - 1) && label[i]) { ctx->labels[j].label_name[i] = tmp_label[i]; i++; } ctx->labels[j].label_name[i] = 0; ctx->labels[j].offset = ctx->cur_script_offset; if (ctx->cur_label_index == j) { ctx->cur_label_index++; } } return 0; } static int goto_label(script_ctx *ctx, char *label) { int i; char tmp_label[MAX_LABEL_SIZE]; i = 0; while (i < (MAX_LABEL_SIZE - 1) && label[i] && label[i] != ':') { tmp_label[i] = label[i]; i++; } tmp_label[i] = 0; i = 0; while (i < ctx->cur_label_index) { if (!strcmp(tmp_label, ctx->labels[i].label_name)) { break; } i++; } if (i != ctx->cur_label_index) { ctx->cur_script_offset = ctx->labels[i].offset; if (ctx->script_file) fseek(ctx->script_file, ctx->cur_script_offset, SEEK_SET); return JTAG_CORE_NO_ERROR; } else { ctx->script_printf(ctx, MSG_ERROR, "Label %s not found\n", tmp_label); return JTAG_CORE_NOT_FOUND; } } /////////////////////////////////////////////////////////////////////////////// static int alu_operations(script_ctx *ctx, char *line) { int i; int valid; env_var_value data_value; env_var_value value_1, value_2; char params_str[5][DEFAULT_BUFLEN]; for (i = 0; i < 5; i++) { params_str[i][0] = 0; } valid = 0; for (i = 0; i < 5; i++) { get_param_str(ctx, line, i, (char *)¶ms_str[i]); if (strlen((char *)¶ms_str[i])) valid++; } data_value = 0; if (((valid == 3) || (valid == 5)) && params_str[1][0] == '=' && params_str[0][0] == '$') { value_1 = get_script_variable(ctx, params_str[2]); if (valid == 5) { value_2 = get_script_variable(ctx, params_str[4]); if (!strcmp(params_str[3], "+")) data_value = value_1 + value_2; if (!strcmp(params_str[3], "-")) data_value = value_1 - value_2; if (!strcmp(params_str[3], "*")) data_value = value_1 * value_2; if (!strcmp(params_str[3], "/") && value_2) data_value = value_1 / value_2; if (!strcmp(params_str[3], "&")) data_value = value_1 & value_2; if (!strcmp(params_str[3], "^")) data_value = value_1 ^ value_2; if (!strcmp(params_str[3], "|")) data_value = value_1 | value_2; if (!strcmp(params_str[3], ">>")) data_value = value_1 >> value_2; if (!strcmp(params_str[3], "<<")) data_value = value_1 << value_2; } else { data_value = value_1; } if (data_value) ctx->last_flags = 1; else ctx->last_flags = 0; set_script_variable(ctx, (char *)¶ms_str[0], data_value); return JTAG_CORE_NO_ERROR; } return JTAG_CORE_BAD_PARAMETER; } void setOutputFunc_script(script_ctx *ctx, SCRIPT_PRINTF_FUNC ext_printf) { ctx->script_printf = ext_printf; return; } int execute_line_script(script_ctx *ctx, char *line) { char command[DEFAULT_BUFLEN]; command[0] = 0; if (extract_cmd(ctx, line, command)) { if (strlen(command)) { if (!is_label(command)) { if (!ctx->dry_run) { if (!is_variable(command)) { ctx->last_error_code = exec_cmd(ctx, command, line); if (ctx->last_error_code == JTAG_CORE_CMD_NOT_FOUND) { ctx->script_printf(ctx, MSG_ERROR, "Command not found ! : %s\n", line); return ctx->last_error_code; } } else { ctx->last_error_code = alu_operations(ctx, line); } } else ctx->last_error_code = JTAG_CORE_NO_ERROR; } else { add_label(ctx, command); ctx->last_error_code = JTAG_CORE_NO_ERROR; } return ctx->last_error_code; } } ctx->last_error_code = JTAG_CORE_BAD_CMD; return ctx->last_error_code; } int execute_file_script(script_ctx *ctx, char *filename) { int err; char line[DEFAULT_BUFLEN]; err = JTAG_CORE_INTERNAL_ERROR; ctx->script_file = fopen(filename, "r"); if (ctx->script_file) { strncpy(ctx->script_file_path, filename, DEFAULT_BUFLEN - 1); ctx->script_file_path[DEFAULT_BUFLEN - 1] = 0; // Dry run -> populate the labels... ctx->dry_run++; do { if (!fgets(line, sizeof(line), ctx->script_file)) break; ctx->cur_script_offset = ftell(ctx->script_file); if (feof(ctx->script_file)) break; execute_line_script(ctx, line); } while (1); fseek(ctx->script_file, 0, SEEK_SET); ctx->cur_script_offset = ftell(ctx->script_file); ctx->dry_run--; if (!ctx->dry_run) { if (strlen(ctx->pre_command)) { err = execute_line_script(ctx, ctx->pre_command); if (err != JTAG_CORE_NO_ERROR) { fclose(ctx->script_file); return err; } } do { if (!fgets(line, sizeof(line), ctx->script_file)) break; ctx->cur_script_offset = ftell(ctx->script_file); if (feof(ctx->script_file)) break; err = execute_line_script(ctx, line); } while (1); } fclose(ctx->script_file); err = JTAG_CORE_NO_ERROR; } else { ctx->script_printf(ctx, MSG_ERROR, "Can't open %s !", filename); ctx->script_file_path[0] = 0; err = JTAG_CORE_ACCESS_ERROR; } return err; } int execute_ram_script(script_ctx *ctx, unsigned char *script_buffer, int buffersize) { int err = 0; int buffer_offset, line_offset; char line[DEFAULT_BUFLEN]; int cont; ctx->dry_run++; cont = 1; while (cont) { buffer_offset = 0; line_offset = 0; ctx->cur_script_offset = 0; do { memset(line, 0, DEFAULT_BUFLEN); line_offset = 0; while ((buffer_offset < buffersize) && script_buffer[buffer_offset] && script_buffer[buffer_offset] != '\n' && script_buffer[buffer_offset] != '\r' && (line_offset < DEFAULT_BUFLEN - 1)) { line[line_offset++] = script_buffer[buffer_offset++]; } while ((buffer_offset < buffersize) && script_buffer[buffer_offset] && (script_buffer[buffer_offset] == '\n' || script_buffer[buffer_offset] == '\r')) { buffer_offset++; } ctx->cur_script_offset = buffer_offset; execute_line_script(ctx, line); buffer_offset = ctx->cur_script_offset; if ((buffer_offset >= buffersize) || !script_buffer[buffer_offset]) break; } while (buffer_offset < buffersize); if (!ctx->dry_run || (ctx->dry_run > 1)) { cont = 0; } else { ctx->dry_run = 0; if (strlen(ctx->pre_command)) execute_line_script(ctx, ctx->pre_command); } } return err; } script_ctx *deinit_script(script_ctx *ctx) { if (ctx) { free(ctx); } ctx = NULL; return ctx; } /////////////////////////////////////////////////////////////////////////////// ///////////////////// Generic commands/operations ///////////////////////////// /////////////////////////////////////////////////////////////////////////////// const char *cmd_goto_help[] = { "", // Arguments "1(type) ..." "explanations line one", // Explanations "explanations line two", "" }; static int cmd_goto(script_ctx *ctx, char *line) { int i; char label_str[DEFAULT_BUFLEN]; i = get_param(ctx, line, 1, label_str); if (i >= 0) { return goto_label(ctx, label_str); } return JTAG_CORE_BAD_PARAMETER; } const char *cmd_if_help[] = { "", // Arguments "1(type) ..." "explanations line one", // Explanations "explanations line two", "" }; static int cmd_if(script_ctx *ctx, char *line) { //"if" command example : // if $VARIABLE > 0x2222 then goto label int i; int eval; int ret; int valid; char params_str[5][DEFAULT_BUFLEN]; env_var_value value_1, value_2, tmp_val; int op_offset; ret = JTAG_CORE_BAD_PARAMETER; eval = 0; for (i = 0; i < 5; i++) { params_str[i][0] = 0; } valid = 0; for (i = 0; i < 5; i++) { get_param(ctx, line, i, (char *)¶ms_str[i]); if (strlen((char *)¶ms_str[i])) valid++; } i = 0; while (i < 5 && strcmp((char *)¶ms_str[i], "then")) { i++; } if (i < 5) { if (i == 2) { value_1 = get_script_variable(ctx, params_str[1]); if (value_1) eval = 1; ret = JTAG_CORE_NO_ERROR; } if (i == 4) { value_1 = get_script_variable(ctx, params_str[1]); value_2 = get_script_variable(ctx, params_str[3]); if (!strcmp((char *)¶ms_str[2], ">=") && ((signed_env_var_value)value_1 >= (signed_env_var_value)value_2)) eval = 1; if (!strcmp((char *)¶ms_str[2], "<=") && ((signed_env_var_value)value_1 <= (signed_env_var_value)value_2)) eval = 1; if (!strcmp((char *)¶ms_str[2], ">") && ((signed_env_var_value)value_1 > (signed_env_var_value)value_2)) eval = 1; if (!strcmp((char *)¶ms_str[2], "<") && ((signed_env_var_value)value_1 < (signed_env_var_value)value_2)) eval = 1; if (!strcmp((char *)¶ms_str[2], "==") && (value_1 == value_2)) eval = 1; if (!strcmp((char *)¶ms_str[2], "!=") && (value_1 != value_2)) eval = 1; if (!strcmp((char *)¶ms_str[2], "&") && (value_1 & value_2)) eval = 1; if (!strcmp((char *)¶ms_str[2], "^") && (value_1 ^ value_2)) eval = 1; if (!strcmp((char *)¶ms_str[2], "|") && (value_1 | value_2)) eval = 1; tmp_val = value_1 >> value_2; if (!strcmp((char *)¶ms_str[2], ">>") && tmp_val) eval = 1; tmp_val = value_1 << value_2; if (!strcmp((char *)¶ms_str[2], "<<") && tmp_val) eval = 1; ret = JTAG_CORE_NO_ERROR; } if (eval) { op_offset = get_param_offset(line, i + 1); if (op_offset >= 0) { ret = execute_line_script(ctx, (char *)&line[op_offset]); } } return ret; } return JTAG_CORE_BAD_PARAMETER; } const char *cmd_return_help[] = { "", // Arguments "1(type) ..." "explanations line one", // Explanations "explanations line two", "" }; static int cmd_return(script_ctx *ctx, char *line) { if (ctx->script_file) { fseek(ctx->script_file, 0, SEEK_END); } return JTAG_CORE_NO_ERROR; } const char *cmd_system_help[] = { "", // Arguments "1(type) ..." "explanations line one", // Explanations "explanations line two", "" }; static int cmd_system(script_ctx *ctx, char *line) { int offs; int ret; offs = get_param_offset(line, 1); if (offs >= 0) { ret = system(&line[offs]); if (ret != 1) return JTAG_CORE_NO_ERROR; else return JTAG_CORE_NOT_FOUND; } return JTAG_CORE_BAD_PARAMETER; } const char *cmd_print_env_var_help[] = { "", // Arguments "1(type) ..." "explanations line one", // Explanations "explanations line two", "" }; static int cmd_print_env_var(script_ctx *ctx, char *line) { int i; char varname[DEFAULT_BUFLEN]; char varvalue[DEFAULT_BUFLEN]; char *ptr; i = get_param(ctx, line, 1, varname); if (i >= 0) { ptr = getEnvVarDat((envvar_entry *)ctx->env, (char *)&varname, (char *)&varvalue, sizeof(varvalue)); if (ptr) { ctx->script_printf(ctx, MSG_INFO_1, "%s = %s", varname, varvalue); return JTAG_CORE_NO_ERROR; } return JTAG_CORE_NOT_FOUND; } else { return JTAG_CORE_BAD_PARAMETER; } } const char *cmd_version_help[] = { "", "prints the version of the tool.", ""}; static int cmd_version(script_ctx *ctx, char *line) { ctx->script_printf(ctx, MSG_INFO_0, "%s, Date : "__DATE__ " "__TIME__ "\n", APP_VER_STR_LONG(APP_VER)); return JTAG_CORE_NO_ERROR; } const char *cmd_print_help[] = { "(string)", "sends to standard output.", ""}; static int cmd_print(script_ctx *ctx, char *line) { int i, j, s; char tmp_str[DEFAULT_BUFLEN]; char str[DEFAULT_BUFLEN * 2]; char *ptr; str[0] = '\0'; j = 1; do { ptr = NULL; i = get_param_offset(line, j); s = 0; if (i >= 0) { tmp_str[0] = '\0'; get_param(ctx, line, j, (char *)&tmp_str); s = strlen(tmp_str); if (s) { if (tmp_str[0] != '$') { genos_strndstcat((char *)str, tmp_str, sizeof(str)); genos_strndstcat((char *)str, " ", sizeof(str)); str[sizeof(str) - 1] = '\0'; } else { ptr = getEnvVarDat((envvar_entry *)ctx->env, &tmp_str[1], NULL, 0); if (ptr) { genos_strndstcat((char *)str, ptr, sizeof(str)); genos_strndstcat((char *)str, " ", sizeof(str)); } else { genos_strndstcat((char *)str, tmp_str, sizeof(str)); genos_strndstcat((char *)str, " ", sizeof(str)); } str[sizeof(str) - 1] = '\0'; } } } j++; } while (s); ctx->script_printf(ctx, MSG_NONE, "%s\n", str); return JTAG_CORE_NO_ERROR; } const char *cmd_pause_help[] = { "(int)", "pauses the program for ms.", ""}; static int cmd_pause(script_ctx *ctx, char *line) { int i; char delay_str[DEFAULT_BUFLEN]; i = get_param(ctx, line, 1, delay_str); if (i >= 0) { genos_pause(str_to_int(delay_str)); return JTAG_CORE_NO_ERROR; } ctx->script_printf(ctx, MSG_ERROR, "Bad/Missing parameter(s) ! : %s\n", line); return JTAG_CORE_BAD_PARAMETER; } const char *cmd_help_help[] = { "(string)", "if no args, it prints the list of commands,", "otherwise the help of the .", ""}; static int cmd_help(script_ctx *ctx, char *line) { int i; int j; int not_found = 1; char hcmd[DEFAULT_BUFLEN]; cmd_list *cmdlist; cmdlist = (cmd_list *)ctx->cmdlist; i = get_param(ctx, line, 1, hcmd); if (i >= 0) { i = 0; while (cmdlist[i].func) { if (0 == strcmp(hcmd, cmdlist[i].command)) { not_found = 0; ctx->script_printf(ctx, MSG_NONE, "Documentation of command '%s' :\n", cmdlist[i].command); ctx->script_printf(ctx, MSG_NONE, "---------------------------------------------------\n"); // help[0] is the parameter list ("" when the command takes // none); description lines follow, terminated by "". if (cmdlist[i].help[0][0]) { ctx->script_printf(ctx, MSG_NONE, "Parameters :\n"); ctx->script_printf(ctx, MSG_NONE, " %s\n", cmdlist[i].help[0]); } j = 1; if (strcmp(cmdlist[i].help[j], "")) { ctx->script_printf(ctx, MSG_NONE, "Description :\n"); while (strcmp(cmdlist[i].help[j], "")) { ctx->script_printf(ctx, MSG_NONE, " %s\n", cmdlist[i].help[j]); j++; } } break; } i++; } if (not_found) { ctx->script_printf(ctx, MSG_ERROR, "Command '%s' not found :\n\n", hcmd); } } else { ctx->script_printf(ctx, MSG_INFO_0, "Supported Commands :\n\n"); i = 0; while (cmdlist[i].func) { ctx->script_printf(ctx, MSG_NONE, "%s\n", cmdlist[i].command); i++; } } return JTAG_CORE_NO_ERROR; } const char *cmd_call_help[] = { "(string)", "Executes a script located at .", "" }; static int cmd_call(script_ctx *ctx, char *line) { int offs; char path[DEFAULT_BUFLEN]; char function[DEFAULT_BUFLEN]; script_ctx *new_ctx; int ret; jtag_core *jc; jc = (jtag_core *)ctx->app_ctx; path[0] = '\0'; get_param(ctx, line, 1, (char *)&path); offs = get_param_offset(line, 1); if (offs >= 0) { ret = JTAG_CORE_INTERNAL_ERROR; new_ctx = init_script((void *)jc, 0x00000000, (void *)jc->envvar); if (new_ctx) { new_ctx->script_printf = ctx->script_printf; function[0] = '\0'; get_param(ctx, line, 2, (char *)&function); if (!strcmp(path, ".")) { if (strlen(function)) { snprintf(new_ctx->pre_command, sizeof(new_ctx->pre_command), "goto %s", function); ret = execute_file_script(new_ctx, (char *)&ctx->script_file_path); new_ctx->pre_command[0] = 0; if (ret == JTAG_CORE_ACCESS_ERROR) { ctx->script_printf(ctx, MSG_ERROR, "call : script not found ! : %s\n", path); } } } else { if (strlen(function)) { snprintf(new_ctx->pre_command, sizeof(new_ctx->pre_command), "goto %s", function); ret = execute_file_script(new_ctx, (char *)&path); new_ctx->pre_command[0] = 0; if (ret == JTAG_CORE_ACCESS_ERROR) { ctx->script_printf(ctx, MSG_ERROR, "call : script/function not found ! : %s %s\n", path, function); } } else { ret = execute_file_script(new_ctx, (char *)&path); if (ret == JTAG_CORE_ACCESS_ERROR) { ctx->script_printf(ctx, MSG_ERROR, "call : script not found ! : %s\n", path); } } } deinit_script(new_ctx); } ctx->last_error_code = ret; return ret; } return JTAG_CORE_BAD_PARAMETER; } const char *cmd_set_env_var_help[] = { "(string) (string)", "Stores in the environmen variable .", ""}; static int cmd_set_env_var(script_ctx *ctx, char *line) { int i, j, ret; char varname[DEFAULT_BUFLEN]; char varvalue[DEFAULT_BUFLEN]; ret = JTAG_CORE_BAD_PARAMETER; i = get_param(ctx, line, 1, varname); j = get_param(ctx, line, 2, varvalue); if (i >= 0 && j >= 0) { if (setEnvVarDat((envvar_entry *)ctx->env, (char *)&varname, (char *)&varvalue) >= 0) { ret = JTAG_CORE_NO_ERROR; } else ret = JTAG_CORE_MEM_ERROR; } return ret; } const char *cmd_rand_help[] = { "(int)", "Generates a random integer. Uses the value if present.", ""}; static int cmd_rand(script_ctx *ctx, char *line) { int i; uint32_t seed; char rand_seed[DEFAULT_BUFLEN]; seed = ctx->rand_seed; i = get_param(ctx, line, 1, rand_seed); if (i >= 0) { seed = str_to_int((char *)rand_seed); } /* Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs" */ seed ^= seed << 13; seed ^= seed >> 17; seed ^= seed << 5; ctx->rand_seed = seed; ctx->last_data_value = seed; return JTAG_CORE_NO_ERROR; } int is_valid_hex_quartet(char c) { if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) return 1; else return 0; } int is_valid_hex_byte(char *str) { if (is_valid_hex_quartet(str[0]) && is_valid_hex_quartet(str[1])) return 1; else return 0; } char *arrayresize(char *array, int size, unsigned char c) { int cursize; char *ptr; if (size < 0) return array; if (array) { if (array[0] == '0' && (array[1] == 'x' || array[1] == 'X')) { ptr = (array + 2); } else { ptr = (array); } } else { array = malloc(DEFAULT_BUFLEN + 1); if (array) { size = DEFAULT_BUFLEN / 2; memset(array, 0, DEFAULT_BUFLEN + 1); } ptr = array; } if (ptr) { cursize = 0; while (is_valid_hex_byte(&ptr[cursize * 2])) { cursize++; } ptr[cursize * 2] = '\0'; if (cursize < size) { while (cursize < size) { sprintf(&ptr[(cursize * 2) + 0], "%.2X", c); ptr[(cursize * 2) + 2] = '\0'; cursize++; } } } return array; } const char *cmd_initarray_help[] = { "(string) (int) (int)", "Initializes an array of size with . Stores it in the environment.", ""}; static int cmd_initarray(script_ctx *ctx, char *line) { // initarray $VARIABLE_1_TEST $BYTES $VALUE int i, j, ret; char varname[DEFAULT_BUFLEN]; char varsize[DEFAULT_BUFLEN]; char varvalue[DEFAULT_BUFLEN]; char *ptr; int size; ret = JTAG_CORE_BAD_PARAMETER; strcpy(varvalue, "0"); varname[0] = '\0'; i = get_param_str(ctx, line, 1, varname); j = get_param(ctx, line, 2, varsize); get_param(ctx, line, 3, varvalue); if (i >= 0 && j >= 0) { size = str_to_int(varsize); if (size >= 0 && strlen(varname)) { ptr = getEnvVarDat((envvar_entry *)ctx->env, (char *)&varname, NULL, 0); if (ptr) { arrayresize(ptr, size, (unsigned char)(str_to_int((char *)&varvalue) & 0xFF)); } else { ptr = malloc(DEFAULT_BUFLEN); if (ptr) { memset(ptr, 0x00, DEFAULT_BUFLEN); arrayresize(ptr, size, (unsigned char)(str_to_int((char *)&varvalue) & 0xFF)); } } if (ptr) setEnvVarDat((envvar_entry *)ctx->env, (char *)&varname[1], ptr); } ret = JTAG_CORE_NO_ERROR; } return ret; } /////////////////////////////////////////////////////////////////////////////// /////////////////////// JTAG commands/operations ////////////////////////////// /////////////////////////////////////////////////////////////////////////////// const char *cmd_autoinit_help[] = { "", // Arguments "1(type) ..." "explanations line one", // Explanations "explanations line two", "" }; static int cmd_autoinit(script_ctx *ctx, char *line) { jtag_core *jc; int number_of_devices, dev_nb; int loaded_bsdl; char szExecPath[MAX_PATH + 1]; char scanfolder[MAX_PATH + 1]; char filename[MAX_PATH + 1]; char entityname[DEFAULT_BUFLEN]; char file[MAX_PATH + 1]; filefoundinfo fileinfo; void *h_file_find; unsigned long chip_id, chip_id_mask; jc = (jtag_core *)ctx->app_ctx; loaded_bsdl = 0; // BSDL Auto load : check which bsdl file match with the device // And load it. jtagcore_scan_and_init_chain(jc); number_of_devices = jtagcore_get_number_of_devices(jc); ctx->script_printf(ctx, MSG_INFO_0, "%d device(s) found\n", number_of_devices); // Get the bsdl_files folder path genos_getcurrentdirectory(szExecPath, MAX_PATH); strncpy(scanfolder, szExecPath, sizeof(scanfolder)); genos_strndstcat(scanfolder, DIR_SEPARATOR "bsdl_files" DIR_SEPARATOR, sizeof(scanfolder) - 1); scanfolder[sizeof(scanfolder) - 1] = '\0'; h_file_find = genos_find_first_file(scanfolder, "*.*", &fileinfo); // Scan and check files in the folder. if (h_file_find) { do { strcpy(filename, szExecPath); genos_strndstcat(filename, DIR_SEPARATOR "bsdl_files" DIR_SEPARATOR, sizeof(filename)); genos_strndstcat(filename, fileinfo.filename, sizeof(filename)); filename[sizeof(filename) - 1] = '\0'; if (!fileinfo.isdirectory) { chip_id_mask = 0xFFFFFFFF; ctx->script_printf(ctx, MSG_INFO_0, "[identify] reading IDCODE from %s :\n", fileinfo.filename); chip_id = jtagcore_get_bsdl_id(jc, filename, &chip_id_mask); if (chip_id) { for (dev_nb = 0; dev_nb < number_of_devices; dev_nb++) { if ((chip_id & chip_id_mask) == (jtagcore_get_dev_id(jc, dev_nb) & chip_id_mask)) { if (jtagcore_get_number_of_pins(jc, dev_nb) > 0) { // A BSDL is already attached to this device. // Several files can legitimately share one // IDCODE (same die in different packages, or // twins like SmartFusion2 / IGLOO2). Keep the // first match and just note the others, rather // than overwriting it and crying "conflict". ctx->script_printf(ctx, MSG_INFO_0, "[skip] %s also matches device %d's IDCODE; keeping the BSDL already loaded\n", fileinfo.filename, dev_nb); continue; } // The BSDL ID match with the device. ctx->script_printf(ctx, MSG_INFO_0, "[load] IDCODE 0x%.8lX matches device %d, attaching %s :\n", chip_id, dev_nb, fileinfo.filename); if (jtagcore_loadbsdlfile(jc, filename, dev_nb) == JTAG_CORE_NO_ERROR) { entityname[0] = 0; jtagcore_get_dev_name(jc, dev_nb, entityname, file); ctx->script_printf(ctx, MSG_INFO_0, "Device %d (%.8X - %s) - BSDL Loaded : %s\n", dev_nb, chip_id, entityname, file); } else { ctx->script_printf(ctx, MSG_ERROR, "ERROR while loading %s !\n", filename); } } } } } } while (genos_find_next_file(h_file_find, scanfolder, "*.*", &fileinfo)); genos_find_close(h_file_find); loaded_bsdl = 0; // Count the loaded bsdl for (dev_nb = 0; dev_nb < number_of_devices; dev_nb++) { if (jtagcore_get_number_of_pins(jc, dev_nb) > 0) { loaded_bsdl++; } else { ctx->script_printf(ctx, MSG_WARNING, "Device %d (%.8X) - NO BSDL Loaded !\n", dev_nb, jtagcore_get_dev_id(jc, dev_nb)); } } } else { ctx->script_printf(ctx, MSG_ERROR, "Can't access the bsdl sub folder ! : %s\n", scanfolder); return JTAG_CORE_ACCESS_ERROR; } // Expose the count to scripts via last_data_value, but report success // (a non-zero return is treated as an error code by the engine). ctx->last_data_value = loaded_bsdl; return JTAG_CORE_NO_ERROR; } const char *cmd_init_and_scan_help[] = { "", "Scan the JTAG chain and report the devices found with their IDCODEs.", "Unlike jtag_autoinit, it does not load any BSDL.", "" }; static int cmd_init_and_scan(script_ctx *ctx, char *line) { jtag_core *jc; int ret, n, i; jc = (jtag_core *)ctx->app_ctx; ret = jtagcore_scan_and_init_chain(jc); if (ret != JTAG_CORE_NO_ERROR) { ctx->script_printf(ctx, MSG_ERROR, "JTAG scan failed (code %d)\n", ret); return ret; } n = jtagcore_get_number_of_devices(jc); ctx->script_printf(ctx, MSG_INFO_0, "%d device(s) found\n", n); for (i = 0; i < n; i++) { ctx->script_printf(ctx, MSG_INFO_0, " Device %d : IDCODE 0x%.8lX\n", i, jtagcore_get_dev_id(jc, i)); } ctx->last_data_value = n; return JTAG_CORE_NO_ERROR; } const char *cmd_print_nb_dev_help[] = { "", // Arguments "1(type) ..." "explanations line one", // Explanations "explanations line two", "" }; static int cmd_print_nb_dev(script_ctx *ctx, char *line) { jtag_core *jc; int i; jc = (jtag_core *)ctx->app_ctx; i = jtagcore_get_number_of_devices(jc); ctx->script_printf(ctx, MSG_INFO_0, "%d device(s) found in chain\n", i); ctx->last_data_value = i; return JTAG_CORE_NO_ERROR; } const char *cmd_bsdl_id_help[] = { "", // Arguments "1(type) ..." "explanations line one", // Explanations "explanations line two", "" }; static void bsdl_id_str(unsigned long id, char *str) { int i; str[0] = 0; for (i = 0; i < 32; i++) { if ((0x80000000 >> i) & id) { strcat(str, "1"); } else { strcat(str, "0"); } if (i == 3) strcat(str, " "); if (i == 19) strcat(str, " "); if (i == 30) strcat(str, " "); } str[i] = 0; } static char *get_id_str(script_ctx *ctx, int numberofdevice) { // compare passed device ID to the one returned from the ID command jtag_core *jc; int i; unsigned int idcode = 0; char *stringbuffer; char tempstr[DEFAULT_BUFLEN]; jc = (jtag_core *)ctx->app_ctx; stringbuffer = NULL; if (numberofdevice < 0 || numberofdevice > 256) return NULL; stringbuffer = malloc(256 * numberofdevice); if (stringbuffer) { memset(stringbuffer, 0, 256 * numberofdevice); // and read the IDCODES for (i = 0; i < numberofdevice; i++) { idcode = jtagcore_get_dev_id(jc, i); sprintf(tempstr, "Device %d : 0x%.8X - ", i, idcode); bsdl_id_str(idcode, &tempstr[strlen(tempstr)]); strcat(stringbuffer, tempstr); strcat(stringbuffer, "\n"); } } return stringbuffer; } const char *cmd_print_devs_list_help[] = { "", // Arguments "1(type) ..." "explanations line one", // Explanations "explanations line two", "" }; static int cmd_print_devs_list(script_ctx *ctx, char *line) { jtag_core *jc; int i; char *ptr; jc = (jtag_core *)ctx->app_ctx; i = jtagcore_get_number_of_devices(jc); if (i > 0) { ptr = get_id_str(ctx, i); if (ptr) { ctx->script_printf(ctx, MSG_INFO_0, "%s\n", ptr); free(ptr); } return JTAG_CORE_NO_ERROR; } return JTAG_CORE_NOT_FOUND; } const char *cmd_print_probes_list_help[] = { "", // Arguments "1(type) ..." "Displays the list of detected probes.", // Explanations "" }; /* Map the flat index shown by jtag_probes (0, 1, 2, ...) to the * encoded (drv << 8 | probe) id, walking drivers/probes in the same order * the list prints them. Returns -1 if the index is out of range. */ static int resolve_flat_probe_index(jtag_core *jc, int flat) { int nb_of_drivers = jtagcore_get_number_of_probes_drv(jc); int j, i, n = 0; for (j = 0; j < nb_of_drivers; j++) { int nb_of_probes = jtagcore_get_number_of_probes(jc, j); for (i = 0; i < nb_of_probes; i++) { if (n == flat) return PROBE_ID(j, i); n++; } } return -1; } static int cmd_print_probes_list(script_ctx *ctx, char *line) { jtag_core *jc; int i, j, flat; char probe_list[64]; int nb_of_drivers, nb_of_probes; jc = (jtag_core *)ctx->app_ctx; nb_of_drivers = jtagcore_get_number_of_probes_drv(jc); flat = 0; j = 0; while (j < nb_of_drivers) { nb_of_probes = jtagcore_get_number_of_probes(jc, j); i = 0; while (i < nb_of_probes) { jtagcore_get_probe_name(jc, PROBE_ID(j, i), probe_list); // [flat index] is what to pass to jtag_open; the // 0x id after it is the raw form, also accepted. ctx->script_printf(ctx, MSG_INFO_0, " [%d] 0x%.8X %s\n", flat, PROBE_ID(j, i), probe_list); flat++; i++; } j++; } return JTAG_CORE_NO_ERROR; } const char *cmd_open_probe_help[] = { "(int)", // Arguments "1(type) ..." "Open a probe by its index from jtag_probes (0, 1, 2, ...).", "A raw 0x-prefixed probe id (as printed after the index) also works.", "" }; static int cmd_open_probe(script_ctx *ctx, char *line) { int ret; int id; char probe_id[64]; jtag_core *jc; jc = (jtag_core *)ctx->app_ctx; if (get_param(ctx, line, 1, probe_id) > 0) { if (probe_id[0] == '0' && (probe_id[1] == 'x' || probe_id[1] == 'X')) { // Raw encoded id (drv << 8 | probe). id = (int)strtoul(probe_id, NULL, 16); } else { // Sequential index from jtag_probes. id = resolve_flat_probe_index(jc, (int)strtoul(probe_id, NULL, 10)); if (id < 0) { ctx->script_printf(ctx, MSG_ERROR, "No probe at index %s. Run jtag_probes first.\n", probe_id); return JTAG_CORE_BAD_PARAMETER; } } ret = jtagcore_select_and_open_probe(jc, id); if (ret != JTAG_CORE_NO_ERROR) { ctx->script_printf(ctx, MSG_ERROR, "Code %d !\n", ret); return ret; } else { ctx->script_printf(ctx, MSG_INFO_0, "Probe Ok !\n"); return JTAG_CORE_NO_ERROR; } } else { ctx->script_printf(ctx, MSG_ERROR, "Bad/Missing parameter(s) ! : %s\n", line); return JTAG_CORE_BAD_PARAMETER; } } const char *cmd_close_probe_help[] = { "", // Arguments "1(type) ..." "Release the currently open probe, freeing its USB handle.", "Use it to hand the probe to another tool, or before driving a", "second target on a different probe: jtag_close, then jtag_open the", "other one and jtag_autoinit to rescan. (Opening another probe also", "releases the current one, so jtag_close is only needed to fully let", "go without immediately reopening.)", "" }; static int cmd_close_probe(script_ctx *ctx, char *line) { jtag_core *jc; (void)line; jc = (jtag_core *)ctx->app_ctx; if (jc->io_functions.drv_DeInit) { // Same teardown jtagcore_loaddriver does before switching drivers: // call the driver's DeInit, then forget its function table so the // chain looks probe-less until the next jtag_open. jc->io_functions.drv_DeInit(jc); memset(&jc->io_functions, 0, sizeof(jc->io_functions)); ctx->script_printf(ctx, MSG_INFO_0, "Probe released.\n"); } else { ctx->script_printf(ctx, MSG_INFO_0, "No probe is open.\n"); } return JTAG_CORE_NO_ERROR; } const char *cmd_load_bsdl_help[] = { "(string) (int)", "Load/attach a bsdl file to a device into the chain.", "" }; static int cmd_load_bsdl(script_ctx *ctx, char *line) { int i, j; char dev_index[DEFAULT_BUFLEN]; char filename[DEFAULT_BUFLEN]; jtag_core *jc; jc = (jtag_core *)ctx->app_ctx; i = get_param(ctx, line, 1, filename); j = get_param(ctx, line, 2, dev_index); if (i >= 0 && j >= 0) { if (jtagcore_loadbsdlfile(jc, filename, str_to_int(dev_index)) >= 0) { ctx->script_printf(ctx, MSG_INFO_0, "BSDL %s loaded and parsed !\n", filename); return JTAG_CORE_NO_ERROR; } else { ctx->script_printf(ctx, MSG_ERROR, "File open & parsing error (%s)!\n", filename); return JTAG_CORE_ACCESS_ERROR; } } ctx->script_printf(ctx, MSG_ERROR, "Bad/Missing parameter(s) ! : %s\n", line); return JTAG_CORE_BAD_PARAMETER; } const char *cmd_set_scan_mode_help[] = { "(int) (string)", "Set the scan mode for a particular device.", "mode to be chosen in EXTEST or SAMPLE", "" }; static int cmd_set_scan_mode(script_ctx *ctx, char *line) { int i, j; char dev_index[DEFAULT_BUFLEN]; char scan_mode[DEFAULT_BUFLEN]; jtag_core *jc; jc = (jtag_core *)ctx->app_ctx; i = get_param(ctx, line, 1, dev_index); j = get_param(ctx, line, 2, scan_mode); if (i >= 0 && j >= 0) { if (!strcmp(scan_mode, "EXTEST")) { jtagcore_set_scan_mode(jc, str_to_int(dev_index), JTAG_CORE_EXTEST_SCANMODE); ctx->script_printf(ctx, MSG_INFO_0, "EXTEST mode\n"); } else { if (!strcmp(scan_mode, "SAMPLE")) { jtagcore_set_scan_mode(jc, str_to_int(dev_index), JTAG_CORE_SAMPLE_SCANMODE); ctx->script_printf(ctx, MSG_INFO_0, "SAMPLE mode\n"); } else { ctx->script_printf(ctx, MSG_ERROR, "%s : unknown mode !\n", scan_mode); return JTAG_CORE_BAD_PARAMETER; } } return JTAG_CORE_NO_ERROR; } ctx->script_printf(ctx, MSG_ERROR, "Bad/Missing parameter(s) ! : %s\n", line); return JTAG_CORE_BAD_PARAMETER; } const char *cmd_push_and_pop_help[] = { "", "Do a JTAG chain transaction.", "" }; static int cmd_push_and_pop(script_ctx *ctx, char *line) { int ret; jtag_core *jc; jc = (jtag_core *)ctx->app_ctx; ret = jtagcore_push_and_pop_chain(jc, JTAG_CORE_WRITE_READ); if (ret != JTAG_CORE_NO_ERROR) { ctx->script_printf(ctx, MSG_ERROR, "Code %d !\n", ret); return ret; } else { ctx->script_printf(ctx, MSG_INFO_0, "JTAG chain updated\n"); } return JTAG_CORE_NO_ERROR; } const char *cmd_set_pin_mode_help[] = { "(int) (string) (int)", "Change the mode (input: 0 or output: 1) of the pin of the given device.", "" }; static int cmd_set_pin_mode(script_ctx *ctx, char *line) { int i, j, k, id; char dev_index[DEFAULT_BUFLEN]; char pinname[DEFAULT_BUFLEN]; char mode[DEFAULT_BUFLEN]; jtag_core *jc; jc = (jtag_core *)ctx->app_ctx; i = get_param(ctx, line, 1, dev_index); j = get_param(ctx, line, 2, pinname); k = get_param(ctx, line, 3, mode); if (i >= 0 && j >= 0 && k >= 0) { id = jtagcore_get_pin_id(jc, str_to_int(dev_index), pinname); if (id >= 0) { jtagcore_set_pin_state(jc, str_to_int(dev_index), id, JTAG_CORE_OE, str_to_int(mode)); ctx->script_printf(ctx, MSG_INFO_0, "Pin %s mode set to %d\n", pinname, str_to_int(mode)); return JTAG_CORE_NO_ERROR; } else { ctx->script_printf(ctx, MSG_ERROR, "Pin %s not found\n", pinname); return JTAG_CORE_NOT_FOUND; } } ctx->script_printf(ctx, MSG_ERROR, "Bad/Missing parameter(s) ! : %s\n", line); return JTAG_CORE_BAD_PARAMETER; } const char *cmd_set_pin_state_help[] = { "(int) (string) (string)", "Change the state (0 or 1) of the pin of the given device.", "" }; static int cmd_set_pin_state(script_ctx *ctx, char *line) { int i, j, k, id; char dev_index[DEFAULT_BUFLEN]; char pinname[DEFAULT_BUFLEN]; char state[DEFAULT_BUFLEN]; jtag_core *jc; jc = (jtag_core *)ctx->app_ctx; i = get_param(ctx, line, 1, dev_index); j = get_param(ctx, line, 2, pinname); k = get_param(ctx, line, 3, state); if (i >= 0 && j >= 0 && k >= 0) { id = jtagcore_get_pin_id(jc, str_to_int(dev_index), pinname); if (id >= 0) { jtagcore_set_pin_state(jc, str_to_int(dev_index), id, JTAG_CORE_OUTPUT, str_to_int(state)); ctx->script_printf(ctx, MSG_INFO_0, "Pin %s set to %d\n", pinname, str_to_int(state)); return JTAG_CORE_NO_ERROR; } else { ctx->script_printf(ctx, MSG_ERROR, "Pin %s not found\n", pinname); return JTAG_CORE_NOT_FOUND; } } ctx->script_printf(ctx, MSG_ERROR, "Bad/Missing parameter(s) ! : %s\n", line); return JTAG_CORE_BAD_PARAMETER; } const char *cmd_get_pin_state_help[] = { "(int) (string)", "Gets the state (0 or 1) of the pin of the given device.", "The mode is to be chosen between 'input' or 'output'.", "" }; static int cmd_get_pin_state(script_ctx *ctx, char *line) { int i, j, k, ret, id; char dev_index[DEFAULT_BUFLEN]; char pinname[DEFAULT_BUFLEN]; jtag_core *jc; jc = (jtag_core *)ctx->app_ctx; i = get_param(ctx, line, 1, dev_index); j = get_param(ctx, line, 2, pinname); if (i >= 0 && j >= 0 && k >= 0) { id = jtagcore_get_pin_id(jc, str_to_int(dev_index), pinname); if (id >= 0) { ret = jtagcore_get_pin_state(jc, str_to_int(dev_index), id, JTAG_CORE_INPUT); ctx->script_printf(ctx, MSG_INFO_0, "Pin %s state : %d\n", pinname, ret); ctx->last_data_value = ret; return JTAG_CORE_NO_ERROR; } else { ctx->script_printf(ctx, MSG_ERROR, "Pin %s not found\n", pinname); return JTAG_CORE_NOT_FOUND; } } ctx->script_printf(ctx, MSG_ERROR, "Bad/Missing parameter(s) ! : %s\n", line); return JTAG_CORE_BAD_PARAMETER; } ///////////////////////////////////////////////////////////////////////////////////////// // I2C Commands ///////////////////////////////////////////////////////////////////////////////////////// const char *cmd_set_i2c_sda_help[] = { "", // Arguments "1(type) ..." "explanations line one", // Explanations "explanations line two", "" }; static int cmd_set_i2c_sda_pin(script_ctx *ctx, char *line) { int i, j, id; char dev_index[DEFAULT_BUFLEN]; char pinname[DEFAULT_BUFLEN]; jtag_core *jc; jc = (jtag_core *)ctx->app_ctx; i = get_param(ctx, line, 1, dev_index); j = get_param(ctx, line, 2, pinname); if (i >= 0 && j >= 0) { id = jtagcore_get_pin_id(jc, str_to_int(dev_index), pinname); if (id >= 0) { jtagcore_i2c_set_sda_pin(jc, str_to_int(dev_index), id); ctx->script_printf(ctx, MSG_INFO_0, "SDA set to Pin %s\n", pinname); return JTAG_CORE_NO_ERROR; } else { ctx->script_printf(ctx, MSG_ERROR, "Pin %s not found\n", pinname); return JTAG_CORE_NOT_FOUND; } } ctx->script_printf(ctx, MSG_ERROR, "Bad/Missing parameter(s) ! : %s\n", line); return JTAG_CORE_BAD_PARAMETER; } const char *cmd_set_i2c_scl_help[] = { "", // Arguments "1(type) ..." "explanations line one", // Explanations "explanations line two", "" }; static int cmd_set_i2c_scl_pin(script_ctx *ctx, char *line) { int i, j, id; char dev_index[DEFAULT_BUFLEN]; char pinname[DEFAULT_BUFLEN]; jtag_core *jc; jc = (jtag_core *)ctx->app_ctx; i = get_param(ctx, line, 1, dev_index); j = get_param(ctx, line, 2, pinname); if (i >= 0 && j >= 0) { id = jtagcore_get_pin_id(jc, str_to_int(dev_index), pinname); if (id >= 0) { jtagcore_i2c_set_scl_pin(jc, str_to_int(dev_index), id); ctx->script_printf(ctx, MSG_INFO_0, "SCL set to Pin %s\n", pinname); return JTAG_CORE_NO_ERROR; } else { ctx->script_printf(ctx, MSG_ERROR, "Pin %s not found\n", pinname); return JTAG_CORE_NOT_FOUND; } } ctx->script_printf(ctx, MSG_ERROR, "Bad/Missing parameter(s) ! : %s\n", line); return JTAG_CORE_BAD_PARAMETER; } const char *cmd_do_i2c_wr_help[] = { "", // Arguments "1(type) ..." "explanations line one", // Explanations "explanations line two", "" }; static int cmd_do_i2c_wr(script_ctx *ctx, char *line) { // jtag_set_do_i2c_wr E8 EAACCDD4455 int i, j; int i2cadr, size, ret; char adresse[DEFAULT_BUFLEN]; char data[DEFAULT_BUFLEN]; unsigned char tmp_buffer2[DEFAULT_BUFLEN]; char tmp_buffer3[16]; jtag_core *jc; jc = (jtag_core *)ctx->app_ctx; i = get_param(ctx, line, 1, adresse); j = get_param(ctx, line, 2, data); if (i >= 0 && j >= 0) { i2cadr = strtoul(adresse, 0, 16); size = strlen(data); size = size / 2; for (i = 0; i < size; i++) { tmp_buffer3[0] = data[i * 2]; tmp_buffer3[1] = data[i * 2 + 1]; tmp_buffer3[2] = 0; tmp_buffer2[i] = (char)strtoul(tmp_buffer3, 0, 16); } ret = jtagcore_i2c_write_read(jc, i2cadr, 0, size, tmp_buffer2, 0, 0); if (ret <= 0) { if (ret == 0) { ctx->script_printf(ctx, MSG_WARNING, "Device Ack not detected ! 0x%.2X\n", i2cadr); } else { ctx->script_printf(ctx, MSG_ERROR, "Code %d !\n", ret); } return ret; } else { for (i = 0; i < size; i++) { sprintf(&data[i * 3], " %.2X", tmp_buffer2[i]); } ctx->script_printf(ctx, MSG_INFO_0, "WR I2C 0x%.2X :%s\n", i2cadr, data); return JTAG_CORE_NO_ERROR; } } ctx->script_printf(ctx, MSG_ERROR, "Bad/Missing parameter(s) ! : %s\n", line); return JTAG_CORE_BAD_PARAMETER; } const char *cmd_do_i2c_rd_help[] = { "", // Arguments "1(type) ..." "explanations line one", // Explanations "explanations line two", "" }; static int cmd_do_i2c_rd(script_ctx *ctx, char *line) { // jtag_set_do_i2c_rd 0xE8 8 int i, j, i2cadr, size; char adresse[DEFAULT_BUFLEN]; char sizebuf[DEFAULT_BUFLEN]; char tmp_buffer[DEFAULT_BUFLEN]; char tmp_buffer2[DEFAULT_BUFLEN]; char tmp_buffer3[16]; int ret; jtag_core *jc; jc = (jtag_core *)ctx->app_ctx; i = get_param(ctx, line, 1, adresse); j = get_param(ctx, line, 2, sizebuf); if (i >= 0 && j >= 0) { i2cadr = strtoul(adresse, 0, 16); size = str_to_int(sizebuf); ret = jtagcore_i2c_write_read(jc, i2cadr, 0, 0, (unsigned char *)tmp_buffer2, size, (unsigned char *)tmp_buffer2); if (ret <= 0) { if (ret == 0) { ctx->script_printf(ctx, MSG_WARNING, "Device Ack not detected ! 0x%.2X\n", i2cadr); } else { ctx->script_printf(ctx, MSG_ERROR, "Code %d !\n", ret); } return ret; } else { memset(tmp_buffer, 0, sizeof(tmp_buffer)); for (i = 0; i < size && i < sizeof(tmp_buffer2); i++) { sprintf(tmp_buffer3, " %.2X", tmp_buffer2[i]); strcat(tmp_buffer, tmp_buffer3); } ctx->script_printf(ctx, MSG_INFO_0, "RD I2C 0x%.2X :%s\n", i2cadr, tmp_buffer); return JTAG_CORE_NO_ERROR; } } ctx->script_printf(ctx, MSG_ERROR, "Bad/Missing parameter(s) ! : %s\n", line); return JTAG_CORE_BAD_PARAMETER; } ///////////////////////////////////////////////////////////////////////////////////////// // MDIO Commands ///////////////////////////////////////////////////////////////////////////////////////// const char *cmd_set_mdio_mdc_pin_help[] = { "", // Arguments "1(type) ..." "explanations line one", // Explanations "explanations line two", "" }; static int cmd_set_mdio_mdc_pin(script_ctx *ctx, char *line) { int i, j, id; char dev_index[DEFAULT_BUFLEN]; char pinname[DEFAULT_BUFLEN]; jtag_core *jc; jc = (jtag_core *)ctx->app_ctx; i = get_param(ctx, line, 1, dev_index); j = get_param(ctx, line, 2, pinname); if (i >= 0 && j >= 0) { id = jtagcore_get_pin_id(jc, str_to_int(dev_index), pinname); if (id >= 0) { jtagcore_mdio_set_mdc_pin(jc, str_to_int(dev_index), id); ctx->script_printf(ctx, MSG_INFO_0, "MDC set to Pin %s\n", pinname); return JTAG_CORE_NO_ERROR; } else { ctx->script_printf(ctx, MSG_ERROR, "Pin %s not found\n", pinname); return JTAG_CORE_NOT_FOUND; } } ctx->script_printf(ctx, MSG_ERROR, "Bad/Missing parameter(s) ! : %s\n", line); return JTAG_CORE_BAD_PARAMETER; } const char *cmd_set_mdio_mdio_pin_help[] = { "", // Arguments "1(type) ..." "explanations line one", // Explanations "explanations line two", "" }; static int cmd_set_mdio_mdio_pin(script_ctx *ctx, char *line) { int i, j, id; char dev_index[DEFAULT_BUFLEN]; char pinname[DEFAULT_BUFLEN]; jtag_core *jc; jc = (jtag_core *)ctx->app_ctx; i = get_param(ctx, line, 1, dev_index); j = get_param(ctx, line, 2, pinname); if (i >= 0 && j >= 0) { id = jtagcore_get_pin_id(jc, str_to_int(dev_index), pinname); if (id >= 0) { jtagcore_mdio_set_mdio_pin(jc, str_to_int(dev_index), id); ctx->script_printf(ctx, MSG_INFO_0, "MDIO set to Pin %s\n", pinname); return JTAG_CORE_NO_ERROR; } else { ctx->script_printf(ctx, MSG_ERROR, "Pin %s not found\n", pinname); return JTAG_CORE_NOT_FOUND; } } ctx->script_printf(ctx, MSG_ERROR, "Bad/Missing parameter(s) ! : %s\n", line); return JTAG_CORE_BAD_PARAMETER; } const char *cmd_do_mdio_wr_help[] = { "", // Arguments "1(type) ..." "explanations line one", // Explanations "explanations line two", "" }; static int cmd_do_mdio_wr(script_ctx *ctx, char *line) { // jtag_mdio_wr 01 04 EAAC int i, j, k, mdioadr, regadr, datatowrite; char address[DEFAULT_BUFLEN]; char reg[DEFAULT_BUFLEN]; char data[DEFAULT_BUFLEN]; int ret; jtag_core *jc; jc = (jtag_core *)ctx->app_ctx; i = get_param(ctx, line, 1, address); j = get_param(ctx, line, 2, reg); k = get_param(ctx, line, 3, data); if (i >= 0 && j >= 0 && k >= 0) { mdioadr = strtoul(address, 0, 16); regadr = strtoul(reg, 0, 16); datatowrite = strtoul(data, 0, 16); ret = jtagcore_mdio_write(jc, mdioadr, regadr, datatowrite); if (ret < 0) { ctx->script_printf(ctx, MSG_ERROR, "Code %d !\n", ret); return ret; } ctx->script_printf(ctx, MSG_INFO_0, "WR MDIO 0x%.2X : [0x%.2X] = 0x%.4X\n", mdioadr, regadr, datatowrite); return JTAG_CORE_NO_ERROR; } ctx->script_printf(ctx, MSG_ERROR, "Bad/Missing parameter(s) ! : %s\n", line); return JTAG_CORE_BAD_PARAMETER; } const char *cmd_do_mdio_rd_help[] = { "", // Arguments "1(type) ..." "explanations line one", // Explanations "explanations line two", "" }; static int cmd_do_mdio_rd(script_ctx *ctx, char *line) { // jtag_mdio_rd 01 04 int i, j, mdioadr, regadr, dataread; char address[DEFAULT_BUFLEN]; char reg[DEFAULT_BUFLEN]; jtag_core *jc; jc = (jtag_core *)ctx->app_ctx; i = get_param(ctx, line, 1, address); j = get_param(ctx, line, 2, reg); if (i >= 0 && j >= 0) { mdioadr = strtoul(address, 0, 16); regadr = strtoul(reg, 0, 16); dataread = jtagcore_mdio_read(jc, mdioadr, regadr); if (dataread < 0) { ctx->script_printf(ctx, MSG_ERROR, "Code %d !\n", dataread); return dataread; } ctx->last_data_value = dataread; ctx->script_printf(ctx, MSG_INFO_0, "RD MDIO 0x%.2X : [0x%.2X] = 0x%.4X\n", mdioadr, regadr, dataread); return JTAG_CORE_NO_ERROR; } ctx->script_printf(ctx, MSG_ERROR, "Bad/Missing parameter(s) ! : %s\n", line); return JTAG_CORE_BAD_PARAMETER; } ///////////////////////////////////////////////////////////////////////////////////////// // SPI Commands ///////////////////////////////////////////////////////////////////////////////////////// const char *cmd_set_spi_cs_pin_help[] = { "", // Arguments "1(type) ..." "explanations line one", // Explanations "explanations line two", "" }; static int cmd_set_spi_cs_pin(script_ctx *ctx, char *line) { int i, j, k, id; char dev_index[DEFAULT_BUFLEN]; char pinname[DEFAULT_BUFLEN]; char polarity[DEFAULT_BUFLEN]; jtag_core *jc; jc = (jtag_core *)ctx->app_ctx; i = get_param(ctx, line, 1, dev_index); j = get_param(ctx, line, 2, pinname); k = get_param(ctx, line, 3, polarity); if (i >= 0 && j >= 0 && k >= 0) { id = jtagcore_get_pin_id(jc, str_to_int(dev_index), pinname); if (id >= 0) { jtagcore_spi_set_cs_pin(jc, str_to_int(dev_index), id, str_to_int(polarity)); ctx->script_printf(ctx, MSG_INFO_0, "CS set to Pin %s with polarity %d\n", pinname, str_to_int(polarity)); return JTAG_CORE_NO_ERROR; } else { ctx->script_printf(ctx, MSG_ERROR, "Pin %s not found\n", pinname); return JTAG_CORE_NOT_FOUND; } } ctx->script_printf(ctx, MSG_ERROR, "Bad/Missing parameter(s) ! : %s\n", line); return JTAG_CORE_BAD_PARAMETER; } const char *cmd_set_spi_clk_pin_help[] = { "", // Arguments "1(type) ..." "explanations line one", // Explanations "explanations line two", "" }; static int cmd_set_spi_clk_pin(script_ctx *ctx, char *line) { int i, j, k, id; char dev_index[DEFAULT_BUFLEN]; char pinname[DEFAULT_BUFLEN]; char polarity[DEFAULT_BUFLEN]; jtag_core *jc; jc = (jtag_core *)ctx->app_ctx; i = get_param(ctx, line, 1, dev_index); j = get_param(ctx, line, 2, pinname); k = get_param(ctx, line, 3, polarity); if (i >= 0 && j >= 0 && k >= 0) { id = jtagcore_get_pin_id(jc, str_to_int(dev_index), pinname); if (id >= 0) { jtagcore_spi_set_clk_pin(jc, str_to_int(dev_index), id, str_to_int(polarity)); ctx->script_printf(ctx, MSG_INFO_0, "CLK set to Pin %s with polarity %d\n", pinname, str_to_int(polarity)); return JTAG_CORE_NO_ERROR; } else { ctx->script_printf(ctx, MSG_ERROR, "Pin %s not found\n", pinname); return JTAG_CORE_NOT_FOUND; } } ctx->script_printf(ctx, MSG_ERROR, "Bad/Missing parameter(s) ! : %s\n", line); return JTAG_CORE_BAD_PARAMETER; } const char *cmd_set_spi_mosi_pin_help[] = { "", // Arguments "1(type) ..." "explanations line one", // Explanations "explanations line two", "" }; static int cmd_set_spi_mosi_pin(script_ctx *ctx, char *line) { int i, j, k, id; char dev_index[DEFAULT_BUFLEN]; char pinname[DEFAULT_BUFLEN]; char phase[DEFAULT_BUFLEN]; jtag_core *jc; jc = (jtag_core *)ctx->app_ctx; i = get_param(ctx, line, 1, dev_index); j = get_param(ctx, line, 2, pinname); k = get_param(ctx, line, 3, phase); if (i >= 0 && j >= 0 && k >= 0) { id = jtagcore_get_pin_id(jc, str_to_int(dev_index), pinname); if (id >= 0) { jtagcore_spi_set_mosi_pin(jc, str_to_int(dev_index), id, str_to_int(phase)); ctx->script_printf(ctx, MSG_INFO_0, "MOSI set to Pin %s with polarity %d\n", pinname, str_to_int(phase)); return JTAG_CORE_NO_ERROR; } else { ctx->script_printf(ctx, MSG_ERROR, "Pin %s not found\n", pinname); return JTAG_CORE_NOT_FOUND; } } ctx->script_printf(ctx, MSG_ERROR, "Bad/Missing parameter(s) ! : %s\n", line); return JTAG_CORE_BAD_PARAMETER; } const char *cmd_set_spi_miso_pin_help[] = { "", // Arguments "1(type) ..." "explanations line one", // Explanations "explanations line two", "" }; static int cmd_set_spi_miso_pin(script_ctx *ctx, char *line) { int i, j, k, id; char dev_index[DEFAULT_BUFLEN]; char pinname[DEFAULT_BUFLEN]; char phase[DEFAULT_BUFLEN]; jtag_core *jc; jc = (jtag_core *)ctx->app_ctx; i = get_param(ctx, line, 1, dev_index); j = get_param(ctx, line, 2, pinname); k = get_param(ctx, line, 3, phase); if (i >= 0 && j >= 0 && k >= 0) { id = jtagcore_get_pin_id(jc, str_to_int(dev_index), pinname); if (id >= 0) { jtagcore_spi_set_miso_pin(jc, str_to_int(dev_index), id, str_to_int(phase)); ctx->script_printf(ctx, MSG_INFO_0, "MISO set to Pin %s with polarity %d\n", pinname, str_to_int(phase)); return JTAG_CORE_NO_ERROR; } else { ctx->script_printf(ctx, MSG_ERROR, "Pin %s not found\n", pinname); return JTAG_CORE_NOT_FOUND; } } ctx->script_printf(ctx, MSG_ERROR, "Parameters error: %s\n", line); return JTAG_CORE_BAD_PARAMETER; } const char *cmd_spi_rd_wr_help[] = { "", // Arguments "1(type) ..." "explanations line one", // Explanations "explanations line two", "" }; static int cmd_spi_rd_wr(script_ctx *ctx, char *line) { int i, j, k, size; char data_out_txt[DEFAULT_BUFLEN]; unsigned char data_out[DEFAULT_BUFLEN]; unsigned char data_in[DEFAULT_BUFLEN]; char lsbfirst[DEFAULT_BUFLEN]; char tmp_buffer[3]; int ret; jtag_core *jc; jc = (jtag_core *)ctx->app_ctx; // jtag_spi_xfer 00123344 1 (DATA LSBFirst) i = get_param(ctx, line, 1, data_out_txt); j = get_param(ctx, line, 2, lsbfirst); if (i >= 0) { if (j >= 0) { jtagcore_spi_set_bitorder(jc, str_to_int(lsbfirst)); } size = strlen(data_out_txt); size = size / 2; for (k = 0; k < size; k++) { tmp_buffer[0] = data_out_txt[k * 2]; tmp_buffer[1] = data_out_txt[k * 2 + 1]; tmp_buffer[2] = 0; data_out[k] = (unsigned char)strtoul(tmp_buffer, 0, 16); } ret = jtagcore_spi_write_read(jc, size, data_out, data_in, 0); if (ret < 0) { ctx->script_printf(ctx, MSG_ERROR, "Code %d !\n", ret); return ret; } ctx->script_printf(ctx, MSG_INFO_0, "SPI TX:"); for (k = 0; k < size; k++) { ctx->script_printf(ctx, MSG_NONE, " %.2X", data_out[k]); } ctx->script_printf(ctx, MSG_NONE, "\n"); ctx->script_printf(ctx, MSG_INFO_0, "SPI RX:"); for (k = 0; k < size; k++) { ctx->script_printf(ctx, MSG_NONE, " %.2X", data_in[k]); } ctx->script_printf(ctx, MSG_NONE, "\n"); return JTAG_CORE_NOT_FOUND; } ctx->script_printf(ctx, MSG_ERROR, "Parameters error: %s\n", line); return JTAG_CORE_BAD_PARAMETER; } const char *cmd_get_pins_list_help[] = { "(int)", "Lists the device pins and their properties", "" }; static int cmd_get_pins_list(script_ctx *ctx, char *line) { int i, j, nb_of_pins; char dev_index[DEFAULT_BUFLEN]; char pinname[DEFAULT_BUFLEN]; int type; jtag_core *jc; jc = (jtag_core *)ctx->app_ctx; i = get_param(ctx, line, 1, dev_index); if (i >= 0) { nb_of_pins = jtagcore_get_number_of_pins(jc, str_to_int(dev_index)); if (nb_of_pins >= 0) { ctx->script_printf(ctx, MSG_INFO_0, "Device %d : %d pin(s)\n", str_to_int(dev_index), nb_of_pins); for (j = 0; j < nb_of_pins; j++) { if (jtagcore_get_pin_properties(jc, str_to_int(dev_index), j, pinname, sizeof(pinname), &type) == JTAG_CORE_NO_ERROR) { ctx->script_printf(ctx, MSG_NONE, "%s : ", pinname); if (type & JTAG_CORE_PIN_IS_INPUT) { ctx->script_printf(ctx, MSG_NONE, " in "); } else { ctx->script_printf(ctx, MSG_NONE, " "); } if (type & JTAG_CORE_PIN_IS_OUTPUT) { ctx->script_printf(ctx, MSG_NONE, " out "); } else { ctx->script_printf(ctx, MSG_NONE, " "); } if (type & JTAG_CORE_PIN_IS_TRISTATES) { ctx->script_printf(ctx, MSG_NONE, " tris"); } else { ctx->script_printf(ctx, MSG_NONE, " "); } ctx->script_printf(ctx, MSG_NONE, "\n"); } } } return JTAG_CORE_NO_ERROR; } return JTAG_CORE_BAD_PARAMETER; } const char *cmd_fpga_list_help[] = { "", "Lists the FPGA targets in the registry (loaded from fpga_registry.yaml).", ""}; static int cmd_fpga_list(script_ctx *ctx, char *line) { int i, n; const fpga_target *t; const char *src; (void)line; n = fpga_get_target_count(); src = fpga_registry_source(); ctx->script_printf(ctx, MSG_INFO_0, "%d FPGA target(s) registered (from %s):\n", n, src ? src : ""); for (i = 0; i < n; i++) { t = fpga_get_target_by_index(i); ctx->script_printf(ctx, MSG_NONE, " [%d] IDCODE %.8lX/%.8lX %s (%s)\n", i, t->idcode, t->idcode_mask, t->name, fpga_family_name(t->family)); ctx->script_printf(ctx, MSG_NONE, " bsdl=%s ir=%d proxy=%s caveats=0x%x\n", t->bsdl_filename, t->ir_length, t->proxy_bitstream ? t->proxy_bitstream : "(none yet)", t->caveats); } return JTAG_CORE_NO_ERROR; } const char *cmd_fpga_info_help[] = { "", "Reports, for each device on the JTAG chain, whether its IDCODE", "matches a known FPGA target. Requires jtag_scan or jtag_autoinit first.", ""}; static int cmd_fpga_info(script_ctx *ctx, char *line) { jtag_core *jc; int i, n; unsigned long idcode; const fpga_target *t; (void)line; jc = (jtag_core *)ctx->app_ctx; n = jtagcore_get_number_of_devices(jc); if (n <= 0) { ctx->script_printf(ctx, MSG_WARNING, "No device on the chain. Run jtag_autoinit first.\n"); return JTAG_CORE_NOT_FOUND; } for (i = 0; i < n; i++) { idcode = jtagcore_get_dev_id(jc, i); t = fpga_lookup_by_idcode(idcode); if (t) { ctx->script_printf(ctx, MSG_INFO_0, "Device %d IDCODE 0x%.8lX -> %s [%s]\n", i, idcode, t->name, fpga_family_name(t->family)); if (t->caveats & FPGA_CAVEAT_CCLK_VIA_STARTUP) { ctx->script_printf(ctx, MSG_NONE, " caveat: CCLK routed via STARTUP primitive (not drivable in EXTEST)\n"); } } else { ctx->script_printf(ctx, MSG_INFO_0, "Device %d IDCODE 0x%.8lX -> not in registry\n", i, idcode); } } return JTAG_CORE_NO_ERROR; } const char *cmd_bscan_set_ir_help[] = { " ", "Shifts into the IR (single-device chain).", "Useful for testing the low-level JTAG primitives.", ""}; static int cmd_bscan_set_ir(script_ctx *ctx, char *line) { char op_txt[DEFAULT_BUFLEN]; char len_txt[DEFAULT_BUFLEN]; unsigned int opcode; int ir_length, ret; jtag_core *jc = (jtag_core *)ctx->app_ctx; if (get_param(ctx, line, 1, op_txt) < 0 || get_param(ctx, line, 2, len_txt) < 0) { ctx->script_printf(ctx, MSG_ERROR, "Usage: bscan_set_ir \n"); return JTAG_CORE_BAD_PARAMETER; } opcode = (unsigned int)strtoul(op_txt, NULL, 16); ir_length = (int)strtoul(len_txt, NULL, 0); ret = bscan_set_ir(jc, opcode, ir_length); if (ret < 0) { ctx->script_printf(ctx, MSG_ERROR, "bscan_set_ir failed (%d)\n", ret); return JTAG_CORE_IO_ERROR; } ctx->script_printf(ctx, MSG_INFO_0, "IR <- 0x%X (%d bits)\n", opcode, ir_length); return JTAG_CORE_NO_ERROR; } const char *cmd_bscan_shift_dr_help[] = { "", "Shifts zeros into DR, prints the captured TDO in hex (LSB first).", "Run after bscan_set_ir to read a register (e.g. IDCODE -> shift 32 bits).", ""}; static int cmd_bscan_shift_dr(script_ctx *ctx, char *line) { char nb_txt[DEFAULT_BUFLEN]; int nbits, nbytes, i, ret; uint8_t *tdo; jtag_core *jc = (jtag_core *)ctx->app_ctx; if (get_param(ctx, line, 1, nb_txt) < 0) { ctx->script_printf(ctx, MSG_ERROR, "Usage: bscan_shift_dr \n"); return JTAG_CORE_BAD_PARAMETER; } nbits = (int)strtoul(nb_txt, NULL, 0); if (nbits <= 0 || nbits > 8 * DEFAULT_BUFLEN) { ctx->script_printf(ctx, MSG_ERROR, "Invalid nbits\n"); return JTAG_CORE_BAD_PARAMETER; } nbytes = (nbits + 7) / 8; tdo = calloc(1, (size_t)nbytes); if (!tdo) return JTAG_CORE_MEM_ERROR; ret = bscan_shift_dr(jc, NULL, tdo, nbits); if (ret < 0) { free(tdo); ctx->script_printf(ctx, MSG_ERROR, "bscan_shift_dr failed (%d)\n", ret); return JTAG_CORE_IO_ERROR; } ctx->script_printf(ctx, MSG_INFO_0, "DR ="); for (i = nbytes - 1; i >= 0; i--) { ctx->script_printf(ctx, MSG_NONE, " %.2X", tdo[i]); } ctx->script_printf(ctx, MSG_NONE, "\n"); free(tdo); return JTAG_CORE_NO_ERROR; } const char *cmd_bscan_load_bitstream_help[] = { " ", "Loads a bitstream (.bit or raw .bin) into device via JPROGRAM/CFG_IN/JSTART.", "Device must be matched in the FPGA registry (run fpga_info to check).", ""}; static int cmd_bscan_load_bitstream(script_ctx *ctx, char *line) { char dev_txt[DEFAULT_BUFLEN]; char path[DEFAULT_BUFLEN]; int device, ret; unsigned long idcode; const fpga_target *t; jtag_core *jc = (jtag_core *)ctx->app_ctx; if (get_param(ctx, line, 1, dev_txt) < 0 || get_param(ctx, line, 2, path) < 0) { ctx->script_printf(ctx, MSG_ERROR, "Usage: bscan_load_bitstream \n"); return JTAG_CORE_BAD_PARAMETER; } device = (int)strtoul(dev_txt, NULL, 0); if (jtagcore_get_number_of_devices(jc) <= 0) { ctx->script_printf(ctx, MSG_ERROR, "No device on the chain. Run jtag_autoinit first.\n"); return JTAG_CORE_NOT_FOUND; } idcode = jtagcore_get_dev_id(jc, device); t = fpga_lookup_by_idcode(idcode); if (!t) { ctx->script_printf(ctx, MSG_ERROR, "Device %d IDCODE 0x%.8lX not in FPGA registry\n", device, idcode); return JTAG_CORE_NOT_FOUND; } ctx->script_printf(ctx, MSG_INFO_0, "Loading %s on device %d (%s)...\n", path, device, t->name); ret = bscan_load_bitstream_file(jc, t, path); if (ret < 0) { ctx->script_printf(ctx, MSG_ERROR, "bscan_load_bitstream_file failed (%d)\n", ret); return JTAG_CORE_IO_ERROR; } ctx->script_printf(ctx, MSG_INFO_0, "Bitstream loaded.\n"); return JTAG_CORE_NO_ERROR; } const char *cmd_bscan_jedec_help[] = { "", "Read the SPI flash JEDEC ID (0x9F) through the loaded BSCAN proxy.", "JEDEC ID = 1 manufacturer byte (e.g. 0x20 Micron) + 2 device bytes;", "identifies which flash chip is wired to the FPGA.", "Requires a proxy bitstream already loaded (bscan_load_bitstream).", ""}; static int cmd_bscan_jedec(script_ctx *ctx, char *line) { char dev_txt[DEFAULT_BUFLEN]; int device; unsigned long idcode; const fpga_target *t; uint8_t tx = 0x9F; uint8_t rx[3] = {0}; jtag_core *jc = (jtag_core *)ctx->app_ctx; if (get_param(ctx, line, 1, dev_txt) < 0) { ctx->script_printf(ctx, MSG_ERROR, "Usage: bscan_jedec \n"); return JTAG_CORE_BAD_PARAMETER; } device = (int)strtoul(dev_txt, NULL, 0); if (jtagcore_get_number_of_devices(jc) <= 0) { ctx->script_printf(ctx, MSG_ERROR, "No device on the chain. Run jtag_autoinit first.\n"); return JTAG_CORE_NOT_FOUND; } idcode = jtagcore_get_dev_id(jc, device); t = fpga_lookup_by_idcode(idcode); if (!t) { ctx->script_printf(ctx, MSG_ERROR, "Device %d IDCODE 0x%.8lX not in FPGA registry\n", device, idcode); return JTAG_CORE_NOT_FOUND; } if (bscan_spi_xfer(jc, t, &tx, 1, rx, sizeof(rx)) < 0) { ctx->script_printf(ctx, MSG_ERROR, "bscan_spi_xfer failed (proxy not loaded?)\n"); return JTAG_CORE_IO_ERROR; } ctx->script_printf(ctx, MSG_INFO_0, "JEDEC ID: %.2X %.2X %.2X (manufacturer 0x%.2X, device 0x%.2X%.2X)\n", rx[0], rx[1], rx[2], rx[0], rx[1], rx[2]); ctx->last_data_value = (rx[0] << 16) | (rx[1] << 8) | rx[2]; return JTAG_CORE_NO_ERROR; } /* Adapt the BSCAN proxy to the spi_flash transport callback. */ struct flash_proxy_ctx { jtag_core *jc; const fpga_target *t; }; static int flash_proxy_xfer(void *c, const uint8_t *tx, size_t txlen, uint8_t *rx, size_t rxlen) { struct flash_proxy_ctx *p = (struct flash_proxy_ctx *)c; return bscan_spi_xfer(p->jc, p->t, tx, txlen, rx, rxlen); } /* Look up the FPGA target for a chain device and wire a spi_flash over * the proxy. Returns 0 and fills *sf/*pc, or prints an error and returns * a JTAG_CORE_* code. */ static int flash_setup(script_ctx *ctx, int device, spi_flash *sf, struct flash_proxy_ctx *pc) { jtag_core *jc = (jtag_core *)ctx->app_ctx; unsigned long idcode; const fpga_target *t; if (jtagcore_get_number_of_devices(jc) <= 0) { ctx->script_printf(ctx, MSG_ERROR, "No device on the chain. Run jtag_autoinit first.\n"); return JTAG_CORE_NOT_FOUND; } idcode = jtagcore_get_dev_id(jc, device); t = fpga_lookup_by_idcode(idcode); if (!t) { ctx->script_printf(ctx, MSG_ERROR, "Device %d IDCODE 0x%.8lX not in FPGA registry\n", device, idcode); return JTAG_CORE_NOT_FOUND; } pc->jc = jc; pc->t = t; memset(sf, 0, sizeof(*sf)); sf->xfer = flash_proxy_xfer; sf->ctx = pc; return JTAG_CORE_NO_ERROR; } const char *cmd_flash_detect_help[] = { "", "Identify the SPI flash behind the loaded BSCAN proxy: read its JEDEC", "ID and match the built-in chip database. Requires a proxy loaded.", ""}; static int cmd_flash_detect(script_ctx *ctx, char *line) { char dev_txt[DEFAULT_BUFLEN]; struct flash_proxy_ctx pc; spi_flash sf; int device, r; if (get_param(ctx, line, 1, dev_txt) < 0) { ctx->script_printf(ctx, MSG_ERROR, "Usage: flash_detect \n"); return JTAG_CORE_BAD_PARAMETER; } device = (int)strtoul(dev_txt, NULL, 0); if ((r = flash_setup(ctx, device, &sf, &pc)) != JTAG_CORE_NO_ERROR) return r; r = spi_flash_detect(&sf); if (r < 0) { ctx->script_printf(ctx, MSG_ERROR, "spi_flash_detect failed (proxy not loaded?)\n"); return JTAG_CORE_IO_ERROR; } ctx->script_printf(ctx, MSG_INFO_0, "JEDEC ID: %.2X %.2X %.2X\n", sf.jedec[0], sf.jedec[1], sf.jedec[2]); ctx->last_data_value = (sf.jedec[0] << 16) | (sf.jedec[1] << 8) | sf.jedec[2]; if (!sf.chip) { ctx->script_printf(ctx, MSG_WARNING, "Flash not in database — add it to spi_flash.c\n"); return JTAG_CORE_NO_ERROR; } ctx->script_printf(ctx, MSG_INFO_0, "Flash: %s - %u MB, page %u B, sector %u B, %d-byte address\n", sf.chip->name, sf.chip->size_bytes / (1024u * 1024u), sf.chip->page_size, sf.chip->sector_size, sf.chip->addr_bytes); return JTAG_CORE_NO_ERROR; } /* Set up the proxy transport and detect the flash. Returns NO_ERROR with * sf->chip set, or an error code (with a message already printed). */ static int flash_setup_detected(script_ctx *ctx, int device, spi_flash *sf, struct flash_proxy_ctx *pc) { int r = flash_setup(ctx, device, sf, pc); if (r != JTAG_CORE_NO_ERROR) return r; if (spi_flash_detect(sf) < 0 || !sf->chip) { ctx->script_printf(ctx, MSG_ERROR, "Flash not detected/known - run flash_detect first.\n"); return JTAG_CORE_NOT_FOUND; } return JTAG_CORE_NO_ERROR; } /* Read a whole file into a malloc'd buffer. Caller frees. */ static uint8_t *read_file(const char *path, size_t *out_len) { FILE *f = fopen(path, "rb"); long sz; uint8_t *b; if (!f) return NULL; if (fseek(f, 0, SEEK_END) != 0) { fclose(f); return NULL; } sz = ftell(f); rewind(f); if (sz <= 0) { fclose(f); return NULL; } b = malloc((size_t)sz); if (!b) { fclose(f); return NULL; } if (fread(b, 1, (size_t)sz, f) != (size_t)sz) { free(b); fclose(f); return NULL; } fclose(f); *out_len = (size_t)sz; return b; } const char *cmd_flash_read_help[] = { " [file]", "Read bytes from the SPI flash at (hex). With [file], dump", "the raw bytes to it (e.g. to back up before erasing); otherwise hex-dump.", "Read-only. Requires a proxy loaded and a flash known to flash_detect.", ""}; static int cmd_flash_read(script_ctx *ctx, char *line) { char dev_txt[DEFAULT_BUFLEN], addr_txt[DEFAULT_BUFLEN], len_txt[DEFAULT_BUFLEN], file[DEFAULT_BUFLEN]; struct flash_proxy_ctx pc; spi_flash sf; uint8_t *buf; uint32_t addr; size_t len, i; int device, r, to_file; if (get_param(ctx, line, 1, dev_txt) < 0 || get_param(ctx, line, 2, addr_txt) < 0 || get_param(ctx, line, 3, len_txt) < 0) { ctx->script_printf(ctx, MSG_ERROR, "Usage: flash_read [file]\n"); return JTAG_CORE_BAD_PARAMETER; } to_file = (get_param(ctx, line, 4, file) > 0); device = (int)strtoul(dev_txt, NULL, 0); addr = (uint32_t)strtoul(addr_txt, NULL, 0); len = (size_t)strtoul(len_txt, NULL, 0); if (len == 0) return JTAG_CORE_NO_ERROR; if (!to_file && len > 65536) { ctx->script_printf(ctx, MSG_ERROR, "flash_read: len capped at 65536 for a hex dump (use a file for more)\n"); return JTAG_CORE_BAD_PARAMETER; } if ((r = flash_setup_detected(ctx, device, &sf, &pc)) != JTAG_CORE_NO_ERROR) return r; buf = malloc(len); if (!buf) return JTAG_CORE_BAD_PARAMETER; if (spi_flash_read(&sf, addr, buf, len) < 0) { free(buf); ctx->script_printf(ctx, MSG_ERROR, "spi_flash_read failed\n"); return JTAG_CORE_IO_ERROR; } if (to_file) { FILE *f = fopen(file, "wb"); size_t wr = 0; if (f) { wr = fwrite(buf, 1, len, f); fclose(f); } free(buf); if (!f || wr != len) { ctx->script_printf(ctx, MSG_ERROR, "Can't write %s\n", file); return JTAG_CORE_IO_ERROR; } ctx->script_printf(ctx, MSG_INFO_0, "Read %lu bytes from 0x%.8X to %s\n", (unsigned long)len, (unsigned)addr, file); return JTAG_CORE_NO_ERROR; } for (i = 0; i < len; i += 16) { char linebuf[16 * 3 + 16]; size_t j, pos = 0; pos += (size_t)snprintf(linebuf + pos, sizeof(linebuf) - pos, "%.8X: ", (unsigned)(addr + i)); for (j = 0; j < 16 && (i + j) < len; j++) { pos += (size_t)snprintf(linebuf + pos, sizeof(linebuf) - pos, "%.2X ", buf[i + j]); } ctx->script_printf(ctx, MSG_INFO_0, "%s\n", linebuf); } free(buf); return JTAG_CORE_NO_ERROR; } const char *cmd_flash_erase_help[] = { " ", "Erase the flash sectors covering [addr, addr+len) (hex). DESTRUCTIVE.", "Requires a proxy loaded and a flash known to flash_detect.", ""}; static int cmd_flash_erase(script_ctx *ctx, char *line) { char dev_txt[DEFAULT_BUFLEN], addr_txt[DEFAULT_BUFLEN], len_txt[DEFAULT_BUFLEN]; struct flash_proxy_ctx pc; spi_flash sf; uint32_t addr, end, a, ss; size_t len; int device, r, nsec = 0; if (get_param(ctx, line, 1, dev_txt) < 0 || get_param(ctx, line, 2, addr_txt) < 0 || get_param(ctx, line, 3, len_txt) < 0) { ctx->script_printf(ctx, MSG_ERROR, "Usage: flash_erase \n"); return JTAG_CORE_BAD_PARAMETER; } device = (int)strtoul(dev_txt, NULL, 0); addr = (uint32_t)strtoul(addr_txt, NULL, 0); len = (size_t)strtoul(len_txt, NULL, 0); if (len == 0) return JTAG_CORE_NO_ERROR; if ((r = flash_setup_detected(ctx, device, &sf, &pc)) != JTAG_CORE_NO_ERROR) return r; ss = sf.chip->sector_size; end = addr + (uint32_t)len; /* exclusive */ for (a = addr - (addr % ss); a < end; a += ss) { if (spi_flash_erase_sector(&sf, a) < 0) { ctx->script_printf(ctx, MSG_ERROR, "Erase failed at 0x%.8X\n", a); return JTAG_CORE_IO_ERROR; } nsec++; } ctx->script_printf(ctx, MSG_INFO_0, "Erased %d sector(s) of %u B from 0x%.8X\n", nsec, ss, addr - (addr % ss)); return JTAG_CORE_NO_ERROR; } const char *cmd_flash_write_help[] = { " ", "Program the flash at (hex) with the contents of . DESTRUCTIVE.", "Does NOT erase first - run flash_erase over the range beforehand.", ""}; static int cmd_flash_write(script_ctx *ctx, char *line) { char dev_txt[DEFAULT_BUFLEN], addr_txt[DEFAULT_BUFLEN], file[DEFAULT_BUFLEN]; struct flash_proxy_ctx pc; spi_flash sf; uint8_t *data; uint32_t addr; size_t len = 0; int device, r; if (get_param(ctx, line, 1, dev_txt) < 0 || get_param(ctx, line, 2, addr_txt) < 0 || get_param(ctx, line, 3, file) < 0) { ctx->script_printf(ctx, MSG_ERROR, "Usage: flash_write \n"); return JTAG_CORE_BAD_PARAMETER; } device = (int)strtoul(dev_txt, NULL, 0); addr = (uint32_t)strtoul(addr_txt, NULL, 0); if ((r = flash_setup_detected(ctx, device, &sf, &pc)) != JTAG_CORE_NO_ERROR) return r; data = read_file(file, &len); if (!data) { ctx->script_printf(ctx, MSG_ERROR, "Can't read %s\n", file); return JTAG_CORE_IO_ERROR; } if (spi_flash_program(&sf, addr, data, len) < 0) { free(data); ctx->script_printf(ctx, MSG_ERROR, "spi_flash_program failed\n"); return JTAG_CORE_IO_ERROR; } free(data); ctx->script_printf(ctx, MSG_INFO_0, "Wrote %lu bytes to 0x%.8X\n", (unsigned long)len, (unsigned)addr); return JTAG_CORE_NO_ERROR; } const char *cmd_flash_verify_help[] = { " ", "Compare the flash content at (hex) against .", ""}; static int cmd_flash_verify(script_ctx *ctx, char *line) { char dev_txt[DEFAULT_BUFLEN], addr_txt[DEFAULT_BUFLEN], file[DEFAULT_BUFLEN]; struct flash_proxy_ctx pc; spi_flash sf; uint8_t *data; uint32_t addr, mismatch = 0; size_t len = 0; int device, r; if (get_param(ctx, line, 1, dev_txt) < 0 || get_param(ctx, line, 2, addr_txt) < 0 || get_param(ctx, line, 3, file) < 0) { ctx->script_printf(ctx, MSG_ERROR, "Usage: flash_verify \n"); return JTAG_CORE_BAD_PARAMETER; } device = (int)strtoul(dev_txt, NULL, 0); addr = (uint32_t)strtoul(addr_txt, NULL, 0); if ((r = flash_setup_detected(ctx, device, &sf, &pc)) != JTAG_CORE_NO_ERROR) return r; data = read_file(file, &len); if (!data) { ctx->script_printf(ctx, MSG_ERROR, "Can't read %s\n", file); return JTAG_CORE_IO_ERROR; } r = spi_flash_verify(&sf, addr, data, len, &mismatch); free(data); if (r < 0) { ctx->script_printf(ctx, MSG_ERROR, "spi_flash_verify failed\n"); return JTAG_CORE_IO_ERROR; } ctx->last_data_value = r; /* 0 = match, 1 = mismatch */ if (r == 1) { ctx->script_printf(ctx, MSG_WARNING, "Verify MISMATCH at offset 0x%X (flash 0x%.8X)\n", (unsigned)mismatch, (unsigned)(addr + mismatch)); return JTAG_CORE_NO_ERROR; } ctx->script_printf(ctx, MSG_INFO_0, "Verify OK (%lu bytes)\n", (unsigned long)len); return JTAG_CORE_NO_ERROR; } cmd_list script_commands_list[] = { {"print", cmd_print, cmd_print_help}, {"help", cmd_help, cmd_help_help}, {"?", cmd_help, cmd_help_help}, {"version", cmd_version, cmd_version_help}, {"pause", cmd_pause, cmd_pause_help}, {"set", cmd_set_env_var, cmd_set_env_var_help}, {"print_env_var", cmd_print_env_var, cmd_print_env_var_help}, {"call", cmd_call, cmd_call_help}, {"system", cmd_system, cmd_system_help}, {"if", cmd_if, cmd_if_help}, {"goto", cmd_goto, cmd_goto_help}, {"return", cmd_return, cmd_return_help}, {"rand", cmd_rand, cmd_rand_help}, {"init_array", cmd_initarray, cmd_initarray_help}, {"jtag_probes", cmd_print_probes_list, cmd_print_probes_list_help}, {"jtag_open", cmd_open_probe, cmd_open_probe_help}, {"jtag_close", cmd_close_probe, cmd_close_probe_help}, {"jtag_autoinit", cmd_autoinit, cmd_autoinit_help}, {"jtag_scan", cmd_init_and_scan, cmd_init_and_scan_help}, {"jtag_ndev", cmd_print_nb_dev, cmd_print_nb_dev_help}, {"jtag_devices", cmd_print_devs_list, cmd_print_devs_list_help}, {"jtag_bsdl", cmd_load_bsdl, cmd_load_bsdl_help}, {"jtag_mode", cmd_set_scan_mode, cmd_set_scan_mode_help}, {"jtag_push_pop", cmd_push_and_pop, cmd_push_and_pop_help}, {"jtag_pins", cmd_get_pins_list, cmd_get_pins_list_help}, {"jtag_pin_dir", cmd_set_pin_mode, cmd_set_pin_mode_help}, {"jtag_pin_set", cmd_set_pin_state, cmd_set_pin_state_help}, {"jtag_pin_get", cmd_get_pin_state, cmd_get_pin_state_help}, {"jtag_i2c_scl", cmd_set_i2c_scl_pin, cmd_set_i2c_scl_help}, {"jtag_i2c_sda", cmd_set_i2c_sda_pin, cmd_set_i2c_sda_help}, {"jtag_i2c_rd", cmd_do_i2c_rd, cmd_do_i2c_wr_help}, {"jtag_i2c_wr", cmd_do_i2c_wr, cmd_do_i2c_rd_help}, {"jtag_mdio_mdc", cmd_set_mdio_mdc_pin, cmd_set_mdio_mdc_pin_help}, {"jtag_mdio_io", cmd_set_mdio_mdio_pin, cmd_set_mdio_mdio_pin_help}, {"jtag_mdio_rd", cmd_do_mdio_rd, cmd_do_mdio_rd_help}, {"jtag_mdio_wr", cmd_do_mdio_wr, cmd_do_mdio_wr_help}, {"jtag_spi_cs", cmd_set_spi_cs_pin, cmd_set_spi_cs_pin_help}, {"jtag_spi_mosi", cmd_set_spi_mosi_pin, cmd_set_spi_mosi_pin_help}, {"jtag_spi_miso", cmd_set_spi_miso_pin, cmd_set_spi_miso_pin_help}, {"jtag_spi_clk", cmd_set_spi_clk_pin, cmd_set_spi_clk_pin_help}, {"jtag_spi_xfer", cmd_spi_rd_wr, cmd_spi_rd_wr_help}, {"fpga_list", cmd_fpga_list, cmd_fpga_list_help}, {"fpga_info", cmd_fpga_info, cmd_fpga_info_help}, {"bscan_set_ir", cmd_bscan_set_ir, cmd_bscan_set_ir_help}, {"bscan_shift_dr", cmd_bscan_shift_dr, cmd_bscan_shift_dr_help}, {"bscan_load_bitstream", cmd_bscan_load_bitstream, cmd_bscan_load_bitstream_help}, {"bscan_jedec", cmd_bscan_jedec, cmd_bscan_jedec_help}, {"flash_detect", cmd_flash_detect, cmd_flash_detect_help}, {"flash_read", cmd_flash_read, cmd_flash_read_help}, {"flash_erase", cmd_flash_erase, cmd_flash_erase_help}, {"flash_write", cmd_flash_write, cmd_flash_write_help}, {"flash_verify", cmd_flash_verify, cmd_flash_verify_help}, {0, 0}}; /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// script_ctx *jtagcore_initScript(jtag_core *jc) { return init_script((void *)jc, 0x00000000, (void *)jc->envvar); } int jtagcore_savePinsStateScript(jtag_core *jc, int device, char *script_path) { FILE *f; int number_of_pins; int pin_type; int i, state; char pin_name[DEFAULT_BUFLEN]; f = fopen(script_path, "w"); if (f) { if (jc) { number_of_pins = jtagcore_get_number_of_pins(jc, device); if (number_of_pins > 0) { for (i = 0; i < number_of_pins; i++) { pin_type = 0; jtagcore_get_pin_properties(jc, device, i, (char *)&pin_name, sizeof(pin_name), &pin_type); if (pin_type) { fprintf(f, "print ----------------------------\n"); // output enable if (pin_type & JTAG_CORE_PIN_IS_TRISTATES) { state = jtagcore_get_pin_state(jc, device, i, JTAG_CORE_OE); fprintf(f, "print Pin %s direction : %d\n", pin_name, state); fprintf(f, "jtag_pin_dir %d %s %d\n", device, pin_name, state); } // output data if (pin_type & JTAG_CORE_PIN_IS_OUTPUT) { state = jtagcore_get_pin_state(jc, device, i, JTAG_CORE_OUTPUT); fprintf(f, "print Pin %s state : %d\n", pin_name, state); fprintf(f, "jtag_pin_set %d %s %d\n", device, pin_name, state); } // input data if (pin_type & JTAG_CORE_PIN_IS_INPUT) { state = jtagcore_get_pin_state(jc, device, i, JTAG_CORE_INPUT); fprintf(f, "print Input pin %s state : %d\n", pin_name, state); } fprintf(f, "\n"); } } fprintf(f, "jtag_push_pop\n"); fprintf(f, "\n"); } } fclose(f); } return 0; }