This is an automated email from Gerrit.

"Daniel Anselmi <danse...@gmx.ch>" just uploaded a new patch set to Gerrit, 
which you can find at https://review.openocd.org/c/openocd/+/7396

-- gerrit

commit 266bfcf737cd02d7afeb8d0ac6c6f431cbed3366
Author: Daniel Anselmi <danse...@gmx.ch>
Date:   Mon Dec 12 09:49:51 2022 +0100

    pld: add support for lattice ecp2 and ecp3 devices
    
    Change-Id: I29c227c37be464f7ecc97a30d9cf3da1442e2b7f
    Signed-off-by: Daniel Anselmi <danse...@gmx.ch>

diff --git a/doc/openocd.texi b/doc/openocd.texi
index d8a5e86b42..e8fcecc413 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -8491,13 +8491,43 @@ openocd -f board/digilent_zedboard.cfg -c "init" \
 @end example
 
 
-
 @deffn {Command} {virtex2 read_stat} num
 Reads and displays the Virtex-II status register (STAT)
 for FPGA @var{num}.
 @end deffn
 @end deffn
 
+
+
+@deffn {FPGA Driver} {lattice} [family]
+The FGPA families ECP2 and ECP3 by Lattice are supported.
+This driver can be used to load the bitstream into the FPGA or read the status 
register and read/write the usercode register.
+
+The option @option{family} is one of @var{ecp2 ecp3}. This is needed when the 
JTAG ID of the device is not known by openocd (newer NX devices).
+
+@deffn {Command} {lattice read_status} num
+Reads and displays the status register
+for FPGA @var{num}.
+@end deffn
+
+@deffn {Command} {lattice read_user} num
+Reads and displays the user register
+for FPGA @var{num}.
+@end deffn
+
+@deffn {Command} {lattice write_user} num val
+Writes the user register.
+for FPGA @var{num} with value @var{val}.
+@end deffn
+
+@deffn {Command} {lattice set_preload} num length
+Set the length of the register for the preload. This is needed when the JTAG 
ID of the device is not known by openocd (newer NX devices).
+The load command for the FPGA @var{num} will use a length for the preload of 
@var{length}.
+@end deffn
+@end deffn
+
+
+
 @node General Commands
 @chapter General Commands
 @cindex commands
diff --git a/src/pld/Makefile.am b/src/pld/Makefile.am
index 14786afbfc..7cff09e151 100644
--- a/src/pld/Makefile.am
+++ b/src/pld/Makefile.am
@@ -2,9 +2,17 @@
 
 noinst_LTLIBRARIES += %D%/libpld.la
 %C%_libpld_la_SOURCES = \
+       %D%/ecp2_3.c \
+       %D%/lattice.c \
+       %D%/lattice_bit.c \
        %D%/pld.c \
+       %D%/raw_bit.c \
        %D%/xilinx_bit.c \
        %D%/virtex2.c \
+       %D%/ecp2_3.h \
+       %D%/lattice.h \
+       %D%/lattice_bit.h \
        %D%/pld.h \
+       %D%/raw_bit.h \
        %D%/xilinx_bit.h \
        %D%/virtex2.h
