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. 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 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 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}}] @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}]]]}]
Starts or stops a IPDBG JTAG-Host server. Arguments can be specified in any order. @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: Command options:
@itemize @bullet @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{-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{-ir @var{ir_value}} states that the JTAG hub is
@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. reachable with dr-scans while the JTAG instruction register has the value @var{ir_value}. Also known as @verb{|USERx|} instructions.
@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. The optional @var{dr_length} is the length of the dr.
@item @option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]} On some devices, the user data-register is reachable if there is a Current JTAG-Hub implementation only supports dr_length=13, which is also the default value.
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{-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 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 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. 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 itemize
@end deffn @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. @deffn {Command} {$hub_name ipdbg stop} @option{-tool @var{number}}
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. Stops a IPDBG JTAG-Host server.
Command options:
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. @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.
The remaining options are described in the previous command. @end itemize
@end deffn @end deffn
Examples: Examples:
@example @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 @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). The connection is through the TAP of a Xilinx Spartan 6 on USER1 instruction (tested with a papillion pro board).
@example @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 @end example
Starts a server listening on tcp-port 60000 which connects to tool 1 (data_up_1/data_down_1). 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). 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 @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 @end example
Starts a server listening on tcp-port 5555 which connects to tool 0 (data_up_0/data_down_0). 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. 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 # END MIGRATION AIDS

View File

