diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml
index 6cbce8649..71bfecc80 100644
--- a/.github/workflows/snapshot.yml
+++ b/.github/workflows/snapshot.yml
@@ -30,7 +30,7 @@ jobs:
           echo "LIBUSB1_SRC=$PWD/libusb-${LIBUSB1_VER}" >> $GITHUB_ENV
       - name: Prepare hidapi
         env:
-          HIDAPI_VER: 0.11.2
+          HIDAPI_VER: 0.13.1
         run: |
           mkdir -p $DL_DIR && cd $DL_DIR
           wget "https://github.com/libusb/hidapi/archive/hidapi-${HIDAPI_VER}.tar.gz"
@@ -56,6 +56,16 @@ jobs:
           wget "https://github.com/aquynh/capstone/archive/${CAPSTONE_VER}.tar.gz"
           tar -xzf ${CAPSTONE_VER}.tar.gz
           echo "CAPSTONE_SRC=$PWD/capstone-${CAPSTONE_VER}" >> $GITHUB_ENV
+      - name: Prepare libjaylink
+        env:
+          LIBJAYLINK_VER: 0.3.1
+        run: |
+          mkdir -p $DL_DIR && cd $DL_DIR
+          wget https://gitlab.zapb.de/libjaylink/libjaylink/-/archive/${LIBJAYLINK_VER}/libjaylink-${LIBJAYLINK_VER}.tar.gz
+          tar -xzf libjaylink-${LIBJAYLINK_VER}.tar.gz
+          cd libjaylink-${LIBJAYLINK_VER}
+          ./autogen.sh
+          echo "LIBJAYLINK_SRC=$PWD" >> $GITHUB_ENV
       - name: Package OpenOCD for windows
         env:
           MAKE_JOBS: 2
@@ -65,6 +75,7 @@ jobs:
           LIBFTDI_CONFIG: -DSTATICLIBS=OFF -DEXAMPLES=OFF -DFTDI_EEPROM=OFF
           CAPSTONE_CONFIG: "CAPSTONE_BUILD_CORE_ONLY=yes CAPSTONE_STATIC=yes CAPSTONE_SHARED=no"
           CAPSTONE_CFLAGS: -I$(CAPSTONE_SRC)/include/capstone
+          LIBJAYLINK_CONFIG: --enable-shared --disable-static
         run: |
           # check if there is tag pointing at HEAD, otherwise take the HEAD SHA-1 as OPENOCD_TAG
           OPENOCD_TAG="`git tag --points-at HEAD`"
@@ -83,6 +94,7 @@ jobs:
           # add missing dlls
           cd $HOST-root/usr
           cp `$HOST-gcc --print-file-name=libwinpthread-1.dll` ./bin/
+          # required by libftdi1.dll. For the gcc-mingw-10.3.x or later "libgcc_s_dw2-1.dll" will need to be copied.
           cp `$HOST-gcc --print-file-name=libgcc_s_sjlj-1.dll` ./bin/
           # prepare the artifact
           ARTIFACT="openocd-${OPENOCD_TAG}-${HOST}.tar.gz"
@@ -92,7 +104,23 @@ jobs:
           echo "ARTIFACT_PATH=$PWD/$ARTIFACT" >> $GITHUB_ENV
           echo "ARTIFACT_NAME=openocd-windows-${OPENOCD_TAG}" >> $GITHUB_ENV
       - name: Publish OpenOCD packaged for windows
-        uses: actions/upload-artifact@v2
+        uses: actions/upload-artifact@v3
         with:
           name: ${{ env.ARTIFACT_NAME }}
           path: ${{ env.ARTIFACT_PATH }}
+      - name: Delete 'latest' Release
+        uses: dev-drprasad/delete-tag-and-release@v0.2.1
+        with:
+          delete_release: true
+          tag_name: ${{ env.RELEASE_NAME }}
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+      - name: Create Release
+        uses: ncipollo/release-action@v1
+        with:
+          tag: ${{ env.RELEASE_NAME }}
+          commit: ${{ github.sha }}
+          draft: false
+          artifacts: ${{ env.ARTIFACT_PATH }}
+          prerelease: ${{ env.IS_PRE_RELEASE }}
+          token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/contrib/cross-build.sh b/contrib/cross-build.sh
index ded169192..f1bd04df3 100755
--- a/contrib/cross-build.sh
+++ b/contrib/cross-build.sh
@@ -41,12 +41,14 @@ WORK_DIR=$PWD
 : ${HIDAPI_SRC:=/path/to/hidapi}
 : ${LIBFTDI_SRC:=/path/to/libftdi}
 : ${CAPSTONE_SRC:=/path/to/capstone}
+: ${LIBJAYLINK_SRC:=/path/to/libjaylink}
 
 OPENOCD_SRC=`readlink -m $OPENOCD_SRC`
 LIBUSB1_SRC=`readlink -m $LIBUSB1_SRC`
 HIDAPI_SRC=`readlink -m $HIDAPI_SRC`
 LIBFTDI_SRC=`readlink -m $LIBFTDI_SRC`
 CAPSTONE_SRC=`readlink -m $CAPSTONE_SRC`
+LIBJAYLINK_SRC=`readlink -m $LIBJAYLINK_SRC`
 
 HOST_TRIPLET=$1
 BUILD_DIR=$WORK_DIR/$HOST_TRIPLET-build
@@ -54,6 +56,7 @@ LIBUSB1_BUILD_DIR=$BUILD_DIR/libusb1
 HIDAPI_BUILD_DIR=$BUILD_DIR/hidapi
 LIBFTDI_BUILD_DIR=$BUILD_DIR/libftdi
 CAPSTONE_BUILD_DIR=$BUILD_DIR/capstone
+LIBJAYLINK_BUILD_DIR=$BUILD_DIR/libjaylink
 OPENOCD_BUILD_DIR=$BUILD_DIR/openocd
 
 ## Root of host file tree
@@ -158,6 +161,16 @@ libdir=${exec_prefix}/lib \
 includedir=${prefix}/include/capstone\n\n;' $CAPSTONE_PC_FILE
 fi
 
+# libjaylink build & install into sysroot
+if [ -d $LIBJAYLINK_SRC ] ; then
+  mkdir -p $LIBJAYLINK_BUILD_DIR
+  cd $LIBJAYLINK_BUILD_DIR
+  $LIBJAYLINK_SRC/configure --build=`$LIBJAYLINK_SRC/config.guess` --host=$HOST_TRIPLET \
+    --with-sysroot=$SYSROOT --prefix=$PREFIX \
+    $LIBJAYLINK_CONFIG
+  make -j $MAKE_JOBS
+  make install DESTDIR=$SYSROOT
+fi
 
 # OpenOCD build & install into sysroot
 mkdir -p $OPENOCD_BUILD_DIR
diff --git a/doc/openocd.texi b/doc/openocd.texi
index 4883e66da..eb9f92f35 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -8811,7 +8811,6 @@ power consumption (because the CPU is needlessly clocked).
 @deffn {Command} {resume} [address]
 Resume the target at its current code position,
 or the optional @var{address} if it is provided.
-OpenOCD will wait 5 seconds for the target to resume.
 @end deffn
 
 @deffn {Command} {step} [address]
@@ -9132,8 +9131,10 @@ format. Optional @option{start} and @option{end} parameters allow to
 limit the address range.
 @end deffn
 
-@deffn {Command} {version}
-Displays a string identifying the version of this OpenOCD server.
+@deffn {Command} {version} [git]
+Returns a string identifying the version of this OpenOCD server.
+With option @option{git}, it returns the git version obtained at compile time
+through ``git describe''.
 @end deffn
 
 @deffn {Command} {virt2phys} virtual_address
@@ -11665,8 +11666,8 @@ way to represent JTAG test patterns in text files.
 In a debug session using JTAG for its transport protocol,
 OpenOCD supports running such test files.
 
-@deffn {Command} {svf} @file{filename} [@option{-tap @var{tapname}}] [@option{[-]quiet}] @
-                     [@option{[-]nil}] [@option{[-]progress}] [@option{[-]ignore_error}] @
+@deffn {Command} {svf} @file{filename} [@option{-tap @var{tapname}}] [@option{-quiet}] @
+                     [@option{-nil}] [@option{-progress}] [@option{-ignore_error}] @
                      [@option{-noreset}] [@option{-addcycles @var{cyclecount}}]
 This issues a JTAG reset (Test-Logic-Reset) and then
 runs the SVF script from @file{filename}.
@@ -11680,11 +11681,11 @@ Command options:
 specified by the SVF file with HIR, TIR, HDR and TDR commands;
 instead, calculate them automatically according to the current JTAG
 chain configuration, targeting @var{tapname};
-@item @option{[-]quiet} do not log every command before execution;
-@item @option{[-]nil} ``dry run'', i.e., do not perform any operations
+@item @option{-quiet} do not log every command before execution;
+@item @option{-nil} ``dry run'', i.e., do not perform any operations
 on the real interface;
-@item @option{[-]progress} enable progress indication;
-@item @option{[-]ignore_error} continue execution despite TDO check
+@item @option{-progress} enable progress indication;
+@item @option{-ignore_error} continue execution despite TDO check
 errors.
 @item @option{-noreset} omit JTAG reset (Test-Logic-Reset) before executing
 content of the SVF file;
diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c
index 0562906b9..7723a1755 100644
--- a/src/flash/nor/tcl.c
+++ b/src/flash/nor/tcl.c
@@ -815,6 +815,7 @@ COMMAND_HANDLER(handle_flash_write_bank_command)
 	if (buf_cnt != length) {
 		LOG_ERROR("Short read");
 		free(buffer);
+		fileio_close(fileio);
 		return ERROR_FAIL;
 	}
 
@@ -1325,40 +1326,27 @@ COMMAND_HANDLER(handle_flash_banks_command)
 	return ERROR_OK;
 }
 
-static int jim_flash_list(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+COMMAND_HANDLER(handle_flash_list)
 {
-	if (argc != 1) {
-		Jim_WrongNumArgs(interp, 1, argv,
-			"no arguments to 'flash list' command");
-		return JIM_ERR;
-	}
-
-	Jim_Obj *list = Jim_NewListObj(interp, NULL, 0);
+	if (CMD_ARGC != 0)
+		return ERROR_COMMAND_SYNTAX_ERROR;
 
 	for (struct flash_bank *p = flash_bank_list(); p; p = p->next) {
-		Jim_Obj *elem = Jim_NewListObj(interp, NULL, 0);
-
-		Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "name", -1));
-		Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, p->name, -1));
-		Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "driver", -1));
-		Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, p->driver->name, -1));
-		Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "base", -1));
-		Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->base));
-		Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "size", -1));
-		Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->size));
-		Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "bus_width", -1));
-		Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->bus_width));
-		Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "chip_width", -1));
-		Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->chip_width));
-		Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "target", -1));
-		Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, target_name(p->target), -1));
-
-		Jim_ListAppendElement(interp, list, elem);
+		command_print(CMD,
+			"{\n"
+			"    name       %s\n"
+			"    driver     %s\n"
+			"    base       " TARGET_ADDR_FMT "\n"
+			"    size       0x%" PRIx32 "\n"
+			"    bus_width  %u\n"
+			"    chip_width %u\n"
+			"    target     %s\n"
+			"}",
+			p->name, p->driver->name, p->base, p->size, p->bus_width, p->chip_width,
+			target_name(p->target));
 	}
 
-	Jim_SetResult(interp, list);
-
-	return JIM_OK;
+	return ERROR_OK;
 }
 
 COMMAND_HANDLER(handle_flash_init_command)
@@ -1405,8 +1393,9 @@ static const struct command_registration flash_config_command_handlers[] = {
 	{
 		.name = "list",
 		.mode = COMMAND_ANY,
-		.jim_handler = jim_flash_list,
+		.handler = handle_flash_list,
 		.help = "Returns a list of details about the flash banks.",
+		.usage = "",
 	},
 	COMMAND_REGISTRATION_DONE
 };
diff --git a/src/helper/command.c b/src/helper/command.c
index b358e18aa..235bec858 100644
--- a/src/helper/command.c
+++ b/src/helper/command.c
@@ -662,19 +662,19 @@ void command_done(struct command_context *cmd_ctx)
 }
 
 /* find full path to file */