diff --git a/src/pld/ecp2_3.c b/src/pld/ecp2_3.c
new file mode 100644
index 0000000000..3172dff747
--- /dev/null
+++ b/src/pld/ecp2_3.c
@@ -0,0 +1,224 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ *   Copyright (C) 2022 by Daniel Anselmi                                  *
+ *   danse...@gmx.ch                                                       *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "lattice.h"
+
+#define LSCC_REFRESH         0x23
+#define ISC_ENABLE           0x15
+#define LSCC_RESET_ADDRESS   0x21
+#define ISC_PROGRAM_USERCODE 0x1A
+#define ISC_ERASE            0x03
+#define READ_USERCODE        0x17
+#define ISC_DISABLE          0x1E
+#define BYPASS               0xFF
+#define LSCC_READ_STATUS     0x53
+#define LSCC_BITSTREAM_BURST 0x02
+
+#define STATUS_DONE_BIT        0x00020000
+#define STATUS_ERROR_BITS_ECP2 0x00040003
+#define STATUS_ERROR_BITS_ECP3 0x00040007
+#define REGISTER_ALL_BITS_1    0xffffffff
+#define REGISTER_ALL_BITS_0    0x00000000
+
+int lattice_ecp2_3_read_status(struct jtag_tap *tap, uint32_t *status, 
uint32_t out, bool do_idle)
+{
+       return lattice_read_u32_register(tap, LSCC_READ_STATUS, status, out, 
do_idle);
+}
+
+int lattice_ecp2_3_read_usercode(struct jtag_tap *tap, uint32_t *usercode, 
uint32_t out)
+{
+       return lattice_read_u32_register(tap, READ_USERCODE, usercode, out, 
false);
+}
+
+int lattice_ecp2_3_write_usercode(struct lattice_pld_device *lattice_device, 
uint32_t usercode)
+{
+       struct jtag_tap *tap = lattice_device->tap;
+       if (!tap)
+               return ERROR_FAIL;
+
+       struct scan_field field;
+       uint8_t buffer[4];
+
+       lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE);
+       jtag_add_runtest(5, TAP_IDLE);
+       jtag_add_sleep(20000);
+
+       lattice_set_instr(tap, ISC_PROGRAM_USERCODE, TAP_IDLE);
+
+       h_u32_to_le(buffer, usercode);
+       field.num_bits = 32;
+       field.out_value = buffer;
+       field.in_value = NULL;
+       jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+       jtag_add_runtest(5, TAP_IDLE);
+       jtag_add_sleep(2000);
+
+       lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE);
+       jtag_add_runtest(5, TAP_IDLE);
+       jtag_add_sleep(200000);
+
+       int retval = jtag_execute_queue();
+       if (retval != ERROR_OK)
+               return retval;
+       return lattice_verify_usercode(lattice_device, 0x0, usercode, 
REGISTER_ALL_BITS_1);
+}
+
+static int lattice_ecp2_3_erase_device(struct lattice_pld_device 
*lattice_device)
+{
+       struct jtag_tap *tap = lattice_device->tap;
+       if (!tap)
+               return ERROR_FAIL;
+
+       struct scan_field field;
+       uint8_t buffer[4] = {0xff, 0xff, 0xff, 0xff};
+
+       /* program user code with all bits set */
+       lattice_set_instr(tap, ISC_PROGRAM_USERCODE, TAP_IRPAUSE);
+       field.num_bits = 32;
+       field.out_value = buffer;
+       field.in_value = NULL;
+       jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+       jtag_add_runtest(5, TAP_IDLE);
+       jtag_add_sleep(2000);
+
+       /* verify every bit is set */
+       const uint32_t out = REGISTER_ALL_BITS_1;
+       const uint32_t mask = REGISTER_ALL_BITS_1;
+       const uint32_t expected_pre = REGISTER_ALL_BITS_1;
+       int retval = lattice_verify_usercode(lattice_device, out, expected_pre, 
mask);
+       if (retval != ERROR_OK)
+               return retval;
+
+       lattice_set_instr(tap, ISC_ERASE, TAP_IDLE);
+       jtag_add_runtest(5, TAP_IDLE);
+       if (lattice_device->family == ecp2)
+               jtag_add_sleep(100000);
+       else
+               jtag_add_sleep(2000000);
+
+       lattice_set_instr(tap, LSCC_RESET_ADDRESS, TAP_IDLE);
+       jtag_add_runtest(5, TAP_IDLE);
+       jtag_add_sleep(2000);
+
+       /* after erasing check all bits in user register are cleared */
+       const uint32_t expected_post = REGISTER_ALL_BITS_0;
+       return lattice_verify_usercode(lattice_device, out, expected_post, 
mask);
+}
+
+static int lattice_ecp2_3_program_config_map(struct lattice_pld_device 
*lattice_device,
+                                                                               
        struct lattice_bit_file *bit_file)
