New C based JTAG debug tool
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Mon, 16 Sep 2019 15:29:08 +0000 (16:29 +0100)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Fri, 20 Sep 2019 06:46:31 +0000 (16:46 +1000)
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 <benh@kernel.crashing.org>
scripts/mw_debug.py [deleted file]
scripts/mw_debug/Makefile [new file with mode: 0644]
scripts/mw_debug/mw_debug.c [new file with mode: 0644]

diff --git a/scripts/mw_debug.py b/scripts/mw_debug.py
deleted file mode 100755 (executable)
index f22039c..0000000
+++ /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 (file)
index 0000000..439b198
--- /dev/null
@@ -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 (file)
index 0000000..f1a7cab
--- /dev/null
@@ -0,0 +1,583 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <getopt.h>
+#include <poll.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <urjtag/urjtag.h>
+
+#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; i<r; i++)
+                       printf("%02x ", buf[i]);
+               printf("\n");
+       }
+       p = buf+1;
+       b = 0;
+       r = read_bits(&p, &b, 2);
+       if (data)
+               *data = read_bits(&p, &b, 64);
+       return r;
+}
+
+static struct backend sim_backend = {
+       .init   = sim_init,
+       .reset = sim_reset,
+       .command = sim_command,
+};
+
+/* -------------- JTAG backend -------------- */
+
+static urj_chain_t *jc;
+
+static int jtag_init(const char *target)
+{
+       const char *sep;
+       const char *cable;
+       char *params[] = { NULL, };
+       urj_part_t *p;
+       uint32_t id;
+       int rc, part;
+
+       if (!target)
+               target = "DigilentHS1";
+       sep = strchr(target, ':');
+       cable = strndup(target, sep - target);
+       if (sep && *sep) {
+               fprintf(stderr, "jtag cable params not supported yet\n");
+               return -1;
+       }
+       if (debug)
+               printf("Opening jtag backend cable '%s'\n", cable);
+
+       jc = urj_tap_chain_alloc();
+       if (!jc) {
+               fprintf(stderr, "Failed to alloc JTAG\n");
+               return -1;
+       }
+       jc->main_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 <command> <args>\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;
+}