ipdbg: split ipdbg command into multiple commands

To simplify the ipdbg start/stop command and be able to
add additional commands in the future, we introduce the
concept of a hub which has to be created before a
ipdbg server can be started.
The hub was created on the fly in previous versions.

Change-Id: I55f317542d01a7324990b2cacd496a41fa5ff875
Signed-off-by: Daniel Anselmi <danselmi@gmx.ch>
Reviewed-on: https://review.openocd.org/c/openocd/+/7979
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Tested-by: jenkins
This commit is contained in:
Daniel Anselmi 2024-01-01 16:05:07 +01:00 committed by Antonio Borneo
parent 1d076d6ce1
commit 7a77355a3e
10 changed files with 490 additions and 187 deletions

View File

@ -12116,55 +12116,84 @@ waveform generator. These are synthesize-able hardware descriptions of
logic circuits in addition to software for control, visualization and further analysis.
In a session using JTAG for its transport protocol, OpenOCD supports the function
of a JTAG-Host. The JTAG-Host is needed to connect the circuit over JTAG to the
control-software. For more details see @url{http://ipdbg.org}.
control-software. The JTAG-Hub is the circuit which transfers the data from JTAG to the
different tools connected to the Hub. Hub implementations for most major FPGA vendors/families
are provided. For more details see @url{http://ipdbg.org}.
@deffn {Command} {ipdbg} [@option{-start|-stop}] @option{-tap @var{tapname}} @option{-hub @var{ir_value} [@var{dr_length}]} [@option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]}] [@option{-port @var{number}}] [@option{-tool @var{number}}]
Starts or stops a IPDBG JTAG-Host server. Arguments can be specified in any order.
@deffn {Command} {ipdbg create-hub} @var{hub_name} @option{-tap @var{tapname}} @option{-ir @var{ir_value} [@var{dr_length}]} [@option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]}]
@deffnx {Command} {ipdbg create-hub} @var{hub_name} @option{-pld @var{pld_name} [@var{user}]} [@option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]}]
Creates a IPDBG JTAG Hub. The created hub is later used to start, stop and configure IPDBG JTAG Host servers.
The first argument @var{hub_name} is the name of the created hub. It can be used later as a reference.
The pld drivers are able to provide the tap and ir_value for the IPDBG JTAG-Host server. This will be used with the second variant with option @option{-pld}.
Command options:
@itemize @bullet
@item @option{-start|-stop} starts or stops a IPDBG JTAG-Host server (default: start).
@item @var{hub_name} the name of the IPDBG hub.
This name is also used to create the object's command, referred to here
as @command{$hub_name}, and in other places where the Hub needs to be identified.
@item @option{-tap @var{tapname}} targeting the TAP @var{tapname}.
@item @option{-hub @var{ir_value}} states that the JTAG hub is
reachable with dr-scans while the JTAG instruction register has the value @var{ir_value}.
@item @option{-port @var{number}} tcp port number where the JTAG-Host will listen. The default is 4242 which is used when the option is not given.
@item @option{-tool @var{number}} number of the tool/feature. These corresponds to the ports "data_(up/down)_(0..6)" at the JtagHub. The default is 1 which is used when the option is not given.
@item @option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]} On some devices, the user data-register is reachable if there is a
specific value in a second dr. This second dr is called vir (virtual ir). With this parameter given, the IPDBG satisfies this condition prior an
@item @option{-ir @var{ir_value}} states that the JTAG hub is
reachable with dr-scans while the JTAG instruction register has the value @var{ir_value}. Also known as @verb{|USERx|} instructions.
The optional @var{dr_length} is the length of the dr.
Current JTAG-Hub implementation only supports dr_length=13, which is also the default value.
@item @option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]} To support more Hubs than USER registers in a single FPGA it is possible to
use a mechanism known as virtual-ir where the user data-register is reachable if there is a specific value in a second dr.
This second dr is called vir (virtual ir). With this parameter given, the IPDBG satisfies this condition prior an
access to the IPDBG-Hub. The value shifted into the vir is given by the first parameter @var{vir_value} (default: 0x11). The second
parameter @var{length} is the length of the vir data register (default: 5). With the @var{instr_code} (default: 0x00e) parameter the ir value to
shift data through vir can be configured.
@item @option{-pld @var{pld_name} [@var{user}]} The defined driver for the pld @var{pld_name} is used to get the tap and user instruction.
The pld devices names can be shown by the command @command{pld devices}. With [@var{user}] one can select a different @verb{|USERx|}-Instruction.
If the IPDBG JTAG-Hub is used without modification the default value of 1 which selects the first @verb{|USERx|} instruction is adequate.
The @verb{|USERx|} instructions are vendor specific and don't change between families of the same vendor.
So if there's a pld driver for your vendor it should work with your FPGA even when the driver is not compatible with your device for the remaining features.
If your device/vendor is not supported you have to use the first variant.
@end itemize
@end deffn
@deffn {Command} {$hub_name ipdbg start} @option{-tool @var{number}} @option{-port @var{number}}
Starts a IPDBG JTAG-Host server. The remaining arguments can be specified in any order.
Command options:
@itemize @bullet
@item @option{-port @var{number}} tcp port number where the JTAG-Host will listen. The default is 4242 which is used when the option is not given.
@item @option{-tool @var{number}} number of the tool/feature. These corresponds to the ports "data_(up/down)_(0..6)" at the JtagHub. The default is 1 which is used when the option is not given.
@end itemize
@end deffn
or
@deffn {Command} {ipdbg} [@option{-start|-stop}] @option{-pld @var{name} [@var{user}]} [@option{-port @var{number}}] [@option{-tool @var{number}}]
Also starts or stops a IPDBG JTAG-Host server. The pld drivers are able to provide the tap and hub/IR for the IPDBG JTAG-Host server.
With the @option{-pld @var{name} [@var{user}]} the information from the pld-driver is used and the options @option{-tap} and @option{-hub} are not required.
The defined driver for the pld @var{name} gets selected. (The pld devices names can be shown by the command @command{pld devices}).
The @verb{|USERx|} instructions are vendor specific and don't change between families of the same vendor.
So if there's a pld driver for your vendor it should work with your FPGA even when the driver is not compatible with your device for the remaining features. If your device/vendor is not supported you have to use the previous command.
With [@var{user}] one can select a different @verb{|USERx|}-Instruction. If the IPDBG JTAG-Hub is used without modification the default value of 1 which selects the first @verb{|USERx|} instruction is adequate.
The remaining options are described in the previous command.
@deffn {Command} {$hub_name ipdbg stop} @option{-tool @var{number}}
Stops a IPDBG JTAG-Host server.
Command options:
@itemize @bullet
@item @option{-tool @var{number}} number of the tool/feature. These corresponds to the ports "data_(up/down)_(0..6)" at the JtagHub. The default is 1 which is used when the option is not given.
@end itemize
@end deffn
Examples:
@example
ipdbg -start -tap xc6s.tap -hub 0x02 -port 4242 -tool 4
ipdbg create-hub xc6s.ipdbghub -tap xc6s.tap -hub 0x02
xc6s.ipdbghub ipdbg start -port 4242 -tool 4
@end example
Starts a server listening on tcp-port 4242 which connects to tool 4.
Creates a IPDBG Hub and starts a server listening on tcp-port 4242 which connects to tool 4.
The connection is through the TAP of a Xilinx Spartan 6 on USER1 instruction (tested with a papillion pro board).
@example
ipdbg -start -tap 10m50.tap -hub 0x00C -vir -port 60000 -tool 1
ipdbg create-hub max10m50.ipdbghub -tap max10m50.tap -hub 0x00C -vir
max10m50.ipdbghub ipdbg start -tool 1 -port 60000
@end example
Starts a server listening on tcp-port 60000 which connects to tool 1 (data_up_1/data_down_1).
The connection is through the TAP of a Intel MAX10 virtual jtag component (sld_instance_index is 0; sld_ir_width is smaller than 5).
@example
ipdbg -start -pld xc7.pld -port 5555 -tool 0
ipdbg create-hub xc7.ipdbghub -pld xc7.pld
xc7.ipdbghub ipdbg start -port 5555 -tool 0
@end example
Starts a server listening on tcp-port 5555 which connects to tool 0 (data_up_0/data_down_0).
The TAP and ir value used to reach the JTAG Hub is given by the pld driver.