-static int jim_find(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+COMMAND_HANDLER(handle_find)
 {
-	if (argc != 2)
-		return JIM_ERR;
-	const char *file = Jim_GetString(argv[1], NULL);
-	char *full_path = find_file(file);
+	if (CMD_ARGC != 1)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
+	char *full_path = find_file(CMD_ARGV[0]);
 	if (!full_path)
-		return JIM_ERR;
-	Jim_Obj *result = Jim_NewStringObj(interp, full_path, strlen(full_path));
+		return ERROR_COMMAND_ARGUMENT_INVALID;
+
+	command_print(CMD, "%s", full_path);
 	free(full_path);
 
-	Jim_SetResult(interp, result);
-	return JIM_OK;
+	return ERROR_OK;
 }
 
 COMMAND_HANDLER(handle_echo)
@@ -1165,7 +1165,7 @@ static const struct command_registration command_builtin_handlers[] = {
 	{
 		.name = "ocd_find",
 		.mode = COMMAND_ANY,
-		.jim_handler = jim_find,
+		.handler = handle_find,
 		.help = "find full path to file",
 		.usage = "file",
 	},
diff --git a/src/helper/compiler.h b/src/helper/compiler.h
index 33a075d64..312d261fc 100644
--- a/src/helper/compiler.h
+++ b/src/helper/compiler.h
@@ -36,9 +36,11 @@
  * clang for Apple defines
  * #define __nonnull _Nonnull
  * that is a per argument attribute, incompatible with the gcc per function attribute __nonnull__.
- * Undefine it to keep compatibility among compilers.
+ * gcc for Apple includes sys/cdefs.h from MacOSX.sdk that defines
+ * #define __nonnull
+ * In both cases, undefine __nonnull to keep compatibility among compilers and platforms.
  */
-#if defined(__clang__) && defined(__APPLE__)
+#if defined(__APPLE__)
 # undef __nonnull
 #endif
 #ifndef __nonnull
diff --git a/src/helper/list.h b/src/helper/list.h
index 552a3202a..c9de0569b 100644
--- a/src/helper/list.h
+++ b/src/helper/list.h
@@ -27,13 +27,6 @@ struct list_head {
 	struct list_head *next, *prev;
 };
 
-struct hlist_head {
-	struct hlist_node *first;
-};
-
-struct hlist_node {
-	struct hlist_node *next, **pprev;
-};
 /* end local changes */
 
 /*
@@ -272,8 +265,7 @@ static inline void list_bulk_move_tail(struct list_head *head,
  * @param list the entry to test
  * @param head the head of the list
  */
-static inline int list_is_first(const struct list_head *list,
-					const struct list_head *head)
+static inline int list_is_first(const struct list_head *list, const struct list_head *head)
 {
 	return list->prev == head;
 }
@@ -283,12 +275,21 @@ static inline int list_is_first(const struct list_head *list,
  * @param list the entry to test
  * @param head the head of the list
  */
-static inline int list_is_last(const struct list_head *list,
-				const struct list_head *head)
+static inline int list_is_last(const struct list_head *list, const struct list_head *head)
 {
 	return list->next == head;
 }
 
+/**
+ * list_is_head - tests whether @a list is the list @a head
+ * @param list the entry to test
+ * @param head the head of the list
+ */
+static inline int list_is_head(const struct list_head *list, const struct list_head *head)
+{
+	return list == head;
+}
+
 /**
  * list_empty - tests whether a list is empty
  * @param head the list to test.
@@ -407,10 +408,9 @@ static inline void list_cut_position(struct list_head *list,
 {
 	if (list_empty(head))
 		return;
-	if (list_is_singular(head) &&
-		(head->next != entry && head != entry))
+	if (list_is_singular(head) && !list_is_head(entry, head) && (entry != head->next))
 		return;
-	if (entry == head)
+	if (list_is_head(entry, head))
 		INIT_LIST_HEAD(list);
 	else
 		__list_cut_position(list, head, entry);
@@ -570,6 +570,19 @@ static inline void list_splice_tail_init(struct list_head *list,
 #define list_next_entry(pos, member) \
 	list_entry((pos)->member.next, typeof(*(pos)), member)
 
+/**
+ * list_next_entry_circular - get the next element in list
+ * @param pos    the type * to cursor.
+ * @param head   the list head to take the element from.
+ * @param member the name of the list_head within the struct.
+ *
+ * Wraparound if pos is the last element (return the first element).
+ * Note, that list is expected to be not empty.
+ */
+#define list_next_entry_circular(pos, head, member) \
+	(list_is_last(&(pos)->member, head) ? \
+	list_first_entry(head, typeof(*(pos)), member) : list_next_entry(pos, member))
+
 /**
  * list_prev_entry - get the prev element in list
  * @param pos    the type * to cursor
@@ -578,13 +591,28 @@ static inline void list_splice_tail_init(struct list_head *list,
 #define list_prev_entry(pos, member) \
 	list_entry((pos)->member.prev, typeof(*(pos)), member)
 
+/**
+ * list_prev_entry_circular - get the prev element in list
+ * @param pos    the type * to cursor.
+ * @param head   the list head to take the element from.
+ * @param member the name of the list_head within the struct.
+ *
+ * Wraparound if pos is the first element (return the last element).
+ * Note, that list is expected to be not empty.
+ */
+#define list_prev_entry_circular(pos, head, member) \
+	(list_is_first(&(pos)->member, head) ? \
+	list_last_entry(head, typeof(*(pos)), member) : list_prev_entry(pos, member))
+
 /**
  * list_for_each	-	iterate over a list
  * @param pos  the &struct list_head to use as a loop cursor.
  * @param head the head for your list.
  */
 #define list_for_each(pos, head) \
-	for (pos = (head)->next; pos != (head); pos = pos->next)
+	for (pos = (head)->next; !list_is_head(pos, (head)); pos = pos->next)
+
+/* Ignore kernel list_for_each_rcu() */
 
 /**
  * list_for_each_continue - continue iteration over a list
@@ -625,6 +653,21 @@ static inline void list_splice_tail_init(struct list_head *list,
 	     pos != (head); \
 	     pos = n, n = pos->prev)
 
+/**
+ * list_count_nodes - count nodes in the list
+ * @param head	the head for your list.
+ */
+static inline size_t list_count_nodes(struct list_head *head)
+{
+	struct list_head *pos;
+	size_t count = 0;
+
+	list_for_each(pos, head)
+		count++;
+
+	return count;
+}
+
 /**
  * list_entry_is_head - test if the entry points to the head of the list
  * @param pos    the type * to cursor
@@ -811,237 +854,7 @@ static inline void list_splice_tail_init(struct list_head *list,
 
 /*
  * Double linked lists with a single pointer list head.
- * Mostly useful for hash tables where the two pointer list head is
- * too wasteful.
- * You lose the ability to access the tail in O(1).
+ * IGNORED
  */
 
-#define HLIST_HEAD_INIT { .first = NULL }
-#define HLIST_HEAD(name) struct hlist_head name = {  .first = NULL }
-#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
-static inline void INIT_HLIST_NODE(struct hlist_node *h)
-{
-	h->next = NULL;
-	h->pprev = NULL;
-}
-
-/**
- * hlist_unhashed - Has node been removed from list and reinitialized?
- * @param h Node to be checked
- *
- * Not that not all removal functions will leave a node in unhashed
- * state.  For example, hlist_nulls_del_init_rcu() does leave the
- * node in unhashed state, but hlist_nulls_del() does not.
- */
-static inline int hlist_unhashed(const struct hlist_node *h)
-{
-	return !h->pprev;
-}
-
-/* Ignore kernel hlist_unhashed_lockless() */
-
-/**
- * hlist_empty - Is the specified hlist_head structure an empty hlist?
- * @param h Structure to check.
- */
-static inline int hlist_empty(const struct hlist_head *h)
-{
-	return !h->first;
-}
-
-static inline void __hlist_del(struct hlist_node *n)
-{
-	struct hlist_node *next = n->next;
-	struct hlist_node **pprev = n->pprev;
-
-	*pprev = next;
-	if (next)
-		next->pprev = pprev;
-}
-
-/**
- * hlist_del - Delete the specified hlist_node from its list
- * @param n Node to delete.
- *
- * Note that this function leaves the node in hashed state.  Use
- * hlist_del_init() or similar instead to unhash @a n.
- */
-static inline void hlist_del(struct hlist_node *n)
-{
-	__hlist_del(n);
-	n->next = LIST_POISON1;
-	n->pprev = LIST_POISON2;
-}
-
-/**
- * hlist_del_init - Delete the specified hlist_node from its list and initialize
- * @param n Node to delete.
- *
- * Note that this function leaves the node in unhashed state.
- */
-static inline void hlist_del_init(struct hlist_node *n)
-{
-	if (!hlist_unhashed(n)) {
-		__hlist_del(n);
-		INIT_HLIST_NODE(n);
-	}
-}
-
-/**
- * hlist_add_head - add a new entry at the beginning of the hlist
- * @param n new entry to be added
- * @param h hlist head to add it after
- *
- * Insert a new entry after the specified head.
- * This is good for implementing stacks.
- */
-static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
-{
-	struct hlist_node *first = h->first;
-	n->next = first;
-	if (first)
-		first->pprev = &n->next;
-	h->first = n;
-	n->pprev = &h->first;
-}
-
-/**
- * hlist_add_before - add a new entry before the one specified
- * @param n    new entry to be added
- * @param next hlist node to add it before, which must be non-NULL
- */
-static inline void hlist_add_before(struct hlist_node *n,
-				    struct hlist_node *next)
-{
-	n->pprev = next->pprev;
-	n->next = next;
-	next->pprev = &n->next;
-	*(n->pprev) = n;
-}
-
-/**
- * hlist_add_behind - add a new entry after the one specified
- * @param n    new entry to be added
- * @param prev hlist node to add it after, which must be non-NULL
- */
-static inline void hlist_add_behind(struct hlist_node *n,
-				    struct hlist_node *prev)
-{
-	n->next = prev->next;
-	prev->next = n;
-	n->pprev = &prev->next;
-
-	if (n->next)
-		n->next->pprev = &n->next;
-}
-
-/**
- * hlist_add_fake - create a fake hlist consisting of a single headless node
- * @param n Node to make a fake list out of
- *
- * This makes @a n appear to be its own predecessor on a headless hlist.
- * The point of this is to allow things like hlist_del() to work correctly
- * in cases where there is no list.
- */
-static inline void hlist_add_fake(struct hlist_node *n)
-{
-	n->pprev = &n->next;
-}
-
-/**
- * hlist_fake: Is this node a fake hlist?
- * @param h Node to check for being a self-referential fake hlist.
- */
-static inline bool hlist_fake(struct hlist_node *h)
-{
-	return h->pprev == &h->next;
-}
-
-/**
- * hlist_is_singular_node - is node the only element of the specified hlist?
- * @param n Node to check for singularity.
- * @param h Header for potentially singular list.
- *
- * Check whether the node is the only node of the head without
- * accessing head, thus avoiding unnecessary cache misses.
- */
-static inline bool
-hlist_is_singular_node(struct hlist_node *n, struct hlist_head *h)
-{
-	return !n->next && n->pprev == &h->first;
-}
-
-/**
- * hlist_move_list - Move an hlist
- * @param old hlist_head for old list.
- * @param new hlist_head for new list.
- *
- * Move a list from one list head to another. Fixup the pprev
- * reference of the first entry if it exists.
- */
-static inline void hlist_move_list(struct hlist_head *old,
-				   struct hlist_head *new)
-{
-	new->first = old->first;
-	if (new->first)
-		new->first->pprev = &new->first;
-	old->first = NULL;
-}
-
-#define hlist_entry(ptr, type, member) container_of(ptr, type, member)
-
-#define hlist_for_each(pos, head) \
-	for (pos = (head)->first; pos ; pos = pos->next)
-
-#define hlist_for_each_safe(pos, n, head) \
-	for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
-	     pos = n)
-
-#define hlist_entry_safe(ptr, type, member) \
-	({ typeof(ptr) ____ptr = (ptr); \
-	   ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
-	})
-
-/**
- * hlist_for_each_entry	- iterate over list of given type
- * @param pos    the type * to use as a loop cursor.
- * @param head   the head for your list.
- * @param member the name of the hlist_node within the struct.
- */
-#define hlist_for_each_entry(pos, head, member)				\
-	for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\
-	     pos;							\
-	     pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
-
-/**
- * hlist_for_each_entry_continue - iterate over a hlist continuing after current point
- * @param pos    the type * to use as a loop cursor.
- * @param member the name of the hlist_node within the struct.
- */
-#define hlist_for_each_entry_continue(pos, member)			\
-	for (pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member);\
-	     pos;							\
-	     pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
-
-/**
- * hlist_for_each_entry_from - iterate over a hlist continuing from current point
- * @param pos    the type * to use as a loop cursor.
- * @param member the name of the hlist_node within the struct.
- */
-#define hlist_for_each_entry_from(pos, member)				\
-	for (; pos;							\
-	     pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
-
-/**
- * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
- * @param pos    the type * to use as a loop cursor.
- * @param n      a &struct hlist_node to use as temporary storage
- * @param head   the head for your list.
- * @param member the name of the hlist_node within the struct.
- */
-#define hlist_for_each_entry_safe(pos, n, head, member)		\
-	for (pos = hlist_entry_safe((head)->first, typeof(*pos), member);\
-	     pos && ({ n = pos->member.next; 1; });			\
-	     pos = hlist_entry_safe(n, typeof(*pos), member))
-
 #endif /* OPENOCD_HELPER_LIST_H */
diff --git a/src/helper/util.c b/src/helper/util.c
index bf18f8e60..5e12021ff 100644
--- a/src/helper/util.c
+++ b/src/helper/util.c
@@ -13,28 +13,21 @@
 #include "log.h"
 #include "time_support.h"
 
-static int jim_util_ms(Jim_Interp *interp,
-	int argc,
-	Jim_Obj * const *argv)
+COMMAND_HANDLER(handler_util_ms)
 {
-	if (argc != 1) {
-		Jim_WrongNumArgs(interp, 1, argv, "ls ?dir?");
-		return JIM_ERR;
-	}
+	if (CMD_ARGC != 0)
+		return ERROR_COMMAND_SYNTAX_ERROR;
 
-	/* Cast from 64 to 32 bit int works for 2's-compliment
-	 * when calculating differences*/
-	Jim_SetResult(interp, Jim_NewIntObj(interp, (int)timeval_ms()));
+	command_print(CMD, "%" PRId64, timeval_ms());
 
-	return JIM_OK;
+	return ERROR_OK;
 }
 
 static const struct command_registration util_command_handlers[] = {
-	/* jim handlers */
 	{
 		.name = "ms",
 		.mode = COMMAND_ANY,
-		.jim_handler = jim_util_ms,
+		.handler = handler_util_ms,
 		.help =
 			"Returns ever increasing milliseconds. Used to calculate differences in time.",
 		.usage = "",
diff --git a/src/jtag/adapter.c b/src/jtag/adapter.c
index 430af6c3c..e70f4a1e8 100644
--- a/src/jtag/adapter.c
+++ b/src/jtag/adapter.c
@@ -374,21 +374,18 @@ done:
 	return equal;
 }
 
-static int jim_adapter_name(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+COMMAND_HANDLER(handle_adapter_name)
 {
-	struct jim_getopt_info goi;
-	jim_getopt_setup(&goi, interp, argc-1, argv + 1);
-
 	/* return the name of the interface */
 	/* TCL code might need to know the exact type... */
 	/* FUTURE: we allow this as a means to "set" the interface. */
-	if (goi.argc != 0) {
-		Jim_WrongNumArgs(goi.interp, 1, goi.argv-1, "(no params)");
-		return JIM_ERR;
-	}
-	const char *name = adapter_driver ? adapter_driver->name : NULL;
-	Jim_SetResultString(goi.interp, name ? name : "undefined", -1);
-	return JIM_OK;
+
+	if (CMD_ARGC != 0)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
+	command_print(CMD, "%s", adapter_driver ? adapter_driver->name : "undefined");
+
+	return ERROR_OK;
 }
 
 COMMAND_HANDLER(adapter_transports_command)
@@ -1123,9 +1120,10 @@ static const struct command_registration adapter_command_handlers[] = {
 	{
 		.name = "name",
 		.mode = COMMAND_ANY,
-		.jim_handler = jim_adapter_name,
+		.handler = handle_adapter_name,
 		.help = "Returns the name of the currently "
 			"selected adapter (driver)",
+		.usage = "",
 	},
 	{
 		.name = "srst",
diff --git a/src/jtag/tcl.c b/src/jtag/tcl.c
index fc0d562e2..b3cbc48b4 100644
--- a/src/jtag/tcl.c
+++ b/src/jtag/tcl.c
@@ -249,12 +249,15 @@ static int jim_command_pathmove(Jim_Interp *interp, int argc, Jim_Obj * const *a
 	return JIM_OK;
 }
 
-
-static int jim_command_flush_count(Jim_Interp *interp, int argc, Jim_Obj * const *args)
+COMMAND_HANDLER(handle_jtag_flush_count)
 {
-	Jim_SetResult(interp, Jim_NewIntObj(interp, jtag_get_flush_queue_count()));
+	if (CMD_ARGC != 0)
+		return ERROR_COMMAND_SYNTAX_ERROR;
 
-	return JIM_OK;
+	int count = jtag_get_flush_queue_count();
+	command_print_sameline(CMD, "%d", count);
+
+	return ERROR_OK;
 }
 
 /* REVISIT Just what about these should "move" ... ?
@@ -279,9 +282,10 @@ static const struct command_registration jtag_command_handlers_to_move[] = {
 	{
 		.name = "flush_count",
 		.mode = COMMAND_EXEC,
-		.jim_handler = jim_command_flush_count,
+		.handler = handle_jtag_flush_count,
 		.help = "Returns the number of times the JTAG queue "
 			"has been flushed.",
+		.usage = "",
 	},
 	{
 		.name = "pathmove",
@@ -664,45 +668,26 @@ static void jtag_tap_handle_event(struct jtag_tap *tap, enum jtag_event e)
 	}
 }
 
-static int jim_jtag_arp_init(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+COMMAND_HANDLER(handle_jtag_arp_init)
 {
-	struct jim_getopt_info goi;
-	jim_getopt_setup(&goi, interp, argc-1, argv + 1);
-	if (goi.argc != 0) {
-		Jim_WrongNumArgs(goi.interp, 1, goi.argv-1, "(no params)");
-		return JIM_ERR;
-	}
-	struct command_context *context = current_command_context(interp);
-	int e = jtag_init_inner(context);
-	if (e != ERROR_OK) {
-		Jim_Obj *obj = Jim_NewIntObj(goi.interp, e);
-		Jim_SetResultFormatted(goi.interp, "error: %#s", obj);
-		return JIM_ERR;
-	}
-	return JIM_OK;
+	if (CMD_ARGC != 0)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
+	return jtag_init_inner(CMD_CTX);
 }
 
-static int jim_jtag_arp_init_reset(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+COMMAND_HANDLER(handle_jtag_arp_init_reset)
 {
-	int e = ERROR_OK;
-	struct jim_getopt_info goi;
-	jim_getopt_setup(&goi, interp, argc-1, argv + 1);
-	if (goi.argc != 0) {
-		Jim_WrongNumArgs(goi.interp, 1, goi.argv-1, "(no params)");
-		return JIM_ERR;
-	}
-	struct command_context *context = current_command_context(interp);
-	if (transport_is_jtag())
-		e = jtag_init_reset(context);
-	else if (transport_is_swd())
-		e = swd_init_reset(context);
+	if (CMD_ARGC != 0)
+		return ERROR_COMMAND_SYNTAX_ERROR;
 
-	if (e != ERROR_OK) {
-		Jim_Obj *obj = Jim_NewIntObj(goi.interp, e);
-		Jim_SetResultFormatted(goi.interp, "error: %#s", obj);
-		return JIM_ERR;
-	}
-	return JIM_OK;
+	if (transport_is_jtag())
+		return jtag_init_reset(CMD_CTX);
+
+	if (transport_is_swd())
+		return swd_init_reset(CMD_CTX);
+
+	return ERROR_OK;
 }
 
 int jim_jtag_newtap(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
@@ -805,24 +790,15 @@ int jim_jtag_configure(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 	return jtag_tap_configure_cmd(&goi, t);
 }
 
-static int jim_jtag_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+COMMAND_HANDLER(handle_jtag_names)
 {
-	struct jim_getopt_info goi;
-	jim_getopt_setup(&goi, interp, argc-1, argv + 1);
-	if (goi.argc != 0) {
-		Jim_WrongNumArgs(goi.interp, 1, goi.argv, "Too many parameters");
-		return JIM_ERR;
-	}
-	Jim_SetResult(goi.interp, Jim_NewListObj(goi.interp, NULL, 0));
-	struct jtag_tap *tap;
+	if (CMD_ARGC != 0)
+		return ERROR_COMMAND_SYNTAX_ERROR;
 
-	for (tap = jtag_all_taps(); tap; tap = tap->next_tap) {
-		Jim_ListAppendElement(goi.interp,
-			Jim_GetResult(goi.interp),
-			Jim_NewStringObj(goi.interp,
-				tap->dotted_name, -1));
-	}
-	return JIM_OK;
+	for (struct jtag_tap *tap = jtag_all_taps(); tap; tap = tap->next_tap)
+		command_print(CMD, "%s", tap->dotted_name);
+
+	return ERROR_OK;
 }
 
 COMMAND_HANDLER(handle_jtag_init_command)
@@ -852,17 +828,19 @@ static const struct command_registration jtag_subcommand_handlers[] = {
 	{
 		.name = "arp_init",
 		.mode = COMMAND_ANY,
-		.jim_handler = jim_jtag_arp_init,
+		.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,
-		.jim_handler = jim_jtag_arp_init_reset,
+		.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'."
+			"the JTAG scan chain, then performs 'jtag arp_init'.",
+		.usage = "",
 	},
 	{
 		.name = "newtap",
@@ -921,8 +899,9 @@ static const struct command_registration jtag_subcommand_handlers[] = {
 	{
 		.name = "names",
 		.mode = COMMAND_ANY,
-		.jim_handler = jim_jtag_names,
+		.handler = handle_jtag_names,
 		.help = "Returns list of all JTAG tap names.",
+		.usage = "",
 	},
 	{
 		.chain = jtag_command_handlers_to_move,
diff --git a/src/openocd.c b/src/openocd.c
index 875da5a62..54c5eb34f 100644
--- a/src/openocd.c
+++ b/src/openocd.c
@@ -51,24 +51,23 @@ static const char openocd_startup_tcl[] = {
 };
 
 /* Give scripts and TELNET a way to find out what version this is */
-static int jim_version_command(Jim_Interp *interp, int argc,
-	Jim_Obj * const *argv)
+COMMAND_HANDLER(handler_version_command)
 {
-	if (argc > 2)
-		return JIM_ERR;
-	const char *str = "";
-	char *version_str;
-	version_str = OPENOCD_VERSION;
+	char *version_str = OPENOCD_VERSION;
 
-	if (argc == 2)
-		str = Jim_GetString(argv[1], NULL);
+	if (CMD_ARGC > 1)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
+	if (CMD_ARGC == 1) {
+		if (strcmp("git", CMD_ARGV[0]))
+			return ERROR_COMMAND_ARGUMENT_INVALID;
 
-	if (strcmp("git", str) == 0)
 		version_str = GITVERSION;
+	}
 
-	Jim_SetResult(interp, Jim_NewStringObj(interp, version_str, -1));
+	command_print(CMD, "%s", version_str);
 
-	return JIM_OK;
+	return ERROR_OK;
 }
 
 static int log_target_callback_event_handler(struct target *target,
@@ -194,9 +193,10 @@ COMMAND_HANDLER(handle_add_script_search_dir_command)
 static const struct command_registration openocd_command_handlers[] = {
 	{
 		.name = "version",
-		.jim_handler = jim_version_command,
+		.handler = handler_version_command,
 		.mode = COMMAND_ANY,
 		.help = "show program version",
+		.usage = "[git]",
 	},
 	{
 		.name = "noinit",
diff --git a/src/rtos/FreeRTOS.c b/src/rtos/FreeRTOS.c
index bf2896cf7..ea37f7fe7 100644
--- a/src/rtos/FreeRTOS.c
+++ b/src/rtos/FreeRTOS.c
@@ -729,6 +729,7 @@ static int freertos_update_threads(struct rtos *rtos)
 
 			tasks_found++;
 			list_thread_count--;
+			rtos->thread_count = tasks_found;
 
 			prev_list_elem_ptr = list_elem_ptr;
 			list_elem_ptr = 0;
@@ -750,7 +751,6 @@ static int freertos_update_threads(struct rtos *rtos)
 	}
 
 	free(list_of_lists);
-	rtos->thread_count = tasks_found;
 	return 0;
 }
 
diff --git a/src/rtt/tcl.c b/src/rtt/tcl.c
index 7cbdccf56..f949aa1c9 100644
--- a/src/rtt/tcl.c
+++ b/src/rtt/tcl.c
@@ -150,17 +150,17 @@ COMMAND_HANDLER(handle_rtt_channels_command)
 	return ERROR_OK;
 }
 
-static int jim_channel_list(Jim_Interp *interp, int argc,
-	Jim_Obj * const *argv)
+COMMAND_HANDLER(handle_channel_list)
 {
-	Jim_Obj *list;
-	Jim_Obj *channel_list;
 	char channel_name[CHANNEL_NAME_SIZE];
 	const struct rtt_control *ctrl;
 	struct rtt_channel_info info;
 
+	if (CMD_ARGC != 0)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
 	if (!rtt_found_cb()) {
-		Jim_SetResultFormatted(interp, "rtt: Control block not available");
+		command_print(CMD, "rtt: Control block not available");
 		return ERROR_FAIL;
 	}
 
@@ -169,81 +169,47 @@ static int jim_channel_list(Jim_Interp *interp, int argc,
 	info.name = channel_name;
 	info.name_length = sizeof(channel_name);
 
-	list = Jim_NewListObj(interp, NULL, 0);
-	channel_list = Jim_NewListObj(interp, NULL, 0);
+	command_print(CMD, "{");
 
 	for (unsigned int i = 0; i < ctrl->num_up_channels; i++) {
-		int ret;
-		Jim_Obj *tmp;
-
-		ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_UP, &info);
-
+		int ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_UP, &info);
 		if (ret != ERROR_OK)
 			return ret;
 
 		if (!info.size)
 			continue;
 
-		tmp = Jim_NewListObj(interp, NULL, 0);
-
-		Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
-			"name", -1));
-		Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
-			info.name, -1));
-
-		Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
-			"size", -1));
-		Jim_ListAppendElement(interp, tmp, Jim_NewIntObj(interp,
-			info.size));
-
-		Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
-			"flags", -1));
-		Jim_ListAppendElement(interp, tmp, Jim_NewIntObj(interp,
-			info.flags));
-
-		Jim_ListAppendElement(interp, channel_list, tmp);
+		command_print(CMD,
+			"    {\n"
+			"        name  %s\n"
+			"        size  0x%" PRIx32 "\n"
+			"        flags 0x%" PRIx32 "\n"
+			"    }",
+			info.name, info.size, info.flags);
 	}
 