+{
+       struct jtag_tap *tap = lattice_device->tap;
+       if (!tap)
+               return ERROR_FAIL;
+
+       struct scan_field field;
+       lattice_set_instr(tap, LSCC_RESET_ADDRESS, TAP_IDLE);
+       jtag_add_runtest(5, TAP_IDLE);
+       jtag_add_sleep(2000);
+       lattice_set_instr(tap, LSCC_BITSTREAM_BURST, TAP_IDLE);
+       field.num_bits = (bit_file->raw_bit.length - bit_file->offset) * 8;
+       field.out_value = bit_file->raw_bit.data + bit_file->offset;
+       field.in_value = NULL;
+       jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+       jtag_add_runtest(256, TAP_IDLE);
+       jtag_add_sleep(2000);
+       return jtag_execute_queue();
+}
+
+static int lattice_ecp2_3_exit_programming_mode(struct lattice_pld_device 
*lattice_device)
+{
+       struct jtag_tap *tap = lattice_device->tap;
+       if (!tap)
+               return ERROR_FAIL;
+
+       lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE);
+       jtag_add_runtest(5, TAP_IDLE);
+       jtag_add_sleep(200000);
+       lattice_set_instr(tap, BYPASS, TAP_IDLE);
+       jtag_add_runtest(100, TAP_IDLE);
+       jtag_add_sleep(1000);
+       return jtag_execute_queue();
+}
+
+int lattice_ecp2_load(struct lattice_pld_device *lattice_device, struct 
lattice_bit_file *bit_file)
+{
+       struct jtag_tap *tap = lattice_device->tap;
+       if (!tap)
+               return ERROR_FAIL;
+
+       int retval = lattice_preload(lattice_device);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* Enable the programming mode */
+       lattice_set_instr(tap, LSCC_REFRESH, TAP_IDLE);
+       lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE);
+       jtag_add_runtest(5, TAP_IDLE);
+       jtag_add_sleep(20000);
+
+       /* Erase the device */
+       retval = lattice_ecp2_3_erase_device(lattice_device);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* Program Fuse Map */
+       retval = lattice_ecp2_3_program_config_map(lattice_device, bit_file);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = lattice_ecp2_3_exit_programming_mode(lattice_device);
+       if (retval != ERROR_OK)
+               return retval;
+
+       const uint32_t out = REGISTER_ALL_BITS_1;
+       const uint32_t mask = STATUS_DONE_BIT | STATUS_ERROR_BITS_ECP2;
+       const uint32_t expected = STATUS_DONE_BIT;
+       return lattice_verify_status_register_u32(lattice_device, out, 
expected, mask, false);
+}
+
+int lattice_ecp3_load(struct lattice_pld_device *lattice_device, struct 
lattice_bit_file *bit_file)
+{
+       struct jtag_tap *tap = lattice_device->tap;
+       if (!tap)
+               return ERROR_FAIL;
+
+       /* Program Bscan register */
+       int retval = lattice_preload(lattice_device);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* Enable the programming mode */
+       lattice_set_instr(tap, LSCC_REFRESH, TAP_IDLE);
+       jtag_add_runtest(5, TAP_IDLE);
+       jtag_add_sleep(500000);
+       lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE);
+       jtag_add_runtest(5, TAP_IDLE);
+       jtag_add_sleep(20000);
+
+       retval = lattice_ecp2_3_erase_device(lattice_device);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* Program Fuse Map */
+       retval = lattice_ecp2_3_program_config_map(lattice_device, bit_file);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = lattice_ecp2_3_exit_programming_mode(lattice_device);
+       if (retval != ERROR_OK)
+               return retval;
+
+       const uint32_t out = REGISTER_ALL_BITS_1;
+       const uint32_t mask = STATUS_DONE_BIT | STATUS_ERROR_BITS_ECP3;
+       const uint32_t expected = STATUS_DONE_BIT;
+       return lattice_verify_status_register_u32(lattice_device, out, 
expected, mask, false);
+}
diff --git a/src/pld/ecp2_3.h b/src/pld/ecp2_3.h
new file mode 100644
index 0000000000..5f3e9e97b3
--- /dev/null
+++ b/src/pld/ecp2_3.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ *   Copyright (C) 2022 by Daniel Anselmi                                  *
+ *   danse...@gmx.ch                                                       *
+ ***************************************************************************/
+
+#ifndef OPENOCD_PLD_ECP2_3_H
+#define OPENOCD_PLD_ECP2_3_H
+
+#include "lattice.h"
+
+int lattice_ecp2_3_read_status(struct jtag_tap *tap, uint32_t *status, 
uint32_t out, bool do_idle);
+int lattice_ecp2_3_read_usercode(struct jtag_tap *tap, uint32_t *usercode, 
uint32_t out);
+int lattice_ecp2_3_write_usercode(struct lattice_pld_device *lattice_device, 
uint32_t usercode);
+int lattice_ecp2_load(struct lattice_pld_device *lattice_device, struct 
lattice_bit_file *bit_file);
+int lattice_ecp3_load(struct lattice_pld_device *lattice_device, struct 
lattice_bit_file *bit_file);
+
+#endif /* OPENOCD_PLD_ECP2_3_H */
diff --git a/src/pld/lattice.c b/src/pld/lattice.c
new file mode 100644
index 0000000000..a612a5463a
--- /dev/null
+++ b/src/pld/lattice.c
@@ -0,0 +1,426 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ *   Copyright (C) 2022 by Daniel Anselmi                                  *
+ *   danse...@gmx.ch                                                       *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "lattice.h"
+#include <jtag/jtag.h>
+#include "pld.h"
+#include "lattice_bit.h"
+#include "ecp2_3.h"
+
+#define PRELOAD              0x1C
+
+struct lattice_devices_elem {
+       uint32_t id;
+       size_t preload_length;
+       enum family_e family;
+};
+
+static const struct lattice_devices_elem lattice_devices[] = {
+       {0x01270043,  654, ecp2 /* ecp2-6e */},
+       {0x01271043,  643, ecp2 /* ecp2-12e */},
+       {0x01272043,  827, ecp2 /* ecp2-20e */},
+       {0x01274043, 1011, ecp2 /* ecp2-35e */},
+       {0x01273043, 1219, ecp2 /* ecp2-50e */},
+       {0x01275043,  654, ecp2 /* ecp2-70e */},
+       {0x01279043,  680, ecp2 /* ecp2m20e */},
+       {0x0127A043,  936, ecp2 /* ecp2m35e */},
+       {0x0127B043, 1056, ecp2 /* ecp2m50e */},
+       {0x0127C043, 1039, ecp2 /* ecp2m70e */},
+       {0x0127D043, 1311, ecp2 /* ecp2m100e */},
+       {0x01010043,  467, ecp3 /* ecp3 lae3-17ea & lfe3-17ea*/},
+       {0x01012043,  675, ecp3 /* ecp3 lae3-35ea & lfe3-35ea*/},
+       {0x01014043, 1077, ecp3 /* ecp3 lfe3-70ea & lfe3-70e & lfe3-95ea && 
lfe3-95e*/},
+       {0x01015043, 1326, ecp3 /* ecp3 lfe3-150e*/},
+};
+
+void lattice_set_instr(struct jtag_tap *tap, uint8_t new_instr, tap_state_t 
endstate)
+{
+       struct scan_field field;
+       field.num_bits = tap->ir_length;
+       void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1);
+       field.out_value = t;
+       buf_set_u32(t, 0, field.num_bits, new_instr);
+       field.in_value = NULL;
+       jtag_add_ir_scan(tap, &field, endstate);
+       free(t);
+}
+
+static int lattice_check_device_family(struct lattice_pld_device 
*lattice_device)
+{
+       if (lattice_device->family != unknown && lattice_device->preload_length 
!= 0)
+               return ERROR_OK;
+
+       if (!lattice_device->tap || !lattice_device->tap->hasidcode)
+               return ERROR_FAIL;
+
+       for (size_t i = 0; i < ARRAY_SIZE(lattice_devices); ++i) {
+               if (lattice_devices[i].id == lattice_device->tap->idcode) {
+                       if (lattice_device->family == unknown)
+                               lattice_device->family = 
lattice_devices[i].family;
+                       if (lattice_device->preload_length == 0)
+                               lattice_device->preload_length = 
lattice_devices[i].preload_length;
+                       return ERROR_OK;
+               }
+       }
+       LOG_ERROR("Unknown id! Specify family and preload-length manually.");
+       return ERROR_FAIL;
+}
+
+int lattice_read_u32_register(struct jtag_tap *tap, uint8_t cmd, uint32_t 
*in_val,
+                                                       uint32_t out_val, bool 
do_idle)
+{
+       struct scan_field field;
+       uint8_t buffer[4];
+
+       lattice_set_instr(tap, cmd, TAP_IDLE);
+       if (do_idle) {
+               jtag_add_runtest(2, TAP_IDLE);
+               jtag_add_sleep(1000);
+       }
+
+       h_u32_to_le(buffer, out_val);
+       field.num_bits = 32;
+       field.out_value = buffer;
+       field.in_value = buffer;
+       jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+       int retval = jtag_execute_queue();
+       if (retval == ERROR_OK)
+               *in_val = le_to_h_u32(buffer);
+
+       return retval;
+}
+
+int lattice_preload(struct lattice_pld_device *lattice_device)
+{
+       struct scan_field field;
+       size_t sz_bytes = DIV_ROUND_UP(lattice_device->preload_length, 8);
+
+       lattice_set_instr(lattice_device->tap, PRELOAD, TAP_IDLE);
+       uint8_t *buffer = malloc(sz_bytes);
+       if (!buffer) {
+               LOG_ERROR("Out of memory");
+               return ERROR_FAIL;
+       }
+       memset(buffer, 0xff, sz_bytes);
+
+       field.num_bits = lattice_device->preload_length;
+       field.out_value = buffer;
+       field.in_value = NULL;
+       jtag_add_dr_scan(lattice_device->tap, 1, &field, TAP_IDLE);
+       int retval = jtag_execute_queue();
+       free(buffer);
+       return retval;
+}
+
+static int lattice_read_usercode(struct lattice_pld_device *lattice_device, 
uint32_t *usercode, uint32_t out)
+{
+       struct jtag_tap *tap = lattice_device->tap;
+       if (!tap)
+               return ERROR_FAIL;
+
+       if (lattice_device->family == ecp2 || lattice_device->family == ecp3)
+               return lattice_ecp2_3_read_usercode(tap, usercode, out);
+
+       return ERROR_FAIL;
+}
+
+int lattice_verify_usercode(struct lattice_pld_device *lattice_device, 
uint32_t out,
+                                               uint32_t expected, uint32_t 
mask)
+{
+       uint32_t usercode;
+
+       int retval = lattice_read_usercode(lattice_device, &usercode, out);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if ((usercode & mask) != expected) {
+               LOG_ERROR("verifying user code register failed got: 0x%08" 
PRIx32 " expected: 0x%08" PRIx32,
+                       usercode & mask, expected);
+               return ERROR_FAIL;
+       }
+       return ERROR_OK;
+}
+
+static int lattice_write_usercode(struct lattice_pld_device *lattice_device, 
uint32_t usercode)
+{
+       if (lattice_device->family == ecp2 || lattice_device->family == ecp3)
+               return lattice_ecp2_3_write_usercode(lattice_device, usercode);
+
+       return ERROR_FAIL;
+}
+
+static int lattice_read_status_u32(struct lattice_pld_device *lattice_device, 
uint32_t *status,
+                                                               uint32_t out, 
bool do_idle)
+{
+       if (!lattice_device->tap)
+               return ERROR_FAIL;
+
+       if (lattice_device->family == ecp2 || lattice_device->family == ecp3)
+               return lattice_ecp2_3_read_status(lattice_device->tap, status, 
out, do_idle);
+
+       return ERROR_FAIL;
+}
+
+int lattice_verify_status_register_u32(struct lattice_pld_device 
*lattice_device, uint32_t out,
+                                               uint32_t expected, uint32_t 
mask, bool do_idle)
+{
+       uint32_t status;
+
+       int retval = lattice_read_status_u32(lattice_device, &status, out, 
do_idle);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if ((status & mask) != expected) {
+               LOG_ERROR("verifying status register failed got: 0x%08" PRIx32 
" expected: 0x%08" PRIx32,
+                       status & mask, expected);
+               return ERROR_FAIL;
+       }
+       return ERROR_OK;
+}
+
+static int lattice_load_command(struct pld_device *pld_device, const char 
*filename)
+{
+       if (!pld_device)
+               return ERROR_FAIL;
+
+       struct lattice_pld_device *lattice_device = pld_device->driver_priv;
+
+       if (!lattice_device || !lattice_device->tap)
+               return ERROR_FAIL;
+       struct jtag_tap *tap = lattice_device->tap;
+
+       if (!tap->hasidcode)
+               return ERROR_FAIL;
+
+       int retval = lattice_check_device_family(lattice_device);
+       if (retval != ERROR_OK)
+               return retval;
+
+       struct lattice_bit_file bit_file;
+       retval = lattice_read_file(&bit_file, filename, lattice_device->family);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = ERROR_FAIL;
+       switch (lattice_device->family) {
+       case ecp2:
+               retval = lattice_ecp2_load(lattice_device, &bit_file);
+               break;
+       case ecp3:
+               retval = lattice_ecp3_load(lattice_device, &bit_file);
+               break;
+       default:
+               LOG_ERROR("loading unknown device family");
+               break;
+       }
+       free(bit_file.raw_bit.data);
+       return retval;
+}
+
+PLD_DEVICE_COMMAND_HANDLER(lattice_pld_device_command)
+{
+       if (CMD_ARGC < 2 || CMD_ARGC > 3)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[1]);
+       if (!tap) {
+               command_print(CMD, "Tap: %s does not exist", CMD_ARGV[1]);
+               return ERROR_FAIL;
+       }
+
+       struct lattice_pld_device *lattice_device = malloc(sizeof(struct 
lattice_pld_device));
+       if (!lattice_device) {
+               LOG_ERROR("Out of memory");
+               return ERROR_FAIL;
+       }
+       /* id is not known yet -> postpone lattice_check_device_family() */
+       enum family_e family = unknown;
+       if (CMD_ARGC == 3) {
+               if (strcasecmp(CMD_ARGV[2], "ecp2") == 0) {
+                       family = ecp2;
+               } else if (strcasecmp(CMD_ARGV[2], "ecp3") == 0) {
+                       family = ecp3;
+               } else {
+                       LOG_ERROR("unknown family");
+                       free(lattice_device);
+                       return ERROR_FAIL;
+               }
+       }
+       lattice_device->tap = tap;
+       lattice_device->family = family;
+       lattice_device->preload_length = 0;
+
+       pld->driver_priv = lattice_device;
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(lattice_read_usercode_register_command_handler)
+{
+       int dev_id;
+       uint32_t usercode;
+
+       if (CMD_ARGC != 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id);
+       struct pld_device *device = get_pld_device_by_num(dev_id);
+       if (!device) {
+               command_print(CMD, "pld device '#%s' is out of bounds", 
CMD_ARGV[0]);
+               return ERROR_FAIL;
+       }
+
+       struct lattice_pld_device *lattice_device = device->driver_priv;
+       if (!lattice_device)
+               return ERROR_FAIL;
+
+       int retval = lattice_check_device_family(lattice_device);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = lattice_read_usercode(lattice_device, &usercode, 0x0);
+       if (retval == ERROR_OK)
+               command_print(CMD, "0x%8.8" PRIx32 "", usercode);
+
+       return retval;
+}
+
+COMMAND_HANDLER(lattice_set_preload_command_handler)
+{
+       int dev_id;
+       unsigned int preload_length;
+
+       if (CMD_ARGC != 2)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id);
+       struct pld_device *device = get_pld_device_by_num(dev_id);
+       if (!device) {
+               command_print(CMD, "pld device '#%s' is out of bounds", 
CMD_ARGV[0]);
+               return ERROR_FAIL;
+       }
+
+       COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], preload_length);
+
+       struct lattice_pld_device *lattice_device = device->driver_priv;
+
+       if (!lattice_device)
+               return ERROR_FAIL;
+
+       lattice_device->preload_length = preload_length;
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(lattice_write_usercode_register_command_handler)
+{
+       int dev_id;
+       uint32_t usercode;
+
+       if (CMD_ARGC != 2)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id);
+       struct pld_device *device = get_pld_device_by_num(dev_id);
+       if (!device) {
+               command_print(CMD, "pld device '#%s' is out of bounds", 
CMD_ARGV[0]);
+               return ERROR_FAIL;
+       }
+
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], usercode);
+
+       struct lattice_pld_device *lattice_device = device->driver_priv;
+       if (!lattice_device)
+               return ERROR_FAIL;
+
+       int retval = lattice_check_device_family(lattice_device);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return lattice_write_usercode(lattice_device, usercode);
+}
+
+COMMAND_HANDLER(lattice_read_status_command_handler)
+{
+       int dev_id;
+
+       if (CMD_ARGC != 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id);
+       struct pld_device *device = get_pld_device_by_num(dev_id);
+       if (!device) {
+               command_print(CMD, "pld device '#%s' is out of bounds", 
CMD_ARGV[0]);
+               return ERROR_FAIL;
+       }
+
+       struct lattice_pld_device *lattice_device = device->driver_priv;
+       if (!lattice_device)
+               return ERROR_FAIL;
+
+       int retval = lattice_check_device_family(lattice_device);
+       if (retval != ERROR_OK)
+               return retval;
+
+       uint32_t status;
+       retval = lattice_read_status_u32(lattice_device, &status, 0x0, false);
+       if (retval == ERROR_OK)
+               command_print(CMD, "0x%8.8" PRIx32 "", status);
+
+       return retval;
+}
+
+static const struct command_registration lattice_exec_command_handlers[] = {
+       {
+               .name = "read_status",
+               .mode = COMMAND_EXEC,
+               .handler = lattice_read_status_command_handler,
+               .help = "reading status register from FPGA",
+               .usage = "num_pld",
+       }, {
+               .name = "read_user",
+               .mode = COMMAND_EXEC,
+               .handler = lattice_read_usercode_register_command_handler,
+               .help = "reading usercode register from FPGA",
+               .usage = "num_pld",
+       }, {
+               .name = "write_user",
+               .mode = COMMAND_EXEC,
+               .handler = lattice_write_usercode_register_command_handler,
+               .help = "writing usercode register to FPGA",
+               .usage = "num_pld value",
+       }, {
+               .name = "set_preload",
+               .mode = COMMAND_EXEC,
+               .handler = lattice_set_preload_command_handler,
+               .help = "set length for preload (device specific)",
+               .usage = "num_pld value",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration lattice_command_handler[] = {
+       {
+               .name = "lattice",
+               .mode = COMMAND_ANY,
+               .help = "lattice specific commands",
+               .usage = "",
+               .chain = lattice_exec_command_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+struct pld_driver lattice_pld = {
+       .name = "lattice",
+       .commands = lattice_command_handler,
+       .pld_device_command = &lattice_pld_device_command,
+       .load = &lattice_load_command,
+};
diff --git a/src/pld/lattice.h b/src/pld/lattice.h
new file mode 100644
index 0000000000..c91af805aa
--- /dev/null
+++ b/src/pld/lattice.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ *   Copyright (C) 2022 by Daniel Anselmi                                  *
+ *   danse...@gmx.ch                                                       *
+ ***************************************************************************/
+
+#ifndef OPENOCD_PLD_LATTICE_H
+#define OPENOCD_PLD_LATTICE_H
+
+#include <jtag/jtag.h>
+#include "pld.h"
+#include "lattice_bit.h"
+
+struct lattice_pld_device {
+       struct jtag_tap *tap;
+       size_t preload_length;
+       enum family_e family;
+};
+
+void lattice_set_instr(struct jtag_tap *tap, uint8_t new_instr, tap_state_t 
endstate);
+int lattice_read_u32_register(struct jtag_tap *tap, uint8_t cmd, uint32_t 
*in_val,
+                                                       uint32_t out_val, bool 
do_idle);
+int lattice_verify_usercode(struct lattice_pld_device *lattice_device, 
uint32_t out,
+                                               uint32_t expected, uint32_t 
mask);
+int lattice_verify_status_register_u32(struct lattice_pld_device 
*lattice_device, uint32_t out,
+                                               uint32_t expected, uint32_t 
mask, bool do_idle);
+int lattice_preload(struct lattice_pld_device *lattice_device);
+
+#endif /* OPENOCD_PLD_LATTICE_H */
diff --git a/src/pld/lattice_bit.c b/src/pld/lattice_bit.c
new file mode 100644
index 0000000000..57a112354f
--- /dev/null
+++ b/src/pld/lattice_bit.c
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ *   Copyright (C) 2022 by Daniel Anselmi                                  *
+ *   danse...@gmx.ch                                                       *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "lattice_bit.h"
+#include "raw_bit.h"
+#include "pld.h"
+#include <helper/system.h>
+#include <helper/log.h>
+#include <helper/binarybuffer.h>
+
+#define SEEK_HEADER_START 1
+#define SEEK_HEADER_END   2
+#define SEEK_PREAMBLE     3
+#define SEEK_ID           4
+#define DONE              5
+
+static int lattice_read_bit_file(struct lattice_bit_file *bit_file, const char 
*filename, enum family_e family)
+{
+       int retval = cpld_read_raw_bit_file(&bit_file->raw_bit, filename);
+       if (retval != ERROR_OK)
+               return retval;
+
+       bit_file->part = 0;
+       bit_file->has_id = false;
+       int state = SEEK_HEADER_START;
+       for (size_t pos = 1; pos < bit_file->raw_bit.length && state != DONE; 
++pos) {
+               switch (state) {
+               case SEEK_HEADER_START:
+                       if (bit_file->raw_bit.data[pos] == 0 && 
bit_file->raw_bit.data[pos - 1] == 0xff)
+                               state = SEEK_HEADER_END;
+                       break;
+               case SEEK_HEADER_END:
+                       if (pos + 6 < bit_file->raw_bit.length &&
+                                       strncmp((const char 
*)(bit_file->raw_bit.data + pos), "Part: ", 6) == 0) {
+                               bit_file->part = (const char 
*)bit_file->raw_bit.data + pos + 6;
+                               LOG_INFO("part found: %s\n", bit_file->part);
+                       } else if (bit_file->raw_bit.data[pos] == 0xff && 
bit_file->raw_bit.data[pos - 1] == 0) {
+                               bit_file->offset = pos;
+                               state = (family != ecp2 || family != ecp3) ? 
SEEK_PREAMBLE : DONE;
+                       }
+                       break;
+               case SEEK_PREAMBLE:
+                       if (pos >= 4 && bit_file->raw_bit.data[pos] == 0xb3) {
+                               if (bit_file->raw_bit.data[pos - 1] == 0xbd &&
+                                       bit_file->raw_bit.data[pos - 2] == 0xff 
&&
+                                       bit_file->raw_bit.data[pos - 3] == 
0xff) {
+                                       state = SEEK_ID;
+                               }
+                               if (bit_file->raw_bit.data[pos - 1] == 0xbf &&
+                                       bit_file->raw_bit.data[pos - 2] == 0xff 
&&
+                                       bit_file->raw_bit.data[pos - 3] == 
0xff) {
+                                       state = DONE;
+                               }
+                               if (bit_file->raw_bit.data[pos - 1] == 0xbe &&
+                                       bit_file->raw_bit.data[pos - 2] == 0xff 
&&
+                                       bit_file->raw_bit.data[pos - 3] == 
0xff) {
+                                       state = DONE;
+                               }
+                       }
+                       break;
+               case SEEK_ID:
+                       if (pos + 7 < bit_file->raw_bit.length && 
bit_file->raw_bit.data[pos] == 0xe2) {
+                               bit_file->idcode = 
be_to_h_u32(&bit_file->raw_bit.data[pos + 4]);
+                               bit_file->has_id = true;
+                               state = DONE;
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       if (state != DONE) {
+               LOG_ERROR("parsing bitstream failed");
+               return ERROR_PLD_FILE_LOAD_FAILED;
+       }
+
+       for (size_t i = bit_file->offset; i < bit_file->raw_bit.length; i++)
+               bit_file->raw_bit.data[i] = flip_u32(bit_file->raw_bit.data[i], 
8);
+
+       return ERROR_OK;
+}
+
+int lattice_read_file(struct lattice_bit_file *bit_file, const char *filename, 
enum family_e family)
+{
+       if (!filename || !bit_file)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       /* check if binary .bin or ascii .bit/.hex */
+       const char *file_suffix_pos = strrchr(filename, '.');
+       if (!file_suffix_pos) {
+               LOG_ERROR("Unable to detect filename suffix");
+               return ERROR_PLD_FILE_LOAD_FAILED;
+       }
+
+       if (strcasecmp(file_suffix_pos, ".bit") == 0)
+               return lattice_read_bit_file(bit_file, filename, family);
+
+       LOG_ERROR("Filetype not supported");
+       return ERROR_PLD_FILE_LOAD_FAILED;
+}
diff --git a/src/pld/lattice_bit.h b/src/pld/lattice_bit.h
new file mode 100644
index 0000000000..25d62c26de
--- /dev/null
+++ b/src/pld/lattice_bit.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ *   Copyright (C) 2022 by Daniel Anselmi                                  *
+ *   danse...@gmx.ch                                                       *
+ ***************************************************************************/
+
+#ifndef OPENOCD_PLD_LATTICE_BIT_H
+#define OPENOCD_PLD_LATTICE_BIT_H
+
+#include "helper/types.h"
+#include "raw_bit.h"
+
+
+struct lattice_bit_file {
+       struct raw_bit_file raw_bit;
+       size_t offset;
+       uint32_t idcode;
+       const char *part; /* reuses memory in raw_bit_file */
+       bool has_id;
+};
+
+enum family_e {ecp2,
+                               ecp3,
+                               ecp5,
+                               certus,
+                               unknown
+};
+
+int lattice_read_file(struct lattice_bit_file *bit_file, const char *filename, 
enum family_e family);
+
+#endif /* OPENOCD_PLD_LATTICE_BIT_H */
diff --git a/src/pld/pld.c b/src/pld/pld.c
index e2e0ef4138..e838888cef 100644
--- a/src/pld/pld.c
+++ b/src/pld/pld.c
@@ -10,6 +10,7 @@
 #endif
 
 #include "pld.h"
+#include <sys/stat.h>
 #include <helper/log.h>
 #include <helper/replacements.h>
 #include <helper/time_support.h>
@@ -17,9 +18,11 @@
 
 /* pld drivers
  */
+extern struct pld_driver lattice_pld;
 extern struct pld_driver virtex2_pld;
 
 static struct pld_driver *pld_drivers[] = {
+       &lattice_pld,
        &virtex2_pld,
        NULL,
 };
@@ -134,6 +137,22 @@ COMMAND_HANDLER(handle_pld_load_command)
                return ERROR_OK;
        }
 
+       struct stat input_stat;
+       if (stat(CMD_ARGV[1], &input_stat) == -1) {
+               LOG_ERROR("couldn't stat() %s: %s", CMD_ARGV[1], 
strerror(errno));
+               return ERROR_PLD_FILE_LOAD_FAILED;
+       }
+
+       if (S_ISDIR(input_stat.st_mode)) {
+               LOG_ERROR("%s is a directory", CMD_ARGV[1]);
+               return ERROR_PLD_FILE_LOAD_FAILED;
+       }
+
+       if (input_stat.st_size == 0) {
+               LOG_ERROR("Empty file %s", CMD_ARGV[1]);
+               return ERROR_PLD_FILE_LOAD_FAILED;
+       }
+
        retval = p->driver->load(p, CMD_ARGV[1]);
        if (retval != ERROR_OK) {
                command_print(CMD, "failed loading file %s to pld device %u",
diff --git a/src/pld/raw_bit.c b/src/pld/raw_bit.c
new file mode 100644
index 0000000000..0c3b92e7e9
--- /dev/null
+++ b/src/pld/raw_bit.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ *   Copyright (C) 2022 by Daniel Anselmi                                  *
+ *   danse...@gmx.ch                                                       *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "raw_bit.h"
+#include "pld.h"
+
+#include <helper/system.h>
+#include <helper/log.h>
+
+
+int cpld_read_raw_bit_file(struct raw_bit_file *bit_file, const char *filename)
+{
+       FILE *input_file = fopen(filename, "rb");
+
+       if (!input_file) {
+               LOG_ERROR("Couldn't open %s: %s", filename, strerror(errno));
+               return ERROR_PLD_FILE_LOAD_FAILED;
+       }
+
+       fseek(input_file, 0, SEEK_END);
+       long length = ftell(input_file);
+       fseek(input_file, 0, SEEK_SET);
+
+       if (length < 0) {
+               fclose(input_file);
+               LOG_ERROR("Failed to get length of file %s: %s", filename, 
strerror(errno));
+               return ERROR_PLD_FILE_LOAD_FAILED;
+       }
+       bit_file->length = (size_t)length;
+
+       bit_file->data = malloc(bit_file->length);
+       if (!bit_file->data) {
+               fclose(input_file);
+               LOG_ERROR("Out of memory");
+               return ERROR_PLD_FILE_LOAD_FAILED;
+       }
+
+       size_t read_count = fread(bit_file->data, sizeof(char), 
bit_file->length, input_file);
+       fclose(input_file);
+       if (read_count != bit_file->length) {
+               free(bit_file->data);
+               bit_file->data = NULL;
+               return ERROR_PLD_FILE_LOAD_FAILED;
+       }
+
+       return ERROR_OK;
+}
diff --git a/src/pld/raw_bit.h b/src/pld/raw_bit.h
new file mode 100644
index 0000000000..583ff76e99
--- /dev/null
+++ b/src/pld/raw_bit.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ *   Copyright (C) 2022 by Daniel Anselmi                                  *
+ *   danse...@gmx.ch                                                       *
+ ***************************************************************************/
+
+#ifndef OPENOCD_PLD_RAW_BIN_H
+#define OPENOCD_PLD_RAW_BIN_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+struct raw_bit_file {
+       size_t length;
+       uint8_t *data;
+};
+
+int cpld_read_raw_bit_file(struct raw_bit_file *bit_file, const char 
*filename);
+
+#endif /* OPENOCD_PLD_RAW_BIN_H */
diff --git a/src/pld/xilinx_bit.c b/src/pld/xilinx_bit.c
index 792b3375b6..e4cc52ef97 100644
--- a/src/pld/xilinx_bit.c
+++ b/src/pld/xilinx_bit.c
@@ -13,7 +13,6 @@
 #include "pld.h"
 #include <helper/log.h>
 
-#include <sys/stat.h>
 #include <helper/system.h>
 
 static int read_section(FILE *input_file, int length_size, char section,
@@ -60,27 +59,11 @@ static int read_section(FILE *input_file, int length_size, 
char section,
 int xilinx_read_bit_file(struct xilinx_bit_file *bit_file, const char 
*filename)
 {
        FILE *input_file;
-       struct stat input_stat;
        int read_count;
 
        if (!filename || !bit_file)
                return ERROR_COMMAND_SYNTAX_ERROR;
 
-       if (stat(filename, &input_stat) == -1) {
-               LOG_ERROR("couldn't stat() %s: %s", filename, strerror(errno));
-               return ERROR_PLD_FILE_LOAD_FAILED;
-       }
-
-       if (S_ISDIR(input_stat.st_mode)) {
-               LOG_ERROR("%s is a directory", filename);
-               return ERROR_PLD_FILE_LOAD_FAILED;
-       }
-
-       if (input_stat.st_size == 0) {
-               LOG_ERROR("Empty file %s", filename);
-               return ERROR_PLD_FILE_LOAD_FAILED;
-       }
-
        input_file = fopen(filename, "rb");
        if (!input_file) {
                LOG_ERROR("couldn't open %s: %s", filename, strerror(errno));
diff --git a/tcl/fpga/lattice_ecp2.cfg b/tcl/fpga/lattice_ecp2.cfg
new file mode 100644
index 0000000000..a1aa2eff1f
--- /dev/null
+++ b/tcl/fpga/lattice_ecp2.cfg
@@ -0,0 +1,31 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+if { [info exists CHIPNAME] } {
+       set _CHIPNAME $_CHIPNAME
+} else {
+       set _CHIPNAME ecp2
+}
+
+# Lattice ECP2 family
+# TAP IDs are extracted from BSDL files found on this page:
+# https://www.latticesemi.com/Products/FPGAandCPLD/LatticeECP2M
+#
+# LFE2M20E: 0x01279043
+# LFE2M35E: 0x0127A043
+# LFE2M50E: 0x0127B043
+# LFE2M70E: 0x0127C043
+# LFE2M100E: 0x0127D043
+# LFEC2_6E: 0x01270043
+# LFEC2_12E: 0x01271043
+# LFEC2_20E: 0x01272043
+# LFEC2_35E: 0x01274043
+# LFEC2_50E: 0x01273043
+# LFEC2_70E: 0x01275043
+
+jtag newtap $_CHIPNAME tap -irlen 8  \
+       -expected-id 0x01279043 -expected-id 0x0127A043 -expected-id 0x0127B043 
\
+       -expected-id 0x0127C043 -expected-id 0x0127D043 -expected-id 0x01270043 
\
+       -expected-id 0x01271043 -expected-id 0x01272043 -expected-id 0x01274043 
\
+       -expected-id 0x01273043 -expected-id 0x01275043
+
+pld device lattice $_CHIPNAME.tap
diff --git a/tcl/fpga/lattice_ecp3.cfg b/tcl/fpga/lattice_ecp3.cfg
new file mode 100644
index 0000000000..7cd5706495
--- /dev/null
+++ b/tcl/fpga/lattice_ecp3.cfg
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+if { [info exists CHIPNAME] } {
+       set _CHIPNAME $_CHIPNAME
+} else {
+       set _CHIPNAME ecp3
+}
+
+# Lattice ECP3 family
+# TAP IDs are extracted from BSDL files found on this page:
+# https://www.latticesemi.com/Products/FPGAandCPLD/LatticeECP3
+#
+# LFE3_17:  0x01010043
+# LFE3_35:  0x01012043
+# LFE3_95:  0x01014043 and LFE3_70
+# LFE3_150: 0x01015043
+
+jtag newtap $_CHIPNAME tap -irlen 8  \
+       -expected-id 0x01010043 -expected-id 0x01012043 \
+       -expected-id 0x01014043 -expected-id 0x01015043
+
+pld device lattice $_CHIPNAME.tap

-- 


Reply via email to