pld: add support for lattice ecp2 and ecp3 devices

Change-Id: I29c227c37be464f7ecc97a30d9cf3da1442e2b7f
Signed-off-by: Daniel Anselmi <danselmi@gmx.ch>
Reviewed-on: https://review.openocd.org/c/openocd/+/7396
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Tested-by: jenkins
This commit is contained in:
Daniel Anselmi
2022-12-12 09:49:51 +01:00
committed by Antonio Borneo
parent 8670ad4caa
commit d35faaa35c
13 changed files with 1044 additions and 1 deletions

View File

@@ -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

250
src/pld/ecp2_3.c Normal file
View File

@@ -0,0 +1,250 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/***************************************************************************
* Copyright (C) 2022 by Daniel Anselmi *
* danselmi@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 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;
int retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
jtag_add_runtest(5, TAP_IDLE);
jtag_add_sleep(20000);
retval = lattice_set_instr(tap, ISC_PROGRAM_USERCODE, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
struct scan_field field;
uint8_t buffer[4];
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);
retval = lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
jtag_add_runtest(5, TAP_IDLE);
jtag_add_sleep(200000);
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;
/* program user code with all bits set */
int retval = lattice_set_instr(tap, ISC_PROGRAM_USERCODE, TAP_IRPAUSE);
if (retval != ERROR_OK)
return retval;
struct scan_field field;
uint8_t buffer[4] = {0xff, 0xff, 0xff, 0xff};
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;
retval = lattice_verify_usercode(lattice_device, out, expected_pre, mask);
if (retval != ERROR_OK)
return retval;
retval = lattice_set_instr(tap, ISC_ERASE, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
jtag_add_runtest(5, TAP_IDLE);
if (lattice_device->family == LATTICE_ECP2)
jtag_add_sleep(100000);
else
jtag_add_sleep(2000000);
retval = lattice_set_instr(tap, LSCC_RESET_ADDRESS, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
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;
int retval = lattice_set_instr(tap, LSCC_RESET_ADDRESS, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
jtag_add_runtest(5, TAP_IDLE);
jtag_add_sleep(2000);
struct scan_field field;
retval = lattice_set_instr(tap, LSCC_BITSTREAM_BURST, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
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;
int retval = lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
jtag_add_runtest(5, TAP_IDLE);
jtag_add_sleep(200000);
retval = lattice_set_instr(tap, BYPASS, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
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 */
retval = lattice_set_instr(tap, LSCC_REFRESH, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
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 */
retval = lattice_set_instr(tap, LSCC_REFRESH, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
jtag_add_runtest(5, TAP_IDLE);
jtag_add_sleep(500000);
retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
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);
}

19
src/pld/ecp2_3.h Normal file
View File

@@ -0,0 +1,19 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/***************************************************************************
* Copyright (C) 2022 by Daniel Anselmi *
* danselmi@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 */

435
src/pld/lattice.c Normal file
View File

@@ -0,0 +1,435 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/***************************************************************************
* Copyright (C) 2022 by Daniel Anselmi *
* danselmi@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 lattice_family_e family;
};
static const struct lattice_devices_elem lattice_devices[] = {
{0x01270043, 654, LATTICE_ECP2 /* ecp2-6e */},
{0x01271043, 643, LATTICE_ECP2 /* ecp2-12e */},
{0x01272043, 827, LATTICE_ECP2 /* ecp2-20e */},
{0x01274043, 1011, LATTICE_ECP2 /* ecp2-35e */},
{0x01273043, 1219, LATTICE_ECP2 /* ecp2-50e */},
{0x01275043, 654, LATTICE_ECP2 /* ecp2-70e */},
{0x01279043, 680, LATTICE_ECP2 /* ecp2m20e */},
{0x0127A043, 936, LATTICE_ECP2 /* ecp2m35e */},
{0x0127B043, 1056, LATTICE_ECP2 /* ecp2m50e */},
{0x0127C043, 1039, LATTICE_ECP2 /* ecp2m70e */},
{0x0127D043, 1311, LATTICE_ECP2 /* ecp2m100e */},
{0x01010043, 467, LATTICE_ECP3 /* ecp3 lae3-17ea & lfe3-17ea*/},
{0x01012043, 675, LATTICE_ECP3 /* ecp3 lae3-35ea & lfe3-35ea*/},
{0x01014043, 1077, LATTICE_ECP3 /* ecp3 lfe3-70ea & lfe3-70e & lfe3-95ea && lfe3-95e*/},
{0x01015043, 1326, LATTICE_ECP3 /* ecp3 lfe3-150e*/},
};
int 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);
if (!t) {
LOG_ERROR("Out of memory");
return ERROR_FAIL;
}
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);
return ERROR_OK;
}
static int lattice_check_device_family(struct lattice_pld_device *lattice_device)
{
if (lattice_device->family != LATTICE_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 == LATTICE_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];
int retval = lattice_set_instr(tap, cmd, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
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);
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);
int retval = lattice_set_instr(lattice_device->tap, PRELOAD, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
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);
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 == LATTICE_ECP2 || lattice_device->family == LATTICE_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 == LATTICE_ECP2 || lattice_device->family == LATTICE_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 == LATTICE_ECP2 || lattice_device->family == LATTICE_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 || !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 LATTICE_ECP2:
retval = lattice_ecp2_load(lattice_device, &bit_file);
break;
case LATTICE_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 lattice_family_e family = LATTICE_UNKNOWN;
if (CMD_ARGC == 3) {
if (strcasecmp(CMD_ARGV[2], "ecp2") == 0) {
family = LATTICE_ECP2;
} else if (strcasecmp(CMD_ARGV[2], "ecp3") == 0) {
family = LATTICE_ECP3;
} else {
command_print(CMD, "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,
};

32
src/pld/lattice.h Normal file
View File

@@ -0,0 +1,32 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/***************************************************************************
* Copyright (C) 2022 by Daniel Anselmi *
* danselmi@gmx.ch *
***************************************************************************/
#ifndef OPENOCD_PLD_LATTICE_H
#define OPENOCD_PLD_LATTICE_H
#include <jtag/jtag.h>
#include "pld.h"
#include "lattice_bit.h"
#define BYPASS 0xFF
struct lattice_pld_device {
struct jtag_tap *tap;
size_t preload_length;
enum lattice_family_e family;
};
int 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 */

105
src/pld/lattice_bit.c Normal file
View File

@@ -0,0 +1,105 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/***************************************************************************
* Copyright (C) 2022 by Daniel Anselmi *
* danselmi@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>
enum read_bit_state {
SEEK_HEADER_START,
SEEK_HEADER_END,
SEEK_PREAMBLE,
SEEK_ID,
DONE,
};
static int lattice_read_bit_file(struct lattice_bit_file *bit_file, const char *filename, enum lattice_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;
enum read_bit_state 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 != LATTICE_ECP2 && family != LATTICE_ECP3) ? SEEK_PREAMBLE : DONE;
}
break;
case SEEK_PREAMBLE:
if (pos >= 4) {
uint32_t preamble = be_to_h_u32(bit_file->raw_bit.data + pos - 3);
switch (preamble) {
case 0xffffbdb3:
state = SEEK_ID;
break;
case 0xffffbfb3:
case 0xffffbeb3:
state = DONE;
break;
}
}
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 lattice_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;
}

33
src/pld/lattice_bit.h Normal file
View File

@@ -0,0 +1,33 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/***************************************************************************
* Copyright (C) 2022 by Daniel Anselmi *
* danselmi@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 lattice_family_e {
LATTICE_ECP2,
LATTICE_ECP3,
LATTICE_ECP5,
LATTICE_CERTUS,
LATTICE_UNKNOWN,
};
int lattice_read_file(struct lattice_bit_file *bit_file, const char *filename, enum lattice_family_e family);
#endif /* OPENOCD_PLD_LATTICE_BIT_H */

View File

@@ -18,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,
};

55
src/pld/raw_bit.c Normal file
View File

@@ -0,0 +1,55 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/***************************************************************************
* Copyright (C) 2022 by Daniel Anselmi *
* danselmi@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;
}

21
src/pld/raw_bit.h Normal file
View File

@@ -0,0 +1,21 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/***************************************************************************
* Copyright (C) 2022 by Daniel Anselmi *
* danselmi@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 */