-	Jim_ListAppendElement(interp, list, channel_list);
-
-	channel_list = Jim_NewListObj(interp, NULL, 0);
+	command_print(CMD, "}\n{");
 
 	for (unsigned int i = 0; i < ctrl->num_down_channels; i++) {
-		int ret;
-		Jim_Obj *tmp;
-
-		ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_DOWN, &info);
-
+		int ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_DOWN, &info);
 		if (ret != ERROR_OK)
 			return ret;
 
 		if (!info.size)
 			continue;
 
-		tmp = Jim_NewListObj(interp, NULL, 0);
-
-		Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
-			"name", -1));
-		Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
-			info.name, -1));
-
-		Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
-			"size", -1));
-		Jim_ListAppendElement(interp, tmp, Jim_NewIntObj(interp,
-			info.size));
-
-		Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
-			"flags", -1));
-		Jim_ListAppendElement(interp, tmp, Jim_NewIntObj(interp,
-			info.flags));
-
-		Jim_ListAppendElement(interp, channel_list, tmp);
+		command_print(CMD,
+			"    {\n"
+			"        name  %s\n"
+			"        size  0x%" PRIx32 "\n"
+			"        flags 0x%" PRIx32 "\n"
+			"    }",
+			info.name, info.size, info.flags);
 	}
 
-	Jim_ListAppendElement(interp, list, channel_list);
-	Jim_SetResult(interp, list);
+	command_print(CMD, "}");
 