@ -15,8 +15,10 @@
#include "ipdbg.h" #include "ipdbg.h"
#define IPDBG_BUFFER_SIZE 16384 #define IPDBG_BUFFER_SIZE 16384
#define IPDBG_MIN_NUM_OF_OPTIONS 2 #define IPDBG_MIN_NUM_OF_CREATE_OPTIONS 3
#define IPDBG_MAX_NUM_OF_OPTIONS 14 #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_MIN_DR_LENGTH 11
#define IPDBG_MAX_DR_LENGTH 13 #define IPDBG_MAX_DR_LENGTH 13
#define IPDBG_TCP_PORT_STR_MAX_LENGTH 6 #define IPDBG_TCP_PORT_STR_MAX_LENGTH 6
@ -75,6 +77,7 @@ struct ipdbg_hub {
uint32_t xoff_mask; uint32_t xoff_mask;
uint32_t tool_mask; uint32_t tool_mask;
uint32_t last_dn_tool; uint32_t last_dn_tool;
char *name;
struct ipdbg_hub *next; struct ipdbg_hub *next;
struct jtag_tap *tap; struct jtag_tap *tap;
struct connection **connections; 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) for (ihub = ipdbg_first_hub; ihub->next; ihub = ihub->next)
; ;
ihub->next = hub; ihub->next = hub;
} else } else {
ipdbg_first_hub = hub; 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) 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; 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) 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; fields->check_mask = NULL;
@ -760,62 +751,18 @@ static const struct service_driver ipdbg_service_driver = {
.keep_client_alive_handler = NULL, .keep_client_alive_handler = NULL,
}; };
static int ipdbg_start(uint16_t port, struct jtag_tap *tap, uint32_t user_instruction, static struct ipdbg_hub *ipdbg_get_hub_by_name(const char *name)
uint8_t data_register_length, struct ipdbg_virtual_ir_info *virtual_ir, uint8_t tool)
{ {
LOG_INFO("starting ipdbg service on port %d for tool %d", port, tool); struct ipdbg_hub *hub = NULL;
for (hub = ipdbg_first_hub; hub; hub = hub->next) {
struct ipdbg_hub *hub = ipdbg_find_hub(tap, user_instruction, virtual_ir); if (strcmp(hub->name, name) == 0)
if (hub) { break;
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;
} }
return hub;
};
struct ipdbg_service *service = NULL; static int ipdbg_stop_service(struct ipdbg_service *service)
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)
{ {
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); int retval = ipdbg_remove_service(service);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
LOG_ERROR("BUG: ipdbg_remove_service failed"); 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"); LOG_ERROR("BUG: remove_service failed");
return retval; 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; 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; uint16_t port = 4242;
uint8_t tool = 1; 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; uint32_t user_instruction = 0x00;
uint8_t data_register_length = IPDBG_MAX_DR_LENGTH; uint8_t data_register_length = IPDBG_MAX_DR_LENGTH;
bool start = true;
bool hub_configured = false;
bool has_virtual_ir = false; bool has_virtual_ir = false;
uint32_t virtual_ir_instruction = 0x00e; uint32_t virtual_ir_instruction = 0x00e;
uint32_t virtual_ir_length = 5; uint32_t virtual_ir_length = 5;
uint32_t virtual_ir_value = 0x11; uint32_t virtual_ir_value = 0x11;
struct ipdbg_virtual_ir_info *virtual_ir = NULL; struct ipdbg_virtual_ir_info *virtual_ir = NULL;
int user_num = 1; 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; 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 (strcmp(CMD_ARGV[i], "-tap") == 0) {
if (i + 1 >= CMD_ARGC || CMD_ARGV[i + 1][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; return ERROR_FAIL;
} }
tap = jtag_tap_by_string(CMD_ARGV[i + 1]); tap = jtag_tap_by_string(CMD_ARGV[i + 1]);
@ -874,7 +1003,7 @@ COMMAND_HANDLER(handle_ipdbg_command)
return ERROR_FAIL; return ERROR_FAIL;
} }
++i; ++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"); COMMAND_PARSE_ADDITIONAL_NUMBER(u32, i, user_instruction, "ir_value to select hub");
hub_configured = true; hub_configured = true;
COMMAND_PARSE_OPTIONAL_NUMBER(u8, i, data_register_length); 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_length);
COMMAND_PARSE_OPTIONAL_NUMBER(u32, i, virtual_ir_instruction); COMMAND_PARSE_OPTIONAL_NUMBER(u32, i, virtual_ir_instruction);
has_virtual_ir = true; 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 { } else {
command_print(CMD, "Unknown argument: %s", CMD_ARGV[i]); command_print(CMD, "Unknown argument: %s", CMD_ARGV[i]);
return ERROR_FAIL; return ERROR_FAIL;
} }
} }
if (!tap) { if (!tap) {
command_print(CMD, "no valid tap selected"); command_print(CMD, "no valid tap selected");
return ERROR_FAIL; return ERROR_FAIL;
@ -941,8 +1061,8 @@ COMMAND_HANDLER(handle_ipdbg_command)
return ERROR_FAIL; return ERROR_FAIL;
} }
if (tool >= ipdbg_max_tools_from_data_register_length(data_register_length)) { if (ipdbg_get_hub_by_name(hub_name)) {
command_print(CMD, "Tool: %d is invalid", tool); LOG_ERROR("IPDBG hub with name '%s' already exists", hub_name);
return ERROR_FAIL; return ERROR_FAIL;
} }
@ -957,20 +1077,38 @@ COMMAND_HANDLER(handle_ipdbg_command)
virtual_ir->value = virtual_ir_value; virtual_ir->value = virtual_ir_value;
} }
if (start) if (ipdbg_find_hub(tap, user_instruction, virtual_ir)) {
return ipdbg_start(port, tap, user_instruction, data_register_length, virtual_ir, tool); LOG_ERROR("IPDBG hub for given TAP and user-instruction already exists");
else free(virtual_ir);
return ipdbg_stop(tap, user_instruction, virtual_ir, tool); 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[] = { static const struct command_registration ipdbg_command_handlers[] = {
{ {
.name = "ipdbg", .name = "ipdbg",
.handler = handle_ipdbg_command, .mode = COMMAND_ANY,
.mode = COMMAND_EXEC, .help = "IPDBG Hub/Host commands.",
.help = "Starts or stops an IPDBG JTAG-Host server.", .usage = "",
.usage = "[-start|-stop] -tap device.tap -hub ir_value [dr_length]" .chain = ipdbg_config_command_handlers,
" [-port number] [-tool number] [-vir [vir_value [length [instr_code]]]]",
}, },
COMMAND_REGISTRATION_DONE COMMAND_REGISTRATION_DONE
}; };

View File

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

View File

@ -23,6 +23,7 @@
#include "openocd.h" #include "openocd.h"
#include "tcl_server.h" #include "tcl_server.h"
#include "telnet_server.h" #include "telnet_server.h"
#include "ipdbg.h"
#include <signal.h> #include <signal.h>
@ -714,6 +715,7 @@ void server_free(void)
tcl_service_free(); tcl_service_free();
telnet_service_free(); telnet_service_free();
jsp_service_free(); jsp_service_free();
ipdbg_server_free();
free(bindto_name); 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 #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" #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 set JTAGSPI_CHAIN_ID cycloneiii.pld

View File

@ -15,7 +15,8 @@ adapter speed 10000
source [find cpld/xilinx-xc7.cfg] 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" #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 set JTAGSPI_CHAIN_ID xc7.pld

View File

@ -16,7 +16,8 @@ adapter speed 6000
source [find fpga/lattice_ecp5.cfg] 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" #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 set JTAGSPI_CHAIN_ID ecp5.pld
source [find cpld/jtagspi.cfg] 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" #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] source [find fpga/efinix_trion.cfg]
#openocd -f board/trion_t20_bga256.cfg -c "init" -c "pld load trion.pld outflow/trion_blinker.bit" #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 set JTAGSPI_CHAIN_ID trion.pld
source [find cpld/jtagspi.cfg] source [find cpld/jtagspi.cfg]