View File

@ -1146,4 +1146,132 @@ proc "pld device" {driver tap_name {opt 0}} {
}
}
lappend _telnet_autocomplete_skip "ipdbg -start"
proc "ipdbg -start" {args} {
echo "DEPRECATED! use 'ipdbg create-hub' and 'chip.ipdbghub ipdbg start ...', not 'ipdbg -start ...'"
set tap_name ""
set pld_name ""
set tool_num "1"
set port_num "4242"
set idx 0
set num_args [llength $args]
while {$idx < $num_args} {
set arg [lindex $args $idx]
switch -- $arg {
"-tap" {
incr idx
if {$idx >= $num_args || [string index [lindex $args $idx] 0] == "-"} {
echo "no TAP name given"
return
}
set tap_name [lindex $args $idx]
}
"-pld" {
incr idx
if {$idx >= $num_args || [string index [lindex $args $idx] 0] == "-"} {
echo "no PLD name given"
return
}
set pld_name [lindex $args $idx]
}
"-tool" {
if {[expr {$idx + 1}] < $num_args && [string index [lindex $args [expr {$idx + 1}]] 0] != "-"} {
set tool_num [lindex $args [expr {$idx + 1}]]
set args [lreplace $args [expr {$idx + 1}] [expr {$idx + 1}]]
incr num_args -1
}
set args [lreplace $args $idx $idx]
incr num_args -1
incr idx -1
}
"-port" {
if {[expr {$idx + 1}] < $num_args && [string index [lindex $args [expr {$idx + 1}]] 0] != "-"} {
set port_num [lindex $args [expr {$idx + 1}]]
set args [lreplace $args [expr {$idx + 1}] [expr {$idx + 1}]]
incr num_args -1
}
set args [lreplace $args $idx $idx]
incr num_args -1
incr idx -1
}
"-hub" {
set args [lreplace $args $idx $idx "-ir" ]
}
default {
# don't touch remaining arguments
}
}
incr idx
}
set hub_name ""
if {$tap_name != ""} {
set hub_name [lindex [split $tap_name .] 0].ipdbghub
} elseif {$pld_name != ""} {
set hub_name [lindex [split $pld_name .] 0].ipdbghub
} else {
echo "parsing arguments failed: no tap and no pld given."
return
}
echo "name: $hub_name"
echo "ipdbg create-hub $hub_name $args"
catch {eval ipdbg create-hub $hub_name $args}
eval $hub_name ipdbg start -tool $tool_num -port $port_num
}
lappend _telnet_autocomplete_skip "ipdbg -stop"
proc "ipdbg -stop" {args} {
echo "DEPRECATED! use 'chip.ipdbghub ipdbg stop ...', not 'ipdbg -stop ...'"
set tap_name ""
set pld_name ""
set tool_num "1"
set idx 0
set num_args [llength $args]
while {$idx < $num_args} {
set arg [lindex $args $idx]
switch -- $arg {
"-tap" {
incr idx
if {$idx >= $num_args || [string index [lindex $args $idx] 0] == "-"} {
echo "no TAP name given"
return
}
set tap_name [lindex $args $idx]
}
"-pld" {
incr idx
if {$idx >= $num_args || [string index [lindex $args $idx] 0] == "-"} {
echo "no PLD name given"
return
}
set pld_name [lindex $args $idx]
}
"-tool" {
if {[expr {$idx + 1}] < $num_args && [string index [lindex $args [expr {$idx + 1}]] 0] != "-"} {
set tool_num [lindex $args [expr {$idx + 1}]]
}
}
default {
# don't touch remaining arguments
}
}
incr idx
}
set hub_name ""
if {$tap_name != ""} {
set hub_name [lindex [split $tap_name .] 0].ipdbghub
} elseif {$pld_name != ""} {
set hub_name [lindex [split $pld_name .] 0].ipdbghub
} else {
echo "parsing arguments failed: no tap and no pld given."
return
}
eval $hub_name ipdbg stop -tool $tool_num
}
# END MIGRATION AIDS