-	return JIM_OK;
+	return ERROR_OK;
 }
 
 static const struct command_registration rtt_subcommand_handlers[] = {
@@ -284,7 +250,7 @@ static const struct command_registration rtt_subcommand_handlers[] = {
 	},
 	{
 		.name = "channellist",
-		.jim_handler = jim_channel_list,
+		.handler = handle_channel_list,
 		.mode = COMMAND_EXEC,
 		.help = "list available channels",
 		.usage = ""
diff --git a/src/server/ipdbg.c b/src/server/ipdbg.c
index f4a6f6cdc..755d0510e 100644
--- a/src/server/ipdbg.c
+++ b/src/server/ipdbg.c
@@ -90,7 +90,7 @@ static void ipdbg_zero_rd_idx(struct ipdbg_fifo *fifo)
 		return;
 
 	size_t ri = fifo->rd_idx;
-	for (size_t idx = 0 ; idx < fifo->count ; ++idx)
+	for (size_t idx = 0; idx < fifo->count; ++idx)
 		fifo->buffer[idx] = fifo->buffer[ri++];
 	fifo->rd_idx = 0;
 }
@@ -149,7 +149,7 @@ static int ipdbg_max_tools_from_data_register_length(uint8_t data_register_lengt
 static struct ipdbg_service *ipdbg_find_service(struct ipdbg_hub *hub, uint8_t tool)
 {
 	struct ipdbg_service *service;
-	for (service = ipdbg_first_service ; service ; service = service->next) {
+	for (service = ipdbg_first_service; service; service = service->next) {
 		if (service->hub == hub && service->tool == tool)
 			break;
 	}
@@ -160,7 +160,7 @@ static void ipdbg_add_service(struct ipdbg_service *service)
 {
 	struct ipdbg_service *iservice;
 	if (ipdbg_first_service) {
-		for (iservice = ipdbg_first_service ; iservice->next; iservice = iservice->next)
+		for (iservice = ipdbg_first_service; iservice->next; iservice = iservice->next)
 			;
 		iservice->next = service;
 	} else
@@ -192,7 +192,7 @@ static int ipdbg_remove_service(struct ipdbg_service *service)
 		return ERROR_OK;
 	}
 
-	for (struct ipdbg_service *iservice = ipdbg_first_service ; iservice->next ; iservice = iservice->next) {
+	for (struct ipdbg_service *iservice = ipdbg_first_service; iservice->next; iservice = iservice->next) {
 		if (service == iservice->next) {
 			iservice->next = service->next;
 			return ERROR_OK;
@@ -205,7 +205,7 @@ static struct ipdbg_hub *ipdbg_find_hub(struct jtag_tap *tap,
 				uint32_t user_instruction, struct ipdbg_virtual_ir_info *virtual_ir)
 {
 	struct ipdbg_hub *hub = NULL;
-	for (hub = ipdbg_first_hub ; hub ; hub = hub->next) {
+	for (hub = ipdbg_first_hub; hub; hub = hub->next) {
 		if (hub->tap == tap && hub->user_instruction == user_instruction) {
 			if ((!virtual_ir && !hub->virtual_ir) ||
 				 (virtual_ir && hub->virtual_ir &&
@@ -223,7 +223,7 @@ static void ipdbg_add_hub(struct ipdbg_hub *hub)
 {
 	struct ipdbg_hub *ihub;
 	if (ipdbg_first_hub) {
-		for (ihub = ipdbg_first_hub ; ihub->next; ihub = ihub->next)
+		for (ihub = ipdbg_first_hub; ihub->next; ihub = ihub->next)
 			;
 		ihub->next = hub;
 	} else
@@ -281,7 +281,7 @@ static int ipdbg_remove_hub(struct ipdbg_hub *hub)
 		return ERROR_OK;
 	}
 
-	for (struct ipdbg_hub *ihub = ipdbg_first_hub ; ihub->next ; ihub = ihub->next) {
+	for (struct ipdbg_hub *ihub = ipdbg_first_hub; ihub->next; ihub = ihub->next) {
 		if (hub == ihub->next) {
 			ihub->next = hub->next;
 			return ERROR_OK;
@@ -447,7 +447,7 @@ static int ipdbg_polling_callback(void *priv)
 
 	/* transfer dn buffers to jtag-hub */
 	unsigned int num_transfers = 0;
-	for (size_t tool = 0 ; tool < hub->max_tools ; ++tool) {
+	for (size_t tool = 0; tool < hub->max_tools; ++tool) {
 		struct connection *conn = hub->connections[tool];
 		if (conn && conn->priv) {
 			struct ipdbg_connection *connection = conn->priv;
@@ -475,7 +475,7 @@ static int ipdbg_polling_callback(void *priv)
 	}
 
 	/* write from up fifos to sockets */
-	for (size_t tool = 0 ; tool < hub->max_tools ; ++tool) {
+	for (size_t tool = 0; tool < hub->max_tools; ++tool) {
 		struct connection *conn = hub->connections[tool];
 		if (conn && conn->priv) {
 			struct ipdbg_connection *connection = conn->priv;
diff --git a/src/svf/svf.c b/src/svf/svf.c
index 719588067..dd3d5175c 100644
--- a/src/svf/svf.c
+++ b/src/svf/svf.c
@@ -22,6 +22,7 @@
 #include "svf.h"
 #include "helper/system.h"
 #include <helper/time_support.h>
+#include <helper/nvp.h>
 #include <stdbool.h>
 
 /* SVF command */
@@ -346,6 +347,37 @@ int svf_add_statemove(tap_state_t state_to)
 	return ERROR_FAIL;
 }
 
+enum svf_cmd_param {
+	OPT_ADDCYCLES,
+	OPT_IGNORE_ERROR,
+	OPT_NIL,
+	OPT_NORESET,
+	OPT_PROGRESS,
+	OPT_QUIET,
+	OPT_TAP,
+	/* DEPRECATED */
+	DEPRECATED_OPT_IGNORE_ERROR,
+	DEPRECATED_OPT_NIL,
+	DEPRECATED_OPT_PROGRESS,
+	DEPRECATED_OPT_QUIET,
+};
+
+static const struct nvp svf_cmd_opts[] = {
+	{ .name = "-addcycles",    .value = OPT_ADDCYCLES },
+	{ .name = "-ignore_error", .value = OPT_IGNORE_ERROR },
+	{ .name = "-nil",          .value = OPT_NIL },
+	{ .name = "-noreset",      .value = OPT_NORESET },
+	{ .name = "-progress",     .value = OPT_PROGRESS },
+	{ .name = "-quiet",        .value = OPT_QUIET },
+	{ .name = "-tap",          .value = OPT_TAP },
+	/* DEPRECATED */
+	{ .name = "ignore_error",  .value = DEPRECATED_OPT_IGNORE_ERROR },
+	{ .name = "nil",           .value = DEPRECATED_OPT_NIL },
+	{ .name = "progress",      .value = DEPRECATED_OPT_PROGRESS },
+	{ .name = "quiet",         .value = DEPRECATED_OPT_QUIET },
+	{ .name = NULL,            .value = -1 }
+};
+
 COMMAND_HANDLER(handle_svf_command)
 {
 #define SVF_MIN_NUM_OF_OPTIONS 1
@@ -355,10 +387,11 @@ COMMAND_HANDLER(handle_svf_command)
 	int64_t time_measure_ms;
 	int time_measure_s, time_measure_m;
 
-	/* use NULL to indicate a "plain" svf file which accounts for
+	/*
+	 * use NULL to indicate a "plain" svf file which accounts for
 	 * any additional devices in the scan chain, otherwise the device
 	 * that should be affected
-	*/
+	 */
 	struct jtag_tap *tap = NULL;
 
 	if ((CMD_ARGC < SVF_MIN_NUM_OF_OPTIONS) || (CMD_ARGC > SVF_MAX_NUM_OF_OPTIONS))
@@ -373,42 +406,74 @@ COMMAND_HANDLER(handle_svf_command)
 	svf_addcycles = 0;
 
 	for (unsigned int i = 0; i < CMD_ARGC; i++) {
-		if (strcmp(CMD_ARGV[i], "-addcycles") == 0) {
+		const struct nvp *n = nvp_name2value(svf_cmd_opts, CMD_ARGV[i]);
+		switch (n->value) {
+		case OPT_ADDCYCLES:
 			svf_addcycles = atoi(CMD_ARGV[i + 1]);
 			if (svf_addcycles > SVF_MAX_ADDCYCLES) {
 				command_print(CMD, "addcycles: %s out of range", CMD_ARGV[i + 1]);
-				return ERROR_FAIL;
+				if (svf_fd)
+					fclose(svf_fd);
+				svf_fd = NULL;
+				return ERROR_COMMAND_ARGUMENT_INVALID;
 			}
 			i++;
-		} else if (strcmp(CMD_ARGV[i], "-tap") == 0) {
+			break;
+
+		case OPT_TAP:
 			tap = jtag_tap_by_string(CMD_ARGV[i+1]);
 			if (!tap) {
 				command_print(CMD, "Tap: %s unknown", CMD_ARGV[i+1]);
-				return ERROR_FAIL;
+				if (svf_fd)
+					fclose(svf_fd);
+				svf_fd = NULL;
+				return ERROR_COMMAND_ARGUMENT_INVALID;
 			}
 			i++;
-		} else if ((strcmp(CMD_ARGV[i],
-				"quiet") == 0) || (strcmp(CMD_ARGV[i], "-quiet") == 0))
+			break;
+
+		case DEPRECATED_OPT_QUIET:
+			LOG_INFO("DEPRECATED flag '%s'; use '-%s'", CMD_ARGV[i], CMD_ARGV[i]);
+			/* fallthrough */
+		case OPT_QUIET:
 			svf_quiet = 1;
-		else if ((strcmp(CMD_ARGV[i], "nil") == 0) || (strcmp(CMD_ARGV[i], "-nil") == 0))
+			break;
+
+		case DEPRECATED_OPT_NIL:
+			LOG_INFO("DEPRECATED flag '%s'; use '-%s'", CMD_ARGV[i], CMD_ARGV[i]);
+			/* fallthrough */
+		case OPT_NIL:
 			svf_nil = 1;
-		else if ((strcmp(CMD_ARGV[i],
-				  "progress") == 0) || (strcmp(CMD_ARGV[i], "-progress") == 0))
+			break;
+
+		case DEPRECATED_OPT_PROGRESS:
+			LOG_INFO("DEPRECATED flag '%s'; use '-%s'", CMD_ARGV[i], CMD_ARGV[i]);
+			/* fallthrough */
+		case OPT_PROGRESS:
 			svf_progress_enabled = 1;
-		else if ((strcmp(CMD_ARGV[i],
-				  "ignore_error") == 0) || (strcmp(CMD_ARGV[i], "-ignore_error") == 0))
+			break;
+
+		case DEPRECATED_OPT_IGNORE_ERROR:
+			LOG_INFO("DEPRECATED flag '%s'; use '-%s'", CMD_ARGV[i], CMD_ARGV[i]);
+			/* fallthrough */
+		case OPT_IGNORE_ERROR:
 			svf_ignore_error = 1;
-		else if (strcmp(CMD_ARGV[i], "-noreset") == 0)
+			break;
+
+		case OPT_NORESET:
 			svf_noreset = true;
-		else {
+			break;
+
+		default:
 			svf_fd = fopen(CMD_ARGV[i], "r");
 			if (!svf_fd) {
 				int err = errno;
 				command_print(CMD, "open(\"%s\"): %s", CMD_ARGV[i], strerror(err));
 				/* no need to free anything now */
 				return ERROR_COMMAND_SYNTAX_ERROR;
-			} else
-				LOG_USER("svf processing file: \"%s\"", CMD_ARGV[i]);
+			}
+			LOG_USER("svf processing file: \"%s\"", CMD_ARGV[i]);
+			break;
 		}
 	}
 
@@ -467,27 +532,31 @@ COMMAND_HANDLER(handle_svf_command)
 		}
 
 		/* HDR %d TDI (0) */
-		if (svf_set_padding(&svf_para.hdr_para, header_dr_len, 0) != ERROR_OK) {
-			LOG_ERROR("failed to set data header");
-			return ERROR_FAIL;
+		ret = svf_set_padding(&svf_para.hdr_para, header_dr_len, 0);
+		if (ret != ERROR_OK) {
+			command_print(CMD, "failed to set data header");
+			goto free_all;
 		}
 
 		/* HIR %d TDI (0xFF) */
-		if (svf_set_padding(&svf_para.hir_para, header_ir_len, 0xFF) != ERROR_OK) {
-			LOG_ERROR("failed to set instruction header");
-			return ERROR_FAIL;
+		ret = svf_set_padding(&svf_para.hir_para, header_ir_len, 0xFF);
+		if (ret != ERROR_OK) {
+			command_print(CMD, "failed to set instruction header");
+			goto free_all;
 		}
 
 		/* TDR %d TDI (0) */
-		if (svf_set_padding(&svf_para.tdr_para, trailer_dr_len, 0) != ERROR_OK) {
-			LOG_ERROR("failed to set data trailer");
-			return ERROR_FAIL;
+		ret = svf_set_padding(&svf_para.tdr_para, trailer_dr_len, 0);
+		if (ret != ERROR_OK) {
+			command_print(CMD, "failed to set data trailer");
+			goto free_all;
 		}
 
 		/* TIR %d TDI (0xFF) */
-		if (svf_set_padding(&svf_para.tir_para, trailer_ir_len, 0xFF) != ERROR_OK) {
-			LOG_ERROR("failed to set instruction trailer");
-			return ERROR_FAIL;
+		ret = svf_set_padding(&svf_para.tir_para, trailer_ir_len, 0xFF);
+		if (ret != ERROR_OK) {
+			command_print(CMD, "failed to set instruction trailer");
+			goto free_all;
 		}
 	}
 
@@ -546,7 +615,7 @@ COMMAND_HANDLER(handle_svf_command)
 free_all:
 
 	fclose(svf_fd);
-	svf_fd = 0;
+	svf_fd = NULL;
 
 	/* free buffers */
 	free(svf_command_buffer);
@@ -1566,7 +1635,7 @@ static const struct command_registration svf_command_handlers[] = {
 		.handler = handle_svf_command,
 		.mode = COMMAND_EXEC,
 		.help = "Runs a SVF file.",
-		.usage = "[-tap device.tap] <file> [quiet] [nil] [progress] [ignore_error] [-noreset] [-addcycles numcycles]",
+		.usage = "[-tap device.tap] [-quiet] [-nil] [-progress] [-ignore_error] [-noreset] [-addcycles numcycles] file",
 	},
 	COMMAND_REGISTRATION_DONE
 };
diff --git a/src/target/aarch64.c b/src/target/aarch64.c
index 8e90e6400..3c33032e9 100644
--- a/src/target/aarch64.c
+++ b/src/target/aarch64.c
@@ -2952,53 +2952,41 @@ COMMAND_HANDLER(aarch64_mask_interrupts_command)
 	return ERROR_OK;
 }
 
-static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+COMMAND_HANDLER(aarch64_mcrmrc_command)
 {
-	struct command *c = jim_to_command(interp);
-	struct command_context *context;
-	struct target *target;
-	struct arm *arm;
-	int retval;
 	bool is_mcr = false;
-	int arg_cnt = 0;
+	unsigned int arg_cnt = 5;
 
-	if (!strcmp(c->name, "mcr")) {
+	if (!strcmp(CMD_NAME, "mcr")) {
 		is_mcr = true;
-		arg_cnt = 7;
-	} else {
 		arg_cnt = 6;
 	}
 
-	context = current_command_context(interp);
-	assert(context);
+	if (arg_cnt != CMD_ARGC)
+		return ERROR_COMMAND_SYNTAX_ERROR;
 
-	target = get_current_target(context);
+	struct target *target = get_current_target(CMD_CTX);
 	if (!target) {
-		LOG_ERROR("%s: no current target", __func__);
-		return JIM_ERR;
+		command_print(CMD, "no current target");
+		return ERROR_FAIL;
 	}
 	if (!target_was_examined(target)) {
-		LOG_ERROR("%s: not yet examined", target_name(target));
-		return JIM_ERR;
+		command_print(CMD, "%s: not yet examined", target_name(target));
+		return ERROR_TARGET_NOT_EXAMINED;
 	}
 
-	arm = target_to_arm(target);
+	struct arm *arm = target_to_arm(target);
 	if (!is_arm(arm)) {
-		LOG_ERROR("%s: not an ARM", target_name(target));
-		return JIM_ERR;
+		command_print(CMD, "%s: not an ARM", target_name(target));
+		return ERROR_FAIL;
 	}
 
 	if (target->state != TARGET_HALTED)
 		return ERROR_TARGET_NOT_HALTED;
 
 	if (arm->core_state == ARM_STATE_AARCH64) {
-		LOG_ERROR("%s: not 32-bit arm target", target_name(target));
-		return JIM_ERR;
-	}
-
-	if (argc != arg_cnt) {
-		LOG_ERROR("%s: wrong number of arguments", __func__);
-		return JIM_ERR;
+		command_print(CMD, "%s: not 32-bit arm target", target_name(target));
+		return ERROR_FAIL;
 	}
 
 	int cpnum;
@@ -3007,87 +2995,62 @@ static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
 	uint32_t crn;
 	uint32_t crm;
 	uint32_t value;
-	long l;
 
 	/* NOTE:  parameter sequence matches ARM instruction set usage:
 	 *	MCR	pNUM, op1, rX, CRn, CRm, op2	; write CP from rX
 	 *	MRC	pNUM, op1, rX, CRn, CRm, op2	; read CP into rX
 	 * The "rX" is necessarily omitted; it uses Tcl mechanisms.
 	 */
-	retval = Jim_GetLong(interp, argv[1], &l);
-	if (retval != JIM_OK)
-		return retval;
-	if (l & ~0xf) {
-		LOG_ERROR("%s: %s %d out of range", __func__,
-			"coprocessor", (int) l);
-		return JIM_ERR;
+	COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], cpnum);
+	if (cpnum & ~0xf) {
+		command_print(CMD, "coprocessor %d out of range", cpnum);
+		return ERROR_COMMAND_ARGUMENT_INVALID;
 	}
-	cpnum = l;
 
-	retval = Jim_GetLong(interp, argv[2], &l);
-	if (retval != JIM_OK)
-		return retval;
-	if (l & ~0x7) {
-		LOG_ERROR("%s: %s %d out of range", __func__,
-			"op1", (int) l);
-		return JIM_ERR;
+	COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], op1);
+	if (op1 & ~0x7) {
+		command_print(CMD, "op1 %d out of range", op1);
+		return ERROR_COMMAND_ARGUMENT_INVALID;
 	}
-	op1 = l;
 
-	retval = Jim_GetLong(interp, argv[3], &l);
-	if (retval != JIM_OK)
-		return retval;
-	if (l & ~0xf) {
-		LOG_ERROR("%s: %s %d out of range", __func__,
-			"CRn", (int) l);
-		return JIM_ERR;
+	COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], crn);
+	if (crn & ~0xf) {
+		command_print(CMD, "CRn %d out of range", crn);
+		return ERROR_COMMAND_ARGUMENT_INVALID;
 	}
-	crn = l;
 
-	retval = Jim_GetLong(interp, argv[4], &l);
-	if (retval != JIM_OK)
-		return retval;
-	if (l & ~0xf) {
-		LOG_ERROR("%s: %s %d out of range", __func__,
-			"CRm", (int) l);
-		return JIM_ERR;
+	COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], crm);
+	if (crm & ~0xf) {
+		command_print(CMD, "CRm %d out of range", crm);
+		return ERROR_COMMAND_ARGUMENT_INVALID;
 	}
-	crm = l;
 
-	retval = Jim_GetLong(interp, argv[5], &l);
-	if (retval != JIM_OK)
-		return retval;
-	if (l & ~0x7) {
-		LOG_ERROR("%s: %s %d out of range", __func__,
-			"op2", (int) l);
-		return JIM_ERR;
+	COMMAND_PARSE_NUMBER(u32, CMD_ARGV[4], op2);
+	if (op2 & ~0x7) {
+		command_print(CMD, "op2 %d out of range", op2);
+		return ERROR_COMMAND_ARGUMENT_INVALID;
 	}
-	op2 = l;
 
-	value = 0;
-
-	if (is_mcr == true) {
-		retval = Jim_GetLong(interp, argv[6], &l);
-		if (retval != JIM_OK)
-			return retval;
-		value = l;
+	if (is_mcr) {
+		COMMAND_PARSE_NUMBER(u32, CMD_ARGV[5], value);
 
 		/* NOTE: parameters reordered! */
 		/* ARMV4_5_MCR(cpnum, op1, 0, crn, crm, op2) */
-		retval = arm->mcr(target, cpnum, op1, op2, crn, crm, value);
+		int retval = arm->mcr(target, cpnum, op1, op2, crn, crm, value);
 		if (retval != ERROR_OK)
-			return JIM_ERR;
+			return retval;
 	} else {
+		value = 0;
 		/* NOTE: parameters reordered! */
 		/* ARMV4_5_MRC(cpnum, op1, 0, crn, crm, op2) */
-		retval = arm->mrc(target, cpnum, op1, op2, crn, crm, &value);
+		int retval = arm->mrc(target, cpnum, op1, op2, crn, crm, &value);
 		if (retval != ERROR_OK)
-			return JIM_ERR;
+			return retval;
 
-		Jim_SetResult(interp, Jim_NewIntObj(interp, value));
+		command_print(CMD, "0x%" PRIx32, value);
 	}
 
-	return JIM_OK;
+	return ERROR_OK;
 }
 
 static const struct command_registration aarch64_exec_command_handlers[] = {
@@ -3122,14 +3085,14 @@ static const struct command_registration aarch64_exec_command_handlers[] = {
 	{
 		.name = "mcr",
 		.mode = COMMAND_EXEC,
-		.jim_handler = jim_mcrmrc,
+		.handler = aarch64_mcrmrc_command,
 		.help = "write coprocessor register",
 		.usage = "cpnum op1 CRn CRm op2 value",
 	},
 	{
 		.name = "mrc",
 		.mode = COMMAND_EXEC,
-		.jim_handler = jim_mcrmrc,
+		.handler = aarch64_mcrmrc_command,
 		.help = "read coprocessor register",
 		.usage = "cpnum op1 CRn CRm op2",
 	},
diff --git a/src/target/adi_v5_jtag.c b/src/target/adi_v5_jtag.c
index eeb796be4..9f66adc68 100644
--- a/src/target/adi_v5_jtag.c
+++ b/src/target/adi_v5_jtag.c
@@ -566,14 +566,20 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap)
 		/* restore SELECT register first */
 		if (!list_empty(&replay_list)) {
 			el = list_first_entry(&replay_list, struct dap_cmd, lh);
+
+			uint8_t out_value_buf[4];
+			buf_set_u32(out_value_buf, 0, 32, (uint32_t)(el->dp_select));
+
 			tmp = dap_cmd_new(dap, JTAG_DP_DPACC,
-					  DP_SELECT, DPAP_WRITE, (uint8_t *)&el->dp_select, NULL, 0);
+					  DP_SELECT, DPAP_WRITE, out_value_buf, NULL, 0);
 			if (!tmp) {
 				retval = ERROR_JTAG_DEVICE_ERROR;
 				goto done;
 			}
 			list_add(&tmp->lh, &replay_list);
 
+			/* TODO: ADIv6 DP SELECT1 handling */
+
 			dap->select = DP_SELECT_INVALID;
 		}
 
diff --git a/src/target/adi_v5_swd.c b/src/target/adi_v5_swd.c
index aea730d4d..653f91f13 100644
--- a/src/target/adi_v5_swd.c
+++ b/src/target/adi_v5_swd.c
@@ -13,7 +13,7 @@
  * is a transport level interface, with "target/arm_adi_v5.[hc]" code
  * understanding operation semantics, shared with the JTAG transport.
  *
- * Single-DAP support only.
+ * Single DAP and multidrop-SWD support.
  *
  * for details, see "ARM IHI 0031A"
  * ARM Debug Interface v5 Architecture Specification
diff --git a/src/target/arm_cti.c b/src/target/arm_cti.c
index 3612874e2..7637ad015 100644
--- a/src/target/arm_cti.c
+++ b/src/target/arm_cti.c
@@ -525,20 +525,17 @@ static int jim_cti_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 	return cti_create(&goi);
 }
 
-static int jim_cti_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+COMMAND_HANDLER(cti_handle_names)
 {
 	struct arm_cti *obj;
 
-	if (argc != 1) {
-		Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
-		return JIM_ERR;
-	}
-	Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
-	list_for_each_entry(obj, &all_cti, lh) {
-		Jim_ListAppendElement(interp, Jim_GetResult(interp),
-			Jim_NewStringObj(interp, obj->name, -1));
-	}
-	return JIM_OK;
+	if (CMD_ARGC != 0)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
+	list_for_each_entry(obj, &all_cti, lh)
+		command_print(CMD, "%s", obj->name);
+
+	return ERROR_OK;
 }
 
 
@@ -553,7 +550,7 @@ static const struct command_registration cti_subcommand_handlers[] = {
 	{
 		.name = "names",
 		.mode = COMMAND_ANY,
-		.jim_handler = jim_cti_names,
+		.handler = cti_handle_names,
 		.usage = "",
 		.help = "Lists all registered CTI objects by name",
 	},
diff --git a/src/target/arm_dap.c b/src/target/arm_dap.c
index e21136dd6..bc9d96236 100644
--- a/src/target/arm_dap.c
+++ b/src/target/arm_dap.c
@@ -421,20 +421,16 @@ static int jim_dap_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 	return dap_create(&goi);
 }
 
-static int jim_dap_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+COMMAND_HANDLER(handle_dap_names)
 {
-	struct arm_dap_object *obj;
+	if (CMD_ARGC != 0)
+		return ERROR_COMMAND_SYNTAX_ERROR;
 
-	if (argc != 1) {
-		Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
-		return JIM_ERR;
-	}
-	Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
-	list_for_each_entry(obj, &all_dap, lh) {
-		Jim_ListAppendElement(interp, Jim_GetResult(interp),
-			Jim_NewStringObj(interp, obj->name, -1));
-	}
-	return JIM_OK;
+	struct arm_dap_object *obj;
+	list_for_each_entry(obj, &all_dap, lh)
+		command_print(CMD, "%s", obj->name);
+
+	return ERROR_OK;
 }
 
 COMMAND_HANDLER(handle_dap_init)
@@ -500,7 +496,7 @@ static const struct command_registration dap_subcommand_handlers[] = {
 	{
 		.name = "names",
 		.mode = COMMAND_ANY,
-		.jim_handler = jim_dap_names,
+		.handler = handle_dap_names,
 		.usage = "",
 		.help = "Lists all registered DAP instances by name",
 	},
diff --git a/src/target/arm_tpiu_swo.c b/src/target/arm_tpiu_swo.c
index 7096db305..5cea682ec 100644
--- a/src/target/arm_tpiu_swo.c
+++ b/src/target/arm_tpiu_swo.c
@@ -595,54 +595,52 @@ static const struct service_driver arm_tpiu_swo_service_driver = {
 	.keep_client_alive_handler = NULL,
 };
 
-static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+COMMAND_HANDLER(handle_arm_tpiu_swo_enable)
 {
-	struct command *c = jim_to_command(interp);
-	struct arm_tpiu_swo_object *obj = c->jim_handler_data;
-	struct command_context *cmd_ctx = current_command_context(interp);
+	struct arm_tpiu_swo_object *obj = CMD_DATA;
 	uint32_t value;
 	int retval;
 
-	if (argc != 1) {
-		Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
-		return JIM_ERR;
-	}
+	if (CMD_ARGC != 0)
+		return ERROR_COMMAND_SYNTAX_ERROR;
 
-	if (cmd_ctx->mode == COMMAND_CONFIG) {
+	if (CMD_CTX->mode == COMMAND_CONFIG) {
 		LOG_DEBUG("%s: enable deferred", obj->name);
 		obj->deferred_enable = true;
-		return JIM_OK;
+		return ERROR_OK;
 	}
 
 	if (obj->enabled)
-		return JIM_OK;
+		return ERROR_OK;
 
 	if (transport_is_hla() && obj->spot.ap_num != 0) {
-		LOG_ERROR("Invalid access port 0x%" PRIx64 ". Only AP#0 allowed with hla transport", obj->spot.ap_num);
-		return JIM_ERR;
+		command_print(CMD,
+			"Invalid access port 0x%" PRIx64 ". Only AP#0 allowed with hla transport",
+			obj->spot.ap_num);
+		return ERROR_FAIL;
 	}
 
 	if (!obj->traceclkin_freq) {
-		LOG_ERROR("Trace clock-in frequency not set");
-		return JIM_ERR;
+		command_print(CMD, "Trace clock-in frequency not set");
+		return ERROR_FAIL;
 	}
 
 	if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_MANCHESTER || obj->pin_protocol == TPIU_SPPR_PROTOCOL_UART)
 		if (!obj->swo_pin_freq)
 			LOG_DEBUG("SWO pin frequency not set, will be autodetected by the adapter");
 
-	struct target *target = get_current_target(cmd_ctx);
+	struct target *target = get_current_target(CMD_CTX);
 
 	/* START_DEPRECATED_TPIU */
 	if (obj->recheck_ap_cur_target) {
 		if (strcmp(target->type->name, "cortex_m") &&
 			strcmp(target->type->name, "hla_target")) {
 			LOG_ERROR(MSG "Current target is not a Cortex-M nor a HLA");
-			return JIM_ERR;
+			return ERROR_FAIL;
 		}
 		if (!target_was_examined(target)) {
 			LOG_ERROR(MSG "Current target not examined yet");
-			return JIM_ERR;
+			return ERROR_FAIL;
 		}
 		struct cortex_m_common *cm = target_to_cm(target);
 		obj->recheck_ap_cur_target = false;
@@ -660,8 +658,8 @@ static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const
 	if (!obj->ap) {
 		obj->ap = dap_get_ap(obj->spot.dap, obj->spot.ap_num);
 		if (!obj->ap) {
-			LOG_ERROR("Cannot get AP");
-			return JIM_ERR;
+			command_print(CMD, "Cannot get AP");
+			return ERROR_FAIL;
 		}
 	}
 
@@ -670,8 +668,8 @@ static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const
 
 	retval = wrap_read_u32(target, obj->ap, obj->spot.base + TPIU_DEVID_OFFSET, &value);
 	if (retval != ERROR_OK) {
-		LOG_ERROR("Unable to read %s", obj->name);
-		return JIM_ERR;
+		command_print(CMD, "Unable to read %s", obj->name);
+		return retval;
 	}
 	switch (obj->pin_protocol) {
 	case TPIU_SPPR_PROTOCOL_SYNC:
@@ -687,21 +685,20 @@ static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const
 		value = 0;
 	}
 	if (!value) {
-		struct jim_nvp *p;
-		jim_nvp_value2name(interp, nvp_arm_tpiu_swo_protocol_opts, obj->pin_protocol, &p);
-		LOG_ERROR("%s does not support protocol %s", obj->name, p->name);
-		return JIM_ERR;
+		struct jim_nvp *p = jim_nvp_value2name_simple(nvp_arm_tpiu_swo_protocol_opts, obj->pin_protocol);
+		command_print(CMD, "%s does not support protocol %s", obj->name, p->name);
+		return ERROR_FAIL;
 	}
 
 	if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_SYNC) {
 		retval = wrap_read_u32(target, obj->ap, obj->spot.base + TPIU_SSPSR_OFFSET, &value);
 		if (retval != ERROR_OK) {
-			LOG_ERROR("Cannot read TPIU register SSPSR");
-			return JIM_ERR;
+			command_print(CMD, "Cannot read TPIU register SSPSR");
+			return retval;
 		}
 		if (!(value & BIT(obj->port_width - 1))) {
-			LOG_ERROR("TPIU does not support port-width of %d bits", obj->port_width);
-			return JIM_ERR;
+			command_print(CMD, "TPIU does not support port-width of %d bits", obj->port_width);
+			return ERROR_FAIL;
 		}
 	}
 
@@ -713,41 +710,42 @@ static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const
 			struct arm_tpiu_swo_priv_connection *priv = malloc(sizeof(*priv));
 			if (!priv) {
 				LOG_ERROR("Out of memory");
-				return JIM_ERR;
+				return ERROR_FAIL;
 			}
 			priv->obj = obj;
 			LOG_INFO("starting trace server for %s on %s", obj->name, &obj->out_filename[1]);
 			retval = add_service(&arm_tpiu_swo_service_driver, &obj->out_filename[1],
 				CONNECTION_LIMIT_UNLIMITED, priv);
 			if (retval != ERROR_OK) {
-				LOG_ERROR("Can't configure trace TCP port %s", &obj->out_filename[1]);
-				return JIM_ERR;
+				command_print(CMD, "Can't configure trace TCP port %s", &obj->out_filename[1]);
+				return retval;
 			}
 		} else if (strcmp(obj->out_filename, "-")) {
 			obj->file = fopen(obj->out_filename, "ab");
 			if (!obj->file) {
-				LOG_ERROR("Can't open trace destination file \"%s\"", obj->out_filename);
-				return JIM_ERR;
+				command_print(CMD, "Can't open trace destination file \"%s\"", obj->out_filename);
+				return ERROR_FAIL;
 			}
 		}
 
 		retval = adapter_config_trace(true, obj->pin_protocol, obj->port_width,
 			&swo_pin_freq, obj->traceclkin_freq, &prescaler);
 		if (retval != ERROR_OK) {
-			LOG_ERROR("Failed to start adapter's trace");
+			command_print(CMD, "Failed to start adapter's trace");
 			arm_tpiu_swo_close_output(obj);
-			return JIM_ERR;
+			return retval;
 		}
 
 		if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_MANCHESTER || obj->pin_protocol == TPIU_SPPR_PROTOCOL_UART)
 			if (!swo_pin_freq) {
 				if (obj->swo_pin_freq)
-					LOG_ERROR("Adapter rejected SWO pin frequency %d Hz", obj->swo_pin_freq);
+					command_print(CMD, "Adapter rejected SWO pin frequency %d Hz", obj->swo_pin_freq);
 				else
-					LOG_ERROR("Adapter does not support auto-detection of SWO pin frequency nor a default value");
+					command_print(CMD,
+						"Adapter does not support auto-detection of SWO pin frequency nor a default value");
 
 				arm_tpiu_swo_close_output(obj);
-				return JIM_ERR;
+				return ERROR_FAIL;
 			}
 
 		if (obj->swo_pin_freq != swo_pin_freq)
@@ -799,10 +797,10 @@ static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const
 	/* END_DEPRECATED_TPIU */
 
 	obj->enabled = true;
-	return JIM_OK;
+	return ERROR_OK;
 
 error_exit:
-	LOG_ERROR("Error!");
+	command_print(CMD, "Error!");
 
 	if (obj->en_capture) {
 		obj->en_capture = false;
@@ -811,27 +809,22 @@ error_exit:
 
 		target_unregister_timer_callback(arm_tpiu_swo_poll_trace, obj);
 
-		retval = adapter_config_trace(false, 0, 0, NULL, 0, NULL);
-		if (retval != ERROR_OK) {
-			LOG_ERROR("Failed to stop adapter's trace");
-			return JIM_ERR;
-		}
+		int retval1 = adapter_config_trace(false, 0, 0, NULL, 0, NULL);
+		if (retval1 != ERROR_OK)
+			command_print(CMD, "Failed to stop adapter's trace");
 	}
-	return JIM_ERR;
+	return retval;
 }
 
-static int jim_arm_tpiu_swo_disable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+COMMAND_HANDLER(handle_arm_tpiu_swo_disable)
 {
-	struct command *c = jim_to_command(interp);
-	struct arm_tpiu_swo_object *obj = c->jim_handler_data;
+	struct arm_tpiu_swo_object *obj = CMD_DATA;
 
-	if (argc != 1) {
-		Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
-		return JIM_ERR;
-	}
+	if (CMD_ARGC != 0)
+		return ERROR_COMMAND_SYNTAX_ERROR;
 
 	if (!obj->enabled)
-		return JIM_OK;
+		return ERROR_OK;
 	obj->enabled = false;
 
 	arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_PRE_DISABLE);
@@ -845,20 +838,19 @@ static int jim_arm_tpiu_swo_disable(Jim_Interp *interp, int argc, Jim_Obj *const
 
 		int retval = adapter_config_trace(false, 0, 0, NULL, 0, NULL);
 		if (retval != ERROR_OK) {
-			LOG_ERROR("Failed to stop adapter's trace");
-			return JIM_ERR;
+			command_print(CMD, "Failed to stop adapter's trace");
+			return retval;
 		}
 	}
 
 	arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_POST_DISABLE);
 
 	/* START_DEPRECATED_TPIU */
-	struct command_context *cmd_ctx = current_command_context(interp);
-	struct target *target = get_current_target(cmd_ctx);
+	struct target *target = get_current_target(CMD_CTX);
 	target_handle_event(target, TARGET_EVENT_TRACE_CONFIG);
 	/* END_DEPRECATED_TPIU */
 
-	return JIM_OK;
+	return ERROR_OK;
 }
 
 static const struct command_registration arm_tpiu_swo_instance_command_handlers[] = {
@@ -886,14 +878,14 @@ static const struct command_registration arm_tpiu_swo_instance_command_handlers[
 	{
 		.name = "enable",
 		.mode = COMMAND_ANY,
-		.jim_handler = jim_arm_tpiu_swo_enable,
+		.handler = handle_arm_tpiu_swo_enable,
 		.usage = "",
 		.help = "Enables the TPIU/SWO output",
 	},
 	{
 		.name = "disable",
 		.mode = COMMAND_EXEC,
-		.jim_handler = jim_arm_tpiu_swo_disable,
+		.handler = handle_arm_tpiu_swo_disable,
 		.usage = "",
 		.help = "Disables the TPIU/SWO output",
 	},
@@ -989,39 +981,34 @@ err_exit:
 	return JIM_ERR;
 }
 
-static int jim_arm_tpiu_swo_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+COMMAND_HANDLER(handle_arm_tpiu_swo_names)
 {
 	struct arm_tpiu_swo_object *obj;
 
-	if (argc != 1) {
-		Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
-		return JIM_ERR;
-	}
-	Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
-	list_for_each_entry(obj, &all_tpiu_swo, lh) {
-		Jim_ListAppendElement(interp, Jim_GetResult(interp),
-			Jim_NewStringObj(interp, obj->name, -1));
-	}
-	return JIM_OK;
+	if (CMD_ARGC != 0)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
+	list_for_each_entry(obj, &all_tpiu_swo, lh)
+		command_print(CMD, "%s", obj->name);
+
+	return ERROR_OK;
 }
 
-static int jim_arm_tpiu_swo_init(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+COMMAND_HANDLER(handle_arm_tpiu_swo_init)
 {
-	struct command_context *cmd_ctx = current_command_context(interp);
 	struct arm_tpiu_swo_object *obj;
-	int retval = JIM_OK;
+	int retval = ERROR_OK;
+
+	if (CMD_ARGC != 0)
+		return ERROR_COMMAND_SYNTAX_ERROR;
 
-	if (argc != 1) {
-		Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
-		return JIM_ERR;
-	}
 	list_for_each_entry(obj, &all_tpiu_swo, lh) {
 		if (!obj->deferred_enable)
 			continue;
 		LOG_DEBUG("%s: running enable during init", obj->name);
-		int retval2 = command_run_linef(cmd_ctx, "%s enable", obj->name);
+		int retval2 = command_run_linef(CMD_CTX, "%s enable", obj->name);
 		if (retval2 != ERROR_OK)
-			retval = JIM_ERR;
+			retval = retval2;
 	}
 	return retval;
 }
@@ -1193,14 +1180,14 @@ static const struct command_registration arm_tpiu_swo_subcommand_handlers[] = {
 	{
 		.name = "names",
 		.mode = COMMAND_ANY,
-		.jim_handler = jim_arm_tpiu_swo_names,
+		.handler = handle_arm_tpiu_swo_names,
 		.usage = "",
 		.help = "Lists all registered TPIU and SWO objects by name",
 	},
 	{
 		.name = "init",
 		.mode = COMMAND_EXEC,
-		.jim_handler = jim_arm_tpiu_swo_init,
+		.handler = handle_arm_tpiu_swo_init,
 		.usage = "",
 		.help = "Initialize TPIU and SWO",
 	},
diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c
index 48af5035a..9586adc97 100644
--- a/src/target/armv4_5.c
+++ b/src/target/armv4_5.c
@@ -989,132 +989,106 @@ COMMAND_HANDLER(handle_arm_disassemble_command)
 #endif
 }
 
-static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+COMMAND_HANDLER(handle_armv4_5_mcrmrc)
 {
-	struct command_context *context;
-	struct target *target;
-	struct arm *arm;
-	int retval;
+	bool is_mcr = false;
+	unsigned int arg_cnt = 5;
 
-	context = current_command_context(interp);
-	assert(context);
+	if (!strcmp(CMD_NAME, "mcr")) {
+		is_mcr = true;
+		arg_cnt = 6;
+	}
 
-	target = get_current_target(context);
+	if (arg_cnt != CMD_ARGC)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
+	struct target *target = get_current_target(CMD_CTX);
 	if (!target) {
-		LOG_ERROR("%s: no current target", __func__);
-		return JIM_ERR;
+		command_print(CMD, "no current target");
+		return ERROR_FAIL;
 	}
 	if (!target_was_examined(target)) {
-		LOG_ERROR("%s: not yet examined", target_name(target));
-		return JIM_ERR;
-	}
-	arm = target_to_arm(target);
-	if (!is_arm(arm)) {
-		LOG_ERROR("%s: not an ARM", target_name(target));
-		return JIM_ERR;
+		command_print(CMD, "%s: not yet examined", target_name(target));
+		return ERROR_TARGET_NOT_EXAMINED;
 	}
 
-	if ((argc < 6) || (argc > 7)) {
-		/* FIXME use the command name to verify # params... */
-		LOG_ERROR("%s: wrong number of arguments", __func__);
-		return JIM_ERR;
+	struct arm *arm = target_to_arm(target);
+	if (!is_arm(arm)) {
+		command_print(CMD, "%s: not an ARM", target_name(target));
+		return ERROR_FAIL;
 	}
 
+	if (target->state != TARGET_HALTED)
+		return ERROR_TARGET_NOT_HALTED;
+
 	int cpnum;
 	uint32_t op1;
 	uint32_t op2;
 	uint32_t crn;
 	uint32_t crm;
 	uint32_t value;
-	long l;
 
 	/* NOTE:  parameter sequence matches ARM instruction set usage:
 	 *	MCR	pNUM, op1, rX, CRn, CRm, op2	; write CP from rX
 	 *	MRC	pNUM, op1, rX, CRn, CRm, op2	; read CP into rX
 	 * The "rX" is necessarily omitted; it uses Tcl mechanisms.
 	 */
-	retval = Jim_GetLong(interp, argv[1], &l);
-	if (retval != JIM_OK)
-		return retval;
-	if (l & ~0xf) {
-		LOG_ERROR("%s: %s %d out of range", __func__,
-			"coprocessor", (int) l);
-		return JIM_ERR;
+	COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], cpnum);
+	if (cpnum & ~0xf) {
+		command_print(CMD, "coprocessor %d out of range", cpnum);
+		return ERROR_COMMAND_ARGUMENT_INVALID;
 	}
-	cpnum = l;
 
-	retval = Jim_GetLong(interp, argv[2], &l);
-	if (retval != JIM_OK)
-		return retval;
-	if (l & ~0x7) {
-		LOG_ERROR("%s: %s %d out of range", __func__,
-			"op1", (int) l);
-		return JIM_ERR;
+	COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], op1);
+	if (op1 & ~0x7) {
+		command_print(CMD, "op1 %d out of range", op1);
+		return ERROR_COMMAND_ARGUMENT_INVALID;
 	}
-	op1 = l;
 
-	retval = Jim_GetLong(interp, argv[3], &l);
-	if (retval != JIM_OK)
-		return retval;
-	if (l & ~0xf) {
-		LOG_ERROR("%s: %s %d out of range", __func__,
-			"CRn", (int) l);
-		return JIM_ERR;
+	COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], crn);
+	if (crn & ~0xf) {
+		command_print(CMD, "CRn %d out of range", crn);
+		return ERROR_COMMAND_ARGUMENT_INVALID;
 	}
-	crn = l;
 
-	retval = Jim_GetLong(interp, argv[4], &l);
-	if (retval != JIM_OK)
-		return retval;
-	if (l & ~0xf) {
-		LOG_ERROR("%s: %s %d out of range", __func__,
-			"CRm", (int) l);
-		return JIM_ERR;
+	COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], crm);
+	if (crm & ~0xf) {
+		command_print(CMD, "CRm %d out of range", crm);
+		return ERROR_COMMAND_ARGUMENT_INVALID;
 	}
-	crm = l;
 
-	retval = Jim_GetLong(interp, argv[5], &l);
-	if (retval != JIM_OK)
-		return retval;
-	if (l & ~0x7) {
-		LOG_ERROR("%s: %s %d out of range", __func__,
-			"op2", (int) l);
-		return JIM_ERR;
+	COMMAND_PARSE_NUMBER(u32, CMD_ARGV[4], op2);
+	if (op2 & ~0x7) {
+		command_print(CMD, "op2 %d out of range", op2);
+		return ERROR_COMMAND_ARGUMENT_INVALID;
 	}
-	op2 = l;
 
-	value = 0;
-
-	/* FIXME don't assume "mrc" vs "mcr" from the number of params;
-	 * that could easily be a typo!  Check both...
-	 *
+	/*
 	 * FIXME change the call syntax here ... simplest to just pass
 	 * the MRC() or MCR() instruction to be executed.  That will also
 	 * let us support the "mrc2" and "mcr2" opcodes (toggling one bit)
 	 * if that's ever needed.
 	 */
-	if (argc == 7) {
-		retval = Jim_GetLong(interp, argv[6], &l);
-		if (retval != JIM_OK)
-			return retval;
-		value = l;
+	if (is_mcr) {
+		COMMAND_PARSE_NUMBER(u32, CMD_ARGV[5], value);
 
 		/* NOTE: parameters reordered! */
 		/* ARMV4_5_MCR(cpnum, op1, 0, crn, crm, op2) */
-		retval = arm->mcr(target, cpnum, op1, op2, crn, crm, value);
+		int retval = arm->mcr(target, cpnum, op1, op2, crn, crm, value);
 		if (retval != ERROR_OK)
-			return JIM_ERR;
+			return retval;
 	} else {
+		value = 0;
 		/* NOTE: parameters reordered! */
 		/* ARMV4_5_MRC(cpnum, op1, 0, crn, crm, op2) */
-		retval = arm->mrc(target, cpnum, op1, op2, crn, crm, &value);
+		int retval = arm->mrc(target, cpnum, op1, op2, crn, crm, &value);
 		if (retval != ERROR_OK)
-			return JIM_ERR;
+			return retval;
 
-		Jim_SetResult(interp, Jim_NewIntObj(interp, value));
+		command_print(CMD, "0x%" PRIx32, value);
 	}
 
-	return JIM_OK;
+	return ERROR_OK;
 }
 
 static const struct command_registration arm_exec_command_handlers[] = {
@@ -1128,14 +1102,14 @@ static const struct command_registration arm_exec_command_handlers[] = {
 	{
 		.name = "mcr",
 		.mode = COMMAND_EXEC,
-		.jim_handler = &jim_mcrmrc,
+		.handler = handle_armv4_5_mcrmrc,
 		.help = "write coprocessor register",
 		.usage = "cpnum op1 CRn CRm op2 value",
 	},
 	{
 		.name = "mrc",
 		.mode = COMMAND_EXEC,
-		.jim_handler = &jim_mcrmrc,
+		.handler = handle_armv4_5_mcrmrc,
 		.help = "read coprocessor register",
 		.usage = "cpnum op1 CRn CRm op2",
 	},
diff --git a/src/target/espressif/esp_semihosting.c b/src/target/espressif/esp_semihosting.c
index 5e9cb9457..51d499866 100644
--- a/src/target/espressif/esp_semihosting.c
+++ b/src/target/espressif/esp_semihosting.c
@@ -17,12 +17,10 @@
 
 static struct esp_semihost_data __attribute__((unused)) *target_to_esp_semihost_data(struct target *target)
 {
-	const char *arch = target_get_gdb_arch(target);
-	if (arch) {
-		if (strncmp(arch, "xtensa", 6) == 0)
-			return &target_to_esp_xtensa(target)->semihost;
-		/* TODO: add riscv */
-	}
+	struct xtensa *xtensa = target->arch_info;
+	if (xtensa->common_magic == XTENSA_COMMON_MAGIC)
+		return &target_to_esp_xtensa(target)->semihost;
+	/* TODO: add riscv */
 	LOG_ERROR("Unknown target arch!");
 	return NULL;
 }
diff --git a/src/target/mips_m4k.c b/src/target/mips_m4k.c
index 491b247b1..14e3f3b27 100644
--- a/src/target/mips_m4k.c
+++ b/src/target/mips_m4k.c
@@ -36,6 +36,8 @@ static int mips_m4k_internal_restore(struct target *target, int current,
 static int mips_m4k_halt(struct target *target);
 static int mips_m4k_bulk_write_memory(struct target *target, target_addr_t address,
 		uint32_t count, const uint8_t *buffer);
+static int mips_m4k_bulk_read_memory(struct target *target, target_addr_t address,
+		uint32_t count, uint8_t *buffer);
 
 static int mips_m4k_examine_debug_reason(struct target *target)
 {
@@ -1021,6 +1023,12 @@ static int mips_m4k_read_memory(struct target *target, target_addr_t address,
 	if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))
 		return ERROR_TARGET_UNALIGNED_ACCESS;
 
+	if (size == 4 && count > 32) {
+		int retval = mips_m4k_bulk_read_memory(target, address, count, buffer);
+		if (retval == ERROR_OK)
+			return ERROR_OK;
+		LOG_WARNING("Falling back to non-bulk read");
+	}
 	/* since we don't know if buffer is aligned, we allocate new mem that is always aligned */
 	void *t = NULL;
 
@@ -1218,8 +1226,8 @@ static int mips_m4k_bulk_write_memory(struct target *target, target_addr_t addre
 
 	fast_data_area = mips32->fast_data_area;
 
-	if (address <= fast_data_area->address + fast_data_area->size &&
-			fast_data_area->address <= address + count) {
+	if (address < (fast_data_area->address + fast_data_area->size) &&
+			fast_data_area->address < (address + count)) {
 		LOG_ERROR("fast_data (" TARGET_ADDR_FMT ") is within write area "
 			  "(" TARGET_ADDR_FMT "-" TARGET_ADDR_FMT ").",
 			  fast_data_area->address, address, address + count);
@@ -1249,6 +1257,71 @@ static int mips_m4k_bulk_write_memory(struct target *target, target_addr_t addre
 	return retval;
 }
 
+static int mips_m4k_bulk_read_memory(struct target *target, target_addr_t address,
+		uint32_t count, uint8_t *buffer)
+{
+	struct mips32_common *mips32 = target_to_mips32(target);
+	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
+	struct working_area *fast_data_area;
+	int retval;
+	int write_t = 0;
+
+	LOG_DEBUG("address: " TARGET_ADDR_FMT ", count: 0x%8.8" PRIx32 "",
+			address, count);
+
+	/* check alignment */
+	if (address & 0x3u)
+		return ERROR_TARGET_UNALIGNED_ACCESS;
+
+	if (!mips32->fast_data_area) {
+		/* Get memory for block read handler
+		 * we preserve this area between calls and gain a speed increase
+		 * of about 3kb/sec when reading flash
+		 * this will be released/nulled by the system when the target is resumed or reset */
+		retval = target_alloc_working_area(target,
+				MIPS32_FASTDATA_HANDLER_SIZE,
+				&mips32->fast_data_area);
+		if (retval != ERROR_OK) {
+			LOG_ERROR("No working area available");
+			return retval;
+		}
+
+		/* reset fastadata state so the algo get reloaded */
+		ejtag_info->fast_access_save = -1;
+	}
+
+	fast_data_area = mips32->fast_data_area;
+
+	if (address < (fast_data_area->address + fast_data_area->size) &&
+			fast_data_area->address < (address + count)) {
+		LOG_ERROR("fast_data (" TARGET_ADDR_FMT ") is within read area "
+				"(" TARGET_ADDR_FMT "-" TARGET_ADDR_FMT ").",
+				fast_data_area->address, address, address + count);
+		LOG_ERROR("Change work-area-phys or load_image address!");
+		return ERROR_FAIL;
+	}
+
+	/* mips32_pracc_fastdata_xfer requires uint32_t in host endianness, */
+	/* but byte array represents target endianness                      */
+	uint32_t *t = malloc(count * sizeof(uint32_t));
+	if (!t) {
+		LOG_ERROR("Out of memory");
+		return ERROR_FAIL;
+	}
+
+	retval = mips32_pracc_fastdata_xfer(ejtag_info, mips32->fast_data_area, write_t, address,
+			count, t);
+
+	target_buffer_set_u32_array(target, buffer, count, t);
+
+	free(t);
+
+	if (retval != ERROR_OK)
+		LOG_ERROR("Fastdata access Failed");
+
+	return retval;
+}
+
 static int mips_m4k_verify_pointer(struct command_invocation *cmd,
 		struct mips_m4k_common *mips_m4k)
 {
diff --git a/src/target/target.c b/src/target/target.c
index e795f784d..0ea808473 100644
--- a/src/target/target.c
+++ b/src/target/target.c
@@ -4592,57 +4592,36 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc,
 	return e;
 }
 
-static int target_jim_read_memory(Jim_Interp *interp, int argc,
-		Jim_Obj * const *argv)
+COMMAND_HANDLER(handle_target_read_memory)
 {
 	/*
-	 * argv[1] = memory address
-	 * argv[2] = desired element width in bits
-	 * argv[3] = number of elements to read
-	 * argv[4] = optional "phys"
+	 * CMD_ARGV[0] = memory address
+	 * CMD_ARGV[1] = desired element width in bits
+	 * CMD_ARGV[2] = number of elements to read
+	 * CMD_ARGV[3] = optional "phys"
 	 */
 
-	if (argc < 4 || argc > 5) {
-		Jim_WrongNumArgs(interp, 1, argv, "address width count ['phys']");
-		return JIM_ERR;
-	}
+	if (CMD_ARGC < 3 || CMD_ARGC > 4)
+		return ERROR_COMMAND_SYNTAX_ERROR;
 
 	/* Arg 1: Memory address. */
-	jim_wide wide_addr;
-	int e;
-	e = Jim_GetWide(interp, argv[1], &wide_addr);
-
-	if (e != JIM_OK)
-		return e;
-
-	target_addr_t addr = (target_addr_t)wide_addr;
+	target_addr_t addr;
+	COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], addr);
 
 	/* Arg 2: Bit width of one element. */
-	long l;
-	e = Jim_GetLong(interp, argv[2], &l);
-
-	if (e != JIM_OK)
-		return e;
-
-	const unsigned int width_bits = l;
+	unsigned int width_bits;
+	COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], width_bits);
 
 	/* Arg 3: Number of elements to read. */
-	e = Jim_GetLong(interp, argv[3], &l);
-
-	if (e != JIM_OK)
-		return e;
-
-	size_t count = l;
+	unsigned int count;
+	COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], count);
 
 	/* Arg 4: Optional 'phys'. */
 	bool is_phys = false;
-
-	if (argc > 4) {
-		const char *phys = Jim_GetString(argv[4], NULL);
-
-		if (strcmp(phys, "phys")) {
-			Jim_SetResultFormatted(interp, "invalid argument '%s', must be 'phys'", phys);
-			return JIM_ERR;
+	if (CMD_ARGC == 4) {
+		if (strcmp(CMD_ARGV[3], "phys")) {
+			command_print(CMD, "invalid argument '%s', must be 'phys'", CMD_ARGV[3]);
+			return ERROR_COMMAND_ARGUMENT_INVALID;
 		}
 
 		is_phys = true;
@@ -4655,37 +4634,33 @@ static int target_jim_read_memory(Jim_Interp *interp, int argc,
 	case 64:
 		break;
 	default:
-		Jim_SetResultString(interp, "invalid width, must be 8, 16, 32 or 64", -1);
-		return JIM_ERR;
+		command_print(CMD, "invalid width, must be 8, 16, 32 or 64");
+		return ERROR_COMMAND_ARGUMENT_INVALID;
 	}
 
 	const unsigned int width = width_bits / 8;
 
 	if ((addr + (count * width)) < addr) {
-		Jim_SetResultString(interp, "read_memory: addr + count wraps to zero", -1);
-		return JIM_ERR;
+		command_print(CMD, "read_memory: addr + count wraps to zero");
+		return ERROR_COMMAND_ARGUMENT_INVALID;
 	}
 
 	if (count > 65536) {
-		Jim_SetResultString(interp, "read_memory: too large read request, exeeds 64K elements", -1);
-		return JIM_ERR;
+		command_print(CMD, "read_memory: too large read request, exceeds 64K elements");
+		return ERROR_COMMAND_ARGUMENT_INVALID;
 	}
 
-	struct command_context *cmd_ctx = current_command_context(interp);
-	assert(cmd_ctx != NULL);
-	struct target *target = get_current_target(cmd_ctx);
+	struct target *target = get_current_target(CMD_CTX);
 
 	const size_t buffersize = 4096;
 	uint8_t *buffer = malloc(buffersize);
 
 	if (!buffer) {
 		LOG_ERROR("Failed to allocate memory");
-		return JIM_ERR;
+		return ERROR_FAIL;
 	}
 
-	Jim_Obj *result_list = Jim_NewListObj(interp, NULL, 0);
-	Jim_IncrRefCount(result_list);
-
+	char *separator = "";
 	while (count > 0) {
 		const unsigned int max_chunk_len = buffersize / width;
 		const size_t chunk_len = MIN(count, max_chunk_len);
@@ -4698,11 +4673,15 @@ static int target_jim_read_memory(Jim_Interp *interp, int argc,
 			retval = target_read_memory(target, addr, width, chunk_len, buffer);
 
 		if (retval != ERROR_OK) {
-			LOG_ERROR("read_memory: read at " TARGET_ADDR_FMT " with width=%u and count=%zu failed",
+			LOG_DEBUG("read_memory: read at " TARGET_ADDR_FMT " with width=%u and count=%zu failed",
 				addr, width_bits, chunk_len);
-			Jim_SetResultString(interp, "read_memory: failed to read memory", -1);
-			e = JIM_ERR;
-			break;
+			/*
+			 * FIXME: we append the errmsg to the list of value already read.
+			 * Add a way to flush and replace old output, but LOG_DEBUG() it
+			 */
+			command_print(CMD, "read_memory: failed to read memory");
+			free(buffer);
+			return retval;
 		}
 
 		for (size_t i = 0; i < chunk_len ; i++) {
@@ -4723,11 +4702,8 @@ static int target_jim_read_memory(Jim_Interp *interp, int argc,
 				break;
 			}
 
-			char value_buf[19];
-			snprintf(value_buf, sizeof(value_buf), "0x%" PRIx64, v);
-
-			Jim_ListAppendElement(interp, result_list,
-				Jim_NewStringObj(interp, value_buf, -1));
+			command_print_sameline(CMD, "%s0x%" PRIx64, separator, v);
+			separator = " ";
 		}
 
 		count -= chunk_len;
@@ -4736,15 +4712,7 @@ static int target_jim_read_memory(Jim_Interp *interp, int argc,
 
 	free(buffer);
 
-	if (e != JIM_OK) {
-		Jim_DecrRefCount(interp, result_list);
-		return e;
-	}
-
-	Jim_SetResult(interp, result_list);
-	Jim_DecrRefCount(interp, result_list);
-
-	return JIM_OK;
+	return ERROR_OK;
 }
 
 static int get_u64_array_element(Jim_Interp *interp, const char *varname, size_t idx, uint64_t *val)
@@ -5748,40 +5716,38 @@ static int jim_target_examine(Jim_Interp *interp, int argc, Jim_Obj *const *argv
 	return JIM_OK;
 }
 
-static int jim_target_was_examined(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+COMMAND_HANDLER(handle_target_was_examined)
 {
-	struct command_context *cmd_ctx = current_command_context(interp);
-	assert(cmd_ctx);
-	struct target *target = get_current_target(cmd_ctx);
+	if (CMD_ARGC != 0)
+		return ERROR_COMMAND_SYNTAX_ERROR;
 
-	Jim_SetResultBool(interp, target_was_examined(target));
-	return JIM_OK;
+	struct target *target = get_current_target(CMD_CTX);
+
+	command_print(CMD, "%d", target_was_examined(target) ? 1 : 0);
+
+	return ERROR_OK;
 }
 
-static int jim_target_examine_deferred(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+COMMAND_HANDLER(handle_target_examine_deferred)
 {
-	struct command_context *cmd_ctx = current_command_context(interp);
-	assert(cmd_ctx);
-	struct target *target = get_current_target(cmd_ctx);
+	if (CMD_ARGC != 0)
+		return ERROR_COMMAND_SYNTAX_ERROR;
 
-	Jim_SetResultBool(interp, target->defer_examine);
-	return JIM_OK;
+	struct target *target = get_current_target(CMD_CTX);
+
+	command_print(CMD, "%d", target->defer_examine ? 1 : 0);
+
+	return ERROR_OK;
 }
 
-static int jim_target_halt_gdb(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+COMMAND_HANDLER(handle_target_halt_gdb)
 {
-	if (argc != 1) {
-		Jim_WrongNumArgs(interp, 1, argv, "[no parameters]");
-		return JIM_ERR;
-	}
-	struct command_context *cmd_ctx = current_command_context(interp);
-	assert(cmd_ctx);
-	struct target *target = get_current_target(cmd_ctx);
+	if (CMD_ARGC != 0)
+		return ERROR_COMMAND_SYNTAX_ERROR;
 
-	if (target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT) != ERROR_OK)
-		return JIM_ERR;
+	struct target *target = get_current_target(CMD_CTX);
 
-	return JIM_OK;
+	return target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT);
 }
 
 static int jim_target_poll(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
@@ -5936,18 +5902,19 @@ COMMAND_HANDLER(handle_target_event_list)
 	command_print(CMD, "***END***");
 	return ERROR_OK;
 }
-static int jim_target_current_state(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+
+COMMAND_HANDLER(handle_target_current_state)
 {
-	if (argc != 1) {
-		Jim_WrongNumArgs(interp, 1, argv, "[no parameters]");
-		return JIM_ERR;
-	}
-	struct command_context *cmd_ctx = current_command_context(interp);
-	assert(cmd_ctx);
-	struct target *target = get_current_target(cmd_ctx);
-	Jim_SetResultString(interp, target_state_name(target), -1);
-	return JIM_OK;
+	if (CMD_ARGC != 0)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
+	struct target *target = get_current_target(CMD_CTX);
+
+	command_print(CMD, "%s", target_state_name(target));
+
+	return ERROR_OK;
 }
+
 static int jim_target_invoke_event(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
 	struct jim_getopt_info goi;
@@ -6074,7 +6041,7 @@ static const struct command_registration target_instance_command_handlers[] = {
 	{
 		.name = "read_memory",
 		.mode = COMMAND_EXEC,
-		.jim_handler = target_jim_read_memory,
+		.handler = handle_target_read_memory,
 		.help = "Read Tcl list of 8/16/32/64 bit numbers from target memory",
 		.usage = "address width count ['phys']",
 	},
@@ -6095,8 +6062,9 @@ static const struct command_registration target_instance_command_handlers[] = {
 	{
 		.name = "curstate",
 		.mode = COMMAND_EXEC,
-		.jim_handler = jim_target_current_state,
+		.handler = handle_target_current_state,
 		.help = "displays the current state of this target",
+		.usage = "",
 	},
 	{
 		.name = "arp_examine",
@@ -6108,20 +6076,23 @@ static const struct command_registration target_instance_command_handlers[] = {
 	{
 		.name = "was_examined",
 		.mode = COMMAND_EXEC,
-		.jim_handler = jim_target_was_examined,
+		.handler = handle_target_was_examined,
 		.help = "used internally for reset processing",
+		.usage = "",
 	},
 	{
 		.name = "examine_deferred",
 		.mode = COMMAND_EXEC,
-		.jim_handler = jim_target_examine_deferred,
+		.handler = handle_target_examine_deferred,
 		.help = "used internally for reset processing",
+		.usage = "",
 	},
 	{
 		.name = "arp_halt_gdb",
 		.mode = COMMAND_EXEC,
-		.jim_handler = jim_target_halt_gdb,
+		.handler = handle_target_halt_gdb,
 		.help = "used internally for reset processing to halt GDB",
+		.usage = "",
 	},
 	{
 		.name = "arp_poll",
@@ -6396,56 +6367,47 @@ static int target_create(struct jim_getopt_info *goi)
 	return JIM_OK;
 }
 
-static int jim_target_current(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+COMMAND_HANDLER(handle_target_current)
 {
-	if (argc != 1) {
-		Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
-		return JIM_ERR;
-	}
-	struct command_context *cmd_ctx = current_command_context(interp);
-	assert(cmd_ctx);
+	if (CMD_ARGC != 0)
+		return ERROR_COMMAND_SYNTAX_ERROR;
 
-	struct target *target = get_current_target_or_null(cmd_ctx);
+	struct target *target = get_current_target_or_null(CMD_CTX);
 	if (target)
-		Jim_SetResultString(interp, target_name(target), -1);
-	return JIM_OK;
+		command_print(CMD, "%s", target_name(target));
+
+	return ERROR_OK;
 }
 
-static int jim_target_types(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+COMMAND_HANDLER(handle_target_types)
 {
-	if (argc != 1) {
-		Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
-		return JIM_ERR;
-	}
-	Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
-	for (unsigned x = 0; target_types[x]; x++) {
-		Jim_ListAppendElement(interp, Jim_GetResult(interp),
-			Jim_NewStringObj(interp, target_types[x]->name, -1));
-	}
-	return JIM_OK;
+	if (CMD_ARGC != 0)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
+	for (unsigned int x = 0; target_types[x]; x++)
+		command_print(CMD, "%s", target_types[x]->name);
+
+	return ERROR_OK;
 }
 
-static int jim_target_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+COMMAND_HANDLER(handle_target_names)
 {
-	if (argc != 1) {
-		Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
-		return JIM_ERR;
-	}
-	Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
+	if (CMD_ARGC != 0)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
 	struct target *target = all_targets;
 	while (target) {
-		Jim_ListAppendElement(interp, Jim_GetResult(interp),
-			Jim_NewStringObj(interp, target_name(target), -1));
+		command_print(CMD, "%s", target_name(target));
 		target = target->next;
 	}
-	return JIM_OK;
+
+	return ERROR_OK;
 }
 
 static struct target_list *
 __attribute__((warn_unused_result))
-create_target_list_node(Jim_Obj *const name) {
-	int len;
-	const char *targetname = Jim_GetString(name, &len);
+create_target_list_node(const char *targetname)
+{
 	struct target *target = get_target(targetname);
 	LOG_DEBUG("%s ", targetname);
 	if (!target)
@@ -6461,7 +6423,8 @@ create_target_list_node(Jim_Obj *const name) {
 	return new;
 }
 
-static int get_target_with_common_rtos_type(struct list_head *lh, struct target **result)
+static int get_target_with_common_rtos_type(struct command_invocation *cmd,
+	struct list_head *lh, struct target **result)
 {
 	struct target *target = NULL;
 	struct target_list *curr;
@@ -6469,39 +6432,39 @@ static int get_target_with_common_rtos_type(struct list_head *lh, struct target
 		struct rtos *curr_rtos = curr->target->rtos;
 		if (curr_rtos) {
 			if (target && target->rtos && target->rtos->type != curr_rtos->type) {
-				LOG_ERROR("Different rtos types in members of one smp target!");
-				return JIM_ERR;
+				command_print(cmd, "Different rtos types in members of one smp target!");
+				return ERROR_FAIL;
 			}
 			target = curr->target;
 		}
 	}
 	*result = target;
-	return JIM_OK;
+	return ERROR_OK;
 }
 
-static int jim_target_smp(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+COMMAND_HANDLER(handle_target_smp)
 {
 	static int smp_group = 1;
 
-	if (argc == 1) {
+	if (CMD_ARGC == 0) {
 		LOG_DEBUG("Empty SMP target");
-		return JIM_OK;
+		return ERROR_OK;
 	}
-	LOG_DEBUG("%d", argc);
-	/* argv[1] = target to associate in smp
-	 * argv[2] = target to associate in smp
-	 * argv[3] ...
+	LOG_DEBUG("%d", CMD_ARGC);
+	/* CMD_ARGC[0] = target to associate in smp
+	 * CMD_ARGC[1] = target to associate in smp
+	 * CMD_ARGC[2] ...
 	 */
 
 	struct list_head *lh = malloc(sizeof(*lh));
 	if (!lh) {
 		LOG_ERROR("Out of memory");
-		return JIM_ERR;
+		return ERROR_FAIL;
 	}
 	INIT_LIST_HEAD(lh);
 
-	for (int i = 1; i < argc; i++) {
-		struct target_list *new = create_target_list_node(argv[i]);
+	for (unsigned int i = 0; i < CMD_ARGC; i++) {
+		struct target_list *new = create_target_list_node(CMD_ARGV[i]);
 		if (new)
 			list_add_tail(&new->lh, lh);
 	}
@@ -6515,14 +6478,13 @@ static int jim_target_smp(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 	smp_group++;
 
 	struct target *rtos_target;
-	int retval = get_target_with_common_rtos_type(lh, &rtos_target);
-	if (retval == JIM_OK && rtos_target)
+	int retval = get_target_with_common_rtos_type(CMD, lh, &rtos_target);
+	if (retval == ERROR_OK && rtos_target)
 		retval = rtos_smp_init(rtos_target);
 
 	return retval;
 }
 
-
 static int jim_target_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
 	struct jim_getopt_info goi;
@@ -6553,26 +6515,29 @@ static const struct command_registration target_subcommand_handlers[] = {
 	{
 		.name = "current",
 		.mode = COMMAND_ANY,
-		.jim_handler = jim_target_current,
+		.handler = handle_target_current,
 		.help = "Returns the currently selected target",
+		.usage = "",
 	},
 	{
 		.name = "types",
 		.mode = COMMAND_ANY,
-		.jim_handler = jim_target_types,
+		.handler = handle_target_types,
 		.help = "Returns the available target types as "
 				"a list of strings",
+		.usage = "",
 	},
 	{
 		.name = "names",
 		.mode = COMMAND_ANY,
-		.jim_handler = jim_target_names,
+		.handler = handle_target_names,
 		.help = "Returns the names of all targets as a list of strings",
+		.usage = "",
 	},
 	{
 		.name = "smp",
 		.mode = COMMAND_ANY,
-		.jim_handler = jim_target_smp,
+		.handler = handle_target_smp,
 		.usage = "targetname1 targetname2 ...",
 		.help = "gather several target in a smp list"
 	},
@@ -7205,7 +7170,7 @@ static const struct command_registration target_exec_command_handlers[] = {
 	{
 		.name = "read_memory",
 		.mode = COMMAND_EXEC,
-		.jim_handler = target_jim_read_memory,
+		.handler = handle_target_read_memory,
 		.help = "Read Tcl list of 8/16/32/64 bit numbers from target memory",
 		.usage = "address width count ['phys']",
 	},
diff --git a/src/transport/transport.c b/src/transport/transport.c
index c05db3f00..81d3d583b 100644
--- a/src/transport/transport.c
+++ b/src/transport/transport.c
@@ -252,64 +252,62 @@ COMMAND_HANDLER(handle_transport_list)
  * set supported by the debug adapter being used.  Return value
  * is scriptable (allowing "if swd then..." etc).
  */
-static int jim_transport_select(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+COMMAND_HANDLER(handle_transport_select)
 {
-	int res;
-	switch (argc) {
-		case 1:	/* autoselect if necessary, then return/display current config */
-			if (!session) {
-				if (!allowed_transports) {
-					LOG_ERROR("Debug adapter does not support any transports? Check config file order.");
-					return JIM_ERR;
-				}
-				LOG_INFO("auto-selecting first available session transport \"%s\". "
-					 "To override use 'transport select <transport>'.", allowed_transports[0]);
-				res = transport_select(global_cmd_ctx, allowed_transports[0]);
-				if (res != JIM_OK)
-					return res;
-			}
-			Jim_SetResultString(interp, session->name, -1);
-			return JIM_OK;
-		case 2:	/* assign */
-			if (session) {
-				if (!strcmp(session->name, argv[1]->bytes)) {
-					LOG_WARNING("Transport \"%s\" was already selected", session->name);
-					Jim_SetResultString(interp, session->name, -1);
-					return JIM_OK;
-				} else {
-					LOG_ERROR("Can't change session's transport after the initial selection was made");
-					return JIM_ERR;
-				}
-			}
+	if (CMD_ARGC > 1)
+		return ERROR_COMMAND_SYNTAX_ERROR;
 
-			/* Is this transport supported by our debug adapter?
-			 * Example, "JTAG-only" means SWD is not supported.
-			 *
-			 * NOTE:  requires adapter to have been set up, with
-			 * transports declared via C.
-			 */
+	if (CMD_ARGC == 0) {
+		/* autoselect if necessary, then return/display current config */
+		if (!session) {
 			if (!allowed_transports) {
-				LOG_ERROR("Debug adapter doesn't support any transports?");
-				return JIM_ERR;
+				command_print(CMD, "Debug adapter does not support any transports? Check config file order.");
+				return ERROR_FAIL;
 			}
-
-			for (unsigned i = 0; allowed_transports[i]; i++) {
-
-				if (strcmp(allowed_transports[i], argv[1]->bytes) == 0) {
-					if (transport_select(global_cmd_ctx, argv[1]->bytes) == ERROR_OK) {
-						Jim_SetResultString(interp, session->name, -1);
-						return JIM_OK;
-					}
-					return JIM_ERR;
-				}
-			}
-
-			LOG_ERROR("Debug adapter doesn't support '%s' transport", argv[1]->bytes);
-			return JIM_ERR;
-		default:
-			Jim_WrongNumArgs(interp, 1, argv, "[too many parameters]");
-			return JIM_ERR;
+			LOG_INFO("auto-selecting first available session transport \"%s\". "
+				"To override use 'transport select <transport>'.", allowed_transports[0]);
+			int retval = transport_select(CMD_CTX, allowed_transports[0]);
+			if (retval != ERROR_OK)
+				return retval;
+		}
+		command_print(CMD, "%s", session->name);
+		return ERROR_OK;
 	}
+
+	/* assign transport */
+	if (session) {
+		if (!strcmp(session->name, CMD_ARGV[0])) {
+			LOG_WARNING("Transport \"%s\" was already selected", session->name);
+			command_print(CMD, "%s", session->name);
+			return ERROR_OK;
+		}
+		command_print(CMD, "Can't change session's transport after the initial selection was made");
+		return ERROR_FAIL;
+	}
+
+	/* Is this transport supported by our debug adapter?
+	 * Example, "JTAG-only" means SWD is not supported.
+	 *
+	 * NOTE:  requires adapter to have been set up, with
+	 * transports declared via C.
+	 */
+	if (!allowed_transports) {
+		command_print(CMD, "Debug adapter doesn't support any transports?");
+		return ERROR_FAIL;
+	}
+
+	for (unsigned int i = 0; allowed_transports[i]; i++) {
+		if (!strcmp(allowed_transports[i], CMD_ARGV[0])) {
+			int retval = transport_select(CMD_CTX, CMD_ARGV[0]);
+			if (retval != ERROR_OK)
+				return retval;
+			command_print(CMD, "%s", session->name);
+			return ERROR_OK;
+		}
+	}
+
+	command_print(CMD, "Debug adapter doesn't support '%s' transport", CMD_ARGV[0]);
+	return ERROR_FAIL;
 }
 
 static const struct command_registration transport_commands[] = {
@@ -333,7 +331,7 @@ static const struct command_registration transport_commands[] = {
 	},
 	{
 		.name = "select",
-		.jim_handler = jim_transport_select,
+		.handler = handle_transport_select,
 		.mode = COMMAND_ANY,
 		.help = "Select this session's transport",
 		.usage = "[transport_name]",
diff --git a/tcl/board/calao-usb-a9260.cfg b/tcl/board/calao-usb-a9260.cfg
new file mode 100644
index 000000000..52fede0fa
--- /dev/null
+++ b/tcl/board/calao-usb-a9260.cfg
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# CALAO Systems USB-A9260 (C01 and C02)
+
+adapter driver ftdi
+ftdi device_desc "USB-A9260"
+ftdi vid_pid 0x0403 0x6001 0x0403 0x6010
+ftdi layout_init 0x0c08 0x0f1b
+ftdi layout_signal nTRST -data 0x0100 -noe 0x0400
+ftdi layout_signal nSRST -data 0x0200 -noe 0x0800
+
+transport select jtag
+
+source [find target/at91sam9260.cfg]
diff --git a/tcl/board/calao-usb-a9g20-c01.cfg b/tcl/board/calao-usb-a9g20-c01.cfg
new file mode 100644
index 000000000..6c4bd40fe
--- /dev/null
+++ b/tcl/board/calao-usb-a9g20-c01.cfg
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# CALAO Systems USB-A9G20-C01
+
+adapter driver ftdi
+ftdi device_desc "USB-A9G20"
+ftdi vid_pid 0x0403 0x6010
+ftdi layout_init 0x0c08 0x0f1b
+ftdi layout_signal nTRST -data 0x0100 -noe 0x0400
+ftdi layout_signal nSRST -data 0x0200 -noe 0x0800
+
+transport select jtag
+
+source [find target/at91sam9g20.cfg]
diff --git a/tcl/cpld/xilinx-xc7.cfg b/tcl/cpld/xilinx-xc7.cfg
index 22e0aea7f..91a07f9eb 100644
--- a/tcl/cpld/xilinx-xc7.cfg
+++ b/tcl/cpld/xilinx-xc7.cfg
@@ -33,19 +33,21 @@ jtag newtap $_CHIPNAME tap -irlen 6 -ignore-version \
 	-expected-id 0x03752093 \
 	-expected-id 0x03751093 \
 	-expected-id 0x03671093 \
-	-expected-id 0x036B3093 \
-	-expected-id 0x036B7093 \
-	-expected-id 0x036BB093 \
-	-expected-id 0x036BF093 \
 	-expected-id 0x03667093 \
 	-expected-id 0x03682093 \
 	-expected-id 0x03687093 \
 	-expected-id 0x03692093 \
 	-expected-id 0x03691093 \
-	-expected-id 0x03696093 \
-	-expected-id 0x036D5093 \
-	-expected-id 0x036D9093 \
-	-expected-id 0x036DB093
+	-expected-id 0x03696093
+
+#jtag newtap $_CHIPNAME tap -irlen 24 -ignore-version \
+#	-expected-id 0x036B3093 -expected-id 0x036B7093 \
+#	-expected-id 0x036BB093 -expected-id 0x036BF093 \
+#	-expected-id 0x036D5093
+
+#jtag newtap $_CHIPNAME tap -irlen 22 -ignore-version -expected-id 0x036D9093
+
+#jtag newtap $_CHIPNAME tap -irlen 38 -ignore-version -expected-id 0x036DB093
 
 pld device virtex2 $_CHIPNAME.tap 1
 
diff --git a/tcl/interface/calao-usb-a9260.cfg b/tcl/interface/calao-usb-a9260.cfg
deleted file mode 100644
index ff652ef8f..000000000
--- a/tcl/interface/calao-usb-a9260.cfg
+++ /dev/null
@@ -1,12 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-or-later
-
-#
-# CALAO Systems USB-A9260 common -C01 -C02 setup
-#
-# http://www.calao-systems.com/
-#
-# See calao-usb-a9260-c01.cfg and calao-usb-a9260-c02.cfg.
-#
-
-adapter srst delay 200
-jtag_ntrst_delay 200
diff --git a/tcl/interface/ftdi/calao-usb-a9260-c01.cfg b/tcl/interface/ftdi/calao-usb-a9260-c01.cfg
deleted file mode 100644
index c84e77874..000000000
--- a/tcl/interface/ftdi/calao-usb-a9260-c01.cfg
+++ /dev/null
@@ -1,24 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-or-later
-
-#
-# CALAO Systems USB-A9260-C01
-#
-# http://www.calao-systems.com/
-#
-
-echo "WARNING!"
-echo "This file was not tested with real interface, but is assumed to work as this"
-echo "interface uses the same layout as configs that were verified. Please report your"
-echo "experience with this file to openocd-devel mailing list, so it could be marked"
-echo "as working or fixed."
-
-adapter driver ftdi
-ftdi device_desc "USB-A9260"
-ftdi vid_pid 0x0403 0x6010
-
-ftdi layout_init 0x0c08 0x0f1b
-ftdi layout_signal nTRST -data 0x0100 -noe 0x0400
-ftdi layout_signal nSRST -data 0x0200 -noe 0x0800
-
-script interface/calao-usb-a9260.cfg
-script target/at91sam9260minimal.cfg
diff --git a/tcl/interface/ftdi/calao-usb-a9260-c02.cfg b/tcl/interface/ftdi/calao-usb-a9260-c02.cfg
deleted file mode 100644
index 9d79b2600..000000000
--- a/tcl/interface/ftdi/calao-usb-a9260-c02.cfg
+++ /dev/null
@@ -1,24 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-or-later
-
-#
-# CALAO Systems USB-A9260-C02
-#
-# http://www.calao-systems.com/
-#
-
-echo "WARNING!"
-echo "This file was not tested with real interface, but is assumed to work as this"
-echo "interface uses the same layout as configs that were verified. Please report your"
-echo "experience with this file to openocd-devel mailing list, so it could be marked"
-echo "as working or fixed."
-
-adapter driver ftdi
-ftdi device_desc "USB-A9260"
-ftdi vid_pid 0x0403 0x6001
-
-ftdi layout_init 0x0c08 0x0f1b
-ftdi layout_signal nTRST -data 0x0100 -noe 0x0400
-ftdi layout_signal nSRST -data 0x0200 -noe 0x0800
-
-script interface/calao-usb-a9260.cfg
-script target/at91sam9260minimal.cfg
diff --git a/tcl/target/zynq_7000.cfg b/tcl/target/zynq_7000.cfg
index 0272587c1..a6f899541 100644
--- a/tcl/target/zynq_7000.cfg
+++ b/tcl/target/zynq_7000.cfg
@@ -1,18 +1,34 @@
 # SPDX-License-Identifier: GPL-2.0-or-later
 
-#
 # Xilinx Zynq-7000 All Programmable SoC
 #
 # http://www.xilinx.com/products/silicon-devices/soc/zynq-7000/index.htm
+# https://www.xilinx.com/member/forms/download/sim-model-eval-license-xef.html?filename=bsdl_zynq_2.zip
 #
+# 0x03736093  XQ7Z100 XC7Z100I XC7Z100
+# 0x03731093  XQ7Z045 XC7Z045I XC7Z045
+# 0x0372c093  XQ7Z030 XC7Z030I XC7Z030 XA7Z030
+# 0x03727093  XQ7Z020 XC7Z020I XC7Z020 XA7Z020
+# 0x03732093  XC7Z035I XC7Z035
+# 0x0373b093  XC7Z015I XC7Z015
+# 0x03728093  XC7Z014S
+# 0x0373c093  XC7Z012S
+# 0x03722093  XC7Z010I XC7Z010 XA7Z010
+# 0x03723093  XC7Z007S
 
 set _CHIPNAME zynq
 set _TARGETNAME $_CHIPNAME.cpu
 
-jtag newtap zynq_pl bs -irlen 6 -ircapture 0x1 -irmask 0x03 \
-    -expected-id 0x23727093 \
-    -expected-id 0x13722093 \
+jtag newtap zynq_pl bs -irlen 6 -ignore-version -ircapture 0x1 -irmask 0x03 \
+    -expected-id 0x03723093 \
+    -expected-id 0x03722093 \
+    -expected-id 0x0373c093 \
+    -expected-id 0x03728093 \
+    -expected-id 0x0373B093 \
+    -expected-id 0x03732093 \
     -expected-id 0x03727093 \
+    -expected-id 0x0372C093 \
+    -expected-id 0x03731093 \
     -expected-id 0x03736093
 
 jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id 0x4ba00477