ipdbg/pld: ipdbg can get tap and hub/ir from pld driver. 69/7369/21
authorDaniel Anselmi <danselmi@gmx.ch>
Fri, 14 Apr 2023 23:13:12 +0000 (01:13 +0200)
committerAntonio Borneo <borneo.antonio@gmail.com>
Sat, 8 Jul 2023 18:04:24 +0000 (18:04 +0000)
To start a ipdbg server one needs to know the tap and the
instruction code to reach the IPDBG-Hub. This instruction is
vendor/family specific. Knowledge which can be provided by the
pld driver.

Change-Id: I13eeb9fee895d65cd48544da4704fcc9b528b869
Signed-off-by: Daniel Anselmi <danselmi@gmx.ch>
Reviewed-on: https://review.openocd.org/c/openocd/+/7369
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
doc/openocd.texi
src/pld/efinix.c
src/pld/gowin.c
src/pld/intel.c
src/pld/lattice.c
src/pld/pld.h
src/pld/virtex2.c
src/server/ipdbg.c
tcl/fpga/efinix_titanium.cfg
tcl/fpga/efinix_trion.cfg

index ee67e7582ad5bec6cd868c90586d7f5e1ad20158..d99917e0d69c98b05071de78db487a47b1072473 100644 (file)
@@ -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} <name>]
 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
index 370f1842619dd427019e8c5f33679fbc94ab3357..8350cb1a2466c6f5465d189d26b94482896851cc 100644 (file)
 
 #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,
 };
index ab3582c4c512cc5f79429f9242f1ecab4258cda1..c42b2f22c9f5ebbcefe908b18fc3a33aadedf9e2 100644 (file)
@@ -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,
 };
index 92a790b547d1089747f3ef88b789ef7a0ce50b8f..e5c9273069c2677c9c033691200be47aef890e7f 100644 (file)
@@ -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,
 };
index 63d730677adeb6f752fdb001a00f279d712716c3..2075f4490d732e5861a4a16b07e6f2afa8ccf3df 100644 (file)
@@ -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,
 };
index 8a2a11831955b3acfd7a9180f911fee2fbf2f19b..b736e6ae200085b8fbadfca25815e3142cc4c95a 100644 (file)
@@ -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) \
index 9007a55d270a660d5a24f24bc698678b8818c5ce..a97c7c6d68f86cba1e5266b3592088172d089928 100644 (file)
@@ -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,
 };
index 69d0f57553d775746fd4e2b06c8f77294ead0f04..3fae0a98d80e993821e5a7e5bb8be6dee190a5aa 100644 (file)
 #include <jtag/jtag.h>
 #include <server/server.h>
 #include <target/target.h>
+#include <pld/pld.h>
 
 #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);
index 8b356cb853ab53741b40c6dcfcfa857dc123d714..3c2cdd71f7545b4f953568a7f65084ac21347465 100644 (file)
@@ -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
index 2b50d8c5dcfe3ce6e404cbe0d42e6f2f0efce4f2..1c789f564269dc138b713041405476b93a16b19e 100644 (file)
@@ -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

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)