initial "transport" framework

This adds the guts of a transport framework with initialization,
which should work with current JTAG-only configurations (tested
with FT2232).

Each debug adapter can declare the transports it supports, and
exactly one transport is initialized.  (with its commands) in
any given OpenOCD session.

  * Define a new "struct transport with init hooks and a few
 "transport"  subcommands to support it:

     "list" ... list the transports configured (just "jtag" for now)
     "select" ... makes the debug session use that transport
     "init" ... initializes the selected transport (internal)

  * "interface_transports" ... declares transports the current interface
    can support.  (Some will do this from C code instead, when there are
    no hardware versioning (or other) issues to prevent it.

Plus some FT2232 tweaks, including a few to streamline upcoming
support for an SWD transport (initially for Luminary adapters).

Eventually src/jtag should probably become src/transport, moving
jtag-specific stuff  to transport/jtag.

Signed-off-by: David Brownell <db@helium.(none)>
This commit is contained in:
David Brownell 2010-07-02 16:45:28 -04:00 committed by David Brownell
parent deb176d335
commit 93f2afa45f
10 changed files with 632 additions and 29 deletions

3
NEWS
View File

@ -17,6 +17,9 @@ JTAG Layer:
Boundary Scan:
Transport framework core ... supporting future work for SWD, SPI, and other
non-JTAG ways to debug targets or program flash.
Target Layer:
ARM:
- basic semihosting support (ARMv7M).

View File

@ -2096,6 +2096,14 @@ target.
List the debug adapter drivers that have been built into
the running copy of OpenOCD.
@end deffn
@deffn Command {interface transports} transport_name+
Specifies the transports supported by this debug adapter.
The adapter driver builds-in similar knowledge; use this only
when external configuration (such as jumpering) changes what
the hardware can support.
@end deffn
@deffn Command {adapter_name}
Returns the name of the debug adapter driver being used.
@ -2428,8 +2436,42 @@ Turn power switch to target on/off.
No arguments: print status.
@end deffn
@section Transport Configuration
As noted earlier, depending on the version of OpenOCD you use,
and the debug adapter you are using,
several transports may be available to
communicate with debug targets (or perhaps to program flash memory).
@deffn Command {transport list}
displays the names of the transports supported by this
version of OpenOCD.
@end deffn
@deffn Command {transport select} transport_name
Select which of the supported transports to use in this OpenOCD session.
The transport must be supported by the debug adapter hardware and by the
version of OPenOCD you are using (including the adapter's driver).
No arguments: print selected transport..
@end deffn
@subsection JTAG Transport
JTAG is the original transport supported by OpenOCD, and most
of the OpenOCD commands support it.
JTAG transports expose a chain of one or more Test Access Points (TAPs),
each of which must be explicitly declared.
JTAG supports both debugging and boundary scan testing.
Flash programming support is built on top of debug support.
@subsection SWD ransport
SWD (Serial Wire Debug) is an ARM-specific transport which exposes one
Debug Access Point (DAP, which must be explicitly declared.
(SWD uses fewer signal wires than JTAG.)
SWD is debug-oriented, and does not support boundary scan testing.
Flash programming support is built on top of debug support.
(Some processors support both JTAG and SWD.)
@subsection SPI ransport
The Serial Peripheral Interface (SPI) is a general purpose transport
which uses four wire signaling. Some processors use it as part of a
solution for flash programming.
@anchor{JTAG Speed}
@section JTAG Speed
JTAG clock setup is part of system setup.

View File

@ -58,6 +58,7 @@ libjtag_la_SOURCES = \
interface.c \
interfaces.c \
tcl.c \
transport.c \
$(DRIVERFILES)
noinst_HEADERS = \
@ -67,6 +68,7 @@ noinst_HEADERS = \
interfaces.h \
minidriver.h \
jtag.h \
transport.h \
minidriver/minidriver_imp.h \
minidummy/jtag_minidriver.h

View File

@ -35,6 +35,7 @@
#include "minidriver.h"
#include "interface.h"
#include "interfaces.h"
#include "transport.h"
#ifdef HAVE_STRINGS_H
#include <strings.h>
@ -92,6 +93,25 @@ static int default_srst_asserted(int *srst_asserted)
return ERROR_OK;
}
COMMAND_HANDLER(interface_transport_command)
{
char **transports;
int retval;
retval = CALL_COMMAND_HANDLER(transport_list_parse, &transports);
if (retval != ERROR_OK) {
return retval;
retval = allow_transports(CMD_CTX, (const char **)transports);
if (retval != ERROR_OK) {
for (unsigned i = 0; transports[i]; i++)
free(transports[i]);
free(transports);
}
}
return retval;
}
COMMAND_HANDLER(handle_interface_list_command)
{
if (strcmp(CMD_NAME, "interface_list") == 0 && CMD_ARGC > 0)
@ -451,6 +471,13 @@ static const struct command_registration interface_command_handlers[] = {
.help = "Select a debug adapter interface (driver)",
.usage = "driver_name",
},
{
.name = "interface_transports",
.handler = interface_transport_command,
.mode = COMMAND_CONFIG,
.help = "Declare transports the interface supports.",
.usage = "transport ... ",
},
{
.name = "interface_list",
.handler = handle_interface_list_command,

View File

@ -33,11 +33,15 @@
#include "jtag.h"
#include "interface.h"
#include "transport.h"
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
/* SVF and XSVF are higher level JTAG command sets (for boundary scan) */
#include "svf/svf.h"
#include "xsvf/xsvf.h"
/// The number of JTAG queue flushes (for profiling and debugging purposes).
static int jtag_flush_queue_count;
@ -1348,6 +1352,21 @@ int adapter_init(struct command_context *cmd_ctx)
return ERROR_JTAG_INIT_FAILED;
}
/* LEGACY SUPPORT ... adapter drivers must declare what
* transports they allow. Until they all do so, assume
* the legacy drivers are JTAG-only
*/
if (!transports_are_declared()) {
static const char *jtag_only[] = { "jtag", NULL, };
LOG_ERROR("Adapter driver '%s' did not declare "
"which transports it allows; assuming"
"JTAG-only", jtag->name);
int retval = allow_transports(cmd_ctx, jtag_only);
if (retval != ERROR_OK)
return retval;
}
int requested_khz = jtag_get_speed_khz();
int actual_khz = requested_khz;
int retval = jtag_get_speed_readable(&actual_khz);
@ -1706,3 +1725,45 @@ unsigned jtag_get_ntrst_assert_width(void)
{
return jtag_ntrst_assert_width;
}
static int jtag_select(struct command_context *ctx)
{
int retval;
/* NOTE: interface init must already have been done.
* That works with only C code ... no Tcl glue required.
*/
retval = jtag_register_commands(ctx);
if (retval != ERROR_OK)
return retval;
retval = svf_register_commands(ctx);
if (retval != ERROR_OK)
return retval;
return xsvf_register_commands(ctx);
}
static struct transport jtag_transport = {
.name = "jtag",
.select = jtag_select,
.init = jtag_init,
};
static void jtag_constructor(void) __attribute__((constructor));
static void jtag_constructor(void)
{
transport_register(&jtag_transport);
}
/** Returns true if the current debug session
* is using JTAG as its transport.
*/
bool transport_is_jtag(void)
{
return get_current_transport() == &jtag_transport;
}

View File

@ -81,6 +81,7 @@
/* project specific includes */
#include <jtag/interface.h>
#include <jtag/transport.h>
#include <helper/time_support.h>
#if IS_CYGWIN == 1
@ -167,6 +168,7 @@ struct ft2232_layout {
void (*reset)(int trst, int srst);
void (*blink)(void);
int channel;
const char **transports;
};
/* init procedures for supported layouts */
@ -210,6 +212,13 @@ static void turtle_jtag_blink(void);
static void signalyzer_h_blink(void);
static void ktlink_blink(void);
/* common transport support options */
static const char *jtag_only[] = { "jtag", NULL };
//static const char *jtag_and_swd[] = { "jtag", "swd", NULL };
#define jtag_and_swd NULL
static const struct ft2232_layout ft2232_layouts[] =
{
{ .name = "usbjtag",
@ -235,10 +244,12 @@ static const struct ft2232_layout ft2232_layouts[] =
{ .name = "evb_lm3s811",
.init = lm3s811_jtag_init,
.reset = ftx23_reset,
.transports = jtag_and_swd,
},
{ .name = "luminary_icdi",
.init = icdi_jtag_init,
.reset = ftx23_reset,
.transports = jtag_and_swd,
},
{ .name = "olimex-jtag",
.init = olimex_jtag_init,
@ -2393,7 +2404,7 @@ static int ft2232_init(void)
/** Updates defaults for DBUS signals: the four JTAG signals
* (TCK, TDI, TDO, TMS) and * the four GPIOL signals.
*/
static inline void ftx232_init_head(void)
static inline void ftx232_dbus_init(void)
{
low_output = 0x08;
low_direction = 0x0b;
@ -2403,7 +2414,7 @@ static inline void ftx232_init_head(void)
* the four GPIOL signals. Initialization covers value and direction,
* as customized for each layout.
*/
static int ftx232_init_tail(void)
static int ftx232_dbus_write(void)
{
uint8_t buf[3];
uint32_t bytes_written;
@ -2452,19 +2463,19 @@ static int usbjtag_init(void)
* NOTE: This is now _specific_ to the "usbjtag" layout.
* Don't try cram any more layouts into this.
*/
ftx232_init_head();
ftx232_dbus_init();
nTRST = 0x10;
nTRSTnOE = 0x10;
nSRST = 0x40;
nSRSTnOE = 0x40;
return ftx232_init_tail();
return ftx232_dbus_write();
}
static int lm3s811_jtag_init(void)
{
ftx232_init_head();
ftx232_dbus_init();
/* There are multiple revisions of LM3S811 eval boards:
* - Rev B (and older?) boards have no SWO trace support.
@ -2478,12 +2489,12 @@ static int lm3s811_jtag_init(void)
low_output = 0x88;
low_direction = 0x8b;
return ftx232_init_tail();
return ftx232_dbus_write();
}
static int icdi_jtag_init(void)
{
ftx232_init_head();
ftx232_dbus_init();
/* Most Luminary eval boards support SWO trace output,
* and should use this "luminary_icdi" layout.
@ -2495,18 +2506,18 @@ static int icdi_jtag_init(void)
low_output = 0x88;
low_direction = 0xcb;
return ftx232_init_tail();
return ftx232_dbus_write();
}
static int signalyzer_init(void)
{
ftx232_init_head();
ftx232_dbus_init();
nTRST = 0x10;
nTRSTnOE = 0x10;
nSRST = 0x20;
nSRSTnOE = 0x20;
return ftx232_init_tail();
return ftx232_dbus_write();
}
static int axm0432_jtag_init(void)
@ -3195,7 +3206,11 @@ COMMAND_HANDLER(ft2232_handle_layout_command)
for (const struct ft2232_layout *l = ft2232_layouts; l->name; l++) {
if (strcmp(l->name, CMD_ARGV[0]) == 0) {
layout = l;
return ERROR_OK;
/* This may also select the transport
* if we only suppport one of them.
*/
return allow_transports(CMD_CTX,
l->transports ? : jtag_only);
}
}

View File

@ -689,4 +689,6 @@ void jtag_poll_set_enabled(bool value);
* level APIs that are used in inner loops. */
#include <jtag/minidriver.h>
bool transport_is_jtag(void);
#endif /* JTAG_H */

373
src/jtag/transport.c Normal file
View File

@ -0,0 +1,373 @@
/*
* Copyright (c) 2010 by David Brownell
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/** @file
* Infrastructure for specifying and managing the transport protocol
* used in a given debug or programming session.
*
* Examples of "debug-capable" transports are JTAG or SWD.
* Additionally, JTAG supports boundary scan testing.
*
* Examples of "programming-capable" transports include SPI or UART;
* those are used (often mediated by a ROM bootloader) for ISP style
* programming, to perform an initial load of code into flash, or
* sometimes into SRAM. Target code could use "variant" options to
* decide how to use such protocols. For example, Cortex-M3 cores
* from TI/Luminary and from NXP use different protocols for for
* UART or SPI based firmware loading.
*
* As a rule, there are protocols layered on top of the transport.
* For example, different chip families use JTAG in different ways
* for debugging. Also, each family that supports programming over
* a UART link for initial firmware loading tends to define its own
* messaging and error handling.
*/
#include <helper/log.h>
#include "transport.h"
/*-----------------------------------------------------------------------*/
/*
* Infrastructure internals
*/
/** List of transports known to OpenOCD. */
static struct transport *transport_list;
/**
* NULL-terminated Vector of names of transports which the
* currently selected debug adapter supports. This is declared
* by the time that adapter is fully set up.
*/
static const char **allowed_transports;
/** * The transport being used for the current OpenOCD session. */
static struct transport *session;
static int transport_select(struct command_context *ctx, const char *name)
{
/* name may only identify a known transport;
* caller guarantees session's transport isn't yet set.*/
for (struct transport *t = transport_list; t; t = t->next) {
if (strcmp(t->name, name) == 0) {
int retval = t->select(ctx);
/* select() registers commands specific to this
* transport, and may also reset the link, e.g.
* forcing it to JTAG or SWD mode.
*/
if (retval == ERROR_OK)
session = t;
else
LOG_ERROR("Error %d selecting '%s' as "
"transport", retval, t->name);
return retval;
}
}
LOG_ERROR("No transport named '%s' is available.", name);
return ERROR_FAIL;
}
/**
* Called by debug adapter drivers, or affiliated Tcl config scripts,
* to declare the set of transports supported by an adapter. When
* there is only one member of that set, it is automatically selected.
*/
int allow_transports(struct command_context *ctx, const char **vector)
{
/* NOTE: caller is required to provide only a list
* of *valid* transport names
*
* REVISIT should we validate that? and insist there's
* at least one non-NULL element in that list?
*/
if (allowed_transports != NULL || session) {
LOG_ERROR("Can't modify the set of allowed transports.");
return ERROR_FAIL;
}
allowed_transports = vector;
/* autoselect if there's no choice ... */
if (!vector[1]) {
LOG_INFO("only one transport option; autoselect '%s'",
vector[0]);
return transport_select(ctx, vector [0]);
} else {
while (*vector)
LOG_DEBUG("allow transport '%s'", *vector++);
return ERROR_OK;
}
}
/**
* Used to verify corrrect adapter driver initialization.
*
* @returns true iff the adapter declared one or more transports.
*/
bool transports_are_declared(void)
{
return allowed_transports != NULL;
}
/**
* Registers a transport. There are general purpose transports
* (such as JTAG), as well as relatively proprietary ones which are
* specific to a given chip (or chip family).
*
* Code implementing a transport needs to register it before it can
* be selected and then activated. This is a dynamic process, so
* that chips (and families) can define transports as needed (without
* nneeding error-prone static tables).
*
* @param new_transport the transport being registered. On a
* successful return, this memory is owned by the transport framework.
*
* @returns ERROR_OK on success, else a fault code.
*/
int transport_register(struct transport *new_transport)
{
struct transport *t;
for (t = transport_list; t; t = t->next) {
if (strcmp(t->name, new_transport->name) == 0) {
LOG_ERROR("transport name already used");
return ERROR_FAIL;
}
}
if (!new_transport->select || !new_transport->init) {
LOG_ERROR("invalid transport %s", new_transport->name);
}
/* splice this into the list */
new_transport->next = transport_list;
transport_list = new_transport;
LOG_DEBUG("register '%s'", t->name);
return ERROR_OK;
}
/**
* Returns the transport currently being used by this debug or
* programming session.
*
* @returns handle to the read-only transport entity.
*/
struct transport *get_current_transport(void)
{
/* REVISIT -- constify */
return session;
}
/*-----------------------------------------------------------------------*/
/*
* Infrastructure for Tcl interface to transports.
*/
/**
* Makes and stores a copy of a set of transports passed as
* parameters to a command.
*
* @param vector where the resulting copy is stored, as an argv-style
* NULL-terminated vector.
*/
COMMAND_HELPER(transport_list_parse, char ***vector)
{
char **argv;
unsigned n = CMD_ARGC;
unsigned j = 0;
*vector = NULL;
if (n < 1)
return ERROR_COMMAND_SYNTAX_ERROR;
/* our return vector must be NULL terminated */
argv = (char **) calloc(n + 1, sizeof(char *));
if (argv == NULL)
return ERROR_FAIL;
for (unsigned i = 0; i < n; i++) {
struct transport *t;
for (t = transport_list; t; t = t->next) {
if (strcmp(t->name, CMD_ARGV[i]) != 0)
continue;
argv[j++] = strdup(CMD_ARGV[i]);
break;
}
if (!t) {
LOG_ERROR("no such transport '%s'", CMD_ARGV[i]);
goto fail;
}
}
*vector = argv;
return ERROR_OK;
fail:
for (unsigned i = 0; i < n; i++)
free(argv[i]);
free(argv);
return ERROR_FAIL;
}
COMMAND_HANDLER(handle_transport_init)
{
LOG_DEBUG("%s", __func__);
if (!session) {
LOG_ERROR("session's transport is not selected.");
return ERROR_FAIL;
}
return session->init(CMD_CTX);
}
COMMAND_HANDLER(handle_transport_list)
{
if (CMD_ARGC != 0)
return ERROR_COMMAND_SYNTAX_ERROR;
command_print(CMD_CTX, "The following transports are available:");
for (struct transport *t = transport_list; t; t = t->next)
command_print(CMD_CTX, "\t%s", t->name);
return ERROR_OK;
}
/**
* Implements the Tcl "transport select" command, choosing the
* transport to be used in this debug session from among the
* set supported by the debug adapter being used.
*/
COMMAND_HANDLER(handle_transport_select)
{
int retval = ERROR_OK;;
switch (CMD_ARGC) {
case 0: /* "select" */
if (session) {
goto show;
}
LOG_ERROR("session's transport is not selected.");
return ERROR_FAIL;
case 1: /* "select FOO" */
if(strcmp(session->name, CMD_ARGV[0]) == 0) {
/* NOP */
LOG_DEBUG("transport '%s' is already selected",
CMD_ARGV[0]);
return ERROR_OK;
} else {
/* we can't change this session's transport after-the-fact */
if (session) {
LOG_ERROR("session's transport is already selected.");
return ERROR_FAIL;
}
}
break;
default: /* select FOO BAR */
/* we only select *one* transport per session */
LOG_ERROR("may only select one transport!");
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, including
* declaring transport via C code or Tcl script.
*/
if (!allowed_transports) {
LOG_ERROR("Debug adapter doesn't support any transports?");
return ERROR_FAIL;
}
for (unsigned i = 0; allowed_transports[i]; i++) {
if (strcmp(allowed_transports[i], CMD_ARGV[0]) == 0)
return transport_select(CMD_CTX, CMD_ARGV[0]);
}
LOG_ERROR("Debug adapter doesn't support '%s' "
"transport?", CMD_ARGV[0]);
return ERROR_FAIL;
show:
/* report the current transport selection */
command_print(CMD_CTX, "%s", session->name);
return retval;
}
static const struct command_registration transport_commands[] = {
{
.name = "init",
.handler = handle_transport_init,
/* this would be COMMAND_CONFIG ... except that
* it needs to trigger event handlers that may
* require COMMAND_EXEC ...
*/
.mode = COMMAND_ANY,
.help = "Initialize this session's transport",
},
{
.name = "list",
.handler = handle_transport_list,
.mode = COMMAND_ANY,
.help = "list all built-in transports",
},
{
.name = "select",
.handler = handle_transport_select,
.mode = COMMAND_ANY,
.help = "Select this session's transport",
.usage = "[transport_name]",
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration transport_group[] = {
{
.name = "transport",
.mode = COMMAND_ANY,
.help = "Transport command group",
.chain = transport_commands,
},
COMMAND_REGISTRATION_DONE
};
int transport_register_commands(struct command_context *ctx)
{
return register_commands(ctx, NULL, transport_group);
}

80
src/jtag/transport.h Normal file
View File

@ -0,0 +1,80 @@
/*
* Copyright (c) 2010 by David Brownell
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "helper/command.h"
/**
* Wrapper for transport lifecycle operations.
*
* OpenOCD talks to targets through some kind of debugging
* or programming adapter, using some protocol that probably
* has target-specific aspects.
*
* A "transport" reflects electrical protocol to the target,
* e..g jtag, swd, spi, uart, ... NOT the messaging protocols
* layered over it (e.g. JTAG has eICE, CoreSight, Nexus, OnCE,
* and more).
*
* In addition to the lifecycle operations packaged by this
* structure, a transport also involves an interface supported
* by debug adapters and used by components such as debug targets.
* For non-debug transports, there may be interfaces used to
* write to flash chips.
*/
struct transport {
/**
* Each transport has a unique name, used to select it
* from among the alternatives. Examples might include
* "jtag", * "swd", "AVR_ISP" and more.
*/
const char *name;
/**
* When a transport is selected, this method registers
* its commands and activates the transport (e.g. resets
* the link).
*
* After those commands are registered, they will often
* be used for further configuration of the debug link.
*/
int (*select)(struct command_context *ctx);
/**
* server startup uses this method to validate transport
* configuration. (For example, with JTAG this interrogates
* the scan chain against the list of expected TAPs.)
*/
int (*init)(struct command_context *ctx);
/**
* Transports are stored in a singly linked list.
*/
struct transport *next;
};
int transport_register(struct transport *new_transport);
struct transport *get_current_transport(void);
int transport_register_commands(struct command_context *ctx);
COMMAND_HELPER(transport_list_parse, char ***vector);
int allow_transports(struct command_context *ctx, const char **vector);
bool transports_are_declared(void);

View File

@ -31,10 +31,9 @@
#include "openocd.h"
#include <jtag/driver.h>
#include <jtag/jtag.h>
#include <jtag/transport.h>
#include <helper/ioutil.h>
#include <helper/configuration.h>
#include <xsvf/xsvf.h>
#include <svf/svf.h>
#include <flash/nor/core.h>
#include <flash/nand/core.h>
#include <pld/pld.h>
@ -120,22 +119,24 @@ COMMAND_HANDLER(handle_init_command)
/* we must be able to set up the debug adapter */
return retval;
}
LOG_DEBUG("Debug Adapter init complete");
/* Try to initialize & examine the JTAG chain at this point,
* but continue startup regardless. Note that platforms
* need to be able to provide JTAG event handlers that use
* a variety of JTAG operations in order to do that...
/* "transport init" verifies the expected devices are present;
* for JTAG, it checks the list of configured TAPs against
* what's discoverable, possibly with help from the platform's
* JTAG event handlers. (which require COMMAND_EXEC)
*/
command_context_mode(CMD_CTX, COMMAND_EXEC);
if (command_run_line(CMD_CTX, "jtag init") == ERROR_OK)
{
retval = command_run_line(CMD_CTX, "transport init");
if (ERROR_OK != retval)
return ERROR_FAIL;
LOG_DEBUG("Examining targets...");
if (target_examine() != ERROR_OK)
LOG_DEBUG("target examination failed");
}
else
LOG_WARNING("jtag initialization failed; try 'jtag init' again.");
command_context_mode(CMD_CTX, COMMAND_CONFIG);
if (command_run_line(CMD_CTX, "flash init") != ERROR_OK)
@ -227,16 +228,13 @@ struct command_context *setup_command_handler(Jim_Interp *interp)
&server_register_commands,
&gdb_register_commands,
&log_register_commands,
&transport_register_commands,
&interface_register_commands,
&jtag_register_commands,
&xsvf_register_commands,
&svf_register_commands,
&target_register_commands,
&flash_register_commands,
&nand_register_commands,
&pld_register_commands,
&mflash_register_commands,
NULL
};
for (unsigned i = 0; NULL != command_registrants[i]; i++)
{