This commit is contained in:
François Dausseur
2025-02-13 17:25:36 +01:00
parent c5fca73cc6
commit f1c68de819
19 changed files with 456 additions and 283 deletions

54
.vscode/launch.json vendored
View File

@@ -9,7 +9,7 @@
"type": "cppdbg", "type": "cppdbg",
"request": "launch", "request": "launch",
"program": "${workspaceFolder}/build/app/bs", "program": "${workspaceFolder}/build/app/bs",
"args": ["-l"], "args": [],
"stopAtEntry": false, "stopAtEntry": false,
"cwd": "${fileDirname}", "cwd": "${fileDirname}",
"environment": [], "environment": [],
@@ -28,56 +28,6 @@
} }
], ],
"preLaunchTask": "build", "preLaunchTask": "build",
}, }
{
"name": "bs scan",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/app/bs",
"args": ["-n", "2", "scan"],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "Set Disassembly Flavor to Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
],
"preLaunchTask": "build",
},
{
"name": "bs devid",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/app/bs",
"args": ["-n", "2", "-b", "/data/frd/xcku15p_ffve1517.bsd", "-d", "0x14a56093"],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "Set Disassembly Flavor to Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
],
"preLaunchTask": "build",
},
] ]
} }

View File

@@ -7,6 +7,8 @@ add_executable(
${ALL_SOURCES} ${ALL_SOURCES}
) )
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)
# linking configuration # linking configuration
target_link_libraries( target_link_libraries(
bs PRIVATE jtag_core bs PRIVATE jtag_core

View File

@@ -4,75 +4,88 @@
#include <getopt.h> #include <getopt.h>
#include <string.h> #include <string.h>
#include "common.h"
#include "args.h" #include "args.h"
char * COMMAND_STRINGS[COMMANDS_NUMBER-1] = { // void global_help() {
"scan" // printf("Usage: bs [[-l] [--list]] [[-n] [--nprobe]] [[-b] [--bsdl]] [[-d] [--device_id]] PROBE_NUM] [<cmd>] [<cmd_options>]\n");
}; // }
void usage() { // int parse_args(struct args *a, int argc, char *argv[]) {
printf("Usage: bs [[-l] [--list]] [[-n] [--nprobe]] [[-b] [--bsdl]] [[-d] [--device_id]] PROBE_NUM] [scan]\n"); // int opt = 0;
} // int i = 0;
// unsigned int devid = 0;
// int command = 0;
// __uint8_t option_arg[MAX_PATH] = {0};
int parse_args(struct args *a, int argc, char *argv[]) { // // Définir les options longues
int opt = 0; // static struct option long_options[] = {
int i = 0; // {"list", no_argument, 0, 'l'},
unsigned int devid = 0; // {"nprobe", required_argument, 0, 'n'},
int command = 0; // {"bsdl", required_argument, 0, 'b'},
__uint8_t option_arg[MAX_PATH] = {0}; // {"device_id", required_argument, 0, 'd'},
// {0, 0, 0, 0}
// };
// Définir les options longues // // Utilisation de getopt_long pour parser les options
static struct option long_options[] = { // while ((opt = getopt_long(argc, argv, "ln:b:d:", long_options, NULL)) != -1) {
{"list", no_argument, 0, 'l'}, // switch (opt) {
{"nprobe", required_argument, 0, 'n'}, // case 'h':
{"bsdl", required_argument, 0, 'b'}, // a->list = 1;
{"device_id", required_argument, 0, 'd'}, // break;
{0, 0, 0, 0} // case 'n':
}; // snprintf(option_arg, sizeof(option_arg)-2, "%s", optarg);
// a->probe = atoi(option_arg);
// break;
// case 'b':
// snprintf(a->bsdl, MAX_PATH-2, "%s", optarg);
// break;
// case 'd':
// i = sscanf(optarg, "0x%x", &devid);
// if (i == 0) {
// printf("Device ID must be an hex value like '0xABCD'");
// return EXIT_FAILURE;
// }
// break;
// default:
// usage();
// return EXIT_FAILURE;
// }
// }
// Utilisation de getopt_long pour parser les options // // Positional arguments
while ((opt = getopt_long(argc, argv, "ln:b:d:", long_options, NULL)) != -1) { // if (optind < argc) {
switch (opt) { // /* Positional arguments */
case 'l': // while (optind < argc) {
a->list = 1; // for (i=0;i<COMMANDS_NUMBER-1;i++) {
break; // if (0 == strcmp(COMMAND_STRINGS[i], argv[optind])) {
case 'n': // a->cmds[command] = (enum commands)i+1;
snprintf(option_arg, sizeof(option_arg)-2, "%s", optarg); // }
a->probe = atoi(option_arg); // }
break; // optind++;
case 'b': // }
snprintf(a->bsdl, MAX_PATH-2, "%s", optarg); // }
break;
case 'd': // // Si aucune option n'est fournie, afficher l'aide
i = sscanf(optarg, "0x%x", &devid); // if (optind == 1) {
if (i == 0) { // usage();
printf("Device ID must be an hex value like '0xABCD'"); // }
return EXIT_FAILURE;
} // return EXIT_SUCCESS;
break; // }
default:
usage(); void parse_command(char *line, int *argc, char **argv) {
return EXIT_FAILURE; *argc = 0;
while (*line != '\0') {
while (*line == ' ' || *line == '\t' || *line == '\n') {
*line++ = '\0';
}
if (*argc >= MAX_ARGS) break;
(*argc)++;
*argv++ = line;
while (*line != '\0' && *line != ' ' && *line != '\t' && *line != '\n') {
line++;
} }
} }
*argv = '\0';
// Positional arguments
if (optind < argc) {
/* Positional arguments */
while (optind < argc) {
for (i=0;i<COMMANDS_NUMBER-1;i++) {
if (0 == strcmp(COMMAND_STRINGS[i], argv[optind])) {
a->cmds[command] = (enum commands)i+1;
}
}
optind++;
}
}
// Si aucune option n'est fournie, afficher l'aide
if (optind == 1) {
usage();
}
return EXIT_SUCCESS;
} }

View File

@@ -1,23 +1,20 @@
#ifndef _ARGS_H #ifndef _ARGS_H
#define _ARGS_H #define _ARGS_H
#define MAX_COMMANDS 16 // #define MAX_LINE 1024
#define MAX_PATH 1024 // #define MAX_ARGS 16
// #define MAX_COMMANDS 16
// #define MAX_PATH 1024
enum commands { // struct args {
NO_COMMAND=0, // int list;
COMMAND_SCAN, // int probe;
COMMANDS_NUMBER, /* The number of enums +1*/ // char bsdl[MAX_PATH];
}; // int devid;
// enum commands cmds[MAX_COMMANDS];
// };
struct args { // int parse_args(struct args *a, int argc, char *argv[]);
int list; void parse_command(char *line, int *argc, char **argv);
int probe;
char bsdl[MAX_PATH];
int devid;
enum commands cmds[MAX_COMMANDS];
};
int parse_args(struct args *a, int argc, char *argv[]);
#endif #endif

11
app/src/cmds/exit.c Normal file
View File

@@ -0,0 +1,11 @@
#include <stdio.h>
#include <stdlib.h>
#include "exit.h"
const char cmd_exit_help[] = "Bla bla.";
int cmd_exit(jtag_core *jc, int argc, char **argv) {
jtagcore_deinit(jc);
exit(0);
}

10
app/src/cmds/exit.h Normal file
View File

@@ -0,0 +1,10 @@
#ifndef _CMD_EXIT_H
#define _CMD_EXIT_H
#include "jtag_core.h"
extern const char cmd_exit_help[];
int cmd_exit(jtag_core *jc, int argc, char *argv[]);
#endif /* _CMD_EXIT_H */

8
app/src/cmds/help.c Normal file
View File

@@ -0,0 +1,8 @@
#include <stdio.h>
#include <stdlib.h>
#include "help.h"
int cmd_help(jtag_core *jc, int argc, char **argv) {
}

8
app/src/cmds/help.h Normal file
View File

@@ -0,0 +1,8 @@
#ifndef _CMD_HELP_H
#define _CMD_HELP_H
#include "jtag_core.h"
int cmd_help(jtag_core *jc, int argc, char *argv[]);
#endif /* _CMD_help_H */

View File

@@ -0,0 +1,69 @@
#include <stdio.h>
#include <string.h>
#include "list_probes.h"
#include "common.h"
const char cmd_list_probes_help[] = "Bla bla.";
struct probe {
int drv;
int probe;
int probe_id;
char name[PROBE_NAME_SIZE];
};
int list_probes(jtag_core *jc, struct probe probes[], int show) {
int i = 0;
int j = 0;
int n = 0;
char probe_name[PROBE_NAME_SIZE] = {0};
int n_probe_drv = 0;
int n_probes = 0;
/* Drivers and probes */
n_probe_drv = jtagcore_get_number_of_probes_drv(jc);
if (n_probe_drv > 0) {
if (0 != show) printf("Found a debug probe driver:\n");
} else {
if (0 != show) printf("No probes driver found\n");
return n;
}
for (i=0;i<n_probe_drv;i++) {
if (0 != show) printf(" JTAG probe driver %d\n", i);
n_probes = jtagcore_get_number_of_probes(jc, i);
if (n_probes > 0) {
if (0 != show) printf("Found a debug probe:\n");
} else {
if (0 != show) printf("No probe found.\n");
continue;
}
for (j=0;j<n_probes;j++) {
jtagcore_get_probe_name(jc, PROBE_ID(i,j), probe_name);
if (n < PROBES_MAX_NUM) {
probes[n].drv = i;
probes[n].probe = j;
probes[n].probe_id = PROBE_ID(i,j);
strncpy(probes[n].name, probe_name, PROBE_NAME_SIZE);
}
if (0 != show) {
printf(" JTAG probe %d: ", n+1);
printf("%s.\n", probe_name);
}
n++;
}
}
return n;
}
int cmd_list_probes(jtag_core *jc, int argc, char *argv[]) {
}

View File

@@ -0,0 +1,10 @@
#ifndef _LIST_PROBES_H
#define _LIST_PROBES_H
#include "jtag_core.h"
const char cmd_list_probes_help[];
int cmd_list_probes(jtag_core *jc, int argc, char *argv[]);
#endif

39
app/src/cmds/scan.c Normal file
View File

@@ -0,0 +1,39 @@
#include <stdio.h>
#include "scan.h"
#include "common.h"
const char cmd_scan_help[] = "Bla bla.";
int scan(jtag_core *jc, int probe_id, int *ndevs, unsigned long ids[], int show) {
int err = JTAG_CORE_NO_ERROR;
int n = 0;
int i = 0;
if (0 != show) printf("Devices scan in progress...\n");
err = jtagcore_scan_and_init_chain(jc);
if (err < 0) {
if (0 != show) printf("Impossible to scan the JTAG chain");
return err;
}
n = jtagcore_get_number_of_devices(jc);
if (n < 0) {
if (0 != show) printf("Error while getting the number of devices on the chain.\n");
return err;
}
*ndevs = n;
for (i=0;i < MIN(n, DEVICES_SCAN_MAX);i++) {
ids[i] = jtagcore_get_dev_id(jc, i);
if (0 != show) printf(" device %d : 0x%08x\n", i, ids[i]);
}
if (0 != show) printf("Done.\n");
return err;
}
int cmd_scan(jtag_core *jc, int argc, char *argv[]) {
}

11
app/src/cmds/scan.h Normal file
View File

@@ -0,0 +1,11 @@
#ifndef _CMDS_SCAN_H
#define _CMDS_SCAN_H
#include "jtag_core.h"
extern const char cmd_scan_help[];
int cmd_scan(jtag_core *jc, int argc, char *argv[]);
#endif

View File

@@ -0,0 +1,16 @@
#include <stdio.h>
#include "select_probe.h"
const char cmd_select_probe_help[] = "Bla bla.";
int cmd_select_probe(jtag_core *jc, int argc, char *argv[]) {
int error = 0;
error = jtagcore_select_and_open_probe(jc, probe_id);
if (error < 0) {
printf("Impossible to open the selected probe.\n");
return error;
}
}

View File

@@ -0,0 +1,10 @@
#ifndef _SELECT_PROBE_H
#define _SELECT_PROBE_H
#include "jtag_core.h"
extern const char cmd_select_probe_help[];
int cmd_select_probe(jtag_core *jc, int argc, char *argv[]);
#endif

41
app/src/common.c Normal file
View File

@@ -0,0 +1,41 @@
#include <stddef.h>
#include <stdio.h>
#include "common.h"
#include "cmds/help.h"
#include "cmds/scan.h"
#include "cmds/list_probes.h"
#include "cmds/exit.h"
#include "cmds/select_probe.h"
// Table des commandes internes
Command commands[] = {
{"help", cmd_help, NULL},
{"list_probes", cmd_list_probes, cmd_list_probes_help},
{"scan", cmd_scan, cmd_scan_help},
{"select_probe", cmd_select_probe, cmd_select_probe_help},
{"exit", cmd_exit, cmd_exit_help},
{NULL, NULL}
};
void jprint(jtag_core *jc, const char *msg) {
printf(msg);
}
jtag_core * bsexp_init(void) {
jtag_core *ret = NULL;
/* initialize the JTAG library */
ret = jtagcore_init();
if (NULL != ret) {
/* Log printing callback */
if (jtagcore_set_logs_callback(ret, jprint) < 0) {
printf("Impossible to define the logs callback!\n");
} else {
jtagcore_set_logs_level(ret, MSG_DEBUG);
}
}
return ret;
}

26
app/src/common.h Normal file
View File

@@ -0,0 +1,26 @@
#ifndef _UTILS_H
#define _UTILS_H
#include "jtag_core.h"
#define MAX_LINE 1024
#define MAX_ARGS 16
#define PROBES_MAX_NUM 16
#define PROBE_NAME_SIZE 64
#define DEVICES_SCAN_MAX 32
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
typedef int (*command_call)(jtag_core *jc, int argc, char *argv[]);
typedef struct {
char *name;
command_call cmd_call;
} Command;
extern Command commands[];
jtag_core *bsexp_init(void);
#endif

View File

@@ -2,162 +2,116 @@
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <readline/readline.h>
#include <readline/history.h>
#include "jtag_core.h" #include "jtag_core.h"
#include "common.h"
#include "args.h" #include "args.h"
#include "utils.h"
// int main(int argc, char *argv[]) {
// int success = 0;
// int n_probes = 0;
// int i = 0;
// int error = 0;
// jtag_core *jc = NULL;
// struct args a = {0};
// struct probe probes[PROBES_MAX_NUM] = {0};
// unsigned long dev_ids[DEVICES_SCAN_MAX] = {0};
// int ndevs = 0;
// success = parse_args(&a, argc, argv);
// if (EXIT_FAILURE == success) exit(EXIT_FAILURE);
// jc = bsexp_init();
// if (NULL == jc) {
// error = JTAG_CORE_MEM_ERROR;
// goto err;
// }
// /* List the probes (and display if asked) */
// n_probes = list_probes(jc, probes, a.list);
// i = 0;
// while ((i<MAX_COMMANDS) && (a.cmds[i] != NO_COMMAND)) {
// switch (a.cmds[i]) {
// case COMMAND_SCAN:
// if ((0 >= a.probe) || (a.probe > MIN(n_probes, PROBES_MAX_NUM))) goto err;
// error = scan(jc, probes[a.probe-1].probe_id, &ndevs, dev_ids, 1);
// break;
// default:
// printf("Unknown command.");
// goto err;
// }
// i++;
// }
// goto end;
// err:
// printf("Exited with error (%d).\n", error);
// end:
// jtagcore_deinit(jc);
// return error;
// }
#define PROBES_MAX_NUM 16 int execute_command(jtag_core *jc, int argc, char **argv) {
#define PROBE_NAME_SIZE 64
#define DEVICES_SCAN_MAX 32
struct probe {
int drv;
int probe;
int probe_id;
char name[PROBE_NAME_SIZE];
};
void jprint(jtag_core *jc, const char *msg) {
printf(msg);
}
int list_probes(jtag_core *jc, struct probe probes[], int show) {
int i = 0;
int j = 0;
int n = 0;
char probe_name[PROBE_NAME_SIZE] = {0};
int n_probe_drv = 0;
int n_probes = 0;
/* Drivers and probes */
n_probe_drv = jtagcore_get_number_of_probes_drv(jc);
if (n_probe_drv > 0) {
if (0 != show) printf("Found a debug probe driver:\n");
} else {
if (0 != show) printf("No probes driver found\n");
return n;
}
for (i=0;i<n_probe_drv;i++) {
if (0 != show) printf(" JTAG probe driver %d\n", i);
n_probes = jtagcore_get_number_of_probes(jc, i);
if (n_probes > 0) {
if (0 != show) printf("Found a debug probe:\n");
} else {
if (0 != show) printf("No probe found.\n");
continue;
}
for (j=0;j<n_probes;j++) {
jtagcore_get_probe_name(jc, PROBE_ID(i,j), probe_name);
if (n < PROBES_MAX_NUM) {
probes[n].drv = i;
probes[n].probe = j;
probes[n].probe_id = PROBE_ID(i,j);
strncpy(probes[n].name, probe_name, PROBE_NAME_SIZE);
}
if (0 != show) {
printf(" JTAG probe %d: ", n+1);
printf("%s.\n", probe_name);
}
n++;
}
}
return n;
}
int scan(jtag_core *jc, int probe_id, int *ndevs, unsigned long ids[], int show) {
int err = JTAG_CORE_NO_ERROR;
int n = 0;
int i = 0;
if (0 != show) printf("Devices scan in progress...\n");
err = jtagcore_select_and_open_probe(jc, probe_id);
if (err < 0) {
if (0 != show) printf("Impossible to open the selected probe.\n");
return err;
}
err = jtagcore_scan_and_init_chain(jc);
if (err < 0) {
if (0 != show) printf("Impossible to scan the JTAG chain");
return err;
}
n = jtagcore_get_number_of_devices(jc);
if (n < 0) {
if (0 != show) printf("Error while getting the number of devices on the chain.\n");
return err;
}
*ndevs = n;
for (i=0;i < MIN(n, DEVICES_SCAN_MAX);i++) {
ids[i] = jtagcore_get_dev_id(jc, i);
if (0 != show) printf(" device %d : 0x%08x\n", i, ids[i]);
}
if (0 != show) printf("Done.\n");
return err;
}
int main(int argc, char *argv[]) {
int success = 0;
int n_probes = 0;
int i = 0;
int error = 0; int error = 0;
if (argv[0] == NULL) {
return 0;
}
for (int i = 0; commands[i].name != NULL; i++) {
if (strcmp(argv[0], commands[i].name) == 0) {
error = commands[i].cmd_call(jc, argc, argv);
return error;
}
}
error = -1;
printf("Command not found\n");
}
int main() {
char *line = NULL;
int error = 0;
int cmd_argc=0;
char *cmd_argv[MAX_ARGS] = {0};
jtag_core *jc = NULL; jtag_core *jc = NULL;
struct args a = {0}; jc = bsexp_init();
struct probe probes[PROBES_MAX_NUM] = {0}; if (NULL == jc) {
unsigned long dev_ids[DEVICES_SCAN_MAX] = {0}; error = JTAG_CORE_MEM_ERROR;
int ndevs = 0; printf("JTAG Core execution failed");
goto err;
success = parse_args(&a, argc, argv);
if (EXIT_FAILURE == success) exit(EXIT_FAILURE);
/* initialize the JTAG library */
jc = jtagcore_init();
/* Log printing callback */
if (jtagcore_set_logs_callback(jc, jprint) < 0) goto err;
jtagcore_set_logs_level(jc, MSG_DEBUG);
/* List the probes (and display if asked) */
n_probes = list_probes(jc, probes, a.list);
i = 0;
while ((i<MAX_COMMANDS) && (a.cmds[i] != NO_COMMAND)) {
switch (a.cmds[i]) {
case COMMAND_SCAN:
if ((0 >= a.probe) || (a.probe > MIN(n_probes, PROBES_MAX_NUM))) goto err;
error = scan(jc, probes[a.probe-1].probe_id, &ndevs, dev_ids, 1);
break;
default:
printf("Unknown command.");
goto err;
}
i++;
} }
goto end; while (1) {
line = readline("bs_explorer> ");
if (line == NULL) {
break;
}
if (*line) {
add_history(line);
}
parse_command(line, &cmd_argc, cmd_argv);
if (cmd_argv[0] == NULL) {
continue;
}
if (strcmp(cmd_argv[0], "exit") == 0) {
break;
}
error = execute_command(jc, cmd_argc, cmd_argv);
printf("\n");
if (0 == error) {
} else {
printf("Command failed with code: %d", error);
}
}
return 0;
err: err:
printf("Exited with error (%d).\n", error);
end:
jtagcore_deinit(jc);
return error; return error;
} }

View File

@@ -1,7 +0,0 @@
#ifndef _UTILS_H
#define _UTILS_H
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
#endif

View File

@@ -1,3 +1,6 @@
#ifndef _JTAG_CORE_H
#define _JTAG_CORE_H
/* /*
* JTAG Core library * JTAG Core library
* Copyright (c) 2008 - 2024 Viveris Technologies * Copyright (c) 2008 - 2024 Viveris Technologies
@@ -340,3 +343,5 @@ int jtagemu_get_regbit_state(jtag_emu * je, int regid, int bit);
int jtagemu_loadbsdlfile(jtag_emu * je, char * path, int device); int jtagemu_loadbsdlfile(jtag_emu * je, char * path, int device);
void jtagemu_deinit(jtag_emu * je); void jtagemu_deinit(jtag_emu * je);
#endif