diff --git a/doc/openocd.texi b/doc/openocd.texi index ee67e7582..d99917e0d 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -8674,9 +8674,10 @@ The load command for the FPGA @var{pld_name} will use a length for the preload o @end deffn -@deffn {FPGA Driver} {efinix} +@deffn {FPGA Driver} {efinix} [@option{-family} ] Both families (Trion and Titanium) sold by Efinix are supported as both use the same protocol for In-System Configuration. This driver can be used to load the bitstream into the FPGA. +For the option @option{-family} @var{name} is one of @var{trion|titanium}. @end deffn @@ -11834,7 +11835,7 @@ In a session using JTAG for its transport protocol, OpenOCD supports the functio 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}. -@deffn {Command} {ipdbg} [@option{-start|-stop}] @option{-tap @var{tapname}} @option{-hub @var{ir_value} [@var{dr_length}]} [@option{-port @var{number}}] [@option{-tool @var{number}}] [@option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]}] +@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. Command options: @@ -11843,15 +11844,28 @@ Command options: @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 is listening. -@item @option{-tool @var{number}} number of the tool/feature. These corresponds to the ports "data_(up/down)_(0..6)" at the JtagHub. -@item @option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]} On some devices, the user data-register is only reachable if there is a +@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 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. @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. +@end deffn Examples: @example @@ -11866,6 +11880,13 @@ ipdbg -start -tap 10m50.tap -hub 0x00C -vir -port 60000 -tool 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). +@example +ipdbg -start -pld xc7.pld -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. + + @node Utility Commands @chapter Utility Commands @cindex Utility Commands diff --git a/src/pld/efinix.c b/src/pld/efinix.c index 370f18426..8350cb1a2 100644 --- a/src/pld/efinix.c +++ b/src/pld/efinix.c @@ -16,13 +16,29 @@ #define PROGRAM 0x4 #define ENTERUSER 0x7 +#define USER1 0x8 +#define USER2 0x9 +#define USER3 0xa +#define USER4 0xb + +enum efinix_family_e { + EFINIX_TRION, + EFINIX_TITANIUM, + EFINIX_UNKNOWN +}; #define TRAILING_ZEROS 4000 #define RUNTEST_START_CYCLES 100 #define RUNTEST_FINISH_CYCLES 100 +struct efinix_device { + uint32_t idcode; + int num_user; +}; + struct efinix_pld_device { struct jtag_tap *tap; + enum efinix_family_e family; }; static int efinix_read_bit_file(struct raw_bit_file *bit_file, const char *filename) @@ -188,9 +204,54 @@ static int efinix_load(struct pld_device *pld_device, const char *filename) return retval; } +static int efinix_get_ipdbg_hub(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub) +{ + if (!pld_device) + return ERROR_FAIL; + + struct efinix_pld_device *pld_device_info = pld_device->driver_priv; + + if (!pld_device_info || !pld_device_info->tap) + return ERROR_FAIL; + + hub->tap = pld_device_info->tap; + + if (pld_device_info->family == EFINIX_UNKNOWN) { + LOG_ERROR("family unknown, please specify for 'pld create'"); + return ERROR_FAIL; + } + int num_user = 2; /* trion */ + if (pld_device_info->family == EFINIX_TITANIUM) + num_user = 4; + + if (user_num > num_user) { + LOG_ERROR("Devices has only user register 1 to %d", num_user); + return ERROR_FAIL; + } + + switch (user_num) { + case 1: + hub->user_ir_code = USER1; + break; + case 2: + hub->user_ir_code = USER2; + break; + case 3: + hub->user_ir_code = USER3; + break; + case 4: + hub->user_ir_code = USER4; + break; + default: + LOG_ERROR("efinix devices only have user register 1 to %d", num_user); + return ERROR_FAIL; + } + return ERROR_OK; +} + PLD_CREATE_COMMAND_HANDLER(efinix_pld_create_command) { - if (CMD_ARGC != 4) + if (CMD_ARGC != 4 && CMD_ARGC != 6) return ERROR_COMMAND_SYNTAX_ERROR; if (strcmp(CMD_ARGV[2], "-chain-position") != 0) @@ -202,12 +263,28 @@ PLD_CREATE_COMMAND_HANDLER(efinix_pld_create_command) return ERROR_FAIL; } + enum efinix_family_e family = EFINIX_UNKNOWN; + if (CMD_ARGC == 6) { + if (strcmp(CMD_ARGV[4], "-family") != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (strcmp(CMD_ARGV[5], "trion") == 0) { + family = EFINIX_TRION; + } else if (strcmp(CMD_ARGV[5], "titanium") == 0) { + family = EFINIX_TITANIUM; + } else { + command_print(CMD, "unknown family"); + return ERROR_FAIL; + } + } + struct efinix_pld_device *efinix_info = malloc(sizeof(struct efinix_pld_device)); if (!efinix_info) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } efinix_info->tap = tap; + efinix_info->family = family; pld->driver_priv = efinix_info; @@ -218,4 +295,5 @@ struct pld_driver efinix_pld = { .name = "efinix", .pld_create_command = &efinix_pld_create_command, .load = &efinix_load, + .get_ipdbg_hub = efinix_get_ipdbg_hub, }; diff --git a/src/pld/gowin.c b/src/pld/gowin.c index ab3582c4c..c42b2f22c 100644 --- a/src/pld/gowin.c +++ b/src/pld/gowin.c @@ -29,6 +29,9 @@ #define ERASE_FLASH 0x75 #define ENABLE_2ND_FLASH 0x78 +#define USER1 0x42 +#define USER2 0x43 + #define STAUS_MASK_MEMORY_ERASE BIT(5) #define STAUS_MASK_SYSTEM_EDIT_MODE BIT(7) @@ -449,6 +452,29 @@ static int gowin_reload_command(struct pld_device *pld_device) return gowin_reload(gowin_info->tap); } +static int gowin_get_ipdbg_hub(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub) +{ + if (!pld_device) + return ERROR_FAIL; + + struct gowin_pld_device *pld_device_info = pld_device->driver_priv; + + if (!pld_device_info || !pld_device_info->tap) + return ERROR_FAIL; + + hub->tap = pld_device_info->tap; + + if (user_num == 1) { + hub->user_ir_code = USER1; + } else if (user_num == 2) { + hub->user_ir_code = USER2; + } else { + LOG_ERROR("gowin devices only have user register 1 & 2"); + return ERROR_FAIL; + } + return ERROR_OK; +} + COMMAND_HANDLER(gowin_read_status_command_handler) { if (CMD_ARGC != 1) @@ -568,4 +594,5 @@ struct pld_driver gowin_pld = { .commands = gowin_command_handler, .pld_create_command = &gowin_pld_create_command, .load = &gowin_load_to_sram, + .get_ipdbg_hub = gowin_get_ipdbg_hub, }; diff --git a/src/pld/intel.c b/src/pld/intel.c index 92a790b54..e5c927306 100644 --- a/src/pld/intel.c +++ b/src/pld/intel.c @@ -18,6 +18,8 @@ #include "raw_bit.h" #define BYPASS 0x3FF +#define USER0 0x00C +#define USER1 0x00E enum intel_family_e { INTEL_CYCLONEIII, @@ -337,6 +339,29 @@ static int intel_load(struct pld_device *pld_device, const char *filename) return jtag_execute_queue(); } +static int intel_get_ipdbg_hub(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub) +{ + if (!pld_device) + return ERROR_FAIL; + + struct intel_pld_device *pld_device_info = pld_device->driver_priv; + + if (!pld_device_info || !pld_device_info->tap) + return ERROR_FAIL; + + hub->tap = pld_device_info->tap; + + if (user_num == 0) { + hub->user_ir_code = USER0; + } else if (user_num == 1) { + hub->user_ir_code = USER1; + } else { + LOG_ERROR("intel devices only have user register 0 & 1"); + return ERROR_FAIL; + } + return ERROR_OK; +} + COMMAND_HANDLER(intel_set_bscan_command_handler) { unsigned int boundary_scan_length; @@ -472,4 +497,5 @@ struct pld_driver intel_pld = { .commands = intel_command_handler, .pld_create_command = &intel_pld_create_command, .load = &intel_load, + .get_ipdbg_hub = intel_get_ipdbg_hub, }; diff --git a/src/pld/lattice.c b/src/pld/lattice.c index 63d730677..2075f4490 100644 --- a/src/pld/lattice.c +++ b/src/pld/lattice.c @@ -18,6 +18,9 @@ #include "certus.h" #define PRELOAD 0x1C +#define USER1 0x32 +#define USER2 0x38 + struct lattice_devices_elem { uint32_t id; @@ -316,6 +319,29 @@ static int lattice_load_command(struct pld_device *pld_device, const char *filen return retval; } +int lattice_get_ipdbg_hub(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub) +{ + if (!pld_device) + return ERROR_FAIL; + + struct lattice_pld_device *pld_device_info = pld_device->driver_priv; + + if (!pld_device_info || !pld_device_info->tap) + return ERROR_FAIL; + + hub->tap = pld_device_info->tap; + + if (user_num == 1) { + hub->user_ir_code = USER1; + } else if (user_num == 2) { + hub->user_ir_code = USER2; + } else { + LOG_ERROR("lattice devices only have user register 1 & 2"); + return ERROR_FAIL; + } + return ERROR_OK; +} + PLD_CREATE_COMMAND_HANDLER(lattice_pld_create_command) { if (CMD_ARGC != 4 && CMD_ARGC != 6) @@ -524,4 +550,5 @@ struct pld_driver lattice_pld = { .commands = lattice_command_handler, .pld_create_command = &lattice_pld_create_command, .load = &lattice_load_command, + .get_ipdbg_hub = lattice_get_ipdbg_hub, }; diff --git a/src/pld/pld.h b/src/pld/pld.h index 8a2a11831..b736e6ae2 100644 --- a/src/pld/pld.h +++ b/src/pld/pld.h @@ -15,11 +15,17 @@ struct pld_device; #define __PLD_CREATE_COMMAND(name) \ COMMAND_HELPER(name, struct pld_device *pld) +struct pld_ipdbg_hub { + struct jtag_tap *tap; + unsigned int user_ir_code; +}; + struct pld_driver { const char *name; __PLD_CREATE_COMMAND((*pld_create_command)); const struct command_registration *commands; int (*load)(struct pld_device *pld_device, const char *filename); + int (*get_ipdbg_hub)(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub); }; #define PLD_CREATE_COMMAND_HANDLER(name) \ diff --git a/src/pld/virtex2.c b/src/pld/virtex2.c index 9007a55d2..a97c7c6d6 100644 --- a/src/pld/virtex2.c +++ b/src/pld/virtex2.c @@ -306,6 +306,26 @@ COMMAND_HANDLER(virtex2_handle_read_stat_command) return ERROR_OK; } +static int xilinx_get_ipdbg_hub(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub) +{ + if (!pld_device) + return ERROR_FAIL; + + struct virtex2_pld_device *pld_device_info = pld_device->driver_priv; + + if (!pld_device_info || !pld_device_info->tap) + return ERROR_FAIL; + + hub->tap = pld_device_info->tap; + if (user_num < 1 || (unsigned int)user_num > pld_device_info->command_set.num_user) { + LOG_ERROR("device has only user register 1 to %d", pld_device_info->command_set.num_user); + return ERROR_FAIL; + } + + hub->user_ir_code = pld_device_info->command_set.user[user_num - 1]; + return ERROR_OK; +} + COMMAND_HANDLER(virtex2_handle_set_instuction_codes_command) { if (CMD_ARGC < 6 || CMD_ARGC > (6 + VIRTEX2_MAX_USER_INSTRUCTIONS)) @@ -439,4 +459,5 @@ struct pld_driver virtex2_pld = { .commands = virtex2_command_handler, .pld_create_command = &virtex2_pld_create_command, .load = &virtex2_load, + .get_ipdbg_hub = xilinx_get_ipdbg_hub, }; diff --git a/src/server/ipdbg.c b/src/server/ipdbg.c index 69d0f5755..3fae0a98d 100644 --- a/src/server/ipdbg.c +++ b/src/server/ipdbg.c @@ -10,11 +10,12 @@ #include #include #include +#include #include "ipdbg.h" #define IPDBG_BUFFER_SIZE 16384 -#define IPDBG_MIN_NUM_OF_OPTIONS 4 +#define IPDBG_MIN_NUM_OF_OPTIONS 2 #define IPDBG_MAX_NUM_OF_OPTIONS 14 #define IPDBG_MIN_DR_LENGTH 11 #define IPDBG_MAX_DR_LENGTH 13 @@ -716,6 +717,7 @@ COMMAND_HANDLER(handle_ipdbg_command) uint32_t virtual_ir_length = 5; uint32_t virtual_ir_value = 0x11; struct ipdbg_virtual_ir_info *virtual_ir = NULL; + int user_num = 1; if ((CMD_ARGC < IPDBG_MIN_NUM_OF_OPTIONS) || (CMD_ARGC > IPDBG_MAX_NUM_OF_OPTIONS)) return ERROR_COMMAND_SYNTAX_ERROR; @@ -742,6 +744,34 @@ COMMAND_HANDLER(handle_ipdbg_command) IPDBG_MIN_DR_LENGTH, IPDBG_MAX_DR_LENGTH); return ERROR_FAIL; } + } else if (strcmp(CMD_ARGV[i], "-pld") == 0) { + ++i; + if (i >= CMD_ARGC || CMD_ARGV[i][0] == '-') + return ERROR_COMMAND_SYNTAX_ERROR; + struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[i]); + if (!device || !device->driver) { + command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[i]); + return ERROR_FAIL; + } + COMMAND_PARSE_OPTIONAL_NUMBER(int, i, user_num); + struct pld_ipdbg_hub pld_hub; + struct pld_driver *driver = device->driver; + if (!driver->get_ipdbg_hub) { + command_print(CMD, "pld driver has no ipdbg support"); + return ERROR_FAIL; + } + if (driver->get_ipdbg_hub(user_num, device, &pld_hub) != ERROR_OK) { + command_print(CMD, "unable to retrieve hub from pld driver"); + return ERROR_FAIL; + } + if (!pld_hub.tap) { + command_print(CMD, "no tap received from pld driver"); + return ERROR_FAIL; + } + hub_configured = true; + user_instruction = pld_hub.user_ir_code; + tap = pld_hub.tap; + } else if (strcmp(CMD_ARGV[i], "-vir") == 0) { COMMAND_PARSE_OPTIONAL_NUMBER(u32, i, virtual_ir_value); COMMAND_PARSE_OPTIONAL_NUMBER(u32, i, virtual_ir_length); diff --git a/tcl/fpga/efinix_titanium.cfg b/tcl/fpga/efinix_titanium.cfg index 8b356cb85..3c2cdd71f 100644 --- a/tcl/fpga/efinix_titanium.cfg +++ b/tcl/fpga/efinix_titanium.cfg @@ -20,4 +20,4 @@ jtag newtap $_CHIPNAME tap -irlen 5 -ignore-version \ -expected-id 0x00680A79 \ -expected-id 0x00684A79 -pld create $_CHIPNAME.pld efinix -chain-position $_CHIPNAME.tap +pld create $_CHIPNAME.pld efinix -chain-position $_CHIPNAME.tap -family titanium diff --git a/tcl/fpga/efinix_trion.cfg b/tcl/fpga/efinix_trion.cfg index 2b50d8c5d..1c789f564 100644 --- a/tcl/fpga/efinix_trion.cfg +++ b/tcl/fpga/efinix_trion.cfg @@ -14,4 +14,4 @@ jtag newtap $_CHIPNAME tap -irlen 4 -ignore-version \ -expected-id 0x00240A79 \ -expected-id 0x00220A79 -pld create $_CHIPNAME.pld efinix -chain-position $_CHIPNAME.tap +pld create $_CHIPNAME.pld efinix -chain-position $_CHIPNAME.tap -family trion