diff --git a/doc/openocd.texi b/doc/openocd.texi index bf4e0ad65..651cc53bb 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -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. diff --git a/src/jtag/startup.tcl b/src/jtag/startup.tcl index 4eca67771..41db38e4a 100644 --- a/src/jtag/startup.tcl +++ b/src/jtag/startup.tcl @@ -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 diff --git a/src/server/ipdbg.c b/src/server/ipdbg.c index 073323032..e218b8244 100644 --- a/src/server/ipdbg.c +++ b/src/server/ipdbg.c @@ -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 }; diff --git a/src/server/ipdbg.h b/src/server/ipdbg.h index 6b7054584..1f4156b7a 100644 --- a/src/server/ipdbg.h +++ b/src/server/ipdbg.h @@ -7,5 +7,6 @@ #include int ipdbg_register_commands(struct command_context *cmd_ctx); +int ipdbg_server_free(void); #endif /* OPENOCD_IPDBG_IPDBG_H */ diff --git a/src/server/server.c b/src/server/server.c index 2be90451f..0649ec942 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -23,6 +23,7 @@ #include "openocd.h" #include "tcl_server.h" #include "telnet_server.h" +#include "ipdbg.h" #include @@ -714,6 +715,7 @@ void server_free(void) tcl_service_free(); telnet_service_free(); jsp_service_free(); + ipdbg_server_free(); free(bindto_name); } diff --git a/tcl/board/bemicro_cycloneiii.cfg b/tcl/board/bemicro_cycloneiii.cfg index bd1459adc..3c92b500c 100644 --- a/tcl/board/bemicro_cycloneiii.cfg +++ b/tcl/board/bemicro_cycloneiii.cfg @@ -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 diff --git a/tcl/board/digilent_cmod_s7.cfg b/tcl/board/digilent_cmod_s7.cfg index c52ee9505..4fa45a17a 100644 --- a/tcl/board/digilent_cmod_s7.cfg +++ b/tcl/board/digilent_cmod_s7.cfg @@ -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 diff --git a/tcl/board/ecp5_evaluation.cfg b/tcl/board/ecp5_evaluation.cfg index dd663f79d..71769f607 100644 --- a/tcl/board/ecp5_evaluation.cfg +++ b/tcl/board/ecp5_evaluation.cfg @@ -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] diff --git a/tcl/board/gowin_runber.cfg b/tcl/board/gowin_runber.cfg index 9496c6f00..6cb07362b 100644 --- a/tcl/board/gowin_runber.cfg +++ b/tcl/board/gowin_runber.cfg @@ -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 diff --git a/tcl/board/trion_t20_bga256.cfg b/tcl/board/trion_t20_bga256.cfg index dc76d3910..ca44f0b8c 100644 --- a/tcl/board/trion_t20_bga256.cfg +++ b/tcl/board/trion_t20_bga256.cfg @@ -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]