View File

@ -15,8 +15,10 @@
#include "ipdbg.h"
#define IPDBG_BUFFER_SIZE 16384
#define IPDBG_MIN_NUM_OF_OPTIONS 2
#define IPDBG_MAX_NUM_OF_OPTIONS 14
#define IPDBG_MIN_NUM_OF_CREATE_OPTIONS 3
#define IPDBG_MAX_NUM_OF_CREATE_OPTIONS 10
#define IPDBG_NUM_OF_START_OPTIONS 4
#define IPDBG_NUM_OF_STOP_OPTIONS 2
#define IPDBG_MIN_DR_LENGTH 11
#define IPDBG_MAX_DR_LENGTH 13
#define IPDBG_TCP_PORT_STR_MAX_LENGTH 6
@ -75,6 +77,7 @@ struct ipdbg_hub {
uint32_t xoff_mask;
uint32_t tool_mask;
uint32_t last_dn_tool;
char *name;
struct ipdbg_hub *next;
struct jtag_tap *tap;
struct connection **connections;
@ -247,73 +250,9 @@ static void ipdbg_add_hub(struct ipdbg_hub *hub)
for (ihub = ipdbg_first_hub; ihub->next; ihub = ihub->next)
;
ihub->next = hub;
} else
} else {
ipdbg_first_hub = hub;
}
static int ipdbg_create_hub(struct jtag_tap *tap, uint32_t user_instruction, uint8_t data_register_length,
struct ipdbg_virtual_ir_info *virtual_ir, struct ipdbg_hub **hub)
{
*hub = NULL;
struct ipdbg_hub *new_hub = calloc(1, sizeof(struct ipdbg_hub));
if (!new_hub)
goto mem_err_hub;
const size_t dreg_buffer_size = DIV_ROUND_UP(data_register_length, 8);
new_hub->max_tools = ipdbg_max_tools_from_data_register_length(data_register_length);
new_hub->scratch_memory.dr_out_vals = calloc(IPDBG_SCRATCH_MEMORY_SIZE, dreg_buffer_size);
new_hub->scratch_memory.dr_in_vals = calloc(IPDBG_SCRATCH_MEMORY_SIZE, dreg_buffer_size);
new_hub->scratch_memory.fields = calloc(IPDBG_SCRATCH_MEMORY_SIZE, sizeof(struct scan_field));
new_hub->connections = calloc(new_hub->max_tools, sizeof(struct connection *));
if (virtual_ir)
new_hub->scratch_memory.vir_out_val = calloc(1, DIV_ROUND_UP(virtual_ir->length, 8));
if (!new_hub->scratch_memory.dr_out_vals || !new_hub->scratch_memory.dr_in_vals ||
!new_hub->scratch_memory.fields || (virtual_ir && !new_hub->scratch_memory.vir_out_val) ||
!new_hub->connections)
goto mem_err2;
if (virtual_ir)
buf_set_u32(new_hub->scratch_memory.vir_out_val, 0, virtual_ir->length, virtual_ir->value);
new_hub->tap = tap;
new_hub->user_instruction = user_instruction;
new_hub->data_register_length = data_register_length;
new_hub->valid_mask = BIT(data_register_length - 1);
new_hub->xoff_mask = BIT(data_register_length - 2);
new_hub->tool_mask = (new_hub->xoff_mask - 1) >> 8;
new_hub->last_dn_tool = new_hub->tool_mask;
new_hub->virtual_ir = virtual_ir;
*hub = new_hub;
return ERROR_OK;
mem_err2:
free(new_hub->scratch_memory.vir_out_val);
free(new_hub->connections);
free(new_hub->scratch_memory.fields);
free(new_hub->scratch_memory.dr_in_vals);
free(new_hub->scratch_memory.dr_out_vals);
free(new_hub);
mem_err_hub:
free(virtual_ir);
LOG_ERROR("Out of memory");
return ERROR_FAIL;
}
static void ipdbg_free_hub(struct ipdbg_hub *hub)
{
if (!hub)
return;
free(hub->connections);
free(hub->virtual_ir);
free(hub->scratch_memory.dr_out_vals);
free(hub->scratch_memory.dr_in_vals);
free(hub->scratch_memory.fields);
free(hub->scratch_memory.vir_out_val);
free(hub);
}
static int ipdbg_remove_hub(struct ipdbg_hub *hub)
@ -335,6 +274,58 @@ static int ipdbg_remove_hub(struct ipdbg_hub *hub)
return ERROR_FAIL;
}
static void ipdbg_free_hub(struct ipdbg_hub *hub)
{
if (!hub)
return;
free(hub->connections);
free(hub->virtual_ir);
free(hub->name);
free(hub->scratch_memory.dr_out_vals);
free(hub->scratch_memory.dr_in_vals);
free(hub->scratch_memory.fields);
free(hub->scratch_memory.vir_out_val);
free(hub);
}
static struct ipdbg_hub *ipdbg_allocate_hub(uint8_t data_register_length, struct ipdbg_virtual_ir_info *virtual_ir,
const char *name)
{
struct ipdbg_hub *new_hub = calloc(1, sizeof(struct ipdbg_hub));
if (!new_hub) {
LOG_ERROR("Out of memory");
return NULL;
}
new_hub->name = strdup(name);
if (!new_hub->name) {
free(new_hub);
LOG_ERROR("Out of memory");
return NULL;
}
const size_t dreg_buffer_size = DIV_ROUND_UP(data_register_length, 8);
uint32_t max_tools = ipdbg_max_tools_from_data_register_length(data_register_length);
new_hub->scratch_memory.dr_out_vals = calloc(IPDBG_SCRATCH_MEMORY_SIZE, dreg_buffer_size);
new_hub->scratch_memory.dr_in_vals = calloc(IPDBG_SCRATCH_MEMORY_SIZE, dreg_buffer_size);
new_hub->scratch_memory.fields = calloc(IPDBG_SCRATCH_MEMORY_SIZE, sizeof(struct scan_field));
new_hub->connections = calloc(max_tools, sizeof(struct connection *));
if (virtual_ir)
new_hub->scratch_memory.vir_out_val = calloc(1, DIV_ROUND_UP(virtual_ir->length, 8));
if (!new_hub->scratch_memory.dr_out_vals || !new_hub->scratch_memory.dr_in_vals ||
!new_hub->scratch_memory.fields || (virtual_ir && !new_hub->scratch_memory.vir_out_val) ||
!new_hub->connections) {
ipdbg_free_hub(new_hub);
LOG_ERROR("Out of memory");
return NULL;
}
return new_hub;
}
static void ipdbg_init_scan_field(struct scan_field *fields, uint8_t *in_value, int num_bits, const uint8_t *out_value)
{
fields->check_mask = NULL;
@ -760,62 +751,18 @@ static const struct service_driver ipdbg_service_driver = {
.keep_client_alive_handler = NULL,
};
static int ipdbg_start(uint16_t port, struct jtag_tap *tap, uint32_t user_instruction,
uint8_t data_register_length, struct ipdbg_virtual_ir_info *virtual_ir, uint8_t tool)
static struct ipdbg_hub *ipdbg_get_hub_by_name(const char *name)
{
LOG_INFO("starting ipdbg service on port %d for tool %d", port, tool);
struct ipdbg_hub *hub = ipdbg_find_hub(tap, user_instruction, virtual_ir);
if (hub) {
free(virtual_ir);
if (hub->data_register_length != data_register_length) {
LOG_DEBUG("hub must have the same data_register_length for all tools");
return ERROR_FAIL;
}
} else {
int retval = ipdbg_create_hub(tap, user_instruction, data_register_length, virtual_ir, &hub);
if (retval != ERROR_OK)
return retval;
struct ipdbg_hub *hub = NULL;
for (hub = ipdbg_first_hub; hub; hub = hub->next) {
if (strcmp(hub->name, name) == 0)
break;
}
return hub;
};
struct ipdbg_service *service = NULL;
int retval = ipdbg_create_service(hub, tool, &service, port);
if (retval != ERROR_OK || !service) {
if (hub->active_services == 0 && hub->active_connections == 0)
ipdbg_free_hub(hub);
return ERROR_FAIL;
}
char port_str_buffer[IPDBG_TCP_PORT_STR_MAX_LENGTH];
snprintf(port_str_buffer, IPDBG_TCP_PORT_STR_MAX_LENGTH, "%u", port);
retval = add_service(&ipdbg_service_driver, port_str_buffer, 1, service);
if (retval == ERROR_OK) {
ipdbg_add_service(service);
if (hub->active_services == 0 && hub->active_connections == 0)
ipdbg_add_hub(hub);
hub->active_services++;
} else {
if (hub->active_services == 0 && hub->active_connections == 0)
ipdbg_free_hub(hub);
free(service);
}
return retval;
}
static int ipdbg_stop(struct jtag_tap *tap, uint32_t user_instruction,
struct ipdbg_virtual_ir_info *virtual_ir, uint8_t tool)
static int ipdbg_stop_service(struct ipdbg_service *service)
{
struct ipdbg_hub *hub = ipdbg_find_hub(tap, user_instruction, virtual_ir);
free(virtual_ir);
if (!hub)
return ERROR_FAIL;
struct ipdbg_service *service = ipdbg_find_service(hub, tool);
if (!service)
return ERROR_FAIL;
int retval = ipdbg_remove_service(service);
if (retval != ERROR_OK) {
LOG_ERROR("BUG: ipdbg_remove_service failed");
@ -831,41 +778,223 @@ static int ipdbg_stop(struct jtag_tap *tap, uint32_t user_instruction,
LOG_ERROR("BUG: remove_service failed");
return retval;
}
hub->active_services--;
if (hub->active_connections == 0 && hub->active_services == 0) {
retval = ipdbg_remove_hub(hub);
if (retval != ERROR_OK) {
LOG_ERROR("BUG: ipdbg_remove_hub failed");
return retval;
}
ipdbg_free_hub(hub);
}
return ERROR_OK;
}
COMMAND_HANDLER(handle_ipdbg_command)
int ipdbg_server_free(void)
{
struct jtag_tap *tap = NULL;
int retval = ERROR_OK;
for (struct ipdbg_hub *hub = ipdbg_first_hub; hub;) {
for (uint8_t tool = 0; tool < hub->max_tools; ++tool) {
struct ipdbg_service *service = ipdbg_find_service(hub, tool);
if (service) {
int new_retval = ipdbg_stop_service(service);
if (new_retval != ERROR_OK)
retval = new_retval;
hub->active_services--;
}
}
struct ipdbg_hub *next_hub = hub->next;
int new_retval = ipdbg_remove_hub(hub);
if (new_retval != ERROR_OK)
retval = new_retval;
ipdbg_free_hub(hub);
hub = next_hub;
}
return retval;
}
static int ipdbg_start(struct ipdbg_hub *hub, uint16_t port, uint8_t tool)
{
LOG_INFO("starting ipdbg service on port %d for tool %d", port, tool);
struct ipdbg_service *service = NULL;
int retval = ipdbg_create_service(hub, tool, &service, port);
if (retval != ERROR_OK || !service) {
if (hub->active_services == 0 && hub->active_connections == 0)
ipdbg_free_hub(hub);
return ERROR_FAIL;
}
char port_str_buffer[IPDBG_TCP_PORT_STR_MAX_LENGTH];
snprintf(port_str_buffer, IPDBG_TCP_PORT_STR_MAX_LENGTH, "%u", port);
retval = add_service(&ipdbg_service_driver, port_str_buffer, 1, service);
if (retval != ERROR_OK) {
free(service);
return retval;
}
ipdbg_add_service(service);
hub->active_services++;
return ERROR_OK;
}
COMMAND_HANDLER(handle_ipdbg_start_command)
{
struct ipdbg_hub *hub = CMD_DATA;
uint16_t port = 4242;
uint8_t tool = 1;
if (CMD_ARGC > IPDBG_NUM_OF_START_OPTIONS)
return ERROR_COMMAND_SYNTAX_ERROR;
for (unsigned int i = 0; i < CMD_ARGC; ++i) {
if (strcmp(CMD_ARGV[i], "-port") == 0) {
COMMAND_PARSE_ADDITIONAL_NUMBER(u16, i, port, "port number");
} else if (strcmp(CMD_ARGV[i], "-tool") == 0) {
COMMAND_PARSE_ADDITIONAL_NUMBER(u8, i, tool, "tool");
} else {
command_print(CMD, "Unknown argument: %s", CMD_ARGV[i]);
return ERROR_FAIL;
}
}
return ipdbg_start(hub, port, tool);
}
static int ipdbg_stop(struct ipdbg_hub *hub, uint8_t tool)
{
struct ipdbg_service *service = ipdbg_find_service(hub, tool);
if (!service) {
LOG_ERROR("No service for hub '%s'/tool %d found", hub->name, tool);
return ERROR_FAIL;
}
int retval = ipdbg_stop_service(service);
hub->active_services--;
LOG_INFO("stopped ipdbg service for tool %d", tool);
return retval;
}
COMMAND_HANDLER(handle_ipdbg_stop_command)
{
struct ipdbg_hub *hub = CMD_DATA;
uint8_t tool = 1;
if (CMD_ARGC > IPDBG_NUM_OF_STOP_OPTIONS)
return ERROR_COMMAND_SYNTAX_ERROR;
for (unsigned int i = 0; i < CMD_ARGC; ++i) {
if (strcmp(CMD_ARGV[i], "-tool") == 0) {
COMMAND_PARSE_ADDITIONAL_NUMBER(u8, i, tool, "tool");
} else {
command_print(CMD, "Unknown argument: %s", CMD_ARGV[i]);
return ERROR_FAIL;
}
}
return ipdbg_stop(hub, tool);
}
static const struct command_registration ipdbg_hostserver_subcommand_handlers[] = {
{
.name = "start",
.mode = COMMAND_EXEC,
.handler = handle_ipdbg_start_command,
.help = "Starts a IPDBG Host server.",
.usage = "-tool number -port port"
}, {
.name = "stop",
.mode = COMMAND_EXEC,
.handler = handle_ipdbg_stop_command,
.help = "Stops a IPDBG Host server.",
.usage = "-tool number"
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration ipdbg_hub_subcommand_handlers[] = {
{
.name = "ipdbg",
.mode = COMMAND_EXEC,
.help = "IPDBG Hub commands.",
.usage = "",
.chain = ipdbg_hostserver_subcommand_handlers
},
COMMAND_REGISTRATION_DONE
};
static int ipdbg_register_hub_command(struct ipdbg_hub *hub, struct command_invocation *cmd)
{
Jim_Interp *interp = CMD_CTX->interp;
/* does this command exist? */
Jim_Cmd *jcmd = Jim_GetCommand(interp, Jim_NewStringObj(interp, hub->name, -1), JIM_NONE);
if (jcmd) {
LOG_ERROR("cannot create Hub because a command with name '%s' already exists", hub->name);
return ERROR_FAIL;
}
const struct command_registration obj_commands[] = {
{
.name = hub->name,
.mode = COMMAND_EXEC,
.help = "IPDBG Hub command group.",
.usage = "",
.chain = ipdbg_hub_subcommand_handlers
},
COMMAND_REGISTRATION_DONE
};
return register_commands_with_data(CMD_CTX, NULL, obj_commands, hub);
}
static int ipdbg_create_hub(struct jtag_tap *tap, uint32_t user_instruction, uint8_t data_register_length,
struct ipdbg_virtual_ir_info *virtual_ir, const char *name, struct command_invocation *cmd)
{
struct ipdbg_hub *new_hub = ipdbg_allocate_hub(data_register_length, virtual_ir, name);
if (!new_hub)
return ERROR_FAIL;
if (virtual_ir)
buf_set_u32(new_hub->scratch_memory.vir_out_val, 0, virtual_ir->length, virtual_ir->value);
new_hub->tap = tap;
new_hub->user_instruction = user_instruction;
new_hub->data_register_length = data_register_length;
new_hub->valid_mask = BIT(data_register_length - 1);
new_hub->xoff_mask = BIT(data_register_length - 2);
new_hub->tool_mask = (new_hub->xoff_mask - 1) >> 8;
new_hub->last_dn_tool = new_hub->tool_mask;
new_hub->virtual_ir = virtual_ir;
new_hub->max_tools = ipdbg_max_tools_from_data_register_length(data_register_length);
int retval = ipdbg_register_hub_command(new_hub, cmd);
if (retval != ERROR_OK) {
LOG_ERROR("Creating hub failed");
ipdbg_free_hub(new_hub);
return ERROR_FAIL;
}
ipdbg_add_hub(new_hub);
return ERROR_OK;
}
COMMAND_HANDLER(handle_ipdbg_create_hub_command)
{
struct jtag_tap *tap = NULL;
uint32_t user_instruction = 0x00;
uint8_t data_register_length = IPDBG_MAX_DR_LENGTH;
bool start = true;
bool hub_configured = false;
bool has_virtual_ir = false;
uint32_t virtual_ir_instruction = 0x00e;
uint32_t virtual_ir_length = 5;
uint32_t virtual_ir_value = 0x11;
struct ipdbg_virtual_ir_info *virtual_ir = NULL;
int user_num = 1;
bool hub_configured = false;
if ((CMD_ARGC < IPDBG_MIN_NUM_OF_OPTIONS) || (CMD_ARGC > IPDBG_MAX_NUM_OF_OPTIONS))
if (CMD_ARGC < IPDBG_MIN_NUM_OF_CREATE_OPTIONS || CMD_ARGC > IPDBG_MAX_NUM_OF_CREATE_OPTIONS)
return ERROR_COMMAND_SYNTAX_ERROR;
for (unsigned int i = 0; i < CMD_ARGC; ++i) {
const char *hub_name = CMD_ARGV[0];
for (unsigned int i = 1; i < CMD_ARGC; ++i) {
if (strcmp(CMD_ARGV[i], "-tap") == 0) {
if (i + 1 >= CMD_ARGC || CMD_ARGV[i + 1][0] == '-') {
command_print(CMD, "no TAP given");
command_print(CMD, "no TAP name given");
return ERROR_FAIL;
}
tap = jtag_tap_by_string(CMD_ARGV[i + 1]);
@ -874,7 +1003,7 @@ COMMAND_HANDLER(handle_ipdbg_command)
return ERROR_FAIL;
}
++i;
} else if (strcmp(CMD_ARGV[i], "-hub") == 0) {
} else if (strcmp(CMD_ARGV[i], "-ir") == 0) {
COMMAND_PARSE_ADDITIONAL_NUMBER(u32, i, user_instruction, "ir_value to select hub");
hub_configured = true;
COMMAND_PARSE_OPTIONAL_NUMBER(u8, i, data_register_length);
@ -917,20 +1046,11 @@ COMMAND_HANDLER(handle_ipdbg_command)
COMMAND_PARSE_OPTIONAL_NUMBER(u32, i, virtual_ir_length);
COMMAND_PARSE_OPTIONAL_NUMBER(u32, i, virtual_ir_instruction);
has_virtual_ir = true;
} else if (strcmp(CMD_ARGV[i], "-port") == 0) {
COMMAND_PARSE_ADDITIONAL_NUMBER(u16, i, port, "port number");
} else if (strcmp(CMD_ARGV[i], "-tool") == 0) {
COMMAND_PARSE_ADDITIONAL_NUMBER(u8, i, tool, "tool");
} else if (strcmp(CMD_ARGV[i], "-stop") == 0) {
start = false;
} else if (strcmp(CMD_ARGV[i], "-start") == 0) {
start = true;
} else {
command_print(CMD, "Unknown argument: %s", CMD_ARGV[i]);
return ERROR_FAIL;
}
}
if (!tap) {
command_print(CMD, "no valid tap selected");
return ERROR_FAIL;
@ -941,8 +1061,8 @@ COMMAND_HANDLER(handle_ipdbg_command)
return ERROR_FAIL;
}
if (tool >= ipdbg_max_tools_from_data_register_length(data_register_length)) {
command_print(CMD, "Tool: %d is invalid", tool);
if (ipdbg_get_hub_by_name(hub_name)) {
LOG_ERROR("IPDBG hub with name '%s' already exists", hub_name);
return ERROR_FAIL;
}
@ -957,20 +1077,38 @@ COMMAND_HANDLER(handle_ipdbg_command)
virtual_ir->value = virtual_ir_value;
}
if (start)
return ipdbg_start(port, tap, user_instruction, data_register_length, virtual_ir, tool);
else
return ipdbg_stop(tap, user_instruction, virtual_ir, tool);
if (ipdbg_find_hub(tap, user_instruction, virtual_ir)) {
LOG_ERROR("IPDBG hub for given TAP and user-instruction already exists");
free(virtual_ir);
return ERROR_FAIL;
}
int retval = ipdbg_create_hub(tap, user_instruction, data_register_length, virtual_ir, hub_name, cmd);
if (retval != ERROR_OK)
free(virtual_ir);
return retval;
}
static const struct command_registration ipdbg_config_command_handlers[] = {
{
.name = "create-hub",
.mode = COMMAND_ANY,
.handler = handle_ipdbg_create_hub_command,
.help = "create a IPDBG Hub",
.usage = "name.ipdbghub (-tap device.tap -ir ir_value [dr_length] |"
" -pld name.pld [user]) [-vir [vir_value [length [instr_code]]]]",
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration ipdbg_command_handlers[] = {
{
.name = "ipdbg",
.handler = handle_ipdbg_command,
.mode = COMMAND_EXEC,
.help = "Starts or stops an IPDBG JTAG-Host server.",
.usage = "[-start|-stop] -tap device.tap -hub ir_value [dr_length]"
" [-port number] [-tool number] [-vir [vir_value [length [instr_code]]]]",
.mode = COMMAND_ANY,
.help = "IPDBG Hub/Host commands.",
.usage = "",
.chain = ipdbg_config_command_handlers,
},
COMMAND_REGISTRATION_DONE
};

View File

@ -7,5 +7,6 @@
#include <helper/command.h>
int ipdbg_register_commands(struct command_context *cmd_ctx);
int ipdbg_server_free(void);
#endif /* OPENOCD_IPDBG_IPDBG_H */

View File

@ -23,6 +23,7 @@
#include "openocd.h"
#include "tcl_server.h"
#include "telnet_server.h"
#include "ipdbg.h"
#include <signal.h>
@ -714,6 +715,7 @@ void server_free(void)
tcl_service_free();
telnet_service_free();
jsp_service_free();
ipdbg_server_free();
free(bindto_name);
}

View File

@ -17,7 +17,8 @@ source [find fpga/altera-cycloneiii.cfg]
#quartus_cpf --option=bitstream_compression=off -c output_files\cycloneiii_blinker.sof cycloneiii_blinker.rbf
#openocd -f board/bemicro_cycloneiii.cfg -c "init" -c "pld load cycloneiii.pld cycloneiii_blinker.rbf"
# "ipdbg -start -tap cycloneiii.tap -hub 0x00e -tool 0 -port 5555"
# "ipdbg create-hub cycloneiii.ipdbghub -tap cycloneiii.tap -ir 0x00e"
# "cycloneiii.ipdbghub ipdbg start -tool 0 -port 5555"
set JTAGSPI_CHAIN_ID cycloneiii.pld

View File

@ -15,7 +15,8 @@ adapter speed 10000
source [find cpld/xilinx-xc7.cfg]
# "ipdbg -start -tap xc7.tap -hub 0x02 -tool 0 -port 5555"
# "ipdbg create-hub xc7.ipdbghub -tap xc7.tap -ir 0x02"
# "xc7.ipdbghub ipdbg start -tool 0 -port 5555"
#openocd -f board/digilent_cmod_s7.cfg -c "init" -c "pld load xc7.pld shared_folder/cmod_s7_fast.bit"
set JTAGSPI_CHAIN_ID xc7.pld

View File

@ -16,7 +16,8 @@ adapter speed 6000
source [find fpga/lattice_ecp5.cfg]
#openocd -f board/ecp5_evaluation.cfg -c "init" -c "pld load ecp5.pld shared_folder/ecp5_blinker_impl1.bit"
#ipdbg -start -tap ecp5.tap -hub 0x32 -port 5555 -tool 0
#ipdbg create-hub ecp5.ipdbghub -tap ecp5.tap -ir 0x32
#ecp5.ipdbghub ipdbg start -tool 0 -port 5555
set JTAGSPI_CHAIN_ID ecp5.pld
source [find cpld/jtagspi.cfg]

View File

@ -16,4 +16,5 @@ source [find fpga/gowin_gw1n.cfg]
#openocd -f board/gowin_runber.cfg -c "init" -c "pld load 0 impl/pnr/gw1n_blinker.fs"
#ipdbg -start -tap gw1n.tap -hub 0x42 -port 5555 -tool 0
#ipdbg create-hub gw1n.ipdbghub -tap gw1n.tap -ir 0x42
#gw1n.ipdbghubipdbg start -tool 0 -port 5555

View File

@ -20,7 +20,8 @@ adapter speed 6000
source [find fpga/efinix_trion.cfg]
#openocd -f board/trion_t20_bga256.cfg -c "init" -c "pld load trion.pld outflow/trion_blinker.bit"
#ipdbg -start -tap trion.tap -hub 0x8 -port 5555 -tool 0
#ipdbg create-hub trion.ipdbghub -tap trion.tap -ir 0x8
#trion.ipdbghub ipdbg start -tool 0 -port 5555
set JTAGSPI_CHAIN_ID trion.pld
source [find cpld/jtagspi.cfg]