From fe275effebf14afd93133eb0a82c85a399ea6212 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 16 Sep 2019 16:29:08 +0100 Subject: [PATCH] New C based JTAG debug tool This works with both the sim socket and urjtag, and supports the new core functions, loading a file in memory etc... The code still needs a lot of cleanup and a help! Signed-off-by: Benjamin Herrenschmidt --- scripts/mw_debug.py | 103 ------- scripts/mw_debug/Makefile | 7 + scripts/mw_debug/mw_debug.c | 583 ++++++++++++++++++++++++++++++++++++ 3 files changed, 590 insertions(+), 103 deletions(-) delete mode 100755 scripts/mw_debug.py create mode 100644 scripts/mw_debug/Makefile create mode 100644 scripts/mw_debug/mw_debug.c diff --git a/scripts/mw_debug.py b/scripts/mw_debug.py deleted file mode 100755 index f22039c..0000000 --- a/scripts/mw_debug.py +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/python3 - -import urjtag; - -def do_command(urc, op, addr, data): - urc.set_dr_in(op,1,0) - urc.set_dr_in(data,65,2) - urc.set_dr_in(addr,73,66) -# print("Sending:", urc.get_dr_in_string()) - urc.shift_dr() - urc.set_dr_in(0x0,73,0) - for x in range(5): - urc.shift_dr() -# print("Received:", urc.get_dr_out_string()) - rsp_code = urc.get_dr_out(1,0) - if rsp_code == 0: - return urc.get_dr_out(65,2) - if rsp_code != 3: - print("Weird response ! rsp=%x" % rsp_code); - print("Timeout sending command !") - -def do_read(urc, addr): - return do_command(urc, 1, addr, 0) - -def do_write(urc, addr, val): - do_command(urc, 2, addr, val) - -def main(): - # Init jtag - #urjtag.loglevel( urjtag.URJ_LOG_LEVEL_ALL ) - - urc = urjtag.chain() - urc.cable("DigilentHS1") - print('Cable frequency:', urc.get_frequency()) - #urc.tap_detect() - #length = urc.len() - #for i in range(0,urc.len()): - # idcode = urc.partid(0) - # print('[%d] 0x%08x' % (i, idcode)) - urc.addpart(6); - print("Part ID: ", urc.partid(0)) - #urc.part(0) - #urc.reset(); - urc.add_register("USER2_REG", 74); - urc.add_instruction("USER2", "000011", "USER2_REG"); - urc.add_register("IDCODE_REG", 32); - urc.add_instruction("IDCODE", "001001", "IDCODE_REG"); - # Send test command - urc.set_instruction("IDCODE") - urc.shift_ir() - urc.shift_dr() - print("Got:", hex(urc.get_dr_out())) - - urc.set_instruction("USER2") - urc.shift_ir() - - print("Reading memory at 0:") - do_write(urc, 0, 0) - do_write(urc, 2, 0x7ff) - print("00: %016x" % do_read(urc, 1)) - print("08: %016x" % do_read(urc, 1)) - print("10: %016x" % do_read(urc, 1)) - print("18: %016x" % do_read(urc, 1)) - do_write(urc, 0, 0x10) - do_write(urc, 1, 0xabcdef0123456789) - do_write(urc, 0, 0) - do_write(urc, 2, 0x7ff) - print("00: %016x" % do_read(urc, 1)) - print("08: %016x" % do_read(urc, 1)) - print("10: %016x" % do_read(urc, 1)) - print("18: %016x" % do_read(urc, 1)) - -# urc.set_dr_in(0,73,0); -# print("Test DR_IN 1:", urc.get_dr_in_string()) -# urc.set_dr_in(0xa,3,0); -# print("Test DR_IN 2:", urc.get_dr_in_string()) -# urc.set_dr_in(0x5,7,4); -# print("Test DR_IN 3:", urc.get_dr_in_string()) -# urc.set_dr_in(1,73,73); -# print("Test DR_IN 4:", urc.get_dr_in_string()) - -# print("Reading ADDR reg: %x" % do_read(urc, 0)) -# print("Writing all 1's to it:") -# do_write(urc, 0, 0xffffffffffffffff) -# print("Reading ADDR reg: %x" % do_read(urc, 0)) -# print("Writing 0xabcdef0123456789 to it:") -# do_write(urc, 0, 0xabcdef0123456789) -# print("Reading ADDR reg: %x" % do_read(urc, 0)) - - - -# urc.set_dr_in(0x1,41,0) -# print("Sending:", urc.get_dr_in_string()) -# urc.shift_dr() -# urc.set_dr_in(0x0,41,0) -# urc.shift_dr() -# print("Got1:", urc.get_dr_out_string()) -# urc.shift_dr() -# print("Got2:", hex(urc.get_dr_out())) - - -if __name__ == "__main__": - main() diff --git a/scripts/mw_debug/Makefile b/scripts/mw_debug/Makefile new file mode 100644 index 0000000..439b198 --- /dev/null +++ b/scripts/mw_debug/Makefile @@ -0,0 +1,7 @@ +CFLAGS = -O2 -g -Wall -std=c99 + +all: mw_debug + +mw_debug: mw_debug.c + $(CC) -o $@ $^ -lurjtag + diff --git a/scripts/mw_debug/mw_debug.c b/scripts/mw_debug/mw_debug.c new file mode 100644 index 0000000..f1a7cab --- /dev/null +++ b/scripts/mw_debug/mw_debug.c @@ -0,0 +1,583 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DBG_WB_ADDR 0x00 +#define DBG_WB_DATA 0x01 +#define DBG_WB_CTRL 0x02 + +#define DBG_CORE_CTRL 0x10 +#define DBG_CORE_CTRL_STOP (1 << 0) +#define DBG_CORE_CTRL_RESET (1 << 1) +#define DBG_CORE_CTRL_ICRESET (1 << 2) +#define DBG_CORE_CTRL_STEP (1 << 3) +#define DBG_CORE_CTRL_START (1 << 4) + +#define DBG_CORE_STAT 0x11 +#define DBG_CORE_STAT_STOPPING (1 << 0) +#define DBG_CORE_STAT_STOPPED (1 << 1) +#define DBG_CORE_STAT_TERM (1 << 2) + +#define DBG_CORE_NIA 0x12 + +static bool debug; + +struct backend { + int (*init)(const char *target); + int (*reset)(void); + int (*command)(uint8_t op, uint8_t addr, uint64_t *data); +}; +static struct backend *b; + +static void check(int r, const char *failstr) +{ + if (r >= 0) + return; + fprintf(stderr, "Error %s\n", failstr); + exit(1); +} + +/* -------------- SIM backend -------------- */ + +static int sim_fd = -1; + +static int sim_init(const char *target) +{ + struct sockaddr_in saddr; + struct hostent *hp; + const char *p, *host; + int port, rc; + + if (!target) + target = "localhost:13245"; + p = strchr(target, ':'); + host = strndup(target, p - target); + if (p && *p) + p++; + else + p = "13245"; + port = strtoul(p, NULL, 10); + if (debug) + printf("Opening sim backend host '%s' port %d\n", host, port); + + sim_fd = socket(PF_INET, SOCK_STREAM, 0); + if (sim_fd < 0) { + fprintf(stderr, "Error opening socket: %s\n", + strerror(errno)); + return -1; + } + hp = gethostbyname(host); + if (!hp) { + fprintf(stderr,"Unknown host '%s'\n", host); + return -1; + } + memcpy(&saddr.sin_addr, hp->h_addr, hp->h_length); + saddr.sin_port = htons(port); + saddr.sin_family = PF_INET; + rc = connect(sim_fd, (struct sockaddr *)&saddr, sizeof(saddr)); + if (rc < 0) { + close(sim_fd); + fprintf(stderr,"Connection to '%s' failed: %s\n", + host, strerror(errno)); + return -1; + } + return 0; +} + +static int sim_reset(void) +{ +} + +static void add_bits(uint8_t **p, int *b, uint64_t d, int c) +{ + uint8_t md = 1 << *b; + uint64_t ms = 1; + + while (c--) { + if (d & ms) + (**p) |= md; + ms <<= 1; + if (*b == 7) { + *b = 0; + (*p)++; + md = 1; + } else { + (*b)++; + md <<= 1; + } + } +} + +static uint64_t read_bits(uint8_t **p, int *b, int c) +{ + uint8_t ms = 1 << *b; + uint64_t md = 1; + uint64_t d = 0; + + while (c--) { + if ((**p) & ms) + d |= md; + md <<= 1; + if (*b == 7) { + *b = 0; + (*p)++; + ms = 1; + } else { + (*b)++; + ms <<= 1; + } + } + return d; +} + +static int sim_command(uint8_t op, uint8_t addr, uint64_t *data) +{ + uint8_t buf[16], *p; + uint64_t d = data ? *data : 0; + int r, s, b = 0; + + memset(buf, 0, 16); + p = buf+1; + add_bits(&p, &b, op, 2); + add_bits(&p, &b, d, 64); + add_bits(&p, &b, addr, 8); + if (b) + p++; + buf[0] = 74; + if (0) + { + int i; + + for (i=0; i<(p-buf); i++) + printf("%02x ", buf[i]); + printf("\n"); + } + write(sim_fd, buf, p - buf); + r = read(sim_fd, buf, 127); + if (0 && r > 0) { + int i; + + for (i=0; imain_part = 0; + + rc = urj_tap_chain_connect(jc, cable, params); + if (rc != URJ_STATUS_OK) { + fprintf(stderr, "JTAG cable detect failed\n"); + return -1; + } + + /* XXX Hard wire part 0, that might need to change (use params and detect !) */ + rc = urj_tap_manual_add(jc, 6); + if (rc < 0) { + fprintf(stderr, "JTAG failed to add part !\n"); + return -1; + } + if (jc->parts == NULL || jc->parts->len == 0) { + fprintf(stderr, "JTAG Something's wrong after adding part !\n"); + return -1; + } + urj_part_parts_set_instruction(jc->parts, "BYPASS"); + + jc->active_part = part = 0; + + p = urj_tap_chain_active_part(jc); + if (!p) { + fprintf(stderr, "Failed to get active JTAG part\n"); + return -1; + } + rc = urj_part_data_register_define(p, "IDCODE_REG", 32); + if (rc != URJ_STATUS_OK) { + fprintf(stderr, "JTAG failed to add IDCODE_REG register !\n"); + return -1; + } + if (urj_part_instruction_define(p, "IDCODE", "001001", "IDCODE_REG") == NULL) { + fprintf(stderr, "JTAG failed to add IDCODE instruction !\n"); + return -1; + } + rc = urj_part_data_register_define(p, "USER2_REG", 74); + if (rc != URJ_STATUS_OK) { + fprintf(stderr, "JTAG failed to add USER2_REG register !\n"); + return -1; + } + if (urj_part_instruction_define(p, "USER2", "000011", "USER2_REG") == NULL) { + fprintf(stderr, "JTAG failed to add USER2 instruction !\n"); + return -1; + } + urj_part_set_instruction(p, "IDCODE"); + urj_tap_chain_shift_instructions(jc); + urj_tap_chain_shift_data_registers(jc, 1); + id = urj_tap_register_get_value(p->active_instruction->data_register->out); + printf("Found device ID: 0x%08x\n", id); + urj_part_set_instruction(p, "USER2"); + urj_tap_chain_shift_instructions(jc); + + return 0; +} + +static int jtag_reset(void) +{ +} + +static int jtag_command(uint8_t op, uint8_t addr, uint64_t *data) +{ + urj_part_t *p = urj_tap_chain_active_part(jc); + urj_part_instruction_t *insn; + urj_data_register_t *dr; + uint64_t d = data ? *data : 0; + int rc; + + if (!p) + return -1; + insn = p->active_instruction; + if (!insn) + return -1; + dr = insn->data_register; + if (!dr) + return -1; + rc = urj_tap_register_set_value_bit_range(dr->in, op, 1, 0); + if (rc != URJ_STATUS_OK) + return -1; + rc = urj_tap_register_set_value_bit_range(dr->in, d, 65, 2); + if (rc != URJ_STATUS_OK) + return -1; + rc = urj_tap_register_set_value_bit_range(dr->in, addr, 73, 66); + if (rc != URJ_STATUS_OK) + return -1; + rc = urj_tap_chain_shift_data_registers(jc, 1); + if (rc != URJ_STATUS_OK) + return -1; + rc = urj_tap_register_get_value_bit_range(dr->out, 1, 0); + if (data) + *data = urj_tap_register_get_value_bit_range(dr->out, 65, 2); + return rc; +} + +static struct backend jtag_backend = { + .init = jtag_init, + .reset = jtag_reset, + .command = jtag_command, +}; + +static int dmi_read(uint8_t addr, uint64_t *data) +{ + int rc; + + rc = b->command(1, addr, data); + if (rc < 0) + return rc; + for (;;) { + rc = b->command(0, 0, data); + if (rc < 0) + return rc; + if (rc == 0) + return 0; + if (rc != 3) + fprintf(stderr, "Unknown status code %d !\n", rc); + } +} + +static int dmi_write(uint8_t addr, uint64_t data) +{ + int rc; + + rc = b->command(2, addr, &data); + if (rc < 0) + return rc; + for (;;) { + rc = b->command(0, 0, NULL); + if (rc < 0) + return rc; + if (rc == 0) + return 0; + if (rc != 3) + fprintf(stderr, "Unknown status code %d !\n", rc); + } +} + +static void core_status(void) +{ + uint64_t stat, nia; + const char *statstr, *statstr2; + + check(dmi_read(DBG_CORE_STAT, &stat), "reading core status"); + check(dmi_read(DBG_CORE_NIA, &nia), "reading core NIA"); + + if (debug) + printf("Core status = 0x%llx\n", (unsigned long long)stat); + statstr = "running"; + statstr2 = ""; + if (stat & DBG_CORE_STAT_STOPPED) { + statstr = "stopped"; + if (!(stat & DBG_CORE_STAT_STOPPING)) + statstr2 = " (restarting?)"; + else if (stat & DBG_CORE_STAT_TERM) + statstr2 = " (terminated)"; + } else if (stat & DBG_CORE_STAT_STOPPING) + statstr = "stopping"; + else if (stat & DBG_CORE_STAT_TERM) + statstr = "odd state (TERM but no STOP)"; + printf("Core: %s%s\n", statstr, statstr2); + printf(" NIA: %016llx\n", (unsigned long long)nia); +} + +static void core_stop(void) +{ + check(dmi_write(DBG_CORE_CTRL, DBG_CORE_CTRL_STOP), "stopping core"); +} + +static void core_start(void) +{ + check(dmi_write(DBG_CORE_CTRL, DBG_CORE_CTRL_START), "starting core"); +} + +static void core_reset(void) +{ + check(dmi_write(DBG_CORE_CTRL, DBG_CORE_CTRL_START), "resetting core"); +} + +static void core_step(void) +{ + uint64_t stat; + + check(dmi_read(DBG_CORE_STAT, &stat), "reading core status"); + + if (!(stat & DBG_CORE_STAT_STOPPED)) { + printf("Core not stopped !\n"); + return; + } + check(dmi_write(DBG_CORE_CTRL, DBG_CORE_CTRL_STEP), "stepping core"); +} + +static void icache_reset(void) +{ + check(dmi_write(DBG_CORE_CTRL, DBG_CORE_CTRL_ICRESET), "resetting icache"); +} + +static void mem_read(uint64_t addr, uint64_t count) +{ + uint64_t data; + int i, rc; + + rc = dmi_write(2, 0x7ff); + if (rc < 0) + return; + rc = dmi_write(0, addr); + if (rc < 0) + return; + for (i = 0; i < count; i++) { + rc = dmi_read(1, &data); + if (rc < 0) + return; + printf("%016llx: %016llx\n", + (unsigned long long)addr, + (unsigned long long)data); + addr += 8; + } +} + +static void load(const char *filename, uint64_t addr) +{ + uint64_t data; + int fd, rc, count; + + fd = open(filename, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "Failed to open '%s': %s\n", filename, strerror(errno)); + exit(1); + } + // XX dumb, do better + rc = dmi_write(2, 0x7ff); + if (rc < 0) + return; + rc = dmi_write(0, addr); + if (rc < 0) + return; + count = 0; + for (;;) { + data = 0; + rc = read(fd, &data, 8); + if (rc <= 0) + break; + // if (rc < 8) XXX fixup endian ? + dmi_write(1, data); + count += 8; + if (!(count % 1024)) + printf("%x...\n", count); + } + printf("%x done.\n", count); +} + +static void usage(const char *cmd) +{ + fprintf(stderr, "Usage: %s \n", cmd); + exit(1); +} + +int main(int argc, char *argv[]) +{ + const char *progname = argv[0]; + const char *target = NULL; + int rc, i = 1; + + b = NULL; + + while(1) { + int c, oindex; + static struct option lopts[] = { + { "help", no_argument, 0, 'h' }, + { "backend", required_argument, 0, 'b' }, + { "target", required_argument, 0, 't' }, + { "debug", no_argument, 0, 'd' }, + { 0, 0, 0, 0 } + }; + c = getopt_long(argc, argv, "dhb:t:", lopts, &oindex); + if (c < 0) + break; + switch(c) { + case 'h': + usage(progname); + break; + case 'b': + if (strcmp(optarg, "sim") == 0) + b = &sim_backend; + else if (strcmp(optarg, "jtag") == 0) + b = &jtag_backend; + else { + fprintf(stderr, "Unknown backend %s\n", optarg); + exit(1); + } + break; + case 't': + target = optarg; + break; + case 'd': + debug = true; + } + } + + if (b == NULL) { + fprintf(stderr, "No backend selected\n"); + exit(1); + } + + rc = b->init(target); + if (rc < 0) + exit(1); + for (i = optind; i < argc; i++) { + if (strcmp(argv[i], "dmiread") == 0) { + uint8_t addr; + uint64_t data; + + if ((i+1) >= argc) + usage(argv[0]); + addr = strtoul(argv[++i], NULL, 16); + dmi_read(addr, &data); + printf("%02x: %016llx\n", addr, (unsigned long long)data); + } else if (strcmp(argv[i], "dmiwrite") == 0) { + uint8_t addr; + uint64_t data; + + if ((i+2) >= argc) + usage(argv[0]); + addr = strtoul(argv[++i], NULL, 16); + data = strtoul(argv[++i], NULL, 16); + dmi_write(addr, data); + } else if (strcmp(argv[i], "creset") == 0) { + core_reset(); + } else if (strcmp(argv[i], "stop") == 0) { + core_stop(); + } else if (strcmp(argv[i], "start") == 0) { + core_start(); + } else if (strcmp(argv[i], "step") == 0) { + core_step(); + } else if (strcmp(argv[i], "quit") == 0) { + dmi_write(0xff, 0); + } else if (strcmp(argv[i], "status") == 0) { + /* do nothing, always done below */ + } else if (strcmp(argv[i], "mr") == 0) { + uint64_t addr, count = 1; + + if ((i+1) >= argc) + usage(argv[0]); + addr = strtoul(argv[++i], NULL, 16); + if (((i+1) < argc) && isdigit(argv[i+1][0])) + count = strtoul(argv[++i], NULL, 16); + mem_read(addr, count); + } else if (strcmp(argv[i], "load") == 0) { + const char *filename; + uint64_t addr = 0; + + if ((i+1) >= argc) + usage(argv[0]); + filename = argv[++i]; + if (((i+1) < argc) && isdigit(argv[i+1][0])) + addr = strtoul(argv[++i], NULL, 16); + load(filename, addr); + } else { + fprintf(stderr, "Unknown command %s\n", argv[i]); + exit(1); + } + } + core_status(); + return 0; +}