From e05ae0c8cb58ea80bbc49ea2fbe063331d79b73f Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Thu, 25 Nov 2021 14:12:13 +0800 Subject: [PATCH 1/6] mw_debug: pass target parameters to urjtag An example ./mw_debug -d -t 'ft2232 vid=0x0403 pid=0x6014' Signed-off-by: Matt Johnston --- scripts/mw_debug/mw_debug.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/scripts/mw_debug/mw_debug.c b/scripts/mw_debug/mw_debug.c index 30803e5..a2c04b0 100644 --- a/scripts/mw_debug/mw_debug.c +++ b/scripts/mw_debug/mw_debug.c @@ -214,18 +214,32 @@ static int jtag_init(const char *target) { const char *sep; const char *cable; - char *params[] = { NULL, }; + const int max_params = 20; + char *params[max_params+1]; urj_part_t *p; uint32_t id; int rc, part; + if (!target) target = "probe"; - sep = strchr(target, ':'); + memset(params, 0x0, sizeof(params)); + sep = strchr(target, ' '); cable = strndup(target, sep - target); if (sep && *sep) { - fprintf(stderr, "jtag cable params not supported yet\n"); - return -1; + char *param_str = strdup(sep); + char *s = param_str; + for (int i = 0; *s; s++) { + if (*s == ' ') { + if (i >= max_params) { + fprintf(stderr, "Too many jtag cable params\n"); + return -1; + } + *s = '\0'; + params[i] = s+1; + i++; + } + } } if (debug) printf("Opening jtag backend cable '%s'\n", cable); @@ -241,25 +255,25 @@ static int jtag_init(const char *target) char *cparams[] = { NULL, NULL,}; rc = urj_tap_cable_usb_probe(cparams); if (rc != URJ_STATUS_OK) { - fprintf(stderr, "JTAG cable probe failed\n"); + fprintf(stderr, "JTAG cable probe failed: %s\n", urj_error_describe()); return -1; } cable = strdup(cparams[1]); } rc = urj_tap_chain_connect(jc, cable, params); if (rc != URJ_STATUS_OK) { - fprintf(stderr, "JTAG cable detect failed\n"); + fprintf(stderr, "JTAG cable detect failed: %s\n", urj_error_describe()); 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"); + fprintf(stderr, "JTAG failed to add part! : %s\n", urj_error_describe()); return -1; } if (jc->parts == NULL || jc->parts->len == 0) { - fprintf(stderr, "JTAG Something's wrong after adding part !\n"); + fprintf(stderr, "JTAG Something's wrong after adding part! : %s\n", urj_error_describe()); return -1; } urj_part_parts_set_instruction(jc->parts, "BYPASS"); From 04cc4a842c4ddfada995c5f8d2a6fbcb6fcca89e Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Fri, 26 Nov 2021 10:43:06 +0800 Subject: [PATCH 2/6] mw_debug: Add -s frequency argument Chose -s for speed, vs -f for --force Signed-off-by: Matt Johnston --- scripts/mw_debug/mw_debug.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/scripts/mw_debug/mw_debug.c b/scripts/mw_debug/mw_debug.c index a2c04b0..4a7f6e1 100644 --- a/scripts/mw_debug/mw_debug.c +++ b/scripts/mw_debug/mw_debug.c @@ -49,7 +49,7 @@ static bool debug; struct backend { - int (*init)(const char *target); + int (*init)(const char *target, int freq); int (*reset)(void); int (*command)(uint8_t op, uint8_t addr, uint64_t *data); }; @@ -67,13 +67,15 @@ static void check(int r, const char *failstr) static int sim_fd = -1; -static int sim_init(const char *target) +static int sim_init(const char *target, int freq) { struct sockaddr_in saddr; struct hostent *hp; const char *p, *host; int port, rc; + (void)freq; + if (!target) target = "localhost:13245"; p = strchr(target, ':'); @@ -210,7 +212,7 @@ static struct backend sim_backend = { static urj_chain_t *jc; -static int jtag_init(const char *target) +static int jtag_init(const char *target, int freq) { const char *sep; const char *cable; @@ -266,6 +268,10 @@ static int jtag_init(const char *target) return -1; } + if (freq) { + urj_tap_cable_set_frequency(jc->cable, freq); + } + /* XXX Hard wire part 0, that might need to change (use params and detect !) */ rc = urj_tap_manual_add(jc, 6); if (rc < 0) { @@ -720,7 +726,7 @@ int main(int argc, char *argv[]) { const char *progname = argv[0]; const char *target = NULL; - int rc, i = 1; + int rc, i = 1, freq = 0; b = NULL; @@ -731,9 +737,10 @@ int main(int argc, char *argv[]) { "backend", required_argument, 0, 'b' }, { "target", required_argument, 0, 't' }, { "debug", no_argument, 0, 'd' }, + { "frequency", no_argument, 0, 's' }, { 0, 0, 0, 0 } }; - c = getopt_long(argc, argv, "dhb:t:", lopts, &oindex); + c = getopt_long(argc, argv, "dhb:t:s:", lopts, &oindex); if (c < 0) break; switch(c) { @@ -753,6 +760,13 @@ int main(int argc, char *argv[]) case 't': target = optarg; break; + case 's': + freq = atoi(optarg); + if (freq == 0) { + fprintf(stderr, "Bad frequency %s\n", optarg); + exit(1); + } + break; case 'd': debug = true; } @@ -761,7 +775,7 @@ int main(int argc, char *argv[]) if (b == NULL) b = &jtag_backend; - rc = b->init(target); + rc = b->init(target, freq); if (rc < 0) exit(1); for (i = optind; i < argc; i++) { From 763138798e8b26ed5a0921faafadfa9919a5bf58 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Fri, 4 Feb 2022 12:08:07 +0800 Subject: [PATCH 3/6] mw_debug: use isxdigit for hex arguments Signed-off-by: Matt Johnston --- scripts/mw_debug/mw_debug.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/mw_debug/mw_debug.c b/scripts/mw_debug/mw_debug.c index 4a7f6e1..1f7688b 100644 --- a/scripts/mw_debug/mw_debug.c +++ b/scripts/mw_debug/mw_debug.c @@ -817,7 +817,7 @@ int main(int argc, char *argv[]) if ((i+1) >= argc) usage(argv[0]); addr = strtoul(argv[++i], NULL, 16); - if (((i+1) < argc) && isdigit(argv[i+1][0])) + if (((i+1) < argc) && isxdigit(argv[i+1][0])) count = strtoul(argv[++i], NULL, 16); mem_read(addr, count); } else if (strcmp(argv[i], "mw") == 0) { @@ -835,7 +835,7 @@ int main(int argc, char *argv[]) if ((i+1) >= argc) usage(argv[0]); filename = argv[++i]; - if (((i+1) < argc) && isdigit(argv[i+1][0])) + if (((i+1) < argc) && isxdigit(argv[i+1][0])) addr = strtoul(argv[++i], NULL, 16); load(filename, addr); } else if (strcmp(argv[i], "save") == 0) { From eb20195a101af2e699a025b6fd5d656612c75a1e Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Fri, 4 Feb 2022 14:40:42 +0800 Subject: [PATCH 4/6] mw_debug: Link urjtag statically liburjtag isn't in Debian, so usually we're pointing at a urjtag build directory when building mw_debug Signed-off-by: Matt Johnston --- scripts/mw_debug/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mw_debug/Makefile b/scripts/mw_debug/Makefile index a669e74..e35fffa 100644 --- a/scripts/mw_debug/Makefile +++ b/scripts/mw_debug/Makefile @@ -4,7 +4,7 @@ CFLAGS = -O2 -g -Wall -std=c99 all: mw_debug mw_debug: mw_debug.c - $(CC) -o $@ $^ $(CFLAGS) -lurjtag + $(CC) -o $@ $^ $(CFLAGS) -Wl,-Bstatic -lurjtag -Wl,-Bdynamic -lftdi1 -lusb-1.0 -lreadline clean: rm -f mw_debug From 3775650df3a53264f37dcd14223248da7c9d9381 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Fri, 26 Nov 2021 10:47:07 +0800 Subject: [PATCH 5/6] dmi_dtm_ecp5: Use ECP5 JTAGG for DMI This uses the JTAGG primitive which is similar to BSCANE2. The LUT4 delay approach came from Florian and Greg in https://github.com/enjoy-digital/litex/pull/1087 Has been tested on an OrangeCrab with 48MHz sysclk FT232H up to 30MHz (though libusb/urjtag is by far the bottleneck vs the JTAG clock) Signed-off-by: Matt Johnston --- Makefile | 1 + dmi_dtm_ecp5.vhdl | 298 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 299 insertions(+) create mode 100644 dmi_dtm_ecp5.vhdl diff --git a/Makefile b/Makefile index cf723e3..85a0fee 100644 --- a/Makefile +++ b/Makefile @@ -192,6 +192,7 @@ ECP_FLASH_OFFSET=0x80000 toplevel=fpga/top-orangecrab0.2.vhdl litedram_target=orangecrab-85-0.2 soc_extra_v += litesdcard/generated/lattice/litesdcard_core.v +dmi_dtm=dmi_dtm_ecp5.vhdl endif # ECP5-EVN diff --git a/dmi_dtm_ecp5.vhdl b/dmi_dtm_ecp5.vhdl new file mode 100644 index 0000000..b2d6ad8 --- /dev/null +++ b/dmi_dtm_ecp5.vhdl @@ -0,0 +1,298 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.math_real.all; + +library work; +use work.wishbone_types.all; + +entity dmi_dtm is + generic(ABITS : INTEGER:=8; + DBITS : INTEGER:=64); + + port(sys_clk : in std_ulogic; + sys_reset : in std_ulogic; + dmi_addr : out std_ulogic_vector(ABITS - 1 downto 0); + dmi_din : in std_ulogic_vector(DBITS - 1 downto 0); + dmi_dout : out std_ulogic_vector(DBITS - 1 downto 0); + dmi_req : out std_ulogic; + dmi_wr : out std_ulogic; + dmi_ack : in std_ulogic +-- dmi_err : in std_ulogic TODO: Add error response + ); +end entity dmi_dtm; + +architecture behaviour of dmi_dtm is + -- Signals coming out of the JTAGG block + signal jtag_reset_n : std_ulogic; + signal tdi : std_ulogic; + signal tdo : std_ulogic; + signal tck : std_ulogic; + signal jce1 : std_ulogic; + signal jshift : std_ulogic; + signal update : std_ulogic; + + -- signals to match dmi_dtb_xilinx + signal jtag_reset : std_ulogic; + signal capture : std_ulogic; + signal jtag_clk : std_ulogic; + signal sel : std_ulogic; + signal shift : std_ulogic; + + -- delays + signal jce1_d : std_ulogic; + constant TCK_DELAY : INTEGER := 8; + signal tck_d : std_ulogic_vector(TCK_DELAY+1 downto 1); + + -- ** JTAG clock domain ** + + -- Shift register + signal shiftr : std_ulogic_vector(ABITS + DBITS + 1 downto 0); + + -- Latched request + signal request : std_ulogic_vector(ABITS + DBITS + 1 downto 0); + + -- A request is present + signal jtag_req : std_ulogic; + + -- Synchronizer for jtag_rsp (sys clk -> jtag_clk) + signal dmi_ack_0 : std_ulogic; + signal dmi_ack_1 : std_ulogic; + + -- ** sys clock domain ** + + -- Synchronizer for jtag_req (jtag clk -> sys clk) + signal jtag_req_0 : std_ulogic; + signal jtag_req_1 : std_ulogic; + + -- ** combination signals + signal jtag_bsy : std_ulogic; + signal op_valid : std_ulogic; + signal rsp_op : std_ulogic_vector(1 downto 0); + + -- ** Constants ** + constant DMI_REQ_NOP : std_ulogic_vector(1 downto 0) := "00"; + constant DMI_REQ_RD : std_ulogic_vector(1 downto 0) := "01"; + constant DMI_REQ_WR : std_ulogic_vector(1 downto 0) := "10"; + constant DMI_RSP_OK : std_ulogic_vector(1 downto 0) := "00"; + constant DMI_RSP_BSY : std_ulogic_vector(1 downto 0) := "11"; + + attribute ASYNC_REG : string; + attribute ASYNC_REG of jtag_req_0: signal is "TRUE"; + attribute ASYNC_REG of jtag_req_1: signal is "TRUE"; + attribute ASYNC_REG of dmi_ack_0: signal is "TRUE"; + attribute ASYNC_REG of dmi_ack_1: signal is "TRUE"; + + -- ECP5 JTAGG + component JTAGG is + generic ( + ER1 : string := "ENABLED"; + ER2 : string := "ENABLED" + ); + port( + JTDO1 : in std_ulogic; + JTDO2 : in std_ulogic; + JTDI : out std_ulogic; + JTCK : out std_ulogic; + JRTI1 : out std_ulogic; + JRTI2 : out std_ulogic; + JSHIFT : out std_ulogic; + JUPDATE : out std_ulogic; + JRSTN : out std_ulogic; + JCE1 : out std_ulogic; + JCE2 : out std_ulogic + ); + end component; + + component LUT4 is + generic ( + INIT : std_logic_vector + ); + port( + A : in STD_ULOGIC; + B : in STD_ULOGIC; + C : in STD_ULOGIC; + D : in STD_ULOGIC; + Z : out STD_ULOGIC + ); + end component; + +begin + + jtag: JTAGG + generic map( + ER2 => "DISABLED" + ) + port map ( + JTDO1 => tdo, + JTDO2 => '0', + JTDI => tdi, + JTCK => tck, + JRTI1 => open, + JRTI2 => open, + JSHIFT => jshift, + JUPDATE => update, + JRSTN => jtag_reset_n, + JCE1 => jce1, + JCE2 => open + ); + + -- JRTI1 looks like it could be connected to SEL, but + -- in practise JRTI1 is only high briefly, not for the duration + -- of the transmission. possibly mw_debug could be modified. + -- The ecp5 is probably the only jtag device anyway. + sel <= '1'; + + -- TDI needs to align with TCK, we use LUT delays here. + -- From https://github.com/enjoy-digital/litex/pull/1087 + tck_d(1) <= tck; + del: for i in 1 to TCK_DELAY generate + attribute keep : boolean; + attribute keep of l: label is true; + begin + l: LUT4 + generic map( + INIT => b"0000_0000_0000_0010" + ) + port map ( + A => tck_d(i), + B => '0', C => '0', D => '0', + Z => tck_d(i+1) + ); + end generate; + jtag_clk <= tck_d(TCK_DELAY+1); + + -- capture signal + jce1_sync : process(jtag_clk) + begin + if rising_edge(jtag_clk) then + jce1_d <= jce1; + capture <= jce1 and not jce1_d; + end if; + end process; + + -- latch the shift signal, otherwise + -- we miss the last shift in + -- (maybe because we are delaying tck?) + shift_sync : process(jtag_clk) + begin + if (sys_reset = '1') then + shift <= '0'; + elsif rising_edge(jtag_clk) then + shift <= jshift; + end if; + end process; + + jtag_reset <= not jtag_reset_n; + + -- dmi_req synchronization + dmi_req_sync : process(sys_clk) + begin + -- sys_reset is synchronous + if rising_edge(sys_clk) then + if (sys_reset = '1') then + jtag_req_0 <= '0'; + jtag_req_1 <= '0'; + else + jtag_req_0 <= jtag_req; + jtag_req_1 <= jtag_req_0; + end if; + end if; + end process; + dmi_req <= jtag_req_1; + + -- dmi_ack synchronization + dmi_ack_sync: process(jtag_clk, jtag_reset) + begin + -- jtag_reset is async (see comments) + if jtag_reset = '1' then + dmi_ack_0 <= '0'; + dmi_ack_1 <= '0'; + elsif rising_edge(jtag_clk) then + dmi_ack_0 <= dmi_ack; + dmi_ack_1 <= dmi_ack_0; + end if; + end process; + + -- jtag_bsy indicates whether we can start a new request, we can when + -- we aren't already processing one (jtag_req) and the synchronized ack + -- of the previous one is 0. + -- + jtag_bsy <= jtag_req or dmi_ack_1; + + -- decode request type in shift register + with shiftr(1 downto 0) select op_valid <= + '1' when DMI_REQ_RD, + '1' when DMI_REQ_WR, + '0' when others; + + -- encode response op + rsp_op <= DMI_RSP_BSY when jtag_bsy = '1' else DMI_RSP_OK; + + -- Some DMI out signals are directly driven from the request register + dmi_addr <= request(ABITS + DBITS + 1 downto DBITS + 2); + dmi_dout <= request(DBITS + 1 downto 2); + dmi_wr <= '1' when request(1 downto 0) = DMI_REQ_WR else '0'; + + -- TDO is wired to shift register bit 0 + tdo <= shiftr(0); + + -- Main state machine. Handles shift registers, request latch and + -- jtag_req latch. Could be split into 3 processes but it's probably + -- not worthwhile. + -- + shifter: process(jtag_clk, jtag_reset, sys_reset) + begin + if jtag_reset = '1' or sys_reset = '1' then + shiftr <= (others => '0'); + jtag_req <= '0'; + request <= (others => '0'); + elsif rising_edge(jtag_clk) then + + -- Handle jtag "commands" when sel is 1 + if sel = '1' then + -- Shift state, rotate the register + if shift = '1' then + shiftr <= tdi & shiftr(ABITS + DBITS + 1 downto 1); + end if; + + -- Update state (trigger) + -- + -- Latch the request if we aren't already processing one and + -- it has a valid command opcode. + -- + if update = '1' and op_valid = '1' then + if jtag_bsy = '0' then + request <= shiftr; + jtag_req <= '1'; + end if; + -- Set the shift register "op" to "busy". This will prevent + -- us from re-starting the command on the next update if + -- the command completes before that. + shiftr(1 downto 0) <= DMI_RSP_BSY; + end if; + + -- Request completion. + -- + -- Capture the response data for reads and clear request flag. + -- + -- Note: We clear req (and thus dmi_req) here which relies on tck + -- ticking and sel set. This means we are stuck with dmi_req up if + -- the jtag interface stops. Slaves must be resilient to this. + -- + if jtag_req = '1' and dmi_ack_1 = '1' then + jtag_req <= '0'; + if request(1 downto 0) = DMI_REQ_RD then + request(DBITS + 1 downto 2) <= dmi_din; + end if; + end if; + + -- Capture state, grab latch content with updated status + if capture = '1' then + shiftr <= request(ABITS + DBITS + 1 downto 2) & rsp_op; + end if; + + end if; + end if; + end process; +end architecture behaviour; + From 9c64f8a98ba63a3ab249f272716ada201fd52aa6 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Fri, 4 Feb 2022 15:29:40 +0800 Subject: [PATCH 6/6] mw_debug: Add Lattice ECP5 support "-b ecp5" will select ECP5 interface that talks to a JTAGG primitive. For example with a FT232H JTAG board: ./mw_debug -t 'ft2232 vid=0x0403 pid=0x6014' -s 30000000 -b ecp5 mr ff003888 6 Connected to libftdi driver. Found device ID: 0x41113043 00000000ff003888: 6d6f636c65570a0a ..Welcom 00000000ff003890: 63694d206f742065 e to Mic 00000000ff003898: 2120747461776f72 rowatt ! 00000000ff0038a0: 0000000000000a0a ........ 00000000ff0038a8: 67697320636f5320 Soc sig 00000000ff0038b0: 203a65727574616e nature: Core: running NIA: c0000000000187f8 MSR: 9000000000001033 Signed-off-by: Matt Johnston --- scripts/mw_debug/mw_debug.c | 110 +++++++++++++++++++++++++++++++----- 1 file changed, 96 insertions(+), 14 deletions(-) diff --git a/scripts/mw_debug/mw_debug.c b/scripts/mw_debug/mw_debug.c index 1f7688b..6271760 100644 --- a/scripts/mw_debug/mw_debug.c +++ b/scripts/mw_debug/mw_debug.c @@ -212,16 +212,13 @@ static struct backend sim_backend = { static urj_chain_t *jc; -static int jtag_init(const char *target, int freq) +static int common_jtag_init(const char *target, int freq) { const char *sep; const char *cable; const int max_params = 20; char *params[max_params+1]; - urj_part_t *p; - uint32_t id; - int rc, part; - + int rc; if (!target) target = "probe"; @@ -272,19 +269,33 @@ static int jtag_init(const char *target, int freq) urj_tap_cable_set_frequency(jc->cable, freq); } + return 0; +} + +static int bscane2_init(const char *target, int freq) +{ + urj_part_t *p; + uint32_t id; + int rc; + + rc = common_jtag_init(target, freq); + if (rc < 0) { + return rc; + } + /* 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! : %s\n", urj_error_describe()); + 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! : %s\n", urj_error_describe()); + 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; + jc->active_part = 0; p = urj_tap_chain_active_part(jc); if (!p) { @@ -320,6 +331,69 @@ static int jtag_init(const char *target, int freq) return 0; } +static int ecp5_init(const char *target, int freq) +{ + urj_part_t *p; + uint32_t id; + int rc; + + rc = common_jtag_init(target, freq); + if (rc < 0) { + return rc; + } + + /* XXX Hard wire part 0, that might need to change (use params and detect !) */ + rc = urj_tap_manual_add(jc, 8); + if (rc < 0) { + fprintf(stderr, "JTAG failed to add part! : %s\n", urj_error_describe()); + return -1; + } + if (jc->parts == NULL || jc->parts->len == 0) { + fprintf(stderr, "JTAG Something's wrong after adding part! : %s\n", urj_error_describe()); + return -1; + } + urj_part_parts_set_instruction(jc->parts, "BYPASS"); + + jc->active_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! : %s\n", + urj_error_describe()); + return -1; + } + // READ_ID = 0xE0 = 11100000, from Lattice TN1260 sysconfig guide + if (urj_part_instruction_define(p, "IDCODE", "11100000", "IDCODE_REG") == NULL) { + fprintf(stderr, "JTAG failed to add IDCODE instruction! : %s\n", + urj_error_describe()); + 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; + } + // ER1 = 0x32 = 00110010b + if (urj_part_instruction_define(p, "USER2", "00110010", "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) { return 0; @@ -359,8 +433,14 @@ static int jtag_command(uint8_t op, uint8_t addr, uint64_t *data) return rc; } -static struct backend jtag_backend = { - .init = jtag_init, +static struct backend bscane2_backend = { + .init = bscane2_init, + .reset = jtag_reset, + .command = jtag_command, +}; + +static struct backend ecp5_backend = { + .init = ecp5_init, .reset = jtag_reset, .command = jtag_command, }; @@ -682,7 +762,7 @@ static void ltrig_set(uint64_t addr) static void usage(const char *cmd) { - fprintf(stderr, "Usage: %s -b \n", cmd); + fprintf(stderr, "Usage: %s -b \n", cmd); fprintf(stderr, "\n"); fprintf(stderr, " CPU core:\n"); @@ -750,8 +830,10 @@ int main(int argc, char *argv[]) case 'b': if (strcmp(optarg, "sim") == 0) b = &sim_backend; - else if (strcmp(optarg, "jtag") == 0) - b = &jtag_backend; + else if (strcmp(optarg, "jtag") == 0 || strcmp(optarg, "bscane2") == 0) + b = &bscane2_backend; + else if (strcmp(optarg, "ecp5") == 0) + b = &ecp5_backend; else { fprintf(stderr, "Unknown backend %s\n", optarg); exit(1); @@ -773,7 +855,7 @@ int main(int argc, char *argv[]) } if (b == NULL) - b = &jtag_backend; + b = &bscane2_backend; rc = b->init(target, freq); if (rc < 0)