This is an automated email from Gerrit.

"Evgeniy Naydanov <[email protected]>" just uploaded a new patch set to Gerrit, 
which you can find at https://review.openocd.org/c/openocd/+/9665

-- gerrit

commit 0a6ae573c5a9dee840934a5326f836a543ca09f7
Author: Evgeniy Naydanov <[email protected]>
Date:   Mon Mar 23 15:06:22 2026 +0300

    jtag: fix behavior of Tcl commands before init
    
    Running
    ```
    openocd -c 'adapter driver dummy' -c 'jtag arp_init'
    ```
    used to result in an assertion failure:
    ```
    ...
    openocd: ../../src/jtag/core.c:350: jtag_checks: Assertion `jtag_trst == 0' 
failed.
    ```
    This is due to the fact that `jtag init` was not called and therefore
    `jtaf_init()` has not called `jtag_add_reset()`, so that `jtag_trst ==
    -1`.
    
    Similar issues can be observed for other JTAG commands.
    
    This patch splits all commands in two groups -- pre-init and post-init.
    Pre-init commands are registered once the JTAG transport is selected.
    Post-ini commands become registered after the JTAG state is reset in
    `jtag_init()`.
    
    Change-Id: I21a1877e1eb3cfa59a43129216117ac397d09b95
    Signed-off-by: Evgeniy Naydanov <[email protected]>

diff --git a/src/jtag/core.c b/src/jtag/core.c
index 650f283901..c620fbfbd5 100644
--- a/src/jtag/core.c
+++ b/src/jtag/core.c
@@ -1688,10 +1688,11 @@ int jtag_init(struct command_context *cmd_ctx)
        if (retval != ERROR_OK)
                return retval;
 
+       int reg_res = jtag_register_post_init_commands(cmd_ctx);
        if (Jim_Eval_Named(cmd_ctx->interp, "jtag_init", __FILE__, __LINE__) != 
JIM_OK)
                return ERROR_FAIL;
 
-       return ERROR_OK;
+       return reg_res;
 }
 
 void jtag_set_verify(bool enable)
@@ -1798,7 +1799,7 @@ static int jtag_select(struct command_context *ctx)
         * That works with only C code ... no Tcl glue required.
         */
 
-       retval = jtag_register_commands(ctx);
+       retval = jtag_register_pre_init_commands(ctx);
 
        if (retval != ERROR_OK)
                return retval;
diff --git a/src/jtag/jtag.h b/src/jtag/jtag.h
index 47efdff37c..4fe93c5b7f 100644
--- a/src/jtag/jtag.h
+++ b/src/jtag/jtag.h
@@ -266,7 +266,8 @@ int jtag_init(struct command_context *cmd_ctx);
 
 /** reset, then initialize JTAG chain */
 int jtag_init_reset(struct command_context *cmd_ctx);
-int jtag_register_commands(struct command_context *cmd_ctx);
+int jtag_register_pre_init_commands(struct command_context *cmd_ctx);
+int jtag_register_post_init_commands(struct command_context *cmd_ctx);
 int jtag_init_inner(struct command_context *cmd_ctx);
 
 /**
diff --git a/src/jtag/tcl.c b/src/jtag/tcl.c
index f4feb9ad16..8c9863c8db 100644
--- a/src/jtag/tcl.c
+++ b/src/jtag/tcl.c
@@ -266,7 +266,19 @@ COMMAND_HANDLER(handle_jtag_flush_count)
  *
  * The "irscan" command (for example) doesn't show twice.
  */
-static const struct command_registration jtag_command_handlers_to_move[] = {
+static const struct command_registration 
jtag_pre_init_command_handlers_to_move[] = {
+       {
+               .name = "flush_count",
+               .mode = COMMAND_ANY,
+               .handler = handle_jtag_flush_count,
+               .help = "Returns the number of times the JTAG queue "
+                       "has been flushed.",
+               .usage = "",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration 
jtag_post_init_command_handlers_to_move[] = {
        {
                .name = "drscan",
                .mode = COMMAND_EXEC,
@@ -275,14 +287,6 @@ static const struct command_registration 
jtag_command_handlers_to_move[] = {
                        "Other TAPs must be in BYPASS mode.",
                .usage = "tap_name (num_bits value)+ ['-endstate' state_name]",
        },
-       {
-               .name = "flush_count",
-               .mode = COMMAND_EXEC,
-               .handler = handle_jtag_flush_count,
-               .help = "Returns the number of times the JTAG queue "
-                       "has been flushed.",
-               .usage = "",
-       },
        {
                .name = "pathmove",
                .mode = COMMAND_EXEC,
@@ -724,7 +728,7 @@ COMMAND_HANDLER(handle_jtag_init_command)
        return jtag_init(CMD_CTX);
 }
 
-static const struct command_registration jtag_subcommand_handlers[] = {
+static const struct command_registration jtag_pre_init_subcommand_handlers[] = 
{
        {
                .name = "init",
                .mode = COMMAND_ANY,
@@ -732,23 +736,6 @@ static const struct command_registration 
jtag_subcommand_handlers[] = {
                .help = "initialize jtag scan chain",
                .usage = ""
        },
-       {
-               .name = "arp_init",
-               .mode = COMMAND_ANY,
-               .handler = handle_jtag_arp_init,
-               .help = "Validates JTAG scan chain against the list of "
-                       "declared TAPs using just the four standard JTAG "
-                       "signals.",
-               .usage = "",
-       },
-       {
-               .name = "arp_init-reset",
-               .mode = COMMAND_ANY,
-               .handler = handle_jtag_arp_init_reset,
-               .help = "Uses TRST and SRST to try resetting everything on "
-                       "the JTAG scan chain, then performs 'jtag arp_init'.",
-               .usage = "",
-       },
        {
                .name = "newtap",
                .mode = COMMAND_CONFIG,
@@ -813,7 +800,7 @@ static const struct command_registration 
jtag_subcommand_handlers[] = {
                .usage = "",
        },
        {
-               .chain = jtag_command_handlers_to_move,
+               .chain = jtag_pre_init_command_handlers_to_move,
        },
        COMMAND_REGISTRATION_DONE
 };
@@ -1139,8 +1126,7 @@ COMMAND_HANDLER(handle_wait_srst_deassert)
        return ERROR_OK;
 }
 
-static const struct command_registration jtag_command_handlers[] = {
-
+static const struct command_registration jtag_pre_init_command_handlers[] = {
        {
                .name = "jtag_flush_queue_sleep",
                .handler = handle_jtag_flush_queue_sleep,
@@ -1179,22 +1165,6 @@ static const struct command_registration 
jtag_command_handlers[] = {
                .help = "print current scan chain configuration",
                .usage = ""
        },
-       {
-               .name = "runtest",
-               .handler = handle_runtest_command,
-               .mode = COMMAND_EXEC,
-               .help = "Move to Run-Test/Idle, and issue TCK for num_cycles.",
-               .usage = "num_cycles"
-       },
-       {
-               .name = "irscan",
-               .handler = handle_irscan_command,
-               .mode = COMMAND_EXEC,
-               .help = "Execute Instruction Register (IR) scan.  The "
-                       "specified opcodes are put into each TAP's IR, "
-                       "and other TAPs are put in BYPASS.",
-               .usage = "[tap_name instruction]* ['-endstate' state_name]",
-       },
        {
                .name = "verify_ircapture",
                .handler = handle_verify_ircapture_command,
@@ -1236,15 +1206,75 @@ static const struct command_registration 
jtag_command_handlers[] = {
                .help = "perform jtag tap actions",
                .usage = "",
 
-               .chain = jtag_subcommand_handlers,
+               .chain = jtag_pre_init_subcommand_handlers,
        },
        {
-               .chain = jtag_command_handlers_to_move,
+               .chain = jtag_pre_init_command_handlers_to_move,
        },
        COMMAND_REGISTRATION_DONE
 };
 
-int jtag_register_commands(struct command_context *cmd_ctx)
+static const struct command_registration jtag_post_init_subcommand_handlers[] 
= {
+       {
+               .name = "arp_init",
+               .mode = COMMAND_ANY,
+               .handler = handle_jtag_arp_init,
+               .help = "Validates JTAG scan chain against the list of "
+                       "declared TAPs using just the four standard JTAG "
+                       "signals.",
+               .usage = "",
+       },
+       {
+               .name = "arp_init-reset",
+               .mode = COMMAND_ANY,
+               .handler = handle_jtag_arp_init_reset,
+               .help = "Uses TRST and SRST to try resetting everything on "
+                       "the JTAG scan chain, then performs 'jtag arp_init'.",
+               .usage = "",
+       },
+       {
+               .name = "irscan",
+               .handler = handle_irscan_command,
+               .mode = COMMAND_EXEC,
+               .help = "Execute Instruction Register (IR) scan.  The "
+                       "specified opcodes are put into each TAP's IR, "
+                       "and other TAPs are put in BYPASS.",
+               .usage = "[tap_name instruction]* ['-endstate' state_name]",
+       },
+       {
+               .chain = jtag_post_init_command_handlers_to_move,
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration jtag_post_init_command_handlers[] = {
+       {
+               .name = "runtest",
+               .handler = handle_runtest_command,
+               .mode = COMMAND_EXEC,
+               .help = "Move to Run-Test/Idle, and issue TCK for num_cycles.",
+               .usage = "num_cycles"
+       },
+       {
+               .name = "jtag",
+               .mode = COMMAND_ANY,
+               .help = "perform jtag tap actions",
+               .usage = "",
+
+               .chain = jtag_post_init_subcommand_handlers,
+       },
+       {
+               .chain = jtag_post_init_command_handlers_to_move,
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+int jtag_register_pre_init_commands(struct command_context *cmd_ctx)
+{
+       return register_commands(cmd_ctx, NULL, jtag_pre_init_command_handlers);
+}
+
+int jtag_register_post_init_commands(struct command_context *cmd_ctx)
 {
-       return register_commands(cmd_ctx, NULL, jtag_command_handlers);
+       return register_commands(cmd_ctx, NULL, 
jtag_post_init_command_handlers);
 }
diff --git a/testing/tcl_commands/Makefile.am b/testing/tcl_commands/Makefile.am
index b0eee4dc96..3565178f67 100644
--- a/testing/tcl_commands/Makefile.am
+++ b/testing/tcl_commands/Makefile.am
@@ -6,7 +6,10 @@ if DUMMY
 TESTS += \
        test-target-create-command.cfg \
        test-target-configure-cget-command.cfg \
-       test-jtag-pathmove.cfg
+       test-irscan-command.cfg \
+       test-drscan-command.cfg \
+       test-jtag-pathmove.cfg \
+       test-jtag-before-init.cfg
 endif
 
 EXTRA_DIST = utils.tcl $(TESTS)
diff --git a/testing/tcl_commands/test-jtag-before-init.cfg 
b/testing/tcl_commands/test-jtag-before-init.cfg
new file mode 100644
index 0000000000..178df4dcae
--- /dev/null
+++ b/testing/tcl_commands/test-jtag-before-init.cfg
@@ -0,0 +1,61 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+namespace import testing_helpers::*
+
+adapter driver dummy
+noinit
+
+jtag newtap the tap -irlen 2
+
+set tap [lindex [jtag names] 0]
+
+scan_chain
+
+flush_count
+
+# FIXME: this command times out. Currently, there is no robust way to check it.
+proc check_wait_srst_deassert_timeout {} {
+       set code [catch {wait_srst_deassert 1} msg]
+       if {$msg ne ""} {error "Expecting empty message, got '$msg'"}
+       if {$code != -4} {error "Expecting ERROR_FAIL, got $code"}
+}
+check_wait_srst_deassert_timeout
+
+check_generic_error {drscan $tap 1 0}
+check_generic_error {jtag arp_init}
+check_generic_error {jtag arp_init-reset}
+check_generic_error {runtest 1}
+check_generic_error {jtag pathmove RESET}
+check_generic_error {jtag tapisenabled $tap}
+check_generic_error {jtag tapenable $tap}
+check_generic_error {jtag tapdisable $tap}
+check_generic_error {jtag cget $tap -event post-reset}
+
+jtag configure $tap -event post-reset {}
+
+jtag_flush_queue_sleep 0
+
+tms_sequence
+tms_sequence short
+
+proc check_jtag_rclk_default {} {
+       # FIXME: the current behavior is not great.
+       set code [catch jtag_rclk msg]
+       if {$msg ne ""} {error "Expecting empty message, got '$msg'"}
+       if {$code != -4} {error "Expecting ERROR_FAIL, got $code"}
+}
+check_jtag_rclk_default
+jtag_rclk 1000
+jtag_rclk
+
+jtag_ntrst_delay
+jtag_ntrst_delay 1
+
+jtag_ntrst_assert_width
+
+verify_ircapture
+verify_ircapture enable
+
+verify_jtag
+verify_jtag enable
+
+shutdown

-- 

Reply via email to